joosy 0.1.0.alpha → 1.0.0.RC1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/.codoopts +5 -0
  2. data/.gitignore +2 -0
  3. data/Gemfile +15 -2
  4. data/Gemfile.lock +102 -81
  5. data/Guardfile +16 -16
  6. data/LICENSE +22 -0
  7. data/MIT-LICENSE +2 -2
  8. data/README.md +118 -0
  9. data/app/assets/javascripts/joosy/core/application.js.coffee +53 -0
  10. data/app/assets/javascripts/joosy/core/form.js.coffee +338 -0
  11. data/app/assets/javascripts/joosy/core/helpers/form.js.coffee +72 -0
  12. data/app/assets/javascripts/joosy/core/helpers/view.js.coffee +42 -0
  13. data/app/assets/javascripts/joosy/core/helpers/widgets.js.coffee +14 -0
  14. data/app/assets/javascripts/joosy/core/joosy.js.coffee +184 -0
  15. data/app/assets/javascripts/joosy/core/layout.js.coffee +168 -0
  16. data/app/assets/javascripts/joosy/core/modules/container.js.coffee +124 -0
  17. data/app/assets/javascripts/joosy/core/modules/events.js.coffee +122 -0
  18. data/app/assets/javascripts/joosy/core/modules/filters.js.coffee +39 -0
  19. data/app/assets/javascripts/joosy/core/modules/log.js.coffee +36 -0
  20. data/app/assets/javascripts/joosy/core/modules/module.js.coffee +117 -0
  21. data/app/assets/javascripts/joosy/core/modules/renderer.js.coffee +200 -0
  22. data/app/assets/javascripts/joosy/core/modules/time_manager.js.coffee +46 -0
  23. data/app/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +87 -0
  24. data/app/assets/javascripts/joosy/core/page.js.coffee +387 -0
  25. data/app/assets/javascripts/joosy/core/preloader.js.coffee +13 -0
  26. data/app/assets/javascripts/joosy/core/resource/collection.js.coffee +175 -0
  27. data/app/assets/javascripts/joosy/core/resource/generic.js.coffee +303 -0
  28. data/app/assets/javascripts/joosy/core/resource/rest.js.coffee +244 -0
  29. data/app/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +24 -0
  30. data/app/assets/javascripts/joosy/core/router.js.coffee +201 -0
  31. data/app/assets/javascripts/joosy/core/templaters/rails_jst.js.coffee +37 -0
  32. data/app/assets/javascripts/joosy/core/widget.js.coffee +85 -0
  33. data/app/assets/javascripts/joosy/preloaders/caching.js.coffee +169 -0
  34. data/app/assets/javascripts/joosy/preloaders/inline.js.coffee +56 -0
  35. data/{vendor → app}/assets/javascripts/joosy.js.coffee +0 -1
  36. data/app/helpers/joosy/sprockets_helper.rb +39 -12
  37. data/joosy.gemspec +4 -3
  38. data/lib/joosy/rails/engine.rb +12 -1
  39. data/lib/joosy/rails/version.rb +2 -2
  40. data/lib/joosy.rb +9 -0
  41. data/lib/rails/generators/joosy/application_generator.rb +15 -3
  42. data/lib/rails/generators/joosy/joosy_base.rb +2 -2
  43. data/lib/rails/generators/joosy/layout_generator.rb +8 -1
  44. data/lib/rails/generators/joosy/page_generator.rb +21 -6
  45. data/lib/rails/generators/joosy/preloader_generator.rb +14 -7
  46. data/lib/rails/generators/joosy/resource_generator.rb +29 -0
  47. data/lib/rails/generators/joosy/templates/app/helpers/application.js.coffee +4 -0
  48. data/lib/rails/generators/joosy/templates/app/layouts/application.js.coffee +1 -0
  49. data/lib/rails/generators/joosy/templates/app/layouts/template.js.coffee +1 -1
  50. data/lib/rails/generators/joosy/templates/app/pages/application.js.coffee +1 -1
  51. data/lib/rails/generators/joosy/templates/app/pages/template.js.coffee +3 -3
  52. data/lib/rails/generators/joosy/templates/app/pages/welcome/index.js.coffee +22 -0
  53. data/lib/rails/generators/joosy/templates/app/resources/template.js.coffee +2 -0
  54. data/lib/rails/generators/joosy/templates/app/routes.js.coffee +7 -1
  55. data/lib/rails/generators/joosy/templates/app/templates/layouts/application.jst.hamlc +2 -0
  56. data/lib/rails/generators/joosy/templates/app/templates/pages/welcome/index.jst.hamlc +7 -0
  57. data/lib/rails/generators/joosy/templates/app/widgets/template.js.coffee +2 -2
  58. data/lib/rails/generators/joosy/templates/app.js.coffee +4 -0
  59. data/lib/rails/generators/joosy/templates/app_preloader.js.coffee.erb +9 -12
  60. data/lib/rails/generators/joosy/templates/app_resources_predefiner.js.coffee.erb +11 -0
  61. data/lib/rails/generators/joosy/templates/preload.html.erb +5 -6
  62. data/lib/rails/generators/joosy/templates/preload.html.haml +3 -5
  63. data/lib/rails/generators/joosy/widget_generator.rb +8 -1
  64. data/lib/rails/resources_with_joosy.rb +11 -0
  65. data/spec/javascripts/helpers/spec_helper.js.coffee +25 -0
  66. data/spec/javascripts/joosy/core/application_spec.js.coffee +40 -0
  67. data/spec/javascripts/joosy/core/form_spec.js.coffee +200 -0
  68. data/spec/javascripts/joosy/core/helpers/forms_spec.js.coffee +103 -0
  69. data/spec/javascripts/joosy/core/helpers/view_spec.js.coffee +10 -0
  70. data/spec/javascripts/joosy/core/joosy_spec.js.coffee +97 -0
  71. data/spec/javascripts/joosy/core/layout_spec.js.coffee +50 -0
  72. data/spec/javascripts/joosy/core/modules/container_spec.js.coffee +32 -27
  73. data/spec/javascripts/joosy/core/modules/events_spec.js.coffee +55 -18
  74. data/spec/javascripts/joosy/core/modules/filters_spec.js.coffee +28 -27
  75. data/spec/javascripts/joosy/core/modules/log_spec.js.coffee +3 -3
  76. data/spec/javascripts/joosy/core/modules/module_spec.js.coffee +6 -15
  77. data/spec/javascripts/joosy/core/modules/renderer_spec.js.coffee +203 -0
  78. data/spec/javascripts/joosy/core/modules/time_manager_spec.js.coffee +12 -7
  79. data/spec/javascripts/joosy/core/modules/widget_manager_spec.js.coffee +31 -17
  80. data/spec/javascripts/joosy/core/page_spec.js.coffee +178 -0
  81. data/spec/javascripts/joosy/core/resource/collection_spec.js.coffee +84 -0
  82. data/spec/javascripts/joosy/core/resource/generic_spec.js.coffee +149 -0
  83. data/spec/javascripts/joosy/core/resource/rest_collection_spec.js.coffee +31 -0
  84. data/spec/javascripts/joosy/core/resource/rest_spec.js.coffee +171 -0
  85. data/spec/javascripts/joosy/core/router_spec.js.coffee +143 -0
  86. data/spec/javascripts/joosy/core/templaters/rails_jst_spec.js.coffee +25 -0
  87. data/spec/javascripts/joosy/core/widget_spec.js.coffee +40 -0
  88. data/spec/javascripts/joosy/preloaders/caching_spec.js.coffee +36 -0
  89. data/spec/javascripts/joosy/preloaders/inline_spec.js.coffee +16 -0
  90. data/spec/javascripts/support/assets/coolface.jpg +0 -0
  91. data/spec/javascripts/support/assets/okay.jpg +0 -0
  92. data/spec/javascripts/support/assets/test.js +1 -0
  93. data/spec/javascripts/support/sinon-ie-1.3.1.js +82 -0
  94. data/vendor/assets/javascripts/jquery.form.js +978 -963
  95. data/vendor/assets/javascripts/metamorph.js +409 -0
  96. data/vendor/assets/javascripts/sugar.js +1057 -366
  97. metadata +95 -50
  98. data/README.rdoc +0 -3
  99. data/lib/joosy/forms.rb +0 -47
  100. data/lib/joosy-rails.rb +0 -5
  101. data/lib/rails/generators/joosy/templates/preload.html.slim +0 -21
  102. data/tmp/javascripts/.gitignore +0 -1
  103. data/tmp/spec/javascripts/helpers/.gitignore +0 -1
  104. data/vendor/assets/javascripts/base64.js +0 -135
  105. data/vendor/assets/javascripts/inflection.js +0 -656
  106. data/vendor/assets/javascripts/joosy/core/application.js.coffee +0 -26
  107. data/vendor/assets/javascripts/joosy/core/form.js.coffee +0 -87
  108. data/vendor/assets/javascripts/joosy/core/joosy.js.coffee +0 -62
  109. data/vendor/assets/javascripts/joosy/core/layout.js.coffee +0 -38
  110. data/vendor/assets/javascripts/joosy/core/modules/container.js.coffee +0 -51
  111. data/vendor/assets/javascripts/joosy/core/modules/events.js.coffee +0 -17
  112. data/vendor/assets/javascripts/joosy/core/modules/filters.js.coffee +0 -39
  113. data/vendor/assets/javascripts/joosy/core/modules/log.js.coffee +0 -12
  114. data/vendor/assets/javascripts/joosy/core/modules/module.js.coffee +0 -28
  115. data/vendor/assets/javascripts/joosy/core/modules/time_manager.js.coffee +0 -23
  116. data/vendor/assets/javascripts/joosy/core/modules/widgets_manager.js.coffee +0 -45
  117. data/vendor/assets/javascripts/joosy/core/page.js.coffee +0 -136
  118. data/vendor/assets/javascripts/joosy/core/resource/rest.js.coffee +0 -69
  119. data/vendor/assets/javascripts/joosy/core/resource/rest_collection.js.coffee +0 -42
  120. data/vendor/assets/javascripts/joosy/core/router.js.coffee +0 -75
  121. data/vendor/assets/javascripts/joosy/core/widget.js.coffee +0 -35
  122. data/vendor/assets/javascripts/joosy/preloader/development.js.coffee +0 -27
  123. data/vendor/assets/javascripts/joosy/preloader/production.js.coffee +0 -84
@@ -0,0 +1,409 @@
1
+ // ==========================================================================
2
+ // Project: metamorph
3
+ // Copyright: ©2011 My Company Inc. All rights reserved.
4
+ // ==========================================================================
5
+
6
+ (function(window) {
7
+
8
+ var K = function(){},
9
+ guid = 0,
10
+ document = window.document,
11
+
12
+ // Feature-detect the W3C range API, the extended check is for IE9 which only partially supports ranges
13
+ supportsRange = ('createRange' in document) && (typeof Range !== 'undefined') && Range.prototype.createContextualFragment,
14
+
15
+ // Internet Explorer prior to 9 does not allow setting innerHTML if the first element
16
+ // is a "zero-scope" element. This problem can be worked around by making
17
+ // the first node an invisible text node. We, like Modernizr, use ­
18
+ needsShy = (function(){
19
+ var testEl = document.createElement('div');
20
+ testEl.innerHTML = "<div></div>";
21
+ testEl.firstChild.innerHTML = "<script></script>";
22
+ return testEl.firstChild.innerHTML === '';
23
+ })();
24
+
25
+ // Constructor that supports either Metamorph('foo') or new
26
+ // Metamorph('foo');
27
+ //
28
+ // Takes a string of HTML as the argument.
29
+
30
+ var Metamorph = function(html) {
31
+ var self;
32
+
33
+ if (this instanceof Metamorph) {
34
+ self = this;
35
+ } else {
36
+ self = new K();
37
+ }
38
+
39
+ self.innerHTML = html;
40
+ var myGuid = 'metamorph-'+(guid++);
41
+ self.start = myGuid + '-start';
42
+ self.end = myGuid + '-end';
43
+
44
+ return self;
45
+ };
46
+
47
+ K.prototype = Metamorph.prototype;
48
+
49
+ var rangeFor, htmlFunc, removeFunc, outerHTMLFunc, appendToFunc, afterFunc, prependFunc, startTagFunc, endTagFunc;
50
+
51
+ outerHTMLFunc = function() {
52
+ return this.startTag() + this.innerHTML + this.endTag();
53
+ };
54
+
55
+ startTagFunc = function() {
56
+ return "<script id='" + this.start + "' type='text/x-placeholder'></script>";
57
+ };
58
+
59
+ endTagFunc = function() {
60
+ return "<script id='" + this.end + "' type='text/x-placeholder'></script>";
61
+ };
62
+
63
+ // If we have the W3C range API, this process is relatively straight forward.
64
+ if (supportsRange) {
65
+
66
+ // IE 9 supports ranges but doesn't define createContextualFragment
67
+ if (!Range.prototype.createContextualFragment) {
68
+ Range.prototype.createContextualFragment = function(html) {
69
+ var frag = document.createDocumentFragment(),
70
+ div = document.createElement("div");
71
+ frag.appendChild(div);
72
+ div.outerHTML = html;
73
+ return frag;
74
+ };
75
+ }
76
+
77
+ // Get a range for the current morph. Optionally include the starting and
78
+ // ending placeholders.
79
+ rangeFor = function(morph, outerToo) {
80
+ var range = document.createRange();
81
+ var before = document.getElementById(morph.start);
82
+ var after = document.getElementById(morph.end);
83
+
84
+ if (outerToo) {
85
+ range.setStartBefore(before);
86
+ range.setEndAfter(after);
87
+ } else {
88
+ range.setStartAfter(before);
89
+ range.setEndBefore(after);
90
+ }
91
+
92
+ return range;
93
+ };
94
+
95
+ htmlFunc = function(html, outerToo) {
96
+ // get a range for the current metamorph object
97
+ var range = rangeFor(this, outerToo);
98
+
99
+ // delete the contents of the range, which will be the
100
+ // nodes between the starting and ending placeholder.
101
+ range.deleteContents();
102
+
103
+ // create a new document fragment for the HTML
104
+ var fragment = range.createContextualFragment(html);
105
+
106
+ // insert the fragment into the range
107
+ range.insertNode(fragment);
108
+ };
109
+
110
+ removeFunc = function() {
111
+ // get a range for the current metamorph object including
112
+ // the starting and ending placeholders.
113
+ var range = rangeFor(this, true);
114
+
115
+ // delete the entire range.
116
+ range.deleteContents();
117
+ };
118
+
119
+ appendToFunc = function(node) {
120
+ var range = document.createRange();
121
+ range.setStart(node);
122
+ range.collapse(false);
123
+ var frag = range.createContextualFragment(this.outerHTML());
124
+ node.appendChild(frag);
125
+ };
126
+
127
+ afterFunc = function(html) {
128
+ var range = document.createRange();
129
+ var after = document.getElementById(this.end);
130
+
131
+ range.setStartAfter(after);
132
+ range.setEndAfter(after);
133
+
134
+ var fragment = range.createContextualFragment(html);
135
+ range.insertNode(fragment);
136
+ };
137
+
138
+ prependFunc = function(html) {
139
+ var range = document.createRange();
140
+ var start = document.getElementById(this.start);
141
+
142
+ range.setStartAfter(start);
143
+ range.setEndAfter(start);
144
+
145
+ var fragment = range.createContextualFragment(html);
146
+ range.insertNode(fragment);
147
+ };
148
+
149
+ } else {
150
+ /**
151
+ * This code is mostly taken from jQuery, with one exception. In jQuery's case, we
152
+ * have some HTML and we need to figure out how to convert it into some nodes.
153
+ *
154
+ * In this case, jQuery needs to scan the HTML looking for an opening tag and use
155
+ * that as the key for the wrap map. In our case, we know the parent node, and
156
+ * can use its type as the key for the wrap map.
157
+ **/
158
+ var wrapMap = {
159
+ select: [ 1, "<select multiple='multiple'>", "</select>" ],
160
+ fieldset: [ 1, "<fieldset>", "</fieldset>" ],
161
+ table: [ 1, "<table>", "</table>" ],
162
+ tbody: [ 2, "<table><tbody>", "</tbody></table>" ],
163
+ tr: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
164
+ colgroup: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
165
+ map: [ 1, "<map>", "</map>" ],
166
+ _default: [ 0, "", "" ]
167
+ };
168
+
169
+ /**
170
+ * Given a parent node and some HTML, generate a set of nodes. Return the first
171
+ * node, which will allow us to traverse the rest using nextSibling.
172
+ *
173
+ * We need to do this because innerHTML in IE does not really parse the nodes.
174
+ **/
175
+ var firstNodeFor = function(parentNode, html) {
176
+ var arr = wrapMap[parentNode.tagName.toLowerCase()] || wrapMap._default;
177
+ var depth = arr[0], start = arr[1], end = arr[2];
178
+
179
+ if (needsShy) { html = '&shy;'+html; }
180
+
181
+ var element = document.createElement('div');
182
+ element.innerHTML = start + html + end;
183
+
184
+ for (var i=0; i<=depth; i++) {
185
+ element = element.firstChild;
186
+ }
187
+
188
+ // Look for &shy; to remove it.
189
+ if (needsShy) {
190
+ var shyElement = element;
191
+
192
+ // Sometimes we get nameless elements with the shy inside
193
+ while (shyElement.nodeType === 1 && !shyElement.nodeName && shyElement.childNodes.length === 1) {
194
+ shyElement = shyElement.firstChild;
195
+ }
196
+
197
+ // At this point it's the actual unicode character.
198
+ if (shyElement.nodeType === 3 && shyElement.nodeValue.charAt(0) === "\u00AD") {
199
+ shyElement.nodeValue = shyElement.nodeValue.slice(1);
200
+ }
201
+ }
202
+
203
+ return element;
204
+ };
205
+
206
+ /**
207
+ * In some cases, Internet Explorer can create an anonymous node in
208
+ * the hierarchy with no tagName. You can create this scenario via:
209
+ *
210
+ * div = document.createElement("div");
211
+ * div.innerHTML = "<table>&shy<script></script><tr><td>hi</td></tr></table>";
212
+ * div.firstChild.firstChild.tagName //=> ""
213
+ *
214
+ * If our script markers are inside such a node, we need to find that
215
+ * node and use *it* as the marker.
216
+ **/
217
+ var realNode = function(start) {
218
+ while (start.parentNode.tagName === "") {
219
+ start = start.parentNode;
220
+ }
221
+
222
+ return start;
223
+ };
224
+
225
+ /**
226
+ * When automatically adding a tbody, Internet Explorer inserts the
227
+ * tbody immediately before the first <tr>. Other browsers create it
228
+ * before the first node, no matter what.
229
+ *
230
+ * This means the the following code:
231
+ *
232
+ * div = document.createElement("div");
233
+ * div.innerHTML = "<table><script id='first'></script><tr><td>hi</td></tr><script id='last'></script></table>
234
+ *
235
+ * Generates the following DOM in IE:
236
+ *
237
+ * + div
238
+ * + table
239
+ * - script id='first'
240
+ * + tbody
241
+ * + tr
242
+ * + td
243
+ * - "hi"
244
+ * - script id='last'
245
+ *
246
+ * Which means that the two script tags, even though they were
247
+ * inserted at the same point in the hierarchy in the original
248
+ * HTML, now have different parents.
249
+ *
250
+ * This code reparents the first script tag by making it the tbody's
251
+ * first child.
252
+ **/
253
+ var fixParentage = function(start, end) {
254
+ if (start.parentNode !== end.parentNode) {
255
+ end.parentNode.insertBefore(start, end.parentNode.firstChild);
256
+ }
257
+ };
258
+
259
+ htmlFunc = function(html, outerToo) {
260
+ // get the real starting node. see realNode for details.
261
+ var start = realNode(document.getElementById(this.start));
262
+ var end = document.getElementById(this.end);
263
+ var parentNode = end.parentNode;
264
+ var node, nextSibling, last;
265
+
266
+ // make sure that the start and end nodes share the same
267
+ // parent. If not, fix it.
268
+ fixParentage(start, end);
269
+
270
+ // remove all of the nodes after the starting placeholder and
271
+ // before the ending placeholder.
272
+ node = start.nextSibling;
273
+ while (node) {
274
+ nextSibling = node.nextSibling;
275
+ last = node === end;
276
+
277
+ // if this is the last node, and we want to remove it as well,
278
+ // set the `end` node to the next sibling. This is because
279
+ // for the rest of the function, we insert the new nodes
280
+ // before the end (note that insertBefore(node, null) is
281
+ // the same as appendChild(node)).
282
+ //
283
+ // if we do not want to remove it, just break.
284
+ if (last) {
285
+ if (outerToo) { end = node.nextSibling; } else { break; }
286
+ }
287
+
288
+ node.parentNode.removeChild(node);
289
+
290
+ // if this is the last node and we didn't break before
291
+ // (because we wanted to remove the outer nodes), break
292
+ // now.
293
+ if (last) { break; }
294
+
295
+ node = nextSibling;
296
+ }
297
+
298
+ // get the first node for the HTML string, even in cases like
299
+ // tables and lists where a simple innerHTML on a div would
300
+ // swallow some of the content.
301
+ node = firstNodeFor(start.parentNode, html);
302
+
303
+ // copy the nodes for the HTML between the starting and ending
304
+ // placeholder.
305
+ while (node) {
306
+ nextSibling = node.nextSibling;
307
+ parentNode.insertBefore(node, end);
308
+ node = nextSibling;
309
+ }
310
+ };
311
+
312
+ // remove the nodes in the DOM representing this metamorph.
313
+ //
314
+ // this includes the starting and ending placeholders.
315
+ removeFunc = function() {
316
+ var start = realNode(document.getElementById(this.start));
317
+ var end = document.getElementById(this.end);
318
+
319
+ this.html('');
320
+ start.parentNode.removeChild(start);
321
+ end.parentNode.removeChild(end);
322
+ };
323
+
324
+ appendToFunc = function(parentNode) {
325
+ var node = firstNodeFor(parentNode, this.outerHTML());
326
+
327
+ while (node) {
328
+ nextSibling = node.nextSibling;
329
+ parentNode.appendChild(node);
330
+ node = nextSibling;
331
+ }
332
+ };
333
+
334
+ afterFunc = function(html) {
335
+ // get the real starting node. see realNode for details.
336
+ var end = document.getElementById(this.end);
337
+ var parentNode = end.parentNode;
338
+ var nextSibling;
339
+ var node;
340
+
341
+ // get the first node for the HTML string, even in cases like
342
+ // tables and lists where a simple innerHTML on a div would
343
+ // swallow some of the content.
344
+ node = firstNodeFor(parentNode, html);
345
+
346
+ // copy the nodes for the HTML between the starting and ending
347
+ // placeholder.
348
+ while (node) {
349
+ nextSibling = node.nextSibling;
350
+ parentNode.insertBefore(node, end.nextSibling);
351
+ node = nextSibling;
352
+ }
353
+ };
354
+
355
+ prependFunc = function(html) {
356
+ var start = document.getElementById(this.start);
357
+ var parentNode = start.parentNode;
358
+ var nextSibling;
359
+ var node;
360
+
361
+ node = firstNodeFor(parentNode, html);
362
+ var insertBefore = start.nextSibling;
363
+
364
+ while (node) {
365
+ nextSibling = node.nextSibling;
366
+ parentNode.insertBefore(node, insertBefore);
367
+ node = nextSibling;
368
+ }
369
+ }
370
+ }
371
+
372
+ Metamorph.prototype.html = function(html) {
373
+ this.checkRemoved();
374
+ if (html === undefined) { return this.innerHTML; }
375
+
376
+ htmlFunc.call(this, html);
377
+
378
+ this.innerHTML = html;
379
+ };
380
+
381
+ Metamorph.prototype.replaceWith = function(html) {
382
+ this.checkRemoved();
383
+ htmlFunc.call(this, html, true);
384
+ };
385
+
386
+ Metamorph.prototype.remove = removeFunc;
387
+ Metamorph.prototype.outerHTML = outerHTMLFunc;
388
+ Metamorph.prototype.appendTo = appendToFunc;
389
+ Metamorph.prototype.after = afterFunc;
390
+ Metamorph.prototype.prepend = prependFunc;
391
+ Metamorph.prototype.startTag = startTagFunc;
392
+ Metamorph.prototype.endTag = endTagFunc;
393
+
394
+ Metamorph.prototype.isRemoved = function() {
395
+ var before = document.getElementById(this.start);
396
+ var after = document.getElementById(this.end);
397
+
398
+ return !before || !after;
399
+ };
400
+
401
+ Metamorph.prototype.checkRemoved = function() {
402
+ if (this.isRemoved()) {
403
+ throw new Error("Cannot perform operations on a Metamorph that is not in the DOM.");
404
+ }
405
+ };
406
+
407
+ window.Metamorph = Metamorph;
408
+ })(this);
409
+