clearwater 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e0dbe512477a239908316a57e35d45ee6071a644
4
- data.tar.gz: 1a1e20bb5da838c0e7abd7cb8f43394fde474763
3
+ metadata.gz: 11ea030584d8c9bbc61d8d81690140cc88fa6a6b
4
+ data.tar.gz: 7a2dc906feb4e2c005f0521c1e842592466edd18
5
5
  SHA512:
6
- metadata.gz: 974c1f2fba54d8cf8b0467fcaaae1ebfa4e92ad1ce419be6096dbe0869044ed402b24bf8fbb557b9ab44fa37ea0ed388f443bbddb97f1a6c0dcc60b8a4e5321a
7
- data.tar.gz: ff9e1f46a84c517f5984b0a7854add9ec298ef00dbbc206cede4b29866898b0b80d4c268e42d6af987bca27a3d565d4bf79330bd0e9fdf37c2df6f6587fa4edf
6
+ metadata.gz: 3b166c268e598a8f5179c05d33200ac7656ed153f49bb0da56e1a7f3e0e5a6d06c79e3e47ecd10b1c0f7be84136e74b7aa2e88490568aa5fb4cf54f1007d13bb
7
+ data.tar.gz: 65fa07556d0afacd3a63bfce7e49cb1d992fd31860afa1dbf8a61a4841a31bb0aa8bc203a7ffe900f36daa3dfc38ba56979b73eb8bd69561ee26fab8f164fff0
@@ -1,3 +1,3 @@
1
1
  module Clearwater
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/clearwater.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "opal"
2
+ require "opal/browser"
2
3
 
3
4
  module Clearwater
4
5
  require_relative "clearwater/version"
@@ -1,7 +1,7 @@
1
1
  module Clearwater
2
2
  module CachedRender
3
3
  def cached_render
4
- if !@cached_render || should_render?
4
+ if !defined?(@cached_render) || should_render?
5
5
  @cached_render = sanitize_content(render)
6
6
  else
7
7
  @cached_render
@@ -141,6 +141,12 @@ module Clearwater
141
141
  end
142
142
 
143
143
  def tag tag_name, attributes=nil, content=nil
144
+ case attributes
145
+ when Array, Component, Numeric, String
146
+ content = attributes
147
+ attributes = nil
148
+ end
149
+
144
150
  VirtualDOM.node(
145
151
  tag_name,
146
152
  sanitize_attributes(attributes),
@@ -157,7 +163,7 @@ module Clearwater
157
163
  end
158
164
 
159
165
  def sanitize_attributes attributes
160
- return nil if attributes.nil?
166
+ return attributes unless attributes.is_a? Hash
161
167
 
162
168
  # Allow specifying `class` instead of `class_name`.
163
169
  # Note: `class_name` is still allowed
@@ -171,7 +177,7 @@ module Clearwater
171
177
  end
172
178
 
173
179
  attributes.each do |key, handler|
174
- if key.start_with? 'on'
180
+ if key[0, 2] == 'on'
175
181
  attributes[key] = proc do |event|
176
182
  handler.call(Browser::Event.new(event))
177
183
  end
@@ -182,20 +188,28 @@ module Clearwater
182
188
  end
183
189
 
184
190
  def sanitize_content content
185
- case content
186
- when Numeric, String
187
- content.to_s
188
- when Array
189
- content.map { |c| sanitize_content(c) }.compact
190
- else
191
- if content.respond_to? :cached_render
192
- content.cached_render
193
- elsif content.respond_to? :render
194
- sanitize_content content.render
195
- else
196
- content
197
- end
198
- end
191
+ %x{
192
+ if(content.$$class) {
193
+ if(content.$$class === Opal.Array) {
194
+ return #{content.map { |c| `self.$sanitize_content(c)` }};
195
+ } else if(content === Opal.nil) {
196
+ return '';
197
+ } else {
198
+ var cached_render = content.$cached_render;
199
+ var render = content.$render;
200
+
201
+ if(cached_render && !cached_render.$$stub) {
202
+ return content.$cached_render();
203
+ } else if(render && !render.$$stub) {
204
+ return self.$sanitize_content(content.$render());
205
+ } else {
206
+ return content;
207
+ }
208
+ }
209
+ } else {
210
+ return content;
211
+ }
212
+ }
199
213
  end
200
214
 
201
215
  def call &block
@@ -86,7 +86,9 @@ class Link
86
86
  end
87
87
 
88
88
  def navigate event
89
- unless event.meta? || event.shift? || event.ctrl? || event.alt?
89
+ # Don't handle middle-button clicks and clicks with modifier keys. Let them
90
+ # pass through to the browser's default handling or the user's modified handling.
91
+ unless event.meta? || event.shift? || event.ctrl? || event.alt? || (event.respond_to?(:button) && event.button == 1)
90
92
  event.prevent
91
93
  if href != $window.location.path
92
94
  $window.history.push href
@@ -3,17 +3,17 @@ var createElement = require("./vdom/create-element.js")
3
3
 
4
4
  module.exports = createElement
5
5
 
6
- },{"./vdom/create-element.js":14}],2:[function(require,module,exports){
6
+ },{"./vdom/create-element.js":13}],2:[function(require,module,exports){
7
7
  var diff = require("./vtree/diff.js")
8
8
 
9
9
  module.exports = diff
10
10
 
11
- },{"./vtree/diff.js":34}],3:[function(require,module,exports){
11
+ },{"./vtree/diff.js":33}],3:[function(require,module,exports){
12
12
  var h = require("./virtual-hyperscript/index.js")
13
13
 
14
14
  module.exports = h
15
15
 
16
- },{"./virtual-hyperscript/index.js":21}],4:[function(require,module,exports){
16
+ },{"./virtual-hyperscript/index.js":20}],4:[function(require,module,exports){
17
17
  var diff = require("./diff.js")
18
18
  var patch = require("./patch.js")
19
19
  var h = require("./h.js")
@@ -30,115 +30,7 @@ module.exports = {
30
30
  VText: VText
31
31
  }
32
32
 
33
- },{"./create-element.js":1,"./diff.js":2,"./h.js":3,"./patch.js":12,"./vnode/vnode.js":30,"./vnode/vtext.js":32}],5:[function(require,module,exports){
34
- /*!
35
- * Cross-Browser Split 1.1.1
36
- * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
37
- * Available under the MIT License
38
- * ECMAScript compliant, uniform cross-browser split method
39
- */
40
-
41
- /**
42
- * Splits a string into an array of strings using a regex or string separator. Matches of the
43
- * separator are not included in the result array. However, if `separator` is a regex that contains
44
- * capturing groups, backreferences are spliced into the result each time `separator` is matched.
45
- * Fixes browser bugs compared to the native `String.prototype.split` and can be used reliably
46
- * cross-browser.
47
- * @param {String} str String to split.
48
- * @param {RegExp|String} separator Regex or string to use for separating the string.
49
- * @param {Number} [limit] Maximum number of items to include in the result array.
50
- * @returns {Array} Array of substrings.
51
- * @example
52
- *
53
- * // Basic use
54
- * split('a b c d', ' ');
55
- * // -> ['a', 'b', 'c', 'd']
56
- *
57
- * // With limit
58
- * split('a b c d', ' ', 2);
59
- * // -> ['a', 'b']
60
- *
61
- * // Backreferences in result array
62
- * split('..word1 word2..', /([a-z]+)(\d+)/i);
63
- * // -> ['..', 'word', '1', ' ', 'word', '2', '..']
64
- */
65
- module.exports = (function split(undef) {
66
-
67
- var nativeSplit = String.prototype.split,
68
- compliantExecNpcg = /()??/.exec("")[1] === undef,
69
- // NPCG: nonparticipating capturing group
70
- self;
71
-
72
- self = function(str, separator, limit) {
73
- // If `separator` is not a regex, use `nativeSplit`
74
- if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
75
- return nativeSplit.call(str, separator, limit);
76
- }
77
- var output = [],
78
- flags = (separator.ignoreCase ? "i" : "") + (separator.multiline ? "m" : "") + (separator.extended ? "x" : "") + // Proposed for ES6
79
- (separator.sticky ? "y" : ""),
80
- // Firefox 3+
81
- lastLastIndex = 0,
82
- // Make `global` and avoid `lastIndex` issues by working with a copy
83
- separator = new RegExp(separator.source, flags + "g"),
84
- separator2, match, lastIndex, lastLength;
85
- str += ""; // Type-convert
86
- if (!compliantExecNpcg) {
87
- // Doesn't need flags gy, but they don't hurt
88
- separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
89
- }
90
- /* Values for `limit`, per the spec:
91
- * If undefined: 4294967295 // Math.pow(2, 32) - 1
92
- * If 0, Infinity, or NaN: 0
93
- * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
94
- * If negative number: 4294967296 - Math.floor(Math.abs(limit))
95
- * If other: Type-convert, then use the above rules
96
- */
97
- limit = limit === undef ? -1 >>> 0 : // Math.pow(2, 32) - 1
98
- limit >>> 0; // ToUint32(limit)
99
- while (match = separator.exec(str)) {
100
- // `separator.lastIndex` is not reliable cross-browser
101
- lastIndex = match.index + match[0].length;
102
- if (lastIndex > lastLastIndex) {
103
- output.push(str.slice(lastLastIndex, match.index));
104
- // Fix browsers whose `exec` methods don't consistently return `undefined` for
105
- // nonparticipating capturing groups
106
- if (!compliantExecNpcg && match.length > 1) {
107
- match[0].replace(separator2, function() {
108
- for (var i = 1; i < arguments.length - 2; i++) {
109
- if (arguments[i] === undef) {
110
- match[i] = undef;
111
- }
112
- }
113
- });
114
- }
115
- if (match.length > 1 && match.index < str.length) {
116
- Array.prototype.push.apply(output, match.slice(1));
117
- }
118
- lastLength = match[0].length;
119
- lastLastIndex = lastIndex;
120
- if (output.length >= limit) {
121
- break;
122
- }
123
- }
124
- if (separator.lastIndex === match.index) {
125
- separator.lastIndex++; // Avoid an infinite loop
126
- }
127
- }
128
- if (lastLastIndex === str.length) {
129
- if (lastLength || !separator.test("")) {
130
- output.push("");
131
- }
132
- } else {
133
- output.push(str.slice(lastLastIndex));
134
- }
135
- return output.length > limit ? output.slice(0, limit) : output;
136
- };
137
-
138
- return self;
139
- })();
140
-
141
- },{}],6:[function(require,module,exports){
33
+ },{"./create-element.js":1,"./diff.js":2,"./h.js":3,"./patch.js":11,"./vnode/vnode.js":29,"./vnode/vtext.js":31}],5:[function(require,module,exports){
142
34
  'use strict';
143
35
 
144
36
  var OneVersionConstraint = require('individual/one-version');
@@ -160,7 +52,7 @@ function EvStore(elem) {
160
52
  return hash;
161
53
  }
162
54
 
163
- },{"individual/one-version":8}],7:[function(require,module,exports){
55
+ },{"individual/one-version":7}],6:[function(require,module,exports){
164
56
  (function (global){
165
57
  'use strict';
166
58
 
@@ -183,7 +75,7 @@ function Individual(key, value) {
183
75
  }
184
76
 
185
77
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
186
- },{}],8:[function(require,module,exports){
78
+ },{}],7:[function(require,module,exports){
187
79
  'use strict';
188
80
 
189
81
  var Individual = require('./index.js');
@@ -207,7 +99,7 @@ function OneVersion(moduleName, version, defaultValue) {
207
99
  return Individual(key, defaultValue);
208
100
  }
209
101
 
210
- },{"./index.js":7}],9:[function(require,module,exports){
102
+ },{"./index.js":6}],8:[function(require,module,exports){
211
103
  (function (global){
212
104
  var topLevel = typeof global !== 'undefined' ? global :
213
105
  typeof window !== 'undefined' ? window : {}
@@ -226,14 +118,14 @@ if (typeof document !== 'undefined') {
226
118
  }
227
119
 
228
120
  }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
229
- },{"min-document":35}],10:[function(require,module,exports){
121
+ },{"min-document":34}],9:[function(require,module,exports){
230
122
  "use strict";
231
123
 
232
124
  module.exports = function isObject(x) {
233
125
  return typeof x === "object" && x !== null;
234
126
  };
235
127
 
236
- },{}],11:[function(require,module,exports){
128
+ },{}],10:[function(require,module,exports){
237
129
  var nativeIsArray = Array.isArray
238
130
  var toString = Object.prototype.toString
239
131
 
@@ -243,12 +135,12 @@ function isArray(obj) {
243
135
  return toString.call(obj) === "[object Array]"
244
136
  }
245
137
 
246
- },{}],12:[function(require,module,exports){
138
+ },{}],11:[function(require,module,exports){
247
139
  var patch = require("./vdom/patch.js")
248
140
 
249
141
  module.exports = patch
250
142
 
251
- },{"./vdom/patch.js":17}],13:[function(require,module,exports){
143
+ },{"./vdom/patch.js":16}],12:[function(require,module,exports){
252
144
  var isObject = require("is-object")
253
145
  var isHook = require("../vnode/is-vhook.js")
254
146
 
@@ -347,7 +239,7 @@ function getPrototype(value) {
347
239
  }
348
240
  }
349
241
 
350
- },{"../vnode/is-vhook.js":25,"is-object":10}],14:[function(require,module,exports){
242
+ },{"../vnode/is-vhook.js":24,"is-object":9}],13:[function(require,module,exports){
351
243
  var document = require("global/document")
352
244
 
353
245
  var applyProperties = require("./apply-properties")
@@ -395,7 +287,7 @@ function createElement(vnode, opts) {
395
287
  return node
396
288
  }
397
289
 
398
- },{"../vnode/handle-thunk.js":23,"../vnode/is-vnode.js":26,"../vnode/is-vtext.js":27,"../vnode/is-widget.js":28,"./apply-properties":13,"global/document":9}],15:[function(require,module,exports){
290
+ },{"../vnode/handle-thunk.js":22,"../vnode/is-vnode.js":25,"../vnode/is-vtext.js":26,"../vnode/is-widget.js":27,"./apply-properties":12,"global/document":8}],14:[function(require,module,exports){
399
291
  // Maps a virtual DOM tree onto a real DOM tree in an efficient manner.
400
292
  // We don't want to read all of the DOM nodes in the tree so we use
401
293
  // the in-order tree indexing to eliminate recursion down certain branches.
@@ -482,13 +374,12 @@ function ascending(a, b) {
482
374
  return a > b ? 1 : -1
483
375
  }
484
376
 
485
- },{}],16:[function(require,module,exports){
377
+ },{}],15:[function(require,module,exports){
486
378
  var applyProperties = require("./apply-properties")
487
379
 
488
380
  var isWidget = require("../vnode/is-widget.js")
489
381
  var VPatch = require("../vnode/vpatch.js")
490
382
 
491
- var render = require("./create-element")
492
383
  var updateWidget = require("./update-widget")
493
384
 
494
385
  module.exports = applyPatch
@@ -536,7 +427,7 @@ function removeNode(domNode, vNode) {
536
427
  }
537
428
 
538
429
  function insertNode(parentNode, vNode, renderOptions) {
539
- var newNode = render(vNode, renderOptions)
430
+ var newNode = renderOptions.render(vNode, renderOptions)
540
431
 
541
432
  if (parentNode) {
542
433
  parentNode.appendChild(newNode)
@@ -553,7 +444,7 @@ function stringPatch(domNode, leftVNode, vText, renderOptions) {
553
444
  newNode = domNode
554
445
  } else {
555
446
  var parentNode = domNode.parentNode
556
- newNode = render(vText, renderOptions)
447
+ newNode = renderOptions.render(vText, renderOptions)
557
448
 
558
449
  if (parentNode && newNode !== domNode) {
559
450
  parentNode.replaceChild(newNode, domNode)
@@ -570,7 +461,7 @@ function widgetPatch(domNode, leftVNode, widget, renderOptions) {
570
461
  if (updating) {
571
462
  newNode = widget.update(leftVNode, domNode) || domNode
572
463
  } else {
573
- newNode = render(widget, renderOptions)
464
+ newNode = renderOptions.render(widget, renderOptions)
574
465
  }
575
466
 
576
467
  var parentNode = domNode.parentNode
@@ -588,7 +479,7 @@ function widgetPatch(domNode, leftVNode, widget, renderOptions) {
588
479
 
589
480
  function vNodePatch(domNode, leftVNode, vNode, renderOptions) {
590
481
  var parentNode = domNode.parentNode
591
- var newNode = render(vNode, renderOptions)
482
+ var newNode = renderOptions.render(vNode, renderOptions)
592
483
 
593
484
  if (parentNode && newNode !== domNode) {
594
485
  parentNode.replaceChild(newNode, domNode)
@@ -636,16 +527,21 @@ function replaceRoot(oldRoot, newRoot) {
636
527
  return newRoot;
637
528
  }
638
529
 
639
- },{"../vnode/is-widget.js":28,"../vnode/vpatch.js":31,"./apply-properties":13,"./create-element":14,"./update-widget":18}],17:[function(require,module,exports){
530
+ },{"../vnode/is-widget.js":27,"../vnode/vpatch.js":30,"./apply-properties":12,"./update-widget":17}],16:[function(require,module,exports){
640
531
  var document = require("global/document")
641
532
  var isArray = require("x-is-array")
642
533
 
534
+ var render = require("./create-element")
643
535
  var domIndex = require("./dom-index")
644
536
  var patchOp = require("./patch-op")
645
537
  module.exports = patch
646
538
 
647
- function patch(rootNode, patches) {
648
- return patchRecursive(rootNode, patches)
539
+ function patch(rootNode, patches, renderOptions) {
540
+ renderOptions = renderOptions || {}
541
+ renderOptions.patch = renderOptions.patch || patchRecursive
542
+ renderOptions.render = renderOptions.render || render
543
+
544
+ return renderOptions.patch(rootNode, patches, renderOptions)
649
545
  }
650
546
 
651
547
  function patchRecursive(rootNode, patches, renderOptions) {
@@ -658,11 +554,8 @@ function patchRecursive(rootNode, patches, renderOptions) {
658
554
  var index = domIndex(rootNode, patches.a, indices)
659
555
  var ownerDocument = rootNode.ownerDocument
660
556
 
661
- if (!renderOptions) {
662
- renderOptions = { patch: patchRecursive }
663
- if (ownerDocument !== document) {
664
- renderOptions.document = ownerDocument
665
- }
557
+ if (!renderOptions.document && ownerDocument !== document) {
558
+ renderOptions.document = ownerDocument
666
559
  }
667
560
 
668
561
  for (var i = 0; i < indices.length; i++) {
@@ -714,7 +607,7 @@ function patchIndices(patches) {
714
607
  return indices
715
608
  }
716
609
 
717
- },{"./dom-index":15,"./patch-op":16,"global/document":9,"x-is-array":11}],18:[function(require,module,exports){
610
+ },{"./create-element":13,"./dom-index":14,"./patch-op":15,"global/document":8,"x-is-array":10}],17:[function(require,module,exports){
718
611
  var isWidget = require("../vnode/is-widget.js")
719
612
 
720
613
  module.exports = updateWidget
@@ -731,7 +624,7 @@ function updateWidget(a, b) {
731
624
  return false
732
625
  }
733
626
 
734
- },{"../vnode/is-widget.js":28}],19:[function(require,module,exports){
627
+ },{"../vnode/is-widget.js":27}],18:[function(require,module,exports){
735
628
  'use strict';
736
629
 
737
630
  var EvStore = require('ev-store');
@@ -760,7 +653,7 @@ EvHook.prototype.unhook = function(node, propertyName) {
760
653
  es[propName] = undefined;
761
654
  };
762
655
 
763
- },{"ev-store":6}],20:[function(require,module,exports){
656
+ },{"ev-store":5}],19:[function(require,module,exports){
764
657
  'use strict';
765
658
 
766
659
  module.exports = SoftSetHook;
@@ -779,7 +672,7 @@ SoftSetHook.prototype.hook = function (node, propertyName) {
779
672
  }
780
673
  };
781
674
 
782
- },{}],21:[function(require,module,exports){
675
+ },{}],20:[function(require,module,exports){
783
676
  'use strict';
784
677
 
785
678
  var isArray = require('x-is-array');
@@ -845,6 +738,8 @@ function h(tagName, properties, children) {
845
738
  function addChild(c, childNodes, tag, props) {
846
739
  if (typeof c === 'string') {
847
740
  childNodes.push(new VText(c));
741
+ } else if (typeof c === 'number') {
742
+ childNodes.push(new VText(String(c)));
848
743
  } else if (isChild(c)) {
849
744
  childNodes.push(c);
850
745
  } else if (isArray(c)) {
@@ -916,14 +811,9 @@ function errorString(obj) {
916
811
  }
917
812
  }
918
813
 
919
- },{"../vnode/is-thunk":24,"../vnode/is-vhook":25,"../vnode/is-vnode":26,"../vnode/is-vtext":27,"../vnode/is-widget":28,"../vnode/vnode.js":30,"../vnode/vtext.js":32,"./hooks/ev-hook.js":19,"./hooks/soft-set-hook.js":20,"./parse-tag.js":22,"x-is-array":11}],22:[function(require,module,exports){
814
+ },{"../vnode/is-thunk":23,"../vnode/is-vhook":24,"../vnode/is-vnode":25,"../vnode/is-vtext":26,"../vnode/is-widget":27,"../vnode/vnode.js":29,"../vnode/vtext.js":31,"./hooks/ev-hook.js":18,"./hooks/soft-set-hook.js":19,"./parse-tag.js":21,"x-is-array":10}],21:[function(require,module,exports){
920
815
  'use strict';
921
816
 
922
- var split = require('browser-split');
923
-
924
- var classIdSplit = /([\.#]?[a-zA-Z0-9_:-]+)/;
925
- var notClassId = /^\.|#/;
926
-
927
817
  module.exports = parseTag;
928
818
 
929
819
  function parseTag(tag, props) {
@@ -933,16 +823,13 @@ function parseTag(tag, props) {
933
823
 
934
824
  var noId = !(props.hasOwnProperty('id'));
935
825
 
936
- var tagParts = split(tag, classIdSplit);
937
- var tagName = null;
826
+ var tagParts = splitTag(tag);
938
827
 
939
- if (notClassId.test(tagParts[1])) {
940
- tagName = 'DIV';
941
- }
828
+ var tagName = tagParts[0] || 'DIV';
942
829
 
943
830
  var classes, part, type, i;
944
831
 
945
- for (i = 0; i < tagParts.length; i++) {
832
+ for (i = 1; i < tagParts.length; i++) {
946
833
  part = tagParts[i];
947
834
 
948
835
  if (!part) {
@@ -951,9 +838,7 @@ function parseTag(tag, props) {
951
838
 
952
839
  type = part.charAt(0);
953
840
 
954
- if (!tagName) {
955
- tagName = part;
956
- } else if (type === '.') {
841
+ if (type === '.') {
957
842
  classes = classes || [];
958
843
  classes.push(part.substring(1, part.length));
959
844
  } else if (type === '#' && noId) {
@@ -972,7 +857,35 @@ function parseTag(tag, props) {
972
857
  return props.namespace ? tagName : tagName.toUpperCase();
973
858
  }
974
859
 
975
- },{"browser-split":5}],23:[function(require,module,exports){
860
+
861
+ function splitTag(tag) {
862
+
863
+ var classIndex, idIndex,
864
+ remaining = tag,
865
+ parts = [],
866
+ last = '';
867
+
868
+ do {
869
+ idIndex = remaining.indexOf('#');
870
+ classIndex = remaining.indexOf('.');
871
+ if ((idIndex === -1 || idIndex > classIndex) && classIndex !== -1) {
872
+ parts.push(last + remaining.substr(0, classIndex));
873
+ last = '.';
874
+ remaining = remaining.substr(classIndex + 1);
875
+ } else if (idIndex !== -1){
876
+ parts.push(last + remaining.substr(0, idIndex));
877
+ last = '#';
878
+ remaining = remaining.substr(idIndex + 1);
879
+ }
880
+
881
+ } while(idIndex !== -1 || classIndex !== -1)
882
+
883
+ parts.push(last + remaining);
884
+
885
+ return parts;
886
+ }
887
+
888
+ },{}],22:[function(require,module,exports){
976
889
  var isVNode = require("./is-vnode")
977
890
  var isVText = require("./is-vtext")
978
891
  var isWidget = require("./is-widget")
@@ -1014,14 +927,14 @@ function renderThunk(thunk, previous) {
1014
927
  return renderedThunk
1015
928
  }
1016
929
 
1017
- },{"./is-thunk":24,"./is-vnode":26,"./is-vtext":27,"./is-widget":28}],24:[function(require,module,exports){
930
+ },{"./is-thunk":23,"./is-vnode":25,"./is-vtext":26,"./is-widget":27}],23:[function(require,module,exports){
1018
931
  module.exports = isThunk
1019
932
 
1020
933
  function isThunk(t) {
1021
934
  return t && t.type === "Thunk"
1022
935
  }
1023
936
 
1024
- },{}],25:[function(require,module,exports){
937
+ },{}],24:[function(require,module,exports){
1025
938
  module.exports = isHook
1026
939
 
1027
940
  function isHook(hook) {
@@ -1030,7 +943,7 @@ function isHook(hook) {
1030
943
  typeof hook.unhook === "function" && !hook.hasOwnProperty("unhook"))
1031
944
  }
1032
945
 
1033
- },{}],26:[function(require,module,exports){
946
+ },{}],25:[function(require,module,exports){
1034
947
  var version = require("./version")
1035
948
 
1036
949
  module.exports = isVirtualNode
@@ -1039,7 +952,7 @@ function isVirtualNode(x) {
1039
952
  return x && x.type === "VirtualNode" && x.version === version
1040
953
  }
1041
954
 
1042
- },{"./version":29}],27:[function(require,module,exports){
955
+ },{"./version":28}],26:[function(require,module,exports){
1043
956
  var version = require("./version")
1044
957
 
1045
958
  module.exports = isVirtualText
@@ -1048,17 +961,17 @@ function isVirtualText(x) {
1048
961
  return x && x.type === "VirtualText" && x.version === version
1049
962
  }
1050
963
 
1051
- },{"./version":29}],28:[function(require,module,exports){
964
+ },{"./version":28}],27:[function(require,module,exports){
1052
965
  module.exports = isWidget
1053
966
 
1054
967
  function isWidget(w) {
1055
968
  return w && w.type === "Widget"
1056
969
  }
1057
970
 
1058
- },{}],29:[function(require,module,exports){
971
+ },{}],28:[function(require,module,exports){
1059
972
  module.exports = "2"
1060
973
 
1061
- },{}],30:[function(require,module,exports){
974
+ },{}],29:[function(require,module,exports){
1062
975
  var version = require("./version")
1063
976
  var isVNode = require("./is-vnode")
1064
977
  var isWidget = require("./is-widget")
@@ -1132,7 +1045,7 @@ function VirtualNode(tagName, properties, children, key, namespace) {
1132
1045
  VirtualNode.prototype.version = version
1133
1046
  VirtualNode.prototype.type = "VirtualNode"
1134
1047
 
1135
- },{"./is-thunk":24,"./is-vhook":25,"./is-vnode":26,"./is-widget":28,"./version":29}],31:[function(require,module,exports){
1048
+ },{"./is-thunk":23,"./is-vhook":24,"./is-vnode":25,"./is-widget":27,"./version":28}],30:[function(require,module,exports){
1136
1049
  var version = require("./version")
1137
1050
 
1138
1051
  VirtualPatch.NONE = 0
@@ -1156,7 +1069,7 @@ function VirtualPatch(type, vNode, patch) {
1156
1069
  VirtualPatch.prototype.version = version
1157
1070
  VirtualPatch.prototype.type = "VirtualPatch"
1158
1071
 
1159
- },{"./version":29}],32:[function(require,module,exports){
1072
+ },{"./version":28}],31:[function(require,module,exports){
1160
1073
  var version = require("./version")
1161
1074
 
1162
1075
  module.exports = VirtualText
@@ -1168,7 +1081,7 @@ function VirtualText(text) {
1168
1081
  VirtualText.prototype.version = version
1169
1082
  VirtualText.prototype.type = "VirtualText"
1170
1083
 
1171
- },{"./version":29}],33:[function(require,module,exports){
1084
+ },{"./version":28}],32:[function(require,module,exports){
1172
1085
  var isObject = require("is-object")
1173
1086
  var isHook = require("../vnode/is-vhook")
1174
1087
 
@@ -1228,7 +1141,7 @@ function getPrototype(value) {
1228
1141
  }
1229
1142
  }
1230
1143
 
1231
- },{"../vnode/is-vhook":25,"is-object":10}],34:[function(require,module,exports){
1144
+ },{"../vnode/is-vhook":24,"is-object":9}],33:[function(require,module,exports){
1232
1145
  var isArray = require("x-is-array")
1233
1146
 
1234
1147
  var VPatch = require("../vnode/vpatch")
@@ -1657,7 +1570,7 @@ function appendPatch(apply, patch) {
1657
1570
  }
1658
1571
  }
1659
1572
 
1660
- },{"../vnode/handle-thunk":23,"../vnode/is-thunk":24,"../vnode/is-vnode":26,"../vnode/is-vtext":27,"../vnode/is-widget":28,"../vnode/vpatch":31,"./diff-props":33,"x-is-array":11}],35:[function(require,module,exports){
1573
+ },{"../vnode/handle-thunk":22,"../vnode/is-thunk":23,"../vnode/is-vnode":25,"../vnode/is-vtext":26,"../vnode/is-widget":27,"../vnode/vpatch":30,"./diff-props":32,"x-is-array":10}],34:[function(require,module,exports){
1661
1574
 
1662
1575
  },{}]},{},[4])(4)
1663
1576
  });
@@ -1,108 +1,80 @@
1
1
  require 'browser'
2
2
  require 'clearwater/virtual_dom/js/virtual_dom.js'
3
3
 
4
- module StringUtils
5
- def self.camelize string
6
- string.gsub(/_(\w)/) { |match| match.gsub(/_/, '').upcase }
4
+ module VirtualDOM
5
+ def self.node(tag_name, attributes, content)
6
+ content = sanitize_content(content)
7
+ attributes = HashUtils.camelize_keys(attributes).to_n
8
+ `virtualDom.h(tag_name, attributes, content)`
7
9
  end
8
- end
9
10
 
10
- module HashUtils
11
- def self.camelize_keys(hash)
12
- return nil if hash.nil?
13
-
14
- Hash[hash.map { |k,v|
15
- key = StringUtils.camelize(k)
16
- value = if Hash === v
17
- camelize_keys(v)
18
- else
19
- v
20
- end
21
-
22
- [key, value]
23
- }]
11
+ def self.diff first, second
12
+ `virtualDom.diff(first, second)`
24
13
  end
25
- end
26
14
 
27
- module VirtualDOM
28
- def self.node(tag_name, attributes, content)
29
- content = Array(content).map { |node|
30
- case node
31
- when Node
32
- node.node
33
- else
34
- node
35
- end
36
- }
37
- attributes = HashUtils.camelize_keys(attributes).to_n
38
- Node.new(`virtualDom.h(tag_name, attributes, content)`)
15
+ def self.patch node, diff
16
+ `virtualDom.patch(node, diff)`
39
17
  end
40
18
 
41
- def self.create_element node
42
- `virtualDom.create(node)`
19
+ def self.sanitize_content content
20
+ %x{
21
+ if(content === Opal.nil) return Opal.nil;
22
+ if(content.$$class === Opal.Array)
23
+ return #{content.map!{ |c| sanitize_content c }};
24
+ return content;
25
+ }
43
26
  end
44
27
 
45
28
  class Document
46
29
  def initialize(root=$document.create_element('div'))
47
30
  @root = root
48
- @rendered_nodes = {}
49
31
  end
50
32
 
51
33
  def render node
52
34
  if rendered?
53
- diff = @node.diff(node)
54
- @tree = Element.new(@tree.patch(diff))
35
+ diff = VirtualDOM.diff @node, node
36
+ VirtualDOM.patch @tree, diff
55
37
  @node = node
56
38
  else
57
39
  @node = node
58
- @tree = node.to_element
59
- @root.inner_dom = @tree.to_n
40
+ @tree = create_element(node)
41
+ @root.inner_dom = @tree
60
42
  @rendered = true
61
43
  end
62
44
  end
63
45
 
46
+ def create_element node
47
+ `virtualDom.create(node)`
48
+ end
49
+
64
50
  def rendered?
65
51
  @rendered
66
52
  end
67
53
  end
68
54
 
69
- class Node
70
- attr_reader :node
71
-
72
- def initialize(node)
73
- @node = node
74
- end
75
-
76
- def method_missing *args, &block
77
- node.send *args, &block
78
- end
79
-
80
- def to_element
81
- Element.new(VirtualDOM.create_element(node))
82
- end
83
-
84
- def diff other
85
- `virtualDom.diff(self.node, other.node)`
86
- end
87
-
88
- def patch diff
89
- `virtualDom.patch(#{to_element.to_n}, diff)`
55
+ module StringUtils
56
+ def self.camelize string
57
+ string.gsub(/_(\w)/) { |match| match.gsub(/_/, '').upcase }
90
58
  end
91
59
  end
92
60
 
93
- class Element
94
- attr_reader :element
61
+ module HashUtils
62
+ def self.camelize_keys(hash)
63
+ return hash unless hash.is_a? Hash
95
64
 
96
- def initialize(element)
97
- @element = element
98
- end
65
+ camelized = {}
66
+ hash.each do |k, v|
67
+ key = StringUtils.camelize(k)
68
+ value = if v.class == Hash
69
+ camelize_keys(v)
70
+ else
71
+ v
72
+ end
99
73
 
100
- def patch(diff)
101
- `virtualDom.patch(#{element}, diff)`
102
- end
74
+ camelized[key] = value
75
+ end
103
76
 
104
- def to_n
105
- @element
77
+ camelized
106
78
  end
107
79
  end
108
80
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clearwater
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Gaskins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-12 00:00:00.000000000 Z
11
+ date: 2015-08-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: opal
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.7.0
19
+ version: '0.7'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.7.0
26
+ version: '0.7'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: opal-browser
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -139,7 +139,6 @@ files:
139
139
  - opal/clearwater/cgi.rb
140
140
  - opal/clearwater/component.rb
141
141
  - opal/clearwater/link.rb
142
- - opal/clearwater/model.rb
143
142
  - opal/clearwater/router.rb
144
143
  - opal/clearwater/router/route.rb
145
144
  - opal/clearwater/router/route_collection.rb
@@ -166,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
166
165
  version: '0'
167
166
  requirements: []
168
167
  rubyforge_project:
169
- rubygems_version: 2.4.6
168
+ rubygems_version: 2.4.8
170
169
  signing_key:
171
170
  specification_version: 4
172
171
  summary: Front-end web framework built on Opal
@@ -1,33 +0,0 @@
1
- require "clearwater/binding"
2
-
3
- module Clearwater
4
- class Model
5
- def initialize attributes={}
6
- @_bindings = Hash.new { |h,k| h[k] = [] }
7
- self.class.attributes.each do |attr|
8
- public_send "#{attr}=", attributes[attr]
9
- end
10
- end
11
-
12
- def add_binding attribute, &block
13
- binding = Binding.new(self, attribute, &block)
14
- @_bindings[attribute].delete_if(&:dead?)
15
- @_bindings[attribute] << binding
16
- binding
17
- end
18
-
19
- def self.attributes *args
20
- @attributes ||= []
21
- args.each do |attr|
22
- attr_reader attr
23
-
24
- define_method "#{attr}=" do |value|
25
- instance_variable_set "@#{attr}", value
26
- @_bindings[attr].each(&:call)
27
- @_bindings[attr].delete_if(&:dead?)
28
- end
29
- end
30
- @attributes.concat args
31
- end
32
- end
33
- end