/* * (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"; // Import var g_oTableId = AscCommon.g_oTableId; var g_oTextMeasurer = AscCommon.g_oTextMeasurer; var c_oAscShdNil = Asc.c_oAscShdNil; var c_oAscRevisionsChangeType = Asc.c_oAscRevisionsChangeType; var reviewtype_Common = 0x00; var reviewtype_Remove = 0x01; var reviewtype_Add = 0x02; function CSpellCheckerMarks() { this.len = 0; this.data = null; this.Check = function(len) { if (len <= this.len) { for (var i = 0; i < len; i++) this.data[i] = 0; return this.data; } this.len = len; this.data = typeof(Int8Array) !== undefined ? new Int8Array(this.len) : new Array(this.len); return this.data; }; } var g_oSpellCheckerMarks = new CSpellCheckerMarks(); /** * * @param Paragraph * @param bMathRun * @constructor * @extends {CParagraphContentWithContentBase} */ function ParaRun(Paragraph, bMathRun) { CParagraphContentWithContentBase.call(this); this.Id = AscCommon.g_oIdCounter.Get_NewId(); // Id данного элемента this.Type = para_Run; // тип данного элемента this.Paragraph = Paragraph; // Ссылка на параграф this.Pr = new CTextPr(); // Текстовые настройки данного run this.Content = []; // Содержимое данного run this.State = new CParaRunState(); // Положение курсора и селекта в данного run this.Selection = this.State.Selection; this.CompiledPr = AscWord.g_textPrCache.add(new AscWord.CTextPr()); // Скомпилированные настройки this.RecalcInfo = new CParaRunRecalcInfo(); // Флаги для пересчета (там же флаг пересчета стиля) this.CollPrChangeMine = false; this.CollPrChangeColor = null; // Если задан, значит это цвет того, кто менял this.CollaborativeMarks = new CRunCollaborativeMarks(); this.m_oContentChanges = new AscCommon.CContentChanges(); // список изменений(добавление/удаление элементов) this.NearPosArray = []; this.SearchMarks = []; this.SpellingMarks = []; this.ReviewInfo = undefined; if (editor && !editor.isPresentationEditor && editor.WordControl && editor.WordControl.m_oLogicDocument && true === editor.WordControl.m_oLogicDocument.IsTrackRevisions() && !editor.WordControl.m_oLogicDocument.RecalcTableHeader && !editor.WordControl.m_oLogicDocument.MoveDrawing && !(this.Paragraph && !this.Paragraph.bFromDocument)) { this.ReviewInfo = AscWord.ReviewInfo.createAdd(); this.ReviewInfo.Update(); } if (bMathRun) { this.Type = para_Math_Run; // запомним позицию для recalculateCursorPosition, когда Run пустой this.pos = new CMathPosition(); this.ParaMath = null; this.Parent = null; this.ArgSize = 0; this.size = new CMathSize(); this.MathPrp = new CMPrp(); this.bEqArray = false; } this.CompositeInput = null; // Добавляем данный класс в таблицу Id (обязательно в конце конструктора) AscCommon.g_oTableId.Add(this, this.Id); if (this.Paragraph && !this.Paragraph.bFromDocument &&AscCommon.History.CanAddChanges()) { this.Save_StartState(); } } ParaRun.prototype = Object.create(CParagraphContentWithContentBase.prototype); ParaRun.prototype.constructor = ParaRun; ParaRun.prototype.Get_Type = function() { return this.Type; }; //----------------------------------------------------------------------------------- // Функции для работы с Id //----------------------------------------------------------------------------------- ParaRun.prototype.Get_Id = function() { return this.Id; }; ParaRun.prototype.GetId = function() { return this.Id; }; ParaRun.prototype.IsRun = function() { return true; }; ParaRun.prototype.Set_ParaMath = function(ParaMath, Parent) { this.ParaMath = ParaMath; this.Parent = Parent; for(var i = 0; i < this.Content.length; i++) { this.Content[i].relate(this); } }; ParaRun.prototype.Save_StartState = function() { this.StartState = new CParaRunStartState(this); }; ParaRun.prototype.SetParagraph = function(oParagraph) { this.Paragraph = oParagraph; for (let nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { let oItem = this.Content[nPos]; if (oItem.IsDrawing()) oItem.SetParent(oParagraph); } }; //----------------------------------------------------------------------------------- // Функции для работы с содержимым данного рана //----------------------------------------------------------------------------------- ParaRun.prototype.Copy = function(Selected, oPr) { if (!oPr) oPr = {}; var isCopyReviewPr = oPr.CopyReviewPr; let isMathRun = this.IsMathRun(); let NewRun = new AscWord.Run(undefined, isMathRun); NewRun.Set_Pr(this.Pr.Copy(isCopyReviewPr, oPr)); var oLogicDocument = this.GetLogicDocument(); if(oPr && oPr.Comparison) { oPr.Comparison.checkCopyParaRun(NewRun, this); } else if (true === isCopyReviewPr || (oLogicDocument && (oLogicDocument.RecalcTableHeader || oLogicDocument.MoveDrawing))) { let reviewType = this.GetReviewType(); let reviewInfo = this.GetReviewInfo(); if (reviewInfo && !(oLogicDocument && (oLogicDocument.RecalcTableHeader || oLogicDocument.MoveDrawing))) reviewInfo.SetMove(Asc.c_oAscRevisionsMove.NoMove); NewRun.SetReviewTypeWithInfo(reviewType, reviewInfo ? reviewInfo.Copy() : undefined); } else if (oLogicDocument && true === oLogicDocument.IsTrackRevisions()) { NewRun.SetReviewType(reviewtype_Add); } if (isMathRun) NewRun.Set_MathPr(this.MathPrp.Copy()); var StartPos = 0; var EndPos = this.Content.length; if (true === Selected && true === this.State.Selection.Use) { StartPos = this.State.Selection.StartPos; EndPos = this.State.Selection.EndPos; if (StartPos > EndPos) { StartPos = this.State.Selection.EndPos; EndPos = this.State.Selection.StartPos; } } else if (true === Selected && true !== this.State.Selection.Use) { EndPos = -1; } var CurPos, AddedPos, Item; if(oPr && oPr.Comparison) { var aCopyContent = []; for (CurPos = StartPos; CurPos < EndPos; CurPos++) { Item = this.Content[CurPos]; if (para_NewLine === Item.Type && oPr && ((oPr.SkipLineBreak && Item.IsLineBreak()) || (oPr.SkipPageBreak && Item.IsPageBreak()) || (oPr.SkipColumnBreak && Item.IsColumnBreak()))) { if (oPr.Paragraph && true !== oPr.Paragraph.IsEmpty()) { aCopyContent.push( new AscWord.CRunSpace()); } } else { // TODO: Как только перенесем para_End в сам параграф (как и нумерацию) убрать здесь if (para_End !== Item.Type && para_RevisionMove !== Item.Type && (para_Drawing !== Item.Type || Item.Is_Inline() || true !== oPr.SkipAnchors) && ((para_FootnoteReference !== Item.Type && para_EndnoteReference !== Item.Type) || true !== oPr.SkipFootnoteReference) && ((para_FieldChar !== Item.Type && para_InstrText !== Item.Type) || true !== oPr.SkipComplexFields)) { aCopyContent.push(Item.Copy(oPr)); } } } NewRun.ConcatToContent(aCopyContent); } else { for (CurPos = StartPos, AddedPos = 0; CurPos < EndPos; CurPos++) { Item = this.Content[CurPos]; if (para_NewLine === Item.Type && oPr && ((oPr.SkipLineBreak && Item.IsLineBreak()) || (oPr.SkipPageBreak && Item.IsPageBreak()) || (oPr.SkipColumnBreak && Item.IsColumnBreak()))) { if (oPr.Paragraph && true !== oPr.Paragraph.IsEmpty()) { NewRun.Add_ToContent(AddedPos, new AscWord.CRunSpace(), false); AddedPos++; } } else { // TODO: Как только перенесем para_End в сам параграф (как и нумерацию) убрать здесь if (para_End !== Item.Type && para_RevisionMove !== Item.Type && (para_Drawing !== Item.Type || Item.Is_Inline() || true !== oPr.SkipAnchors) && ((para_FootnoteReference !== Item.Type && para_EndnoteReference !== Item.Type) || true !== oPr.SkipFootnoteReference) && ((para_FieldChar !== Item.Type && para_InstrText !== Item.Type) || true !== oPr.SkipComplexFields)) { NewRun.Add_ToContent(AddedPos, Item.Copy(oPr), false); AddedPos++; } } } } return NewRun; }; ParaRun.prototype.Copy2 = function(oPr) { var NewRun = new ParaRun(this.Paragraph); NewRun.Set_Pr( this.Pr.Copy(undefined, oPr) ); if(oPr && oPr.Comparison) { oPr.Comparison.checkCopyParaRun(NewRun, this); } var StartPos = 0; var EndPos = this.Content.length; var CurPos; if(oPr && oPr.Comparison) { var aContentToInsert = []; for (CurPos = StartPos; CurPos < EndPos; CurPos++ ) { aContentToInsert.push(this.Content[CurPos].Copy(oPr)); } NewRun.ConcatToContent(aContentToInsert); } else { for (CurPos = StartPos; CurPos < EndPos; CurPos++ ) { var Item = this.Content[CurPos]; NewRun.Add_ToContent( CurPos - StartPos, Item.Copy(oPr), false ); } } return NewRun; }; ParaRun.prototype.createDuplicateForSmartArt = function(oPr) { var NewRun = new ParaRun(this.Paragraph); NewRun.Set_Pr(this.Pr.createDuplicateForSmartArt(oPr)); var StartPos = 0; var EndPos = this.Content.length; var CurPos; for (CurPos = StartPos; CurPos < EndPos; CurPos++ ) { var Item = this.Content[CurPos]; NewRun.Add_ToContent( CurPos - StartPos, Item.Copy(oPr), false ); } return NewRun; }; ParaRun.prototype.CopyContent = function(Selected) { return [this.Copy(Selected, {CopyReviewPr : true})]; }; ParaRun.prototype.GetSelectedContent = function(oSelectedContent) { if (oSelectedContent.IsTrackRevisions()) { var nReviewType = this.GetReviewType(); var oReviewInfo = this.GetReviewInfo(); if (reviewtype_Add === nReviewType || reviewtype_Common === nReviewType) { var oRun = this.Copy(true, {CopyReviewPr : false}); if (reviewtype_Common !== nReviewType && (oReviewInfo.IsMovedTo() || oReviewInfo.IsMovedFrom())) oSelectedContent.SetMovedParts(true); if (oSelectedContent.IsMoveTrack()) oSelectedContent.AddRunForMoveTrack(oRun); for (var nPos = 0, nCount = oRun.Content.length; nPos < nCount; ++nPos) { if (oRun.Content[nPos].Type === para_RevisionMove) { oRun.RemoveFromContent(nPos, 1); nPos--; nCount--; oSelectedContent.SetMovedParts(true); } } return oRun; } } else { return this.Copy(true, {CopyReviewPr : true}); } return null; }; ParaRun.prototype.GetAllDrawingObjects = function(arrDrawingObjects) { if (!arrDrawingObjects) arrDrawingObjects = []; for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var oItem = this.Content[nPos]; if (para_Drawing === oItem.Type) { arrDrawingObjects.push(oItem); oItem.GetAllDrawingObjects(arrDrawingObjects); } } return arrDrawingObjects; }; ParaRun.prototype.Clear_ContentChanges = function() { this.m_oContentChanges.Clear(); }; ParaRun.prototype.Add_ContentChanges = function(Changes) { this.m_oContentChanges.Add( Changes ); }; ParaRun.prototype.Refresh_ContentChanges = function() { this.m_oContentChanges.Refresh(); }; ParaRun.prototype.Get_Text = function(Text) { if (null === Text.Text) return; var ContentLen = this.Content.length; for (var CurPos = 0; CurPos < ContentLen; CurPos++) { var Item = this.Content[CurPos]; var ItemType = Item.Type; var bBreak = false; switch (ItemType) { case para_Drawing: case para_PageNum: case para_PageCount: { if (true === Text.BreakOnNonText) { Text.Text = null; bBreak = true; } break; } case para_End: { if (true === Text.BreakOnNonText) { Text.Text = null; bBreak = true; break; } let oParagraph = this.GetParagraph(); if (oParagraph && null === oParagraph.Get_DocumentNext() && oParagraph.IsTableCellContent()) { if (!oParagraph.Parent.IsLastTableCellInRow(false)) Text.Text += undefined !== Text.TableCellSeparator ? Text.TableCellSeparator : '\t'; else Text.Text += undefined !== Text.TableRowSeparator ? Text.TableRowSeparator : '\r\n'; } else { Text.Text += undefined !== Text.ParaSeparator ? Text.ParaSeparator : '\r\n'; } break; } case para_Text : { Text.Text += String.fromCharCode(Item.Value); break; } case para_NewLine: { Text.Text += undefined !== Text.NewLineSeparator ? Text.NewLineSeparator : "\r"; break; } case para_Tab: { Text.Text += undefined !== Text.TabSymbol ? Text.TabSymbol : " "; break; } case para_Space: { Text.Text += " "; break; } } if (true === bBreak) break; } }; /** * Получем текст из данного рана * @param oText * @returns {string} */ ParaRun.prototype.GetText = function(oText) { if (!oText) { oText = { Text : "" }; } this.Get_Text(oText); return oText.Text; }; /** * * @param {MathTextAndStyles | boolean} oMathText * @param {boolean} isSelectedText * @constructor */ ParaRun.prototype.GetTextOfElement = function(oMathText, isSelectedText) { oMathText = new AscMath.MathTextAndStyles(oMathText); let isLatex = oMathText.IsLaTeX(); let nStartPos = (isSelectedText == true ? Math.min(this.Selection.StartPos, this.Selection.EndPos) : 0); let nEndPos = (isSelectedText == true ? Math.max(this.Selection.StartPos, this.Selection.EndPos) : this.Content.length); let isStrFont = false; if (oMathText.IsLaTeX() && this.math_autocorrection) { if (this.math_autocorrection.getIsMathRm() || this.math_autocorrection.getIsText()) { let str = ''; for (let i = nStartPos; i < nEndPos; i++) { let oCurrentElement = this.Content[i]; str += oCurrentElement.GetTextOfElement().GetText(); } if (this.math_autocorrection.getIsMathRm()) oMathText.AddText(new AscMath.MathText('\\mathrm{' + str + '}', this)); else if (this.math_autocorrection.getIsText()) oMathText.AddText(new AscMath.MathText('\\text{' + str + '}', this)); return oMathText; } } // [Unicode] Investigate the mechanism for converting an escaped backslash. Information about separating it // into a separate Run is not enough. for (let i = nStartPos; i < nEndPos; i++) { let oCurrentElement = this.Content[i]; let strCurrentElement = oCurrentElement.GetTextOfElement().GetText(); if (this.Content.length === 1 && oCurrentElement.value === 11034) return oMathText; let oLast = oMathText.GetLastContent(); let strLast = "" if (oLast) strLast = oLast.text[oLast.text.length - 1]; // for LaTeX space processing while convert to professional mode if (oMathText.IsDefaultText) { oMathText.AddText(new AscMath.MathText(strCurrentElement, this)); continue; } let arrFontContent = oMathText.IsLaTeX() ? AscMath.GetLaTeXFont[strCurrentElement] : undefined; let strMathFontName = arrFontContent ? AscMath.oStandardFont[arrFontContent[0]] : undefined; if (!strMathFontName && isLatex) { let strTemp = AscMath.SymbolsToLaTeX[strCurrentElement]; if (strTemp) strCurrentElement = strTemp; } if (strMathFontName) { if (!isStrFont) oMathText.AddText(new AscMath.MathText(strMathFontName + "{", this)); isStrFont = true; oMathText.AddText(new AscMath.MathText(arrFontContent[1], this)); } else if (isStrFont && !arrFontContent) { isStrFont = false; oMathText.AddText(new AscMath.MathText('}', this)); } else { if (oMathText.IsLaTeX()) { if (strCurrentElement === " " && strLast !== "\\") //normal space oMathText.AddText(new AscMath.MathText('\\ ', this)) else if (strCurrentElement === " ") oMathText.AddText(new AscMath.MathText("\\quad", this)); // else if (strCurrentElement === " ") // oMathText.AddText(new AscMath.MathText("\\:", this)); // else if (strCurrentElement === " ") // oMathText.AddText(new AscMath.MathText("\\;", this)); else { oMathText.AddText(new AscMath.MathText(strCurrentElement, this)); } } else { // in Word if slash in separate ParaRun -> slash interpreted as an escaped slash // if (strCurrentElement === "/" && this.Content.length === 1 && strLast !== "\\") // { // let oEscSlash = new AscMath.MathText("\\/", this); // let oAddData = oEscSlash.GetAdditionalData(); // let oMathMetaData = oAddData.GetMathMetaData(); // oMathMetaData.setIsEscapedSlash(); // oMathText.AddText(oEscSlash, this); // } // else // { let mathText = new AscMath.MathText(strCurrentElement, this); let additionalData = mathText.GetAdditionalData(); if (this.math_autocorrection) additionalData.metaData = this.math_autocorrection.Copy(); oMathText.AddText(mathText); //} } } } if (isStrFont) oMathText.AddText(new AscMath.MathText('}', this)); return oMathText; }; ParaRun.prototype.MathAutocorrection_GetBracketsOperatorsInfo = function (isLaTeX) { const arrBracketsInfo = []; let isOpen = false; let isClose = false; for (let intCounter = 0; intCounter < this.Content.length; intCounter++) { let strContent = String.fromCharCode(this.Content[intCounter].value); let intCount = null; if ((strContent === "{" || strContent === "}") && isLaTeX) continue; if (strContent === "├") { isOpen = true; continue; } else if (strContent === "┤") { if (intCounter === this.Content.length - 1) { arrBracketsInfo.push([intCounter - 1, 1]); } else { isClose = true; continue; } } if (AscMath.MathLiterals.lBrackets.SearchU(strContent)) intCount = -1; else if (AscMath.MathLiterals.rBrackets.SearchU(strContent)) intCount = 1; else if (AscMath.MathLiterals.lrBrackets.SearchU(strContent)) intCount = 0; else if (AscMath.MathLiterals.operator.SearchU(strContent)) intCount = 2; if (intCount === null && isOpen) { arrBracketsInfo.push([intCounter - 1, -1]); isOpen = false; } else if (intCount === null && isClose) { arrBracketsInfo.push([intCounter - 1, 1]); isClose = false; } if (intCount !== null) arrBracketsInfo.push([intCounter, intCount]); } return arrBracketsInfo; } ParaRun.prototype.MathAutocorrection_GetOperatorInfo = function () { const arrOperatorContent = []; for (let intCounter = 0; intCounter < this.Content.length; intCounter++) { let strContent = String.fromCharCode(this.Content[intCounter].value); if (AscMath.MathLiterals.operator.SearchU(strContent)) arrOperatorContent.push(intCounter); } return arrOperatorContent; } ParaRun.prototype.MathAutocorrection_GetSlashesInfo = function () { const arrOperatorContent = []; for (let intCounter = 0; intCounter < this.Content.length; intCounter++) { let strContent = String.fromCharCode(this.Content[intCounter].value); if (strContent === "\\") arrOperatorContent.push(intCounter); } return arrOperatorContent; } ParaRun.prototype.MathAutocorrection_IsLastElement = function(type) { if (this.Content.length === 0) return false; let oLastElement = this.Content[this.Content.length - 1]; let strLastElement = String.fromCharCode(oLastElement.value); return type.SearchU(strLastElement); } ParaRun.prototype.MathAutoCorrection_DeleteLastSpace = function() { if (this.Content.length === 0) return false; let oLastElement = this.Content[this.Content.length - 1]; if (oLastElement.value === 32) { this.Remove_FromContent(this.Content.length - 1, 1); return true; } return false; } // Проверяем пустой ли ран ParaRun.prototype.Is_Empty = function(oProps) { var SkipAnchor = (undefined !== oProps ? oProps.SkipAnchor : false); let SkipDrawing = (undefined !== oProps ? oProps.SkipDrawing : false); var SkipEnd = (undefined !== oProps ? oProps.SkipEnd : false); var SkipPlcHldr = (undefined !== oProps ? oProps.SkipPlcHldr : false); var SkipNewLine = (undefined !== oProps ? oProps.SkipNewLine : false); var SkipCF = (undefined !== oProps ? oProps.SkipComplexFields : false); var SkipSpace = (undefined !== oProps ? oProps.SkipSpace : false); var SkipTab = (undefined !== oProps ? oProps.SkipTab : false); var nCount = this.Content.length; if (true !== SkipAnchor && true !== SkipEnd && true !== SkipPlcHldr && true !== SkipNewLine && true !== SkipCF && true !== SkipSpace) { if (nCount > 0) return false; else return true; } else { for (var nCurPos = 0; nCurPos < nCount; ++nCurPos) { var oItem = this.Content[nCurPos]; var nType = oItem.Type; if ((true !== SkipAnchor || para_Drawing !== nType || false !== oItem.Is_Inline()) && (true !== SkipDrawing || para_Drawing !== nType) && (true !== SkipEnd || para_End !== nType) && (true !== SkipPlcHldr || true !== oItem.IsPlaceholder()) && (true !== SkipNewLine || para_NewLine !== nType) && (true !== SkipCF || (para_InstrText !== nType && para_FieldChar !== nType) && (true !== SkipSpace || para_Space !== nType) && (true !== SkipTab || para_Tab !== nType))) return false; } return true; } }; ParaRun.prototype.Is_CheckingNearestPos = function() { if (this.NearPosArray.length > 0) return true; return false; }; // Начинается ли данный ран с новой строки ParaRun.prototype.IsStartFromNewLine = function() { if (this.protected_GetLinesCount() < 2 || 0 !== this.protected_GetRangeStartPos(1, 0)) return false; return true; }; /** * Добавляем новый элменет в текущую позицию * @param {AscWord.CRunElementBase} oItem */ ParaRun.prototype.Add = function(oItem) { var oRun; if (!this.IsMathRun() && !(oItem instanceof CMathText)) oRun = this.CheckRunBeforeAdd(oItem); if (!oRun) oRun = this; oRun.private_AddItemToRun(oRun.State.ContentPos, oItem); var nFlags = 0; if (para_Run === oRun.Type && (nFlags = oItem.GetAutoCorrectFlags())) oRun.ProcessAutoCorrect(oRun.State.ContentPos - 1, nFlags); }; /** * Ищем подходящий ран для добавления текста в режиме рецензирования (если нужно создаем новый), если возвращается * null, значит текущий ран подходит. * @param {?ParaRun} oNewRun * @returns {?ParaRun} */ ParaRun.prototype.private_CheckTrackRevisionsBeforeAdd = function(oNewRun) { var TrackRevisions = false; if (this.Paragraph && this.Paragraph.LogicDocument) TrackRevisions = this.Paragraph.LogicDocument.IsTrackRevisions(); var ReviewType = this.GetReviewType(); if ((true === TrackRevisions && (reviewtype_Add !== ReviewType || true !== this.ReviewInfo.IsCurrentUser())) || (false === TrackRevisions && reviewtype_Common !== ReviewType)) { var DstReviewType = true === TrackRevisions ? reviewtype_Add : reviewtype_Common; if (oNewRun) { oNewRun.SetReviewType(DstReviewType); return oNewRun; } // Если мы стоим в конце рана, тогда проверяем следующий элемент родительского класса, аналогично если мы стоим // в начале рана, проверяем предыдущий элемент родительского класса. var Parent = this.Get_Parent(); if (null === Parent) return null; // Ищем данный элемент в родительском классе var RunPos = this.private_GetPosInParent(Parent); if (-1 === RunPos) return null; var CurPos = this.State.ContentPos; if (0 === CurPos && RunPos > 0) { var PrevElement = Parent.Content[RunPos - 1]; if (para_Run === PrevElement.Type && DstReviewType === PrevElement.GetReviewType() && true === this.Pr.Is_Equal(PrevElement.Pr) && PrevElement.ReviewInfo && true === PrevElement.ReviewInfo.IsCurrentUser()) { PrevElement.State.ContentPos = PrevElement.Content.length; return PrevElement; } } if (this.Content.length === CurPos && (RunPos < Parent.Content.length - 2 || (RunPos < Parent.Content.length - 1 && !(Parent instanceof Paragraph)))) { var NextElement = Parent.Content[RunPos + 1]; if (para_Run === NextElement.Type && DstReviewType === NextElement.GetReviewType() && true === this.Pr.Is_Equal(NextElement.Pr) && NextElement.ReviewInfo && true === NextElement.ReviewInfo.IsCurrentUser()) { NextElement.State.ContentPos = 0; return NextElement; } } var NewRun = new ParaRun(this.Paragraph, this.IsMathRun()); NewRun.Set_Pr(this.Pr.Copy()); NewRun.SetReviewType(DstReviewType); NewRun.State.ContentPos = 0; if (0 === CurPos) { Parent.Add_ToContent(RunPos, NewRun); } else if (this.Content.length === CurPos) { Parent.Add_ToContent(RunPos + 1, NewRun); } else { var OldReviewInfo = (this.ReviewInfo ? this.ReviewInfo.Copy() : undefined); var OldReviewType = this.GetReviewType(); // Нужно разделить данный ран в текущей позиции var RightRun = this.Split2(CurPos); Parent.Add_ToContent(RunPos + 1, NewRun); Parent.Add_ToContent(RunPos + 2, RightRun); this.SetReviewTypeWithInfo(OldReviewType, OldReviewInfo); RightRun.SetReviewTypeWithInfo(OldReviewType, OldReviewInfo); } return NewRun; } return oNewRun; }; /** * Проверяем корректность настроек рана перед добавлением элемента * @param {?ParaRun} oNewRun * @param oItem */ ParaRun.prototype.private_CheckTextScriptBeforeAdd = function(oNewRun, oItem) { if (!oItem || !oItem.IsText()) return oNewRun; let script = oItem.GetScript(); if (AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED === script || AscFonts.HB_SCRIPT.HB_SCRIPT_COMMON === script) return oNewRun; let oPr = this.Pr; // TODO: Когда будет обрабатывать RTL добавить тут let isAddRTL = false, isRemoveRTL = false; let isAddCS = (AscCommon.IsComplexScript(oItem.GetCodePoint()) && !oPr.CS); let isRemoveCS = (!AscCommon.IsComplexScript(oItem.GetCodePoint()) && oPr.CS); if (!oNewRun && (isAddCS || isRemoveCS || isAddRTL || isRemoveRTL)) { let runToApply; if (this.IsOnlyCommonTextScript()) { runToApply = this; } else { oNewRun = this.private_SplitRunInCurPos(); runToApply = oNewRun; } if (isAddCS) runToApply.ApplyComplexScript(true); else if (isRemoveCS) runToApply.ApplyComplexScript(false); } return oNewRun; }; /** * Проверяем, не является ли это ран с символом конца параграфа * @param {!ParaRun} oNewRun * @returns {?ParaRun} */ ParaRun.prototype.private_CheckParaEndRunBeforeAdd = function(oNewRun) { if (!oNewRun && this.IsParaEndRun()) oNewRun = this.private_SplitRunInCurPos(); return oNewRun; }; /** * Проверяем язык ввода * @param {!ParaRun} oNewRun * @param {CDocument}oLogicDocument * @param {!ParaRun} oNewRun * @returns {?ParaRun} */ ParaRun.prototype.private_CheckLanguageBeforeAdd = function(oNewRun, oLogicDocument) { if (!oLogicDocument) return oNewRun; var oApi = oLogicDocument.GetApi(); // Специальный код, связанный с обработкой изменения языка ввода при наборе. if (true === oLogicDocument.CheckLanguageOnTextAdd && oApi) { var nRequiredLanguage = oApi.asc_getKeyboardLanguage(); var nCurrentLanguage = this.Get_CompiledPr(false).Lang.Val; if (-1 !== nRequiredLanguage && nRequiredLanguage !== nCurrentLanguage) { var oNewLang = new CLang(); oNewLang.Val = nRequiredLanguage; if (oNewRun) { oNewRun.Set_Lang(oNewLang); } else if (this.IsEmpty()) { this.Set_Lang(oNewLang); } else { oNewRun = this.private_SplitRunInCurPos(); if (oNewRun) oNewRun.Set_Lang(oNewLang); } } } return oNewRun; }; /** * Провяеряем добавление ссылки на сноску или добавление текста рядом с ссылкой на сноску * @param {!ParaRun} oNewRun * @param {AscWord.CRunElementBase} oItem * @param {CDocument} oLogicDocument * @returns {?ParaRun} */ ParaRun.prototype.private_CheckFootnoteReferencesBeforeAdd = function(oNewRun, oItem, oLogicDocument) { if (!oLogicDocument || !this.Paragraph || !this.Paragraph.bFromDocument) return oNewRun; // Специальный код, связанный с работой сносок: // 1. При добавлении сноски мы ее оборачиваем в отдельный ран со специальным стилем. // 2. Если мы находимся в ране со специальным стилем сносок и следующий или предыдущий элемент и есть сноска, тогда // мы добавляем элемент (если это не ссылка на сноску) в новый ран без стиля для сносок. var oStyles = oLogicDocument.GetStyles(); if (oItem && (para_FootnoteRef === oItem.Type || para_FootnoteReference === oItem.Type || para_EndnoteRef === oItem.Type || para_EndnoteReference === oItem.Type)) { var isFootnote = (para_FootnoteRef === oItem.Type || para_FootnoteReference === oItem.Type); if (oNewRun) { oNewRun.SetVertAlign(undefined); oNewRun.SetRStyle(isFootnote ? oStyles.GetDefaultFootnoteReference() : oStyles.GetDefaultEndnoteReference()); } else if (this.IsEmpty()) { this.SetVertAlign(undefined); this.SetRStyle(isFootnote ? oStyles.GetDefaultFootnoteReference() : oStyles.GetDefaultEndnoteReference()); } else { oNewRun = this.private_SplitRunInCurPos(); if (oNewRun) { oNewRun.SetVertAlign(undefined); oNewRun.SetRStyle(isFootnote ? oStyles.GetDefaultFootnoteReference() : oStyles.GetDefaultEndnoteReference()); } } } else if (true === this.IsCurPosNearFootEndnoteReference()) { if (!oNewRun) oNewRun = this.private_SplitRunInCurPos(); if (oNewRun) oNewRun.SetVertAlign(AscCommon.vertalign_Baseline); } return oNewRun; }; /** * Проверяем выделение текста перед добавление нового элемента * @param {!ParaRun} oNewRun * @returns {?ParaRun} */ ParaRun.prototype.private_CheckHighlightBeforeAdd = function(oNewRun) { // Специальный код с обработкой выделения (highlight) // Текст, который пишем до или после выделенного текста делаем без выделения. if ((0 === this.State.ContentPos || this.Content.length === this.State.ContentPos) && highlight_None !== this.Get_CompiledPr(false).HighLight) { var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(Parent); if (null !== Parent && -1 !== RunPos) { if ((0 === this.State.ContentPos && (0 === RunPos || Parent.Content[RunPos - 1].Type !== para_Run || highlight_None === Parent.Content[RunPos - 1].Get_CompiledPr(false).HighLight)) || (this.Content.length === this.State.ContentPos && (RunPos === Parent.Content.length - 1 || para_Run !== Parent.Content[RunPos + 1].Type || highlight_None === Parent.Content[RunPos + 1].Get_CompiledPr(false).HighLight) || (RunPos === Parent.Content.length - 2 && Parent instanceof Paragraph))) { if (!oNewRun) oNewRun = this.private_SplitRunInCurPos(); if (oNewRun) oNewRun.Set_HighLight(highlight_None); } } } return oNewRun; }; /** * Проверяем выделение текста перед добавление нового элемента * @param {!ParaRun} oNewRun * @returns {?ParaRun} */ ParaRun.prototype.private_CheckHighlightColorBeforeAdd = function(oNewRun) { // Специальный код с обработкой выделения (highlight) // Текст, который пишем до или после выделенного текста делаем без выделения. if ((0 === this.State.ContentPos || this.Content.length === this.State.ContentPos) && undefined !== this.Get_CompiledPr(false).HighlightColor) { var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(Parent); if (null !== Parent && -1 !== RunPos) { if ((0 === this.State.ContentPos && (0 === RunPos || Parent.Content[RunPos - 1].Type !== para_Run || undefined === Parent.Content[RunPos - 1].Get_CompiledPr(false).HighlightColor)) || (this.Content.length === this.State.ContentPos && (RunPos === Parent.Content.length - 1 || para_Run !== Parent.Content[RunPos + 1].Type || undefined === Parent.Content[RunPos + 1].Get_CompiledPr(false).HighlightColor) || (RunPos === Parent.Content.length - 2 && Parent instanceof Paragraph))) { if (!oNewRun) oNewRun = this.private_SplitRunInCurPos(); if (oNewRun) { oNewRun.SetHighlightColor(undefined); } } } } return oNewRun; }; /** * Проверяем принудительный перенос в начале математического рана * @param {!ParaRun} oNewRun * @returns {?ParaRun} */ ParaRun.prototype.private_CheckMathBreakOperatorBeforeAdd = function(oNewRun) { // Если в начале текущего Run идет принудительный перенос => создаем новый Run if (!oNewRun && para_Math_Run === this.Type && 0 === this.State.ContentPos && true === this.Is_StartForcedBreakOperator()) oNewRun = this.private_SplitRunInCurPos(); return oNewRun; }; /** * Функция проверяет настройки рана, перед добавлением внутрь элементов * Если необходимо, то добавляется новый ран с необходимыми настройками * @param {?AscWord.CRunElementBase} oItem * @returns {?ParaRun} */ ParaRun.prototype.CheckRunBeforeAdd = function(oItem) { if (this.GetParentForm()) return null; var oNewRun = null; var oLogicDocument = this.GetLogicDocument(); oNewRun = this.private_CheckParaEndRunBeforeAdd(oNewRun); oNewRun = this.private_CheckLanguageBeforeAdd(oNewRun, oLogicDocument); oNewRun = this.private_CheckFootnoteReferencesBeforeAdd(oNewRun, oItem, oLogicDocument); oNewRun = this.private_CheckHighlightBeforeAdd(oNewRun); oNewRun = this.private_CheckHighlightColorBeforeAdd(oNewRun); oNewRun = this.private_CheckMathBreakOperatorBeforeAdd(oNewRun); oNewRun = this.private_CheckTextScriptBeforeAdd(oNewRun, oItem); if (oNewRun) oNewRun.MoveCursorToStartPos(); // В функции private_CheckTrackRevisionsBeforeAdd возможно, что вернется не новый, а существующий левый или правый ран // и нужно брать позицию из рана, поэтому сдвигаться в начало рана нельзя oNewRun = this.private_CheckTrackRevisionsBeforeAdd(oNewRun); if (oNewRun) oNewRun.SetThisElementCurrentInParagraph(); return oNewRun; }; /** * Специальная функция проверяет, что в ране присутствуют текстовые элементы только из общих скриптов (т.е. не * принадлижащие какой-то конкретной пиьменности). Если текстовых элементов нет вообще, то вернется false * @returns {boolean} */ ParaRun.prototype.IsOnlyCommonTextScript = function() { let isCommonScript = false; for (let index = 0, count = this.Content.length; index < count; ++index) { let item = this.Content[index]; if (item.IsText()) { let script = item.GetScript(); if (AscFonts.HB_SCRIPT.HB_SCRIPT_INHERITED === script || AscFonts.HB_SCRIPT.HB_SCRIPT_COMMON === script) isCommonScript = true; else return false; } } return isCommonScript; }; /** * Is a run inside smartArt * @param [bReturnSmartArtShape] {boolean} * @returns {boolean|null|AscFormat.CShape} */ ParaRun.prototype.IsInsideSmartArtShape = function (bReturnSmartArtShape) { const oParagraph = this.GetParagraph(); if (oParagraph) { return oParagraph.IsInsideSmartArtShape(bReturnSmartArtShape); } return bReturnSmartArtShape ? null : false; }; /** * Проверяем, предзназначен ли данный ран чисто для математических формул. * @returns {boolean} */ ParaRun.prototype.IsMathRun = function() { return this.Type === para_Math_Run ? true : false; }; ParaRun.prototype.private_SplitRunInCurPos = function() { var NewRun = null; var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(); if (null !== Parent && -1 !== RunPos) { // Если мы стоим в начале рана, тогда добавим новый ран в начало, если мы стоим в конце рана, тогда // добавим новый ран после текущего, а если мы в середине рана, тогда надо разбивать текущий ран. NewRun = new ParaRun(this.Paragraph, para_Math_Run === this.Type); NewRun.Set_Pr(this.Pr.Copy()); var CurPos = this.State.ContentPos; if (0 === CurPos) { Parent.Add_ToContent(RunPos, NewRun); } else if (this.Content.length === CurPos) { Parent.Add_ToContent(RunPos + 1, NewRun); } else { // Нужно разделить данный ран в текущей позиции var RightRun = this.Split2(CurPos); Parent.Add_ToContent(RunPos + 1, NewRun); Parent.Add_ToContent(RunPos + 2, RightRun); } } return NewRun; }; ParaRun.prototype.IsCurPosNearFootEndnoteReference = function() { if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument) { var oStyles = this.Paragraph.LogicDocument.Get_Styles(); var nCurPos = this.State.ContentPos; if (!oStyles) return false; if ((this.GetRStyle() === oStyles.GetDefaultFootnoteReference() && ((nCurPos > 0 && this.Content[nCurPos - 1] && (para_FootnoteRef === this.Content[nCurPos - 1].Type || para_FootnoteReference === this.Content[nCurPos - 1].Type)) || (nCurPos < this.Content.length && this.Content[nCurPos] && (para_FootnoteRef === this.Content[nCurPos].Type || para_FootnoteReference === this.Content[nCurPos].Type)))) || (this.GetRStyle() === oStyles.GetDefaultEndnoteReference() && ((nCurPos > 0 && this.Content[nCurPos - 1] && (para_EndnoteRef === this.Content[nCurPos - 1].Type || para_EndnoteReference === this.Content[nCurPos - 1].Type)) || (nCurPos < this.Content.length && this.Content[nCurPos] && (para_EndnoteRef === this.Content[nCurPos].Type || para_EndnoteReference === this.Content[nCurPos].Type))))) return true; } return false; }; ParaRun.prototype.private_AddItemToRun = function(nPos, Item) { if ((para_FootnoteReference === Item.Type || para_EndnoteReference === Item.Type) && true === Item.IsCustomMarkFollows() && undefined !== Item.GetCustomText()) { this.AddToContent(nPos, Item, true); this.AddText(Item.GetCustomText(), nPos + 1); } else { this.Add_ToContent(nPos, Item, true); } }; /** * Очищаем все содержимое данного рана */ ParaRun.prototype.ClearContent = function() { if (this.Content.length <= 0) return; this.RemoveFromContent(0, this.Content.length, true); }; ParaRun.prototype.Remove = function(Direction, bOnAddText) { var TrackRevisions = null; if (this.Paragraph && this.Paragraph.LogicDocument) TrackRevisions = this.Paragraph.LogicDocument.IsTrackRevisions(); var Selection = this.State.Selection; if (true === TrackRevisions && !this.CanDeleteInReviewMode()) { if (reviewtype_Remove === this.GetReviewType()) { // Тут мы ничего не делаем, просто перешагиваем через удаленный текст if (true !== Selection.Use) { var CurPos = this.State.ContentPos; if (Direction < 0) { while (CurPos > 0 && this.Content[CurPos - 1].IsDrawing() && !this.Content[CurPos - 1].IsInline()) CurPos--; if (CurPos <= 0) return false; this.State.ContentPos--; this.Make_ThisElementCurrent(); } else { if (CurPos >= this.Content.length || para_End === this.Content[CurPos].Type) return false; let oItem = this.Content[CurPos]; if (oItem.IsText()) { let oInfo = this.RemoveTextCluster(CurPos); oInfo.SetDocumentPositionHere(); } else { this.State.ContentPos++; this.Make_ThisElementCurrent(); } } } else { // Ничего не делаем } } else { if (true === Selection.Use) { // Мы должны данный ран разбить в начальной и конечной точках выделения и центральный ран пометить как // удаленный. var StartPos = Selection.StartPos; var EndPos = Selection.EndPos; if (StartPos > EndPos) { StartPos = Selection.EndPos; EndPos = Selection.StartPos; } var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(Parent); if (-1 !== RunPos) { var DeletedRun = null; if (StartPos <= 0 && EndPos >= this.Content.length) DeletedRun = this; else if (StartPos <= 0) { this.Split2(EndPos, Parent, RunPos); DeletedRun = this; } else if (EndPos >= this.Content.length) { DeletedRun = this.Split2(StartPos, Parent, RunPos); } else { this.Split2(EndPos, Parent, RunPos); DeletedRun = this.Split2(StartPos, Parent, RunPos); } DeletedRun.SetReviewType(reviewtype_Remove, true); DeletedRun.SelectAll(Selection.EndPos - Selection.StartPos); } } else { var CurPos = this.State.ContentPos; let oInfo; if (Direction < 0) { while (CurPos > 0 && this.Content[CurPos - 1].IsDrawing() && !this.Content[CurPos - 1].IsInline()) CurPos--; if (CurPos <= 0) return false; if (this.Content[CurPos - 1].IsDrawing() && this.Content[CurPos - 1].IsInline()) return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos - 1].GetId()); oInfo = this.RemoveItemInReview(CurPos, Direction); } else { if (CurPos >= this.Content.length || para_End === this.Content[CurPos].Type) return false; if (this.Content[CurPos].IsDrawing() && this.Content[CurPos].IsInline()) return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos].GetId()); if (this.Content[CurPos].IsText()) oInfo = this.RemoveTextCluster(CurPos); else oInfo = this.RemoveItemInReview(CurPos, Direction); } oInfo.SetDocumentPositionHere(); } } } else { if (true === Selection.Use) { var StartPos = Selection.StartPos; var EndPos = Selection.EndPos; if (StartPos > EndPos) { var Temp = StartPos; StartPos = EndPos; EndPos = Temp; } // Если в выделение попадает ParaEnd, тогда удаляем все кроме этого элемента if (true === this.Selection_CheckParaEnd()) { for (var CurPos = EndPos - 1; CurPos >= StartPos; CurPos--) { if (para_End !== this.Content[CurPos].Type) this.Remove_FromContent(CurPos, 1, true); } } else { this.Remove_FromContent(StartPos, EndPos - StartPos, true); } this.RemoveSelection(); this.State.ContentPos = StartPos; } else { var CurPos = this.State.ContentPos; if (Direction < 0) { while (CurPos > 0 && this.Content[CurPos - 1].IsDrawing() && !this.Content[CurPos - 1].IsInline()) CurPos--; if (CurPos <= 0) return false; if (this.Content[CurPos - 1].IsDrawing() && this.Content[CurPos - 1].IsInline()) { return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos - 1].GetId()); } else if (para_FieldChar === this.Content[CurPos - 1].Type) { var oComplexField = this.Content[CurPos - 1].GetComplexField(); if (oComplexField) { oComplexField.SelectField(); var oLogicDocument = (this.Paragraph && this.Paragraph.bFromDocument) ? this.Paragraph.LogicDocument : null; if (oLogicDocument) { oLogicDocument.Document_UpdateInterfaceState(); oLogicDocument.Document_UpdateSelectionState(); } } return true; } var oStyles = (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument) ? this.Paragraph.LogicDocument.GetStyles() : null; if (oStyles && 1 === this.Content.length && ((para_FootnoteReference === this.Content[0].Type && this.GetRStyle() === oStyles.GetDefaultFootnoteReference()) || (para_EndnoteReference === this.Content[0].Type && this.GetRStyle() === oStyles.GetDefaultEndnoteReference()))) this.SetRStyle(undefined); this.RemoveFromContent(CurPos - 1, 1, true); this.State.ContentPos = CurPos - 1; } else { while (CurPos < this.Content.length && this.Content[CurPos].IsDrawing() && !this.Content[CurPos].IsInline()) CurPos++; if (CurPos >= this.Content.length || para_End === this.Content[CurPos].Type) return false; if (this.Content[CurPos].IsDrawing() && this.Content[CurPos].IsInline()) { return this.Paragraph.Parent.Select_DrawingObject(this.Content[CurPos].GetId()); } else if (para_FieldChar === this.Content[CurPos].Type) { var oComplexField = this.Content[CurPos].GetComplexField(); if (oComplexField) { oComplexField.SelectField(); var oLogicDocument = (this.Paragraph && this.Paragraph.bFromDocument) ? this.Paragraph.LogicDocument : null; if (oLogicDocument) { oLogicDocument.Document_UpdateInterfaceState(); oLogicDocument.Document_UpdateSelectionState(); } } return true; } var oStyles = (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument) ? this.Paragraph.LogicDocument.GetStyles() : null; if (oStyles && 1 === this.Content.length && ((para_FootnoteReference === this.Content[0].Type && this.GetRStyle() === oStyles.GetDefaultFootnoteReference()) || (para_EndnoteReference === this.Content[0].Type && this.GetRStyle() === oStyles.GetDefaultEndnoteReference()))) this.SetRStyle(undefined); let oItem = this.Content[CurPos]; if (oItem.IsText() || oItem.IsMathText()) { let oInfo = this.RemoveTextCluster(CurPos); oInfo.SetDocumentPositionHere(); } else { this.RemoveFromContent(CurPos, 1, true); this.State.ContentPos = CurPos; } } } } return true; }; ParaRun.prototype.RemoveParaEnd = function() { let nEndPos = -1; let nCount = this.Content.length; for (let nPos = 0; nPos < nCount; ++nPos) { if (this.Content[nPos].IsParaEnd()) { nEndPos = nPos; break; } } if (-1 === nEndPos) return false; this.RemoveFromContent(nEndPos, nCount - nEndPos, true); return true; }; ParaRun.prototype.RemoveTextCluster = function(nPos) { let oParagraph = this.GetParagraph(); let oLogicDocument = this.GetLogicDocument(); let isTrack = oLogicDocument && oLogicDocument.IsTrackRevisions() && !this.CanDeleteInReviewMode(); if (!oParagraph || nPos >= this.Content.length || (!this.Content[nPos].IsText() && !this.Content[nPos].IsMathText())) return new CRunWithPosition(this, nPos); let oCurRun = this; if (!isTrack) { this.RemoveFromContent(nPos, 1, true); } else if (reviewtype_Remove !== this.GetReviewType()) { let oInfo = this.RemoveItemInReview(nPos, 1); oCurRun = oInfo.Run; nPos = oInfo.Pos; } else { nPos++; } let oNextInfo = oCurRun.GetNextRunElementEx(nPos); let oNext = oNextInfo ? oNextInfo.Element : null; if (!oNext || (!oNext.IsText() && !oNext.IsMathText()) || !oNext.IsCombiningMark()) return new CRunWithPosition(oCurRun, nPos); let oContentPos = oNextInfo.Pos; let nInRunPos = oContentPos.Get(oContentPos.GetDepth()); oContentPos.DecreaseDepth(1); let oRun = oParagraph.GetElementByPos(oContentPos); if (!(oRun instanceof ParaRun)) return new CRunWithPosition(oCurRun, nPos); return oRun.RemoveTextCluster(nInRunPos); }; ParaRun.prototype.RemoveItemInReview = function(nPos, nDirection) { let nResultPos = nPos + 1; let oResultRun = this; let oParent = this.GetParent(); let nInParentPos = this.GetPosInParent(oParent); if (!oParent || -1 === nInParentPos) return new CRunWithPosition(oResultRun, nResultPos) let oPrev, oNext; if (nDirection > 0) { if (0 === nPos && 1 === this.Content.length) { this.SetReviewType(reviewtype_Remove, true); oResultRun = this; nResultPos = 1; } else if (0 === nPos && this.Content.length > 0 && nInParentPos > 0 && (oPrev = oParent.GetElement(nInParentPos - 1)).IsRun() && reviewtype_Remove === oPrev.GetReviewType() && this.Pr.IsEqual(oPrev.GetDirectTextPr())) { let oItem = this.Content[0]; this.RemoveFromContent(0, 1, true); oPrev.AddToContent(oPrev.GetElementsCount(), oItem); oResultRun = this; nResultPos = 0; } else if (this.Content.length - 1 === nPos && this.Content.length > 0 && nInParentPos < oParent.GetElementsCount() - 1 && (oNext = oParent.GetElement(nInParentPos + 1)).IsRun() && reviewtype_Remove === oNext.GetReviewType() && this.Pr.IsEqual(oNext.GetDirectTextPr())) { let oItem = this.Content[nPos]; this.RemoveFromContent(nPos, 1, true); oNext.AddToContent(0, oItem, true); oResultRun = oNext; nResultPos = 1; } else if (nPos < this.Content.length) { let oRRun = nPos < this.Content.length - 1 ? this.Split2(nPos + 1, oParent, nInParentPos) : null; let oCRun = nPos > 0 ? this.Split2(nPos, oParent, nInParentPos) : this; oCRun.SetReviewType(reviewtype_Remove, true); if (oRRun) { oResultRun = oRRun; nResultPos = 0; } else { oResultRun = this; nResultPos = this.Content.length; } } } else { if (1 === this.Content.length && 1 === nPos) { this.SetReviewType(reviewtype_Remove, true); oResultRun = this; nResultPos = 0; } else if (1 === nPos && this.Content.length > 0 && nInParentPos > 0 && (oPrev = oParent.GetElement(nInParentPos - 1)).IsRun() && reviewtype_Remove === oPrev.GetReviewType() && this.Pr.IsEqual(oPrev.GetDirectTextPr())) { let nPrevLen = oPrev.GetElementsCount(); let oItem = this.Content[0]; this.RemoveFromContent(0, 1, true); oPrev.AddToContent(nPrevLen, oItem); oResultRun = oPrev; nResultPos = nPrevLen; } else if (this.Content.length === nPos && this.Content.length > 0 && nInParentPos < oParent.GetElementsCount() - 1 && (oNext = oParent.GetElement(nInParentPos + 1)).IsRun() && reviewtype_Remove === oNext.GetReviewType() && this.Pr.IsEqual(oNext.GetDirectTextPr())) { let oItem = this.Content[nPos - 1]; this.RemoveFromContent(nPos - 1, 1, true); oNext.AddToContent(0, oItem); oResultRun = this; nResultPos = nPos - 1; } else if (nPos > 0) { if (nPos < this.Content.length) this.Split2(nPos, oParent, nInParentPos); let oCRun = nPos > 1 ? this.Split2(nPos - 1, oParent, nInParentPos) : this; oCRun.SetReviewType(reviewtype_Remove, true); oResultRun = oCRun; nResultPos = 0; } } return new CRunWithPosition(oResultRun, nResultPos); }; /** * Обновляем позиции селекта, курсора и переносов строк при добавлении элемента в контент данного рана. * @param Pos */ ParaRun.prototype.private_UpdatePositionsOnAdd = function(Pos) { // Обновляем текущую позицию if (this.State.ContentPos >= Pos) this.State.ContentPos++; // Обновляем начало и конец селекта if (true === this.State.Selection.Use) { if (this.State.Selection.StartPos >= Pos) this.State.Selection.StartPos++; if (this.State.Selection.EndPos >= Pos) this.State.Selection.EndPos++; } // Также передвинем всем метки переносов страниц и строк var LinesCount = this.protected_GetLinesCount(); for (var CurLine = 0; CurLine < LinesCount; CurLine++) { var RangesCount = this.protected_GetRangesCount(CurLine); for (var CurRange = 0; CurRange < RangesCount; CurRange++) { var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); if (StartPos > Pos) StartPos++; if (EndPos > Pos) EndPos++; this.protected_FillRange(CurLine, CurRange, StartPos, EndPos); } // Особый случай, когда мы добавляем элемент в самый последний ран if (Pos === this.Content.length - 1 && LinesCount - 1 === CurLine) { this.protected_FillRangeEndPos(CurLine, RangesCount - 1, this.protected_GetRangeEndPos(CurLine, RangesCount - 1) + 1); } } }; /** * Обновляем позиции селекта, курсора и переносов строк при удалении элементов из контента данного рана. * @param Pos * @param Count */ ParaRun.prototype.private_UpdatePositionsOnRemove = function(Pos, Count) { // Обновим текущую позицию if (this.State.ContentPos > Pos + Count) this.State.ContentPos -= Count; else if (this.State.ContentPos > Pos) this.State.ContentPos = Pos; // Обновим начало и конец селекта if (true === this.State.Selection.Use) { if (this.State.Selection.StartPos <= this.State.Selection.EndPos) { if (this.State.Selection.StartPos > Pos + Count) this.State.Selection.StartPos -= Count; else if (this.State.Selection.StartPos > Pos) this.State.Selection.StartPos = Pos; if (this.State.Selection.EndPos >= Pos + Count) this.State.Selection.EndPos -= Count; else if (this.State.Selection.EndPos > Pos) this.State.Selection.EndPos = Math.max(0, Pos - 1); } else { if (this.State.Selection.StartPos >= Pos + Count) this.State.Selection.StartPos -= Count; else if (this.State.Selection.StartPos > Pos) this.State.Selection.StartPos = Math.max(0, Pos - 1); if (this.State.Selection.EndPos > Pos + Count) this.State.Selection.EndPos -= Count; else if (this.State.Selection.EndPos > Pos) this.State.Selection.EndPos = Pos; } } // Также передвинем всем метки переносов страниц и строк var LinesCount = this.protected_GetLinesCount(); for (var CurLine = 0; CurLine < LinesCount; CurLine++) { var RangesCount = this.protected_GetRangesCount(CurLine); for (var CurRange = 0; CurRange < RangesCount; CurRange++) { var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); if (StartPos > Pos + Count) StartPos -= Count; else if (StartPos > Pos) StartPos = Math.max(0, Pos); if (EndPos >= Pos + Count) EndPos -= Count; else if (EndPos >= Pos) EndPos = Math.max(0, Pos); this.protected_FillRange(CurLine, CurRange, StartPos, EndPos); } } }; ParaRun.prototype.private_UpdateCompositeInputPositionsOnAdd = function(Pos) { if (!this.CompositeInput) return; this.CompositeInput.updateOnAdd(Pos); }; ParaRun.prototype.private_UpdateCompositeInputPositionsOnRemove = function(Pos, Count) { if (!this.CompositeInput) return; this.CompositeInput.updateOnRemove(Pos, Count); }; ParaRun.prototype.GetLogicDocument = function() { if (this.Paragraph && this.Paragraph.LogicDocument) return this.Paragraph.LogicDocument; if (editor && editor.WordControl) return editor.WordControl.m_oLogicDocument; return null; }; // Добавляем элемент в позицию с сохранием в историю ParaRun.prototype.Add_ToContent = function(Pos, Item, UpdatePosition) { if (this.GetTextForm() && this.GetTextForm().IsComb()) this.RecalcInfo.Measure = true; this.CheckParentFormKey(); if (-1 === Pos) Pos = this.Content.length; if (Item.SetParent) Item.SetParent(this); // Здесь проверка на возвожность добавления в историю стоит заранее для ускорения открытия файлов, чтобы // не создавалось лишних классов if (AscCommon.History.CanAddChanges()) AscCommon.History.Add(new CChangesRunAddItem(this, Pos, [Item], true)); if (Pos >= this.Content.length) { Pos = this.Content.length; this.Content.push(Item); } else { this.Content.splice(Pos, 0, Item); } if (true === UpdatePosition) this.private_UpdatePositionsOnAdd(Pos); // Обновляем позиции в NearestPos var NearPosLen = this.NearPosArray.length; for ( var Index = 0; Index < NearPosLen; Index++ ) { var RunNearPos = this.NearPosArray[Index]; var ContentPos = RunNearPos.NearPos.ContentPos; var Depth = RunNearPos.Depth; if ( ContentPos.Data[Depth] >= Pos ) ContentPos.Data[Depth]++; } this.private_UpdateMarksOnAdd(Pos, 1); this.private_UpdateDocumentOutline(); this.private_UpdateTrackRevisionOnChangeContent(true); // Обновляем позиции меток совместного редактирования this.CollaborativeMarks.Update_OnAdd( Pos ); this.RecalcInfo.OnAdd(Pos); this.OnContentChange(); }; ParaRun.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition) { if (Count <= 0) return; if (this.GetTextForm() && this.GetTextForm().IsComb()) this.RecalcInfo.Measure = true; this.CheckParentFormKey(); for (var nIndex = Pos, nCount = Math.min(Pos + Count, this.Content.length); nIndex < nCount; ++nIndex) { if (this.Content[nIndex].PreDelete) this.Content[nIndex].PreDelete(); } if (AscCommon.History.CanAddChanges()) { var DeletedItems = this.Content.slice(Pos, Pos + Count); AscCommon.History.Add(new CChangesRunRemoveItem(this, Pos, DeletedItems)); } this.Content.splice(Pos, Count); if (true === UpdatePosition) this.private_UpdatePositionsOnRemove(Pos, Count); // Обновляем позиции в NearestPos var NearPosLen = this.NearPosArray.length; for ( var Index = 0; Index < NearPosLen; Index++ ) { var RunNearPos = this.NearPosArray[Index]; var ContentPos = RunNearPos.NearPos.ContentPos; var Depth = RunNearPos.Depth; if ( ContentPos.Data[Depth] > Pos + Count ) ContentPos.Data[Depth] -= Count; else if ( ContentPos.Data[Depth] > Pos ) ContentPos.Data[Depth] = Math.max( 0 , Pos ); } this.private_UpdateMarksOnRemove(Pos, Count); this.private_UpdateDocumentOutline(); this.private_UpdateTrackRevisionOnChangeContent(true); // Обновляем позиции меток совместного редактирования this.CollaborativeMarks.Update_OnRemove( Pos, Count ); this.RecalcInfo.OnRemove(Pos, Count); this.OnContentChange(); }; /** * Добавляем к массиву содержимого массив новых элементов * @param arrNewItems */ ParaRun.prototype.ConcatToContent = function(arrNewItems) { this.CheckParentFormKey(); for (var nIndex = 0, nCount = arrNewItems.length; nIndex < nCount; ++nIndex) { if (arrNewItems[nIndex].SetParent) arrNewItems[nIndex].SetParent(this); } var StartPos = this.Content.length; this.Content = this.Content.concat(arrNewItems); AscCommon.History.Add(new CChangesRunAddItem(this, StartPos, arrNewItems, false)); this.private_UpdateTrackRevisionOnChangeContent(true); // Отмечаем, что надо перемерить элементы в данном ране this.RecalcInfo.Measure = true; this.OnContentChange(); }; /** * Добавляем в конец рана заданную строку * @param {string} sString * @param {number} [nPos=-1] если позиция не задана (или значение -1), то добавляем в конец * @returns {number} Позиция после добавленных элементов */ ParaRun.prototype.AddText = function(sString, nPos) { var nCharPos = undefined !== nPos && null !== nPos && -1 !== nPos ? nPos : this.Content.length; let oForm = this.GetParentForm(); var oTextForm = oForm ? oForm.GetTextFormPr() : null; var nMax = oTextForm ? oTextForm.GetMaxCharacters() : 0; if (this.IsMathRun()) { for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next()) { var nCharCode = oIterator.value(); var oMathText = new CMathText(); oMathText.add(nCharCode); this.AddToContent(nCharPos++, oMathText); } } else if (nMax > 0) { var arrLetters = [], nLettersCount = 0; for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next()) { var nCharCode = oIterator.value(); if (9 === nCharCode) // \t continue; else if (10 === nCharCode) // \n continue; else if (13 === nCharCode) // \r continue; else if (AscCommon.IsSpace(nCharCode)) // space { nLettersCount++; arrLetters.push(new AscWord.CRunSpace(nCharCode)); } else { nLettersCount++; arrLetters.push(new AscWord.CRunText(nCharCode)); } } for (var nIndex = 0; nIndex < arrLetters.length; ++nIndex) { this.AddToContent(nCharPos++, arrLetters[nIndex], true); } oForm.TrimTextForm(); } else { for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next()) { var nCharCode = oIterator.value(); if (9 === nCharCode) // \t this.AddToContent(nCharPos++, new AscWord.CRunTab(), true); else if (10 === nCharCode) // \n this.AddToContent(nCharPos++, new AscWord.CRunBreak(AscWord.break_Line), true); else if (13 === nCharCode) // \r continue; else if (AscCommon.IsSpace(nCharCode)) // space this.AddToContent(nCharPos++, new AscWord.CRunSpace(nCharCode), true); else this.AddToContent(nCharPos++, new AscWord.CRunText(nCharCode), true); } } return nCharPos; }; /** * Добавляем в конец рана заданную инструкцию для сложного поля * @param {string} sString * @param {number} [nPos=-1] если позиция не задана (или значение -1), то добавляем в конец * @returns {AscWord.ParaInstrText[]} */ ParaRun.prototype.AddInstrText = function(sString, nPos) { let items = []; var nCharPos = undefined !== nPos && null !== nPos && -1 !== nPos ? nPos : this.Content.length; for (var oIterator = sString.getUnicodeIterator(); oIterator.check(); oIterator.next()) { let instrText = new AscWord.ParaInstrText(oIterator.value()); this.AddToContent(nCharPos++, instrText); items.push(instrText); } return items; }; // Определим строку и отрезок текущей позиции ParaRun.prototype.GetCurrentParaPos = function(align) { var Pos = this.State.ContentPos; if (-1 === this.StartLine) return new CParaPos(-1, -1, -1, -1); var CurLine = 0; var CurRange = 0; var LinesCount = this.protected_GetLinesCount(); for (; CurLine < LinesCount; CurLine++) { var RangesCount = this.protected_GetRangesCount(CurLine); for (CurRange = 0; CurRange < RangesCount; CurRange++) { var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); if (((-1 === align) && (StartPos < Pos && Pos <= EndPos)) || ((-1 !== align) && (StartPos <= Pos && Pos < EndPos))) return new CParaPos((CurLine === 0 ? CurRange + this.StartRange : CurRange), CurLine + this.StartLine, 0, 0); } } // Значит курсор стоит в самом конце, поэтому посылаем последний отрезок if(this.Type == para_Math_Run && LinesCount > 1) { var Line = LinesCount - 1, Range = this.protected_GetRangesCount(LinesCount - 1) - 1; StartPos = this.protected_GetRangeStartPos(Line, Range); EndPos = this.protected_GetRangeEndPos(Line, Range); // учтем, что в одной строке в формуле может быть только один Range while(StartPos == EndPos && Line > 0 && this.Content.length !== 0) // == this.Content.length, т.к. последний Range { Line--; StartPos = this.protected_GetRangeStartPos(Line, Range); EndPos = this.protected_GetRangeEndPos(Line, Range); } return new CParaPos((this.protected_GetRangesCount(Line) - 1), Line + this.StartLine, 0, 0 ); } return new CParaPos((LinesCount <= 1 ? this.protected_GetRangesCount(0) - 1 + this.StartRange : this.protected_GetRangesCount(LinesCount - 1) - 1), LinesCount - 1 + this.StartLine, 0, 0 ); }; ParaRun.prototype.Get_ParaPosByContentPos = function(ContentPos, Depth) { if (this.StartRange < 0 || this.StartLine < 0) return new CParaPos(0, 0, 0, 0); var Pos = ContentPos.Get(Depth); var CurLine = 0; var CurRange = 0; var LinesCount = this.protected_GetLinesCount(); if (LinesCount <= 0) return new CParaPos(0, 0, 0, 0); for (; CurLine < LinesCount; CurLine++) { var RangesCount = this.protected_GetRangesCount(CurLine); for (CurRange = 0; CurRange < RangesCount; CurRange++) { var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var bUpdateMathRun = Pos == EndPos && StartPos == EndPos && EndPos == this.Content.length && this.Type == para_Math_Run; // для para_Run позиция может быть после последнего элемента (пример: Run, за ним идет мат объект) if (Pos < EndPos && Pos >= StartPos || bUpdateMathRun) return new CParaPos((CurLine === 0 ? CurRange + this.StartRange : CurRange), CurLine + this.StartLine, 0, 0); } } return new CParaPos((LinesCount === 1 ? this.protected_GetRangesCount(0) - 1 + this.StartRange : this.protected_GetRangesCount(LinesCount - 1) - 1), LinesCount - 1 + this.StartLine, 0, 0); }; ParaRun.prototype.recalculateCursorPosition = function(positionCalculator, isCurrent) { if (this.IsMathRun()) { positionCalculator.handleMathRun(this, isCurrent, this.State.ContentPos); return; } let rangePos = this.getRangePos(positionCalculator.line, positionCalculator.range); let startPos = rangePos[0]; let endPos = rangePos[1]; for (let pos = startPos; pos < endPos; ++pos) { let item = this.private_CheckInstrText(this.Content[pos]); let isCurPos = isCurrent && pos === this.State.ContentPos; let isNearNoteRef = isCurPos ? this.IsCurPosNearFootEndnoteReference() : false; positionCalculator.handleRunElement(item, this, isCurPos, isNearNoteRef, pos); } if (isCurrent && endPos === this.State.ContentPos) positionCalculator.setNextCurrent(this, this.Content.length && endPos === this.Content.length ? this.Content[this.Content.length - 1] : null); } /** * Get auto color against current background color * @returns {AscWord.CDocumentColor} */ ParaRun.prototype.getAutoColor = function() { let paragraph = this.GetParagraph(); if (!paragraph) return AscWord.BLACK_COLOR; let textPr = this.getCompiledPr(); if (textPr.FontRef && textPr.FontRef.Color) { textPr.FontRef.Color.check(paragraph.getTheme(), paragraph.getColorMap()); let RGBA = textPr.FontRef.Color.RGBA; return new AscWord.CDocumentColor(RGBA.R, RGBA.G, RGBA.B, RGBA.A); } let bgColor = null; if (textPr.Shd && !textPr.Shd.IsNil()) { bgColor = textPr.Shd.GetSimpleColor(paragraph.getTheme(), paragraph.getColorMap()); } else { let paraPr = paragraph.getCompiledPr().ParaPr; if (paraPr.Shd && !paraPr.Shd.IsNil()) { if (paraPr.Shd.Unifill) { paraPr.Shd.Unifill.check(this.Paragraph.Get_Theme(), this.Paragraph.Get_ColorMap()); let RGBA = paraPr.Shd.Unifill.getRGBAColor(); bgColor = new AscWord.CDocumentColor(RGBA.R, RGBA.G, RGBA.B, RGBA.A); } else { bgColor = paraPr.Shd.Color; } } else if (paragraph.GetParent()) { bgColor = paragraph.GetParent().Get_TextBackGroundColor(); } } return bgColor && !bgColor.isBlackAutoColor() ? AscWord.WHITE_COLOR : AscWord.BLACK_COLOR; }; /** * Проверяем являются ли заданные изменения заданного рана простыми (например, последовательное удаление или набор текста) * @param arrChanges * @param [nStart=0] {number} * @param [nEnd=arrChanges.length - 1] {number} * @returns {?CParaPos} */ ParaRun.prototype.GetSimpleChangesRange = function(arrChanges, nStart, nEnd) { if (this.IsMathRun()) return null; var oParaPos = null; var _nStart = undefined !== nStart ? nStart : 0; var _nEnd = undefined !== nEnd ? nEnd : arrChanges.length - 1; var arrAddItems = [], arrRemItems = []; for (var nIndex = _nStart; nIndex <= _nEnd; ++nIndex) { var oChange = arrChanges[nIndex]; if (oChange.IsDescriptionChange()) continue; if (!oChange || !oChange.IsContentChange() || 1 !== oChange.GetItemsCount()) return null; var nType = oChange.GetType(); if (AscDFH.historyitem_ParaRun_AddItem !== nType && AscDFH.historyitem_ParaRun_RemoveItem !== nType) return null; var nItemsCount = oChange.GetItemsCount(); for (var nItemIndex = 0; nItemIndex < nItemsCount; ++nItemIndex) { var oItem = oChange.GetItem(nItemIndex); if (!oItem) return null; if (AscDFH.historyitem_ParaRun_AddItem === nType) arrAddItems.push(oItem); else arrRemItems.push(oItem); // Добавление/удаление картинок может изменить размер строки. Добавление/удаление переноса строки/страницы/колонки // нельзя обсчитывать функцией Recalculate_Fast. Добавление и удаление разметок сложных полей тоже нельзя // обсчитывать в быстром пересчете. // TODO: Но на самом деле стоило бы сделать нормальную проверку на высоту строки в функции Recalculate_Fast var nItemType = oItem.Type; if (para_Drawing === nItemType || para_NewLine === nItemType || para_FootnoteRef === nItemType || para_FootnoteReference === nItemType || para_FieldChar === nItemType || para_InstrText === nItemType || para_EndnoteRef === nItemType || para_EndnoteReference === nItemType || para_Tab === nItemType) return null; var nChangePos = oChange.GetPos(nItemIndex); // Проверяем, что все изменения произошли в одном и том же отрезке var oCurParaPos = this.Get_SimpleChanges_ParaPos(nType, nChangePos); if (!oCurParaPos) return null; if (!oParaPos) oParaPos = oCurParaPos; else if (oParaPos.Line !== oCurParaPos.Line || oParaPos.Range !== oCurParaPos.Range || oParaPos.Page !== oCurParaPos.Page) return null; } } // Сравниваем, нужно ли использовать метрики данного Run до и после изменений // Если значение не совпало, тогда метрики поменялись, значит пересчитывать надо полноценно if (this.private_IsChangedLineMetrics(arrAddItems, arrRemItems)) return null; return oParaPos; }; ParaRun.prototype.private_IsChangedLineMetrics = function(arrAddItems, arrRemItems) { var isUseMetricsBefore = false; var isUseMetricsAfter = false; for (var nPos = 0, nContentCount = this.Content.length; nPos < nContentCount; ++nPos) { var oItem = this.Content[nPos]; var nItemType = oItem.Type; if (para_Sym === nItemType || para_Text === nItemType || para_PageNum === nItemType || para_PageCount === nItemType || para_FootnoteReference === nItemType || para_FootnoteRef === nItemType || para_EndnoteReference === nItemType || para_EndnoteRef === nItemType || para_Separator === nItemType || para_ContinuationSeparator === nItemType || para_Math_Text === nItemType || para_Math_Ampersand === nItemType || para_Math_Placeholder === nItemType || para_Math_BreakOperator === nItemType || (para_Drawing === nItemType && (true === oItem.Is_Inline() || true === this.GetParagraph().Parent.Is_DrawingShape())) || (para_FieldChar === nItemType && oItem.IsVisual())) { var isAdd = false; for (var nIndex = 0, nCount = arrAddItems.length; nIndex < nCount; ++nIndex) { if (oItem === arrAddItems[nIndex]) { isAdd = true; break; } } if (!isAdd) isUseMetricsBefore = true; isUseMetricsAfter = true; } if (isUseMetricsAfter && isUseMetricsBefore) break; } if (!isUseMetricsBefore) { for (var nIndex = 0, nCount = arrRemItems.length; nIndex < nCount; ++nIndex) { var oItem = arrRemItems[nIndex]; var nItemType = oItem.Type; if (para_Sym === nItemType || para_Text === nItemType || para_PageNum === nItemType || para_PageCount === nItemType || para_FootnoteReference === nItemType || para_FootnoteRef === nItemType || para_EndnoteReference === nItemType || para_EndnoteRef === nItemType || para_Separator === nItemType || para_ContinuationSeparator === nItemType || para_Math_Text === nItemType || para_Math_Ampersand === nItemType || para_Math_Placeholder === nItemType || para_Math_BreakOperator === nItemType || (para_Drawing === nItemType && (true === oItem.Is_Inline() || true === this.GetParagraph().Parent.Is_DrawingShape())) || (para_FieldChar === nItemType && oItem.IsVisual())) { isUseMetricsBefore = true; break; } } } return (isUseMetricsBefore !== isUseMetricsAfter); }; /** * Проверяем произошло ли простое изменение параграфа, сейчас главное, чтобы это было не добавлениe/удаление картинки * или ссылки на сноску или разметки сложного поля, или изменение типа реценизрования для рана со знаком конца * параграфа. На вход приходит либо массив изменений, либо одно изменение * (можно не в массиве). * @param {[CChangesBase] | CChangesBase} arrChanges * @returns {boolean} */ ParaRun.prototype.IsParagraphSimpleChanges = function(arrChanges) { var _arrChanges = arrChanges; if (!arrChanges.length) _arrChanges = [arrChanges]; for (var nChangesIndex = 0, nChangesCount = _arrChanges.length; nChangesIndex < nChangesCount; ++nChangesIndex) { var oChange = _arrChanges[nChangesIndex]; var nType = oChange.GetType(); if (AscDFH.historyitem_ParaRun_AddItem === nType || AscDFH.historyitem_ParaRun_RemoveItem === nType) { for (var nItemIndex = 0, nItemsCount = oChange.GetItemsCount(); nItemIndex < nItemsCount; ++nItemIndex) { var oItem = oChange.GetItem(nItemIndex); if (para_Drawing === oItem.Type || para_FootnoteReference === oItem.Type || para_FieldChar === oItem.Type || para_InstrText === oItem.Type || para_EndnoteReference === oItem.Type) return false; } } else if (AscDFH.historyitem_ParaRun_ReviewType === nType && this.GetParaEnd()) { return false; } } return true; }; /** * Проверяем, подходит ли содержимое данного рана быстрого пересчета * @returns {boolean} */ ParaRun.prototype.IsContentSuitableForParagraphSimpleChanges = function() { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var nItemType = this.Content[nPos].Type; if (1 !== g_oSRCFPSC[nItemType]) return false; } return true; }; // Возвращаем строку и отрезок, в котором произошли простейшие изменения ParaRun.prototype.Get_SimpleChanges_ParaPos = function(Type, Pos) { if (AscDFH.historyitem_ParaRun_AddItem !== Type && AscDFH.historyitem_ParaRun_RemoveItem !== Type) return null; if (Pos < this.protected_GetRangeStartPos(0, 0)) { // Если отрезок остается пустым, тогда надо все заново пересчитывать if (this.protected_GetRangeStartPos(0, 0) === this.protected_GetRangeEndPos(0, 0)) return null; return new CParaPos(this.StartRange, this.StartLine, 0, 0); } else { for (let curLine = 0, lineCount = this.protected_GetLinesCount(); curLine < lineCount; ++curLine) { for (let curRange = 0, rangeCount = this.protected_GetRangesCount(curLine); curRange < rangeCount; ++curRange) { let rangeStartPos = this.protected_GetRangeStartPos(curLine, curRange); let rangeEndPos = this.protected_GetRangeEndPos(curLine, curRange); if ((rangeStartPos <= Pos && Pos < rangeEndPos) || (Pos >= rangeEndPos && curLine === lineCount - 1 && curRange === rangeCount - 1)) { // Если отрезок остается пустым, тогда надо все заново пересчитывать if (rangeStartPos === rangeEndPos) return null; return new CParaPos((curLine === 0 ? curRange + this.StartRange : curRange), curLine + this.StartLine, 0, 0); } } } } return null; }; ParaRun.prototype.Split = function (ContentPos, Depth) { var CurPos = ContentPos.Get(Depth); return this.Split2( CurPos ); }; ParaRun.prototype.Split2 = function(CurPos, Parent, ParentPos) { // Данная функция специальная, расчитана на то, что в параграфе данный ран делится в заданной позиции на 2 рана // Поэтому ВСЕ метки (поиск, орфографии, позиций и остального) обновляются именно здесь, а не через // стандартный механизм AddToContent/RemoveFromContent. Чтобы все работало правильно, делаем в следующей // последовательности: // 1 Создаем новый ран и добавляем туда КОПИИ элементов после точки разделения // 2 Переносим все метки, попадающие после точки разделения, в новый ран // 3 Удаляем из текущего рана элементы после точки разделения // Если задается Parent и ParentPos, тогда ран автоматически добавляется в родительский класс var UpdateParent = (undefined !== Parent && undefined !== ParentPos && this === Parent.Content[ParentPos] ? true : false); var UpdateSelection = (true === UpdateParent && true === Parent.IsSelectionUse() && true === this.IsSelectionUse() ? true : false); // Создаем новый ран var bMathRun = this.Type == para_Math_Run; var NewRun = new ParaRun(this.Paragraph, bMathRun); AscCommon.History.Add(new CChangesRunOnStartSplit(this, CurPos, NewRun)); AscCommon.CollaborativeEditing.OnStart_SplitRun(this, CurPos); // Копируем настройки NewRun.SetPr(this.Pr.Copy(true)); if ((0 === CurPos || this.Content.length === CurPos) && this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument) { var oStyles = this.Paragraph.LogicDocument.GetStyles(); if (this.GetRStyle() === oStyles.GetDefaultFootnoteReference() || this.GetRStyle() === oStyles.GetDefaultEndnoteReference()) { if (0 === CurPos) { this.SetRStyle(undefined); this.SetVertAlign(undefined); } else { NewRun.SetRStyle(undefined); NewRun.SetVertAlign(undefined); } } } NewRun.SetReviewTypeWithInfo(this.GetReviewType(), this.ReviewInfo ? this.ReviewInfo.Copy() : undefined); NewRun.CollPrChangeMine = this.CollPrChangeMine; NewRun.CollPrChangeColor = this.CollPrChangeColor; if(bMathRun) NewRun.Set_MathPr(this.MathPrp.Copy()); // TODO: Как только избавимся от para_End переделать тут // Проверим, если наш ран содержит para_End, тогда мы должны para_End переметить в правый ран var CheckEndPos = -1; var CheckEndPos2 = Math.min( CurPos, this.Content.length ); for ( var Pos = 0; Pos < CheckEndPos2; Pos++ ) { if ( para_End === this.Content[Pos].Type ) { CheckEndPos = Pos; break; } } if ( -1 !== CheckEndPos ) CurPos = CheckEndPos; var ParentOldSelectionStartPos, ParentOldSelectionEndPos, OldSelectionStartPos, OldSelectionEndPos; if (true === UpdateSelection) { ParentOldSelectionStartPos = Parent.Selection.StartPos; ParentOldSelectionEndPos = Parent.Selection.EndPos; OldSelectionStartPos = this.Selection.StartPos; OldSelectionEndPos = this.Selection.EndPos; } // ВСЕГДА копируем элементы, для корректной работы не надо переносить имеющиеся элементы в новый ран for (var nIndex = CurPos, nNewIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex, ++nNewIndex) { var oNewItem = this.Content[nIndex].Copy(); NewRun.AddToContent(nNewIndex, oNewItem, false); if (para_FieldChar === this.Content[nIndex].Type) { var oComplexField = this.Content[nIndex].GetComplexField(); if (oComplexField) oComplexField.ReplaceChar(oNewItem); } } if (UpdateParent) { Parent.Add_ToContent(ParentPos + 1, NewRun); // Обновим массив NearPosArray for (var Index = 0, Count = this.NearPosArray.length; Index < Count; Index++) { var RunNearPos = this.NearPosArray[Index]; var ContentPos = RunNearPos.NearPos.ContentPos; var Depth = RunNearPos.Depth; var Pos = ContentPos.Get(Depth); if (Pos >= CurPos) { ContentPos.Update2(Pos - CurPos, Depth); ContentPos.Update2(ParentPos + 1, Depth - 1); this.NearPosArray.splice(Index, 1); Count--; Index--; NewRun.NearPosArray.push(RunNearPos); if (this.Paragraph) { for (var ParaIndex = 0, ParaCount = this.Paragraph.NearPosArray.length; ParaIndex < ParaCount; ParaIndex++) { var ParaNearPos = this.Paragraph.NearPosArray[ParaIndex]; if (ParaNearPos.Classes[ParaNearPos.Classes.length - 1] === this) ParaNearPos.Classes[ParaNearPos.Classes.length - 1] = NewRun; } } } } // Обновляем позиции в поиске for (var nIndex = 0, nSearchMarksCount = this.SearchMarks.length; nIndex < nSearchMarksCount; ++nIndex) { var oMark = this.SearchMarks[nIndex]; var oContentPos = oMark.Start ? oMark.SearchResult.StartPos : oMark.SearchResult.EndPos; var nDepth = oMark.Depth; if (oContentPos.Get(nDepth) > CurPos || (oContentPos.Get(nDepth) === CurPos && oMark.Start)) { this.SearchMarks.splice(nIndex, 1); NewRun.SearchMarks.splice(NewRun.SearchMarks.length, 0, oMark); oContentPos.Data[nDepth] -= CurPos; oContentPos.Data[nDepth - 1]++; if (oMark.Start) oMark.SearchResult.ClassesS[oMark.SearchResult.ClassesS.length - 1] = NewRun; else oMark.SearchResult.ClassesE[oMark.SearchResult.ClassesE.length - 1] = NewRun; nSearchMarksCount--; nIndex--; } } } this.private_UpdateMarksOnSplit(CurPos, NewRun); this.RemoveFromContent(CurPos, this.Content.length - CurPos, true); if (true === UpdateSelection) { if (ParentOldSelectionStartPos <= ParentPos && ParentPos <= ParentOldSelectionEndPos) Parent.Selection.EndPos = ParentOldSelectionEndPos + 1; else if (ParentOldSelectionEndPos <= ParentPos && ParentPos <= ParentOldSelectionStartPos) Parent.Selection.StartPos = ParentOldSelectionStartPos + 1; if (OldSelectionStartPos <= CurPos && CurPos <= OldSelectionEndPos) { this.Selection.EndPos = this.Content.length; NewRun.Selection.Use = true; NewRun.Selection.StartPos = 0; NewRun.Selection.EndPos = OldSelectionEndPos - CurPos; } else if (OldSelectionEndPos <= CurPos && CurPos <= OldSelectionStartPos) { this.Selection.StartPos = this.Content.length; NewRun.Selection.Use = true; NewRun.Selection.EndPos = 0; NewRun.Selection.StartPos = OldSelectionStartPos - CurPos; } } AscCommon.History.Add(new CChangesRunOnEndSplit(this, CurPos, NewRun)); AscCommon.CollaborativeEditing.OnEnd_SplitRun(NewRun); return NewRun; }; ParaRun.prototype.SplitNoDuplicate = function(oContentPos, nDepth, oNewParagraph) { if (this.IsSolid()) return; var oNewRun = this.Split(oContentPos, nDepth); if (!oNewRun) return; var oLogicDocument = this.GetLogicDocument(); if (oLogicDocument && oNewRun.GetRStyle() === oLogicDocument.GetStyles().GetDefaultHyperlink()) oNewRun.SetRStyle(null); oNewParagraph.AddToContent(oNewParagraph.Content.length, oNewRun, false); }; ParaRun.prototype.SplitForSpreadCollaborativeMark = function(CurPos) // переносим сами объекты, а не копии { var bMathRun = this.Type == para_Math_Run; var NewRun = new ParaRun(this.Paragraph, false); AscCommon.History.Add(new CChangesRunOnStartSplit(this, CurPos, NewRun)); AscCommon.CollaborativeEditing.OnStart_SplitRun(this, CurPos); NewRun.SetReviewTypeWithInfo(this.GetReviewType(), this.ReviewInfo ? this.ReviewInfo.Copy() : undefined); if(bMathRun) NewRun.Set_MathPr(this.MathPrp.Copy()); // Копируем настройки NewRun.SetPr(this.Pr.Copy(true)); for (let nIndex = CurPos, nNewIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex, ++nNewIndex) { let oNewItem = this.Content[nIndex]; NewRun.AddToContent(nNewIndex, oNewItem, false); if (para_FieldChar === this.Content[nIndex].Type) { let oComplexField = this.Content[nIndex].GetComplexField(); if (oComplexField) oComplexField.ReplaceChar(oNewItem); } } this.RemoveFromContent(CurPos, this.Content.length - CurPos, true); AscCommon.History.Add(new CChangesRunOnEndSplit(this, CurPos, NewRun)); AscCommon.CollaborativeEditing.OnEnd_SplitRun(NewRun); return NewRun; }; ParaRun.prototype.GetCollaborativeMarks = function () { return this.CollaborativeMarks.Ranges; } ParaRun.prototype.Check_NearestPos = function(ParaNearPos, Depth) { var RunNearPos = new CParagraphElementNearPos(); RunNearPos.NearPos = ParaNearPos.NearPos; RunNearPos.Depth = Depth; this.NearPosArray.push( RunNearPos ); ParaNearPos.Classes.push( this ); }; ParaRun.prototype.Get_DrawingObjectRun = function(Id) { var ContentLen = this.Content.length; for ( var CurPos = 0; CurPos < ContentLen; CurPos++ ) { var Element = this.Content[CurPos]; if ( para_Drawing === Element.Type && Id === Element.Get_Id() ) return this; } return null; }; ParaRun.prototype.Get_DrawingObjectContentPos = function(Id, ContentPos, Depth) { var ContentLen = this.Content.length; for ( var CurPos = 0; CurPos < ContentLen; CurPos++ ) { var Element = this.Content[CurPos]; if ( para_Drawing === Element.Type && Id === Element.Get_Id() ) { ContentPos.Update( CurPos, Depth ); return true; } } return false; }; ParaRun.prototype.GetRunByElement = function(oRunElement) { for (var nCurPos = 0, nLen = this.Content.length; nCurPos < nLen; ++nCurPos) { if (this.Content[nCurPos] === oRunElement) return {Run : this, Pos : nCurPos}; } return null; }; ParaRun.prototype.Get_DrawingObjectSimplePos = function(Id) { var ContentLen = this.Content.length; for (var CurPos = 0; CurPos < ContentLen; CurPos++) { var Element = this.Content[CurPos]; if (para_Drawing === Element.Type && Id === Element.Get_Id()) return CurPos; } return -1; }; ParaRun.prototype.Remove_DrawingObject = function(Id) { var ContentLen = this.Content.length; for ( var CurPos = 0; CurPos < ContentLen; CurPos++ ) { var Element = this.Content[CurPos]; if ( para_Drawing === Element.Type && Id === Element.Get_Id() ) { var TrackRevisions = null; if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument) TrackRevisions = this.Paragraph.LogicDocument.IsTrackRevisions(); if (true === TrackRevisions) { var ReviewType = this.GetReviewType(); if (reviewtype_Common === ReviewType) { // Разбиваем ран на две части var StartPos = CurPos; var EndPos = CurPos + 1; var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(Parent); if (-1 !== RunPos && Parent) { var DeletedRun = null; if (StartPos <= 0 && EndPos >= this.Content.length) DeletedRun = this; else if (StartPos <= 0) { this.Split2(EndPos, Parent, RunPos); DeletedRun = this; } else if (EndPos >= this.Content.length) { DeletedRun = this.Split2(StartPos, Parent, RunPos); } else { this.Split2(EndPos, Parent, RunPos); DeletedRun = this.Split2(StartPos, Parent, RunPos); } DeletedRun.SetReviewType(reviewtype_Remove); } } else if (reviewtype_Add === ReviewType) { this.Remove_FromContent(CurPos, 1, true); } else if (reviewtype_Remove === ReviewType) { // Ничего не делаем } } else { this.Remove_FromContent(CurPos, 1, true); } return; } } }; ParaRun.prototype.Get_Layout = function(DrawingLayout, UseContentPos, ContentPos, Depth) { var CurLine = DrawingLayout.Line - this.StartLine; var CurRange = ( 0 === CurLine ? DrawingLayout.Range - this.StartRange : DrawingLayout.Range ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var CurContentPos = ( true === UseContentPos ? ContentPos.Get(Depth) : -1 ); var CurPos = StartPos; for ( ; CurPos < EndPos; CurPos++ ) { if ( CurContentPos === CurPos ) break; var Item = this.Content[CurPos]; var ItemType = Item.Type; var WidthVisible = Item.GetWidthVisible(); switch ( ItemType ) { case para_Text: case para_Space: case para_PageNum: case para_PageCount: { DrawingLayout.LastW = WidthVisible; break; } case para_Drawing: { if ( true === Item.Is_Inline() || true === DrawingLayout.Paragraph.Parent.Is_DrawingShape() ) { DrawingLayout.LastW = WidthVisible; } break; } } DrawingLayout.X += WidthVisible; } if (CurContentPos === CurPos) DrawingLayout.Layout = true; }; ParaRun.prototype.GetNextRunElements = function(oRunElements, isUseContentPos, nDepth) { if (true === isUseContentPos) oRunElements.SetStartClass(this.GetParent()); var nStartPos = true === isUseContentPos ? oRunElements.ContentPos.Get(nDepth) : 0; for (var nCurPos = nStartPos, nCount = this.Content.length; nCurPos < nCount; ++nCurPos) { if (oRunElements.IsEnoughElements() || this.IsEmpty()) return; oRunElements.UpdatePos(nCurPos, nDepth); oRunElements.Add(this.Content[nCurPos], this); } }; ParaRun.prototype.GetPrevRunElements = function(oRunElements, isUseContentPos, nDepth) { if (true === isUseContentPos) oRunElements.SetStartClass(this.GetParent()); var nStartPos = true === isUseContentPos ? oRunElements.ContentPos.Get(nDepth) - 1 : this.Content.length - 1; for (var nCurPos = nStartPos; nCurPos >= 0; --nCurPos) { if (oRunElements.IsEnoughElements() || this.IsEmpty()) return; oRunElements.UpdatePos(nCurPos, nDepth); oRunElements.Add(this.Content[nCurPos], this); } }; ParaRun.prototype.CollectDocumentStatistics = function(ParaStats) { var Count = this.Content.length; for (var Index = 0; Index < Count; Index++) { var Item = this.Content[Index]; var ItemType = Item.Type; var bSymbol = false; var bSpace = false; var bNewWord = false; if ((para_Text === ItemType && false === Item.IsNBSP()) || (para_PageNum === ItemType || para_PageCount === ItemType)) { if (false === ParaStats.Word) bNewWord = true; bSymbol = true; bSpace = false; ParaStats.Word = true; ParaStats.EmptyParagraph = false; } else if ((para_Text === ItemType && true === Item.IsNBSP()) || para_Space === ItemType || para_Tab === ItemType) { bSymbol = true; bSpace = true; ParaStats.Word = false; } if (true === bSymbol) ParaStats.Stats.Add_Symbol(bSpace); if (true === bNewWord) ParaStats.Stats.Add_Word(); } }; ParaRun.prototype.Create_FontMap = function(Map) { // для Math_Para_Pun argSize учитывается, когда мержатся текстовые настройки в Internal_Compile_Pr() if ( undefined !== this.Paragraph && null !== this.Paragraph ) { var TextPr; var FontSize, FontSizeCS; if(this.Type === para_Math_Run) { TextPr = this.Get_CompiledPr(false); FontSize = TextPr.FontSize; FontSizeCS = TextPr.FontSizeCS; if(null !== this.Parent && undefined !== this.Parent && null !== this.Parent.ParaMath && undefined !== this.Parent.ParaMath) { TextPr.FontSize = this.Math_GetRealFontSize(TextPr.FontSize); TextPr.FontSizeCS = this.Math_GetRealFontSize(TextPr.FontSizeCS); } } else TextPr = this.Get_CompiledPr(false); TextPr.Document_CreateFontMap(Map, this.Paragraph.Get_Theme().themeElements.fontScheme); var Count = this.Content.length; for (var Index = 0; Index < Count; Index++) { var Item = this.Content[Index]; if (para_Drawing === Item.Type) Item.documentCreateFontMap(Map); else if (para_FootnoteReference === Item.Type || para_EndnoteReference === Item.Type) Item.CreateDocumentFontMap(Map); } if(this.Type === para_Math_Run) { TextPr.FontSize = FontSize; TextPr.FontSizeCS = FontSizeCS; } } }; ParaRun.prototype.Get_AllFontNames = function(AllFonts) { this.Pr.Document_Get_AllFontNames(AllFonts); var Count = this.Content.length; for (var Index = 0; Index < Count; Index++) { var Item = this.Content[Index]; if (para_Drawing === Item.Type) Item.documentGetAllFontNames(AllFonts); else if (para_FootnoteReference === Item.Type || para_EndnoteReference === Item.Type) Item.GetAllFontNames(AllFonts); } }; ParaRun.prototype.GetSelectedText = function(bAll, bClearText, oPr) { var StartPos = 0; var EndPos = 0; if ( true === bAll ) { StartPos = 0; EndPos = this.Content.length; } else if ( true === this.Selection.Use ) { StartPos = this.State.Selection.StartPos; EndPos = this.State.Selection.EndPos; if ( StartPos > EndPos ) { var Temp = EndPos; EndPos = StartPos; StartPos = Temp; } } var Str = ""; for ( var Pos = StartPos; Pos < EndPos; Pos++ ) { var Item = this.Content[Pos]; var ItemType = Item.Type; switch ( ItemType ) { case para_Drawing: case para_Numbering: case para_PresentationNumbering: case para_PageNum: case para_PageCount: { if ( true === bClearText ) return null; break; } case para_Text : { Str += AscCommon.encodeSurrogateChar(Item.Value); break; } case para_Space: { Str += " "; break; } case para_Tab: { Str += oPr && undefined !== oPr.TabSymbol ? oPr.TabSymbol : ' '; break; } case para_Math_Text: case para_Math_BreakOperator: { Str += AscCommon.encodeSurrogateChar(Item.value); break; } case para_NewLine: { Str += oPr && undefined !== oPr.NewLineSeparator ? oPr.NewLineSeparator : '\r'; break; } case para_End: { var oParagraph = this.GetParagraph(); if (oParagraph && null === oParagraph.Get_DocumentNext() && oParagraph.IsTableCellContent()) { if (!oParagraph.Parent.IsLastTableCellInRow(true)) Str += oPr && undefined !== oPr.TableCellSeparator ? oPr.TableCellSeparator : '\t'; else Str += oPr && undefined !== oPr.TableRowSeparator ? oPr.TableRowSeparator : '\r\n'; } else { Str += oPr && undefined !== oPr.ParaSeparator ? oPr.ParaSeparator : '\r\n'; } break; } } } return Str; }; ParaRun.prototype.GetSelectDirection = function() { if (true !== this.Selection.Use) return 0; if (this.Selection.StartPos <= this.Selection.EndPos) return 1; return -1; }; ParaRun.prototype.CanAddDropCap = function() { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { switch (this.Content[nPos].Type) { case para_Text: return true; case para_Space: case para_Tab: case para_PageNum: case para_PageCount: return false; } } return null; }; ParaRun.prototype.Get_TextForDropCap = function(DropCapText, UseContentPos, ContentPos, Depth) { var EndPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length ); for ( var Pos = 0; Pos < EndPos; Pos++ ) { var Item = this.Content[Pos]; var ItemType = Item.Type; if ( true === DropCapText.Check ) { if (para_Space === ItemType || para_Tab === ItemType || para_PageNum === ItemType || para_PageCount === ItemType || para_Drawing === ItemType || para_End === ItemType) { DropCapText.Mixed = true; return; } } else { if ( para_Text === ItemType ) { DropCapText.Runs.push(this); DropCapText.Text.push(Item); this.Remove_FromContent( Pos, 1, true ); Pos--; EndPos--; if ( true === DropCapText.Mixed ) return; } } } }; ParaRun.prototype.Get_StartTabsCount = function(TabsCounter) { var ContentLen = this.Content.length; for ( var Pos = 0; Pos < ContentLen; Pos++ ) { var Item = this.Content[Pos]; var ItemType = Item.Type; if ( para_Tab === ItemType ) { TabsCounter.Count++; TabsCounter.Pos.push( Pos ); } else if ( para_Text === ItemType || para_Space === ItemType || (para_Drawing === ItemType && true === Item.Is_Inline() ) || para_PageNum === ItemType || para_PageCount === ItemType || para_Math === ItemType ) return false; } return true; }; ParaRun.prototype.Remove_StartTabs = function(TabsCounter) { var ContentLen = this.Content.length; for ( var Pos = 0; Pos < ContentLen; Pos++ ) { var Item = this.Content[Pos]; var ItemType = Item.Type; if ( para_Tab === ItemType ) { this.Remove_FromContent( Pos, 1, true ); TabsCounter.Count--; Pos--; ContentLen--; } else if ( para_Text === ItemType || para_Space === ItemType || (para_Drawing === ItemType && true === Item.Is_Inline() ) || para_PageNum === ItemType || para_PageCount === ItemType || para_Math === ItemType ) return false; } return true; }; //----------------------------------------------------------------------------------- // Функции пересчета //----------------------------------------------------------------------------------- // Пересчитываем размеры всех элементов ParaRun.prototype.Recalculate_MeasureContent = function() { if (!this.RecalcInfo.IsMeasureNeed()) return; this.Paragraph.ShapeText(); var oTextPr = this.Get_CompiledPr(false); var oTheme = this.Paragraph.GetTheme(); let _oTextPr = oTextPr; if (this.IsUseAscFont(oTextPr)) { _oTextPr = oTextPr.Copy(); _oTextPr.RFonts.SetAll("ASCW3"); } g_oTextMeasurer.SetTextPr(_oTextPr, oTheme); var oInfoMathText; if (this.IsMathRun()) { oInfoMathText = new CMathInfoTextPr({ TextPr : oTextPr, ArgSize : this.Parent.Compiled_ArgSz.value, bNormalText : this.IsNormalText(), bEqArray : this.Parent.IsEqArray() }); } var nMaxComb = -1; var nCombWidth = null; var oTextForm = this.GetTextForm(); let oTextFormPDF = this.GetFormPDF(); if (oTextFormPDF && oTextFormPDF.GetType() !== AscPDF.FIELD_TYPES.text) oTextFormPDF = null; let isKeepWidth = false; if (oTextForm && oTextForm.IsComb()) { let textMetrics = this.getTextMetrics(); let textAscent = textMetrics.Ascent + textMetrics.LineGap; const nWRule = oTextForm.GetWidthRule(); isKeepWidth = Asc.CombFormWidthRule.Exact === nWRule; nMaxComb = oTextForm.GetMaxCharacters(); if (undefined === oTextForm.Width || nWRule === Asc.CombFormWidthRule.Auto) nCombWidth = 0; else if (oTextForm.Width < 0) nCombWidth = textAscent * (Math.abs(oTextForm.Width) / 100); else nCombWidth = AscCommon.TwipsToMM(oTextForm.Width); if (!nCombWidth || nCombWidth < 0) nCombWidth = textAscent; let oParagraph = this.GetParagraph(); if (oParagraph && oParagraph.IsInFixedForm() && oParagraph.GetInnerForm() && !oParagraph.GetInnerForm().IsComplexForm()) { isKeepWidth = true; var oShape = oParagraph.Parent.Is_DrawingShape(true); var oBounds = oShape.getFormRelRect(); if (nMaxComb > 0) nCombWidth = oBounds.W / nMaxComb; } } // for pdf text forms else if (oTextFormPDF && oTextFormPDF.IsComb() == true) { isKeepWidth = true; nMaxComb = oTextFormPDF.GetCharLimit(); nCombWidth = oTextFormPDF.getFormRelRect().W / nMaxComb; } if (nCombWidth && nMaxComb > 1) { var oCombBorder, nCombBorderW; if (oTextForm) { oCombBorder = oTextForm.GetCombBorder(); nCombBorderW = oCombBorder? oCombBorder.GetWidth() : 0; this.private_MeasureCombForm(nCombBorderW, nCombWidth, nMaxComb, oTextForm, isKeepWidth, oTextPr, oTheme, oInfoMathText); } else if (oTextFormPDF) { let oViewer = editor.getDocumentRenderer(); let scaleCoef = oViewer.zoom * AscCommon.AscBrowser.retinaPixelRatio; if (oTextFormPDF.borderStyle == "solid" || oTextFormPDF.borderStyle == "dashed") nCombBorderW = oTextFormPDF.GetBordersWidth().left * AscCommon.g_dKoef_pix_to_mm / scaleCoef; else nCombBorderW = 0; this.private_MeasureCombForm(nCombBorderW, nCombWidth, nMaxComb, oTextFormPDF, isKeepWidth, oTextPr, oTheme, oInfoMathText); } } else if (this.RecalcInfo.Measure) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { this.private_MeasureElement(nPos, oTextPr, oTheme, oInfoMathText); } } else { for (var nIndex = 0, nCount = this.RecalcInfo.MeasurePositions.length; nIndex < nCount; ++nIndex) { var nPos = this.RecalcInfo.MeasurePositions[nIndex]; if (!this.Content[nPos]) continue; this.private_MeasureElement(nPos, oTextPr, oTheme, oInfoMathText); } } this.RecalcInfo.Recalc = true; this.RecalcInfo.ResetMeasure(); }; ParaRun.prototype.getTextMetrics = function(isForceEmpty) { let textPr = this.Get_CompiledPr(false); if (this.IsUseAscFont(textPr)) { textPr = textPr.Copy(); textPr.RFonts.SetAll("ASCW3"); } // TODO: Пока для формул сделаем, чтобы работало по-старому, в дальнейшем надо будет переделать на fontslot let fontSlot = this.IsMathRun() ? AscWord.fontslot_ASCII : AscWord.fontslot_None; for (let nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { fontSlot |= this.Content[nPos].GetFontSlot(textPr); } if ((AscWord.fontslot_Unknown === fontSlot) || (AscWord.fontslot_None === fontSlot && isForceEmpty)) fontSlot = textPr.CS || textPr.RTL ? AscWord.fontslot_CS : AscWord.fontslot_ASCII; return textPr.GetTextMetrics(fontSlot, this.Paragraph.GetTheme()); }; ParaRun.prototype.getYOffset = function() { return this.Get_Position(); }; ParaRun.prototype.private_MeasureCombForm = function(nCombBorderW, nCombWidth, nMaxComb, oTextForm, isKeepWidth, oTextPr, oTheme, oInfoMathText) { let nCharsCount = 0; for (let nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { let oItem = this.Content[nPos]; if (!oItem.IsText() && !oItem.IsSpace()) continue; nCharsCount++; while (oItem.IsText() && nPos < nCount - 1 && this.Content[nPos + 1].IsText() && this.Content[nPos + 1].IsCombiningMark()) { nPos++; } } for (let nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { this.private_MeasureElement(nPos, oTextPr, oTheme, oInfoMathText); let oItem = this.Content[nPos]; if (!oItem.IsText() && !oItem.IsSpace()) continue; let nLeftGap = nCombBorderW / 2; let nRightGap = nCombBorderW / 2; let nWidth = oItem.GetCombWidth() + nLeftGap + nRightGap; if (isKeepWidth || nWidth < nCombWidth) { nLeftGap += (nCombWidth - nWidth) / 2; nRightGap += (nCombWidth - nWidth) / 2; } let nCellWidth = Math.max(oItem.GetCombWidth() + nLeftGap + nRightGap, nCombWidth); oItem.ResetGapBackground(); if (oItem.IsText() && nPos < nCount - 1 && this.Content[nPos + 1].IsText() && this.Content[nPos + 1].IsCombiningMark()) { let nFirstPos = nPos; oItem.SetGaps(nLeftGap, 0, nCellWidth); while (this.Content[nPos].IsText() && nPos < nCount - 1 && this.Content[nPos + 1].IsText() && this.Content[nPos + 1].IsCombiningMark()) { if (nPos !== nFirstPos) this.Content[nPos].SetGaps(0, 0, nCellWidth); nPos++; this.Content[nPos].ResetGapBackground(); } oItem = this.Content[nPos]; nLeftGap = 0; } if (nPos === nCount - 1 && nCharsCount < nMaxComb) { if (oTextForm.CombPlaceholderSymbol) { oItem.SetGapBackground(nMaxComb - nCharsCount, oTextForm.CombPlaceholderSymbol, nCombWidth, g_oTextMeasurer, oTextForm.CombPlaceholderFont, oTextPr, oTheme, nCombBorderW); nRightGap += (nMaxComb - nCharsCount) * oItem.RGapShift; } else { if (Asc.editor.isPdfEditor()) { let nCellsToGap; if (oTextForm.GetAlign() == AscPDF.ALIGN_TYPE.center) nCellsToGap = (nMaxComb - nCharsCount) % 2 == 0 ? 0 : 1; else if (oTextForm.GetAlign() == AscPDF.ALIGN_TYPE.right) nCellsToGap = 0; else nCellsToGap = nMaxComb - nCharsCount; oItem.SetGapBackground(nCellsToGap, 0, nCombWidth, g_oTextMeasurer, null, oTextPr, oTheme, nCombBorderW); nRightGap += nCellsToGap * Math.max(nCombWidth, nCombBorderW); } else { oItem.SetGapBackground(nMaxComb - nCharsCount, 0, nCombWidth, g_oTextMeasurer, null, oTextPr, oTheme, nCombBorderW); nRightGap += (nMaxComb - nCharsCount) * Math.max(nCombWidth, nCombBorderW); } } } oItem.SetGaps(nLeftGap, nRightGap, nCellWidth); } }; ParaRun.prototype.private_MeasureElement = function(nPos, oTextPr, oTheme, oInfoMathText) { let oParagraph = this.GetParagraph(); let oItem = this.Content[nPos]; if (oItem.IsDrawing()) { oItem.Parent = oParagraph; oItem.DocumentContent = oParagraph.Parent; oItem.DrawingDocument = oParagraph.Parent.DrawingDocument; } // TODO: Как только избавимся от para_End переделать здесь if (oItem.IsParaEnd()) { var oEndTextPr = oParagraph.GetParaEndCompiledPr(); g_oTextMeasurer.SetTextPr(oEndTextPr, oTheme); oItem.Measure(g_oTextMeasurer, oEndTextPr, oParagraph.IsLastParagraphInCell()); } else { oItem.Measure(g_oTextMeasurer, oTextPr, oInfoMathText, this); } if (oItem.IsDrawing()) { // После автофигур надо заново выставлять настройки g_oTextMeasurer.SetTextPr(oTextPr, oTheme); g_oTextMeasurer.SetFontSlot(AscWord.fontslot_ASCII); } }; ParaRun.prototype.Recalculate_Measure2 = function(Metrics) { var TAscent = Metrics.Ascent; var TDescent = Metrics.Descent; var Count = this.Content.length; for ( var Index = 0; Index < Count; Index++ ) { var Item = this.Content[Index]; var ItemType = Item.Type; if ( para_Text === ItemType ) { var Temp = g_oTextMeasurer.Measure2(String.fromCharCode(Item.Value)); if ( null === TAscent || TAscent < Temp.Ascent ) TAscent = Temp.Ascent; if ( null === TDescent || TDescent > Temp.Ascent - Temp.Height ) TDescent = Temp.Ascent - Temp.Height; } } Metrics.Ascent = TAscent; Metrics.Descent = TDescent; }; ParaRun.prototype.Recalculate_Range = function(PRS, ParaPr, Depth) { if ( this.Paragraph !== PRS.Paragraph ) { this.Paragraph = PRS.Paragraph; this.RecalcInfo.TextPr = true; this.RecalcInfo.Measure = true; this.OnContentChange(); } // Сначала измеряем элементы (можно вызывать каждый раз, внутри разруливается, чтобы измерялось 1 раз) this.Recalculate_MeasureContent(); var CurLine = PRS.Line - this.StartLine; var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range ); // Если мы рассчитываем первый отрезок в первой строке, тогда нам нужно обновить информацию о нумерации if ( 0 === CurRange && 0 === CurLine ) { var PrevRecalcInfo = PRS.RunRecalcInfoLast; // Либо до этого ничего не было (изначально первая строка и первый отрезок), либо мы заново пересчитываем // первую строку и первый отрезок (из-за обтекания, например). if ( null === PrevRecalcInfo ) this.RecalcInfo.NumberingAdd = true; else this.RecalcInfo.NumberingAdd = PrevRecalcInfo.NumberingAdd; this.RecalcInfo.NumberingUse = false; this.RecalcInfo.NumberingItem = null; } // Сохраняем ссылку на информацию пересчета данного рана PRS.RunRecalcInfoLast = this.RecalcInfo; // Добавляем информацию о новом отрезке var RangeStartPos = this.protected_AddRange(CurLine, CurRange); var RangeEndPos = 0; var Para = PRS.Paragraph; var MoveToLBP = PRS.MoveToLBP; var NewRange = PRS.NewRange; var ForceNewPage = PRS.ForceNewPage; var NewPage = PRS.NewPage; var End = PRS.End; var Word = PRS.Word; var StartWord = PRS.StartWord; var FirstItemOnLine = PRS.FirstItemOnLine; var EmptyLine = PRS.EmptyLine; var TextOnLine = PRS.TextOnLine; var RangesCount = PRS.RangesCount; var SpaceLen = PRS.SpaceLen; var WordLen = PRS.WordLen; var X = PRS.X; var XEnd = this.Paragraph.IsUseXLimit() ? PRS.XEnd : MEASUREMENT_MAX_MM_VALUE * 10; var ParaLine = PRS.Line; var ParaRange = PRS.Range; var bMathWordLarge = PRS.bMathWordLarge; var OperGapRight = PRS.OperGapRight; var OperGapLeft = PRS.OperGapLeft; var bInsideOper = PRS.bInsideOper; var bContainCompareOper = PRS.bContainCompareOper; var bEndRunToContent = PRS.bEndRunToContent; var bNoOneBreakOperator = PRS.bNoOneBreakOperator; var bForcedBreak = PRS.bForcedBreak; var Pos = RangeStartPos; var ContentLen = this.Content.length; var XRange = PRS.XRange; var oSectionPr = undefined; let isSkipFillRange = false; let textPr = this.Get_CompiledPr(false); // TODO: Сделать возможность показывать инструкцию var isHiddenCFPart = PRS.ComplexFields.isHiddenComplexFieldPart(); PRS.CheckUpdateLBP(Pos, Depth); if (false === StartWord && true === FirstItemOnLine && XEnd - X < 0.001 && RangesCount > 0) { NewRange = true; RangeEndPos = Pos; } else { for (; Pos < ContentLen; Pos++) { var Item = this.Content[Pos]; var ItemType = Item.Type; if (PRS.ComplexFields.isHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType) continue; if (para_InstrText === ItemType) { if (PRS.IsFastRecalculate()) { if (Item.GetReplacementItem()) { Item = Item.GetReplacementItem(); ItemType = Item.Type; } } else { var oInstrText = Item; if (!isHiddenCFPart) { if (AscCommon.IsSpace(Item.Value)) { Item = new AscWord.CRunSpace(Item.Value); ItemType = para_Space; Item.Measure(g_oTextMeasurer, this.getCompiledPr()); } else { // TODO: Пока для такого текста не шейпим по-нормальному, а как по-старому по одному отдельному символу Item = new AscWord.CRunText(Item.Value); ItemType = para_Text; AscWord.ParagraphTextShaper.ShapeRunTextItem(Item, this.getCompiledPr()); } oInstrText.SetReplacementItem(Item); } else { oInstrText.SetReplacementItem(null); } } } if (isHiddenCFPart && para_End !== ItemType && para_FieldChar !== ItemType) continue; // Проверяем, не нужно ли добавить нумерацию к данному элементу if (true === this.RecalcInfo.NumberingAdd && true === Item.CanAddNumbering()) X = this.private_RecalculateNumbering(PRS, Item, ParaPr, X); switch (ItemType) { case para_Sym: case para_Text: case para_FootnoteReference: case para_FootnoteRef: case para_Separator: case para_ContinuationSeparator: case para_EndnoteReference: case para_EndnoteRef: { // Отмечаем, что началось слово StartWord = true; if (para_ContinuationSeparator === ItemType || para_Separator === ItemType) Item.UpdateWidth(PRS); else if (para_Text === ItemType) { Item.ResetTemporaryGrapheme(); Item.ResetTemporaryHyphenAfter(); } if (true !== PRS.IsFastRecalculate()) { if (para_FootnoteReference === ItemType) { if (this.GetLogicDocument() && !this.GetLogicDocument().RecalcTableHeader) { Item.UpdateNumber(PRS, this.GetLogicDocument().PrintSelection); PRS.AddFootnoteReference(Item, PRS.GetCurrentContentPos(Pos)); } else { Item.private_Measure(); } } else if (para_EndnoteReference === ItemType) { if (this.GetLogicDocument() && !this.GetLogicDocument().RecalcTableHeader) { Item.UpdateNumber(PRS, this.GetLogicDocument().PrintSelection); PRS.AddEndnoteReference(Item, PRS.GetCurrentContentPos(Pos)); } else { Item.private_Measure(); } } else if (para_FootnoteRef === ItemType || para_EndnoteRef === ItemType) { Item.UpdateNumber(PRS.TopDocument); } } let isBreakBefore = Item.IsSpaceBefore(); if (isBreakBefore && Word && PRS.LastItem.CanBeAtEndOfLine() && Item.CanBeAtBeginOfLine()) { PRS.Set_LineBreakPos(Pos, FirstItemOnLine); X += SpaceLen + WordLen; Word = false; EmptyLine = false; TextOnLine = true; FirstItemOnLine = false; SpaceLen = 0; WordLen = 0; } // При проверке, убирается ли слово, мы должны учитывать ширину предшествующих пробелов let LetterLen = Item.GetWidth(); let isLigature = Item.IsLigature(); let GraphemeLen = isLigature ? Item.GetLigatureWidth() : LetterLen; let isBreakAfter = Item.IsSpaceAfter() || textPr.RFonts.Hint === AscWord.fonthint_EastAsia; if (FirstItemOnLine && (X + SpaceLen + WordLen + GraphemeLen > XEnd || (PRS.IsNeedShapeFirstWord(PRS.Line) && PRS.IsLastElementInWord(this, Pos)))) { let oCurrentPos = PRS.CurPos.Copy(); oCurrentPos.Update(Pos, Depth); if (isLigature) oCurrentPos = Para.GetLigatureEndPos(oCurrentPos); else oCurrentPos.Update(Pos + 1, Depth); Para.ShapeTextInRange(PRS.LineBreakPos, oCurrentPos); SpaceLen = 0; LetterLen = 0; GraphemeLen = 0; WordLen = Para.GetContentWidthInRange(PRS.LineBreakPos, oCurrentPos); if (X + WordLen > XEnd && (Word || !Para.IsSingleRangeOnLine(ParaLine, ParaRange))) { // Слово оказалось единственным элементом в промежутке, и, все равно, // не умещается целиком. Делаем следующее: // // 1) Если у нас строка с вырезами, тогда ставим перенос внутри строки в начале слова // 2) Если у нас строка без вырезов, тогда мы ищем перенос строки, начиная с текущего // места в обратном направлении, при этом решейпим текст в заданном промежутке let isBreak = true; if (Para.IsSingleRangeOnLine(ParaLine, ParaRange)) { let oLineStartPos = PRS.LineBreakPos.Copy(); PRS.LineBreakPos = Para.FindLineBreakInLongWord(XEnd - X, PRS.LineBreakPos, oCurrentPos); if (PRS.LineBreakPos.IsEqual(oLineStartPos) || PRS.LineBreakPos.IsEqual(oCurrentPos)) { PRS.LineBreakPos = oLineStartPos; LetterLen = WordLen; WordLen = 0; isBreak = false; } else { this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeStartPos); Para.Recalculate_SetRangeBounds(ParaLine, ParaRange, oLineStartPos, PRS.LineBreakPos); isSkipFillRange = true; PRS.LongWord = true; EmptyLine = false; TextOnLine = true; X += WordLen; WordLen = 0; } } if (isBreak) { MoveToLBP = true; NewRange = true; break; } } else if (!Word) { WordLen = 0; LetterLen = Item.GetWidth(); } } if (!Word) { // Слово только началось. Делаем следующее: // 1) Если до него на строке ничего не было и данная строка не // имеет разрывов, тогда не надо проверять убирается ли слово в строке. // 2) В противном случае, проверяем убирается ли слово в промежутке. // Если слово только началось, и до него на строке ничего не было, и в строке нет разрывов, тогда не надо проверять убирается ли оно на строке. if (!FirstItemOnLine || !Para.IsSingleRangeOnLine(ParaLine, ParaRange)) { if (X + SpaceLen + LetterLen > XEnd) { if (para_Text === ItemType && !Item.CanBeAtBeginOfLine() && !PRS.LineBreakFirst) { MoveToLBP = true; NewRange = true; } else { NewRange = true; RangeEndPos = Pos; PRS.checkLastAutoHyphen(); } } } if (true !== NewRange) { // Если с данного элемента не может начинаться строка, тогда считает все пробелы идущие // до него частью этого слова. // Если места для разрыва строки еще не было, значит это все еще первый элемент идет, и // тогда общую ширину пробелов прибавляем к ширине символа. // Если разрыв были и с данного символа не может начинаться строка, тогда испоьльзуем // предыдущий разрыв. if (PRS.LineBreakFirst && !Item.CanBeAtBeginOfLine()) { Word = true; FirstItemOnLine = true; WordLen = X - PRS.XRange + LetterLen + SpaceLen; SpaceLen = 0; X = PRS.XRange; PRS.X = X; } else { if (Item.CanBeAtBeginOfLine()) { PRS.Set_LineBreakPos(Pos, FirstItemOnLine); PRS.checkLastAutoHyphen(); } // Если текущий символ с переносом, например, дефис, тогда на нем заканчивается слово if (isBreakAfter || (PRS.canPlaceAutoHyphenAfter(Item) && X + SpaceLen + LetterLen + PRS.getAutoHyphenWidth(Item, this) <= XEnd && (FirstItemOnLine || PRS.checkHyphenationZone(X + SpaceLen)))) { if (!isBreakAfter) PRS.lastAutoHyphen = Item; // Добавляем длину пробелов до слова и ширину самого слова. X += SpaceLen + LetterLen; Word = false; FirstItemOnLine = false; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; } else { Word = true; WordLen = LetterLen; } } } } else { let autoHyphenWidth = PRS.getAutoHyphenWidth(Item, this); let fitOnLine = PRS.isFitOnLine(X, SpaceLen + WordLen + GraphemeLen + autoHyphenWidth); if (!fitOnLine && !FirstItemOnLine) { MoveToLBP = true; NewRange = true; } if (true !== NewRange) { // Мы убираемся в пределах данной строки. Прибавляем ширину буквы к ширине слова WordLen += LetterLen; if (isBreakAfter || (PRS.canPlaceAutoHyphenAfter(Item) && fitOnLine && (FirstItemOnLine || PRS.checkHyphenationZone(X + SpaceLen)))) { if (!isBreakAfter) PRS.lastAutoHyphen = Item; // Добавляем длину пробелов до слова и ширину самого слова. X += SpaceLen + WordLen; Word = false; FirstItemOnLine = false; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; } } } break; } case para_Math_Text: case para_Math_Ampersand: case para_Math_Placeholder: { // Отмечаем, что началось слово StartWord = true; // При проверке, убирается ли слово, мы должны учитывать ширину предшествующих пробелов. var LetterLen = Item.Get_Width2() / AscWord.TEXTWIDTH_DIVIDER;//var LetterLen = Item.GetWidth(); if (true !== Word) { // Если слово только началось, и до него на строке ничего не было, и в строке нет разрывов, тогда не надо проверять убирается ли оно на строке. if (true !== FirstItemOnLine /*|| false === Para.IsSingleRangeOnLine(ParaLine, ParaRange)*/) { if (X + SpaceLen + LetterLen > XEnd) { NewRange = true; RangeEndPos = Pos; } else if(bForcedBreak == true) { MoveToLBP = true; NewRange = true; PRS.Set_LineBreakPos(Pos, FirstItemOnLine); } } if(true !== NewRange) { if(this.Parent.bRoot == true) PRS.Set_LineBreakPos(Pos, FirstItemOnLine); WordLen += LetterLen; Word = true; } } else { if(X + SpaceLen + WordLen + LetterLen > XEnd) { if(true === FirstItemOnLine /*&& true === Para.IsSingleRangeOnLine(ParaLine, ParaRange)*/) { // Слово оказалось единственным элементом в промежутке, и, все равно, не умещается целиком. // для Формулы слово не разбиваем, перенос не делаем, пишем в одну строку (слово выйдет за границу как в Ворде) bMathWordLarge = true; } else { // Слово не убирается в отрезке. Переносим слово в следующий отрезок MoveToLBP = true; NewRange = true; } } if (true !== NewRange) { // Мы убираемся в пределах данной строки. Прибавляем ширину буквы к ширине слова WordLen += LetterLen; } } break; } case para_Space: { // TODO: Проверку Balanced перенести в Measure (и избавиться от WidthEn) if (PRS.IsBalanceSingleByteDoubleByteWidth(this, Pos)) Item.BalanceSingleByteDoubleByteWidth(); else if (PRS.IsCondensedSpaces()) PRS.AddCondensedSpaceToRange(Item); else Item.ResetCondensedWidth(); if (Word && PRS.LastItem && para_Text === PRS.LastItem.Type && !PRS.LastItem.CanBeAtEndOfLine()) { WordLen += Item.GetWidth(); break; } FirstItemOnLine = false; if (true === Word) { // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять // убирается ли слово, мы это проверяем при добавленнии букв. X += SpaceLen + WordLen; Word = false; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; } // На пробеле не делаем перенос. Перенос строки или внутристрочный // перенос делаем при добавлении любого непробельного символа SpaceLen += Item.GetWidth(); break; } case para_Math_BreakOperator: { var BrkLen = Item.Get_Width2()/AscWord.TEXTWIDTH_DIVIDER; var oFirstContent = (PRS.Word === false && this.Content.length > 0) ? this.Content[0] : null; var strFirstLetter = oFirstContent !== null ? String.fromCharCode(oFirstContent.value) : ""; var isFirstOperator = PRS.Word === false && AscMath.MathLiterals.operator.SearchU(strFirstLetter); var bCompareOper = Item.Is_CompareOperator(); var bOperBefore = isFirstOperator || this.ParaMath.Is_BrkBinBefore() == true; var bOperInEndContent = bOperBefore === false && bEndRunToContent === true && Pos == ContentLen - 1 && Word == true, // необходимо для того, чтобы у контентов мат объектов (к-ые могут разбиваться на строки) не было отметки Set_LineBreakPos, иначе скобка (или GapLeft), перед которой стоит break_Operator, перенесется на следующую строку (без текста !) bLowPriority = bCompareOper == false && bContainCompareOper == false; if(Pos == 0 && true === this.IsForcedBreak()) // принудительный перенос срабатывает всегда { if(FirstItemOnLine === true && Word == false && bNoOneBreakOperator == true) // первый оператор в строке { WordLen += BrkLen; } else if(bOperBefore) { X += SpaceLen + WordLen; WordLen = 0; SpaceLen = 0; NewRange = true; RangeEndPos = Pos; } else { if(FirstItemOnLine == false && X + SpaceLen + WordLen + BrkLen > XEnd) { MoveToLBP = true; NewRange = true; } else { X += SpaceLen + WordLen; Word = false; MoveToLBP = true; NewRange = true; PRS.Set_LineBreakPos(1, FirstItemOnLine); } } } else if(bOperInEndContent || bLowPriority) // у этого break Operator приоритет низкий(в контенте на данном уровне есть другие операторы с более высоким приоритетом) => по нему не разбиваем, обрабатываем как обычную букву { if(X + SpaceLen + WordLen + BrkLen > XEnd) { if(FirstItemOnLine == true) { bMathWordLarge = true; } else { // Слово не убирается в отрезке. Переносим слово в следующий отрезок MoveToLBP = true; NewRange = true; } } else { WordLen += BrkLen; } } else { var WorLenCompareOper = WordLen + X - XRange + (bOperBefore ? SpaceLen : BrkLen); var bOverXEnd, bOverXEndMWordLarge; var bNotUpdBreakOper = false; var bCompareWrapIndent = PRS.bFirstLine == true ? WorLenCompareOper > PRS.WrapIndent : true; if(PRS.bPriorityOper == true && bCompareOper == true && bContainCompareOper == true && bCompareWrapIndent == true && !(Word == false && FirstItemOnLine === true)) // (Word == true && FirstItemOnLine == true) - не первый элемент в строке bContainCompareOper = false; if(bOperBefore) // оператор "до" => оператор находится в начале строки { bOverXEnd = X + WordLen + SpaceLen + BrkLen > XEnd; // BrkLen прибавляем дла случая, если идут подряд Brk Operators в конце bOverXEndMWordLarge = X + WordLen + SpaceLen > XEnd; // ширину самого оператора не учитываем при расчете bMathWordLarge, т.к. он будет находится на следующей строке if(bOverXEnd && (true !== FirstItemOnLine || true === Word)) { // если вышли за границы не обновляем параметр bInsideOper, т.к. если уже были breakOperator, то, соответственно, он уже выставлен в true // а если на этом уровне не было breakOperator, то и обновлять его нне нужо if(FirstItemOnLine === false) { MoveToLBP = true; NewRange = true; } else { if(Word == true && bOverXEndMWordLarge == true) { bMathWordLarge = true; } X += SpaceLen + WordLen; if(PRS.bBreakPosInLWord == true) { PRS.Set_LineBreakPos(Pos, FirstItemOnLine); } else { bNotUpdBreakOper = true; } RangeEndPos = Pos; SpaceLen = 0; WordLen = 0; NewRange = true; EmptyLine = false; TextOnLine = true; } } else { if(FirstItemOnLine === false) bInsideOper = true; if(Word == false && FirstItemOnLine == true ) { SpaceLen += BrkLen; } else { // проверка на FirstItemOnLine == false нужна для случая, если иду подряд несколько breakOperator // в этом случае Word == false && FirstItemOnLine == false, нужно также поставить отметку для потенциального переноса X += SpaceLen + WordLen; PRS.Set_LineBreakPos(Pos, FirstItemOnLine); EmptyLine = false; TextOnLine = true; WordLen = BrkLen; SpaceLen = 0; } // в первой строке может не быть ни одного break Operator, при этом слово не выходит за границы, т.о. обновляем FirstItemOnLine также и на Word = true // т.к. оператор идет в начале строки, то соответственно слово в стоке не будет первым, если в строке больше одного оператора if(bNoOneBreakOperator == false || Word == true) FirstItemOnLine = false; } } else // оператор "после" => оператор находится в конце строки { bOverXEnd = X + WordLen + BrkLen - Item.GapRight > XEnd; bOverXEndMWordLarge = bOverXEnd; if(bOverXEnd && FirstItemOnLine === false) // Слово не убирается в отрезке. Переносим слово в следующий отрезок { MoveToLBP = true; NewRange = true; if(Word == false) PRS.Set_LineBreakPos(Pos, FirstItemOnLine); } else { bInsideOper = true; // осуществляем здесь, чтобы не изменить GapRight в случае, когда новое слово не убирается на break_Operator OperGapRight = Item.GapRight; if(bOverXEndMWordLarge == true) // FirstItemOnLine == true { bMathWordLarge = true; } X += BrkLen + WordLen; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; var bNotUpdate = bOverXEnd == true && PRS.bBreakPosInLWord == false; // FirstItemOnLine == true if(bNotUpdate == false) // LineBreakPos обновляем здесь, т.к. слово может начаться с мат объекта, а не с Run, в мат объекте нет соответствующей проверки { PRS.Set_LineBreakPos(Pos + 1, FirstItemOnLine); } else { bNotUpdBreakOper = true; } FirstItemOnLine = false; Word = false; } } } if(bNotUpdBreakOper == false) bNoOneBreakOperator = false; break; } case para_Drawing: { if(oSectionPr === undefined) { oSectionPr = Para.Get_SectPr(); } Item.CheckRecalcAutoFit(oSectionPr); if (true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape()) { // TODO: Нельзя что-то писать в историю во время пересчета, это действие надо делать при открытии // if (true !== Item.Is_Inline()) // Item.Set_DrawingType(drawing_Inline); if (true === StartWord) FirstItemOnLine = false; Item.YOffset = this.getYOffset(); // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы, // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если // данный элемент убирается if (true === Word || WordLen > 0) { // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять // убирается ли слово, мы это проверяем при добавленнии букв. X += SpaceLen + WordLen; Word = false; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; } var DrawingWidth = Item.GetWidth(); if (X + SpaceLen + DrawingWidth > XEnd && ( false === FirstItemOnLine || false === Para.IsSingleRangeOnLine(ParaLine, ParaRange) )) { // Автофигура не убирается, ставим перенос перед ней NewRange = true; RangeEndPos = Pos; } else { // Добавляем длину пробелов до автофигуры X += SpaceLen + DrawingWidth; FirstItemOnLine = false; EmptyLine = false; } SpaceLen = 0; } else if (!Item.IsSkipOnRecalculate()) { // Основная обработка происходит в Recalculate_Range_Spaces. Здесь обрабатывается единственный случай, // когда после второго пересчета с уже добавленной картинкой оказывается, что место в параграфе, где // идет картинка ушло на следующую страницу. В этом случае мы ставим перенос страницы перед картинкой. var LogicDocument = Para.Parent; var LDRecalcInfo = LogicDocument.RecalcInfo; var DrawingObjects = LogicDocument.DrawingObjects; var CurPage = PRS.Page; if (true === LDRecalcInfo.Check_FlowObject(Item) && true === LDRecalcInfo.Is_PageBreakBefore()) { LDRecalcInfo.Reset(); let continueCalc = false; // Добавляем разрыв страницы. Если это первая страница, тогда ставим разрыв страницы в начале параграфа, // если нет, тогда в начале текущей строки. if (null != Para.Get_DocumentPrev() && true != Para.IsTableCellContent() && 0 === CurPage) { Para.Recalculate_Drawing_AddPageBreak(0, 0, true); PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Page; PRS.NewRange = true; return; } else { if (ParaLine != Para.Pages[CurPage].FirstLine) { Para.Recalculate_Drawing_AddPageBreak(ParaLine, CurPage, false); PRS.RecalcResult = recalcresult_NextPage | recalcresultflags_Page; PRS.NewRange = true; return; } else if (Para.IsStartFromNewPage()) { // Делаем как MSWord перестаем учитывать обтекание данного объекта continueCalc = true; LDRecalcInfo.Set_FlowObject(Item, 0, recalcresult_NextElement, -1); LDRecalcInfo.Set_PageBreakBefore(false); LDRecalcInfo.SetForceNoWrap(true); PRS.ForceNewPageAfter = true; } else { RangeEndPos = Pos; NewRange = true; ForceNewPage = true; } } // Если до этого было слово, тогда не надо проверять убирается ли оно if (!continueCalc && (true === Word || WordLen > 0)) { // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять // убирается ли слово, мы это проверяем при добавленнии букв. X += SpaceLen + WordLen; Word = false; SpaceLen = 0; WordLen = 0; } } } break; } case para_PageCount: case para_PageNum: { if (para_PageCount === ItemType) { var oHdrFtr = Para.Parent.IsHdrFtr(true); if (oHdrFtr) oHdrFtr.Add_PageCountElement(Item); } else if (para_PageNum === ItemType) { let logicDocument = Para.LogicDocument; let sectInfo = logicDocument.Get_SectionPageNumInfo2(Para.GetAbsolutePage(PRS.Page)); let sectPr = logicDocument.GetSections().GetSectPrByIndex(sectInfo.SectIndex); Item.SetValue(sectInfo.CurPage, sectPr.GetPageNumFormat()); } // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы, // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если // данный элемент убирается if (true === Word || WordLen > 0) { // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять // убирается ли слово, мы это проверяем при добавленнии букв. X += SpaceLen + WordLen; Word = false; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; } // Если на строке начиналось какое-то слово, тогда данная строка уже не пустая if (true === StartWord) FirstItemOnLine = false; var PageNumWidth = Item.GetWidth(); if (X + SpaceLen + PageNumWidth > XEnd && ( false === FirstItemOnLine || false === Para.IsSingleRangeOnLine(ParaLine, ParaRange) )) { // Данный элемент не убирается, ставим перенос перед ним NewRange = true; RangeEndPos = Pos; } else { // Добавляем длину пробелов до слова и ширину данного элемента X += SpaceLen + PageNumWidth; FirstItemOnLine = false; EmptyLine = false; TextOnLine = true; } SpaceLen = 0; break; } case para_Tab: { // Сначала проверяем, если у нас уже есть таб, которым мы должны рассчитать, тогда высчитываем // его ширину. var isLastTabToRightEdge = PRS.LastTab && -1 !== PRS.LastTab.Value ? PRS.LastTab.TabRightEdge : false; X = this.private_RecalculateLastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen); // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять // убирается ли слово, мы это проверяем при добавленнии букв. X += SpaceLen + WordLen; Word = false; SpaceLen = 0; WordLen = 0; var TabPos = Para.private_RecalculateGetTabPos(PRS, X, ParaPr, PRS.Page, false); var NewX = X + TabPos.TabWidth; var TabValue = TabPos.TabValue; Item.SetLeader(TabPos.TabLeader, this.Get_CompiledPr(false)); PRS.LastTab.TabPos = NewX; PRS.LastTab.Value = TabValue; PRS.LastTab.X = X; PRS.LastTab.Item = Item; PRS.LastTab.TabRightEdge = TabPos.TabRightEdge; var nCompatibilityMode = PRS.getCompatibilityMode(); // Если таб не левый, значит он не может быть сразу рассчитан, а если левый, тогда // рассчитываем его сразу здесь if (tab_Left !== TabValue) { Item.Width = 0; // В Word2013 и раньше, если не левый таб заканчивается правее правой границы, тогда у параграфа // правая граница имеет максимально возможное значение (55см) if (AscCommon.MMToTwips(NewX) > AscCommon.MMToTwips(XEnd) && nCompatibilityMode <= AscCommon.document_compatibility_mode_Word14) { // TODO: Временно сделаем так. По-хорошему надо помечать промежуток, что в нем не учитывается границы при расчете переносов, // а XEnd не менять Para.Lines[PRS.Line].Ranges[PRS.Range].XEndOrigin = Para.Lines[PRS.Line].Ranges[PRS.Range].XEnd; Para.Lines[PRS.Line].Ranges[PRS.Range].XEnd = 558.7; XEnd = 558.7; PRS.XEnd = XEnd; PRS.BadLeftTab = true; } } else { // TODO: Если таб расположен между правым полем страницы и правым отступом параграфа (отступ // должен быть положительным), то начиная с версии AscCommon.document_compatibility_mode_Word15 // табы немного неправильно рассчитываются. Смотри файл "Табы. Рассчет табов рядом с правым краем(2016).docx" var twX = AscCommon.MMToTwips(X); var twXEnd = AscCommon.MMToTwips(XEnd); var twNewX = AscCommon.MMToTwips(NewX); if (nCompatibilityMode <= AscCommon.document_compatibility_mode_Word14 && !isLastTabToRightEdge && true !== TabPos.DefaultTab && (twNewX >= twXEnd && XEnd < 558.7 && PRS.Range >= PRS.RangesCount - 1)) { Para.Lines[PRS.Line].Ranges[PRS.Range].XEnd = 558.7; XEnd = 558.7; PRS.XEnd = XEnd; PRS.BadLeftTab = true; twXEnd = AscCommon.MMToTwips(XEnd); } if (!PRS.BadLeftTab && (false === FirstItemOnLine || false === Para.IsSingleRangeOnLine(ParaLine, ParaRange)) && (((TabPos.DefaultTab || PRS.Range < PRS.RangesCount - 1) && twNewX > twXEnd) || (!TabPos.DefaultTab && twNewX > AscCommon.MMToTwips(TabPos.PageXLimit)))) { WordLen = NewX - X; RangeEndPos = Pos; NewRange = true; } else { Item.Width = NewX - X; X = NewX; } } // Считаем, что с таба начинается слово PRS.Set_LineBreakPos(Pos, FirstItemOnLine); // Если перенос идет по строке, а не из-за обтекания, тогда разрываем перед табом, а если // из-за обтекания, тогда разрываем перед последним словом, идущим перед табом if (RangesCount === CurRange) { if (true === StartWord) { FirstItemOnLine = false; EmptyLine = false; TextOnLine = true; } } StartWord = true; Word = true; break; } case para_NewLine: { // Сначала проверяем, если у нас уже есть таб, которым мы должны рассчитать, тогда высчитываем // его ширину. X = this.private_RecalculateLastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen); X += WordLen; if (true === Word) { EmptyLine = false; TextOnLine = true; Word = false; X += SpaceLen; SpaceLen = 0; } let isLineBreak = Item.IsLineBreak(); if (Item.IsPageBreak() || Item.IsColumnBreak()) { isLineBreak = false; PRS.BreakPageLine = true; if (Item.IsPageBreak()) PRS.BreakRealPageLine = true; if (Para.IsTableCellContent() || !Para.IsInline()) { Item.Flags.Use = false; continue; } else if (!(PRS.GetTopDocument() instanceof CDocument)) { // Везде кроме таблиц считаем такие разрывы обычными разрывами строки isLineBreak = true; } else { if (Item.IsPageBreak() && !Para.CheckSplitPageOnPageBreak(Item)) continue; Item.Flags.NewLine = true; NewPage = true; NewRange = true; } } if (isLineBreak) { PRS.BreakLine = true; NewRange = true; EmptyLine = false; TextOnLine = true; // здесь оставляем проверку, т.к. в случае, если после неинлайновой формулы нах-ся инлайновая необходимо в любом случае сделать перенос (проверка в private_RecalculateRange(), где выставляется PRS.ForceNewLine = true не пройдет) if (true === PRS.MathNotInline) PRS.ForceNewLine = true; } PRS.onEndRecalculateLineRange(); RangeEndPos = Pos + 1; break; } case para_End: { if (true === Word) { FirstItemOnLine = false; EmptyLine = false; TextOnLine = true; } X += WordLen; if (true === Word) { X += SpaceLen; SpaceLen = 0; WordLen = 0; } X = this.private_RecalculateLastTab(PRS.LastTab, X, XEnd, Word, WordLen, SpaceLen); NewRange = true; End = true; PRS.onEndRecalculateLineRange(); RangeEndPos = Pos + 1; break; } case para_FieldChar: { if (PRS.IsFastRecalculate()) break; Item.SetXY(X + SpaceLen + WordLen, PRS.Y); Item.SetPage(Para.GetAbsolutePage(PRS.Page)); Item.SetRun(this); PRS.ComplexFields.processFieldChar(Item); isHiddenCFPart = PRS.ComplexFields.isHiddenComplexFieldPart(); if (Item.IsSeparate()) { var oComplexField = Item.GetComplexField(); var oHdrFtr = Para.Parent.IsHdrFtr(true); if (oHdrFtr && !oComplexField && this.Paragraph) { // Т.к. Recalculate_Width запускается после Recalculate_Range, то возможен случай, когда у нас // поля еще не собраны, но в колонтитулах они нам нужны уже собранные this.Paragraph.ProcessComplexFields(); oComplexField = Item.GetComplexField(); } var oInstruction = oComplexField ? oComplexField.GetInstruction() : null; let isHiddenValue = !!(oHdrFtr && oInstruction && (AscWord.fieldtype_NUMPAGES === oInstruction.GetType() || AscWord.fieldtype_PAGE === oInstruction.GetType() || AscWord.fieldtype_FORMULA === oInstruction.GetType())); Item.SetHiddenValue(isHiddenValue); } else if (Item.IsEnd() && !isHiddenCFPart) { // Специальная ветка, для полей PAGE и NUMPAGES, находящихся в колонтитуле var oComplexField = Item.GetComplexField(); var oHdrFtr = Para.Parent.IsHdrFtr(true); // TODO: Ранее обработка была на Separate и поле могло быть не собрано, теперь оно на End // и такого просиходить не должно if (oHdrFtr && !oComplexField && this.Paragraph) { // Т.к. Recalculate_Width запускается после Recalculate_Range, то возможен случай, когда у нас // поля еще не собраны, но в колонтитулах они нам нужны уже собранные this.Paragraph.ProcessComplexFields(); oComplexField = Item.GetComplexField(); } let isVisualFieldChar = false; var oInstruction = oComplexField ? oComplexField.GetInstruction() : null; if (oHdrFtr && oInstruction && (AscWord.fieldtype_NUMPAGES === oInstruction.GetType() || AscWord.fieldtype_PAGE === oInstruction.GetType() || AscWord.fieldtype_FORMULA === oInstruction.GetType())) { if (AscWord.fieldtype_NUMPAGES === oInstruction.GetType()) { oHdrFtr.Add_PageCountElement(Item); let logicDocument = Para.LogicDocument; if (!Item.IsNumValue() && logicDocument && logicDocument.IsDocumentEditor()) { let numFormat = oInstruction.haveNumericFormat() ? oInstruction.getNumericFormat() : Asc.c_oAscNumberingFormat.Decimal; Item.SetNumValue(logicDocument.Pages.length, numFormat); } } else if (AscWord.fieldtype_PAGE === oInstruction.GetType()) { let logicDocument = Para.LogicDocument; let sectInfo = logicDocument.Get_SectionPageNumInfo2(Para.GetAbsolutePage(PRS.Page)); let sectPr = logicDocument.GetSections().GetSectPrByIndex(sectInfo.SectIndex); let numFormat = oInstruction.haveNumericFormat() ? oInstruction.getNumericFormat() : sectPr.GetPageNumFormat(); Item.SetNumValue(sectInfo.CurPage, numFormat); } else { if (oComplexField.IsHaveNestedNUMPAGES()) oHdrFtr.Add_PageCountElement(Item); var sValue = oComplexField.CalculateValue(); var nValue = parseInt(sValue); if (isNaN(nValue)) nValue = 0; Item.SetFormulaValue(nValue); } isVisualFieldChar = true; } else if (oComplexField && oComplexField.IsFormCheckBox()) { isVisualFieldChar = true; Item.SetFormCheckBox(true); } else { Item.SetNumValue(null); } if (isVisualFieldChar) { var oParent = this.GetParent(); var nRunPos = this.private_GetPosInParent(oParent); // Заглушка на случай, когда настройки текущего рана не совпадают с настройками рана, // где расположено значение поля, либо начало поля let numValueTextPr = this.Get_CompiledPr(false); if (Pos <= 0 && oParent && nRunPos > 0 && oParent.Content[nRunPos - 1] instanceof AscWord.Run) numValueTextPr = oParent.Content[nRunPos - 1].Get_CompiledPr(false); g_oTextMeasurer.SetTextPr(numValueTextPr, this.Paragraph.Get_Theme()); Item.Measure(g_oTextMeasurer, numValueTextPr); // Если до этого было слово, тогда не надо проверять убирается ли оно, но если стояли пробелы, // тогда мы их учитываем при проверке убирается ли данный элемент, и добавляем только если // данный элемент убирается if (true === Word || WordLen > 0) { // Добавляем длину пробелов до слова + длина самого слова. Не надо проверять // убирается ли слово, мы это проверяем при добавленнии букв. X += SpaceLen + WordLen; Word = false; EmptyLine = false; TextOnLine = true; SpaceLen = 0; WordLen = 0; } // Если на строке начиналось какое-то слово, тогда данная строка уже не пустая if (true === StartWord) FirstItemOnLine = false; var PageNumWidth = Item.GetWidth(); if (X + SpaceLen + PageNumWidth > XEnd && ( false === FirstItemOnLine || false === Para.IsSingleRangeOnLine(ParaLine, ParaRange) )) { // Данный элемент не убирается, ставим перенос перед ним NewRange = true; RangeEndPos = Pos; } else { // Добавляем длину пробелов до слова и ширину данного элемента X += SpaceLen + PageNumWidth; FirstItemOnLine = false; EmptyLine = false; TextOnLine = true; } SpaceLen = 0; } } break; } } if (para_Space !== ItemType) { PRS.LastItem = Item; PRS.LastItemRun = this; } if (true === NewRange) break; } } PRS.MoveToLBP = MoveToLBP; PRS.NewRange = NewRange; PRS.ForceNewPage = ForceNewPage; PRS.NewPage = NewPage; PRS.End = End; PRS.Word = Word; PRS.StartWord = StartWord; PRS.FirstItemOnLine = FirstItemOnLine; PRS.EmptyLine = EmptyLine; PRS.TextOnLine = TextOnLine; PRS.SpaceLen = SpaceLen; PRS.WordLen = WordLen; PRS.bMathWordLarge = bMathWordLarge; PRS.OperGapRight = OperGapRight; PRS.OperGapLeft = OperGapLeft; PRS.X = X; PRS.XEnd = XEnd; PRS.bInsideOper = bInsideOper; PRS.bContainCompareOper = bContainCompareOper; PRS.bEndRunToContent = bEndRunToContent; PRS.bNoOneBreakOperator = bNoOneBreakOperator; PRS.bForcedBreak = bForcedBreak; if (this.Type == para_Math_Run) { if (true === NewRange) { var WidthLine = X - XRange; if (this.ParaMath.Is_BrkBinBefore() == false) WidthLine += SpaceLen; this.ParaMath.UpdateWidthLine(PRS, WidthLine); } else { // для пустого Run, обновляем LineBreakPos на случай, если пустой Run находится между break_operator (мат. объект) и мат объектом if (this.Content.length == 0) { if (PRS.bForcedBreak == true) { PRS.MoveToLBP = true; PRS.NewRange = true; PRS.Set_LineBreakPos(0, PRS.FirstItemOnLine); } else if (this.ParaMath.Is_BrkBinBefore() == false && Word == false && PRS.bBreakBox == true) { PRS.Set_LineBreakPos(Pos, PRS.FirstItemOnLine); PRS.X += SpaceLen; PRS.SpaceLen = 0; } } // запоминаем конец Run PRS.PosEndRun.Set(PRS.CurPos); PRS.PosEndRun.Update2(this.Content.length, Depth); } } if (!isSkipFillRange) { if (Pos >= ContentLen) RangeEndPos = Pos; this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos); } this.RecalcInfo.Recalc = false; }; ParaRun.prototype.Recalculate_Set_RangeEndPos = function(PRS, PRP, Depth) { var CurLine = PRS.Line - this.StartLine; var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range ); var CurPos = PRP.Get(Depth); this.protected_FillRangeEndPos(CurLine, CurRange, CurPos); }; ParaRun.prototype.Recalculate_SetRangeBounds = function(_CurLine, _CurRange, oStartPos, oEndPos, nDepth) { let isStartPos = oStartPos && nDepth <= oStartPos.GetDepth(); let isEndPos = oEndPos && nDepth <= oEndPos.GetDepth(); let nStartPos = isStartPos ? oStartPos.Get(nDepth) : 0; let nEndPos = isEndPos ? oEndPos.Get(nDepth) : this.Content.length; var CurLine = _CurLine - this.StartLine; var CurRange = 0 === CurLine ? _CurRange - this.StartRange : _CurRange; if (isStartPos) { this.protected_FillRangeEndPos(CurLine, CurRange, nEndPos); } else { this.protected_AddRange(CurLine, CurRange); this.protected_FillRange(CurLine, CurRange, nStartPos, nEndPos); } }; ParaRun.prototype.GetContentWidthInRange = function(oStartPos, oEndPos, nDepth) { let nWidth = 0; let nStartPos = oStartPos && nDepth <= oStartPos.GetDepth() ? oStartPos.Get(nDepth) : 0; let nEndPos = oEndPos && nDepth <= oEndPos.GetDepth() ? oEndPos.Get(nDepth) : this.Content.length; for (let nPos = nStartPos; nPos < nEndPos; ++nPos) { nWidth += this.Content[nPos].GetInlineWidth(); } return nWidth; }; ParaRun.prototype.Recalculate_LineMetrics = function(PRS, ParaPr, _CurLine, _CurRange, ContentMetrics) { var Para = PRS.Paragraph; // Если заданный отрезок пустой, тогда мы не должны учитывать метрики данного рана. var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var UpdateLineMetricsText = false; var LineRule = ParaPr.Spacing.LineRule; let textPr = this.Get_CompiledPr(false); if (this.IsUseAscFont(textPr)) { textPr = textPr.Copy(); textPr.RFonts.SetAll("ASCW3"); } // TODO: Пока для формул сделаем, чтобы работало по-старому, в дальнейшем надо будет переделать на fontslot let fontSlot = this.IsMathRun() ? AscWord.fontslot_ASCII : AscWord.fontslot_None; let fontMap = {}; for (var CurPos = StartPos; CurPos < EndPos; CurPos++) { var Item = this.private_CheckInstrText(this.Content[CurPos]); if (Item === Para.Numbering.Item) { PRS.LineAscent = Para.Numbering.LineAscent; } if (para_Text === Item.Type) { let fontId = AscFonts.GetGraphemeFontId(Item.GetGrapheme()); if (fontId) { let fontSize = Item.GetFontSlot(textPr) === fontslot_CS ? textPr.FontSizeCS : textPr.FontSize; if (undefined === fontMap[fontId]) fontMap[fontId] = fontSize; else fontMap[fontId] = Math.max(fontSize, fontMap[fontId]); } UpdateLineMetricsText = true; continue; } fontSlot |= Item.GetFontSlot(textPr); switch (Item.Type) { case para_Sym: case para_Text: case para_PageNum: case para_PageCount: case para_FootnoteReference: case para_FootnoteRef: case para_EndnoteReference: case para_EndnoteRef: case para_Separator: case para_ContinuationSeparator: { UpdateLineMetricsText = true; break; } case para_Math_Text: case para_Math_Ampersand: case para_Math_Placeholder: case para_Math_BreakOperator: { ContentMetrics.UpdateMetrics(Item.size); break; } case para_Space: { break; } case para_Drawing: { if (true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape()) { // Обновим метрики строки if (Asc.linerule_Exact === LineRule) { if (PRS.LineAscent < Item.getHeight()) PRS.LineAscent = Item.getHeight(); } else { let yOffset = this.getYOffset(); if (PRS.LineAscent < Item.getHeight() + yOffset) PRS.LineAscent = Item.getHeight() + yOffset; if (PRS.LineDescent < -yOffset) PRS.LineDescent = -yOffset; } } break; } case para_End: { break; } case para_FieldChar: { if (Item.IsVisual()) UpdateLineMetricsText = true; break; } } } if (!UpdateLineMetricsText) { var oTextForm = this.GetTextForm(); if (oTextForm && oTextForm.IsComb()) UpdateLineMetricsText = true; } if (UpdateLineMetricsText) { if (AscWord.fontslot_Unknown === fontSlot) fontSlot = textPr.CS || textPr.RTL ? AscWord.fontslot_CS : AscWord.fontslot_ASCII; let metrics = textPr.GetTextMetrics(fontSlot, this.Paragraph.GetTheme()); for (let fontId in fontMap) { let fontName = AscFonts.GetFontNameByFontId(fontId); let fontStyle = AscFonts.GetFontStyleByFontId(fontId); metrics.Update(fontName, fontMap[fontId], fontStyle); } let textDescent = metrics.Descent; let textAscent2 = metrics.Ascent; let textAscent = textAscent2 + metrics.LineGap; if (Asc.linerule_Exact === LineRule) { // Смещение не учитывается в метриках строки, когда расстояние между строк точное if (PRS.LineAscent < textAscent) PRS.LineAscent = textAscent; if (PRS.LineDescent < textDescent) PRS.LineDescent = textDescent; } else { let yOffset = this.getYOffset(); if (yOffset >= 0) { PRS.LineAscent = Math.max(PRS.LineAscent, textAscent + yOffset); textDescent = Math.max(0, textDescent - yOffset); } else { PRS.LineDescent = Math.max(PRS.LineDescent, textDescent - yOffset); textAscent2 = Math.max(0, textAscent2 + yOffset); } textAscent = textAscent2 + metrics.LineGap; } // Пересчитаем метрику строки относительно размера данного текста if (PRS.LineTextAscent < textAscent) PRS.LineTextAscent = textAscent; if (PRS.LineTextAscent2 < textAscent2) PRS.LineTextAscent2 = textAscent2; if (PRS.LineTextDescent < textDescent) PRS.LineTextDescent = textDescent; } }; ParaRun.prototype.Recalculate_Range_Width = function(PRSC, _CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); let textPr = this.Get_CompiledPr(false); // TODO: Сделать возможность показывать инструкцию var isHiddenCFPart = PRSC.ComplexFields.isHiddenComplexFieldPart(); for ( var Pos = StartPos; Pos < EndPos; Pos++ ) { var Item = this.private_CheckInstrText(this.Content[Pos]); var ItemType = Item.Type; if (PRSC.ComplexFields.isHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType) continue; if (isHiddenCFPart && para_End !== ItemType && para_FieldChar !== ItemType && para_InstrText !== ItemType) continue; if (!isHiddenCFPart && para_InstrText === ItemType) ItemType = para_Text; switch( ItemType ) { case para_Sym: case para_Text: case para_FootnoteReference: case para_FootnoteRef: case para_EndnoteReference: case para_EndnoteRef: case para_Separator: case para_ContinuationSeparator: { PRSC.Letters++; if ( true !== PRSC.Word ) { PRSC.Word = true; PRSC.Words++; } PRSC.Range.W += Item.GetWidth(textPr); PRSC.Range.W += PRSC.SpaceLen; PRSC.SpaceLen = 0; // Пробелы перед первым словом в строке не считаем if (PRSC.Words > 1) PRSC.Spaces += PRSC.SpacesCount; else PRSC.SpacesSkip += PRSC.SpacesCount; PRSC.SpacesCount = 0; if (Item.IsSpaceAfter()) PRSC.Word = false; break; } case para_Math_Text: case para_Math_Placeholder: case para_Math_Ampersand: case para_Math_BreakOperator: { PRSC.Letters++; PRSC.Range.W += Item.GetWidth() / AscWord.TEXTWIDTH_DIVIDER; // GetWidth рассчитываем ширину с учетом состояний Gaps break; } case para_Space: { if ( true === PRSC.Word ) { PRSC.Word = false; PRSC.SpacesCount = 1; PRSC.SpaceLen = Item.GetWidth(); } else { PRSC.SpacesCount++; PRSC.SpaceLen += Item.GetWidth(); } break; } case para_Drawing: { if (!Item.IsInline() && !PRSC.Paragraph.Parent.Is_DrawingShape()) break; PRSC.Words++; PRSC.Range.W += PRSC.SpaceLen; if (PRSC.Words > 1) PRSC.Spaces += PRSC.SpacesCount; else PRSC.SpacesSkip += PRSC.SpacesCount; PRSC.Word = false; PRSC.SpacesCount = 0; PRSC.SpaceLen = 0; PRSC.Range.W += Item.GetWidth(); break; } case para_PageNum: case para_PageCount: { PRSC.Words++; PRSC.Range.W += PRSC.SpaceLen; if (PRSC.Words > 1) PRSC.Spaces += PRSC.SpacesCount; else PRSC.SpacesSkip += PRSC.SpacesCount; PRSC.Word = false; PRSC.SpacesCount = 0; PRSC.SpaceLen = 0; PRSC.Range.W += Item.GetWidth(); break; } case para_Tab: { PRSC.Range.W += Item.GetWidth(); PRSC.Range.W += PRSC.SpaceLen; // Учитываем только слова и пробелы, идущие после последнего таба PRSC.LettersSkip += PRSC.Letters; PRSC.SpacesSkip += PRSC.Spaces; PRSC.Words = 0; PRSC.Spaces = 0; PRSC.Letters = 0; PRSC.SpaceLen = 0; PRSC.SpacesCount = 0; PRSC.Word = false; break; } case para_NewLine: { if (true === PRSC.Word && PRSC.Words > 1) PRSC.Spaces += PRSC.SpacesCount; PRSC.SpacesCount = 0; PRSC.Word = false; PRSC.LineBreak = true; break; } case para_End: { if ( true === PRSC.Word ) PRSC.Spaces += PRSC.SpacesCount; PRSC.ParaEnd = true; break; } case para_FieldChar: { if (PRSC.isFastRecalculation()) PRSC.ComplexFields.processFieldChar(Item); else PRSC.ComplexFields.processFieldCharAndCollectComplexField(Item); isHiddenCFPart = PRSC.ComplexFields.isHiddenComplexFieldPart(); if (Item.IsVisual()) { PRSC.Words++; PRSC.Range.W += PRSC.SpaceLen; if (PRSC.Words > 1) PRSC.Spaces += PRSC.SpacesCount; else PRSC.SpacesSkip += PRSC.SpacesCount; PRSC.Word = false; PRSC.SpacesCount = 0; PRSC.SpaceLen = 0; PRSC.Range.W += Item.GetWidth(); } break; } case para_InstrText: { if (PRSC.isFastRecalculation() || reviewtype_Remove === this.GetReviewType()) break; PRSC.ComplexFields.processInstruction(Item); break; } } } }; ParaRun.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, CurPage) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); // TODO: Сделать возможность показывать инструкцию var isHiddenCFPart = PRSA.ComplexFields.isHiddenComplexFieldPart(); for ( var Pos = StartPos; Pos < EndPos; Pos++ ) { var Item = this.private_CheckInstrText(this.Content[Pos]); var ItemType = Item.Type; if (PRSA.ComplexFields.isHiddenFieldContent() && para_End !== ItemType && para_FieldChar !== ItemType) { // Чтобы правильно позиционировался курсор и селект Item.WidthVisible = 0; continue; } if (isHiddenCFPart && para_End !== ItemType && para_FieldChar !== ItemType) { Item.WidthVisible = 0; continue; } switch( ItemType ) { case para_Sym: case para_Text: case para_FootnoteReference: case para_FootnoteRef: case para_EndnoteReference: case para_EndnoteRef: case para_Separator: case para_ContinuationSeparator: { let WidthVisible = 0; if ( 0 !== PRSA.LettersSkip ) { WidthVisible = Item.GetWidth(); PRSA.LettersSkip--; } else WidthVisible = Item.GetWidth() + PRSA.JustifyWord; Item.SetWidthVisible(WidthVisible, this.Get_CompiledPr(false)); if (para_FootnoteReference === ItemType || para_EndnoteReference === ItemType) { var oFootnote = Item.GetFootnote(); oFootnote.UpdatePositionInfo(this.Paragraph, this, _CurLine, _CurRange, PRSA.X, WidthVisible); } PRSA.X += WidthVisible; PRSA.LastW = WidthVisible; break; } case para_Math_Text: case para_Math_Placeholder: case para_Math_BreakOperator: case para_Math_Ampersand: { var WidthVisible = Item.GetWidth() / AscWord.TEXTWIDTH_DIVIDER; // GetWidth рассчитываем ширину с учетом состояний Gaps Item.WidthVisible = (WidthVisible * AscWord.TEXTWIDTH_DIVIDER)| 0;//Item.SetWidthVisible(WidthVisible); PRSA.X += WidthVisible; PRSA.LastW = WidthVisible; break; } case para_Space: { var WidthVisible = Item.GetWidth(); if ( 0 !== PRSA.SpacesSkip ) { PRSA.SpacesSkip--; } else if ( 0 !== PRSA.SpacesCounter ) { WidthVisible += PRSA.JustifySpace; PRSA.SpacesCounter--; } Item.SetWidthVisible(WidthVisible); PRSA.X += WidthVisible; PRSA.LastW = WidthVisible; break; } case para_Drawing: { Item.SetForceNoWrap(false); var Para = PRSA.Paragraph; var isInHdrFtr = Para.Parent.IsHdrFtr(); var PageAbs = Para.GetAbsolutePage(CurPage); var PageRel = Para.GetRelativePage(CurPage); var ColumnAbs = Para.GetAbsoluteColumn(CurPage); var LogicDocument = PRSA.getLogicDocument(); var LD_PageLimits = LogicDocument.Get_PageLimits(PageAbs); var LD_PageFields = LogicDocument.Get_PageFields(PageAbs, isInHdrFtr); var Page_Width = LD_PageLimits.XLimit; var Page_Height = LD_PageLimits.YLimit; var DrawingObjects = Para.Parent.DrawingObjects; var PageLimits = Para.Parent.Get_PageLimits(PageRel); var PageFields = Para.Parent.Get_PageFields(PageRel, isInHdrFtr); var X_Left_Field = PageFields.X; var Y_Top_Field = PageFields.Y; var X_Right_Field = PageFields.XLimit; var Y_Bottom_Field = PageFields.YLimit; var X_Left_Margin = PageFields.X - PageLimits.X; var Y_Top_Margin = PageFields.Y - PageLimits.Y; var X_Right_Margin = PageLimits.XLimit - PageFields.XLimit; var Y_Bottom_Margin = PageLimits.YLimit - PageFields.YLimit; var isTableCellContent = Para.IsTableCellContent(); var isUseWrap = Item.Use_TextWrap(); var isLayoutInCell = Item.IsLayoutInCell(); // TODO: Надо здесь почистить все, а то названия переменных путаются, и некоторые имеют неправильное значение if (isTableCellContent && !isLayoutInCell) { X_Left_Field = LD_PageFields.X; Y_Top_Field = LD_PageFields.Y; X_Right_Field = LD_PageFields.XLimit; Y_Bottom_Field = LD_PageFields.YLimit; X_Left_Margin = X_Left_Field; X_Right_Margin = Page_Width - X_Right_Field; Y_Bottom_Margin = Page_Height - Y_Bottom_Field; Y_Top_Margin = Y_Top_Field; } var _CurPage = 0; if (0 !== PageAbs && CurPage > ColumnAbs) _CurPage = CurPage - ColumnAbs; var ColumnStartX, ColumnEndX; if (0 === CurPage) { // Нужно обновлять, т.к. картинка могла быть внутри данного параграфа и она могла изменить // позицию привязки, а при этом в функцию Para.Reset мы не зашли (баг #44739) if (Para.Parent.RecalcInfo.Can_RecalcObject() && 0 === CurLine) Para.private_RecalculateColumnLimits(); ColumnStartX = Para.X_ColumnStart; ColumnEndX = Para.X_ColumnEnd; } else { ColumnStartX = Para.Pages[_CurPage].X; ColumnEndX = Para.Pages[_CurPage].XLimit; } var Top_Margin = Y_Top_Margin; var Bottom_Margin = Y_Bottom_Margin; var Page_H = Page_Height; if (isTableCellContent && isUseWrap) { Top_Margin = 0; Bottom_Margin = 0; Page_H = 0; } var PageLimitsOrigin = Para.Parent.Get_PageLimits(PageRel); if (isTableCellContent && !isLayoutInCell) { PageLimitsOrigin = LogicDocument.Get_PageLimits(PageAbs); var PageFieldsOrigin = LogicDocument.Get_PageFields(PageAbs, isInHdrFtr); ColumnStartX = PageFieldsOrigin.X; ColumnEndX = PageFieldsOrigin.XLimit; } let isInTable = isTableCellContent && isLayoutInCell; if (!isUseWrap) { PageFields.X = X_Left_Field; PageFields.Y = Y_Top_Field; PageFields.XLimit = X_Right_Field; PageFields.YLimit = Y_Bottom_Field; if (!isTableCellContent || !isLayoutInCell) { PageLimits.X = 0; PageLimits.Y = 0; PageLimits.XLimit = Page_Width; PageLimits.YLimit = Page_Height; } } if ( true === Item.Is_Inline() || true === Para.Parent.Is_DrawingShape() ) { if (linerule_Exact === Para.Get_CompiledPr2(false).ParaPr.Spacing.LineRule) Item.SetVerticalClip(PRSA.getLineTop(), PRSA.getLineBottom()); else Item.SetVerticalClip(null, null); Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine, isInTable); Item.Reset_SavedPosition(); PRSA.X += Item.WidthVisible; PRSA.LastW = Item.WidthVisible; } else if (!Item.IsSkipOnRecalculate()) { Para.Pages[CurPage].Add_Drawing(Item); if ( true === PRSA.RecalcFast ) { // Если у нас быстрый пересчет, тогда мы не трогаем плавающие картинки // TODO: Если здесь привязка к символу, тогда быстрый пересчет надо отменить break; } if (true === PRSA.RecalcFast2) { // Тут мы должны сравнить положение картинок var oRecalcObj = Item.SaveRecalculateObject(); Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine, isInTable); if (Math.abs(Item.X - oRecalcObj.X) > 0.001 || Math.abs(Item.Y - oRecalcObj.Y) > 0.001 || Item.PageNum !== oRecalcObj.PageNum) { // Положение картинок не совпало, отправляем пересчет текущей страницы. PRSA.RecalcResult = recalcresult_CurPage | recalcresultflags_Page; return; } break; } // У нас Flow-объект. Если он с обтеканием, тогда мы останавливаем пересчет и // запоминаем текущий объект. В функции Internal_Recalculate_2 пересчитываем // его позицию и сообщаем ее внешнему классу. // Не учитываем обтекание, если у нас на странице больше 100 объектов с обтеканием (баг 73462) if (isUseWrap && DrawingObjects && DrawingObjects.graphicPages && DrawingObjects.graphicPages[PageAbs] && DrawingObjects.graphicPages[PageAbs].beforeTextObjects.length >= 100) { isUseWrap = false; let LDRecalcInfo = Para.Parent.RecalcInfo; if (LDRecalcInfo.FlowObject) LDRecalcInfo.Reset(); } if (isUseWrap) { var LogicDocument = Para.Parent; var LDRecalcInfo = Para.Parent.RecalcInfo; if ( true === LDRecalcInfo.Can_RecalcObject() ) { // Обновляем позицию объекта Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[_CurLine].Y - Para.Lines[_CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine, isInTable); // For headers we do not check for exceeding lower bound in this case if (!isInHdrFtr && PRSA.getCompatibilityMode() >= AscCommon.document_compatibility_mode_Word15 && 0 === CurPage && !PRSA.isParagraphStartFromNewPage() && Item.Get_Bounds().Bottom >= Y_Bottom_Field && Item.IsMoveWithTextVertically()) { // TODO: По хорошему надо пересчитать заново всю текущую страницу с условием, что заданный параграф начинается с новой страницы Para.StartFromNewPage(); PRSA.RecalcResult = recalcresult_NextPage; } else { LDRecalcInfo.Set_FlowObject(Item, 0, recalcresult_NextElement, -1); // TODO: Добавить проверку на не попадание в предыдущие колонки if (0 === PRSA.CurPage && Item.wrappingPolygon.top > PRSA.PageY + 0.001 && Item.wrappingPolygon.left > PRSA.PageX + 0.001) PRSA.RecalcResult = recalcresult_CurPagePara; else PRSA.RecalcResult = recalcresult_CurPage | recalcresultflags_Page; } return; } else if ( true === LDRecalcInfo.Check_FlowObject(Item) ) { // Если мы находимся с таблице, тогда делаем как Word, не пересчитываем предыдущую страницу, // даже если это необходимо. Такое поведение нужно для точного определения рассчиталась ли // данная страница окончательно или нет. Если у нас будет ветка с переходом на предыдущую страницу, // тогда не рассчитав следующую страницу мы о конечном рассчете текущей страницы не узнаем. // Если данный объект нашли, значит он уже был рассчитан и нам надо проверить номер страницы. // Заметим, что даже если картинка привязана к колонке, и после пересчета место привязки картинки // сдвигается в следующую колонку, мы проверяем все равно только реальную страницу (без // учета колонок, так делает и Word). if ( Item.PageNum === PageAbs ) { if (LDRecalcInfo.IsForceNoWrap()) { Item.SetForceNoWrap(true); Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y , PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[_CurLine].Y - Para.Lines[_CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine, isInTable); } // Все нормально, можно продолжить пересчет LDRecalcInfo.Reset(); Item.Reset_SavedPosition(); } else if (isTableCellContent) { // Картинка не на нужной странице, но так как это таблица // мы пересчитываем заново текущую страницу, а не предыдущую // Обновляем позицию объекта Item.Update_Position(PRSA.Paragraph, new CParagraphLayout( PRSA.X, PRSA.Y, PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent, Para.Pages[_CurPage].Y), PageLimits, PageLimitsOrigin, _CurLine, isInTable); LDRecalcInfo.Set_FlowObject( Item, 0, recalcresult_NextElement, -1 ); LDRecalcInfo.Set_PageBreakBefore( false ); PRSA.RecalcResult = recalcresult_CurPage | recalcresultflags_Page; return; } else { LDRecalcInfo.Set_PageBreakBefore( true ); DrawingObjects.removeById( Item.PageNum, Item.Get_Id() ); PRSA.RecalcResult = recalcresult_PrevPage | recalcresultflags_Page; return; } } else { // Либо данный элемент уже обработан, либо будет обработан в будущем } continue; } else { let nParaTop = Para.Pages[_CurPage].Y; let nLineTop = Para.Pages[CurPage].Y + Para.Lines[CurLine].Y - Para.Lines[CurLine].Metrics.Ascent; // ColumnStartX и ParaTop считаются по тексту, смотри баг #50253 let compatibilityMode = LogicDocument && LogicDocument.IsDocumentEditor() ? LogicDocument.GetCompatibilityMode() : AscCommon.document_compatibility_mode_Current; if (compatibilityMode <= AscCommon.document_compatibility_mode_Word14) { let nPageStartLine = Para.Pages[_CurPage].StartLine; nParaTop = Para.Pages[_CurPage].Y + Para.Lines[nPageStartLine].Top; if (Para.Lines[nPageStartLine].Ranges.length > 1) { var arrTempRanges = Para.Lines[nPageStartLine].Ranges; for (var nTempCurRange = 0, nTempRangesCount = arrTempRanges.length; nTempCurRange < nTempRangesCount; ++nTempCurRange) { if (arrTempRanges[nTempCurRange].W > 0.001 || arrTempRanges[nTempCurRange].WEnd > 0.001) { ColumnStartX = arrTempRanges[nTempCurRange].X; break; } } } } // Картинка ложится на или под текст, в данном случае пересчет можно спокойно продолжать Item.Update_Position(PRSA.Paragraph, new CParagraphLayout(PRSA.X, PRSA.Y, PageAbs, PRSA.LastW, ColumnStartX, ColumnEndX, X_Left_Margin, X_Right_Margin, Page_Width, Top_Margin, Bottom_Margin, Page_H, PageFields.X, PageFields.Y, nLineTop, nParaTop), PageLimits, PageLimitsOrigin, _CurLine, isInTable); Item.Reset_SavedPosition(); } } break; } case para_PageNum: case para_PageCount: { PRSA.X += Item.WidthVisible; PRSA.LastW = Item.WidthVisible; break; } case para_Tab: { PRSA.X += Item.GetWidthVisible(); break; } case para_End: { Item.CheckMark(PRSA.Paragraph, PRSA.RTL ? PRSA.LeftSpace : PRSA.XEnd - PRSA.X); let paraEndW = Item.GetWidthVisible(); PRSA.Range.WEnd = paraEndW; PRSA.X += paraEndW; break; } case para_NewLine: { if (Item.IsPageBreak() || Item.IsColumnBreak()) Item.Update_String(PRSA.RTL ? PRSA.LeftSpace : PRSA.XEnd - PRSA.X); let breakW = Item.GetWidthVisible(); PRSA.Range.WBreak = breakW; PRSA.X += breakW; break; } case para_FieldChar: { PRSA.ComplexFields.processFieldChar(Item); isHiddenCFPart = PRSA.ComplexFields.isHiddenComplexFieldPart(); if (Item.IsVisual()) { PRSA.X += Item.GetWidthVisible(); PRSA.LastW = Item.GetWidthVisible(); } break; } } } }; ParaRun.prototype.Recalculate_PageEndInfo = function(PRSI, _CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); for (var Pos = StartPos; Pos < EndPos; ++Pos) { var Item = this.Content[Pos]; if (para_FieldChar === Item.Type) { PRSI.processFieldChar(Item); } } }; ParaRun.prototype.RecalculateEndInfo = function(PRSI) { var isRemovedInReview = (reviewtype_Remove === this.GetReviewType()); if (PRSI.isFastRecalculation() || (this.Paragraph && this.Paragraph.bFromDocument === false)) return; for (var nCurPos = 0, nCount = this.Content.length; nCurPos < nCount; ++nCurPos) { var oItem = this.Content[nCurPos]; if (para_FieldChar === oItem.Type) { PRSI.processFieldCharAndCollectComplexField(oItem); } else if (para_InstrText === oItem.Type && !isRemovedInReview) { PRSI.processInstruction(oItem); } } }; ParaRun.prototype.private_RecalculateNumbering = function(PRS, Item, ParaPr, _X) { var X = PRS.Recalculate_Numbering(Item, this, ParaPr, _X); // Запоминаем, что на данном элементе была добавлена нумерация this.RecalcInfo.NumberingAdd = false; this.RecalcInfo.NumberingUse = true; this.RecalcInfo.NumberingItem = PRS.Paragraph.Numbering; return X; }; ParaRun.prototype.private_RecalculateLastTab = function(LastTab, X, XEnd, Word, WordLen, SpaceLen) { if (tab_Left === LastTab.Value) { LastTab.Reset(); } else if ( -1 !== LastTab.Value ) { var TempXPos = X; if ( true === Word || WordLen > 0 ) TempXPos += SpaceLen + WordLen; var TabItem = LastTab.Item; var TabStartX = LastTab.X; var TabRangeW = TempXPos - TabStartX; var TabValue = LastTab.Value; var TabPos = LastTab.TabPos; var oLogicDocument = this.Paragraph ? this.Paragraph.LogicDocument : null; var nCompatibilityMode = oLogicDocument && oLogicDocument.GetCompatibilityMode ? oLogicDocument.GetCompatibilityMode() : AscCommon.document_compatibility_mode_Current; if (AscCommon.MMToTwips(TabPos) > AscCommon.MMToTwips(XEnd) && nCompatibilityMode >= AscCommon.document_compatibility_mode_Word15) { TabValue = tab_Right; TabPos = XEnd; } var TabCalcW = 0; if ( tab_Right === TabValue ) TabCalcW = Math.max( TabPos - (TabStartX + TabRangeW), 0 ); else if ( tab_Center === TabValue ) TabCalcW = Math.max( TabPos - (TabStartX + TabRangeW / 2), 0 ); if ( X + TabCalcW > LastTab.PageXLimit ) TabCalcW = LastTab.PageXLimit - X; TabItem.Width = TabCalcW; TabItem.WidthVisible = TabCalcW; LastTab.Reset(); return X + TabCalcW; } return X; }; /** * Специальная функия для проверки InstrText. Если InstrText идет не между Begin и Separate сложного поля, тогда * мы заменяем его обычным текстовым элементом. * @param oItem */ ParaRun.prototype.private_CheckInstrText = function(oItem) { if (!oItem) return oItem; if (para_InstrText !== oItem.Type) return oItem; var oReplacement = oItem.GetReplacementItem(); return (oReplacement ? oReplacement : oItem); }; ParaRun.prototype.Refresh_RecalcData = function(oData) { let oPara = this.GetParagraph(); if (this.IsMathRun()) { if (this.Parent !== null && this.Parent !== undefined) { this.Parent.Refresh_RecalcData(); } } else if (-1 !== this.StartLine && oPara) { var nCurLine = this.StartLine; if (oData instanceof CChangesRunAddItem || oData instanceof CChangesRunRemoveItem) { nCurLine = -1; var nChangePos = oData.GetMinPos(); for (var nLine = 0, nLinesCount = this.protected_GetLinesCount(); nLine < nLinesCount; ++nLine) { for (var nRange = 0, nRangesCount = this.protected_GetRangesCount(nLine); nRange < nRangesCount; ++nRange) { var nStartPos = this.protected_GetRangeStartPos(nLine, nRange); var nEndPos = this.protected_GetRangeEndPos(nLine, nRange); if (nStartPos <= nChangePos && nChangePos < nEndPos) { nCurLine = nLine + this.StartLine; break; } } if (-1 !== nCurLine) break; } if (-1 === nCurLine) nCurLine = this.StartLine + this.protected_GetLinesCount() - 1; } for (var nCurPage = 0, nPagesCount = oPara.GetPagesCount(); nCurPage < nPagesCount; ++nCurPage) { var oPage = oPara.Pages[nCurPage]; if (oPage.StartLine <= nCurLine && nCurLine <= oPage.EndLine) { oPara.Refresh_RecalcData2(nCurPage); return; } } oPara.Refresh_RecalcData2(0); } else if (oPara) { oPara.Refresh_RecalcData2(); } }; ParaRun.prototype.Refresh_RecalcData2 = function() { this.Refresh_RecalcData(); }; ParaRun.prototype.SaveRecalculateObject = function(Copy) { var RecalcObj = new CRunRecalculateObject(this.StartLine, this.StartRange); RecalcObj.Save_Lines( this, Copy ); RecalcObj.SaveRunContent(this, Copy); return RecalcObj; }; ParaRun.prototype.LoadRecalculateObject = function(RecalcObj) { RecalcObj.Load_Lines(this); RecalcObj.LoadRunContent(this); }; ParaRun.prototype.PrepareRecalculateObject = function() { this.protected_ClearLines(); var Count = this.Content.length; for (var Index = 0; Index < Count; Index++) { var Item = this.Content[Index]; var ItemType = Item.Type; if (para_PageNum === ItemType || para_Drawing === ItemType) Item.PrepareRecalculateObject(); } }; ParaRun.prototype.IsEmptyRange = function(_CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); if (EndPos <= StartPos) return true; return false; }; ParaRun.prototype.Check_Range_OnlyMath = function(Checker, _CurRange, _CurLine) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); for (var Pos = StartPos; Pos < EndPos; Pos++) { var Item = this.Content[Pos]; var ItemType = Item.Type; if (para_End === ItemType || para_NewLine === ItemType || (para_Drawing === ItemType && true !== Item.Is_Inline())) continue; else { Checker.Result = false; Checker.Math = null; break; } } }; ParaRun.prototype.ProcessNotInlineObjectCheck = function(oChecker) { var Count = this.Content.length; if (Count <= 0) return; var Item = oChecker.Direction > 0 ? this.Content[0] : this.Content[Count - 1]; var ItemType = Item.Type; if (para_End === ItemType || para_NewLine === ItemType) { oChecker.Result = true; oChecker.Found = true; } else { oChecker.Result = false; oChecker.Found = true; } }; ParaRun.prototype.Check_PageBreak = function() { var Count = this.Content.length; for (var Pos = 0; Pos < Count; Pos++) { var Item = this.Content[Pos]; if (Item.IsBreak() && (Item.IsPageBreak() || Item.IsColumnBreak())) return true; } return false; }; ParaRun.prototype.CheckSplitPageOnPageBreak = function(oChecker) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var oItem = this.Content[nPos]; if (oChecker.IsFindPageBreak()) { oChecker.CheckPageBreakItem(oItem); } else { var nItemType = oItem.Type; if (para_End === nItemType && !oChecker.IsSplitPageBreakAndParaMark()) return false; else if (para_Drawing !== nItemType || drawing_Anchor !== oItem.Get_DrawingType()) return true; } } return false; }; ParaRun.prototype.RecalculateMinMaxContentWidth = function(MinMax) { this.Recalculate_MeasureContent(); var bWord = MinMax.bWord; var nWordLen = MinMax.nWordLen; var nSpaceLen = MinMax.nSpaceLen; var nMinWidth = MinMax.nMinWidth; var nMaxWidth = MinMax.nMaxWidth; var nCurMaxWidth = MinMax.nCurMaxWidth; var nMaxHeight = MinMax.nMaxHeight; var bCheckTextHeight = false; var Count = this.Content.length; for ( var Pos = 0; Pos < Count; Pos++ ) { var Item = this.private_CheckInstrText(this.Content[Pos]); var ItemType = Item.Type; switch( ItemType ) { case para_Text: { var ItemWidth = Item.GetWidth(); if ( false === bWord ) { bWord = true; nWordLen = ItemWidth; } else { nWordLen += ItemWidth; if (Item.IsSpaceAfter()) { if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; bWord = false; nWordLen = 0; } } if ( nSpaceLen > 0 ) { nCurMaxWidth += nSpaceLen; nSpaceLen = 0; } nCurMaxWidth += ItemWidth; bCheckTextHeight = true; // Если текущий символ с переносом, например, дефис, тогда на нем заканчивается слово if (Item.IsSpaceAfter()) { if (nMinWidth < nWordLen) nMinWidth = nWordLen; bWord = false; nWordLen = 0; nSpaceLen = 0; } break; } case para_Math_Text: case para_Math_Ampersand: case para_Math_Placeholder: { var ItemWidth = Item.GetWidth() / AscWord.TEXTWIDTH_DIVIDER; if ( false === bWord ) { bWord = true; nWordLen = ItemWidth; } else { nWordLen += ItemWidth; } nCurMaxWidth += ItemWidth; bCheckTextHeight = true; break; } case para_Space: { if ( true === bWord ) { if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; bWord = false; nWordLen = 0; } // Мы сразу не добавляем ширину пробелов к максимальной ширине, потому что // пробелы, идущие в конце параграфа или перед переносом строки(явным), не // должны учитываться. nSpaceLen += Item.GetWidth(); bCheckTextHeight = true; break; } case para_Math_BreakOperator: { let itemWidth = Item.GetWidth() / AscWord.TEXTWIDTH_DIVIDER; if (!bWord) nWordLen = itemWidth; else nWordLen += itemWidth; if (nMinWidth < nWordLen) nMinWidth = nWordLen; bWord = false; nWordLen = 0; nCurMaxWidth += itemWidth; bCheckTextHeight = true; break; } case para_Drawing: { if ( true === bWord ) { if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; bWord = false; nWordLen = 0; } if ((true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape()) && Item.Width > nMinWidth) { nMinWidth = Item.Width; } else if (true === Item.Use_TextWrap()) { nMinWidth = Math.max(nMinWidth, Item.getExtX()); } if ((true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape()) && Item.getHeight() > nMaxHeight) { nMaxHeight = Item.getHeight(); } else if (true === Item.Use_TextWrap()) { nMaxHeight = Math.max(nMaxHeight, Item.getExtY()); } if ( nSpaceLen > 0 ) { nCurMaxWidth += nSpaceLen; nSpaceLen = 0; } if ( true === Item.Is_Inline() || true === this.Paragraph.Parent.Is_DrawingShape() ) nCurMaxWidth += Item.Width; break; } case para_PageNum: case para_PageCount: { if ( true === bWord ) { if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; bWord = false; nWordLen = 0; } if ( Item.Width > nMinWidth ) nMinWidth = Item.GetWidth(); if ( nSpaceLen > 0 ) { nCurMaxWidth += nSpaceLen; nSpaceLen = 0; } nCurMaxWidth += Item.GetWidth(); bCheckTextHeight = true; break; } case para_Tab: { nWordLen += Item.Width; if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; bWord = false; nWordLen = 0; if ( nSpaceLen > 0 ) { nCurMaxWidth += nSpaceLen; nSpaceLen = 0; } nCurMaxWidth += Item.Width; bCheckTextHeight = true; break; } case para_NewLine: { if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; bWord = false; nWordLen = 0; nSpaceLen = 0; if ( nCurMaxWidth > nMaxWidth ) nMaxWidth = nCurMaxWidth; nCurMaxWidth = 0; bCheckTextHeight = true; break; } case para_End: { if ( nMinWidth < nWordLen ) nMinWidth = nWordLen; if ( nCurMaxWidth > nMaxWidth ) nMaxWidth = nCurMaxWidth; if (nMaxHeight < 0.001) bCheckTextHeight = true; break; } } } let textMetrics = this.getTextMetrics(); let textHeight = textMetrics.Ascent + textMetrics.LineGap + textMetrics.Descent; if (true === bCheckTextHeight && nMaxHeight < textHeight) nMaxHeight = textHeight; MinMax.bWord = bWord; MinMax.nWordLen = nWordLen; MinMax.nSpaceLen = nSpaceLen; MinMax.nMinWidth = nMinWidth; MinMax.nMaxWidth = nMaxWidth; MinMax.nCurMaxWidth = nCurMaxWidth; MinMax.nMaxHeight = nMaxHeight; }; ParaRun.prototype.Get_Range_VisibleWidth = function(RangeW, _CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); for ( var Pos = StartPos; Pos < EndPos; Pos++ ) { var Item = this.private_CheckInstrText(this.Content[Pos]); var ItemType = Item.Type; switch( ItemType ) { case para_Sym: case para_Text: case para_Space: case para_Math_Text: case para_Math_Ampersand: case para_Math_Placeholder: case para_Math_BreakOperator: { RangeW.W += Item.GetWidthVisible(); break; } case para_Drawing: { if ( true === Item.Is_Inline() ) RangeW.W += Item.Width; break; } case para_PageNum: case para_PageCount: case para_Tab: { RangeW.W += Item.Width; break; } case para_NewLine: { RangeW.W += Item.WidthVisible; break; } case para_End: { RangeW.W += Item.GetWidthVisible(); RangeW.End = true; break; } default: { RangeW.W += Item.GetWidthVisible(); break; } } } }; ParaRun.prototype.Shift_Range = function(Dx, Dy, _CurLine, _CurRange, _CurPage) { var CurLine = _CurLine - this.StartLine; var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var nPageAbs = undefined; var oParagraph = this.GetParagraph(); if (oParagraph) nPageAbs = oParagraph.GetAbsolutePage(_CurPage); for (var CurPos = StartPos; CurPos < EndPos; CurPos++) { var Item = this.Content[CurPos]; if (para_Drawing === Item.Type) { if (!Item.IsInline()) { if (!Item.IsMoveWithTextVertically()) Dy = 0; if (!Item.IsMoveWithTextHorizontally()) Dx = 0; } Item.Shift(Dx, Dy, nPageAbs); } } }; //----------------------------------------------------------------------------------- // Функции отрисовки //----------------------------------------------------------------------------------- ParaRun.prototype.Draw_HighLights = function(drawState) { let rangePos = this.getRangePos(drawState.Line, drawState.Range); let startPos = rangePos[0]; let endPos = rangePos[1]; if (startPos >= endPos) return; this.CollaborativeMarks.Init_Drawing(); for (let pos = startPos; pos < endPos; ++pos) { let item = this.private_CheckInstrText(this.Content[pos]); for (let iMark = 0, nMarks = this.SearchMarks.length; iMark < nMarks; ++iMark) { let mark = this.SearchMarks[iMark]; let markPos = mark.SearchResult.StartPos.Get(mark.Depth); if (pos === markPos && mark.Start) drawState.increaseSearchCounter(); } let collaborationColor = this.CollaborativeMarks.Check(pos); drawState.handleRunElement(item, this, collaborationColor); for (let iMark = 0, nMarks = this.SearchMarks.length; iMark < nMarks; ++iMark) { let mark = this.SearchMarks[iMark]; let markPos = mark.SearchResult.EndPos.Get(mark.Depth); if (pos + 1 === markPos && !mark.Start) drawState.decreaseSearchCounter(); } } }; ParaRun.prototype.Draw_Elements = function(drawState) { let rangePos = this.getRangePos(drawState.Line, drawState.Range); let startPos = rangePos[0]; let endPos = rangePos[1]; if (startPos >= endPos) return; for (let pos = startPos; pos < endPos; ++pos) { let item = this.private_CheckInstrText(this.Content[pos]); drawState.handleRunElement(item, this); } }; ParaRun.prototype.Draw_Lines = function(lineDrawState) { let rangePos = this.getRangePos(lineDrawState.Line, lineDrawState.Range); let startPos = rangePos[0]; let endPos = rangePos[1]; if (startPos >= endPos) return; lineDrawState.CurPos.Update(startPos, lineDrawState.CurDepth); var nSpellingErrorsCounter = lineDrawState.GetSpellingErrorsCounter(); var SpellDataLen = endPos + 1; var SpellData = g_oSpellCheckerMarks.Check(SpellDataLen); for (var iMark = 0, nMarks = this.SpellingMarks.length; iMark < nMarks; ++iMark) { let mark = this.SpellingMarks[iMark]; if (!mark.isMisspelled()) continue; let markPos = mark.getPos(); if (markPos >= SpellDataLen) continue; if (mark.isStart()) SpellData[markPos] += 1; else SpellData[markPos] -= 1; } lineDrawState.initCustomMarks(this, startPos); for (let pos = startPos; pos < endPos; ++pos) { if (SpellData[pos]) nSpellingErrorsCounter += SpellData[pos]; let item = this.private_CheckInstrText(this.Content[pos]); lineDrawState.handleRunElement(item, this, pos, nSpellingErrorsCounter > 0); } }; ParaRun.prototype.SkipDraw = function(PDS) { var CurLine = PDS.Line - this.StartLine; var CurRange = (0 === CurLine ? PDS.Range - this.StartRange : PDS.Range); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var X = PDS.X; for (var Pos = StartPos; Pos < EndPos; Pos++) { var oItem = this.private_CheckInstrText(this.Content[Pos]); var nItemType = oItem.Type; if (para_End === nItemType) X += oItem.GetWidth(); else if (para_Drawing !== nItemType || oItem.Is_Inline()) X += oItem.GetWidthVisible(); } // Обновим позицию X PDS.X = X; }; //----------------------------------------------------------------------------------- // Функции для работы с курсором //----------------------------------------------------------------------------------- // Находится ли курсор в начале рана ParaRun.prototype.IsCursorPlaceable = function() { return true; }; ParaRun.prototype.Cursor_Is_Start = function() { if ( this.State.ContentPos <= 0 ) return true; return false; }; // Проверяем нужно ли поправить позицию курсора ParaRun.prototype.Cursor_Is_NeededCorrectPos = function() { if ( true === this.Is_Empty(false) ) return true; var NewRangeStart = false; var RangeEnd = false; var Pos = this.State.ContentPos; var LinesLen = this.protected_GetLinesCount(); for ( var CurLine = 0; CurLine < LinesLen; CurLine++ ) { var RangesLen = this.protected_GetRangesCount(CurLine); for ( var CurRange = 0; CurRange < RangesLen; CurRange++ ) { var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); if (0 !== CurLine || 0 !== CurRange) { if (Pos === StartPos) { NewRangeStart = true; } } if (Pos === EndPos) { RangeEnd = true; } } if ( true === NewRangeStart ) break; } if ( true !== NewRangeStart && true !== RangeEnd && true === this.Cursor_Is_Start() ) return true; return false; }; ParaRun.prototype.Cursor_Is_End = function() { if ( this.State.ContentPos >= this.Content.length ) return true; return false; }; ParaRun.prototype.IsStartPos = function(contentPos, depth) { if (depth >= contentPos.Depth) return true; return 0 === contentPos.Get(depth); }; ParaRun.prototype.IsEndPos = function(contentPos, depth) { if (depth >= contentPos.Depth) return true; return contentPos.Get(depth) >= this.Content.length; }; /** * Проверяем находится ли курсор в начале рана * @returns {boolean} */ ParaRun.prototype.IsCursorAtBegin = function() { return this.Cursor_Is_Start(); }; /** * Проверяем находится ли курсор в конце рана * @returns {boolean} */ ParaRun.prototype.IsCursorAtEnd = function() { return this.Cursor_Is_End(); }; ParaRun.prototype.MoveCursorToStartPos = function() { this.State.ContentPos = 0; }; ParaRun.prototype.MoveCursorToEndPos = function(SelectFromEnd) { if ( true === SelectFromEnd ) { var Selection = this.State.Selection; Selection.Use = true; Selection.StartPos = this.Content.length; Selection.EndPos = this.Content.length; } else { var CurPos = this.Content.length; while ( CurPos > 0 ) { if ( para_End === this.Content[CurPos - 1].Type ) CurPos--; else break; } this.State.ContentPos = CurPos; } }; ParaRun.prototype.getParagraphContentPosByXY = function(searchState) { let rangePos = this.getRangePos(searchState.line, searchState.range); let startPos = rangePos[0]; let endPos = rangePos[1]; if (startPos > endPos) return; for (let pos = startPos; pos < endPos; ++pos) { let item = this.private_CheckInstrText(this.Content[pos]); searchState.handleRunElement(item, this, pos); } searchState.handleRun(this); }; ParaRun.prototype.Get_ParaContentPos = function(bSelection, bStart, ContentPos, bUseCorrection) { var Pos = ( true !== bSelection ? this.State.ContentPos : ( false !== bStart ? this.State.Selection.StartPos : this.State.Selection.EndPos ) ); if (Pos < 0) Pos = 0; if (Pos > this.Content.length) Pos = this.Content.length; ContentPos.Add(Pos); }; ParaRun.prototype.Set_ParaContentPos = function(ContentPos, Depth) { var Pos = ContentPos.Get(Depth); var Count = this.Content.length; if ( Pos > Count ) Pos = Count; // TODO: Как только переделаем работу c Para_End переделать здесь for ( var TempPos = 0; TempPos < Pos; TempPos++ ) { if ( para_End === this.Content[TempPos].Type ) { Pos = TempPos; break; } } if ( Pos < 0 ) Pos = 0; this.State.ContentPos = Pos; }; /** * Функция для перевода позиции внутри параграфа в специальную позицию используемую в ApiRange * @param {AscWord.CParagraphContentPos} oContentPos - если null -> возвращает количество символов в элементе. * @param {number} nDepth * @return {number} */ ParaRun.prototype.ConvertParaContentPosToRangePos = function(oContentPos, nDepth) { var nRangePos = 0; var nCurPos = oContentPos ? Math.max(0, Math.min(this.Content.length, oContentPos.Get(nDepth))) : this.Content.length; for (var nPos = 0; nPos < nCurPos; ++nPos) { nRangePos++; } return nRangePos; }; ParaRun.prototype.Get_PosByElement = function(Class, ContentPos, Depth, UseRange, Range, Line) { if ( this === Class ) return true; return false; }; ParaRun.prototype.Get_ElementByPos = function(ContentPos, Depth) { return this; }; ParaRun.prototype.GetPosByDrawing = function(Id, ContentPos, Depth) { var Count = this.Content.length; for ( var CurPos = 0; CurPos < Count; CurPos++ ) { var Item = this.Content[CurPos]; if ( para_Drawing === Item.Type && Id === Item.Get_Id() ) { ContentPos.Update( CurPos, Depth ); return true; } } return false; }; ParaRun.prototype.Get_RunElementByPos = function(ContentPos, Depth) { if ( undefined !== ContentPos ) { var CurPos = ContentPos.Get(Depth); var ContentLen = this.Content.length; if ( CurPos >= this.Content.length || CurPos < 0 ) return null; return this.Content[CurPos]; } else { if ( this.Content.length > 0 ) return this.Content[0]; else return null; } }; ParaRun.prototype.Get_LastRunInRange = function(_CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); return this; }; ParaRun.prototype.Get_LeftPos = function(SearchPos, ContentPos, Depth, UseContentPos) { var CurPos = true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length; var isHiddenPart = SearchPos.isHiddenComplexFieldPart(); var isFieldValue = SearchPos.isComplexFieldValue(); var isHiddenCF = SearchPos.isHiddenComplexField(); while (true) { CurPos--; var Item = this.private_CheckInstrText(this.Content[CurPos]); if (CurPos >= 0 && para_FieldChar === Item.Type) { SearchPos.ProcessComplexFieldChar(-1, Item); isHiddenPart = SearchPos.isComplexFieldCode(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if (CurPos >= 0 && (isHiddenPart || isHiddenCF)) continue; if (CurPos < 0 || (!(para_Drawing === Item.Type && false === Item.Is_Inline() && false === SearchPos.IsCheckAnchors()) && !((para_FootnoteReference === Item.Type || para_EndnoteReference === Item.Type) && true === Item.IsCustomMarkFollows()))) break; } if (CurPos >= 0) { SearchPos.Found = true; SearchPos.Pos.Update(CurPos, Depth); } }; ParaRun.prototype.Get_RightPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd) { var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 ); var isHiddenPart = SearchPos.isHiddenComplexFieldPart(); var isFieldValue = SearchPos.isComplexFieldValue(); var isHiddenCF = SearchPos.isHiddenComplexField(); var Count = this.Content.length; while (true) { CurPos++; // Мы встали в конец рана: // Если мы перешагнули para_End или para_Drawing Anchor, тогда возвращаем false // В противном случае true if (Count === CurPos) { if (CurPos === 0) return; var PrevItem = this.private_CheckInstrText(this.Content[CurPos - 1]); var PrevItemType = PrevItem.Type; if (para_FieldChar === PrevItem.Type) { SearchPos.ProcessComplexFieldChar(1, PrevItem); isHiddenPart = SearchPos.isHiddenComplexFieldPart(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if (isHiddenPart || isHiddenCF) return; if ((true !== StepEnd && para_End === PrevItemType) || (para_Drawing === PrevItemType && false === PrevItem.Is_Inline() && false === SearchPos.IsCheckAnchors()) || ((para_FootnoteReference === PrevItemType || para_EndnoteReference === PrevItemType) && true === PrevItem.IsCustomMarkFollows())) return; break; } if (CurPos > Count) break; // Минимальное значение CurPos = 1, т.к. мы начинаем со значния >= 0 и добавляем 1 var Item = this.private_CheckInstrText(this.Content[CurPos - 1]); var ItemType = Item.Type; if (para_FieldChar === Item.Type) { SearchPos.ProcessComplexFieldChar(1, Item); isHiddenPart = SearchPos.isHiddenComplexFieldPart(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if (isHiddenPart || isHiddenCF) continue; if (!(true !== StepEnd && para_End === ItemType) && !(para_Drawing === Item.Type && false === Item.Is_Inline()) && !((para_FootnoteReference === Item.Type || para_EndnoteReference === Item.Type) && true === Item.IsCustomMarkFollows())) break; } if (CurPos <= Count) { SearchPos.Found = true; SearchPos.Pos.Update(CurPos, Depth); } }; ParaRun.prototype.Get_WordStartPos = function(SearchPos, ContentPos, Depth, UseContentPos) { var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) - 1 : this.Content.length - 1 ); SearchPos.UpdatePos = false; if (CurPos < 0 || this.Content.length <= 0) return; SearchPos.Shift = true; var isHiddenPart = SearchPos.isHiddenComplexFieldPart(); var isFieldValue = SearchPos.isComplexFieldValue(); var isHiddenCF = SearchPos.isHiddenComplexField(); // На первом этапе ищем позицию первого непробельного элемента if ( 0 === SearchPos.Stage ) { while ( true ) { var Item = this.private_CheckInstrText(this.Content[CurPos]); var Type = Item.Type; var bSpace = false; if (para_FieldChar === Type) { SearchPos.ProcessComplexFieldChar(-1, Item); isHiddenPart = SearchPos.isHiddenComplexFieldPart(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if ( para_Space === Type || para_Tab === Type || ( para_Text === Type && true === Item.IsNBSP() ) || ( para_Drawing === Type && true !== Item.Is_Inline() ) ) bSpace = true; if (true === bSpace || isHiddenPart || isHiddenCF) { CurPos--; if (CurPos < 0) { SearchPos.Pos.Update(0, Depth); SearchPos.UpdatePos = true; return; } } else { // Если мы остановились на нетекстовом элементе, тогда его и возвращаем if ( para_Text !== this.Content[CurPos].Type && para_Math_Text !== this.Content[CurPos].Type) { SearchPos.Pos.Update( CurPos, Depth ); SearchPos.Found = true; SearchPos.UpdatePos = true; return; } SearchPos.Pos.Update( CurPos, Depth ); SearchPos.Stage = 1; SearchPos.Punctuation = this.Content[CurPos].IsPunctuation(); SearchPos.UpdatePos = true; break; } } } else { CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : this.Content.length ); } // На втором этапе мы смотрим на каком элементе мы встали: если текст - пунктуация, тогда сдвигаемся // до конца всех знаков пунктуации while ( CurPos > 0 ) { CurPos--; var Item = this.private_CheckInstrText(this.Content[CurPos]); var TempType = Item.Type; if (para_FieldChar === Item.Type) { SearchPos.ProcessComplexFieldChar(-1, Item); isHiddenPart = SearchPos.isHiddenComplexFieldPart(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if (isHiddenPart || isHiddenCF) continue; if ( (para_Text !== TempType && para_Math_Text !== TempType) || true === Item.IsNBSP() || ( true === SearchPos.Punctuation && true !== Item.IsPunctuation() ) || ( false === SearchPos.Punctuation && false !== Item.IsPunctuation() ) ) { SearchPos.Found = true; break; } else { SearchPos.Pos.Update(CurPos, Depth); SearchPos.UpdatePos = true; } } }; ParaRun.prototype.Get_WordEndPos = function(SearchPos, ContentPos, Depth, UseContentPos, StepEnd) { var CurPos = ( true === UseContentPos ? ContentPos.Get(Depth) : 0 ); SearchPos.UpdatePos = false; var ContentLen = this.Content.length; if (CurPos >= ContentLen || ContentLen <= 0) return; var isHiddenPart = SearchPos.isHiddenComplexFieldPart(); var isFieldValue = SearchPos.isComplexFieldValue(); var isHiddenCF = SearchPos.isHiddenComplexField(); if ( 0 === SearchPos.Stage ) { // На первом этапе ищем первый нетекстовый ( и не таб ) элемент while ( true ) { var Item = this.private_CheckInstrText(this.Content[CurPos]); var Type = Item.Type; var bText = false; if (para_FieldChar === Type) { SearchPos.ProcessComplexFieldChar(1, Item); isHiddenPart = SearchPos.isHiddenComplexFieldPart(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if ( (para_Text === Type || para_Math_Text === Type) && true != Item.IsNBSP() && ( true === SearchPos.First || ( SearchPos.Punctuation === Item.IsPunctuation() ) ) ) bText = true; if (true === bText || isHiddenPart || isHiddenCF) { if (!isHiddenPart && !isHiddenCF) { if (true === SearchPos.First) { SearchPos.First = false; SearchPos.Punctuation = Item.IsPunctuation(); } // Отмечаем, что сдвиг уже произошел SearchPos.Shift = true; } CurPos++; if (CurPos >= ContentLen) { SearchPos.Pos.Update(CurPos, Depth); SearchPos.UpdatePos = true; return; } } else { SearchPos.Stage = 1; // Первый найденный элемент не текстовый, смещаемся вперед if ( true === SearchPos.First ) { // Если первый найденный элемент - конец параграфа, тогда выходим из поиска if ( para_End === Type ) { if ( true === StepEnd ) { SearchPos.Pos.Update( CurPos + 1, Depth ); SearchPos.Found = true; SearchPos.UpdatePos = true; } return; } CurPos++; // Отмечаем, что сдвиг уже произошел SearchPos.Shift = true; } if (SearchPos.IsTrimSpaces()) { SearchPos.Pos.Update(CurPos, Depth); SearchPos.Found = true; SearchPos.UpdatePos = true; return; } break; } } } if (CurPos >= ContentLen) { SearchPos.Pos.Update(CurPos, Depth); SearchPos.UpdatePos = true; return; } // На втором этапе мы смотрим на каком элементе мы встали: если это не пробел, тогда // останавливаемся здесь. В противном случае сдвигаемся вперед, пока не попали на первый // не пробельный элемент. if ( !(para_Space === this.Content[CurPos].Type || ( para_Text === this.Content[CurPos].Type && true === this.Content[CurPos].IsNBSP() ) ) ) { SearchPos.Pos.Update( CurPos, Depth ); SearchPos.Found = true; SearchPos.UpdatePos = true; } else { while ( CurPos < ContentLen - 1 ) { CurPos++; var Item = this.private_CheckInstrText(this.Content[CurPos]); var TempType = Item.Type; if (para_FieldChar === Item.Type) { SearchPos.ProcessComplexFieldChar(1, Item); isHiddenPart = SearchPos.isHiddenComplexFieldPart(); isFieldValue = SearchPos.isComplexFieldValue(); isHiddenCF = SearchPos.isHiddenComplexField(); } if (isHiddenPart || isHiddenCF) continue; if ( (true !== StepEnd && para_End === TempType) || !( para_Space === TempType || ( para_Text === TempType && true === Item.IsNBSP() ) ) ) { SearchPos.Found = true; break; } } // Обновляем позицию в конце каждого рана (хуже от этого не будет) SearchPos.Pos.Update(CurPos, Depth); SearchPos.UpdatePos = true; } }; ParaRun.prototype.Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var LastPos = -1; for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ ) { var Item = this.Content[CurPos]; var ItemType = Item.Type; if ( !((para_Drawing === ItemType && true !== Item.Is_Inline()) || para_End === ItemType || (Item.IsBreak() && Item.IsLineBreak()))) LastPos = CurPos + 1; } // Проверяем, попал ли хоть один элемент в данный отрезок, если нет, тогда не регистрируем такой ран if ( -1 !== LastPos ) { SearchPos.Pos.Update( LastPos, Depth ); return true; } else return false; }; ParaRun.prototype.Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var FirstPos = -1; for ( var CurPos = EndPos - 1; CurPos >= StartPos; CurPos-- ) { var Item = this.Content[CurPos]; if ( !(para_Drawing === Item.Type && true !== Item.Is_Inline()) ) FirstPos = CurPos; } // Проверяем, попал ли хоть один элемент в данный отрезок, если нет, тогда не регистрируем такой ран if ( -1 !== FirstPos ) { SearchPos.Pos.Update( FirstPos, Depth ); return true; } else return false; }; ParaRun.prototype.Get_StartRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var Pos = this.protected_GetRangeStartPos(CurLine, CurRange); ContentPos.Update( Pos, Depth ); }; ParaRun.prototype.Get_EndRangePos2 = function(_CurLine, _CurRange, ContentPos, Depth) { var CurLine = _CurLine - this.StartLine; var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange); var Pos = this.protected_GetRangeEndPos(CurLine, CurRange); ContentPos.Update(Pos, Depth); }; ParaRun.prototype.Get_StartPos = function(ContentPos, Depth) { ContentPos.Update( 0, Depth ); }; ParaRun.prototype.Get_EndPos = function(BehindEnd, ContentPos, Depth) { var ContentLen = this.Content.length; if ( true === BehindEnd ) ContentPos.Update( ContentLen, Depth ); else { for ( var CurPos = 0; CurPos < ContentLen; CurPos++ ) { if ( para_End === this.Content[CurPos].Type ) { ContentPos.Update( CurPos, Depth ); return; } } // Не нашли para_End ContentPos.Update( ContentLen, Depth ); } }; //----------------------------------------------------------------------------------- // Функции для работы с селектом //----------------------------------------------------------------------------------- ParaRun.prototype.Set_SelectionContentPos = function(StartContentPos, EndContentPos, Depth, StartFlag, EndFlag) { var StartPos = 0; switch (StartFlag) { case 1: StartPos = 0; break; case -1: StartPos = this.Content.length; break; case 0: StartPos = StartContentPos.Get(Depth); break; } var EndPos = 0; switch (EndFlag) { case 1: EndPos = 0; break; case -1: EndPos = this.Content.length; break; case 0: EndPos = EndContentPos.Get(Depth); break; } var Selection = this.State.Selection; Selection.StartPos = StartPos; Selection.EndPos = EndPos; Selection.Use = true; }; ParaRun.prototype.SetContentSelection = function(StartDocPos, EndDocPos, Depth, StartFlag, EndFlag) { var StartPos = 0; switch (StartFlag) { case 1: StartPos = 0; break; case -1: StartPos = this.Content.length; break; case 0: StartPos = StartDocPos[Depth].Position; break; } var EndPos = 0; switch (EndFlag) { case 1: EndPos = 0; break; case -1: EndPos = this.Content.length; break; case 0: EndPos = EndDocPos[Depth].Position; break; } var Selection = this.State.Selection; Selection.StartPos = StartPos; Selection.EndPos = EndPos; Selection.Use = true; }; ParaRun.prototype.SetContentPosition = function(DocPos, Depth, Flag) { var Pos = 0; switch (Flag) { case 1: Pos = 0; break; case -1: Pos = this.Content.length; break; case 0: Pos = DocPos[Depth].Position; break; } var nLen = this.Content.length; if (nLen > 0 && Pos >= nLen && para_End === this.Content[nLen - 1].Type) Pos = nLen - 1; this.State.ContentPos = Pos; }; ParaRun.prototype.Set_SelectionAtEndPos = function() { this.Set_SelectionContentPos(null, null, 0, -1, -1); }; ParaRun.prototype.Set_SelectionAtStartPos = function() { this.Set_SelectionContentPos(null, null, 0, 1, 1); }; ParaRun.prototype.IsSelectionUse = function() { return this.State.Selection.Use; }; ParaRun.prototype.IsSelectedAll = function(Props) { var Selection = this.State.Selection; if ( false === Selection.Use && true !== this.Is_Empty( Props ) ) return false; var SkipAnchor = Props ? Props.SkipAnchor : false; var SkipEnd = Props ? Props.SkipEnd : false; var StartPos = Selection.StartPos; var EndPos = Selection.EndPos; if ( EndPos < StartPos ) { StartPos = Selection.EndPos; EndPos = Selection.StartPos; } for ( var Pos = 0; Pos < StartPos; Pos++ ) { var Item = this.Content[Pos]; var ItemType = Item.Type; if ( !( ( true === SkipAnchor && ( para_Drawing === ItemType && true !== Item.Is_Inline() ) ) || ( true === SkipEnd && para_End === ItemType ) ) ) return false; } var Count = this.Content.length; for ( var Pos = EndPos; Pos < Count; Pos++ ) { var Item = this.Content[Pos]; var ItemType = Item.Type; if ( !( ( true === SkipAnchor && ( para_Drawing === ItemType && true !== Item.Is_Inline() ) ) || ( true === SkipEnd && para_End === ItemType ) ) ) return false; } return true; }; ParaRun.prototype.IsSelectedFromStart = function() { if (!this.Selection.Use && !this.IsEmpty()) return false; return (Math.min(this.Selection.StartPos, this.Selection.EndPos) === 0); }; ParaRun.prototype.IsSelectedToEnd = function() { if (!this.Selection.Use && !this.IsEmpty()) return false; return (Math.max(this.Selection.StartPos, this.Selection.EndPos) === this.Content.length); }; ParaRun.prototype.GetSelectionStartPos = function() { return (this.Selection.StartPos > this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos); }; ParaRun.prototype.GetSelectionEndPos = function() { return (this.Selection.StartPos > this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos); }; ParaRun.prototype.SkipAnchorsAtSelectionStart = function(Direction) { if (false === this.Selection.Use || true === this.IsEmpty({SkipAnchor : true})) return true; var oSelection = this.State.Selection; var nStartPos = Math.min(oSelection.StartPos, oSelection.EndPos); var nEndPos = Math.max(oSelection.StartPos, oSelection.EndPos); for (var nPos = 0; nPos < nStartPos; ++nPos) { var oItem = this.Content[nPos]; if (para_Drawing !== oItem.Type || true === oItem.Is_Inline()) return false; } for (var nPos = nStartPos; nPos < nEndPos; ++nPos) { var oItem = this.Content[nPos]; if (para_Drawing === oItem.Type && true !== oItem.Is_Inline()) { if (1 === Direction) oSelection.StartPos = nPos + 1; else oSelection.EndPos = nPos + 1; } else { return false; } } if (nEndPos < this.Content.length) return false; return true; }; ParaRun.prototype.RemoveSelection = function() { if (this.Selection.Use) this.State.ContentPos = Math.min(this.Content.length, Math.max(0, this.Selection.EndPos)); this.Selection.Use = false; this.Selection.StartPos = 0; this.Selection.EndPos = 0; }; ParaRun.prototype.SelectAll = function(nDirection) { this.Selection.Use = true; if (nDirection < 0) { this.Selection.StartPos = this.Content.length; this.Selection.EndPos = 0; } else { this.Selection.StartPos = 0; this.Selection.EndPos = this.Content.length; } }; ParaRun.prototype.drawSelectionInRange = function(line, range, drawSelectionState) { let rangeInfo = this.getRangePos(line, range); let rangeStart = rangeInfo[0]; let rangeEnd = rangeInfo[1]; if (rangeStart >= rangeEnd) return; let selectionStart = this.State.Selection.StartPos; let selectionEnd = this.State.Selection.EndPos; if (!this.State.Selection.Use) { selectionStart = -1; selectionEnd = -1; } else if (selectionStart > selectionEnd) { selectionStart = this.State.Selection.EndPos; selectionEnd = this.State.Selection.StartPos; } for (let pos = rangeStart; pos < rangeEnd; ++pos) { let item = this.private_CheckInstrText(this.Content[pos]); drawSelectionState.handleRunElement(item, selectionStart <= pos && pos < selectionEnd); } }; ParaRun.prototype.IsSelectionEmpty = function(CheckEnd) { var Selection = this.State.Selection; if (true !== Selection.Use) return true; if (this.IsMathRun() && this.IsPlaceholder()) return false; var StartPos = Selection.StartPos; var EndPos = Selection.EndPos; if ( StartPos > EndPos ) { StartPos = Selection.EndPos; EndPos = Selection.StartPos; } if ( true === CheckEnd ) return ( EndPos > StartPos ? false : true ); else if(this.Type == para_Math_Run && this.Is_Empty()) { return false; } else { for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ ) { var ItemType = this.Content[CurPos].Type; if (para_End !== ItemType) return false; } } return true; }; ParaRun.prototype.Selection_CheckParaEnd = function() { var Selection = this.State.Selection; if ( true !== Selection.Use ) return false; var StartPos = Selection.StartPos; var EndPos = Selection.EndPos; if ( StartPos > EndPos ) { StartPos = Selection.EndPos; EndPos = Selection.StartPos; } for ( var CurPos = StartPos; CurPos < EndPos; CurPos++ ) { var Item = this.Content[CurPos]; if ( para_End === Item.Type ) return true; } return false; }; ParaRun.prototype.Selection_CheckParaContentPos = function(ContentPos, Depth, bStart, bEnd) { var CurPos = ContentPos.Get(Depth); if (this.Selection.StartPos <= this.Selection.EndPos && this.Selection.StartPos <= CurPos && CurPos <= this.Selection.EndPos) { if ((true !== bEnd) || (true === bEnd && CurPos !== this.Selection.EndPos)) return true; } else if (this.Selection.StartPos > this.Selection.EndPos && this.Selection.EndPos <= CurPos && CurPos <= this.Selection.StartPos) { if ((true !== bEnd) || (true === bEnd && CurPos !== this.Selection.StartPos)) return true; } return false; }; //----------------------------------------------------------------------------------- // Функции для работы с настройками текста свойств //----------------------------------------------------------------------------------- ParaRun.prototype.Clear_TextFormatting = function(DefHyper, bHighlight) { // Highlight и Lang не сбрасываются при очистке текстовых настроек this.SetBold(undefined); this.SetBoldCS(undefined); this.SetItalic(undefined); this.SetItalicCS(undefined); this.SetStrikeout(undefined); this.SetUnderline(undefined); this.SetFontSize(undefined); this.SetFontSizeCS(undefined); this.Set_Color(undefined); this.Set_Unifill(undefined); this.Set_VertAlign(undefined); this.Set_Spacing(undefined); this.Set_DStrikeout(undefined); this.Set_Caps(undefined); this.Set_SmallCaps(undefined); this.Set_Position(undefined); this.Set_RFonts2(undefined); this.Set_RStyle(undefined); this.Set_Shd(undefined); this.Set_TextFill(undefined); this.Set_TextOutline(undefined); if(bHighlight) { this.Set_HighLight(undefined); this.SetHighlightColor(undefined); } // Насильно заставим пересчитать стиль, т.к. как данная функция вызывается у параграфа, у которого мог смениться стиль this.Recalc_CompiledPr(true); }; ParaRun.prototype.Get_TextPr = function() { return this.Pr.Copy(); }; ParaRun.prototype.GetTextPr = function() { return this.Pr.Copy(); }; ParaRun.prototype.Get_FirstTextPr = function() { return this.Pr; }; ParaRun.prototype.Get_CompiledTextPr = function(Copy) { if (true === this.State.Selection.Use && true === this.Selection_CheckParaEnd()) { var oRunTextPr = this.Get_CompiledPr(true); var oEndTextPr = this.Paragraph.GetParaEndCompiledPr(); oRunTextPr = oRunTextPr.Compare(oEndTextPr); return oRunTextPr; } else { return this.Get_CompiledPr(Copy); } }; ParaRun.prototype.GetDirectTextPr = function() { return this.Pr; }; ParaRun.prototype.Recalc_CompiledPr = function(RecalcMeasure) { this.RecalcInfo.TextPr = true; if (RecalcMeasure) this.RecalcMeasure(); // Если мы в формуле, тогда ее надо пересчитывать this.private_RecalcCtrPrp(); this.OnTextPrChange(); }; ParaRun.prototype.RecalcMeasure = function() { this.RecalcInfo.Measure = true; this.private_UpdateShapeText(); }; ParaRun.prototype.Recalc_RunsCompiledPr = function() { this.Recalc_CompiledPr(true); }; /** * @param bCopy {boolean} return a duplicate or reference to the compiled textPr object * @returns {CTextPr} */ ParaRun.prototype.Get_CompiledPr = function(bCopy) { if (this.IsStyleHyperlink() && this.IsInHyperlinkInTOC()) this.RecalcInfo.TextPr = true; if (this.RecalcInfo.TextPr) { AscWord.g_textPrCache.remove(this.CompiledPr); // Пока настройки параграфа не считаются скомпилированными, мы не можем считать скомпилированными настройки рана this.RecalcInfo.TextPr = !!(this.Paragraph && !this.Paragraph.IsParaPrCompiled()); let textPr = this.Internal_Compile_Pr(); this.CompiledPr = AscWord.g_textPrCache.add(textPr); } if ( false === bCopy ) return this.CompiledPr; else return this.CompiledPr.Copy(); // Отдаем копию объекта, чтобы никто не поменял извне настройки стиля }; /** * Return a reference to the compiled textPr object * @returns {AscWord.CTextPr} */ ParaRun.prototype.getCompiledPr = function() { return this.Get_CompiledPr(false); }; ParaRun.prototype.Internal_Compile_Pr = function () { if (undefined === this.Paragraph || null === this.Paragraph) { // Сюда мы никогда не должны попадать, но на всякий случай, // чтобы не выпадало ошибок сгенерим дефолтовые настройки var TextPr = new CTextPr(); TextPr.InitDefault(); this.RecalcInfo.TextPr = true; return TextPr; } // Получим настройки текста, для данного параграфа var TextPr = this.Paragraph.Get_CompiledPr2(false).TextPr.Copy(); let paraParent = this.Paragraph.GetParent(); let Styles = paraParent && paraParent.Get_Styles() ? paraParent.Get_Styles() : null; // Мержим настройки стиля. // Одно исключение, когда задан стиль Hyperlink внутри класса Hyperlink внутри поля TOC, то стиль // мержить не надо и, более того, цвет и подчеркивание из прямых настроек тоже не используется. if (Styles && Styles instanceof AscWord.CStyles && this.Pr.RStyle && (!this.IsStyleHyperlink() || !this.IsInHyperlinkInTOC())) { var StyleTextPr = Styles.Get_Pr(this.Pr.RStyle, styletype_Character).TextPr; TextPr.Merge(StyleTextPr); } if (this.Type === para_Math_Run) { if (undefined === this.Parent || null === this.Parent) { // Сюда мы никогда не должны попадать, но на всякий случай, // чтобы не выпадало ошибок сгенерим дефолтовые настройки var TextPr = new CTextPr(); TextPr.InitDefault(); this.RecalcInfo.TextPr = true; return TextPr; } if (!this.IsNormalText() && Styles) // math text { // выставим дефолтные текстовые настройки для математических Run var StyleId = this.Paragraph.Style_Get(); // скопируем текстовые настройки прежде чем подменим на пустые var MathFont = {Name : "Cambria Math", Index : -1}; var oShapeStyle = null, oShapeTextPr = null; if (Styles && typeof Styles.lastId === "string") { StyleId = Styles.lastId; Styles = Styles.styles; oShapeStyle = Styles.Get(StyleId); oShapeTextPr = oShapeStyle.TextPr.Copy(); oShapeStyle.TextPr.RFonts.Merge({Ascii : MathFont}); } var StyleDefaultTextPr = Styles.Default.TextPr.Copy(); // Ascii - по умолчанию шрифт Cambria Math // hAnsi, eastAsia, cs - по умолчанию шрифты не Cambria Math, а те, которые компилируются в документе Styles.Default.TextPr.RFonts.Merge({Ascii : MathFont}); var Pr = Styles.Get_Pr(StyleId, styletype_Paragraph, null, null); TextPr.RFonts.Set_FromObject(Pr.TextPr.RFonts); // подменяем обратно Styles.Default.TextPr = StyleDefaultTextPr; if (oShapeStyle && oShapeTextPr) { oShapeStyle.TextPr = oShapeTextPr; } } if (this.IsPlaceholder()) { TextPr.Merge(this.Parent.GetCtrPrp()); TextPr.Merge(this.Pr); // Мержим прямые настройки данного рана } else { TextPr.Merge(this.Pr); // Мержим прямые настройки данного рана if (!this.IsNormalText()) // math text { var MPrp = this.MathPrp.GetTxtPrp(); TextPr.Merge(MPrp); // bold, italic } } } else { var FontScale = TextPr.FontScale; TextPr.Merge(this.Pr); // Мержим прямые настройки данного рана TextPr.FontScale = FontScale; if (this.Pr.Color && !this.Pr.Unifill) { TextPr.Unifill = undefined; } } var oTheme = this.Paragraph.Get_Theme(); var oColorMap = this.Paragraph.Get_ColorMap() if (oTheme && oColorMap) { if (TextPr.TextFill) TextPr.TextFill.check(oTheme, oColorMap); else if (TextPr.Unifill) TextPr.Unifill.check(oTheme, oColorMap); TextPr.ReplaceThemeFonts(oTheme.themeElements.fontScheme); } if(this.Paragraph.bFromDocument === false) { TextPr.BoldCS = TextPr.Bold; TextPr.ItalicCS = TextPr.Italic; TextPr.FontSizeCS = TextPr.FontSize; } TextPr.CheckFontScale(); // Для совместимости со старыми версиями запишем FontFamily TextPr.FontFamily.Name = TextPr.RFonts.Ascii.Name; TextPr.FontFamily.Index = TextPr.RFonts.Ascii.Index; if (this.Paragraph.IsInFixedForm()) TextPr.Position = 0; let layoutCoeff = this.Paragraph.getLayoutFontSizeCoefficient(); TextPr.FontSize *= layoutCoeff; TextPr.FontSizeCS *= layoutCoeff; return TextPr; }; ParaRun.prototype.IsStyleHyperlink = function() { if (!this.Paragraph || !this.Paragraph.bFromDocument || !this.Paragraph.LogicDocument || !this.Paragraph.LogicDocument.Get_Styles() || !this.Paragraph.LogicDocument.Get_Styles().GetDefaultHyperlink) return false; return (this.Pr.RStyle === this.Paragraph.LogicDocument.Get_Styles().GetDefaultHyperlink() ? true : false); }; ParaRun.prototype.IsInHyperlinkInTOC = function() { var oParagraph = this.GetParagraph(); if (!oParagraph || !oParagraph.bFromDocument) return false; var oPos = oParagraph.Get_PosByElement(this); if (!oPos) return false; var isHyperlink = false; var arrClasses = oParagraph.Get_ClassesByPos(oPos); for (var nIndex = 0, nCount = arrClasses.length; nIndex < nCount; ++nIndex) { if (arrClasses[nIndex] instanceof ParaHyperlink) { isHyperlink = true; break; } } var arrComplexFields = oParagraph.GetComplexFieldsByPos(oPos); if (!isHyperlink) { for (var nIndex = 0, nCount = arrComplexFields.length; nIndex < nCount; ++nIndex) { var oInstruction = arrComplexFields[nIndex].GetInstruction(); if (oInstruction && AscWord.fieldtype_HYPERLINK === oInstruction.GetType()) { isHyperlink = true; break; } } if (!isHyperlink) return false; } for (var nIndex = 0, nCount = arrComplexFields.length; nIndex < nCount; ++nIndex) { var oInstruction = arrComplexFields[nIndex].GetInstruction(); if (oInstruction && AscWord.fieldtype_TOC === oInstruction.GetType()) return true; } return false; }; ParaRun.prototype.Set_Pr = function(TextPr) { return this.SetPr(TextPr); }; /** * Жестко меняем настройки на заданные * @param {CTextPr} oTextPr */ ParaRun.prototype.SetPr = function(oTextPr) { AscCommon.History.Add(new CChangesRunTextPr(this, this.Pr, oTextPr, this.private_IsCollPrChangeMine())); this.Pr = oTextPr; this.Recalc_CompiledPr(true); this.private_UpdateSpellChecking(); this.private_UpdateTrackRevisionOnChangeTextPr(true); }; ParaRun.prototype.Apply_TextPr = function(TextPr, IncFontSize, ApplyToAll) { if (undefined === IncFontSize && this.Pr.Is_Equal(TextPr) && (!this.IsParaEndRun() || !this.Paragraph || this.Paragraph.TextPr.Value.Is_Equal(TextPr))) return [null, this, null]; var bReview = false; if (this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument && true === this.Paragraph.LogicDocument.IsTrackRevisions()) bReview = true; var ReviewType = this.GetReviewType(); var IsPrChange = this.HavePrChange(); if ( true === ApplyToAll ) { if (true === bReview && true !== this.HavePrChange()) this.AddPrChange(); if (undefined === IncFontSize) this.Apply_Pr(TextPr); else this.IncreaseDecreaseFontSize(IncFontSize); // TODO: Возможно, стоит на этапе пересчета запонимать, лежит ли para_End в данном ране. Чтобы в каждом // ране потом не бегать каждый раз по всему массиву в поисках para_End. if (this.IsParaEndRun()) { if (undefined === IncFontSize) { if (!TextPr.AscFill && !TextPr.AscLine && !TextPr.AscUnifill) { this.Paragraph.TextPr.Apply_TextPr(TextPr); } else { var oEndTextPr = this.Paragraph.GetParaEndCompiledPr(); if (TextPr.AscFill) { this.Paragraph.TextPr.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oEndTextPr.TextFill, 1)); } if (TextPr.AscUnifill) { this.Paragraph.TextPr.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oEndTextPr.Unifill, 0)); } if (TextPr.AscLine) { this.Paragraph.TextPr.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oEndTextPr.TextOutline, 0)); } } } else { // TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут this.Paragraph.TextPr.IncreaseDecreaseFontSize(IncFontSize); } } this.OnTextPrChange(); } else { var Result = []; var LRun = this, CRun = null, RRun = null; if ( true === this.State.Selection.Use ) { var StartPos = this.State.Selection.StartPos; var EndPos = this.State.Selection.EndPos; if (StartPos === EndPos && 0 !== this.Content.length) { CRun = this; LRun = null; RRun = null; } else { var Direction = 1; if (StartPos > EndPos) { var Temp = StartPos; StartPos = EndPos; EndPos = Temp; Direction = -1; } // Если выделено не до конца, тогда разделяем по последней точке if (EndPos < this.Content.length) { RRun = LRun.Split_Run(EndPos); RRun.SetReviewType(ReviewType); if (IsPrChange) RRun.AddPrChange(); } // Если выделено не с начала, тогда делим по начальной точке if (StartPos > 0) { CRun = LRun.Split_Run(StartPos); CRun.SetReviewType(ReviewType); if (IsPrChange) CRun.AddPrChange(); } else { CRun = LRun; LRun = null; } if (null !== LRun) { LRun.Selection.Use = true; LRun.Selection.StartPos = LRun.Content.length; LRun.Selection.EndPos = LRun.Content.length; } CRun.SelectAll(Direction); if (true === bReview && true !== CRun.HavePrChange()) CRun.AddPrChange(); if (undefined === IncFontSize) CRun.Apply_Pr(TextPr); else CRun.IncreaseDecreaseFontSize(IncFontSize); if (null !== RRun) { RRun.Selection.Use = true; RRun.Selection.StartPos = 0; RRun.Selection.EndPos = 0; } // Дополнительно проверим, если у нас para_End лежит в данном ране и попадает в выделение, тогда // применим заданные настроки к символу конца параграфа // TODO: Возможно, стоит на этапе пересчета запонимать, лежит ли para_End в данном ране. Чтобы в каждом // ране потом не бегать каждый раз по всему массиву в поисках para_End. if (true === this.Selection_CheckParaEnd()) { if (undefined === IncFontSize) { if (!TextPr.AscFill && !TextPr.AscLine && !TextPr.AscUnifill) { this.Paragraph.TextPr.Apply_TextPr(TextPr); } else { var oEndTextPr = this.Paragraph.GetParaEndCompiledPr(); if (TextPr.AscFill) { this.Paragraph.TextPr.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oEndTextPr.TextFill, 1)); } if (TextPr.AscUnifill) { this.Paragraph.TextPr.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oEndTextPr.Unifill, 0)); } if (TextPr.AscLine) { this.Paragraph.TextPr.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oEndTextPr.TextOutline, 0)); } } } else { // TODO: Как только перенесем историю изменений TextPr в сам класс CTextPr, переделать тут this.Paragraph.TextPr.IncreaseDecreaseFontSize(IncFontSize); } } } } else { var CurPos = this.State.ContentPos; // Если выделено не до конца, тогда разделяем по последней точке if ( CurPos < this.Content.length ) { RRun = LRun.Split_Run(CurPos); RRun.SetReviewType(ReviewType); if (IsPrChange) RRun.AddPrChange(); } if ( CurPos > 0 ) { CRun = LRun.Split_Run(CurPos); CRun.SetReviewType(ReviewType); if (IsPrChange) CRun.AddPrChange(); } else { CRun = LRun; LRun = null; } if ( null !== LRun ) LRun.RemoveSelection(); CRun.RemoveSelection(); CRun.MoveCursorToStartPos(); if (true === bReview && true !== CRun.HavePrChange()) CRun.AddPrChange(); if (undefined === IncFontSize) CRun.Apply_Pr(TextPr); else CRun.IncreaseDecreaseFontSize(IncFontSize); if ( null !== RRun ) RRun.RemoveSelection(); } Result.push( LRun ); Result.push( CRun ); Result.push( RRun ); this.OnTextPrChange(); return Result; } }; ParaRun.prototype.Split_Run = function(Pos) { // Создаем новый ран var bMathRun = this.Type == para_Math_Run; var NewRun = new ParaRun(this.Paragraph, bMathRun); AscCommon.History.Add(new CChangesRunOnStartSplit(this, Pos, NewRun)); AscCommon.CollaborativeEditing.OnStart_SplitRun(this, Pos); // Копируем настройки NewRun.Set_Pr(this.Pr.Copy(true)); if(bMathRun) NewRun.Set_MathPr(this.MathPrp.Copy()); var OldCrPos = this.State.ContentPos; var OldSSPos = this.State.Selection.StartPos; var OldSEPos = this.State.Selection.EndPos; // Разделяем содержимое по ранам NewRun.ConcatToContent( this.Content.slice(Pos) ); // Если были точки орфографии, тогда переместим их в новый ран for (let iMark = 0, nMarks = this.SpellingMarks.length; iMark < nMarks; ++iMark) { let mark = this.SpellingMarks[iMark]; if (mark.getPos() >= Pos) { mark.movePos(-Pos); NewRun.SpellingMarks.push(mark); this.SpellingMarks.splice(iMark, 1); --nMarks; --iMark; } } this.private_UpdateCustomMarksOnSplit(Pos, NewRun); this.Remove_FromContent( Pos, this.Content.length - Pos, true ); // Подправим точки селекта и текущей позиции if ( OldCrPos >= Pos ) { NewRun.State.ContentPos = OldCrPos - Pos; this.State.ContentPos = this.Content.length; } else { NewRun.State.ContentPos = 0; } if ( OldSSPos >= Pos ) { NewRun.State.Selection.StartPos = OldSSPos - Pos; this.State.Selection.StartPos = this.Content.length; } else { NewRun.State.Selection.StartPos = 0; } if ( OldSEPos >= Pos ) { NewRun.State.Selection.EndPos = OldSEPos - Pos; this.State.Selection.EndPos = this.Content.length; } else { NewRun.State.Selection.EndPos = 0; } AscCommon.History.Add(new CChangesRunOnEndSplit(this, Pos, NewRun)); AscCommon.CollaborativeEditing.OnEnd_SplitRun(NewRun); return NewRun; }; ParaRun.prototype.Clear_TextPr = function() { // Данная функция вызывается пока только при изменении стиля параграфа. Оставляем в этой ситуации язык неизмененным, // а также не трогаем highlight. var NewTextPr = new CTextPr(); NewTextPr.Lang = this.Pr.Lang.Copy(); NewTextPr.HighLight = this.Pr.Copy_HighLight(); this.Set_Pr( NewTextPr ); }; /** * В данной функции мы применяем приходящие настройки поверх старых. Если значение undefined, то старое значение * не меняем, а если null, то удаляем его из прямых настроек. * @param {CTextPr} TextPr */ ParaRun.prototype.Apply_Pr = function(TextPr) { this.private_AddCollPrChangeMine(); if (this.Type == para_Math_Run && false === this.IsNormalText()) { if (null === TextPr.Bold && null === TextPr.Italic) this.Math_Apply_Style(undefined); else { if (undefined != TextPr.Bold) { if (TextPr.Bold == true) { if (this.MathPrp.sty == STY_ITALIC || this.MathPrp.sty == undefined) this.Math_Apply_Style(STY_BI); else if (this.MathPrp.sty == STY_PLAIN) this.Math_Apply_Style(STY_BOLD); } else if (TextPr.Bold == false || TextPr.Bold == null) { if (this.MathPrp.sty == STY_BI || this.MathPrp.sty == undefined) this.Math_Apply_Style(STY_ITALIC); else if (this.MathPrp.sty == STY_BOLD) this.Math_Apply_Style(STY_PLAIN); } } if (undefined != TextPr.Italic) { if (TextPr.Italic == true) { if (this.MathPrp.sty == STY_BOLD) this.Math_Apply_Style(STY_BI); else if (this.MathPrp.sty == STY_PLAIN || this.MathPrp.sty == undefined) this.Math_Apply_Style(STY_ITALIC); } else if (TextPr.Italic == false || TextPr.Italic == null) { if (this.MathPrp.sty == STY_BI) this.Math_Apply_Style(STY_BOLD); else if (this.MathPrp.sty == STY_ITALIC || this.MathPrp.sty == undefined) this.Math_Apply_Style(STY_PLAIN); } } } } else { if (undefined !== TextPr.Bold) { this.SetBold(null === TextPr.Bold ? undefined : TextPr.Bold); this.SetBoldCS(null === TextPr.Bold ? undefined : TextPr.Bold); } if (undefined !== TextPr.Italic) { this.SetItalic(null === TextPr.Italic ? undefined : TextPr.Italic); this.SetItalicCS(null === TextPr.Italic ? undefined : TextPr.Italic); } } if (undefined !== TextPr.Strikeout) this.SetStrikeout(null === TextPr.Strikeout ? undefined : TextPr.Strikeout); if (undefined !== TextPr.Underline) this.SetUnderline(null === TextPr.Underline ? undefined : TextPr.Underline); if (undefined !== TextPr.FontSize) { this.SetFontSize(null === TextPr.FontSize ? undefined : TextPr.FontSize); this.SetFontSizeCS(null === TextPr.FontSize ? undefined : TextPr.FontSize); } var oCompiledPr; if (undefined !== TextPr.AscUnifill && null !== TextPr.AscUnifill) { if(this.Paragraph && !this.Paragraph.bFromDocument) { oCompiledPr = this.Get_CompiledPr(true); this.Set_Unifill(AscFormat.CorrectUniFill(TextPr.AscUnifill, oCompiledPr.Unifill, 0), AscCommon.isRealObject(TextPr.AscUnifill) && TextPr.AscUnifill.asc_CheckForseSet()); this.Set_Color(undefined); this.Set_TextFill(undefined); } } else if (undefined !== TextPr.AscFill && null !== TextPr.AscFill) { var oMergeUnifill, oColor; if (this.Paragraph && this.Paragraph.bFromDocument) { oCompiledPr = this.Get_CompiledPr(true); if (oCompiledPr.TextFill) { oMergeUnifill = oCompiledPr.TextFill; } else if (oCompiledPr.Unifill) { oMergeUnifill = oCompiledPr.Unifill; } else if (oCompiledPr.Color) { oColor = oCompiledPr.Color; oMergeUnifill = AscFormat.CreateUnfilFromRGB(oColor.r, oColor.g, oColor.b); } this.Set_Unifill(undefined); this.Set_Color(undefined); this.Set_TextFill(AscFormat.CorrectUniFill(TextPr.AscFill, oMergeUnifill, 1), AscCommon.isRealObject(TextPr.AscFill) && TextPr.AscFill.asc_CheckForseSet()); } } else { if (undefined !== TextPr.Color) { this.Set_Color(null === TextPr.Color ? undefined : TextPr.Color); if(null !== TextPr.Color) { this.Set_Unifill(undefined); this.Set_TextFill(undefined); } } if (undefined !== TextPr.Unifill) { this.Set_Unifill(null === TextPr.Unifill ? undefined : TextPr.Unifill); if(null !== TextPr.Unifill) { this.Set_Color(undefined); this.Set_TextFill(undefined); } } if (undefined !== TextPr.TextFill) { this.Set_TextFill(null === TextPr.TextFill ? undefined : TextPr.TextFill); if(null !== TextPr.TextFill) { this.Set_Unifill(undefined); this.Set_Color(undefined); } } } if (undefined !== TextPr.AscLine && null !== TextPr.AscLine) { if(this.Paragraph) { oCompiledPr = this.Get_CompiledPr(true); this.Set_TextOutline(AscFormat.CorrectUniStroke(TextPr.AscLine, oCompiledPr.TextOutline, 0)); } } else if (undefined !== TextPr.TextOutline) { this.Set_TextOutline(null === TextPr.TextOutline ? undefined : TextPr.TextOutline); } if (undefined !== TextPr.VertAlign) this.Set_VertAlign(null === TextPr.VertAlign ? undefined : TextPr.VertAlign); if (undefined !== TextPr.HighLight) this.Set_HighLight(null === TextPr.HighLight ? undefined : TextPr.HighLight); if(undefined !== TextPr.HighlightColor) this.SetHighlightColor(null === TextPr.HighlightColor ? undefined : TextPr.HighlightColor); if (undefined !== TextPr.RStyle) this.Set_RStyle(null === TextPr.RStyle ? undefined : TextPr.RStyle); if (undefined !== TextPr.Spacing) this.Set_Spacing(null === TextPr.Spacing ? undefined : TextPr.Spacing); if (undefined !== TextPr.DStrikeout) this.Set_DStrikeout(null === TextPr.DStrikeout ? undefined : TextPr.DStrikeout); if (undefined !== TextPr.Caps) this.Set_Caps(null === TextPr.Caps ? undefined : TextPr.Caps); if (undefined !== TextPr.SmallCaps) this.Set_SmallCaps(null === TextPr.SmallCaps ? undefined : TextPr.SmallCaps); if (undefined !== TextPr.Position) this.Set_Position(null === TextPr.Position ? undefined : TextPr.Position); if (TextPr.RFonts && !this.IsInCheckBox()) { if (para_Math_Run === this.Type && !this.IsNormalText()) // при смене Font в этом случае (даже на Cambria Math) cs, eastAsia не меняются { // только для редактирования // делаем так для проверки действительно ли нужно сменить Font, чтобы при смене других текстовых настроек не выставился Cambria Math (TextPr.RFonts приходит всегда в виде объекта) if (TextPr.RFonts.Ascii !== undefined || TextPr.RFonts.HAnsi !== undefined) { var RFonts = new CRFonts(); RFonts.SetAll("Cambria Math", -1); this.Set_RFonts2(RFonts); } } else { if (TextPr.FontFamily) this.ApplyFontFamily(TextPr.FontFamily.Name); else this.Set_RFonts2(TextPr.RFonts); } } if (undefined !== TextPr.Lang && undefined !== TextPr.Lang.Val) { let lcid = TextPr.Lang.Val; let dirFlag = this.GetDirectionFlagInRange(0, this.Content.length); if (AscBidi.DIRECTION_FLAG.None === dirFlag) { this.Set_Lang_Bidi(lcid); this.Set_Lang_Val(lcid); } else { if (AscBidi.DIRECTION_FLAG.LTR & dirFlag) this.Set_Lang_Val(lcid); if (AscBidi.DIRECTION_FLAG.RTL & dirFlag) this.Set_Lang_Bidi(lcid); let paragraph = this.GetParagraph(); if (AscBidi.DIRECTION_FLAG.Other === dirFlag && paragraph) { if (paragraph.isRtlDirection()) this.Set_Lang_Bidi(lcid); else this.Set_Lang_Val(lcid); } } } if (undefined !== TextPr.Shd) this.Set_Shd(null === TextPr.Shd ? undefined : TextPr.Shd); if (undefined !== TextPr.Ligatures) this.SetLigatures(null === TextPr.Ligatures ? undefined : TextPr.Ligatures); for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { if (para_End === this.Content[nPos].Type) return this.Paragraph.TextPr.Apply_TextPr(TextPr); } }; ParaRun.prototype.ApplyPr = function(oTextPr) { return this.Apply_Pr(oTextPr); }; ParaRun.prototype.HavePrChange = function() { return this.Pr.HavePrChange(); }; ParaRun.prototype.GetPrReviewColor = function() { if (this.Pr.ReviewInfo) return this.Pr.ReviewInfo.Get_Color(); return REVIEW_COLOR; }; ParaRun.prototype.AddPrChange = function() { if (false === this.HavePrChange()) { this.Pr.AddPrChange(); AscCommon.History.Add(new CChangesRunPrChange(this, { PrChange : undefined, ReviewInfo : undefined }, { PrChange : this.Pr.PrChange, ReviewInfo : this.Pr.ReviewInfo })); this.updateTrackRevisions(); } }; ParaRun.prototype.SetPrChange = function(PrChange, ReviewInfo) { AscCommon.History.Add(new CChangesRunPrChange(this, { PrChange : this.Pr.PrChange, ReviewInfo : this.Pr.ReviewInfo ? this.Pr.ReviewInfo.Copy() : undefined }, { PrChange : PrChange, ReviewInfo : ReviewInfo ? ReviewInfo.Copy() : undefined })); this.Pr.SetPrChange(PrChange, ReviewInfo); this.updateTrackRevisions(); }; ParaRun.prototype.RemovePrChange = function() { if (true === this.HavePrChange()) { AscCommon.History.Add(new CChangesRunPrChange(this, { PrChange : this.Pr.PrChange, ReviewInfo : this.Pr.ReviewInfo }, { PrChange : undefined, ReviewInfo : undefined })); this.Pr.RemovePrChange(); this.updateTrackRevisions(); } }; ParaRun.prototype.RejectPrChange = function() { if (true === this.HavePrChange()) { if (this.GetParaEnd()) this.Paragraph.TextPr.SetPr(this.Pr.PrChange); this.Set_Pr(this.Pr.PrChange); this.RemovePrChange(); } }; ParaRun.prototype.AcceptPrChange = function() { this.RemovePrChange(); }; ParaRun.prototype.GetDiffPrChange = function() { return this.Pr.GetDiffPrChange(); }; ParaRun.prototype.SetBold = function(isBold) { if (isBold !== this.Pr.Bold) { AscCommon.History.Add(new CChangesRunBold(this, this.Pr.Bold, isBold, this.private_IsCollPrChangeMine())); this.Pr.Bold = isBold; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Bold = function() { return this.Get_CompiledPr(false).Bold; }; ParaRun.prototype.SetBoldCS = function(isBold) { if (isBold !== this.Pr.BoldCS) { AscCommon.History.Add(new CChangesRunBoldCS(this, this.Pr.BoldCS, isBold, this.private_IsCollPrChangeMine())); this.Pr.BoldCS = isBold; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.GetBoldCS = function() { return this.Get_CompiledPr(false).BoldCS; }; ParaRun.prototype.SetItalic = function(isItalic) { if (isItalic !== this.Pr.Italic) { AscCommon.History.Add(new CChangesRunItalic(this, this.Pr.Italic, isItalic, this.private_IsCollPrChangeMine())); this.Pr.Italic = isItalic; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Italic = function() { return this.Get_CompiledPr(false).Italic; }; ParaRun.prototype.SetItalicCS = function(isItalic) { if (isItalic !== this.Pr.ItalicCS) { AscCommon.History.Add(new CChangesRunItalicCS(this, this.Pr.ItalicCS, isItalic, this.private_IsCollPrChangeMine())); this.Pr.ItalicCS = isItalic; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.GetItalicCS = function() { return this.Get_CompiledPr(false).ItalicCS; }; ParaRun.prototype.SetStrikeout = function(Value) { if ( Value !== this.Pr.Strikeout ) { var OldValue = this.Pr.Strikeout; this.Pr.Strikeout = Value; AscCommon.History.Add(new CChangesRunStrikeout(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Strikeout = function() { return this.Get_CompiledPr(false).Strikeout; }; ParaRun.prototype.SetUnderline = function(Value) { if ( Value !== this.Pr.Underline ) { var OldValue = this.Pr.Underline; this.Pr.Underline = Value; AscCommon.History.Add(new CChangesRunUnderline(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Underline = function() { return this.Get_CompiledPr(false).Underline; }; ParaRun.prototype.SetFontSize = function(nFontSize) { if (nFontSize !== this.Pr.FontSize) { AscCommon.History.Add(new CChangesRunFontSize(this, this.Pr.FontSize, nFontSize, this.private_IsCollPrChangeMine())); this.Pr.FontSize = nFontSize; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_FontSize = function() { return this.Get_CompiledPr(false).FontSize; }; ParaRun.prototype.SetFontSizeCS = function(nFontSize) { if (nFontSize !== this.Pr.FontSizeCS) { AscCommon.History.Add(new CChangesRunFontSizeCS(this, this.Pr.FontSizeCS, nFontSize, this.private_IsCollPrChangeMine())); this.Pr.FontSizeCS = nFontSize; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.GetFontSizeCS = function() { return this.Get_CompiledPr(false).FontSizeCS; }; ParaRun.prototype.Set_Color = function(Value) { if ( ( undefined === Value && undefined !== this.Pr.Color ) || ( Value instanceof CDocumentColor && ( undefined === this.Pr.Color || false === Value.Compare(this.Pr.Color) ) ) ) { var OldValue = this.Pr.Color; this.Pr.Color = Value; AscCommon.History.Add(new CChangesRunColor(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetColor = function(color) { return this.Set_Color(color); }; ParaRun.prototype.Set_Unifill = function(Value, bForce) { if ( ( undefined === Value && undefined !== this.Pr.Unifill ) || ( Value instanceof AscFormat.CUniFill && ( undefined === this.Pr.Unifill || false === AscFormat.CompareUnifillBool(this.Pr.Unifill, Value) ) ) || bForce ) { var OldValue = this.Pr.Unifill; this.Pr.Unifill = Value; AscCommon.History.Add(new CChangesRunUnifill(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Set_TextFill = function(Value, bForce) { if ( ( undefined === Value && undefined !== this.Pr.TextFill ) || ( Value instanceof AscFormat.CUniFill && ( undefined === this.Pr.TextFill || false === AscFormat.CompareUnifillBool(this.Pr.TextFill.IsIdentical, Value) ) ) || bForce ) { var OldValue = this.Pr.TextFill; this.Pr.TextFill = Value; AscCommon.History.Add(new CChangesRunTextFill(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Set_TextOutline = function(Value) { if ( ( undefined === Value && undefined !== this.Pr.TextOutline ) || ( Value instanceof AscFormat.CLn && ( undefined === this.Pr.TextOutline || false === this.Pr.TextOutline.IsIdentical(Value) ) ) ) { var OldValue = this.Pr.TextOutline; this.Pr.TextOutline = Value; AscCommon.History.Add(new CChangesRunTextOutline(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Color = function() { return this.Get_CompiledPr(false).Color; }; ParaRun.prototype.Set_VertAlign = function(Value) { if ( Value !== this.Pr.VertAlign ) { var OldValue = this.Pr.VertAlign; this.Pr.VertAlign = Value; AscCommon.History.Add(new CChangesRunVertAlign(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_VertAlign = function() { return this.Get_CompiledPr(false).VertAlign; }; ParaRun.prototype.SetVertAlign = function(nAlign) { this.Set_VertAlign(nAlign); }; ParaRun.prototype.GetVertAlign = function() { return this.Get_VertAlign(); }; ParaRun.prototype.Set_HighLight = function(Value) { var OldValue = this.Pr.HighLight; if ( (undefined === Value && undefined !== OldValue) || ( highlight_None === Value && highlight_None !== OldValue ) || ( Value instanceof CDocumentColor && ( undefined === OldValue || highlight_None === OldValue || false === Value.Compare(OldValue) ) ) ) { this.Pr.HighLight = Value; AscCommon.History.Add(new CChangesRunHighLight(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetHighlightColor = function(Value) { var OldValue = this.Pr.HighlightColor; if ( OldValue && !OldValue.IsIdentical(Value) || Value && !Value.IsIdentical(OldValue) ) { this.Pr.HighlightColor = Value; AscCommon.History.Add(new CChangesRunHighlightColor(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); } }; ParaRun.prototype.Get_HighLight = function() { return this.Get_CompiledPr(false).HighLight; }; ParaRun.prototype.Set_RStyle = function(styleId) { if (!styleId) styleId = undefined; if (styleId === this.Pr.RStyle) return; let oldStyleId = this.Pr.RStyle; this.Pr.RStyle = styleId; AscCommon.History.Add(new CChangesRunRStyle(this, oldStyleId, styleId, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); }; ParaRun.prototype.Get_RStyle = function() { return this.Get_CompiledPr(false).RStyle; }; ParaRun.prototype.GetRStyle = function() { return this.Get_RStyle(); }; ParaRun.prototype.SetRStyle = function(sStyleId) { this.Set_RStyle(sStyleId); }; ParaRun.prototype.Set_Spacing = function(Value) { if (Value !== this.Pr.Spacing) { var OldValue = this.Pr.Spacing; this.Pr.Spacing = Value; AscCommon.History.Add(new CChangesRunSpacing(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Spacing = function() { return this.Get_CompiledPr(false).Spacing; }; ParaRun.prototype.Set_DStrikeout = function(Value) { if ( Value !== this.Pr.DStrikeout ) { var OldValue = this.Pr.DStrikeout; this.Pr.DStrikeout = Value; AscCommon.History.Add(new CChangesRunDStrikeout(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_DStrikeout = function() { return this.Get_CompiledPr(false).DStrikeout; }; ParaRun.prototype.Set_Caps = function(Value) { if ( Value !== this.Pr.Caps ) { var OldValue = this.Pr.Caps; this.Pr.Caps = Value; AscCommon.History.Add(new CChangesRunCaps(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Caps = function() { return this.Get_CompiledPr(false).Caps; }; ParaRun.prototype.Set_SmallCaps = function(Value) { if ( Value !== this.Pr.SmallCaps ) { var OldValue = this.Pr.SmallCaps; this.Pr.SmallCaps = Value; AscCommon.History.Add(new CChangesRunSmallCaps(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_SmallCaps = function() { return this.Get_CompiledPr(false).SmallCaps; }; ParaRun.prototype.Set_Position = function(Value) { if ( Value !== this.Pr.Position ) { var OldValue = this.Pr.Position; this.Pr.Position = Value; AscCommon.History.Add(new CChangesRunPosition(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Get_Position = function() { return this.Get_CompiledPr(false).Position; }; ParaRun.prototype.Set_RFonts = function(Value) { var OldValue = this.Pr.RFonts; this.Pr.RFonts = Value; AscCommon.History.Add(new CChangesRunRFonts(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); }; ParaRun.prototype.Get_RFonts = function() { return this.Get_CompiledPr(false).RFonts; }; ParaRun.prototype.Set_RFonts2 = function(oRFonts) { if (undefined !== oRFonts) { if (oRFonts.AsciiTheme) { this.SetRFontsAscii(undefined); this.SetRFontsAsciiTheme(oRFonts.AsciiTheme); } else if (oRFonts.Ascii) { this.SetRFontsAscii(oRFonts.Ascii); this.SetRFontsAsciiTheme(undefined); } else { if (null === oRFonts.Ascii) this.SetRFontsAscii(undefined); if (null === oRFonts.AsciiTheme) this.SetRFontsAsciiTheme(undefined); } if (oRFonts.HAnsiTheme) { this.SetRFontsHAnsi(undefined); this.SetRFontsHAnsiTheme(oRFonts.HAnsiTheme); } else if (oRFonts.HAnsi) { this.SetRFontsHAnsi(oRFonts.HAnsi); this.SetRFontsHAnsiTheme(undefined); } else { if (null === oRFonts.HAnsi) this.SetRFontsHAnsi(undefined); if (null === oRFonts.HAnsiTheme) this.SetRFontsHAnsiTheme(undefined); } if (oRFonts.CSTheme) { this.SetRFontsCS(undefined); this.SetRFontsCSTheme(oRFonts.CSTheme); } else if (oRFonts.CS) { this.SetRFontsCS(oRFonts.CS); this.SetRFontsCSTheme(undefined); } else { if (null === oRFonts.CS) this.SetRFontsCS(undefined); if (null === oRFonts.CSTheme) this.SetRFontsCSTheme(undefined); } if (oRFonts.EastAsiaTheme) { this.SetRFontsEastAsia(undefined); this.SetRFontsEastAsiaTheme(oRFonts.EastAsiaTheme); } else if (oRFonts.EastAsia) { this.SetRFontsEastAsia(oRFonts.EastAsia); this.SetRFontsEastAsiaTheme(undefined); } else { if (null === oRFonts.EastAsia) this.SetRFontsEastAsia(undefined); if (null === oRFonts.EastAsiaTheme) this.SetRFontsEastAsiaTheme(undefined); } if (undefined !== oRFonts.Hint) this.SetRFontsHint(null === oRFonts.Hint ? undefined : oRFonts.Hint); } else { this.SetRFontsAscii(undefined); this.SetRFontsAsciiTheme(undefined); this.SetRFontsHAnsi(undefined); this.SetRFontsHAnsiTheme(undefined); this.SetRFontsCS(undefined); this.SetRFontsCSTheme(undefined); this.SetRFontsEastAsia(undefined); this.SetRFontsEastAsiaTheme(undefined); this.SetRFontsHint(undefined); } }; ParaRun.prototype.Set_RFont_ForMathRun = function() { this.SetRFontsAscii({Name : "Cambria Math", Index : -1}); this.SetRFontsCS({Name : "Cambria Math", Index : -1}); this.SetRFontsEastAsia({Name : "Cambria Math", Index : -1}); this.SetRFontsHAnsi({Name : "Cambria Math", Index : -1}); }; ParaRun.prototype.SetRFontsAscii = function(Value) { var _Value = (null === Value ? undefined : Value); if (_Value !== this.Pr.RFonts.Ascii) { var OldValue = this.Pr.RFonts.Ascii; this.Pr.RFonts.Ascii = _Value; AscCommon.History.Add(new CChangesRunRFontsAscii(this, OldValue, _Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsHAnsi = function(Value) { var _Value = (null === Value ? undefined : Value); if (_Value !== this.Pr.RFonts.HAnsi) { var OldValue = this.Pr.RFonts.HAnsi; this.Pr.RFonts.HAnsi = _Value; AscCommon.History.Add(new CChangesRunRFontsHAnsi(this, OldValue, _Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsCS = function(Value) { var _Value = (null === Value ? undefined : Value); if (_Value !== this.Pr.RFonts.CS) { var OldValue = this.Pr.RFonts.CS; this.Pr.RFonts.CS = _Value; AscCommon.History.Add(new CChangesRunRFontsCS(this, OldValue, _Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsEastAsia = function(Value) { var _Value = (null === Value ? undefined : Value); if (_Value !== this.Pr.RFonts.EastAsia) { var OldValue = this.Pr.RFonts.EastAsia; this.Pr.RFonts.EastAsia = _Value; AscCommon.History.Add(new CChangesRunRFontsEastAsia(this, OldValue, _Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsHint = function(Value) { var _Value = (null === Value ? undefined : Value); if (_Value !== this.Pr.RFonts.Hint) { var OldValue = this.Pr.RFonts.Hint; this.Pr.RFonts.Hint = _Value; AscCommon.History.Add(new CChangesRunRFontsHint(this, OldValue, _Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsAsciiTheme = function(sValue) { var _sValue = (!sValue ? undefined : sValue); if (_sValue !== this.Pr.RFonts.AsciiTheme) { AscCommon.History.Add(new CChangesRunRFontsAsciiTheme(this, this.Pr.RFonts.AsciiTheme, _sValue, this.private_IsCollPrChangeMine())); this.Pr.RFonts.AsciiTheme = _sValue; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsHAnsiTheme = function(sValue) { var _sValue = (!sValue ? undefined : sValue); if (_sValue !== this.Pr.RFonts.HAnsiTheme) { AscCommon.History.Add(new CChangesRunRFontsHAnsiTheme(this, this.Pr.RFonts.HAnsiTheme, _sValue, this.private_IsCollPrChangeMine())); this.Pr.RFonts.HAnsiTheme = _sValue; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsCSTheme = function(sValue) { var _sValue = (!sValue ? undefined : sValue); if (_sValue !== this.Pr.RFonts.CSTheme) { AscCommon.History.Add(new CChangesRunRFontsCSTheme(this, this.Pr.RFonts.CSTheme, _sValue, this.private_IsCollPrChangeMine())); this.Pr.RFonts.CSTheme = _sValue; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.SetRFontsEastAsiaTheme = function(sValue) { var _sValue = (!sValue ? undefined : sValue); if (_sValue !== this.Pr.RFonts.EastAsiaTheme) { AscCommon.History.Add(new CChangesRunRFontsEastAsiaTheme(this, this.Pr.RFonts.EastAsiaTheme, _sValue, this.private_IsCollPrChangeMine())); this.Pr.RFonts.EastAsiaTheme = _sValue; this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Set_Lang = function(Value) { var OldValue = this.Pr.Lang; this.Pr.Lang = new CLang(); if ( undefined != Value ) this.Pr.Lang.Set_FromObject( Value ); AscCommon.History.Add(new CChangesRunLang(this, OldValue, this.Pr.Lang, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); }; ParaRun.prototype.Set_Lang2 = function(Lang) { if ( undefined != Lang ) { if ( undefined != Lang.Bidi ) this.Set_Lang_Bidi( Lang.Bidi ); if ( undefined != Lang.EastAsia ) this.Set_Lang_EastAsia( Lang.EastAsia ); if ( undefined != Lang.Val ) this.Set_Lang_Val( Lang.Val ); this.private_UpdateSpellChecking(); } }; ParaRun.prototype.Set_Lang_Bidi = function(Value) { if ( Value !== this.Pr.Lang.Bidi ) { var OldValue = this.Pr.Lang.Bidi; this.Pr.Lang.Bidi = Value; AscCommon.History.Add(new CChangesRunLangBidi(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Set_Lang_EastAsia = function(Value) { if ( Value !== this.Pr.Lang.EastAsia ) { var OldValue = this.Pr.Lang.EastAsia; this.Pr.Lang.EastAsia = Value; AscCommon.History.Add(new CChangesRunLangEastAsia(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Set_Lang_Val = function(Value) { if ( Value !== this.Pr.Lang.Val ) { var OldValue = this.Pr.Lang.Val; this.Pr.Lang.Val = Value; AscCommon.History.Add(new CChangesRunLangVal(this, OldValue, Value, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.Set_Shd = function(Shd) { if ( (undefined === this.Pr.Shd && undefined === Shd) || (undefined !== this.Pr.Shd && undefined !== Shd && true === this.Pr.Shd.Compare( Shd ) ) ) return; var OldShd = this.Pr.Shd; if ( undefined !== Shd ) { this.Pr.Shd = new CDocumentShd(); this.Pr.Shd.Set_FromObject( Shd ); } else this.Pr.Shd = undefined; AscCommon.History.Add(new CChangesRunShd(this, OldShd, this.Pr.Shd, this.private_IsCollPrChangeMine())); this.Recalc_CompiledPr(false); this.private_UpdateTrackRevisionOnChangeTextPr(true); }; ParaRun.prototype.SetLigatures = function(nType) { if (this.Pr.Ligatures === nType) return; AscCommon.History.Add(new CChangesRunLigatures(this, this.Pr.Ligatures, nType)); this.Pr.Ligatures = nType; this.Recalc_CompiledPr(true); this.private_UpdateShapeText(); this.private_UpdateTrackRevisionOnChangeTextPr(false); }; ParaRun.prototype.IsCS = function() { return this.Get_CompiledPr(false).CS; }; ParaRun.prototype.SetCS = function(isCS) { if (this.Pr.CS === isCS) return; let oChange = new CChangesRunCS(this, this.Pr.CS, isCS); AscCommon.History.Add(oChange); oChange.Redo(); }; ParaRun.prototype.IsRTL = function() { return this.Get_CompiledPr(false).RTL; }; ParaRun.prototype.SetRTL = function(isRTL) { if (this.Pr.RTL === isRTL) return; let oChange = new CChangesRunRTL(this, this.Pr.RTL, isRTL); AscCommon.History.Add(oChange); oChange.Redo(); }; ParaRun.prototype.ApplyComplexScript = function(isCS) { if (isCS && !this.Pr.CS) { this.SetCS(true); this.SetRFontsHint(AscWord.fonthint_CS); if (undefined === this.Pr.BoldCS && undefined !== this.Pr.Bold) this.SetBoldCS(this.Pr.Bold); if (undefined === this.Pr.ItalicCS && undefined !== this.Pr.Italic) this.SetItalicCS(this.Pr.Italic); if (undefined === this.Pr.FontSizeCS && undefined !== this.Pr.FontSize) this.SetFontSizeCS(this.Pr.FontSize); } else if (!isCS && this.Pr.CS) { this.SetCS(undefined); this.SetRFontsHint(undefined); if (undefined === this.Pr.Bold && undefined !== this.Pr.BoldCS) this.SetBold(this.Pr.BoldCS); if (undefined === this.Pr.Italic && undefined !== this.Pr.ItalicCS) this.SetItalic(this.Pr.ItalicCS); if (undefined === this.Pr.FontSize && undefined !== this.Pr.FontSizeCS) this.SetFontSize(this.Pr.FontSizeCS); } }; ParaRun.prototype.IncreaseDecreaseFontSize = function(isIncrease) { let oTextPr = this.Get_CompiledPr(false); this.private_AddCollPrChangeMine(); this.SetFontSizeCS(oTextPr.GetIncDecFontSizeCS(isIncrease)); this.SetFontSize(oTextPr.GetIncDecFontSize(isIncrease)); }; ParaRun.prototype.ApplyFontFamily = function(sFontName) { // let nFontSlot = this.GetFontSlotInRange(0, this.Content.length); // if (nFontSlot & AscWord.fontslot_EastAsia) // this.SetRFontsEastAsia({Name : sFontName, Index : -1}); // https://bugzilla.onlyoffice.com/show_bug.cgi?id=60106 // Пока мы не можем разруливать как в MSWord, потому что у нас нет возможности получать текущую раскладку // и нет события о смене раскладки this.SetRFontsEastAsia({Name : sFontName, Index : -1}); //------------------------------------------------------------------------------------------------------------------ this.SetRFontsAscii({Name : sFontName, Index : -1}); this.SetRFontsHAnsi({Name : sFontName, Index : -1}); this.SetRFontsCS({Name : sFontName, Index : -1}); this.SetRFontsAsciiTheme(undefined); this.SetRFontsHAnsiTheme(undefined); this.SetRFontsCSTheme(undefined); }; //----------------------------------------------------------------------------------- // Undo/Redo функции //----------------------------------------------------------------------------------- ParaRun.prototype.Check_HistoryUninon = function(Data1, Data2) { return (AscDFH.historyitem_ParaRun_AddItem === Data1.Type && AscDFH.historyitem_ParaRun_AddItem === Data2.Type && 1 === Data1.Items.length && 1 === Data2.Items.length && Data1.Pos === Data2.Pos - 1 && ((Data1.Items[0].IsText() && Data2.Items[0].IsText()) || (Data1.Items[0].IsSpace() && Data2.Items[0].IsSpace()))); }; //----------------------------------------------------------------------------------- // Функции для совместного редактирования //----------------------------------------------------------------------------------- ParaRun.prototype.Write_ToBinary2 = function(Writer) { Writer.WriteLong( AscDFH.historyitem_type_ParaRun ); // Long : Type // String : Id // String : Paragraph Id // Variable : CTextPr // Long : ReviewType // Bool : isUndefined ReviewInfo // ->false : ReviewInfo // Long : Количество элементов // Array of variable : массив с элементами Writer.WriteLong(this.Type); var ParagraphToWrite, PrToWrite, ContentToWrite; if(this.StartState) { ParagraphToWrite = this.StartState.Paragraph; PrToWrite = this.StartState.Pr; ContentToWrite = this.StartState.Content; } else { ParagraphToWrite = this.Paragraph; PrToWrite = this.Pr; ContentToWrite = this.Content; } Writer.WriteString2( this.Id ); Writer.WriteString2( null !== ParagraphToWrite && undefined !== ParagraphToWrite ? ParagraphToWrite.Get_Id() : "" ); PrToWrite.Write_ToBinary( Writer ); if (this.ReviewInfo) { Writer.WriteBool(false); this.ReviewInfo.WriteToBinary(Writer); } else { Writer.WriteBool(true); } var Count = ContentToWrite.length; Writer.WriteLong( Count ); for ( var Index = 0; Index < Count; Index++ ) { var Item = ContentToWrite[Index]; Item.Write_ToBinary( Writer ); } }; ParaRun.prototype.Read_FromBinary2 = function(Reader) { // Long : Type // String : Id // String : Paragraph Id // Variable : CTextPr // Long : ReviewType // Bool : isUndefined ReviewInfo // ->false : ReviewInfo // Long : Количество элементов // Array of variable : массив с элементами this.Type = Reader.GetLong(); this.Id = Reader.GetString2(); this.Paragraph = g_oTableId.Get_ById( Reader.GetString2() ); this.Pr = new CTextPr(); this.Pr.Read_FromBinary( Reader ); if (!Reader.GetBool()) this.ReviewInfo = AscWord.ReviewInfo.fromBinary(Reader); if (para_Math_Run == this.Type) { this.MathPrp = new CMPrp(); this.size = new CMathSize(); this.pos = new CMathPosition(); } if(undefined !== editor && true === editor.isDocumentEditor) { var Count = Reader.GetLong(); this.Content = []; for ( var Index = 0; Index < Count; Index++ ) { var Element = AscWord.ReadRunElementFromBinary(Reader); if ( null !== Element ) this.Content.push( Element ); } } }; ParaRun.prototype.Clear_CollaborativeMarks = function() { this.CollaborativeMarks.Clear(); this.CollPrChangeColor = null; }; ParaRun.prototype.private_AddCollPrChangeMine = function() { this.CollPrChangeMine = true; this.CollPrChangeColor = null; }; ParaRun.prototype.private_IsCollPrChangeMine = function() { if (true === this.CollPrChangeMine) return true; return false; }; ParaRun.prototype.setCollPrChangeColor = function(color) { this.CollPrChangeColor = color; AscCommon.CollaborativeEditing.Add_ChangedClass(this); }; ParaRun.prototype.getCollPrChangeColor = function() { return this.CollPrChangeColor; }; /** * Специальная функция-заглушка, добавляем элементы за знаком конца параграфа, для поддержки разделителей, лежащих * между параграфами * @param {AscWord.CRunElementBase} oElement */ ParaRun.prototype.AddAfterParaEnd = function(oElement) { this.State.ContentPos = this.Content.length; this.AddToContent(this.State.ContentPos, oElement); }; /** * Специальная функция очищающая метки переноса во время рецензирования * @param {AscWord.CTrackRevisionsManager} oTrackManager */ ParaRun.prototype.RemoveTrackMoveMarks = function(oTrackManager) { var oTrackMove = oTrackManager.GetProcessTrackMove(); var sMoveId = oTrackMove.GetMoveId(); var isFrom = oTrackMove.IsFrom(); for (var nPos = this.Content.length - 1; nPos >= 0; --nPos) { var oItem = this.Content[nPos]; if (para_RevisionMove === oItem.Type) { if (sMoveId === oItem.GetMarkId()) { if (isFrom === oItem.IsFrom()) this.RemoveFromContent(nPos, 1, true); } else { oTrackMove.RegisterOtherMove(oItem.GetMarkId()); } } } }; ParaRun.prototype.IsContainMathOperators = function () { for (let i = 0; i < this.Content.length; i++) { let oCurrentMathText = this.Content[i]; let strOperator = String.fromCharCode(oCurrentMathText.value); let isNamesOFLiteralsOperator = AscMath.MathLiterals.operator.SearchU(strOperator); if (oCurrentMathText.IsBreakOperator() || isNamesOFLiteralsOperator) return true; } return false; }; ParaRun.prototype.IsContainSpaces = function () { for (let i = 0; i < this.Content.length; i++) { let oCurrentMathText = this.Content[i]; let strSpace = String.fromCharCode(oCurrentMathText.value); let isSpace = AscMath.MathLiterals.space.SearchU(strSpace); if (isSpace) return true; } return false; } ParaRun.prototype.IsContainNormalText = function() { for (let i = 0; i < this.Content.length; i++) { let oCurrentMathText = this.Content[i]; if (!oCurrentMathText.IsBreakOperator()) return true; } return false; } ParaRun.prototype.private_RecalcCtrPrp = function() { if (para_Math_Run === this.Type && undefined !== this.Parent && null !== this.Parent && null !== this.Parent.ParaMath) this.Parent.ParaMath.SetRecalcCtrPrp(this); }; function CParaRunSelection() { this.Use = false; this.StartPos = 0; this.EndPos = 0; } function CParaRunState() { this.Selection = new CParaRunSelection(); this.ContentPos = 0; } function CParaRunRecalcInfo() { this.TextPr = true; // Нужно ли пересчитать скомпилированные настройки this.Measure = true; // Нужно ли перемерять элементы this.Recalc = true; // Нужно ли пересчитывать (только если текстовый ран) this.MeasurePositions = []; // Массив позиций элементов, которые нужно пересчитать // Далее идут параметры, которые выставляются после пересчета данного Range, такие как пересчитывать ли нумерацию this.NumberingItem = null; this.NumberingUse = false; // Используется ли нумерация в данном ране this.NumberingAdd = true; // Нужно ли в следующем ране использовать нумерацию } CParaRunRecalcInfo.prototype.Reset = function() { this.TextPr = true; this.Measure = true; this.Recalc = true; this.MeasurePositions = []; }; /** * Вызываем данную функцию после пересчета элементов рана */ CParaRunRecalcInfo.prototype.ResetMeasure = function() { this.Measure = false; this.MeasurePositions = []; }; /** * Проверяем нужен ли пересчет элементов рана * @return {boolean} */ CParaRunRecalcInfo.prototype.IsMeasureNeed = function() { return (this.Measure || this.MeasurePositions.length > 0); }; /** * Регистрируем добавление элемента в ран * @param nPos {number} */ CParaRunRecalcInfo.prototype.OnAdd = function(nPos) { if (this.Measure) return; for (var nIndex = 0, nCount = this.MeasurePositions.length; nIndex < nCount; ++nIndex) { if (this.MeasurePositions[nIndex] >= nPos) this.MeasurePositions[nIndex]++; } this.MeasurePositions.push(nPos); }; /** * Регистрируем удаление элементов из рана * @param nPos {number} * @param nCount {number} */ CParaRunRecalcInfo.prototype.OnRemove = function(nPos, nCount) { if (this.Measure) return; for (var nIndex = 0, nLen = this.MeasurePositions.length; nIndex < nLen; ++nIndex) { if (nPos <= this.MeasurePositions[nIndex] && this.MeasurePositions[nIndex] <= nPos + nCount - 1) { this.MeasurePositions.splice(nIndex, 1); nIndex--; } else if (this.MeasurePositions[nIndex] >= nPos + nCount) { this.MeasurePositions[nIndex] -= nCount; } } }; function CParaRunRange(StartPos, EndPos) { this.StartPos = StartPos; // Начальная позиция в контенте, с которой начинается данный отрезок this.EndPos = EndPos; // Конечная позиция в контенте, на которой заканчивается данный отрезок (перед которой) } function CParaRunLine() { this.Ranges = []; this.Ranges[0] = new CParaRunRange( 0, 0 ); this.RangesLength = 0; } CParaRunLine.prototype.addRange = function(RangeIndex, StartPos, EndPos) { if (0 !== RangeIndex) { this.Ranges[RangeIndex] = new CParaRunRange(StartPos, EndPos); this.RangesLength = RangeIndex + 1; } else { this.Ranges[0].StartPos = StartPos; this.Ranges[0].EndPos = EndPos; this.RangesLength = 1; } if (this.Ranges.length > this.RangesLength) this.Ranges.legth = this.RangesLength; }; CParaRunLine.prototype = { Copy : function() { var NewLine = new CParaRunLine(); NewLine.RangesLength = this.RangesLength; for ( var CurRange = 0; CurRange < this.RangesLength; CurRange++ ) { var Range = this.Ranges[CurRange]; NewLine.Ranges[CurRange] = new CParaRunRange( Range.StartPos, Range.EndPos ); } return NewLine; }, Compare : function(OtherLine, CurRange) { // Сначала проверим наличие данного отрезка в обеих строках if ( this.RangesLength <= CurRange || OtherLine.RangesLength <= CurRange ) return false; var OtherRange = OtherLine.Ranges[CurRange]; var ThisRange = this.Ranges[CurRange]; if ( OtherRange.StartPos !== ThisRange.StartPos || OtherRange.EndPos !== ThisRange.EndPos ) return false; return true; } }; // Метка о конце или начале изменений пришедших от других соавторов документа var pararun_CollaborativeMark_Start = 0x00; var pararun_CollaborativeMark_End = 0x01; function CParaRunCollaborativeMark(Pos, Type) { this.Pos = Pos; this.Type = Type; } function FontSize_IncreaseDecreaseValue(bIncrease, Value) { // Закон изменения размеров : // 1. Если значение меньше 8, тогда мы увеличиваем/уменьшаем по 1 (от 1 до 8) // 2. Если значение больше 72, тогда мы увеличиваем/уменьшаем по 10 (от 80 до бесконечности // 3. Если значение в отрезке [8,72], тогда мы переходим по следующим числам 8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72 var Sizes = [8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72]; var NewValue = Value; if ( true === bIncrease ) { if ( Value < Sizes[0] ) { if ( Value >= Sizes[0] - 1 ) NewValue = Sizes[0]; else NewValue = Math.floor(Value + 1); } else if ( Value >= Sizes[Sizes.length - 1] ) { NewValue = Math.min( 300, Math.floor( Value / 10 + 1 ) * 10 ); } else { for ( var Index = 0; Index < Sizes.length; Index++ ) { if ( Value < Sizes[Index] ) { NewValue = Sizes[Index]; break; } } } } else { if ( Value <= Sizes[0] ) { NewValue = Math.max( Math.floor( Value - 1 ), 1 ); } else if ( Value > Sizes[Sizes.length - 1] ) { if ( Value <= Math.floor( Sizes[Sizes.length - 1] / 10 + 1 ) * 10 ) NewValue = Sizes[Sizes.length - 1]; else NewValue = Math.floor( Math.ceil(Value / 10) - 1 ) * 10; } else { for ( var Index = Sizes.length - 1; Index >= 0; Index-- ) { if ( Value > Sizes[Index] ) { NewValue = Sizes[Index]; break; } } } } return NewValue; } function CRunCollaborativeMarks() { this.Ranges = []; this.DrawingObj = {}; } CRunCollaborativeMarks.prototype = { Add : function(PosS, PosE, Color) { var Count = this.Ranges.length; for ( var Index = 0; Index < Count; Index++ ) { var Range = this.Ranges[Index]; if ( PosS > Range.PosE ) continue; else if ( PosS >= Range.PosS && PosS <= Range.PosE && PosE >= Range.PosS && PosE <= Range.PosE ) { if ( true !== Color.Compare(Range.Color) ) { var _PosE = Range.PosE; Range.PosE = PosS; this.Ranges.splice( Index + 1, 0, new CRunCollaborativeRange(PosS, PosE, Color) ); this.Ranges.splice( Index + 2, 0, new CRunCollaborativeRange(PosE, _PosE, Range.Color) ); } return; } else if ( PosE < Range.PosS ) { this.Ranges.splice( Index, 0, new CRunCollaborativeRange(PosS, PosE, Color) ); return; } else if ( PosS < Range.PosS && PosE > Range.PosE ) { Range.PosS = PosS; Range.PosE = PosE; Range.Color = Color; return; } else if ( PosS < Range.PosS ) // && PosE <= Range.PosE ) { if ( true === Color.Compare(Range.Color) ) Range.PosS = PosS; else { Range.PosS = PosE; this.Ranges.splice( Index, 0, new CRunCollaborativeRange(PosS, PosE, Color) ); } return; } else //if ( PosS >= Range.PosS && PosE > Range.Pos.E ) { if ( true === Color.Compare(Range.Color) ) Range.PosE = PosE; else { Range.PosE = PosS; this.Ranges.splice( Index + 1, 0, new CRunCollaborativeRange(PosS, PosE, Color) ); } return; } } this.Ranges.push( new CRunCollaborativeRange(PosS, PosE, Color) ); }, Update_OnAdd : function(Pos) { var Count = this.Ranges.length; for ( var Index = 0; Index < Count; Index++ ) { var Range = this.Ranges[Index]; if ( Pos <= Range.PosS ) { Range.PosS++; Range.PosE++; } else if ( Pos > Range.PosS && Pos < Range.PosE ) { var NewRange = new CRunCollaborativeRange( Pos + 1, Range.PosE + 1, Range.Color.Copy() ); this.Ranges.splice( Index + 1, 0, NewRange ); Range.PosE = Pos; Count++; Index++; } //else if ( Pos < Range.PosE ) // Range.PosE++; } }, Update_OnRemove : function(Pos, Count) { var Len = this.Ranges.length; for ( var Index = 0; Index < Len; Index++ ) { var Range = this.Ranges[Index]; var PosE = Pos + Count; if ( Pos < Range.PosS ) { if ( PosE <= Range.PosS ) { Range.PosS -= Count; Range.PosE -= Count; } else if ( PosE >= Range.PosE ) { this.Ranges.splice( Index, 1 ); Len--; Index--;continue; } else { Range.PosS = Pos; Range.PosE -= Count; } } else if ( Pos >= Range.PosS && Pos < Range.PosE ) { if ( PosE >= Range.PosE ) Range.PosE = Pos; else Range.PosE -= Count; } else continue; } }, Clear : function() { this.Ranges = []; }, Init_Drawing : function() { this.DrawingObj = {}; var Count = this.Ranges.length; for ( var CurPos = 0; CurPos < Count; CurPos++ ) { var Range = this.Ranges[CurPos]; for ( var Pos = Range.PosS; Pos < Range.PosE; Pos++ ) this.DrawingObj[Pos] = Range.Color; } }, Check : function(Pos) { if ( undefined !== this.DrawingObj[Pos] ) return this.DrawingObj[Pos]; return null; } }; function CRunCollaborativeRange(PosS, PosE, Color) { this.PosS = PosS; this.PosE = PosE; this.Color = Color; } ParaRun.prototype.Math_SetPosition = function(pos, PosInfo) { var Line = PosInfo.CurLine, Range = PosInfo.CurRange; var CurLine = Line - this.StartLine; var CurRange = ( 0 === CurLine ? Range - this.StartRange : Range ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); // запомним позицию для recalculateCursorPosition, когда Run пустой this.pos.x = pos.x; this.pos.y = pos.y; for(var Pos = StartPos; Pos < EndPos; Pos++) { var Item = this.Content[Pos]; if(PosInfo.DispositionOpers !== null && Item.Type == para_Math_BreakOperator) { PosInfo.DispositionOpers.push(pos.x + Item.GapLeft); } this.Content[Pos].setPosition(pos); pos.x += this.Content[Pos].GetWidthVisible(); // GetWidth => GetWidthVisible // GetWidthVisible - Width + Gaps с учетом настроек состояния } }; ParaRun.prototype.Math_Get_StartRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bStartLine) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var Pos = this.State.ContentPos; var Result = true; if(bStartLine || StartPos < Pos) { SearchPos.Pos.Update(StartPos, Depth); } else { Result = false; } return Result; }; ParaRun.prototype.Math_Get_EndRangePos = function(_CurLine, _CurRange, SearchPos, Depth, bEndLine) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var Pos = this.State.ContentPos; var Result = true; if(bEndLine || Pos < EndPos) { SearchPos.Pos.Update(EndPos, Depth); } else { Result = false; } return Result; }; ParaRun.prototype.Math_Is_End = function(_CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); return EndPos == this.Content.length; }; ParaRun.prototype.IsEmptyRange = function(_CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); return StartPos == EndPos; }; ParaRun.prototype.Recalculate_Range_OneLine = function(PRS, ParaPr, Depth) { // данная функция используется только для мат объектов, которые на строки не разбиваются // AscWord.CRunText (ParagraphContent.js) // для настройки TextPr // Measure // FontClassification.js // Get_FontClass var Lng = this.Content.length; var CurLine = PRS.Line - this.StartLine; var CurRange = ( 0 === CurLine ? PRS.Range - this.StartRange : PRS.Range ); // обновляем позиции start и end для Range var RangeStartPos = this.protected_AddRange(CurLine, CurRange); var RangeEndPos = Lng; this.Math_RecalculateContent(PRS); this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos); }; ParaRun.prototype.Math_RecalculateContent = function(PRS) { var WidthPoints = this.Parent.Get_WidthPoints(); this.bEqArray = this.Parent.IsEqArray(); var ascent = 0, descent = 0, width = 0; this.Recalculate_MeasureContent(); var Lng = this.Content.length; for(var i = 0 ; i < Lng; i++) { var Item = this.Content[i]; var size = Item.size, Type = Item.Type; var WidthItem = Item.GetWidthVisible(); // GetWidth => GetWidthVisible // GetWidthVisible - Width + Gaps с учетом настроек состояния width += WidthItem; if(ascent < size.ascent) ascent = size.ascent; if (descent < size.height - size.ascent) descent = size.height - size.ascent; if(this.bEqArray) { if(Type === para_Math_Ampersand && true === Item.IsAlignPoint()) { WidthPoints.AddNewAlignRange(); } else { WidthPoints.UpdatePoint(WidthItem); } } } this.size.width = width; this.size.ascent = ascent; this.size.height = ascent + descent; }; ParaRun.prototype.Math_Set_EmptyRange = function(_CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange); var RangeStartPos = this.protected_AddRange(CurLine, CurRange); var RangeEndPos = RangeStartPos; this.protected_FillRange(CurLine, CurRange, RangeStartPos, RangeEndPos); }; // в этой функции проставляем состояние Gaps (крайние или нет) для всех операторов, к-ые участвуют в разбиении, чтобы не получилось случайно, что при изменении разбивки формулы на строки произошло, что у оператора не будет проставлен Gap ParaRun.prototype.UpdateOperators = function(_CurLine, _CurRange, bEmptyGapLeft, bEmptyGapRight) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); for(var Pos = StartPos; Pos < EndPos; Pos++) { var _bEmptyGapLeft = bEmptyGapLeft && Pos == StartPos, _bEmptyGapRight = bEmptyGapRight && Pos == EndPos - 1; this.Content[Pos].Update_StateGapLeft(_bEmptyGapLeft); this.Content[Pos].Update_StateGapRight(_bEmptyGapRight); } }; ParaRun.prototype.Math_Apply_Style = function(Value) { if(Value !== this.MathPrp.sty) { var OldValue = this.MathPrp.sty; this.MathPrp.sty = Value; AscCommon.History.Add(new CChangesRunMathStyle(this, OldValue, Value)); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); } }; ParaRun.prototype.IsNormalText = function() { var comp_MPrp = this.MathPrp.GetCompiled_ScrStyles(); return comp_MPrp.nor === true; }; ParaRun.prototype.getPropsForWrite = function() { var prRPr = null, wRPrp = null; if(this.Paragraph && false === this.Paragraph.bFromDocument){ prRPr = this.Pr.Copy(); } else{ wRPrp = this.Pr.Copy(); } var mathRPrp = this.MathPrp.Copy(); return {wRPrp: wRPrp, mathRPrp: mathRPrp, prRPrp: prRPr}; }; ParaRun.prototype.GetMathPr = function(isCopy) { if (para_Math_Run === this.Type) { if (isCopy) return this.MathPrp.Copy(); else return this.MathPrp; } return null; }; ParaRun.prototype.Math_PreRecalc = function(Parent, ParaMath, ArgSize, RPI, GapsInfo) { this.Parent = Parent; this.Paragraph = ParaMath.Paragraph; var FontSize = this.Get_CompiledPr(false).FontSize; if(RPI.bChangeInline) this.RecalcInfo.Measure = true; // нужно сделать пересчет элементов, например для дроби, т.к. ArgSize у внутренних контентов будет другой => размер if(RPI.bCorrect_ConvertFontSize) // изменение FontSize после конвертации из старого формата в новый { var FontKoef; if(ArgSize == -1 || ArgSize == -2) { var Pr = new CTextPr(); if(this.Pr.FontSize !== null && this.Pr.FontSize !== undefined) { FontKoef = MatGetKoeffArgSize(this.Pr.FontSize, ArgSize); Pr.FontSize = (((this.Pr.FontSize/FontKoef * 2 + 0.5) | 0) / 2); this.RecalcInfo.TextPr = true; this.RecalcInfo.Measure = true; } if(this.Pr.FontSizeCS !== null && this.Pr.FontSizeCS !== undefined) { FontKoef = MatGetKoeffArgSize( this.Pr.FontSizeCS, ArgSize); Pr.FontSizeCS = (((this.Pr.FontSizeCS/FontKoef * 2 + 0.5) | 0) / 2); this.RecalcInfo.TextPr = true; this.RecalcInfo.Measure = true; } this.Apply_Pr(Pr); } } for (var Pos = 0 ; Pos < this.Content.length; Pos++ ) { if( !this.Content[Pos].IsAlignPoint() ) GapsInfo.setGaps(this.Content[Pos], FontSize); this.Content[Pos].PreRecalc(this, ParaMath); this.Content[Pos].SetUpdateGaps(false); } }; ParaRun.prototype.Math_GetRealFontSize = function(FontSize) { var RealFontSize = FontSize ; if(FontSize !== null && FontSize !== undefined) { var ArgSize = this.Parent.Compiled_ArgSz.value; RealFontSize = FontSize*MatGetKoeffArgSize(FontSize, ArgSize); } return RealFontSize; }; ParaRun.prototype.Math_GetFontSize = function(fromBegin) { let compiledPr = this.Get_CompiledPr(false); let fontSize = compiledPr.FontSize; if (this.Content.length > 0) { let runItem = this.Content[fromBegin ? 0 : this.Content.length - 1]; fontSize = runItem.IsCS() ? compiledPr.FontSizeCS : compiledPr.FontSize; } return this.Math_GetRealFontSize(fontSize); }; ParaRun.prototype.Math_EmptyRange = function(_CurLine, _CurRange) // до пересчета нужно узнать будет ли данный Run пустым или нет в данном Range, необходимо для того, чтобы выставить wrapIndent { var bEmptyRange = true; var Lng = this.Content.length; if(Lng > 0) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); bEmptyRange = this.protected_GetPrevRangeEndPos(CurLine, CurRange) >= Lng; } return bEmptyRange; }; ParaRun.prototype.Math_UpdateGaps = function(_CurLine, _CurRange, GapsInfo) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var FontSize = this.Get_CompiledPr(false).FontSize; for(var Pos = StartPos; Pos < EndPos; Pos++) { GapsInfo.updateCurrentObject(this.Content[Pos], FontSize); var bUpdateCurrent = this.Content[Pos].IsNeedUpdateGaps(); if(bUpdateCurrent || GapsInfo.bUpdate) { GapsInfo.updateGaps(); } GapsInfo.bUpdate = bUpdateCurrent; this.Content[Pos].SetUpdateGaps(false); } }; ParaRun.prototype.Math_Can_ModidyForcedBreak = function(Pr, bStart, bEnd) { var Pos = this.Math_GetPosForcedBreak(bStart, bEnd); if(Pos !== null) { if(this.MathPrp.IsBreak()) { Pr.Set_DeleteForcedBreak(); } else { Pr.Set_InsertForcedBreak(); } } }; ParaRun.prototype.Math_GetPosForcedBreak = function(bStart, bEnd) { var ResultPos = null; if(this.Content.length > 0) { var StartPos = this.Selection.StartPos, EndPos = this.Selection.EndPos, bSelect = this.Selection.Use; if(StartPos > EndPos) { StartPos = this.Selection.EndPos; EndPos = this.Selection.StartPos; } var bCheckTwoItem = bSelect == false || (bSelect == true && EndPos == StartPos), bCheckOneItem = bSelect == true && EndPos - StartPos == 1; if(bStart) { ResultPos = this.Content[0].Type == para_Math_BreakOperator ? 0 : ResultPos; } else if(bEnd) { var lastPos = this.Content.length - 1; ResultPos = this.Content[lastPos].Type == para_Math_BreakOperator ? lastPos : ResultPos; } else if(bCheckTwoItem) { var Pos = bSelect == false ? this.State.ContentPos : StartPos; var bPrevBreakOperator = Pos > 0 ? this.Content[Pos - 1].Type == para_Math_BreakOperator : false, bCurrBreakOperator = Pos < this.Content.length ? this.Content[Pos].Type == para_Math_BreakOperator : false; if(bCurrBreakOperator) { ResultPos = Pos } else if(bPrevBreakOperator) { ResultPos = Pos - 1; } } else if(bCheckOneItem) { if(this.Content[StartPos].Type == para_Math_BreakOperator) { ResultPos = StartPos; } } } return ResultPos; }; ParaRun.prototype.Check_ForcedBreak = function(bStart, bEnd) { return this.Math_GetPosForcedBreak(bStart, bEnd) !== null; }; ParaRun.prototype.Set_MathForcedBreak = function(bInsert, alnAt) { if (bInsert == true && false == this.MathPrp.IsBreak()) { AscCommon.History.Add(new CChangesRunMathForcedBreak(this, true, alnAt)); this.MathPrp.Insert_ForcedBreak(alnAt); } else if (bInsert == false && true == this.MathPrp.IsBreak()) { AscCommon.History.Add(new CChangesRunMathForcedBreak(this, false, this.MathPrp.Get_AlnAt())); this.MathPrp.Delete_ForcedBreak(); } }; ParaRun.prototype.Math_SplitRunForcedBreak = function() { var Pos = this.Math_GetPosForcedBreak(); var NewRun = null; if(Pos != null && Pos > 0) // разбиваем Run на два { NewRun = this.Split_Run(Pos); } return NewRun; }; ParaRun.prototype.UpdLastElementForGaps = function(_CurLine, _CurRange, GapsInfo) { var CurLine = _CurLine - this.StartLine; var CurRange = ( 0 === CurLine ? _CurRange - this.StartRange : _CurRange ); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); var FontSize = this.Get_CompiledPr(false).FontSize; var Last = this.Content[EndPos]; GapsInfo.updateCurrentObject(Last, FontSize); }; ParaRun.prototype.IsPlaceholder = function() { return this.Content.length == 1 && this.Content[0].IsPlaceholder && this.Content[0].IsPlaceholder(); }; ParaRun.prototype.AddMathPlaceholder = function() { var oPlaceholder = new CMathText(false); oPlaceholder.SetPlaceholder(); this.Add_ToContent(0, oPlaceholder, false); // TODO: Расчет стилей разный для плейсхолдера и для текса (разобраться почему) this.Recalc_CompiledPr(); }; ParaRun.prototype.RemoveMathPlaceholder = function() { for (var nPos = 0; nPos < this.Content.length; ++nPos) { if (para_Math_Placeholder === this.Content[nPos].Type) { this.Remove_FromContent(nPos, 1, true); nPos--; } } // TODO: Расчет стилей разный для плейсхолдера и для текса (разобраться почему) this.Recalc_CompiledPr(); }; ParaRun.prototype.ProcessingOldEquationConvert = function() { for (let nPos = 0; nPos < this.Content.length; nPos++) { let oCurrentCMathText = this.Content[nPos]; if (oCurrentCMathText.value === 8202 || oCurrentCMathText.value === 8201) { this.Remove_FromContent(nPos, 1); nPos--; } else if (oCurrentCMathText.value === 8203) { oCurrentCMathText.add("⥂".charCodeAt(0)); } else if (oCurrentCMathText.value === 8197) { oCurrentCMathText.add(" ".charCodeAt(0)); //3/MSP } } } ParaRun.prototype.Set_MathPr = function(MPrp) { var OldValue = this.MathPrp; this.MathPrp.Set_Pr(MPrp); AscCommon.History.Add(new CChangesRunMathPrp(this, OldValue, this.MathPrp)); this.Recalc_CompiledPr(true); this.private_UpdateTrackRevisionOnChangeTextPr(true); }; ParaRun.prototype.Set_MathTextPr2 = function(TextPr, MathPr) { this.Set_Pr(TextPr.Copy()); this.Set_MathPr(MathPr.Copy()); }; ParaRun.prototype.IsAccent = function() { return this.Parent.IsAccent(); }; ParaRun.prototype.GetCompiled_ScrStyles = function() { return this.MathPrp.GetCompiled_ScrStyles(); }; ParaRun.prototype.IsEqArray = function() { return this.Parent.IsEqArray(); }; ParaRun.prototype.IsForcedBreak = function() { var bForcedBreak = false; if(this.ParaMath!== null) bForcedBreak = false == this.ParaMath.Is_Inline() && true == this.MathPrp.IsBreak(); return bForcedBreak; }; ParaRun.prototype.Is_StartForcedBreakOperator = function() { var bStartOperator = this.Content.length > 0 && this.Content[0].Type == para_Math_BreakOperator; return true == this.IsForcedBreak() && true == bStartOperator; }; ParaRun.prototype.Get_AlignBrk = function(_CurLine, bBrkBefore) { // null - break отсутствует // 0 - break присутствует, alnAt = undefined // Number = break присутствует, alnAt = Number // если оператор находится в конце строки и по этому оператору осушествляется принудительный перенос (Forced) // тогда StartPos = 0, EndPos = 1 (для предыдущей строки), т.к. оператор с принудительным переносом всегда должен находится в начале Run var CurLine = _CurLine - this.StartLine; var AlnAt = null; if(CurLine > 0) { var RangesCount = this.protected_GetRangesCount(CurLine - 1); var StartPos = this.protected_GetRangeStartPos(CurLine - 1, RangesCount - 1); var EndPos = this.protected_GetRangeEndPos(CurLine - 1, RangesCount - 1); var bStartBreakOperator = bBrkBefore == true && StartPos == 0 && EndPos == 0; var bEndBreakOperator = bBrkBefore == false && StartPos == 0 && EndPos == 1; if(bStartBreakOperator || bEndBreakOperator) { AlnAt = false == this.Is_StartForcedBreakOperator() ? null : this.MathPrp.Get_AlignBrk(); } } return AlnAt; }; ParaRun.prototype.Math_Is_InclineLetter = function() { var result = false; if(this.Content.length == 1) result = this.Content[0].Is_InclineLetter(); return result; }; ParaRun.prototype.GetMathTextPrForMenu = function() { var TextPr = new CTextPr(); if(this.IsPlaceholder()) TextPr.Merge(this.Parent.GetCtrPrp()); TextPr.Merge(this.Pr); var MathTextPr = this.MathPrp.Copy(); var BI = MathTextPr.GetBoldItalic(); TextPr.Italic = BI.Italic; TextPr.Bold = BI.Bold; return TextPr; }; ParaRun.prototype.ToMathRun = function() { if (this.IsMathRun()) return this.Copy(); let oRun = new ParaRun(undefined, true); for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { let oMathItem = this.Content[nPos].ToMathElement(); if (oMathItem) oRun.Add(oMathItem); } oRun.ApplyPr(this.GetDirectTextPr()); return oRun; }; ParaRun.prototype.ApplyPoints = function(PointsInfo) { if(this.Parent.IsEqArray()) { this.size.width = 0; for(var Pos = 0; Pos < this.Content.length; Pos++) { var Item = this.Content[Pos]; if(Item.Type === para_Math_Ampersand && true === Item.IsAlignPoint()) { PointsInfo.NextAlignRange(); Item.size.width = PointsInfo.GetAlign(); } this.size.width += this.Content[Pos].GetWidthVisible(); // GetWidth => GetWidthVisible // GetWidthVisible - Width + Gaps с учетом настроек состояния } } }; ParaRun.prototype.IsShade = function() { var oShd = this.Get_CompiledPr(false).Shd; return !(oShd === undefined || c_oAscShdNil === oShd.Value); }; ParaRun.prototype.Get_RangesByPos = function(Pos) { var Ranges = []; var LinesCount = this.protected_GetLinesCount(); for (var LineIndex = 0; LineIndex < LinesCount; LineIndex++) { var RangesCount = this.protected_GetRangesCount(LineIndex); for (var RangeIndex = 0; RangeIndex < RangesCount; RangeIndex++) { var StartPos = this.protected_GetRangeStartPos(LineIndex, RangeIndex); var EndPos = this.protected_GetRangeEndPos(LineIndex, RangeIndex); if (StartPos <= Pos && Pos <= EndPos) Ranges.push({Range : (LineIndex === 0 ? RangeIndex + this.StartRange : RangeIndex), Line : LineIndex + this.StartLine}); } } return Ranges; }; ParaRun.prototype.CompareDrawingsLogicPositions = function(CompareObject) { var Drawing1 = CompareObject.Drawing1; var Drawing2 = CompareObject.Drawing2; for (var Pos = 0, Count = this.Content.length; Pos < Count; Pos++) { var Item = this.Content[Pos]; if (Item === Drawing1) { CompareObject.Result = 1; return; } else if (Item === Drawing2) { CompareObject.Result = -1; return; } } }; ParaRun.prototype.GetReviewType = function() { return this.ReviewInfo ? this.ReviewInfo.getType() : reviewtype_Common; }; ParaRun.prototype.GetReviewMoveType = function() { return this.ReviewInfo ? this.ReviewInfo.GetMoveType() : Asc.c_oAscRevisionsMove.NoMove; }; ParaRun.prototype.RemoveReviewMoveType = function() { if (!this.ReviewInfo || Asc.c_oAscRevisionsMove.NoMove === this.ReviewInfo.GetMoveType()) return; let newInfo = this.ReviewInfo.Copy(); newInfo.SetMoveType(Asc.c_oAscRevisionsMove.NoMove); AscCommon.History.Add(new CChangesRunContentReviewInfo(this, this.ReviewInfo, newInfo.Copy())); this.ReviewInfo = newInfo; this.updateTrackRevisions(); }; ParaRun.prototype.GetReviewInfo = function() { return this.ReviewInfo; }; ParaRun.prototype.GetReviewColor = function() { if (this.ReviewInfo) return this.ReviewInfo.Get_Color(); return REVIEW_COLOR; }; /** * Меняем тип рецензирования для данного рана * @param {number} nType * @param {boolean} [isCheckDeleteAdded=false] - нужно ли проверять, что происходит удаление добавленного ранее * @constructor */ ParaRun.prototype.SetReviewType = function(nType, isCheckDeleteAdded) { var oParagraph = this.GetParagraph(); if (this.IsParaEndRun() && oParagraph) { var oParent = oParagraph.GetParent(); if (reviewtype_Common !== nType && !oParagraph.Get_DocumentNext() && oParent && (oParent instanceof CDocument || (oParent instanceof CDocumentContent && oParent.GetParent() instanceof CTableCell))) { return; } } if (nType === this.GetReviewType()) return; let prevType = this.GetReviewType(); let prevInfo = this.ReviewInfo ? this.ReviewInfo.Copy() : undefined; if (reviewtype_Add === prevType && reviewtype_Remove === nType && isCheckDeleteAdded) this.ReviewInfo.SavePrev(prevType); if (!this.ReviewInfo) this.ReviewInfo = new AscWord.ReviewInfo(); this.ReviewInfo.setType(nType); this.ReviewInfo.Update(); if (this.GetLogicDocument() && null !== this.GetLogicDocument().TrackMoveId) this.ReviewInfo.SetMove(Asc.c_oAscRevisionsMove.MoveFrom); AscCommon.History.Add(new CChangesRunContentReviewInfo(this, prevInfo, this.ReviewInfo.Copy())); this.updateTrackRevisions(); }; /** * Меняем тип рецензирования вместе с информацией о рецензента * @param {number} reviewType * @param {AscWord.ReviewInfo} reviewInfo * @param {boolean} [isCheckLastParagraph=true] Нужно ли проверять последний параграф в документе или в ячейке таблицы */ ParaRun.prototype.SetReviewTypeWithInfo = function(reviewType, reviewInfo, isCheckLastParagraph) { var oParagraph = this.GetParagraph(); if (false !== isCheckLastParagraph && this.IsParaEndRun() && oParagraph) { var oParent = oParagraph.GetParent(); if (reviewtype_Common !== reviewType && !oParagraph.Get_DocumentNext() && oParent && (oParent instanceof CDocument || (oParent instanceof CDocumentContent && oParent.GetParent() instanceof CTableCell))) { return; } } if (reviewtype_Common === reviewType) reviewInfo = undefined; else if (!reviewInfo) reviewInfo = new AscWord.ReviewInfo(); if (reviewInfo) reviewInfo.setType(reviewType); AscCommon.History.Add(new CChangesRunContentReviewInfo(this, this.ReviewInfo ? this.ReviewInfo.Copy() : undefined, reviewInfo)); this.ReviewInfo = reviewInfo; this.updateTrackRevisions(); }; ParaRun.prototype.Get_Parent = function() { return this.GetParent(); }; ParaRun.prototype.private_GetPosInParent = function(_Parent) { return this.GetPosInParent(_Parent); }; ParaRun.prototype.Make_ThisElementCurrent = function(bUpdateStates) { if (this.IsUseInDocument()) { this.SetThisElementCurrentInParagraph(); this.Paragraph.Document_SetThisElementCurrent(true === bUpdateStates ? true : false); } }; ParaRun.prototype.SetThisElementCurrent = function() { var ContentPos = this.Paragraph.Get_PosByElement(this); if (!ContentPos) return; var StartPos = ContentPos.Copy(); this.Get_StartPos(StartPos, StartPos.GetDepth() + 1); this.Paragraph.Set_ParaContentPos(StartPos, true, -1, -1, false); this.Paragraph.Document_SetThisElementCurrent(false); }; /** * Устанавливаем курсор параграфа в текущую позицию данного рана */ ParaRun.prototype.SetThisElementCurrentInParagraph = function() { if (!this.Paragraph) return; var oContentPos = this.Paragraph.Get_PosByElement(this); if (!oContentPos) return; oContentPos.Add(this.State.ContentPos); this.Paragraph.Set_ParaContentPos(oContentPos, true, -1, -1, false); }; ParaRun.prototype.GetDocumentPositionForCurrentPosition = function() { let docPos = this.GetDocumentPositionFromObject(); docPos.push({Class : this, Position : this.State.ContentPos}); return docPos; }; ParaRun.prototype.GetAllParagraphs = function(Props, ParaArray) { var ContentLen = this.Content.length; for (var CurPos = 0; CurPos < ContentLen; CurPos++) { if (para_Drawing === this.Content[CurPos].Type) this.Content[CurPos].GetAllParagraphs(Props, ParaArray); } }; ParaRun.prototype.GetAllTables = function(oProps, arrTables) { if (!arrTables) arrTables = []; for (var nCurPos = 0, nLen = this.Content.length; nCurPos < nLen; ++nCurPos) { if (para_Drawing === this.Content[nCurPos].Type) this.Content[nCurPos].GetAllTables(oProps, arrTables); } return arrTables; }; ParaRun.prototype.CheckRevisionsChanges = function(Checker, ContentPos, Depth) { if (this.Is_Empty()) return; if (true !== Checker.Is_ParaEndRun() && true !== Checker.Is_CheckOnlyTextPr()) { var ReviewType = this.GetReviewType(); if (Checker.IsStopAddRemoveChange(ReviewType, this.GetReviewInfo())) { Checker.FlushAddRemoveChange(); ContentPos.Update(0, Depth); if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType) Checker.StartAddRemove(ReviewType, ContentPos, this.GetReviewMoveType()); } if (reviewtype_Add === ReviewType || reviewtype_Remove === ReviewType) { var Text = ""; var ContentLen = this.Content.length; for (var CurPos = 0; CurPos < ContentLen; CurPos++) { var Item = this.Content[CurPos]; var ItemType = Item.Type; switch (ItemType) { case para_Drawing: { Checker.Add_Text(Text); Text = ""; Checker.Add_Drawing(Item); break; } case para_Text : { Text += String.fromCharCode(Item.Value); break; } case para_Math_Text: { Text += String.fromCharCode(Item.getCodeChr()); break; } case para_Space: case para_Tab : { Text += " "; break; } } } Checker.Add_Text(Text); ContentPos.Update(this.Content.length, Depth); Checker.Set_AddRemoveEndPos(ContentPos); Checker.Update_AddRemoveReviewInfo(this.ReviewInfo); } } var HavePrChange = this.HavePrChange(); var DiffPr = this.GetDiffPrChange(); if (HavePrChange !== Checker.HavePrChange() || true !== Checker.ComparePrChange(DiffPr) || this.Pr.ReviewInfo.GetUserId() !== Checker.Get_PrChangeUserId()) { Checker.FlushTextPrChange(); ContentPos.Update(0, Depth); if (true === HavePrChange) { Checker.Start_PrChange(DiffPr, ContentPos); } } if (true === HavePrChange) { ContentPos.Update(this.Content.length, Depth); Checker.SetPrChangeEndPos(ContentPos); Checker.Update_PrChangeReviewInfo(this.Pr.ReviewInfo); } }; ParaRun.prototype.private_UpdateTrackRevisionOnChangeContent = function(bUpdateInfo) { if (reviewtype_Common !== this.GetReviewType()) { this.updateTrackRevisions(); if (true === bUpdateInfo && this.Paragraph && this.Paragraph.LogicDocument && this.Paragraph.bFromDocument && true === this.Paragraph.LogicDocument.IsTrackRevisions() && this.ReviewInfo && true === this.ReviewInfo.IsCurrentUser()) { var OldReviewInfo = this.ReviewInfo.Copy(); this.ReviewInfo.Update(); AscCommon.History.Add(new CChangesRunContentReviewInfo(this, OldReviewInfo, this.ReviewInfo.Copy())); } } }; ParaRun.prototype.private_UpdateTrackRevisionOnChangeTextPr = function(bUpdateInfo) { if (true === this.HavePrChange()) { this.updateTrackRevisions(); if (true === bUpdateInfo && this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument && true === this.Paragraph.LogicDocument.IsTrackRevisions()) { var OldReviewInfo = this.Pr.ReviewInfo.Copy(); this.Pr.ReviewInfo.Update(); AscCommon.History.Add(new CChangesRunPrReviewInfo(this, OldReviewInfo, this.Pr.ReviewInfo.Copy())); } } }; ParaRun.prototype.AcceptRevisionChanges = function(nType, bAll) { if (this.Selection.Use && c_oAscRevisionsChangeType.MoveMarkRemove === nType) return this.RemoveReviewMoveType(); var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(); var ReviewType = this.GetReviewType(); var HavePrChange = this.HavePrChange(); // Нет изменений в данном ране if (reviewtype_Common === ReviewType && true !== HavePrChange) return; var oTrackManager = this.GetLogicDocument() ? this.GetLogicDocument().GetTrackRevisionsManager() : null; var oProcessMove = oTrackManager ? oTrackManager.GetProcessTrackMove() : null; if (true === this.Selection.Use || true === bAll) { var StartPos = this.Selection.StartPos; var EndPos = this.Selection.EndPos; if (StartPos > EndPos) { StartPos = this.Selection.EndPos; EndPos = this.Selection.StartPos; } if (true === bAll) { StartPos = 0; EndPos = this.Content.length; } var CenterRun = null, CenterRunPos = RunPos; if (0 === StartPos && this.Content.length === EndPos) { CenterRun = this; } else if (StartPos > 0 && this.Content.length === EndPos) { CenterRun = this.Split2(StartPos, Parent, RunPos); CenterRunPos = RunPos + 1; } else if (0 === StartPos && this.Content.length > EndPos) { CenterRun = this; this.Split2(EndPos, Parent, RunPos); } else { this.Split2(EndPos, Parent, RunPos); CenterRun = this.Split2(StartPos, Parent, RunPos); CenterRunPos = RunPos + 1; } if (true === HavePrChange && (undefined === nType || c_oAscRevisionsChangeType.TextPr === nType)) { CenterRun.RemovePrChange(); } if (reviewtype_Add === ReviewType && (undefined === nType || c_oAscRevisionsChangeType.TextAdd === nType || (c_oAscRevisionsChangeType.MoveMark === nType && Asc.c_oAscRevisionsMove.NoMove !== this.GetReviewMoveType() && oProcessMove && !oProcessMove.IsFrom() && oProcessMove.GetUserId() === this.GetReviewInfo().GetUserId()))) { CenterRun.SetReviewType(reviewtype_Common); } else if (reviewtype_Remove === ReviewType && (undefined === nType || c_oAscRevisionsChangeType.TextRem === nType || (c_oAscRevisionsChangeType.MoveMark === nType && Asc.c_oAscRevisionsMove.NoMove !== this.GetReviewMoveType() && oProcessMove && oProcessMove.IsFrom() && oProcessMove.GetUserId() === this.GetReviewInfo().GetUserId()))) { Parent.RemoveFromContent(CenterRunPos, 1); CenterRun.ClearContent(); if (Parent.GetContentLength() <= 0) { Parent.RemoveSelection(); Parent.AddToContent(0, new ParaRun()); Parent.MoveCursorToStartPos(); } } } }; ParaRun.prototype.RejectRevisionChanges = function(nType, bAll) { var Parent = this.Get_Parent(); var RunPos = this.private_GetPosInParent(); var ReviewType = this.GetReviewType(); var HavePrChange = this.HavePrChange(); // Нет изменений в данном ране if (reviewtype_Common === ReviewType && true !== HavePrChange) return; var oTrackManager = this.GetLogicDocument() ? this.GetLogicDocument().GetTrackRevisionsManager() : null; var oProcessMove = oTrackManager ? oTrackManager.GetProcessTrackMove() : null; if (true === this.Selection.Use || true === bAll) { var StartPos = this.Selection.StartPos; var EndPos = this.Selection.EndPos; if (StartPos > EndPos) { StartPos = this.Selection.EndPos; EndPos = this.Selection.StartPos; } if (true === bAll) { StartPos = 0; EndPos = this.Content.length; } var CenterRun = null, CenterRunPos = RunPos; if (0 === StartPos && this.Content.length === EndPos) { CenterRun = this; } else if (StartPos > 0 && this.Content.length === EndPos) { CenterRun = this.Split2(StartPos, Parent, RunPos); CenterRunPos = RunPos + 1; } else if (0 === StartPos && this.Content.length > EndPos) { CenterRun = this; this.Split2(EndPos, Parent, RunPos); } else { this.Split2(EndPos, Parent, RunPos); CenterRun = this.Split2(StartPos, Parent, RunPos); CenterRunPos = RunPos + 1; } if (true === HavePrChange && (undefined === nType || c_oAscRevisionsChangeType.TextPr === nType)) { CenterRun.Set_Pr(CenterRun.Pr.PrChange); } let reviewInfo = this.GetReviewInfo(); let prevInfo = reviewInfo ? reviewInfo.GetPrevAdded() : null; if ((reviewtype_Add === ReviewType && (undefined === nType || c_oAscRevisionsChangeType.TextAdd === nType || (c_oAscRevisionsChangeType.MoveMark === nType && Asc.c_oAscRevisionsMove.NoMove !== this.GetReviewMoveType() && oProcessMove && !oProcessMove.IsFrom() && oProcessMove.GetUserId() === reviewInfo.GetUserId()))) || (undefined === nType && bAll && reviewtype_Remove === ReviewType && prevInfo)) { Parent.RemoveFromContent(CenterRunPos, 1); CenterRun.ClearContent(); if (Parent.GetContentLength() <= 0) { Parent.RemoveSelection(); Parent.AddToContent(0, new ParaRun()); Parent.MoveCursorToStartPos(); } } else if (reviewtype_Remove === ReviewType && (undefined === nType || c_oAscRevisionsChangeType.TextRem === nType || (c_oAscRevisionsChangeType.MoveMark === nType && Asc.c_oAscRevisionsMove.NoMove !== this.GetReviewMoveType() && oProcessMove && oProcessMove.IsFrom() && oProcessMove.GetUserId() === reviewInfo.GetUserId()))) { if (prevInfo && c_oAscRevisionsChangeType.MoveMark !== nType) { CenterRun.SetReviewTypeWithInfo(reviewtype_Add, prevInfo.Copy()); } else { CenterRun.SetReviewType(reviewtype_Common); } } } }; ParaRun.prototype.IsInHyperlink = function() { if (!this.Paragraph) return false; var ContentPos = this.Paragraph.Get_PosByElement(this); var Classes = this.Paragraph.Get_ClassesByPos(ContentPos); var bHyper = false; var bRun = false; for (var Index = 0, Count = Classes.length; Index < Count; Index++) { var Item = Classes[Index]; if (Item === this) { bRun = true; break; } else if (Item instanceof ParaHyperlink) { bHyper = true; } } return (bHyper && bRun); }; ParaRun.prototype.Get_ClassesByPos = function(Classes, ContentPos, Depth) { Classes.push(this); }; /** * Получаем позицию данного рана в родительском параграфе * @param nInObjectPos {?number} * @returns {?AscWord.CParagraphContentPos} */ ParaRun.prototype.GetParagraphContentPosFromObject = function(nInObjectPos) { if (undefined === nInObjectPos) nInObjectPos = 0; var oParagraph = this.GetParagraph(); if (!oParagraph) return null; var oContentPos = oParagraph.GetPosByElement(this); if (!oContentPos) return null; oContentPos.Add(nInObjectPos); return oContentPos; }; ParaRun.prototype.Displace_BreakOperator = function(isForward, bBrkBefore, CountOperators) { var bResult = true; var bFirstItem = this.State.ContentPos == 0 || this.State.ContentPos == 1, bLastItem = this.State.ContentPos == this.Content.length - 1 || this.State.ContentPos == this.Content.length; if(true === this.Is_StartForcedBreakOperator() && bFirstItem == true) { var AlnAt = this.MathPrp.Get_AlnAt(); var NotIncrease = AlnAt == CountOperators && isForward == true; if(NotIncrease == false) { this.MathPrp.Displace_Break(isForward); var NewAlnAt = this.MathPrp.Get_AlnAt(); if(AlnAt !== NewAlnAt) { AscCommon.History.Add(new CChangesRunMathAlnAt(this, AlnAt, NewAlnAt)); } } } else { bResult = (bLastItem && bBrkBefore) || (bFirstItem && !bBrkBefore) ? false : true; } return bResult; // применили смещение к данному Run }; ParaRun.prototype.Math_UpdateLineMetrics = function(PRS, ParaPr) { var LineRule = ParaPr.Spacing.LineRule; let textMetrics = this.getTextMetrics(); let ascent = textMetrics.Ascent + textMetrics.LineGap; let ascent2 = textMetrics.Ascent; let descent = textMetrics.Descent; // Пересчитаем метрику строки относительно размера данного текста if ( PRS.LineTextAscent < ascent ) PRS.LineTextAscent = ascent; if ( PRS.LineTextAscent2 < ascent2 ) PRS.LineTextAscent2 = ascent2; if ( PRS.LineTextDescent < descent ) PRS.LineTextDescent = descent; if ( Asc.linerule_Exact === LineRule ) { // Смещение не учитывается в метриках строки, когда расстояние между строк точное if ( PRS.LineAscent < ascent ) PRS.LineAscent = ascent; if ( PRS.LineDescent < descent ) PRS.LineDescent = descent; } else { let yOffset = this.getYOffset(); if ( PRS.LineAscent < ascent + yOffset) PRS.LineAscent = ascent + yOffset; if ( PRS.LineDescent < descent - yOffset) PRS.LineDescent = descent - yOffset; } }; ParaRun.prototype.Set_CompositeInput = function(oCompositeInput) { this.CompositeInput = oCompositeInput; }; ParaRun.prototype.GetFootnotesList = function(oEngine) { for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex) { var oItem = this.Content[nIndex]; if ((oEngine.IsCheckFootnotes() && para_FootnoteReference === oItem.Type) || (oEngine.IsCheckEndnotes() && para_EndnoteReference === oItem.Type)) { oEngine.Add(oItem.GetFootnote(), oItem, this); } } }; ParaRun.prototype.GetParaEnd = function() { for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex) { if (this.Content[nIndex].Type === para_End) return this.Content[nIndex]; } return null; }; /** * Проверяем, является ли это ран со знаком конца параграфа * @returns {boolean} */ ParaRun.prototype.IsParaEndRun = function() { return this.GetParaEnd() ? true : false; }; ParaRun.prototype.RemoveElement = function(oElement) { for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex) { if (oElement === this.Content[nIndex]) { this.RemoveFromContent(nIndex, 1, true); return true; } } return false; }; ParaRun.prototype.GotoFootnoteRef = function(isNext, isCurrent, isStepOver, isStepFootnote, isStepEndnote) { var nPos = 0; if (true === isCurrent) { if (true === this.Selection.Use) nPos = Math.min(this.Selection.StartPos, this.Selection.EndPos); else nPos = this.State.ContentPos; } else { if (true === isNext) nPos = 0; else nPos = this.Content.length - 1; } var nResult = 0; if (true === isNext) { for (var nIndex = nPos, nCount = this.Content.length; nIndex < nCount; ++nIndex) { if (((para_FootnoteReference === this.Content[nIndex].Type && isStepFootnote) || (para_EndnoteReference === this.Content[nIndex].Type && isStepEndnote)) && ((true !== isCurrent && true === isStepOver) || (true === isCurrent && (true === this.Selection.Use || nPos !== nIndex)))) { if (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument) this.Paragraph.LogicDocument.RemoveSelection(); this.State.ContentPos = nIndex; this.Make_ThisElementCurrent(true); return -1; } nResult++; } } else { for (var nIndex = Math.min(nPos, this.Content.length - 1); nIndex >= 0; --nIndex) { if (((para_FootnoteReference === this.Content[nIndex].Type && isStepFootnote) || (para_EndnoteReference === this.Content[nIndex].Type && isStepEndnote)) && ((true !== isCurrent && true === isStepOver) || (true === isCurrent && (true === this.Selection.Use || nPos !== nIndex)))) { if (this.Paragraph && this.Paragraph.bFromDocument && this.Paragraph.LogicDocument) this.Paragraph.LogicDocument.RemoveSelection(); this.State.ContentPos = nIndex; this.Make_ThisElementCurrent(true); return -1; } nResult++; } } return nResult; }; ParaRun.prototype.GetFootnoteRefsInRange = function(arrFootnotes, _CurLine, _CurRange) { var CurLine = _CurLine - this.StartLine; var CurRange = (0 === CurLine ? _CurRange - this.StartRange : _CurRange); var StartPos = this.protected_GetRangeStartPos(CurLine, CurRange); var EndPos = this.protected_GetRangeEndPos(CurLine, CurRange); for (var CurPos = StartPos; CurPos < EndPos; CurPos++) { if (para_FootnoteReference === this.Content[CurPos].Type || para_EndnoteReference === this.Content[CurPos].Type) arrFootnotes.push(this.Content[CurPos]); } }; ParaRun.prototype.GetSelectedContentControls = function(arrContentControls) { let startPos = (this.Selection.StartPos < this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos); let endPos = (this.Selection.StartPos < this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos); for (let i = startPos; i < endPos; ++i) { let item = this.Content[i]; if (item.IsDrawing()) item.GetAllContentControls(arrContentControls); } }; ParaRun.prototype.GetAllContentControls = function(arrContentControls) { if (!arrContentControls) return; for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex) { var oItem = this.Content[nIndex]; if (para_Drawing === oItem.Type || para_FootnoteReference === oItem.Type || para_EndnoteReference === oItem.Type) { oItem.GetAllContentControls(arrContentControls); } } }; /** * Получаем позицию заданного элемента * @param oElement * @returns {number} позиция, либо -1, если заданного элемента нет */ ParaRun.prototype.GetElementPosition = function(oElement) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { if (oElement === this.Content[nPos]) return nPos; } return -1; }; /** * Устанавливаем текущее положение позиции курсора в данном ране * @param nPos */ ParaRun.prototype.SetCursorPosition = function(nPos) { this.State.ContentPos = Math.max(0, Math.min(nPos, this.Content.length)); }; /** * Получаем номер строки по заданной позиции. * @param nPos */ ParaRun.prototype.GetLineByPosition = function(nPos) { for (var nLineIndex = 0, nLinesCount = this.protected_GetLinesCount(); nLineIndex < nLinesCount; ++nLineIndex) { for (var nRangeIndex = 0, nRangesCount = this.protected_GetRangesCount(nLineIndex); nRangeIndex < nRangesCount; ++nRangeIndex) { var nStartPos = this.protected_GetRangeStartPos(nLineIndex, nRangeIndex); var nEndPos = this.protected_GetRangeEndPos(nLineIndex, nRangeIndex); if (nPos >= nStartPos && nPos < nEndPos) return nLineIndex + this.StartLine; } } return this.StartLine; }; /** * Данная функция вызывается перед удалением данного рана из родительского класса. */ ParaRun.prototype.PreDelete = function(isDeep) { if (this.Paragraph && this.Paragraph.isPreventedPreDelete()) return; // TODO: Перенести это, когда удаляется непосредственно элемент из класса // Сейчас работает не совсем корректно, потому что при большой вложенности у элементов чистится Parent, // хотя по факту он должен чистится только у первого уровня элементов, с которых начинается удаление if (true !== isDeep) this.SetParent(null); for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex) { if (this.Content[nIndex].PreDelete) this.Content[nIndex].PreDelete(true); } this.RemoveSelection(); }; ParaRun.prototype.CorrectPosToPermRanges = function(state, paraPos, depth, isCurrent) { if (!isCurrent && state.inPermRange()) { state.setPos(state.isForward() ? 0 : this.Content.length, depth); state.stop(true); return; } let start, end; if (state.isForward()) { start = isCurrent ? paraPos.Get(depth) : 0; end = this.Content.length; } else { start = 0; end = isCurrent ? Math.min(this.Content.length, paraPos.Get(depth)) : this.Content.length; } for (let i = start; i < end; ++i) { if (!this.Content[i].IsDrawing() || this.Content[i].IsInline()) { state.stop(false); return; } } }; ParaRun.prototype.GetCurrentComplexFields = function(arrComplexFields, isCurrent, isFieldPos) { var nEndPos = isCurrent ? this.State.ContentPos : this.Content.length; for (var nPos = 0; nPos < nEndPos; ++nPos) { var oItem = this.Content[nPos]; if (oItem.Type !== para_FieldChar) continue; if (isFieldPos) { var oComplexField = oItem.GetComplexField(); if (oItem.IsBegin()) { arrComplexFields.push(new CComplexFieldStatePos(oComplexField, true)); } else if (oItem.IsSeparate()) { if (arrComplexFields.length > 0) { arrComplexFields[arrComplexFields.length - 1].SetFieldCode(false) } } else if (oItem.IsEnd()) { if (arrComplexFields.length > 0) { arrComplexFields.splice(arrComplexFields.length - 1, 1); } } } else { if (oItem.IsBegin()) { arrComplexFields.push(oItem.GetComplexField()); } else if (oItem.IsEnd()) { if (arrComplexFields.length > 0) { arrComplexFields.splice(arrComplexFields.length - 1, 1); } } } } }; ParaRun.prototype.RemoveTabsForTOC = function(_isTab) { var isTab = _isTab; for (var nPos = 0; nPos < this.Content.length; ++nPos) { if (para_Tab === this.Content[nPos].Type) { if (!isTab) { // Первый таб в параграфе оставляем isTab = true; } else { this.Remove_FromContent(nPos, 1); } } } return isTab; }; ParaRun.prototype.GetAllFields = function(isUseSelection, arrFields) { var nStartPos = isUseSelection ? (this.Selection.StartPos < this.Selection.EndPos ? this.Selection.StartPos : this.Selection.EndPos) : 0; var nEndPos = isUseSelection ? (this.Selection.StartPos < this.Selection.EndPos ? this.Selection.EndPos : this.Selection.StartPos) : this.Content.length; for (var nPos = nStartPos; nPos < nEndPos; ++nPos) { var oItem = this.Content[nPos]; if (para_FieldChar === oItem.Type) { let complexField = oItem.GetComplexField(); if (complexField && complexField.IsValid() && -1 === arrFields.indexOf(complexField)) { arrFields.push(complexField); } } else if (para_Drawing === oItem.Type) { oItem.GetAllFields(false, arrFields); } else if (para_FootnoteReference === oItem.Type || para_EndnoteReference === oItem.Type) { oItem.GetFootnote().GetAllFields(false, arrFields); } } }; ParaRun.prototype.GetAllSeqFieldsByType = function(sType, aFields) { for (var nPos = 0; nPos < this.Content.length; ++nPos) { var oItem = this.Content[nPos]; if (para_FieldChar === oItem.Type) { let complexField = oItem.GetComplexField(); let instruction = complexField && complexField.IsValid() ? complexField.GetInstruction() : null; if (instruction && instruction.Type === AscWord.fieldtype_SEQ && instruction.CheckId(sType) && -1 === aFields.indexOf(complexField)) { aFields.push(complexField); } } else if (para_Field === oItem.Type && oItem.FieldType === AscWord.fieldtype_SEQ && oItem.Arguments[0] === sType) { aFields.push(oItem); } else if (para_Drawing === oItem.Type) { oItem.GetAllSeqFieldsByType(sType, aFields); } } }; ParaRun.prototype.GetLastSEQPos = function(sType) { for (var nPos = this.Content.length - 1; nPos > -1; --nPos) { var oItem = this.Content[nPos]; if (para_FieldChar === oItem.Type) { var oComplexField = oItem.GetComplexField(); if(oComplexField) { var oInstruction = oComplexField.Instruction; if(oInstruction) { if(oInstruction.Type === AscWord.fieldtype_SEQ) { if(oInstruction.Id === sType) { return this.GetParagraphContentPosFromObject(nPos + 1); } } } } } else if(para_Field === oItem.Type) { if(oItem.FieldType === AscWord.fieldtype_SEQ) { if(oItem.Arguments[0] === sType) { return this.GetParagraphContentPosFromObject(nPos + 1); } } } } return null; }; ParaRun.prototype.FindNoSpaceElement = function(nStart) { for(var nIndex = nStart; nIndex < this.Content.length; ++nIndex) { var oElement = this.Content[nIndex]; if(oElement.Type === para_Space || oElement.Type === para_Tab || oElement.Type === para_NewLine) { continue; } else { return nIndex; } } return -1; }; ParaRun.prototype.AddToContent = function(nPos, oItem, isUpdatePositions) { return this.Add_ToContent(nPos, oItem, isUpdatePositions); }; ParaRun.prototype.AddToContentToEnd = function(oItem, isUpdatePositions) { return this.Add_ToContent(this.GetElementsCount(), oItem, isUpdatePositions); }; ParaRun.prototype.RemoveFromContent = function(nPos, nCount, isUpdatePositions) { return this.Remove_FromContent(nPos, nCount, isUpdatePositions); }; ParaRun.prototype.GetComplexField = function(nType) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var oItem = this.Content[nPos]; if (para_FieldChar === oItem.Type && oItem.IsBegin()) { var oComplexField = oItem.GetComplexField(); if (!oComplexField) continue; var oInstruction = oComplexField.GetInstruction(); if (!oInstruction) continue; if (nType === oInstruction.GetType()) return oComplexField; } } return null; }; ParaRun.prototype.GetComplexFieldsArray = function(nType, arrComplexFields) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var oItem = this.Content[nPos]; if (para_FieldChar === oItem.Type && oItem.IsBegin()) { var oComplexField = oItem.GetComplexField(); if (!oComplexField) continue; var oInstruction = oComplexField.GetInstruction(); if (!oInstruction) continue; if (nType === oInstruction.GetType()) arrComplexFields.push(oComplexField); } } }; /** * Получаем количество элементов в ране * @returns {Number} */ ParaRun.prototype.GetElementsCount = function() { return this.Content.length; }; /** * Получаем элемент по заданной позиции * @param nPos {number} * @returns {?AscWord.CRunElementBase} */ ParaRun.prototype.GetElement = function(nPos) { if (nPos < 0 || nPos >= this.Content.length) return null; return this.Content[nPos]; }; /** * Проверяем является ли данный ран специальным, содержащим ссылку на сноску * @returns {boolean} */ ParaRun.prototype.IsFootEndnoteReferenceRun = function() { return (1 === this.Content.length && (para_FootnoteReference === this.Content[0].Type || para_EndnoteReference == this.Content[0].Type)); }; /** * Производим автозамену * @param {number} nPos - позиция, на которой был добавлен последний элемент, с которого стартовала автозамена * @param {number} nFlags - флаги, какие автозамены мы пробуем делать * @param {number} [nHistoryActions=1] Автозамене предществовало заданное количество точек в истории * @returns {number} Возвращаются флаги, произведенных автозамен */ ParaRun.prototype.ProcessAutoCorrect = function(nPos, nFlags, nHistoryActions) { return (new AscWord.CRunAutoCorrect(this, nPos).DoAutoCorrect(nFlags, nHistoryActions)); }; /** * Выполняем автозамену в конце параграфа * @param {number} [nHistoryActions=1] Автозамене предществовало заданное количество точек в истории */ ParaRun.prototype.ProcessAutoCorrectOnParaEnd = function(nHistoryActions) { var oParaEnd = this.GetParaEnd(); if (!oParaEnd) return; this.ProcessAutoCorrect(0, oParaEnd.GetAutoCorrectFlags(), nHistoryActions); }; ParaRun.prototype.CollectTextToUnicode = function(ListForUnicode, oSettings) { if (!this.Selection.Use) return; if (oSettings.nDirection === 1) oSettings.textForUnicode += this.GetSelectedText(false); else oSettings.textForUnicode = this.GetSelectedText(false) + oSettings.textForUnicode; let startPos = this.Selection.StartPos; let endPos = this.Selection.EndPos; function HandleItem(run, pos) { let item = run.Content[pos]; if (para_Text === item.Type || para_Space === item.Type || para_Math_Text === item.Type || para_Math_BreakOperator === item.Type) { ListForUnicode[oSettings.fFlagForUnicode++] = { oRun: run, currentPos: pos, value: item.GetCodePoint() }; if (para_Math_Text === item.Type || para_Math_BreakOperator === item.Type) oSettings.IsForMathPart = -1; } else { if (!item.IsParaEnd()) oSettings.bBreak = true; return true; } return false; } if (startPos > endPos) { oSettings.nDirection = -1; for (let pos = startPos - 1; pos >= endPos; --pos) { if (HandleItem(this, pos)) break; } } else { oSettings.nDirection = 1; for (let pos = startPos; pos < endPos; ++pos) { if (HandleItem(this, pos)) break; } } }; ParaRun.prototype.SetMathMetaData = function(oMathMetaData) { if (!oMathMetaData) return; if (this.math_autocorrection) { let oOldMetaData = oMathMetaData.Copy(); this.math_autocorrection.Set(oMathMetaData); AscCommon.History.Add(new CChangesRunMathMetaData(this, oOldMetaData, this.math_autocorrection)); } else { this.math_autocorrection = oMathMetaData.Copy(); AscCommon.History.Add(new CChangesRunMathMetaData(this, false, this.math_autocorrection)); } }; ParaRun.prototype.UpdateBookmarks = function(oManager) { for (var nIndex = 0, nCount = this.Content.length; nIndex < nCount; ++nIndex) { if (para_Drawing === this.Content[nIndex].Type) this.Content[nIndex].UpdateBookmarks(oManager); } }; ParaRun.prototype.CheckRunContent = function(fCheck, oStartPos, oEndPos, nDepth, oCurrentPos, isForward) { let nStartPos = oStartPos && oStartPos.GetDepth() >= nDepth ? oStartPos.Get(nDepth) : 0; let nEndPos = oEndPos && oEndPos.GetDepth() >= nDepth ? oEndPos.Get(nDepth) : this.Content.length; return fCheck(this, nStartPos, nEndPos, oCurrentPos); }; ParaRun.prototype.ProcessComplexFields = function(oComplexFields) { var isRemovedInReview = (reviewtype_Remove === this.GetReviewType()); for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var oItem = this.private_CheckInstrText(this.Content[nPos]); var nItemType = oItem.Type; if (oComplexFields.isHiddenFieldContent() && para_End !== nItemType && para_FieldChar !== nItemType) continue; if (para_FieldChar === nItemType) oComplexFields.processFieldCharAndCollectComplexField(oItem); else if (para_InstrText === nItemType && !isRemovedInReview) oComplexFields.processInstruction(oItem); } }; ParaRun.prototype.GetSelectedElementsInfo = function(oInfo) { if (oInfo && oInfo.IsCheckAllSelection() && !this.IsSelectionEmpty(true)) { oInfo.RegisterReviewType(this.GetReviewType()); var oElement; for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { oElement = this.Content[nPos]; if (para_RevisionMove === oElement.Type) { oInfo.RegisterTrackMoveMark(oElement.Type); } else if(para_FootnoteReference === oElement.Type || para_EndnoteReference === oElement.Type) { oInfo.RegisterFootEndNoteRef(oElement); } } } }; ParaRun.prototype.GetLastTrackMoveMark = function() { for (var nPos = this.Content.length - 1; nPos >= 0; --nPos) { if (para_RevisionMove === this.Content[nPos].Type) return this.Content[nPos]; } return null; }; /** * Можно ли удалять данный ран во время рецензирования * @returns {boolean} */ ParaRun.prototype.CanDeleteInReviewMode = function() { var nReviewType = this.GetReviewType(); var oReviewInfo = this.GetReviewInfo(); return ((reviewtype_Add === nReviewType && oReviewInfo.IsCurrentUser() && (!oReviewInfo.IsMovedTo() || this.Paragraph.LogicDocument.TrackMoveRelocation)) || (reviewtype_Remove === nReviewType && oReviewInfo.IsPrevAddedByCurrentUser())); }; /** * Данная функция используется в иерархии классов для поиска первого рана * @returns {ParaRun} */ ParaRun.prototype.GetFirstRun = function() { return this; }; ParaRun.prototype.GetFirstRunElementPos = function(nType, oStartPos, oEndPos, nDepth) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { if (nType === this.Content[nPos].Type) { oStartPos.Update(nPos, nDepth); oEndPos.Update(nPos + 1, nDepth); return true; } } return false; }; ParaRun.prototype.GetTextForm = function() { var oTextFormPr = this.Parent instanceof CInlineLevelSdt && this.Parent.IsTextForm() ? this.Parent.GetTextFormPr() : null; if (!oTextFormPr) return null; return oTextFormPr; }; ParaRun.prototype.GetFormPDF = function() { let oPara = this.GetParagraph(); let oParaParent = oPara.GetParent(); if (oParaParent && oParaParent.ParentPDF) return oParaParent.ParentPDF; return null; }; ParaRun.prototype.IsInCheckBox = function() { var arrParentCC = this.GetParentContentControls(); for (var nIndex = 0, nCount = arrParentCC.length; nIndex < nCount; ++nIndex) { if (arrParentCC[nIndex].IsCheckBox()) return true; } return false; }; ParaRun.prototype.GetTextFormAutoWidth = function() { this.Recalculate_MeasureContent(); let metrics = this.getTextMetrics(); return metrics.Ascent + metrics.LineGap; }; ParaRun.prototype.CheckParentFormKey = function() { let oForm = this.GetParentForm(); let oLogicDocument = this.GetLogicDocument(); if (oForm && oLogicDocument && oLogicDocument.IsDocumentEditor()) oLogicDocument.OnChangeForm(oForm); }; ParaRun.prototype.GetParentForm = function() { return (this.Parent instanceof CInlineLevelSdt && this.Parent.IsForm() ? this.Parent : null); }; ParaRun.prototype.GetParentPictureContentControl = function() { var arrParentCC = this.GetParentContentControls(); for (var nIndex = 0, nCount = arrParentCC.length; nIndex < nCount; ++nIndex) { if (arrParentCC[nIndex].IsPicture()) return arrParentCC[nIndex]; } return null; }; ParaRun.prototype.CopyTextFormContent = function(oRun) { var nRunLen = oRun.Content.length; var oTextForm = this.GetTextForm(); if (oTextForm && undefined !== oTextForm.GetMaxCharacters() && oTextForm.GetMaxCharacters() > 0) nRunLen = Math.min(oTextForm.GetMaxCharacters(), nRunLen); // Упрощенный вариант сравнения двух контентов. Сравниваем просто начало и конец var nStart = 0; var nEnd = 0; var nCount = Math.min(this.Content.length, oRun.Content.length); for (var nPos = 0; nPos < nCount; ++nPos) { if (this.Content[nPos].IsEqual(oRun.Content[nPos])) nStart = nPos + 1; else break; } nCount -= nStart; for (var nPos = 0; nPos < nCount; ++nPos) { if (this.Content[this.Content.length - 1 - nPos].IsEqual(oRun.Content[nRunLen - 1 - nPos])) nEnd = nPos + 1; else break; } if (this.Content.length - nStart - nEnd > 0) this.RemoveFromContent(nStart, this.Content.length - nStart - nEnd, true); for (var nPos = nStart, nEndPos = nRunLen - nEnd; nPos < nEndPos; ++nPos) { this.AddToContent(nPos, oRun.Content[nPos].Copy(), true); } }; /** * Изменяем содержимое и настройки рана при конвертации одного типа сносок в другие * @param isToFootnote {boolean} * @param oStyles {CStyles} * @param oFootnote {CFootEndnote} * @param oRef {AscWord.CRunFootnoteReference | AscWord.CRunEndnoteReference} */ ParaRun.prototype.ConvertFootnoteType = function(isToFootnote, oStyles, oFootnote, oRef) { let _t = this; function replaceRef(pos, newRef) { AscCommon.executeNoPreDelete(function(){ _t.RemoveFromContent(pos, 1); _t.AddToContent(pos, newRef); }, _t.GetLogicDocument()); } var sRStyle = this.GetRStyle(); if (isToFootnote) { if (sRStyle === oStyles.GetDefaultEndnoteTextChar()) this.SetRStyle(oStyles.GetDefaultFootnoteTextChar()); else if (sRStyle === oStyles.GetDefaultEndnoteReference()) this.SetRStyle(oStyles.GetDefaultFootnoteReference()); for (let nCurPos = 0, nCount = this.Content.length; nCurPos < nCount; ++nCurPos) { let oElement = this.Content[nCurPos]; if (!oRef || oRef === oElement) { if (para_EndnoteReference === oElement.Type) replaceRef(nCurPos, new AscWord.CRunFootnoteReference(oFootnote, oElement.CustomMark)); else if (para_EndnoteRef === oElement.Type) replaceRef(nCurPos, new AscWord.CRunFootnoteRef(oFootnote)); } } } else { if (sRStyle === oStyles.GetDefaultFootnoteTextChar()) this.SetRStyle(oStyles.GetDefaultEndnoteTextChar()); else if (sRStyle === oStyles.GetDefaultFootnoteReference()) this.SetRStyle(oStyles.GetDefaultEndnoteReference()); for (let nCurPos = 0, nCount = this.Content.length; nCurPos < nCount; ++nCurPos) { let oElement = this.Content[nCurPos]; if (!oRef || oRef === oElement) { if (para_FootnoteReference === oElement.Type) replaceRef(nCurPos, new AscWord.CRunEndnoteReference(oFootnote, oElement.CustomMark)); else if (para_FootnoteRef === oElement.Type) replaceRef(nCurPos, new AscWord.CRunEndnoteRef(oFootnote)); } } } }; ParaRun.prototype.FindNextFillingForm = function(isNext, isCurrent, isStart) { var nCurPos = this.Selection.Use === true ? this.Selection.EndPos : this.State.ContentPos; var nStartPos = 0, nEndPos = 0; if (isCurrent) { if (isStart) { nStartPos = nCurPos; nEndPos = isNext ? this.Content.length : 0; } else { nStartPos = isNext ? 0 : this.Content.length; nEndPos = nCurPos; } } else { if (isNext) { nStartPos = 0; nEndPos = this.Content.length; } else { nStartPos = this.Content.length; nEndPos = 0; } } if (isNext) { for (var nIndex = nStartPos; nIndex < nEndPos; ++nIndex) { if (this.Content[nIndex].FindNextFillingForm) { var oRes = this.Content[nIndex].FindNextFillingForm(true, false, false); if (oRes) return oRes; } } } else { for (var nIndex = nStartPos - 1; nIndex >= nEndPos; --nIndex) { if (this.Content[nIndex].FindNextFillingForm) { var oRes = this.Content[nIndex].FindNextFillingForm(false, false, false); if (oRes) return oRes; } } } return null; }; ParaRun.prototype.CalculateTextToTable = function(oEngine) { if (reviewtype_Remove === this.GetReviewType()) return; // В формулах делим только по ранам, находящимся в самом верху стэка формулы if (this.IsMathRun() && (!this.ParaMath || this.Parent !== this.ParaMath.Root)) return; if (oEngine.IsCalculateTableSizeMode()) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { if (oEngine.CheckSeparator(this.Content[nPos])) { oEngine.AddItem(); } } } else if (oEngine.IsCheckSeparatorMode()) { for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { var oItem = this.Content[nPos]; var nItemType = oItem.Type; if (para_Tab === nItemType) oEngine.AddTab(); else if ((para_Text === nItemType && 0x3B === oItem.Value) || (para_Math_Text === nItemType && 0x3B === oItem.value)) oEngine.AddSemicolon(); } } else if (oEngine.IsConvertMode()) { var oRunPos = null, oParagraph = null; for (var nPos = 0, nCount = this.Content.length; nPos < nCount; ++nPos) { if (oEngine.CheckSeparator(this.Content[nPos])) { if (!oRunPos) { oParagraph = this.GetParagraph(); if (!oParagraph) return; oRunPos = oParagraph.GetPosByElement(this); if (!oRunPos) return; } var oContentPos = oRunPos.Copy(); oContentPos.Add(nPos); oEngine.AddParaPosition(oContentPos); } } } }; ParaRun.prototype.IsUseAscFont = function(oTextPr) { return (1 === this.Content.length && para_Text === this.Content[0].Type && this.IsInCheckBox() && AscCommon.IsAscFontSupport(oTextPr.RFonts.Ascii.Name, this.Content[0].Value)); }; /** * Получаем предыдущий элемент, с учетом предыдущих классов внутри параграфа * @param nPos {number} позиция внутри данного рана * @returns {?AscWord.CRunElementBase} */ ParaRun.prototype.GetPrevRunElement = function(nPos) { if (nPos > 0) return this.Content[nPos - 1]; var oParagraph = this.GetParagraph(); if (!oParagraph) return null; var oContentPos = this.GetParagraphContentPosFromObject(0); var oRunElements = new CParagraphRunElements(oContentPos, 1, null, true); oParagraph.GetPrevRunElements(oRunElements); if (oRunElements.Elements.length <= 0) return null; return oRunElements.Elements[0]; }; /** * Получаем следующий элемент, с учетом следующих классов внутри параграфа * @param nPos {number} позиция внутри данного рана * @returns {?AscWord.CRunElementBase} */ ParaRun.prototype.GetNextRunElement = function(nPos) { if (nPos <= this.Content.length - 1 && nPos >= 0) return this.Content[nPos]; var oParagraph = this.GetParagraph(); if (!oParagraph) return null; var oContentPos = this.GetParagraphContentPosFromObject(this.Content.length); var oRunElements = new CParagraphRunElements(oContentPos, 1, null, true); oParagraph.GetNextRunElements(oRunElements); if (oRunElements.Elements.length <= 0) return null; return oRunElements.Elements[0]; }; /** * Получаем позицию следующего элемента внутри параграфа * @param nPos {number} позиция внутри данного рана * @returns {?{Element : AscWord.CRunElementBase, Pos : AscWord.CParagraphContentPos}} */ ParaRun.prototype.GetNextRunElementEx = function(nPos) { let oParagraph = this.GetParagraph(); if (!oParagraph) return null; if (nPos <= this.Content.length - 1 && nPos >= 0) { let oContentPos = this.GetParagraphContentPosFromObject(nPos); if (!oContentPos) return null; return { Element : this.Content[nPos], Pos : oContentPos } } let oContentPos = this.GetParagraphContentPosFromObject(this.Content.length); let oRunElements = new CParagraphRunElements(oContentPos, 1, null, true); oRunElements.SkipMath = false; oRunElements.SetSaveContentPositions(true); oParagraph.GetNextRunElements(oRunElements); let arrPositions = oRunElements.GetContentPositions(); let arrElements = oRunElements.GetElements(); if (1 !== arrPositions.length || 1 !== arrElements.length) return null; return { Element : arrElements[0], Pos : arrPositions[0] } }; //---------------------------------------------------------------------------------------------------------------------- // SpellCheck //---------------------------------------------------------------------------------------------------------------------- ParaRun.prototype.RestartSpellCheck = function() { this.Recalc_CompiledPr(false); for (let nIndex = 0, nCount = this.Content.length; nIndex < nCount; nIndex++) { let oItem = this.Content[nIndex]; if (oItem.IsDrawing()) oItem.RestartSpellCheck(); } }; ParaRun.prototype.CheckSpelling = function(oCollector, nDepth) { if (oCollector.IsExceedLimit()) return; if (reviewtype_Remove === this.GetReviewType()) { oCollector.FlushWord(); return; } let nStartPos = 0; let oCurTextPr = this.Get_CompiledPr(false); if (oCollector.IsFindStart()) { nStartPos = oCollector.GetPos(nDepth); oCollector.SetFindStart(false); } else { this.SpellingMarks = []; if (true === this.IsEmpty()) return; oCollector.HandleLang(oCurTextPr.Lang); } for (let nPos = nStartPos, nContentLen = this.Content.length; nPos < nContentLen; ++nPos) { oCollector.UpdatePos(nPos, nDepth); oCollector.HandleRunElement(this.Content[nPos], oCurTextPr, this, nPos); if (oCollector.IsExceedLimit()) break; } }; ParaRun.prototype.AddSpellCheckerElement = function(spellMark) { this.SpellingMarks.push(spellMark); }; ParaRun.prototype.RemoveSpellCheckerElement = function(element) { for (let iMark = this.SpellingMarks.length - 1; iMark >= 0; --iMark) { if (this.SpellingMarks[iMark].getElement() === element) this.SpellingMarks.splice(iMark, 1); } }; ParaRun.prototype.ClearSpellingMarks = function() { this.SpellingMarks = []; }; ParaRun.prototype.GetSelectedDrawingObjectsInText = function(arrDrawings) { if (!this.IsSelectionUse()) return; let nStartPos = this.Selection.StartPos; let nEndPos = this.Selection.EndPos; if (nStartPos > nEndPos) { let nTemp = nStartPos; nStartPos = nEndPos; nEndPos = nTemp; } for (let nPos = nStartPos; nPos < nEndPos; ++nPos) { let oItem = this.Content[nPos]; if (oItem.IsDrawing()) arrDrawings.push(oItem); } return arrDrawings; }; //---------------------------------------------------------------------------------------------------------------------- // Search //---------------------------------------------------------------------------------------------------------------------- ParaRun.prototype.Search = function(ParaSearch) { this.SearchMarks = []; var Para = ParaSearch.Paragraph; var SearchEngine = ParaSearch.SearchEngine; var Type = ParaSearch.Type; let isWholeWords = SearchEngine.IsWholeWords(); for (var nPos = 0, nContentLen = this.Content.length; nPos < nContentLen; ++nPos) { var oItem = this.Content[nPos]; if (para_Drawing === oItem.Type) oItem.Search(SearchEngine, Type); while (ParaSearch.SearchIndex > 0 && !ParaSearch.Check(ParaSearch.SearchIndex, oItem)) { if (isWholeWords) { ParaSearch.Reset(); break; } else { ParaSearch.SearchIndex = ParaSearch.GetPrefix(ParaSearch.SearchIndex - 1); if (0 === ParaSearch.SearchIndex) { ParaSearch.Reset(); break; } else if (ParaSearch.Check(ParaSearch.SearchIndex, oItem)) { ParaSearch.StartPos = ParaSearch.StartPosBuf.shift(); break; } } } if (ParaSearch.Check(ParaSearch.SearchIndex, oItem)) { if (0 === ParaSearch.SearchIndex) { if (isWholeWords) { var oPrevElement = this.GetPrevRunElement(nPos); if (!oPrevElement || (!oPrevElement.IsLetter() && !oPrevElement.IsDigit())) ParaSearch.StartPos = {Run : this, Pos : nPos}; } else { ParaSearch.StartPos = {Run : this, Pos : nPos}; } } if (0 !== ParaSearch.GetPrefix(ParaSearch.SearchIndex)) ParaSearch.StartPosBuf.push({Run : this, Pos : nPos}); ParaSearch.SearchIndex++; if (ParaSearch.CheckSearchEnd()) { if (ParaSearch.StartPos) { var isAdd = false; if (isWholeWords) { var oNextElement = this.GetNextRunElement(nPos + 1); if (!oNextElement || (!oNextElement.IsLetter() && !oNextElement.IsDigit())) isAdd = true; } else { isAdd = true; } if (isAdd) { Para.AddSearchResult( SearchEngine.Add(Para), ParaSearch.StartPos.Run.GetParagraphContentPosFromObject(ParaSearch.StartPos.Pos), this.GetParagraphContentPosFromObject(nPos + 1), Type ); } } ParaSearch.Reset(); } } } }; ParaRun.prototype.AddSearchResult = function(oSearchResult, isStart, oContentPos, nDepth) { oSearchResult.RegisterClass(isStart, this); this.SearchMarks.push(new AscCommonWord.CParagraphSearchMark(oSearchResult, isStart, nDepth)); }; ParaRun.prototype.ClearSearchResults = function() { this.SearchMarks = []; }; ParaRun.prototype.RemoveSearchResult = function(oSearchResult) { for (var nIndex = 0, nMarksCount = this.SearchMarks.length; nIndex < nMarksCount; ++nIndex) { var oMark = this.SearchMarks[nIndex]; if (oSearchResult === oMark.SearchResult) { this.SearchMarks.splice(nIndex, 1); nIndex--; nMarksCount--; } } }; ParaRun.prototype.GetSearchElementId = function(bNext, bUseContentPos, ContentPos, Depth) { var StartPos = 0; if ( true === bUseContentPos ) { StartPos = ContentPos.Get( Depth ); } else { if ( true === bNext ) { StartPos = 0; } else { StartPos = this.Content.length; } } var NearElementId = null; if ( true === bNext ) { var NearPos = this.Content.length; var SearchMarksCount = this.SearchMarks.length; for ( var SPos = 0; SPos < SearchMarksCount; SPos++) { var Mark = this.SearchMarks[SPos]; var MarkPos = Mark.SearchResult.StartPos.Get(Mark.Depth); if (Mark.SearchResult.ClassesS.length > 0 && this === Mark.SearchResult.ClassesS[Mark.SearchResult.ClassesS.length - 1] && MarkPos >= StartPos && MarkPos < NearPos) { NearElementId = Mark.SearchResult.Id; NearPos = MarkPos; } } for ( var CurPos = StartPos; CurPos < NearPos; CurPos++ ) { var Item = this.Content[CurPos]; if ( para_Drawing === Item.Type ) { var TempElementId = Item.GetSearchElementId( true, false ); if ( null != TempElementId ) return TempElementId; } } } else { var NearPos = -1; var SearchMarksCount = this.SearchMarks.length; for ( var SPos = 0; SPos < SearchMarksCount; SPos++) { var Mark = this.SearchMarks[SPos]; var MarkPos = Mark.SearchResult.StartPos.Get(Mark.Depth); if (Mark.SearchResult.ClassesS.length > 0 && this === Mark.SearchResult.ClassesS[Mark.SearchResult.ClassesS.length - 1] && MarkPos < StartPos && MarkPos > NearPos) { NearElementId = Mark.SearchResult.Id; NearPos = MarkPos; } } StartPos = Math.min( this.Content.length - 1, StartPos - 1 ); for ( var CurPos = StartPos; CurPos > NearPos; CurPos-- ) { var Item = this.Content[CurPos]; if ( para_Drawing === Item.Type ) { var TempElementId = Item.GetSearchElementId( false, false ); if ( null != TempElementId ) return TempElementId; } } } return NearElementId; }; //---------------------------------------------------------------------------------------------------------------------- ParaRun.prototype.GetFontSlotInRange = function(nStartPos, nEndPos) { if (nStartPos >= nEndPos || nStartPos >= this.Content.length || nEndPos <= 0 || this.IsMathRun()) return AscWord.fontslot_None; let oTextPr = this.Get_CompiledPr(false); let nFontSlot = AscWord.fontslot_None; for (let nPos = nStartPos; nPos < nEndPos; ++nPos) { let oItem = this.Content[nPos]; nFontSlot |= oItem.GetFontSlot(oTextPr) } if (AscWord.fontslot_Unknown === nFontSlot) return AscWord.fontslot_Unknown; if (oTextPr.RTL || oTextPr.CS) return AscWord.fontslot_CS; return nFontSlot; }; ParaRun.prototype.GetDirectionFlagInRange = function(startPos, endPos) { if (startPos >= endPos || startPos >= this.Content.length || endPos <= 0 || this.IsMathRun()) return AscBidi.DIRECTION_FLAG.None; let dir = AscBidi.DIRECTION_FLAG.None; for (let pos = startPos; pos < endPos; ++pos) { let item = this.Content[pos]; dir |= item.GetDirectionFlag(); } return dir; }; /** * Get first find parent typeof CMathContent or MathBase * @return {*} */ ParaRun.prototype.GetMathBaseFirst = function() { if (!this.IsMathRun()) return false; return this.Parent.GetMathBaseFirst(); } ParaRun.prototype.GetFontSlotByPosition = function(nPos) { if (nPos > this.Content.length || nPos < 0 || this.Content.length <= 0) return AscWord.fontslot_None; let oTextPr = this.Get_CompiledPr(false); if (oTextPr.RTL || oTextPr.CS) return AscWord.fontslot_CS; let oPrev, oNext; if (nPos > 0) oPrev = this.GetElement(nPos - 1); if (nPos < this.Content.length) oNext = this.GetElement(nPos); let nFontSlot = AscWord.fontslot_None; if (oPrev) nFontSlot = oPrev.GetFontSlot(oTextPr); else if (oNext) nFontSlot = oNext.GetFontSlot(oTextPr); return nFontSlot; }; ParaRun.prototype.SetIsRecalculated = function(isRecalculated) { if (!isRecalculated && this.Paragraph) this.Paragraph.SetIsRecalculated(false); }; ParaRun.prototype.private_UpdateMarksOnAdd = function(pos, count) { if (AscCommon.CollaborativeEditing.IsSplitConcatRun()) return; for (let iMark = 0, nMarks = this.SearchMarks.length; iMark < nMarks; ++iMark) { var Mark = this.SearchMarks[iMark]; var ContentPos = ( true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos ); var Depth = Mark.Depth; if (ContentPos.Data[Depth] > pos || (ContentPos.Data[Depth] === pos && true === Mark.Start)) ContentPos.Data[Depth] += count; } for (let iMark = 0, nMarks = this.SpellingMarks.length; iMark < nMarks; ++iMark) { this.SpellingMarks[iMark].onAdd(pos, count); } this.private_UpdateCustomMarksOnAdd(pos, count); }; ParaRun.prototype.private_UpdateMarksOnRemove = function(pos, count) { if (AscCommon.CollaborativeEditing.IsSplitConcatRun()) return; for (let iMark = 0, nMarks = this.SearchMarks.length; iMark < nMarks; ++iMark) { var Mark = this.SearchMarks[iMark]; var ContentPos = (true === Mark.Start ? Mark.SearchResult.StartPos : Mark.SearchResult.EndPos); var Depth = Mark.Depth; if (ContentPos.Data[Depth] > pos + count) ContentPos.Data[Depth] -= count; else if (ContentPos.Data[Depth] > pos) ContentPos.Data[Depth] = Math.max(0, pos); } for (let iMark = 0, nMarks = this.SpellingMarks.length; iMark < nMarks; ++iMark) { this.SpellingMarks[iMark].onRemove(pos, count); } this.private_UpdateCustomMarksOnRemove(pos, count); }; ParaRun.prototype.private_UpdateMarksOnSplit = function(pos, nextRun) { if (!nextRun) return; for (let iMark = 0, nMarks = this.SpellingMarks.length; iMark < nMarks; ++iMark) { let mark = this.SpellingMarks[iMark]; if (mark.getPos() >= pos) { mark.movePos(-pos); nextRun.SpellingMarks.push(mark); this.SpellingMarks.splice(iMark, 1); --nMarks; --iMark; } } this.private_UpdateCustomMarksOnSplit(pos, nextRun); }; ParaRun.prototype.private_UpdateMarksOnConcat = function(pos, run) { if (!run) return; // Присылаем сюда позицию pos не потому что в любой позции соединяем, а чтобы данный вызов не контролировать // относительно времени соединения ранов (т.е. на данный момент соединение уже может быть, а может и не быть) // Мы, в любом случае считаем, что когда раны соединялись, то длина первого рана равнялась pos for (let iMark = 0, nMarks = run.SpellingMarks.length; iMark < nMarks; ++iMark) { let mark = run.SpellingMarks[iMark]; mark.movePos(pos); this.SpellingMarks.push(mark); } this.private_UpdateCustomMarksOnConcat(pos, run); }; ParaRun.prototype.private_UpdateCustomMarksOnAdd = function(pos, count) { let logicDocument = this.GetLogicDocument(); let customMarks = logicDocument && logicDocument.IsDocumentEditor() ? logicDocument.GetCustomMarks() : null; if (customMarks) customMarks.onAddToRun(this.GetId(), pos, count); }; ParaRun.prototype.private_UpdateCustomMarksOnRemove = function(pos, count) { let logicDocument = this.GetLogicDocument(); let customMarks = logicDocument && logicDocument.IsDocumentEditor() ? logicDocument.GetCustomMarks() : null; if (customMarks) customMarks.onRemoveFromRun(this.GetId(), pos, count); }; ParaRun.prototype.private_UpdateCustomMarksOnSplit = function(pos, nextRun) { let logicDocument = this.GetLogicDocument(); let customMarks = logicDocument && logicDocument.IsDocumentEditor() ? logicDocument.GetCustomMarks() : null; if (customMarks) customMarks.onSplitRun(this.GetId(), pos, nextRun.GetId()); }; ParaRun.prototype.private_UpdateCustomMarksOnConcat = function(pos, run) { let logicDocument = this.GetLogicDocument(); let customMarks = logicDocument && logicDocument.IsDocumentEditor() ? logicDocument.GetCustomMarks() : null; if (customMarks) customMarks.onConcatRun(this.GetId(), pos, run.GetId()); }; function CParaRunStartState(Run) { this.Paragraph = Run.Paragraph; this.Pr = Run.Pr.Copy(); this.Content = []; for(var i = 0; i < Run.Content.length; ++i) { this.Content.push(Run.Content[i]); } } /** * @constructor */ function CRunWithPosition(oRun, nPos) { this.Run = oRun; this.Pos = nPos; } CRunWithPosition.prototype.SetDocumentPositionHere = function() { this.Run.State.ContentPos = this.Pos; this.Run.Make_ThisElementCurrent(); // Не корректируем позицию внутри параграфа в данной функции, либо надо переделывать удаление в обратном // порядке в ране в случае рецензирования, т.к. в такой ситуации можно оставлять курсор между CombiningMarks, // в то время как в обычной ситуации мы не даем туда поставить курсор }; function CanUpdatePosition(Para, Run) { return (Para && true === Para.IsUseInDocument() && true === Run.IsUseInParagraph()); } //--------------------------------------------------------export---------------------------------------------------- window['AscCommonWord'] = window['AscCommonWord'] || {}; window['AscCommonWord'].ParaRun = ParaRun; window['AscCommonWord'].CanUpdatePosition = CanUpdatePosition; window['AscWord'] = window['AscWord'] || {}; window['AscWord'].ParaRun = ParaRun; window['AscWord'].CRun = ParaRun; window['AscWord'].Run = ParaRun;