18 | This is a very controversial article that invites comments.
19 |
20 |
21 |
Comments
22 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
45 |
46 |
80 |
81 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/resources/lib/module.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Author Shane Tomlinson
3 | * Original source can be found at:
4 | * https://github.com/stomlinson/appcore/blob/master/js/module.js
5 | * Licences under Mozilla Tri-License
6 | */
7 | BrowserID.module = (function() {
8 | "use strict";
9 |
10 | var registration = {},
11 | created = {},
12 | running = {};
13 |
14 | function register(service, module, config) {
15 | if (!module) {
16 | throw "module constructor missing for " + service;
17 | }
18 |
19 | registration[service] = {
20 | constructor: module,
21 | config: config
22 | };
23 | }
24 |
25 | function getRegistration(service) {
26 | return registration[service];
27 | }
28 |
29 | function getModule(service) {
30 | return registration[service].constructor;
31 | }
32 |
33 | function reset() {
34 | registration = {};
35 | running = {};
36 | created = {};
37 | }
38 |
39 | function start(service, data) {
40 | if (running[service]) {
41 | throw "module already running for " + service;
42 | }
43 |
44 | var module = created[service];
45 |
46 | if (!module) {
47 | var registration = getRegistration(service);
48 | if (registration) {
49 | var constr = registration.constructor,
50 | config = registration.config;
51 |
52 | module = new constr();
53 | created[service] = module;
54 | module.init(config);
55 | }
56 | else {
57 | throw "module not registered for " + service;
58 | }
59 | }
60 |
61 | module.start(data);
62 | running[service] = module;
63 |
64 | return module;
65 | }
66 |
67 | function stop(service) {
68 | var module = running[service];
69 |
70 | if (module) {
71 | module.stop();
72 | delete running[service];
73 | }
74 | else {
75 | throw "module not started for " + service;
76 | }
77 | }
78 |
79 | function stopAll() {
80 | for(var key in running) {
81 | var module = running[key];
82 | module.stop();
83 | delete running[key];
84 | }
85 | }
86 |
87 |
88 | return {
89 | register: register,
90 | getModule: getModule,
91 | reset: reset,
92 | start: start,
93 | stop: stop,
94 | stopAll: stopAll
95 | };
96 | }());
97 |
--------------------------------------------------------------------------------
/resources/src/core/storage.js:
--------------------------------------------------------------------------------
1 | /* ***** BEGIN LICENSE BLOCK *****
2 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 | *
4 | * The contents of this file are subject to the Mozilla Public License Version
5 | * 1.1 (the "License"); you may not use this file except in compliance with
6 | * the License. You may obtain a copy of the License at
7 | * http://www.mozilla.org/MPL/
8 | *
9 | * Software distributed under the License is distributed on an "AS IS" basis,
10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 | * for the specific language governing rights and limitations under the
12 | * License.
13 | *
14 | * The Original Code is Mozilla BrowserID.
15 | *
16 | * The Initial Developer of the Original Code is Mozilla.
17 | * Portions created by the Initial Developer are Copyright (C) 2011
18 | * the Initial Developer. All Rights Reserved.
19 | *
20 | * Contributor(s):
21 | *
22 | * Alternatively, the contents of this file may be used under the terms of
23 | * either the GNU General Public License Version 2 or later (the "GPL"), or
24 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25 | * in which case the provisions of the GPL or the LGPL are applicable instead
26 | * of those above. If you wish to allow use of your version of this file only
27 | * under the terms of either the GPL or the LGPL, and not to allow others to
28 | * use your version of this file under the terms of the MPL, indicate your
29 | * decision by deleting the provisions above and replace them with the notice
30 | * and other provisions required by the GPL or the LGPL. If you do not delete
31 | * the provisions above, a recipient may use your version of this file under
32 | * the terms of any one of the MPL, the GPL or the LGPL.
33 | *
34 | * ***** END LICENSE BLOCK ***** */
35 |
36 | BrowserID.Storage = (function() {
37 | var storage = window.localStorage;
38 |
39 | function clear() {
40 | storage.removeItem("profile");
41 | }
42 |
43 | function profileGet(key) {
44 | var info = JSON.parse(storage.profile || "{}");
45 | return info[key];
46 | }
47 |
48 | function profileSet(key, value) {
49 | var info = JSON.parse(storage.profile || "{}");
50 | info[key] = value;
51 | storage.profile = JSON.stringify(info);
52 | }
53 |
54 | function profileRemove(key) {
55 | var info = JSON.parse(storage.profile || "{}");
56 | delete info[key];
57 | storage.profile = JSON.stringify(info);
58 | }
59 |
60 | return {
61 | profile: {
62 | get: profileGet,
63 | set: profileSet,
64 | remove: profileRemove
65 | }
66 | };
67 | }());
68 |
--------------------------------------------------------------------------------
/resources/test/tests/include_unit_test.js:
--------------------------------------------------------------------------------
1 | /*jshint browsers:true, forin: true, laxbreak: true */
2 | /*global steal: true, test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID:true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla BrowserID.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | (function() {
38 | "use strict";
39 |
40 | var profile = navigator.profile;
41 |
42 | var ChannelMock = {
43 |
44 | };
45 |
46 | module("include.js", {
47 | setup: function() {
48 | profile.init({
49 | channel: ChannelMock
50 | });
51 | },
52 | teardown: function() {
53 | }
54 | });
55 |
56 | test("get with success", function() {
57 | profile.get(function(profile) {
58 | ok(profile.n, "name is returned");
59 | ok(profile.photo, "photo is returned");
60 | start();
61 | }, {
62 | required: ['name'],
63 | optional: ['photo']
64 | });
65 |
66 | stop();
67 | });
68 | }());
69 |
--------------------------------------------------------------------------------
/resources/src/models/profile-model.js:
--------------------------------------------------------------------------------
1 | /*jshint browsers:true, forin: true, laxbreak: true */
2 | /*global BrowserID: true, _: true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla BrowserID.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | (function() {
38 | "use strict";
39 |
40 | var bid = BrowserID,
41 | storage = bid.Storage,
42 | schema = {
43 | fname: { type: 'string' },
44 | lname: { type: 'string' },
45 | avatar: { type: 'string' }
46 | };
47 |
48 |
49 | bid.Models = BrowserID.Models || {};
50 |
51 | bid.Models.Profile = AFrame.Model.extend({
52 | schema: schema,
53 |
54 | save: function() {
55 | var self = this;
56 | var data = self.toSerializedJSON();
57 | for(var key in data) {
58 | storage.profile.set(key, data[key]);
59 | }
60 | },
61 |
62 | load: function() {
63 | for(var key in schema) {
64 | this.set(key, storage.profile.get(key));
65 | }
66 | }
67 | });
68 | }());
69 |
70 |
--------------------------------------------------------------------------------
/resources/test/tests/core/storage_unit_test.js:
--------------------------------------------------------------------------------
1 | /*jshint browsers:true, forin: true, laxbreak: true */
2 | /*global steal: true, test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID:true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla BrowserID.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | (function() {
38 | var storage = BrowserID.Storage;
39 |
40 | module("core/storage", {
41 | setup: function() {
42 | storage.clear();
43 | },
44 |
45 | teardown: function() {
46 | storage.clear();
47 | }
48 | });
49 |
50 | test("profile.set->get", function() {
51 | storage.profile.set("fname", "BrowserID User");
52 |
53 | equal(storage.profile.get("fname"), "BrowserID User", "fname set and retreived");
54 | });
55 |
56 | test("profile.set->remove", function() {
57 | storage.profile.set("fname", "BrowserID User");
58 | storage.profile.remove("fname");
59 |
60 | equal(typeof storage.profile.get("fname"), "undefined", "fname was removed");
61 |
62 | });
63 |
64 | });
65 |
66 |
--------------------------------------------------------------------------------
/resources/src/modules/profile-module.js:
--------------------------------------------------------------------------------
1 | /*jshint browser:true, jQuery: true, forin: true, laxbreak:true */
2 | /*global BrowserID:true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla BrowserID.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | BrowserID.Modules = BrowserID.Modules || {};
38 | BrowserID.Modules.Profile = (function() {
39 | "use strict";
40 |
41 | var bid = BrowserID,
42 | Module = bid.Module,
43 | dom = bid.DOM;
44 |
45 | function formSubmit() {
46 | var self=this;
47 | if(!self.isRunning()) {
48 | throw "cannot save module if not running";
49 | }
50 |
51 | self.form.save();
52 | }
53 |
54 | var Profile = Module.extend({
55 | domevents: {
56 | "submit form": formSubmit
57 | },
58 |
59 | start: function(data) {
60 | var self=this;
61 | Profile.sc.start.call(self, data);
62 |
63 | // Create the form when we have the appropriate data
64 | self.form = AFrame.DataForm.create({
65 | target: self.target,
66 | data: data
67 | });
68 | },
69 |
70 | stop: function() {
71 | Profile.sc.stop.call(this);
72 |
73 | var self=this;
74 | // After stop, changes to model should have no effect on the form fields.
75 | self.form.teardown();
76 | delete self.form;
77 | },
78 |
79 | submit: formSubmit
80 | });
81 |
82 | return Profile;
83 | }());
84 |
--------------------------------------------------------------------------------
/resources/test/tests/models/profile-model_unit_test.js:
--------------------------------------------------------------------------------
1 | /*jshint browsers:true, forin: true, laxbreak: true */
2 | /*global wrappedAsyncTest: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID: true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla BrowserID.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | (function() {
38 | "use strict";
39 |
40 | var bid = BrowserID,
41 | storage = bid.Storage,
42 | Profile = bid.Models.Profile,
43 | profile;
44 |
45 | module("models/profile-model", {
46 | setup: function() {
47 | profile = Profile.create({
48 | data: {
49 | "fname": "Jack",
50 | "lname": "Sparrow"
51 | }
52 | });
53 | },
54 |
55 | teardown: function() {
56 | if(profile) {
57 | profile.teardown();
58 | profile = null;
59 | }
60 | }
61 | });
62 |
63 | test("Can create profile model", function() {
64 | ok(profile, "can create a model");
65 | equal(profile.get("fname"), "Jack", "first name set");
66 | equal(profile.get("lname"), "Sparrow", "last name set");
67 | });
68 |
69 | test("saving a model persists data", function() {
70 | profile.set("fname", "Captain");
71 |
72 | profile.save();
73 |
74 | equal(storage.profile.get("fname"), "Captain", "fname saved to storage on save");
75 | equal(storage.profile.get("lname"), "Sparrow", "lname saved to storage on save");
76 | });
77 |
78 | test("loading a model loads model correctly", function() {
79 | storage.profile.set("fname", "Clark");
80 | storage.profile.set("lname", "Kent");
81 |
82 | profile.load();
83 |
84 | equal(profile.get("fname"), "Clark", "fname loaded from storage on load");
85 | equal(profile.get("lname"), "Kent", "lname loaded from storage on load");
86 | });
87 | }());
88 |
--------------------------------------------------------------------------------
/resources/test/tests/modules/profile-module_unit_test.js:
--------------------------------------------------------------------------------
1 | /*jshint browsers:true, forin: true, laxbreak: true */
2 | /*global steal: true, test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID:true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla BrowserID.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | (function() {
38 | "use strict";
39 |
40 | var bid = BrowserID,
41 | ProfileModel = bid.Models.Profile,
42 | ProfileModule = bid.Modules.Profile,
43 | model,
44 | profileModule;
45 |
46 | module("modules/profile_module", {
47 | setup: function() {
48 | $("#formModule input").val("");
49 |
50 | model = ProfileModel.create({
51 | data: {
52 | fname: "Browser",
53 | lname: "ID"
54 | }
55 | });
56 |
57 | profileModule = ProfileModule.create({
58 | target: "#formModule"
59 | });
60 | },
61 |
62 | teardown: function() {
63 | model.teardown();
64 | profileModule.teardown();
65 | }
66 | });
67 |
68 |
69 | test("profile module start fills in data", function() {
70 | // no data filled in before start
71 | equal($("input[name=fname]").val(), "", "input not filled in before start");
72 | equal($("input[name=lname]").val(), "", "input not filled in before start");
73 |
74 | profileModule.start(model);
75 |
76 | equal($("input[name=fname]").val(), "Browser", "inputfilled in after start");
77 | equal($("input[name=lname]").val(), "ID", "input filled in after start");
78 | });
79 |
80 | test("data is not autosaved to model, but saved on submit", function() {
81 | profileModule.start(model);
82 |
83 | $("input[name=fname]").val("BrowserID");
84 |
85 |
86 | equal(model.get("fname"), "Browser", "model not updated until submit");
87 |
88 | profileModule.submit();
89 |
90 | equal(model.get("fname"), "BrowserID", "model updated on submit");
91 | });
92 |
93 | test("exception thrown if saving before start", function() {
94 | var error;
95 | try {
96 | profileModule.submit();
97 | }
98 | catch(e) {
99 | error = e;
100 | }
101 |
102 | equal(error, "cannot save module if not running", "exception thrown when saving before start");
103 | });
104 |
105 | test("stop works", function() {
106 | profileModule.start(model);
107 | profileModule.stop();
108 |
109 | // this should have no effect on the element after stop
110 | model.set("fname", "BrowserID");
111 | equal($("input[name=fname]").val(), "Browser", "after teardown, changes to the model do not effect fields");
112 | });
113 |
114 |
115 | }());
116 |
117 |
118 |
--------------------------------------------------------------------------------
/resources/test/tests/core/module-tracker_unit_test.js:
--------------------------------------------------------------------------------
1 | /*jshint browsers:true, forin: true, laxbreak: true */
2 | /*global steal: true, test: true, start: true, stop: true, module: true, ok: true, equal: true, BrowserID: true */
3 | /**
4 | * Original code authored by Shane Tomlinson
5 | * original source at: https://github.com/stomlinson/appcore/blob/master/test/module_unit_test.js
6 | * Licenced under Mozilla Tri-license.
7 | */
8 | (function() {
9 | "use strict";
10 |
11 | var bid = BrowserID,
12 | moduleTracker = bid.moduleTracker,
13 | moduleConstructed = false,
14 | moduleInited = false,
15 | moduleInitData,
16 | moduleStarted = false,
17 | moduleStartData,
18 | moduleStopped = false;
19 |
20 | function Module() {
21 | moduleConstructed = true;
22 | }
23 |
24 | Module.prototype = {
25 | constructor: Module,
26 | init: function(data) {
27 | moduleInited = true;
28 | moduleInitData = data;
29 | },
30 |
31 | start: function(data) {
32 | moduleStarted = true;
33 | moduleStartData = data;
34 | },
35 |
36 | stop: function() {
37 | moduleStopped = true;
38 | }
39 | };
40 |
41 | module("core/moduleTracker", {
42 | setup: function() {
43 | moduleConstructed = moduleInited = moduleStarted = moduleStopped = false;
44 | moduleStartData = moduleInitData = undefined;
45 | moduleTracker.reset();
46 | },
47 |
48 | teardown: function() {
49 | moduleTracker.reset();
50 | }
51 | });
52 |
53 | test("register a module with no constructor throws an exception", function() {
54 | var error;
55 |
56 | try {
57 | moduleTracker.register("service");
58 | } catch(e) {
59 | error = e;
60 | }
61 |
62 | equal(error, "module constructor missing for service", "exception correctly thrown");
63 | });
64 |
65 |
66 | test("register a module", function() {
67 | moduleTracker.register("service", Module);
68 | strictEqual(moduleTracker.getModule("service"), Module, "register->getModule are same module");
69 | });
70 |
71 | test("start a module that has not been registered throws exception", function() {
72 | var error;
73 |
74 | try {
75 | moduleTracker.start("service");
76 | } catch(e) {
77 | error = e;
78 | }
79 |
80 | equal(error, "module not registered for service", "exception correctly thrown");
81 | });
82 |
83 | test("start a module that is registered", function() {
84 | var initData = { initField: true };
85 | moduleTracker.register("service", Module, initData);
86 |
87 | var startData = { someField: true };
88 | var module = moduleTracker.start("service", startData);
89 |
90 | ok(moduleConstructed, "module has been constructed");
91 | ok(moduleInited, "module has been inited");
92 | ok(moduleInitData === initData, "initData passed in on start");
93 |
94 | ok(moduleStarted, "module has been started");
95 | ok(moduleStartData === startData, "startData passed in on start");
96 |
97 | ok(module, "module returned on start");
98 | });
99 |
100 | test("stop a module that has not been started throws exception", function() {
101 | moduleTracker.register("service", Module);
102 |
103 | var error;
104 | try {
105 | moduleTracker.stop("service");
106 | } catch(e) {
107 | error = e;
108 | }
109 |
110 | equal(error, "module not started for service", "exception correctly thrown");
111 | });
112 |
113 | test("stop a module that is running", function() {
114 | moduleTracker.register("service", Module);
115 | moduleTracker.start("service");
116 | moduleTracker.stop("service");
117 |
118 | ok(moduleStopped, "module has been stopped");
119 | });
120 |
121 | test("start a module that is already started", function() {
122 | moduleTracker.register("service", Module);
123 | moduleTracker.start("service");
124 |
125 | var error;
126 |
127 | try {
128 | moduleTracker.start("service");
129 | } catch(e) {
130 | error = e;
131 | }
132 |
133 | equal(error, "module already running for service", "exception correctly thrown");
134 | });
135 |
136 | test("restart a module that was stopped, ", function() {
137 | moduleTracker.register("service", Module);
138 | var module = moduleTracker.start("service");
139 | moduleTracker.stop("service");
140 | var module2 = moduleTracker.start("service");
141 |
142 | strictEqual(module, module2, "only one module instance ever created");
143 | });
144 | }());
145 |
--------------------------------------------------------------------------------
/resources/test/tests/core/module_unit_test.js:
--------------------------------------------------------------------------------
1 | /*jshint browser:true, jQuery: true, forin: true, laxbreak:true */
2 | /*globals BrowserID: true, _:true */
3 | /* ***** BEGIN LICENSE BLOCK *****
4 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 | *
6 | * The contents of this file are subject to the Mozilla Public License Version
7 | * 1.1 (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | * http://www.mozilla.org/MPL/
10 | *
11 | * Software distributed under the License is distributed on an "AS IS" basis,
12 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 | * for the specific language governing rights and limitations under the
14 | * License.
15 | *
16 | * The Original Code is Mozilla bid.
17 | *
18 | * The Initial Developer of the Original Code is Mozilla.
19 | * Portions created by the Initial Developer are Copyright (C) 2011
20 | * the Initial Developer. All Rights Reserved.
21 | *
22 | * Contributor(s):
23 | *
24 | * Alternatively, the contents of this file may be used under the terms of
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
28 | * of those above. If you wish to allow use of your version of this file only
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
30 | * use your version of this file under the terms of the MPL, indicate your
31 | * decision by deleting the provisions above and replace them with the notice
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
33 | * the provisions above, a recipient may use your version of this file under
34 | * the terms of any one of the MPL, the GPL or the LGPL.
35 | *
36 | * ***** END LICENSE BLOCK ***** */
37 | (function() {
38 | "use strict";
39 |
40 | var Module = BrowserID.Module,
41 | mod,
42 | config = {
43 | target: "#formModule"
44 | };
45 |
46 | module("core/module", {
47 | setup: function() {
48 | },
49 |
50 | teardown: function() {
51 | if (mod) {
52 | mod.teardown();
53 | }
54 | }
55 | });
56 |
57 | test("can create, initialize with data", function() {
58 | mod = Module.create(config);
59 |
60 | equal(mod.getConfig(), config, "config is saved in init");
61 | equal(mod.isRunning(), false, "module is not yet running");
62 | });
63 |
64 | test("start starts the module", function() {
65 | mod = Module.create(config);
66 | mod.start("data");
67 |
68 | equal(mod.getStartData(), "data", "data is set on start");
69 | ok(mod.isRunning(), "module is running");
70 | });
71 |
72 | test("cannot call start twice without stopping", function() {
73 | mod = Module.create(config);
74 | mod.start("data");
75 |
76 | var error;
77 | try {
78 | mod.start("data");
79 | } catch(e) {
80 | error = e;
81 | }
82 |
83 | equal(error, "module is already running");
84 | });
85 |
86 | test("stop stops the module", function() {
87 | mod = Module.create(config);
88 | mod.start("data");
89 | mod.stop();
90 |
91 | equal(mod.isRunning(), false, "module is no longer running");
92 | });
93 |
94 | test("cannot call stop without calling start", function() {
95 | mod = Module.create(config);
96 | var error;
97 | try {
98 | mod.stop();
99 | } catch(e) {
100 | error = e;
101 | }
102 |
103 | equal(error, "module is not running");
104 | });
105 |
106 | test("cannot call stop twice consecutively without start", function() {
107 | mod = Module.create(config);
108 | mod.start("data");
109 | mod.stop();
110 | var error;
111 | try {
112 | mod.stop();
113 | } catch(e) {
114 | error = e;
115 | }
116 |
117 | equal(error, "module is not running");
118 | });
119 |
120 | test("dom events are bound on start if domevents are declared, events unbound when stop is called", function() {
121 | function formClick(event) {
122 | event.preventDefault();
123 | this.clicked = true;
124 | }
125 |
126 | var InheritedModule = Module.extend({
127 | domevents: {
128 | "click form": formClick
129 | }
130 | });
131 |
132 | mod = InheritedModule.create(config);
133 |
134 | // bind the dom events
135 | mod.start();
136 |
137 | $("#formModule").trigger("click");
138 | ok(mod.clicked, "event bound, handler run");
139 |
140 | // unbind the dom events
141 | mod.clicked = false;
142 | mod.stop();
143 | $("#formModule").trigger("click");
144 | equal(mod.clicked, false, "event not bound, handler not run");
145 | });
146 |
147 | test("teardown stops module", function() {
148 | mod = Module.create(config);
149 | mod.start("data");
150 | mod.teardown();
151 |
152 | equal(mod.isRunning(), false, "module is no longer running after teardown");
153 | mod = null;
154 | });
155 |
156 | }());
157 |
--------------------------------------------------------------------------------
/resources/test/qunit/qunit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit - A JavaScript Unit Testing Framework
3 | *
4 | * http://docs.jquery.com/QUnit
5 | *
6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer
7 | * Dual licensed under the MIT (MIT-LICENSE.txt)
8 | * or GPL (GPL-LICENSE.txt) licenses.
9 | */
10 |
11 | /** Font Family and Sizes */
12 |
13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
15 | }
16 |
17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
18 | #qunit-tests { font-size: smaller; }
19 |
20 |
21 | /** Resets */
22 |
23 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
28 |
29 | /** Header */
30 |
31 | #qunit-header {
32 | padding: 0.5em 0 0.5em 1em;
33 |
34 | color: #8699a4;
35 | background-color: #0d3349;
36 |
37 | font-size: 1.5em;
38 | line-height: 1em;
39 | font-weight: normal;
40 |
41 | border-radius: 15px 15px 0 0;
42 | -moz-border-radius: 15px 15px 0 0;
43 | -webkit-border-top-right-radius: 15px;
44 | -webkit-border-top-left-radius: 15px;
45 | }
46 |
47 | #qunit-header a {
48 | text-decoration: none;
49 | color: #c2ccd1;
50 | }
51 |
52 | #qunit-header a:hover,
53 | #qunit-header a:focus {
54 | color: #fff;
55 | }
56 |
57 | #qunit-banner {
58 | height: 5px;
59 | }
60 |
61 | #qunit-testrunner-toolbar {
62 | padding: 0.5em 0 0.5em 2em;
63 | color: #5E740B;
64 | background-color: #eee;
65 | }
66 |
67 | #qunit-userAgent {
68 | padding: 0.5em 0 0.5em 2.5em;
69 | background-color: #2b81af;
70 | color: #fff;
71 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
72 | }
73 |
74 |
75 | /** Tests: Pass/Fail */
76 |
77 | #qunit-tests {
78 | list-style-position: inside;
79 | }
80 |
81 | #qunit-tests li {
82 | padding: 0.4em 0.5em 0.4em 2.5em;
83 | border-bottom: 1px solid #fff;
84 | list-style-position: inside;
85 | }
86 |
87 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
88 | display: none;
89 | }
90 |
91 | #qunit-tests li strong {
92 | cursor: pointer;
93 | }
94 |
95 | #qunit-tests li a {
96 | padding: 0.5em;
97 | color: #c2ccd1;
98 | text-decoration: none;
99 | }
100 | #qunit-tests li a:hover,
101 | #qunit-tests li a:focus {
102 | color: #000;
103 | }
104 |
105 | #qunit-tests ol {
106 | margin-top: 0.5em;
107 | padding: 0.5em;
108 |
109 | background-color: #fff;
110 |
111 | border-radius: 15px;
112 | -moz-border-radius: 15px;
113 | -webkit-border-radius: 15px;
114 |
115 | box-shadow: inset 0px 2px 13px #999;
116 | -moz-box-shadow: inset 0px 2px 13px #999;
117 | -webkit-box-shadow: inset 0px 2px 13px #999;
118 | }
119 |
120 | #qunit-tests table {
121 | border-collapse: collapse;
122 | margin-top: .2em;
123 | }
124 |
125 | #qunit-tests th {
126 | text-align: right;
127 | vertical-align: top;
128 | padding: 0 .5em 0 0;
129 | }
130 |
131 | #qunit-tests td {
132 | vertical-align: top;
133 | }
134 |
135 | #qunit-tests pre {
136 | margin: 0;
137 | white-space: pre-wrap;
138 | word-wrap: break-word;
139 | }
140 |
141 | #qunit-tests del {
142 | background-color: #e0f2be;
143 | color: #374e0c;
144 | text-decoration: none;
145 | }
146 |
147 | #qunit-tests ins {
148 | background-color: #ffcaca;
149 | color: #500;
150 | text-decoration: none;
151 | }
152 |
153 | /*** Test Counts */
154 |
155 | #qunit-tests b.counts { color: black; }
156 | #qunit-tests b.passed { color: #5E740B; }
157 | #qunit-tests b.failed { color: #710909; }
158 |
159 | #qunit-tests li li {
160 | margin: 0.5em;
161 | padding: 0.4em 0.5em 0.4em 0.5em;
162 | background-color: #fff;
163 | border-bottom: none;
164 | list-style-position: inside;
165 | }
166 |
167 | /*** Passing Styles */
168 |
169 | #qunit-tests li li.pass {
170 | color: #5E740B;
171 | background-color: #fff;
172 | border-left: 26px solid #C6E746;
173 | }
174 |
175 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
176 | #qunit-tests .pass .test-name { color: #366097; }
177 |
178 | #qunit-tests .pass .test-actual,
179 | #qunit-tests .pass .test-expected { color: #999999; }
180 |
181 | #qunit-banner.qunit-pass { background-color: #C6E746; }
182 |
183 | /*** Failing Styles */
184 |
185 | #qunit-tests li li.fail {
186 | color: #710909;
187 | background-color: #fff;
188 | border-left: 26px solid #EE5757;
189 | }
190 |
191 | #qunit-tests > li:last-child {
192 | border-radius: 0 0 15px 15px;
193 | -moz-border-radius: 0 0 15px 15px;
194 | -webkit-border-bottom-right-radius: 15px;
195 | -webkit-border-bottom-left-radius: 15px;
196 | }
197 |
198 | #qunit-tests .fail { color: #000000; background-color: #EE5757; }
199 | #qunit-tests .fail .test-name,
200 | #qunit-tests .fail .module-name { color: #000000; }
201 |
202 | #qunit-tests .fail .test-actual { color: #EE5757; }
203 | #qunit-tests .fail .test-expected { color: green; }
204 |
205 | #qunit-banner.qunit-fail { background-color: #EE5757; }
206 |
207 |
208 | /** Result */
209 |
210 | #qunit-testresult {
211 | padding: 0.5em 0.5em 0.5em 2.5em;
212 |
213 | color: #2b81af;
214 | background-color: #D2E0E6;
215 |
216 | border-bottom: 1px solid white;
217 | }
218 |
219 | /** Fixture */
220 |
221 | #qunit-fixture {
222 | position: absolute;
223 | top: -10000px;
224 | left: -10000px;
225 | }
226 |
--------------------------------------------------------------------------------
/resources/lib/underscore-min.js:
--------------------------------------------------------------------------------
1 | // Underscore.js 1.1.7
2 | // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc.
3 | // Underscore is freely distributable under the MIT license.
4 | // Portions of Underscore are inspired or borrowed from Prototype,
5 | // Oliver Steele's Functional, and John Resig's Micro-Templating.
6 | // For all details and documentation:
7 | // http://documentcloud.github.com/underscore
8 | (function(){var p=this,C=p._,m={},i=Array.prototype,n=Object.prototype,f=i.slice,D=i.unshift,E=n.toString,l=n.hasOwnProperty,s=i.forEach,t=i.map,u=i.reduce,v=i.reduceRight,w=i.filter,x=i.every,y=i.some,o=i.indexOf,z=i.lastIndexOf;n=Array.isArray;var F=Object.keys,q=Function.prototype.bind,b=function(a){return new j(a)};typeof module!=="undefined"&&module.exports?(module.exports=b,b._=b):p._=b;b.VERSION="1.1.7";var h=b.each=b.forEach=function(a,c,b){if(a!=null)if(s&&a.forEach===s)a.forEach(c,b);else if(a.length===
9 | +a.length)for(var e=0,k=a.length;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,
13 | c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;bd?1:0}),"value")};b.groupBy=function(a,b){var d={};h(a,function(a,f){var g=b(a,f);(d[g]||(d[g]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d||
14 | (d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a,c){return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=f.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after=
20 | function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}};b.keys=F||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)l.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){h(f.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){h(f.call(arguments,
21 | 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,c){if(a===c)return!0;var d=typeof a;if(d!=typeof c)return!1;if(a==c)return!0;if(!a&&c||a&&!c)return!1;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual)return a.isEqual(c);if(c.isEqual)return c.isEqual(a);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return!1;
22 | if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return!1;if(a.length&&a.length!==c.length)return!1;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return!1;for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return!1;return!0};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(l.call(a,c))return!1;return!0};b.isElement=function(a){return!!(a&&a.nodeType==
23 | 1)};b.isArray=n||function(a){return E.call(a)==="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return!(!a||!l.call(a,"callee"))};b.isFunction=function(a){return!(!a||!a.constructor||!a.call||!a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===!0||a===!1};b.isDate=function(a){return!(!a||!a.getTimezoneOffset||
24 | !a.setUTCFullYear)};b.isRegExp=function(a){return!(!a||!a.test||!a.exec||!(a.ignoreCase||a.ignoreCase===!1))};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){p._=C;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g};
25 | b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d};
26 | var j=function(a){this._wrapped=a};b.prototype=j.prototype;var r=function(a,c){return c?b(a).chain():a},H=function(a,c){j.prototype[a]=function(){var a=f.call(arguments);D.call(a,this._wrapped);return r(c.apply(b,a),this._chain)}};b.mixin(b);h(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=i[a];j.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});h(["concat","join","slice"],function(a){var b=i[a];j.prototype[a]=function(){return r(b.apply(this._wrapped,
27 | arguments),this._chain)}});j.prototype.chain=function(){this._chain=!0;return this};j.prototype.value=function(){return this._wrapped}})();
28 |
--------------------------------------------------------------------------------
/resources/lib/ejs.js:
--------------------------------------------------------------------------------
1 | (function(){
2 |
3 |
4 | var rsplit = function(string, regex) {
5 | var result = regex.exec(string),retArr = new Array(), first_idx, last_idx, first_bit;
6 | while (result != null)
7 | {
8 | first_idx = result.index; last_idx = regex.lastIndex;
9 | if ((first_idx) != 0)
10 | {
11 | first_bit = string.substring(0,first_idx);
12 | retArr.push(string.substring(0,first_idx));
13 | string = string.slice(first_idx);
14 | }
15 | retArr.push(result[0]);
16 | string = string.slice(result[0].length);
17 | result = regex.exec(string);
18 | }
19 | if (! string == '')
20 | {
21 | retArr.push(string);
22 | }
23 | return retArr;
24 | },
25 | chop = function(string){
26 | return string.substr(0, string.length - 1);
27 | },
28 | extend = function(d, s){
29 | for(var n in s){
30 | if(s.hasOwnProperty(n)) d[n] = s[n]
31 | }
32 | }
33 |
34 |
35 | EJS = function( options ){
36 | options = typeof options == "string" ? {view: options} : options
37 | this.set_options(options);
38 | if(options.precompiled){
39 | this.template = {};
40 | this.template.process = options.precompiled;
41 | EJS.update(this.name, this);
42 | return;
43 | }
44 | if(options.element)
45 | {
46 | if(typeof options.element == 'string'){
47 | var name = options.element
48 | options.element = document.getElementById( options.element )
49 | if(options.element == null) throw name+'does not exist!'
50 | }
51 | if(options.element.value){
52 | this.text = options.element.value
53 | }else{
54 | this.text = options.element.innerHTML
55 | }
56 | this.name = options.element.id
57 | this.type = '['
58 | }else if(options.url){
59 | options.url = EJS.endExt(options.url, this.extMatch);
60 | this.name = this.name ? this.name : options.url;
61 | var url = options.url
62 | //options.view = options.absolute_url || options.view || options.;
63 | var template = EJS.get(this.name /*url*/, this.cache);
64 | if (template) return template;
65 | if (template == EJS.INVALID_PATH) return null;
66 | try{
67 | this.text = EJS.request( url+(this.cache ? '' : '?'+Math.random() ));
68 | }catch(e){}
69 |
70 | if(this.text == null){
71 | throw( {type: 'EJS', message: 'There is no template at '+url} );
72 | }
73 | //this.name = url;
74 | }
75 | var template = new EJS.Compiler(this.text, this.type);
76 |
77 | template.compile(options, this.name);
78 |
79 |
80 | EJS.update(this.name, this);
81 | this.template = template;
82 | };
83 | /* @Prototype*/
84 | EJS.prototype = {
85 | /**
86 | * Renders an object with extra view helpers attached to the view.
87 | * @param {Object} object data to be rendered
88 | * @param {Object} extra_helpers an object with additonal view helpers
89 | * @return {String} returns the result of the string
90 | */
91 | render : function(object, extra_helpers){
92 | object = object || {};
93 | this._extra_helpers = extra_helpers;
94 | var v = new EJS.Helpers(object, extra_helpers || {});
95 | return this.template.process.call(object, object,v);
96 | },
97 | update : function(element, options){
98 | if(typeof element == 'string'){
99 | element = document.getElementById(element)
100 | }
101 | if(options == null){
102 | _template = this;
103 | return function(object){
104 | EJS.prototype.update.call(_template, element, object)
105 | }
106 | }
107 | if(typeof options == 'string'){
108 | params = {}
109 | params.url = options
110 | _template = this;
111 | params.onComplete = function(request){
112 | var object = eval( request.responseText )
113 | EJS.prototype.update.call(_template, element, object)
114 | }
115 | EJS.ajax_request(params)
116 | }else
117 | {
118 | element.innerHTML = this.render(options)
119 | }
120 | },
121 | out : function(){
122 | return this.template.out;
123 | },
124 | /**
125 | * Sets options on this view to be rendered with.
126 | * @param {Object} options
127 | */
128 | set_options : function(options){
129 | this.type = options.type || EJS.type;
130 | this.cache = options.cache != null ? options.cache : EJS.cache;
131 | this.text = options.text || null;
132 | this.name = options.name || null;
133 | this.ext = options.ext || EJS.ext;
134 | this.extMatch = new RegExp(this.ext.replace(/\./, '\.'));
135 | }
136 | };
137 | EJS.endExt = function(path, match){
138 | if(!path) return null;
139 | match.lastIndex = 0
140 | return path+ (match.test(path) ? '' : this.ext )
141 | }
142 |
143 |
144 |
145 |
146 | /* @Static*/
147 | EJS.Scanner = function(source, left, right) {
148 |
149 | extend(this,
150 | {left_delimiter: left +'%',
151 | right_delimiter: '%'+right,
152 | double_left: left+'%%',
153 | double_right: '%%'+right,
154 | left_equal: left+'%=',
155 | left_comment: left+'%#'})
156 |
157 | this.SplitRegexp = left=='[' ? /(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/ : new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)') ;
158 |
159 | this.source = source;
160 | this.stag = null;
161 | this.lines = 0;
162 | };
163 |
164 | EJS.Scanner.to_text = function(input){
165 | if(input == null || input === undefined)
166 | return '';
167 | if(input instanceof Date)
168 | return input.toDateString();
169 | if(input.toString)
170 | return input.toString();
171 | return '';
172 | };
173 |
174 | EJS.Scanner.prototype = {
175 | scan: function(block) {
176 | scanline = this.scanline;
177 | regex = this.SplitRegexp;
178 | if (! this.source == '')
179 | {
180 | var source_split = rsplit(this.source, /\n/);
181 | for(var i=0; i 0)
228 | {
229 | for (var i=0; i 0)
303 | {
304 | buff.push(put_cmd + '"' + clean(content) + '")');
305 | }
306 | content = '';
307 | break;
308 | case scanner.double_left:
309 | content = content + scanner.left_delimiter;
310 | break;
311 | default:
312 | content = content + token;
313 | break;
314 | }
315 | }
316 | else {
317 | switch(token) {
318 | case scanner.right_delimiter:
319 | switch(scanner.stag) {
320 | case scanner.left_delimiter:
321 | if (content[content.length - 1] == '\n')
322 | {
323 | content = chop(content);
324 | buff.push(content);
325 | buff.cr();
326 | }
327 | else {
328 | buff.push(content);
329 | }
330 | break;
331 | case scanner.left_equal:
332 | buff.push(insert_cmd + "(EJS.Scanner.to_text(" + content + ")))");
333 | break;
334 | }
335 | scanner.stag = null;
336 | content = '';
337 | break;
338 | case scanner.double_right:
339 | content = content + scanner.right_delimiter;
340 | break;
341 | default:
342 | content = content + token;
343 | break;
344 | }
345 | }
346 | });
347 | if (content.length > 0)
348 | {
349 | // Chould be content.dump in Ruby
350 | buff.push(put_cmd + '"' + clean(content) + '")');
351 | }
352 | buff.close();
353 | this.out = buff.script + ";";
354 | var to_be_evaled = '/*'+name+'*/this.process = function(_CONTEXT,_VIEW) { try { with(_VIEW) { with (_CONTEXT) {'+this.out+" return ___ViewO.join('');}}}catch(e){e.lineNumber=null;throw e;}};";
355 |
356 | try{
357 | eval(to_be_evaled);
358 | }catch(e){
359 | if(typeof JSLINT != 'undefined'){
360 | JSLINT(this.out);
361 | for(var i = 0; i < JSLINT.errors.length; i++){
362 | var error = JSLINT.errors[i];
363 | if(error.reason != "Unnecessary semicolon."){
364 | error.line++;
365 | var e = new Error();
366 | e.lineNumber = error.line;
367 | e.message = error.reason;
368 | if(options.view)
369 | e.fileName = options.view;
370 | throw e;
371 | }
372 | }
373 | }else{
374 | throw e;
375 | }
376 | }
377 | }
378 | };
379 |
380 |
381 | //type, cache, folder
382 | /**
383 | * Sets default options for all views
384 | * @param {Object} options Set view with the following options
385 | *
";
632 |
633 | QUnit.log(details);
634 |
635 | config.current.assertions.push({
636 | result: !!result,
637 | message: output
638 | });
639 | },
640 |
641 | url: function( params ) {
642 | params = extend( extend( {}, QUnit.urlParams ), params );
643 | var querystring = "?",
644 | key;
645 | for ( key in params ) {
646 | querystring += encodeURIComponent( key ) + "=" +
647 | encodeURIComponent( params[ key ] ) + "&";
648 | }
649 | return window.location.pathname + querystring.slice( 0, -1 );
650 | },
651 |
652 | // Logging callbacks; all receive a single argument with the listed properties
653 | // run test/logs.html for any related changes
654 | begin: function() {},
655 | // done: { failed, passed, total, runtime }
656 | done: function() {},
657 | // log: { result, actual, expected, message }
658 | log: function() {},
659 | // testStart: { name }
660 | testStart: function() {},
661 | // testDone: { name, failed, passed, total }
662 | testDone: function() {},
663 | // moduleStart: { name }
664 | moduleStart: function() {},
665 | // moduleDone: { name, failed, passed, total }
666 | moduleDone: function() {}
667 | });
668 |
669 | if ( typeof document === "undefined" || document.readyState === "complete" ) {
670 | config.autorun = true;
671 | }
672 |
673 | addEvent(window, "load", function() {
674 | QUnit.begin({});
675 |
676 | // Initialize the config, saving the execution queue
677 | var oldconfig = extend({}, config);
678 | QUnit.init();
679 | extend(config, oldconfig);
680 |
681 | config.blocking = false;
682 |
683 | var userAgent = id("qunit-userAgent");
684 | if ( userAgent ) {
685 | userAgent.innerHTML = navigator.userAgent;
686 | }
687 | var banner = id("qunit-header");
688 | if ( banner ) {
689 | banner.innerHTML = ' ' + banner.innerHTML + ' ' +
690 | '' +
691 | '';
692 | addEvent( banner, "change", function( event ) {
693 | var params = {};
694 | params[ event.target.name ] = event.target.checked ? true : undefined;
695 | window.location = QUnit.url( params );
696 | });
697 | }
698 |
699 | var toolbar = id("qunit-testrunner-toolbar");
700 | if ( toolbar ) {
701 | var filter = document.createElement("input");
702 | filter.type = "checkbox";
703 | filter.id = "qunit-filter-pass";
704 | addEvent( filter, "click", function() {
705 | var ol = document.getElementById("qunit-tests");
706 | if ( filter.checked ) {
707 | ol.className = ol.className + " hidepass";
708 | } else {
709 | var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
710 | ol.className = tmp.replace(/ hidepass /, " ");
711 | }
712 | if ( defined.sessionStorage ) {
713 | if (filter.checked) {
714 | sessionStorage.setItem("qunit-filter-passed-tests", "true");
715 | } else {
716 | sessionStorage.removeItem("qunit-filter-passed-tests");
717 | }
718 | }
719 | });
720 | if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) {
721 | filter.checked = true;
722 | var ol = document.getElementById("qunit-tests");
723 | ol.className = ol.className + " hidepass";
724 | }
725 | toolbar.appendChild( filter );
726 |
727 | var label = document.createElement("label");
728 | label.setAttribute("for", "qunit-filter-pass");
729 | label.innerHTML = "Hide passed tests";
730 | toolbar.appendChild( label );
731 | }
732 |
733 | var main = id('qunit-fixture');
734 | if ( main ) {
735 | config.fixture = main.innerHTML;
736 | }
737 |
738 | if (config.autostart) {
739 | QUnit.start();
740 | }
741 | });
742 |
743 | function done() {
744 | config.autorun = true;
745 |
746 | // Log the last module results
747 | if ( config.currentModule ) {
748 | QUnit.moduleDone( {
749 | name: config.currentModule,
750 | failed: config.moduleStats.bad,
751 | passed: config.moduleStats.all - config.moduleStats.bad,
752 | total: config.moduleStats.all
753 | } );
754 | }
755 |
756 | var banner = id("qunit-banner"),
757 | tests = id("qunit-tests"),
758 | runtime = +new Date - config.started,
759 | passed = config.stats.all - config.stats.bad,
760 | html = [
761 | 'Tests completed in ',
762 | runtime,
763 | ' milliseconds. ',
764 | '',
765 | passed,
766 | ' tests of ',
767 | config.stats.all,
768 | ' passed, ',
769 | config.stats.bad,
770 | ' failed.'
771 | ].join('');
772 |
773 | if ( banner ) {
774 | banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass");
775 | }
776 |
777 | if ( tests ) {
778 | id( "qunit-testresult" ).innerHTML = html;
779 | }
780 |
781 | if ( typeof document !== "undefined" && document.title ) {
782 | // show ✖ for good, ✔ for bad suite result in title
783 | // use escape sequences in case file gets loaded with non-utf-8-charset
784 | document.title = (config.stats.bad ? "\u2716" : "\u2714") + " " + document.title;
785 | }
786 |
787 | QUnit.done( {
788 | failed: config.stats.bad,
789 | passed: passed,
790 | total: config.stats.all,
791 | runtime: runtime
792 | } );
793 | }
794 |
795 | function validTest( name ) {
796 | var filter = config.filter,
797 | run = false;
798 |
799 | if ( !filter ) {
800 | return true;
801 | }
802 |
803 | var not = filter.charAt( 0 ) === "!";
804 | if ( not ) {
805 | filter = filter.slice( 1 );
806 | }
807 |
808 | if ( name.indexOf( filter ) !== -1 ) {
809 | return !not;
810 | }
811 |
812 | if ( not ) {
813 | run = true;
814 | }
815 |
816 | return run;
817 | }
818 |
819 | // so far supports only Firefox, Chrome and Opera (buggy)
820 | // could be extended in the future to use something like https://github.com/csnover/TraceKit
821 | function sourceFromStacktrace() {
822 | try {
823 | throw new Error();
824 | } catch ( e ) {
825 | if (e.stacktrace) {
826 | // Opera
827 | return e.stacktrace.split("\n")[6];
828 | } else if (e.stack) {
829 | // Firefox, Chrome
830 | return e.stack.split("\n")[4];
831 | }
832 | }
833 | }
834 |
835 | function escapeHtml(s) {
836 | if (!s) {
837 | return "";
838 | }
839 | s = s + "";
840 | return s.replace(/[\&"<>\\]/g, function(s) {
841 | switch(s) {
842 | case "&": return "&";
843 | case "\\": return "\\\\";
844 | case '"': return '\"';
845 | case "<": return "<";
846 | case ">": return ">";
847 | default: return s;
848 | }
849 | });
850 | }
851 |
852 | function synchronize( callback ) {
853 | config.queue.push( callback );
854 |
855 | if ( config.autorun && !config.blocking ) {
856 | process();
857 | }
858 | }
859 |
860 | function process() {
861 | var start = (new Date()).getTime();
862 |
863 | while ( config.queue.length && !config.blocking ) {
864 | if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) {
865 | config.queue.shift()();
866 | } else {
867 | window.setTimeout( process, 13 );
868 | break;
869 | }
870 | }
871 | if (!config.blocking && !config.queue.length) {
872 | done();
873 | }
874 | }
875 |
876 | function saveGlobal() {
877 | config.pollution = [];
878 |
879 | if ( config.noglobals ) {
880 | for ( var key in window ) {
881 | config.pollution.push( key );
882 | }
883 | }
884 | }
885 |
886 | function checkPollution( name ) {
887 | var old = config.pollution;
888 | saveGlobal();
889 |
890 | var newGlobals = diff( config.pollution, old );
891 | if ( newGlobals.length > 0 ) {
892 | ok( false, "Introduced global variable(s): " + newGlobals.join(", ") );
893 | }
894 |
895 | var deletedGlobals = diff( old, config.pollution );
896 | if ( deletedGlobals.length > 0 ) {
897 | ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") );
898 | }
899 | }
900 |
901 | // returns a new Array with the elements that are in a but not in b
902 | function diff( a, b ) {
903 | var result = a.slice();
904 | for ( var i = 0; i < result.length; i++ ) {
905 | for ( var j = 0; j < b.length; j++ ) {
906 | if ( result[i] === b[j] ) {
907 | result.splice(i, 1);
908 | i--;
909 | break;
910 | }
911 | }
912 | }
913 | return result;
914 | }
915 |
916 | function fail(message, exception, callback) {
917 | if ( typeof console !== "undefined" && console.error && console.warn ) {
918 | console.error(message);
919 | console.error(exception);
920 | console.warn(callback.toString());
921 |
922 | } else if ( window.opera && opera.postError ) {
923 | opera.postError(message, exception, callback.toString);
924 | }
925 | }
926 |
927 | function extend(a, b) {
928 | for ( var prop in b ) {
929 | if ( b[prop] === undefined ) {
930 | delete a[prop];
931 | } else {
932 | a[prop] = b[prop];
933 | }
934 | }
935 |
936 | return a;
937 | }
938 |
939 | function addEvent(elem, type, fn) {
940 | if ( elem.addEventListener ) {
941 | elem.addEventListener( type, fn, false );
942 | } else if ( elem.attachEvent ) {
943 | elem.attachEvent( "on" + type, fn );
944 | } else {
945 | fn();
946 | }
947 | }
948 |
949 | function id(name) {
950 | return !!(typeof document !== "undefined" && document && document.getElementById) &&
951 | document.getElementById( name );
952 | }
953 |
954 | // Test for equality any JavaScript type.
955 | // Discussions and reference: http://philrathe.com/articles/equiv
956 | // Test suites: http://philrathe.com/tests/equiv
957 | // Author: Philippe Rathé
958 | QUnit.equiv = function () {
959 |
960 | var innerEquiv; // the real equiv function
961 | var callers = []; // stack to decide between skip/abort functions
962 | var parents = []; // stack to avoiding loops from circular referencing
963 |
964 | // Call the o related callback with the given arguments.
965 | function bindCallbacks(o, callbacks, args) {
966 | var prop = QUnit.objectType(o);
967 | if (prop) {
968 | if (QUnit.objectType(callbacks[prop]) === "function") {
969 | return callbacks[prop].apply(callbacks, args);
970 | } else {
971 | return callbacks[prop]; // or undefined
972 | }
973 | }
974 | }
975 |
976 | var callbacks = function () {
977 |
978 | // for string, boolean, number and null
979 | function useStrictEquality(b, a) {
980 | if (b instanceof a.constructor || a instanceof b.constructor) {
981 | // to catch short annotaion VS 'new' annotation of a declaration
982 | // e.g. var i = 1;
983 | // var j = new Number(1);
984 | return a == b;
985 | } else {
986 | return a === b;
987 | }
988 | }
989 |
990 | return {
991 | "string": useStrictEquality,
992 | "boolean": useStrictEquality,
993 | "number": useStrictEquality,
994 | "null": useStrictEquality,
995 | "undefined": useStrictEquality,
996 |
997 | "nan": function (b) {
998 | return isNaN(b);
999 | },
1000 |
1001 | "date": function (b, a) {
1002 | return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf();
1003 | },
1004 |
1005 | "regexp": function (b, a) {
1006 | return QUnit.objectType(b) === "regexp" &&
1007 | a.source === b.source && // the regex itself
1008 | a.global === b.global && // and its modifers (gmi) ...
1009 | a.ignoreCase === b.ignoreCase &&
1010 | a.multiline === b.multiline;
1011 | },
1012 |
1013 | // - skip when the property is a method of an instance (OOP)
1014 | // - abort otherwise,
1015 | // initial === would have catch identical references anyway
1016 | "function": function () {
1017 | var caller = callers[callers.length - 1];
1018 | return caller !== Object &&
1019 | typeof caller !== "undefined";
1020 | },
1021 |
1022 | "array": function (b, a) {
1023 | var i, j, loop;
1024 | var len;
1025 |
1026 | // b could be an object literal here
1027 | if ( ! (QUnit.objectType(b) === "array")) {
1028 | return false;
1029 | }
1030 |
1031 | len = a.length;
1032 | if (len !== b.length) { // safe and faster
1033 | return false;
1034 | }
1035 |
1036 | //track reference to avoid circular references
1037 | parents.push(a);
1038 | for (i = 0; i < len; i++) {
1039 | loop = false;
1040 | for(j=0;j= 0) {
1185 | type = "array";
1186 | } else {
1187 | type = typeof obj;
1188 | }
1189 | return type;
1190 | },
1191 | separator:function() {
1192 | return this.multiline ? this.HTML ? ' ' : '\n' : this.HTML ? ' ' : ' ';
1193 | },
1194 | indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing
1195 | if ( !this.multiline )
1196 | return '';
1197 | var chr = this.indentChar;
1198 | if ( this.HTML )
1199 | chr = chr.replace(/\t/g,' ').replace(/ /g,' ');
1200 | return Array( this._depth_ + (extra||0) ).join(chr);
1201 | },
1202 | up:function( a ) {
1203 | this._depth_ += a || 1;
1204 | },
1205 | down:function( a ) {
1206 | this._depth_ -= a || 1;
1207 | },
1208 | setParser:function( name, parser ) {
1209 | this.parsers[name] = parser;
1210 | },
1211 | // The next 3 are exposed so you can use them
1212 | quote:quote,
1213 | literal:literal,
1214 | join:join,
1215 | //
1216 | _depth_: 1,
1217 | // This is the list of parsers, to modify them, use jsDump.setParser
1218 | parsers:{
1219 | window: '[Window]',
1220 | document: '[Document]',
1221 | error:'[ERROR]', //when no parser is found, shouldn't happen
1222 | unknown: '[Unknown]',
1223 | 'null':'null',
1224 | 'undefined':'undefined',
1225 | 'function':function( fn ) {
1226 | var ret = 'function',
1227 | name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE
1228 | if ( name )
1229 | ret += ' ' + name;
1230 | ret += '(';
1231 |
1232 | ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join('');
1233 | return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' );
1234 | },
1235 | array: array,
1236 | nodelist: array,
1237 | arguments: array,
1238 | object:function( map ) {
1239 | var ret = [ ];
1240 | QUnit.jsDump.up();
1241 | for ( var key in map )
1242 | ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) );
1243 | QUnit.jsDump.down();
1244 | return join( '{', ret, '}' );
1245 | },
1246 | node:function( node ) {
1247 | var open = QUnit.jsDump.HTML ? '<' : '<',
1248 | close = QUnit.jsDump.HTML ? '>' : '>';
1249 |
1250 | var tag = node.nodeName.toLowerCase(),
1251 | ret = open + tag;
1252 |
1253 | for ( var a in QUnit.jsDump.DOMAttrs ) {
1254 | var val = node[QUnit.jsDump.DOMAttrs[a]];
1255 | if ( val )
1256 | ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' );
1257 | }
1258 | return ret + close + open + '/' + tag + close;
1259 | },
1260 | functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function
1261 | var l = fn.length;
1262 | if ( !l ) return '';
1263 |
1264 | var args = Array(l);
1265 | while ( l-- )
1266 | args[l] = String.fromCharCode(97+l);//97 is 'a'
1267 | return ' ' + args.join(', ') + ' ';
1268 | },
1269 | key:quote, //object calls it internally, the key part of an item in a map
1270 | functionCode:'[code]', //function calls it internally, it's the content of the function
1271 | attribute:quote, //node calls it internally, it's an html attribute value
1272 | string:quote,
1273 | date:quote,
1274 | regexp:literal, //regex
1275 | number:literal,
1276 | 'boolean':literal
1277 | },
1278 | DOMAttrs:{//attributes to dump from nodes, name=>realName
1279 | id:'id',
1280 | name:'name',
1281 | 'class':'className'
1282 | },
1283 | HTML:false,//if true, entities are escaped ( <, >, \t, space and \n )
1284 | indentChar:' ',//indentation unit
1285 | multiline:true //if true, items in a collection, are separated by a \n, else just a space.
1286 | };
1287 |
1288 | return jsDump;
1289 | })();
1290 |
1291 | // from Sizzle.js
1292 | function getText( elems ) {
1293 | var ret = "", elem;
1294 |
1295 | for ( var i = 0; elems[i]; i++ ) {
1296 | elem = elems[i];
1297 |
1298 | // Get the text from text nodes and CDATA nodes
1299 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
1300 | ret += elem.nodeValue;
1301 |
1302 | // Traverse everything else, except comment nodes
1303 | } else if ( elem.nodeType !== 8 ) {
1304 | ret += getText( elem.childNodes );
1305 | }
1306 | }
1307 |
1308 | return ret;
1309 | };
1310 |
1311 | /*
1312 | * Javascript Diff Algorithm
1313 | * By John Resig (http://ejohn.org/)
1314 | * Modified by Chu Alan "sprite"
1315 | *
1316 | * Released under the MIT license.
1317 | *
1318 | * More Info:
1319 | * http://ejohn.org/projects/javascript-diff-algorithm/
1320 | *
1321 | * Usage: QUnit.diff(expected, actual)
1322 | *
1323 | * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over"
1324 | */
1325 | QUnit.diff = (function() {
1326 | function diff(o, n){
1327 | var ns = new Object();
1328 | var os = new Object();
1329 |
1330 | for (var i = 0; i < n.length; i++) {
1331 | if (ns[n[i]] == null)
1332 | ns[n[i]] = {
1333 | rows: new Array(),
1334 | o: null
1335 | };
1336 | ns[n[i]].rows.push(i);
1337 | }
1338 |
1339 | for (var i = 0; i < o.length; i++) {
1340 | if (os[o[i]] == null)
1341 | os[o[i]] = {
1342 | rows: new Array(),
1343 | n: null
1344 | };
1345 | os[o[i]].rows.push(i);
1346 | }
1347 |
1348 | for (var i in ns) {
1349 | if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) {
1350 | n[ns[i].rows[0]] = {
1351 | text: n[ns[i].rows[0]],
1352 | row: os[i].rows[0]
1353 | };
1354 | o[os[i].rows[0]] = {
1355 | text: o[os[i].rows[0]],
1356 | row: ns[i].rows[0]
1357 | };
1358 | }
1359 | }
1360 |
1361 | for (var i = 0; i < n.length - 1; i++) {
1362 | if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null &&
1363 | n[i + 1] == o[n[i].row + 1]) {
1364 | n[i + 1] = {
1365 | text: n[i + 1],
1366 | row: n[i].row + 1
1367 | };
1368 | o[n[i].row + 1] = {
1369 | text: o[n[i].row + 1],
1370 | row: i + 1
1371 | };
1372 | }
1373 | }
1374 |
1375 | for (var i = n.length - 1; i > 0; i--) {
1376 | if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null &&
1377 | n[i - 1] == o[n[i].row - 1]) {
1378 | n[i - 1] = {
1379 | text: n[i - 1],
1380 | row: n[i].row - 1
1381 | };
1382 | o[n[i].row - 1] = {
1383 | text: o[n[i].row - 1],
1384 | row: i - 1
1385 | };
1386 | }
1387 | }
1388 |
1389 | return {
1390 | o: o,
1391 | n: n
1392 | };
1393 | }
1394 |
1395 | return function(o, n){
1396 | o = o.replace(/\s+$/, '');
1397 | n = n.replace(/\s+$/, '');
1398 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/));
1399 |
1400 | var str = "";
1401 |
1402 | var oSpace = o.match(/\s+/g);
1403 | if (oSpace == null) {
1404 | oSpace = [" "];
1405 | }
1406 | else {
1407 | oSpace.push(" ");
1408 | }
1409 | var nSpace = n.match(/\s+/g);
1410 | if (nSpace == null) {
1411 | nSpace = [" "];
1412 | }
1413 | else {
1414 | nSpace.push(" ");
1415 | }
1416 |
1417 | if (out.n.length == 0) {
1418 | for (var i = 0; i < out.o.length; i++) {
1419 | str += '' + out.o[i] + oSpace[i] + "";
1420 | }
1421 | }
1422 | else {
1423 | if (out.n[0].text == null) {
1424 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) {
1425 | str += '' + out.o[n] + oSpace[n] + "";
1426 | }
1427 | }
1428 |
1429 | for (var i = 0; i < out.n.length; i++) {
1430 | if (out.n[i].text == null) {
1431 | str += '' + out.n[i] + nSpace[i] + "";
1432 | }
1433 | else {
1434 | var pre = "";
1435 |
1436 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) {
1437 | pre += '' + out.o[n] + oSpace[n] + "";
1438 | }
1439 | str += " " + out.n[i].text + nSpace[i] + pre;
1440 | }
1441 | }
1442 | }
1443 |
1444 | return str;
1445 | };
1446 | })();
1447 |
1448 | })(this);
1449 |
--------------------------------------------------------------------------------
/resources/lib/jquery-1.6.2.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery JavaScript Library v1.6.2
3 | * http://jquery.com/
4 | *
5 | * Copyright 2011, John Resig
6 | * Dual licensed under the MIT or GPL Version 2 licenses.
7 | * http://jquery.org/license
8 | *
9 | * Includes Sizzle.js
10 | * http://sizzlejs.com/
11 | * Copyright 2011, The Dojo Foundation
12 | * Released under the MIT, BSD, and GPL Licenses.
13 | *
14 | * Date: Thu Jun 30 14:16:56 2011 -0400
15 | */
16 | (function(a,b){function cv(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cs(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cr(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cq(){cn=b}function cp(){setTimeout(cq,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bx(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bm(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(be,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bl(a){f.nodeName(a,"input")?bk(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bk)}function bk(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bj(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bi(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bh(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(a,b){return(a&&a!=="*"?a+".":"")+b.replace(z,"`").replace(A,"&")}function M(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function K(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function E(){return!0}function D(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"$1-$2").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z])/ig,x=function(a,b){return b.toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.6.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.done(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!A){A=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1;var c;for(c in a);return c===b||D.call(a,c)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(b,c,d){a.DOMParser?(d=new DOMParser,c=d.parseFromString(b,"text/xml")):(c=new ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b)),d=c.documentElement,(!d||!d.nodeName||d.nodeName==="parsererror")&&e.error("Invalid XML: "+b);return c},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55$/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0},m&&f.extend(p,{position:"absolute",left:-1e3,top:-1e3});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="