510 lines
16 KiB
JavaScript
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;
|