hyper-element 0.11.1 → 0.12.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.
@@ -1,483 +0,0 @@
1
-
2
- (function (factory) {
3
-
4
- if (typeof exports === 'object') {
5
- // Node, CommonJS-like
6
- module.exports = factory(require('hyperhtml/cjs'));
7
- } else if (typeof define === 'function' && define.amd) {
8
- // AMD
9
- define(['hyperhtml'], factory);
10
- } else {
11
- window.hyperElement = factory(window.hyperHTML);
12
- }
13
-
14
- }(function (hyperHTML) {
15
-
16
- const manager = { }, sharedAttrs = { }, customTagMatch = /<\s*[a-z]+-[a-z][^>]*>/g, isCustomTag = /<+\w+[-]+\w/
17
-
18
-
19
- function makeid() {
20
- var text = "";
21
- var possible = "bcdfghjklmnpqrstvwxyz";
22
-
23
- for (var i = 0; i < 15; i++)
24
- text += possible.charAt(Math.floor(Math.random() * possible.length));
25
-
26
- return text;
27
- }
28
-
29
- //=====================================================
30
- //=========================== re-render on store change
31
- //=====================================================
32
-
33
- function onNext(that,store){
34
-
35
- const storeFn = ("function" == typeof store) ? store : () => store
36
-
37
- const render = this.render
38
-
39
- const render2 = (...data)=>{
40
-
41
- if(undefined === store){
42
- that.store = undefined;
43
- render(...data)
44
- } else {
45
- that.store = storeFn()
46
- render(that.store,...data)
47
- }
48
- }
49
- this.render = render2;
50
-
51
- return render2;
52
- }
53
-
54
- //=====================================================
55
- //======================== Observer change to innerHTML
56
- //=====================================================
57
-
58
- function observer(ref){
59
- const that = ref.this
60
- const mutationObserver = new MutationObserver((mutations)=> {
61
- /*
62
- //if(!this.textContent){
63
- const mutation = mutations[mutations.length - 1]
64
- const addedNodes = mutation.addedNodes[0]
65
- console.log(this,addedNodes,ref.observe)
66
- //}
67
- */
68
- let textContent = this.textContent
69
- /*
70
- //if("" === textContent){
71
- // const mutation = mutations[mutations.length - 1]
72
- // const addedNodes = mutation.addedNodes[0]
73
- if(addedNodes)
74
- textContent = addedNodes.data
75
- // }
76
-
77
- console.log(textContent === this.wrapedConten,"TEXT_CONTENT:",textContent, "WRAPED_CONTENT:",this.wrappedContent)
78
- */
79
-
80
- if(!ref.observe) return;
81
-
82
- ref.innerHTML = this.innerHTML
83
- // that.wrappedContent = textContent
84
- if(that.attrs.template){
85
- //this.attachAttrs(this.attributes)
86
- that.attrs = this.attachAttrs(this.attributes) || {};
87
- }
88
-
89
- //reset the element
90
- hyperHTML.bind(ref.shadow)`` // HACK, dont know why this works?
91
-
92
- that.wrappedContent = textContent
93
- this.render()
94
- });
95
-
96
- mutationObserver.observe(this, {
97
- // Set to true if mutations to target's attributes are to be observed.
98
- //attributes: true,
99
-
100
- // Set to true if mutations to target's data are to be observed.
101
- // characterData: true, // re-render on content change
102
-
103
- // Set to true if additions and removals of the target node's child elements (including text nodes) are to be observed.
104
- childList: true,
105
-
106
- // Set to true if mutations to target and target's descendants are to be observed.
107
- subtree: true,
108
-
109
- // Set to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.
110
- //attributeOldValue: true,
111
-
112
- // Set to true if characterData is set to true and target's data before the mutation needs to be recorded.
113
- //characterDataOldValue: true
114
- });
115
- }
116
-
117
- function buildTemplate(innerHTML){
118
-
119
- const re = /(\{[\w]+\})/g// /\s*(\{[\w]+\})\s*/g
120
- const templateVals = innerHTML.split(re).reduce((vals,item)=>{
121
-
122
- if("{" === item[0] && "}" === item.slice(-1)){
123
- vals.keys.push(item.slice(1,-1))
124
- } else {
125
- vals.markup.push(item)
126
- }
127
-
128
- return vals
129
- },{markup:[],keys:[]})
130
-
131
- templateVals.id = ":"+templateVals.markup.join().trim()
132
-
133
- function fragment(data,render){
134
-
135
- const output = [templateVals.markup,...templateVals.keys.map( key => data[key] )]
136
- output.raw = { value:templateVals.markup}
137
- return output
138
- }
139
-
140
- return function template(data){
141
- if("object" !== typeof data){
142
- throw new Error("Templates must be passed an object to be populated with. You passed "+JSON.stringify(data)+" to "+templateVals.id)
143
- }
144
- return hyperHTML.wire(data,templateVals.id)(...fragment(data))
145
- }
146
-
147
- } // END buildTemplate
148
-
149
- function parceAttribute(key,value){
150
- if("template" === key && "" === value){
151
- return true
152
- }
153
-
154
- if((+value)+"" === value.trim()){
155
- return +value; // to number
156
- }
157
-
158
- const lowerCaseValue = value.toLowerCase().trim()
159
-
160
- if("true" === lowerCaseValue){
161
- return true
162
- } else if("false" === lowerCaseValue){
163
- return false
164
- } // END boolean check
165
-
166
- //if("data-json"===key){
167
- if(lowerCaseValue[0] === "[" && lowerCaseValue.slice(-1) === "]"
168
- || lowerCaseValue[0] === "{" && lowerCaseValue.slice(-1) === "}"){
169
- return JSON.parse(value)
170
- }
171
-
172
- return value
173
- } // END parceAttribute
174
-
175
-
176
-
177
- //=====================================================
178
- //======================================= All the magic
179
- //=====================================================
180
-
181
- function createdCallback(){
182
-
183
- // an instance of the element is created
184
- this.identifier = Symbol(this.localName);
185
- const ref = manager[this.identifier] = {attrsToIgnore:{}}
186
- ref.innerHTML = this.innerHTML
187
- const that = ref.this = {element:this}
188
- that.wrappedContent = this.textContent
189
-
190
- observer.call(this,ref) // observer change to innerHTML
191
-
192
- Object.getOwnPropertyNames(this.__proto__)
193
- .filter(name => ! (
194
- "constructor" === name ||
195
- "setup" === name ||
196
- "render" === name
197
- ))
198
- .forEach( name => {
199
- if(/^[A-Z]/.test(name)){
200
- let result;
201
- const templatestrings = {};
202
- const wrapFragment = (data)=>{
203
-
204
- if(undefined !== result && result.once)
205
- return result
206
-
207
- result = this[name](data)
208
- if(!!result.template){
209
- if("string" === typeof result.template){
210
- /* if(undefined === result.values){
211
- throw new Error("'values' was not defined for a 'template' in "+name)
212
- }*/
213
- if(!templatestrings[result.template]){
214
- templatestrings[result.template] = buildTemplate(result.template)
215
- }
216
- result = { any : templatestrings[result.template]( result.values || data ) }
217
- } // END "string" === typeof result.template
218
- else if("object" === typeof result.template
219
- && "function" === typeof result.template.then ){
220
-
221
- result = Object.assign({},result,{ any : result.template.then(args => {
222
-
223
- let { template, values } = args
224
- if(!template && "string" === typeof args){
225
- template = args;
226
- values = {};
227
- }
228
-
229
- if(!templatestrings[template]){
230
- templatestrings[template] = buildTemplate(template)
231
- }
232
- if(Array.isArray(values)){
233
- result = { any : values.map(templatestrings[template]), once: result.once }
234
- } else {
235
- result = { any : templatestrings[template]( values || data ), once: result.once }
236
- }
237
- return result.any;
238
- })
239
- })// END Object.assign
240
-
241
- } // END result.template is promise ?
242
- else {
243
- throw new Error("unknow template type:"+typeof result.template +" | "+JSON.stringify(result.template))
244
- }
245
- } // END !!result.template
246
- return result
247
- } // END wrapFragment
248
- hyperHTML.define(name,wrapFragment)
249
- }else{
250
- that[name] = this[name].bind(that)
251
- }
252
- delete this[name]
253
- })
254
- function toString(){ return "hyper-element: "+this.localName }
255
- Object.defineProperty(that,"toString",{ value: toString.bind(this), writable: false })
256
- // use shadow DOM, else fallback to render to element
257
- ref.shadow = this//.attachShadow ? this.attachShadow({mode: 'closed'}) : this
258
-
259
- // Restrict access to hyperHTML
260
- const hyperHTMLbind = hyperHTML.bind(ref.shadow);
261
- ref.Html = function Html(...args){
262
-
263
- if( args.some(item => "function" === typeof item)
264
- && args[0].some(t=>isCustomTag.test(t))){
265
-
266
- let inCustomTag = false;
267
- let localName = ""
268
- const lookup = []
269
-
270
- args[0].forEach((item, index, items)=>{
271
-
272
- if(isCustomTag.test(item)){
273
- inCustomTag = -1 === item.substring(item.match(isCustomTag).index).indexOf(">")
274
- localName = inCustomTag && item.substring(item.indexOf(item.match(isCustomTag))).split(" ")[0].substr(1);
275
- }// END if CustomTag start
276
- else if(0<=item.indexOf(">")){
277
- inCustomTag = false
278
- localName = ""
279
- }// END if CustomTag end
280
-
281
- if( ! inCustomTag){
282
- return
283
- }
284
- const val = args[index+1]
285
-
286
- if("function" === typeof val || "object" === typeof val){
287
- const attrName = item.split(" ").pop().slice(0, -1);
288
- if("on" === attrName.substring(0,2)){
289
- throw new Error(`'on' is reserve for native elements. Change: "${attrName}" for "${localName}" to something else`)
290
- }
291
- const id = makeid()
292
- sharedAttrs[id] = { attrName, val, localName }
293
- args[index+1] = ("function" === typeof val ? 'fn-':'ob-')+id;
294
- }// END if("function" === typeof val)
295
- })// END forEach
296
- }// END if
297
-
298
- return hyperHTMLbind(...args)
299
- } // END ref.Html
300
- ref.Html.wire = function wire(...args){return hyperHTML.wire(...args)}
301
- ref.Html.lite = function lite(...args){return hyperHTML(...args)}
302
-
303
- if(this.attrs){
304
- throw new Error("'attrs' is defined!!")
305
- }
306
- that.attrs = this.attachAttrs(this.attributes) || {};
307
- that.dataset = this.getDataset()
308
- const render = this.render
309
- this.render = (...data)=>{
310
- ref.observe = false
311
- setTimeout(()=>{ref.observe = true},0)
312
-
313
- render.call(that,ref.Html,...data)
314
-
315
- //after render check if dataset has chacked
316
- Object.getOwnPropertyNames(that.dataset)
317
- .filter(key => !this.dataset[key])
318
- .forEach( key => {
319
-
320
- const value = that.dataset[key]
321
- this.addDataset(that.dataset, key.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`))
322
- that.dataset[key] = value
323
- })
324
- }
325
-
326
- if(this.setup){
327
- ref.teardown = this.setup.call(that,onNext.bind(this,that))
328
- }
329
-
330
- this.render()
331
-
332
- }
333
-
334
- //=====================================================
335
- //==================================== Wrap the element
336
- //=====================================================
337
-
338
- class hyperElement extends HTMLElement{
339
-
340
- //++++++++++++++++++++++++++++++++ get element content
341
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
342
-
343
- get innerShadow(){
344
- return manager[this.identifier].shadow.innerHTML
345
- }
346
-
347
- //++++++++++++++++++++++++++++++++++++++++++++++ Setup
348
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
349
- createdCallback(){
350
- createdCallback.call(this)
351
- }
352
-
353
- // Called when the element is inserted into a document, including into a shadow tree
354
- connectedCallback(){
355
- createdCallback.call(this)
356
- }
357
-
358
- //+++++++++++++++++++++++++++++++++++++++ attach Attrs
359
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
360
-
361
- addDataset(dataset, dash_key){
362
-
363
- const camel_key = dash_key.replace(/-([a-z])/g, g => g[1].toUpperCase())
364
-
365
- Object.defineProperty(dataset, camel_key, {
366
- enumerable:true, // can be selected
367
- configurable: true, // can be delete
368
- get: ()=> parceAttribute(camel_key,this.dataset[camel_key]),
369
- set: (value)=> {
370
- manager[this.identifier].attrsToIgnore["data-"+dash_key] = true
371
- if("string" === typeof value){
372
- this.dataset[camel_key] = value
373
- } else {
374
- this.dataset[camel_key] = JSON.stringify(value)
375
- }// END else
376
- } // END set
377
-
378
- }) // END defineProperty
379
- } // END addDataset
380
-
381
- getDataset(){
382
- const dataset = {}
383
- Object.keys(this.dataset)
384
- .forEach(key => this.addDataset(dataset, key.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`) ))// END forEach
385
- return dataset
386
- } // END getDataset
387
-
388
- attachAttrs(attributes){
389
-
390
- const accumulator = { };
391
-
392
- for (let i = 0; i < attributes.length; i++) {
393
- const { value, name } = attributes[i];
394
-
395
- if("template" === name && !value){
396
-
397
- const ref = manager[this.identifier]
398
- ref.Html.template = buildTemplate(ref.innerHTML)
399
- accumulator[name] = true;
400
-
401
- } else if ("fn-" === value.substr(0,3) || "ob-" === value.substr(0,3)
402
- && !!sharedAttrs[value.substr(3)]
403
- && sharedAttrs[value.substr(3)].localName === this.localName){
404
- accumulator[name] = sharedAttrs[value.substr(3)].val
405
- } else {
406
- if((+value)+"" === (value+"").trim()){
407
- accumulator[name] = +value
408
- } else{
409
- accumulator[name] = value//parceAttribute(name,value)
410
- }
411
- }
412
- }
413
- return accumulator;
414
- }
415
- /*
416
- attachedCallback(){
417
- console.log("an instance was inserted into the document")
418
- //an instance was inserted into the document
419
- }
420
- */
421
-
422
- //+++++++++++++++++++++++++++++++++++ element teardown
423
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
424
- /*
425
- detachedCallback(){
426
- this.disposer && this.disposer()
427
- this.disconnectedCallback()
428
- }
429
- */
430
- attributeChangedCallback(name,oldVal,newVal){
431
- if((+newVal)+"" === newVal.trim()){
432
- newVal = +newVal; // to number
433
- }
434
- const ref = manager[this.identifier]
435
- const { attrsToIgnore } = ref;
436
- const that = ref.this
437
- if(0 <= name.indexOf("data-")){
438
- // we have data
439
- const dataSetName = name.slice("data-".length)
440
- if(null === oldVal){
441
- //if(undefined === that.dataset[dataSetName]){
442
- this.addDataset(that.dataset, dataSetName)
443
- } else if(null === newVal){
444
- // Object.defineProperty(that.dataset, dataSetName, { }) // END defineProperty
445
- const camel_key = dataSetName.replace(/-([a-z])/g, g => g[1].toUpperCase())
446
- delete that.dataset[camel_key]
447
- }
448
- }
449
- //newVal = parceAttribute(name,newVal)
450
-
451
- if( newVal === that.attrs[name]) {
452
- return
453
- }
454
- if(null === newVal){
455
- delete that.attrs[name]
456
- }
457
- else{
458
- that.attrs[name] = newVal
459
- }
460
- if(!!attrsToIgnore[name]){
461
- delete attrsToIgnore[name]
462
- return
463
- } else{
464
- this.render();
465
- } // END else
466
-
467
- } // END attributeChangedCallback
468
-
469
- disconnectedCallback(){
470
- const ref = manager[this.identifier]
471
- ref.teardown && ref.teardown()
472
- //ref.teardown = null
473
- //Called when the element is removed from a document
474
- } // END disconnectedCallback
475
- }
476
-
477
- //=====================================================
478
- //================================================ Done
479
- //=====================================================
480
-
481
- return hyperElement;
482
-
483
- }));