Files
DocumentServer-v-9.2.0/sdkjs/word/Editor/sections/document-sections.js
T
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

810 lines
22 KiB
JavaScript

/*
* (c) Copyright Ascensio System SIA 2010-2025
*
* 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()
{
/**
* Class for managing document sections and their header/footer content.
*
* @param {AscWord.Document} logicDocument - The parent document object
* @constructor
*/
function DocumentSections(logicDocument)
{
this.logicDocument = logicDocument;
this.Elements = [];
this.needUpdate = true;
this.paragraphToCheck = {};
this.paraToSection = {};
}
DocumentSections.prototype.GetFirstSectPr = function()
{
this.Update();
if (!this.Elements.length)
return this.logicDocument.GetFinalSectPr();
return this.Elements[0].SectPr;
};
/**
* @returns {AscWord.SectPr}
*/
DocumentSections.prototype.GetNextSectPr = function(sectPr)
{
this.Update();
let index = this.Find(sectPr);
if (-1 === index || index >= this.Elements.length - 1)
return sectPr;
return this.Elements[index + 1].SectPr;
};
DocumentSections.prototype.GetSectionsCount = function()
{
this.Update();
return this.Elements.length;
};
DocumentSections.prototype.Find_ByHdrFtr = function(HdrFtr)
{
if (!HdrFtr)
return -1;
this.Update();
var Count = this.Elements.length;
for (var Index = 0; Index < Count; Index++)
{
var SectPr = this.Elements[Index].SectPr;
if (HdrFtr === SectPr.Get_Header_First()
|| HdrFtr === SectPr.Get_Header_Default()
|| HdrFtr === SectPr.Get_Header_Even()
|| HdrFtr === SectPr.Get_Footer_First()
|| HdrFtr === SectPr.Get_Footer_Default()
|| HdrFtr === SectPr.Get_Footer_Even())
return Index;
}
return -1;
};
DocumentSections.prototype.Reset_HdrFtrRecalculateCache = function()
{
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.Reset_RecalculateCache();
});
};
DocumentSections.prototype.GetAllParagraphs = function(props, paragraphs)
{
if (!paragraphs)
paragraphs = [];
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.GetAllParagraphs(props, paragraphs);
});
return paragraphs;
};
DocumentSections.prototype.GetAllTables = function(props, tables)
{
if (!tables)
tables = [];
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.GetAllTables(props, tables);
});
return tables;
};
DocumentSections.prototype.GetAllDrawingObjects = function(drawings)
{
if (!drawings)
drawings = [];
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.GetAllDrawingObjects(drawings);
});
return drawings;
};
DocumentSections.prototype.UpdateBookmarks = function(bookmarkManager)
{
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.UpdateBookmarks(bookmarkManager);
});
};
DocumentSections.prototype.Document_CreateFontMap = function(fontMap)
{
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.Document_CreateFontMap(fontMap);
});
};
DocumentSections.prototype.Document_CreateFontCharMap = function(fontCharMap)
{
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.Document_CreateFontCharMap(fontCharMap);
});
};
DocumentSections.prototype.Document_Get_AllFontNames = function(allFonts)
{
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.Document_Get_AllFontNames(allFonts);
});
};
DocumentSections.prototype.GetSectPrByElement = function(element)
{
this.Update();
let finalSectPr = this.logicDocument.GetFinalSectPr();
if (!element)
return finalSectPr;
let docPos = element.GetDocumentPositionFromObject();
if (!docPos || !docPos.length)
return finalSectPr;
let topClass = docPos[0].Class;
if (topClass !== this.logicDocument)
{
let sectPr = topClass.Get_SectPr();
return sectPr ? sectPr : finalSectPr;
}
let b = 0;
let e = this.Elements.length - 1;
while (b < e)
{
let m = (b + e) >> 1;
let _docPos = this.Elements[m].Paragraph.GetDocumentPositionFromObject();
if (AscWord.CompareDocumentPositions(docPos, _docPos) <= 0)
e = m;
else
b = m + 1;
}
return this.Elements[b].SectPr;
};
DocumentSections.prototype.GetFirstParagraph = function(sectionIndex)
{
if (0 === sectionIndex)
return this.logicDocument.GetFirstParagraph();
let prevParagraph = this.Elements[sectionIndex - 1].Paragraph;
return prevParagraph.GetNextParagraph();
};
DocumentSections.prototype.GetSectPrByIndex = function(index)
{
return this.Elements[index].SectPr;
};
DocumentSections.prototype.Find = function(sectPr)
{
if (!sectPr)
return -1;
this.Update();
for (let i = 0, count = this.Elements.length; i < count; ++i)
{
if (this.Elements[i].SectPr === sectPr)
return i;
}
return -1;
};
DocumentSections.prototype.Update = function()
{
if (!this.CheckNeedUpdate())
return;
this._clear();
let paragraphs = this.logicDocument.GetAllSectPrParagraphs();
for (let i = 0; i < paragraphs.length; ++i)
{
this._addSection(paragraphs[i].Get_SectionPr(), paragraphs[i]);
}
this._addSection(this.logicDocument.GetFinalSectPr(), this.logicDocument);
// Когда полностью обновляются секции надо пересчитывать с самого начала
this.logicDocument.RecalcInfo.Set_NeedRecalculateFromStart(true);
this.needUpdate = false;
};
DocumentSections.prototype.CheckNeedUpdate = function()
{
for (let paraId in this.paragraphToCheck)
{
let para = this.paragraphToCheck[paraId];
if (!para.Get_SectionPr() || para.CanAddSectionPr())
{
this.needUpdate = true;
break;
}
}
return this.needUpdate;
};
DocumentSections.prototype.CheckParagraph = function(paragraph)
{
if (paragraph && paragraph.Get_SectionPr())
this.paragraphToCheck[paragraph.GetId()] = paragraph;
};
DocumentSections.prototype.UpdateOnAdd = function(items)
{
this.Update();
for (let i = 0, count = items.length; i < count; ++i)
{
let paragraphs = items[i].GetAllSectPrParagraphs();
for (let paraIndex = 0, paraCount = paragraphs.length; paraIndex < paraCount; ++paraIndex)
{
let paragraph = paragraphs[paraIndex];
let paraId = paragraph.GetId();
let sectPr = paragraph.Get_SectionPr();
if (!sectPr || this.paraToSection[paraId])
continue;
let sectionPos = this.GetIndexByElement(paragraph);
if (-1 === sectionPos)
continue;
this._insertSection(sectionPos, sectPr, paragraph);
}
}
};
DocumentSections.prototype.UpdateOnRemove = function(items, checkHdrFtr)
{
this.Update();
let paragraphs = [];
for (let i = 0, count = items.length; i < count; ++i)
{
items[i].GetAllSectPrParagraphs(paragraphs);
}
// По логике удаляемые секции должны идти последовательно, но будем проверять каждую отдельно
for (let i = 0, count = paragraphs.length; i < count; ++i)
{
let sectionPos = this.GetIndexByElement(paragraphs[i]);
if (-1 === sectionPos)
continue;
if (checkHdrFtr && sectionPos < this.Elements.length - 1)
{
let currSectPr = this.Elements[sectionPos].SectPr;
let nextSectPr = this.Elements[sectionPos + 1].SectPr;
if (nextSectPr.IsAllHdrFtrNull() && !currSectPr.IsAllHdrFtrNull())
{
nextSectPr.Set_Header_First(currSectPr.Get_Header_First());
nextSectPr.Set_Header_Even(currSectPr.Get_Header_Even());
nextSectPr.Set_Header_Default(currSectPr.Get_Header_Default());
nextSectPr.Set_Footer_First(currSectPr.Get_Footer_First());
nextSectPr.Set_Footer_Even(currSectPr.Get_Footer_Even());
nextSectPr.Set_Footer_Default(currSectPr.Get_Footer_Default());
}
}
this._removeSection(sectionPos);
}
};
DocumentSections.prototype.GetCount = function()
{
this.Update();
return this.Elements.length;
};
/**
* Получаем секцию по заданному номеру
* @param {number} nIndex
* @returns {DocumentSection}
*/
DocumentSections.prototype.Get = function(nIndex)
{
this.Update();
return this.Elements[nIndex];
};
/**
* Получаем номер секции, в которой лежит заданный элемент
* @param element
* @returns {number}
*/
DocumentSections.prototype.GetIndexByElement = function(element)
{
this.Update();
let b = 0;
let e = this.Elements.length - 1;
if (!element)
return -1;
let docPos = element.GetDocumentPositionFromObject();
if (!docPos || !docPos.length)
return -1;
let topClass = docPos[0].Class;
if (topClass !== this.logicDocument)
{
let sectPr = topClass.Get_SectPr();
return this.Find(sectPr);
}
while (b < e)
{
let m = (b + e) >> 1;
let _docPos = this.Elements[m].Paragraph.GetDocumentPositionFromObject();
if (AscWord.CompareDocumentPositions(docPos, _docPos) <= 0)
e = m;
else
b = m + 1;
}
return b;
};
/**
* Получаем массив всех колонтитулов, используемых в данном документе
* @returns {Array.CHeaderFooter}
*/
DocumentSections.prototype.GetAllHdrFtrs = function()
{
let result = [];
this.forEachHdrFtr(function(hdrFtr){
result.push(hdrFtr);
});
return result;
};
DocumentSections.prototype.GetAllContentControls = function(contentControls)
{
this.forEachHdrFtr(function(hdrFtr){
hdrFtr.GetAllContentControls(contentControls);
});
};
/**
* Обновляем заданную секцию
* @param paragraph {AscWord.Paragraph} - Параграф, в котором обновляется секция
* @param prevSectPr {AscWord.SectPr} - Предыдущая секция в заданном параграфе (если она была)
* @param checkHdrFtr {boolean} - Нужно ли проверять колонтитулы при удалении секции
* @returns {boolean} Если не смогли обновить, возвращаем false
*/
DocumentSections.prototype.UpdateSection = function(paragraph, prevSectPr, checkHdrFtr)
{
this.Update();
let newSectPr = paragraph.Get_SectionPr();
if (prevSectPr)
{
let sectionPos = this.Find(prevSectPr);
if (-1 === sectionPos || this.paraToSection[paragraph.GetId()] !== this.Elements[sectionPos])
return;
if (newSectPr)
{
this.Elements[sectionPos].SectPr = newSectPr;
}
else
{
if (checkHdrFtr && sectionPos < this.Elements.length - 1)
{
let currSectPr = this.Elements[sectionPos].SectPr;
let nextSectPr = this.Elements[sectionPos + 1].SectPr;
if (nextSectPr.IsAllHdrFtrNull() && !currSectPr.IsAllHdrFtrNull())
{
nextSectPr.Set_Header_First(currSectPr.Get_Header_First());
nextSectPr.Set_Header_Even(currSectPr.Get_Header_Even());
nextSectPr.Set_Header_Default(currSectPr.Get_Header_Default());
nextSectPr.Set_Footer_First(currSectPr.Get_Footer_First());
nextSectPr.Set_Footer_Even(currSectPr.Get_Footer_Even());
nextSectPr.Set_Footer_Default(currSectPr.Get_Footer_Default());
}
}
this._removeSection(sectionPos);
}
}
else if (newSectPr)
{
if (this.paraToSection[paragraph.GetId()])
{
this.paraToSection[paragraph.GetId()].SectPr = newSectPr;
}
else
{
let sectionPos = this.GetIndexByElement(paragraph);
if (-1 === sectionPos)
return;
this._insertSection(sectionPos, newSectPr, paragraph)
}
}
};
DocumentSections.prototype.private_GetHdrFtrsArray = function(oCurHdrFtr)
{
var isEvenOdd = EvenAndOddHeaders;
var nCurPos = -1;
var arrHdrFtrs = [];
for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
var oSectPr = this.Elements[nIndex].SectPr;
var isFirst = oSectPr.Get_TitlePage();
var oHeaderFirst = oSectPr.Get_Header_First();
var oHeaderEven = oSectPr.Get_Header_Even();
var oHeaderDefault = oSectPr.Get_Header_Default();
var oFooterFirst = oSectPr.Get_Footer_First();
var oFooterEven = oSectPr.Get_Footer_Even();
var oFooterDefault = oSectPr.Get_Footer_Default();
if (oHeaderFirst && isFirst)
arrHdrFtrs.push(oHeaderFirst);
if (oHeaderEven && isEvenOdd)
arrHdrFtrs.push(oHeaderEven);
if (oHeaderDefault)
arrHdrFtrs.push(oHeaderDefault);
if (oFooterFirst && isFirst)
arrHdrFtrs.push(oFooterFirst);
if (oFooterEven && isEvenOdd)
arrHdrFtrs.push(oFooterEven);
if (oFooterDefault)
arrHdrFtrs.push(oFooterDefault);
}
if (oCurHdrFtr)
{
for (var nIndex = 0, nCount = arrHdrFtrs.length; nIndex < nCount; ++nIndex)
{
if (oCurHdrFtr === arrHdrFtrs[nIndex])
{
nCurPos = nIndex;
break;
}
}
}
return {
HdrFtrs : arrHdrFtrs,
CurPos : nCurPos
};
};
DocumentSections.prototype.FindNextFillingForm = function(isNext, oCurHdrFtr)
{
var oInfo = this.private_GetHdrFtrsArray(oCurHdrFtr);
var arrHdrFtrs = oInfo.HdrFtrs;
var nCurPos = oInfo.CurPos;
var nCount = arrHdrFtrs.length;
var isCurrent = true;
if (-1 === nCurPos)
{
isCurrent = false;
nCurPos = isNext ? 0 : arrHdrFtrs.length - 1;
if (arrHdrFtrs[nCurPos])
oCurHdrFtr = arrHdrFtrs[nCurPos];
}
if (nCurPos >= 0 && nCurPos <= nCount - 1)
{
var oRes = oCurHdrFtr.GetContent().FindNextFillingForm(isNext, isCurrent, isCurrent);
if (oRes)
return oRes;
if (isNext)
{
for (var nIndex = nCurPos + 1; nIndex < nCount; ++nIndex)
{
oRes = arrHdrFtrs[nIndex].GetContent().FindNextFillingForm(isNext, false);
if (oRes)
return oRes;
}
}
else
{
for (var nIndex = nCurPos - 1; nIndex >= 0; --nIndex)
{
oRes = arrHdrFtrs[nIndex].GetContent().FindNextFillingForm(isNext, false);
if (oRes)
return oRes;
}
}
}
return null;
};
DocumentSections.prototype.RestartSpellCheck = function()
{
var bEvenOdd = EvenAndOddHeaders;
for (let nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
var SectPr = this.Elements[nIndex].SectPr;
var bFirst = SectPr.Get_TitlePage();
if (null != SectPr.HeaderFirst && true === bFirst)
SectPr.HeaderFirst.RestartSpellCheck();
if (null != SectPr.HeaderEven && true === bEvenOdd)
SectPr.HeaderEven.RestartSpellCheck();
if (null != SectPr.HeaderDefault)
SectPr.HeaderDefault.RestartSpellCheck();
if (null != SectPr.FooterFirst && true === bFirst)
SectPr.FooterFirst.RestartSpellCheck();
if (null != SectPr.FooterEven && true === bEvenOdd)
SectPr.FooterEven.RestartSpellCheck();
if (null != SectPr.FooterDefault)
SectPr.FooterDefault.RestartSpellCheck();
}
};
DocumentSections.prototype.RemoveEmptyHdrFtrs = function()
{
for (let nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
let oSectPr = this.Elements[nIndex].SectPr;
oSectPr.RemoveEmptyHdrFtrs();
}
};
DocumentSections.prototype.CheckRunContent = function(fCheck)
{
let headers = this.GetAllHdrFtrs();
for (let index = 0, count = headers.length; index < count; ++index)
{
headers[index].GetContent().CheckRunContent(fCheck);
}
};
//------------------------------------------------------------------------------------------------------------------
// Search
//------------------------------------------------------------------------------------------------------------------
DocumentSections.prototype.Search = function(oSearchEngine)
{
var bEvenOdd = EvenAndOddHeaders;
for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
var oSectPr = this.Elements[nIndex].SectPr;
var bFirst = oSectPr.Get_TitlePage();
if (oSectPr.HeaderFirst && true === bFirst)
oSectPr.HeaderFirst.Search(oSearchEngine, search_Header);
if (oSectPr.HeaderEven && true === bEvenOdd)
oSectPr.HeaderEven.Search(oSearchEngine, search_Header);
if (oSectPr.HeaderDefault)
oSectPr.HeaderDefault.Search(oSearchEngine, search_Header);
if (oSectPr.FooterFirst && true === bFirst)
oSectPr.FooterFirst.Search(oSearchEngine, search_Footer);
if (oSectPr.FooterEven && true === bEvenOdd)
oSectPr.FooterEven.Search(oSearchEngine, search_Footer);
if (oSectPr.FooterDefault)
oSectPr.FooterDefault.Search(oSearchEngine, search_Footer);
}
};
DocumentSections.prototype.GetSearchElementId = function(bNext, CurHdrFtr)
{
var HdrFtrs = [];
var CurPos = -1;
var bEvenOdd = EvenAndOddHeaders;
var Count = this.Elements.length;
for (var Index = 0; Index < Count; Index++)
{
var SectPr = this.Elements[Index].SectPr;
var bFirst = SectPr.Get_TitlePage();
if (null != SectPr.HeaderFirst && true === bFirst)
{
HdrFtrs.push(SectPr.HeaderFirst);
if (CurHdrFtr === SectPr.HeaderFirst)
CurPos = HdrFtrs.length - 1;
}
if (null != SectPr.HeaderEven && true === bEvenOdd)
{
HdrFtrs.push(SectPr.HeaderEven);
if (CurHdrFtr === SectPr.HeaderEven)
CurPos = HdrFtrs.length - 1;
}
if (null != SectPr.HeaderDefault)
{
HdrFtrs.push(SectPr.HeaderDefault);
if (CurHdrFtr === SectPr.HeaderDefault)
CurPos = HdrFtrs.length - 1;
}
if (null != SectPr.FooterFirst && true === bFirst)
{
HdrFtrs.push(SectPr.FooterFirst);
if (CurHdrFtr === SectPr.FooterFirst)
CurPos = HdrFtrs.length - 1;
}
if (null != SectPr.FooterEven && true === bEvenOdd)
{
HdrFtrs.push(SectPr.FooterEven);
if (CurHdrFtr === SectPr.FooterEven)
CurPos = HdrFtrs.length - 1;
}
if (null != SectPr.FooterDefault)
{
HdrFtrs.push(SectPr.FooterDefault);
if (CurHdrFtr === SectPr.FooterDefault)
CurPos = HdrFtrs.length - 1;
}
}
var Count = HdrFtrs.length;
var isCurrent = true;
if (-1 === CurPos)
{
isCurrent = false;
CurPos = bNext ? 0 : HdrFtrs.length - 1;
if (HdrFtrs[CurPos])
CurHdrFtr = HdrFtrs[CurPos];
}
if (CurPos >= 0 && CurPos <= HdrFtrs.length - 1)
{
var Id = CurHdrFtr.GetSearchElementId(bNext, isCurrent);
if (null != Id)
return Id;
if (true === bNext)
{
for (var Index = CurPos + 1; Index < Count; Index++)
{
Id = HdrFtrs[Index].GetSearchElementId(bNext, false);
if (null != Id)
return Id;
}
}
else
{
for (var Index = CurPos - 1; Index >= 0; Index--)
{
Id = HdrFtrs[Index].GetSearchElementId(bNext, false);
if (null != Id)
return Id;
}
}
}
return null;
};
//------------------------------------------------------------------------------------------------------------------
// Private area
//------------------------------------------------------------------------------------------------------------------
/**
* Iterates through all sections and executes a callback function for each header and footer.
* @param {Function} callback
*/
DocumentSections.prototype.forEachHdrFtr = function(callback)
{
this.Update();
for (let i = 0, count = this.Elements.length; i < count; ++i)
{
let sectPr = this.Elements[i].SectPr;
if (null != sectPr.HeaderFirst)
callback.call(this, sectPr.HeaderFirst);
if (null != sectPr.HeaderDefault)
callback.call(this, sectPr.HeaderDefault);
if (null != sectPr.HeaderEven)
callback.call(this, sectPr.HeaderEven);
if (null != sectPr.FooterFirst)
callback.call(this, sectPr.FooterFirst);
if (null != sectPr.FooterDefault)
callback.call(this, sectPr.FooterDefault);
if (null != sectPr.FooterEven)
callback.call(this, sectPr.FooterEven);
}
};
DocumentSections.prototype._clear = function()
{
//console.log(`Clear all sections`);
this.Elements.length = 0;
this.paraToSection = {};
};
DocumentSections.prototype._insertSection = function(pos, sectPr, paragraph)
{
//console.log(`Insert sections at pos ${pos} paraId=${paragraph.GetId()}`);
let documentSection = new DocumentSection(sectPr, paragraph);
this.paraToSection[paragraph.GetId()] = documentSection;
this.Elements.splice(pos, 0, documentSection);
};
DocumentSections.prototype._addSection = function(sectPr, paragraph)
{
let documentSection = new DocumentSection(sectPr, paragraph);
this.paraToSection[paragraph.GetId()] = documentSection;
this.Elements.push(documentSection);
//console.log(`Add section at the end. Current count=${this.Elements.length} paraId=${paragraph.GetId()}`);
};
DocumentSections.prototype._removeSection = function(pos)
{
let docSection = this.Elements[pos];
//console.log(`Remove section at pos ${pos} paraId=${docSection.Paragraph.GetId()}`);
delete this.paraToSection[docSection.Paragraph.GetId()];
this.Elements.splice(pos, 1);
};
//------------------------------------------------------------------------------------------------------------------
/**
* Represents a document section associated with a specific paragraph.
*
* @param {AscWord.SectPr} sectPr - Section properties object containing formatting settings
* @param {AscWord.Paragraph} paragraph - The paragraph object that ends this section
* @constructor
*/
function DocumentSection(sectPr, paragraph)
{
this.SectPr = sectPr;
this.Paragraph = paragraph;
}
//--------------------------------------------------------export----------------------------------------------------
AscWord.DocumentSections = DocumentSections;
AscWord.DocumentSection = DocumentSection;
})();