tao_on_rails 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2b59124fa26b5e654fb672ef1fc59beee2a8b1aa
4
- data.tar.gz: d1ecab0813707fb29fce18a95fa4304395551dd4
3
+ metadata.gz: f8b45a9f5ea2544ee0e862a0fda2951823782acf
4
+ data.tar.gz: 0f0d0a4e37d370970168da6ea3713648345f8129
5
5
  SHA512:
6
- metadata.gz: 7d052ab6fa7224f82e04bcad380a1e7298669c91a968f2598112bb04758cb9e4c359bc85f72cb8a89dba74219128bf611533233582cc9a12d75287c844296727
7
- data.tar.gz: 71089fae4c210927397d969e9ccc88192d84b17b62610ac25727b8c2829cf1d392e493e093bc3e60369b26b2ef9911006c41dbe1961c3818debb3134fc62a999
6
+ metadata.gz: 401af2ff83fcc21a8cbb43bdbb60582f392b311ef2509dd7cfe4c61c3f1cf6c5411c37bdf68f47fda4ef3092308b202bdb1286e9df14e1095ce4cf4ac70b10f1
7
+ data.tar.gz: a724d766fa57de46db680b9397c96779ca24de274eeb9d36738fca24bfff297273fe19cbbbaa354658afcf2de4ee1611ac1ebd34a4ac4286b9898e70825e1768
@@ -1,5 +1,5 @@
1
1
  module TaoOnRails
2
2
  module Rails
3
- VERSION = "0.1.1"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -1,55 +1,54 @@
1
1
  namespace :tao do
2
- namespace :svg_icons do
3
- desc 'generate svg icons.'
4
- task :generate => :environment do
5
- Dir.mkdir "#{Rails.root}/vendor/assets/javascripts/tao"
6
-
7
- File.open "#{Rails.root}/vendor/assets/javascripts/tao/icons.coffee", 'w' do |f|
8
- f.puts %{tao.iconsHtml = '''#{svg_html}'''}
9
- end
10
- end
11
2
 
12
- private
3
+ desc 'generate svg icons.'
4
+ task :generate_icons => :environment do
5
+ Dir.mkdir "#{Rails.root}/vendor/assets/javascripts/tao"
13
6
 
14
- def svg_html
15
- %{<svg id="tao-icons" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none">\n#{symbols}</svg>}
7
+ File.open "#{Rails.root}/vendor/assets/javascripts/tao/icons.coffee", 'w' do |f|
8
+ f.puts %{tao.iconsHtml = '''#{svg_html}'''}
16
9
  end
10
+ end
17
11
 
18
- def svg_files
19
- @svg_files ||= Dir.glob(File.expand_path("#{::Rails.root}/app/assets/icons/*.svg")).uniq
20
- end
12
+ private
21
13
 
22
- def symbols
23
- svg_files.map {|file| " #{symbol(file)}\n"}.join
24
- end
14
+ def svg_html
15
+ %{<svg id="tao-icons" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none">\n#{symbols}</svg>}
16
+ end
25
17
 
26
- def symbol(path)
27
- name = File.basename(path, ".*").underscore().dasherize()
28
- content = File.read(path)
29
- content.gsub(/<?.+\?>/,'')
30
- .gsub(/<!.+?>/,'')
31
- .gsub(/<title>.*<\/title>/, '')
32
- .gsub(/<desc>.*<\/desc>/, '')
33
- .gsub(/id=/,'class=')
34
- .gsub(/<svg.+?>/, %Q{<svg id="icon-#{name}" #{dimensions(content)}>})
35
- .gsub(/svg/,'symbol')
36
- .gsub(/\n/, '') # Remove endlines
37
- .gsub(/\s{2,}/, ' ') # Remove whitespace
38
- .gsub(/>\s+</, '><') # Remove whitespace between tags
39
- end
18
+ def svg_files
19
+ @svg_files ||= Dir.glob(File.expand_path("#{::Rails.root}/app/assets/icons/*.svg")).uniq
20
+ end
40
21
 
41
- def dimensions(content)
42
- dimension = content.scan(/<svg.+(viewBox=["'](.+?)["'])/).flatten
43
- viewbox = dimension.first
44
- #coords = dimension.last.split(' ')
45
-
46
- #width = coords[2].to_i - coords[0].to_i
47
- #height = coords[3].to_i - coords[1].to_i
48
- #hack android svg
49
- width = '100%'
50
- height = '100%'
51
- %Q{#{viewbox} width="#{width}" height="#{height}"}
52
- end
22
+ def symbols
23
+ svg_files.map {|file| " #{symbol(file)}\n"}.join
24
+ end
25
+
26
+ def symbol(path)
27
+ name = File.basename(path, ".*").underscore().dasherize()
28
+ content = File.read(path)
29
+ content.gsub(/<?.+\?>/,'')
30
+ .gsub(/<!.+?>/,'')
31
+ .gsub(/<title>.*<\/title>/, '')
32
+ .gsub(/<desc>.*<\/desc>/, '')
33
+ .gsub(/id=/,'class=')
34
+ .gsub(/<svg.+?>/, %Q{<svg id="icon-#{name}" #{dimensions(content)}>})
35
+ .gsub(/svg/,'symbol')
36
+ .gsub(/\n/, '') # Remove endlines
37
+ .gsub(/\s{2,}/, ' ') # Remove whitespace
38
+ .gsub(/>\s+</, '><') # Remove whitespace between tags
39
+ end
40
+
41
+ def dimensions(content)
42
+ dimension = content.scan(/<svg.+(viewBox=["'](.+?)["'])/).flatten
43
+ viewbox = dimension.first
44
+ #coords = dimension.last.split(' ')
45
+
46
+ #width = coords[2].to_i - coords[0].to_i
47
+ #height = coords[3].to_i - coords[1].to_i
48
+ #hack android svg
49
+ width = '100%'
50
+ height = '100%'
51
+ %Q{#{viewbox} width="#{width}" height="#{height}"}
53
52
  end
54
53
 
55
54
  end
@@ -0,0 +1,861 @@
1
+ //= require native-shim
2
+
3
+ 'use strict';
4
+
5
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
6
+
7
+ var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
8
+
9
+ function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
10
+
11
+ //= require native-shim
12
+
13
+ /**
14
+ * @license
15
+ * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
16
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
17
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
18
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
19
+ * Code distributed by Google as part of the polymer project is also
20
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
21
+ */
22
+
23
+ /**
24
+ * 2.3
25
+ * http://w3c.github.io/webcomponents/spec/custom/#dfn-element-definition
26
+ * @typedef {{
27
+ * name: string,
28
+ * localName: string,
29
+ * constructor: function(new:HTMLElement),
30
+ * connectedCallback: (Function|undefined),
31
+ * disconnectedCallback: (Function|undefined),
32
+ * attributeChangedCallback: (Function|undefined),
33
+ * observedAttributes: Array<string>,
34
+ * }}
35
+ */
36
+ var CustomElementDefinition = void 0;
37
+
38
+ /**
39
+ * @typedef {{
40
+ * resolve: !function(undefined),
41
+ * promise: !Promise<undefined>,
42
+ * }}
43
+ */
44
+ var Deferred = void 0;
45
+
46
+ (function () {
47
+ 'use strict';
48
+
49
+ var doc = document;
50
+ var win = window;
51
+
52
+ /**
53
+ * Gets 'customElement' from window so that it could be modified after
54
+ * the polyfill loads.
55
+ * @function
56
+ * @return {CustomElementRegistry}
57
+ */
58
+ var _customElements = function _customElements() {
59
+ return win['customElements'];
60
+ };
61
+
62
+ var _observerProp = '__$CE_observer';
63
+ var _attachedProp = '__$CE_attached';
64
+ var _upgradedProp = '__$CE_upgraded';
65
+
66
+ if (_customElements()) {
67
+ _customElements().flush = function () {};
68
+ if (!_customElements().forcePolyfill) {
69
+ nativeShim();
70
+ return;
71
+ }
72
+ }
73
+
74
+ // name validation
75
+ // https://html.spec.whatwg.org/multipage/scripting.html#valid-custom-element-name
76
+
77
+ /**
78
+ * @const
79
+ * @type {Array<string>}
80
+ */
81
+ var reservedTagList = ['annotation-xml', 'color-profile', 'font-face', 'font-face-src', 'font-face-uri', 'font-face-format', 'font-face-name', 'missing-glyph'];
82
+
83
+ /**
84
+ * @param {!string} name
85
+ * @return {!Error|undefined}
86
+ */
87
+ function checkValidCustomElementName(name) {
88
+ if (!(/^[a-z][.0-9_a-z]*-[\-.0-9_a-z]*$/.test(name) && reservedTagList.indexOf(name) === -1)) {
89
+ return new Error('The element name \'' + name + '\' is not valid.');
90
+ }
91
+ }
92
+
93
+ /**
94
+ * @param {!Node} root
95
+ * @return {TreeWalker}
96
+ */
97
+ function createTreeWalker(root) {
98
+ // IE 11 requires the third and fourth arguments be present. If the third
99
+ // arg is null, it applies the default behaviour. However IE also requires
100
+ // the fourth argument be present even though the other browsers ignore it.
101
+ return doc.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null, false);
102
+ }
103
+
104
+ /**
105
+ * @param {!Node} node
106
+ * @return {boolean}
107
+ */
108
+ function isElement(node) {
109
+ return node.nodeType === Node.ELEMENT_NODE;
110
+ }
111
+
112
+ /**
113
+ * @param {!Element} element
114
+ * @return {boolean}
115
+ */
116
+ function isHtmlImport(element) {
117
+ return element.tagName === 'LINK' && element.rel && element.rel.toLowerCase().split(' ').indexOf('import') !== -1;
118
+ }
119
+
120
+ /**
121
+ * @param {!Element} element
122
+ * @return {boolean}
123
+ */
124
+ function isConnected(element) {
125
+ var n = element;
126
+ do {
127
+ if (n[_attachedProp] || n.nodeType === Node.DOCUMENT_NODE) return true;
128
+ n = n.parentNode || n.nodeType === Node.DOCUMENT_FRAGMENT_NODE && n.host;
129
+ } while (n);
130
+ return false;
131
+ }
132
+
133
+ /**
134
+ * A registry of custom element definitions.
135
+ *
136
+ * See https://html.spec.whatwg.org/multipage/scripting.html#customelementsregistry
137
+ *
138
+ * @property {boolean} enableFlush Set to true to enable the flush() method
139
+ * to work. This should only be done for tests, as it causes a memory leak.
140
+ */
141
+
142
+ var CustomElementRegistry = function () {
143
+ function CustomElementRegistry() {
144
+ _classCallCheck(this, CustomElementRegistry);
145
+
146
+ /** @private {!Map<string, !CustomElementDefinition>} **/
147
+ this._definitions = new Map();
148
+
149
+ /** @private {!Map<Function, string>} **/
150
+ this._constructors = new Map();
151
+
152
+ /** @private {!Map<string, !Deferred>} **/
153
+ this._whenDefinedMap = new Map();
154
+
155
+ /** @private {!Set<!MutationObserver>} **/
156
+ this._observers = new Set();
157
+
158
+ /** @private {!MutationObserver} **/
159
+ this._attributeObserver = new MutationObserver(
160
+ /** @type {function(Array<MutationRecord>, MutationObserver)} */
161
+ this._handleAttributeChange.bind(this));
162
+
163
+ /** @private {?HTMLElement} **/
164
+ this._newInstance = null;
165
+
166
+ /** @private {!Set<string>} **/
167
+ this._pendingHtmlImportUrls = new Set();
168
+
169
+ /** @type {boolean} **/
170
+ this.enableFlush = true;
171
+
172
+ /** @private {boolean} **/
173
+ this._upgradeScheduled = false;
174
+
175
+ /** @type {MutationObserver} **/
176
+ this._mainDocumentObserver = null;
177
+ }
178
+
179
+ // HTML spec part 4.13.4
180
+ // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregistry-define
181
+ /**
182
+ * @param {string} name
183
+ * @param {function(new:HTMLElement)} constructor
184
+ * @param {{extends: string}} options
185
+ * @return {undefined}
186
+ */
187
+
188
+
189
+ _createClass(CustomElementRegistry, [{
190
+ key: 'define',
191
+ value: function define(name, constructor, options) {
192
+ // 1:
193
+ if (typeof constructor !== 'function') {
194
+ throw new TypeError('constructor must be a Constructor');
195
+ }
196
+
197
+ // 2. If constructor is an interface object whose corresponding interface
198
+ // either is HTMLElement or has HTMLElement in its set of inherited
199
+ // interfaces, throw a TypeError and abort these steps.
200
+ //
201
+ // It doesn't appear possible to check this condition from script
202
+
203
+ // 3:
204
+ var nameError = checkValidCustomElementName(name);
205
+ if (nameError) throw nameError;
206
+
207
+ // 4, 5:
208
+ // Note: we don't track being-defined names and constructors because
209
+ // define() isn't normally reentrant. The only time user code can run
210
+ // during define() is when getting callbacks off the prototype, which
211
+ // would be highly-unusual. We can make define() reentrant-safe if needed.
212
+ if (this._definitions.has(name)) {
213
+ throw new Error('An element with name \'' + name + '\' is already defined');
214
+ }
215
+
216
+ // 6, 7:
217
+ if (this._constructors.has(constructor)) {
218
+ throw new Error('Definition failed for \'' + name + '\': ' + 'The constructor is already used.');
219
+ }
220
+
221
+ // 8:
222
+ /** @type {string} */
223
+ var localName = name;
224
+
225
+ // 9, 10: We do not support extends currently.
226
+
227
+ // 11, 12, 13: Our define() isn't rentrant-safe
228
+
229
+ // 14.1:
230
+ /** @type {Object} */
231
+ var prototype = constructor.prototype;
232
+
233
+ // 14.2:
234
+ if ((typeof prototype === 'undefined' ? 'undefined' : _typeof(prototype)) !== 'object') {
235
+ throw new TypeError('Definition failed for \'' + name + '\': ' + 'constructor.prototype must be an object');
236
+ }
237
+
238
+ /**
239
+ * @param {string} callbackName
240
+ * @return {Function|undefined}
241
+ */
242
+ function getCallback(callbackName) {
243
+ var callback = prototype[callbackName];
244
+ if (callback !== undefined && typeof callback !== 'function') {
245
+ throw new Error(localName + ' \'' + callbackName + '\' is not a Function');
246
+ }
247
+ return callback;
248
+ }
249
+
250
+ // 3, 4:
251
+ var connectedCallback = getCallback('connectedCallback');
252
+
253
+ // 5, 6:
254
+ var disconnectedCallback = getCallback('disconnectedCallback');
255
+
256
+ // Divergence from spec: we always throw if attributeChangedCallback is
257
+ // not a function.
258
+
259
+ // 7, 9.1:
260
+ var attributeChangedCallback = getCallback('attributeChangedCallback');
261
+
262
+ // 8, 9.2, 9.3:
263
+ var observedAttributes = attributeChangedCallback && constructor['observedAttributes'] || [];
264
+
265
+ // 15:
266
+ /** @type {CustomElementDefinition} */
267
+ var definition = {
268
+ name: name,
269
+ localName: localName,
270
+ constructor: constructor,
271
+ connectedCallback: connectedCallback,
272
+ disconnectedCallback: disconnectedCallback,
273
+ attributeChangedCallback: attributeChangedCallback,
274
+ observedAttributes: observedAttributes
275
+ };
276
+
277
+ // 16:
278
+ this._definitions.set(localName, definition);
279
+ this._constructors.set(constructor, localName);
280
+
281
+ // 17, 18, 19:
282
+ this._upgradeDoc();
283
+
284
+ // 20:
285
+ /** @type {Deferred} **/
286
+ var deferred = this._whenDefinedMap.get(localName);
287
+ if (deferred) {
288
+ deferred.resolve(undefined);
289
+ this._whenDefinedMap.delete(localName);
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Returns the constructor defined for `name`, or `null`.
295
+ *
296
+ * @param {string} name
297
+ * @return {Function|undefined}
298
+ */
299
+
300
+ }, {
301
+ key: 'get',
302
+ value: function get(name) {
303
+ // https://html.spec.whatwg.org/multipage/scripting.html#custom-elements-api
304
+ var def = this._definitions.get(name);
305
+ return def ? def.constructor : undefined;
306
+ }
307
+
308
+ /**
309
+ * Returns a `Promise` that resolves when a custom element for `name` has
310
+ * been defined.
311
+ *
312
+ * @param {string} name
313
+ * @return {!Promise}
314
+ */
315
+
316
+ }, {
317
+ key: 'whenDefined',
318
+ value: function whenDefined(name) {
319
+ // https://html.spec.whatwg.org/multipage/scripting.html#dom-customelementsregistry-whendefined
320
+ var nameError = checkValidCustomElementName(name);
321
+ if (nameError) return Promise.reject(nameError);
322
+ if (this._definitions.has(name)) return Promise.resolve();
323
+
324
+ /** @type {Deferred} **/
325
+ var deferred = this._whenDefinedMap.get(name);
326
+ if (deferred) return deferred.promise;
327
+
328
+ var resolve = void 0;
329
+ var promise = new Promise(function (_resolve, _) {
330
+ resolve = _resolve;
331
+ });
332
+ deferred = { promise: promise, resolve: resolve };
333
+ this._whenDefinedMap.set(name, deferred);
334
+ return promise;
335
+ }
336
+
337
+ /**
338
+ * Causes all pending mutation records to be processed, and thus all
339
+ * customization, upgrades and custom element reactions to be called.
340
+ * `enableFlush` must be true for this to work. Only use during tests!
341
+ */
342
+
343
+ }, {
344
+ key: 'flush',
345
+ value: function flush() {
346
+ if (this.enableFlush) {
347
+ // console.warn("flush!!!");
348
+ this._handleMutations(this._mainDocumentObserver.takeRecords());
349
+ this._handleAttributeChange(this._attributeObserver.takeRecords());
350
+ this._observers.forEach(
351
+ /**
352
+ * @param {!MutationObserver} observer
353
+ * @this {CustomElementRegistry}
354
+ */
355
+ function (observer) {
356
+ this._handleMutations(observer.takeRecords());
357
+ }, this);
358
+ }
359
+ }
360
+
361
+ /**
362
+ * Upgrade all existing in document elements. This process is expensive so
363
+ * is optionally batched based on the state of HTMLImports. (Note,
364
+ * this batching might not be necessary if instead of walking the dom,
365
+ * a map of upgrade candidates was maintained.)
366
+ * @private
367
+ */
368
+
369
+ }, {
370
+ key: '_upgradeDoc',
371
+ value: function _upgradeDoc() {
372
+ var _this2 = this;
373
+
374
+ if (!this._upgradeScheduled) {
375
+ this._upgradeScheduled = true;
376
+ var onReady = function onReady() {
377
+ _this2._upgradeScheduled = false;
378
+ if (!_this2._mainDocumentObserver) {
379
+ _this2._mainDocumentObserver = _this2._observeRoot(doc);
380
+ }
381
+ _this2._addNodes(doc.childNodes);
382
+ };
383
+ if (window['HTMLImports']) {
384
+ window['HTMLImports']['whenReady'](onReady);
385
+ } else {
386
+ onReady();
387
+ }
388
+ }
389
+ }
390
+
391
+ /**
392
+ * @param {?HTMLElement} instance
393
+ * @private
394
+ */
395
+
396
+ }, {
397
+ key: '_setNewInstance',
398
+ value: function _setNewInstance(instance) {
399
+ this._newInstance = instance;
400
+ }
401
+
402
+ /**
403
+ * Observes a DOM root for mutations that trigger upgrades and reactions.
404
+ * @param {Node} root
405
+ * @private
406
+ */
407
+
408
+ }, {
409
+ key: '_observeRoot',
410
+ value: function _observeRoot(root) {
411
+ // console.log('_observeRoot', root, root.baseURI);
412
+ // console.assert(!root[_observerProp]);
413
+ if (root[_observerProp] != null) {
414
+ //console.warn(`Root ${root} is already observed`);
415
+ return root[_observerProp];
416
+ }
417
+ root[_observerProp] = new MutationObserver(
418
+ /** @type {function(Array<MutationRecord>, MutationObserver)} */
419
+ this._handleMutations.bind(this));
420
+ root[_observerProp].observe(root, { childList: true, subtree: true });
421
+ if (this.enableFlush) {
422
+ // this is memory leak, only use in tests
423
+ this._observers.add(root[_observerProp]);
424
+ }
425
+ return root[_observerProp];
426
+ }
427
+
428
+ /**
429
+ * @param {Node} root
430
+ * @private
431
+ */
432
+
433
+ }, {
434
+ key: '_unobserveRoot',
435
+ value: function _unobserveRoot(root) {
436
+ if (root[_observerProp] != null) {
437
+ root[_observerProp].disconnect();
438
+ if (this.enableFlush) {
439
+ this._observers.delete(root[_observerProp]);
440
+ }
441
+ root[_observerProp] = null;
442
+ }
443
+ }
444
+
445
+ /**
446
+ * @param {!Array<!MutationRecord>} mutations
447
+ * @private
448
+ */
449
+
450
+ }, {
451
+ key: '_handleMutations',
452
+ value: function _handleMutations(mutations) {
453
+ for (var i = 0; i < mutations.length; i++) {
454
+ /** @type {!MutationRecord} */
455
+ var mutation = mutations[i];
456
+ if (mutation.type === 'childList') {
457
+ // Note: we can't get an ordering between additions and removals, and
458
+ // so might diverge from spec reaction ordering
459
+ var addedNodes = /** @type {!NodeList<!Node>} */mutation.addedNodes;
460
+ var removedNodes = /** @type {!NodeList<!Node>} */mutation.removedNodes;
461
+ this._removeNodes(removedNodes);
462
+ this._addNodes(addedNodes);
463
+ }
464
+ }
465
+ }
466
+
467
+ /**
468
+ * @param {!(NodeList<!Node>|Array<!Node>)} nodeList
469
+ * @param {?Set<Node>=} visitedNodes
470
+ * @private
471
+ */
472
+
473
+ }, {
474
+ key: '_addNodes',
475
+ value: function _addNodes(nodeList, visitedNodes) {
476
+ visitedNodes = visitedNodes || new Set();
477
+
478
+ for (var i = 0; i < nodeList.length; i++) {
479
+ var root = nodeList[i];
480
+
481
+ if (!isElement(root)) {
482
+ continue;
483
+ }
484
+
485
+ // Since we're adding this node to an observed tree, we can unobserve
486
+ this._unobserveRoot(root);
487
+
488
+ var walker = createTreeWalker(root);
489
+ do {
490
+ var node = /** @type {!HTMLElement} */walker.currentNode;
491
+ this._addElement(node, visitedNodes);
492
+ } while (walker.nextNode());
493
+ }
494
+ }
495
+
496
+ /**
497
+ * @param {!HTMLElement} element
498
+ * @param {!Set<Node>=} visitedNodes
499
+ */
500
+
501
+ }, {
502
+ key: '_addElement',
503
+ value: function _addElement(element, visitedNodes) {
504
+ if (visitedNodes.has(element)) return;
505
+ visitedNodes.add(element);
506
+
507
+ /** @type {?CustomElementDefinition} */
508
+ var definition = this._definitions.get(element.localName);
509
+ if (definition) {
510
+ if (!element[_upgradedProp]) {
511
+ this._upgradeElement(element, definition, true);
512
+ }
513
+ if (element[_upgradedProp] && !element[_attachedProp] && isConnected(element)) {
514
+ element[_attachedProp] = true;
515
+ if (definition.connectedCallback) {
516
+ definition.connectedCallback.call(element);
517
+ }
518
+ }
519
+ }
520
+ if (element.shadowRoot) {
521
+ // TODO(justinfagnani): do we need to check that the shadowRoot
522
+ // is observed?
523
+ this._addNodes(element.shadowRoot.childNodes, visitedNodes);
524
+ }
525
+ if (isHtmlImport(element)) {
526
+ this._addImport( /** @type {!HTMLLinkElement} */element, visitedNodes);
527
+ }
528
+ }
529
+
530
+ /**
531
+ * @param {!HTMLLinkElement} link
532
+ * @param {!Set<Node>=} visitedNodes
533
+ */
534
+
535
+ }, {
536
+ key: '_addImport',
537
+ value: function _addImport(link, visitedNodes) {
538
+ var _this3 = this;
539
+
540
+ // During a tree walk to add or upgrade nodes, we may encounter multiple
541
+ // HTML imports that reference the same document, and may encounter
542
+ // imports in various states of loading.
543
+
544
+ // First, we only want to process the first import for a document in a
545
+ // walk, so we check visitedNodes for the document, not the link.
546
+ //
547
+ // Second, for documents that haven't loaded yet, we only want to add one
548
+ // listener, regardless of the number of links or walks, so we track
549
+ // pending loads in _pendingHtmlImportUrls.
550
+
551
+ // Check to see if the import is loaded
552
+ /** @type {?Document} */
553
+ var _import = link.import;
554
+ if (_import) {
555
+ // The import is loaded, but only process the first link element
556
+ if (visitedNodes.has(_import)) return;
557
+ visitedNodes.add(_import);
558
+
559
+ // The import is loaded observe it
560
+ if (!_import[_observerProp]) this._observeRoot(_import);
561
+
562
+ // walk the document
563
+ this._addNodes(_import.childNodes, visitedNodes);
564
+ } else {
565
+ var _ret = function () {
566
+ // The import is not loaded, so wait for it
567
+ /** @type {string} */
568
+ var importUrl = link.href;
569
+ if (_this3._pendingHtmlImportUrls.has(importUrl)) return {
570
+ v: void 0
571
+ };
572
+ _this3._pendingHtmlImportUrls.add(importUrl);
573
+
574
+ /**
575
+ * @const
576
+ * @type {CustomElementRegistry}
577
+ */
578
+ var _this = _this3;
579
+ var onLoad = function onLoad() {
580
+ link.removeEventListener('load', /** @type {function(Event)} */onLoad);
581
+ if (!link.import[_observerProp]) _this._observeRoot(link.import);
582
+ // We don't pass visitedNodes because this is async and not part of
583
+ // the current tree walk.
584
+ _this._addNodes(link.import.childNodes);
585
+ };
586
+ link.addEventListener('load', onLoad);
587
+ }();
588
+
589
+ if ((typeof _ret === 'undefined' ? 'undefined' : _typeof(_ret)) === "object") return _ret.v;
590
+ }
591
+ }
592
+
593
+ /**
594
+ * @param {NodeList} nodeList
595
+ * @private
596
+ */
597
+
598
+ }, {
599
+ key: '_removeNodes',
600
+ value: function _removeNodes(nodeList) {
601
+ for (var i = 0; i < nodeList.length; i++) {
602
+ var root = nodeList[i];
603
+
604
+ if (!isElement(root)) {
605
+ continue;
606
+ }
607
+
608
+ // Since we're detatching this element from an observed root, we need to
609
+ // reobserve it.
610
+ // TODO(justinfagnani): can we do this in a microtask so we don't thrash
611
+ // on creating and destroying MutationObservers on batch DOM mutations?
612
+ this._observeRoot(root);
613
+
614
+ var walker = createTreeWalker(root);
615
+ do {
616
+ var node = walker.currentNode;
617
+ if (node[_upgradedProp] && node[_attachedProp]) {
618
+ node[_attachedProp] = false;
619
+ var definition = this._definitions.get(node.localName);
620
+ if (definition && definition.disconnectedCallback) {
621
+ definition.disconnectedCallback.call(node);
622
+ }
623
+ }
624
+ } while (walker.nextNode());
625
+ }
626
+ }
627
+
628
+ /**
629
+ * Upgrades or customizes a custom element.
630
+ *
631
+ * @param {HTMLElement} element
632
+ * @param {CustomElementDefinition} definition
633
+ * @param {boolean} callConstructor
634
+ * @private
635
+ */
636
+
637
+ }, {
638
+ key: '_upgradeElement',
639
+ value: function _upgradeElement(element, definition, callConstructor) {
640
+ var prototype = definition.constructor.prototype;
641
+ element.__proto__ = prototype;
642
+ if (callConstructor) {
643
+ this._setNewInstance(element);
644
+ new definition.constructor();
645
+ element[_upgradedProp] = true;
646
+ console.assert(this._newInstance == null);
647
+ }
648
+
649
+ var observedAttributes = definition.observedAttributes;
650
+ var attributeChangedCallback = definition.attributeChangedCallback;
651
+ if (attributeChangedCallback && observedAttributes.length > 0) {
652
+ this._attributeObserver.observe(element, {
653
+ attributes: true,
654
+ attributeOldValue: true,
655
+ attributeFilter: observedAttributes
656
+ });
657
+
658
+ // Trigger attributeChangedCallback for existing attributes.
659
+ // https://html.spec.whatwg.org/multipage/scripting.html#upgrades
660
+ for (var i = 0; i < observedAttributes.length; i++) {
661
+ var name = observedAttributes[i];
662
+ if (element.hasAttribute(name)) {
663
+ var value = element.getAttribute(name);
664
+ attributeChangedCallback.call(element, name, null, value, null);
665
+ }
666
+ }
667
+ }
668
+ }
669
+
670
+ /**
671
+ * @param {!Array<!MutationRecord>} mutations
672
+ * @private
673
+ */
674
+
675
+ }, {
676
+ key: '_handleAttributeChange',
677
+ value: function _handleAttributeChange(mutations) {
678
+ for (var i = 0; i < mutations.length; i++) {
679
+ var mutation = mutations[i];
680
+ if (mutation.type === 'attributes') {
681
+ var target = /** @type {HTMLElement} */mutation.target;
682
+ // We should be gaurenteed to have a definition because this mutation
683
+ // observer is only observing custom elements observedAttributes
684
+ var definition = this._definitions.get(target.localName);
685
+ var name = /** @type {!string} */mutation.attributeName;
686
+ var oldValue = mutation.oldValue;
687
+ var newValue = target.getAttribute(name);
688
+ // Skip changes that were handled synchronously by setAttribute
689
+ if (newValue !== oldValue) {
690
+ var namespace = mutation.attributeNamespace;
691
+ definition.attributeChangedCallback.call(target, name, oldValue, newValue, namespace);
692
+ }
693
+ }
694
+ }
695
+ }
696
+ }]);
697
+
698
+ return CustomElementRegistry;
699
+ }();
700
+
701
+ // Closure Compiler Exports
702
+
703
+
704
+ window['CustomElementRegistry'] = CustomElementRegistry;
705
+ CustomElementRegistry.prototype['define'] = CustomElementRegistry.prototype.define;
706
+ CustomElementRegistry.prototype['get'] = CustomElementRegistry.prototype.get;
707
+ CustomElementRegistry.prototype['whenDefined'] = CustomElementRegistry.prototype.whenDefined;
708
+ CustomElementRegistry.prototype['flush'] = CustomElementRegistry.prototype.flush;
709
+ CustomElementRegistry.prototype['polyfilled'] = true;
710
+ // TODO(justinfagnani): remove these in production code
711
+ CustomElementRegistry.prototype['_observeRoot'] = CustomElementRegistry.prototype._observeRoot;
712
+ CustomElementRegistry.prototype['_addImport'] = CustomElementRegistry.prototype._addImport;
713
+
714
+ // patch window.HTMLElement
715
+
716
+ /** @const */
717
+ var origHTMLElement = win.HTMLElement;
718
+ /**
719
+ * @type {function(new: HTMLElement)}
720
+ */
721
+ var newHTMLElement = function HTMLElement() {
722
+ var customElements = _customElements();
723
+
724
+ // If there's an being upgraded, return that
725
+ if (customElements._newInstance) {
726
+ var i = customElements._newInstance;
727
+ customElements._newInstance = null;
728
+ return i;
729
+ }
730
+ if (this.constructor) {
731
+ // Find the tagname of the constructor and create a new element with it
732
+ var tagName = customElements._constructors.get(this.constructor);
733
+ return _createElement(doc, tagName, undefined, false);
734
+ }
735
+ throw new Error('Unknown constructor. Did you call customElements.define()?');
736
+ };
737
+ win.HTMLElement = newHTMLElement;
738
+ win.HTMLElement.prototype = Object.create(origHTMLElement.prototype, {
739
+ constructor: { value: win.HTMLElement, configurable: true, writable: true }
740
+ });
741
+
742
+ // patch doc.createElement
743
+ // TODO(justinfagnani): why is the cast neccessary?
744
+ // Can we fix the Closure DOM externs?
745
+ var _origCreateElement =
746
+ /** @type {function(this:Document, string, (Object|undefined)=): !HTMLElement}}*/
747
+ doc.createElement;
748
+
749
+ /**
750
+ * Creates a new element and upgrades it if it's a custom element.
751
+ * @param {!Document} doc
752
+ * @param {!string} tagName
753
+ * @param {Object|undefined} options
754
+ * @param {boolean} callConstructor whether or not to call the elements
755
+ * constructor after upgrading. If an element is created by calling its
756
+ * constructor, then `callConstructor` should be false to prevent double
757
+ * initialization.
758
+ */
759
+ function _createElement(doc, tagName, options, callConstructor) {
760
+ var customElements = _customElements();
761
+ var element = options ? _origCreateElement.call(doc, tagName, options) : _origCreateElement.call(doc, tagName);
762
+ var definition = customElements._definitions.get(tagName.toLowerCase());
763
+ if (definition) {
764
+ customElements._upgradeElement(element, definition, callConstructor);
765
+ }
766
+ if (tagName.toLowerCase() !== 'html') {
767
+ customElements._observeRoot(element);
768
+ }
769
+ return element;
770
+ };
771
+ doc.createElement = function (tagName, options) {
772
+ return _createElement(doc, tagName, options, true);
773
+ };
774
+
775
+ // patch doc.createElementNS
776
+
777
+ var HTMLNS = 'http://www.w3.org/1999/xhtml';
778
+
779
+ /** @type {function(this:Document,string,string):Element} */
780
+ var _origCreateElementNS = doc.createElementNS;
781
+ doc.createElementNS =
782
+ /** @type {function(this:Document,(string|null),string):!Element} */
783
+ function (namespaceURI, qualifiedName) {
784
+ if (namespaceURI === 'http://www.w3.org/1999/xhtml') {
785
+ return doc.createElement(qualifiedName);
786
+ } else {
787
+ return _origCreateElementNS.call(doc, namespaceURI, qualifiedName);
788
+ }
789
+ };
790
+
791
+ // patch Element.attachShadow
792
+
793
+ /** @type {function({closed: boolean})} */
794
+ var _origAttachShadow = Element.prototype['attachShadow'];
795
+ if (_origAttachShadow) {
796
+ Object.defineProperty(Element.prototype, 'attachShadow', {
797
+ value: function value(options) {
798
+ /** @type {!Node} */
799
+ var root = _origAttachShadow.call(this, options);
800
+ /** @type {CustomElementRegistry} */
801
+ var customElements = _customElements();
802
+ customElements._observeRoot(root);
803
+ return root;
804
+ }
805
+ });
806
+ }
807
+
808
+ // patch doc.importNode
809
+
810
+ var rawImportNode = doc.importNode;
811
+ doc.importNode = function (node, deep) {
812
+ var clone = /** @type{!Node} */rawImportNode.call(doc, node, deep);
813
+ var customElements = _customElements();
814
+ var nodes = isElement(clone) ? [clone] : clone.childNodes;
815
+ /** @type {CustomElementRegistry} */_customElements()._addNodes(nodes);
816
+ return clone;
817
+ };
818
+
819
+ // patch Element.setAttribute & removeAttribute
820
+
821
+ var _origSetAttribute = Element.prototype.setAttribute;
822
+ Element.prototype['setAttribute'] = function (name, value) {
823
+ changeAttribute(this, name, value, _origSetAttribute);
824
+ };
825
+ var _origRemoveAttribute = Element.prototype.removeAttribute;
826
+ Element.prototype['removeAttribute'] = function (name) {
827
+ changeAttribute(this, name, null, _origRemoveAttribute);
828
+ };
829
+
830
+ function changeAttribute(element, name, value, operation) {
831
+ name = name.toLowerCase();
832
+ var oldValue = element.getAttribute(name);
833
+ operation.call(element, name, value);
834
+
835
+ // Bail if this wasn't a fully upgraded custom element
836
+ if (element[_upgradedProp] == true) {
837
+ var definition = _customElements()._definitions.get(element.localName);
838
+ var observedAttributes = definition.observedAttributes;
839
+ var attributeChangedCallback = definition.attributeChangedCallback;
840
+ if (attributeChangedCallback && observedAttributes.indexOf(name) >= 0) {
841
+ var newValue = element.getAttribute(name);
842
+ if (newValue !== oldValue) {
843
+ attributeChangedCallback.call(element, name, oldValue, newValue, null);
844
+ }
845
+ }
846
+ }
847
+ }
848
+
849
+ Object.defineProperty(window, 'customElements', {
850
+ value: new CustomElementRegistry(),
851
+ configurable: true,
852
+ enumerable: true
853
+ });
854
+
855
+ // TODO(justinfagnani): Remove. Temporary for backward-compatibility
856
+ window['CustomElements'] = {
857
+ takeRecords: function takeRecords() {
858
+ if (_customElements().flush) _customElements().flush();
859
+ }
860
+ };
861
+ })();
@@ -0,0 +1,90 @@
1
+
2
+ window.nativeShim = ->
3
+ eval '''
4
+ 'use strict';
5
+
6
+ const NativeHTMLElement = window.HTMLElement;
7
+ const nativeDefine = window.customElements.define;
8
+ const nativeGet = window.customElements.get;
9
+
10
+ /**
11
+ * Map of user-provided constructors to tag names.
12
+ *
13
+ * @type {Map<Function, string>}
14
+ */
15
+ const tagnameByConstructor = new Map();
16
+
17
+ /**
18
+ * Map of tag anmes to user-provided constructors.
19
+ *
20
+ * @type {Map<string, Function>}
21
+ */
22
+ const constructorByTagname = new Map();
23
+
24
+
25
+ /**
26
+ * Whether the constructors are being called by a browser process, ie parsing
27
+ * or createElement.
28
+ */
29
+ let browserConstruction = false;
30
+
31
+ /**
32
+ * Whether the constructors are being called by a user-space process, ie
33
+ * calling an element constructor.
34
+ */
35
+ let userConstruction = false;
36
+
37
+ window.HTMLElement = function() {
38
+ if (!browserConstruction) {
39
+ const tagname = tagnameByConstructor.get(this.constructor);
40
+ const fakeClass = nativeGet.call(window.customElements, tagname);
41
+
42
+ // Make sure that the fake constructor doesn't call back to this constructor
43
+ userConstruction = true;
44
+ const instance = new (fakeClass)();
45
+ return instance;
46
+ }
47
+ // Else do nothing. This will be reached by ES5-style classes doing
48
+ // HTMLElement.call() during initialization
49
+ browserConstruction = false;
50
+ };
51
+
52
+ window.HTMLElement.prototype = Object.create(NativeHTMLElement.prototype);
53
+ window.HTMLElement.prototype.constructor = window.HTMLElement;
54
+
55
+ window.customElements.define = (tagname, elementClass) => {
56
+ const elementProto = elementClass.prototype;
57
+ const StandInElement = class extends NativeHTMLElement {
58
+ constructor() {
59
+ // Call the native HTMLElement constructor, this gives us the
60
+ // under-construction instance as `this`:
61
+ super();
62
+
63
+ // The prototype will be wrong up because the browser used our fake
64
+ // class, so fix it:
65
+ Object.setPrototypeOf(this, elementProto);
66
+
67
+ if (!userConstruction) {
68
+ // Make sure that user-defined constructor bottom's out to a do-nothing
69
+ // HTMLElement() call
70
+ browserConstruction = true;
71
+ // Call the user-defined constructor on our instance:
72
+ elementClass.call(this);
73
+ }
74
+ userConstruction = false;
75
+ }
76
+ };
77
+ const standInProto = StandInElement.prototype;
78
+ StandInElement.observedAttributes = elementClass.observedAttributes;
79
+ standInProto.connectedCallback = elementProto.connectedCallback;
80
+ standInProto.disconnectedCallback = elementProto.disconnectedCallback;
81
+ standInProto.attributeChangedCallback = elementProto.attributeChangedCallback;
82
+ standInProto.adoptedCallback = elementProto.adoptedCallback;
83
+
84
+ tagnameByConstructor.set(elementClass, tagname);
85
+ constructorByTagname.set(tagname, elementClass);
86
+ nativeDefine.call(window.customElements, tagname, StandInElement);
87
+ };
88
+
89
+ window.customElements.get = (tagname) => constructorByTagname.get(tagname);
90
+ '''
@@ -5,6 +5,9 @@
5
5
  #= require i18n
6
6
 
7
7
  #= require_self
8
- #= require_tree ./tao
8
+ #= require_tree tao/application
9
+ #= require_tree tao/page
10
+ #= require_tree tao/helpers
11
+ #= require_tree tao/icons
9
12
 
10
13
  window.tao = {}
@@ -1,4 +1,6 @@
1
1
  #= require lodash
2
+ #= require custom-elements
3
+ #= require native-shim
2
4
 
3
5
  components = {}
4
6
 
@@ -60,6 +62,18 @@ TaoComponentBasedOn = (superClass = 'HTMLElement') ->
60
62
  attributeChangedCallback: (attrName, oldValue, newValue) ->
61
63
  @["#{_.camelCase attrName}Changed"]?(newValue, oldValue)
62
64
 
65
+ on: (args...) ->
66
+ $(@).on args...
67
+
68
+ off: (args...) ->
69
+ $(@).off args...
70
+
71
+ trigger: (args...) ->
72
+ $(@).triggerHandler(args...)
73
+
74
+ one: (args...) ->
75
+ $(@).one args...
76
+
63
77
  _init: ->
64
78
  # to be implemented
65
79
 
@@ -0,0 +1,2 @@
1
+
2
+ # generate this file by exec: rake tao:generate_icons
@@ -1,3 +1,42 @@
1
- #= require qing-module
1
+ class TaoModule
2
2
 
3
- window.TaoModule = QingModule
3
+ @extend: (obj) ->
4
+ unless obj and typeof obj == 'object'
5
+ throw new Error('TaoModule.extend: param should be an object')
6
+
7
+ for key, val of obj when key not in ['included', 'extended']
8
+ @[key] = val
9
+
10
+ obj.extended?.call(@)
11
+ @
12
+
13
+ @include: (obj) ->
14
+ unless obj and typeof obj == 'object'
15
+ throw new Error('TaoModule.include: param should be an object')
16
+
17
+ for key, val of obj when key not in ['included', 'extended']
18
+ @::[key] = val
19
+
20
+ obj.included?.call(@)
21
+ @
22
+
23
+ constructor: (opts) ->
24
+ @_setOptions opts
25
+ @_init()
26
+
27
+ _setOptions: (opts) ->
28
+ @opts = $.extend {}, TaoModule.opts, opts
29
+
30
+ _init: ->
31
+
32
+ on: (args...) ->
33
+ $(@).on args...
34
+
35
+ off: (args...) ->
36
+ $(@).off args...
37
+
38
+ trigger: (args...) ->
39
+ $(@).triggerHandler(args...)
40
+
41
+ one: (args...) ->
42
+ $(@).one args...
@@ -1,5 +1,2 @@
1
- /*
2
- *= require normalize-rails
3
- *= require_tree ./tao
4
- *
5
- */
1
+ //= require normalize-rails
2
+ //= require_tree tao/icons
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tao_on_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Siyuan Liu
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2016-12-01 00:00:00.000000000 Z
12
+ date: 2016-12-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -176,10 +176,13 @@ files:
176
176
  - lib/tao_on_rails/rails/version.rb
177
177
  - lib/tasks/tao_icons.rake
178
178
  - tao_on_rails.gemspec
179
+ - vendor/assets/javascripts/custom-elements.js
180
+ - vendor/assets/javascripts/native-shim.coffee
179
181
  - vendor/assets/javascripts/tao.coffee
180
182
  - vendor/assets/javascripts/tao/application.coffee
181
183
  - vendor/assets/javascripts/tao/component.coffee
182
184
  - vendor/assets/javascripts/tao/helpers.coffee
185
+ - vendor/assets/javascripts/tao/icons.coffee
183
186
  - vendor/assets/javascripts/tao/module.coffee
184
187
  - vendor/assets/javascripts/tao/page.coffee
185
188
  - vendor/assets/stylesheets/tao.scss