/*
* (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()
{
/**
* Класс представляющий менеджер CustomXMLs
* @param {AscWord.CDocument} document
* @constructor
*/
function CustomXmlManager(document)
{
this.Id = AscCommon.g_oIdCounter.Get_NewId();
this.document = document;
this.xml = [];
this.m_arrXmlById = {};
AscCommon.g_oTableId.Add(this, this.Id);
}
CustomXmlManager.prototype.Get_Id = function()
{
return this.Id;
};
CustomXmlManager.prototype.add = function(oCustomXml)
{
let sId = oCustomXml.GetId();
AscCommon.History.Add(new AscDFH.CChangesCustomXmlManagerAdd(this, sId, oCustomXml));
this.m_arrXmlById[sId] = oCustomXml;
this.xml.push(oCustomXml);
};
CustomXmlManager.prototype.isXmlExist = function(uid, prefix)
{
for (let nXmlCounter = 0; nXmlCounter < this.getCount(); nXmlCounter++)
{
let customXml = this.getCustomXml(nXmlCounter);
if (uid === customXml.itemId || customXml.checkUrl(prefix))
return true;
}
return false;
};
CustomXmlManager.prototype.getExactXml = function (uId, prefix)
{
for (let nXmlCounter = 0; nXmlCounter < this.getCount(); nXmlCounter++)
{
let customXml = this.getCustomXml(nXmlCounter);
if (uId === customXml.itemId || customXml.checkUrl(prefix))
return customXml;
}
};
CustomXmlManager.prototype.getXmlByNamespace = function (namespace)
{
let arrXml = [];
for (let nXmlCounter = 0; nXmlCounter < this.getCount(); nXmlCounter++)
{
let customXml = this.getCustomXml(nXmlCounter);
if (customXml.checkUrl(namespace))
arrXml.push(customXml);
}
return arrXml;
};
CustomXmlManager.prototype.deleteExactXml = function (uId, prefix)
{
for (let nXmlCounter = 0; nXmlCounter < this.getCount(); nXmlCounter++)
{
let oCustomXml = this.getCustomXml(nXmlCounter);
if (uId === oCustomXml.itemId || oCustomXml.checkUrl(prefix))
{
AscCommon.History.Add(new AscDFH.CChangesCustomXmlManagerRemove(this, oCustomXml.Id, oCustomXml));
this.xml.splice(nXmlCounter, 1);
return true;
}
}
return false;
};
CustomXmlManager.prototype.getCount = function()
{
return this.xml.length;
};
CustomXmlManager.prototype.getCustomXml = function(index)
{
return this.xml[index];
};
CustomXmlManager.prototype.createCustomXml = function(content, schemaRefs)
{
let oXML = new AscWord.CustomXml(this, false, schemaRefs, content);
this.add(oXML);
oXML.writeContent("", oXML.getText());
return oXML;
};
/**
* Get custom xml data of content control by data binding property
* @param dataBinding {window.AscWord.DataBinding}
* @param oContentLink {CBlockLevelSdt | CInlineLevelSdt}
* @return {string | null}
*/
CustomXmlManager.prototype.getContentByDataBinding = function(dataBinding, oContentLink)
{
for (let i = 0; i < this.xml.length; ++i)
{
let customXml = this.xml[i];
customXml.oContentLink = oContentLink;
if (dataBinding.storeItemID === customXml.itemId)
{
let xPath = dataBinding.xpath;
if (!xPath)
return null;
let arrFind = customXml.findElementByXPath(xPath);
if (arrFind.length)
return arrFind[0];
}
}
return null;
};
/**
* Set custom xml data of content control by data binding property
* @param {window.AscWord.DataBinding} dataBinding
* @param data {string}
*/
CustomXmlManager.prototype.setContentByDataBinding = function (dataBinding, data)
{
for (let i = 0; i < this.xml.length; ++i)
{
let customXml = this.xml[i];
if (dataBinding.storeItemID === customXml.itemId)
{
let xPath = dataBinding.xpath;
let arrFind = customXml.findElementByXPath(xPath);
if (arrFind.length)
arrFind[0].setTextContent(data);
}
}
};
/**
* Set custom xml data of content control by data binding property
* @param {AscWord.CBlockLevelSdt | AscWord.CInlineLevelSdt} contentControl
*/
CustomXmlManager.prototype.updateDataBinding = function(contentControl)
{
if (!this.isSupported())
return;
let dataBinding = contentControl.getDataBinding();
if (!dataBinding)
return;
if (contentControl.Pr.Text || contentControl.IsComboBox() || contentControl.IsDropDownList() || contentControl.IsDatePicker())
this.setContentByDataBinding(dataBinding, contentControl.GetInnerText());
else if (contentControl.IsCheckBox())
this.setContentByDataBinding(dataBinding, contentControl.IsCheckBoxChecked() ? "true" : "false");
else if (contentControl instanceof AscWord.CBlockLevelSdt)
this.updateRichTextCustomXML(contentControl);
else
this.setContentByDataBinding(dataBinding, contentControl.GetInnerText());
};
CustomXmlManager.prototype.GetRichTextContentToWrite = function (oCC, fCallback)
{
function replaceSubstring(originalString, startPoint, endPoint, insertionString)
{
if (startPoint < 0 || endPoint >= originalString.length || startPoint > endPoint)
return originalString;
const prefix = originalString.substring(0, startPoint);
const suffix = originalString.substring(endPoint + 1);
return prefix + insertionString + suffix;
}
return AscCommon.ExecuteNoHistory(function() {
let doc = new AscWord.CDocument(null, false);
let oSdtContent = oCC.GetContent().Copy();
let jsZlib = new AscCommon.ZLib();
let copyContent = [];
for (let i = 0, count = oSdtContent.GetElementsCount(); i < count; ++i)
{
copyContent.push(oSdtContent.GetElement(i).Copy());
}
doc.ReplaceContent(copyContent);
jsZlib.create();
doc.toZip(jsZlib, new AscCommon.XmlWriterContext(AscCommon.c_oEditorId.Word));
let openDoc = new AscCommon.openXml.OpenXmlPackage(jsZlib, null);
let outputUString = "";
let arrPath = jsZlib.getPaths();
arrPath.forEach(function(path)
{
if ((path === "_rels/.rels" || path === "word/document.xml" || path === "word/_rels/document.xml.rels") && !path.includes("glossary"))
{
let ctfBytes = jsZlib.getFile(path);
let ctfText = AscCommon.UTF8ArrayToString(ctfBytes, 0, ctfBytes.length);
let type = openDoc.getContentType(path);
if (path === "word/_rels/document.xml.rels")
{
let text = '';
let arrRelationships = openDoc.getRelationships();
for (let i = 0; i < arrRelationships.length; i++)
{
let relation = arrRelationships[i];
let relId = relation.relationshipId;
let relType = relation.relationshipType;
let relTarget = relation.target;
if (i === 0)
{
relType = relType.replace("relationships\/officeDocument", "relationships\/styles");
relTarget = relTarget.replace("word/document.xml", "styles.xml");
}
text += ""
}
let nStart = ctfText.indexOf("", 0) + "".length;
let nEnd = ctfText.indexOf("", nStart) - 1;
ctfText = replaceSubstring(ctfText, nStart, nEnd, text);
}
outputUString += " " +
"" + ctfText.replace("", "").replace("\n", "") + ""
}
});
outputUString = outputUString.replace("pkg:contentType=\"application/xml\"", "pkg:contentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"");
outputUString += "";
outputUString = outputUString.replaceAll("<", "<");
outputUString = outputUString.replaceAll(">", ">");
if (fCallback)
fCallback(outputUString, this);
return outputUString;
}, this.document, this, []);
};
CustomXmlManager.prototype.GetDataFromContentControl = function (contentControl)
{
if (!this.isSupported())
return "";
if (contentControl instanceof AscWord.CBlockLevelSdt)
{
return this.GetRichTextContentToWrite(contentControl);
}
else if (contentControl.IsPicture())
{
var oImg;
var allDrawings = contentControl.GetAllDrawingObjects();
for (var nDrawing = 0; nDrawing < allDrawings.length; nDrawing++)
{
if (allDrawings[nDrawing].IsPicture())
{
oImg = allDrawings[nDrawing].GraphicObj;
break;
}
}
if (oImg)
return oImg.getBase64Img();
return "";
}
else if (contentControl.GetInnerText)
{
return contentControl.GetInnerText();
}
};
/**
* Write linear xml data of content control in CustomXML
* @param oCC {CBlockLevelSdt}
*/
CustomXmlManager.prototype.updateRichTextCustomXML = function (oCC)
{
this.GetRichTextContentToWrite(oCC, function (resultStr, oThis) {
oThis.setContentByDataBinding(oCC.Pr.DataBinding, resultStr);
})
};
/**
* Proceed linear xml from CustomXMl attribute or element for fill content control
* @param strLinearXML {string}
* @return {[]} Return array of CC content
*/
CustomXmlManager.prototype.proceedLinearXMl = function (strLinearXML)
{
let drawingDocument = this.document.GetDrawingDocument();
let docContent = AscCommon.ExecuteNoHistory(function(){
strLinearXML = strLinearXML.replaceAll("<", "<");
strLinearXML = strLinearXML.replaceAll(">", ">");
strLinearXML = strLinearXML.replaceAll("", "");
strLinearXML = strLinearXML.replaceAll("", "");
// при записи в атрибут больше проблем, изменить подход если в будущем еще будут проблемы c html entry
strLinearXML = strLinearXML.replaceAll("
", "");
strLinearXML = strLinearXML.replaceAll("&", "&");
strLinearXML = strLinearXML.replaceAll(""", "\"");
strLinearXML = strLinearXML.replaceAll("'", "'");
strLinearXML = strLinearXML.replaceAll("'", "\"");
let zLib = new AscCommon.ZLib;
zLib.create();
zLib.addFile('[Content_Types].xml', AscCommon.Utf8.encode('' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
'' +
''));
let nPos = 0;
while (true)
{
let nStartPos = nPos = strLinearXML.indexOf('', nStartPos);
let strText = strLinearXML.substring(nStartPos, nEndPos);
let nPosStartName = strText.indexOf('name="', 0) + 'name="'.length;
let nPosEndName = strText.indexOf('"', nPosStartName);
let name = strText.substring(nPosStartName, nPosEndName);
let nDataStartPos = strText.indexOf('', 0);
let nDataEndPos;
if (nDataStartPos !== -1)
{
nDataStartPos = nDataStartPos + ''.length;
nDataEndPos = strText.indexOf('', nDataStartPos);
}
else
{
nDataStartPos = strText.indexOf('', 0);
if (nDataStartPos !== -1)
nDataStartPos += ''.length;
nDataEndPos = strText.indexOf('', nDataStartPos);
}
if (nStartPos === -1 || nEndPos === -1)
continue;
let data = strText.substring(nDataStartPos, nDataEndPos).trim();
if (name[0] === "/")
name = name.substring(1, name.length);
zLib.addFile(name, AscCommon.Utf8.encode(data));
}
let arr = zLib.save();
let Doc = new AscWord.CDocument(drawingDocument, false);
let xmlParserContext = new AscCommon.XmlParserContext();
let jsZlib = new AscCommon.ZLib();
xmlParserContext.DrawingDocument = drawingDocument;
if (!jsZlib.open(arr))
return [];
let oBinaryFileReader = new AscCommonWord.BinaryFileReader(Doc, {});
oBinaryFileReader.PreLoadPrepare(undefined, false);
Doc.fromZip(jsZlib, xmlParserContext, oBinaryFileReader.oReadResult);
//очищать pptx_content_loader не надо чтобы не было проблем с вызовом внутри ReadPPTXElement и т.к. открываем zip
//лучше уйти от глобального pptx_content_loader
oBinaryFileReader.PostLoadPrepare(xmlParserContext, false);
jsZlib.close();
return Doc.Content;
}, this.document, this, []);
let resultContent = [];
for (let i = 0; i < docContent.length; ++i)
{
resultContent.push(docContent[i].Copy(null));
}
return resultContent;
};
/**
* Get CustomXML text
* @param oCustomXMl {AscWord.CustomXml}
* @return {string}
*/
CustomXmlManager.prototype.getCustomXMLString = function(oCustomXMl)
{
return oCustomXMl.getText();
};
CustomXmlManager.prototype.isSupported = function()
{
return window['Asc'] && window['Asc']['Addons'] && true === window['Asc']['Addons']['ooxml'];
};
CustomXmlManager.prototype.Refresh_RecalcData = function(Data)
{
};
//--------------------------------------------------------export----------------------------------------------------
AscWord.CustomXmlManager = CustomXmlManager;
})();