ajsfw
Version:
Ajs Framework
469 lines (468 loc) • 24.3 kB
JavaScript
;
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;