Files
Yajbir Singh f1b860b25c
check / markdownlint (push) Has been cancelled
check / spellchecker (push) Has been cancelled
updated
2025-12-11 19:03:17 +05:30

510 lines
16 KiB
JavaScript

/*
* (c) Copyright Ascensio System SIA 2010-2024
*
* 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";
/**
* Класс для работы со структурой документа
* @param {CDocument} oLogicDocument
*/
function CDocumentOutline(oLogicDocument)
{
this.LogicDocument = oLogicDocument;
this.Use = false;
this.Elements = [];
this.CurPos = -1;
this.ParagraphsToUpdate = {};
}
CDocumentOutline.prototype.SetUse = function(isUse)
{
this.Use = isUse;
if (this.Use)
this.UpdateAll();
};
CDocumentOutline.prototype.IsUse = function()
{
return this.Use;
};
CDocumentOutline.prototype.UpdateAll = function()
{
if (!this.Use)
return;
this.ParagraphsToUpdate = {};
this.Elements = [];
this.LogicDocument.GetOutlineParagraphs(this.Elements, {SkipEmptyParagraphs : false, SkipTables : true, SkipDrawings : true, OutlineStart : 1, OutlineEnd : 9});
if (this.Elements.length > 0)
{
this.LogicDocument.UpdateContentIndexing();
if (0 !== this.Elements[0].Paragraph.GetIndex())
{
this.Elements.splice(0, 0, {Paragraph : null, Lvl : 0});
}
}
this.CurPos = -1;
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdate(this);
this.LogicDocument.UpdateDocumentOutlinePosition();
};
CDocumentOutline.prototype.CheckParagraph = function(oParagraph)
{
if ((-1 !== this.private_FindElementByParagraph(oParagraph)
|| undefined !== oParagraph.GetOutlineLvl())
&& !this.ParagraphsToUpdate[oParagraph.GetId()])
{
this.ParagraphsToUpdate[oParagraph.GetId()] = oParagraph;
}
};
CDocumentOutline.prototype.Update = function()
{
// TODO: Надо проверить нумерацию
var arrParagraphs = [];
for (var sId in this.ParagraphsToUpdate)
{
arrParagraphs.push(this.ParagraphsToUpdate[sId]);
}
if (arrParagraphs.length > 0)
{
this.LogicDocument.UpdateContentIndexing();
for (var nIndex = 0, nCount = arrParagraphs.length; nIndex < nCount; ++nIndex)
{
var oParagraph = arrParagraphs[nIndex];
var nPos = this.private_FindElementByParagraph(oParagraph);
var nLevel = oParagraph.GetOutlineLvl();
var isUse = oParagraph.IsUseInDocument();
if (undefined !== nLevel && isUse)
{
if (-1 === nPos)
{
nPos = this.private_GetParagraphPosition(oParagraph);
if (0 === nPos && this.Elements[0] && null === this.Elements[0].Paragraph)
{
this.Elements.splice(0, 1);
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateRemove(0);
}
this.Elements.splice(nPos, 0, {Paragraph : oParagraph, Lvl : nLevel});
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateAdd(nPos);
if (0 === nPos)
{
this.LogicDocument.UpdateContentIndexing();
if (0 !== this.Elements[0].Paragraph.GetIndex())
{
this.Elements.splice(0, 0, {Paragraph : null, Lvl : 0});
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateAdd(0);
}
}
}
else
{
this.Elements[nPos].Lvl = nLevel;
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateChange(nPos);
}
}
else if (-1 !== nPos && (undefined === nLevel || !isUse))
{
this.Elements.splice(nPos, 1);
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateRemove(nPos);
if (0 === nPos && (!this.Elements[0] || (null !== this.Elements[0].Paragraph && 0 !== this.Elements[0].Paragraph.GetIndex())))
{
this.Elements.splice(0, 0, {Paragraph : null, Lvl : 0});
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateAdd(0);
}
if (1 === this.Elements.length && this.Elements[0].Paragraph === null)
{
this.Elements.splice(0, 1);
this.LogicDocument.GetApi().sync_OnDocumentOutlineUpdateRemove(0);
}
}
}
}
this.ParagraphsToUpdate = {};
};
CDocumentOutline.prototype.private_FindElementByParagraph = function(oParagraph)
{
for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
if (this.Elements[nIndex].Paragraph === oParagraph)
return nIndex;
}
return -1;
};
CDocumentOutline.prototype.private_GetParagraphPosition = function(oParagraph)
{
var arrParaPos = oParagraph.GetDocumentPositionFromObject();
for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
if ((this.Elements[nIndex].Paragraph && this.private_CompareDocumentPositions(arrParaPos, this.Elements[nIndex].Paragraph.GetDocumentPositionFromObject()) <= 0)
|| (!this.Elements[nIndex].Paragraph && this.private_IsStartDocumentPosition(arrParaPos)))
return nIndex;
}
return this.Elements.length;
};
CDocumentOutline.prototype.private_CompareDocumentPositions = function(arrDocPos1, arrDocPos2)
{
var nLen1 = arrDocPos1.length;
var nLen2 = arrDocPos2.length;
for (var nPos = 0; nPos < nLen1; ++nPos)
{
if (nLen2 <= nPos)
return 1;
if (arrDocPos1[nPos].Position < arrDocPos2[nPos].Position)
return -1;
else if (arrDocPos1[nPos].Position > arrDocPos2[nPos].Position)
return 1;
}
if (nLen2 > nLen1)
return -1;
return 0;
};
CDocumentOutline.prototype.private_IsStartDocumentPosition = function(arrDocPos)
{
if (arrDocPos.length <= 0)
return false;
for (var nIndex = 0, nCount = arrDocPos.length; nIndex < nCount; ++nIndex)
{
if (0 !== arrDocPos[nIndex].Position)
return false;
}
return true;
};
CDocumentOutline.prototype.GetElementsCount = function()
{
return this.Elements.length;
};
CDocumentOutline.prototype.GetText = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return "";
var oParagraph = this.Elements[nIndex].Paragraph;
if (!oParagraph)
return "";
let text = oParagraph.GetText({Numbering : false});
let numText = oParagraph.IsNumberedNumbering() ? oParagraph.GetNumberingText() : "";
if (numText !== "")
text = numText + " " + text;
return text;
};
CDocumentOutline.prototype.GetLevel = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return -1;
return this.Elements[nIndex].Lvl;
};
CDocumentOutline.prototype.GoTo = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return -1;
var oParagraph = this.Elements[nIndex].Paragraph;
this.LogicDocument.RemoveSelection();
if (!oParagraph)
{
this.LogicDocument.MoveCursorToStartPos(false);
}
else
{
oParagraph.MoveCursorToStartPos();
oParagraph.SkipPageColumnBreaks();
oParagraph.Document_SetThisElementCurrent(true);
}
};
CDocumentOutline.prototype.Demote = function(nIndex)
{
this.private_PromoteDemote(nIndex, false);
};
CDocumentOutline.prototype.Promote = function(nIndex)
{
this.private_PromoteDemote(nIndex, true);
};
CDocumentOutline.prototype.private_PromoteDemote = function(nIndex, isPromote)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return;
var nLevel = this.Elements[nIndex].Lvl;
var oParagraph = this.Elements[nIndex].Paragraph;
if (!oParagraph)
return;
if (isPromote && (nLevel <= 0 || nLevel > 8) || (!isPromote && (nLevel >= 8 || nLevel < 0)))
return;
var arrParagraphs = [oParagraph];
var arrLevels = [nLevel];
nIndex++;
while (nIndex < this.Elements.length)
{
var nCurLevel = this.Elements[nIndex].Lvl;
var oCurParagraph = this.Elements[nIndex].Paragraph;
if (nCurLevel <= nLevel)
break;
arrParagraphs.push(oCurParagraph);
arrLevels.push(nCurLevel);
nIndex++;
}
if (false === this.LogicDocument.Document_Is_SelectionLocked(changestype_None, {
Type : AscCommon.changestype_2_ElementsArray_and_Type,
Elements : arrParagraphs,
CheckType : AscCommon.changestype_Paragraph_Properties
}))
{
this.LogicDocument.StartAction(AscDFH.historydescription_Document_ChangeOutlineLevel);
for (var nPos = 0, nCount = arrParagraphs.length; nPos < nCount; ++nPos)
{
var nCurLevel = arrLevels[nPos];
if (isPromote && nCurLevel > 0 && nCurLevel <= 8)
nCurLevel--;
else if (!isPromote && nCurLevel < 8 && nCurLevel >= 0)
nCurLevel++;
else
continue;
var sStyleId = this.LogicDocument.GetStyles().GetDefaultHeading(nCurLevel);
arrParagraphs[nPos].SetParagraphStyleById(sStyleId);
}
this.LogicDocument.Recalculate();
this.LogicDocument.UpdateInterface();
this.LogicDocument.FinalizeAction();
}
};
CDocumentOutline.prototype.InsertHeader = function(nIndex, isBefore)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return;
var nPos = this.private_GetPositionForInsertHeaderBefore(isBefore ? nIndex : this.private_GetNextSiblingOrHigher(nIndex));
var nLevel = this.GetLevel(nIndex);
// Локов особо проверять не нужно, т.к. мы добавляем параграф в верхний класс, но возможно есть глобальный лок,
// так что проверка нужна все равно, но без типа изменения.
if (false === this.LogicDocument.Document_Is_SelectionLocked(changestype_None))
{
this.LogicDocument.StartAction(AscDFH.historydescription_Document_AddElementToOutline);
var oParagraph = new AscWord.Paragraph();
oParagraph.SetParagraphStyleById(this.LogicDocument.GetStyles().GetDefaultHeading(nLevel));
this.LogicDocument.AddToContent(nPos, oParagraph);
this.LogicDocument.Recalculate();
oParagraph.MoveCursorToStartPos(false);
oParagraph.Document_SetThisElementCurrent(true);
this.LogicDocument.FinalizeAction();
}
};
CDocumentOutline.prototype.InsertSubHeader = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return;
var nPos = this.private_GetPositionForInsertHeaderBefore(this.private_GetNextSiblingOrHigher(nIndex));
var nLevel = this.GetLevel(nIndex);
if (nLevel >= 8)
return;
// Локов особо проверять не нужно, т.к. мы добавляем параграф в верхний класс, но возможно есть глобальный лок,
// так что проверка нужна все равно, но без типа изменения.
if (false === this.LogicDocument.Document_Is_SelectionLocked(changestype_None))
{
this.LogicDocument.StartAction(AscDFH.historydescription_Document_AddElementToOutline);
var oParagraph = new AscWord.Paragraph();
oParagraph.SetParagraphStyleById(this.LogicDocument.GetStyles().GetDefaultHeading(nLevel + 1));
this.LogicDocument.AddToContent(nPos, oParagraph);
this.LogicDocument.Recalculate();
oParagraph.MoveCursorToStartPos(false);
oParagraph.Document_SetThisElementCurrent(true);
this.LogicDocument.FinalizeAction();
}
};
CDocumentOutline.prototype.private_GetPositionForInsertHeaderBefore = function(nIndex)
{
if (nIndex === this.Elements.length)
return this.LogicDocument.GetElementsCount();
var oParagraph = this.Elements[nIndex].Paragraph;
if (!oParagraph)
return 0;
this.LogicDocument.UpdateContentIndexing();
return oParagraph.GetIndex();
};
CDocumentOutline.prototype.private_GetNextSiblingOrHigher = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return 0;
var nLevel = this.GetLevel(nIndex);
var nPos = nIndex + 1;
while (nPos < this.Elements.length)
{
if (nLevel >= this.GetLevel(nPos))
return nPos;
nPos++;
}
return this.Elements.length;
};
CDocumentOutline.prototype.IsFirstItemNotHeader = function()
{
return (this.Elements.length <= 0 || !this.Elements[0].Paragraph ? true : false);
};
CDocumentOutline.prototype.SelectContent = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return;
var oStartParagraph = this.Elements[nIndex].Paragraph,
oEndParagraph = null;
var nNextIndex = this.private_GetNextSiblingOrHigher(nIndex);
if (nNextIndex < this.Elements.length)
oEndParagraph = this.Elements[nNextIndex].Paragraph;
this.LogicDocument.UpdateContentIndexing();
var nStartPos = (oStartParagraph ? oStartParagraph.GetIndex() : 0);
var nEndPos = (oEndParagraph ? oEndParagraph.GetIndex() : this.LogicDocument.GetElementsCount()) - 1;
this.LogicDocument.RemoveSelection();
this.LogicDocument.SelectRange(nStartPos, nEndPos);
};
CDocumentOutline.prototype.UpdateCurrentPosition = function(arrDocPos)
{
if (null === arrDocPos)
{
this.LogicDocument.GetApi().sync_OnDocumentOutlineCurrentPosition(null);
return;
}
this.LogicDocument.UpdateContentIndexing();
var nFindIndex = this.Elements.length - 1;
for (var nIndex = 0, nCount = this.Elements.length; nIndex < nCount; ++nIndex)
{
var oParagraph = this.Elements[nIndex].Paragraph;
// Такое может случиться только для первого элемента списка
if (!oParagraph)
continue;
if (this.private_CompareDocumentPositions(oParagraph.GetDocumentPositionFromObject(), arrDocPos) > 0)
{
nFindIndex = nIndex - 1;
break;
}
}
if (nFindIndex !== this.CurPos)
{
this.CurPos = nFindIndex;
this.LogicDocument.GetApi().sync_OnDocumentOutlineCurrentPosition(nFindIndex);
}
};
CDocumentOutline.prototype.IsEmptyItem = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length || !this.Elements[nIndex].Paragraph)
return true;
let paragraph= this.Elements[nIndex].Paragraph;
if (paragraph.IsNumberedNumbering() && "" !== paragraph.GetNumberingText())
return false;
return this.Elements[nIndex].Paragraph.IsEmpty();
};
CDocumentOutline.prototype.GetCurrentPosition = function()
{
return this.CurPos;
};
CDocumentOutline.prototype.GetDestinationXY = function(nIndex)
{
if (nIndex < 0 || nIndex >= this.Elements.length)
return null;
let paragraph = this.Elements[nIndex].Paragraph;
if (!paragraph)
return null;
return paragraph.GetStartPosXY();
};
//-------------------------------------------------------------export---------------------------------------------------
CDocumentOutline.prototype["get_ElementsCount"] = CDocumentOutline.prototype.GetElementsCount;
CDocumentOutline.prototype["get_Text"] = CDocumentOutline.prototype.GetText;
CDocumentOutline.prototype["get_Level"] = CDocumentOutline.prototype.GetLevel;
CDocumentOutline.prototype["get_CurrentPosition"] = CDocumentOutline.prototype.GetCurrentPosition;
CDocumentOutline.prototype["goto"] = CDocumentOutline.prototype.GoTo;
CDocumentOutline.prototype["promote"] = CDocumentOutline.prototype.Promote;
CDocumentOutline.prototype["demote"] = CDocumentOutline.prototype.Demote;
CDocumentOutline.prototype["insertHeader"] = CDocumentOutline.prototype.InsertHeader;
CDocumentOutline.prototype["insertSubHeader"] = CDocumentOutline.prototype.InsertSubHeader;
CDocumentOutline.prototype["isFirstItemNotHeader"] = CDocumentOutline.prototype.IsFirstItemNotHeader;
CDocumentOutline.prototype["selectContent"] = CDocumentOutline.prototype.SelectContent;
CDocumentOutline.prototype["isEmptyItem"] = CDocumentOutline.prototype.IsEmptyItem;