hyper-element 0.10.0 → 0.12.0

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,472 +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
-
142
- return hyperHTML.wire(data,templateVals.id)(...fragment(data))
143
- }
144
-
145
- } // END buildTemplate
146
-
147
- function parceAttribute(key,value){
148
- if("template" === key && "" === value){
149
- return true
150
- }
151
-
152
- if((+value)+"" === value.trim()){
153
- return +value; // to number
154
- }
155
-
156
- const lowerCaseValue = value.toLowerCase().trim()
157
-
158
- if("true" === lowerCaseValue){
159
- return true
160
- } else if("false" === lowerCaseValue){
161
- return false
162
- } // END boolean check
163
-
164
- //if("data-json"===key){
165
- if(lowerCaseValue[0] === "[" && lowerCaseValue.slice(-1) === "]"
166
- || lowerCaseValue[0] === "{" && lowerCaseValue.slice(-1) === "}"){
167
- return JSON.parse(value)
168
- }
169
-
170
- return value
171
- } // END parceAttribute
172
-
173
-
174
-
175
- //=====================================================
176
- //======================================= All the magic
177
- //=====================================================
178
-
179
- function createdCallback(){
180
-
181
- // an instance of the element is created
182
- this.identifier = Symbol(this.localName);
183
- const ref = manager[this.identifier] = {attrsToIgnore:{}}
184
- ref.innerHTML = this.innerHTML
185
- const that = ref.this = {element:this}
186
- that.wrappedContent = this.textContent
187
-
188
- observer.call(this,ref) // observer change to innerHTML
189
-
190
- Object.getOwnPropertyNames(this.__proto__)
191
- .filter(name => ! (
192
- "constructor" === name ||
193
- "setup" === name ||
194
- "render" === name
195
- ))
196
- .forEach( name => {
197
- if(/^[A-Z]/.test(name)){
198
- let result;
199
- const templatestrings = {};
200
- const wrapFragment = (data)=>{
201
-
202
- if(undefined !== result && result.once)
203
- return result
204
-
205
- result = this[name](data)
206
- if(!!result.template){
207
- if("string" === typeof result.template){
208
- /* if(undefined === result.values){
209
- throw new Error("'values' was not defined for a 'template' in "+name)
210
- }*/
211
- if(!templatestrings[result.template]){
212
- templatestrings[result.template] = buildTemplate(result.template)
213
- }
214
- result = { any : templatestrings[result.template]( result.values || data ) }
215
- } // END "string" === typeof result.template
216
- else if("object" === typeof result.template
217
- && "function" === typeof result.template.then ){
218
-
219
- result = Object.assign({},result,{ any : result.template.then(({template,values}) => {
220
-
221
- if(!templatestrings[template]){
222
- templatestrings[template] = buildTemplate(template)
223
- }
224
- if(Array.isArray(values)){
225
- result = { any : values.map(templatestrings[template]) }
226
- } else { //TODO: test if values is an object
227
- result = { any : templatestrings[template]( values || data ) }
228
- }
229
- return result.any;
230
- })
231
- })// END Object.assign
232
-
233
- } // END result.template is promise ?
234
- else {
235
- throw new Error("unknow template type:"+typeof result.template +" | "+JSON.stringify(result.template))
236
- }
237
- } // END !!result.template
238
- return result
239
- } // END wrapFragment
240
- hyperHTML.define(name,wrapFragment)
241
- }else{
242
- that[name] = this[name].bind(that)
243
- }
244
- delete this[name]
245
- })
246
- function toString(){ return "hyper-element: "+this.localName }
247
- Object.defineProperty(that,"toString",{ value: toString.bind(this), writable: false })
248
- // use shadow DOM, else fallback to render to element
249
- ref.shadow = this//.attachShadow ? this.attachShadow({mode: 'closed'}) : this
250
-
251
- // Restrict access to hyperHTML
252
- const hyperHTMLbind = hyperHTML.bind(ref.shadow);
253
- ref.Html = function Html(...args){
254
-
255
- if( args.some(item => "function" === typeof item)
256
- && args[0].some(t=>isCustomTag.test(t))){
257
-
258
- let inCustomTag = false;
259
- let localName = ""
260
- const lookup = []
261
-
262
- args[0].forEach((item, index, items)=>{
263
-
264
- if(isCustomTag.test(item)){
265
- inCustomTag = -1 === item.substring(item.match(isCustomTag).index).indexOf(">")
266
- localName = inCustomTag && item.substring(item.indexOf(item.match(isCustomTag))).split(" ")[0].substr(1);
267
- }// END if CustomTag start
268
- else if(0<=item.indexOf(">")){
269
- inCustomTag = false
270
- localName = ""
271
- }// END if CustomTag end
272
-
273
- if( ! inCustomTag){
274
- return
275
- }
276
- const val = args[index+1]
277
-
278
- if("function" === typeof val){
279
- const attrName = item.split(" ").pop().slice(0, -1);
280
- if("on" === attrName.substring(0,2)){
281
- throw new Error(`'on' is reserve for native elements. Change: "${attrName}" for "${localName}" to something else`)
282
- }
283
- const id = makeid()
284
- sharedAttrs[id] = { attrName, val, localName }
285
- args[index+1] = 'fn-'+id;
286
- }// END if("function" === typeof val)
287
- })// END forEach
288
- }// END if
289
-
290
- return hyperHTMLbind(...args)
291
- } // END ref.Html
292
- ref.Html.wire = function wire(...args){return hyperHTML.wire(...args)}
293
- ref.Html.lite = function lite(...args){return hyperHTML(...args)}
294
-
295
- if(this.attrs){
296
- throw new Error("'attrs' is defined!!")
297
- }
298
- that.attrs = this.attachAttrs(this.attributes) || {};
299
- that.dataset = this.getDataset()
300
- const render = this.render
301
- this.render = (...data)=>{
302
- ref.observe = false
303
- setTimeout(()=>{ref.observe = true},0)
304
-
305
- render.call(that,ref.Html,...data)
306
-
307
- //after render check if dataset has chacked
308
- Object.getOwnPropertyNames(that.dataset)
309
- .filter(key => !this.dataset[key])
310
- .forEach( key => {
311
-
312
- const value = that.dataset[key]
313
- this.addDataset(that.dataset, key.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`))
314
- that.dataset[key] = value
315
- })
316
- }
317
-
318
- if(this.setup){
319
- ref.teardown = this.setup.call(that,onNext.bind(this,that))
320
- }
321
-
322
- this.render()
323
-
324
- }
325
-
326
- //=====================================================
327
- //==================================== Wrap the element
328
- //=====================================================
329
-
330
- class hyperElement extends HTMLElement{
331
-
332
- //++++++++++++++++++++++++++++++++ get element content
333
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
334
-
335
- get innerShadow(){
336
- return manager[this.identifier].shadow.innerHTML
337
- }
338
-
339
- //++++++++++++++++++++++++++++++++++++++++++++++ Setup
340
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
341
- createdCallback(){
342
- createdCallback.call(this)
343
- }
344
-
345
- // Called when the element is inserted into a document, including into a shadow tree
346
- connectedCallback(){
347
- createdCallback.call(this)
348
- }
349
-
350
- //+++++++++++++++++++++++++++++++++++++++ attach Attrs
351
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
352
-
353
- addDataset(dataset, dash_key){
354
-
355
- const camel_key = dash_key.replace(/-([a-z])/g, g => g[1].toUpperCase())
356
-
357
- Object.defineProperty(dataset, camel_key, {
358
- enumerable:true, // can be selected
359
- configurable: true, // can be delete
360
- get: ()=> parceAttribute(camel_key,this.dataset[camel_key]),
361
- set: (value)=> {
362
- manager[this.identifier].attrsToIgnore["data-"+dash_key] = true
363
- if("string" === typeof value){
364
- this.dataset[camel_key] = value
365
- } else {
366
- this.dataset[camel_key] = JSON.stringify(value)
367
- }// END else
368
- } // END set
369
-
370
- }) // END defineProperty
371
- } // END addDataset
372
-
373
- getDataset(){
374
- const dataset = {}
375
- Object.keys(this.dataset)
376
- .forEach(key => this.addDataset(dataset, key.replace(/([A-Z])/g, (g) => `-${g[0].toLowerCase()}`) ))// END forEach
377
- return dataset
378
- } // END getDataset
379
-
380
- attachAttrs(attributes){
381
-
382
- const accumulator = { };
383
-
384
- for (let i = 0; i < attributes.length; i++) {
385
- const { value, name } = attributes[i];
386
-
387
- if("template" === name && !value){
388
-
389
- const ref = manager[this.identifier]
390
- ref.Html.template = buildTemplate(ref.innerHTML)
391
- accumulator[name] = true;
392
-
393
- } else if ("fn-" === value.substr(0,3)
394
- && !!sharedAttrs[value.substr(3)]
395
- && sharedAttrs[value.substr(3)].localName === this.localName){
396
- accumulator[name] = sharedAttrs[value.substr(3)].val
397
- } else {
398
- if((+value)+"" === (value+"").trim()){
399
- accumulator[name] = +value
400
- } else{
401
- accumulator[name] = value//parceAttribute(name,value)
402
- }
403
- }
404
- }
405
- return accumulator;
406
- }
407
- /*
408
- attachedCallback(){
409
- console.log("an instance was inserted into the document")
410
- //an instance was inserted into the document
411
- }
412
- */
413
-
414
- //+++++++++++++++++++++++++++++++++++ element teardown
415
- //++++++++++++++++++++++++++++++++++++++++++++++++++++
416
- /*
417
- detachedCallback(){
418
- this.disposer && this.disposer()
419
- this.disconnectedCallback()
420
- }
421
- */
422
- attributeChangedCallback(name,oldVal,newVal){
423
- const ref = manager[this.identifier]
424
- const { attrsToIgnore } = ref;
425
- const that = ref.this
426
- if(0 <= name.indexOf("data-")){
427
- // we have data
428
- const dataSetName = name.slice("data-".length)
429
- if(null === oldVal){
430
- //if(undefined === that.dataset[dataSetName]){
431
- this.addDataset(that.dataset, dataSetName)
432
- } else if(null === newVal){
433
- // Object.defineProperty(that.dataset, dataSetName, { }) // END defineProperty
434
- const camel_key = dataSetName.replace(/-([a-z])/g, g => g[1].toUpperCase())
435
- delete that.dataset[camel_key]
436
- }
437
- }
438
- //newVal = parceAttribute(name,newVal)
439
-
440
- if( newVal === that.attrs[name]) {
441
- return
442
- }
443
- if(null === newVal){
444
- delete that.attrs[name]
445
- }
446
- else{
447
- that.attrs[name] = newVal
448
- }
449
- if(!!attrsToIgnore[name]){
450
- delete attrsToIgnore[name]
451
- return
452
- } else{
453
- this.render();
454
- } // END else
455
-
456
- } // END attributeChangedCallback
457
-
458
- disconnectedCallback(){
459
- const ref = manager[this.identifier]
460
- ref.teardown && ref.teardown()
461
- //ref.teardown = null
462
- //Called when the element is removed from a document
463
- } // END disconnectedCallback
464
- }
465
-
466
- //=====================================================
467
- //================================================ Done
468
- //=====================================================
469
-
470
- return hyperElement;
471
-
472
- }));