');
102 | },
103 |
104 | log: function(str) {
105 | //this.updateTestResults(str);
106 | }
107 | };
108 |
109 | // export public
110 | jasmine.TitaniumNodeReporter = TitaniumNodeReporter;
111 | })();
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2009 Appcelerator, Inc.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | (or the full text of the license is below)
10 |
11 | Unless required by applicable law or agreed to in writing, software
12 | distributed under the License is distributed on an "AS IS" BASIS,
13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | See the License for the specific language governing permissions and
15 | limitations under the License.
16 |
17 |
18 |
19 | Apache License
20 | Version 2.0, January 2004
21 | http://www.apache.org/licenses/
22 |
23 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
24 |
25 | 1. Definitions.
26 |
27 | "License" shall mean the terms and conditions for use, reproduction,
28 | and distribution as defined by Sections 1 through 9 of this document.
29 |
30 | "Licensor" shall mean the copyright owner or entity authorized by
31 | the copyright owner that is granting the License.
32 |
33 | "Legal Entity" shall mean the union of the acting entity and all
34 | other entities that control, are controlled by, or are under common
35 | control with that entity. For the purposes of this definition,
36 | "control" means (i) the power, direct or indirect, to cause the
37 | direction or management of such entity, whether by contract or
38 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
39 | outstanding shares, or (iii) beneficial ownership of such entity.
40 |
41 | "You" (or "Your") shall mean an individual or Legal Entity
42 | exercising permissions granted by this License.
43 |
44 | "Source" form shall mean the preferred form for making modifications,
45 | including but not limited to software source code, documentation
46 | source, and configuration files.
47 |
48 | "Object" form shall mean any form resulting from mechanical
49 | transformation or translation of a Source form, including but
50 | not limited to compiled object code, generated documentation,
51 | and conversions to other media types.
52 |
53 | "Work" shall mean the work of authorship, whether in Source or
54 | Object form, made available under the License, as indicated by a
55 | copyright notice that is included in or attached to the work
56 | (an example is provided in the Appendix below).
57 |
58 | "Derivative Works" shall mean any work, whether in Source or Object
59 | form, that is based on (or derived from) the Work and for which the
60 | editorial revisions, annotations, elaborations, or other modifications
61 | represent, as a whole, an original work of authorship. For the purposes
62 | of this License, Derivative Works shall not include works that remain
63 | separable from, or merely link (or bind by name) to the interfaces of,
64 | the Work and Derivative Works thereof.
65 |
66 | "Contribution" shall mean any work of authorship, including
67 | the original version of the Work and any modifications or additions
68 | to that Work or Derivative Works thereof, that is intentionally
69 | submitted to Licensor for inclusion in the Work by the copyright owner
70 | or by an individual or Legal Entity authorized to submit on behalf of
71 | the copyright owner. For the purposes of this definition, "submitted"
72 | means any form of electronic, verbal, or written communication sent
73 | to the Licensor or its representatives, including but not limited to
74 | communication on electronic mailing lists, source code control systems,
75 | and issue tracking systems that are managed by, or on behalf of, the
76 | Licensor for the purpose of discussing and improving the Work, but
77 | excluding communication that is conspicuously marked or otherwise
78 | designated in writing by the copyright owner as "Not a Contribution."
79 |
80 | "Contributor" shall mean Licensor and any individual or Legal Entity
81 | on behalf of whom a Contribution has been received by Licensor and
82 | subsequently incorporated within the Work.
83 |
84 | 2. Grant of Copyright License. Subject to the terms and conditions of
85 | this License, each Contributor hereby grants to You a perpetual,
86 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
87 | copyright license to reproduce, prepare Derivative Works of,
88 | publicly display, publicly perform, sublicense, and distribute the
89 | Work and such Derivative Works in Source or Object form.
90 |
91 | 3. Grant of Patent License. Subject to the terms and conditions of
92 | this License, each Contributor hereby grants to You a perpetual,
93 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
94 | (except as stated in this section) patent license to make, have made,
95 | use, offer to sell, sell, import, and otherwise transfer the Work,
96 | where such license applies only to those patent claims licensable
97 | by such Contributor that are necessarily infringed by their
98 | Contribution(s) alone or by combination of their Contribution(s)
99 | with the Work to which such Contribution(s) was submitted. If You
100 | institute patent litigation against any entity (including a
101 | cross-claim or counterclaim in a lawsuit) alleging that the Work
102 | or a Contribution incorporated within the Work constitutes direct
103 | or contributory patent infringement, then any patent licenses
104 | granted to You under this License for that Work shall terminate
105 | as of the date such litigation is filed.
106 |
107 | 4. Redistribution. You may reproduce and distribute copies of the
108 | Work or Derivative Works thereof in any medium, with or without
109 | modifications, and in Source or Object form, provided that You
110 | meet the following conditions:
111 |
112 | (a) You must give any other recipients of the Work or
113 | Derivative Works a copy of this License; and
114 |
115 | (b) You must cause any modified files to carry prominent notices
116 | stating that You changed the files; and
117 |
118 | (c) You must retain, in the Source form of any Derivative Works
119 | that You distribute, all copyright, patent, trademark, and
120 | attribution notices from the Source form of the Work,
121 | excluding those notices that do not pertain to any part of
122 | the Derivative Works; and
123 |
124 | (d) If the Work includes a "NOTICE" text file as part of its
125 | distribution, then any Derivative Works that You distribute must
126 | include a readable copy of the attribution notices contained
127 | within such NOTICE file, excluding those notices that do not
128 | pertain to any part of the Derivative Works, in at least one
129 | of the following places: within a NOTICE text file distributed
130 | as part of the Derivative Works; within the Source form or
131 | documentation, if provided along with the Derivative Works; or,
132 | within a display generated by the Derivative Works, if and
133 | wherever such third-party notices normally appear. The contents
134 | of the NOTICE file are for informational purposes only and
135 | do not modify the License. You may add Your own attribution
136 | notices within Derivative Works that You distribute, alongside
137 | or as an addendum to the NOTICE text from the Work, provided
138 | that such additional attribution notices cannot be construed
139 | as modifying the License.
140 |
141 | You may add Your own copyright statement to Your modifications and
142 | may provide additional or different license terms and conditions
143 | for use, reproduction, or distribution of Your modifications, or
144 | for any such Derivative Works as a whole, provided Your use,
145 | reproduction, and distribution of the Work otherwise complies with
146 | the conditions stated in this License.
147 |
148 | 5. Submission of Contributions. Unless You explicitly state otherwise,
149 | any Contribution intentionally submitted for inclusion in the Work
150 | by You to the Licensor shall be under the terms and conditions of
151 | this License, without any additional terms or conditions.
152 | Notwithstanding the above, nothing herein shall supersede or modify
153 | the terms of any separate license agreement you may have executed
154 | with Licensor regarding such Contributions.
155 |
156 | 6. Trademarks. This License does not grant permission to use the trade
157 | names, trademarks, service marks, or product names of the Licensor,
158 | except as required for reasonable and customary use in describing the
159 | origin of the Work and reproducing the content of the NOTICE file.
160 |
161 | 7. Disclaimer of Warranty. Unless required by applicable law or
162 | agreed to in writing, Licensor provides the Work (and each
163 | Contributor provides its Contributions) on an "AS IS" BASIS,
164 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
165 | implied, including, without limitation, any warranties or conditions
166 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
167 | PARTICULAR PURPOSE. You are solely responsible for determining the
168 | appropriateness of using or redistributing the Work and assume any
169 | risks associated with Your exercise of permissions under this License.
170 |
171 | 8. Limitation of Liability. In no event and under no legal theory,
172 | whether in tort (including negligence), contract, or otherwise,
173 | unless required by applicable law (such as deliberate and grossly
174 | negligent acts) or agreed to in writing, shall any Contributor be
175 | liable to You for damages, including any direct, indirect, special,
176 | incidental, or consequential damages of any character arising as a
177 | result of this License or out of the use or inability to use the
178 | Work (including but not limited to damages for loss of goodwill,
179 | work stoppage, computer failure or malfunction, or any and all
180 | other commercial damages or losses), even if such Contributor
181 | has been advised of the possibility of such damages.
182 |
183 | 9. Accepting Warranty or Additional Liability. While redistributing
184 | the Work or Derivative Works thereof, You may choose to offer,
185 | and charge a fee for, acceptance of support, warranty, indemnity,
186 | or other liability obligations and/or rights consistent with this
187 | License. However, in accepting such obligations, You may act only
188 | on Your own behalf and on Your sole responsibility, not on behalf
189 | of any other Contributor, and only if You agree to indemnify,
190 | defend, and hold each Contributor harmless for any liability
191 | incurred by, or claims asserted against, such Contributor by reason
192 | of your accepting any such warranty or additional liability.
193 |
194 | END OF TERMS AND CONDITIONS
195 |
196 | APPENDIX: How to apply the Apache License to your work.
197 |
198 | To apply the Apache License to your work, attach the following
199 | boilerplate notice, with the fields enclosed by brackets "[]"
200 | replaced with your own identifying information. (Don't include
201 | the brackets!) The text should be enclosed in the appropriate
202 | comment syntax for the file format. We also recommend that a
203 | file or class name and description of purpose be included on the
204 | same "printed page" as the copyright notice for easier
205 | identification within third-party archives.
206 |
207 | Copyright [yyyy] [name of copyright owner]
208 |
209 | Licensed under the Apache License, Version 2.0 (the "License");
210 | you may not use this file except in compliance with the License.
211 | You may obtain a copy of the License at
212 |
213 | http://www.apache.org/licenses/LICENSE-2.0
214 |
215 | Unless required by applicable law or agreed to in writing, software
216 | distributed under the License is distributed on an "AS IS" BASIS,
217 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
218 | See the License for the specific language governing permissions and
219 | limitations under the License.
--------------------------------------------------------------------------------
/Resources/test-backup/jquery-core.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 | // To learn how to write Jasmine tests, please read Jasmine documentation:
4 | // https://github.com/pivotal/jasmine/wiki
5 |
6 | // ok
7 | //^\s*ok\(\s*([^,]+),\s*["]([^"]+)["]\s*\);
8 | //it("\2", function(){ expect(\1).toBeDefined(); });
9 |
10 | // equals
11 | //^\s*equals\(\s*([^,]+),\s*([^,]+),\s*["]([^"]+)["]\s*\);
12 | //it("\3", function(){ expect(\1).toEqual(\2); });
13 |
14 | // same
15 | //^\s*same\(\s*([^,]+),\s*([^,]+),\s*["]([^"]+)["]\s*\);
16 | //it("\3", function(){ expect(\1).toBeSameTiElementsAs(\2); });
17 |
18 | beforeEach(function(){
19 | //Ti.API.log('winchildren', win.children);
20 |
21 | this.addMatchers({
22 | toBeSameTiElementsAs: function(els) {
23 |
24 | function getUUID(el){
25 | return el._uuid;
26 | }
27 |
28 | var thisStr = (Array.isArray(this.actual) ? this.actual : [this.actual]).map(getUUID).join(', '),
29 | compStr = (Array.isArray(els) ? els : [els]).map(getUUID).join(', ');
30 |
31 | return thisStr === compStr;
32 | }
33 | });
34 |
35 | var els = [];
36 | Object.keys(K.elsByName).forEach(function(key){
37 | els.concat(K.elsByName[key]||[]);
38 | });
39 | els.forEach(function(el){
40 | el.getParent().remove(el);
41 | });
42 |
43 | /*(win.children||[]).forEach(function(child){
44 | win.remove(child);
45 | });*/
46 |
47 | K.reset();
48 | });
49 |
50 | describe('jQuery-Core', function() {
51 |
52 | describe('Basic requirements', function(){
53 | it('Array.push()', function(){ expect(Array.prototype.push).toBeDefined(); });
54 | it('Function.apply()', function(){ expect(Function.prototype.apply).toBeDefined(); });
55 | it('getElementById', function(){ expect(getElementById).toBeDefined(); });
56 | it('getElementsByTagName', function(){ expect(getElementsByTagName).toBeDefined(); });
57 | it('RegExp', function(){ expect(RegExp).toBeDefined(); });
58 | it('K', function(){ expect(K).toBeDefined(); });
59 | });
60 |
61 | describe('K()', function(){
62 | it("K() === K([])", function(){ expect(K().length).toEqual(0); });
63 | it("K(undefined) === K([])", function(){ expect(K(undefined).length).toEqual(0); });
64 | it("K(null) === K([])", function(){ expect(K(null).length).toEqual(0); });
65 | it("K('') === K([])", function(){ expect(K("").length).toEqual(0); });
66 | it("K('#') === K([])", function(){ expect(K("#").length).toEqual(0); });
67 | });
68 |
69 | describe('element connectors', function(){
70 | it("Free KElement hasn't parentNode", function(){ expect(K({ type: 'label' }).get(0).getParent()).toBeNull(); });
71 | it("Added KElement has parentNode", function(){ expect(K({ type: 'label' }).appendTo(win).get(0).getParent()._uuid).not.toBeUndefined(); });
72 | it("Added KElement has correct parentNode", function(){ expect(K({ type: 'label' }).appendTo(win).get(0).getParent()._uuid).toEqual(win._uuid); });
73 |
74 | });
75 |
76 | var labelBlueprints = [];
77 | for(var i = 0; i < 6; i++){ labelBlueprints.push({ width: 50, height: 50, top: i*10, left: 10*i, opacity: 0.3, backgroundColor: '#f00', type: 'label', text: i, className: 'lengthTest', id: 'label' + i }); }
78 |
79 | describe("length", function () {
80 | it("Get Number of Elements Found", function () {
81 | K(labelBlueprints).appendTo(win);
82 | expect(K(".lengthTest", win).length).toEqual(6);
83 | });
84 | });
85 |
86 | describe("size()", function () {
87 | it("Get Number of Elements Found", function () {
88 | K(labelBlueprints).appendTo(win);
89 | expect(K(".lengthTest", win).size()).toEqual(6);
90 | });
91 | });
92 |
93 | var getElBlueprints = [
94 | { type: 'view', id: 'getView', className: 'getEl', backgroundColor: '#0f0' },
95 | { type: 'label', id: 'getLabel', text: 'get()', className: 'getEl' },
96 | { type: 'imageview', id: 'getImageView', className: 'getEl', image: 'http://krawaller.se/logo_mini.png' }
97 | ];
98 |
99 | describe("get()", function () {
100 | it("Get All Elements", function(){
101 | var els = K(getElBlueprints).appendTo(win);
102 | expect(els.get()).toBeSameTiElementsAs(K.elsByClassName.getEl);
103 | });
104 | });
105 |
106 | describe("toArray()", function () {
107 | it("Convert K object to an Array", function(){
108 | var els = K(getElBlueprints).appendTo(win);
109 | expect(els.toArray()).toBeSameTiElementsAs(K.elsByClassName.getEl);
110 | });
111 | });
112 |
113 | describe("get(Number)", function () {
114 | it("Get A Single Element", function () {
115 | K(labelBlueprints).appendTo(win);
116 | expect(K("label").get(0)).toBeSameTiElementsAs(getElementById("label0"));
117 | });
118 |
119 | it("Try get with index larger elements count", function(){
120 | expect(K('#label0').get(1)).toBeUndefined();
121 | });
122 | });
123 |
124 | describe("get(-Number)", function () {
125 | it("Get a single element with negative index", function () {
126 | K(labelBlueprints).appendTo(win);
127 | var id = labelBlueprints[labelBlueprints.length - 1].id,
128 | el = getElementById(id);
129 |
130 | expect(K("label").get(-1)).toBeSameTiElementsAs(el);
131 | });
132 |
133 | it("Try get with index negative index larger then elements count", function(){
134 | expect(K('#label0').get(-2)).toBeUndefined();
135 | });
136 | });
137 |
138 | describe("each(Function)", function () {
139 | it('Execute a function, Relative', function () {
140 | K(labelBlueprints).appendTo(win);
141 |
142 | var div = K("label");
143 | div.each(function () {
144 | this.foo = 'zoo';
145 | });
146 | var pass = true;
147 | for (var i = 0; i < div.size(); i++) {
148 | if (div.get(i).foo != "zoo") pass = false;
149 | }
150 | expect(pass).toBeTruthy();
151 | });
152 | });
153 |
154 | describe("slice()", function () {
155 | var $labels;
156 | beforeEach(function(){
157 | $labels = K(labelBlueprints).appendTo(win);
158 | });
159 |
160 | it("slice(1,2)", function(){
161 | expect($labels.slice(1,2).get()).toBeSameTiElementsAs(q('label1'));
162 | });
163 | it("slice(1)", function(){
164 | expect($labels.slice(1).get()).toBeSameTiElementsAs(q('label1, label2, label3, label4, label5'));
165 | });
166 | it("slice(0,3)", function(){
167 | expect($labels.slice(0,3).get()).toBeSameTiElementsAs(q('label0, label1, label2'));
168 | });
169 |
170 | it("slice(-1)", function () {
171 | var id = labelBlueprints[labelBlueprints.length - 1].id,
172 | el = q(id);
173 |
174 | expect($labels.slice(-1).get()).toBeSameTiElementsAs(el);
175 | });
176 | it("eq(1)", function () {
177 | expect($labels.eq(1).get()).toBeSameTiElementsAs(q(labelBlueprints[1].id));
178 | });
179 | it("eq('2')", function () {
180 | expect($labels.eq('2').get()).toBeSameTiElementsAs(q(labelBlueprints[2].id));
181 | });
182 | it("eq(-1)", function () {
183 | expect($labels.eq(-1).get()).toBeSameTiElementsAs(q(labelBlueprints[labelBlueprints.length - 1].id));
184 | });
185 | });
186 |
187 | describe("first()/last()", function () {
188 | var $labels,
189 | $none;
190 | beforeEach(function(){
191 | $labels = K(labelBlueprints).appendTo(win);
192 | $none = K('none');
193 | });
194 |
195 | it("first()", function () {
196 | expect($labels.first().get()).toBeSameTiElementsAs(q("label0"));
197 | });
198 | it("last()", function () {
199 | expect($labels.last().get()).toBeSameTiElementsAs(q("label5"));
200 | });
201 | it("first() none", function () {
202 | expect($none.first().get()).toBeSameTiElementsAs([]);
203 | });
204 | it("last() none", function () {
205 | expect($none.last().get()).toBeSameTiElementsAs([]);
206 | });
207 | });
208 |
209 | /*describe("map()", function () {
210 |
211 | same(
212 | K("#ap").map(function () {
213 | return K(this).find("a").get();
214 | }).get(), q("google", "groups", "anchor1", "mark"), "Array Map");
215 |
216 | same(
217 | K("#ap > a").map(function () {
218 | return this.parentNode;
219 | }).get(), q("ap", "ap", "ap"), "Single Map");
220 |
221 | //for #2616
222 | var keys = K.map({
223 | a: 1,
224 | b: 2
225 | }, function (v, k) {
226 | return k;
227 | });
228 | it("Map the keys from a hash to an array", function () {
229 | expect(keys.join("")).toEqual("ab");
230 | });
231 |
232 | var values = K.map({
233 | a: 1,
234 | b: 2
235 | }, function (v, k) {
236 | return v;
237 | });
238 | it("Map the values from a hash to an array", function () {
239 | expect(values.join("")).toEqual("12");
240 | });
241 |
242 | // object with length prop
243 | var values = K.map({
244 | a: 1,
245 | b: 2,
246 | length: 3
247 | }, function (v, k) {
248 | return v;
249 | });
250 | it("Map the values from a hash with a length property to an array", function () {
251 | expect(values.join("")).toEqual("123");
252 | });
253 |
254 | var scripts = document.getElementsByTagName("script");
255 | var mapped = K.map(scripts, function (v, k) {
256 | return v;
257 | });
258 | it("Map an array(-like) to a hash", function () {
259 | expect(mapped.length).toEqual(scripts.length);
260 | });
261 |
262 | var flat = K.map(Array(4), function (v, k) {
263 | return k % 2 ? k : [k, k, k]; //try mixing array and regular returns
264 | });
265 | it("try the new flatten technique(#2616)", function () {
266 | expect(flat.join("")).toEqual("00012223");
267 | });
268 | });*/
269 |
270 |
271 |
272 | /*describe("K.merge()", function () {
273 |
274 | var parse = K.merge;
275 |
276 | same(parse([], []), [], "Empty arrays");
277 |
278 | same(parse([1], [2]), [1, 2], "Basic");
279 | same(parse([1, 2], [3, 4]), [1, 2, 3, 4], "Basic");
280 |
281 | same(parse([1, 2], []), [1, 2], "Second empty");
282 | same(parse([], [1, 2]), [1, 2], "First empty");
283 |
284 | // Fixed at [5998], #3641
285 | same(parse([-2, -1], [0, 1, 2]), [-2, -1, 0, 1, 2], "Second array including a zero (falsy)");
286 |
287 | // After fixing #5527
288 | same(parse([], [null, undefined]), [null, undefined], "Second array including null and undefined values");
289 | same(parse({
290 | length: 0
291 | }, [1, 2]), {
292 | length: 2,
293 | 0: 1,
294 | 1: 2
295 | }, "First array like");
296 | });
297 |
298 | describe("K.extend(Object, Object)", function () {
299 |
300 | var settings = {
301 | xnumber1: 5,
302 | xnumber2: 7,
303 | xstring1: "peter",
304 | xstring2: "pan"
305 | },
306 | options = {
307 | xnumber2: 1,
308 | xstring2: "x",
309 | xxx: "newstring"
310 | },
311 | optionsCopy = {
312 | xnumber2: 1,
313 | xstring2: "x",
314 | xxx: "newstring"
315 | },
316 | merged = {
317 | xnumber1: 5,
318 | xnumber2: 1,
319 | xstring1: "peter",
320 | xstring2: "x",
321 | xxx: "newstring"
322 | },
323 | deep1 = {
324 | foo: {
325 | bar: true
326 | }
327 | },
328 | deep1copy = {
329 | foo: {
330 | bar: true
331 | }
332 | },
333 | deep2 = {
334 | foo: {
335 | baz: true
336 | },
337 | foo2: document
338 | },
339 | deep2copy = {
340 | foo: {
341 | baz: true
342 | },
343 | foo2: document
344 | },
345 | deepmerged = {
346 | foo: {
347 | bar: true,
348 | baz: true
349 | },
350 | foo2: document
351 | },
352 | arr = [1, 2, 3],
353 | nestedarray = {
354 | arr: arr
355 | };
356 |
357 | K.extend(settings, options);
358 | it("Check if extended: settings must be extended", function () {
359 | expect(settings).toBe(merged);
360 | });
361 | it("Check if not modified: options must not be modified", function () {
362 | expect(options).toBe(optionsCopy);
363 | });
364 |
365 | K.extend(settings, null, options);
366 | it("Check if extended: settings must be extended", function () {
367 | expect(settings).toBe(merged);
368 | });
369 | it("Check if not modified: options must not be modified", function () {
370 | expect(options).toBe(optionsCopy);
371 | });
372 |
373 | K.extend(true, deep1, deep2);
374 | it("Check if foo: settings must be extended", function () {
375 | expect(deep1.foo).toBe(deepmerged.foo);
376 | });
377 | it("Check if not deep2: options must not be modified", function () {
378 | expect(deep2.foo).toBe(deep2copy.foo);
379 | });
380 | it("Make sure that a deep clone was not attempted on the document", function () {
381 | expect(deep1.foo2).toEqual(document);
382 | });
383 |
384 | ok(K.extend(true, {}, nestedarray).arr !== arr, "Deep extend of object must clone child array");
385 |
386 | // #5991
387 | ok(K.isArray(K.extend(true, {
388 | arr: {}
389 | }, nestedarray).arr), "Cloned array heve to be an Array");
390 | ok(K.isPlainObject(K.extend(true, {
391 | arr: arr
392 | }, {
393 | arr: {}
394 | }).arr), "Cloned object heve to be an plain object");
395 |
396 | var empty = {};
397 | var optionsWithLength = {
398 | foo: {
399 | length: -1
400 | }
401 | };
402 | K.extend(true, empty, optionsWithLength);
403 | it("The length property must copy correctly", function () {
404 | expect(empty.foo).toBe(optionsWithLength.foo);
405 | });
406 |
407 | empty = {};
408 | var optionsWithDate = {
409 | foo: {
410 | date: new Date
411 | }
412 | };
413 | K.extend(true, empty, optionsWithDate);
414 | it("Dates copy correctly", function () {
415 | expect(empty.foo).toBe(optionsWithDate.foo);
416 | });
417 |
418 | var myKlass = function () {};
419 | var customObject = new myKlass();
420 | var optionsWithCustomObject = {
421 | foo: {
422 | date: customObject
423 | }
424 | };
425 | empty = {};
426 | K.extend(true, empty, optionsWithCustomObject);
427 | it("Custom objects copy correctly (no methods)", function () {
428 | expect(empty.foo && empty.foo.date === customObject).toBeDefined();
429 | });
430 |
431 | // Makes the class a little more realistic
432 | myKlass.prototype = {
433 | someMethod: function () {}
434 | };
435 | empty = {};
436 | K.extend(true, empty, optionsWithCustomObject);
437 | it("Custom objects copy correctly", function () {
438 | expect(empty.foo && empty.foo.date === customObject).toBeDefined();
439 | });
440 |
441 | var ret = K.extend(true, {
442 | foo: 4
443 | }, {
444 | foo: new Number(5)
445 | });
446 | it("Wrapped numbers copy correctly", function () {
447 | expect(ret.foo == 5).toBeDefined();
448 | });
449 |
450 | var nullUndef;
451 | nullUndef = K.extend({}, options, {
452 | xnumber2: null
453 | });
454 | it("Check to make sure null values are copied", function () {
455 | expect(nullUndef.xnumber2 === null).toBeDefined();
456 | });
457 |
458 | nullUndef = K.extend({}, options, {
459 | xnumber2: undefined
460 | });
461 | it("Check to make sure undefined values are not copied", function () {
462 | expect(nullUndef.xnumber2 === options.xnumber2).toBeDefined();
463 | });
464 |
465 | nullUndef = K.extend({}, options, {
466 | xnumber0: null
467 | });
468 | it("Check to make sure null values are inserted", function () {
469 | expect(nullUndef.xnumber0 === null).toBeDefined();
470 | });
471 |
472 | var target = {};
473 | var recursive = {
474 | foo: target,
475 | bar: 5
476 | };
477 | K.extend(true, target, recursive);
478 | it("Check to make sure a recursive obj doesn't go never-ending loop by not copying it over", function () {
479 | expect(target).toBe({
480 | bar: 5
481 | });
482 | });
483 |
484 | var ret = K.extend(true, {
485 | foo: []
486 | }, {
487 | foo: [0]
488 | }); // 1907
489 | it("Check to make sure a value with coersion 'false' copies over when necessary to fix #1907", function () {
490 | expect(ret.foo.length).toEqual(1);
491 | });
492 |
493 | var ret = K.extend(true, {
494 | foo: "1,2,3"
495 | }, {
496 | foo: [1, 2, 3]
497 | });
498 | it("Check to make sure values equal with coersion (but not actually equal) overwrite correctly", function () {
499 | expect(typeof ret.foo != "string").toBeDefined();
500 | });
501 |
502 | var ret = K.extend(true, {
503 | foo: "bar"
504 | }, {
505 | foo: null
506 | });
507 | it("Make sure a null value doesn't crash with deep extend, for #1908", function () {
508 | expect(typeof ret.foo !== 'undefined').toBeDefined();
509 | });
510 |
511 | var obj = {
512 | foo: null
513 | };
514 | K.extend(true, obj, {
515 | foo: "notnull"
516 | });
517 | it("Make sure a null value can be overwritten", function () {
518 | expect(obj.foo).toEqual("notnull");
519 | });
520 |
521 | function func() {}
522 | K.extend(func, {
523 | key: "value"
524 | });
525 | it("Verify a function can be extended", function () {
526 | expect(func.key).toEqual("value");
527 | });
528 |
529 | var defaults = {
530 | xnumber1: 5,
531 | xnumber2: 7,
532 | xstring1: "peter",
533 | xstring2: "pan"
534 | },
535 | defaultsCopy = {
536 | xnumber1: 5,
537 | xnumber2: 7,
538 | xstring1: "peter",
539 | xstring2: "pan"
540 | },
541 | options1 = {
542 | xnumber2: 1,
543 | xstring2: "x"
544 | },
545 | options1Copy = {
546 | xnumber2: 1,
547 | xstring2: "x"
548 | },
549 | options2 = {
550 | xstring2: "xx",
551 | xxx: "newstringx"
552 | },
553 | options2Copy = {
554 | xstring2: "xx",
555 | xxx: "newstringx"
556 | },
557 | merged2 = {
558 | xnumber1: 5,
559 | xnumber2: 1,
560 | xstring1: "peter",
561 | xstring2: "xx",
562 | xxx: "newstringx"
563 | };
564 |
565 | var settings = K.extend({}, defaults, options1, options2);
566 | it("Check if extended: settings must be extended", function () {
567 | expect(settings).toBe(merged2);
568 | });
569 | it("Check if not modified: options1 must not be modified", function () {
570 | expect(defaults).toBe(defaultsCopy);
571 | });
572 | it("Check if not modified: options1 must not be modified", function () {
573 | expect(options1).toBe(options1Copy);
574 | });
575 | it("Check if not modified: options2 must not be modified", function () {
576 | expect(options2).toBe(options2Copy);
577 | });
578 | });
579 |
580 | describe("K.proxy", function () {
581 |
582 | var test = function () {
583 | equals(this, thisObject, "Make sure that scope is set properly.");
584 | };
585 | var thisObject = {
586 | foo: "bar",
587 | method: test
588 | };
589 |
590 | // Make sure normal works
591 | test.call(thisObject);
592 |
593 | // Basic scoping
594 | K.proxy(test, thisObject)();
595 |
596 | // Make sure it doesn't freak out
597 | equals(K.proxy(null, thisObject), undefined, "Make sure no function was returned.");
598 |
599 | // Partial application
600 | var test2 = function (a) {
601 | equals(a, "pre-applied", "Ensure arguments can be pre-applied.");
602 | };
603 | K.proxy(test2, null, "pre-applied")();
604 |
605 | // Partial application w/ normal arguments
606 | var test3 = function (a, b) {
607 | equals(b, "normal", "Ensure arguments can be pre-applied and passed as usual.");
608 | };
609 | K.proxy(test3, null, "pre-applied")("normal");
610 |
611 | // Test old syntax
612 | var test4 = {
613 | meth: function (a) {
614 | equals(a, "boom", "Ensure old syntax works.");
615 | }
616 | };
617 | K.proxy(test4, "meth")("boom");
618 | });
619 |
620 |
621 | it('get predefined label text', function() {
622 | expect(K({ type: 'label', text: 'labelText' }).text()).toBe('labelText');
623 | });
624 |
625 | it('set label text', function() {
626 | expect(K({ type: 'label' }).text('setLabelText').text()).toBe('setLabelText');
627 | });*/
628 |
629 | });
630 |
631 | })();
--------------------------------------------------------------------------------
/Resources/jade.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 | // CommonJS require()
4 | function require(p){var path=require.resolve(p),mod=require.modules[path];if(!mod)throw new Error('failed to require "'+p+'"');mod.exports||(mod.exports={},mod.call(mod.exports,mod,mod.exports,require.relative(path)));return mod.exports}require.modules={},require.resolve=function(path){var orig=path,reg=path+".js",index=path+"/index.js";return require.modules[reg]&®||require.modules[index]&&index||orig},require.register=function(path,fn){require.modules[path]=fn},require.relative=function(parent){return function(p){if("."!=p[0])return require(p);var path=parent.split("/"),segs=p.split("/");path.pop();for(var i=0;i"))},visitBlockComment:function(comment){!comment.buffer||(0==comment.val.indexOf("if")?(this.buffer("")):(this.buffer("")))},visitCode:function(code,obj,tagName){valueAttrByTagName={label:"text",textfield:"value",button:"title",def:"text"},tagName?this.buf.push(", "+(valueAttrByTagName[tagName]||valueAttrByTagName.def)+": ("+code.val.trim()+")"):this.buf.push(code.val),code.block&&(code.buffer||this.buf.push("{"),this.visit(code.block,obj),code.buffer||this.buf.push("}"))},visitEach:function(each,obj){this.buf.push("each("+each.obj+", function("+each.val+", "+each.key+"){ "),this.visit(each.block,!0),this.buf.push(" });")},visitAttributes:function(attrs,obj){var classes=[],buf=[];attrs.forEach(function(attr){attr.name=="class"?classes.push(attr.val):buf.push(attr.name+": "+attr.val)}),classes.length&&(classes=classes.join(" + ' ' + "),buf.push("className: "+classes)),this.buf.push(", "+buf.join(", "))}};function escape(html){return String(html).replace(/&(?!\w+;)/g,"&").replace(//g,">").replace(/"/g,""")}}),require.register("doctypes.js",function(module,exports,require){}),require.register("filters.js",function(module,exports,require){}),require.register("inline-tags.js",function(module,exports,require){}),require.register("jade.js",function(module,exports,require){var Parser=require("./parser"),Compiler=require("./compiler");exports.version="0.13.0";var cache=exports.cache={};exports.filters=require("./filters"),exports.utils=require("./utils"),exports.Compiler=Compiler,exports.Parser=Parser;function rethrow(err,str,filename,lineno){var context=3,lines=str.split("\n"),start=Math.max(lineno-context,0),end=Math.min(lines.length,lineno+context),context=lines.slice(start,end).map(function(line,i){var curr=i+start+1;return(curr==lineno?" > ":" ")+curr+"| "+line}).join("\n");err.path=filename,err.message=(filename||"Jade")+":"+lineno+"\n"+context+"\n\n"+err.message;throw err}function parse(str,options){var filename=options.filename;try{var parser=new Parser(str,filename);options.debug&&parser.debug();var compiler=new(options.compiler||Compiler)(parser.parse(),options),js=compiler.compile();options.debug&&console.log("\n[1mCompiled Function[0m:\n\n%s",js.replace(/^/gm," "));try{return"var __els = [];\n"+(options.self?"var self = locals || {}, __ = __ || locals.__;\n"+js:"with (locals || {}) {"+js+"}")+"return __els;"}catch(err){process.compile(js,filename||"Jade");return}}catch(err){rethrow(err,str,filename,parser.lexer.lineno)}}exports.compile=function(str,options){var options=options||{},input=JSON.stringify(str),filename=options.filename?JSON.stringify(options.filename):"undefined",fn=["var __ = { lineno: 1, input: "+input+", filename: "+filename+" };",rethrow.toString(),"try {",parse(String(str),options||{}),"} catch (err) {"," rethrow(err, __.input, __.filename, __.lineno);","}"].join("\n");return new Function("locals",fn)}}),require.register("lexer.js",function(module,exports,require){var Lexer=module.exports=function Lexer(str){this.input=str.replace(/\r\n|\r/g,"\n"),this.deferredTokens=[],this.lastIndents=0,this.lineno=1,this.stash=[],this.indentStack=[],this.indentRe=null,this.pipeless=!1};Lexer.prototype={tok:function(type,val){return{type:type,line:this.lineno,val:val}},consume:function(len){this.input=this.input.substr(len)},scan:function(regexp,type){var captures;if(captures=regexp.exec(this.input)){this.consume(captures[0].length);return this.tok(type,captures[1])}},defer:function(tok){this.deferredTokens.push(tok)},lookahead:function(n){var fetch=n-this.stash.length;while(fetch-->0)this.stash.push(this.next());return this.stash[--n]},indexOfDelimiters:function(start,end){var str=this.input,nstart=0,nend=0,pos=0;for(var i=0,len=str.length;iindents)this.stash.push(this.tok("outdent")),this.indentStack.shift();tok=this.stash.pop()}else indents&&indents!=this.indentStack[0]?(this.indentStack.unshift(indents),tok=this.tok("indent",indents)):tok=this.tok("newline");return tok}},pipelessText:function(){if(this.pipeless){if("\n"==this.input[0])return;var i=this.input.indexOf("\n");-1==i&&(i=this.input.length);var str=this.input.substr(0,i);this.consume(str.length);return this.tok("text",str)}},colon:function(){return this.scan(/^: */,":")},advance:function(){return this.stashed()||this.next()},next:function(){return this.deferred()||this.eos()||this.pipelessText()||this.doctype()||this.include()||this.mixin()||this.tag()||this.filter()||this.each()||this.code()||this.id()||this.className()||this.attrs()||this.indent()||this.comment()||this.colon()||this.text()}}}),require.register("nodes/block-comment.js",function(module,exports,require){}),require.register("nodes/block.js",function(module,exports,require){var Node=require("./node"),Block=module.exports=function Block(node){this.nodes=[],node&&this.push(node)};Block.prototype=new Node,Block.prototype.constructor=Block,Block.prototype.push=function(node){return this.nodes.push(node)},Block.prototype.unshift=function(node){return this.nodes.unshift(node)}}),require.register("nodes/code.js",function(module,exports,require){var Node=require("./node"),Code=module.exports=function Code(val,buffer,escape){this.val=val,this.buffer=buffer,this.escape=escape,/^ *else/.test(val)&&(this.instrumentLineNumber=!1)};Code.prototype=new Node,Code.prototype.constructor=Code}),require.register("nodes/comment.js",function(module,exports,require){var Node=require("./node"),Comment=module.exports=function Comment(val,buffer){this.val=val,this.buffer=buffer};Comment.prototype=new Node,Comment.prototype.constructor=Comment}),require.register("nodes/doctype.js",function(module,exports,require){}),require.register("nodes/each.js",function(module,exports,require){var Node=require("./node"),Each=module.exports=function Each(obj,val,key,block){this.obj=obj,this.val=val,this.key=key,this.block=block};Each.prototype=new Node,Each.prototype.constructor=Each}),require.register("nodes/filter.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Filter=module.exports=function Filter(name,block,attrs){this.name=name,this.block=block,this.attrs=attrs,this.isASTFilter=block instanceof Block};Filter.prototype=new Node,Filter.prototype.constructor=Filter}),require.register("nodes/index.js",function(module,exports,require){exports.Node=require("./node"),exports.Tag=require("./tag"),exports.Code=require("./code"),exports.Each=require("./each"),exports.Text=require("./text"),exports.Block=require("./block"),exports.Mixin=require("./mixin"),exports.Filter=require("./filter"),exports.Comment=require("./comment"),exports.BlockComment=require("./block-comment"),exports.Doctype=require("./doctype")}),require.register("nodes/mixin.js",function(module,exports,require){}),require.register("nodes/node.js",function(module,exports,require){var Node=module.exports=function(){}}),require.register("nodes/tag.js",function(module,exports,require){var Node=require("./node"),Block=require("./block"),Tag=module.exports=function Tag(name,block){this.name=name,this.attrs=[],this.block=block||new Block};Tag.prototype=new Node,Tag.prototype.constructor=Tag,Tag.prototype.setAttribute=function(name,val){this.attrs.push({name:name,val:val});return this},Tag.prototype.removeAttribute=function(name){for(var i=0,len=this.attrs.length;i= result.computed && (result = {value : value, computed : computed});
227 | });
228 | return result.value;
229 | };
230 |
231 | // Return the minimum element (or element-based computation).
232 | _.min = function(obj, iterator, context) {
233 | if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
234 | var result = {computed : Infinity};
235 | each(obj, function(value, index, list) {
236 | var computed = iterator ? iterator.call(context, value, index, list) : value;
237 | computed < result.computed && (result = {value : value, computed : computed});
238 | });
239 | return result.value;
240 | };
241 |
242 | // Sort the object's values by a criterion produced by an iterator.
243 | _.sortBy = function(obj, iterator, context) {
244 | return _.pluck(_.map(obj, function(value, index, list) {
245 | return {
246 | value : value,
247 | criteria : iterator.call(context, value, index, list)
248 | };
249 | }).sort(function(left, right) {
250 | var a = left.criteria, b = right.criteria;
251 | return a < b ? -1 : a > b ? 1 : 0;
252 | }), 'value');
253 | };
254 |
255 | // Groups the object's values by a criterion produced by an iterator
256 | _.groupBy = function(obj, iterator) {
257 | var result = {};
258 | each(obj, function(value, index) {
259 | var key = iterator(value, index);
260 | (result[key] || (result[key] = [])).push(value);
261 | });
262 | return result;
263 | };
264 |
265 | // Use a comparator function to figure out at what index an object should
266 | // be inserted so as to maintain order. Uses binary search.
267 | _.sortedIndex = function(array, obj, iterator) {
268 | iterator || (iterator = _.identity);
269 | var low = 0, high = array.length;
270 | while (low < high) {
271 | var mid = (low + high) >> 1;
272 | iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
273 | }
274 | return low;
275 | };
276 |
277 | // Safely convert anything iterable into a real, live array.
278 | _.toArray = function(iterable) {
279 | if (!iterable) return [];
280 | if (iterable.toArray) return iterable.toArray();
281 | if (_.isArray(iterable)) return slice.call(iterable);
282 | if (_.isArguments(iterable)) return slice.call(iterable);
283 | return _.values(iterable);
284 | };
285 |
286 | // Return the number of elements in an object.
287 | _.size = function(obj) {
288 | return _.toArray(obj).length;
289 | };
290 |
291 | // Array Functions
292 | // ---------------
293 |
294 | // Get the first element of an array. Passing **n** will return the first N
295 | // values in the array. Aliased as `head`. The **guard** check allows it to work
296 | // with `_.map`.
297 | _.first = _.head = function(array, n, guard) {
298 | return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
299 | };
300 |
301 | // Returns everything but the first entry of the array. Aliased as `tail`.
302 | // Especially useful on the arguments object. Passing an **index** will return
303 | // the rest of the values in the array from that index onward. The **guard**
304 | // check allows it to work with `_.map`.
305 | _.rest = _.tail = function(array, index, guard) {
306 | return slice.call(array, (index == null) || guard ? 1 : index);
307 | };
308 |
309 | // Get the last element of an array.
310 | _.last = function(array) {
311 | return array[array.length - 1];
312 | };
313 |
314 | // Trim out all falsy values from an array.
315 | _.compact = function(array) {
316 | return _.filter(array, function(value){ return !!value; });
317 | };
318 |
319 | // Return a completely flattened version of an array.
320 | _.flatten = function(array) {
321 | return _.reduce(array, function(memo, value) {
322 | if (_.isArray(value)) return memo.concat(_.flatten(value));
323 | memo[memo.length] = value;
324 | return memo;
325 | }, []);
326 | };
327 |
328 | // Return a version of the array that does not contain the specified value(s).
329 | _.without = function(array) {
330 | return _.difference(array, slice.call(arguments, 1));
331 | };
332 |
333 | // Produce a duplicate-free version of the array. If the array has already
334 | // been sorted, you have the option of using a faster algorithm.
335 | // Aliased as `unique`.
336 | _.uniq = _.unique = function(array, isSorted) {
337 | return _.reduce(array, function(memo, el, i) {
338 | if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
339 | return memo;
340 | }, []);
341 | };
342 |
343 | // Produce an array that contains the union: each distinct element from all of
344 | // the passed-in arrays.
345 | _.union = function() {
346 | return _.uniq(_.flatten(arguments));
347 | };
348 |
349 | // Produce an array that contains every item shared between all the
350 | // passed-in arrays. (Aliased as "intersect" for back-compat.)
351 | _.intersection = _.intersect = function(array) {
352 | var rest = slice.call(arguments, 1);
353 | return _.filter(_.uniq(array), function(item) {
354 | return _.every(rest, function(other) {
355 | return _.indexOf(other, item) >= 0;
356 | });
357 | });
358 | };
359 |
360 | // Take the difference between one array and another.
361 | // Only the elements present in just the first array will remain.
362 | _.difference = function(array, other) {
363 | return _.filter(array, function(value){ return !_.include(other, value); });
364 | };
365 |
366 | // Zip together multiple lists into a single array -- elements that share
367 | // an index go together.
368 | _.zip = function() {
369 | var args = slice.call(arguments);
370 | var length = _.max(_.pluck(args, 'length'));
371 | var results = new Array(length);
372 | for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
373 | return results;
374 | };
375 |
376 | // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
377 | // we need this function. Return the position of the first occurrence of an
378 | // item in an array, or -1 if the item is not included in the array.
379 | // Delegates to **ECMAScript 5**'s native `indexOf` if available.
380 | // If the array is large and already in sort order, pass `true`
381 | // for **isSorted** to use binary search.
382 | _.indexOf = function(array, item, isSorted) {
383 | if (array == null) return -1;
384 | var i, l;
385 | if (isSorted) {
386 | i = _.sortedIndex(array, item);
387 | return array[i] === item ? i : -1;
388 | }
389 | if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
390 | for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
391 | return -1;
392 | };
393 |
394 |
395 | // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
396 | _.lastIndexOf = function(array, item) {
397 | if (array == null) return -1;
398 | if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
399 | var i = array.length;
400 | while (i--) if (array[i] === item) return i;
401 | return -1;
402 | };
403 |
404 | // Generate an integer Array containing an arithmetic progression. A port of
405 | // the native Python `range()` function. See
406 | // [the Python documentation](http://docs.python.org/library/functions.html#range).
407 | _.range = function(start, stop, step) {
408 | if (arguments.length <= 1) {
409 | stop = start || 0;
410 | start = 0;
411 | }
412 | step = arguments[2] || 1;
413 |
414 | var len = Math.max(Math.ceil((stop - start) / step), 0);
415 | var idx = 0;
416 | var range = new Array(len);
417 |
418 | while(idx < len) {
419 | range[idx++] = start;
420 | start += step;
421 | }
422 |
423 | return range;
424 | };
425 |
426 | // Function (ahem) Functions
427 | // ------------------
428 |
429 | // Create a function bound to a given object (assigning `this`, and arguments,
430 | // optionally). Binding with arguments is also known as `curry`.
431 | // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
432 | // We check for `func.bind` first, to fail fast when `func` is undefined.
433 | _.bind = function(func, obj) {
434 | if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
435 | var args = slice.call(arguments, 2);
436 | return function() {
437 | return func.apply(obj, args.concat(slice.call(arguments)));
438 | };
439 | };
440 |
441 | // Bind all of an object's methods to that object. Useful for ensuring that
442 | // all callbacks defined on an object belong to it.
443 | _.bindAll = function(obj) {
444 | var funcs = slice.call(arguments, 1);
445 | if (funcs.length == 0) funcs = _.functions(obj);
446 | each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
447 | return obj;
448 | };
449 |
450 | // Memoize an expensive function by storing its results.
451 | _.memoize = function(func, hasher) {
452 | var memo = {};
453 | hasher || (hasher = _.identity);
454 | return function() {
455 | var key = hasher.apply(this, arguments);
456 | return hasOwnProperty.call(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
457 | };
458 | };
459 |
460 | // Delays a function for the given number of milliseconds, and then calls
461 | // it with the arguments supplied.
462 | _.delay = function(func, wait) {
463 | var args = slice.call(arguments, 2);
464 | return setTimeout(function(){ return func.apply(func, args); }, wait);
465 | };
466 |
467 | // Defers a function, scheduling it to run after the current call stack has
468 | // cleared.
469 | _.defer = function(func) {
470 | return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
471 | };
472 |
473 | // Internal function used to implement `_.throttle` and `_.debounce`.
474 | var limit = function(func, wait, debounce) {
475 | var timeout;
476 | return function() {
477 | var context = this, args = arguments;
478 | var throttler = function() {
479 | timeout = null;
480 | func.apply(context, args);
481 | };
482 | if (debounce) clearTimeout(timeout);
483 | if (debounce || !timeout) timeout = setTimeout(throttler, wait);
484 | };
485 | };
486 |
487 | // Returns a function, that, when invoked, will only be triggered at most once
488 | // during a given window of time.
489 | _.throttle = function(func, wait) {
490 | return limit(func, wait, false);
491 | };
492 |
493 | // Returns a function, that, as long as it continues to be invoked, will not
494 | // be triggered. The function will be called after it stops being called for
495 | // N milliseconds.
496 | _.debounce = function(func, wait) {
497 | return limit(func, wait, true);
498 | };
499 |
500 | // Returns a function that will be executed at most one time, no matter how
501 | // often you call it. Useful for lazy initialization.
502 | _.once = function(func) {
503 | var ran = false, memo;
504 | return function() {
505 | if (ran) return memo;
506 | ran = true;
507 | return memo = func.apply(this, arguments);
508 | };
509 | };
510 |
511 | // Returns the first function passed as an argument to the second,
512 | // allowing you to adjust arguments, run code before and after, and
513 | // conditionally execute the original function.
514 | _.wrap = function(func, wrapper) {
515 | return function() {
516 | var args = [func].concat(slice.call(arguments));
517 | return wrapper.apply(this, args);
518 | };
519 | };
520 |
521 | // Returns a function that is the composition of a list of functions, each
522 | // consuming the return value of the function that follows.
523 | _.compose = function() {
524 | var funcs = slice.call(arguments);
525 | return function() {
526 | var args = slice.call(arguments);
527 | for (var i = funcs.length - 1; i >= 0; i--) {
528 | args = [funcs[i].apply(this, args)];
529 | }
530 | return args[0];
531 | };
532 | };
533 |
534 | // Returns a function that will only be executed after being called N times.
535 | _.after = function(times, func) {
536 | return function() {
537 | if (--times < 1) { return func.apply(this, arguments); }
538 | };
539 | };
540 |
541 |
542 | // Object Functions
543 | // ----------------
544 |
545 | // Retrieve the names of an object's properties.
546 | // Delegates to **ECMAScript 5**'s native `Object.keys`
547 | _.keys = nativeKeys || function(obj) {
548 | if (obj !== Object(obj)) throw new TypeError('Invalid object');
549 | var keys = [];
550 | for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
551 | return keys;
552 | };
553 |
554 | // Retrieve the values of an object's properties.
555 | _.values = function(obj) {
556 | return _.map(obj, _.identity);
557 | };
558 |
559 | // Return a sorted list of the function names available on the object.
560 | // Aliased as `methods`
561 | _.functions = _.methods = function(obj) {
562 | var names = [];
563 | for (var key in obj) {
564 | if (_.isFunction(obj[key])) names.push(key);
565 | }
566 | return names.sort();
567 | };
568 |
569 | // Extend a given object with all the properties in passed-in object(s).
570 | _.extend = function(obj) {
571 | each(slice.call(arguments, 1), function(source) {
572 | for (var prop in source) {
573 | if (source[prop] !== void 0) obj[prop] = source[prop];
574 | }
575 | });
576 | return obj;
577 | };
578 |
579 | // Fill in a given object with default properties.
580 | _.defaults = function(obj) {
581 | each(slice.call(arguments, 1), function(source) {
582 | for (var prop in source) {
583 | if (obj[prop] == null) obj[prop] = source[prop];
584 | }
585 | });
586 | return obj;
587 | };
588 |
589 | // Create a (shallow-cloned) duplicate of an object.
590 | _.clone = function(obj) {
591 | return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
592 | };
593 |
594 | // Invokes interceptor with the obj, and then returns obj.
595 | // The primary purpose of this method is to "tap into" a method chain, in
596 | // order to perform operations on intermediate results within the chain.
597 | _.tap = function(obj, interceptor) {
598 | interceptor(obj);
599 | return obj;
600 | };
601 |
602 | // Perform a deep comparison to check if two objects are equal.
603 | _.isEqual = function(a, b) {
604 | // Check object identity.
605 | if (a === b) return true;
606 | // Different types?
607 | var atype = typeof(a), btype = typeof(b);
608 | if (atype != btype) return false;
609 | // Basic equality test (watch out for coercions).
610 | if (a == b) return true;
611 | // One is falsy and the other truthy.
612 | if ((!a && b) || (a && !b)) return false;
613 | // Unwrap any wrapped objects.
614 | if (a._chain) a = a._wrapped;
615 | if (b._chain) b = b._wrapped;
616 | // One of them implements an isEqual()?
617 | if (a.isEqual) return a.isEqual(b);
618 | if (b.isEqual) return b.isEqual(a);
619 | // Check dates' integer values.
620 | if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
621 | // Both are NaN?
622 | if (_.isNaN(a) && _.isNaN(b)) return false;
623 | // Compare regular expressions.
624 | if (_.isRegExp(a) && _.isRegExp(b))
625 | return a.source === b.source &&
626 | a.global === b.global &&
627 | a.ignoreCase === b.ignoreCase &&
628 | a.multiline === b.multiline;
629 | // If a is not an object by this point, we can't handle it.
630 | if (atype !== 'object') return false;
631 | // Check for different array lengths before comparing contents.
632 | if (a.length && (a.length !== b.length)) return false;
633 | // Nothing else worked, deep compare the contents.
634 | var aKeys = _.keys(a), bKeys = _.keys(b);
635 | // Different object sizes?
636 | if (aKeys.length != bKeys.length) return false;
637 | // Recursive comparison of contents.
638 | for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
639 | return true;
640 | };
641 |
642 | // Is a given array or object empty?
643 | _.isEmpty = function(obj) {
644 | if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
645 | for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
646 | return true;
647 | };
648 |
649 | // Is a given value a DOM element?
650 | _.isElement = function(obj) {
651 | return !!(obj && obj.nodeType == 1);
652 | };
653 |
654 | // Is a given value an array?
655 | // Delegates to ECMA5's native Array.isArray
656 | _.isArray = nativeIsArray || function(obj) {
657 | return toString.call(obj) === '[object Array]';
658 | };
659 |
660 | // Is a given variable an object?
661 | _.isObject = function(obj) {
662 | return obj === Object(obj);
663 | };
664 |
665 | // Is a given variable an arguments object?
666 | _.isArguments = function(obj) {
667 | return !!(obj && hasOwnProperty.call(obj, 'callee'));
668 | };
669 |
670 | // Is a given value a function?
671 | _.isFunction = function(obj) {
672 | return !!(obj && obj.constructor && obj.call && obj.apply);
673 | };
674 |
675 | // Is a given value a string?
676 | _.isString = function(obj) {
677 | return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
678 | };
679 |
680 | // Is a given value a number?
681 | _.isNumber = function(obj) {
682 | return !!(obj === 0 || (obj && obj.toExponential && obj.toFixed));
683 | };
684 |
685 | // Is the given value `NaN`? `NaN` happens to be the only value in JavaScript
686 | // that does not equal itself.
687 | _.isNaN = function(obj) {
688 | return obj !== obj;
689 | };
690 |
691 | // Is a given value a boolean?
692 | _.isBoolean = function(obj) {
693 | return obj === true || obj === false;
694 | };
695 |
696 | // Is a given value a date?
697 | _.isDate = function(obj) {
698 | return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
699 | };
700 |
701 | // Is the given value a regular expression?
702 | _.isRegExp = function(obj) {
703 | return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
704 | };
705 |
706 | // Is a given value equal to null?
707 | _.isNull = function(obj) {
708 | return obj === null;
709 | };
710 |
711 | // Is a given variable undefined?
712 | _.isUndefined = function(obj) {
713 | return obj === void 0;
714 | };
715 |
716 | // Utility Functions
717 | // -----------------
718 |
719 | // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
720 | // previous owner. Returns a reference to the Underscore object.
721 | _.noConflict = function() {
722 | root._ = previousUnderscore;
723 | return this;
724 | };
725 |
726 | // Keep the identity function around for default iterators.
727 | _.identity = function(value) {
728 | return value;
729 | };
730 |
731 | // Run a function **n** times.
732 | _.times = function (n, iterator, context) {
733 | for (var i = 0; i < n; i++) iterator.call(context, i);
734 | };
735 |
736 | // Add your own custom functions to the Underscore object, ensuring that
737 | // they're correctly added to the OOP wrapper as well.
738 | _.mixin = function(obj) {
739 | each(_.functions(obj), function(name){
740 | addToWrapper(name, _[name] = obj[name]);
741 | });
742 | };
743 |
744 | // Generate a unique integer id (unique within the entire client session).
745 | // Useful for temporary DOM ids.
746 | var idCounter = 0;
747 | _.uniqueId = function(prefix) {
748 | var id = idCounter++;
749 | return prefix ? prefix + id : id;
750 | };
751 |
752 | // By default, Underscore uses ERB-style template delimiters, change the
753 | // following template settings to use alternative delimiters.
754 | _.templateSettings = {
755 | evaluate : /<%([\s\S]+?)%>/g,
756 | interpolate : /<%=([\s\S]+?)%>/g
757 | };
758 |
759 | // JavaScript micro-templating, similar to John Resig's implementation.
760 | // Underscore templating handles arbitrary delimiters, preserves whitespace,
761 | // and correctly escapes quotes within interpolated code.
762 | _.template = function(str, data) {
763 | var c = _.templateSettings;
764 | var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
765 | 'with(obj||{}){__p.push(\'' +
766 | str.replace(/\\/g, '\\\\')
767 | .replace(/'/g, "\\'")
768 | .replace(c.interpolate, function(match, code) {
769 | return "'," + code.replace(/\\'/g, "'") + ",'";
770 | })
771 | .replace(c.evaluate || null, function(match, code) {
772 | return "');" + code.replace(/\\'/g, "'")
773 | .replace(/[\r\n\t]/g, ' ') + "__p.push('";
774 | })
775 | .replace(/\r/g, '\\r')
776 | .replace(/\n/g, '\\n')
777 | .replace(/\t/g, '\\t')
778 | + "');}return __p.join('');";
779 | var func = new Function('obj', tmpl);
780 | return data ? func(data) : func;
781 | };
782 |
783 | // The OOP Wrapper
784 | // ---------------
785 |
786 | // If Underscore is called as a function, it returns a wrapped object that
787 | // can be used OO-style. This wrapper holds altered versions of all the
788 | // underscore functions. Wrapped objects may be chained.
789 | var wrapper = function(obj) { this._wrapped = obj; };
790 |
791 | // Expose `wrapper.prototype` as `_.prototype`
792 | _.prototype = wrapper.prototype;
793 |
794 | // Helper function to continue chaining intermediate results.
795 | var result = function(obj, chain) {
796 | return chain ? _(obj).chain() : obj;
797 | };
798 |
799 | // A method to easily add functions to the OOP wrapper.
800 | var addToWrapper = function(name, func) {
801 | wrapper.prototype[name] = function() {
802 | var args = slice.call(arguments);
803 | unshift.call(args, this._wrapped);
804 | return result(func.apply(_, args), this._chain);
805 | };
806 | };
807 |
808 | // Add all of the Underscore functions to the wrapper object.
809 | _.mixin(_);
810 |
811 | // Add all mutator Array functions to the wrapper.
812 | each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
813 | var method = ArrayProto[name];
814 | wrapper.prototype[name] = function() {
815 | method.apply(this._wrapped, arguments);
816 | return result(this._wrapped, this._chain);
817 | };
818 | });
819 |
820 | // Add all accessor Array functions to the wrapper.
821 | each(['concat', 'join', 'slice'], function(name) {
822 | var method = ArrayProto[name];
823 | wrapper.prototype[name] = function() {
824 | return result(method.apply(this._wrapped, arguments), this._chain);
825 | };
826 | });
827 |
828 | // Start chaining a wrapped Underscore object.
829 | wrapper.prototype.chain = function() {
830 | this._chain = true;
831 | return this;
832 | };
833 |
834 | // Extracts the result from a wrapped and chained object.
835 | wrapper.prototype.value = function() {
836 | return this._wrapped;
837 | };
838 |
839 | })();
--------------------------------------------------------------------------------
/Resources/kranium/lib/backbone/backbone.js:
--------------------------------------------------------------------------------
1 | // Backbone.js 0.5.3
2 | // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Backbone may be freely distributed under the MIT license.
4 | // For all details and documentation:
5 | // http://documentcloud.github.com/backbone
6 |
7 | (function(){
8 |
9 | // Initial Setup
10 | // -------------
11 |
12 | // Save a reference to the global object.
13 | var root = this;
14 |
15 | // Save the previous value of the `Backbone` variable.
16 | var previousBackbone = root.Backbone;
17 |
18 | // The top-level namespace. All public Backbone classes and modules will
19 | // be attached to this. Exported for both CommonJS and the browser.
20 | var Backbone;
21 | if (typeof exports !== 'undefined') {
22 | Backbone = exports;
23 | } else {
24 | Backbone = root.Backbone = {};
25 | }
26 |
27 | // Current version of the library. Keep in sync with `package.json`.
28 | Backbone.VERSION = '0.5.3';
29 |
30 | // Require Underscore, if we're on the server, and it's not already present.
31 | var _ = root._;
32 | if (!_ && (typeof require !== 'undefined')) _ = require('underscore')._;
33 |
34 | // For Backbone's purposes, jQuery or Zepto owns the `$` variable.
35 | var $ = root.jQuery || root.Zepto;
36 |
37 | // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
38 | // to its previous owner. Returns a reference to this Backbone object.
39 | Backbone.noConflict = function() {
40 | root.Backbone = previousBackbone;
41 | return this;
42 | };
43 |
44 | // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option will
45 | // fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and set a
46 | // `X-Http-Method-Override` header.
47 | Backbone.emulateHTTP = false;
48 |
49 | // Turn on `emulateJSON` to support legacy servers that can't deal with direct
50 | // `application/json` requests ... will encode the body as
51 | // `application/x-www-form-urlencoded` instead and will send the model in a
52 | // form param named `model`.
53 | Backbone.emulateJSON = false;
54 |
55 | // Backbone.Events
56 | // -----------------
57 |
58 | // A module that can be mixed in to *any object* in order to provide it with
59 | // custom events. You may `bind` or `unbind` a callback function to an event;
60 | // `trigger`-ing an event fires all callbacks in succession.
61 | //
62 | // var object = {};
63 | // _.extend(object, Backbone.Events);
64 | // object.bind('expand', function(){ alert('expanded'); });
65 | // object.trigger('expand');
66 | //
67 | Backbone.Events = {
68 |
69 | // Bind an event, specified by a string name, `ev`, to a `callback` function.
70 | // Passing `"all"` will bind the callback to all events fired.
71 | bind : function(ev, callback, context) {
72 | var calls = this._callbacks || (this._callbacks = {});
73 | var list = calls[ev] || (calls[ev] = []);
74 | list.push([callback, context]);
75 | return this;
76 | },
77 |
78 | // Remove one or many callbacks. If `callback` is null, removes all
79 | // callbacks for the event. If `ev` is null, removes all bound callbacks
80 | // for all events.
81 | unbind : function(ev, callback) {
82 | var calls;
83 | if (!ev) {
84 | this._callbacks = {};
85 | } else if (calls = this._callbacks) {
86 | if (!callback) {
87 | calls[ev] = [];
88 | } else {
89 | var list = calls[ev];
90 | if (!list) return this;
91 | for (var i = 0, l = list.length; i < l; i++) {
92 | if (list[i] && callback === list[i][0]) {
93 | list[i] = null;
94 | break;
95 | }
96 | }
97 | }
98 | }
99 | return this;
100 | },
101 |
102 | // Trigger an event, firing all bound callbacks. Callbacks are passed the
103 | // same arguments as `trigger` is, apart from the event name.
104 | // Listening for `"all"` passes the true event name as the first argument.
105 | trigger : function(eventName) {
106 | var list, calls, ev, callback, args;
107 | var both = 2;
108 | if (!(calls = this._callbacks)) return this;
109 | while (both--) {
110 | ev = both ? eventName : 'all';
111 | if (list = calls[ev]) {
112 | for (var i = 0, l = list.length; i < l; i++) {
113 | if (!(callback = list[i])) {
114 | list.splice(i, 1); i--; l--;
115 | } else {
116 | args = both ? Array.prototype.slice.call(arguments, 1) : arguments;
117 | callback[0].apply(callback[1] || this, args);
118 | }
119 | }
120 | }
121 | }
122 | return this;
123 | }
124 |
125 | };
126 |
127 | // Backbone.Model
128 | // --------------
129 |
130 | // Create a new model, with defined attributes. A client id (`cid`)
131 | // is automatically generated and assigned for you.
132 | Backbone.Model = function(attributes, options) {
133 | var defaults;
134 | attributes || (attributes = {});
135 | if (defaults = this.defaults) {
136 | if (_.isFunction(defaults)) defaults = defaults.call(this);
137 | attributes = _.extend({}, defaults, attributes);
138 | }
139 | this.attributes = {};
140 | this._escapedAttributes = {};
141 | this.cid = _.uniqueId('c');
142 | this.set(attributes, {silent : true});
143 | this._changed = false;
144 | this._previousAttributes = _.clone(this.attributes);
145 | if (options && options.collection) this.collection = options.collection;
146 | this.initialize(attributes, options);
147 | };
148 |
149 | // Attach all inheritable methods to the Model prototype.
150 | _.extend(Backbone.Model.prototype, Backbone.Events, {
151 |
152 | // A snapshot of the model's previous attributes, taken immediately
153 | // after the last `"change"` event was fired.
154 | _previousAttributes : null,
155 |
156 | // Has the item been changed since the last `"change"` event?
157 | _changed : false,
158 |
159 | // The default name for the JSON `id` attribute is `"id"`. MongoDB and
160 | // CouchDB users may want to set this to `"_id"`.
161 | idAttribute : 'id',
162 |
163 | // Initialize is an empty function by default. Override it with your own
164 | // initialization logic.
165 | initialize : function(){},
166 |
167 | // Return a copy of the model's `attributes` object.
168 | toJSON : function() {
169 | return _.clone(this.attributes);
170 | },
171 |
172 | // Get the value of an attribute.
173 | get : function(attr) {
174 | return this.attributes[attr];
175 | },
176 |
177 | // Get the HTML-escaped value of an attribute.
178 | escape : function(attr) {
179 | var html;
180 | if (html = this._escapedAttributes[attr]) return html;
181 | var val = this.attributes[attr];
182 | return this._escapedAttributes[attr] = escapeHTML(val == null ? '' : '' + val);
183 | },
184 |
185 | // Returns `true` if the attribute contains a value that is not null
186 | // or undefined.
187 | has : function(attr) {
188 | return this.attributes[attr] != null;
189 | },
190 |
191 | // Set a hash of model attributes on the object, firing `"change"` unless you
192 | // choose to silence it.
193 | set : function(attrs, options) {
194 |
195 | // Extract attributes and options.
196 | options || (options = {});
197 | if (!attrs) return this;
198 | if (attrs.attributes) attrs = attrs.attributes;
199 | var now = this.attributes, escaped = this._escapedAttributes;
200 |
201 | // Run validation.
202 | if (!options.silent && this.validate && !this._performValidation(attrs, options)) return false;
203 |
204 | // Check for changes of `id`.
205 | if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
206 |
207 | // We're about to start triggering change events.
208 | var alreadyChanging = this._changing;
209 | this._changing = true;
210 |
211 | // Update attributes.
212 | for (var attr in attrs) {
213 | var val = attrs[attr];
214 | if (!_.isEqual(now[attr], val)) {
215 | now[attr] = val;
216 | delete escaped[attr];
217 | this._changed = true;
218 | if (!options.silent) this.trigger('change:' + attr, this, val, options);
219 | }
220 | }
221 |
222 | // Fire the `"change"` event, if the model has been changed.
223 | if (!alreadyChanging && !options.silent && this._changed) this.change(options);
224 | this._changing = false;
225 | return this;
226 | },
227 |
228 | // Remove an attribute from the model, firing `"change"` unless you choose
229 | // to silence it. `unset` is a noop if the attribute doesn't exist.
230 | unset : function(attr, options) {
231 | if (!(attr in this.attributes)) return this;
232 | options || (options = {});
233 | var value = this.attributes[attr];
234 |
235 | // Run validation.
236 | var validObj = {};
237 | validObj[attr] = void 0;
238 | if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
239 |
240 | // Remove the attribute.
241 | delete this.attributes[attr];
242 | delete this._escapedAttributes[attr];
243 | if (attr == this.idAttribute) delete this.id;
244 | this._changed = true;
245 | if (!options.silent) {
246 | this.trigger('change:' + attr, this, void 0, options);
247 | this.change(options);
248 | }
249 | return this;
250 | },
251 |
252 | // Clear all attributes on the model, firing `"change"` unless you choose
253 | // to silence it.
254 | clear : function(options) {
255 | options || (options = {});
256 | var attr;
257 | var old = this.attributes;
258 |
259 | // Run validation.
260 | var validObj = {};
261 | for (attr in old) validObj[attr] = void 0;
262 | if (!options.silent && this.validate && !this._performValidation(validObj, options)) return false;
263 |
264 | this.attributes = {};
265 | this._escapedAttributes = {};
266 | this._changed = true;
267 | if (!options.silent) {
268 | for (attr in old) {
269 | this.trigger('change:' + attr, this, void 0, options);
270 | }
271 | this.change(options);
272 | }
273 | return this;
274 | },
275 |
276 | // Fetch the model from the server. If the server's representation of the
277 | // model differs from its current attributes, they will be overriden,
278 | // triggering a `"change"` event.
279 | fetch : function(options) {
280 | options || (options = {});
281 | var model = this;
282 | var success = options.success;
283 | options.success = function(resp, status, xhr) {
284 | if (!model.set(model.parse(resp, xhr), options)) return false;
285 | if (success) success(model, resp);
286 | };
287 | options.error = wrapError(options.error, model, options);
288 | return (this.sync || Backbone.sync).call(this, 'read', this, options);
289 | },
290 |
291 | // Set a hash of model attributes, and sync the model to the server.
292 | // If the server returns an attributes hash that differs, the model's
293 | // state will be `set` again.
294 | save : function(attrs, options) {
295 | options || (options = {});
296 | if (attrs && !this.set(attrs, options)) return false;
297 | var model = this;
298 | var success = options.success;
299 | options.success = function(resp, status, xhr) {
300 | if (!model.set(model.parse(resp, xhr), options)) return false;
301 | if (success) success(model, resp, xhr);
302 | };
303 | options.error = wrapError(options.error, model, options);
304 | var method = this.isNew() ? 'create' : 'update';
305 | return (this.sync || Backbone.sync).call(this, method, this, options);
306 | },
307 |
308 | // Destroy this model on the server if it was already persisted. Upon success, the model is removed
309 | // from its collection, if it has one.
310 | destroy : function(options) {
311 | options || (options = {});
312 | if (this.isNew()) return this.trigger('destroy', this, this.collection, options);
313 | var model = this;
314 | var success = options.success;
315 | options.success = function(resp) {
316 | model.trigger('destroy', model, model.collection, options);
317 | if (success) success(model, resp);
318 | };
319 | options.error = wrapError(options.error, model, options);
320 | return (this.sync || Backbone.sync).call(this, 'delete', this, options);
321 | },
322 |
323 | // Default URL for the model's representation on the server -- if you're
324 | // using Backbone's restful methods, override this to change the endpoint
325 | // that will be called.
326 | url : function() {
327 | var base = getUrl(this.collection) || this.urlRoot || urlError();
328 | if (this.isNew()) return base;
329 | return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
330 | },
331 |
332 | // **parse** converts a response into the hash of attributes to be `set` on
333 | // the model. The default implementation is just to pass the response along.
334 | parse : function(resp, xhr) {
335 | return resp;
336 | },
337 |
338 | // Create a new model with identical attributes to this one.
339 | clone : function() {
340 | return new this.constructor(this);
341 | },
342 |
343 | // A model is new if it has never been saved to the server, and lacks an id.
344 | isNew : function() {
345 | return this.id == null;
346 | },
347 |
348 | // Call this method to manually fire a `change` event for this model.
349 | // Calling this will cause all objects observing the model to update.
350 | change : function(options) {
351 | this.trigger('change', this, options);
352 | this._previousAttributes = _.clone(this.attributes);
353 | this._changed = false;
354 | },
355 |
356 | // Determine if the model has changed since the last `"change"` event.
357 | // If you specify an attribute name, determine if that attribute has changed.
358 | hasChanged : function(attr) {
359 | if (attr) return this._previousAttributes[attr] != this.attributes[attr];
360 | return this._changed;
361 | },
362 |
363 | // Return an object containing all the attributes that have changed, or false
364 | // if there are no changed attributes. Useful for determining what parts of a
365 | // view need to be updated and/or what attributes need to be persisted to
366 | // the server.
367 | changedAttributes : function(now) {
368 | now || (now = this.attributes);
369 | var old = this._previousAttributes;
370 | var changed = false;
371 | for (var attr in now) {
372 | if (!_.isEqual(old[attr], now[attr])) {
373 | changed = changed || {};
374 | changed[attr] = now[attr];
375 | }
376 | }
377 | return changed;
378 | },
379 |
380 | // Get the previous value of an attribute, recorded at the time the last
381 | // `"change"` event was fired.
382 | previous : function(attr) {
383 | if (!attr || !this._previousAttributes) return null;
384 | return this._previousAttributes[attr];
385 | },
386 |
387 | // Get all of the attributes of the model at the time of the previous
388 | // `"change"` event.
389 | previousAttributes : function() {
390 | return _.clone(this._previousAttributes);
391 | },
392 |
393 | // Run validation against a set of incoming attributes, returning `true`
394 | // if all is well. If a specific `error` callback has been passed,
395 | // call that instead of firing the general `"error"` event.
396 | _performValidation : function(attrs, options) {
397 | var error = this.validate(attrs);
398 | if (error) {
399 | if (options.error) {
400 | options.error(this, error, options);
401 | } else {
402 | this.trigger('error', this, error, options);
403 | }
404 | return false;
405 | }
406 | return true;
407 | }
408 |
409 | });
410 |
411 | // Backbone.Collection
412 | // -------------------
413 |
414 | // Provides a standard collection class for our sets of models, ordered
415 | // or unordered. If a `comparator` is specified, the Collection will maintain
416 | // its models in sort order, as they're added and removed.
417 | Backbone.Collection = function(models, options) {
418 | options || (options = {});
419 | if (options.comparator) this.comparator = options.comparator;
420 | _.bindAll(this, '_onModelEvent', '_removeReference');
421 | this._reset();
422 | if (models) this.reset(models, {silent: true});
423 | this.initialize.apply(this, arguments);
424 | };
425 |
426 | // Define the Collection's inheritable methods.
427 | _.extend(Backbone.Collection.prototype, Backbone.Events, {
428 |
429 | // The default model for a collection is just a **Backbone.Model**.
430 | // This should be overridden in most cases.
431 | model : Backbone.Model,
432 |
433 | // Initialize is an empty function by default. Override it with your own
434 | // initialization logic.
435 | initialize : function(){},
436 |
437 | // The JSON representation of a Collection is an array of the
438 | // models' attributes.
439 | toJSON : function() {
440 | return this.map(function(model){ return model.toJSON(); });
441 | },
442 |
443 | // Add a model, or list of models to the set. Pass **silent** to avoid
444 | // firing the `added` event for every new model.
445 | add : function(models, options) {
446 | if (_.isArray(models)) {
447 | for (var i = 0, l = models.length; i < l; i++) {
448 | this._add(models[i], options);
449 | }
450 | } else {
451 | this._add(models, options);
452 | }
453 | return this;
454 | },
455 |
456 | // Remove a model, or a list of models from the set. Pass silent to avoid
457 | // firing the `removed` event for every model removed.
458 | remove : function(models, options) {
459 | if (_.isArray(models)) {
460 | for (var i = 0, l = models.length; i < l; i++) {
461 | this._remove(models[i], options);
462 | }
463 | } else {
464 | this._remove(models, options);
465 | }
466 | return this;
467 | },
468 |
469 | // Get a model from the set by id.
470 | get : function(id) {
471 | if (id == null) return null;
472 | return this._byId[id.id != null ? id.id : id];
473 | },
474 |
475 | // Get a model from the set by client id.
476 | getByCid : function(cid) {
477 | return cid && this._byCid[cid.cid || cid];
478 | },
479 |
480 | // Get the model at the given index.
481 | at: function(index) {
482 | return this.models[index];
483 | },
484 |
485 | // Force the collection to re-sort itself. You don't need to call this under normal
486 | // circumstances, as the set will maintain sort order as each item is added.
487 | sort : function(options) {
488 | options || (options = {});
489 | if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
490 | this.models = this.sortBy(this.comparator);
491 | if (!options.silent) this.trigger('reset', this, options);
492 | return this;
493 | },
494 |
495 | // Pluck an attribute from each model in the collection.
496 | pluck : function(attr) {
497 | return _.map(this.models, function(model){ return model.get(attr); });
498 | },
499 |
500 | // When you have more items than you want to add or remove individually,
501 | // you can reset the entire set with a new list of models, without firing
502 | // any `added` or `removed` events. Fires `reset` when finished.
503 | reset : function(models, options) {
504 | models || (models = []);
505 | options || (options = {});
506 | this.each(this._removeReference);
507 | this._reset();
508 | this.add(models, {silent: true});
509 | if (!options.silent) this.trigger('reset', this, options);
510 | return this;
511 | },
512 |
513 | // Fetch the default set of models for this collection, resetting the
514 | // collection when they arrive. If `add: true` is passed, appends the
515 | // models to the collection instead of resetting.
516 | fetch : function(options) {
517 | options || (options = {});
518 | var collection = this;
519 | var success = options.success;
520 | options.success = function(resp, status, xhr) {
521 | collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
522 | if (success) success(collection, resp);
523 | };
524 | options.error = wrapError(options.error, collection, options);
525 | return (this.sync || Backbone.sync).call(this, 'read', this, options);
526 | },
527 |
528 | // Create a new instance of a model in this collection. After the model
529 | // has been created on the server, it will be added to the collection.
530 | // Returns the model, or 'false' if validation on a new model fails.
531 | create : function(model, options) {
532 | var coll = this;
533 | options || (options = {});
534 | model = this._prepareModel(model, options);
535 | if (!model) return false;
536 | var success = options.success;
537 | options.success = function(nextModel, resp, xhr) {
538 | coll.add(nextModel, options);
539 | if (success) success(nextModel, resp, xhr);
540 | };
541 | model.save(null, options);
542 | return model;
543 | },
544 |
545 | // **parse** converts a response into a list of models to be added to the
546 | // collection. The default implementation is just to pass it through.
547 | parse : function(resp, xhr) {
548 | return resp;
549 | },
550 |
551 | // Proxy to _'s chain. Can't be proxied the same way the rest of the
552 | // underscore methods are proxied because it relies on the underscore
553 | // constructor.
554 | chain: function () {
555 | return _(this.models).chain();
556 | },
557 |
558 | // Reset all internal state. Called when the collection is reset.
559 | _reset : function(options) {
560 | this.length = 0;
561 | this.models = [];
562 | this._byId = {};
563 | this._byCid = {};
564 | },
565 |
566 | // Prepare a model to be added to this collection
567 | _prepareModel: function(model, options) {
568 | if (!(model instanceof Backbone.Model)) {
569 | var attrs = model;
570 | model = new this.model(attrs, {collection: this});
571 | if (model.validate && !model._performValidation(attrs, options)) model = false;
572 | } else if (!model.collection) {
573 | model.collection = this;
574 | }
575 | return model;
576 | },
577 |
578 | // Internal implementation of adding a single model to the set, updating
579 | // hash indexes for `id` and `cid` lookups.
580 | // Returns the model, or 'false' if validation on a new model fails.
581 | _add : function(model, options) {
582 | options || (options = {});
583 | model = this._prepareModel(model, options);
584 | if (!model) return false;
585 | var already = this.getByCid(model);
586 | if (already) throw new Error(["Can't add the same model to a set twice", already.id]);
587 | this._byId[model.id] = model;
588 | this._byCid[model.cid] = model;
589 | var index = options.at != null ? options.at :
590 | this.comparator ? this.sortedIndex(model, this.comparator) :
591 | this.length;
592 | this.models.splice(index, 0, model);
593 | model.bind('all', this._onModelEvent);
594 | this.length++;
595 | if (!options.silent) model.trigger('add', model, this, options);
596 | return model;
597 | },
598 |
599 | // Internal implementation of removing a single model from the set, updating
600 | // hash indexes for `id` and `cid` lookups.
601 | _remove : function(model, options) {
602 | options || (options = {});
603 | model = this.getByCid(model) || this.get(model);
604 | if (!model) return null;
605 | delete this._byId[model.id];
606 | delete this._byCid[model.cid];
607 | this.models.splice(this.indexOf(model), 1);
608 | this.length--;
609 | if (!options.silent) model.trigger('remove', model, this, options);
610 | this._removeReference(model);
611 | return model;
612 | },
613 |
614 | // Internal method to remove a model's ties to a collection.
615 | _removeReference : function(model) {
616 | if (this == model.collection) {
617 | delete model.collection;
618 | }
619 | model.unbind('all', this._onModelEvent);
620 | },
621 |
622 | // Internal method called every time a model in the set fires an event.
623 | // Sets need to update their indexes when models change ids. All other
624 | // events simply proxy through. "add" and "remove" events that originate
625 | // in other collections are ignored.
626 | _onModelEvent : function(ev, model, collection, options) {
627 | if ((ev == 'add' || ev == 'remove') && collection != this) return;
628 | if (ev == 'destroy') {
629 | this._remove(model, options);
630 | }
631 | if (model && ev === 'change:' + model.idAttribute) {
632 | delete this._byId[model.previous(model.idAttribute)];
633 | this._byId[model.id] = model;
634 | }
635 | this.trigger.apply(this, arguments);
636 | }
637 |
638 | });
639 |
640 | // Underscore methods that we want to implement on the Collection.
641 | var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find', 'detect',
642 | 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include',
643 | 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex', 'toArray', 'size',
644 | 'first', 'rest', 'last', 'without', 'indexOf', 'lastIndexOf', 'isEmpty', 'groupBy'];
645 |
646 | // Mix in each Underscore method as a proxy to `Collection#models`.
647 | _.each(methods, function(method) {
648 | Backbone.Collection.prototype[method] = function() {
649 | return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
650 | };
651 | });
652 |
653 | // Backbone.Router
654 | // -------------------
655 |
656 | // Routers map faux-URLs to actions, and fire events when routes are
657 | // matched. Creating a new one sets its `routes` hash, if not set statically.
658 | Backbone.Router = function(options) {
659 | options || (options = {});
660 | if (options.routes) this.routes = options.routes;
661 | this._bindRoutes();
662 | this.initialize.apply(this, arguments);
663 | };
664 |
665 | // Cached regular expressions for matching named param parts and splatted
666 | // parts of route strings.
667 | var namedParam = /:([\w\d]+)/g;
668 | var splatParam = /\*([\w\d]+)/g;
669 | var escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g;
670 |
671 | // Set up all inheritable **Backbone.Router** properties and methods.
672 | _.extend(Backbone.Router.prototype, Backbone.Events, {
673 |
674 | // Initialize is an empty function by default. Override it with your own
675 | // initialization logic.
676 | initialize : function(){},
677 |
678 | // Manually bind a single named route to a callback. For example:
679 | //
680 | // this.route('search/:query/p:num', 'search', function(query, num) {
681 | // ...
682 | // });
683 | //
684 | route : function(route, name, callback) {
685 | Backbone.history || (Backbone.history = new Backbone.History);
686 | if (!_.isRegExp(route)) route = this._routeToRegExp(route);
687 | Backbone.history.route(route, _.bind(function(fragment) {
688 | var args = this._extractParameters(route, fragment);
689 | callback.apply(this, args);
690 | this.trigger.apply(this, ['route:' + name].concat(args));
691 | }, this));
692 | },
693 |
694 | // Simple proxy to `Backbone.history` to save a fragment into the history.
695 | navigate : function(fragment, triggerRoute) {
696 | Backbone.history.navigate(fragment, triggerRoute);
697 | },
698 |
699 | // Bind all defined routes to `Backbone.history`. We have to reverse the
700 | // order of the routes here to support behavior where the most general
701 | // routes can be defined at the bottom of the route map.
702 | _bindRoutes : function() {
703 | if (!this.routes) return;
704 | var routes = [];
705 | for (var route in this.routes) {
706 | routes.unshift([route, this.routes[route]]);
707 | }
708 | for (var i = 0, l = routes.length; i < l; i++) {
709 | this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
710 | }
711 | },
712 |
713 | // Convert a route string into a regular expression, suitable for matching
714 | // against the current location hash.
715 | _routeToRegExp : function(route) {
716 | route = route.replace(escapeRegExp, "\\$&")
717 | .replace(namedParam, "([^\/]*)")
718 | .replace(splatParam, "(.*?)");
719 | return new RegExp('^' + route + '$');
720 | },
721 |
722 | // Given a route, and a URL fragment that it matches, return the array of
723 | // extracted parameters.
724 | _extractParameters : function(route, fragment) {
725 | return route.exec(fragment).slice(1);
726 | }
727 |
728 | });
729 |
730 | // Backbone.History
731 | // ----------------
732 |
733 | // Handles cross-browser history management, based on URL fragments. If the
734 | // browser does not support `onhashchange`, falls back to polling.
735 | Backbone.History = function() {
736 | this.handlers = [];
737 | _.bindAll(this, 'checkUrl');
738 | };
739 |
740 | // Cached regex for cleaning hashes.
741 | var hashStrip = /^#*/;
742 |
743 | // Cached regex for detecting MSIE.
744 | var isExplorer = /msie [\w.]+/;
745 |
746 | // Has the history handling already been started?
747 | var historyStarted = false;
748 |
749 | // Set up all inheritable **Backbone.History** properties and methods.
750 | _.extend(Backbone.History.prototype, {
751 |
752 | // The default interval to poll for hash changes, if necessary, is
753 | // twenty times a second.
754 | interval: 50,
755 |
756 | // Get the cross-browser normalized URL fragment, either from the URL,
757 | // the hash, or the override.
758 | getFragment : function(fragment, forcePushState) {
759 | if (fragment == null) {
760 | if (this._hasPushState || forcePushState) {
761 | fragment = window.location.pathname;
762 | var search = window.location.search;
763 | if (search) fragment += search;
764 | if (fragment.indexOf(this.options.root) == 0) fragment = fragment.substr(this.options.root.length);
765 | } else {
766 | fragment = window.location.hash;
767 | }
768 | }
769 | return decodeURIComponent(fragment.replace(hashStrip, ''));
770 | },
771 |
772 | // Start the hash change handling, returning `true` if the current URL matches
773 | // an existing route, and `false` otherwise.
774 | start : function(options) {
775 |
776 | // Figure out the initial configuration. Do we need an iframe?
777 | // Is pushState desired ... is it available?
778 | if (historyStarted) throw new Error("Backbone.history has already been started");
779 | this.options = _.extend({}, {root: '/'}, this.options, options);
780 | this._wantsPushState = !!this.options.pushState;
781 | this._hasPushState = !!(this.options.pushState && window.history && window.history.pushState);
782 | var fragment = this.getFragment();
783 | var docMode = document.documentMode;
784 | var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
785 | if (oldIE) {
786 | this.iframe = $('').hide().appendTo('body')[0].contentWindow;
787 | this.navigate(fragment);
788 | }
789 |
790 | // Depending on whether we're using pushState or hashes, and whether
791 | // 'onhashchange' is supported, determine how we check the URL state.
792 | if (this._hasPushState) {
793 | $(window).bind('popstate', this.checkUrl);
794 | } else if ('onhashchange' in window && !oldIE) {
795 | $(window).bind('hashchange', this.checkUrl);
796 | } else {
797 | setInterval(this.checkUrl, this.interval);
798 | }
799 |
800 | // Determine if we need to change the base url, for a pushState link
801 | // opened by a non-pushState browser.
802 | this.fragment = fragment;
803 | historyStarted = true;
804 | var loc = window.location;
805 | var atRoot = loc.pathname == this.options.root;
806 | if (this._wantsPushState && !this._hasPushState && !atRoot) {
807 | this.fragment = this.getFragment(null, true);
808 | window.location.replace(this.options.root + '#' + this.fragment);
809 | // Return immediately as browser will do redirect to new url
810 | return true;
811 | } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
812 | this.fragment = loc.hash.replace(hashStrip, '');
813 | window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
814 | }
815 |
816 | if (!this.options.silent) {
817 | return this.loadUrl();
818 | }
819 | },
820 |
821 | // Add a route to be tested when the fragment changes. Routes added later may
822 | // override previous routes.
823 | route : function(route, callback) {
824 | this.handlers.unshift({route : route, callback : callback});
825 | },
826 |
827 | // Checks the current URL to see if it has changed, and if it has,
828 | // calls `loadUrl`, normalizing across the hidden iframe.
829 | checkUrl : function(e) {
830 | var current = this.getFragment();
831 | if (current == this.fragment && this.iframe) current = this.getFragment(this.iframe.location.hash);
832 | if (current == this.fragment || current == decodeURIComponent(this.fragment)) return false;
833 | if (this.iframe) this.navigate(current);
834 | this.loadUrl() || this.loadUrl(window.location.hash);
835 | },
836 |
837 | // Attempt to load the current URL fragment. If a route succeeds with a
838 | // match, returns `true`. If no defined routes matches the fragment,
839 | // returns `false`.
840 | loadUrl : function(fragmentOverride) {
841 | var fragment = this.fragment = this.getFragment(fragmentOverride);
842 | var matched = _.any(this.handlers, function(handler) {
843 | if (handler.route.test(fragment)) {
844 | handler.callback(fragment);
845 | return true;
846 | }
847 | });
848 | return matched;
849 | },
850 |
851 | // Save a fragment into the hash history. You are responsible for properly
852 | // URL-encoding the fragment in advance. This does not trigger
853 | // a `hashchange` event.
854 | navigate : function(fragment, triggerRoute) {
855 | var frag = (fragment || '').replace(hashStrip, '');
856 | if (this.fragment == frag || this.fragment == decodeURIComponent(frag)) return;
857 | if (this._hasPushState) {
858 | var loc = window.location;
859 | if (frag.indexOf(this.options.root) != 0) frag = this.options.root + frag;
860 | this.fragment = frag;
861 | window.history.pushState({}, document.title, loc.protocol + '//' + loc.host + frag);
862 | } else {
863 | window.location.hash = this.fragment = frag;
864 | if (this.iframe && (frag != this.getFragment(this.iframe.location.hash))) {
865 | this.iframe.document.open().close();
866 | this.iframe.location.hash = frag;
867 | }
868 | }
869 | if (triggerRoute) this.loadUrl(fragment);
870 | }
871 |
872 | });
873 |
874 | // Backbone.View
875 | // -------------
876 |
877 | // Creating a Backbone.View creates its initial element outside of the DOM,
878 | // if an existing element is not provided...
879 | Backbone.View = function(options) {
880 | this.cid = _.uniqueId('view');
881 | this._configure(options || {});
882 | this._ensureElement();
883 | this.delegateEvents();
884 | this.initialize.apply(this, arguments);
885 | };
886 |
887 | // Element lookup, scoped to DOM elements within the current view.
888 | // This should be prefered to global lookups, if you're dealing with
889 | // a specific view.
890 | var selectorDelegate = function(selector) {
891 | return $(selector, this.el);
892 | };
893 |
894 | // Cached regex to split keys for `delegate`.
895 | var eventSplitter = /^(\S+)\s*(.*)$/;
896 |
897 | // List of view options to be merged as properties.
898 | var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];
899 |
900 | // Set up all inheritable **Backbone.View** properties and methods.
901 | _.extend(Backbone.View.prototype, Backbone.Events, {
902 |
903 | // The default `tagName` of a View's element is `"div"`.
904 | tagName : 'div',
905 |
906 | // Attach the `selectorDelegate` function as the `$` property.
907 | $ : selectorDelegate,
908 |
909 | // Initialize is an empty function by default. Override it with your own
910 | // initialization logic.
911 | initialize : function(){},
912 |
913 | // **render** is the core function that your view should override, in order
914 | // to populate its element (`this.el`), with the appropriate HTML. The
915 | // convention is for **render** to always return `this`.
916 | render : function() {
917 | return this;
918 | },
919 |
920 | // Remove this view from the DOM. Note that the view isn't present in the
921 | // DOM by default, so calling this method may be a no-op.
922 | remove : function() {
923 | $(this.el).remove();
924 | return this;
925 | },
926 |
927 | // For small amounts of DOM Elements, where a full-blown template isn't
928 | // needed, use **make** to manufacture elements, one at a time.
929 | //
930 | // var el = this.make('li', {'class': 'row'}, this.model.escape('title'));
931 | //
932 | make : function(tagName, attributes, content) {
933 | var el = document.createElement(tagName);
934 | if (attributes) $(el).attr(attributes);
935 | if (content) $(el).html(content);
936 | return el;
937 | },
938 |
939 | // Set callbacks, where `this.callbacks` is a hash of
940 | //
941 | // *{"event selector": "callback"}*
942 | //
943 | // {
944 | // 'mousedown .title': 'edit',
945 | // 'click .button': 'save'
946 | // }
947 | //
948 | // pairs. Callbacks will be bound to the view, with `this` set properly.
949 | // Uses event delegation for efficiency.
950 | // Omitting the selector binds the event to `this.el`.
951 | // This only works for delegate-able events: not `focus`, `blur`, and
952 | // not `change`, `submit`, and `reset` in Internet Explorer.
953 | delegateEvents : function(events) {
954 | if (!(events || (events = this.events))) return;
955 | if (_.isFunction(events)) events = events.call(this);
956 | $(this.el).unbind('.delegateEvents' + this.cid);
957 | for (var key in events) {
958 | var method = this[events[key]];
959 | if (!method) throw new Error('Event "' + events[key] + '" does not exist');
960 | var match = key.match(eventSplitter);
961 | var eventName = match[1], selector = match[2];
962 | method = _.bind(method, this);
963 | eventName += '.delegateEvents' + this.cid;
964 | if (selector === '') {
965 | $(this.el).bind(eventName, method);
966 | } else {
967 | $(this.el).delegate(selector, eventName, method);
968 | }
969 | }
970 | },
971 |
972 | // Performs the initial configuration of a View with a set of options.
973 | // Keys with special meaning *(model, collection, id, className)*, are
974 | // attached directly to the view.
975 | _configure : function(options) {
976 | if (this.options) options = _.extend({}, this.options, options);
977 | for (var i = 0, l = viewOptions.length; i < l; i++) {
978 | var attr = viewOptions[i];
979 | if (options[attr]) this[attr] = options[attr];
980 | }
981 | this.options = options;
982 | },
983 |
984 | // Ensure that the View has a DOM element to render into.
985 | // If `this.el` is a string, pass it through `$()`, take the first
986 | // matching element, and re-assign it to `el`. Otherwise, create
987 | // an element from the `id`, `className` and `tagName` proeprties.
988 | _ensureElement : function() {
989 | if (!this.el) {
990 | var attrs = this.attributes || {};
991 | if (this.id) attrs.id = this.id;
992 | if (this.className) attrs['class'] = this.className;
993 | this.el = this.make(this.tagName, attrs);
994 | } else if (_.isString(this.el)) {
995 | this.el = $(this.el).get(0);
996 | }
997 | }
998 |
999 | });
1000 |
1001 | // The self-propagating extend function that Backbone classes use.
1002 | var extend = function (protoProps, classProps) {
1003 | var child = inherits(this, protoProps, classProps);
1004 | child.extend = this.extend;
1005 | return child;
1006 | };
1007 |
1008 | // Set up inheritance for the model, collection, and view.
1009 | Backbone.Model.extend = Backbone.Collection.extend =
1010 | Backbone.Router.extend = Backbone.View.extend = extend;
1011 |
1012 | // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
1013 | var methodMap = {
1014 | 'create': 'POST',
1015 | 'update': 'PUT',
1016 | 'delete': 'DELETE',
1017 | 'read' : 'GET'
1018 | };
1019 |
1020 | // Backbone.sync
1021 | // -------------
1022 |
1023 | // Override this function to change the manner in which Backbone persists
1024 | // models to the server. You will be passed the type of request, and the
1025 | // model in question. By default, uses makes a RESTful Ajax request
1026 | // to the model's `url()`. Some possible customizations could be:
1027 | //
1028 | // * Use `setTimeout` to batch rapid-fire updates into a single request.
1029 | // * Send up the models as XML instead of JSON.
1030 | // * Persist models via WebSockets instead of Ajax.
1031 | //
1032 | // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
1033 | // as `POST`, with a `_method` parameter containing the true HTTP method,
1034 | // as well as all requests with the body as `application/x-www-form-urlencoded` instead of
1035 | // `application/json` with the model in a param named `model`.
1036 | // Useful when interfacing with server-side languages like **PHP** that make
1037 | // it difficult to read the body of `PUT` requests.
1038 | Backbone.sync = function(method, model, options) {
1039 | var type = methodMap[method];
1040 |
1041 | // Default JSON-request options.
1042 | var params = _.extend({
1043 | type: type,
1044 | dataType: 'json'
1045 | }, options);
1046 |
1047 | // Ensure that we have a URL.
1048 | if (!params.url) {
1049 | params.url = getUrl(model) || urlError();
1050 | }
1051 |
1052 | // Ensure that we have the appropriate request data.
1053 | if (!params.data && model && (method == 'create' || method == 'update')) {
1054 | params.contentType = 'application/json';
1055 | params.data = JSON.stringify(model.toJSON());
1056 | }
1057 |
1058 | // For older servers, emulate JSON by encoding the request into an HTML-form.
1059 | if (Backbone.emulateJSON) {
1060 | params.contentType = 'application/x-www-form-urlencoded';
1061 | params.data = params.data ? {model : params.data} : {};
1062 | }
1063 |
1064 | // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
1065 | // And an `X-HTTP-Method-Override` header.
1066 | if (Backbone.emulateHTTP) {
1067 | if (type === 'PUT' || type === 'DELETE') {
1068 | if (Backbone.emulateJSON) params.data._method = type;
1069 | params.type = 'POST';
1070 | params.beforeSend = function(xhr) {
1071 | xhr.setRequestHeader('X-HTTP-Method-Override', type);
1072 | };
1073 | }
1074 | }
1075 |
1076 | // Don't process data on a non-GET request.
1077 | if (params.type !== 'GET' && !Backbone.emulateJSON) {
1078 | params.processData = false;
1079 | }
1080 |
1081 | // Make the request.
1082 | return $.ajax(params);
1083 | };
1084 |
1085 | // Helpers
1086 | // -------
1087 |
1088 | // Shared empty constructor function to aid in prototype-chain creation.
1089 | var ctor = function(){};
1090 |
1091 | // Helper function to correctly set up the prototype chain, for subclasses.
1092 | // Similar to `goog.inherits`, but uses a hash of prototype properties and
1093 | // class properties to be extended.
1094 | var inherits = function(parent, protoProps, staticProps) {
1095 | var child;
1096 |
1097 | // The constructor function for the new subclass is either defined by you
1098 | // (the "constructor" property in your `extend` definition), or defaulted
1099 | // by us to simply call `super()`.
1100 | if (protoProps && protoProps.hasOwnProperty('constructor')) {
1101 | child = protoProps.constructor;
1102 | } else {
1103 | child = function(){ return parent.apply(this, arguments); };
1104 | }
1105 |
1106 | // Inherit class (static) properties from parent.
1107 | _.extend(child, parent);
1108 |
1109 | // Set the prototype chain to inherit from `parent`, without calling
1110 | // `parent`'s constructor function.
1111 | ctor.prototype = parent.prototype;
1112 | child.prototype = new ctor();
1113 |
1114 | // Add prototype properties (instance properties) to the subclass,
1115 | // if supplied.
1116 | if (protoProps) _.extend(child.prototype, protoProps);
1117 |
1118 | // Add static properties to the constructor function, if supplied.
1119 | if (staticProps) _.extend(child, staticProps);
1120 |
1121 | // Correctly set child's `prototype.constructor`.
1122 | child.prototype.constructor = child;
1123 |
1124 | // Set a convenience property in case the parent's prototype is needed later.
1125 | child.__super__ = parent.prototype;
1126 |
1127 | return child;
1128 | };
1129 |
1130 | // Helper function to get a URL from a Model or Collection as a property
1131 | // or as a function.
1132 | var getUrl = function(object) {
1133 | if (!(object && object.url)) return null;
1134 | return _.isFunction(object.url) ? object.url() : object.url;
1135 | };
1136 |
1137 | // Throw an error when a URL is needed, and none is supplied.
1138 | var urlError = function() {
1139 | throw new Error('A "url" property or function must be specified');
1140 | };
1141 |
1142 | // Wrap an optional error callback with a fallback error event.
1143 | var wrapError = function(onError, model, options) {
1144 | return function(resp) {
1145 | if (onError) {
1146 | onError(model, resp, options);
1147 | } else {
1148 | model.trigger('error', model, resp, options);
1149 | }
1150 | };
1151 | };
1152 |
1153 | // Helper function to escape a string for HTML rendering.
1154 | var escapeHTML = function(string) {
1155 | return string.replace(/&(?!\w+;|#\d+;|#x[\da-f]+;)/gi, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/');
1156 | };
1157 |
1158 | }).call(this);
--------------------------------------------------------------------------------
/Resources/test-backup/traversing.js:
--------------------------------------------------------------------------------
1 | (function () {
2 |
3 | // To learn how to write Jasmine tests, please read Jasmine documentation:
4 | // https://github.com/pivotal/jasmine/wiki
5 | // ok
6 | //^\s*ok\(\s*([^,]+),\s*["]([^"]+)["]\s*\);
7 | //it("\2", function(){ expect(\1).toBeDefined(); });
8 | // equals
9 | //^\s*equals\(\s*([^,]+),\s*([^,]+),\s*["]([^"]+)["]\s*\);
10 | //it("\3", function(){ expect(\1).toEqual(\2); });
11 | // same
12 | //^\s*same\(\s*([^,]+),\s*([^,]+),\s*["]([^"]+)["]\s*\);
13 | //it("\3", function(){ expect(\1).toBeSameTiElementsAs(\2); });
14 | beforeEach(function () {
15 | //Ti.API.log('winchildren', win.children);
16 | this.addMatchers({
17 | toBeSameTiElementsAs: function (els) {
18 |
19 | function getUUID(el) {
20 | return el._uuid;
21 | }
22 |
23 | var thisStr = (Array.isArray(this.actual) ? this.actual : [this.actual]).map(getUUID).join(', '),
24 | compStr = (Array.isArray(els) ? els : [els]).map(getUUID).join(', ');
25 |
26 | return thisStr === compStr;
27 | }
28 | });
29 |
30 | var els = [];
31 | Object.keys(K.elsByName).forEach(function (key) {
32 | els.concat(K.elsByName[key] || []);
33 | });
34 | els.forEach(function (el) {
35 | el.getParent().remove(el);
36 | });
37 |
38 | K.reset();
39 | });
40 |
41 | describe('Traversing', function () {
42 |
43 | var testViewBlueprint = {
44 | type: 'view',
45 | id: 'main',
46 | children: [{
47 | type: 'view',
48 | id: 'foo',
49 | children: [{
50 | type: 'label',
51 | text: 'Yahoo',
52 | id: 'blogTest',
53 | className: 'blogTest',
54 | children: [{
55 | type: 'label',
56 | className: 'subLabel',
57 | text: 'subLabel'
58 | }]
59 | }]
60 | }, {
61 | type: 'view',
62 | id: 'moretests'
63 | }]
64 | };
65 |
66 |
67 | describe("find(String)", function () {
68 |
69 | it("Check for find", function () {
70 | K(testViewBlueprint).appendTo(win);
71 | expect(K('#foo').find('.blogTest').text()).toEqual('Yahoo');
72 | });
73 |
74 | it("find direct child elements", function () {
75 | K(testViewBlueprint).appendTo(win);
76 | expect(K("#foo").find("> label").get()).toBeSameTiElementsAs(q("blogTest"));
77 | });
78 |
79 | /*it("find direct child elements, twin selector", function () {
80 | K(testViewBlueprint).appendTo(win);
81 | expect(K("#main").find("> #foo, > #moretests").get()).toBeSameTiElementsAs(q("foo", "moretests"));
82 | });*/
83 |
84 | it("find direct children och direct child", function () {
85 | expect(K("#main").find("> #foo > label").get()).toBeSameTiElementsAs(q("blogTest"));
86 | });
87 |
88 | });
89 |
90 | // Won't support this for now
91 | /*
92 | describe("find(node|K object)", function () {
93 |
94 | var $foo = K('#foo'),
95 | $blog = K('.blogTest'),
96 | $first = K('#first'),
97 | $two = $blog.add($first),
98 | $fooTwo = $foo.add($blog);
99 |
100 | it("Find with blog K object", function () {
101 | expect($foo.find($blog).text()).toEqual('Yahoo');
102 | });
103 |
104 | return;
105 | it("Find with blog node", function () {
106 | expect($foo.find($blog[0]).text()).toEqual('Yahoo');
107 | });
108 | it("#first is not in #foo", function () {
109 | expect($foo.find($first).length).toEqual(0);
110 | });
111 | it("#first not in #foo (node)", function () {
112 | expect($foo.find($first[0]).length).toEqual(0);
113 | });
114 | it('Find returns only nodes within #foo', function () {
115 | expect($foo.find($two).is('.blogTest')).toBeTruthy();
116 | });
117 | it('Blog is part of the collection, but also within foo', function () {
118 | expect($fooTwo.find($blog).is('.blogTest')).toBeTruthy();
119 | });
120 | it('Blog is part of the collection, but also within foo(node)', function () {
121 | expect($fooTwo.find($blog[0]).is('.blogTest')).toBeTruthy();
122 | });
123 | it("Foo is not in two elements", function () {
124 | expect($two.find($foo).length).toEqual(0);
125 | });
126 | it("Foo is not in two elements(node)", function () {
127 | expect($two.find($foo[0]).length).toEqual(0);
128 | });
129 | it("first is in the collection and not within two", function () {
130 | expect($two.find($first).length).toEqual(0);
131 | });
132 | it("first is in the collection and not within two(node)", function () {
133 | expect($two.find($first).length).toEqual(0);
134 | });
135 |
136 | });*/
137 |
138 | describe("is(String|undefined)", function () {
139 | it('Check for element: A label must be a label', function () {
140 | K({ type: 'label', id: 'isLabel' }).appendTo(win);
141 | expect(K('#isLabel').is('label')).toBeTruthy();
142 | });
143 |
144 | it('Check for element: A label is not a button', function () {
145 | K({ type: 'label', id: 'isLabel' }).appendTo(win);
146 | expect(K('#isLabel').is('button')).toBeFalsy();
147 | });
148 |
149 | it('Check for class: Expected class "isLabel"', function () {
150 | K({ type: 'label', id: 'isLabel', className: 'isLabel' }).appendTo(win);
151 | expect(K('#isLabel').is('.isLabel')).toBeTruthy();
152 | });
153 |
154 | it('Check for class: Did not expect class "isButton"', function () {
155 | K({ type: 'label', id: 'isLabel', className: 'isLabel' }).appendTo(win);
156 | expect(K('#isLabel').is('.isButton')).toBeFalsy();
157 | });
158 |
159 | // Fix multi class selector - this is a false friend atm
160 | it('Check for multiple classes: Expected classes "isLabel" and "isPretty"', function () {
161 | K({ type: 'label', id: 'isLabel', className: 'isLabel isPretty' }).appendTo(win);
162 | expect(K('#isLabel').is('.isLabel.isPretty')).toBeTruthy();
163 | });
164 |
165 | it('Check for multiple classes: Expected classes "isLabel" and "isPretty", but not "isButton"', function () {
166 | K({ type: 'label', id: 'isLabel', className: 'isLabel isPretty' }).appendTo(win);
167 | expect(K('#isLabel').is('.isButton')).toBeFalsy();
168 | });
169 |
170 | return; // Quick return before adapting tests below
171 |
172 | it('Check for attribute: Expected attribute lang to be "en"', function () {
173 | K({ type: 'label', id: 'lang', lang: 'en' }).appendTo(win);
174 | expect(K('#lang').is('[lang="en"]')).toBeTruthy();
175 | });
176 |
177 | it('Check for attribute: Expected attribute lang to be "en", not "de"', function () {
178 | K({ type: 'label', id: 'lang', lang: 'en' }).appendTo(win);
179 | expect(K('#lang').is('[lang="de"]')).toBeFalsy();
180 | });
181 |
182 | it('Check for attribute: Expected attribute type to be "text"', function () {
183 | expect(K('#isLabel').is('[type="text"]')).toBeTruthy();
184 | });
185 |
186 | it('Check for attribute: Expected attribute type to be "text", not "radio"', function () {
187 | expect(!K('#text1').is('[type="radio"]')).toBeTruthy();
188 | });
189 | it('Check for pseudoclass: Expected to be disabled', function () {
190 | expect(K('#text2').is(':disabled')).toBeTruthy();
191 | });
192 |
193 | it('Check for pseudoclass: Expected not disabled', function () {
194 | expect(!K('#text1').is(':disabled')).toBeTruthy();
195 | });
196 |
197 | it('Check for pseudoclass: Expected to be checked', function () {
198 | expect(K('#radio2').is(':checked')).toBeTruthy();
199 | });
200 |
201 | it('Check for pseudoclass: Expected not checked', function () {
202 | expect(!K('#radio1').is(':checked')).toBeTruthy();
203 | });
204 |
205 | it('Check for child: Expected a child "p" element', function () {
206 | expect(K('#foo').is(':has(p)')).toBeTruthy();
207 | });
208 |
209 | it('Check for child: Did not expect "ul" element', function () {
210 | expect(!K('#foo').is(':has(ul)')).toBeTruthy();
211 | });
212 |
213 | it('Check for childs: Expected "p", "a" and "code" child elements', function () {
214 | expect(K('#foo').is(':has(p):has(a):has(code)')).toBeTruthy();
215 | });
216 |
217 | it('Check for childs: Expected "p", "a" and "code" child elements, but no "ol"', function () {
218 | expect(!K('#foo').is(':has(p):has(a):has(code):has(ol)')).toBeTruthy();
219 | });
220 |
221 | it('Expected false for an invalid expression - 0', function () {
222 | expect(!K('#foo').is(0)).toBeTruthy();
223 | });
224 |
225 | it('Expected false for an invalid expression - null', function () {
226 | expect(!K('#foo').is(null)).toBeTruthy();
227 | });
228 |
229 | it('Expected false for an invalid expression - ""', function () {
230 | expect(!K('#foo').is('')).toBeTruthy();
231 | });
232 |
233 | it('Expected false for an invalid expression - undefined', function () {
234 | expect(!K('#foo').is(undefined)).toBeTruthy();
235 | });
236 |
237 | it('Check passing invalid object', function () {
238 | expect(!K('#foo').is({
239 | plain: "object"
240 | })).toBeTruthy();
241 | });
242 |
243 | // test is() with comma-seperated expressions
244 | /*ok(K('#en').is('[lang="en"],[lang="de"]'), 'Comma-seperated; Check for lang attribute: Expect en or de');
245 | ok(K('#en').is('[lang="de"],[lang="en"]'), 'Comma-seperated; Check for lang attribute: Expect en or de');
246 | ok(K('#en').is('[lang="en"] , [lang="de"]'), 'Comma-seperated; Check for lang attribute: Expect en or de');
247 | ok(K('#en').is('[lang="de"] , [lang="en"]'), 'Comma-seperated; Check for lang attribute: Expect en or de');*/
248 | });
249 |
250 | return; // Tests below not adapted yet
251 |
252 | describe("is(K)", function () {
253 | it('Check for element: A form is a form', function () {
254 | expect(K('#form').is(K('form'))).toBeTruthy();
255 | });
256 | it('Check for element: A form is not a div', function () {
257 | expect(!K('#form').is(K('div'))).toBeTruthy();
258 | });
259 | it('Check for class: Expected class "blog"', function () {
260 | expect(K('#mark').is(K('.blog'))).toBeTruthy();
261 | });
262 | it('Check for class: Did not expect class "link"', function () {
263 | expect(!K('#mark').is(K('.link'))).toBeTruthy();
264 | });
265 | it('Check for multiple classes: Expected classes "blog" and "link"', function () {
266 | expect(K('#simon').is(K('.blog.link'))).toBeTruthy();
267 | });
268 | it('Check for multiple classes: Expected classes "blog" and "link", but not "blogTest"', function () {
269 | expect(!K('#simon').is(K('.blogTest'))).toBeTruthy();
270 | });
271 | it('Check for attribute: Expected attribute lang to be "en"', function () {
272 | expect(K('#en').is(K('[lang="en"]'))).toBeTruthy();
273 | });
274 | it('Check for attribute: Expected attribute lang to be "en", not "de"', function () {
275 | expect(!K('#en').is(K('[lang="de"]'))).toBeTruthy();
276 | });
277 | it('Check for attribute: Expected attribute type to be "text"', function () {
278 | expect(K('#text1').is(K('[type="text"]'))).toBeTruthy();
279 | });
280 | it('Check for attribute: Expected attribute type to be "text", not "radio"', function () {
281 | expect(!K('#text1').is(K('[type="radio"]'))).toBeTruthy();
282 | });
283 | it('Check for pseudoclass: Expected not disabled', function () {
284 | expect(!K('#text1').is(K(':disabled'))).toBeTruthy();
285 | });
286 | it('Check for pseudoclass: Expected to be checked', function () {
287 | expect(K('#radio2').is(K(':checked'))).toBeTruthy();
288 | });
289 | it('Check for pseudoclass: Expected not checked', function () {
290 | expect(!K('#radio1').is(K(':checked'))).toBeTruthy();
291 | });
292 | it('Check for child: Expected a child "p" element', function () {
293 | expect(K('#foo').is(K(':has(p)'))).toBeTruthy();
294 | });
295 | it('Check for child: Did not expect "ul" element', function () {
296 | expect(!K('#foo').is(K(':has(ul)'))).toBeTruthy();
297 | });
298 | it('Check for childs: Expected "p", "a" and "code" child elements', function () {
299 | expect(K('#foo').is(K(':has(p):has(a):has(code)'))).toBeTruthy();
300 | });
301 | it('Check for childs: Expected "p", "a" and "code" child elements, but no "ol"', function () {
302 | expect(!K('#foo').is(K(':has(p):has(a):has(code):has(ol)'))).toBeTruthy();
303 | });
304 |
305 | // Some raw elements
306 | it('Check for element: A form is a form', function () {
307 | expect(K('#form').is(K('form')[0])).toBeTruthy();
308 | });
309 | it('Check for element: A form is not a div', function () {
310 | expect(!K('#form').is(K('div')[0])).toBeTruthy();
311 | });
312 | it('Check for class: Expected class "blog"', function () {
313 | expect(K('#mark').is(K('.blog')[0])).toBeTruthy();
314 | });
315 | it('Check for class: Did not expect class "link"', function () {
316 | expect(!K('#mark').is(K('.link')[0])).toBeTruthy();
317 | });
318 | it('Check for multiple classes: Expected classes "blog" and "link"', function () {
319 | expect(K('#simon').is(K('.blog.link')[0])).toBeTruthy();
320 | });
321 | it('Check for multiple classes: Expected classes "blog" and "link", but not "blogTest"', function () {
322 | expect(!K('#simon').is(K('.blogTest')[0])).toBeTruthy();
323 | });
324 | });
325 |
326 | describe("index()", function () {
327 |
328 |
329 | equals(K("#text2").index(), 2, "Returns the index of a child amongst its siblings")
330 | });
331 |
332 | describe("index(Object|String|undefined)", function () {
333 |
334 |
335 | var elements = K([window, document]),
336 | inputElements = K('#radio1,#radio2,#check1,#check2');
337 |
338 | // Passing a node
339 | it("Check for index of elements", function () {
340 | expect(elements.index(window)).toEqual(0);
341 | });
342 | it("Check for index of elements", function () {
343 | expect(elements.index(document)).toEqual(1);
344 | });
345 | it("Check for index of elements", function () {
346 | expect(inputElements.index(document.getElementById('radio1'))).toEqual(0);
347 | });
348 | it("Check for index of elements", function () {
349 | expect(inputElements.index(document.getElementById('radio2'))).toEqual(1);
350 | });
351 | it("Check for index of elements", function () {
352 | expect(inputElements.index(document.getElementById('check1'))).toEqual(2);
353 | });
354 | it("Check for index of elements", function () {
355 | expect(inputElements.index(document.getElementById('check2'))).toEqual(3);
356 | });
357 | it("Check for not found index", function () {
358 | expect(inputElements.index(window)).toEqual(-1);
359 | });
360 | it("Check for not found index", function () {
361 | expect(inputElements.index(document)).toEqual(-1);
362 | });
363 |
364 | // Passing a K object
365 | // enabled since [5500]
366 | it("Pass in a K object", function () {
367 | expect(elements.index(elements)).toEqual(0);
368 | });
369 | it("Pass in a K object", function () {
370 | expect(elements.index(elements.eq(1))).toEqual(1);
371 | });
372 | it("Pass in a K object", function () {
373 | expect(K("#form :radio").index(K("#radio2"))).toEqual(1);
374 | });
375 |
376 | // Passing a selector or nothing
377 | // enabled since [6330]
378 | it("Check for index amongst siblings", function () {
379 | expect(K('#text2').index()).toEqual(2);
380 | });
381 | it("Check for index amongst siblings", function () {
382 | expect(K('#form').children().eq(4).index()).toEqual(4);
383 | });
384 | it("Check for index within a selector", function () {
385 | expect(K('#radio2').index('#form :radio')).toEqual(1);
386 | });
387 | it("Check for index within a selector", function () {
388 | expect(K('#form :radio').index(K('#radio2'))).toEqual(1);
389 | });
390 | it("Check for index not found within a selector", function () {
391 | expect(K('#radio2').index('#form :text')).toEqual(-1);
392 | });
393 | });
394 |
395 | describe("filter(Selector|undefined)", function () {
396 |
397 | same(K("#form input").filter(":checked").get(), q("radio2", "check1"), "filter(String)");
398 | same(K("p").filter("#ap, #sndp").get(), q("ap", "sndp"), "filter('String, String')");
399 | same(K("p").filter("#ap,#sndp").get(), q("ap", "sndp"), "filter('String,String')");
400 | it("filter(null) should return an empty K object", function () {
401 | expect(K('p').filter(null).get()).toBeSameTiElementsAs([]);
402 | });
403 | it("filter(undefined) should return an empty K object", function () {
404 | expect(K('p').filter(undefined).get()).toBeSameTiElementsAs([]);
405 | });
406 | it("filter(0) should return an empty K object", function () {
407 | expect(K('p').filter(0).get()).toBeSameTiElementsAs([]);
408 | });
409 | it("filter('') should return an empty K object", function () {
410 | expect(K('p').filter('').get()).toBeSameTiElementsAs([]);
411 | });
412 |
413 | // using contents will get comments regular, text, and comment nodes
414 | var j = K("#nonnodes").contents();
415 | it("Check node,textnode,comment to filter the one span", function () {
416 | expect(j.filter("span").length).toEqual(1);
417 | });
418 | it("Check node,textnode,comment to filter the one span", function () {
419 | expect(j.filter("[name]").length).toEqual(0);
420 | });
421 | });
422 |
423 | describe("filter(Function)", function () {
424 |
425 |
426 | same(K("#main p").filter(function () {
427 | return !K("a", this).length
428 | }).get(), q("sndp", "first"), "filter(Function)");
429 |
430 | same(K("#main p").filter(function (i, elem) {
431 | return !K("a", elem).length
432 | }).get(), q("sndp", "first"), "filter(Function) using arg");
433 | });
434 |
435 | describe("filter(Element)", function () {
436 |
437 |
438 | var element = document.getElementById("text1");
439 | it("filter(Element)", function () {
440 | expect(K("#form input").filter(element).get()).toBeSameTiElementsAs(q("text1"));
441 | });
442 | });
443 |
444 | describe("filter(Array)", function () {
445 |
446 |
447 | var elements = [document.getElementById("text1")];
448 | it("filter(Element)", function () {
449 | expect(K("#form input").filter(elements).get()).toBeSameTiElementsAs(q("text1"));
450 | });
451 | });
452 |
453 | describe("filter(K)", function () {
454 |
455 |
456 | var elements = K("#text1");
457 | it("filter(Element)", function () {
458 | expect(K("#form input").filter(elements).get()).toBeSameTiElementsAs(q("text1"));
459 | });
460 | })
461 |
462 | describe("closest()", function () {
463 |
464 | it("closest(body)", function () {
465 | expect(K("body").closest("body").get()).toBeSameTiElementsAs(q("body"));
466 | });
467 | it("closest(html)", function () {
468 | expect(K("body").closest("html").get()).toBeSameTiElementsAs(q("html"));
469 | });
470 | it("closest(div)", function () {
471 | expect(K("body").closest("div").get()).toBeSameTiElementsAs([]);
472 | });
473 | same(K("#main").closest("span,#html").get(), q("html"), "closest(span,#html)");
474 | it("closest(div:first)", function () {
475 | expect(K("div:eq(1)").closest("div:first").get()).toBeSameTiElementsAs([]);
476 | });
477 | it("closest(body:first div:last)", function () {
478 | expect(K("div").closest("body:first div:last").get()).toBeSameTiElementsAs(q("fx-tests"));
479 | });
480 |
481 | // Test .closest() limited by the context
482 | var jq = K("#nothiddendivchild");
483 | same(jq.closest("html", document.body).get(), [], "Context limited.");
484 | same(jq.closest("body", document.body).get(), [], "Context limited.");
485 | same(jq.closest("#nothiddendiv", document.body).get(), q("nothiddendiv"), "Context not reached.");
486 |
487 | //Test that .closest() returns unique'd set
488 | it("Closest should return a unique set", function () {
489 | expect(K('#main p').closest('#main').length).toEqual(1);
490 | });
491 |
492 | // Test on disconnected node
493 | it("Make sure disconnected closest work.", function () {
494 | expect(K("
").find("p").closest("table").length).toEqual(0);
495 | });
496 |
497 | // Bug #7369
498 | it("Disconnected nodes with attribute selector", function () {
499 | expect(K('').closest('[foo]').length).toEqual(1);
500 | });
501 | it("Disconnected nodes with text and non-existent attribute selector", function () {
502 | expect(K('
text
').closest('[lang]').length).toEqual(0);
503 | });
504 | });
505 |
506 | describe("closest(Array)", function () {
507 |
508 | same(K("body").closest(["body"]), [{
509 | selector: "body",
510 | elem: document.body,
511 | level: 1
512 | }], "closest([body])");
513 | same(K("body").closest(["html"]), [{
514 | selector: "html",
515 | elem: document.documentElement,
516 | level: 2
517 | }], "closest([html])");
518 | it("closest([div])", function () {
519 | expect(K("body").closest(["div"])).toBeSameTiElementsAs([]);
520 | });
521 | same(K("#yahoo").closest(["div"]), [{
522 | "selector": "div",
523 | "elem": document.getElementById("foo"),
524 | "level": 3
525 | }, {
526 | "selector": "div",
527 | "elem": document.getElementById("main"),
528 | "level": 4
529 | }], "closest([div])");
530 | same(K("#main").closest(["span,#html"]), [{
531 | selector: "span,#html",
532 | elem: document.documentElement,
533 | level: 4
534 | }], "closest([span,#html])");
535 |
536 | same(K("body").closest(["body", "html"]), [{
537 | selector: "body",
538 | elem: document.body,
539 | level: 1
540 | }, {
541 | selector: "html",
542 | elem: document.documentElement,
543 | level: 2
544 | }], "closest([body, html])");
545 | same(K("body").closest(["span", "html"]), [{
546 | selector: "html",
547 | elem: document.documentElement,
548 | level: 2
549 | }], "closest([body, html])");
550 | });
551 |
552 | describe("closest(K)", function () {
553 |
554 | var $child = K("#nothiddendivchild"),
555 | $parent = K("#nothiddendiv"),
556 | $main = K("#main"),
557 | $body = K("body");
558 | it("closest( K('#nothiddendiv') )", function () {
559 | expect($child.closest($parent).is('#nothiddendiv')).toBeDefined();
560 | });
561 | it("closest( K('#nothiddendiv') ) :: node", function () {
562 | expect($child.closest($parent[0]).is('#nothiddendiv')).toBeDefined();
563 | });
564 | it("child is included", function () {
565 | expect($child.closest($child).is('#nothiddendivchild')).toBeDefined();
566 | });
567 | it("child is included :: node", function () {
568 | expect($child.closest($child[0]).is('#nothiddendivchild')).toBeDefined();
569 | });
570 | it("created element is not related", function () {
571 | expect($child.closest(document.createElement('div')).length).toEqual(0);
572 | });
573 | it("Main not a parent of child", function () {
574 | expect($child.closest($main).length).toEqual(0);
575 | });
576 | it("Main not a parent of child :: node", function () {
577 | expect($child.closest($main[0]).length).toEqual(0);
578 | });
579 | it("Closest ancestor retrieved.", function () {
580 | expect($child.closest($body.add($parent)).is('#nothiddendiv')).toBeDefined();
581 | });
582 | });
583 |
584 | describe("not(Selector|undefined)", function () {
585 |
586 | it("not('selector')", function () {
587 | expect(K("#main > p#ap > a").not("#google").length).toEqual(2);
588 | });
589 | same(K("p").not(".result").get(), q("firstp", "ap", "sndp", "en", "sap", "first"), "not('.class')");
590 | same(K("p").not("#ap, #sndp, .result").get(), q("firstp", "en", "sap", "first"), "not('selector, selector')");
591 | same(K("#form option").not("option.emptyopt:contains('Nothing'),[selected],[value='1']").get(), q("option1c", "option1d", "option2c", "option3d", "option3e", "option4e", "option5b"), "not('complex selector')");
592 |
593 | same(K('#ap *').not('code').get(), q("google", "groups", "anchor1", "mark"), "not('tag selector')");
594 | same(K('#ap *').not('code, #mark').get(), q("google", "groups", "anchor1"), "not('tag, ID selector')");
595 | same(K('#ap *').not('#mark, code').get(), q("google", "groups", "anchor1"), "not('ID, tag selector')");
596 |
597 | var all = K('p').get();
598 | it("not(null) should have no effect", function () {
599 | expect(K('p').not(null).get()).toBeSameTiElementsAs(all);
600 | });
601 | it("not(undefined) should have no effect", function () {
602 | expect(K('p').not(undefined).get()).toBeSameTiElementsAs(all);
603 | });
604 | it("not(0) should have no effect", function () {
605 | expect(K('p').not(0).get()).toBeSameTiElementsAs(all);
606 | });
607 | it("not('') should have no effect", function () {
608 | expect(K('p').not('').get()).toBeSameTiElementsAs(all);
609 | });
610 | });
611 |
612 | describe("not(Element)", function () {
613 |
614 |
615 | var selects = K("#form select");
616 | same(selects.not(selects[1]).get(), q("select1", "select3", "select4", "select5"), "filter out DOM element");
617 | });
618 |
619 | describe("not(Function)", function () {
620 | same(K("#main p").not(function () {
621 | return K("a", this).length
622 | }).get(), q("sndp", "first"), "not(Function)");
623 | });
624 |
625 | describe("not(Array)", function () {
626 |
627 | it("not(DOMElement)", function () {
628 | expect(K("#main > p#ap > a").not(document.getElementById("google")).length).toEqual(2);
629 | });
630 | it("not(Array-like DOM collection)", function () {
631 | expect(K("p").not(document.getElementsByTagName("p")).length).toEqual(0);
632 | });
633 | });
634 |
635 | describe("not(K)", function () {
636 |
637 |
638 | same(K("p").not(K("#ap, #sndp, .result")).get(), q("firstp", "en", "sap", "first"), "not(K)");
639 | });
640 |
641 | describe("has(Element)", function () {
642 |
643 |
644 | var obj = K("#main").has(K("#sndp")[0]);
645 | it("Keeps elements that have the element as a descendant", function () {
646 | expect(obj.get()).toBeSameTiElementsAs(q("main"));
647 | });
648 |
649 | var multipleParent = K("#main, #header").has(K("#sndp")[0]);
650 | it("Does not include elements that do not have the element as a descendant", function () {
651 | expect(obj.get()).toBeSameTiElementsAs(q("main"));
652 | });
653 | });
654 |
655 | describe("has(Selector)", function () {
656 |
657 |
658 | var obj = K("#main").has("#sndp");
659 | it("Keeps elements that have any element matching the selector as a descendant", function () {
660 | expect(obj.get()).toBeSameTiElementsAs(q("main"));
661 | });
662 |
663 | var multipleParent = K("#main, #header").has("#sndp");
664 | it("Does not include elements that do not have the element as a descendant", function () {
665 | expect(obj.get()).toBeSameTiElementsAs(q("main"));
666 | });
667 |
668 | var multipleHas = K("#main").has("#sndp, #first");
669 | it("Only adds elements once", function () {
670 | expect(multipleHas.get()).toBeSameTiElementsAs(q("main"));
671 | });
672 | });
673 |
674 | describe("has(Arrayish)", function () {
675 |
676 |
677 | var simple = K("#main").has(K("#sndp"));
678 | it("Keeps elements that have any element in the K list as a descendant", function () {
679 | expect(simple.get()).toBeSameTiElementsAs(q("main"));
680 | });
681 |
682 | var multipleParent = K("#main, #header").has(K("#sndp"));
683 | it("Does not include elements that do not have an element in the K list as a descendant", function () {
684 | expect(multipleParent.get()).toBeSameTiElementsAs(q("main"));
685 | });
686 |
687 | var multipleHas = K("#main").has(K("#sndp, #first"));
688 | it("Only adds elements once", function () {
689 | expect(simple.get()).toBeSameTiElementsAs(q("main"));
690 | });
691 | });
692 |
693 | describe("andSelf()", function () {
694 |
695 | same(K("#en").siblings().andSelf().get(), q("sndp", "en", "sap"), "Check for siblings and self");
696 | same(K("#foo").children().andSelf().get(), q("foo", "sndp", "en", "sap"), "Check for children and self");
697 | same(K("#sndp, #en").parent().andSelf().get(), q("foo", "sndp", "en"), "Check for parent and self");
698 | same(K("#groups").parents("p, div").andSelf().get(), q("main", "ap", "groups"), "Check for parents and self");
699 | });
700 |
701 | describe("siblings([String])", function () {
702 |
703 | same(K("#en").siblings().get(), q("sndp", "sap"), "Check for siblings");
704 | it("Check for filtered siblings (has code child element)", function () {
705 | expect(K("#sndp").siblings(":has(code)").get()).toBeSameTiElementsAs(q("sap"));
706 | });
707 | same(K("#sndp").siblings(":has(a)").get(), q("en", "sap"), "Check for filtered siblings (has anchor child element)");
708 | same(K("#foo").siblings("form, b").get(), q("form", "floatTest", "lengthtest", "name-tests", "testForm"), "Check for multiple filters");
709 | var set = q("sndp", "en", "sap");
710 | same(K("#en, #sndp").siblings().get(), set, "Check for unique results from siblings");
711 | });
712 |
713 | describe("children([String])", function () {
714 |
715 | same(K("#foo").children().get(), q("sndp", "en", "sap"), "Check for children");
716 | same(K("#foo").children(":has(code)").get(), q("sndp", "sap"), "Check for filtered children");
717 | same(K("#foo").children("#en, #sap").get(), q("en", "sap"), "Check for multiple filters");
718 | });
719 |
720 | describe("parent([String])", function () {
721 |
722 | it("Simple parent check", function () {
723 | expect(K("#groups").parent()[0].id).toEqual("ap");
724 | });
725 | it("Filtered parent check", function () {
726 | expect(K("#groups").parent("p")[0].id).toEqual("ap");
727 | });
728 | it("Filtered parent check, no match", function () {
729 | expect(K("#groups").parent("div").length).toEqual(0);
730 | });
731 | equals(K("#groups").parent("div, p")[0].id, "ap", "Check for multiple filters");
732 | same(K("#en, #sndp").parent().get(), q("foo"), "Check for unique results from parent");
733 | });
734 |
735 | describe("parents([String])", function () {
736 |
737 | it("Simple parents check", function () {
738 | expect(K("#groups").parents()[0].id).toEqual("ap");
739 | });
740 | it("Filtered parents check", function () {
741 | expect(K("#groups").parents("p")[0].id).toEqual("ap");
742 | });
743 | it("Filtered parents check2", function () {
744 | expect(K("#groups").parents("div")[0].id).toEqual("main");
745 | });
746 | same(K("#groups").parents("p, div").get(), q("ap", "main"), "Check for multiple filters");
747 | same(K("#en, #sndp").parents().get(), q("foo", "main", "dl", "body", "html"), "Check for unique results from parents");
748 | });
749 |
750 | describe("parentsUntil([String])", function () {
751 |
752 |
753 | var parents = K("#groups").parents();
754 | it("parentsUntil with no selector (nextAll)", function () {
755 | expect(K("#groups").parentsUntil().get()).toBeSameTiElementsAs(parents.get());
756 | });
757 | it("parentsUntil with invalid selector (nextAll)", function () {
758 | expect(K("#groups").parentsUntil(".foo").get()).toBeSameTiElementsAs(parents.get());
759 | });
760 | it("Simple parentsUntil check", function () {
761 | expect(K("#groups").parentsUntil("#html").get()).toBeSameTiElementsAs(parents.not(':last').get());
762 | });
763 | it("Simple parentsUntil check", function () {
764 | expect(K("#groups").parentsUntil("#ap").length).toEqual(0);
765 | });
766 | same(K("#groups").parentsUntil("#html, #body").get(), parents.slice(0, 3).get(), "Less simple parentsUntil check");
767 | same(K("#groups").parentsUntil("#html", "div").get(), K("#main").get(), "Filtered parentsUntil check");
768 | same(K("#groups").parentsUntil("#html", "p,div,dl").get(), parents.slice(0, 3).get(), "Multiple-filtered parentsUntil check");
769 | equals(K("#groups").parentsUntil("#html", "span").length, 0, "Filtered parentsUntil check, no match");
770 | same(K("#groups, #ap").parentsUntil("#html", "p,div,dl").get(), parents.slice(0, 3).get(), "Multi-source, multiple-filtered parentsUntil check");
771 | });
772 |
773 | describe("next([String])", function () {
774 |
775 | it("Simple next check", function () {
776 | expect(K("#ap").next()[0].id).toEqual("foo");
777 | });
778 | it("Filtered next check", function () {
779 | expect(K("#ap").next("div")[0].id).toEqual("foo");
780 | });
781 | it("Filtered next check, no match", function () {
782 | expect(K("#ap").next("p").length).toEqual(0);
783 | });
784 | equals(K("#ap").next("div, p")[0].id, "foo", "Multiple filters");
785 | });
786 |
787 | describe("prev([String])", function () {
788 |
789 | it("Simple prev check", function () {
790 | expect(K("#foo").prev()[0].id).toEqual("ap");
791 | });
792 | it("Filtered prev check", function () {
793 | expect(K("#foo").prev("p")[0].id).toEqual("ap");
794 | });
795 | it("Filtered prev check, no match", function () {
796 | expect(K("#foo").prev("div").length).toEqual(0);
797 | });
798 | equals(K("#foo").prev("p, div")[0].id, "ap", "Multiple filters");
799 | });
800 |
801 | describe("nextAll([String])", function () {
802 |
803 |
804 | var elems = K('#form').children();
805 | it("Simple nextAll check", function () {
806 | expect(K("#label-for").nextAll().get()).toBeSameTiElementsAs(elems.not(':first').get());
807 | });
808 | it("Filtered nextAll check", function () {
809 | expect(K("#label-for").nextAll('input').get()).toBeSameTiElementsAs(elems.not(':first').filter('input').get());
810 | });
811 | same(K("#label-for").nextAll('input,select').get(), elems.not(':first').filter('input,select').get(), "Multiple-filtered nextAll check");
812 | same(K("#label-for, #hidden1").nextAll('input,select').get(), elems.not(':first').filter('input,select').get(), "Multi-source, multiple-filtered nextAll check");
813 | });
814 |
815 | describe("prevAll([String])", function () {
816 |
817 |
818 | var elems = K(K('#form').children().slice(0, 12).get().reverse());
819 | it("Simple prevAll check", function () {
820 | expect(K("#area1").prevAll().get()).toBeSameTiElementsAs(elems.get());
821 | });
822 | it("Filtered prevAll check", function () {
823 | expect(K("#area1").prevAll('input').get()).toBeSameTiElementsAs(elems.filter('input').get());
824 | });
825 | same(K("#area1").prevAll('input,select').get(), elems.filter('input,select').get(), "Multiple-filtered prevAll check");
826 | same(K("#area1, #hidden1").prevAll('input,select').get(), elems.filter('input,select').get(), "Multi-source, multiple-filtered prevAll check");
827 | });
828 |
829 | describe("nextUntil([String])", function () {
830 |
831 |
832 | var elems = K('#form').children().slice(2, 12);
833 | it("nextUntil with no selector (nextAll)", function () {
834 | expect(K("#text1").nextUntil().get()).toBeSameTiElementsAs(K("#text1").nextAll().get());
835 | });
836 | it("nextUntil with invalid selector (nextAll)", function () {
837 | expect(K("#text1").nextUntil(".foo").get()).toBeSameTiElementsAs(K("#text1").nextAll().get());
838 | });
839 | it("Simple nextUntil check", function () {
840 | expect(K("#text1").nextUntil("#area1").get()).toBeSameTiElementsAs(elems.get());
841 | });
842 | it("Simple nextUntil check", function () {
843 | expect(K("#text1").nextUntil("#text2").length).toEqual(0);
844 | });
845 | same(K("#text1").nextUntil("#area1, #radio1").get(), K("#text1").next().get(), "Less simple nextUntil check");
846 | same(K("#text1").nextUntil("#area1", "input").get(), elems.not("button").get(), "Filtered nextUntil check");
847 | same(K("#text1").nextUntil("#area1", "button").get(), elems.not("input").get(), "Filtered nextUntil check");
848 | same(K("#text1").nextUntil("#area1", "button,input").get(), elems.get(), "Multiple-filtered nextUntil check");
849 | equals(K("#text1").nextUntil("#area1", "div").length, 0, "Filtered nextUntil check, no match");
850 | same(K("#text1, #hidden1").nextUntil("#area1", "button,input").get(), elems.get(), "Multi-source, multiple-filtered nextUntil check");
851 | it("Non-element nodes must be skipped, since they have no attributes", function () {
852 | expect(K("#text1").nextUntil("[class=foo]").get()).toBeSameTiElementsAs(K("#text1").nextAll().get());
853 | });
854 | });
855 |
856 | describe("prevUntil([String])", function () {
857 |
858 |
859 | var elems = K("#area1").prevAll();
860 | it("prevUntil with no selector (prevAll)", function () {
861 | expect(K("#area1").prevUntil().get()).toBeSameTiElementsAs(elems.get());
862 | });
863 | it("prevUntil with invalid selector (prevAll)", function () {
864 | expect(K("#area1").prevUntil(".foo").get()).toBeSameTiElementsAs(elems.get());
865 | });
866 | it("Simple prevUntil check", function () {
867 | expect(K("#area1").prevUntil("label").get()).toBeSameTiElementsAs(elems.not(':last').get());
868 | });
869 | it("Simple prevUntil check", function () {
870 | expect(K("#area1").prevUntil("#button").length).toEqual(0);
871 | });
872 | same(K("#area1").prevUntil("label, #search").get(), K("#area1").prev().get(), "Less simple prevUntil check");
873 | same(K("#area1").prevUntil("label", "input").get(), elems.not(':last').not("button").get(), "Filtered prevUntil check");
874 | same(K("#area1").prevUntil("label", "button").get(), elems.not(':last').not("input").get(), "Filtered prevUntil check");
875 | same(K("#area1").prevUntil("label", "button,input").get(), elems.not(':last').get(), "Multiple-filtered prevUntil check");
876 | equals(K("#area1").prevUntil("label", "div").length, 0, "Filtered prevUntil check, no match");
877 | same(K("#area1, #hidden1").prevUntil("label", "button,input").get(), elems.not(':last').get(), "Multi-source, multiple-filtered prevUntil check");
878 | });
879 |
880 | describe("contents()", function () {
881 |
882 | it("Check element contents", function () {
883 | expect(K("#ap").contents().length).toEqual(9);
884 | });
885 | it("Check existance of IFrame document", function () {
886 | expect(K("#iframe").contents()[0]).toBeDefined();
887 | });
888 | var ibody = K("#loadediframe").contents()[0].body;
889 | it("Check existance of IFrame body", function () {
890 | expect(ibody).toBeDefined();
891 | });
892 |
893 | equals(K("span", ibody).text(), "span text", "Find span in IFrame and check its text");
894 |
895 | K(ibody).append("
init text
");
896 | equals(K("div", ibody).length, 2, "Check the original div and the new div are in IFrame");
897 |
898 | equals(K("div:last", ibody).text(), "init text", "Add text to div in IFrame");
899 |
900 | K("div:last", ibody).text("div text");
901 | equals(K("div:last", ibody).text(), "div text", "Add text to div in IFrame");
902 |
903 | K("div:last", ibody).remove();
904 | equals(K("div", ibody).length, 1, "Delete the div and check only one div left in IFrame");
905 |
906 | equals(K("div", ibody).text(), "span text", "Make sure the correct div is still left after deletion in IFrame");
907 |
908 | K("
", ibody).append("
cell
").appendTo(ibody);
909 | K("table", ibody).remove();
910 | equals(K("div", ibody).length, 1, "Check for JS error on add and delete of a table in IFrame");
911 |
912 | // using contents will get comments regular, text, and comment nodes
913 | var c = K("#nonnodes").contents().contents();
914 | it("Check node,textnode,comment contents is just one", function () {
915 | expect(c.length).toEqual(1);
916 | });
917 | it("Check node,textnode,comment contents is just the one from span", function () {
918 | expect(c[0].nodeValue).toEqual("hi");
919 | });
920 | });
921 |
922 | describe("add(String|Element|Array|undefined)", function () {
923 |
924 | same(K("#sndp").add("#en").add("#sap").get(), q("sndp", "en", "sap"), "Check elements from document");
925 | same(K("#sndp").add(K("#en")[0]).add(K("#sap")).get(), q("sndp", "en", "sap"), "Check elements from document");
926 | it("Check elements from array", function () {
927 | expect(K([]).add(K("#form")[0].elements).length >= 13).toBeDefined();
928 | });
929 |
930 | // For the time being, we're discontinuing support for K(form.elements) since it's ambiguous in IE
931 | // use K([]).add(form.elements) instead.
932 | //equals( K([]).add(K("#form")[0].elements).length, K(K("#form")[0].elements).length, "Array in constructor must equals array in add()" );
933 | var divs = K("").add("#sndp");
934 | it("Make sure the first element is still the disconnected node.", function () {
935 | expect(!divs[0].parentNode).toBeDefined();
936 | });
937 |
938 | divs = K("
test
").add("#sndp");
939 | it("Make sure the first element is still the disconnected node.", function () {
940 | expect(divs[0].parentNode.nodeType).toEqual(11);
941 | });
942 |
943 | divs = K("#sndp").add("");
944 | it("Make sure the first element is still the disconnected node.", function () {
945 | expect(!divs[1].parentNode).toBeDefined();
946 | });
947 |
948 | var tmp = K("");
949 |
950 | var x = K([]).add(K("
xxx
").appendTo(tmp)).add(K("
xxx
").appendTo(tmp));
951 | it("Check on-the-fly element1", function () {
952 | expect(x[0].id).toEqual("x1");
953 | });
954 | it("Check on-the-fly element2", function () {
955 | expect(x[1].id).toEqual("x2");
956 | });
957 |
958 | var x = K([]).add(K("
xxx
").appendTo(tmp)[0]).add(K("
xxx
").appendTo(tmp)[0]);
959 | it("Check on-the-fly element1", function () {
960 | expect(x[0].id).toEqual("x1");
961 | });
962 | it("Check on-the-fly element2", function () {
963 | expect(x[1].id).toEqual("x2");
964 | });
965 |
966 | var x = K([]).add(K("
xxx
")).add(K("
xxx
"));
967 | it("Check on-the-fly element1", function () {
968 | expect(x[0].id).toEqual("x1");
969 | });
970 | it("Check on-the-fly element2", function () {
971 | expect(x[1].id).toEqual("x2");
972 | });
973 |
974 | var x = K([]).add("
xxx
").add("
xxx
");
975 | it("Check on-the-fly element1", function () {
976 | expect(x[0].id).toEqual("x1");
977 | });
978 | it("Check on-the-fly element2", function () {
979 | expect(x[1].id).toEqual("x2");
980 | });
981 |
982 | var notDefined;
983 | it("Check that undefined adds nothing", function () {
984 | expect(K([]).add(notDefined).length).toEqual(0);
985 | });
986 | it("Add a form (adds the elements)", function () {
987 | expect(K([]).add(document.getElementById('form')).length >= 13).toBeDefined();
988 | });
989 | });
990 |
991 | describe("add(String, Context)", function () {
992 |
993 |
994 | deepEqual(K("#firstp").add("#ap").get(), q("firstp", "ap"), "Add selector to selector ");
995 | deepEqual(K(document.getElementById("firstp")).add("#ap").get(), q("firstp", "ap"), "Add gEBId to selector");
996 | deepEqual(K(document.getElementById("firstp")).add(document.getElementById("ap")).get(), q("firstp", "ap"), "Add gEBId to gEBId");
997 |
998 | var ctx = document.getElementById("firstp");
999 | deepEqual(K("#firstp").add("#ap", ctx).get(), q("firstp"), "Add selector to selector ");
1000 | deepEqual(K(document.getElementById("firstp")).add("#ap", ctx).get(), q("firstp"), "Add gEBId to selector, not in context");
1001 | deepEqual(K(document.getElementById("firstp")).add("#ap", document.getElementsByTagName("body")[0]).get(), q("firstp", "ap"), "Add gEBId to selector, in context");
1002 | });
1003 | });
1004 |
1005 | })();
--------------------------------------------------------------------------------