894 lines
22 KiB
JavaScript
894 lines
22 KiB
JavaScript
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2023
|
||
*
|
||
* This program is a free software product. You can redistribute it and/or
|
||
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
||
* version 3 as published by the Free Software Foundation. In accordance with
|
||
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
||
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
||
* of any third-party rights.
|
||
*
|
||
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
||
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
||
*
|
||
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
||
* street, Riga, Latvia, EU, LV-1050.
|
||
*
|
||
* The interactive user interfaces in modified source and object code versions
|
||
* of the Program must display Appropriate Legal Notices, as required under
|
||
* Section 5 of the GNU AGPL version 3.
|
||
*
|
||
* Pursuant to Section 7(b) of the License you must retain the original Product
|
||
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
||
* grant you any rights under trademark law for use of our trademarks.
|
||
*
|
||
* All the Product's GUI elements, including illustrations and icon sets, as
|
||
* well as technical writing content are licensed under the terms of the
|
||
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
||
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
||
*
|
||
*/
|
||
|
||
"use strict";
|
||
|
||
(function()
|
||
{
|
||
/**
|
||
* @param {AscWord.CustomXmlManager} xmlManager
|
||
* @param {string} [itemId=null]
|
||
* @param {string[]} [schemaRefs=null]
|
||
* @param {CustomXmlContent} [content]
|
||
*
|
||
* Класс представляющий CustomXML
|
||
* @constructor
|
||
*/
|
||
function CustomXml(xmlManager, itemId, schemaRefs, content)
|
||
{
|
||
this.Id = AscCommon.g_oIdCounter.Get_NewId();
|
||
this.Parent = xmlManager;
|
||
this.itemId = itemId ? itemId : AscCommon.CreateGUID();
|
||
this.content = null;
|
||
this.nsManager = new CustomXmlPrefixMappings(); //
|
||
this.nsURI = ""; // calculated from content
|
||
this.schemaRefs = new CustomXMLSchemaRefs(schemaRefs);
|
||
|
||
this.addContentByXMLString(content);
|
||
this.m_aCustomXmlData = '';
|
||
|
||
AscCommon.g_oTableId.Add(this, this.Id);
|
||
}
|
||
CustomXml.prototype.Copy = function ()
|
||
{
|
||
let strXml = this.getText();
|
||
let oCopy = new CustomXml(
|
||
this.Parent,
|
||
this.itemId,
|
||
Object.assign([], this.schemaRefs),
|
||
undefined
|
||
);
|
||
|
||
oCopy.addContentByXMLString(strXml);
|
||
|
||
return oCopy;
|
||
};
|
||
CustomXml.prototype.Delete = function ()
|
||
{
|
||
if (this.Parent)
|
||
return this.Parent.deleteExactXml(this.itemId);
|
||
|
||
return false;
|
||
};
|
||
CustomXml.prototype.Get_Id = function ()
|
||
{
|
||
return this.Id;
|
||
};
|
||
CustomXml.prototype.GetId = function()
|
||
{
|
||
return this.Id;
|
||
};
|
||
CustomXml.prototype.Refresh_RecalcData = function(Data)
|
||
{
|
||
// Ничего не делаем
|
||
};
|
||
CustomXml.prototype.Write_ToBinary2 = function(Writer)
|
||
{
|
||
Writer.WriteLong(AscDFH.historyitem_type_CustomXml);
|
||
// String : Id
|
||
// Long : Количество элементов
|
||
// Array of Strings : массив с Id элементов
|
||
|
||
Writer.WriteString2(this.Id);
|
||
Writer.WriteString2(this.itemId);
|
||
this.schemaRefs.Write_ToBinary2(Writer);
|
||
};
|
||
CustomXml.prototype.Read_FromBinary2 = function(Reader)
|
||
{
|
||
// String : Id
|
||
// Long : Количество элементов
|
||
// Array of Strings : массив с Id элементов
|
||
this.Id = Reader.GetString2();
|
||
this.itemId = Reader.GetString2();
|
||
|
||
let editor = Asc.editor
|
||
if (editor && editor.wb && editor.wb.model)
|
||
this.Parent = editor.wb.model.getCustomXmlManager(); // Cell editor
|
||
else if (editor && editor.WordControl && editor.WordControl.m_oLogicDocument)
|
||
this.Parent = editor.WordControl.m_oLogicDocument.getCustomXmlManager(); // Word editor and Slide
|
||
|
||
this.schemaRefs.Read_FromBinary2(Reader);
|
||
};
|
||
CustomXml.prototype.Write_ToBinary = function(Writer)
|
||
{
|
||
this.Write_ToBinary2(Writer);
|
||
};
|
||
CustomXml.prototype.Read_FromBinary = function (Reader)
|
||
{
|
||
this.Read_FromBinary2(Reader);
|
||
};
|
||
CustomXml.prototype.writeContent = function(strPrevXml, strCustomXml)
|
||
{
|
||
const BINARY_PART_HISTORY_LIMIT = 1048576;
|
||
const maxLen = Math.max(strCustomXml.length, strPrevXml.length);
|
||
const oldParts = [];
|
||
const newParts = [];
|
||
const amountOfParts = Math.ceil(maxLen / BINARY_PART_HISTORY_LIMIT);
|
||
for (let i = 0; i < amountOfParts; i += 1) {
|
||
oldParts.push(strPrevXml.slice(i * BINARY_PART_HISTORY_LIMIT, (i + 1) * BINARY_PART_HISTORY_LIMIT));
|
||
newParts.push(strCustomXml.slice(i * BINARY_PART_HISTORY_LIMIT, (i + 1) * BINARY_PART_HISTORY_LIMIT));
|
||
}
|
||
|
||
AscCommon.History.Add(new AscDFH.CChangesCustomXmlContentStart(this, null, null, false));
|
||
for (let i = 0; i < amountOfParts; i += 1) {
|
||
AscCommon.History.Add(new AscDFH.CChangesCustomXmlContentPart(this, oldParts[i], newParts[i], false));
|
||
}
|
||
AscCommon.History.Add(new AscDFH.CChangesCustomXmlContentEnd(this, null, null, false));
|
||
this.m_aBinaryData = strCustomXml;
|
||
};
|
||
/**
|
||
* Set UID of CustomXML by given data
|
||
* @param itemId {string}
|
||
*/
|
||
CustomXml.prototype.setItemId = function (itemId)
|
||
{
|
||
this.itemId = itemId;
|
||
};
|
||
/**
|
||
* Add given uri to CustomXML namespace list
|
||
* @param {string} prefix
|
||
* @param {string} ns
|
||
*/
|
||
CustomXml.prototype.addNamespace = function(prefix, ns)
|
||
{
|
||
let nNsCount = this.nsManager.getNsCount();
|
||
let nsPrefix = (nNsCount > 0 ) ? nNsCount : "";
|
||
|
||
if (!prefix || prefix === "")
|
||
prefix = "ns" + nsPrefix;
|
||
|
||
this.nsManager.addNamespace(prefix, ns);
|
||
return true;
|
||
};
|
||
CustomXml.prototype.getNamespaceURI = function()
|
||
{
|
||
return this.nsURI;
|
||
};
|
||
CustomXml.prototype.setNamespaceURI = function(nsURI)
|
||
{
|
||
this.nsURI = nsURI;
|
||
};
|
||
/**
|
||
* Add given schemaRef to CustomXML
|
||
* @param {string} schemaRef
|
||
*/
|
||
CustomXml.prototype.addSchemaRef = function(ref)
|
||
{
|
||
return this.schemaRefs.add(ref);
|
||
};
|
||
CustomXml.prototype.getSchemaRefs = function()
|
||
{
|
||
return this.schemaRefs.getAll();
|
||
};
|
||
/**
|
||
* Get CustomXML data by string
|
||
* @return {string}
|
||
*/
|
||
CustomXml.prototype.getText = function ()
|
||
{
|
||
if (this.content)
|
||
return this.content.getStringFromBuffer();
|
||
else
|
||
return "";
|
||
};
|
||
/**
|
||
* Find url in uri array
|
||
* @return {boolean}
|
||
*/
|
||
CustomXml.prototype.checkUrl = function (str)
|
||
{
|
||
if (!str)
|
||
return false;
|
||
|
||
return this.nsManager.getPrefix(str) !== undefined;
|
||
}
|
||
/**
|
||
* Add content of CustomXML
|
||
* @param arrData {array}
|
||
*/
|
||
CustomXml.prototype.addContent = function (arrData)
|
||
{
|
||
let customXml = fromUtf8(arrData);
|
||
let startPos = customXml.indexOf("<");
|
||
if (-1 !== startPos)
|
||
customXml = customXml.slice(customXml.indexOf("<")); // Skip "L"
|
||
|
||
this.addContentByXMLString(customXml);
|
||
};
|
||
CustomXml.prototype.addContentByXMLString = function(strCustomXml)
|
||
{
|
||
if (strCustomXml === undefined)
|
||
return;
|
||
|
||
if (strCustomXml instanceof CustomXmlContent)
|
||
strCustomXml = strCustomXml.getStringFromBuffer();
|
||
|
||
this.content = CustomXmlCreateContent(strCustomXml, this);
|
||
};
|
||
CustomXml.prototype.findElementByXPath = function (xpath) {
|
||
function getDescendantsByTagName(node, tagName) {
|
||
let result = [];
|
||
|
||
function recurse(current) {
|
||
for (let i = 0; i < current.childNodes.length; i++)
|
||
{
|
||
let child = current.childNodes[i];
|
||
let nameParts = child.nodeName.split(':');
|
||
let pureName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
|
||
|
||
if (pureName === tagName || tagName === '*')
|
||
result.push(child);
|
||
|
||
if (child.childNodes && child.childNodes.length)
|
||
recurse(child);
|
||
}
|
||
}
|
||
|
||
recurse(node);
|
||
return result;
|
||
}
|
||
|
||
function parseSteps(xpath) {
|
||
let steps = [];
|
||
|
||
const marker = '#DOUBLE_SLASH#';
|
||
let temp = xpath.replace(/\/\//g, function() {return '/' + marker + '/'});
|
||
let parts = temp.split('/').filter(function(el) {return el !== ""});
|
||
let deepNext = false;
|
||
|
||
for (let i = 0; i < parts.length; i++) {
|
||
let part = parts[i];
|
||
if (part === marker) {
|
||
deepNext = true;
|
||
continue;
|
||
}
|
||
steps.push({ part : part, deepNext : deepNext });
|
||
deepNext = false;
|
||
}
|
||
return steps;
|
||
}
|
||
|
||
function findMatchingNodes(elements, steps) {
|
||
|
||
if (steps.length === 0)
|
||
return elements;
|
||
|
||
let step = steps[0];
|
||
let part = step.part;
|
||
let deep = step.deepNext;
|
||
let restSteps = steps.slice(1);
|
||
|
||
let tagName = null;
|
||
let index = null;
|
||
|
||
if (part[0] === '@')
|
||
{
|
||
let attrName = part.slice(1);
|
||
return elements.map(function (el) {
|
||
if (el.getAttribute(attrName))
|
||
return el
|
||
});
|
||
}
|
||
|
||
if (part === '*')
|
||
{
|
||
tagName = '*';
|
||
}
|
||
else
|
||
{
|
||
let bracketOpen = part.indexOf('[');
|
||
let bracketClose = part.indexOf(']');
|
||
|
||
if (bracketOpen !== -1 && bracketClose !== -1 && bracketClose > bracketOpen)
|
||
{
|
||
let rawTag = part.slice(0, bracketOpen);
|
||
let rawIndex = part.slice(bracketOpen + 1, bracketClose);
|
||
tagName = rawTag.includes(':') ? rawTag.split(':')[1] : rawTag;
|
||
index = parseInt(rawIndex, 10) - 1;
|
||
}
|
||
else
|
||
{
|
||
tagName = part.includes(':') ? part.split(':')[1] : part;
|
||
}
|
||
}
|
||
|
||
let matched = [];
|
||
|
||
for (let i = 0; i < elements.length; i++)
|
||
{
|
||
let el = elements[i];
|
||
let candidates = deep
|
||
? getDescendantsByTagName(el, tagName)
|
||
: el.childNodes.filter(function(child) {
|
||
let nameParts = child.nodeName.split(':');
|
||
let pureName = nameParts.length > 1 ? nameParts[1] : nameParts[0];
|
||
return tagName === '*' || pureName === tagName;
|
||
});
|
||
|
||
if (index !== null)
|
||
{
|
||
if (index >= 0 && index < candidates.length)
|
||
{
|
||
matched.push(candidates[index]);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
matched = matched.concat(candidates);
|
||
}
|
||
}
|
||
|
||
return findMatchingNodes(matched, restSteps);
|
||
}
|
||
|
||
let steps = parseSteps(xpath);
|
||
let result = findMatchingNodes([this.content], steps);
|
||
return result;
|
||
};
|
||
CustomXml.prototype.deleteAttribute = function(xPath, name)
|
||
{
|
||
return this.Change(function (){
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
return el.deleteAttribute(name);
|
||
}
|
||
return false;
|
||
}, this);
|
||
};
|
||
CustomXml.prototype.insertAttribute = function(xPath, name, value)
|
||
{
|
||
return this.Change(function (){
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
if (!el.attributes[name])
|
||
return el.setAttribute(name, value);
|
||
}
|
||
return false;
|
||
}, this);
|
||
};
|
||
CustomXml.prototype.updateAttribute = function(xPath, name, value)
|
||
{
|
||
return this.Change(function (){
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
if (el.attributes[name])
|
||
return el.setAttribute(name, value);
|
||
}
|
||
return false;
|
||
}, this);
|
||
};
|
||
CustomXml.prototype.getAttribute = function(xPath, name)
|
||
{
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
if (el.attributes[name])
|
||
return el.attributes[name];
|
||
}
|
||
return null;
|
||
};
|
||
CustomXml.prototype.deleteElement = function (xPath)
|
||
{
|
||
return this.Change(function (){
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
return el.delete();
|
||
}
|
||
return false;
|
||
}, this);
|
||
};
|
||
CustomXml.prototype.updateElement = function(xPath, xmlStr)
|
||
{
|
||
return this.Change(function (){
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
el.setXml(xmlStr);
|
||
return true;
|
||
}
|
||
return false;
|
||
}, this);
|
||
};
|
||
CustomXml.prototype.insertElement = function (xPath, xmlStr, index)
|
||
{
|
||
return this.Change(function (){
|
||
let nodes = this.findElementByXPath(xPath);
|
||
if (nodes.length)
|
||
{
|
||
let el = nodes[0];
|
||
el.addElement(xmlStr, index);
|
||
return true;
|
||
}
|
||
return false;
|
||
}, this);
|
||
};
|
||
CustomXml.prototype.beforeChange = function ()
|
||
{
|
||
this.lastContent = this.Copy();
|
||
};
|
||
CustomXml.prototype.afterChange = function ()
|
||
{
|
||
let strLast = this.lastContent.getText();
|
||
let strCurrentData = this.getText();
|
||
|
||
if (strLast !== strCurrentData)
|
||
this.writeContent(strLast, strCurrentData);
|
||
|
||
this.lastContent = undefined;
|
||
};
|
||
CustomXml.prototype.Change = function (f, oThis)
|
||
{
|
||
this.beforeChange();
|
||
let data = f.apply(oThis);
|
||
this.afterChange();
|
||
return data;
|
||
};
|
||
CustomXml.prototype.getAllNamespaces = function()
|
||
{
|
||
return Object.keys(this.nsManager.urls);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function CustomXmlContent(oParentNode, oNodeName, xml)
|
||
{
|
||
this.parentNode = oParentNode;
|
||
this.nodeName = oNodeName ? oNodeName : "";
|
||
this.childNodes = [];
|
||
this.attributes = {};
|
||
this.text = "";
|
||
this.xmlQuestionHeader = null;
|
||
this.xml = xml;
|
||
|
||
this.getNamespace = function ()
|
||
{
|
||
const parts = this.nodeName.split(":");
|
||
let prefix = parts.length === 2 ? parts[0] : null;
|
||
|
||
if (prefix)
|
||
return this.xml.nsManager.getNamespace(prefix);
|
||
|
||
return "";
|
||
}
|
||
this.getNodeName = function ()
|
||
{
|
||
return this.nodeName;
|
||
};
|
||
this.getText = function ()
|
||
{
|
||
return this.text;
|
||
};
|
||
this.getXPath = function ()
|
||
{
|
||
let parent = this.getParent();
|
||
let parentText = parent ? parent.getXPath() + "/" : "/";
|
||
let curNodeName = this.getNodeName();
|
||
let count = parent ? parent.getPosOfChilderNode(this) : null;
|
||
let textOfCount = count !== null ? "[" + count + "]" : "";
|
||
|
||
if (!curNodeName)
|
||
return '';
|
||
|
||
return parentText + curNodeName + textOfCount;
|
||
};
|
||
this.getChildNodesCount = function()
|
||
{
|
||
return this.childNodes.length;
|
||
};
|
||
this.getPosOfChilderNode = function(childNode)
|
||
{
|
||
if (!childNode || !(childNode instanceof CustomXmlContent) || this.childNodes.length <= 1)
|
||
return null;
|
||
|
||
let childNameNodes = this.childNodes.filter(function(node){return node.nodeName === childNode.nodeName});
|
||
|
||
if (childNameNodes.length <= 1)
|
||
return null;
|
||
|
||
for (let i = 0; i < childNameNodes.length; i++)
|
||
{
|
||
let node = childNameNodes[i];
|
||
if (node === childNode)
|
||
return i + 1;
|
||
}
|
||
};
|
||
this.deleteChild = function (childNode)
|
||
{
|
||
this.childNodes = this.childNodes.filter(function (item) {return item !== childNode});
|
||
};
|
||
this.delete = function ()
|
||
{
|
||
this.parentNode.deleteChild(this);
|
||
};
|
||
this.addAttribute = function (name, value)
|
||
{
|
||
this.attributes[name] = value;
|
||
};
|
||
this.getAttribute = function (name)
|
||
{
|
||
return this.attributes[name];
|
||
};
|
||
this.addContent = function(name)
|
||
{
|
||
let newItem = new CustomXmlContent(this, name, this.xml);
|
||
|
||
this.childNodes.push(newItem);
|
||
return newItem;
|
||
};
|
||
this.addElement = function(xmlStr, index)
|
||
{
|
||
let newItem = new CustomXmlContent(this, null, this.xml);
|
||
newItem.setXml(xmlStr);
|
||
|
||
if (index !== undefined)
|
||
this.childNodes.splice(index, 0, newItem);
|
||
else
|
||
this.childNodes.push(newItem);
|
||
};
|
||
this.setAttribute = function (attribute, value)
|
||
{
|
||
this.attributes[attribute] = value;
|
||
};
|
||
this.deleteAttribute = function(name)
|
||
{
|
||
if (this.attributes[name])
|
||
{
|
||
delete this.attributes[name];
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
this.getParent = function ()
|
||
{
|
||
if (this.parentNode)
|
||
return this.parentNode;
|
||
|
||
return null;
|
||
};
|
||
this.addTextContent = function (text)
|
||
{
|
||
if (text !== "")
|
||
this.text += text;
|
||
};
|
||
this.setTextContent = function (str)
|
||
{
|
||
this.text = str;
|
||
return true;
|
||
};
|
||
this.getInnerText = function ()
|
||
{
|
||
let result = [];
|
||
|
||
function GetText(node)
|
||
{
|
||
if (node.text)
|
||
result.push(node.text);
|
||
|
||
for (let i = 0; i < node.childNodes.length; i++)
|
||
{
|
||
GetText(node.childNodes[i]);
|
||
}
|
||
}
|
||
|
||
GetText(this);
|
||
|
||
return result.join("");
|
||
}
|
||
this.getBuffer = function ()
|
||
{
|
||
let writer = new AscCommon.CMemory();
|
||
|
||
function Write(content)
|
||
{
|
||
if (content.nodeName === "" && content.text === "" && content.childNodes.length === 0)
|
||
{
|
||
writer.WriteXmlString("");
|
||
return;
|
||
}
|
||
|
||
let current;
|
||
if (!content.nodeName)
|
||
{
|
||
if (content.xmlQuestionHeader !== null)
|
||
writer.WriteXmlString(content.xmlQuestionHeader + "\n");
|
||
|
||
current = content.childNodes[0];
|
||
}
|
||
else
|
||
{
|
||
current = content;
|
||
}
|
||
|
||
writer.WriteXmlNodeStart(current.nodeName);
|
||
|
||
let atr = Object.keys(current.attributes)
|
||
|
||
for (let i = 0; i < atr.length; i++)
|
||
{
|
||
let cur = atr[i];
|
||
writer.WriteXmlAttributeStringEncode(cur, current.attributes[cur]);
|
||
}
|
||
|
||
writer.WriteXmlAttributesEnd();
|
||
|
||
for (let i = 0; i < current.childNodes.length; i++)
|
||
{
|
||
Write(current.childNodes[i]);
|
||
}
|
||
|
||
if (current.text)
|
||
writer.WriteXmlString(current.text.toString().trim());
|
||
|
||
writer.WriteXmlNodeEnd(current.nodeName);
|
||
}
|
||
|
||
Write(this);
|
||
return writer;
|
||
};
|
||
this.getStringFromBuffer = function (isOnlyInner)
|
||
{
|
||
let buffer = this.getBuffer(isOnlyInner);
|
||
let str = fromUtf8(buffer.GetData());
|
||
str = str.replaceAll(""", "\"");
|
||
str = str.replaceAll("&", "&");
|
||
return str;
|
||
};
|
||
this.setXml = function(strXml)
|
||
{
|
||
let content = CustomXmlCreateContent(strXml, this.xml);
|
||
let data = content.childNodes[0];
|
||
|
||
this.nodeName = data.nodeName;
|
||
this.childNodes = data.childNodes;
|
||
this.attributes = data.attributes;
|
||
this.text = data.text;
|
||
|
||
if (data.xmlQuestionHeader)
|
||
this.xmlQuestionHeader = data.xmlQuestionHeader;
|
||
};
|
||
this.Write_ToBinary2 = function (Writer)
|
||
{
|
||
Writer.WriteString2( this.getStringFromBuffer() );
|
||
};
|
||
this.Read_FromBinary2 = function (Reader)
|
||
{
|
||
let oContent = AscWord.CustomXmlCreateContent(Reader.GetString2(), this.xml);
|
||
|
||
this.parentNode = oContent.parentNode;
|
||
this.name = oContent.name;
|
||
this.childNodes = oContent.childNodes;
|
||
this.attributes = oContent.attributes;
|
||
this.textContent = oContent.textContent;
|
||
this.xmlQuestionHeader = oContent.xmlQuestionHeader;
|
||
};
|
||
}
|
||
|
||
// TODO: Временно вынес метод сюда, потом перенести надо будет
|
||
// разница с AscCommon.UTF8ArrayToString, что тут на 0-символе не останавливаемся
|
||
function fromUtf8(buffer, start, len)
|
||
{
|
||
if (undefined === start)
|
||
start = 0;
|
||
if (undefined === len)
|
||
len = buffer.length;
|
||
|
||
var result = "";
|
||
var index = start;
|
||
var end = start + len;
|
||
while (index < end)
|
||
{
|
||
var u0 = buffer[index++];
|
||
if (!(u0 & 128))
|
||
{
|
||
result += String.fromCharCode(u0);
|
||
continue;
|
||
}
|
||
var u1 = buffer[index++] & 63;
|
||
if ((u0 & 224) == 192)
|
||
{
|
||
result += String.fromCharCode((u0 & 31) << 6 | u1);
|
||
continue;
|
||
}
|
||
var u2 = buffer[index++] & 63;
|
||
if ((u0 & 240) == 224)
|
||
u0 = (u0 & 15) << 12 | u1 << 6 | u2;
|
||
else
|
||
u0 = (u0 & 7) << 18 | u1 << 12 | u2 << 6 | buffer[index++] & 63;
|
||
if (u0 < 65536)
|
||
result += String.fromCharCode(u0);
|
||
else
|
||
{
|
||
var ch = u0 - 65536;
|
||
result += String.fromCharCode(55296 | ch >> 10, 56320 | ch & 1023);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
function CustomXmlCreateContent(strCustomXml, xml)
|
||
{
|
||
function getPrefix(xmlnsAttrName) {
|
||
if (xmlnsAttrName.startsWith("xmlns:"))
|
||
return xmlnsAttrName.slice(6);
|
||
return null;
|
||
}
|
||
|
||
let nXmlHeaderStart = strCustomXml.indexOf('<?', 0);
|
||
let nXmlHeaderEnd = strCustomXml.indexOf('?>', nXmlHeaderStart);
|
||
let strXmlHeader = null;
|
||
if (nXmlHeaderStart !== -1 && nXmlHeaderEnd !== -1)
|
||
{
|
||
strXmlHeader = strCustomXml.substring(nXmlHeaderStart, nXmlHeaderEnd + "?>".length);
|
||
strCustomXml = strCustomXml.substring(nXmlHeaderEnd + '?>'.length, strCustomXml.length);
|
||
}
|
||
|
||
let oStax = new StaxParser(strCustomXml),
|
||
rootContent = new CustomXmlContent(null, null, xml);
|
||
|
||
if (strXmlHeader !== null)
|
||
rootContent.xmlQuestionHeader = strXmlHeader;
|
||
|
||
while (oStax.Read())
|
||
{
|
||
switch (oStax.GetEventType()) {
|
||
case EasySAXEvent.CHARACTERS:
|
||
rootContent.addTextContent(oStax.text);
|
||
break;
|
||
case EasySAXEvent.END_ELEMENT:
|
||
rootContent = rootContent.getParent();
|
||
break;
|
||
case EasySAXEvent.START_ELEMENT:
|
||
let name = oStax.GetName();
|
||
let childElement = rootContent.addContent(name);
|
||
|
||
while (oStax.MoveToNextAttribute())
|
||
{
|
||
let attributeName = oStax.GetName();
|
||
let attributeValue = oStax.GetValue();
|
||
|
||
if (attributeName.length >= 5 && attributeName.slice(0,5) === 'xmlns')
|
||
{
|
||
// Add unique namespace URI to schema references
|
||
rootContent.xml.addSchemaRef(attributeValue);
|
||
|
||
// Register any namespace in NamespaceManager
|
||
let prefix = getPrefix(attributeName);
|
||
rootContent.xml.addNamespace(prefix, attributeValue);
|
||
|
||
// Set the main NamespaceURI from root element if not set yet
|
||
if (rootContent.parentNode === null && rootContent.xml.nsURI === "")
|
||
rootContent.xml.setNamespaceURI(attributeValue);
|
||
}
|
||
|
||
childElement.addAttribute(attributeName, attributeValue);
|
||
}
|
||
rootContent = childElement;break;
|
||
}
|
||
}
|
||
return rootContent;
|
||
}
|
||
function CustomXmlPrefixMappings()
|
||
{
|
||
this.prefixMappings = {};
|
||
this.prefix = {};
|
||
|
||
this.getPrefixes = function()
|
||
{
|
||
return Object.keys(this.prefix);
|
||
};
|
||
this.getNamespaces = function()
|
||
{
|
||
return Object.keys(this.prefixMappings);
|
||
};
|
||
this.getNsCount = function()
|
||
{
|
||
let arrNamespaces = this.getNamespaces();
|
||
return arrNamespaces.length;
|
||
};
|
||
this.addNamespace = function (prefix, ns)
|
||
{
|
||
if (ns !== "" && this.namespaceUri === "")
|
||
this.namespaceUri = ns;
|
||
|
||
if (prefix && ns)
|
||
{
|
||
let prevPrefix = this.prefixMappings[ns];
|
||
|
||
this.prefixMappings[ns] = prefix;
|
||
|
||
if (prevPrefix)
|
||
delete this.prefix[prevPrefix];
|
||
|
||
this.prefix[prefix] = ns;
|
||
}
|
||
};
|
||
this.getNamespace = function(prefix)
|
||
{
|
||
return this.prefix[prefix];
|
||
};
|
||
this.getPrefix = function(ns)
|
||
{
|
||
return this.prefixMappings[ns];
|
||
};
|
||
}
|
||
|
||
function CustomXMLSchemaRefs(refs)
|
||
{
|
||
this.refs = refs ? Object.assign([], refs) : [];
|
||
|
||
this.getAll = function()
|
||
{
|
||
return Object.assign([], this.refs);
|
||
};
|
||
this.add = function(schemaUri)
|
||
{
|
||
if (schemaUri && schemaUri.trim() !== "" && !this.refs.includes(schemaUri))
|
||
{
|
||
this.refs.push(schemaUri);
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
this.Write_ToBinary2 = function(Writer)
|
||
{
|
||
let Count = this.refs.length;
|
||
Writer.WriteLong(Count);
|
||
|
||
for (let Index = 0; Index < Count; Index++)
|
||
Writer.WriteString2(this.refs[Index]);
|
||
};
|
||
this.Read_FromBinary2 = function(Reader)
|
||
{
|
||
let Count = Reader.GetLong();
|
||
for (let Index = 0; Index < Count; Index++)
|
||
this.refs.push(Reader.GetString2());
|
||
};
|
||
}
|
||
|
||
//--------------------------------------------------------export----------------------------------------------------
|
||
AscWord.CustomXml = CustomXml;
|
||
AscWord.CustomXmlContent = CustomXmlContent;
|
||
AscWord.CustomXmlCreateContent = CustomXmlCreateContent;
|
||
})();
|