snabberb 0.5.0 → 1.3.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
  SHA256:
3
- metadata.gz: cedc3e54bfcb4b628750f8a7779975624cb72226c46ca0c2e7ea787d5b31e9f2
4
- data.tar.gz: e0d593a26c2058022d6e6c3df9dc200c235aedf2524a9c774ebcabbfa8df7d3a
3
+ metadata.gz: cb82424f513fedb084f9889e64adc0b3484e3403522d5f0fb1ab3531c9fd627b
4
+ data.tar.gz: '08a6595aa3bed2cde156991811e6a612296e11aaeae9a24a10dd9aca58c2f3f8'
5
5
  SHA512:
6
- metadata.gz: c0d1c3b840a0f0475204cdcdf8a603441bbbcc5f7fb1b3653081e4b8e25690663116ba639775b4ae8f7c045f904207225fa6d7bee27931a778c441c76e8385d9
7
- data.tar.gz: f32c2619a9c422fe33cf7fdeddd97b968c7a68002865619f1077c63349e66caa24c820aad00fa66bf60de623d5e8e7f46f7a16ba374f9836cd9ce653badffddc
6
+ metadata.gz: 9f599f947849c63880508953ec5f096f6ccfc4936c08fe51d7c8a3fd087260b921cdba6d7b64b70e5a6e565c63d2cf02cd1962880c1b5ae4b96f4a793cddfe3d
7
+ data.tar.gz: 06d6ff61cf0853e796f4c8d4896db4e4a74b7dd28a79a421fdc4df947d99e92f7eec63ca604c993ab445142bd9f095d782122730f11936387ee4314313fc4768
data/.rubocop.yml CHANGED
@@ -1,21 +1,24 @@
1
1
  Layout/FirstArrayElementIndentation:
2
2
  Enabled: false
3
3
 
4
+ Layout/LineLength:
5
+ Max: 120
6
+
4
7
  Metrics/AbcSize:
5
8
  Enabled: false
6
9
 
7
10
  Metrics/BlockLength:
8
11
  Enabled: False
9
12
 
13
+ Metrics/ClassLength:
14
+ Enabled: False
15
+
10
16
  Metrics/CyclomaticComplexity:
11
17
  Enabled: False
12
18
 
13
19
  Metrics/PerceivedComplexity:
14
20
  Enabled: False
15
21
 
16
- Metrics/LineLength:
17
- Max: 120
18
-
19
22
  Metrics/MethodLength:
20
23
  Enabled: false
21
24
 
@@ -41,4 +44,6 @@ Style/TrailingCommaInHashLiteral:
41
44
  Enabled: false
42
45
 
43
46
  AllCops:
44
- TargetRubyVersion: 2.3
47
+ NewCops: enable
48
+ TargetRubyVersion: 2.4
49
+ SuggestExtensions: false
data/build.js CHANGED
@@ -1,10 +1,11 @@
1
- // browserify deps.js -p esmify -s snabbdom > opal/vendor/snabbdom.js
1
+ // browserify build.js -p esmify -s snabbdom > opal/vendor/snabbdom.js
2
2
  import { init } from './node_modules/snabbdom/build/package/init'
3
3
  import { h } from './node_modules/snabbdom/build/package/h'
4
4
  import { toVNode } from './node_modules/snabbdom/build/package/tovnode'
5
5
 
6
6
  import { attributesModule } from './node_modules/snabbdom/build/package/modules/attributes'
7
7
  import { classModule } from './node_modules/snabbdom/build/package/modules/class'
8
+ import { datasetModule } from './node_modules/snabbdom/build/package/modules/dataset'
8
9
  import { eventListenersModule } from './node_modules/snabbdom/build/package/modules/eventlisteners'
9
10
  import { propsModule } from './node_modules/snabbdom/build/package/modules/props'
10
11
  import { styleModule } from './node_modules/snabbdom/build/package/modules/style'
@@ -15,6 +16,7 @@ module.exports.toVNode = toVNode
15
16
 
16
17
  module.exports.attributesModule = attributesModule
17
18
  module.exports.classModule = classModule
19
+ module.exports.datasetModule = datasetModule
18
20
  module.exports.eventListenersModule = eventListenersModule
19
21
  module.exports.propsModule = propsModule
20
22
  module.exports.styleModule = styleModule
@@ -2,7 +2,7 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'c_lexer'
6
5
  gem 'opal'
7
6
  gem 'rack'
8
7
  gem 'snabberb', path: '../..'
8
+ gem 'webrick'
@@ -1,31 +1,29 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- snabberb (0.4.2)
5
- opal (~> 1.0)
4
+ snabberb (1.3.0)
5
+ opal (~> 1.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- ast (2.4.1)
11
- c_lexer (2.6.4.1.1)
12
- ast (~> 2.4.0)
13
- parser (= 2.6.4.1)
14
- opal (1.0.3)
10
+ ast (2.4.2)
11
+ opal (1.1.1)
15
12
  ast (>= 2.3.0)
16
- parser (~> 2.6)
17
- parser (2.6.4.1)
18
- ast (~> 2.4.0)
13
+ parser (~> 3.0)
14
+ parser (3.0.0.0)
15
+ ast (~> 2.4.1)
19
16
  rack (2.2.3)
17
+ webrick (1.7.0)
20
18
 
21
19
  PLATFORMS
22
20
  ruby
23
21
 
24
22
  DEPENDENCIES
25
- c_lexer
26
23
  opal
27
24
  rack
28
25
  snabberb!
26
+ webrick
29
27
 
30
28
  BUNDLED WITH
31
- 2.1.4
29
+ 2.2.3
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../..
3
3
  specs:
4
- snabberb (0.4.2)
4
+ snabberb (1.0.0)
5
5
  opal (~> 1.0)
6
6
 
7
7
  GEM
data/lib/snabberb.rb CHANGED
@@ -55,11 +55,11 @@ module Snabberb
55
55
 
56
56
  def self.prerender_script(layout, application, application_id, javascript_include_tags: '', **needs)
57
57
  needs = wrap(needs)
58
- attach_func = wrap_s("Opal.$$.#{application}.$attach(\"#{application_id}\", #{needs})")
58
+ attach_func = wrap_s("Opal.#{application}.$attach(\"#{application_id}\", #{needs})")
59
59
 
60
60
  <<~JS
61
- Opal.$$.#{layout}.$html(Opal.hash({
62
- application: Opal.$$.#{application}.$new(null, #{needs}).$render(),
61
+ Opal.#{layout}.$html(Opal.hash({
62
+ application: Opal.#{application}.$new(null, #{needs}).$render(),
63
63
  javascript_include_tags: '#{javascript_include_tags.gsub("\n", '')}',
64
64
  attach_func: #{attach_func}
65
65
  }))
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Snabberb
4
- VERSION = '0.5.0'
4
+ VERSION = '1.3.1'
5
5
  end
data/opal/snabberb.rb CHANGED
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'erb'
3
4
  require 'native'
4
-
5
5
  require 'vendor/snabbdom'
6
- require 'vendor/snabbdom-to-html'
7
-
8
6
  require 'snabberb/component'
9
7
 
10
8
  module Snabberb
@@ -5,6 +5,99 @@ module Snabberb
5
5
  attr_accessor :node
6
6
  attr_reader :root
7
7
 
8
+ %x{
9
+ const VOID = new Set([
10
+ 'area',
11
+ 'base',
12
+ 'br',
13
+ 'col',
14
+ 'embed',
15
+ 'hr',
16
+ 'img',
17
+ 'input',
18
+ 'keygen',
19
+ 'link',
20
+ 'meta',
21
+ 'param',
22
+ 'source',
23
+ 'track',
24
+ 'wbr',
25
+ ])
26
+
27
+ const IGNORE = new Set([
28
+ 'attributes',
29
+ 'childElementCount',
30
+ 'children',
31
+ 'classList',
32
+ 'clientHeight',
33
+ 'clientLeft',
34
+ 'clientTop',
35
+ 'clientWidth',
36
+ 'currentStyle',
37
+ 'firstElementChild',
38
+ 'innerHTML',
39
+ 'lastElementChild',
40
+ 'nextElementSibling',
41
+ 'ongotpointercapture',
42
+ 'onlostpointercapture',
43
+ 'onwheel',
44
+ 'outerHTML',
45
+ 'previousElementSibling',
46
+ 'runtimeStyle',
47
+ 'scrollHeight',
48
+ 'scrollLeft',
49
+ 'scrollLeftMax',
50
+ 'scrollTop',
51
+ 'scrollTopMax',
52
+ 'scrollWidth',
53
+ 'tabStop',
54
+ 'tagName',
55
+ ])
56
+
57
+ const BOOLEAN = new Set([
58
+ 'disabled',
59
+ 'visible',
60
+ 'checked',
61
+ 'readonly',
62
+ 'required',
63
+ 'allowfullscreen',
64
+ 'autofocus',
65
+ 'autoplay',
66
+ 'compact',
67
+ 'controls',
68
+ 'default',
69
+ 'formnovalidate',
70
+ 'hidden',
71
+ 'ismap',
72
+ 'itemscope',
73
+ 'loop',
74
+ 'multiple',
75
+ 'muted',
76
+ 'noresize',
77
+ 'noshade',
78
+ 'novalidate',
79
+ 'nowrap',
80
+ 'open',
81
+ 'reversed',
82
+ 'seamless',
83
+ 'selected',
84
+ 'sortable',
85
+ 'truespeed',
86
+ 'typemustmatch',
87
+ ])
88
+ }
89
+
90
+ %x{
91
+ const PATCHER = snabbdom.init([
92
+ snabbdom.attributesModule,
93
+ snabbdom.classModule,
94
+ snabbdom.datasetModule,
95
+ snabbdom.eventListenersModule,
96
+ snabbdom.propsModule,
97
+ snabbdom.styleModule,
98
+ ])
99
+ }
100
+
8
101
  # You can define needs in each component. They are automatically set as instance variables
9
102
  #
10
103
  # For example:
@@ -27,7 +120,7 @@ module Snabberb
27
120
  def self.attach(container, **passed_needs)
28
121
  component = new(nil, passed_needs)
29
122
  component.node = `document.getElementById(#{container})`
30
- component.update
123
+ component.update!
31
124
  end
32
125
 
33
126
  # Render the component as an HTML string using snabbdom-to-html.
@@ -57,7 +150,7 @@ module Snabberb
57
150
  end
58
151
 
59
152
  def html
60
- `toHTML(#{render})`
153
+ node_to_s(render)
61
154
  end
62
155
 
63
156
  # Building block for dom elements using Snabbdom h and Snabberb components.
@@ -95,15 +188,8 @@ module Snabberb
95
188
  request_ids.shift
96
189
  return unless request_ids.empty?
97
190
 
98
- @@patcher ||= %x{snabbdom.init([
99
- snabbdom.attributesModule,
100
- snabbdom.classModule,
101
- snabbdom.eventListenersModule,
102
- snabbdom.propsModule,
103
- snabbdom.styleModule,
104
- ])}
105
191
  node = @root.render
106
- @@patcher.call(@root.node, node)
192
+ `PATCHER(#{root.node}, #{node})`
107
193
  @root.node = node
108
194
  end
109
195
 
@@ -151,6 +237,113 @@ module Snabberb
151
237
  end
152
238
  end
153
239
  end
240
+
241
+ # rubocop:disable Lint/UnusedMethodArgument
242
+ def parse_sel(sel)
243
+ %x{
244
+ let tag = ''
245
+ let id = ''
246
+ const classes = {}
247
+ const parts = sel.split(".")
248
+
249
+ parts.forEach((part, index) => {
250
+ if (index == 0) {
251
+ part = part.split('#')
252
+ if (part.length > 1) id = part[1]
253
+ part = part[0]
254
+ index == 0 ? tag = part : classes[part] = true
255
+ } else if (!tag) {
256
+ tag = part
257
+ } else {
258
+ classes[part] = true
259
+ }
260
+ })
261
+
262
+ return {
263
+ tag: tag,
264
+ id: id,
265
+ classes: classes,
266
+ }
267
+ }
268
+ end
269
+
270
+ def node_to_s(vnode)
271
+ %x{
272
+ if (!vnode.sel) return self.$escape(vnode.text)
273
+
274
+ const sel = self.$parse_sel(vnode.sel)
275
+
276
+ for (const key in vnode.data.class) {
277
+ vnode.data.class[key] ? sel['classes'][key] = true : delete sel['classes'][key]
278
+ }
279
+
280
+ let attributes = {}
281
+ if (sel['id'].length > 0) attributes['id'] = sel['id']
282
+
283
+ const classes = Object.keys(sel['classes'])
284
+ if (classes.length > 0) attributes['class'] = classes.join(' ')
285
+
286
+ for (const key in vnode.data.attrs) {
287
+ attributes[key] = vnode.data.attrs[key]
288
+ }
289
+
290
+ for (const key in vnode.data.dataset) {
291
+ attributes['data-' + key] = vnode.data.dataset[key]
292
+ }
293
+
294
+ for (const key in vnode.data.props) {
295
+ if (!IGNORE.has(key)) {
296
+ const value = vnode.data.props[key]
297
+
298
+ if (BOOLEAN.has(key)) {
299
+ if (value) attributes[key] = key
300
+ } else {
301
+ attributes[key] = value
302
+ }
303
+ }
304
+ }
305
+
306
+ const styles = []
307
+
308
+ for (let key in vnode.data.style) {
309
+ const value = vnode.data.style[key]
310
+ key = key.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
311
+ styles.push(key + ': ' + value)
312
+ }
313
+
314
+ if (styles.length > 0) attributes['style'] = styles.join('; ')
315
+
316
+ attributes = Object.keys(attributes).map(key =>
317
+ self.$escape(key) + '="' + self.$escape(attributes[key]) + '"'
318
+ )
319
+
320
+ const tag = sel['tag']
321
+ const elements = ['<' + tag]
322
+ if (attributes.length > 0) elements.push(' ' + attributes.join(' '))
323
+ elements.push('>')
324
+
325
+ if (!VOID.has(tag)) {
326
+ if (vnode.data.props && vnode.data.props.innerHTML) {
327
+ elements.push(vnode.data.props.innerHTML)
328
+ } else if (vnode.text) {
329
+ elements.push(self.$escape(vnode.text))
330
+ } else if (vnode.children) {
331
+ vnode.children.forEach(child =>
332
+ elements.push(self.$node_to_s(child))
333
+ )
334
+ }
335
+
336
+ elements.push('</' + tag + '>')
337
+ }
338
+
339
+ return elements.join('')
340
+ }
341
+ end
342
+ # rubocop:enable Lint/UnusedMethodArgument
343
+
344
+ def escape(html)
345
+ ERB::Util.html_escape(html)
346
+ end
154
347
  end
155
348
 
156
349
  # Sublcass this to prerender applications.
@@ -11,22 +11,26 @@ var _attributes = require("./node_modules/snabbdom/build/package/modules/attribu
11
11
 
12
12
  var _class = require("./node_modules/snabbdom/build/package/modules/class");
13
13
 
14
+ var _dataset = require("./node_modules/snabbdom/build/package/modules/dataset");
15
+
14
16
  var _eventlisteners = require("./node_modules/snabbdom/build/package/modules/eventlisteners");
15
17
 
16
18
  var _props = require("./node_modules/snabbdom/build/package/modules/props");
17
19
 
18
20
  var _style = require("./node_modules/snabbdom/build/package/modules/style");
19
21
 
22
+ // browserify build.js -p esmify -s snabbdom > opal/vendor/snabbdom.js
20
23
  module.exports.init = _init.init;
21
24
  module.exports.h = _h.h;
22
25
  module.exports.toVNode = _tovnode.toVNode;
23
26
  module.exports.attributesModule = _attributes.attributesModule;
24
27
  module.exports.classModule = _class.classModule;
28
+ module.exports.datasetModule = _dataset.datasetModule;
25
29
  module.exports.eventListenersModule = _eventlisteners.eventListenersModule;
26
30
  module.exports.propsModule = _props.propsModule;
27
31
  module.exports.styleModule = _style.styleModule;
28
32
 
29
- },{"./node_modules/snabbdom/build/package/h":2,"./node_modules/snabbdom/build/package/init":4,"./node_modules/snabbdom/build/package/modules/attributes":6,"./node_modules/snabbdom/build/package/modules/class":7,"./node_modules/snabbdom/build/package/modules/eventlisteners":8,"./node_modules/snabbdom/build/package/modules/props":9,"./node_modules/snabbdom/build/package/modules/style":10,"./node_modules/snabbdom/build/package/tovnode":11}],2:[function(require,module,exports){
33
+ },{"./node_modules/snabbdom/build/package/h":2,"./node_modules/snabbdom/build/package/init":4,"./node_modules/snabbdom/build/package/modules/attributes":6,"./node_modules/snabbdom/build/package/modules/class":7,"./node_modules/snabbdom/build/package/modules/dataset":8,"./node_modules/snabbdom/build/package/modules/eventlisteners":9,"./node_modules/snabbdom/build/package/modules/props":10,"./node_modules/snabbdom/build/package/modules/style":11,"./node_modules/snabbdom/build/package/tovnode":12}],2:[function(require,module,exports){
30
34
  "use strict";
31
35
 
32
36
  Object.defineProperty(exports, "__esModule", {
@@ -101,7 +105,7 @@ function h(sel, b, c) {
101
105
 
102
106
  ;
103
107
 
104
- },{"./is.js":5,"./vnode.js":12}],3:[function(require,module,exports){
108
+ },{"./is.js":5,"./vnode.js":13}],3:[function(require,module,exports){
105
109
  "use strict";
106
110
 
107
111
  Object.defineProperty(exports, "__esModule", {
@@ -560,7 +564,7 @@ function init(modules, domApi) {
560
564
  };
561
565
  }
562
566
 
563
- },{"./htmldomapi.js":3,"./is.js":5,"./vnode.js":12}],5:[function(require,module,exports){
567
+ },{"./htmldomapi.js":3,"./is.js":5,"./vnode.js":13}],5:[function(require,module,exports){
564
568
  "use strict";
565
569
 
566
570
  Object.defineProperty(exports, "__esModule", {
@@ -682,6 +686,55 @@ exports.classModule = classModule;
682
686
  },{}],8:[function(require,module,exports){
683
687
  "use strict";
684
688
 
689
+ Object.defineProperty(exports, "__esModule", {
690
+ value: true
691
+ });
692
+ exports.datasetModule = void 0;
693
+ const CAPS_REGEX = /[A-Z]/g;
694
+
695
+ function updateDataset(oldVnode, vnode) {
696
+ const elm = vnode.elm;
697
+ let oldDataset = oldVnode.data.dataset;
698
+ let dataset = vnode.data.dataset;
699
+ let key;
700
+ if (!oldDataset && !dataset) return;
701
+ if (oldDataset === dataset) return;
702
+ oldDataset = oldDataset || {};
703
+ dataset = dataset || {};
704
+ const d = elm.dataset;
705
+
706
+ for (key in oldDataset) {
707
+ if (!dataset[key]) {
708
+ if (d) {
709
+ if (key in d) {
710
+ delete d[key];
711
+ }
712
+ } else {
713
+ elm.removeAttribute('data-' + key.replace(CAPS_REGEX, '-$&').toLowerCase());
714
+ }
715
+ }
716
+ }
717
+
718
+ for (key in dataset) {
719
+ if (oldDataset[key] !== dataset[key]) {
720
+ if (d) {
721
+ d[key] = dataset[key];
722
+ } else {
723
+ elm.setAttribute('data-' + key.replace(CAPS_REGEX, '-$&').toLowerCase(), dataset[key]);
724
+ }
725
+ }
726
+ }
727
+ }
728
+
729
+ const datasetModule = {
730
+ create: updateDataset,
731
+ update: updateDataset
732
+ };
733
+ exports.datasetModule = datasetModule;
734
+
735
+ },{}],9:[function(require,module,exports){
736
+ "use strict";
737
+
685
738
  Object.defineProperty(exports, "__esModule", {
686
739
  value: true
687
740
  });
@@ -774,7 +827,7 @@ const eventListenersModule = {
774
827
  };
775
828
  exports.eventListenersModule = eventListenersModule;
776
829
 
777
- },{}],9:[function(require,module,exports){
830
+ },{}],10:[function(require,module,exports){
778
831
  "use strict";
779
832
 
780
833
  Object.defineProperty(exports, "__esModule", {
@@ -810,7 +863,7 @@ const propsModule = {
810
863
  };
811
864
  exports.propsModule = propsModule;
812
865
 
813
- },{}],10:[function(require,module,exports){
866
+ },{}],11:[function(require,module,exports){
814
867
  "use strict";
815
868
 
816
869
  Object.defineProperty(exports, "__esModule", {
@@ -942,7 +995,7 @@ const styleModule = {
942
995
  };
943
996
  exports.styleModule = styleModule;
944
997
 
945
- },{}],11:[function(require,module,exports){
998
+ },{}],12:[function(require,module,exports){
946
999
  "use strict";
947
1000
 
948
1001
  Object.defineProperty(exports, "__esModule", {
@@ -996,7 +1049,7 @@ function toVNode(node, domApi) {
996
1049
  }
997
1050
  }
998
1051
 
999
- },{"./htmldomapi.js":3,"./vnode.js":12}],12:[function(require,module,exports){
1052
+ },{"./htmldomapi.js":3,"./vnode.js":13}],13:[function(require,module,exports){
1000
1053
  "use strict";
1001
1054
 
1002
1055
  Object.defineProperty(exports, "__esModule", {