251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
403 |
404 |
405 |
406 |
--------------------------------------------------------------------------------
/public/font/material-design-icons/LICENSE.txt:
--------------------------------------------------------------------------------
1 | https://github.com/google/material-design-icons/blob/master/LICENSE
2 | https://github.com/FezVrasta/bootstrap-material-design/blob/master/fonts/LICENSE.txt
3 |
4 | Attribution-ShareAlike 4.0 International
5 |
6 | =======================================================================
7 |
8 | Creative Commons Corporation ("Creative Commons") is not a law firm and
9 | does not provide legal services or legal advice. Distribution of
10 | Creative Commons public licenses does not create a lawyer-client or
11 | other relationship. Creative Commons makes its licenses and related
12 | information available on an "as-is" basis. Creative Commons gives no
13 | warranties regarding its licenses, any material licensed under their
14 | terms and conditions, or any related information. Creative Commons
15 | disclaims all liability for damages resulting from their use to the
16 | fullest extent possible.
17 |
18 | Using Creative Commons Public Licenses
19 |
20 | Creative Commons public licenses provide a standard set of terms and
21 | conditions that creators and other rights holders may use to share
22 | original works of authorship and other material subject to copyright
23 | and certain other rights specified in the public license below. The
24 | following considerations are for informational purposes only, are not
25 | exhaustive, and do not form part of our licenses.
26 |
27 | Considerations for licensors: Our public licenses are
28 | intended for use by those authorized to give the public
29 | permission to use material in ways otherwise restricted by
30 | copyright and certain other rights. Our licenses are
31 | irrevocable. Licensors should read and understand the terms
32 | and conditions of the license they choose before applying it.
33 | Licensors should also secure all rights necessary before
34 | applying our licenses so that the public can reuse the
35 | material as expected. Licensors should clearly mark any
36 | material not subject to the license. This includes other CC-
37 | licensed material, or material used under an exception or
38 | limitation to copyright. More considerations for licensors:
39 | wiki.creativecommons.org/Considerations_for_licensors
40 |
41 | Considerations for the public: By using one of our public
42 | licenses, a licensor grants the public permission to use the
43 | licensed material under specified terms and conditions. If
44 | the licensor's permission is not necessary for any reason--for
45 | example, because of any applicable exception or limitation to
46 | copyright--then that use is not regulated by the license. Our
47 | licenses grant only permissions under copyright and certain
48 | other rights that a licensor has authority to grant. Use of
49 | the licensed material may still be restricted for other
50 | reasons, including because others have copyright or other
51 | rights in the material. A licensor may make special requests,
52 | such as asking that all changes be marked or described.
53 | Although not required by our licenses, you are encouraged to
54 | respect those requests where reasonable. More_considerations
55 | for the public:
56 | wiki.creativecommons.org/Considerations_for_licensees
57 |
58 | =======================================================================
59 |
60 | Creative Commons Attribution-ShareAlike 4.0 International Public
61 | License
62 |
63 | By exercising the Licensed Rights (defined below), You accept and agree
64 | to be bound by the terms and conditions of this Creative Commons
65 | Attribution-ShareAlike 4.0 International Public License ("Public
66 | License"). To the extent this Public License may be interpreted as a
67 | contract, You are granted the Licensed Rights in consideration of Your
68 | acceptance of these terms and conditions, and the Licensor grants You
69 | such rights in consideration of benefits the Licensor receives from
70 | making the Licensed Material available under these terms and
71 | conditions.
72 |
73 |
74 | Section 1 -- Definitions.
75 |
76 | a. Adapted Material means material subject to Copyright and Similar
77 | Rights that is derived from or based upon the Licensed Material
78 | and in which the Licensed Material is translated, altered,
79 | arranged, transformed, or otherwise modified in a manner requiring
80 | permission under the Copyright and Similar Rights held by the
81 | Licensor. For purposes of this Public License, where the Licensed
82 | Material is a musical work, performance, or sound recording,
83 | Adapted Material is always produced where the Licensed Material is
84 | synched in timed relation with a moving image.
85 |
86 | b. Adapter's License means the license You apply to Your Copyright
87 | and Similar Rights in Your contributions to Adapted Material in
88 | accordance with the terms and conditions of this Public License.
89 |
90 | c. BY-SA Compatible License means a license listed at
91 | creativecommons.org/compatiblelicenses, approved by Creative
92 | Commons as essentially the equivalent of this Public License.
93 |
94 | d. Copyright and Similar Rights means copyright and/or similar rights
95 | closely related to copyright including, without limitation,
96 | performance, broadcast, sound recording, and Sui Generis Database
97 | Rights, without regard to how the rights are labeled or
98 | categorized. For purposes of this Public License, the rights
99 | specified in Section 2(b)(1)-(2) are not Copyright and Similar
100 | Rights.
101 |
102 | e. Effective Technological Measures means those measures that, in the
103 | absence of proper authority, may not be circumvented under laws
104 | fulfilling obligations under Article 11 of the WIPO Copyright
105 | Treaty adopted on December 20, 1996, and/or similar international
106 | agreements.
107 |
108 | f. Exceptions and Limitations means fair use, fair dealing, and/or
109 | any other exception or limitation to Copyright and Similar Rights
110 | that applies to Your use of the Licensed Material.
111 |
112 | g. License Elements means the license attributes listed in the name
113 | of a Creative Commons Public License. The License Elements of this
114 | Public License are Attribution and ShareAlike.
115 |
116 | h. Licensed Material means the artistic or literary work, database,
117 | or other material to which the Licensor applied this Public
118 | License.
119 |
120 | i. Licensed Rights means the rights granted to You subject to the
121 | terms and conditions of this Public License, which are limited to
122 | all Copyright and Similar Rights that apply to Your use of the
123 | Licensed Material and that the Licensor has authority to license.
124 |
125 | j. Licensor means the individual(s) or entity(ies) granting rights
126 | under this Public License.
127 |
128 | k. Share means to provide material to the public by any means or
129 | process that requires permission under the Licensed Rights, such
130 | as reproduction, public display, public performance, distribution,
131 | dissemination, communication, or importation, and to make material
132 | available to the public including in ways that members of the
133 | public may access the material from a place and at a time
134 | individually chosen by them.
135 |
136 | l. Sui Generis Database Rights means rights other than copyright
137 | resulting from Directive 96/9/EC of the European Parliament and of
138 | the Council of 11 March 1996 on the legal protection of databases,
139 | as amended and/or succeeded, as well as other essentially
140 | equivalent rights anywhere in the world.
141 |
142 | m. You means the individual or entity exercising the Licensed Rights
143 | under this Public License. Your has a corresponding meaning.
144 |
145 |
146 | Section 2 -- Scope.
147 |
148 | a. License grant.
149 |
150 | 1. Subject to the terms and conditions of this Public License,
151 | the Licensor hereby grants You a worldwide, royalty-free,
152 | non-sublicensable, non-exclusive, irrevocable license to
153 | exercise the Licensed Rights in the Licensed Material to:
154 |
155 | a. reproduce and Share the Licensed Material, in whole or
156 | in part; and
157 |
158 | b. produce, reproduce, and Share Adapted Material.
159 |
160 | 2. Exceptions and Limitations. For the avoidance of doubt, where
161 | Exceptions and Limitations apply to Your use, this Public
162 | License does not apply, and You do not need to comply with
163 | its terms and conditions.
164 |
165 | 3. Term. The term of this Public License is specified in Section
166 | 6(a).
167 |
168 | 4. Media and formats; technical modifications allowed. The
169 | Licensor authorizes You to exercise the Licensed Rights in
170 | all media and formats whether now known or hereafter created,
171 | and to make technical modifications necessary to do so. The
172 | Licensor waives and/or agrees not to assert any right or
173 | authority to forbid You from making technical modifications
174 | necessary to exercise the Licensed Rights, including
175 | technical modifications necessary to circumvent Effective
176 | Technological Measures. For purposes of this Public License,
177 | simply making modifications authorized by this Section 2(a)
178 | (4) never produces Adapted Material.
179 |
180 | 5. Downstream recipients.
181 |
182 | a. Offer from the Licensor -- Licensed Material. Every
183 | recipient of the Licensed Material automatically
184 | receives an offer from the Licensor to exercise the
185 | Licensed Rights under the terms and conditions of this
186 | Public License.
187 |
188 | b. Additional offer from the Licensor -- Adapted Material.
189 | Every recipient of Adapted Material from You
190 | automatically receives an offer from the Licensor to
191 | exercise the Licensed Rights in the Adapted Material
192 | under the conditions of the Adapter's License You apply.
193 |
194 | c. No downstream restrictions. You may not offer or impose
195 | any additional or different terms or conditions on, or
196 | apply any Effective Technological Measures to, the
197 | Licensed Material if doing so restricts exercise of the
198 | Licensed Rights by any recipient of the Licensed
199 | Material.
200 |
201 | 6. No endorsement. Nothing in this Public License constitutes or
202 | may be construed as permission to assert or imply that You
203 | are, or that Your use of the Licensed Material is, connected
204 | with, or sponsored, endorsed, or granted official status by,
205 | the Licensor or others designated to receive attribution as
206 | provided in Section 3(a)(1)(A)(i).
207 |
208 | b. Other rights.
209 |
210 | 1. Moral rights, such as the right of integrity, are not
211 | licensed under this Public License, nor are publicity,
212 | privacy, and/or other similar personality rights; however, to
213 | the extent possible, the Licensor waives and/or agrees not to
214 | assert any such rights held by the Licensor to the limited
215 | extent necessary to allow You to exercise the Licensed
216 | Rights, but not otherwise.
217 |
218 | 2. Patent and trademark rights are not licensed under this
219 | Public License.
220 |
221 | 3. To the extent possible, the Licensor waives any right to
222 | collect royalties from You for the exercise of the Licensed
223 | Rights, whether directly or through a collecting society
224 | under any voluntary or waivable statutory or compulsory
225 | licensing scheme. In all other cases the Licensor expressly
226 | reserves any right to collect such royalties.
227 |
228 |
229 | Section 3 -- License Conditions.
230 |
231 | Your exercise of the Licensed Rights is expressly made subject to the
232 | following conditions.
233 |
234 | a. Attribution.
235 |
236 | 1. If You Share the Licensed Material (including in modified
237 | form), You must:
238 |
239 | a. retain the following if it is supplied by the Licensor
240 | with the Licensed Material:
241 |
242 | i. identification of the creator(s) of the Licensed
243 | Material and any others designated to receive
244 | attribution, in any reasonable manner requested by
245 | the Licensor (including by pseudonym if
246 | designated);
247 |
248 | ii. a copyright notice;
249 |
250 | iii. a notice that refers to this Public License;
251 |
252 | iv. a notice that refers to the disclaimer of
253 | warranties;
254 |
255 | v. a URI or hyperlink to the Licensed Material to the
256 | extent reasonably practicable;
257 |
258 | b. indicate if You modified the Licensed Material and
259 | retain an indication of any previous modifications; and
260 |
261 | c. indicate the Licensed Material is licensed under this
262 | Public License, and include the text of, or the URI or
263 | hyperlink to, this Public License.
264 |
265 | 2. You may satisfy the conditions in Section 3(a)(1) in any
266 | reasonable manner based on the medium, means, and context in
267 | which You Share the Licensed Material. For example, it may be
268 | reasonable to satisfy the conditions by providing a URI or
269 | hyperlink to a resource that includes the required
270 | information.
271 |
272 | 3. If requested by the Licensor, You must remove any of the
273 | information required by Section 3(a)(1)(A) to the extent
274 | reasonably practicable.
275 |
276 | b. ShareAlike.
277 |
278 | In addition to the conditions in Section 3(a), if You Share
279 | Adapted Material You produce, the following conditions also apply.
280 |
281 | 1. The Adapter's License You apply must be a Creative Commons
282 | license with the same License Elements, this version or
283 | later, or a BY-SA Compatible License.
284 |
285 | 2. You must include the text of, or the URI or hyperlink to, the
286 | Adapter's License You apply. You may satisfy this condition
287 | in any reasonable manner based on the medium, means, and
288 | context in which You Share Adapted Material.
289 |
290 | 3. You may not offer or impose any additional or different terms
291 | or conditions on, or apply any Effective Technological
292 | Measures to, Adapted Material that restrict exercise of the
293 | rights granted under the Adapter's License You apply.
294 |
295 |
296 | Section 4 -- Sui Generis Database Rights.
297 |
298 | Where the Licensed Rights include Sui Generis Database Rights that
299 | apply to Your use of the Licensed Material:
300 |
301 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right
302 | to extract, reuse, reproduce, and Share all or a substantial
303 | portion of the contents of the database;
304 |
305 | b. if You include all or a substantial portion of the database
306 | contents in a database in which You have Sui Generis Database
307 | Rights, then the database in which You have Sui Generis Database
308 | Rights (but not its individual contents) is Adapted Material,
309 |
310 | including for purposes of Section 3(b); and
311 | c. You must comply with the conditions in Section 3(a) if You Share
312 | all or a substantial portion of the contents of the database.
313 |
314 | For the avoidance of doubt, this Section 4 supplements and does not
315 | replace Your obligations under this Public License where the Licensed
316 | Rights include other Copyright and Similar Rights.
317 |
318 |
319 | Section 5 -- Disclaimer of Warranties and Limitation of Liability.
320 |
321 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
322 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
323 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
324 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
325 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
326 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
327 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
328 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
329 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
330 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
331 |
332 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
333 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
334 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
335 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
336 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
337 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
338 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
339 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
340 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
341 |
342 | c. The disclaimer of warranties and limitation of liability provided
343 | above shall be interpreted in a manner that, to the extent
344 | possible, most closely approximates an absolute disclaimer and
345 | waiver of all liability.
346 |
347 |
348 | Section 6 -- Term and Termination.
349 |
350 | a. This Public License applies for the term of the Copyright and
351 | Similar Rights licensed here. However, if You fail to comply with
352 | this Public License, then Your rights under this Public License
353 | terminate automatically.
354 |
355 | b. Where Your right to use the Licensed Material has terminated under
356 | Section 6(a), it reinstates:
357 |
358 | 1. automatically as of the date the violation is cured, provided
359 | it is cured within 30 days of Your discovery of the
360 | violation; or
361 |
362 | 2. upon express reinstatement by the Licensor.
363 |
364 | For the avoidance of doubt, this Section 6(b) does not affect any
365 | right the Licensor may have to seek remedies for Your violations
366 | of this Public License.
367 |
368 | c. For the avoidance of doubt, the Licensor may also offer the
369 | Licensed Material under separate terms or conditions or stop
370 | distributing the Licensed Material at any time; however, doing so
371 | will not terminate this Public License.
372 |
373 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
374 | License.
375 |
376 |
377 | Section 7 -- Other Terms and Conditions.
378 |
379 | a. The Licensor shall not be bound by any additional or different
380 | terms or conditions communicated by You unless expressly agreed.
381 |
382 | b. Any arrangements, understandings, or agreements regarding the
383 | Licensed Material not stated herein are separate from and
384 | independent of the terms and conditions of this Public License.
385 |
386 |
387 | Section 8 -- Interpretation.
388 |
389 | a. For the avoidance of doubt, this Public License does not, and
390 | shall not be interpreted to, reduce, limit, restrict, or impose
391 | conditions on any use of the Licensed Material that could lawfully
392 | be made without permission under this Public License.
393 |
394 | b. To the extent possible, if any provision of this Public License is
395 | deemed unenforceable, it shall be automatically reformed to the
396 | minimum extent necessary to make it enforceable. If the provision
397 | cannot be reformed, it shall be severed from this Public License
398 | without affecting the enforceability of the remaining terms and
399 | conditions.
400 |
401 | c. No term or condition of this Public License will be waived and no
402 | failure to comply consented to unless expressly agreed to by the
403 | Licensor.
404 |
405 | d. Nothing in this Public License constitutes or may be interpreted
406 | as a limitation upon, or waiver of, any privileges and immunities
407 | that apply to the Licensor or You, including from the legal
408 | processes of any jurisdiction or authority.
409 |
410 |
411 | =======================================================================
412 |
413 | Creative Commons is not a party to its public licenses.
414 | Notwithstanding, Creative Commons may elect to apply one of its public
415 | licenses to material it publishes and in those instances will be
416 | considered the "Licensor." Except for the limited purpose of indicating
417 | that material is shared under a Creative Commons public license or as
418 | otherwise permitted by the Creative Commons policies published at
419 | creativecommons.org/policies, Creative Commons does not authorize the
420 | use of the trademark "Creative Commons" or any other trademark or logo
421 | of Creative Commons without its prior written consent including,
422 | without limitation, in connection with any unauthorized modifications
423 | to any of its public licenses or any other arrangements,
424 | understandings, or agreements concerning use of licensed material. For
425 | the avoidance of doubt, this paragraph does not form part of the public
426 | licenses.
427 |
428 | Creative Commons may be contacted at creativecommons.org.
429 |
--------------------------------------------------------------------------------
/public/js/helpers/backbone.stickit.js:
--------------------------------------------------------------------------------
1 | // Backbone.Stickit v0.9.2, MIT Licensed
2 | // Copyright (c) 2012-2015 The New York Times, CMS Group, Matthew DeLambo
3 |
4 | (function (factory) {
5 |
6 | // Set up Stickit appropriately for the environment. Start with AMD.
7 | if (typeof define === 'function' && define.amd)
8 | define(['underscore', 'backbone', 'exports'], factory);
9 |
10 | // Next for Node.js or CommonJS.
11 | else if (typeof exports === 'object')
12 | factory(require('underscore'), require('backbone'), exports);
13 |
14 | // Finally, as a browser global.
15 | else
16 | factory(_, Backbone, {});
17 |
18 | }(function (_, Backbone, Stickit) {
19 |
20 | // Stickit Namespace
21 | // --------------------------
22 |
23 | // Export onto Backbone object
24 | Backbone.Stickit = Stickit;
25 |
26 | Stickit._handlers = [];
27 |
28 | Stickit.addHandler = function(handlers) {
29 | // Fill-in default values.
30 | handlers = _.map(_.flatten([handlers]), function(handler) {
31 | return _.defaults({}, handler, {
32 | updateModel: true,
33 | updateView: true,
34 | updateMethod: 'text'
35 | });
36 | });
37 | this._handlers = this._handlers.concat(handlers);
38 | };
39 |
40 | // Backbone.View Mixins
41 | // --------------------
42 |
43 | Stickit.ViewMixin = {
44 |
45 | // Collection of model event bindings.
46 | // [{model,event,fn,config}, ...]
47 | _modelBindings: null,
48 |
49 | // Unbind the model and event bindings from `this._modelBindings` and
50 | // `this.$el`. If the optional `model` parameter is defined, then only
51 | // delete bindings for the given `model` and its corresponding view events.
52 | unstickit: function(model, bindingSelector) {
53 |
54 | // Support passing a bindings hash in place of bindingSelector.
55 | if (_.isObject(bindingSelector)) {
56 | _.each(bindingSelector, function(v, selector) {
57 | this.unstickit(model, selector);
58 | }, this);
59 | return;
60 | }
61 |
62 | var models = [], destroyFns = [];
63 | this._modelBindings = _.reject(this._modelBindings, function(binding) {
64 | if (model && binding.model !== model) return;
65 | if (bindingSelector && binding.config.selector != bindingSelector) return;
66 |
67 | binding.model.off(binding.event, binding.fn);
68 | destroyFns.push(binding.config._destroy);
69 | models.push(binding.model);
70 | return true;
71 | });
72 |
73 | // Trigger an event for each model that was unbound.
74 | _.invoke(_.uniq(models), 'trigger', 'stickit:unstuck', this.cid);
75 |
76 | // Call `_destroy` on a unique list of the binding callbacks.
77 | _.each(_.uniq(destroyFns), function(fn) { fn.call(this); }, this);
78 |
79 | this.$el.off('.stickit' + (model ? '.' + model.cid : ''), bindingSelector);
80 | },
81 |
82 | // Initilize Stickit bindings for the view. Subsequent binding additions
83 | // can either call `stickit` with the new bindings, or add them directly
84 | // with `addBinding`. Both arguments to `stickit` are optional.
85 | stickit: function(optionalModel, optionalBindingsConfig) {
86 | var model = optionalModel || this.model,
87 | bindings = optionalBindingsConfig || _.result(this, "bindings") || {};
88 |
89 | this._modelBindings || (this._modelBindings = []);
90 |
91 | // Add bindings in bulk using `addBinding`.
92 | this.addBinding(model, bindings);
93 |
94 | // Wrap `view.remove` to unbind stickit model and dom events.
95 | var remove = this.remove;
96 | if (!remove.stickitWrapped) {
97 | this.remove = function() {
98 | var ret = this;
99 | this.unstickit();
100 | if (remove) ret = remove.apply(this, arguments);
101 | return ret;
102 | };
103 | }
104 | this.remove.stickitWrapped = true;
105 | return this;
106 | },
107 |
108 | // Add a single Stickit binding or a hash of bindings to the model. If
109 | // `optionalModel` is ommitted, will default to the view's `model` property.
110 | addBinding: function(optionalModel, selector, binding) {
111 | var model = optionalModel || this.model,
112 | namespace = '.stickit.' + model.cid;
113 |
114 | binding = binding || {};
115 |
116 | // Support jQuery-style {key: val} event maps.
117 | if (_.isObject(selector)) {
118 | var bindings = selector;
119 | _.each(bindings, function(val, key) {
120 | this.addBinding(model, key, val);
121 | }, this);
122 | return;
123 | }
124 |
125 | // Special case the ':el' selector to use the view's this.$el.
126 | var $el = selector === ':el' ? this.$el : this.$(selector);
127 |
128 | // Clear any previous matching bindings.
129 | this.unstickit(model, selector);
130 |
131 | // Fail fast if the selector didn't match an element.
132 | if (!$el.length) return;
133 |
134 | // Allow shorthand setting of model attributes - `'selector':'observe'`.
135 | if (_.isString(binding)) binding = {observe: binding};
136 |
137 | // Handle case where `observe` is in the form of a function.
138 | if (_.isFunction(binding.observe)) binding.observe = binding.observe.call(this);
139 |
140 | // Find all matching Stickit handlers that could apply to this element
141 | // and store in a config object.
142 | var config = getConfiguration($el, binding);
143 |
144 | // The attribute we're observing in our config.
145 | var modelAttr = config.observe;
146 |
147 | // Store needed properties for later.
148 | config.selector = selector;
149 | config.view = this;
150 |
151 | // Create the model set options with a unique `bindId` so that we
152 | // can avoid double-binding in the `change:attribute` event handler.
153 | var bindId = config.bindId = _.uniqueId();
154 |
155 | // Add a reference to the view for handlers of stickitChange events
156 | var options = _.extend({stickitChange: config}, config.setOptions);
157 |
158 | // Add a `_destroy` callback to the configuration, in case `destroy`
159 | // is a named function and we need a unique function when unsticking.
160 | config._destroy = function() {
161 | applyViewFn.call(this, config.destroy, $el, model, config);
162 | };
163 |
164 | initializeAttributes($el, config, model, modelAttr);
165 | initializeVisible($el, config, model, modelAttr);
166 | initializeClasses($el, config, model, modelAttr);
167 |
168 | if (modelAttr) {
169 | // Setup one-way (input element -> model) bindings.
170 | _.each(config.events, function(type) {
171 | var eventName = type + namespace;
172 | var listener = function(event) {
173 | var val = applyViewFn.call(this, config.getVal, $el, event, config, slice.call(arguments, 1));
174 |
175 | // Don't update the model if false is returned from the `updateModel` configuration.
176 | var currentVal = evaluateBoolean(config.updateModel, val, event, config);
177 | if (currentVal) setAttr(model, modelAttr, val, options, config);
178 | };
179 | var sel = selector === ':el'? '' : selector;
180 | this.$el.on(eventName, sel, _.bind(listener, this));
181 | }, this);
182 |
183 | // Setup a `change:modelAttr` observer to keep the view element in sync.
184 | // `modelAttr` may be an array of attributes or a single string value.
185 | _.each(_.flatten([modelAttr]), function(attr) {
186 | observeModelEvent(model, 'change:' + attr, config, function(m, val, options) {
187 | var changeId = options && options.stickitChange && options.stickitChange.bindId;
188 | if (changeId !== bindId) {
189 | var currentVal = getAttr(model, modelAttr, config);
190 | updateViewBindEl($el, config, currentVal, model);
191 | }
192 | });
193 | });
194 |
195 | var currentVal = getAttr(model, modelAttr, config);
196 | updateViewBindEl($el, config, currentVal, model, true);
197 | }
198 |
199 | // After each binding is setup, call the `initialize` callback.
200 | applyViewFn.call(this, config.initialize, $el, model, config);
201 | }
202 | };
203 |
204 | _.extend(Backbone.View.prototype, Stickit.ViewMixin);
205 |
206 | // Helpers
207 | // -------
208 |
209 | var slice = [].slice;
210 |
211 | // Evaluates the given `path` (in object/dot-notation) relative to the given
212 | // `obj`. If the path is null/undefined, then the given `obj` is returned.
213 | var evaluatePath = function(obj, path) {
214 | var parts = (path || '').split('.');
215 | var result = _.reduce(parts, function(memo, i) { return memo[i]; }, obj);
216 | return result == null ? obj : result;
217 | };
218 |
219 | // If the given `fn` is a string, then view[fn] is called, otherwise it is
220 | // a function that should be executed.
221 | var applyViewFn = function(fn) {
222 | fn = _.isString(fn) ? evaluatePath(this, fn) : fn;
223 | if (fn) return (fn).apply(this, slice.call(arguments, 1));
224 | };
225 |
226 | // Given a function, string (view function reference), or a boolean
227 | // value, returns the truthy result. Any other types evaluate as false.
228 | // The first argument must be `reference` and the last must be `config`, but
229 | // middle arguments can be variadic.
230 | var evaluateBoolean = function(reference, val, config) {
231 | if (_.isBoolean(reference)) {
232 | return reference;
233 | } else if (_.isFunction(reference) || _.isString(reference)) {
234 | var view = _.last(arguments).view;
235 | return applyViewFn.apply(view, arguments);
236 | }
237 | return false;
238 | };
239 |
240 | // Setup a model event binding with the given function, and track the event
241 | // in the view's _modelBindings.
242 | var observeModelEvent = function(model, event, config, fn) {
243 | var view = config.view;
244 | model.on(event, fn, view);
245 | view._modelBindings.push({model:model, event:event, fn:fn, config:config});
246 | };
247 |
248 | // Prepares the given `val`ue and sets it into the `model`.
249 | var setAttr = function(model, attr, val, options, config) {
250 | var value = {}, view = config.view;
251 | if (config.onSet) {
252 | val = applyViewFn.call(view, config.onSet, val, config);
253 | }
254 |
255 | if (config.set) {
256 | applyViewFn.call(view, config.set, attr, val, options, config);
257 | } else {
258 | value[attr] = val;
259 | // If `observe` is defined as an array and `onSet` returned
260 | // an array, then map attributes to their values.
261 | if (_.isArray(attr) && _.isArray(val)) {
262 | value = _.reduce(attr, function(memo, attribute, index) {
263 | memo[attribute] = _.has(val, index) ? val[index] : null;
264 | return memo;
265 | }, {});
266 | }
267 | model.set(value, options);
268 | }
269 | };
270 |
271 | // Returns the given `attr`'s value from the `model`, escaping and
272 | // formatting if necessary. If `attr` is an array, then an array of
273 | // respective values will be returned.
274 | var getAttr = function(model, attr, config) {
275 | var view = config.view;
276 | var retrieveVal = function(field) {
277 | return model[config.escape ? 'escape' : 'get'](field);
278 | };
279 | var sanitizeVal = function(val) {
280 | return val == null ? '' : val;
281 | };
282 | var val = _.isArray(attr) ? _.map(attr, retrieveVal) : retrieveVal(attr);
283 | if (config.onGet) val = applyViewFn.call(view, config.onGet, val, config);
284 | return _.isArray(val) ? _.map(val, sanitizeVal) : sanitizeVal(val);
285 | };
286 |
287 | // Find handlers in `Backbone.Stickit._handlers` with selectors that match
288 | // `$el` and generate a configuration by mixing them in the order that they
289 | // were found with the given `binding`.
290 | var getConfiguration = Stickit.getConfiguration = function($el, binding) {
291 | var handlers = [{
292 | updateModel: false,
293 | updateMethod: 'text',
294 | update: function($el, val, m, opts) { if ($el[opts.updateMethod]) $el[opts.updateMethod](val); },
295 | getVal: function($el, e, opts) { return $el[opts.updateMethod](); }
296 | }];
297 | handlers = handlers.concat(_.filter(Stickit._handlers, function(handler) {
298 | return $el.is(handler.selector);
299 | }));
300 | handlers.push(binding);
301 |
302 | // Merge handlers into a single config object. Last props in wins.
303 | var config = _.extend.apply(_, handlers);
304 |
305 | // `updateView` is defaulted to false for configutrations with
306 | // `visible`; otherwise, `updateView` is defaulted to true.
307 | if (!_.has(config, 'updateView')) config.updateView = !config.visible;
308 | return config;
309 | };
310 |
311 | // Setup the attributes configuration - a list that maps an attribute or
312 | // property `name`, to an `observe`d model attribute, using an optional
313 | // `onGet` formatter.
314 | //
315 | // attributes: [{
316 | // name: 'attributeOrPropertyName',
317 | // observe: 'modelAttrName'
318 | // onGet: function(modelAttrVal, modelAttrName) { ... }
319 | // }, ...]
320 | //
321 | var initializeAttributes = function($el, config, model, modelAttr) {
322 | var props = ['autofocus', 'autoplay', 'async', 'checked', 'controls',
323 | 'defer', 'disabled', 'hidden', 'indeterminate', 'loop', 'multiple',
324 | 'open', 'readonly', 'required', 'scoped', 'selected'];
325 |
326 | var view = config.view;
327 |
328 | _.each(config.attributes || [], function(attrConfig) {
329 | attrConfig = _.clone(attrConfig);
330 | attrConfig.view = view;
331 |
332 | var lastClass = '';
333 | var observed = attrConfig.observe || (attrConfig.observe = modelAttr);
334 | var updateAttr = function() {
335 | var updateType = _.contains(props, attrConfig.name) ? 'prop' : 'attr',
336 | val = getAttr(model, observed, attrConfig);
337 |
338 | // If it is a class then we need to remove the last value and add the new.
339 | if (attrConfig.name === 'class') {
340 | $el.removeClass(lastClass).addClass(val);
341 | lastClass = val;
342 | } else {
343 | $el[updateType](attrConfig.name, val);
344 | }
345 | };
346 |
347 | _.each(_.flatten([observed]), function(attr) {
348 | observeModelEvent(model, 'change:' + attr, config, updateAttr);
349 | });
350 |
351 | // Initialize the matched element's state.
352 | updateAttr();
353 | });
354 | };
355 |
356 | var initializeClasses = function($el, config, model, modelAttr) {
357 | _.each(config.classes || [], function(classConfig, name) {
358 | if (_.isString(classConfig)) classConfig = {observe: classConfig};
359 | classConfig.view = config.view;
360 |
361 | var observed = classConfig.observe;
362 | var updateClass = function() {
363 | var val = getAttr(model, observed, classConfig);
364 | $el.toggleClass(name, !!val);
365 | };
366 |
367 | _.each(_.flatten([observed]), function(attr) {
368 | observeModelEvent(model, 'change:' + attr, config, updateClass);
369 | });
370 | updateClass();
371 | });
372 | };
373 |
374 | // If `visible` is configured, then the view element will be shown/hidden
375 | // based on the truthiness of the modelattr's value or the result of the
376 | // given callback. If a `visibleFn` is also supplied, then that callback
377 | // will be executed to manually handle showing/hiding the view element.
378 | //
379 | // observe: 'isRight',
380 | // visible: true, // or function(val, options) {}
381 | // visibleFn: function($el, isVisible, options) {} // optional handler
382 | //
383 | var initializeVisible = function($el, config, model, modelAttr) {
384 | if (config.visible == null) return;
385 | var view = config.view;
386 |
387 | var visibleCb = function() {
388 | var visible = config.visible,
389 | visibleFn = config.visibleFn,
390 | val = getAttr(model, modelAttr, config),
391 | isVisible = !!val;
392 |
393 | // If `visible` is a function then it should return a boolean result to show/hide.
394 | if (_.isFunction(visible) || _.isString(visible)) {
395 | isVisible = !!applyViewFn.call(view, visible, val, config);
396 | }
397 |
398 | // Either use the custom `visibleFn`, if provided, or execute the standard show/hide.
399 | if (visibleFn) {
400 | applyViewFn.call(view, visibleFn, $el, isVisible, config);
401 | } else {
402 | $el.toggle(isVisible);
403 | }
404 | };
405 |
406 | _.each(_.flatten([modelAttr]), function(attr) {
407 | observeModelEvent(model, 'change:' + attr, config, visibleCb);
408 | });
409 |
410 | visibleCb();
411 | };
412 |
413 | // Update the value of `$el` using the given configuration and trigger the
414 | // `afterUpdate` callback. This action may be blocked by `config.updateView`.
415 | //
416 | // update: function($el, val, model, options) {}, // handler for updating
417 | // updateView: true, // defaults to true
418 | // afterUpdate: function($el, val, options) {} // optional callback
419 | //
420 | var updateViewBindEl = function($el, config, val, model, isInitializing) {
421 | var view = config.view;
422 | if (!evaluateBoolean(config.updateView, val, config)) return;
423 | applyViewFn.call(view, config.update, $el, val, model, config);
424 | if (!isInitializing) applyViewFn.call(view, config.afterUpdate, $el, val, config);
425 | };
426 |
427 | // Default Handlers
428 | // ----------------
429 |
430 | Stickit.addHandler([{
431 | selector: '[contenteditable]',
432 | updateMethod: 'html',
433 | events: ['input', 'change']
434 | }, {
435 | selector: 'input',
436 | events: ['propertychange', 'input', 'change'],
437 | update: function($el, val) { $el.val(val); },
438 | getVal: function($el) {
439 | return $el.val();
440 | }
441 | }, {
442 | selector: 'textarea',
443 | events: ['propertychange', 'input', 'change'],
444 | update: function($el, val) { $el.val(val); },
445 | getVal: function($el) { return $el.val(); }
446 | }, {
447 | selector: 'input[type="radio"]',
448 | events: ['change'],
449 | update: function($el, val) {
450 | $el.filter('[value="'+val+'"]').prop('checked', true);
451 | },
452 | getVal: function($el) {
453 | return $el.filter(':checked').val();
454 | }
455 | }, {
456 | selector: 'input[type="checkbox"]',
457 | events: ['change'],
458 | update: function($el, val, model, options) {
459 | if ($el.length > 1) {
460 | // There are multiple checkboxes so we need to go through them and check
461 | // any that have value attributes that match what's in the array of `val`s.
462 | val || (val = []);
463 | $el.each(function(i, el) {
464 | var checkbox = Backbone.$(el);
465 | var checked = _.contains(val, checkbox.val());
466 | checkbox.prop('checked', checked);
467 | });
468 | } else {
469 | var checked = _.isBoolean(val) ? val : val === $el.val();
470 | $el.prop('checked', checked);
471 | }
472 | },
473 | getVal: function($el) {
474 | var val;
475 | if ($el.length > 1) {
476 | val = _.reduce($el, function(memo, el) {
477 | var checkbox = Backbone.$(el);
478 | if (checkbox.prop('checked')) memo.push(checkbox.val());
479 | return memo;
480 | }, []);
481 | } else {
482 | val = $el.prop('checked');
483 | // If the checkbox has a value attribute defined, then
484 | // use that value. Most browsers use "on" as a default.
485 | var boxval = $el.val();
486 | if (boxval !== 'on' && boxval != null) {
487 | val = val ? $el.val() : null;
488 | }
489 | }
490 | return val;
491 | }
492 | }, {
493 | selector: 'select',
494 | events: ['change'],
495 | update: function($el, val, model, options) {
496 | var optList,
497 | selectConfig = options.selectOptions,
498 | list = selectConfig && selectConfig.collection || undefined,
499 | isMultiple = $el.prop('multiple');
500 |
501 | // If there are no `selectOptions` then we assume that the `