UNPKG

ajsfw

Version:
469 lines (468 loc) 24.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var logger = require("ajsfw/dbg/logger"); var utils = require("ajsfw/utils"); var exceptions = require("./exceptions"); var DocumentManager = (function () { function DocumentManager(resourceManager, renderTarget) { logger.log(logger.LogType.Constructor, 0, "ajs.doc", this); if (renderTarget === undefined || renderTarget === null) { logger.log(logger.LogType.Warning, 0, "ajs.doc", this, "Render target not set or does not exist in the document. Using document.body"); renderTarget = document.body; } logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Managing the DOM document", renderTarget.ownerDocument); this.__resourceManager = resourceManager; this.__renderTarget = renderTarget; this.__targetDocument = renderTarget.ownerDocument; this.__styleSheets = []; this.__touchEventsCount = 0; logger.log(logger.LogType.Exit, 0, "ajs.doc", this); } Object.defineProperty(DocumentManager.prototype, "renderTarget", { get: function () { return this.__renderTarget; }, enumerable: true, configurable: true }); Object.defineProperty(DocumentManager.prototype, "_uniqeId", { get: function () { this.__uniqueId++; return this.__uniqueId; }, enumerable: true, configurable: true }); ; DocumentManager.prototype.clean = function (renderTarget) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Cleaning up the target document and render target", this.__targetDocument, renderTarget); if (renderTarget.ownerDocument !== this.__targetDocument) { logger.log(logger.LogType.Error, 0, "ajs.doc", this, "Render target is not contained in the managed document", this.__targetDocument, renderTarget); throw new exceptions.RenderTargetNotInManagedDocumentException(); } var styleSheets = this.__targetDocument.head.getElementsByTagName("style"); for (var i = 0; i < styleSheets.length; i++) { if (styleSheets.item(i).hasAttribute("id") && this.__styleSheets.indexOf(styleSheets.item(i).getAttribute("id")) !== -1) { this.__targetDocument.head.removeChild(styleSheets.item(i)); } } this.__styleSheets = []; function removeTree(node) { for (var i = 0; i < node.childNodes.length; i++) { removeTree(node.childNodes.item(i)); } if (node.ajsData && node.ajsData.eventListeners) { for (var i = 0; i < node.ajsData.eventListeners.length; i++) { node.removeEventListener(node.ajsData.eventListeners[i].eventType, node.ajsData.eventListeners[i].eventListener); } node.ajsData = null; delete node.ajsData; } node.parentNode.removeChild(node); } for (var i = 0; i < this.__renderTarget.childNodes.length; i++) { removeTree(this.__renderTarget.childNodes.item(i)); } renderTarget.innerHTML = ""; logger.log(logger.LogType.Exit, 0, "ajs.doc", this); }; DocumentManager.prototype.updateDom = function (source, target) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Updating DOM structure", source, target); if (target.ownerDocument !== this.__targetDocument) { logger.log(logger.LogType.Error, 0, "ajs.doc", this, "Render target is not contained in the managed document", this.__targetDocument, target); throw new exceptions.RenderTargetNotInManagedDocumentException(); } var src = source; var tgt = target; if (src.ajsData && (!tgt.ajsData || src.ajsData.component !== tgt.ajsData.component)) { if (target !== undefined && target !== null && target.parentNode !== undefined && target.parentNode !== null) { var nodeToUpdate = this._findSameComponent(src, tgt); if (nodeToUpdate === null) { if (target === this.__renderTarget) { nodeToUpdate = this._appendNode(src, tgt); } else { nodeToUpdate = this._insertBefore(src, tgt); } } this.updateDom(src, nodeToUpdate); } else { logger.log(logger.LogType.Error, 0, "ajs.doc", this, "Target or its parent is unknown!", this.__targetDocument, target); throw new exceptions.TargetOrParentIsUnknownException(); } } else { if (src.ajsData === undefined || !src.ajsData.skipUpdate) { if (src.nodeName !== tgt.nodeName) { var adoptedNode = this._replaceNode(src, tgt); this.updateDom(source, adoptedNode); return; } if (src.nodeName === "ASHTML") { try { var adoptedNode = this._replaceNode(src, tgt, true); var srcAhrefs = src.getElementsByTagName("a"); var tgtAhrefs = adoptedNode.getElementsByTagName("a"); for (var i = 0; i < srcAhrefs.length; i++) { this._registerEventListeners(srcAhrefs.item(i), tgtAhrefs.item(i)); } return; } catch (e) { console.error(e); } } this._updateNodeAttributes(src, tgt); this._updateChildren(src, tgt); while (source.childNodes.length < target.childNodes.length) { tgt.removeChild(tgt.childNodes.item(src.childNodes.length)); } } } }; DocumentManager.prototype.getTargetNodeByUniqueId = function (id) { function searchNode(nodeId, tgtNode) { if (tgtNode.ajsData && tgtNode.ajsData.component && tgtNode.ajsData.component.componentViewId === nodeId) { return tgtNode; } for (var i = 0; i < tgtNode.childNodes.length; i++) { var node = searchNode(nodeId, tgtNode.childNodes.item(i)); if (node !== null) { return node; } } return null; } return searchNode(id, this.__targetDocument.body); }; DocumentManager.prototype.removeNodeByUniqueId = function (id) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Removing the target node by assigned to the source node " + id); var node = this.getTargetNodeByUniqueId(id); if (node !== null) { this.removeNode(node); } logger.log(logger.LogType.Exit, 0, "ajs.doc", this); }; DocumentManager.prototype._findSameComponent = function (src, tgt) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Looking for the same component", src, tgt); if (src.ajsData !== undefined && src.ajsData.component !== undefined) { for (var i = 0; i < tgt.parentNode.childNodes.length; i++) { var targetNode = tgt.parentNode.childNodes.item(i); if (targetNode.ajsData && targetNode.ajsData.component === src.ajsData.component) { logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Component found", tgt.parentNode.childNodes.item(i)); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return tgt.parentNode.childNodes.item(i); } } } logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Component not found"); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return null; }; DocumentManager.prototype._updateChildren = function (src, tgt) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Updating children node", src, tgt); for (var i = 0; i < src.childNodes.length; i++) { var child = void 0; if (i < tgt.childNodes.length) { child = tgt.childNodes.item(i); } else { try { if (src.childNodes.item(i).nodeName === "ASHTML") { var adoptedNode = this._appendNode(src.childNodes.item(i), tgt, true); var srcAhrefs = src.getElementsByTagName("a"); var tgtAhrefs = adoptedNode.getElementsByTagName("a"); for (var i_1 = 0; i_1 < srcAhrefs.length; i_1++) { this._registerEventListeners(srcAhrefs.item(i_1), tgtAhrefs.item(i_1)); } continue; } } catch (e) { console.error(e); } child = this._appendNode(src.childNodes.item(i), tgt); } this.updateDom(src.childNodes.item(i), child); } logger.log(logger.LogType.Exit, 0, "ajs.doc", this); }; DocumentManager.prototype._appendNode = function (src, tgt, innerHTML) { if (innerHTML === void 0) { innerHTML = false; } logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.DomAppendChild, 0, "ajs.doc", this, "Appending new node", src, tgt); var clonedNode = src.cloneNode(false); var adoptedNode = tgt.ownerDocument.adoptNode(clonedNode); if (innerHTML) { adoptedNode.innerHTML = src.innerHTML; } this._setNodeMetadata(src, adoptedNode); this._adoptStrangeAttributes(adoptedNode); this._registerEventListeners(src, adoptedNode); tgt.appendChild(adoptedNode); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return adoptedNode; }; DocumentManager.prototype._insertBefore = function (src, tgt, innerHTML) { if (innerHTML === void 0) { innerHTML = false; } logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.DomAppendChild, 0, "ajs.doc", this, "Inserting new node before", src, tgt); var clonedNode = src.cloneNode(false); var adoptedNode = tgt.ownerDocument.adoptNode(clonedNode); if (innerHTML) { adoptedNode.innerHTML = src.innerHTML; } this._setNodeMetadata(src, adoptedNode); this._adoptStrangeAttributes(adoptedNode); this._registerEventListeners(src, adoptedNode); tgt.parentNode.insertBefore(adoptedNode, tgt); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return adoptedNode; }; DocumentManager.prototype._replaceNode = function (src, tgt, innerHTML) { if (innerHTML === void 0) { innerHTML = false; } logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.DomReplaceChild, 0, "ajs.doc", this, "Replacing target node with source node", src, tgt); if (tgt.ajsData) { if (tgt.ajsData.eventListeners instanceof Array) { for (var i = 0; i < tgt.ajsData.eventListeners.length; i++) { tgt.removeEventListener(tgt.ajsData.eventListeners[i].eventType, tgt.ajsData.eventListeners[i].eventListener); } } tgt.ajsData = null; delete (tgt.ajsData); } var clonedNode = src.cloneNode(false); var adoptedNode = tgt.ownerDocument.adoptNode(clonedNode); if (innerHTML) { adoptedNode.innerHTML = src.innerHTML; } this._adoptStrangeAttributes(adoptedNode); this._setNodeMetadata(src, adoptedNode); this._registerEventListeners(src, adoptedNode); tgt.parentNode.replaceChild(adoptedNode, tgt); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return adoptedNode; }; DocumentManager.prototype.removeNode = function (target) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Removing the target node", target); if (!target || target === null) { logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return; } if (target.ownerDocument !== this.__targetDocument) { logger.log(logger.LogType.Error, 0, "ajs.doc", this, "Render target is not contained in the managed document", this.__targetDocument, target); throw new exceptions.RenderTargetNotInManagedDocumentException(); } for (var i = 0; i < target.childNodes.length; i++) { this.removeNode(target.childNodes.item(i)); } var tgt = target; if (tgt.ajsData) { if (tgt.ajsData.eventListeners instanceof Array) { for (var i = 0; i < tgt.ajsData.eventListeners.length; i++) { tgt.removeEventListener(tgt.ajsData.eventListeners[i].eventType, tgt.ajsData.eventListeners[i].eventListener); } } tgt.ajsData = null; delete (tgt.ajsData); } if (tgt.parentNode !== null) { tgt.parentNode.removeChild(tgt); } logger.log(logger.LogType.Exit, 0, "ajs.doc", this); }; DocumentManager.prototype._updateNodeAttributes = function (source, target) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Updating node attributes", source, target); if (source.nodeType === Node.ELEMENT_NODE) { var i = 0; while (i < target.attributes.length) { if (!source.hasAttribute(target.attributes.item(i).nodeName)) { logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Removing attribute ", target.attributes.item(i).nodeName); try { target.attributes.removeNamedItem(target.attributes.item(i).nodeName); } catch (e) { logger.log(logger.LogType.Error, 0, "ajs.doc", this, "Removing attribute " + target.attributes.item(i).nodeName + " failed."); break; } } else { i++; } } for (i = 0; i < source.attributes.length; i++) { var tattr = target.attributes.getNamedItem(source.attributes.item(i).nodeName); if (tattr === null) { logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Adding attribute " + source.attributes.item(i).nodeName + "=" + source.attributes.item(i).nodeValue); tattr = target.ownerDocument.createAttribute(source.attributes.item(i).nodeName); tattr.value = source.attributes.item(i).nodeValue; target.attributes.setNamedItem(tattr); this._processStrangeAttributes(target, tattr); } else { if (tattr.nodeValue !== source.attributes.item(i).nodeValue) { logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Updating the attribute value " + tattr.nodeName + "=" + source.attributes.item(i).nodeValue); tattr.nodeValue = source.attributes.item(i).nodeValue; this._processStrangeAttributes(target, tattr); } } } } else { if (source.nodeType === Node.TEXT_NODE) { if (source.nodeValue !== target.nodeValue) { target.nodeValue = source.nodeValue; } } } logger.log(logger.LogType.Exit, 0, "ajs.doc", this); }; DocumentManager.prototype._adoptStrangeAttributes = function (adoptedNode) { if (adoptedNode.nodeType === Node.ELEMENT_NODE) { for (var i = 0; i < adoptedNode.attributes.length; i++) { this._processStrangeAttributes(adoptedNode, adoptedNode.attributes[i]); } } }; DocumentManager.prototype._processStrangeAttributes = function (element, attribute) { if (element instanceof HTMLElement && attribute.name.toLowerCase() === "onrender") { if (element.ajsData && element.ajsData.ownerComponent && element.ajsData.ownerComponent[attribute.value] instanceof Function) { element.ajsData.ownerComponent[attribute.value](element); } element.attributes.removeNamedItem(attribute.name); } if (element instanceof HTMLInputElement && element.type.toLowerCase() === "text" && attribute.name.toLowerCase() === "value") { element.value = attribute.value; } if (element instanceof HTMLInputElement && element.type.toLowerCase() === "checkbox" && attribute.name.toLowerCase() === "checked") { if (attribute.value.toLowerCase() === "true") { element.checked = true; } else { element.attributes.removeNamedItem("checked"); element.checked = false; } } }; DocumentManager.prototype._setNodeMetadata = function (src, tgt) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Setting node metadata", src, tgt); if (src.ajsData) { tgt.ajsData = src.ajsData; } logger.log(logger.LogType.Exit, 0, "ajs.doc", this); }; DocumentManager.prototype._registerEventListeners = function (src, tgt) { logger.log(logger.LogType.Enter, 0, "ajs.doc", this); if (src.ajsData && src.ajsData.eventListeners instanceof Array) { for (var i = 0; i < src.ajsData.eventListeners.length; i++) { logger.log(logger.LogType.DomAddListener, 0, "ajs.doc", this, "Registering event listener " + src.ajsData.eventListeners[i].eventType, src, tgt); tgt.addEventListener(src.ajsData.eventListeners[i].eventType, src.ajsData.eventListeners[i].eventListener); } } }; DocumentManager.prototype.applyStyleSheetsFromTemplate = function (template) { var _this = this; logger.log(logger.LogType.Enter, 0, "ajs.doc", this); logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Applying Style Sheets from template " + template.name + "(" + template.styleSheets.length + ")"); var styleSheetsToProcess = []; for (var i = 0; i < template.styleSheets.length; i++) { var id = template.name + i; if (this.__styleSheets.indexOf(id) === -1) { this.__styleSheets.push(id); styleSheetsToProcess.push(this._processStyleSheet(template, i)); } } var applyPromise = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { var styleSheets, i, id, style, e_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, Promise.all(styleSheetsToProcess)]; case 1: styleSheets = _a.sent(); for (i = 0; i < styleSheets.length; i++) { id = template.name + i; style = this.__targetDocument.createElement("style"); style.setAttribute("type", "text/css"); style.setAttribute("id", id); style.textContent = template.styleSheets[i]; logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Adding processed stylesheet to the render target", template.styleSheets[i]); this.__targetDocument.head.appendChild(style); } return [3, 3]; case 2: e_1 = _a.sent(); logger.log(logger.LogType.Error, 0, "ajs.doc", this, "Required CSS resource can't be reached", e_1); reject(new exceptions.CSSRequiredResourceNotLoadedException(e_1)); return [3, 3]; case 3: resolve(); return [2]; } }); }); }); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return applyPromise; }; DocumentManager.prototype._processStyleSheet = function (template, index) { var _this = this; logger.log(logger.LogType.Enter, 0, "ajs.doc", this); var resourcesPromises = []; var urls = template.styleSheets[index].match(/url\(('|")(.*)('|")\)/g); if (urls !== null) { for (var i = 0; i < urls.length; i++) { var url = (/('|")(.*)('|")/g).exec(urls[i]); if (url.length < 2) { logger.log(logger.LogType.Error, 0, "ajs.doc", this, "CSS Invalid URL specification " + urls[i]); throw new exceptions.CSSInvalidResourceSpecificationException(); } if (url[2].substr(0, 4) !== "data") { resourcesPromises.push(this.__resourceManager.getResource(url[2], template.storageType, template.cachePolicy, template.loadingPreference)); } } } var styleSheetPromise = new Promise(function (resolve, reject) { return __awaiter(_this, void 0, void 0, function () { var resources_1, i, e_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); return [4, Promise.all(resourcesPromises)]; case 1: resources_1 = _a.sent(); for (i = 0; i < resources_1.length; i++) { template.styleSheets[index] = utils.replaceAll(template.styleSheets[index], resources_1[i].url, "data:image;base64," + resources_1[i].data); } return [3, 3]; case 2: e_2 = _a.sent(); logger.log(logger.LogType.Warning, 0, "ajs.doc", this, "Unable to reach one of requested resources for the stylesheet", e_2); reject(e_2); return [3, 3]; case 3: logger.log(logger.LogType.Info, 0, "ajs.doc", this, "Discovered style sheet resources succesfully loaded"); resolve(template.styleSheets[index]); return [2]; } }); }); }); logger.log(logger.LogType.Exit, 0, "ajs.doc", this); return styleSheetPromise; }; return DocumentManager; }()); exports.DocumentManager = DocumentManager;