├── vendor
├── sarge
│ ├── .gitignore
│ ├── Rakefile
│ ├── test
│ │ ├── jsTestDriver.conf
│ │ └── tests
│ │ │ └── sarge_test.js
│ ├── Jsfile
│ ├── README.textile
│ ├── doc
│ │ └── api.txt
│ └── sarge.js
├── sarge-eventually
│ ├── .gitmodules
│ ├── test
│ │ ├── jsTestDriver.conf
│ │ └── tests
│ │ │ └── sarge-eventually_test.js
│ ├── README.textile
│ └── sarge-eventually.js
├── copperplate
│ ├── test
│ │ ├── jsTestDriver.conf
│ │ └── tests
│ │ │ └── copperplate_test.js
│ ├── README.textile
│ └── copperplate.js
└── sarge-standards-css-select
│ ├── README.textile
│ └── sarge-standards-css-select.js
├── public
├── js
│ ├── lib
│ │ ├── sarge.js
│ │ ├── js-epub.js
│ │ ├── js-unzip.js
│ │ ├── js-inflate.js
│ │ ├── copperplate.js
│ │ ├── sarge-eventually.js
│ │ └── sarge-standards-css-select.js
│ ├── booktorious
│ │ ├── reader.js
│ │ ├── loading.js
│ │ └── spine_entry.js
│ ├── booktorious.js
│ ├── application.js
│ └── sarge-fu.js
├── screen.css
└── index.html
├── README
└── .gitmodules
/vendor/sarge/.gitignore:
--------------------------------------------------------------------------------
1 | test/lib
2 | vendor
--------------------------------------------------------------------------------
/public/js/lib/sarge.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/sarge/sarge.js
--------------------------------------------------------------------------------
/public/js/lib/js-epub.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/js-epub/js-epub.js
--------------------------------------------------------------------------------
/public/js/lib/js-unzip.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/js-unzip/js-unzip.js
--------------------------------------------------------------------------------
/public/js/lib/js-inflate.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/js-inflate/js-inflate.js
--------------------------------------------------------------------------------
/public/js/lib/copperplate.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/copperplate/copperplate.js
--------------------------------------------------------------------------------
/public/js/lib/sarge-eventually.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/sarge-eventually/sarge-eventually.js
--------------------------------------------------------------------------------
/public/js/lib/sarge-standards-css-select.js:
--------------------------------------------------------------------------------
1 | ../../../vendor/sarge-standards-css-select/sarge-standards-css-select.js
--------------------------------------------------------------------------------
/vendor/sarge-eventually/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "vendor/sarge"]
2 | path = vendor/sarge
3 | url = git://github.com/augustl/sarge.git
4 |
--------------------------------------------------------------------------------
/vendor/copperplate/test/jsTestDriver.conf:
--------------------------------------------------------------------------------
1 | server: http://localhost:4224
2 |
3 | load:
4 | - ../copperplate.js
5 | - tests/*_test.js
6 |
--------------------------------------------------------------------------------
/vendor/sarge/Rakefile:
--------------------------------------------------------------------------------
1 | desc "Generates the documentation in doc/."
2 | task :generate_doc do
3 | exec("asciidoc -a toc doc/api.txt")
4 | end
5 |
--------------------------------------------------------------------------------
/vendor/sarge/test/jsTestDriver.conf:
--------------------------------------------------------------------------------
1 | server: http://localhost:4224
2 |
3 | load:
4 | - ../sarge.js
5 | - lib/*.js
6 | - tests/*_test.js
7 |
--------------------------------------------------------------------------------
/vendor/sarge-standards-css-select/README.textile:
--------------------------------------------------------------------------------
1 | h2. Sarge standards css select
2 |
3 | Adds CSS selectors support to sarge, via the standards document.querySelectorAll.
--------------------------------------------------------------------------------
/vendor/sarge-eventually/test/jsTestDriver.conf:
--------------------------------------------------------------------------------
1 | server: http://localhost:4224
2 |
3 | load:
4 | - ../vendor/sarge/sarge.js
5 | - ../sarge-eventually.js
6 | - tests/*_test.js
7 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | HTML5 EPUB reader proof of concept.
2 |
3 | To get started, run a HTTP server with public/ as document root. Or use file:// to open public/index.html, but that won't work in Chrome.
--------------------------------------------------------------------------------
/vendor/sarge-eventually/README.textile:
--------------------------------------------------------------------------------
1 | h2. sarge-eventually
2 |
3 | Adds basic event binding and event triggering to "sarge":http://github.com/augustl/sarge.
4 |
5 | Tested on IE6-8, Opera 10, Firefox 3.0-3.6, Chrome 5, Safari 5
--------------------------------------------------------------------------------
/vendor/sarge-standards-css-select/sarge-standards-css-select.js:
--------------------------------------------------------------------------------
1 | sarge.api.cssSelect = function (selector, rootNode) {
2 | var nodes = (rootNode || document).querySelectorAll(selector);
3 | return Array.prototype.slice.call(nodes);
4 | };
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "vendor/js-epub"]
2 | path = vendor/js-epub
3 | url = git://github.com/augustl/js-epub.git
4 | [submodule "vendor/js-unzip"]
5 | path = vendor/js-unzip
6 | url = git://github.com/augustl/js-unzip.git
7 | [submodule "vendor/js-inflate"]
8 | path = vendor/js-inflate
9 | url = git://github.com/augustl/js-inflate.git
--------------------------------------------------------------------------------
/vendor/sarge/Jsfile:
--------------------------------------------------------------------------------
1 | # My own unreleased dependency manager. Sorry. Will release it soon.
2 |
3 | group :test do
4 | path "test/lib"
5 |
6 | git "git://gitorious.org/sinon/sinon.git",
7 | :files => ["src/sinon.js", "src/sinon/spy.js", "src/sinon/mock.js", "src/sinon/stub.js", "src/sinon/*.js"],
8 | :out => "sinon.js"
9 | end
10 |
11 |
--------------------------------------------------------------------------------
/public/js/booktorious/reader.js:
--------------------------------------------------------------------------------
1 | booktorious.reader = {
2 | initialize: function (epub) {
3 | booktorious.loadTemplate("reader");
4 | var bookContent = sarge("#book_content");
5 | for (var i = 0, il = epub.opf.spine.length; i < il; i++) {
6 | var spineEntry = booktorious
7 | .create(booktorious.spineEntry);
8 | spineEntry.initialize(epub, i);
9 | spineEntry.renderIframe(bookContent);
10 | }
11 | }
12 | };
--------------------------------------------------------------------------------
/vendor/sarge/README.textile:
--------------------------------------------------------------------------------
1 | h2. Sarge
2 |
3 | Cross browser JavaScript DOM library.
4 |
5 | Sarge itself does not implement any functionality for DOM interaction, this is provided via plugins.
6 |
7 | That's great becaue you can choose how hacky the implementation of the DOM interaction is. Writing a HTML5 app and don't care about IE? Great, use a lightweight hack-free plugin. Need to support IE? Use a hackish IE plugin.
8 |
9 | In other words, you get to use the same top level API - sarge itself - and change the implementation of the DOM interaction via plugins.
10 |
11 | Work in progress.
--------------------------------------------------------------------------------
/public/js/booktorious.js:
--------------------------------------------------------------------------------
1 | this.booktorious = {
2 | loadTemplate: function (name, data) {
3 | var element = sarge("#templates script[data-template-name=" + name + "]");
4 | var template = new Copperplate(element.html());
5 |
6 | if (!this.hasOwnProperty("wrapper")) {
7 | this.wrapper = sarge("#wrapper");
8 | }
9 |
10 | this.wrapper.html(template.html(data || {}));
11 | },
12 |
13 | create: (function () {
14 | function F(){};
15 | return function (proto) {
16 | F.prototype = proto;
17 | return new F();
18 | };
19 | }())
20 | };
--------------------------------------------------------------------------------
/public/screen.css:
--------------------------------------------------------------------------------
1 | html {
2 | background-color: #333;
3 | }
4 |
5 | body {
6 | font-family: Arial, sans-serif;
7 | font-size: 14px;
8 | margin: 0;
9 | }
10 |
11 | .section {
12 | width: 960px;
13 | margin: 20px auto;
14 | }
15 |
16 | #wrapper {
17 | padding: 10px;
18 | background-color: #fff;
19 | }
20 |
21 | #footer {
22 | color: #fff;
23 | }
24 |
25 | #footer a {
26 | color: #999;
27 | }
28 |
29 | h1 {
30 | color: #fff;
31 | background-color: #369;
32 | font-size: 40px;
33 | margin: 0;
34 | padding: 10px;
35 | }
36 |
37 | h2 {
38 | font-size: 25px;
39 | border-bottom: 1px solid #ccc;
40 | }
41 |
42 | .error {
43 | background: #fdd;
44 | padding: 10px;
45 | font-size: 16px;
46 | }
47 |
48 | #book_content iframe {
49 | border: 0;
50 | overflow: hidden;
51 | display: block;
52 | width: 100%;
53 | background-color: #fff;
54 | margin-bottom: 20px;
55 | }
--------------------------------------------------------------------------------
/vendor/sarge-eventually/sarge-eventually.js:
--------------------------------------------------------------------------------
1 | sarge.api.bindEvent = function(element, event, handler) {
2 | var wrappedHandler = function (e) {
3 | if (handler.call(this, e) === false) {
4 | if (e.stopPropagation && e.preventDefault) {
5 | e.stopPropagation();
6 | e.preventDefault();
7 | } else { // Assuming IE
8 | e.cancelBubble = true;
9 | e.returnValue = false;
10 | }
11 | }
12 | }
13 |
14 | if (element.attachEvent) {
15 | element.attachEvent("on" + event, wrappedHandler);
16 | } else if (element.addEventListener) {
17 | element.addEventListener(event, wrappedHandler, false);
18 | }
19 | };
20 |
21 | sarge.api.triggerEvent = function(element, eventName) {
22 | if (document.createEvent) {
23 | var event = document.createEvent("HTMLEvents");
24 |
25 | // Type, can bubble, cancelable.
26 | event.initEvent(eventName, true, true);
27 |
28 | element.dispatchEvent(event);
29 | } else if (element.fireEvent) {
30 | element.fireEvent("on" + eventName);
31 | }
32 | };
--------------------------------------------------------------------------------
/vendor/sarge-eventually/test/tests/sarge-eventually_test.js:
--------------------------------------------------------------------------------
1 | TestCase("SargeEventuallyTest", {
2 | setUp: function () {
3 | /*:DOC element =
*/
4 | this.e = sarge(this.element);
5 | },
6 |
7 | "test binding and triggering event": function () {
8 | var timesCalled = 0;
9 |
10 | this.e.event("click", function () {
11 | timesCalled++;
12 | });
13 |
14 | this.e.event("click");
15 | this.e.event("click");
16 |
17 | assertEquals(2, timesCalled);
18 | },
19 |
20 |
21 | "test returning false to stop propagation and default": function () {
22 | /*:DOC+=*/
23 |
24 | var calls = [];
25 | var foo = sarge(document.getElementById("foo"));
26 | var bar = sarge(document.getElementById("bar"));
27 |
28 | foo.event("click", function () {
29 | calls.push("foo");
30 | return false;
31 | });
32 |
33 | bar.event("click", function () {
34 | calls.push("bar");
35 | return false;
36 | });
37 |
38 | bar.event("click");
39 |
40 | assertEquals(["bar"], calls);
41 | }
42 | });
--------------------------------------------------------------------------------
/public/js/booktorious/loading.js:
--------------------------------------------------------------------------------
1 | booktorious.loading = {
2 | initialize: function (blob) {
3 | var self = this;
4 | booktorious.loadTemplate("loading");
5 | this.blob = blob;
6 | this.messageTarget = sarge("#message");
7 | this.epub = new JSEpub(this.blob);
8 | this.epub.processInSteps(function (step, extras) {
9 | self.step(step, extras);
10 | });
11 | },
12 |
13 | step: function (stepId, extras) {
14 | if (stepId === 1) {
15 | this.addMessage("Unarchiving");
16 | } else if (stepId === 2) {
17 | this.addMessage("Uncompressing " + extras);
18 | } else if (stepId === 3 || stepId === 4) {
19 | this.addMessage("Post processing")
20 | } else if (stepId === 5) {
21 | booktorious
22 | .create(booktorious.reader)
23 | .initialize(this.epub);
24 | } else if (stepId === -1) {
25 | this.addMessage("The file does not seem to be an EPUB.");
26 | } else if (stepId < 0) {
27 | this.addMessage("An unknown error occured.");
28 | } else {
29 | // Wtf.
30 | }
31 | },
32 |
33 | addMessage: function (msg) {
34 | this.messageTarget.html(msg);
35 | }
36 | };
--------------------------------------------------------------------------------
/public/js/booktorious/spine_entry.js:
--------------------------------------------------------------------------------
1 | booktorious.spineEntry = {
2 | initialize: function (epub, i) {
3 | this.epub = epub;
4 | this.href = this.epub.opf.manifest[this.epub.opf.spine[i]]["href"];
5 | this.doc = this.epub.files[this.href];
6 | this.iframe = document.createElement("iframe");
7 | },
8 |
9 | renderIframe: function (target) {
10 | var self = this;
11 |
12 | target.append(this.iframe);
13 |
14 | this.iframe.contentDocument.open();
15 | var html = new XMLSerializer().serializeToString(this.doc);
16 | this.iframe.contentDocument.write(html);
17 | this.contentResizeIframe();
18 | this.iframe.contentDocument.close();
19 |
20 | sarge(this.iframe.contentDocument).find("img").event("load", function () {
21 | self.contentResizeIframe();
22 | });
23 |
24 | var links = sarge(this.iframe.contentDocument).find("a");
25 | links.event("mouseover", function (e) {});
26 | links.event("mouseout", function (e) {});
27 | links.event("click", function (e) {
28 | // self.didClickAnchor(sarge(this).attr("href"));
29 | // alert("Internal linking doesn't work yet.");
30 | return false;
31 | });
32 | },
33 |
34 | contentResizeIframe: function () {
35 | sarge(this.iframe)
36 | .attr("height", this.iframe.contentDocument.height)
37 | .attr("height", this.iframe.contentDocument.documentElement.scrollHeight);
38 | }
39 | };
--------------------------------------------------------------------------------
/vendor/copperplate/README.textile:
--------------------------------------------------------------------------------
1 | h2. Copperplate.
2 |
3 | JavaScript templating engine with HTML syntax.
4 |
5 | HTML syntax is a good idea. It blends in with your text editors HTML mode. Proper indentation in if/else blocks with no editor configuration, yay!
6 |
7 | h2. Control flow
8 |
9 | If and else.
10 |
11 | var t = new Copperplate("Hello, World!Moon.");
12 |
13 | t.html({thing: true}); // "Hello, World!"
14 | t.html({thing: false}); // "Hello, Moon."
15 |
16 | Elseif.
17 |
18 | var t = new Copperplate("OneTwo");
19 |
20 | t.html({one: true, two: false}); // "One"
21 | t.html({one: false, two: true}); // "Two"
22 | t.html({one: false, two: false}); // ""
23 |
24 | Nesting.
25 |
26 | var t = new Copperplate(""
27 | + ""
28 | + "two"
29 | + ""
30 | + "three"
31 | + ""
32 | + "");
33 |
34 | t.html({one: true, two: true, three: false}); // "two"
35 | t.html({one: true, two: false, three: false}); // ""
36 | t.html({one: true, two: false, three: true}); // "three"
37 | t.html({one: false, two: false, three: true}); // ""
38 |
39 |
40 |
41 | h2. Variables
42 |
43 | The variable syntax is {{foo}}.
44 |
45 | var t = new Copperplate('Hello, {{thing}}!');
46 | t.html({thing: "World"}) // "Hello, World!";
47 | t.html({thing: "Moon"}) // "Hello, Moon!";
--------------------------------------------------------------------------------
/public/js/application.js:
--------------------------------------------------------------------------------
1 | sarge(window).event("load", function () {
2 | var fileReaderSupported = ("FileReader" in window);
3 |
4 | function showLoading(blob) {
5 | booktorious.create(booktorious.loading).initialize(blob);
6 | };
7 |
8 | function handleFiles(files) {
9 | var file = files[0];
10 | if (file) {
11 | var reader = new FileReader();
12 | reader.onloadend = function () {
13 | showLoading(reader.result);
14 | };
15 | reader.onerror = function (event) {
16 | alert("An error occurred while reading the file. Error code: " + event.target.error.code);
17 | };
18 | reader.readAsBinaryString(file);
19 | } else {
20 | alert("No file chosen.");
21 | }
22 | };
23 |
24 | booktorious.loadTemplate("choose_file", {
25 | inputFileReadSupported: fileReaderSupported
26 | });
27 |
28 | if (!fileReaderSupported) { return; }
29 |
30 | var fileInput = sarge("input[type=file]").element();
31 | sarge("button").event("click", function () {
32 | if ("files" in fileInput) {
33 | handleFiles(fileInput.files);
34 | }
35 | });
36 |
37 | sarge(window)
38 | .event("dragover", function () {
39 | return false;
40 | })
41 | .event("drop", function (e) {
42 | if ("dataTransfer" in e) {
43 | if ("files" in e.dataTransfer) {
44 | handleFiles(e.dataTransfer.files);
45 | }
46 | }
47 | return false;
48 | });
49 | });
--------------------------------------------------------------------------------
/public/js/sarge-fu.js:
--------------------------------------------------------------------------------
1 | /* A custom Firefox/Chrome compatible API implementation for sarge. */
2 | sarge.api.getAttribute = function (element, attribute) {
3 | return element.getAttribute(attribute);
4 | };
5 |
6 | sarge.api.setAttribute = function (element, attribute, value) {
7 | element.setAttribute(attribute, value);
8 | };
9 |
10 | sarge.api.getHtml = function (element) {
11 | return element.innerHTML;
12 | };
13 |
14 | sarge.api.setHtml = function (element, html) {
15 | if (html instanceof sarge) {
16 | sarge(element).clear().append(html);
17 | } else {
18 | element.innerHTML = html;
19 | }
20 | };
21 |
22 |
23 | sarge.api.clear = function (element) {
24 | while (element.firstChild) {
25 | element.removeChild(element.firstChild);
26 | }
27 | };
28 |
29 | sarge.api.append = function (element, html) {
30 | if (html instanceof sarge) {
31 | element.appendChild(html.element());
32 | } else if (typeof html === "string") {
33 | element.innerHTML = element.innerHTML + html;
34 | } else {
35 | element.appendChild(html);
36 | }
37 | };
38 |
39 |
40 | sarge.api.hide = function (element) {
41 | element.style.display = "none";
42 | };
43 |
44 | sarge.api.show = function (element) {
45 | element.style.display = "inherit";
46 | };
47 |
48 |
49 | (function () {
50 | var regexpSpecials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g");
51 | var regexpEscape = function (string) {
52 | return string.replace(regexpSpecials, "\\$&");
53 | };
54 | var classRegexp = function (cssClass) {
55 | return new RegExp("\\s?\\b" + regexpEscape(cssClass) + "\\b\\s?");
56 | };
57 |
58 | sarge.api.addClass = function (element, cssClass) {
59 | var s = sarge(element);
60 | if (!s.hasClass(cssClass)) {
61 | var current = s.attr("class");
62 | if (current) {
63 | s.attr("class", current + " " + cssClass);
64 | } else {
65 | s.attr("class", cssClass);
66 | }
67 | }
68 | };
69 |
70 | sarge.api.removeClass = function (element, cssClass) {
71 | var s = sarge(element);
72 | var r = classRegexp(cssClass);
73 | if (s.hasClass(cssClass)) {
74 | s.attr("class", s.attr("class").replace(r, ""));
75 | }
76 | };
77 |
78 | sarge.api.hasClass = function (element, cssClass) {
79 | var r = classRegexp(cssClass);
80 | return r.test(sarge(element).attr("class"));
81 | };
82 | }());
--------------------------------------------------------------------------------
/vendor/sarge/doc/api.txt:
--------------------------------------------------------------------------------
1 | Sarge 1.0 plugin API documentation
2 | ==================================
3 |
4 | Documentation for the API that Sarge plugins use to implement functionality in Sarge.
5 |
6 | :Author: August Lilleaas
7 | :Email:
8 |
9 | :All elements: The function is called on all the elements in the sarge instance.
10 | :One element: The function is only called on the first element in the sarge instance.
11 |
12 | Sarge Core
13 | ----------
14 |
15 | cssSelect(selector)
16 | ~~~~~~~~~~~~~~~~~~~
17 |
18 | Performs a CSS selector query on `document`. Returns an array.
19 |
20 | [source,javascript]
21 | sarge("a css selector");
22 |
23 | cssSelect(selector,rootNode)
24 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 |
26 | Like `cssSelect`, but runs the query on `rootNode` instead of `document`.
27 |
28 | [source,javascript]
29 | sarge(foo).find("a css selector");
30 |
31 |
32 | Attributes
33 | ----------
34 |
35 | attr(name)
36 | ~~~~~~~~~~
37 |
38 | Gets an attribute.
39 |
40 | [source,javascript]
41 | sarge(foo).attr("id");
42 |
43 | {oneelement}
44 |
45 | attr(name,value)
46 | ~~~~~~~~~~~~~~~~
47 |
48 | Sets an attribute.
49 |
50 | [source,javascript]
51 | sarge(foo).attr("href", myHref);
52 |
53 | {allelements}
54 |
55 | addClass(class)
56 | ~~~~~~~~~~~~~~~
57 |
58 | Adds a class to the elements.
59 |
60 | [source,javascript]
61 | sarge(foo).addClass("my_class");
62 |
63 | {allelements}
64 |
65 | removeClass(class)
66 | ~~~~~~~~~~~~~~~~~~
67 |
68 | Removes a class to the elements.
69 |
70 | [source,javascript]
71 | sarge(foo).removeClass("my_class");
72 |
73 | {allelements}
74 |
75 | hasClass(class)
76 | ~~~~~~~~~~~~~~~
77 |
78 | Checks if the element has a class.
79 |
80 | [source,javascript]
81 | sarge(foo).hasClass("my_class");
82 |
83 | {oneelement}
84 |
85 | CSS
86 | ---
87 |
88 | hide()
89 | ~~~~~~
90 |
91 | Hides the elements.
92 |
93 | [source,javascript]
94 | sarge(foo).hide();
95 |
96 | {allelements}
97 |
98 | show()
99 | ~~~~~~
100 |
101 | Shows the elements.
102 |
103 | [source,javascript]
104 | sarge(foo).show();
105 |
106 | {allelements}
107 |
108 | Events
109 | ------
110 |
111 | event(name)
112 | ~~~~~~~~~~~
113 |
114 | Triggers an event.
115 |
116 | [source,javascript]
117 | sarge(foo).event("click");
118 |
119 | {allelements}
120 |
121 | event(name, function)
122 | ~~~~~~~~~~~~~~~~~~~~~
123 |
124 | Binds an event.
125 |
126 | [source,javascript]
127 | sarge(foo).event("click", function () { ... });
128 |
129 | {allelements}
130 |
131 |
132 | Manipulation
133 | ------------
134 |
135 | append(thing)
136 | ~~~~~~~~~~~~~
137 |
138 | Appends HTML to an element.
139 |
140 | [source,javascript]
141 | sarge(foo).append(thing);
142 |
143 | {allelements}
144 |
145 | clear()
146 | ~~~~~~~
147 |
148 | Removes all content from the elements.
149 |
150 | [source,javascript]
151 | sarge(foo).clear();
152 |
153 | {allelements}
154 |
155 | html()
156 | ~~~~~~
157 |
158 | Gets the inner HTML.
159 |
160 | [source,javascript]
161 | sarge(foo).html();
162 |
163 | {oneelement}
164 |
165 | html(myHtml)
166 | ~~~~~~~~~~~~
167 |
168 | Sets the inner HTML of an element.
169 | [source,javascript]
170 | sarge(foo).html(myHtml);
171 |
172 | {allelements}
173 |
174 | Traversing
175 | ----------
176 |
177 | find(selector)
178 | ~~~~~~~~~~~~~~
179 |
180 | Finds children by CSS selector. Returns a new sarge instance.
181 |
182 | [source,javascript]
183 | sarge(foo).find(".my_thing");
184 |
185 | {oneelement}
186 |
--------------------------------------------------------------------------------
/vendor/sarge/sarge.js:
--------------------------------------------------------------------------------
1 | (function (GLOBAL) {
2 | /*
3 | * The core. Does nothing useful by itself. Needs plugins.
4 | *
5 | */
6 | var sarge = function (obj) {
7 | if (!(this instanceof sarge)) {
8 | return new sarge(obj);
9 | }
10 |
11 | var t = typeof(obj);
12 |
13 | if (t === "string") {
14 | this.elements = this.callApiFunction("cssSelect", obj);
15 | } else if (obj instanceof sarge) {
16 | return obj;
17 | } else if (obj instanceof Array) {
18 | this.elements = obj;
19 | } else if (t === "object") {
20 | this.elements = [obj];
21 | } else {
22 | throw new TypeError("Invalid object '" + obj + "' passed to sarge().");
23 | }
24 | };
25 |
26 | // API functions lives here.
27 | sarge.api = {};
28 |
29 | sarge.prototype = {
30 | event: function (name, listener) {
31 | if (listener) {
32 | this.withElements("bindEvent", name, listener);
33 | } else {
34 | this.withElements("triggerEvent", name);
35 | }
36 |
37 | return this;
38 | },
39 |
40 | html: function (html) {
41 | if (html === undefined) {
42 | return this.withElement("getHtml");
43 | } else {
44 | this.withElements("setHtml", html);
45 | return this;
46 | }
47 | },
48 |
49 | append: function (html) {
50 | this.withElements("append", html);
51 | return this;
52 | },
53 |
54 | clear: function () {
55 | this.withElements("clear");
56 | return this;
57 | },
58 |
59 | find: function (selector) {
60 | return sarge(this.callApiFunction("cssSelect", selector, this.element()));
61 | },
62 |
63 | hide: function () {
64 | this.withElements("hide");
65 | return this;
66 | },
67 |
68 | show: function () {
69 | this.withElements("show");
70 | return this;
71 | },
72 |
73 | addClass: function (className) {
74 | this.withElements("addClass", className);
75 | return this;
76 | },
77 |
78 | removeClass: function (className) {
79 | this.withElements("removeClass", className);
80 | return this;
81 | },
82 |
83 | hasClass: function (className) {
84 | return this.withElement("hasClass", className);
85 | },
86 |
87 | attr: function (attribute, value) {
88 | if (value === undefined) {
89 | return this.withElement("getAttribute", attribute);
90 | } else {
91 | this.withElements("setAttribute", attribute, value);
92 | return this;
93 | }
94 | },
95 |
96 | /*
97 | * Returns the first element in the list, or throws an error
98 | * if no elements are in the list.
99 | */
100 | element: function () {
101 | if (this.elements.length === 0) {
102 | throw "No elements."
103 | } else {
104 | return this.elements[0];
105 | }
106 | },
107 |
108 | withElement: function () {
109 | return this.callApiFunctionForElement(this.element(), arguments);
110 | },
111 |
112 | /*
113 | * Calls API function once for each element in this.elements.
114 | *
115 | * First argument is the name of the API function. The API function
116 | * will get [theElement, arguments, passed, to, withElements, here]
117 | * passed to it.
118 | *
119 | */
120 | withElements: function () {
121 | for (var i = 0, il = this.elements.length; i < il; i++) {
122 | this.callApiFunctionForElement(this.elements[i], arguments);
123 | }
124 | },
125 |
126 | callApiFunctionForElement: function (element, args) {
127 | var args = Array.prototype.slice.call(args);
128 | // Add element as 2nd item in array.
129 | args.splice(1, 0, element);
130 | return this.callApiFunction.apply(this, args);
131 | },
132 |
133 | /*
134 | * Calls an API function. An API function is a function on
135 | * sarge.Instance.prototype.
136 | *
137 | * The first argument is the name of the API function. All successive
138 | * arguments are passed to that function.
139 | *
140 | */
141 | callApiFunction: function () {
142 | var args = Array.prototype.slice.call(arguments);
143 | var apiFunc = args.shift();
144 |
145 | if (typeof(sarge.api[apiFunc]) === "function") {
146 | return sarge.api[apiFunc].apply(this, args);
147 | } else {
148 | throw "Sarge: API for '" + apiFunc + "' has not been loaded.";
149 | }
150 | }
151 | };
152 |
153 | GLOBAL.sarge = sarge;
154 | sarge.originalDollar = GLOBAL.$;
155 | GLOBAL.$ = sarge;
156 |
157 | sarge.noConflict = function () {
158 | GLOBAL.$ = sarge.originalDollar;
159 | }
160 |
161 | }(this));
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
Loading..
24 |
If you see this message for more than a second or so, your browser isn't supported.
25 |
The site has only been tested to work in Chromium 5 and Firefox 3.6.
26 |
27 |
28 |
29 |
33 |
34 |
35 |
93 |
97 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/vendor/copperplate/copperplate.js:
--------------------------------------------------------------------------------
1 | (function (GLOBAL) {
2 | var Copperplate = function (template) {
3 | this.template = template;
4 | }
5 |
6 | Copperplate.prototype = {
7 | html: function (data) {
8 | var elements = this.template.match(/\<[^\>]+\>|[^\<]+/g);
9 | var out = [];
10 | var ifBlocks = [];
11 | var previousTagWasConditionalEndTag;
12 |
13 | for (var i = 0, il = elements.length; i < il; i++) {
14 | var e = this.insertVariables(elements[i], data);
15 | var ifBlocksEntry = ifBlocks[ifBlocks.length - 1];
16 |
17 | // End tag
18 | if (/^\<\//.test(e)) {
19 | var t = this.getTag(e);
20 |
21 | if (t[0] === "if") {
22 | previousTagWasConditionalEndTag = true;
23 | ifBlocksEntry.previousEndTag = "if";
24 | } else if (t[0] === "else") {
25 | previousTagWasConditionalEndTag = true;
26 | if (ifBlocks.length === 0) {
27 | throw Error("Unexpected else, not in a tree.")
28 | }
29 |
30 | ifBlocksEntry.previousEndTag = "else";
31 |
32 | ifBlocks.pop();
33 | } else if (t[0] === "elseif") {
34 | if (previousTagWasConditionalEndTag) {
35 | ifBlocks.pop();
36 | }
37 |
38 | previousTagWasConditionalEndTag = true;
39 | if (ifBlocks.length === 0) {
40 | throw Error("Unexpected elseif, not in a tree.")
41 | }
42 |
43 | ifBlocksEntry.previousEndTag = "elseif";
44 | } else {
45 | if (ifBlocksEntry) {
46 | if (previousTagWasConditionalEndTag && ifBlocksEntry.previousEndTag) {
47 | ifBlocks.pop();
48 | }
49 | }
50 |
51 | if (!this.ifBlocksContainsFalse(ifBlocks)) {
52 | out.push(e);
53 | }
54 | }
55 |
56 |
57 | // Start tag
58 | } else if (/^\]+)/);
154 | if (rawAttrs) {
155 | data = rawAttrs[1].split(/ +/g);
156 | var attrs = [];
157 | for (var i = 0, il = data.length; i < il; i++) {
158 | var split = data[i].split("=");
159 | var val = split[1] || null;
160 |
161 | if (val) {
162 | val = val.replace(/^['"](.*?)['"]$/, "$1");
163 | }
164 |
165 | attrs.push([split[0], val]);
166 | }
167 | out.push(attrs);
168 | } else {
169 | out.push([]);
170 | }
171 |
172 | return out;
173 | },
174 |
175 | insertVariables: function (string, data) {
176 | return string.replace(/{{([^}]+)}}/, function (all, key) {
177 | return data[key] || "";
178 | });
179 | }
180 | }
181 |
182 | GLOBAL.Copperplate = Copperplate;
183 | }(this));
--------------------------------------------------------------------------------
/vendor/sarge/test/tests/sarge_test.js:
--------------------------------------------------------------------------------
1 | TestCase("SargeTest", {
2 | tearDown: function() {
3 | sarge.api = {};
4 | },
5 |
6 | "test passing string calls cssSelect": function () {
7 | sarge.api.cssSelect = sinon.spy();
8 |
9 | sarge("foo");
10 | sarge("bar");
11 |
12 | assertTrue(sarge.api.cssSelect.calledTwice);
13 | assertTrue(sarge.api.cssSelect.getCall(0).calledWithExactly("foo"))
14 | assertTrue(sarge.api.cssSelect.getCall(1).calledWithExactly("bar"))
15 | },
16 |
17 | "test passing string stores in elements": function () {
18 | sarge.api.cssSelect = function () { return [1, 2] };
19 | var s = sarge("foo");
20 | assertEquals([1, 2], s.elements);
21 | },
22 |
23 | "test passing object stores in elements": function () {
24 | var obj = {};
25 | var s = sarge(obj);
26 | assertEquals([obj], s.elements);
27 | },
28 |
29 | "test passing array stores it as elements directly": function () {
30 | var s = sarge([1, 2]);
31 | assertEquals([1, 2], s.elements);
32 | },
33 |
34 | "test passing sarge objects returns the sarge object": function () {
35 | sarge.api.cssSelect = sinon.stub();
36 | var s = sarge("foo");
37 | assertSame(s, sarge(s));
38 | },
39 |
40 | "test withElement": function () {
41 | sarge.api.hide = sinon.stub();
42 | var s = sarge(["abc", "123"]);
43 | s.withElement("hide");
44 |
45 | assertTrue(sarge.api.hide.calledOnce);
46 | assertTrue(sarge.api.hide.getCall(0).calledWithExactly("abc"));
47 | },
48 |
49 | "test with elements": function () {
50 | var s = sarge([]);
51 | s.elements = ["foo", "bar", "baz"];
52 | sarge.api.goWild = sinon.spy();
53 | s.withElements("goWild", 123, "abc");
54 |
55 | assertTrue(sarge.api.goWild.calledThrice);
56 | assertTrue(sarge.api.goWild.getCall(0).calledWithExactly("foo",123,"abc"));
57 | assertTrue(sarge.api.goWild.getCall(1).calledWithExactly("bar",123,"abc"));
58 | assertTrue(sarge.api.goWild.getCall(2).calledWithExactly("baz",123,"abc"));
59 | },
60 |
61 | "test calling none existing api function": function () {
62 | expectAsserts(1);
63 |
64 | var s = sarge({});
65 | try {
66 | s.callApiFunction("doesNotExist");
67 | } catch (e) {
68 | assertTrue(true);
69 | }
70 | },
71 |
72 | "test find": function () {
73 | sarge.api.cssSelect = function () { return [1, 2] };
74 | var s = sarge({}).find("stubbed");
75 | assertEquals([1, 2], s.elements);
76 | },
77 |
78 | "test element with elements": function () {
79 | var s = sarge(["abc", "123"]);
80 | assertEquals("abc", s.element());
81 | },
82 |
83 | "test element without elements": function () {
84 | expectAsserts(1);
85 | var s = sarge([]);
86 |
87 | try {
88 | s.element()
89 | } catch(e) {
90 | assertTrue(true);
91 | }
92 | },
93 |
94 | "test dollar and noConflict": function () {
95 | // TODO: Figure out how to test this properly.
96 | }
97 | });
98 |
99 | TestCase("SargeApiProxiesTest", {
100 | tearDown: function() {
101 | sarge.api = {};
102 | },
103 |
104 | "test binding event": function () {
105 | var obj = {};
106 | var listener = function () {};
107 | sarge.api.bindEvent = sinon.stub();
108 |
109 | var s = sarge(obj);
110 | assertSame(s, s.event("foo", listener));
111 | assertTrue(sarge.api.bindEvent.calledOnce);
112 | assertTrue(sarge.api.bindEvent.getCall(0).calledWithExactly(obj, "foo", listener));
113 | },
114 |
115 | "test triggering event": function () {
116 | var obj = {};
117 | sarge.api.triggerEvent = sinon.stub();
118 |
119 | var s = sarge(obj);
120 | assertSame(s, s.event("foo"));
121 |
122 | assertTrue(sarge.api.triggerEvent.calledOnce);
123 | assertTrue(sarge.api.triggerEvent.getCall(0).calledWithExactly(obj, "foo"));
124 | },
125 |
126 | "test getting html": function () {
127 | var obj = {};
128 | var args;
129 | sarge.api.getHtml = sinon.spy(function (el) { return "foo" });
130 |
131 | var s = sarge(obj);
132 |
133 | assertEquals("foo", s.html());
134 | assertTrue(sarge.api.getHtml.calledOnce);
135 | assertTrue(sarge.api.getHtml.getCall(0).calledWithExactly(obj))
136 | },
137 |
138 | "test setting html": function () {
139 | var obj = {};
140 | sarge.api.setHtml = sinon.spy();;
141 |
142 | var s = sarge(obj);
143 | assertSame(s, s.html("foo"));
144 | assertTrue(sarge.api.setHtml.calledOnce);
145 | assertTrue(sarge.api.setHtml.getCall(0).calledWithExactly(obj, "foo"));
146 | },
147 |
148 | "test append": function () {
149 | var obj = {};
150 | sarge.api.append = sinon.spy();
151 |
152 | var s = sarge(obj);
153 | assertSame(s, s.append("foo"));
154 | assertTrue(sarge.api.append.calledOnce);
155 | assertTrue(sarge.api.append.getCall(0).calledWithExactly(obj, "foo"))
156 | },
157 |
158 | "test clear": function () {
159 | var obj = {};
160 | sarge.api.clear = sinon.spy();
161 |
162 | var s = sarge(obj);
163 | assertSame(s, s.clear());
164 | assertTrue(sarge.api.clear.calledOnce);
165 | assertTrue(sarge.api.clear.getCall(0).calledWithExactly(obj));
166 | },
167 |
168 | "test find": function () {
169 | var obj = {};
170 | var args;
171 | sarge.api.cssSelect = sinon.spy(function () { return [] });
172 |
173 | var s = sarge(obj);
174 | var res = s.find("foo");
175 | assertNotSame(s, res);
176 | assertTrue(res instanceof sarge);
177 |
178 | assertTrue(sarge.api.cssSelect.calledOnce)
179 | assertTrue(sarge.api.cssSelect.getCall(0).calledWithExactly("foo", obj))
180 | },
181 |
182 | "test hide": function () {
183 | var obj = {};
184 | sarge.api.hide = sinon.spy();
185 |
186 | var s = sarge(obj);
187 | assertSame(s, s.hide());
188 | assertTrue(sarge.api.hide.calledOnce)
189 | assertTrue(sarge.api.hide.getCall(0).calledWithExactly(obj));
190 | },
191 |
192 | "test show": function () {
193 | var obj = {};
194 | sarge.api.show = sinon.spy();
195 |
196 | var s = sarge(obj);
197 | assertSame(s, s.show());
198 | assertTrue(sarge.api.show.calledOnce);
199 | assertTrue(sarge.api.show.getCall(0).calledWithExactly(obj));
200 | },
201 |
202 | "test addClass": function () {
203 | var obj = {};
204 | sarge.api.addClass = sinon.spy();
205 |
206 | var s = sarge(obj);
207 | assertSame(s, s.addClass("foo"));
208 | assertTrue(sarge.api.addClass.calledOnce);
209 | assertTrue(sarge.api.addClass.getCall(0).calledWithExactly(obj, "foo"));
210 | },
211 |
212 | "test removeClass": function () {
213 | var obj = {};
214 | sarge.api.removeClass = sinon.spy();
215 |
216 | var s = sarge(obj);
217 | assertSame(s, s.removeClass("foo"));
218 | assertTrue(sarge.api.removeClass.calledOnce);
219 | assertTrue(sarge.api.removeClass.getCall(0).calledWithExactly(obj, "foo"));
220 | },
221 |
222 | "test hasClass": function () {
223 | var obj = {};
224 | var args;
225 | sarge.api.hasClass = sinon.spy(function () { return true });
226 |
227 | var s = sarge(obj);
228 | assertTrue(s.hasClass("foo"));
229 | assertTrue(sarge.api.hasClass.calledOnce);
230 | assertTrue(sarge.api.hasClass.getCall(0).calledWithExactly(obj, "foo"))
231 | },
232 |
233 | "test getting attr": function () {
234 | var obj = {};
235 | var args;
236 | sarge.api.getAttribute = sinon.spy(function () { return "foo" });
237 |
238 | var s = sarge(obj);
239 | assertEquals("foo", s.attr("anything"));
240 | assertTrue(sarge.api.getAttribute.calledOnce);
241 | assertTrue(sarge.api.getAttribute.getCall(0).calledWithExactly(obj, "anything"))
242 | },
243 |
244 | "test setting attr": function () {
245 | var obj = {};
246 | sarge.api.setAttribute = sinon.spy();
247 |
248 | var s = sarge(obj);
249 | assertSame(s, s.attr("foo", "bar"));
250 | assertTrue(sarge.api.setAttribute.calledOnce);
251 | assertTrue(sarge.api.setAttribute.getCall(0).calledWithExactly(obj, "foo", "bar"))
252 | }
253 | });
--------------------------------------------------------------------------------
/vendor/copperplate/test/tests/copperplate_test.js:
--------------------------------------------------------------------------------
1 | TestCase("CopperplateControlFlowTest", {
2 | "test basic if": function () {
3 | var t = 'this';
4 |
5 | assertEquals("this", new Copperplate(t).html({someCondition: true}));
6 | assertEquals("", new Copperplate(t).html({someCondition: false}));
7 | },
8 |
9 | "test basic if with falsey value": function () {
10 | var t = 'this';
11 |
12 | assertEquals("this", new Copperplate(t).html({someCondition: true}));
13 | assertEquals("", new Copperplate(t).html({}));
14 | },
15 |
16 | "test with function as condition": function () {
17 | var t = new Copperplate('a');
18 |
19 | assertEquals("a", t.html({a: function () { return true }}));
20 | assertEquals("", t.html({a: function () { return false }}));
21 | assertEquals("", t.html({a: function () { }}));
22 | },
23 |
24 | "test with function as condition it sets the scope": function () {
25 | var t = new Copperplate('a');
26 | obj = {
27 | a: function () {
28 | return this.shouldRender;
29 | }
30 | }
31 |
32 | obj.shouldRender = true;
33 | assertEquals("a", t.html(obj));
34 |
35 | obj.shouldRender = false;
36 | assertEquals("", t.html(obj));
37 | },
38 |
39 | "test two ifs": function () {
40 | var t = 'thisthat';
41 |
42 | assertEquals("this", new Copperplate(t).html({a: true, b: false}));
43 | assertEquals("thisthat", new Copperplate(t).html({a: true, b: true}));
44 | assertEquals("that", new Copperplate(t).html({a: false, b: true}));
45 | assertEquals("", new Copperplate(t).html({a: false, b: false}));
46 | },
47 |
48 | "test basic if/else": function () {
49 | var t = 'thisthat';
50 |
51 | assertEquals("this", new Copperplate(t).html({someCondition: true}));
52 | assertEquals("that", new Copperplate(t).html({someCondition: false}));
53 | },
54 |
55 | "test basic if/else with whitespace": function () {
56 | var t = 'this that';
57 |
58 | assertEquals("this ", new Copperplate(t).html({someCondition: true}));
59 | assertEquals(" that", new Copperplate(t).html({someCondition: false}));
60 | },
61 |
62 | "test basic if/elseif": function () {
63 | var t = 'thisthat';
64 |
65 | assertEquals("this", new Copperplate(t).html({a: true, b: false}));
66 | assertEquals("this", new Copperplate(t).html({a: true, b: true}));
67 | assertEquals("that", new Copperplate(t).html({a: false, b: true}));
68 | assertEquals("", new Copperplate(t).html({a: false, b: false}));
69 | },
70 |
71 | "test if/elseif/else": function() {
72 | var t = 'foobarbaz';
73 |
74 | assertEquals("foo", new Copperplate(t).html({a: true, b: false}));
75 | assertEquals("bar", new Copperplate(t).html({a:false, b: true}));
76 | assertEquals("baz", new Copperplate(t).html({a: false, b: false}));
77 | },
78 |
79 | "test nested ifs": function () {
80 | var t = 'helloworld';
81 | assertEquals("world", new Copperplate(t).html({
82 | something: true,
83 | last: true,
84 | other: false
85 | }));
86 | },
87 |
88 | "test nesting hell": function() {
89 | var t =
90 | 'a'
91 | + 'b'
92 | + 'c'
93 | + 'd'
94 | + ''
95 | + 'xefg';
96 |
97 | assertEquals("a", new Copperplate(t).html({
98 | a: true, b: false, c: false, d:false, e: false, f: false
99 | }));
100 |
101 | assertEquals("bc", new Copperplate(t).html({
102 | a: false, b: true, c: true, d:false, e: false, f: false
103 | }));
104 |
105 | assertEquals("bd", new Copperplate(t).html({
106 | a: false, b: true, c: false, d:true, e: false, f: false
107 | }));
108 |
109 | assertEquals("b", new Copperplate(t).html({
110 | a: false, b: true, c: false, d:false, e: false, f: false
111 | }));
112 |
113 | assertEquals("xg", new Copperplate(t).html({
114 | a: false, b: false, c: false, d:false, e: false, f: false
115 | }));
116 |
117 | assertEquals("xg", new Copperplate(t).html({
118 | a: false, b: false, c: false, d:false, e: false, f: false
119 | }));
120 |
121 | assertEquals("xeg", new Copperplate(t).html({
122 | a: false, b: false, c: false, d:false, e: true, f: false
123 | }));
124 |
125 | assertEquals("xef", new Copperplate(t).html({
126 | a: false, b: false, c: false, d:false, e: true, f: true
127 | }));
128 |
129 | assertEquals("xf", new Copperplate(t).html({
130 | a: false, b: false, c: false, d:false, e: false, f: true
131 | }));
132 | },
133 |
134 | "test if with other content": function () {
135 | var t = ' foo a
b';
136 |
137 | assertEquals(" foo a
", new Copperplate(t).html({
138 | a: true, b: false
139 | }));
140 |
141 | assertEquals(" foo a
b", new Copperplate(t).html({
142 | a: true, b: true
143 | }));
144 |
145 | assertEquals(" foo
b", new Copperplate(t).html({
146 | a: false, b: true
147 | }));
148 |
149 | assertEquals(" foo
", new Copperplate(t).html({
150 | a: false, b: false
151 | }));
152 |
153 | var t = 'ahi
';
154 |
155 | assertEquals('ahi
', new Copperplate(t).html({a: true}));
156 | assertEquals('hi
', new Copperplate(t).html({a: false}));
157 | },
158 |
159 | "test if and else with other content": function () {
160 | var t = 'hi
abhi
';
161 |
162 | assertEquals('hi
ahi
', new Copperplate(t).html({a: true}));
163 | assertEquals('hi
bhi
', new Copperplate(t).html({a: false}));
164 |
165 | var t = 'hi
ab hi';
166 | assertEquals('hi
a hi', new Copperplate(t).html({a: true}));
167 | assertEquals('hi
b hi', new Copperplate(t).html({a: false}));
168 |
169 | var t = 'hi
ab hi';
170 | assertEquals('hi
b hi', new Copperplate(t).html({a: false}));
171 | },
172 |
173 | "test if, else and elseif with other content": function () {
174 | var t = 'hi
aarf a';
175 |
176 | assertEquals("hi
a a", new Copperplate(t).html({
177 | a: true, b: false
178 | }));
179 |
180 | assertEquals("hi
arf a", new Copperplate(t).html({
181 | a: false, b: true
182 | }));
183 |
184 | assertEquals("hi
a", new Copperplate(t).html({
185 | a: false, b: false
186 | }));
187 |
188 | var t = 'hi
aarfhi
';
189 |
190 | assertEquals("hi
ahi
", new Copperplate(t).html({
191 | a: true, b: false
192 | }));
193 |
194 | assertEquals("hi
arfhi
", new Copperplate(t).html({
195 | a: false, b: true
196 | }));
197 |
198 | assertEquals("hi
hi
", new Copperplate(t).html({
199 | a: false, b: false
200 | }));
201 | }
202 | });
203 |
204 | TestCase("CopperplateVariablesTest", {
205 | "test variable": function () {
206 | var t = new Copperplate('Hello, {{thing}}!');
207 | assertEquals("Hello, World!", t.html({thing: "World"}));
208 | assertEquals("Hello, Moon!", t.html({thing: "Moon"}));
209 | },
210 |
211 | "test none existing variable": function () {
212 | var t = new Copperplate('Hello, {{thing}}!');
213 | assertEquals("Hello, !", t.html({not: "here"}));
214 | },
215 |
216 | "test false-y variable": function () {
217 | var t = new Copperplate('Hello, {{thing}}!');
218 | assertEquals("Hello, !", t.html({thing: null}));
219 | assertEquals("Hello, !", t.html({thing: undefined}));
220 | assertEquals("Hello, !", t.html({thing: false}));
221 | },
222 |
223 | "test variable in contidional": function () {
224 | var t = new Copperplate('{{b}}');
225 | assertEquals("foo", t.html({a: true, b: "foo"}));
226 | assertEquals("", t.html({a: false, b: "foo"}));
227 | assertEquals("", t.html({a: true, b: ""}));
228 | },
229 |
230 | "test variable in attribute": function () {
231 | var t = new Copperplate('{{title}}');
232 | assertEquals('yo', t.html({href: "foo", title: "yo"}));
233 | }
234 | });
235 |
236 | TestCase("CopperplateVariousTest", {
237 | "test getTag": function () {
238 | var gt = Copperplate.prototype.getTag;
239 | assertEquals("if", gt('')[0]);
240 | assertEquals([], gt('')[1]);
241 |
242 | assertEquals("if", gt('')[0]);
243 | assertEquals([["something", null]], gt('')[1]);
244 |
245 | assertEquals([["something","other"]], gt('')[1]);
246 | assertEquals("if", gt('')[0]);
247 |
248 | assertEquals("test", gt('')[0]);
249 | assertEquals([["test", null]], gt('')[1]);
250 |
251 | assertEquals([
252 | ["something", null],
253 | ["other", "this"],
254 | ["baz", null],
255 | ["maz", null],
256 | ["foo", "bar"]
257 | ], gt('