data-tier
Advanced tools
Comparing version 0.6.19 to 0.6.20
@@ -1,2 +0,2 @@ | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -30,13 +30,11 @@ | ||
set: function(input) { | ||
let oldData = data, | ||
newData = ensureObservable(input); | ||
if (data) data.revoke(); | ||
data = newData; | ||
if (data) data.observe(observer); | ||
namespace.DataTier.views.processChanges(name, [{ | ||
type: 'update', | ||
value: data, | ||
oldValue: oldData, | ||
path: [] | ||
}]); | ||
if (input !== data) { | ||
let oldData = data; | ||
data = ensureObservable(input); | ||
if (data) data.observe(observer); | ||
namespace.DataTier.views.processChanges(name, [{ | ||
path: [] | ||
}]); | ||
if (oldData) oldData.revoke(); | ||
} | ||
} | ||
@@ -108,5 +106,4 @@ }); | ||
}); | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -187,3 +184,3 @@ | ||
function defaultIsChangedPathRelevant(changedPath, viewedPath) { | ||
return viewedPath.startsWith(changedPath); | ||
return viewedPath.indexOf(changedPath) === 0; | ||
} | ||
@@ -209,3 +206,3 @@ | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -227,4 +224,5 @@ | ||
if (!ref) return; | ||
for (let i = 0, pathLength = path.length; i < pathLength; i++) { | ||
if (ref && path[i] in ref) ref = ref[path[i]]; | ||
for (let i = 0, l = path.length, n; i < l; i++) { | ||
n = path[i]; | ||
if (ref && ref.hasOwnProperty(n)) ref = ref[n]; | ||
else return; | ||
@@ -267,49 +265,43 @@ } | ||
function add(view) { | ||
let localCustomElementName; | ||
if (view.nodeName === 'IFRAME') { | ||
initDocumentObserver(view.contentDocument); | ||
view.addEventListener('load', function() { | ||
initDocumentObserver(this.contentDocument); | ||
collect(this.contentDocument); | ||
}); | ||
collect(view.contentDocument); | ||
} else if (Node.ELEMENT_NODE === view.nodeType && (localCustomElementName = getLocalNameIfCustomElement(view))) { | ||
customElements.whenDefined(localCustomElementName).then(() => processAddedView(view)); | ||
} else if (view.dataset) { | ||
processAddedView(view); | ||
function add(elements) { | ||
if (!elements.length) elements = [elements]; | ||
for (let i = 0, l = elements.length; i < l; i++) { | ||
let element = elements[i]; | ||
if (element.nodeName === 'IFRAME') { | ||
initDocumentObserver(element.contentDocument); | ||
element.addEventListener('load', function() { | ||
initDocumentObserver(this.contentDocument); | ||
collect(this.contentDocument); | ||
}); | ||
collect(element.contentDocument); | ||
} else if (Node.ELEMENT_NODE === element.nodeType) { | ||
if (element.localName.indexOf('-') < 0 && !element.hasAttribute('is')) { | ||
processAddedElement(element); | ||
} else { | ||
customElements.whenDefined(element.getAttribute('is') || element.localName).then(() => processAddedElement(element)); | ||
} | ||
} | ||
} | ||
} | ||
function getLocalNameIfCustomElement(view) { | ||
let result; | ||
if (view.localName.includes('-')) { | ||
result = view.localName; | ||
} else if (!(result = view.getAttribute('is')) || !result.includes('-')) { | ||
result = null; | ||
} | ||
return result; | ||
} | ||
function processAddedElement(element) { | ||
let ds = element.dataset, keys = Object.keys(ds), l = keys.length; | ||
while (l--) { | ||
let key = keys[l]; | ||
if (key.indexOf('tie') !== 0) continue; | ||
function processAddedView(view) { | ||
let keys = Object.keys(view.dataset), key, | ||
controller, controllerParam, pathString, | ||
tieViews, procViews, pathViews, i; | ||
i = keys.length; | ||
while (i--) { | ||
key = keys[i]; | ||
if (!key.startsWith('tie')) continue; | ||
controller = controllers.get(key); | ||
let controller = controllers.get(key); | ||
if (controller) { | ||
controllerParam = controller.parseParam(view.dataset[controller.name]); | ||
pathString = controllerParam.dataPath.join('.'); | ||
tieViews = views[controllerParam.tieName] || (views[controllerParam.tieName] = {}); | ||
procViews = tieViews[controller.name] || (tieViews[controller.name] = {}); | ||
pathViews = procViews[pathString] || (procViews[pathString] = []); | ||
let controllerParam = controller.parseParam(ds[controller.name]), | ||
pathString = controllerParam.dataPath.join('.'); | ||
if (pathViews.indexOf(view) < 0) { | ||
pathViews.push(view); | ||
update(view, controller.name); | ||
let tieViews = views[controllerParam.tieName] || (views[controllerParam.tieName] = {}), | ||
ctrlViews = tieViews[controller.name] || (tieViews[controller.name] = {}), | ||
pathViews = ctrlViews[pathString] || (ctrlViews[pathString] = []); | ||
if (pathViews.indexOf(element) < 0) { | ||
pathViews.push(element); | ||
update(element, controller.name); | ||
if (controller.changeDOMEventType) { | ||
addChangeListener(view, controller.changeDOMEventType); | ||
addChangeListener(element, controller.changeDOMEventType); | ||
} | ||
@@ -320,3 +312,3 @@ } | ||
if (!nlvs[key]) nlvs[key] = []; | ||
nlvs[key].push(view); | ||
nlvs[key].push(element); | ||
} | ||
@@ -339,3 +331,3 @@ } | ||
if (rootElement && (rootElement.nodeType === Node.DOCUMENT_NODE || rootElement.nodeType === Node.ELEMENT_NODE)) { | ||
let list, i; | ||
let list; | ||
if (rootElement.nodeName === 'IFRAME') { | ||
@@ -348,4 +340,3 @@ list = rootElement.contentDocument.getElementsByTagName('*'); | ||
add(rootElement); | ||
i = list.length; | ||
while (i--) add(list[i]); | ||
add(list); | ||
} | ||
@@ -475,3 +466,2 @@ } | ||
} else if (changeType === 'childList') { | ||
// process added nodes | ||
@@ -535,3 +525,3 @@ added = change.addedNodes; | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -621,3 +611,2 @@ | ||
}); | ||
})(); | ||
@@ -720,5 +709,4 @@ (() => { | ||
} | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -754,4 +742,5 @@ | ||
value = view.dataset[key]; | ||
if (key.startsWith('tie') && value.startsWith(itemId)) | ||
if (key.startsWith('tie') && value.startsWith(itemId)) { | ||
relevantKeys.push([key, value.replace(itemId, '')]); | ||
} | ||
} | ||
@@ -758,0 +747,0 @@ if (relevantKeys.length) { |
@@ -1,1 +0,1 @@ | ||
(()=>{"use strict";(()=>{let e=window,t=Symbol.for("data-tier");for(;e.parent!==e;)e=e.parent;if(e[t])throw new Error("data-tier found to already being running within this application, cancelling current execution");e[t]=!0})();const e=this||window,t={};function n(e){return t[e]}function o(n,o,r){if(function(e){if(!e||"string"!=typeof e)throw new Error("tie name MUST be a non-empty string");if(/\W/.test(e))throw new Error("tie name MUST consist of alphanumerics or underlines ([a-zA-Z0-9_]) ONLY")}(n),t[n])throw new Error("existing tie ("+n+") MAY NOT be re-created, use the tie's own APIs to reconfigure it");return new function(n,o,r){let a;function l(t){e.DataTier.views.processChanges(n,t)}Reflect.defineProperty(this,"name",{value:n}),Reflect.defineProperty(this,"data",{get:function(){return a},set:function(t){let o=a,r=i(t);a&&a.revoke(),(a=r)&&a.observe(l),e.DataTier.views.processChanges(n,[{type:"update",value:a,oldValue:o,path:[]}])}}),t[n]=this,this.data=o,Object.seal(this)}(n,i(o),r)}function r(e){e&&t[e]&&(t[e].observable.revoke(),delete t[e])}function i(t){if(void 0===t||null===t)return t;if("object"!=typeof t)throw new Error(t+" is not of type Observable and not an object");if("function"==typeof t.observe&&"function"==typeof t.unobserve&&"function"==typeof t.revoke)return t;if(e.Observable){if("function"==typeof t.observe||"function"==typeof t.unobserve||"function"==typeof t.revoke)throw new Error(t+" is not of type Observable and can not be transformed into Observable (some of its functions already implemented?)");return e.Observable.from(t)}throw new Error(t+" is not of type Observable and no embedded Observable implementation found")}Reflect.defineProperty(e,"DataTier",{value:{}}),Reflect.defineProperty(e.DataTier,"ties",{value:{get get(){return n},get create(){return o},get remove(){return r}}})})(),(()=>{"use strict";const e=this||window,t={};function n(e,t){Reflect.defineProperty(this,"name",{value:e}),Object.assign(this,t)}function o(o,r){if("string"!=typeof o||!o)throw new Error("name MUST be a non-empty string");if(t[o])throw new Error('data controller "'+o+'" already exists; you may want to reconfigure the existing one');if("object"!=typeof r||!r)throw new Error("configuration MUST be a non-null object");if("function"!=typeof r.toView)throw new Error('configuration MUST have a "toView" function defined');t[o]=new n(o,r),e.DataTier.views.applyController(t[o])}function r(e){return t[e]}function i(e){if("string"!=typeof e||!e)throw new Error("controller name MUST be a non-empty string");return delete t[e]}function a(e){let n=[];return e&&e.dataset&&Object.keys(e.dataset).filter(e=>e in t).map(e=>t[e]).forEach(e=>n.push(e)),n}function l(e){let t="",n=[];return e&&(t=(n=e.trim().split(".")).shift()),{tieName:t,dataPath:n}}function s(e,t){return t.startsWith(e)}n.prototype.toData=function(e){!function(e,t,n){let o;if(!e)return;for(o=0;o<t.length-1;o++)e=e[t[o]]&&"object"==typeof e[t[o]]?e[t[o]]:e[t[o]]={};e[t[o]]=n}(e.data,e.path,e.view.value)},n.prototype.parseParam=l,n.prototype.isChangedPathRelevant=s,Reflect.defineProperty(n.prototype,"parseParam",{value:l}),Reflect.defineProperty(n.prototype,"isChangedPathRelevant",{value:s}),Reflect.defineProperty(e.DataTier,"controllers",{value:{get get(){return r},get add(){return o},get remove(){return i},get getApplicable(){return a}}})})(),(()=>{"use strict";const e=this||window;if(!e.DataTier)throw new Error("data-tier framework was not properly initialized");const t=e.DataTier.ties,n=e.DataTier.controllers,o={},r={};function i(e){let o,r,i,a,l=e.target,s=n.getApplicable(l);for(a=s.length;a--;)if(o=s[a],e.type===o.changeDOMEventType){if(r=o.parseParam(l.dataset[o.name]),i=t.get(r.tieName),!r.dataPath)return void console.error("path to data not available");if(!i)return void console.error('tie "'+r.tieName+'" not found');o.toData({data:i.data,path:r.dataPath,view:l})}}function a(e,t){e.addEventListener(t,i)}function l(e){let t;"IFRAME"===e.nodeName?(g(e.contentDocument),e.addEventListener("load",function(){g(this.contentDocument),u(this.contentDocument)}),u(e.contentDocument)):Node.ELEMENT_NODE===e.nodeType&&(t=function(e){let t;e.localName.includes("-")?t=e.localName:(t=e.getAttribute("is"))&&t.includes("-")||(t=null);return t}(e))?customElements.whenDefined(t).then(()=>s(e)):e.dataset&&s(e)}function s(e){let t,i,l,s,u,f,d,p,h=Object.keys(e.dataset);for(p=h.length;p--;)(t=h[p]).startsWith("tie")&&((i=n.get(t))?(s=(l=i.parseParam(e.dataset[i.name])).dataPath.join("."),(d=(f=(u=o[l.tieName]||(o[l.tieName]={}))[i.name]||(u[i.name]={}))[s]||(f[s]=[])).indexOf(e)<0&&(d.push(e),c(e,i.name),i.changeDOMEventType&&a(e,i.changeDOMEventType))):(r[t]||(r[t]=[]),r[t].push(e)))}function c(e,o){let r,i,a,l;i=(r=n.get(o)).parseParam(e.dataset[o]),(a=t.get(i.tieName))&&(l=function(e,t){if(e){for(let n=0,o=t.length;n<o;n++){if(!(e&&t[n]in e))return;e=e[t[n]]}return e}}(a.data,i.dataPath),r.toView(l,e))}function u(e){if(e&&(e.nodeType===Node.DOCUMENT_NODE||e.nodeType===Node.ELEMENT_NODE)){let t,n;for(t="IFRAME"===e.nodeName?e.contentDocument.getElementsByTagName("*"):e.getElementsByTagName("*"),l(e),n=t.length;n--;)l(t[n])}}function f(e){if(e&&e.getElementsByTagName){let a,l,s,c,u,f,d,p,h,m=e.getElementsByTagName("*");for(c=0,u=m.length;c<=u;c++)if((a=c<u?m[c]:e).dataset&&Object.keys(a.dataset).length)for(f=(l=n.getApplicable(a)).length;f--;)d=(s=l[f]).parseParam(a.dataset[s.name]),(h=(p=o[d.tieName][s.name][d.dataPath.join(".")]).indexOf(a))>=0&&(p.splice(h,1),s.changeDOMEventType&&(t=a,r=s.changeDOMEventType,t.removeEventListener(r,i)))}var t,r}function d(e,t,r,i){let a;if(a=n.get(t)){if(r){let i=n.get(t).parseParam(r);if(o[i.tieName]&&o[i.tieName][t]){let n=o[i.tieName][t][i.dataPath],r=-1;n&&(r=n.indexOf(e)),r>=0&&n.splice(r,1)}}if(i){let r=n.get(t).parseParam(i);o[r.tieName]||(o[r.tieName]={}),o[r.tieName][t]||(o[r.tieName][t]={}),o[r.tieName][t][r.dataPath]||(o[r.tieName][t][r.dataPath]=[]),o[r.tieName][t][r.dataPath].push(e),c(e,t)}}}function p(e,t){let r,i,a,l,s,u,f,d,p,h,m,g,y,E=o[e];if(E)for(h=t.length;h--;)for(i=(r=t[h]).path?r.path.join("."):null,m=(a=Object.keys(E)).length;m--;)if(d=E[l=a[m]])for(s=n.get(l),g=(u=Object.keys(d)).length;g--;)if(f=u[g],s.isChangedPathRelevant(i,f))for(y=(p=d[f]).length;y--;)c(p[y],l)}function h(e){r[e.name]&&(r[e.name].forEach(l),delete r[e.name])}function m(e){let t,n=2,o=e.split("-");for(t=o[1];n<o.length;)t+=o[n][0].toUpperCase()+o[n++].substr(1);return t}function g(e){new MutationObserver(function(e){let t,n,o,r,i,a,l,s;for(t=e.length;t--;)if("attributes"===(i=(r=e[t]).type)){let e=r.target,t=r.attributeName;if(e.nodeType!==Node.DOCUMENT_NODE&&e.nodeType!==Node.ELEMENT_NODE)continue;0===t.indexOf("data-tie")?d(e,m(t),r.oldValue,e.getAttribute(t)):"src"===t&&"IFRAME"===e.nodeName&&f(e.contentDocument)}else if("childList"===i){for(n=(a=r.addedNodes).length;n--;)(s=a[n]).nodeType!==Node.DOCUMENT_NODE&&s.nodeType!==Node.ELEMENT_NODE||("IFRAME"===s.nodeName?(s.contentDocument&&(g(s.contentDocument),u(s.contentDocument)),s.addEventListener("load",function(){g(this.contentDocument),u(this.contentDocument)})):u(s));for(o=(l=r.removedNodes).length;o--;)(s=l[o]).nodeType!==Node.DOCUMENT_NODE&&s.nodeType!==Node.ELEMENT_NODE||("IFRAME"===s.nodeName?f(s.contentDocument):f(s))}}).observe(e,{childList:!0,attributes:!0,characterData:!1,subtree:!0,attributeOldValue:!0,characterDataOldValue:!1})}Reflect.defineProperty(e.DataTier,"views",{value:{get processChanges(){return p},get applyController(){return h},get updateView(){return c}}}),g(document),u(document)})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;e("tieProperty",{parseParam:function(e){return this.constructor.prototype.parseParam(e?e.split("=>").shift().trim():null)},toView:(e,t)=>{t[t.dataset.tieProperty.split("=>").pop().trim()]=e}}),e("tieValue",{toView:function(e,t){"checkbox"===t.type?t.checked=e:t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"change"}),e("tieInput",{toView:function(e,t){t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"input"}),e("tieText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e:""}}),e("tiePlaceholder",{toView:function(e,t){t.placeholder=void 0!==e&&null!==e?e:""}}),e("tieTooltip",{toView:function(e,t){t.title=void 0!==e&&null!==e?e:""}}),e("tieSrc",{toView:function(e,t){t.src=void 0!==e&&null!==e?e:""}}),e("tieHref",{toView:function(e,t){t.href=void 0!==e&&null!==e?e:""}}),e("tieClasses",{isChangedPathRelevant:function(e,t){let n=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===n.length||2===n.length&&""===n[0]},toView:function(e,t){e&&"object"==typeof e&&Object.keys(e).forEach(function(n){e[n]?t.classList.add(n):t.classList.remove(n)})}})})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;function t(e){let t=e||"textContent";this.format="dd/MM/yyyy hh:mm:ss",this.toView=function(e,n){let o=e;if(e)if(e instanceof Date)o=r(e,this.format);else try{let t=new Date(e);t instanceof Date&&(o=r(t,this.format))}catch(t){console.error('failed to parse "'+e+'" as date',t)}else o="";n[t]=o}}function n(){t.call(this,"value"),this.toData=function(e){console.warn("yet to be implemented, react on "+e)}}e("tieDateValue",{toView:function(e,t){t.value=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDateText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDatetimeText",new t),e("tieDatetimeValue",new n),n.prototype=Object.create(t.prototype),n.prototype.constructor=n;let o={d:function(e,t){return e.getDate().toString().padStart(t,"0")},M:function(e,t){return(e.getMonth()+1).toString().padStart(t,"0")},y:function(e,t){let n=e.getFullYear().toString();return n.length>t?n.substr(n.length-t):n.padStart(t,"0")},h:function(e,t){return e.getHours().toString().padStart(t,"0")},m:function(e,t){return e.getMinutes().toString().padStart(t,"0")},s:function(e,t){return e.getSeconds().toString().padStart(t,"0")},f:function(e,t){return e.getMilliseconds().toString().padStart(t,"0")}};function r(e,t){let n="";if(t){let r,i;for(let a=0,l=t.length;a<l;a++)if(r=t.charAt(a),o[r]){for(i=1;a<l-1&&t.charAt(a+1)===r;)i++,a++;n+=o[r](e,i)}else n+=r}else n=e.toLocaleString();return n}})(),(()=>{"use strict";const e=this||window,t=e.DataTier.controllers.add,n=e.DataTier.views;function o(e,t,n,o,r){let i,a,l,s,c,u,f,d,p,h,m,g=null,y=o,E=n[0]+".";for(a=t.content,f=(i=function(e,t){let n,o,r,i,a,l,s={index:[]},c=e.content.querySelectorAll("*"),u=c.length;for(;u--;)if((n=c[u]).nodeType===Node.DOCUMENT_NODE||n.nodeType===Node.ELEMENT_NODE){for(r=(o=Object.keys(n.dataset)).length,l=[];r--;)i=o[r],a=n.dataset[i],i.startsWith("tie")&&a.startsWith(t)&&l.push([i,a.replace(t,"")]);l.length&&(s[u]=l,s.index.push(u))}return s}(t,n[2])).index;y<r;y++){for(d=(l=a.cloneNode(!0)).querySelectorAll("*"),s=f.length;s--;)for(p=d[u=f[s]],c=(h=i[u]).length;c--;)m=h[c][0],p.dataset[m]=E+y+h[c][1];y===o?g=l:g.appendChild(l)}e.appendChild(g)}t("tieList",{parseParam:function(e){return this.constructor.prototype.parseParam(e.split(/\s*=>\s*/)[0])},isChangedPathRelevant:function(e,t){if(!e)return!0;let n=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===n.length||2===n.length&&""===n[0]},toView:function(e,t){if(!Array.isArray(e)||!t)return;let r,i,a,l=t.parentNode,s=e.length;if("TEMPLATE"!==t.nodeName)throw new Error("tieList may be defined on template elements only");if(1!==t.content.childElementCount)throw new Error("tieList's TEMPLATE element MUST HAVE exactly one direct child element");(a=(i=t.content.firstElementChild.dataset).dtListItemAid)||(a=(new Date).getTime(),i.dtListItemAid=a);let c=l.querySelectorAll('[data-dt-list-item-aid="'+a+'"]'),u=c.length;if(u>s)for(;u>s;)l.removeChild(c[--u]);!function(e,t,o){let r,i=e.content.querySelectorAll("*"),a=[];for(r=i.length;r--;)a[r]=Object.keys(i[r].dataset).filter(e=>e.startsWith("tie"));let l,s,c,u,f,d,p=0;for(r=0;p<o;)if((c=t.childNodes[r++])!==e&&(c.nodeType===Node.DOCUMENT_NODE||c.nodeType===Node.ELEMENT_NODE)&&c.dataset.dtListItemAid){for(u=c.querySelectorAll("*"),l=a.length;l--;)for(f=l?u[l-1]:c,s=(d=a[l]).length;s--;)n.updateView(f,d[s]);p++}}(t,l,u),u<s&&o(l,t,r=function(e){let t;if(e&&(!(t=e.trim().split(/\s+/))||3!==t.length||"=>"!==t[1]))throw new Error('invalid parameter for "tieList" rule specified');return t}(t.dataset.tieList),u,s)}})})(); | ||
(()=>{"use strict";(()=>{let e=window,t=Symbol.for("data-tier");for(;e.parent!==e;)e=e.parent;if(e[t])throw new Error("data-tier found to already being running within this application, cancelling current execution");e[t]=!0})();const e=this||window,t={};function n(e){return t[e]}function o(n,o,r){if(function(e){if(!e||"string"!=typeof e)throw new Error("tie name MUST be a non-empty string");if(/\W/.test(e))throw new Error("tie name MUST consist of alphanumerics or underlines ([a-zA-Z0-9_]) ONLY")}(n),t[n])throw new Error("existing tie ("+n+") MAY NOT be re-created, use the tie's own APIs to reconfigure it");return new function(n,o,r){let a;function l(t){e.DataTier.views.processChanges(n,t)}Reflect.defineProperty(this,"name",{value:n}),Reflect.defineProperty(this,"data",{get:function(){return a},set:function(t){if(t!==a){let o=a;(a=i(t))&&a.observe(l),e.DataTier.views.processChanges(n,[{path:[]}]),o&&o.revoke()}}}),t[n]=this,this.data=o,Object.seal(this)}(n,i(o),r)}function r(e){e&&t[e]&&(t[e].observable.revoke(),delete t[e])}function i(t){if(void 0===t||null===t)return t;if("object"!=typeof t)throw new Error(t+" is not of type Observable and not an object");if("function"==typeof t.observe&&"function"==typeof t.unobserve&&"function"==typeof t.revoke)return t;if(e.Observable){if("function"==typeof t.observe||"function"==typeof t.unobserve||"function"==typeof t.revoke)throw new Error(t+" is not of type Observable and can not be transformed into Observable (some of its functions already implemented?)");return e.Observable.from(t)}throw new Error(t+" is not of type Observable and no embedded Observable implementation found")}Reflect.defineProperty(e,"DataTier",{value:{}}),Reflect.defineProperty(e.DataTier,"ties",{value:{get get(){return n},get create(){return o},get remove(){return r}}})})(),(()=>{"use strict";const e=this||window,t={};function n(e,t){Reflect.defineProperty(this,"name",{value:e}),Object.assign(this,t)}function o(o,r){if("string"!=typeof o||!o)throw new Error("name MUST be a non-empty string");if(t[o])throw new Error('data controller "'+o+'" already exists; you may want to reconfigure the existing one');if("object"!=typeof r||!r)throw new Error("configuration MUST be a non-null object");if("function"!=typeof r.toView)throw new Error('configuration MUST have a "toView" function defined');t[o]=new n(o,r),e.DataTier.views.applyController(t[o])}function r(e){return t[e]}function i(e){if("string"!=typeof e||!e)throw new Error("controller name MUST be a non-empty string");return delete t[e]}function a(e){let n=[];return e&&e.dataset&&Object.keys(e.dataset).filter(e=>e in t).map(e=>t[e]).forEach(e=>n.push(e)),n}function l(e){let t="",n=[];return e&&(t=(n=e.trim().split(".")).shift()),{tieName:t,dataPath:n}}function s(e,t){return 0===t.indexOf(e)}n.prototype.toData=function(e){!function(e,t,n){let o;if(!e)return;for(o=0;o<t.length-1;o++)e=e[t[o]]&&"object"==typeof e[t[o]]?e[t[o]]:e[t[o]]={};e[t[o]]=n}(e.data,e.path,e.view.value)},n.prototype.parseParam=l,n.prototype.isChangedPathRelevant=s,Reflect.defineProperty(n.prototype,"parseParam",{value:l}),Reflect.defineProperty(n.prototype,"isChangedPathRelevant",{value:s}),Reflect.defineProperty(e.DataTier,"controllers",{value:{get get(){return r},get add(){return o},get remove(){return i},get getApplicable(){return a}}})})(),(()=>{"use strict";const e=this||window;if(!e.DataTier)throw new Error("data-tier framework was not properly initialized");const t=e.DataTier.ties,n=e.DataTier.controllers,o={},r={};function i(e){let o,r,i,a,l=e.target,s=n.getApplicable(l);for(a=s.length;a--;)if(o=s[a],e.type===o.changeDOMEventType){if(r=o.parseParam(l.dataset[o.name]),i=t.get(r.tieName),!r.dataPath)return void console.error("path to data not available");if(!i)return void console.error('tie "'+r.tieName+'" not found');o.toData({data:i.data,path:r.dataPath,view:l})}}function a(e){e.length||(e=[e]);for(let t=0,n=e.length;t<n;t++){let n=e[t];"IFRAME"===n.nodeName?(m(n.contentDocument),n.addEventListener("load",function(){m(this.contentDocument),c(this.contentDocument)}),c(n.contentDocument)):Node.ELEMENT_NODE===n.nodeType&&(n.localName.indexOf("-")<0&&!n.hasAttribute("is")?l(n):customElements.whenDefined(n.getAttribute("is")||n.localName).then(()=>l(n)))}}function l(e){let t=e.dataset,a=Object.keys(t),l=a.length;for(;l--;){let u=a[l];if(0!==u.indexOf("tie"))continue;let d=n.get(u);if(d){let n=d.parseParam(t[d.name]),r=n.dataPath.join("."),a=o[n.tieName]||(o[n.tieName]={}),l=a[d.name]||(a[d.name]={}),u=l[r]||(l[r]=[]);u.indexOf(e)<0&&(u.push(e),s(e,d.name),d.changeDOMEventType&&(c=e,f=d.changeDOMEventType,c.addEventListener(f,i)))}else r[u]||(r[u]=[]),r[u].push(e)}var c,f}function s(e,o){let r,i,a,l;i=(r=n.get(o)).parseParam(e.dataset[o]),(a=t.get(i.tieName))&&(l=function(e,t){if(e){for(let n,o=0,r=t.length;o<r;o++){if(n=t[o],!e||!e.hasOwnProperty(n))return;e=e[n]}return e}}(a.data,i.dataPath),r.toView(l,e))}function c(e){if(e&&(e.nodeType===Node.DOCUMENT_NODE||e.nodeType===Node.ELEMENT_NODE)){let t;t="IFRAME"===e.nodeName?e.contentDocument.getElementsByTagName("*"):e.getElementsByTagName("*"),a(e),a(t)}}function f(e){if(e&&e.getElementsByTagName){let a,l,s,c,f,u,d,h,p,m=e.getElementsByTagName("*");for(c=0,f=m.length;c<=f;c++)if((a=c<f?m[c]:e).dataset&&Object.keys(a.dataset).length)for(u=(l=n.getApplicable(a)).length;u--;)d=(s=l[u]).parseParam(a.dataset[s.name]),(p=(h=o[d.tieName][s.name][d.dataPath.join(".")]).indexOf(a))>=0&&(h.splice(p,1),s.changeDOMEventType&&(t=a,r=s.changeDOMEventType,t.removeEventListener(r,i)))}var t,r}function u(e,t,r,i){let a;if(a=n.get(t)){if(r){let i=n.get(t).parseParam(r);if(o[i.tieName]&&o[i.tieName][t]){let n=o[i.tieName][t][i.dataPath],r=-1;n&&(r=n.indexOf(e)),r>=0&&n.splice(r,1)}}if(i){let r=n.get(t).parseParam(i);o[r.tieName]||(o[r.tieName]={}),o[r.tieName][t]||(o[r.tieName][t]={}),o[r.tieName][t][r.dataPath]||(o[r.tieName][t][r.dataPath]=[]),o[r.tieName][t][r.dataPath].push(e),s(e,t)}}}function d(e,t){let r,i,a,l,c,f,u,d,h,p,m,g,y,E=o[e];if(E)for(p=t.length;p--;)for(i=(r=t[p]).path?r.path.join("."):null,m=(a=Object.keys(E)).length;m--;)if(d=E[l=a[m]])for(c=n.get(l),g=(f=Object.keys(d)).length;g--;)if(u=f[g],c.isChangedPathRelevant(i,u))for(y=(h=d[u]).length;y--;)s(h[y],l)}function h(e){r[e.name]&&(r[e.name].forEach(a),delete r[e.name])}function p(e){let t,n=2,o=e.split("-");for(t=o[1];n<o.length;)t+=o[n][0].toUpperCase()+o[n++].substr(1);return t}function m(e){new MutationObserver(function(e){let t,n,o,r,i,a,l,s;for(t=e.length;t--;)if("attributes"===(i=(r=e[t]).type)){let e=r.target,t=r.attributeName;if(e.nodeType!==Node.DOCUMENT_NODE&&e.nodeType!==Node.ELEMENT_NODE)continue;0===t.indexOf("data-tie")?u(e,p(t),r.oldValue,e.getAttribute(t)):"src"===t&&"IFRAME"===e.nodeName&&f(e.contentDocument)}else if("childList"===i){for(n=(a=r.addedNodes).length;n--;)(s=a[n]).nodeType!==Node.DOCUMENT_NODE&&s.nodeType!==Node.ELEMENT_NODE||("IFRAME"===s.nodeName?(s.contentDocument&&(m(s.contentDocument),c(s.contentDocument)),s.addEventListener("load",function(){m(this.contentDocument),c(this.contentDocument)})):c(s));for(o=(l=r.removedNodes).length;o--;)(s=l[o]).nodeType!==Node.DOCUMENT_NODE&&s.nodeType!==Node.ELEMENT_NODE||("IFRAME"===s.nodeName?f(s.contentDocument):f(s))}}).observe(e,{childList:!0,attributes:!0,characterData:!1,subtree:!0,attributeOldValue:!0,characterDataOldValue:!1})}Reflect.defineProperty(e.DataTier,"views",{value:{get processChanges(){return d},get applyController(){return h},get updateView(){return s}}}),m(document),c(document)})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;e("tieProperty",{parseParam:function(e){return this.constructor.prototype.parseParam(e?e.split("=>").shift().trim():null)},toView:(e,t)=>{t[t.dataset.tieProperty.split("=>").pop().trim()]=e}}),e("tieValue",{toView:function(e,t){"checkbox"===t.type?t.checked=e:t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"change"}),e("tieInput",{toView:function(e,t){t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"input"}),e("tieText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e:""}}),e("tiePlaceholder",{toView:function(e,t){t.placeholder=void 0!==e&&null!==e?e:""}}),e("tieTooltip",{toView:function(e,t){t.title=void 0!==e&&null!==e?e:""}}),e("tieSrc",{toView:function(e,t){t.src=void 0!==e&&null!==e?e:""}}),e("tieHref",{toView:function(e,t){t.href=void 0!==e&&null!==e?e:""}}),e("tieClasses",{isChangedPathRelevant:function(e,t){let n=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===n.length||2===n.length&&""===n[0]},toView:function(e,t){e&&"object"==typeof e&&Object.keys(e).forEach(function(n){e[n]?t.classList.add(n):t.classList.remove(n)})}})})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;function t(e){let t=e||"textContent";this.format="dd/MM/yyyy hh:mm:ss",this.toView=function(e,n){let o=e;if(e)if(e instanceof Date)o=r(e,this.format);else try{let t=new Date(e);t instanceof Date&&(o=r(t,this.format))}catch(t){console.error('failed to parse "'+e+'" as date',t)}else o="";n[t]=o}}function n(){t.call(this,"value"),this.toData=function(e){console.warn("yet to be implemented, react on "+e)}}e("tieDateValue",{toView:function(e,t){t.value=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDateText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDatetimeText",new t),e("tieDatetimeValue",new n),n.prototype=Object.create(t.prototype),n.prototype.constructor=n;let o={d:function(e,t){return e.getDate().toString().padStart(t,"0")},M:function(e,t){return(e.getMonth()+1).toString().padStart(t,"0")},y:function(e,t){let n=e.getFullYear().toString();return n.length>t?n.substr(n.length-t):n.padStart(t,"0")},h:function(e,t){return e.getHours().toString().padStart(t,"0")},m:function(e,t){return e.getMinutes().toString().padStart(t,"0")},s:function(e,t){return e.getSeconds().toString().padStart(t,"0")},f:function(e,t){return e.getMilliseconds().toString().padStart(t,"0")}};function r(e,t){let n="";if(t){let r,i;for(let a=0,l=t.length;a<l;a++)if(r=t.charAt(a),o[r]){for(i=1;a<l-1&&t.charAt(a+1)===r;)i++,a++;n+=o[r](e,i)}else n+=r}else n=e.toLocaleString();return n}})(),(()=>{"use strict";const e=this||window,t=e.DataTier.controllers.add,n=e.DataTier.views;function o(e,t,n,o,r){let i,a,l,s,c,f,u,d,h,p,m,g=null,y=o,E=n[0]+".";for(a=t.content,u=(i=function(e,t){let n,o,r,i,a,l,s={index:[]},c=e.content.querySelectorAll("*"),f=c.length;for(;f--;)if((n=c[f]).nodeType===Node.DOCUMENT_NODE||n.nodeType===Node.ELEMENT_NODE){for(r=(o=Object.keys(n.dataset)).length,l=[];r--;)i=o[r],a=n.dataset[i],i.startsWith("tie")&&a.startsWith(t)&&l.push([i,a.replace(t,"")]);l.length&&(s[f]=l,s.index.push(f))}return s}(t,n[2])).index;y<r;y++){for(d=(l=a.cloneNode(!0)).querySelectorAll("*"),s=u.length;s--;)for(h=d[f=u[s]],c=(p=i[f]).length;c--;)m=p[c][0],h.dataset[m]=E+y+p[c][1];y===o?g=l:g.appendChild(l)}e.appendChild(g)}t("tieList",{parseParam:function(e){return this.constructor.prototype.parseParam(e.split(/\s*=>\s*/)[0])},isChangedPathRelevant:function(e,t){if(!e)return!0;let n=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===n.length||2===n.length&&""===n[0]},toView:function(e,t){if(!Array.isArray(e)||!t)return;let r,i,a,l=t.parentNode,s=e.length;if("TEMPLATE"!==t.nodeName)throw new Error("tieList may be defined on template elements only");if(1!==t.content.childElementCount)throw new Error("tieList's TEMPLATE element MUST HAVE exactly one direct child element");(a=(i=t.content.firstElementChild.dataset).dtListItemAid)||(a=(new Date).getTime(),i.dtListItemAid=a);let c=l.querySelectorAll('[data-dt-list-item-aid="'+a+'"]'),f=c.length;if(f>s)for(;f>s;)l.removeChild(c[--f]);!function(e,t,o){let r,i=e.content.querySelectorAll("*"),a=[];for(r=i.length;r--;)a[r]=Object.keys(i[r].dataset).filter(e=>e.startsWith("tie"));let l,s,c,f,u,d,h=0;for(r=0;h<o;)if((c=t.childNodes[r++])!==e&&(c.nodeType===Node.DOCUMENT_NODE||c.nodeType===Node.ELEMENT_NODE)&&c.dataset.dtListItemAid){for(f=c.querySelectorAll("*"),l=a.length;l--;)for(u=l?f[l-1]:c,s=(d=a[l]).length;s--;)n.updateView(u,d[s]);h++}}(t,l,f),f<s&&o(l,t,r=function(e){let t;if(e&&(!(t=e.trim().split(/\s+/))||3!==t.length||"=>"!==t[1]))throw new Error('invalid parameter for "tieList" rule specified');return t}(t.dataset.tieList),f,s)}})})(); |
@@ -1,519 +0,608 @@ | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
const scope = this || window, | ||
proxiesToTargetsMap = new Map(), | ||
targetsToObserved = new Map(), | ||
observedToObservable = new Map(), | ||
nonObservables = ['Date', 'Blob', 'Number', 'String', 'Boolean', 'Error', 'SyntaxError', 'TypeError', 'URIError', 'Function', 'Promise', 'RegExp']; | ||
const | ||
scope = this || window, | ||
INSERT = 'insert', | ||
UPDATE = 'update', | ||
DELETE = 'delete', | ||
REVERSE = 'reverse', | ||
SHUFFLE = 'shuffle', | ||
sysObsKey = Symbol('system-observer-key'), | ||
nonObservables = { | ||
Date: true, | ||
Blob: true, | ||
Number: true, | ||
String: true, | ||
Boolean: true, | ||
Error: true, | ||
SyntaxError: true, | ||
TypeError: true, | ||
URIError: true, | ||
Function: true, | ||
Promise: true, | ||
RegExp: true | ||
}, | ||
observableDefinition = { | ||
revoke: { | ||
value: function() { | ||
this[sysObsKey].revoke(); | ||
} | ||
}, | ||
observe: { | ||
value: function(observer) { | ||
let systemObserver = this[sysObsKey], | ||
observers = systemObserver.observers; | ||
if (systemObserver.isRevoked) { throw new TypeError('revoked Observable MAY NOT be observed anymore'); } | ||
if (typeof observer !== 'function') { throw new Error('observer parameter MUST be a function'); } | ||
function copyShallow(target) { | ||
return Array.isArray(target) ? | ||
target.slice() : | ||
Object.assign({}, target); | ||
} | ||
function isNonObservable(target) { | ||
return nonObservables.indexOf(target.constructor.name) >= 0; | ||
} | ||
function proxiedArrayGet(target, key) { | ||
let result, | ||
observed = targetsToObserved.get(target), | ||
observable = observedToObservable.get(observed.root); | ||
if (key === 'pop') { | ||
result = function proxiedPop() { | ||
let poppedIndex, popResult, tmpTarget, changes; | ||
poppedIndex = target.length - 1; | ||
popResult = Reflect.apply(target[key], target, arguments); | ||
tmpTarget = proxiesToTargetsMap.get(popResult); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
if (observers.indexOf(observer) < 0) { | ||
observers.push(observer); | ||
} else { | ||
console.info('observer may be bound to an observable only once'); | ||
} | ||
} | ||
changes = [new DeleteChange(observed.path.concat(poppedIndex), tmpTarget || popResult)]; | ||
observable.notify(changes); | ||
return tmpTarget || popResult; | ||
}; | ||
} else if (key === 'push') { | ||
result = function proxiedPush() { | ||
let pushContent, pushResult, changes = [], startingLength; | ||
pushContent = Array.from(arguments); | ||
startingLength = target.length; | ||
for (let i = 0, l = pushContent.length, item; i < l; i++) { | ||
item = pushContent[i]; | ||
if (item && typeof item === 'object') { | ||
pushContent[i] = new Observed(item, startingLength + i, observed).proxy; | ||
}, | ||
unobserve: { | ||
value: function() { | ||
let systemObserver = this[sysObsKey], | ||
observers = systemObserver.observers, | ||
l, idx; | ||
if (systemObserver.isRevoked) { throw new TypeError('revoked Observable MAY NOT be unobserved anymore'); } | ||
l = arguments.length; | ||
if (l) { | ||
while (l--) { | ||
idx = observers.indexOf(arguments[l]); | ||
if (idx >= 0) observers.splice(idx, 1); | ||
} | ||
} else { | ||
observers.splice(0); | ||
} | ||
changes.push(new InsertChange(observed.path.concat(startingLength + i), item)); | ||
} | ||
pushResult = Reflect.apply(target[key], target, pushContent); | ||
observable.notify(changes); | ||
return pushResult; | ||
}; | ||
} else if (key === 'shift') { | ||
result = function proxiedShift() { | ||
let shiftResult, changes, tmpTarget; | ||
shiftResult = Reflect.apply(target[key], target, arguments); | ||
tmpTarget = proxiesToTargetsMap.get(shiftResult); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
} | ||
}, | ||
prepareArray = function(origin, destination, observer) { | ||
let l = origin.length, item; | ||
destination[sysObsKey] = observer; | ||
while (l--) { | ||
item = origin[l]; | ||
if (item && typeof item === 'object' && !nonObservables.hasOwnProperty(item.constructor.name)) { | ||
destination[l] = Array.isArray(item) | ||
? new ArrayObserver({target: item, ownKey: l, parent: observer}).proxy | ||
: new ObjectObserver({target: item, ownKey: l, parent: observer}).proxy; | ||
} else { | ||
destination[l] = item; | ||
} | ||
} | ||
}, | ||
prepareObject = function(origin, destination, observer) { | ||
let keys = Object.keys(origin), l = keys.length, key, item; | ||
destination[sysObsKey] = observer; | ||
while (l--) { | ||
key = keys[l]; | ||
item = origin[key]; | ||
if (item && typeof item === 'object' && !nonObservables.hasOwnProperty(item.constructor.name)) { | ||
destination[key] = Array.isArray(item) | ||
? new ArrayObserver({target: item, ownKey: key, parent: observer}).proxy | ||
: new ObjectObserver({target: item, ownKey: key, parent: observer}).proxy; | ||
} else { | ||
destination[key] = item; | ||
} | ||
} | ||
}, | ||
callObservers = function(observers, changes) { | ||
let l = observers.length; | ||
while (l--) { | ||
try { | ||
observers[l](changes); | ||
} catch (e) { | ||
console.error('failed to deliver changes to listener' + observers[l], e); | ||
} | ||
} | ||
}, | ||
getAncestorInfo = function(self) { | ||
let tmp = [], result, l1 = 0, l2 = 0; | ||
while (self.parent) { | ||
tmp[l1++] = self.ownKey; | ||
self = self.parent; | ||
} | ||
result = new Array(l1); | ||
while (l1--) result[l2++] = tmp[l1]; | ||
return {observers: self.observers, path: result}; | ||
}; | ||
// update indices of the remaining items | ||
for (let i = 0, l = target.length, item, tmpObserved; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(item)); | ||
class ArrayObserver { | ||
constructor(properties) { | ||
let origin = properties.target, clone = new Array(origin.length); | ||
if (properties.parent === null) { | ||
this.isRevoked = false; | ||
this.observers = []; | ||
Object.defineProperties(clone, observableDefinition); | ||
} else { | ||
this.parent = properties.parent; | ||
this.ownKey = properties.ownKey; | ||
} | ||
prepareArray(origin, clone, this); | ||
this.revokable = Proxy.revocable(clone, this); | ||
this.proxy = this.revokable.proxy; | ||
this.target = clone; | ||
} | ||
// returns an unobserved graph (effectively this is an opposite of an ArrayObserver constructor logic) | ||
revoke() { | ||
// revoke native proxy | ||
this.revokable.revoke(); | ||
// roll back observed array to an unobserved one | ||
let target = this.target, l = target.length, item; | ||
while (l--) { | ||
item = target[l]; | ||
if (item && typeof item === 'object') { | ||
let tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
target[l] = tmpObserved.revoke(); | ||
} | ||
} | ||
} | ||
return target; | ||
} | ||
get(target, key) { | ||
const proxiedArrayMethods = { | ||
pop: function proxiedPop(target, observed) { | ||
let poppedIndex, popResult; | ||
poppedIndex = target.length - 1; | ||
popResult = target.pop(); | ||
if (popResult && typeof popResult === 'object') { | ||
let tmpObserved = popResult[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} else { | ||
console.error('unexpectedly failed to resolve proxy -> target -> observed'); | ||
popResult = tmpObserved.revoke(); | ||
} | ||
} | ||
} | ||
changes = [new DeleteChange(observed.path.concat(0), tmpTarget || shiftResult)]; | ||
observable.notify(changes); | ||
return tmpTarget || shiftResult; | ||
}; | ||
} else if (key === 'unshift') { | ||
result = function proxiedUnshift() { | ||
let unshiftContent, unshiftResult, changes = [], tmpObserved; | ||
unshiftContent = Array.from(arguments); | ||
unshiftContent.forEach(function(item, index) { | ||
if (item && typeof item === 'object') { | ||
unshiftContent[index] = new Observed(item, index, observed).proxy; | ||
// publish changes | ||
let ad = getAncestorInfo(observed); | ||
if (ad.observers.length) { | ||
ad.path.push(poppedIndex); | ||
callObservers(ad.observers, [{type: DELETE, path: ad.path, oldValue: popResult}]); | ||
} | ||
}); | ||
unshiftResult = Reflect.apply(target[key], target, unshiftContent); | ||
for (let i = 0, l = target.length, item; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(item)); | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} else { | ||
console.error('failed to resolve proxy -> target -> observed'); | ||
return popResult; | ||
}, | ||
push: function proxiedPush(target, observed) { | ||
let i, l = arguments.length - 2, item, pushContent = new Array(l), pushResult, changes, | ||
initialLength, ad = getAncestorInfo(observed); | ||
initialLength = target.length; | ||
for (i = 0; i < l; i++) { | ||
item = arguments[i + 2]; | ||
if (item && typeof item === 'object' && !nonObservables.hasOwnProperty(item.constructor.name)) { | ||
item = Array.isArray(item) | ||
? new ArrayObserver({target: item, ownKey: initialLength + i, parent: observed}).proxy | ||
: new ObjectObserver({target: item, ownKey: initialLength + i, parent: observed}).proxy; | ||
} | ||
pushContent[i] = item; | ||
} | ||
} | ||
for (let i = 0, l = unshiftContent.length; i < l; i++) { | ||
changes.push(new InsertChange(observed.path.concat(i), target[i])); | ||
} | ||
observable.notify(changes); | ||
return unshiftResult; | ||
}; | ||
} else if (key === 'reverse') { | ||
result = function proxiedReverse() { | ||
let changes, tmpObserved; | ||
Reflect.apply(target[key], target, arguments); | ||
for (let i = 0, l = target.length, item; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(item)); | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} else { | ||
console.error('failed to resolve proxy -> target -> observed'); | ||
pushResult = Reflect.apply(target.push, target, pushContent); | ||
// publish changes | ||
if (ad.observers.length) { | ||
changes = []; | ||
for (i = initialLength, l = target.length; i < l; i++) { | ||
let path = ad.path.slice(0); | ||
path.push(i); | ||
changes[i - initialLength] = {type: INSERT, path: path, value: target[i]}; | ||
} | ||
callObservers(ad.observers, changes); | ||
} | ||
} | ||
changes = [new ReverseChange()]; | ||
observable.notify(changes); | ||
return this; | ||
}; | ||
} else if (key === 'sort') { | ||
result = function proxiedSort() { | ||
let changes, tmpObserved; | ||
Reflect.apply(target[key], target, arguments); | ||
for (let i = 0, l = target.length, item; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(item)); | ||
return pushResult; | ||
}, | ||
shift: function proxiedShift(target, observed) { | ||
let shiftResult, i, l, item, ad, changes; | ||
shiftResult = target.shift(); | ||
if (shiftResult && typeof shiftResult === 'object') { | ||
let tmpObserved = shiftResult[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} else { | ||
console.error('failed to resolve proxy -> target -> observed'); | ||
shiftResult = tmpObserved.revoke(); | ||
} | ||
} | ||
} | ||
changes = [new ShuffleChange()]; | ||
observable.notify(changes); | ||
return this; | ||
}; | ||
} else if (key === 'fill') { | ||
result = function proxiedFill() { | ||
let start, end, changes = [], prev, argLen = arguments.length, tarLen = target.length; | ||
start = argLen < 2 ? 0 : (arguments[1] < 0 ? tarLen + arguments[1] : arguments[1]); | ||
end = argLen < 3 ? tarLen : (arguments[2] < 0 ? tarLen + arguments[2] : arguments[2]); | ||
prev = target.slice(); | ||
Reflect.apply(target[key], target, arguments); | ||
for (let i = start, item, tmpTarget; i < end; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
target[i] = new Observed(item, i, observed).proxy; | ||
// update indices of the remaining items | ||
for (i = 0, l = target.length; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
let tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} | ||
} | ||
} | ||
if (prev.hasOwnProperty(i)) { | ||
tmpTarget = proxiesToTargetsMap.get(prev[i]); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
// publish changes | ||
ad = getAncestorInfo(observed); | ||
if (ad.observers.length) { | ||
ad.path.push(0); | ||
changes = [{type: DELETE, path: ad.path, oldValue: shiftResult}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
return shiftResult; | ||
}, | ||
unshift: function proxiedUnshift(target, observed) { | ||
let unshiftContent, unshiftResult, ad, changes; | ||
unshiftContent = Array.from(arguments); | ||
unshiftContent.splice(0, 2); | ||
unshiftContent.forEach((item, index) => { | ||
if (item && typeof item === 'object' && !nonObservables.hasOwnProperty(item.constructor.name)) { | ||
unshiftContent[index] = Array.isArray(item) | ||
? new ArrayObserver({target: item, ownKey: index, parent: observed}).proxy | ||
: new ObjectObserver({target: item, ownKey: index, parent: observed}).proxy; | ||
} | ||
}); | ||
unshiftResult = Reflect.apply(target.unshift, target, unshiftContent); | ||
for (let i = 0, l = target.length, item; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
let tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} | ||
} | ||
} | ||
changes.push(new UpdateChange(observed.path.concat(i), target[i], tmpTarget || prev[i])); | ||
} else { | ||
changes.push(new InsertChange(observed.path.concat(i), target[i])); | ||
// publish changes | ||
ad = getAncestorInfo(observed); | ||
if (ad.observers.length) { | ||
let l = unshiftContent.length, path; | ||
changes = new Array(l); | ||
for (let i = 0; i < l; i++) { | ||
path = ad.path.slice(0); | ||
path.push(i); | ||
changes[i] = {type: INSERT, path: path, value: target[i]}; | ||
} | ||
callObservers(ad.observers, changes); | ||
} | ||
} | ||
observable.notify(changes); | ||
return this; | ||
}; | ||
} else if (key === 'splice') { | ||
result = function proxiedSplice() { | ||
let spliceContent, spliceResult, changes = [], tmpObserved, | ||
startIndex, removed, inserted, splLen, tarLen = target.length; | ||
return unshiftResult; | ||
}, | ||
reverse: function proxiedReverse(target, observed) { | ||
let i, l, item, ad, changes; | ||
target.reverse(); | ||
for (i = 0, l = target.length; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
let tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} | ||
} | ||
} | ||
spliceContent = Array.from(arguments); | ||
splLen = spliceContent.length; | ||
// publish changes | ||
ad = getAncestorInfo(observed); | ||
if (ad.observers.length) { | ||
changes = [{type: REVERSE, path: ad.path}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
return observed.proxy; | ||
}, | ||
sort: function proxiedSort(target, observed, comparator) { | ||
let i, l, item, ad, changes; | ||
target.sort(comparator); | ||
for (i = 0, l = target.length; i < l; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
let tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} | ||
} | ||
} | ||
// observify the newcomers | ||
for (let i = 0, item; i < splLen; i++) { | ||
item = spliceContent[i]; | ||
if (i > 1 && item && typeof item === 'object') { | ||
spliceContent[i] = new Observed(item, i, observed).proxy; | ||
// publish changes | ||
ad = getAncestorInfo(observed); | ||
if (ad.observers.length) { | ||
changes = [{type: SHUFFLE, path: ad.path}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
} | ||
return observed.proxy; | ||
}, | ||
fill: function proxiedFill(target, observed) { | ||
let ad = getAncestorInfo(observed), normArgs, argLen, | ||
start, end, changes = [], prev, tarLen = target.length, path; | ||
normArgs = Array.from(arguments); | ||
normArgs.splice(0, 2); | ||
argLen = normArgs.length; | ||
start = argLen < 2 ? 0 : (normArgs[1] < 0 ? tarLen + normArgs[1] : normArgs[1]); | ||
end = argLen < 3 ? tarLen : (normArgs[2] < 0 ? tarLen + normArgs[2] : normArgs[2]); | ||
prev = target.slice(0); | ||
Reflect.apply(target.fill, target, normArgs); | ||
// calculate pointers | ||
startIndex = splLen === 0 ? 0 : (spliceContent[0] < 0 ? tarLen + spliceContent[0] : spliceContent[0]); | ||
removed = splLen < 2 ? tarLen - startIndex : spliceContent[1]; | ||
inserted = Math.max(splLen - 2, 0); | ||
spliceResult = Reflect.apply(target[key], target, spliceContent); | ||
for (let i = start, item, tmpTarget; i < end; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object' && !nonObservables.hasOwnProperty(item.constructor.name)) { | ||
target[i] = Array.isArray(item) | ||
? new ArrayObserver({target: item, ownKey: i, parent: observed}).proxy | ||
: new ObjectObserver({target: item, ownKey: i, parent: observed}).proxy; | ||
} | ||
if (prev.hasOwnProperty(i)) { | ||
tmpTarget = prev[i]; | ||
if (tmpTarget && typeof tmpTarget === 'object') { | ||
let tmpObserved = tmpTarget[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpTarget = tmpObserved.revoke(); | ||
} | ||
} | ||
// reindex the paths | ||
for (let i = 0, item; i < tarLen; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = targetsToObserved.get(proxiesToTargetsMap.get(item)); | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
path = ad.path.slice(0); | ||
path.push(i); | ||
changes.push({type: UPDATE, path: path, value: target[i], oldValue: tmpTarget}); | ||
} else { | ||
console.error('failed to resolve proxy -> target -> observed'); | ||
path = ad.path.slice(0); | ||
path.push(i); | ||
changes.push({type: INSERT, path: path, value: target[i]}); | ||
} | ||
} | ||
} | ||
// revoke removed Observed | ||
for (let i = 0, l = spliceResult.length, item, tmpTarget; i < l; i++) { | ||
item = spliceResult[i]; | ||
tmpTarget = proxiesToTargetsMap.get(item); | ||
if (tmpTarget) { | ||
targetsToObserved.get(tmpTarget).revoke(); | ||
spliceResult[i] = tmpTarget; | ||
// publish changes | ||
if (ad.observers.length) { | ||
callObservers(ad.observers, changes); | ||
} | ||
} | ||
return observed.proxy; | ||
}, | ||
splice: function proxiedSplice(target, observed) { | ||
let ad = getAncestorInfo(observed), | ||
spliceContent, spliceResult, changes = [], tmpObserved, | ||
startIndex, removed, inserted, splLen, tarLen = target.length; | ||
// publish changes | ||
let index; | ||
for (index = 0; index < removed; index++) { | ||
if (index < inserted) { | ||
changes.push(new UpdateChange(observed.path.concat(startIndex + index), target[startIndex + index], spliceResult[index])); | ||
} else { | ||
changes.push(new DeleteChange(observed.path.concat(startIndex + index), spliceResult[index])); | ||
spliceContent = Array.from(arguments); | ||
spliceContent.splice(0, 2); | ||
splLen = spliceContent.length; | ||
// observify the newcomers | ||
for (let i = 2, item; i < splLen; i++) { | ||
item = spliceContent[i]; | ||
if (item && typeof item === 'object' && !nonObservables.hasOwnProperty(item.constructor.name)) { | ||
spliceContent[i] = Array.isArray(item) | ||
? new ArrayObserver({target: item, ownKey: i, parent: observed}).proxy | ||
: new ObjectObserver({target: item, ownKey: i, parent: observed}).proxy; | ||
} | ||
} | ||
} | ||
for (; index < inserted; index++) { | ||
changes.push(new InsertChange(observed.path.concat(startIndex + index), target[startIndex + index])); | ||
} | ||
observable.notify(changes); | ||
return spliceResult; | ||
}; | ||
} else { | ||
result = Reflect.get(target, key); | ||
} | ||
return result; | ||
} | ||
// calculate pointers | ||
startIndex = splLen === 0 ? 0 : (spliceContent[0] < 0 ? tarLen + spliceContent[0] : spliceContent[0]); | ||
removed = splLen < 2 ? tarLen - startIndex : spliceContent[1]; | ||
inserted = Math.max(splLen - 2, 0); | ||
spliceResult = Reflect.apply(target.splice, target, spliceContent); | ||
tarLen = target.length; | ||
function proxiedSet(target, key, value) { | ||
let oldValuePresent = target.hasOwnProperty(key), | ||
oldValue = target[key], | ||
result, | ||
oldTarget, | ||
observed = targetsToObserved.get(target), | ||
observable = observedToObservable.get(observed.root); | ||
// reindex the paths | ||
for (let i = 0, item; i < tarLen; i++) { | ||
item = target[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
tmpObserved.ownKey = i; | ||
} | ||
} | ||
} | ||
if (value && typeof value === 'object' && !isNonObservable(value)) { | ||
result = Reflect.set(target, key, new Observed(value, key, observed).proxy); | ||
} else { | ||
result = Reflect.set(target, key, value); | ||
} | ||
// revoke removed Observed | ||
let i, l, item; | ||
for (i = 0, l = spliceResult.length; i < l; i++) { | ||
item = spliceResult[i]; | ||
if (item && typeof item === 'object') { | ||
tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
spliceResult[i] = tmpObserved.revoke(); | ||
} | ||
} | ||
} | ||
if (result) { | ||
oldTarget = proxiesToTargetsMap.get(oldValue); | ||
if (oldTarget) { | ||
targetsToObserved.get(oldTarget).revoke(); | ||
} | ||
if (observable.hasListeners) { | ||
let path = observed.path.concat(key), | ||
changes = [oldValuePresent ? new UpdateChange(path, value, oldTarget || oldValue) : new InsertChange(path, value)]; | ||
if (!observed.preventCallbacks) { | ||
observable.notify(changes); | ||
// publish changes | ||
if (ad.observers.length) { | ||
let index, path; | ||
for (index = 0; index < removed; index++) { | ||
path = ad.path.slice(0); | ||
path.push(startIndex + index); | ||
if (index < inserted) { | ||
changes.push({ | ||
type: UPDATE, | ||
path: path, | ||
value: target[startIndex + index], | ||
oldValue: spliceResult[index] | ||
}); | ||
} else { | ||
changes.push({type: DELETE, path: path, oldValue: spliceResult[index]}); | ||
} | ||
} | ||
for (; index < inserted; index++) { | ||
path = ad.path.slice(0); | ||
path.push(startIndex + index); | ||
changes.push({type: INSERT, path: path, value: target[startIndex + index]}); | ||
} | ||
callObservers(ad.observers, changes); | ||
} | ||
return spliceResult; | ||
} | ||
}; | ||
if (proxiedArrayMethods.hasOwnProperty(key)) { | ||
return proxiedArrayMethods[key].bind(undefined, target, this); | ||
} else { | ||
return target[key]; | ||
} | ||
} | ||
return result; | ||
} | ||
function proxiedDelete(target, key) { | ||
let oldValue = target[key], | ||
result, | ||
oldTarget, | ||
observed = targetsToObserved.get(target), | ||
observable = observedToObservable.get(observed.root); | ||
set(target, key, value) { | ||
let oldValue = target[key], ad, changes; | ||
result = Reflect.deleteProperty(target, key); | ||
if (result) { | ||
oldTarget = proxiesToTargetsMap.get(oldValue); | ||
if (oldTarget) { | ||
targetsToObserved.get(oldTarget).revoke(); | ||
if (value && typeof value === 'object' && !nonObservables.hasOwnProperty(value.constructor.name)) { | ||
target[key] = Array.isArray(value) | ||
? new ArrayObserver({target: value, ownKey: key, parent: this}).proxy | ||
: new ObjectObserver({target: value, ownKey: key, parent: this}).proxy; | ||
} else { | ||
target[key] = value; | ||
} | ||
if (observable.hasListeners) { | ||
let path = observed.path.concat(key), | ||
changes = [new DeleteChange(path, oldTarget || oldValue)]; | ||
if (!observed.preventCallbacks) { | ||
observable.notify(changes); | ||
if (oldValue && typeof oldValue === 'object') { | ||
let tmpObserved = oldValue[sysObsKey]; | ||
if (tmpObserved) { | ||
oldValue = tmpObserved.revoke(); | ||
} | ||
} | ||
} | ||
return result; | ||
} | ||
function processArraySubgraph(graph, parentObserved) { | ||
for (let i = 0, l = graph.length, item; i < l; i++) { | ||
item = graph[i]; | ||
if (item && typeof item === 'object' && !isNonObservable(item)) { | ||
graph[i] = new Observed(item, i, parentObserved).proxy; | ||
// publish changes | ||
ad = getAncestorInfo(this); | ||
if (ad.observers.length) { | ||
ad.path.push(key); | ||
changes = typeof oldValue === 'undefined' | ||
? [{type: INSERT, path: ad.path, value: value}] | ||
: [{type: UPDATE, path: ad.path, value: value, oldValue: oldValue}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
return true; | ||
} | ||
} | ||
function processObjectSubgraph(graph, parentObserved) { | ||
let keys = Object.keys(graph); | ||
for (let i = 0, l = keys.length, key, item; i < l; i++) { | ||
key = keys[i]; | ||
item = graph[key]; | ||
if (item && typeof item === 'object' && !isNonObservable(item)) { | ||
graph[key] = new Observed(item, key, parentObserved).proxy; | ||
} | ||
} | ||
} | ||
deleteProperty(target, key) { | ||
let oldValue = target[key], ad, changes; | ||
// CLASSES | ||
if (delete target[key]) { | ||
if (oldValue && typeof oldValue === 'object') { | ||
let tmpObserved = oldValue[sysObsKey]; | ||
if (tmpObserved) { | ||
oldValue = tmpObserved.revoke(); | ||
} | ||
} | ||
function Observed(origin, ownKey, parent) { | ||
let targetClone, revokable, proxy; | ||
if (!origin || typeof origin !== 'object') { | ||
throw new Error('Observed MUST be created from a non null object origin'); | ||
// publish changes | ||
ad = getAncestorInfo(this); | ||
if (ad.observers.length) { | ||
ad.path.push(key); | ||
changes = [{type: DELETE, path: ad.path, oldValue: oldValue}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
if (parent && (typeof ownKey === 'undefined' || ownKey === null)) { | ||
throw new Error('any non-root (parent-less) Observed MUST have an own path; now parent is ' + parent + '; key is ' + ownKey); | ||
} | ||
if (parent && !(parent instanceof Observed)) { | ||
throw new Error('parent, when supplied, MUST be an instance of Observed'); | ||
} | ||
targetClone = copyShallow(origin); | ||
if (Array.isArray(targetClone)) { | ||
processArraySubgraph(targetClone, this); | ||
revokable = Proxy.revocable(targetClone, { | ||
set: proxiedSet, | ||
get: proxiedArrayGet, | ||
deleteProperty: proxiedDelete | ||
}); | ||
} else { | ||
processObjectSubgraph(targetClone, this); | ||
revokable = Proxy.revocable(targetClone, { | ||
set: proxiedSet, | ||
deleteProperty: proxiedDelete | ||
}); | ||
} | ||
proxy = revokable.proxy; | ||
targetsToObserved.set(targetClone, this); | ||
proxiesToTargetsMap.set(proxy, targetClone); | ||
Object.defineProperties(this, { | ||
revokable: {value: revokable}, | ||
proxy: {value: proxy}, | ||
parent: {value: parent}, | ||
ownKey: {value: ownKey, writable: true} | ||
}); | ||
} | ||
Object.defineProperty(Observed.prototype, 'root', { | ||
get: function() { | ||
let result = this; | ||
while (result.parent) { | ||
result = result.parent; | ||
class ObjectObserver { | ||
constructor(properties) { | ||
let origin = properties.target, clone = {}; | ||
if (properties.parent === null) { | ||
this.isRevoked = false; | ||
this.observers = []; | ||
Object.defineProperties(clone, observableDefinition); | ||
} else { | ||
this.parent = properties.parent; | ||
this.ownKey = properties.ownKey; | ||
} | ||
return result; | ||
prepareObject(origin, clone, this); | ||
this.revokable = Proxy.revocable(clone, this); | ||
this.proxy = this.revokable.proxy; | ||
this.target = clone; | ||
} | ||
}); | ||
Object.defineProperty(Observed.prototype, 'path', { | ||
get: function() { | ||
let result = [], pointer = this; | ||
while (typeof pointer.ownKey !== 'undefined') { | ||
result.unshift(pointer.ownKey); | ||
pointer = pointer.parent; | ||
} | ||
return result; | ||
} | ||
}); | ||
Object.defineProperty(Observed.prototype, 'revoke', { | ||
value: function() { | ||
let target = proxiesToTargetsMap.get(this.proxy), | ||
keys = Object.keys(target); | ||
// returns an unobserved graph (effectively this is an opposite of an ObjectObserver constructor logic) | ||
revoke() { | ||
// revoke native proxy | ||
this.revokable.revoke(); | ||
// roll back observed graph to unobserved one | ||
for (let i = 0, l = keys.length, key, tmpTarget; i < l; i++) { | ||
key = keys[i]; | ||
tmpTarget = proxiesToTargetsMap.get(target[key]); | ||
if (tmpTarget) { | ||
target[key] = targetsToObserved.get(tmpTarget).revoke(); | ||
// roll back observed graph to an unobserved one | ||
let target = this.target, keys = Object.keys(target), l = keys.length, key, item; | ||
while (l--) { | ||
key = keys[l]; | ||
item = target[key]; | ||
if (item && typeof item === 'object') { | ||
let tmpObserved = item[sysObsKey]; | ||
if (tmpObserved) { | ||
target[key] = tmpObserved.revoke(); | ||
} | ||
} | ||
} | ||
// clean revoked Observed from the maps | ||
proxiesToTargetsMap.delete(this.proxy); | ||
targetsToObserved.delete(target); | ||
// return an unobserved graph (effectively this is an opposite of an Observed constructor logic) | ||
return target; | ||
} | ||
}); | ||
function Observable(observed) { | ||
let isRevoked = false, callbacks = []; | ||
set(target, key, value) { | ||
let oldValue = target[key], ad, changes; | ||
function observe(callback) { | ||
if (isRevoked) { throw new TypeError('revoked Observable MAY NOT be observed anymore'); } | ||
if (typeof callback !== 'function') { throw new Error('observer (callback) parameter MUST be a function'); } | ||
if (callbacks.indexOf(callback) < 0) { | ||
callbacks.push(callback); | ||
if (value && typeof value === 'object' && !nonObservables.hasOwnProperty(value.constructor.name)) { | ||
target[key] = Array.isArray(value) | ||
? new ArrayObserver({target: value, ownKey: key, parent: this}).proxy | ||
: new ObjectObserver({target: value, ownKey: key, parent: this}).proxy; | ||
} else { | ||
console.info('observer (callback) may be bound to an observable only once'); | ||
target[key] = value; | ||
} | ||
} | ||
function unobserve() { | ||
if (isRevoked) { throw new TypeError('revoked Observable MAY NOT be unobserved anymore'); } | ||
if (arguments.length) { | ||
for (let i = 0, l = arguments.length, idx; i < l; i++) { | ||
idx = callbacks.indexOf(arguments[i]); | ||
if (idx >= 0) callbacks.splice(idx, 1); | ||
if (oldValue && typeof oldValue === 'object') { | ||
let tmpObserved = oldValue[sysObsKey]; | ||
if (tmpObserved) { | ||
oldValue = tmpObserved.revoke(); | ||
} | ||
} else { | ||
callbacks.splice(0, callbacks.length); | ||
} | ||
} | ||
function revoke() { | ||
if (!isRevoked) { | ||
isRevoked = true; | ||
observed.revoke(); | ||
} else { | ||
console.log('revoking of Observable effective only once'); | ||
// publish changes | ||
ad = getAncestorInfo(this); | ||
if (ad.observers.length) { | ||
ad.path.push(key); | ||
changes = typeof oldValue === 'undefined' | ||
? [{type: INSERT, path: ad.path, value: value}] | ||
: [{type: UPDATE, path: ad.path, value: value, oldValue: oldValue}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
return true; | ||
} | ||
function hasListeners() { | ||
return callbacks.length > 0; | ||
} | ||
deleteProperty(target, key) { | ||
let oldValue = target[key], ad, changes; | ||
function notify(changes) { | ||
for (let i = 0, l = callbacks.length, callback; i < l; i++) { | ||
callback = callbacks[i]; | ||
try { | ||
callback(changes); | ||
} catch (e) { | ||
console.error('one/some of the observing callbacks failed with ', e); | ||
if (delete target[key]) { | ||
if (oldValue && typeof oldValue === 'object') { | ||
let tmpObserved = oldValue[sysObsKey]; | ||
if (tmpObserved) { | ||
oldValue = tmpObserved.revoke(); | ||
} | ||
} | ||
// publish changes | ||
ad = getAncestorInfo(this); | ||
if (ad.observers.length) { | ||
ad.path.push(key); | ||
changes = [{type: DELETE, path: ad.path, oldValue: oldValue}]; | ||
callObservers(ad.observers, changes); | ||
} | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
Object.defineProperties(observed.proxy, { | ||
observe: {value: observe}, | ||
unobserve: {value: unobserve}, | ||
revoke: {value: revoke} | ||
}); | ||
Object.defineProperties(this, { | ||
hasListeners: {value: hasListeners}, | ||
notify: {value: notify} | ||
}); | ||
} | ||
function InsertChange(path, value) { | ||
Object.defineProperties(this, { | ||
type: {value: 'insert'}, | ||
path: {value: path}, | ||
value: {value: value} | ||
}); | ||
} | ||
class Observable { | ||
constructor() { | ||
throw new Error('Observable MAY NOT be created via constructor, see "Observable.from" API'); | ||
} | ||
function UpdateChange(path, value, oldValue) { | ||
Object.defineProperties(this, { | ||
type: {value: 'update'}, | ||
path: {value: path}, | ||
value: {value: value}, | ||
oldValue: {value: oldValue} | ||
}); | ||
} | ||
function DeleteChange(path, oldValue) { | ||
Object.defineProperties(this, { | ||
type: {value: 'delete'}, | ||
path: {value: path}, | ||
oldValue: {value: oldValue} | ||
}); | ||
} | ||
function ReverseChange() { | ||
Object.defineProperties(this, { | ||
type: {value: 'reverse'} | ||
}); | ||
} | ||
function ShuffleChange() { | ||
Object.defineProperties(this, { | ||
type: {value: 'shuffle'} | ||
}); | ||
} | ||
Object.defineProperty(Observable, 'from', { | ||
value: function(target) { | ||
if (!target || typeof target !== 'object') { | ||
throw new Error('observable MAY ONLY be created from non-null object only'); | ||
} else if ('observe' in target || 'unobserve' in target || 'revoke' in target) { | ||
throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"'); | ||
} else if (isNonObservable(target)) { | ||
throw new Error(target + ' found to be one of non-observable object types: ' + nonObservables); | ||
static from(target) { | ||
if (target && typeof target === 'object' && !nonObservables.hasOwnProperty(target.constructor.name) && !('observe' in target) && !('unobserve' in target) && !('revoke' in target)) { | ||
let observed = Array.isArray(target) | ||
? new ArrayObserver({target: target, ownKey: null, parent: null}) | ||
: new ObjectObserver({target: target, ownKey: null, parent: null}); | ||
return observed.proxy; | ||
} else { | ||
if (!target || typeof target !== 'object') { | ||
throw new Error('observable MAY ONLY be created from non-null object only'); | ||
} else if ('observe' in target || 'unobserve' in target || 'revoke' in target) { | ||
throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"'); | ||
} else if (nonObservables.hasOwnProperty(target.constructor.name)) { | ||
throw new Error(target + ' found to be one of non-observable object types: ' + nonObservables); | ||
} | ||
} | ||
let observed = new Observed(target), | ||
observable = new Observable(observed); | ||
observedToObservable.set(observed, observable); | ||
return observed.proxy; | ||
} | ||
}); | ||
} | ||
Object.freeze(Observable); | ||
Object.defineProperty(scope, 'Observable', {value: Observable}); | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -547,13 +636,11 @@ | ||
set: function(input) { | ||
let oldData = data, | ||
newData = ensureObservable(input); | ||
if (data) data.revoke(); | ||
data = newData; | ||
if (data) data.observe(observer); | ||
namespace.DataTier.views.processChanges(name, [{ | ||
type: 'update', | ||
value: data, | ||
oldValue: oldData, | ||
path: [] | ||
}]); | ||
if (input !== data) { | ||
let oldData = data; | ||
data = ensureObservable(input); | ||
if (data) data.observe(observer); | ||
namespace.DataTier.views.processChanges(name, [{ | ||
path: [] | ||
}]); | ||
if (oldData) oldData.revoke(); | ||
} | ||
} | ||
@@ -625,5 +712,4 @@ }); | ||
}); | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -704,3 +790,3 @@ | ||
function defaultIsChangedPathRelevant(changedPath, viewedPath) { | ||
return viewedPath.startsWith(changedPath); | ||
return viewedPath.indexOf(changedPath) === 0; | ||
} | ||
@@ -726,3 +812,3 @@ | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -744,4 +830,5 @@ | ||
if (!ref) return; | ||
for (let i = 0, pathLength = path.length; i < pathLength; i++) { | ||
if (ref && path[i] in ref) ref = ref[path[i]]; | ||
for (let i = 0, l = path.length, n; i < l; i++) { | ||
n = path[i]; | ||
if (ref && ref.hasOwnProperty(n)) ref = ref[n]; | ||
else return; | ||
@@ -784,49 +871,43 @@ } | ||
function add(view) { | ||
let localCustomElementName; | ||
if (view.nodeName === 'IFRAME') { | ||
initDocumentObserver(view.contentDocument); | ||
view.addEventListener('load', function() { | ||
initDocumentObserver(this.contentDocument); | ||
collect(this.contentDocument); | ||
}); | ||
collect(view.contentDocument); | ||
} else if (Node.ELEMENT_NODE === view.nodeType && (localCustomElementName = getLocalNameIfCustomElement(view))) { | ||
customElements.whenDefined(localCustomElementName).then(() => processAddedView(view)); | ||
} else if (view.dataset) { | ||
processAddedView(view); | ||
function add(elements) { | ||
if (!elements.length) elements = [elements]; | ||
for (let i = 0, l = elements.length; i < l; i++) { | ||
let element = elements[i]; | ||
if (element.nodeName === 'IFRAME') { | ||
initDocumentObserver(element.contentDocument); | ||
element.addEventListener('load', function() { | ||
initDocumentObserver(this.contentDocument); | ||
collect(this.contentDocument); | ||
}); | ||
collect(element.contentDocument); | ||
} else if (Node.ELEMENT_NODE === element.nodeType) { | ||
if (element.localName.indexOf('-') < 0 && !element.hasAttribute('is')) { | ||
processAddedElement(element); | ||
} else { | ||
customElements.whenDefined(element.getAttribute('is') || element.localName).then(() => processAddedElement(element)); | ||
} | ||
} | ||
} | ||
} | ||
function getLocalNameIfCustomElement(view) { | ||
let result; | ||
if (view.localName.includes('-')) { | ||
result = view.localName; | ||
} else if (!(result = view.getAttribute('is')) || !result.includes('-')) { | ||
result = null; | ||
} | ||
return result; | ||
} | ||
function processAddedElement(element) { | ||
let ds = element.dataset, keys = Object.keys(ds), l = keys.length; | ||
while (l--) { | ||
let key = keys[l]; | ||
if (key.indexOf('tie') !== 0) continue; | ||
function processAddedView(view) { | ||
let keys = Object.keys(view.dataset), key, | ||
controller, controllerParam, pathString, | ||
tieViews, procViews, pathViews, i; | ||
i = keys.length; | ||
while (i--) { | ||
key = keys[i]; | ||
if (!key.startsWith('tie')) continue; | ||
controller = controllers.get(key); | ||
let controller = controllers.get(key); | ||
if (controller) { | ||
controllerParam = controller.parseParam(view.dataset[controller.name]); | ||
pathString = controllerParam.dataPath.join('.'); | ||
tieViews = views[controllerParam.tieName] || (views[controllerParam.tieName] = {}); | ||
procViews = tieViews[controller.name] || (tieViews[controller.name] = {}); | ||
pathViews = procViews[pathString] || (procViews[pathString] = []); | ||
let controllerParam = controller.parseParam(ds[controller.name]), | ||
pathString = controllerParam.dataPath.join('.'); | ||
if (pathViews.indexOf(view) < 0) { | ||
pathViews.push(view); | ||
update(view, controller.name); | ||
let tieViews = views[controllerParam.tieName] || (views[controllerParam.tieName] = {}), | ||
ctrlViews = tieViews[controller.name] || (tieViews[controller.name] = {}), | ||
pathViews = ctrlViews[pathString] || (ctrlViews[pathString] = []); | ||
if (pathViews.indexOf(element) < 0) { | ||
pathViews.push(element); | ||
update(element, controller.name); | ||
if (controller.changeDOMEventType) { | ||
addChangeListener(view, controller.changeDOMEventType); | ||
addChangeListener(element, controller.changeDOMEventType); | ||
} | ||
@@ -837,3 +918,3 @@ } | ||
if (!nlvs[key]) nlvs[key] = []; | ||
nlvs[key].push(view); | ||
nlvs[key].push(element); | ||
} | ||
@@ -856,3 +937,3 @@ } | ||
if (rootElement && (rootElement.nodeType === Node.DOCUMENT_NODE || rootElement.nodeType === Node.ELEMENT_NODE)) { | ||
let list, i; | ||
let list; | ||
if (rootElement.nodeName === 'IFRAME') { | ||
@@ -865,4 +946,3 @@ list = rootElement.contentDocument.getElementsByTagName('*'); | ||
add(rootElement); | ||
i = list.length; | ||
while (i--) add(list[i]); | ||
add(list); | ||
} | ||
@@ -992,3 +1072,2 @@ } | ||
} else if (changeType === 'childList') { | ||
// process added nodes | ||
@@ -1052,3 +1131,3 @@ added = change.addedNodes; | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -1138,3 +1217,2 @@ | ||
}); | ||
})(); | ||
@@ -1237,5 +1315,4 @@ (() => { | ||
} | ||
})(); | ||
(() => { | ||
(() => { | ||
'use strict'; | ||
@@ -1271,4 +1348,5 @@ | ||
value = view.dataset[key]; | ||
if (key.startsWith('tie') && value.startsWith(itemId)) | ||
if (key.startsWith('tie') && value.startsWith(itemId)) { | ||
relevantKeys.push([key, value.replace(itemId, '')]); | ||
} | ||
} | ||
@@ -1275,0 +1353,0 @@ if (relevantKeys.length) { |
@@ -1,1 +0,1 @@ | ||
(()=>{"use strict";const e=this||window,t=new Map,n=new Map,o=new Map,r=["Date","Blob","Number","String","Boolean","Error","SyntaxError","TypeError","URIError","Function","Promise","RegExp"];function i(e){return r.indexOf(e.constructor.name)>=0}function a(e,r){let i,a=n.get(e),l=o.get(a.root);return i="pop"===r?function(){let o,i,s,c;return o=e.length-1,i=Reflect.apply(e[r],e,arguments),(s=t.get(i))&&n.get(s).revoke(),c=[new d(a.path.concat(o),s||i)],l.notify(c),s||i}:"push"===r?function(){let t,n,o,i=[];t=Array.from(arguments),o=e.length;for(let e,n=0,r=t.length;n<r;n++)(e=t[n])&&"object"==typeof e&&(t[n]=new c(e,o+n,a).proxy),i.push(new u(a.path.concat(o+n),e));return n=Reflect.apply(e[r],e,t),l.notify(i),n}:"shift"===r?function(){let o,i,s;o=Reflect.apply(e[r],e,arguments),(s=t.get(o))&&n.get(s).revoke();for(let o,r,i=0,a=e.length;i<a;i++)(o=e[i])&&"object"==typeof o&&((r=n.get(t.get(o)))?r.ownKey=i:console.error("unexpectedly failed to resolve proxy -> target -> observed"));return i=[new d(a.path.concat(0),s||o)],l.notify(i),s||o}:"unshift"===r?function(){let o,i,s,f=[];(o=Array.from(arguments)).forEach(function(e,t){e&&"object"==typeof e&&(o[t]=new c(e,t,a).proxy)}),i=Reflect.apply(e[r],e,o);for(let o,r=0,i=e.length;r<i;r++)(o=e[r])&&"object"==typeof o&&((s=n.get(t.get(o)))?s.ownKey=r:console.error("failed to resolve proxy -> target -> observed"));for(let t=0,n=o.length;t<n;t++)f.push(new u(a.path.concat(t),e[t]));return l.notify(f),i}:"reverse"===r?function(){let o,i;Reflect.apply(e[r],e,arguments);for(let o,r=0,a=e.length;r<a;r++)(o=e[r])&&"object"==typeof o&&((i=n.get(t.get(o)))?i.ownKey=r:console.error("failed to resolve proxy -> target -> observed"));return o=[new function(){Object.defineProperties(this,{type:{value:"reverse"}})}],l.notify(o),this}:"sort"===r?function(){let o,i;Reflect.apply(e[r],e,arguments);for(let o,r=0,a=e.length;r<a;r++)(o=e[r])&&"object"==typeof o&&((i=n.get(t.get(o)))?i.ownKey=r:console.error("failed to resolve proxy -> target -> observed"));return o=[new function(){Object.defineProperties(this,{type:{value:"shuffle"}})}],l.notify(o),this}:"fill"===r?function(){let o,i,s,f=[],d=arguments.length,h=e.length;o=d<2?0:arguments[1]<0?h+arguments[1]:arguments[1],i=d<3?h:arguments[2]<0?h+arguments[2]:arguments[2],s=e.slice(),Reflect.apply(e[r],e,arguments);for(let r,l,d=o;d<i;d++)(r=e[d])&&"object"==typeof r&&(e[d]=new c(r,d,a).proxy),s.hasOwnProperty(d)?((l=t.get(s[d]))&&n.get(l).revoke(),f.push(new p(a.path.concat(d),e[d],l||s[d]))):f.push(new u(a.path.concat(d),e[d]));return l.notify(f),this}:"splice"===r?function(){let o,i,s,f,h,y,g,v,b=[],w=e.length;g=(o=Array.from(arguments)).length;for(let e,t=0;t<g;t++)e=o[t],t>1&&e&&"object"==typeof e&&(o[t]=new c(e,t,a).proxy);f=0===g?0:o[0]<0?w+o[0]:o[0],h=g<2?w-f:o[1],y=Math.max(g-2,0),i=Reflect.apply(e[r],e,o);for(let o,r=0;r<w;r++)(o=e[r])&&"object"==typeof o&&((s=n.get(t.get(o)))?s.ownKey=r:console.error("failed to resolve proxy -> target -> observed"));for(let e,o,r=0,a=i.length;r<a;r++)e=i[r],(o=t.get(e))&&(n.get(o).revoke(),i[r]=o);for(v=0;v<h;v++)v<y?b.push(new p(a.path.concat(f+v),e[f+v],i[v])):b.push(new d(a.path.concat(f+v),i[v]));for(;v<y;v++)b.push(new u(a.path.concat(f+v),e[f+v]));return l.notify(b),i}:Reflect.get(e,r)}function l(e,r,a){let l,s,f=e.hasOwnProperty(r),d=e[r],h=n.get(e),y=o.get(h.root);if((l=a&&"object"==typeof a&&!i(a)?Reflect.set(e,r,new c(a,r,h).proxy):Reflect.set(e,r,a))&&((s=t.get(d))&&n.get(s).revoke(),y.hasListeners)){let e=h.path.concat(r),t=[f?new p(e,a,s||d):new u(e,a)];h.preventCallbacks||y.notify(t)}return l}function s(e,r){let i,a,l=e[r],s=n.get(e),c=o.get(s.root);if((i=Reflect.deleteProperty(e,r))&&((a=t.get(l))&&n.get(a).revoke(),c.hasListeners)){let e=[new d(s.path.concat(r),a||l)];s.preventCallbacks||c.notify(e)}return i}function c(e,o,r){let f,u,p;if(!e||"object"!=typeof e)throw new Error("Observed MUST be created from a non null object origin");if(r&&(void 0===o||null===o))throw new Error("any non-root (parent-less) Observed MUST have an own path; now parent is "+r+"; key is "+o);if(r&&!(r instanceof c))throw new Error("parent, when supplied, MUST be an instance of Observed");var d;d=e,f=Array.isArray(d)?d.slice():Object.assign({},d),Array.isArray(f)?(!function(e,t){for(let n,o=0,r=e.length;o<r;o++)(n=e[o])&&"object"==typeof n&&!i(n)&&(e[o]=new c(n,o,t).proxy)}(f,this),u=Proxy.revocable(f,{set:l,get:a,deleteProperty:s})):(!function(e,t){let n=Object.keys(e);for(let o,r,a=0,l=n.length;a<l;a++)(r=e[o=n[a]])&&"object"==typeof r&&!i(r)&&(e[o]=new c(r,o,t).proxy)}(f,this),u=Proxy.revocable(f,{set:l,deleteProperty:s})),p=u.proxy,n.set(f,this),t.set(p,f),Object.defineProperties(this,{revokable:{value:u},proxy:{value:p},parent:{value:r},ownKey:{value:o,writable:!0}})}function f(e){let t=!1,n=[];Object.defineProperties(e.proxy,{observe:{value:function(e){if(t)throw new TypeError("revoked Observable MAY NOT be observed anymore");if("function"!=typeof e)throw new Error("observer (callback) parameter MUST be a function");n.indexOf(e)<0?n.push(e):console.info("observer (callback) may be bound to an observable only once")}},unobserve:{value:function(){if(t)throw new TypeError("revoked Observable MAY NOT be unobserved anymore");if(arguments.length)for(let e,t=0,o=arguments.length;t<o;t++)(e=n.indexOf(arguments[t]))>=0&&n.splice(e,1);else n.splice(0,n.length)}},revoke:{value:function(){t?console.log("revoking of Observable effective only once"):(t=!0,e.revoke())}}}),Object.defineProperties(this,{hasListeners:{value:function(){return n.length>0}},notify:{value:function(e){for(let t,o=0,r=n.length;o<r;o++){t=n[o];try{t(e)}catch(e){console.error("one/some of the observing callbacks failed with ",e)}}}}})}function u(e,t){Object.defineProperties(this,{type:{value:"insert"},path:{value:e},value:{value:t}})}function p(e,t,n){Object.defineProperties(this,{type:{value:"update"},path:{value:e},value:{value:t},oldValue:{value:n}})}function d(e,t){Object.defineProperties(this,{type:{value:"delete"},path:{value:e},oldValue:{value:t}})}Object.defineProperty(c.prototype,"root",{get:function(){let e=this;for(;e.parent;)e=e.parent;return e}}),Object.defineProperty(c.prototype,"path",{get:function(){let e=[],t=this;for(;void 0!==t.ownKey;)e.unshift(t.ownKey),t=t.parent;return e}}),Object.defineProperty(c.prototype,"revoke",{value:function(){let e=t.get(this.proxy),o=Object.keys(e);this.revokable.revoke();for(let r,i,a=0,l=o.length;a<l;a++)r=o[a],(i=t.get(e[r]))&&(e[r]=n.get(i).revoke());return t.delete(this.proxy),n.delete(e),e}}),Object.defineProperty(f,"from",{value:function(e){if(!e||"object"!=typeof e)throw new Error("observable MAY ONLY be created from non-null object only");if("observe"in e||"unobserve"in e||"revoke"in e)throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"');if(i(e))throw new Error(e+" found to be one of non-observable object types: "+r);let t=new c(e),n=new f(t);return o.set(t,n),t.proxy}}),Object.defineProperty(e,"Observable",{value:f})})(),(()=>{"use strict";(()=>{let e=window,t=Symbol.for("data-tier");for(;e.parent!==e;)e=e.parent;if(e[t])throw new Error("data-tier found to already being running within this application, cancelling current execution");e[t]=!0})();const e=this||window,t={};function n(e){return t[e]}function o(n,o,r){if(function(e){if(!e||"string"!=typeof e)throw new Error("tie name MUST be a non-empty string");if(/\W/.test(e))throw new Error("tie name MUST consist of alphanumerics or underlines ([a-zA-Z0-9_]) ONLY")}(n),t[n])throw new Error("existing tie ("+n+") MAY NOT be re-created, use the tie's own APIs to reconfigure it");return new function(n,o,r){let a;function l(t){e.DataTier.views.processChanges(n,t)}Reflect.defineProperty(this,"name",{value:n}),Reflect.defineProperty(this,"data",{get:function(){return a},set:function(t){let o=a,r=i(t);a&&a.revoke(),(a=r)&&a.observe(l),e.DataTier.views.processChanges(n,[{type:"update",value:a,oldValue:o,path:[]}])}}),t[n]=this,this.data=o,Object.seal(this)}(n,i(o),r)}function r(e){e&&t[e]&&(t[e].observable.revoke(),delete t[e])}function i(t){if(void 0===t||null===t)return t;if("object"!=typeof t)throw new Error(t+" is not of type Observable and not an object");if("function"==typeof t.observe&&"function"==typeof t.unobserve&&"function"==typeof t.revoke)return t;if(e.Observable){if("function"==typeof t.observe||"function"==typeof t.unobserve||"function"==typeof t.revoke)throw new Error(t+" is not of type Observable and can not be transformed into Observable (some of its functions already implemented?)");return e.Observable.from(t)}throw new Error(t+" is not of type Observable and no embedded Observable implementation found")}Reflect.defineProperty(e,"DataTier",{value:{}}),Reflect.defineProperty(e.DataTier,"ties",{value:{get get(){return n},get create(){return o},get remove(){return r}}})})(),(()=>{"use strict";const e=this||window,t={};function n(e,t){Reflect.defineProperty(this,"name",{value:e}),Object.assign(this,t)}function o(o,r){if("string"!=typeof o||!o)throw new Error("name MUST be a non-empty string");if(t[o])throw new Error('data controller "'+o+'" already exists; you may want to reconfigure the existing one');if("object"!=typeof r||!r)throw new Error("configuration MUST be a non-null object");if("function"!=typeof r.toView)throw new Error('configuration MUST have a "toView" function defined');t[o]=new n(o,r),e.DataTier.views.applyController(t[o])}function r(e){return t[e]}function i(e){if("string"!=typeof e||!e)throw new Error("controller name MUST be a non-empty string");return delete t[e]}function a(e){let n=[];return e&&e.dataset&&Object.keys(e.dataset).filter(e=>e in t).map(e=>t[e]).forEach(e=>n.push(e)),n}function l(e){let t="",n=[];return e&&(t=(n=e.trim().split(".")).shift()),{tieName:t,dataPath:n}}function s(e,t){return t.startsWith(e)}n.prototype.toData=function(e){!function(e,t,n){let o;if(!e)return;for(o=0;o<t.length-1;o++)e=e[t[o]]&&"object"==typeof e[t[o]]?e[t[o]]:e[t[o]]={};e[t[o]]=n}(e.data,e.path,e.view.value)},n.prototype.parseParam=l,n.prototype.isChangedPathRelevant=s,Reflect.defineProperty(n.prototype,"parseParam",{value:l}),Reflect.defineProperty(n.prototype,"isChangedPathRelevant",{value:s}),Reflect.defineProperty(e.DataTier,"controllers",{value:{get get(){return r},get add(){return o},get remove(){return i},get getApplicable(){return a}}})})(),(()=>{"use strict";const e=this||window;if(!e.DataTier)throw new Error("data-tier framework was not properly initialized");const t=e.DataTier.ties,n=e.DataTier.controllers,o={},r={};function i(e){let o,r,i,a,l=e.target,s=n.getApplicable(l);for(a=s.length;a--;)if(o=s[a],e.type===o.changeDOMEventType){if(r=o.parseParam(l.dataset[o.name]),i=t.get(r.tieName),!r.dataPath)return void console.error("path to data not available");if(!i)return void console.error('tie "'+r.tieName+'" not found');o.toData({data:i.data,path:r.dataPath,view:l})}}function a(e,t){e.addEventListener(t,i)}function l(e){let t;"IFRAME"===e.nodeName?(g(e.contentDocument),e.addEventListener("load",function(){g(this.contentDocument),f(this.contentDocument)}),f(e.contentDocument)):Node.ELEMENT_NODE===e.nodeType&&(t=function(e){let t;e.localName.includes("-")?t=e.localName:(t=e.getAttribute("is"))&&t.includes("-")||(t=null);return t}(e))?customElements.whenDefined(t).then(()=>s(e)):e.dataset&&s(e)}function s(e){let t,i,l,s,f,u,p,d,h=Object.keys(e.dataset);for(d=h.length;d--;)(t=h[d]).startsWith("tie")&&((i=n.get(t))?(s=(l=i.parseParam(e.dataset[i.name])).dataPath.join("."),(p=(u=(f=o[l.tieName]||(o[l.tieName]={}))[i.name]||(f[i.name]={}))[s]||(u[s]=[])).indexOf(e)<0&&(p.push(e),c(e,i.name),i.changeDOMEventType&&a(e,i.changeDOMEventType))):(r[t]||(r[t]=[]),r[t].push(e)))}function c(e,o){let r,i,a,l;i=(r=n.get(o)).parseParam(e.dataset[o]),(a=t.get(i.tieName))&&(l=function(e,t){if(e){for(let n=0,o=t.length;n<o;n++){if(!(e&&t[n]in e))return;e=e[t[n]]}return e}}(a.data,i.dataPath),r.toView(l,e))}function f(e){if(e&&(e.nodeType===Node.DOCUMENT_NODE||e.nodeType===Node.ELEMENT_NODE)){let t,n;for(t="IFRAME"===e.nodeName?e.contentDocument.getElementsByTagName("*"):e.getElementsByTagName("*"),l(e),n=t.length;n--;)l(t[n])}}function u(e){if(e&&e.getElementsByTagName){let a,l,s,c,f,u,p,d,h,y=e.getElementsByTagName("*");for(c=0,f=y.length;c<=f;c++)if((a=c<f?y[c]:e).dataset&&Object.keys(a.dataset).length)for(u=(l=n.getApplicable(a)).length;u--;)p=(s=l[u]).parseParam(a.dataset[s.name]),(h=(d=o[p.tieName][s.name][p.dataPath.join(".")]).indexOf(a))>=0&&(d.splice(h,1),s.changeDOMEventType&&(t=a,r=s.changeDOMEventType,t.removeEventListener(r,i)))}var t,r}function p(e,t,r,i){let a;if(a=n.get(t)){if(r){let i=n.get(t).parseParam(r);if(o[i.tieName]&&o[i.tieName][t]){let n=o[i.tieName][t][i.dataPath],r=-1;n&&(r=n.indexOf(e)),r>=0&&n.splice(r,1)}}if(i){let r=n.get(t).parseParam(i);o[r.tieName]||(o[r.tieName]={}),o[r.tieName][t]||(o[r.tieName][t]={}),o[r.tieName][t][r.dataPath]||(o[r.tieName][t][r.dataPath]=[]),o[r.tieName][t][r.dataPath].push(e),c(e,t)}}}function d(e,t){let r,i,a,l,s,f,u,p,d,h,y,g,v,b=o[e];if(b)for(h=t.length;h--;)for(i=(r=t[h]).path?r.path.join("."):null,y=(a=Object.keys(b)).length;y--;)if(p=b[l=a[y]])for(s=n.get(l),g=(f=Object.keys(p)).length;g--;)if(u=f[g],s.isChangedPathRelevant(i,u))for(v=(d=p[u]).length;v--;)c(d[v],l)}function h(e){r[e.name]&&(r[e.name].forEach(l),delete r[e.name])}function y(e){let t,n=2,o=e.split("-");for(t=o[1];n<o.length;)t+=o[n][0].toUpperCase()+o[n++].substr(1);return t}function g(e){new MutationObserver(function(e){let t,n,o,r,i,a,l,s;for(t=e.length;t--;)if("attributes"===(i=(r=e[t]).type)){let e=r.target,t=r.attributeName;if(e.nodeType!==Node.DOCUMENT_NODE&&e.nodeType!==Node.ELEMENT_NODE)continue;0===t.indexOf("data-tie")?p(e,y(t),r.oldValue,e.getAttribute(t)):"src"===t&&"IFRAME"===e.nodeName&&u(e.contentDocument)}else if("childList"===i){for(n=(a=r.addedNodes).length;n--;)(s=a[n]).nodeType!==Node.DOCUMENT_NODE&&s.nodeType!==Node.ELEMENT_NODE||("IFRAME"===s.nodeName?(s.contentDocument&&(g(s.contentDocument),f(s.contentDocument)),s.addEventListener("load",function(){g(this.contentDocument),f(this.contentDocument)})):f(s));for(o=(l=r.removedNodes).length;o--;)(s=l[o]).nodeType!==Node.DOCUMENT_NODE&&s.nodeType!==Node.ELEMENT_NODE||("IFRAME"===s.nodeName?u(s.contentDocument):u(s))}}).observe(e,{childList:!0,attributes:!0,characterData:!1,subtree:!0,attributeOldValue:!0,characterDataOldValue:!1})}Reflect.defineProperty(e.DataTier,"views",{value:{get processChanges(){return d},get applyController(){return h},get updateView(){return c}}}),g(document),f(document)})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;e("tieProperty",{parseParam:function(e){return this.constructor.prototype.parseParam(e?e.split("=>").shift().trim():null)},toView:(e,t)=>{t[t.dataset.tieProperty.split("=>").pop().trim()]=e}}),e("tieValue",{toView:function(e,t){"checkbox"===t.type?t.checked=e:t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"change"}),e("tieInput",{toView:function(e,t){t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"input"}),e("tieText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e:""}}),e("tiePlaceholder",{toView:function(e,t){t.placeholder=void 0!==e&&null!==e?e:""}}),e("tieTooltip",{toView:function(e,t){t.title=void 0!==e&&null!==e?e:""}}),e("tieSrc",{toView:function(e,t){t.src=void 0!==e&&null!==e?e:""}}),e("tieHref",{toView:function(e,t){t.href=void 0!==e&&null!==e?e:""}}),e("tieClasses",{isChangedPathRelevant:function(e,t){let n=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===n.length||2===n.length&&""===n[0]},toView:function(e,t){e&&"object"==typeof e&&Object.keys(e).forEach(function(n){e[n]?t.classList.add(n):t.classList.remove(n)})}})})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;function t(e){let t=e||"textContent";this.format="dd/MM/yyyy hh:mm:ss",this.toView=function(e,n){let o=e;if(e)if(e instanceof Date)o=r(e,this.format);else try{let t=new Date(e);t instanceof Date&&(o=r(t,this.format))}catch(t){console.error('failed to parse "'+e+'" as date',t)}else o="";n[t]=o}}function n(){t.call(this,"value"),this.toData=function(e){console.warn("yet to be implemented, react on "+e)}}e("tieDateValue",{toView:function(e,t){t.value=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDateText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDatetimeText",new t),e("tieDatetimeValue",new n),n.prototype=Object.create(t.prototype),n.prototype.constructor=n;let o={d:function(e,t){return e.getDate().toString().padStart(t,"0")},M:function(e,t){return(e.getMonth()+1).toString().padStart(t,"0")},y:function(e,t){let n=e.getFullYear().toString();return n.length>t?n.substr(n.length-t):n.padStart(t,"0")},h:function(e,t){return e.getHours().toString().padStart(t,"0")},m:function(e,t){return e.getMinutes().toString().padStart(t,"0")},s:function(e,t){return e.getSeconds().toString().padStart(t,"0")},f:function(e,t){return e.getMilliseconds().toString().padStart(t,"0")}};function r(e,t){let n="";if(t){let r,i;for(let a=0,l=t.length;a<l;a++)if(r=t.charAt(a),o[r]){for(i=1;a<l-1&&t.charAt(a+1)===r;)i++,a++;n+=o[r](e,i)}else n+=r}else n=e.toLocaleString();return n}})(),(()=>{"use strict";const e=this||window,t=e.DataTier.controllers.add,n=e.DataTier.views;function o(e,t,n,o,r){let i,a,l,s,c,f,u,p,d,h,y,g=null,v=o,b=n[0]+".";for(a=t.content,u=(i=function(e,t){let n,o,r,i,a,l,s={index:[]},c=e.content.querySelectorAll("*"),f=c.length;for(;f--;)if((n=c[f]).nodeType===Node.DOCUMENT_NODE||n.nodeType===Node.ELEMENT_NODE){for(r=(o=Object.keys(n.dataset)).length,l=[];r--;)i=o[r],a=n.dataset[i],i.startsWith("tie")&&a.startsWith(t)&&l.push([i,a.replace(t,"")]);l.length&&(s[f]=l,s.index.push(f))}return s}(t,n[2])).index;v<r;v++){for(p=(l=a.cloneNode(!0)).querySelectorAll("*"),s=u.length;s--;)for(d=p[f=u[s]],c=(h=i[f]).length;c--;)y=h[c][0],d.dataset[y]=b+v+h[c][1];v===o?g=l:g.appendChild(l)}e.appendChild(g)}t("tieList",{parseParam:function(e){return this.constructor.prototype.parseParam(e.split(/\s*=>\s*/)[0])},isChangedPathRelevant:function(e,t){if(!e)return!0;let n=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===n.length||2===n.length&&""===n[0]},toView:function(e,t){if(!Array.isArray(e)||!t)return;let r,i,a,l=t.parentNode,s=e.length;if("TEMPLATE"!==t.nodeName)throw new Error("tieList may be defined on template elements only");if(1!==t.content.childElementCount)throw new Error("tieList's TEMPLATE element MUST HAVE exactly one direct child element");(a=(i=t.content.firstElementChild.dataset).dtListItemAid)||(a=(new Date).getTime(),i.dtListItemAid=a);let c=l.querySelectorAll('[data-dt-list-item-aid="'+a+'"]'),f=c.length;if(f>s)for(;f>s;)l.removeChild(c[--f]);!function(e,t,o){let r,i=e.content.querySelectorAll("*"),a=[];for(r=i.length;r--;)a[r]=Object.keys(i[r].dataset).filter(e=>e.startsWith("tie"));let l,s,c,f,u,p,d=0;for(r=0;d<o;)if((c=t.childNodes[r++])!==e&&(c.nodeType===Node.DOCUMENT_NODE||c.nodeType===Node.ELEMENT_NODE)&&c.dataset.dtListItemAid){for(f=c.querySelectorAll("*"),l=a.length;l--;)for(u=l?f[l-1]:c,s=(p=a[l]).length;s--;)n.updateView(u,p[s]);d++}}(t,l,f),f<s&&o(l,t,r=function(e){let t;if(e&&(!(t=e.trim().split(/\s+/))||3!==t.length||"=>"!==t[1]))throw new Error('invalid parameter for "tieList" rule specified');return t}(t.dataset.tieList),f,s)}})})(); | ||
(()=>{"use strict";const e=this||window,t="insert",r="update",n="delete",o="reverse",a="shuffle",i=Symbol("system-observer-key"),s={Date:!0,Blob:!0,Number:!0,String:!0,Boolean:!0,Error:!0,SyntaxError:!0,TypeError:!0,URIError:!0,Function:!0,Promise:!0,RegExp:!0},l={revoke:{value:function(){this[i].revoke()}},observe:{value:function(e){let t=this[i],r=t.observers;if(t.isRevoked)throw new TypeError("revoked Observable MAY NOT be observed anymore");if("function"!=typeof e)throw new Error("observer parameter MUST be a function");r.indexOf(e)<0?r.push(e):console.info("observer may be bound to an observable only once")}},unobserve:{value:function(){let e,t,r=this[i],n=r.observers;if(r.isRevoked)throw new TypeError("revoked Observable MAY NOT be unobserved anymore");if(e=arguments.length)for(;e--;)(t=n.indexOf(arguments[e]))>=0&&n.splice(t,1);else n.splice(0)}}},c=function(e,t,r){let n,o=e.length;for(t[i]=r;o--;)(n=e[o])&&"object"==typeof n&&!s.hasOwnProperty(n.constructor.name)?t[o]=Array.isArray(n)?new h({target:n,ownKey:o,parent:r}).proxy:new y({target:n,ownKey:o,parent:r}).proxy:t[o]=n},p=function(e,t,r){let n,o,a=Object.keys(e),l=a.length;for(t[i]=r;l--;)(o=e[n=a[l]])&&"object"==typeof o&&!s.hasOwnProperty(o.constructor.name)?t[n]=Array.isArray(o)?new h({target:o,ownKey:n,parent:r}).proxy:new y({target:o,ownKey:n,parent:r}).proxy:t[n]=o},f=function(e,t){let r=e.length;for(;r--;)try{e[r](t)}catch(t){console.error("failed to deliver changes to listener"+e[r],t)}},u=function(e){let t,r=[],n=0,o=0;for(;e.parent;)r[n++]=e.ownKey,e=e.parent;for(t=new Array(n);n--;)t[o++]=r[n];return{observers:e.observers,path:t}};class h{constructor(e){let t=e.target,r=new Array(t.length);null===e.parent?(this.isRevoked=!1,this.observers=[],Object.defineProperties(r,l)):(this.parent=e.parent,this.ownKey=e.ownKey),c(t,r,this),this.revokable=Proxy.revocable(r,this),this.proxy=this.revokable.proxy,this.target=r}revoke(){this.revokable.revoke();let e,t=this.target,r=t.length;for(;r--;)if((e=t[r])&&"object"==typeof e){let n=e[i];n&&(t[r]=n.revoke())}return t}get(e,l){const c={pop:function(e,t){let r,o;if(r=e.length-1,(o=e.pop())&&"object"==typeof o){let e=o[i];e&&(o=e.revoke())}let a=u(t);return a.observers.length&&(a.path.push(r),f(a.observers,[{type:n,path:a.path,oldValue:o}])),o},push:function(e,r){let n,o,a,i,l,c=arguments.length-2,p=new Array(c),d=u(r);for(l=e.length,n=0;n<c;n++)(o=arguments[n+2])&&"object"==typeof o&&!s.hasOwnProperty(o.constructor.name)&&(o=Array.isArray(o)?new h({target:o,ownKey:l+n,parent:r}).proxy:new y({target:o,ownKey:l+n,parent:r}).proxy),p[n]=o;if(a=Reflect.apply(e.push,e,p),d.observers.length){for(i=[],n=l,c=e.length;n<c;n++){let r=d.path.slice(0);r.push(n),i[n-l]={type:t,path:r,value:e[n]}}f(d.observers,i)}return a},shift:function(e,t){let r,o,a,s,l,c;if((r=e.shift())&&"object"==typeof r){let e=r[i];e&&(r=e.revoke())}for(o=0,a=e.length;o<a;o++)if((s=e[o])&&"object"==typeof s){let e=s[i];e&&(e.ownKey=o)}return(l=u(t)).observers.length&&(l.path.push(0),c=[{type:n,path:l.path,oldValue:r}],f(l.observers,c)),r},unshift:function(e,r){let n,o,a,l;(n=Array.from(arguments)).splice(0,2),n.forEach((e,t)=>{e&&"object"==typeof e&&!s.hasOwnProperty(e.constructor.name)&&(n[t]=Array.isArray(e)?new h({target:e,ownKey:t,parent:r}).proxy:new y({target:e,ownKey:t,parent:r}).proxy)}),o=Reflect.apply(e.unshift,e,n);for(let t,r=0,n=e.length;r<n;r++)if((t=e[r])&&"object"==typeof t){let e=t[i];e&&(e.ownKey=r)}if((a=u(r)).observers.length){let r,o=n.length;l=new Array(o);for(let n=0;n<o;n++)(r=a.path.slice(0)).push(n),l[n]={type:t,path:r,value:e[n]};f(a.observers,l)}return o},reverse:function(e,t){let r,n,a,s,l;for(e.reverse(),r=0,n=e.length;r<n;r++)if((a=e[r])&&"object"==typeof a){let e=a[i];e&&(e.ownKey=r)}return(s=u(t)).observers.length&&(l=[{type:o,path:s.path}],f(s.observers,l)),t.proxy},sort:function(e,t,r){let n,o,s,l,c;for(e.sort(r),n=0,o=e.length;n<o;n++)if((s=e[n])&&"object"==typeof s){let e=s[i];e&&(e.ownKey=n)}return(l=u(t)).observers.length&&(c=[{type:a,path:l.path}],f(l.observers,c)),t.proxy},fill:function(e,n){let o,a,l,c,p,d,g=u(n),v=[],b=e.length;(o=Array.from(arguments)).splice(0,2),l=(a=o.length)<2?0:o[1]<0?b+o[1]:o[1],c=a<3?b:o[2]<0?b+o[2]:o[2],p=e.slice(0),Reflect.apply(e.fill,e,o);for(let o,a,f=l;f<c;f++)if((o=e[f])&&"object"==typeof o&&!s.hasOwnProperty(o.constructor.name)&&(e[f]=Array.isArray(o)?new h({target:o,ownKey:f,parent:n}).proxy:new y({target:o,ownKey:f,parent:n}).proxy),p.hasOwnProperty(f)){if((a=p[f])&&"object"==typeof a){let e=a[i];e&&(a=e.revoke())}(d=g.path.slice(0)).push(f),v.push({type:r,path:d,value:e[f],oldValue:a})}else(d=g.path.slice(0)).push(f),v.push({type:t,path:d,value:e[f]});return g.observers.length&&f(g.observers,v),n.proxy},splice:function(e,o){let a,l,c,p,d,g,v,b,w,m,E=u(o),O=[],N=e.length;(a=Array.from(arguments)).splice(0,2),v=a.length;for(let e,t=2;t<v;t++)(e=a[t])&&"object"==typeof e&&!s.hasOwnProperty(e.constructor.name)&&(a[t]=Array.isArray(e)?new h({target:e,ownKey:t,parent:o}).proxy:new y({target:e,ownKey:t,parent:o}).proxy);p=0===v?0:a[0]<0?N+a[0]:a[0],d=v<2?N-p:a[1],g=Math.max(v-2,0),l=Reflect.apply(e.splice,e,a),N=e.length;for(let t,r=0;r<N;r++)(t=e[r])&&"object"==typeof t&&(c=t[i])&&(c.ownKey=r);for(b=0,w=l.length;b<w;b++)(m=l[b])&&"object"==typeof m&&(c=m[i])&&(l[b]=c.revoke());if(E.observers.length){let o,a;for(o=0;o<d;o++)(a=E.path.slice(0)).push(p+o),o<g?O.push({type:r,path:a,value:e[p+o],oldValue:l[o]}):O.push({type:n,path:a,oldValue:l[o]});for(;o<g;o++)(a=E.path.slice(0)).push(p+o),O.push({type:t,path:a,value:e[p+o]});f(E.observers,O)}return l}};return c.hasOwnProperty(l)?c[l].bind(void 0,e,this):e[l]}set(e,n,o){let a,l,c=e[n];if(o&&"object"==typeof o&&!s.hasOwnProperty(o.constructor.name)?e[n]=Array.isArray(o)?new h({target:o,ownKey:n,parent:this}).proxy:new y({target:o,ownKey:n,parent:this}).proxy:e[n]=o,c&&"object"==typeof c){let e=c[i];e&&(c=e.revoke())}return(a=u(this)).observers.length&&(a.path.push(n),l=void 0===c?[{type:t,path:a.path,value:o}]:[{type:r,path:a.path,value:o,oldValue:c}],f(a.observers,l)),!0}deleteProperty(e,t){let r,o,a=e[t];if(delete e[t]){if(a&&"object"==typeof a){let e=a[i];e&&(a=e.revoke())}return(r=u(this)).observers.length&&(r.path.push(t),o=[{type:n,path:r.path,oldValue:a}],f(r.observers,o)),!0}return!1}}class y{constructor(e){let t=e.target,r={};null===e.parent?(this.isRevoked=!1,this.observers=[],Object.defineProperties(r,l)):(this.parent=e.parent,this.ownKey=e.ownKey),p(t,r,this),this.revokable=Proxy.revocable(r,this),this.proxy=this.revokable.proxy,this.target=r}revoke(){this.revokable.revoke();let e,t,r=this.target,n=Object.keys(r),o=n.length;for(;o--;)if((t=r[e=n[o]])&&"object"==typeof t){let n=t[i];n&&(r[e]=n.revoke())}return r}set(e,n,o){let a,l,c=e[n];if(o&&"object"==typeof o&&!s.hasOwnProperty(o.constructor.name)?e[n]=Array.isArray(o)?new h({target:o,ownKey:n,parent:this}).proxy:new y({target:o,ownKey:n,parent:this}).proxy:e[n]=o,c&&"object"==typeof c){let e=c[i];e&&(c=e.revoke())}return(a=u(this)).observers.length&&(a.path.push(n),l=void 0===c?[{type:t,path:a.path,value:o}]:[{type:r,path:a.path,value:o,oldValue:c}],f(a.observers,l)),!0}deleteProperty(e,t){let r,o,a=e[t];if(delete e[t]){if(a&&"object"==typeof a){let e=a[i];e&&(a=e.revoke())}return(r=u(this)).observers.length&&(r.path.push(t),o=[{type:n,path:r.path,oldValue:a}],f(r.observers,o)),!0}return!1}}class d{constructor(){throw new Error('Observable MAY NOT be created via constructor, see "Observable.from" API')}static from(e){if(!(!e||"object"!=typeof e||s.hasOwnProperty(e.constructor.name)||"observe"in e||"unobserve"in e||"revoke"in e)){return(Array.isArray(e)?new h({target:e,ownKey:null,parent:null}):new y({target:e,ownKey:null,parent:null})).proxy}if(!e||"object"!=typeof e)throw new Error("observable MAY ONLY be created from non-null object only");if("observe"in e||"unobserve"in e||"revoke"in e)throw new Error('target object MUST NOT have nor own neither inherited properties from the following list: "observe", "unobserve", "revoke"');if(s.hasOwnProperty(e.constructor.name))throw new Error(e+" found to be one of non-observable object types: "+s)}}Object.freeze(d),Object.defineProperty(e,"Observable",{value:d})})(),(()=>{"use strict";(()=>{let e=window,t=Symbol.for("data-tier");for(;e.parent!==e;)e=e.parent;if(e[t])throw new Error("data-tier found to already being running within this application, cancelling current execution");e[t]=!0})();const e=this||window,t={};function r(e){return t[e]}function n(r,n,o){if(function(e){if(!e||"string"!=typeof e)throw new Error("tie name MUST be a non-empty string");if(/\W/.test(e))throw new Error("tie name MUST consist of alphanumerics or underlines ([a-zA-Z0-9_]) ONLY")}(r),t[r])throw new Error("existing tie ("+r+") MAY NOT be re-created, use the tie's own APIs to reconfigure it");return new function(r,n,o){let i;function s(t){e.DataTier.views.processChanges(r,t)}Reflect.defineProperty(this,"name",{value:r}),Reflect.defineProperty(this,"data",{get:function(){return i},set:function(t){if(t!==i){let n=i;(i=a(t))&&i.observe(s),e.DataTier.views.processChanges(r,[{path:[]}]),n&&n.revoke()}}}),t[r]=this,this.data=n,Object.seal(this)}(r,a(n),o)}function o(e){e&&t[e]&&(t[e].observable.revoke(),delete t[e])}function a(t){if(void 0===t||null===t)return t;if("object"!=typeof t)throw new Error(t+" is not of type Observable and not an object");if("function"==typeof t.observe&&"function"==typeof t.unobserve&&"function"==typeof t.revoke)return t;if(e.Observable){if("function"==typeof t.observe||"function"==typeof t.unobserve||"function"==typeof t.revoke)throw new Error(t+" is not of type Observable and can not be transformed into Observable (some of its functions already implemented?)");return e.Observable.from(t)}throw new Error(t+" is not of type Observable and no embedded Observable implementation found")}Reflect.defineProperty(e,"DataTier",{value:{}}),Reflect.defineProperty(e.DataTier,"ties",{value:{get get(){return r},get create(){return n},get remove(){return o}}})})(),(()=>{"use strict";const e=this||window,t={};function r(e,t){Reflect.defineProperty(this,"name",{value:e}),Object.assign(this,t)}function n(n,o){if("string"!=typeof n||!n)throw new Error("name MUST be a non-empty string");if(t[n])throw new Error('data controller "'+n+'" already exists; you may want to reconfigure the existing one');if("object"!=typeof o||!o)throw new Error("configuration MUST be a non-null object");if("function"!=typeof o.toView)throw new Error('configuration MUST have a "toView" function defined');t[n]=new r(n,o),e.DataTier.views.applyController(t[n])}function o(e){return t[e]}function a(e){if("string"!=typeof e||!e)throw new Error("controller name MUST be a non-empty string");return delete t[e]}function i(e){let r=[];return e&&e.dataset&&Object.keys(e.dataset).filter(e=>e in t).map(e=>t[e]).forEach(e=>r.push(e)),r}function s(e){let t="",r=[];return e&&(t=(r=e.trim().split(".")).shift()),{tieName:t,dataPath:r}}function l(e,t){return 0===t.indexOf(e)}r.prototype.toData=function(e){!function(e,t,r){let n;if(!e)return;for(n=0;n<t.length-1;n++)e=e[t[n]]&&"object"==typeof e[t[n]]?e[t[n]]:e[t[n]]={};e[t[n]]=r}(e.data,e.path,e.view.value)},r.prototype.parseParam=s,r.prototype.isChangedPathRelevant=l,Reflect.defineProperty(r.prototype,"parseParam",{value:s}),Reflect.defineProperty(r.prototype,"isChangedPathRelevant",{value:l}),Reflect.defineProperty(e.DataTier,"controllers",{value:{get get(){return o},get add(){return n},get remove(){return a},get getApplicable(){return i}}})})(),(()=>{"use strict";const e=this||window;if(!e.DataTier)throw new Error("data-tier framework was not properly initialized");const t=e.DataTier.ties,r=e.DataTier.controllers,n={},o={};function a(e){let n,o,a,i,s=e.target,l=r.getApplicable(s);for(i=l.length;i--;)if(n=l[i],e.type===n.changeDOMEventType){if(o=n.parseParam(s.dataset[n.name]),a=t.get(o.tieName),!o.dataPath)return void console.error("path to data not available");if(!a)return void console.error('tie "'+o.tieName+'" not found');n.toData({data:a.data,path:o.dataPath,view:s})}}function i(e){e.length||(e=[e]);for(let t=0,r=e.length;t<r;t++){let r=e[t];"IFRAME"===r.nodeName?(d(r.contentDocument),r.addEventListener("load",function(){d(this.contentDocument),c(this.contentDocument)}),c(r.contentDocument)):Node.ELEMENT_NODE===r.nodeType&&(r.localName.indexOf("-")<0&&!r.hasAttribute("is")?s(r):customElements.whenDefined(r.getAttribute("is")||r.localName).then(()=>s(r)))}}function s(e){let t=e.dataset,i=Object.keys(t),s=i.length;for(;s--;){let f=i[s];if(0!==f.indexOf("tie"))continue;let u=r.get(f);if(u){let r=u.parseParam(t[u.name]),o=r.dataPath.join("."),i=n[r.tieName]||(n[r.tieName]={}),s=i[u.name]||(i[u.name]={}),f=s[o]||(s[o]=[]);f.indexOf(e)<0&&(f.push(e),l(e,u.name),u.changeDOMEventType&&(c=e,p=u.changeDOMEventType,c.addEventListener(p,a)))}else o[f]||(o[f]=[]),o[f].push(e)}var c,p}function l(e,n){let o,a,i,s;a=(o=r.get(n)).parseParam(e.dataset[n]),(i=t.get(a.tieName))&&(s=function(e,t){if(e){for(let r,n=0,o=t.length;n<o;n++){if(r=t[n],!e||!e.hasOwnProperty(r))return;e=e[r]}return e}}(i.data,a.dataPath),o.toView(s,e))}function c(e){if(e&&(e.nodeType===Node.DOCUMENT_NODE||e.nodeType===Node.ELEMENT_NODE)){let t;t="IFRAME"===e.nodeName?e.contentDocument.getElementsByTagName("*"):e.getElementsByTagName("*"),i(e),i(t)}}function p(e){if(e&&e.getElementsByTagName){let i,s,l,c,p,f,u,h,y,d=e.getElementsByTagName("*");for(c=0,p=d.length;c<=p;c++)if((i=c<p?d[c]:e).dataset&&Object.keys(i.dataset).length)for(f=(s=r.getApplicable(i)).length;f--;)u=(l=s[f]).parseParam(i.dataset[l.name]),(y=(h=n[u.tieName][l.name][u.dataPath.join(".")]).indexOf(i))>=0&&(h.splice(y,1),l.changeDOMEventType&&(t=i,o=l.changeDOMEventType,t.removeEventListener(o,a)))}var t,o}function f(e,t,o,a){let i;if(i=r.get(t)){if(o){let a=r.get(t).parseParam(o);if(n[a.tieName]&&n[a.tieName][t]){let r=n[a.tieName][t][a.dataPath],o=-1;r&&(o=r.indexOf(e)),o>=0&&r.splice(o,1)}}if(a){let o=r.get(t).parseParam(a);n[o.tieName]||(n[o.tieName]={}),n[o.tieName][t]||(n[o.tieName][t]={}),n[o.tieName][t][o.dataPath]||(n[o.tieName][t][o.dataPath]=[]),n[o.tieName][t][o.dataPath].push(e),l(e,t)}}}function u(e,t){let o,a,i,s,c,p,f,u,h,y,d,g,v,b=n[e];if(b)for(y=t.length;y--;)for(a=(o=t[y]).path?o.path.join("."):null,d=(i=Object.keys(b)).length;d--;)if(u=b[s=i[d]])for(c=r.get(s),g=(p=Object.keys(u)).length;g--;)if(f=p[g],c.isChangedPathRelevant(a,f))for(v=(h=u[f]).length;v--;)l(h[v],s)}function h(e){o[e.name]&&(o[e.name].forEach(i),delete o[e.name])}function y(e){let t,r=2,n=e.split("-");for(t=n[1];r<n.length;)t+=n[r][0].toUpperCase()+n[r++].substr(1);return t}function d(e){new MutationObserver(function(e){let t,r,n,o,a,i,s,l;for(t=e.length;t--;)if("attributes"===(a=(o=e[t]).type)){let e=o.target,t=o.attributeName;if(e.nodeType!==Node.DOCUMENT_NODE&&e.nodeType!==Node.ELEMENT_NODE)continue;0===t.indexOf("data-tie")?f(e,y(t),o.oldValue,e.getAttribute(t)):"src"===t&&"IFRAME"===e.nodeName&&p(e.contentDocument)}else if("childList"===a){for(r=(i=o.addedNodes).length;r--;)(l=i[r]).nodeType!==Node.DOCUMENT_NODE&&l.nodeType!==Node.ELEMENT_NODE||("IFRAME"===l.nodeName?(l.contentDocument&&(d(l.contentDocument),c(l.contentDocument)),l.addEventListener("load",function(){d(this.contentDocument),c(this.contentDocument)})):c(l));for(n=(s=o.removedNodes).length;n--;)(l=s[n]).nodeType!==Node.DOCUMENT_NODE&&l.nodeType!==Node.ELEMENT_NODE||("IFRAME"===l.nodeName?p(l.contentDocument):p(l))}}).observe(e,{childList:!0,attributes:!0,characterData:!1,subtree:!0,attributeOldValue:!0,characterDataOldValue:!1})}Reflect.defineProperty(e.DataTier,"views",{value:{get processChanges(){return u},get applyController(){return h},get updateView(){return l}}}),d(document),c(document)})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;e("tieProperty",{parseParam:function(e){return this.constructor.prototype.parseParam(e?e.split("=>").shift().trim():null)},toView:(e,t)=>{t[t.dataset.tieProperty.split("=>").pop().trim()]=e}}),e("tieValue",{toView:function(e,t){"checkbox"===t.type?t.checked=e:t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"change"}),e("tieInput",{toView:function(e,t){t.value=void 0!==e&&null!==e?e:""},changeDOMEventType:"input"}),e("tieText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e:""}}),e("tiePlaceholder",{toView:function(e,t){t.placeholder=void 0!==e&&null!==e?e:""}}),e("tieTooltip",{toView:function(e,t){t.title=void 0!==e&&null!==e?e:""}}),e("tieSrc",{toView:function(e,t){t.src=void 0!==e&&null!==e?e:""}}),e("tieHref",{toView:function(e,t){t.href=void 0!==e&&null!==e?e:""}}),e("tieClasses",{isChangedPathRelevant:function(e,t){let r=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===r.length||2===r.length&&""===r[0]},toView:function(e,t){e&&"object"==typeof e&&Object.keys(e).forEach(function(r){e[r]?t.classList.add(r):t.classList.remove(r)})}})})(),(()=>{"use strict";const e=(this||window).DataTier.controllers.add;function t(e){let t=e||"textContent";this.format="dd/MM/yyyy hh:mm:ss",this.toView=function(e,r){let n=e;if(e)if(e instanceof Date)n=o(e,this.format);else try{let t=new Date(e);t instanceof Date&&(n=o(t,this.format))}catch(t){console.error('failed to parse "'+e+'" as date',t)}else n="";r[t]=n}}function r(){t.call(this,"value"),this.toData=function(e){console.warn("yet to be implemented, react on "+e)}}e("tieDateValue",{toView:function(e,t){t.value=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDateText",{toView:function(e,t){t.textContent=void 0!==e&&null!==e?e.toLocaleString():""}}),e("tieDatetimeText",new t),e("tieDatetimeValue",new r),r.prototype=Object.create(t.prototype),r.prototype.constructor=r;let n={d:function(e,t){return e.getDate().toString().padStart(t,"0")},M:function(e,t){return(e.getMonth()+1).toString().padStart(t,"0")},y:function(e,t){let r=e.getFullYear().toString();return r.length>t?r.substr(r.length-t):r.padStart(t,"0")},h:function(e,t){return e.getHours().toString().padStart(t,"0")},m:function(e,t){return e.getMinutes().toString().padStart(t,"0")},s:function(e,t){return e.getSeconds().toString().padStart(t,"0")},f:function(e,t){return e.getMilliseconds().toString().padStart(t,"0")}};function o(e,t){let r="";if(t){let o,a;for(let i=0,s=t.length;i<s;i++)if(o=t.charAt(i),n[o]){for(a=1;i<s-1&&t.charAt(i+1)===o;)a++,i++;r+=n[o](e,a)}else r+=o}else r=e.toLocaleString();return r}})(),(()=>{"use strict";const e=this||window,t=e.DataTier.controllers.add,r=e.DataTier.views;function n(e,t,r,n,o){let a,i,s,l,c,p,f,u,h,y,d,g=null,v=n,b=r[0]+".";for(i=t.content,f=(a=function(e,t){let r,n,o,a,i,s,l={index:[]},c=e.content.querySelectorAll("*"),p=c.length;for(;p--;)if((r=c[p]).nodeType===Node.DOCUMENT_NODE||r.nodeType===Node.ELEMENT_NODE){for(o=(n=Object.keys(r.dataset)).length,s=[];o--;)a=n[o],i=r.dataset[a],a.startsWith("tie")&&i.startsWith(t)&&s.push([a,i.replace(t,"")]);s.length&&(l[p]=s,l.index.push(p))}return l}(t,r[2])).index;v<o;v++){for(u=(s=i.cloneNode(!0)).querySelectorAll("*"),l=f.length;l--;)for(h=u[p=f[l]],c=(y=a[p]).length;c--;)d=y[c][0],h.dataset[d]=b+v+y[c][1];v===n?g=s:g.appendChild(s)}e.appendChild(g)}t("tieList",{parseParam:function(e){return this.constructor.prototype.parseParam(e.split(/\s*=>\s*/)[0])},isChangedPathRelevant:function(e,t){if(!e)return!0;let r=e.replace(t,"").split(".");return this.constructor.prototype.isChangedPathRelevant(e,t)||1===r.length||2===r.length&&""===r[0]},toView:function(e,t){if(!Array.isArray(e)||!t)return;let o,a,i,s=t.parentNode,l=e.length;if("TEMPLATE"!==t.nodeName)throw new Error("tieList may be defined on template elements only");if(1!==t.content.childElementCount)throw new Error("tieList's TEMPLATE element MUST HAVE exactly one direct child element");(i=(a=t.content.firstElementChild.dataset).dtListItemAid)||(i=(new Date).getTime(),a.dtListItemAid=i);let c=s.querySelectorAll('[data-dt-list-item-aid="'+i+'"]'),p=c.length;if(p>l)for(;p>l;)s.removeChild(c[--p]);!function(e,t,n){let o,a=e.content.querySelectorAll("*"),i=[];for(o=a.length;o--;)i[o]=Object.keys(a[o].dataset).filter(e=>e.startsWith("tie"));let s,l,c,p,f,u,h=0;for(o=0;h<n;)if((c=t.childNodes[o++])!==e&&(c.nodeType===Node.DOCUMENT_NODE||c.nodeType===Node.ELEMENT_NODE)&&c.dataset.dtListItemAid){for(p=c.querySelectorAll("*"),s=i.length;s--;)for(f=s?p[s-1]:c,l=(u=i[s]).length;l--;)r.updateView(f,u[l]);h++}}(t,s,p),p<l&&n(s,t,o=function(e){let t;if(e&&(!(t=e.trim().split(/\s+/))||3!==t.length||"=>"!==t[1]))throw new Error('invalid parameter for "tieList" rule specified');return t}(t.dataset.tieList),p,l)}})})(); |
{ | ||
"name": "data-tier", | ||
"version": "0.6.19", | ||
"main": "dist/data-tier.js", | ||
"files": [ | ||
"dist" | ||
], | ||
"scripts": { | ||
"concat": "node -e 'require(./tools/build-concat.js).execute()'", | ||
"minify": "node -e 'require(./tools/build-minify.js).execute()'", | ||
"build": "npm run concat && npm run minify" | ||
}, | ||
"version": "0.6.20", | ||
"description": "Tiny and fast two way (MV-VM) data binding framework for browser environments.", | ||
@@ -29,2 +20,12 @@ "keywords": [ | ||
], | ||
"homepage": "https://github.com/gullerya/data-tier", | ||
"bugs": { | ||
"url": "https://github.com/gullerya/data-tier/issues", | ||
"email": "gullerya@gmail.com" | ||
}, | ||
"license": "MIT", | ||
"files": [ | ||
"dist" | ||
], | ||
"main": "dist/data-tier.min.js", | ||
"author": { | ||
@@ -38,20 +39,21 @@ "name": "Guller Yuri", | ||
}, | ||
"homepage": "https://github.com/gullerya/data-tier/README.md", | ||
"scripts": { | ||
"eslint": "eslint -c ./build/.eslintrc.json ./src/**/*.js", | ||
"build": "node ./build/tools/build-dist.js" | ||
}, | ||
"dependencies": { | ||
"object-observer": "^0.2.6" | ||
"object-observer": "^1.1.2", | ||
"@gullerya/observable": "^1.1.2" | ||
}, | ||
"devDependencies": { | ||
"adm-zip": "^0.4.7", | ||
"grunt": "^1.0.2", | ||
"grunt-cli": "^1.2.0", | ||
"eslint": "^5.6.1", | ||
"eslint-plugin-node": "^7.0.1", | ||
"eslint-plugin-import": "^2.14.0", | ||
"eslint-plugin-promise": "^4.0.1", | ||
"eslint-plugin-standard": "^4.0.0", | ||
"eslint-config-standard": "^12.0.0", | ||
"fs-extra": "^7.0.0", | ||
"uglify-es": "^3.3.9", | ||
"babel-eslint": "^8.2.2", | ||
"eslint-plugin-react": "^7.7.0", | ||
"gruntify-eslint": "^4.0.0" | ||
}, | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/gullerya/data-tier/issues", | ||
"email": "gullerya@gmail.com" | ||
"just-test": "^0.1.0" | ||
} | ||
} |
139
README.md
@@ -1,2 +0,3 @@ | ||
[![npm version](https://badge.fury.io/js/data-tier.svg)](https://badge.fury.io/js/data-tier) | ||
[![GitHub](https://img.shields.io/github/license/gullerya/data-tier.svg)](https://github.com/gullerya/data-tier) | ||
[![npm](https://img.shields.io/npm/v/data-tier.svg?label=npm%20data-tier)](https://www.npmjs.com/package/data-tier) | ||
[![Build Status](https://travis-ci.org/gullerya/data-tier.svg?branch=master)](https://travis-ci.org/gullerya/data-tier) | ||
@@ -7,32 +8,39 @@ | ||
`data-tier` ('tier' from 'to tie') is a two way binding (MVVM) service targeting client (browser) HTML/Javascript applications. | ||
`data-tier.js` relies on an [`Observable`](https://github.com/gullerya/object-observer-js#observable-static-properties)-driven event cycle, having an embedded [`object-observer`](https://github.com/gullerya/object-observer-js) as the default `Observable` provider. | ||
`data-tier` relies on an [`Observable`](https://github.com/gullerya/object-observer/blob/master/docs/observable.md)-driven event cycle, having an embedded [`object-observer`](https://github.com/gullerya/object-observer) as the default `Observable` provider. | ||
It is possible to provide custom `Observable` implementation. In this case you may want to use lighter `data-tier-wo-oo.js` where `object-observer.js` opted out. | ||
#### Support matrix: ![CHROME](tools/browser_icons/chrome.png) <sub>49+</sub> | ![FIREFOX](tools/browser_icons/firefox.png) <sub>44+</sub> | ![EDGE](tools/browser_icons/edge.png) <sub>13+</sub> | ||
Support matrix is currently as wide as that of [`object-observer`](https://github.com/gullerya/object-observer-js), assuming that in most of the cases consumers will not provide their own object observer, but will use an embedded one. | ||
#### Support matrix: ![CHROME](https://github.com/gullerya/data-tier/blob/master/docs/icons/chrome.png) <sub>49+</sub> | ![FIREFOX](https://github.com/gullerya/data-tier/blob/master/docs/icons/firefox.png) <sub>44+</sub> | ![EDGE](https://github.com/gullerya/data-tier/blob/master/docs/icons/edge.png) <sub>13+</sub> | ||
Support matrix is currently as wide as that of [`object-observer`](https://github.com/gullerya/object-observer), assuming that in most of the cases consumers will not provide their own object observer, but will use an embedded one. | ||
`data-tier` supports custom elements as well, obviously this functionality is available only on supporting environments. | ||
#### Versions | ||
> IMPORTANT! Starting with 0.6.20 version `data-tier` as ES6 module becomes available. | ||
Yet, this one comes with API breaking changes as it is reflecting somewhat different approach to the architecture or data binding in web applications. | ||
Read more on [this new API page](https://github.com/gullerya/data-tier/blob/master/new-readme.md). | ||
- __0.6.19__ | ||
- Fixed incorrect behavior when `tie-property` configured on the element **after** it was added to the DOM | ||
#### Versions ([full changelog](https://github.com/gullerya/data-tier/blob/master/docs/changelog.md)) | ||
- __0.6.18__ | ||
- Fixed [issue no. 12](https://github.com/gullerya/data-tier/issues/12) | ||
* __0.6.20__ | ||
* initial provisioning of `data-tier` as ES6 module | ||
* new API defined and implemented in ES6 module distribution | ||
- __0.6.17__ | ||
- Added `tie-property` OOTB controller - having parameter syntax `path.to.data => propName` it is made possible to tie to arbitrary element property (yes, this is having `CustomElements` in mind) | ||
* __0.6.19__ | ||
* Fixed incorrect behavior when `tie-property` configured on the element **after** it was added to the DOM | ||
- __0.6.16__ | ||
- Fixed potential issue with empty (`null`) object traversal in deep tying | ||
* __0.6.18__ | ||
* Fixed [issue no. 12](https://github.com/gullerya/data-tier/issues/12) | ||
- __0.6.15__ | ||
- Fixed [issue no. 11](https://github.com/gullerya/data-tier/issues/11) | ||
- Moved most of the changes [here](changelog.md), while here will be shown only a most recent versions | ||
## Loading the Library | ||
You have few ways to load the library: as an __ES6 module__ (pay attention to the __`module`__ in the path) or as a __regular script__ (into a 'window' global scope, or a custom scope provided by you). See examples below. | ||
## Loading the Library | ||
> Attention: in some (observable :-)) future non-module syntax flavor will be frozen in a stable state and only defect fixes will be done there. | ||
Active development will focus on the ES6 module code base, which is effectively raising the support matrix of Chrome to 61, FireFox to 60 and Edge to 16. | ||
Also pay attention, that ES6 module styled library bear also significant API changes, see remark above in this page and elsewhere. | ||
There are 2 ways to load the library: into a `window` global scope, or a custom scope provided by you. | ||
* ES6 module (__preferred__): | ||
```javascript | ||
// browser | ||
import * as DataTier from 'dist/module/data-tier.min.js'; | ||
``` | ||
@@ -43,12 +51,12 @@ * Simple reference (script tag) to the `data-tier.js`/`data-tier.min.js` in your HTML will load it into the __global scope__: | ||
<script> | ||
let person = { name: 'Uriya', age: 8 }; | ||
DataTier.ties.create('person', person); | ||
DataTier.ties.create('settings'); | ||
let person = { name: 'Uriya', age: 8 }, | ||
tiedPerson = DataTier.ties.create('person', person), | ||
tiedSettings = DataTier.ties.create('settings'); | ||
</script> | ||
``` | ||
<sup><sub> | ||
* __tie__ `person` has its `data` property set to `Observable.from(person)`, original `person` object remains untouched and its own changes __aren't__ being watched | ||
* __tie__ `settings` has its `data` as `null`, it may be set to any object later on | ||
</sub></sup> | ||
> __tie__ `person` has its `data` property set to `Observable.from(person)`, original `person` object remains untouched and its own changes __aren't__ being watched. | ||
In order to make a changes on a tied object and see an immediate reflection in the UI use `tiedPerson.data` object. | ||
> __tie__ `settings` has its `data` as `null`, it may be set to any object later on in this way: `tiedSettings.data = {}` (or any other arbitrary data structure). | ||
* The snippet below exemplifies how to load the library into a __custom scope__ (add error handling as appropriate): | ||
@@ -60,10 +68,10 @@ ```javascript | ||
fetch('data-tier.min.js').then(function (response) { | ||
if (response.status === 200) { | ||
response.text().then(function (code) { | ||
Function(code).call(customNamespace); | ||
// the below code is an example of consumption, locate it in your app lifecycle/flow as appropriate | ||
customNamespace.DataTier.ties.create('person', person); | ||
}); | ||
} | ||
if (response.status === 200) { | ||
response.text().then(function (code) { | ||
Function(code).call(customNamespace); | ||
// the below code is an example of consumption, locate it in your app lifecycle/flow as appropriate | ||
customNamespace.DataTier.ties.create('person', person); | ||
}); | ||
} | ||
}); | ||
@@ -77,3 +85,3 @@ ``` | ||
My, definitely opinionated, insights of how client application should look like in general and how `data-tier` library comes into that picture can be found [__here__](docs/client-app-architecture.md). That would probably be the most completed overview of the library's overall usage intent. | ||
My, definitely opinionated, insights of how client application should look like in general and how `data-tier` library comes into that picture can be found [__here__](https://github.com/gullerya/data-tier/blob/master/docs/client-app-architecture.md). That would probably be the most completed overview of the library's overall usage intent. | ||
@@ -84,2 +92,5 @@ Here I'll just outline the very essentials, namely 2 main concepts: __`Tie`__ and __`Controller`__. | ||
#### Tie | ||
> This part of the API will undergo slight change (mostly in the syntax of HTML part declaration) in the ES6 module approach. | ||
See [new api](https://github.com/gullerya/data-tier/blob/master/new-readme.md) for more info. | ||
__`Tie`__ holds an observable data structure associated with tie's name, it's about __what__ to tie. | ||
@@ -91,11 +102,11 @@ Thus, ties serve most and foremost data segregation and management purposes. | ||
let bands = [ | ||
{ | ||
id: 1234, | ||
name: 'Dream Theater', | ||
since: 1985, | ||
albums: [ | ||
{ id: 2345, name: 'When Dream and Day Unite', since: 1988 }, | ||
{ id: 2346, name: 'Images and Words', since: 1991 } | ||
] | ||
} | ||
{ | ||
id: 1234, | ||
name: 'Dream Theater', | ||
since: 1985, | ||
albums: [ | ||
{ id: 2345, name: 'When Dream and Day Unite', since: 1988 }, | ||
{ id: 2346, name: 'Images and Words', since: 1991 } | ||
] | ||
} | ||
]; | ||
@@ -112,17 +123,17 @@ bands.totalTooltip = generateTooltipText(); | ||
<span data-tie-text="bandsTie.length" | ||
data-tie-tooltip="bandsTie.totalTooltip"> | ||
data-tie-tooltip="bandsTie.totalTooltip"> | ||
</span> | ||
<div> | ||
<template data-tie-list="bandsTie.0.albums => album"> | ||
<span data-tie-text="album.name"></span> | ||
</template> | ||
<template data-tie-list="bandsTie.0.albums => album"> | ||
<span data-tie-text="album.name"></span> | ||
</template> | ||
</div> | ||
``` | ||
where: | ||
- the first item in the path is always the tie's name | ||
- `bandsTie.0` - refer to the whole object at index 0 of our array | ||
- `bandsTie.length` - `length` property, inherited from the native `Array`, may also be used | ||
- `bandsTie.0.name` - path can get deeper... | ||
- `bandsTie.0.albums.1.since` - ...actually, it can get to any level of deepness | ||
* the first item in the path is always the tie's name | ||
* `bandsTie.0` - refer to the whole object at index 0 of our array | ||
* `bandsTie.length` - `length` property, inherited from the native `Array`, may also be used | ||
* `bandsTie.0.name` - path can get deeper... | ||
* `bandsTie.0.albums.1.since` - ...actually, it can get to any level of deepness | ||
@@ -133,6 +144,9 @@ Basically, it is possible to create a single dataset for the whole application, making a single 'uber-tie' from it and operating everything from there, but it should be considered as a bad practice. | ||
`Tie` object not only meant to hold the link between the data and its namespace, but also tie's specific configurations/customizations and data management APIs. | ||
For more details see [__API reference__](docs/api-reference.md). | ||
For more details see [__API reference__](https://github.com/gullerya/data-tier/blob/master/docs/api-reference.md). | ||
#### Controller | ||
> This part of the API will undergo significant change (mostly removal) in the ES6 module approach and eventually will become deprecated. | ||
See [new api](https://github.com/gullerya/data-tier/blob/master/new-readme.md) for more info. | ||
__`Controller`__ is a holder of the transition logic, it's about __how__ to translate the data from/to view/data. | ||
@@ -144,9 +158,9 @@ | ||
<span data-tie-text="bandsTie.length" | ||
data-tie-tooltip="bandsTie.totalTooltip"> | ||
data-tie-tooltip="bandsTie.totalTooltip"> | ||
</span> | ||
<div> | ||
<template data-tie-list="bandsTie.0.albums => album"> | ||
<span data-tie-text="album.name"></span> | ||
</template> | ||
<template data-tie-list="bandsTie.0.albums => album"> | ||
<span data-tie-text="album.name"></span> | ||
</template> | ||
</div> | ||
@@ -160,14 +174,9 @@ ``` | ||
OOTB provided controllers reviewed in the [__Controllers reference__](docs/controllers-reference.md). | ||
This set will eventually be updated and enhanced. | ||
But even more important is the fact, that any custom controllers may be provided by the consuming application. | ||
This can be done at any phase of application's lifecycle, so that there is no special ceremony around it whatsoever. | ||
Controllers' management described in the relevant section in [__API reference__](docs/api-reference.md). | ||
Controllers' management described in the relevant section in [__API reference__](https://github.com/gullerya/data-tier/blob/master/docs/api-reference.md). | ||
## Documentation | ||
[__Tutorials__](docs/tutorials.md) | ||
[__New `data-tier`__](https://github.com/gullerya/data-tier/blob/master/new-readme.md) | ||
[__API reference__](docs/api-reference.md) | ||
[__OOTB Controllers reference__](docs/controllers-reference.md) | ||
[__Tutorials__](https://github.com/gullerya/data-tier/blob/master/docs/tutorials.md) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
163264
11
3018
1
173
2
9
+ Added@gullerya/observable@^1.1.2
+ Addedobject-observer@1.2.0(transitive)
- Removedobject-observer@0.2.6(transitive)
Updatedobject-observer@^1.1.2