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

3809 lines
153 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* (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";
var c_oAscSectionBreakType = Asc.c_oAscSectionBreakType;
CTable.prototype.Recalculate_Page = function(PageIndex)
{
//-------------------------------------------------------------------------------------------------------------
// Обрабатываем настройку "не отрывать от следующего"
//-------------------------------------------------------------------------------------------------------------
let result = this.RecalculateKeepNext(PageIndex);
if (result !== recalcresult_NextElement)
return result;
this.SetIsRecalculated(true);
if (0 === PageIndex)
{
// TODO: Внутри функции private_RecalculateBorders происходит персчет метрик каждой ячейки, это надо бы
// вынести в отдельную функцию. Из-за этого функцию private_RecalculateHeader приходится запускать позже.
this.private_RecalculateGrid();
this.private_RecalculateBorders();
this.private_RecalculateHeader();
}
this.private_RecalculatePageXY(PageIndex);
if (true !== this.private_RecalculateCheckPageColumnBreak(PageIndex))
return recalcresult_NextPage | recalcresultflags_Column;
this.private_RecalculatePositionX(PageIndex);
result = this.private_RecalculatePage(PageIndex);
if (result & recalcresult_CurPage)
return result;
this.private_RecalculatePositionY(PageIndex);
if (result & recalcresult_NextElement)
this.RecalcInfo.Reset(false);
if (result & recalcresult_NextElement && window['AscCommon'].g_specialPasteHelper && window['AscCommon'].g_specialPasteHelper.showButtonIdParagraph === this.GetId())
window['AscCommon'].g_specialPasteHelper.SpecialPasteButtonById_Show();
this.Sections[this.Sections.length - 1].endPage = PageIndex;
return result;
};
CTable.prototype.Recalculate_SkipPage = function(PageIndex)
{
if (0 === PageIndex)
{
this.StartFromNewPage();
}
else
{
var PrevPage = this.Pages[PageIndex - 1];
var LastRow = Math.max(PrevPage.FirstRow, PrevPage.LastRow); // На случай, если предыдущая страница тоже пустая
var NewPage = new CTablePage(PrevPage.X, PrevPage.Y, PrevPage.XLimit, PrevPage.YLimit, LastRow, PrevPage.MaxTopBorder);
NewPage.FirstRow = LastRow;
NewPage.LastRow = LastRow - 1;
this.Pages[PageIndex] = NewPage;
this.HeaderInfo.Pages[PageIndex] = {};
this.HeaderInfo.Pages[PageIndex].Draw = false;
for (let rowIndex = -1; rowIndex < this.Content.length; ++rowIndex)
{
if (!this.TableRowsBottom[rowIndex])
this.TableRowsBottom[rowIndex] = [];
this.TableRowsBottom[rowIndex][PageIndex] = 0;
}
}
};
CTable.prototype.Recalculate_Grid = function()
{
this.private_RecalculateGrid();
};
CTable.prototype.SaveRecalculateObject = function()
{
var RecalcObj = new CTableRecalculateObject();
RecalcObj.Save(this);
return RecalcObj;
};
CTable.prototype.LoadRecalculateObject = function(RecalcObj)
{
RecalcObj.Load(this);
};
CTable.prototype.PrepareRecalculateObject = function()
{
this.TableSumGrid = [];
this.TableGridCalc = [];
this.TableRowsBottom = [];
this.RowsInfo = [];
this.HeaderInfo = {
Count : 0,
H : 0,
PageIndex : 0,
Pages : []
};
this.Pages = [];
this.MaxTopBorder = [];
this.MaxBotBorder = [];
this.MaxBotMargin = [];
this.RecalcInfo.Reset(true);
var Count = this.Content.length;
for (var Index = 0; Index < Count; Index++)
{
this.Content[Index].PrepareRecalculateObject();
}
};
CTable.prototype.StartFromNewPage = function()
{
this.Pages.length = 1;
this.Pages[0] = new CTablePage(0, 0, 0, 0, 0, 0);
this.Pages[0].LastRow = -1;
this.HeaderInfo.Pages[0] = {};
this.HeaderInfo.Pages[0].Draw = false;
this.RowsInfo[0] = new CTableRowsInfo();
this.RowsInfo[0].Init();
// Обнуляем таблицу суммарных высот ячеек
for (var Index = -1; Index < this.Content.length; Index++)
{
this.TableRowsBottom[Index] = [];
this.TableRowsBottom[Index][0] = 0;
}
this.Pages[0].MaxBotBorder = 0;
this.Pages[0].BotBorders = [];
if (this.Content.length > 0)
{
var CellsCount = this.Content[0].Get_CellsCount();
for (var CurCell = 0; CurCell < CellsCount; CurCell++)
{
var Cell = this.Content[0].Get_Cell(CurCell);
Cell.Content.StartFromNewPage();
Cell.PagesCount = 2;
}
}
};
//----------------------------------------------------------------------------------------------------------------------
// Приватные функции связанные с расчетом таблицы
//----------------------------------------------------------------------------------------------------------------------
CTable.prototype.private_RecalculateCheckPageColumnBreak = function(CurPage)
{
if (true !== this.Is_Inline()) // Случай Flow разбирается в Document.js
return true;
let logicDocument = this.GetLogicDocument();
if (!this.Parent || !this.Parent.IsAllowSectionBreak() || !logicDocument)
return true;
let docSections = logicDocument.GetSections();
var isPageBreakOnPrevLine = false;
var isColumnBreakOnPrevLine = false;
var PrevElement = this.Get_DocumentPrev();
while (PrevElement && (PrevElement instanceof CBlockLevelSdt))
PrevElement = PrevElement.GetLastElement();
if (null !== PrevElement && type_Paragraph === PrevElement.Get_Type() && true === PrevElement.Is_Empty() && undefined !== PrevElement.Get_SectionPr())
{
var PrevSectPr = PrevElement.Get_SectionPr();
var CurSectPr = docSections.GetSectPrByElement(this);
if (c_oAscSectionBreakType.Continuous === CurSectPr.Get_Type() && true === CurSectPr.Compare_PageSize(PrevSectPr))
PrevElement = PrevElement.Get_DocumentPrev();
}
if ((0 === CurPage || true === this.Check_EmptyPages(CurPage - 1)) && null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
{
var bNeedPageBreak = true;
if (undefined !== PrevElement.Get_SectionPr())
{
var PrevSectPr = PrevElement.Get_SectionPr();
var CurSectPr = docSections.GetSectPrByElement(this);
if (c_oAscSectionBreakType.Continuous !== CurSectPr.Get_Type() || true !== CurSectPr.Compare_PageSize(PrevSectPr))
bNeedPageBreak = false;
}
if (true === bNeedPageBreak)
{
var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
if (-1 !== EndLine && PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage)
isPageBreakOnPrevLine = true;
}
}
// ColumnBreak для случая CurPage > 0 не разбираем здесь, т.к. он срабатывает автоматически
if (0 === CurPage && null !== PrevElement && type_Paragraph === PrevElement.Get_Type())
{
var EndLine = PrevElement.Pages[PrevElement.Pages.length - 1].EndLine;
if (-1 !== EndLine && !(PrevElement.Lines[EndLine].Info & paralineinfo_BreakRealPage) && PrevElement.Lines[EndLine].Info & paralineinfo_BreakPage)
isColumnBreakOnPrevLine = true;
}
if ((true === isPageBreakOnPrevLine && (0 !== this.GetAbsoluteColumn(CurPage) || (0 === CurPage && null !== PrevElement)))
|| (true === isColumnBreakOnPrevLine && 0 === CurPage))
{
this.Recalculate_SkipPage(CurPage);
return false;
}
return true;
};
CTable.prototype.private_RecalculateGrid = function(pageFields)
{
if (this.GetRowsCount() <= 0)
return;
//---------------------------------------------------------------------------
// 1 часть пересчета ширины таблицы : Рассчитываем фиксированную ширину
//---------------------------------------------------------------------------
var TablePr = this.Get_CompiledPr(false).TablePr;
var PctWidth = this.CalculatedPctWidth;
var MinWidth = this.CalculatedMinWidth;
var nTableW = this.CalculatedTableW;
if (null === this.CalculatedX || null === this.CalculatedXLimit || Math.abs(this.X - this.CalculatedX) > 0.001 || Math.abs(this.XLimit - this.CalculatedXLimit))
{
this.CalculatedX = this.X;
this.CalculatedXLimit = this.XLimit;
this.RecalcInfo.TableGrid = true;
this.RecalcInfo.TableBorders = true;
// Запускаем пересчет границ, потому что там пересчитываются метрики ячеек, которые зависят от X, XLimit
}
if (this.RecalcInfo.TableGrid)
{
let layoutCoeff = this.getLayoutScaleCoefficient();
var arrSumGrid = [];
var nTempSum = 0;
arrSumGrid[-1] = 0;
for (var nIndex = 0, nCount = this.TableGrid.length; nIndex < nCount; ++nIndex)
{
nTempSum += this.TableGrid[nIndex] * layoutCoeff;
arrSumGrid[nIndex] = nTempSum;
}
PctWidth = this.private_RecalculatePercentWidth();
MinWidth = this.private_GetTableMinWidth() * layoutCoeff;
nTableW = 0;
if (tblwidth_Auto === TablePr.TableW.Type)
{
nTableW = 0;
}
else if (tblwidth_Nil === TablePr.TableW.Type)
{
nTableW = MinWidth;
}
else
{
if (tblwidth_Pct === TablePr.TableW.Type)
nTableW = PctWidth * TablePr.TableW.W / 100;
else
nTableW = TablePr.TableW.W * layoutCoeff;
if (0.001 > nTableW)
nTableW = 0;
else if (nTableW < MinWidth)
nTableW = MinWidth;
}
var nCurGridCol = 0;
for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
{
var oRow = this.GetRow(nCurRow);
oRow.SetIndex(nCurRow);
// Смотрим на ширину пропущенных колонок сетки в начале строки
var oBeforeInfo = oRow.GetBefore();
nCurGridCol = oBeforeInfo.Grid;
if (nCurGridCol > 0 && arrSumGrid[nCurGridCol - 1] < oBeforeInfo.W)
{
var nTempDiff = oBeforeInfo.W - arrSumGrid[nCurGridCol - 1];
for (var nTempIndex = nCurGridCol - 1; nTempIndex < arrSumGrid.length; ++nTempIndex)
{
arrSumGrid[nTempIndex] += nTempDiff;
}
}
var nCellSpacing = oRow.GetCellSpacing();
for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
{
var oCell = oRow.GetCell(nCurCell);
oCell.SetIndex(nCurCell);
var oCellW = oCell.GetW();
var nGridSpan = oCell.GetGridSpan();
if (vmerge_Restart !== oCell.GetVMerge())
{
nCurGridCol += nGridSpan;
continue;
}
if (nCurGridCol + nGridSpan - 1 > arrSumGrid.length)
{
for (var nAddIndex = arrSumGrid.length; nAddIndex <= nCurGridCol + nGridSpan - 1; ++nAddIndex)
{
// Добавляем столбик шириной в 2 см
arrSumGrid[nAddIndex] = arrSumGrid[nAddIndex - 1] + 20;
}
}
if (tblwidth_Auto !== oCellW.Type && tblwidth_Nil !== oCellW.Type)
{
var nCellWidth = 0;
if (tblwidth_Pct === oCellW.Type)
nCellWidth = PctWidth * oCellW.W / 100;
else
nCellWidth = oCellW.W * layoutCoeff;
if (null !== nCellSpacing)
{
if (0 === nCurCell)
nCellWidth += nCellSpacing / 2;
nCellWidth += nCellSpacing;
if (nCellsCount - 1 === nCurCell)
nCellWidth += nCellSpacing / 2;
}
if (nCellWidth + arrSumGrid[nCurGridCol - 1] > arrSumGrid[nCurGridCol + nGridSpan - 1])
{
var nTempDiff = nCellWidth + arrSumGrid[nCurGridCol - 1] - arrSumGrid[nCurGridCol + nGridSpan - 1];
for (var nTempIndex = nCurGridCol + nGridSpan - 1; nTempIndex < arrSumGrid.length; ++nTempIndex)
{
arrSumGrid[nTempIndex] += nTempDiff;
}
}
}
nCurGridCol += nGridSpan;
}
// Смотрим на ширину пропущенных колонок сетки в конце строки
var oAfterInfo = oRow.GetAfter();
if (nCurGridCol + oAfterInfo.Grid - 1 > arrSumGrid.length)
{
for (var nAddIndex = arrSumGrid.length; nAddIndex <= nCurGridCol + oAfterInfo.Grid - 1; ++nAddIndex)
{
// Добавляем столбик шириной в 2 см
arrSumGrid[nAddIndex] = arrSumGrid[nAddIndex - 1] + 20;
}
}
if (arrSumGrid[nCurGridCol + oAfterInfo.Grid - 1] < oAfterInfo.W + arrSumGrid[nCurGridCol - 1])
{
var nTempDiff = oAfterInfo.W + arrSumGrid[nCurGridCol - 1] - arrSumGrid[nCurGridCol + oAfterInfo.Grid - 1];
for (var nTempIndex = nCurGridCol + oAfterInfo.Grid - 1; nTempIndex < arrSumGrid.length; ++nTempIndex)
{
arrSumGrid[nTempIndex] += nTempDiff;
}
}
}
// TODO: разобраться с минимальной шириной таблицы и ячеек
// Задана общая ширина таблицы и последняя ячейка вышла за пределы
// данной ширины. Уменьшаем все столбцы сетки пропорционально, чтобы
// суммарная ширина стала равной заданной ширине таблицы.
if (nTableW > 0 && Math.abs(arrSumGrid[arrSumGrid.length - 1] - nTableW) > 0.01)
arrSumGrid = this.Internal_ScaleTableWidth(arrSumGrid, nTableW);
else if (MinWidth > arrSumGrid[arrSumGrid.length - 1])
arrSumGrid = this.Internal_ScaleTableWidth(arrSumGrid, arrSumGrid[arrSumGrid.length - 1]);
// По массиву SumGrid восстанавливаем ширины самих колонок
this.TableGridCalc = [];
this.TableGridCalc[0] = arrSumGrid[0];
for (var nIndex = 1, nCount = arrSumGrid.length; nIndex < nCount; ++nIndex)
{
this.TableGridCalc[nIndex] = arrSumGrid[nIndex] - arrSumGrid[nIndex - 1];
}
this.TableSumGrid = arrSumGrid;
this.CalculatedPctWidth = PctWidth;
this.CalculatedMinWidth = MinWidth;
this.CalculatedTableW = nTableW;
this.RecalcInfo.TableGrid = false;
}
var TopTable = this.Parent ? this.Parent.IsInTable(true) : null;
if ((null === TopTable && tbllayout_AutoFit === TablePr.TableLayout) || (null != TopTable && tbllayout_AutoFit === TopTable.Get_CompiledPr(false).TablePr.TableLayout))
{
//---------------------------------------------------------------------------
// 2 часть пересчета ширины таблицы : Рассчитываем ширину по содержимому
//---------------------------------------------------------------------------
// 1. Расчитаем минимальные и максимальные значения ширины для всех колонок, а также минимальное значение
// отступов и предпочитаемую ширину колонок
var arrMinMargin = [],
arrMinContent = [],
arrMaxContent = [],
arrPreferred = [], // 0 - ориентируемся на содержимое ячеек, > 0 - ориентируемся только на ширину ячеек записанную в свойствах
arrMinNoPref = []; // минимальное значение контента, только без учета предпочитаемы ширин
var nColsCount = this.TableGridCalc.length;
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
arrMinMargin[nCurCol] = 0;
arrMinContent[nCurCol] = 0;
arrMaxContent[nCurCol] = 0;
arrPreferred[nCurCol] = 0;
arrMinNoPref[nCurCol] = 0;
}
this.private_RecalculateGridMinContent(PctWidth, arrMinMargin, arrMinContent, arrMaxContent, arrPreferred, arrMinNoPref);
// 2. Проследим, чтобы значения arrMinContent и arrMaxContent не превосходили значение 55,87см(так работает Word)
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
if (arrMaxContent[nCurCol] < arrMinContent[nCurCol])
arrMaxContent[nCurCol] = arrMinContent[nCurCol];
if (arrMinNoPref[nCurCol] > 558.7)
arrMinNoPref[nCurCol] = 558.7;
if (arrMinContent[nCurCol] > 558.7)
arrMinContent[nCurCol] = 558.7;
if (arrMaxContent[nCurCol] > 558.7)
arrMaxContent[nCurCol] = 558.7;
}
// 3. Рассчитаем максимально допустимую ширину под всю таблицу
var oPageFields;
if (pageFields)
{
oPageFields = {
X : pageFields.X,
Y : pageFields.Y,
XLimit : pageFields.XLimit,
YLimit : pageFields.YLimit
};
}
else if (!this.Parent)
{
oPageFields = {
X : 0,
Y : 0,
XLimit : 0,
YLimit : 0
};
}
else
{
// Случай, когда таблица лежит внутри CBlockLevelSdt
if (this.Parent instanceof CDocumentContent && this.LogicDocument && this.Parent.IsBlockLevelSdtContent() && this.Parent.GetTopDocumentContent() === this.LogicDocument && !this.Parent.IsTableCellContent())
oPageFields = this.LogicDocument.GetColumnFields(this.GetAbsolutePage(this.PageNum), this.GetAbsoluteColumn(this.PageNum), this.GetAbsoluteSection(this.PageNum));
if (!oPageFields)
oPageFields = this.Parent.GetColumnFields ? this.Parent.GetColumnFields(this.GetAbsolutePage(this.PageNum), this.GetAbsoluteColumn(this.PageNum), this.GetAbsoluteSection(this.PageNum)) : this.Parent.Get_PageFields(this.GetRelativePage(this.PageNum), this.Parent.IsHdrFtr());
}
this.CalculatedPageFields = {
X : oPageFields.X,
Y : oPageFields.Y,
XLimit : oPageFields.XLimit,
YLimit : oPageFields.YLimit
};
var oFramePr = this.GetFramePr();
if (oFramePr && undefined !== oFramePr.GetW())
{
oPageFields.X = 0;
oPageFields.XLimit = oFramePr.GetW();
}
else if (this.LogicDocument && this.LogicDocument.IsDocumentEditor() && this.IsInline())
{
var _X = oPageFields.X;
var _XLimit = oPageFields.XLimit;
var arrRanges = this.Parent.CheckRange(_X, this.Y, _XLimit, this.Y + 0.001, this.Y, this.Y + 0.001, _X, _XLimit, this.GetRelativePage(0));
if (arrRanges.length > 0)
{
for (var nRangeIndex = 0, nRangesCount = arrRanges.length; nRangeIndex < nRangesCount; ++nRangeIndex)
{
if (arrRanges[nRangeIndex].X0 < oPageFields.X + 3.2 && arrRanges[nRangeIndex].X1 > _X)
_X = arrRanges[nRangeIndex].X1 + 0.001;
if (arrRanges[nRangeIndex].X1 > oPageFields.XLimit - 3.2 && arrRanges[nRangeIndex].X0 < _XLimit)
_XLimit = arrRanges[nRangeIndex].X0 - 0.001;
}
}
oPageFields.X = _X;
oPageFields.XLimit = _XLimit;
}
var nMaxTableW = oPageFields.XLimit - oPageFields.X - TablePr.TableInd - this.GetTableOffsetCorrection() + this.GetRightTableOffsetCorrection();
// 4. Рассчитаем желаемую ширину таблицы таблицы
var arrMaxOverMin = [],
nSumMaxOverMin = 0,
nSumMin = 0,
nSumMinMargin = 0,
nSumMax = 0;
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
arrMaxOverMin[nCurCol] = Math.max(0, arrMaxContent[nCurCol] - arrMinContent[nCurCol]);
nSumMin += arrMinContent[nCurCol];
nSumMaxOverMin += arrMaxOverMin[nCurCol];
nSumMinMargin += arrMinMargin[nCurCol];
nSumMax += arrMinContent[nCurCol] + arrMaxOverMin[nCurCol];
}
var nMaxTableWOrigin = nMaxTableW;
if ((TablePr.TableW.IsMM() || TablePr.TableW.IsPercent()) && nMaxTableW < nTableW)
nMaxTableW = nTableW;
if (nSumMin < nMaxTableW)
{
if (nSumMax <= nMaxTableW || nSumMaxOverMin < 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = Math.max(arrMinContent[nCurCol], arrMaxContent[nCurCol]);
}
}
else
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinContent[nCurCol] + (nMaxTableW - nSumMin) * arrMaxOverMin[nCurCol] / nSumMaxOverMin;
}
}
// Если у таблицы задана ширина, тогда ориентируемся по ширине, а если нет, тогда ориентируемся по
// максимальным значениям.
if (TablePr.TableW.IsMM() || TablePr.TableW.IsPercent())
{
if (nSumMin < 0.001 && nSumMax < 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = nTableW / nColsCount;
}
}
else if (nSumMin >= nTableW)
{
var nSumMinContent = 0,
nSumPrefOverMinContent = 0,
arrPrefOverMinContent = [];
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
arrPrefOverMinContent[nCurCol] = Math.max(0, arrMinContent[nCurCol] - arrMinNoPref[nCurCol]);
nSumPrefOverMinContent += arrPrefOverMinContent[nCurCol];
nSumMinContent += arrMinNoPref[nCurCol];
}
if (nSumMinContent >= nTableW)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinNoPref[nCurCol];
}
}
else
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinNoPref[nCurCol] + arrPrefOverMinContent[nCurCol] * (nTableW - nSumMinContent) / nSumPrefOverMinContent;
}
}
}
else
{
// nSumMin < nMaxTableW, значит у нас есть свободное пространство для распределения
// Колонки, у которых задана предпочитаемая ширина не трогаем, с одним исключением, когда
// такие колонки все, в этом случае растягиваем их пропрорционально
var nSumMaxOverMin = 0,
isAllPreferred = true,
arrNoPrefMaxOverMin = [],
nSumMaxOverMin = 0,
nSumNonPrefMax = 0,
nSumPrefMin = 0,
nSumNoPrefMin = 0;
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
if (arrPreferred[nCurCol] < 0.001)
{
isAllPreferred = false;
var nMinW = arrMinContent[nCurCol];
var nMaxW = Math.max(arrMaxContent[nCurCol], nMinW);
arrNoPrefMaxOverMin[nCurCol] = nMaxW - nMinW;
nSumMaxOverMin += nMaxW - nMinW;
nSumNonPrefMax += nMaxW;
nSumNoPrefMin += nMinW;
}
else
{
nSumPrefMin += arrMinContent[nCurCol];
arrNoPrefMaxOverMin[nCurCol] = 0;
}
}
// Если данное условие выполняется, значит у нас все ячейки с предпочитаемыми значениями, тогда
// мы растягиваем все ячейки равномерно. Если не выполняется, значит есть ячейки, в которых
// предпочитаемое значение не задано, и тогда растягиваем только такие ячейки.
if (isAllPreferred)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinContent[nCurCol] * nTableW / nSumMin;
}
}
else if (nSumNonPrefMax < nMaxTableW - nSumMin && nSumNonPrefMax > 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
if (arrPreferred[nCurCol] < 0.001)
this.TableGridCalc[nCurCol] = arrMaxContent[nCurCol] * (nTableW - nSumPrefMin) / nSumNonPrefMax;
else
this.TableGridCalc[nCurCol] = arrMinContent[nCurCol];
}
}
else if (nSumMaxOverMin > 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinContent[nCurCol] + (nTableW - nSumMin) * arrNoPrefMaxOverMin[nCurCol] / nSumMaxOverMin;
}
}
else if (nSumNoPrefMin > 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
if (arrPreferred[nCurCol] < 0.001)
this.TableGridCalc[nCurCol] = arrMinContent[nCurCol] * (nTableW - nSumPrefMin) / nSumNoPrefMin;
else
this.TableGridCalc[nCurCol] = arrMinContent[nCurCol];
}
}
else
{
// Такого быть не должно
}
}
}
}
else
{
// Если в таблице сделать все ячейки нулевой ширины (для контента), и все равно она получается шире
// максимальной допустимой ширины, тогда выставляем ширины всех колоно по минимальному значению
// маргинов и оставляем так как есть
if (nMaxTableW - nSumMinMargin < 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinMargin[nCurCol];
}
}
else
{
var nSumMinContent = 0,
nSumPrefOverMinContent = 0,
arrPrefOverMinContent = [];
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
arrPrefOverMinContent[nCurCol] = Math.max(0, arrMinContent[nCurCol] - arrMinNoPref[nCurCol]);
nSumPrefOverMinContent += arrPrefOverMinContent[nCurCol];
nSumMinContent += arrMinNoPref[nCurCol];
}
if (nSumMinContent > nMaxTableW)
{
if (nTableW > nMaxTableWOrigin)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinNoPref[nCurCol];
}
}
else
{
var nSumMinNoPrefOverMinMargin = 0,
arrMinNoPrefOverMinMargin = [];
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
arrMinNoPrefOverMinMargin[nCurCol] = Math.max(arrMinNoPref[nCurCol] - arrMinMargin[nCurCol], 0);
nSumMinNoPrefOverMinMargin += arrMinNoPrefOverMinMargin[nCurCol];
}
if (nSumMinNoPrefOverMinMargin > 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinMargin[nCurCol] + arrMinNoPrefOverMinMargin[nCurCol] * (nMaxTableW - nSumMinMargin) / nSumMinNoPrefOverMinMargin;
}
}
else
{
// Такого быть не должно, т.к. мы в ветке nMaxTableW > nSumMinMargin + 0.001 && nSumMinContent > nMaxTableW
}
}
}
else
{
// Если попали в эту ветку, то это может означать только одно, что у нас есть ячейки с заданной
// шириной, превышающей минимальное значения ширины контента
if ((TablePr.TableW.IsMM() || TablePr.TableW.IsPercent()) && nTableW < nSumMinContent)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinNoPref[nCurCol];
}
}
else
{
var _nTableW = (TablePr.TableW.IsMM() || TablePr.TableW.IsPercent() ? nTableW : nMaxTableWOrigin);
var nSumPrefOverMinContent = 0,
arrPrefOverMinContent = [];
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
arrPrefOverMinContent[nCurCol] = Math.max(arrMinContent[nCurCol] - arrMinNoPref[nCurCol], 0);
nSumPrefOverMinContent += arrPrefOverMinContent[nCurCol];
}
if (nSumPrefOverMinContent > 0.001)
{
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinNoPref[nCurCol] + arrPrefOverMinContent[nCurCol] * (_nTableW - nSumMinContent) / nSumPrefOverMinContent;
}
}
else
{
// Такого быть не должно
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
{
this.TableGridCalc[nCurCol] = arrMinNoPref[nCurCol];
}
}
}
}
}
}
this.TableSumGrid[-1] = 0;
for (var nCurCol = 0; nCurCol < nColsCount; ++nCurCol)
this.TableSumGrid[nCurCol] = this.TableSumGrid[nCurCol - 1] + this.TableGridCalc[nCurCol];
}
};
CTable.prototype.private_RecalculateGridMinContent = function(nPctWidth, arrMinMargins, arrMinContent, arrMaxContent, arrPreferred, arrMinNoPreferred)
{
// Сначала мы высчитываем минимальный и максимальный контент для всех ячеек с GridSpan=1, ячейки
// у которых GridSpan > 1 заносим в массив arrMergedColumns.
// После обработки всех ячеек с GridSpan=1, мы пробегаемся по массиву arrMergedPreferred, это ячейки, у которых
// GridSpan > 1 и у которых задана предпочтительная ширина. Далее на основе этих ячееки высчитываем предпочтительную
// ширину колонок. Причем делаем это начиная с ячеек с наименьшим GridSpan.
// Далее пробегаемся по arrMergedCells и если какой-нибудь отрезок из колонок (StartGrid, StartGrid+GridSpan)
// по ширине занимает место больше, чем эти колонки по отдельности, тогда мы добавочное место распределяем среди
// колонок с сохранением соотношения их ширины, как частный случай, если у нас встретилась колонка нулевой ширины,
// например, у которой вообще не было целой ячейки внутри колонки, тогда она так и останется нулевой ширины
// после распределения. Причем тут важно, что мы пробегаемся по массиву подряд, а не на основе GridSpan, как
// у arrMergedPreferred, поэтому результат для одной и той же таблицы, с переставленными двумя строками может
// быть разным.
let layoutCoeff = this.getLayoutScaleCoefficient();
var arrMergedColumns = [];
var arrMergedPreferred = [];
var nMergedPrefCount = 0;
for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
{
var oRow = this.GetRow(nCurRow);
var nSpacing = oRow.GetCellSpacing();
var nSpacingW = (null !== nSpacing ? nSpacing : 0);
var nCurGridCol = 0;
var oBeforeInfo = oRow.GetBefore();
var nGridBefore = oBeforeInfo.Grid;
var nBeforeW = oBeforeInfo.W.GetCalculatedValue(nPctWidth);
if (nBeforeW > 0 && nGridBefore > 0)
{
if (1 === nGridBefore)
{
if (arrMinContent[nCurGridCol] < nBeforeW)
arrMinContent[nCurGridCol] = nBeforeW;
if (0 === arrPreferred[nCurGridCol] || arrPreferred[nCurGridCol] < nBeforeW)
arrPreferred[nCurGridCol] = nBeforeW;
if (arrPreferred[nCurGridCol])
arrMaxContent[nCurGridCol] = arrPreferred[nCurGridCol];
else if (arrMaxContent[nCurGridCol] < nBeforeW)
arrMaxContent[nCurGridCol] = nBeforeW;
}
else
{
arrMergedColumns.push({
Start : nCurGridCol,
Min : nBeforeW,
Max : nBeforeW,
Preferred : nBeforeW,
Margins : 0,
Grid : nGridBefore,
MinNoPref : 0
});
if (!arrMergedPreferred[nGridBefore])
arrMergedPreferred[nGridBefore] = [];
arrMergedPreferred[nGridBefore].push({
Start : nCurGridCol,
W : nBeforeW
});
nMergedPrefCount++;
}
}
nCurGridCol = nGridBefore;
for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
{
var oCell = oRow.GetCell(nCurCell);
var oCellMinMax = oCell.RecalculateMinMaxContentWidth(false, nPctWidth);
var nGridSpan = oCell.GetGridSpan();
var nCellMin = oCellMinMax.Min;
var nCellMax = oCellMinMax.Max;
var oCellW = oCell.GetW();
var oMargins = oCell.GetMargins();
var nPreferred = oCellW.GetCalculatedValue(nPctWidth) * layoutCoeff;
var nSpacingAdd = (0 === nCurCell || nCellsCount - 1 === nCurCell) ? 3 / 2 * nSpacingW : nSpacingW;
var nMarginsMin = nSpacingAdd + oMargins.Left.W + oMargins.Right.W;
nCellMin += nSpacingAdd;
nCellMax += nSpacingAdd;
if (1 === nGridSpan)
{
if (arrMinContent[nCurGridCol] < nCellMin)
arrMinContent[nCurGridCol] = nCellMin;
if (nPreferred && arrPreferred[nCurGridCol] < nPreferred)
arrPreferred[nCurGridCol] = nPreferred;
if (arrPreferred[nCurGridCol])
arrMaxContent[nCurGridCol] = arrPreferred[nCurGridCol];
else if (arrMaxContent[nCurGridCol] < nCellMax)
arrMaxContent[nCurGridCol] = nCellMax;
if (arrMinMargins[nCurGridCol] < nMarginsMin)
arrMinMargins[nCurGridCol] = nMarginsMin;
if (arrMinNoPreferred[nCurGridCol] < oCellMinMax.ContentMin + nSpacingAdd)
arrMinNoPreferred[nCurGridCol] = oCellMinMax.ContentMin + nSpacingAdd;
}
else if (nGridSpan > 1)
{
arrMergedColumns.push({
Start : nCurGridCol,
Min : nCellMin,
Max : nCellMax,
Preferred : nPreferred,
Margins : nMarginsMin,
Grid : nGridSpan,
MinNoPref : oCellMinMax.ContentMin + nSpacingAdd
});
if (nPreferred > 0.001)
{
if (!arrMergedPreferred[nGridSpan])
arrMergedPreferred[nGridSpan] = [];
arrMergedPreferred[nGridSpan].push({
Start : nCurGridCol,
W : nPreferred
});
nMergedPrefCount++;
}
}
nCurGridCol += nGridSpan;
}
var oAfterInfo = oRow.GetAfter();
var nGridAfter = oAfterInfo.Grid;
var nAfterW = oAfterInfo.W.GetCalculatedValue(nPctWidth);
if (nAfterW > 0 && nGridAfter > 0)
{
if (1 === nGridAfter)
{
if (arrMinContent[nCurGridCol] < nAfterW)
arrMinContent[nCurGridCol] = nAfterW;
if (0 === arrPreferred[nCurGridCol] || arrPreferred[nCurGridCol] < nAfterW)
arrPreferred[nCurGridCol] = nAfterW;
if (arrPreferred[nCurGridCol])
arrMaxContent[nCurGridCol] = arrPreferred[nCurGridCol];
else if (arrMaxContent[nCurGridCol] < nAfterW)
arrMaxContent[nCurGridCol] = nAfterW;
}
else
{
arrMergedColumns.push({
Start : nCurGridCol,
Min : nAfterW,
Max : nAfterW,
Preferred : nAfterW,
Margins : 0,
Grid : nGridAfter,
MinNoPref : 0
});
if (!arrMergedPreferred[nGridAfter])
arrMergedPreferred[nGridAfter] = [];
arrMergedPreferred[nGridAfter].push({
Start : nCurGridCol,
W : nAfterW
});
nMergedPrefCount++;
}
}
}
while (nMergedPrefCount > 0)
{
var nPrevCount = nMergedPrefCount;
for (var nGridSpan = 2, nMaxGridSpan = arrMergedPreferred.length; nGridSpan < nMaxGridSpan; ++nGridSpan)
{
if (!arrMergedPreferred[nGridSpan])
continue;
for (var nIndex = arrMergedPreferred[nGridSpan].length - 1; nIndex >= 0; --nIndex)
{
var nStart = arrMergedPreferred[nGridSpan][nIndex].Start;
var nPreferred = arrMergedPreferred[nGridSpan][nIndex].W;
var nPreferredSum = 0;
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan - 1; ++nCurSpan)
{
if (arrPreferred[nCurSpan] > 0 && -1 !== nPreferredSum)
nPreferredSum += arrPreferred[nCurSpan];
else
nPreferredSum = -1;
}
if (-1 !== nPreferredSum && nPreferred > nPreferredSum && arrPreferred[nStart + nGridSpan - 1] < nPreferred - nPreferredSum)
{
arrPreferred[nStart + nGridSpan - 1] = nPreferred - nPreferredSum;
if (arrMinContent[nStart + nGridSpan - 1] < arrPreferred[nStart + nGridSpan - 1])
arrMinContent[nStart + nGridSpan - 1] = arrPreferred[nStart + nGridSpan - 1];
arrMergedPreferred[nGridSpan].splice(nIndex, 1);
nMergedPrefCount--;
}
}
}
if (nPrevCount <= nMergedPrefCount)
break;
}
for (var nIndex = 0, nCount = arrMergedColumns.length; nIndex < nCount; ++nIndex)
{
var nStart = arrMergedColumns[nIndex].Start;
var nMin = arrMergedColumns[nIndex].Min;
var nMax = arrMergedColumns[nIndex].Max;
var nMargins = arrMergedColumns[nIndex].Margins;
var nPreferred = arrMergedColumns[nIndex].Preferred;
var nGridSpan = arrMergedColumns[nIndex].Grid;
var nMinNoPref = arrMergedColumns[nIndex].MinNoPref;
var nSumSpanMin = 0;
var nSumSpanMax = 0;
var nSumMargin = 0;
var nSumSpanMinNoPref = 0;
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
nSumSpanMin += arrMinContent[nCurSpan];
nSumSpanMax += arrMaxContent[nCurSpan];
nSumMargin += arrMinMargins[nCurSpan];
nSumSpanMinNoPref += arrMinNoPreferred[nCurSpan];
}
if (nMargins > nSumMargin)
{
if (nSumMargin < 0.001)
{
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
arrMinMargins[nCurSpan] = nMargins / nGridSpan;
}
}
else
{
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
arrMinMargins[nCurSpan] = arrMinMargins[nCurSpan] * nMargins / nSumMargin;
}
}
}
if (nMin > nSumSpanMin)
{
if (nSumSpanMin < 0.001)
{
// Такого не должно быть, но на всякий случай в данной ситуации делаем равномерное распределение
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
arrMinContent[nCurSpan] = nMin / nGridSpan;
}
}
else
{
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
arrMinContent[nCurSpan] = arrMinContent[nCurSpan] * nMin / nSumSpanMin;
}
}
}
if (nMinNoPref > nSumSpanMinNoPref)
{
if (nSumSpanMin < 0.001)
{
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
arrMinNoPreferred[nCurSpan] = nMinNoPref / nGridSpan;
}
}
else
{
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
arrMinNoPreferred[nCurSpan] = arrMinContent[nCurSpan] * nMinNoPref / nSumSpanMin;
}
}
}
if (nMax > nSumSpanMax)
{
// Если у нас в объединении несколько колонок, тогда явно записанная ширина ячейки не
// перекрывает ширину ни одной из колонок, она всего лишь учавствует в определении
// максимальной ширины.
// Высчитываем сумму максимумов по колонкам, у которых стоит флаг false
var nSumSpanMax2 = 0;
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
if (arrPreferred[nCurSpan] < 0.001)
nSumSpanMax2 += arrMaxContent[nCurSpan];
}
// Если nSumSpanMax2=0, тогда во всех колонках выставлен флаг=true и мы должны учитывать
// уже имеющиеся там значения, а текущее значение будет проигнорировано
if (nSumSpanMax2 > 0.001)
{
for (var nCurSpan = nStart; nCurSpan < nStart + nGridSpan; ++nCurSpan)
{
if (arrPreferred[nCurSpan] < 0.001)
{
arrMaxContent[nCurSpan] = arrMaxContent[nCurSpan] * (nSumSpanMax - nMax + nSumSpanMax2) / nSumSpanMax2;
if (nPreferred > 0.001)
arrPreferred[nCurSpan] = arrMaxContent[nCurSpan];
}
}
}
}
}
};
CTable.prototype.private_RecalculateBorders = function()
{
if ( true != this.RecalcInfo.TableBorders )
return;
// Обнуляем таблицу суммарных высот ячеек
for ( var Index = -1; Index < this.Content.length; Index++ )
{
this.TableRowsBottom[Index] = [];
this.TableRowsBottom[Index][0] = 0;
}
// Изначально найдем верхние границы и (если нужно) нижние границы
// для каждой ячейки.
var MaxTopBorder = [];
var MaxBotBorder = [];
var MaxBotMargin = [];
for ( var Index = 0; Index < this.Content.length; Index++ )
{
MaxBotBorder[Index] = 0;
MaxTopBorder[Index] = 0;
MaxBotMargin[Index] = 0;
}
var TablePr = this.Get_CompiledPr(false).TablePr;
var TableBorders = this.Get_Borders();
var nRowsCountInHeader = this.GetRowsCountInHeader();
var oHeaderLastRow = nRowsCountInHeader ? this.GetRow(nRowsCountInHeader - 1) : null;
for ( var CurRow = 0; CurRow < this.Content.length; CurRow++ )
{
var Row = this.Content[CurRow];
var CellsCount = Row.Get_CellsCount();
var CellSpacing = Row.Get_CellSpacing();
var BeforeInfo = Row.Get_Before();
var AfterInfo = Row.Get_After();
var CurGridCol = BeforeInfo.GridBefore;
// Нам нужно пробежаться по текущей строке и выяснить максимальное значение ширины верхней
// границы и ширины нижней границы, заодно рассчитаем вид границы у каждой ячейки,
// также надо рассчитать максимальное значение нижнего отступа всей строки.
var bSpacing_Top = false;
var bSpacing_Bot = false;
if ( null != CellSpacing )
{
bSpacing_Bot = true;
bSpacing_Top = true;
}
else
{
if ( 0 != CurRow )
{
var PrevCellSpacing = this.Content[CurRow - 1].Get_CellSpacing();
if ( null != PrevCellSpacing )
bSpacing_Top = true;
}
if ( this.Content.length - 1 != CurRow )
{
var NextCellSpacing = this.Content[CurRow + 1].Get_CellSpacing();
if ( null != NextCellSpacing )
bSpacing_Bot = true;
}
}
Row.Set_SpacingInfo( bSpacing_Top, bSpacing_Bot );
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var GridSpan = Cell.Get_GridSpan();
var Vmerge = Cell.GetVMerge();
Row.Set_CellInfo( CurCell, CurGridCol, 0, 0, 0, 0, 0, 0 );
// Bug 32418 ячейки, участвующие в вертикальном объединении, все равно участвуют в определении границы
// строки, поэтому здесь мы их не пропускаем.
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
var CellMargins;
var CellBorders;
if(!this.bPresentation)
{
CellMargins = Cell.GetMargins();
CellBorders = Cell.Get_Borders();
if ( CellMargins.Bottom.W > MaxBotMargin[CurRow + VMergeCount - 1] )
MaxBotMargin[CurRow + VMergeCount - 1] = CellMargins.Bottom.W;
}
else
{
let oTopCell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
CellMargins = oTopCell.GetMargins();
CellBorders = oTopCell.Get_Borders();
MaxBotMargin[CurRow] = Math.max(MaxBotMargin[CurRow], CellMargins.Bottom.W);
}
if ( true === bSpacing_Top )
{
if ( border_Single === CellBorders.Top.Value && MaxTopBorder[CurRow] < CellBorders.Top.Size )
MaxTopBorder[CurRow] = CellBorders.Top.Size;
Cell.SetBorderInfoTop([CellBorders.Top]);
Cell.SetBorderInfoTopHeader([CellBorders.Top]);
}
else
{
if ( 0 === CurRow )
{
// Сравним границы
var Result_Border = this.private_ResolveBordersConflict( TableBorders.Top, CellBorders.Top, true, false );
if ( border_Single === Result_Border.Value && MaxTopBorder[CurRow] < Result_Border.Size )
MaxTopBorder[CurRow] = Result_Border.Size;
var BorderInfo_Top = [];
for ( var TempIndex = 0; TempIndex < GridSpan; TempIndex++ )
BorderInfo_Top.push( Result_Border );
Cell.SetBorderInfoTop(BorderInfo_Top);
Cell.SetBorderInfoTopHeader(BorderInfo_Top);
}
else
{
var oCellTopInfo = this.private_RecalculateCellTopBorder(this.GetRow(CurRow - 1), CurRow, CurGridCol, GridSpan, TableBorders, CellBorders);
var oCellTopHeaderInfo = oHeaderLastRow ? this.private_RecalculateCellTopBorder(oHeaderLastRow, CurRow, CurGridCol, GridSpan, TableBorders, CellBorders) : oCellTopInfo;
if (MaxTopBorder[CurRow] < oCellTopInfo.Max)
MaxTopBorder[CurRow] = oCellTopInfo.Max;
Cell.SetBorderInfoTop(oCellTopInfo.Info);
Cell.SetBorderInfoTopHeader(oCellTopHeaderInfo.Info);
}
}
var CellBordersBottom = CellBorders.Bottom;
if (VMergeCount > 1 && !this.bPresentation)
{
// Берем нижнюю границу нижней ячейки вертикального объединения.
var BottomCell = this.Internal_Get_EndMergedCell(CurRow, CurGridCol, GridSpan);
if (null !== BottomCell)
CellBordersBottom = BottomCell.Get_Borders().Bottom;
}
if ( true === bSpacing_Bot )
{
Cell.Set_BorderInfo_Bottom( [CellBordersBottom], -1, -1 );
if ( border_Single === CellBordersBottom.Value && CellBordersBottom.Size > MaxBotBorder[CurRow + VMergeCount - 1] )
MaxBotBorder[CurRow + VMergeCount - 1] = CellBordersBottom.Size;
}
else
{
if ( this.Content.length - 1 === CurRow + VMergeCount - 1 )
{
// Сравним границы
var Result_Border = this.private_ResolveBordersConflict( TableBorders.Bottom, CellBordersBottom, true, false );
if ( border_Single === Result_Border.Value && Result_Border.Size > MaxBotBorder[CurRow + VMergeCount - 1] )
MaxBotBorder[CurRow + VMergeCount - 1] = Result_Border.Size;
if ( GridSpan > 0 )
{
for ( var TempIndex = 0; TempIndex < GridSpan; TempIndex++ )
Cell.Set_BorderInfo_Bottom( [ Result_Border ], -1, -1 );
}
else
Cell.Set_BorderInfo_Bottom( [ ], -1, -1 );
}
else
{
// Мы должны проверить нижнюю границу ячейки, на предмет того, что со следующей строкой
// она может пересекаться по GridBefore и/или GridAfter. Везде в таких местах мы должны
// нарисовать нижнюю границу. Пересечение с ячейками нам неинтересено, потому что этот
// случай будет учтен при обсчете следующей строки (там будет случай bSpacing_Top = false
// и 0 != CurRow )
var Next_Row = this.Content[CurRow + VMergeCount];
var Next_CellsCount = Next_Row.Get_CellsCount();
var Next_BeforeInfo = Next_Row.Get_Before();
var Next_AfterInfo = Next_Row.Get_After();
var Border_Bottom_Info = [];
// Сначала посмотрим пересечение с GridBefore предыдущей строки
var BeforeCount = 0;
if ( CurGridCol <= Next_BeforeInfo.GridBefore - 1 )
{
var Result_Border = this.private_ResolveBordersConflict( TableBorders.Left, CellBordersBottom, true, false );
BeforeCount = Math.min( Next_BeforeInfo.GridBefore - CurGridCol, GridSpan );
for ( var TempIndex = 0; TempIndex < BeforeCount; TempIndex++ )
Border_Bottom_Info.push( Result_Border );
}
var Next_GridCol = Next_BeforeInfo.GridBefore;
for ( var NextCell = 0; NextCell < Next_CellsCount; NextCell++ )
{
var Next_Cell = Next_Row.Get_Cell( NextCell );
var Next_GridSpan = Next_Cell.Get_GridSpan();
Next_GridCol += Next_GridSpan;
}
// Посмотрим пересечение с GridAfter предыдущей строки
var AfterCount = 0;
if ( Next_AfterInfo.GridAfter > 0 )
{
var StartAfterGrid = Next_GridCol;
if ( CurGridCol + GridSpan - 1 >= StartAfterGrid )
{
var Result_Border = this.private_ResolveBordersConflict( TableBorders.Right, CellBordersBottom, true, false );
AfterCount = Math.min( CurGridCol + GridSpan - StartAfterGrid, GridSpan );
for ( var TempIndex = 0; TempIndex < AfterCount; TempIndex++ )
Border_Bottom_Info.push( Result_Border );
}
}
Cell.Set_BorderInfo_Bottom( Border_Bottom_Info, BeforeCount, AfterCount );
}
}
CurGridCol += GridSpan;
}
}
this.MaxTopBorder = MaxTopBorder;
this.MaxBotBorder = MaxBotBorder;
this.MaxBotMargin = MaxBotMargin;
let layoutCoeff = this.getLayoutScaleCoefficient();
// Также для каждой ячейки обсчитаем ее метрики и левую и правую границы
for ( var CurRow = 0; CurRow < this.Content.length; CurRow++ )
{
var Row = this.Content[CurRow];
var CellsCount = Row.Get_CellsCount();
var CellSpacing = Row.Get_CellSpacing();
var BeforeInfo = Row.Get_Before();
var AfterInfo = Row.Get_After();
var CurGridCol = BeforeInfo.GridBefore;
var Row_x_max = 0;
var Row_x_min = 0;
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var GridSpan = Cell.Get_GridSpan();
var Vmerge = Cell.GetVMerge();
// начальная и конечная точки данного GridSpan'a
var X_grid_start = this.TableSumGrid[CurGridCol - 1];
var X_grid_end = this.TableSumGrid[CurGridCol + GridSpan - 1];
// границы самой ячейки
var X_cell_start = X_grid_start;
var X_cell_end = X_grid_end;
if ( null != CellSpacing )
{
if ( 0 === CurCell )
{
if ( 0 === BeforeInfo.GridBefore )
{
if ( border_None === TableBorders.Left.Value || CellSpacing > TableBorders.Left.Size / 2 )
X_cell_start += CellSpacing;
else
X_cell_start += TableBorders.Left.Size / 2;
}
else
{
if ( border_None === TableBorders.Left.Value || CellSpacing > TableBorders.Left.Size ) // CellSpacing / 2 > TableBorders.Left.Size / 2
X_cell_start += CellSpacing / 2;
else
X_cell_start += TableBorders.Left.Size / 2;
}
}
else
X_cell_start += CellSpacing / 2;
if ( CellsCount - 1 === CurCell )
{
if ( 0 === AfterInfo.GridAfter )
{
if ( border_None === TableBorders.Right.Value || CellSpacing > TableBorders.Right.Size / 2 )
X_cell_end -= CellSpacing;
else
X_cell_end -= TableBorders.Right.Size / 2;
}
else
{
if ( border_None === TableBorders.Right.Value || CellSpacing > TableBorders.Right.Size ) // CellSpacing / 2 > TableBorders.Right.Size / 2
X_cell_end -= CellSpacing / 2;
else
X_cell_end -= TableBorders.Right.Size / 2;
}
}
else
X_cell_end -= CellSpacing / 2;
}
var CellMar = Cell.GetMargins();
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
// начальная и конечная точка для содержимого данной ячейки
var X_content_start = X_cell_start;
var X_content_end = X_cell_end;
// Левая и правая границы ячейки рисуются вовнутрь ячейки, если Spacing != null.
var CellBorders = Cell.Get_Borders();
if ( null != CellSpacing )
{
X_content_start += CellMar.Left.W * layoutCoeff;
X_content_end -= CellMar.Right.W * layoutCoeff;
if ( border_Single === CellBorders.Left.Value )
X_content_start += CellBorders.Left.Size * layoutCoeff;
if ( border_Single === CellBorders.Right.Value )
X_content_end -= CellBorders.Right.Size * layoutCoeff;
}
else
{
if ( vmerge_Continue === Vmerge )
{
X_content_start += CellMar.Left.W * layoutCoeff;
X_content_end -= CellMar.Right.W * layoutCoeff;
// Границы для этих ячеек рассчитываются во время расчета границ первой ячейки в вертикальном
// объединении. Но может случиться, что если что-то пошло не так и у нас первая же ячейка первой строки
// идет с флагом vmerge_Continue. Защищаемся от этого плохого случая
if (!Cell.GetBorderInfoLeft())
{
let leftBorder = Cell.GetBorders().Left;
Cell.Set_BorderInfo_Left([leftBorder], leftBorder.GetWidth());
}
if (!Cell.GetBorderInfoRight())
{
let rightBorder = Cell.GetBorders().Right;
Cell.Set_BorderInfo_Right([rightBorder], rightBorder.GetWidth());
}
}
else
{
// Линии правой и левой границы рисуются ровно по сетке
// (середина линии(всмысле толщины линии) совпадает с линией сетки).
// Мы должны найти максимальную толщину линии, участвущую в правой/левой
// границах. Если данная толщина меньше соответствующего отступа, тогда
// она не влияет на расположение содержимого ячейки, в противном случае,
// максимальная толщина линии и задает отступ для содержимого.
// Поэтому первым шагом определим максимальную толщину правой и левой границ.
var Max_r_w = 0;
var Max_l_w = 0;
var Borders_Info = {
Right : [],
Left : [],
Right_Max : 0,
Left_Max : 0
};
const oTopMergedCell = this.bPresentation ? this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan) : null;
let oTempCellBorders = oTopMergedCell ? oTopMergedCell.GetBorders() : null;
for (var nTempCurRow = 0; nTempCurRow < VMergeCount; ++nTempCurRow)
{
var oTempRow = this.GetRow(CurRow + nTempCurRow);
var nTempCurCell = this.private_GetCellIndexByStartGridCol(CurRow + nTempCurRow, CurGridCol);
if (nTempCurCell < 0)
continue;
const oTempCell = oTempRow.GetCell(nTempCurCell);
if (!oTopMergedCell) {
oTempCellBorders = oTempCell.GetBorders();
}
// Обработка левой границы
if (0 === nTempCurCell)
{
var oLeftBorder = this.private_ResolveBordersConflict(TableBorders.Left, oTempCellBorders.Left, true, false);
if (border_Single === oLeftBorder.Value && oLeftBorder.Size > Max_l_w)
Max_l_w = oLeftBorder.Size;
Borders_Info.Left.push(oLeftBorder);
}
else
{
let oLeftBorder;
const oLeftCell = oTempRow.GetCell(nTempCurCell - 1);
if (this.bPresentation) {
const oLeftTopCell = this.GetStartMergedCell(nTempCurCell - 1, CurRow + nTempCurRow);
oLeftBorder = this.private_ResolveBordersConflict(oLeftTopCell.GetBorders().Right, oTempCellBorders.Left, false, false, oLeftCell === oLeftTopCell, oTempCell === oTopMergedCell);
} else {
oLeftBorder = this.private_ResolveBordersConflict(oLeftCell.GetBorders().Right, oTempCellBorders.Left, false, false);
}
if (border_Single === oLeftBorder.Value && oLeftBorder.Size > Max_l_w)
Max_l_w = oLeftBorder.Size;
Borders_Info.Left.push(oLeftBorder);
}
// Обработка правой границы
if (oTempRow.GetCellsCount() - 1 === nTempCurCell)
{
var oRightBorder = this.private_ResolveBordersConflict(TableBorders.Right, oTempCellBorders.Right, true, false);
if (border_Single === oRightBorder.Value && oRightBorder.Size > Max_r_w)
Max_r_w = oRightBorder.Size;
Borders_Info.Right.push(oRightBorder);
}
else
{
let oRightBorder;
const oRightCell = oTempRow.GetCell(nTempCurCell + 1);
if (this.bPresentation) {
const oRightTopCell = this.GetStartMergedCell(nTempCurCell + 1, CurRow + nTempCurRow);
oRightBorder = this.private_ResolveBordersConflict(oRightTopCell.GetBorders().Left, oTempCellBorders.Right,false, false, oRightCell === oRightTopCell, oTopMergedCell === oTempCell);
} else {
oRightBorder = this.private_ResolveBordersConflict(oRightCell.GetBorders().Left, oTempCellBorders.Right, false, false);
}
if (border_Single === oRightBorder.Value && oRightBorder.Size > Max_r_w)
Max_r_w = oRightBorder.Size;
Borders_Info.Right.push(oRightBorder);
}
}
Borders_Info.Right_Max = Max_r_w;
Borders_Info.Left_Max = Max_l_w;
if ( Max_l_w / 2 > CellMar.Left.W )
X_content_start += Max_l_w / 2 * layoutCoeff;
else
X_content_start += CellMar.Left.W * layoutCoeff;
if ( Max_r_w / 2 > CellMar.Right.W )
X_content_end -= Max_r_w / 2 * layoutCoeff;
else
X_content_end -= CellMar.Right.W * layoutCoeff;
Cell.Set_BorderInfo_Left ( Borders_Info.Left, Max_l_w );
Cell.Set_BorderInfo_Right( Borders_Info.Right, Max_r_w );
}
}
if ( 0 === CurCell )
{
if ( null != CellSpacing )
{
Row_x_min = X_grid_start;
if ( border_Single === TableBorders.Left.Value )
Row_x_min -= TableBorders.Left.Size / 2;
}
else
{
var BorderInfo = Cell.GetBorderInfo();
Row_x_min = X_grid_start - BorderInfo.MaxLeft / 2;
}
}
if ( CellsCount - 1 === CurCell )
{
if ( null != CellSpacing )
{
Row_x_max = X_grid_end;
if ( border_Single === TableBorders.Right.Value )
Row_x_max += TableBorders.Right.Size / 2;
}
else
{
var BorderInfo = Cell.GetBorderInfo();
Row_x_max = X_grid_end + BorderInfo.MaxRight / 2;
}
}
Cell.Set_Metrics( CurGridCol, X_grid_start, X_grid_end, X_cell_start, X_cell_end, X_content_start, X_content_end );
CurGridCol += GridSpan;
}
Row.Set_Metrics_X( Row_x_min, Row_x_max );
}
this.RecalcInfo.TableBorders = false;
};
CTable.prototype.private_RecalculateCellTopBorder = function(oPrevRow, nCurRow, nCurGridCol, nGridSpan, oTableBorders, oCellBorders)
{
// Ищем в предыдущей строке первую ячейку, пересекающуюся с [nCurGridCol, nCurGridCol + nGridSpan]
var nPrevCellsCount = oPrevRow.GetCellsCount();
var oPrevBefore = oPrevRow.GetBefore();
var oPrevAfter = oPrevRow.GetAfter();
var nPrevPos = -1;
var nPrevGridCol = oPrevBefore.Grid;
for (var nPrevCell = 0; nPrevCell < nPrevCellsCount; ++nPrevCell)
{
var oPrevCell = oPrevRow.GetCell(nPrevCell);
var nPrevGridSpan = oPrevCell.GetGridSpan();
if (nPrevGridCol <= nCurGridCol + nGridSpan - 1 && nPrevGridCol + nPrevGridSpan - 1 >= nCurGridCol)
{
nPrevPos = nPrevCell;
break;
}
nPrevGridCol += nPrevGridSpan;
}
var arrBorderTopInfo = [];
var nMaxTopBorder = 0;
// Сначала посмотрим пересечение с Before.Grid предыдущей строки
if (nCurGridCol <= oPrevBefore.Grid - 1)
{
var oBorder = this.private_ResolveBordersConflict(oTableBorders.Left, oCellBorders.Top, true, false);
var nBorderW = oBorder.GetWidth();
if (nMaxTopBorder < nBorderW)
nMaxTopBorder = nBorderW;
for (var nCurGrid = 0, nGridCount = Math.min(oPrevBefore.Grid - nCurGridCol, nGridSpan); nCurGrid < nGridCount; ++nCurGrid)
arrBorderTopInfo.push(oBorder);
}
if (-1 !== nPrevPos)
{
while (nPrevGridCol <= nCurGridCol + nGridSpan - 1 && nPrevPos < nPrevCellsCount)
{
var oPrevCell = oPrevRow.GetCell(nPrevPos);
var nPrevGridSpan = oPrevCell.GetGridSpan();
// Если данная ячейка участвует в вертикальном объединении, тогда нам нужно использовать нижнюю ячейку
// в этом объединении, но в не в случае, когда мы расчитываем границу соприкасающуюся с заголовком таблицы
// TODO: Надо проверить, зачем вообще это тут добавлено, т.к. ячейка предыдущей строки по логике
// не должны быть не последней в своем вертикальном объединении
if (oPrevRow === this.GetRow(nCurRow - 1) && vmerge_Continue === oPrevCell.GetVMerge()) {
if (this.bPresentation)
{
oPrevCell = this.Internal_Get_StartMergedCell(nCurRow - 1, nPrevGridCol, nPrevGridSpan);
}
else
{
oPrevCell = this.Internal_Get_EndMergedCell(nCurRow - 1, nPrevGridCol, nPrevGridSpan);
}
}
let bCheckPrevTopMergedCell = false;
// Надо добавить столько раз, сколько колонок находится в пересечении этих двух ячееки
var nGridCount = 0;
if (nPrevGridCol >= nCurGridCol)
{
bCheckPrevTopMergedCell = true;
if (nPrevGridCol + nPrevGridSpan - 1 > nCurGridCol + nGridSpan - 1)
nGridCount = nCurGridCol + nGridSpan - nPrevGridCol;
else
nGridCount = nPrevGridSpan;
}
else if (nPrevGridCol + nPrevGridSpan - 1 > nCurGridCol + nGridSpan - 1)
{
nGridCount = nGridSpan;
}
else
{
nGridCount = nPrevGridCol + nPrevGridSpan - nCurGridCol;
}
var oPrevBottom = oPrevCell.GetBorders().Bottom;
if (this.bPresentation)
{
for (var nCurGrid = 0; nCurGrid < nGridCount; ++nCurGrid)
{
var oBorder = this.private_ResolveBordersConflict(oPrevBottom, oCellBorders.Top, false, false, bCheckPrevTopMergedCell ? !nCurGrid : false, !arrBorderTopInfo.length);
var nBorderW = oBorder.GetWidth();
if (nMaxTopBorder < nBorderW)
nMaxTopBorder = nBorderW;
arrBorderTopInfo.push(oBorder);
}
}
else
{
var oBorder = this.private_ResolveBordersConflict(oPrevBottom, oCellBorders.Top, false, false);
var nBorderW = oBorder.GetWidth();
if (nMaxTopBorder < nBorderW)
nMaxTopBorder = nBorderW;
for (var nCurGrid = 0; nCurGrid < nGridCount; ++nCurGrid)
arrBorderTopInfo.push(oBorder);
}
nPrevPos++;
nPrevGridCol += nPrevGridSpan;
}
}
// Посмотрим пересечение с GridAfter предыдущей строки
if (oPrevAfter.Grid > 0)
{
var nStartAfterGrid = oPrevRow.GetCellInfo(nPrevCellsCount - 1).StartGridCol + oPrevRow.GetCell(nPrevCellsCount - 1).GetGridSpan();
if (nCurGridCol + nGridSpan - 1 >= nStartAfterGrid)
{
var oBorder = this.private_ResolveBordersConflict(oTableBorders.Right, oCellBorders.Top, true, false);
var nBorderW = oBorder.GetWidth();
if (nMaxTopBorder < nBorderW)
nMaxTopBorder = nBorderW;
for (var nCurGrid = 0, nGridCount = Math.min(nCurGridCol + nGridSpan - nStartAfterGrid, nGridSpan); nCurGrid < nGridCount; ++nCurGrid)
arrBorderTopInfo.push(oBorder);
}
}
return {
Info : arrBorderTopInfo,
Max : nMaxTopBorder
};
};
CTable.prototype.private_RecalculateHeader = function()
{
// Если у нас таблица внутри таблицы, тогда в ней заголовочных строк не должно быть,
// потому что так делает Word.
if (!this.Parent || true === this.Parent.IsTableCellContent())
{
this.HeaderInfo.Count = 0;
return;
}
// Здесь мы подготавливаем информацию для пересчета заголовка таблицы
var Header_RowsCount = 0;
var Rows_Count = this.Content.length;
for ( var Index = 0; Index < Rows_Count; Index++ )
{
var Row = this.Content[Index];
if ( true != Row.IsHeader() )
break;
Header_RowsCount++;
}
// Избавимся от строк, в которых есть вертикально объединенные ячейки, которые одновременно есть в заголовке
// и не в заголовке
for ( var CurRow = Header_RowsCount - 1; CurRow >= 0; CurRow-- )
{
var Row = this.Content[CurRow];
var Cells_Count = Row.Get_CellsCount();
var bContinue = false;
for ( var CurCell = 0; CurCell < Cells_Count; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var GridSpan = Cell.Get_GridSpan();
var CurGridCol = Cell.Metrics.StartGridCol;
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
// В данной строке нашли вертикально объединенную ячейку с ячейкой не из заголовка
// Поэтому выкидываем данную строку и проверяем предыдущую
if ( VMergeCount > 1 )
{
Header_RowsCount--;
bContinue = true;
break;
}
}
if ( true != bContinue )
{
// Если дошли до этого места, значит данная строка, а, следовательно, и все строки выше
// нормальные в плане объединенных вертикально ячеек.
break;
}
}
this.HeaderInfo.Count = Header_RowsCount;
};
CTable.prototype.private_RecalculatePageXY = function(CurPage)
{
var FirstRow = 0;
if (0 !== CurPage)
{
if (true === this.IsEmptyPage(CurPage - 1))
FirstRow = this.Pages[CurPage - 1].FirstRow;
else if (true === this.Pages[CurPage - 1].LastRowSplit)
FirstRow = this.Pages[CurPage - 1].LastRow;
else
FirstRow = Math.min(this.Pages[CurPage - 1].LastRow + 1, this.Content.length - 1);
}
let maxTopBorder = this.Get_MaxTopBorder(FirstRow);
let contentFrame = this.GetPageContentFrame(CurPage);
this.Pages.length = CurPage + 1;
let yLimit = contentFrame.YLimit;
if (0 === CurPage
&& !this.IsInline()
&& c_oAscVAnchor.Text === this.PositionV.RelativeFrom
&& !this.PositionV.Align)
{
yLimit -= this.PositionV.Value;
}
this.Pages[CurPage] = new CTablePage(contentFrame.X, contentFrame.Y, contentFrame.XLimit, yLimit, FirstRow, maxTopBorder);
};
CTable.prototype.private_RecalculatePositionX = function(CurPage)
{
var isHdtFtr = this.Parent.IsHdrFtr();
var TablePr = this.Get_CompiledPr(false).TablePr;
var PageLimits = this.Parent.Get_PageLimits(this.PageNum);
var PageFields = this.Parent.Get_PageFields(this.PageNum, isHdtFtr, this.Get_SectPr());
var LD_PageLimits = this.LogicDocument.Get_PageLimits(this.GetAbsoluteStartPage());
var LD_PageFields = this.LogicDocument.Get_PageFields(this.GetAbsoluteStartPage(), isHdtFtr);
let tableInd = TablePr.TableInd;
if ( true === this.Is_Inline() )
{
var Page = this.Pages[CurPage];
if (0 === CurPage)
{
this.AnchorPosition.CalcX = this.X_origin + tableInd;
this.AnchorPosition.Set_X(this.TableSumGrid[this.TableSumGrid.length - 1], this.X_origin, LD_PageFields.X, LD_PageFields.XLimit, LD_PageLimits.XLimit, PageLimits.X, PageLimits.XLimit);
}
switch (TablePr.Jc)
{
case AscCommon.align_Left :
{
Page.X = Page.X_origin + this.GetTableOffsetCorrection() + tableInd;
break;
}
case AscCommon.align_Right :
{
var TableWidth = this.TableSumGrid[this.TableSumGrid.length - 1];
if (false === this.Parent.IsTableCellContent())
Page.X = Page.XLimit - TableWidth + this.GetRightTableOffsetCorrection();
else
Page.X = Page.XLimit - TableWidth;
break;
}
case AscCommon.align_Center :
{
var TableWidth = this.TableSumGrid[this.TableSumGrid.length - 1];
var RangeWidth = Page.XLimit - Page.X_origin;
Page.X = Page.X_origin + ( RangeWidth - TableWidth ) / 2;
break;
}
}
}
else
{
if (0 === CurPage)
{
var OffsetCorrection_Left = this.GetTableOffsetCorrection();
var OffsetCorrection_Right = this.GetRightTableOffsetCorrection();
this.X = this.X_origin + OffsetCorrection_Left;
this.AnchorPosition.Set_X(this.TableSumGrid[this.TableSumGrid.length - 1], this.X_origin, PageFields.X + OffsetCorrection_Left, PageFields.XLimit + OffsetCorrection_Right, LD_PageLimits.XLimit, PageLimits.X + OffsetCorrection_Left, PageLimits.XLimit + OffsetCorrection_Right);
// Непонятно по какой причине, но Word для плавающих таблиц добаляется значение TableInd
this.AnchorPosition.Calculate_X(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
this.AnchorPosition.CalcX += tableInd;
this.X = this.AnchorPosition.CalcX;
this.X_origin = this.X - OffsetCorrection_Left;
if (undefined != this.PositionH_Old)
{
// Восстанови старые значения, чтобы в историю изменений все нормально записалось
this.PositionH.RelativeFrom = this.PositionH_Old.RelativeFrom;
this.PositionH.Align = this.PositionH_Old.Align;
this.PositionH.Value = this.PositionH_Old.Value;
// Рассчитаем сдвиг с учетом старой привязки
var Value = this.AnchorPosition.Calculate_X_Value(this.PositionH_Old.RelativeFrom);
this.Set_PositionH(this.PositionH_Old.RelativeFrom, false, Value);
// На всякий случай пересчитаем заново координату
this.X = this.AnchorPosition.Calculate_X(this.PositionH.RelativeFrom, this.PositionH.Align, this.PositionH.Value);
this.X_origin = this.X - OffsetCorrection_Left;
this.PositionH_Old = undefined;
}
}
this.Pages[CurPage].X = this.X;
this.Pages[CurPage].XLimit = this.XLimit;
this.Pages[CurPage].X_origin = this.X_origin;
}
};
CTable.prototype.private_RecalculatePage = function(CurPage)
{
if ( true === this.TurnOffRecalc )
return;
var isInnerTable = this.Parent.IsTableCellContent();
var oTopDocument = this.Parent.Is_TopDocument(true);
var isTopLogicDocument = (oTopDocument instanceof CDocument ? true : false);
var oFootnotes = (isTopLogicDocument && !isInnerTable ? oTopDocument.Footnotes : null);
var nPageAbs = this.GetAbsolutePage(CurPage);
var nColumnAbs = this.GetAbsoluteColumn(CurPage);
this.TurnOffRecalc = true;
var FirstRow = 0;
var LastRow = 0;
var ResetStartElement = false;
if ( 0 === CurPage )
{
// Обнуляем таблицу суммарных высот ячеек
for ( var Index = -1; Index < this.Content.length; Index++ )
{
this.TableRowsBottom[Index] = [];
this.TableRowsBottom[Index][0] = 0;
}
}
else
{
if (true === this.IsEmptyPage(CurPage - 1))
{
ResetStartElement = false;
FirstRow = this.Pages[CurPage - 1].FirstRow;
}
else if (true === this.Pages[CurPage - 1].LastRowSplit)
{
ResetStartElement = false;
FirstRow = this.Pages[CurPage - 1].LastRow;
}
else
{
ResetStartElement = true;
FirstRow = Math.min(this.Pages[CurPage - 1].LastRow + 1, this.Content.length - 1);
}
LastRow = FirstRow;
}
var MaxTopBorder = this.MaxTopBorder;
var MaxBotBorder = this.MaxBotBorder;
var MaxBotMargin = this.MaxBotMargin;
var StartPos = this.Pages[CurPage];
if (true === this.Check_EmptyPages(CurPage - 1))
this.HeaderInfo.PageIndex = -1;
var Page = this.Pages[CurPage];
var TempMaxTopBorder = Page.MaxTopBorder;
var Y = StartPos.Y;
var TableHeight = 0;
var oLogicDocument = this.GetLogicDocument();
if (oLogicDocument && oLogicDocument.IsDocumentEditor() && this.IsInline())
{
var nTableX_min = -1;
var nTableX_max = -1;
for (var nCurRow = 0, nRowsCount = this.GetRowsCount(); nCurRow < nRowsCount; ++nCurRow)
{
var oRow = this.GetRow(nCurRow);
var nCellsCount = oRow.GetCellsCount();
if (!nCellsCount)
continue;
var nRowX_min = oRow.GetCell(0).Metrics.X_content_start;
var nRowX_max = oRow.GetCell(nCellsCount - 1).Metrics.X_content_end;
if (-1 === nTableX_min || nRowX_min < nTableX_min)
nTableX_min = nRowX_min;
if (-1 === nTableX_max || nRowX_max > nTableX_max)
nTableX_max = nRowX_max;
}
nTableX_min += Page.X;
nTableX_max += Page.X;
var arrRanges = this.Parent.CheckRange(nTableX_min, Page.Y, nTableX_max, Page.Y + 0.001, Page.Y, Page.Y + 0.001, nTableX_min, nTableX_max, this.GetRelativePage(CurPage));
if (arrRanges.length > 0)
{
for (var nRangeIndex = 0, nRangesCount = arrRanges.length; nRangeIndex < nRangesCount; ++nRangeIndex)
{
if (Y < arrRanges[nRangeIndex].Y1)
{
var nShiftY = arrRanges[nRangeIndex].Y1 - Y;
Y = arrRanges[nRangeIndex].Y1 + 0.001;
Page.Y = Y;
Page.Bounds.Top += nShiftY;
}
}
}
}
var TableBorders = this.Get_Borders();
var nHeaderMaxTopBorder = -1;
var X_max = -1;
var X_min = -1;
if (this.HeaderInfo.Count > 0 && this.HeaderInfo.PageIndex != -1 && CurPage > this.HeaderInfo.PageIndex && this.IsInline())
{
this.HeaderInfo.HeaderRecalculate = true;
this.HeaderInfo.Pages[CurPage] = {};
this.HeaderInfo.Pages[CurPage].RowsInfo = [];
var HeaderPage = this.HeaderInfo.Pages[CurPage];
// Рисуем ли заголовок на данной странице
HeaderPage.Draw = true;
this.LogicDocument.RecalcTableHeader = true;
this.private_RecalculatePrepareHeaderPageRows(HeaderPage);
var bHeaderNextPage = false;
for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
{
HeaderPage.RowsInfo[CurRow] = {};
HeaderPage.RowsInfo[CurRow].Y = 0;
HeaderPage.RowsInfo[CurRow].H = 0;
HeaderPage.RowsInfo[CurRow].TopDy = 0;
HeaderPage.RowsInfo[CurRow].MaxTopBorder = 0;
HeaderPage.RowsInfo[CurRow].TableRowsBottom = 0;
var Row = HeaderPage.Rows[CurRow];
var CellsCount = Row.Get_CellsCount();
var CellSpacing = Row.Get_CellSpacing();
var BeforeInfo = Row.Get_Before();
var CurGridCol = BeforeInfo.GridBefore;
// Добавляем ширину верхней границы у текущей строки (используем MaxTopBorder самой таблицы)
Y += MaxTopBorder[CurRow];
TableHeight += MaxTopBorder[CurRow];
// Если таблица с расстоянием между ячейками, тогда добавляем его
if ( 0 === CurRow )
{
if ( null != CellSpacing )
{
var TableBorder_Top = this.Get_Borders().Top;
if ( border_Single === TableBorder_Top.Value )
{
Y += TableBorder_Top.Size;
TableHeight += TableBorder_Top.Size;
}
Y += CellSpacing;
TableHeight += CellSpacing;
}
}
else
{
var PrevCellSpacing = HeaderPage.Rows[CurRow - 1].Get_CellSpacing();
if ( null != CellSpacing && null != PrevCellSpacing )
{
Y += (PrevCellSpacing + CellSpacing) / 2;
TableHeight += (PrevCellSpacing + CellSpacing) / 2;
}
else if ( null != CellSpacing )
{
Y += CellSpacing / 2;
TableHeight += CellSpacing / 2;
}
else if ( null != PrevCellSpacing )
{
Y += PrevCellSpacing / 2;
TableHeight += PrevCellSpacing / 2;
}
}
var Row_x_max = Row.Metrics.X_max;
var Row_x_min = Row.Metrics.X_min;
if ( -1 === X_min || Row_x_min < X_min )
X_min = Row_x_min;
if ( -1 === X_max || Row_x_max > X_max )
X_max = Row_x_max;
// Дополнительный параметр для случая, если данная строка начнется с новой страницы.
// Мы запоминаем максимальное значение нижней границы(первой страницы (текущей)) у ячеек,
// объединенных вертикально так, чтобы это объединение заканчивалось на данной строке.
// И если данная строка начнется сразу с новой страницы (Pages > 0, FirstPage = false), тогда
// мы должны данный параметр сравнить со значением нижней границы предыдущей строки.
var MaxBotValue_vmerge = -1;
var RowH = Row.Get_Height();
var VerticallCells = [];
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var GridSpan = Cell.Get_GridSpan();
var Vmerge = Cell.GetVMerge();
var CellMar = Cell.GetMargins();
Row.Update_CellInfo(CurCell);
var CellMetrics = Row.Get_CellInfo( CurCell );
var X_content_start = Page.X + CellMetrics.X_content_start;
var X_content_end = Page.X + CellMetrics.X_content_end;
var Y_content_start = Y + CellMar.Top.W;
var Y_content_end = this.Pages[CurPage].YLimit;
// TODO: При расчете YLimit для ячейки сделать учет толщины нижних
// границ ячейки и таблицы
if ( null != CellSpacing )
{
if ( this.Content.length - 1 === CurRow )
Y_content_end -= CellSpacing;
else
Y_content_end -= CellSpacing / 2;
}
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
Y_content_end -= BottomMargin;
// Такие ячейки мы обсчитываем, если либо сейчас происходит переход на новую страницу, либо
// это последняя ячейка в объединении.
// Обсчет такик ячеек произошел ранее
Cell.Temp.Y = Y_content_start;
if ( VMergeCount > 1 )
{
CurGridCol += GridSpan;
continue;
}
else
{
// Возьмем верхнюю ячейку теккущего объединения
if ( vmerge_Restart != Vmerge )
{
// Найдем ячейку в самой таблице, а дальше по индексам ячейки и строки получим ее в скопированном заголовке
Cell = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
var cIndex = Cell.Index;
var rIndex = Cell.Row.Index;
Cell = HeaderPage.Rows[rIndex].Get_Cell( cIndex );
CellMar = Cell.GetMargins();
Y_content_start = Cell.Temp.Y + CellMar.Top.W;
}
}
if (true === Cell.IsVerticalText())
{
VerticallCells.push(Cell);
CurGridCol += GridSpan;
continue;
}
Cell.Content.Set_StartPage( CurPage );
Cell.Content.Reset( X_content_start, Y_content_start, X_content_end, Y_content_end );
Cell.Content.Set_ClipInfo(0, Page.X + CellMetrics.X_cell_start, Page.X + CellMetrics.X_cell_end);
Cell.Content.RecalculateEndInfo();
if ( recalcresult2_NextPage === Cell.Content.Recalculate_Page( 0, true ) )
{
bHeaderNextPage = true;
break;
}
var CellContentBounds = Cell.Content.Get_PageBounds( 0, undefined, true );
var CellContentBounds_Bottom = CellContentBounds.Bottom + BottomMargin;
if ( undefined === HeaderPage.RowsInfo[CurRow].TableRowsBottom || HeaderPage.RowsInfo[CurRow].TableRowsBottom < CellContentBounds_Bottom )
HeaderPage.RowsInfo[CurRow].TableRowsBottom = CellContentBounds_Bottom;
if ( vmerge_Continue === Vmerge )
{
if ( -1 === MaxBotValue_vmerge || MaxBotValue_vmerge < CellContentBounds_Bottom )
MaxBotValue_vmerge = CellContentBounds_Bottom;
}
CurGridCol += GridSpan;
}
// Если заголовок целиком на странице не убирается, тогда мы его попросту не рисуем на данной странице
if ( true === bHeaderNextPage )
{
Y = StartPos.Y;
TableHeight = 0;
HeaderPage.Draw = false;
break;
}
// Здесь мы выставляем только начальную координату строки (для каждой страницы)
// высоту строки(для каждой страницы) мы должны обсчитать после общего цикла, т.к.
// в одной из следйющих строк может оказаться ячейка с вертикальным объединением,
// захватывающим данную строку. Значит, ее содержимое может изменить высоту нашей строки.
var TempY = Y;
var TempMaxTopBorder = MaxTopBorder[CurRow];
if ( null != CellSpacing )
{
HeaderPage.RowsInfo[CurRow].Y = TempY;
HeaderPage.RowsInfo[CurRow].TopDy = 0;
HeaderPage.RowsInfo[CurRow].X0 = Row_x_min;
HeaderPage.RowsInfo[CurRow].X1 = Row_x_max;
HeaderPage.RowsInfo[CurRow].MaxTopBorder = TempMaxTopBorder;
HeaderPage.RowsInfo[CurRow].MaxBotBorder = MaxBotBorder[CurRow];
}
else
{
HeaderPage.RowsInfo[CurRow].Y = TempY - TempMaxTopBorder;
HeaderPage.RowsInfo[CurRow].TopDy = TempMaxTopBorder;
HeaderPage.RowsInfo[CurRow].X0 = Row_x_min;
HeaderPage.RowsInfo[CurRow].X1 = Row_x_max;
HeaderPage.RowsInfo[CurRow].MaxTopBorder = TempMaxTopBorder;
HeaderPage.RowsInfo[CurRow].MaxBotBorder = MaxBotBorder[CurRow];
}
var CellHeight = HeaderPage.RowsInfo[CurRow].TableRowsBottom - Y;
// TODO: улучшить проверку на высоту строки (для строк разбитых на страницы)
if (false === bHeaderNextPage && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact === RowH.HRule) && CellHeight < RowH.Value - MaxTopBorder[CurRow])
{
CellHeight = RowH.Value - MaxTopBorder[CurRow];
HeaderPage.RowsInfo[CurRow].TableRowsBottom = Y + CellHeight;
}
// Рассчитываем ячейки с вертикальным текстом
var CellsCount2 = VerticallCells.length;
for (var TempCellIndex = 0; TempCellIndex < CellsCount2; TempCellIndex++)
{
var Cell = VerticallCells[TempCellIndex];
var CurCell = Cell.Index;
var GridSpan = Cell.Get_GridSpan();
var CurGridCol = Cell.Metrics.StartGridCol;
// Возьмем верхнюю ячейку текущего объединения
Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
var cIndex = Cell.Index;
var rIndex = Cell.Row.Index;
Cell = HeaderPage.Rows[rIndex].Get_Cell( cIndex );
var CellMar = Cell.GetMargins();
var CellMetrics = Cell.Row.Get_CellInfo(CurCell);
var X_content_start = Page.X + CellMetrics.X_content_start;
var X_content_end = Page.X + CellMetrics.X_content_end;
var Y_content_start = Cell.Temp.Y;
var Y_content_end = HeaderPage.RowsInfo[CurRow].TableRowsBottom;
// TODO: При расчете YLimit для ячейки сделать учет толщины нижних
// границ ячейки и таблицы
if (null != CellSpacing)
{
if (this.Content.length - 1 === CurRow)
Y_content_end -= CellSpacing;
else
Y_content_end -= CellSpacing / 2;
}
var VMergeCount = this.Internal_GetVertMergeCount(CurRow, CurGridCol, GridSpan);
var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
Y_content_end -= BottomMargin;
Cell.PagesCount = 1;
Cell.Content.Set_StartPage(CurPage);
Cell.Content.Reset(0, 0, Y_content_end - Y_content_start, 10000);
Cell.Temp.X_start = X_content_start;
Cell.Temp.Y_start = Y_content_start;
Cell.Temp.X_end = X_content_end;
Cell.Temp.Y_end = Y_content_end;
Cell.Temp.X_cell_start = Page.X + CellMetrics.X_cell_start;
Cell.Temp.X_cell_end = Page.X + CellMetrics.X_cell_end;
Cell.Temp.Y_cell_start = Y_content_start - CellMar.Top.W;
Cell.Temp.Y_cell_end = Y_content_end + BottomMargin;
// Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
// Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
// Recalculate_Page от несуществующих страниц.
var CellPageIndex = CurPage - Cell.Content.GetRelativeStartPage();
if (0 === CellPageIndex)
{
Cell.Content.Recalculate_Page(CellPageIndex, true);
}
}
if ( null != CellSpacing )
HeaderPage.RowsInfo[CurRow].H = CellHeight;
else
HeaderPage.RowsInfo[CurRow].H = CellHeight + TempMaxTopBorder;
Y += CellHeight;
TableHeight += CellHeight;
Row.Height = CellHeight;
Y += MaxBotBorder[CurRow];
TableHeight += MaxBotBorder[CurRow];
// Сделаем вертикальное выравнивание ячеек в таблице. Делаем как Word, если ячейка разбилась на несколько
// страниц, тогда вертикальное выравнивание применяем только к первой странице.
}
if ( false === bHeaderNextPage )
{
// Сделаем вертикальное выравнивание ячеек в таблице. Делаем как Word, если ячейка разбилась на несколько
// страниц, тогда вертикальное выравнивание применяем только к первой странице.
// Делаем это не в общем цикле, потому что объединенные вертикально ячейки могут вносить поправки в значения
// this.TableRowsBottom, в последней строке.
for ( var CurRow = 0; CurRow < this.HeaderInfo.Count; CurRow++ )
{
var Row = HeaderPage.Rows[CurRow];
var CellsCount = Row.Get_CellsCount();
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
if ( VMergeCount > 1 )
continue;
else
{
var Vmerge = Cell.GetVMerge();
// Возьмем верхнюю ячейку теккущего объединения
if ( vmerge_Restart != Vmerge )
{
Cell = this.Internal_Get_StartMergedCell( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
var cIndex = Cell.Index;
var rIndex = Cell.Row.Index;
Cell = HeaderPage.Rows[rIndex].Get_Cell( cIndex );
}
}
var CellMar = Cell.GetMargins();
var VAlign = Cell.Get_VAlign();
var CellPageIndex = CurPage - Cell.Content.GetRelativeStartPage();
if ( CellPageIndex >= Cell.PagesCount )
continue;
// Для прилегания к верху или для второй страницы ничего не делаем (так изначально рассчитывалось)
if ( vertalignjc_Top === VAlign || CellPageIndex > 1 )
{
Cell.Temp.Y_VAlign_offset[CellPageIndex] = 0;
continue;
}
// Рассчитаем имеющуюся в распоряжении высоту ячейки
var TempCurRow = Cell.Row.Index;
var TempCellSpacing = HeaderPage.Rows[TempCurRow].Get_CellSpacing();
var Y_0 = HeaderPage.RowsInfo[TempCurRow].Y;
if ( null === TempCellSpacing )
Y_0 += MaxTopBorder[TempCurRow];
Y_0 += CellMar.Top.W;
var Y_1 = HeaderPage.RowsInfo[CurRow].TableRowsBottom - CellMar.Bottom.W;
var CellHeight = Y_1 - Y_0;
var CellContentBounds = Cell.Content.Get_PageBounds( CellPageIndex, CellHeight, true );
var ContentHeight = CellContentBounds.Bottom - CellContentBounds.Top;
var Dy = 0;
if (true === Cell.IsVerticalText())
{
var CellMetrics = Cell.Row.Get_CellInfo(Cell.Index);
CellHeight = CellMetrics.X_cell_end - CellMetrics.X_cell_start - CellMar.Left.W - CellMar.Right.W;
}
if ( CellHeight - ContentHeight > 0.001 )
{
if ( vertalignjc_Bottom === VAlign )
Dy = CellHeight - ContentHeight;
else if ( vertalignjc_Center === VAlign )
Dy = (CellHeight - ContentHeight) / 2;
Cell.ShiftCellContent(CellPageIndex, 0, Dy);
}
Cell.Temp.Y_VAlign_offset[CellPageIndex] = Dy;
}
}
}
nHeaderMaxTopBorder = this.private_GetMaxTopBorderWidth(FirstRow, true);
this.LogicDocument.RecalcTableHeader = false;
}
else
{
this.HeaderInfo.Pages[CurPage] = {};
this.HeaderInfo.Pages[CurPage].Draw = false;
}
this.HeaderInfo.HeaderRecalculate = false;
var bNextPage = false;
// Блок переменных для учета сносок
var nFootnotesHeight = 0;
var arrSavedY = [];
var arrSavedTableHeight = [];
var arrFootnotesObject = [];
var nResetFootnotesIndex = -1;
var nCompatibilityMode = oLogicDocument && oLogicDocument.GetCompatibilityMode ? oLogicDocument.GetCompatibilityMode() : AscCommon.document_compatibility_mode_Current;
for (var CurRow = FirstRow; CurRow < this.Content.length; ++CurRow)
{
if (oFootnotes && (-1 === nResetFootnotesIndex || CurRow > nResetFootnotesIndex))
{
nFootnotesHeight = oFootnotes.GetHeight(nPageAbs, nColumnAbs);
arrFootnotesObject[CurRow] = oFootnotes.SaveRecalculateObject(nPageAbs, nColumnAbs);
arrSavedY[CurRow] = Y;
arrSavedTableHeight[CurRow] = TableHeight;
this.Pages[CurPage].FootnotesH = nFootnotesHeight;
}
if ((0 === CurRow && true === this.Check_EmptyPages(CurPage - 1)) || CurRow != FirstRow || (CurRow === FirstRow && true === ResetStartElement))
{
this.RowsInfo[CurRow] = new CTableRowsInfo();
this.RowsInfo[CurRow].StartPage = CurPage;
this.TableRowsBottom[CurRow] = [];
}
else
{
this.RowsInfo[CurRow].Pages = CurPage - this.RowsInfo[CurRow].StartPage + 1;
}
this.TableRowsBottom[CurRow][CurPage] = Y;
var Row = this.Content[CurRow];
var CellsCount = Row.Get_CellsCount();
var CellSpacing = Row.Get_CellSpacing();
var BeforeInfo = Row.Get_Before();
var AfterInfo = Row.Get_After();
var CurGridCol = BeforeInfo.GridBefore;
// Данная ширина используется для проверки влезает ли строка на страницу, т.к. если данная строка последняя
// и нужно нарисовать границу у данной строки, то мы можем не убраться именно из-за толщины нижней границы
// MaxBotBorder - это расчитанная ширина нижней границы строки, если не учитывать разбивку на страницы
let rowMaxBotBorder = 0;
var nMaxTopBorder = MaxTopBorder[CurRow];
if (CurRow === FirstRow && nHeaderMaxTopBorder > 0)
nMaxTopBorder = nHeaderMaxTopBorder;
if (this.private_IsVMergedRow(CurRow) && CurRow < this.Content.length - 1)
{
this.RowsInfo[CurRow].FirstPage = true;
this.RowsInfo[CurRow].Y[CurPage] = Y;
this.RowsInfo[CurRow].TopDy[CurPage] = 0;
this.RowsInfo[CurRow].X0 = Row.Metrics.X_min;
this.RowsInfo[CurRow].X1 = Row.Metrics.X_max;
this.RowsInfo[CurRow].MaxTopBorder[CurPage] = 0;
this.RowsInfo[CurRow].MaxBotBorder = 0;
this.RowsInfo[CurRow].H[CurPage] = 0;
this.RowsInfo[CurRow].VMerged = true;
for (let iCell = 0, nCells = Row.GetCellsCount(); iCell < nCells; ++iCell)
{
Row.Update_CellInfo(iCell);
let cell = Row.GetCell(iCell);
cell.Temp.Y = Y;
}
continue;
}
// Добавляем ширину верхней границы у текущей строки
if(!this.bPresentation)
{
Y += nMaxTopBorder;
TableHeight += nMaxTopBorder;
}
// Если таблица с расстоянием между ячейками, тогда добавляем его
if (FirstRow === CurRow)
{
if (null != CellSpacing)
{
var TableBorder_Top = this.Get_Borders().Top;
if (border_Single === TableBorder_Top.Value)
{
Y += TableBorder_Top.Size;
TableHeight += TableBorder_Top.Size;
}
if (true === this.HeaderInfo.Pages[CurPage].Draw || (0 === CurRow && (0 === CurPage || (1 === CurPage && false === this.RowsInfo[0].FirstPage))))
{
Y += CellSpacing;
TableHeight += CellSpacing;
}
else
{
Y += CellSpacing / 2;
TableHeight += CellSpacing / 2;
}
}
}
else
{
var PrevCellSpacing = this.Content[CurRow - 1].Get_CellSpacing();
if (null != CellSpacing && null != PrevCellSpacing)
{
Y += (PrevCellSpacing + CellSpacing) / 2;
TableHeight += (PrevCellSpacing + CellSpacing) / 2;
}
else if (null != CellSpacing)
{
Y += CellSpacing / 2;
TableHeight += CellSpacing / 2;
}
else if (null != PrevCellSpacing)
{
Y += PrevCellSpacing / 2;
TableHeight += PrevCellSpacing / 2;
}
}
var Row_x_max = Row.Metrics.X_max;
var Row_x_min = Row.Metrics.X_min;
if (-1 === X_min || Row_x_min < X_min)
X_min = Row_x_min;
if (-1 === X_max || Row_x_max > X_max)
X_max = Row_x_max;
var MaxTopMargin = 0;
for (var CurCell = 0; CurCell < CellsCount; CurCell++)
{
var Cell = Row.Get_Cell(CurCell);
var Vmerge = Cell.GetVMerge();
var CellMar = Cell.GetMargins();
if (vmerge_Restart === Vmerge && CellMar.Top.W > MaxTopMargin)
MaxTopMargin = CellMar.Top.W;
}
var RowH = Row.Get_Height();
var RowHValue;
if(!this.bPresentation)
{
// В данном значении не учитываются маргины
RowHValue = RowH.Value + this.MaxBotMargin[CurRow] + MaxTopMargin;
}
else
{
RowHValue = RowH.Value;
}
// В таблице с отступами размер отступа входит в значение высоты строки
if (null !== CellSpacing)
RowHValue -= CellSpacing;
// Для строк с точной высотой строк значение высоты считается вместе с шириной верхней границы
if (Asc.linerule_Exact === RowH.HRule)
RowHValue -= nMaxTopBorder;
if (oFootnotes && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact === RowH.HRule))
{
oFootnotes.PushCellLimit(Y + RowHValue);
}
// Дополнительный параметр для случая, если данная строка начнется с новой страницы.
// Мы запоминаем максимальное значение нижней границы(первой страницы (текущей)) у ячеек,
// объединенных вертикально так, чтобы это объединение заканчивалось на данной строке.
// И если данная строка начнется сразу с новой страницы (Pages > 0, FirstPage = false), тогда
// мы должны данный параметр сравнить со значением нижней границы предыдущей строки.
var MaxBotValue_vmerge = -1;
var Merged_Cell = [];
var VerticallCells = [];
var bAllCellsVertical = true;
var bFootnoteBreak = false;
let Y_content_end_row = this.Pages[CurPage].YLimit - nFootnotesHeight;
if (null != CellSpacing)
{
if (this.Content.length - 1 === CurRow)
Y_content_end_row -= CellSpacing;
else
Y_content_end_row -= CellSpacing / 2;
}
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var GridSpan = Cell.Get_GridSpan();
var Vmerge = Cell.GetVMerge();
var CellMar = Cell.GetMargins();
Row.Update_CellInfo(CurCell);
// Обновляем сразу EndInfo, т.к. мы можем начать пересчет следующей ячейки, до окончания полного пересчета
// предыдущей ячейки в строке. Кроме того пересчет EndInfo внутри параграфа, в любом случае, выполняется
// не более одного раза за текущий Document.RecalcId, поэтому, можем не боятся, что пересчет EndInfo
// вызовется несколько раз для параграфа
Cell.Content.RecalculateEndInfo();
var CellMetrics = Row.Get_CellInfo( CurCell );
var X_content_start = Page.X + CellMetrics.X_content_start;
var X_content_end = Page.X + CellMetrics.X_content_end;
var Y_content_start = Y + CellMar.Top.W;
var Y_content_end = Y_content_end_row;
// TODO: При расчете YLimit для ячейки сделать учет толщины нижних
// границ ячейки и таблицы
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, CurGridCol, GridSpan );
var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
Y_content_end -= BottomMargin;
// Такие ячейки мы обсчитываем, если либо сейчас происходит переход на новую страницу, либо
// это последняя ячейка в объединении.
// Обсчет такик ячеек произошел ранее
let clipTop = undefined;
let clipBottom = undefined;
if (Asc.linerule_Exact === RowH.HRule)
{
clipTop = Y;
clipBottom = Y + RowHValue;
}
Cell.Temp.Y = Y_content_start;
Cell.Temp.ClipTop = Y;
Cell.Temp.ClipBottom = Y + RowHValue;
Cell.Temp.ClipPage = CurPage;
// Сохраняем ссылку на исходную ячейку
var oOriginCell = Cell;
if ( VMergeCount > 1 )
{
CurGridCol += GridSpan;
Merged_Cell.push( Cell );
continue;
}
else
{
// Возьмем верхнюю ячейку текущего объединения
if ( vmerge_Restart != Vmerge )
{
Cell = this.Internal_Get_StartMergedCell( CurRow, CurGridCol, GridSpan );
CellMar = Cell.GetMargins();
var oTempRow = Cell.GetRow();
var oTempCellMetrics = oTempRow.GetCellInfo(Cell.GetIndex());
X_content_start = Page.X + oTempCellMetrics.X_content_start;
X_content_end = Page.X + oTempCellMetrics.X_content_end;
Y_content_start = Cell.Temp.Y + CellMar.Top.W;
// TODO: Клип пока выставляем для первой страницы ячейки, по логике надо просто выставлять клип на
// ячейку на текущей странице
if (undefined !== Cell.Temp.ClipTop && CurPage === Cell.Temp.ClipPage)
{
clipTop = Cell.Temp.ClipTop;
Cell.Temp.ClipBottom = clipBottom;
}
}
}
Cell.Temp.UseClip = false;
if (true === Cell.IsVerticalText())
{
VerticallCells.push(Cell);
CurGridCol += GridSpan;
continue;
}
// Для случая, когда смерженная вертикально ячейка идет в строке не с точной высотой, а заканчивается
// в строке с точной высотой строки
if (Asc.linerule_Exact === RowH.HRule)
Cell.Temp.UseClip = true;
if (null === CellSpacing)
{
let bottomBorder = this.private_ResolveBordersConflict(Cell.GetBottomBorder(), TableBorders.Bottom, false, true);
if (!bottomBorder.IsNone() && rowMaxBotBorder < bottomBorder.GetSize())
rowMaxBotBorder = bottomBorder.GetSize();
}
bAllCellsVertical = false;
var bCanShift = false;
var ShiftDy = 0;
var ShiftDx = 0;
if ((0 === Cell.Row.Index && true === this.Check_EmptyPages(CurPage - 1)) || Cell.Row.Index > FirstRow || (Cell.Row.Index === FirstRow && true === ResetStartElement))
{
Cell.Content.Set_StartPage( CurPage );
if ( true === this.Is_Inline() && 1 === Cell.PagesCount && 1 === Cell.Content.Pages.length && true != this.RecalcInfo.Check_Cell( Cell ) )
{
var X_content_start_old = Cell.Content.Pages[0].X;
var X_content_end_old = Cell.Content.Pages[0].XLimit;
var Y_content_height_old = Cell.Content.Pages[0].Bounds.Bottom - Cell.Content.Pages[0].Bounds.Top;
// Проверим по X, Y
if (Math.abs(X_content_start - X_content_start_old) < 0.001 && Math.abs(X_content_end_old - X_content_end) < 0.001 && Y_content_start + Y_content_height_old < Y_content_end)
{
bCanShift = true;
ShiftDy = -Cell.Content.Pages[0].Y + Y_content_start;
// Если в ячейке есть ссылки на сноски, тогда такую ячейку нужно пересчитывать
var arrFootnotes = Cell.Content.GetFootnotesList(null, null, false);
var arrEndnotes = Cell.Content.GetFootnotesList(null, null, true);
if ((arrFootnotes && arrFootnotes.length > 0)
|| (arrEndnotes && arrEndnotes.length > 0))
{
bCanShift = false;
}
}
}
if (Asc.linerule_Exact === RowH.HRule)
Y_content_end = Asc.NoYLimit;
Cell.PagesCount = 1;
Cell.Content.Reset(X_content_start, Y_content_start, X_content_end, Y_content_end);
}
// Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
// Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
// Recalculate_Page от несуществующих страниц.
var CellPageIndex = CurPage - Cell.Content.GetRelativeStartPage();
Cell.Content.Set_ClipInfo(CellPageIndex, Page.X + CellMetrics.X_cell_start, Page.X + CellMetrics.X_cell_end, clipTop, clipBottom);
if ( CellPageIndex < Cell.PagesCount )
{
if ( true === bCanShift )
{
Cell.ShiftCell(0, ShiftDx, ShiftDy);
Cell.Content.Set_ClipInfo(CellPageIndex, Page.X + CellMetrics.X_cell_start, Page.X + CellMetrics.X_cell_end, clipTop, clipBottom);
Cell.Content.UpdateEndInfo();
}
else
{
var RecalcResult = Cell.Content.Recalculate_Page(CellPageIndex, true);
if (recalcresult2_CurPage & RecalcResult)
{
var _RecalcResult = recalcresult_CurPage;
if (RecalcResult & recalcresultflags_Column)
_RecalcResult |= recalcresultflags_Column;
if (RecalcResult & recalcresultflags_Footnotes)
_RecalcResult |= recalcresultflags_Footnotes;
this.TurnOffRecalc = false;
return _RecalcResult;
}
else if (recalcresult2_NextPage & RecalcResult)
{
Cell.PagesCount = Cell.Content.Pages.length + 1;
bNextPage = true;
}
else if (recalcresult2_End & RecalcResult)
{
// Ничего не делаем
}
}
var CellContentBounds = Cell.Content.Get_PageBounds( CellPageIndex, undefined, true );
var CellContentBounds_Bottom = CellContentBounds.Bottom + BottomMargin;
if ( undefined === this.TableRowsBottom[CurRow][CurPage] || this.TableRowsBottom[CurRow][CurPage] < CellContentBounds_Bottom )
this.TableRowsBottom[CurRow][CurPage] = CellContentBounds_Bottom;
if ( vmerge_Continue === Vmerge )
{
if ( -1 === MaxBotValue_vmerge || MaxBotValue_vmerge < CellContentBounds_Bottom )
MaxBotValue_vmerge = CellContentBounds_Bottom;
}
}
var nCurFootnotesHeight = oFootnotes ? oFootnotes.GetHeight(nPageAbs, nColumnAbs) : 0;
if (oFootnotes && nCurFootnotesHeight > nFootnotesHeight + 0.001)
{
this.Pages[CurPage].FootnotesH = nCurFootnotesHeight;
nFootnotesHeight = nCurFootnotesHeight;
nResetFootnotesIndex = CurRow;
Y = arrSavedY[oOriginCell.Row.Index];
TableHeight = arrSavedTableHeight[oOriginCell.Row.Index];
oFootnotes.LoadRecalculateObject(nPageAbs, nColumnAbs, arrFootnotesObject[oOriginCell.Row.Index]);
CurRow = oOriginCell.Row.Index - 1;
bFootnoteBreak = true;
break;
}
CurGridCol += GridSpan;
}
if (oFootnotes && (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact == RowH.HRule))
{
oFootnotes.PopCellLimit();
}
if (bFootnoteBreak)
continue;
if (undefined === this.TableRowsBottom[CurRow][CurPage])
this.TableRowsBottom[CurRow][CurPage] = Y;
// Если в строке все ячейки с вертикальным выравниванием
if (bAllCellsVertical && Asc.linerule_Auto === RowH.HRule)
this.TableRowsBottom[CurRow][CurPage] = Y + 4.5 + this.MaxBotMargin[CurRow] + MaxTopMargin;
if (Asc.linerule_Exact === RowH.HRule)
this.TableRowsBottom[CurRow][CurPage] = Y + RowHValue;
if ((Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact === RowH.HRule)
&& AscCommon.MMToTwips(Y + RowHValue + rowMaxBotBorder, 1) >= AscCommon.MMToTwips(Y_content_end_row, -1)
&& ((0 === CurRow && 0 === CurPage && null !== this.Get_DocumentPrev() && !this.Parent.IsFirstElementOnPage(this.GetRelativePage(CurPage), this.GetIndex()))
|| CurRow !== FirstRow))
{
bNextPage = true;
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var Vmerge = Cell.GetVMerge();
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
// Проверяем только начальные ячейки вертикального объединения..
if ( vmerge_Continue === Vmerge || VMergeCount > 1 )
continue;
Cell.Content.StartFromNewPage();
Cell.PagesCount = 2;
}
}
// Данная строка разбилась на несколько страниц. Нам нужно сделать несколько дополнительных действий:
// 1. Проверяем есть ли хоть какой-либо контент данной строки на первой странице, т.е. реально данная
// строка начинается со 2-ой страницы.
// 2. Пересчитать все смерженные вертикально ячейки, которые также разбиваются на несколько страниц,
// но у которых вертикальное объединение не заканчивается на данной странице.
if ( true === bNextPage )
{
// TODO: Здесь происходит расчет параметра FirstPage для строки, на которой произошел разрыв страницы
// Непонятная ситуация, если строка разывается и на следующей странице, то параметр высчитывается
// зачем-то заново с учетом текущей, хотя он имеет смысл только для первой страницы. Надо разобраться
var bContentOnFirstPage = false;
var bNoContentOnFirstPage = false;
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var Vmerge = Cell.GetVMerge();
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
// Проверяем только начальные ячейки вертикального объединения..
if ( vmerge_Continue === Vmerge || VMergeCount > 1 )
continue;
if (true === Cell.IsVerticalText() || true === Cell.Content_Is_ContentOnFirstPage())
{
bContentOnFirstPage = true;
}
else
{
bNoContentOnFirstPage = true;
}
}
if (CurRow > 0 && (CurRow > FirstRow || CurPage > 0) && this.RowsInfo[CurRow - 1].VMerged)
{
bContentOnFirstPage = true;
bNoContentOnFirstPage = false;
}
if ( true === bContentOnFirstPage && true === bNoContentOnFirstPage )
{
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var Vmerge = Cell.GetVMerge();
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
// Проверяем только начальные ячейки вертикального объединения..
if ( vmerge_Continue === Vmerge || VMergeCount > 1 )
continue;
Cell.Content.StartFromNewPage();
Cell.PagesCount = 2;
}
bContentOnFirstPage = false;
}
this.RowsInfo[CurRow].FirstPage = bContentOnFirstPage;
// Не сраниваем MaxBotValue_vmerge с -1, т.к. значения в this.TableRowsBottom в любом случае неотрицательные
if ( 0 != CurRow && false === this.RowsInfo[CurRow].FirstPage )
{
if ( this.TableRowsBottom[CurRow - 1][CurPage] < MaxBotValue_vmerge )
{
// Поскольку мы правим настройку не текущей строки, надо подправить и
// запись о рассчитанной высоте строки
var Diff = MaxBotValue_vmerge - this.TableRowsBottom[CurRow - 1][CurPage];
this.TableRowsBottom[CurRow - 1][CurPage] = MaxBotValue_vmerge;
this.RowsInfo[CurRow - 1].H[CurPage] += Diff;
}
}
// Здесь мы должны рассчитать ячейки, которые попали в вертикальное объединение и из-за этого не были рассчитаны
var CellsCount2 = Merged_Cell.length;
var bFootnoteBreak = false;
for (var TempCellIndex = 0; TempCellIndex < CellsCount2; TempCellIndex++)
{
var Cell = Merged_Cell[TempCellIndex];
var CurCell = Cell.Index;
var GridSpan = Cell.Get_GridSpan();
var CurGridCol = Cell.Metrics.StartGridCol;
// Возьмем верхнюю ячейку теккущего объединения
Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
if (true === Cell.IsVerticalText())
{
VerticallCells.push(Cell);
CurGridCol += GridSpan;
continue;
}
var CellMar = Cell.GetMargins();
var CellMetrics = Row.Get_CellInfo(CurCell);
var X_content_start = Page.X + CellMetrics.X_content_start;
var X_content_end = Page.X + CellMetrics.X_content_end;
// Если в текущей строке на данной странице не убралось ничего из других ячеек, тогда
// рассчитываем вертикально объединенные ячейки до начала данной строки.
var Y_content_start = Cell.Temp.Y;
var Y_content_end = false === bContentOnFirstPage ? Y : this.Pages[CurPage].YLimit - nFootnotesHeight;
// TODO: При расчете YLimit для ячейки сделать учет толщины нижних
// границ ячейки и таблицы
if (null != CellSpacing)
{
if (this.Content.length - 1 === CurRow)
Y_content_end -= CellSpacing;
else
Y_content_end -= CellSpacing / 2;
}
var VMergeCount = this.Internal_GetVertMergeCount(CurRow, CurGridCol, GridSpan);
var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
Y_content_end -= BottomMargin;
if ((0 === Cell.Row.Index && 0 === CurPage) || Cell.Row.Index > FirstRow)
{
Cell.PagesCount = 1;
Cell.Content.Set_StartPage(CurPage);
Cell.Content.Reset(X_content_start, Y_content_start, X_content_end, Y_content_end);
}
// Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
// Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
// Recalculate_Page от несуществующих страниц.
var CellPageIndex = CurPage - Cell.Content.GetRelativeStartPage();
if (CellPageIndex < Cell.PagesCount)
{
if (recalcresult2_NextPage === Cell.Content.Recalculate_Page(CellPageIndex, true))
{
Cell.PagesCount = Cell.Content.Pages.length + 1;
bNextPage = true;
}
var CellContentBounds = Cell.Content.Get_PageBounds(CellPageIndex, undefined, true);
var CellContentBounds_Bottom = CellContentBounds.Bottom + BottomMargin;
if (0 != CurRow && false === this.RowsInfo[CurRow].FirstPage)
{
if (this.TableRowsBottom[CurRow - 1][CurPage] < CellContentBounds_Bottom)
{
// Поскольку мы правим настройку не текущей строки, надо подправить и
// запись о рассчитанной высоте строки
var Diff = CellContentBounds_Bottom - this.TableRowsBottom[CurRow - 1][CurPage];
this.TableRowsBottom[CurRow - 1][CurPage] = CellContentBounds_Bottom;
this.RowsInfo[CurRow - 1].H[CurPage] += Diff;
}
}
else if (Asc.linerule_Exact !== RowH.HRule)
{
if (undefined === this.TableRowsBottom[CurRow][CurPage] || this.TableRowsBottom[CurRow][CurPage] < CellContentBounds_Bottom)
this.TableRowsBottom[CurRow][CurPage] = CellContentBounds_Bottom;
}
}
// Проверяем наличие сносок, т.к. они могли появится в смерженных ячейках
var nCurFootnotesHeight = oFootnotes ? oFootnotes.GetHeight(nPageAbs, nColumnAbs) : 0;
if (oFootnotes && nCurFootnotesHeight > nFootnotesHeight + 0.001 && Cell.Row.Index >= FirstRow)
{
this.Pages[CurPage].FootnotesH = nCurFootnotesHeight;
nFootnotesHeight = nCurFootnotesHeight;
nResetFootnotesIndex = CurRow;
Y = arrSavedY[Cell.Row.Index];
TableHeight = arrSavedTableHeight[Cell.Row.Index];
oFootnotes.LoadRecalculateObject(nPageAbs, nColumnAbs, arrFootnotesObject[Cell.Row.Index]);
CurRow = Cell.Row.Index - 1;
bFootnoteBreak = true;
break;
}
CurGridCol += GridSpan;
}
if (bFootnoteBreak)
continue;
// Еще раз обновляем параметр, есть ли текст на первой странице
bContentOnFirstPage = false;
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var Vmerge = Cell.GetVMerge();
// Проверяем только начальные ячейки вертикального объединения..
if ( vmerge_Continue === Vmerge )
continue;
if (true === Cell.IsVerticalText())
continue;
if ( true === Cell.Content_Is_ContentOnFirstPage() )
{
bContentOnFirstPage = true;
break;
}
}
if (CurRow > 0 && (CurRow > FirstRow || CurPage > 0) && this.RowsInfo[CurRow - 1].VMerged)
bContentOnFirstPage = true;
this.RowsInfo[CurRow].FirstPage = bContentOnFirstPage;
}
// Выставляем так, чтобы высота была равна 0
if (true !== this.RowsInfo[CurRow].FirstPage && CurPage === this.RowsInfo[CurRow].StartPage)
this.TableRowsBottom[CurRow][CurPage] = Y;
// Здесь мы выставляем только начальную координату строки (для каждой страницы)
// высоту строки(для каждой страницы) мы должны обсчитать после общего цикла, т.к.
// в одной из следйющих строк может оказаться ячейка с вертикальным объединением,
// захватывающим данную строку. Значит, ее содержимое может изменить высоту нашей строки.
var TempY = Y;
var TempMaxTopBorder = nMaxTopBorder;
if ( null != CellSpacing )
{
this.RowsInfo[CurRow].Y[CurPage] = TempY;
this.RowsInfo[CurRow].TopDy[CurPage] = 0;
this.RowsInfo[CurRow].X0 = Row_x_min;
this.RowsInfo[CurRow].X1 = Row_x_max;
this.RowsInfo[CurRow].MaxTopBorder[CurPage] = TempMaxTopBorder;
this.RowsInfo[CurRow].MaxBotBorder = MaxBotBorder[CurRow];
}
else
{
this.RowsInfo[CurRow].Y[CurPage] = TempY - TempMaxTopBorder;
this.RowsInfo[CurRow].TopDy[CurPage] = TempMaxTopBorder;
this.RowsInfo[CurRow].X0 = Row_x_min;
this.RowsInfo[CurRow].X1 = Row_x_max;
this.RowsInfo[CurRow].MaxTopBorder[CurPage] = TempMaxTopBorder;
this.RowsInfo[CurRow].MaxBotBorder = MaxBotBorder[CurRow];
}
var CellHeight = this.TableRowsBottom[CurRow][CurPage] - Y;
// TODO: улучшить проверку на высоту строки (для строк разбитых на страницы)
// Условие Y + RowHValue < Y_content_end добавлено из-за сносок.
if (false === bNextPage
&& (Asc.linerule_AtLeast === RowH.HRule || Asc.linerule_Exact === RowH.HRule)
&& CellHeight < RowHValue
&& (nFootnotesHeight < 0.001 || Y + RowHValue + rowMaxBotBorder < Y_content_end))
{
CellHeight = RowHValue;
this.TableRowsBottom[CurRow][CurPage] = Y + CellHeight;
}
// Рассчитываем ячейки с вертикальным текстом
var CellsCount2 = VerticallCells.length;
for (var TempCellIndex = 0; TempCellIndex < CellsCount2; TempCellIndex++)
{
var Cell = VerticallCells[TempCellIndex];
var CurCell = Cell.Index;
var GridSpan = Cell.Get_GridSpan();
var CurGridCol = Cell.Metrics.StartGridCol;
// Возьмем верхнюю ячейку текущего объединения
Cell = this.Internal_Get_StartMergedCell(CurRow, CurGridCol, GridSpan);
var CellMar = Cell.GetMargins();
var CellMetrics = Cell.Row.Get_CellInfo(Cell.Index);
var X_content_start = Page.X + CellMetrics.X_content_start;
var X_content_end = Page.X + CellMetrics.X_content_end;
var Y_content_start = Cell.Temp.Y;
var Y_content_end = this.TableRowsBottom[CurRow][CurPage];
// TODO: При расчете YLimit для ячейки сделать учет толщины нижних
// границ ячейки и таблицы
if (null != CellSpacing)
{
if (this.Content.length - 1 === CurRow)
Y_content_end -= CellSpacing;
else
Y_content_end -= CellSpacing / 2;
}
var VMergeCount = this.Internal_GetVertMergeCount(CurRow, CurGridCol, GridSpan);
var BottomMargin = this.MaxBotMargin[CurRow + VMergeCount - 1];
Y_content_end -= BottomMargin;
if ((0 === Cell.Row.Index && true === this.Check_EmptyPages(CurPage - 1)) || Cell.Row.Index > FirstRow || (Cell.Row.Index === FirstRow && true === ResetStartElement))
{
// TODO: Здесь надо сделать, чтобы ячейка не билась на страницы
Cell.PagesCount = 1;
Cell.Content.Set_StartPage(CurPage);
Cell.Content.Reset(0, 0, Y_content_end - Y_content_start, 10000);
Cell.Temp.X_start = X_content_start;
Cell.Temp.Y_start = Y_content_start;
Cell.Temp.X_end = X_content_end;
Cell.Temp.Y_end = Y_content_end;
Cell.Temp.X_cell_start = Page.X + CellMetrics.X_cell_start;
Cell.Temp.X_cell_end = Page.X + CellMetrics.X_cell_end;
Cell.Temp.Y_cell_start = Y_content_start - CellMar.Top.W;
Cell.Temp.Y_cell_end = Y_content_end + BottomMargin;
}
// Какие-то ячейки в строке могут быть не разбиты на строки, а какие то разбиты.
// Здесь контролируем этот момент, чтобы у тех, которые не разбиты не вызывать
// Recalculate_Page от несуществующих страниц.
var CellPageIndex = CurPage - Cell.Content.GetRelativeStartPage();
if (0 === CellPageIndex)
{
Cell.Content.Recalculate_Page(CellPageIndex, true);
}
}
// Еще раз проверим, были ли сноски
var nCurFootnotesHeight = oFootnotes ? oFootnotes.GetHeight(nPageAbs, nColumnAbs) : 0;
if (oFootnotes && nCurFootnotesHeight > nFootnotesHeight + 0.001)
{
this.Pages[CurPage].FootnotesH = nCurFootnotesHeight;
nFootnotesHeight = nCurFootnotesHeight;
nResetFootnotesIndex = CurRow;
Y = arrSavedY[CurRow];
TableHeight = arrSavedTableHeight[CurRow];
oFootnotes.LoadRecalculateObject(nPageAbs, nColumnAbs, arrFootnotesObject[CurRow]);
CurRow--;
continue;
}
if ( null != CellSpacing )
this.RowsInfo[CurRow].H[CurPage] = CellHeight;
else
this.RowsInfo[CurRow].H[CurPage] = CellHeight + TempMaxTopBorder;
Y += CellHeight;
TableHeight += CellHeight;
Row.Height = CellHeight;
Y += MaxBotBorder[CurRow];
TableHeight += MaxBotBorder[CurRow];
if ( this.Content.length - 1 === CurRow )
{
if ( null != CellSpacing )
{
TableHeight += CellSpacing;
var TableBorder_Bottom = this.Get_Borders().Bottom;
if ( border_Single === TableBorder_Bottom.Value )
TableHeight += TableBorder_Bottom.Size;
}
}
if ( true === bNextPage )
{
LastRow = CurRow;
this.Pages[CurPage].LastRow = CurRow;
if (-1 === this.HeaderInfo.PageIndex && this.HeaderInfo.Count > 0 && CurRow >= this.HeaderInfo.Count)
this.HeaderInfo.PageIndex = CurPage;
if ((CurRow < this.HeaderInfo.Count || (CurRow === this.HeaderInfo.Count && !this.RowsInfo[CurRow].FirstPage && nCompatibilityMode >= AscCommon.document_compatibility_mode_Word14))
&& (0 === CurPage && null !== this.Get_DocumentPrev() && !this.Parent.IsFirstElementOnPage(this.GetRelativePage(CurPage), this.GetIndex())))
{
this.HeaderInfo.PageIndex = -1;
LastRow = 0;
this.RowsInfo[0].FirstPage = false;
this.Pages[CurPage].LastRow = 0;
}
break;
}
else if ( this.Content.length - 1 === CurRow )
{
LastRow = this.Content.length - 1;
this.Pages[CurPage].LastRow = this.Content.length - 1;
}
}
// Сделаем вертикальное выравнивание ячеек в таблице. Делаем как Word, если ячейка разбилась на несколько
// страниц, тогда вертикальное выравнивание применяем только к первой странице.
// Делаем это не в общем цикле, потому что объединенные вертикально ячейки могут вносить поправки в значения
// this.TableRowsBottom, в последней строке.
for ( var CurRow = FirstRow; CurRow <= LastRow; CurRow++ )
{
var Row = this.Content[CurRow];
var CellsCount = Row.Get_CellsCount();
for ( var CurCell = 0; CurCell < CellsCount; CurCell++ )
{
var Cell = Row.Get_Cell( CurCell );
var VMergeCount = this.Internal_GetVertMergeCount( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
if ( VMergeCount > 1 && CurRow != LastRow )
continue;
else
{
var Vmerge = Cell.GetVMerge();
// Возьмем верхнюю ячейку текущего объединения
if ( vmerge_Restart != Vmerge )
{
Cell = this.Internal_Get_StartMergedCell( CurRow, Cell.Metrics.StartGridCol, Cell.Get_GridSpan() );
}
}
var CellMar = Cell.GetMargins();
var VAlign = Cell.Get_VAlign();
let cellContent = Cell.GetContent();
var CellPageIndex = CurPage - cellContent.GetRelativeStartPage();
if ( CellPageIndex >= Cell.PagesCount )
continue;
// Рассчитаем имеющуюся в распоряжении высоту ячейки
var TempCurRow = Cell.Row.Index;
// Для прилегания к верху или для второй страницы ничего не делаем (так изначально рассчитывалось)
let topAlign = (vertalignjc_Top === VAlign);
if (!topAlign)
{
for (let tmpCellPage = 0; tmpCellPage < CellPageIndex; ++tmpCellPage)
{
if (!cellContent.IsEmptyPage(tmpCellPage))
{
topAlign = true;
break;
}
}
}
if (topAlign)
{
Cell.Temp.Y_VAlign_offset[CellPageIndex] = 0;
continue;
}
var TempCellSpacing = this.Content[TempCurRow].Get_CellSpacing();
var Y_0 = this.RowsInfo[TempCurRow].Y[CurPage];
if(!this.bPresentation)
{
if ( null === TempCellSpacing )
Y_0 += MaxTopBorder[TempCurRow];
}
Y_0 += CellMar.Top.W;
var Y_1 = this.TableRowsBottom[CurRow][CurPage] - CellMar.Bottom.W;
var CellHeight = Y_1 - Y_0;
var CellContentBounds = Cell.Content.Get_PageBounds( CellPageIndex, CellHeight, true );
var ContentHeight = CellContentBounds.Bottom - CellContentBounds.Top;
var Dy = 0;
if (true === Cell.IsVerticalText())
{
var CellMetrics = Row.Get_CellInfo(CurCell);
CellHeight = CellMetrics.X_cell_end - CellMetrics.X_cell_start - CellMar.Left.W - CellMar.Right.W;
}
// В версиях совместимости до 14, если текст в ячейке повернут, то выравнивание идет по центру, даже если
// содержимое не убирается в пределах ячейки. В более поздних версиях всегда к верху выравнивание, в такой
// ситуации
if (CellHeight - ContentHeight > 0.001
|| (nCompatibilityMode <= AscCommon.document_compatibility_mode_Word14 && Cell.IsVerticalText()))
{
if (vertalignjc_Bottom === VAlign)
Dy = CellHeight - ContentHeight;
else if (vertalignjc_Center === VAlign)
Dy = (CellHeight - ContentHeight) / 2;
Cell.ShiftCellContent(CellPageIndex, 0, Dy, true);
}
Cell.Temp.Y_VAlign_offset[CellPageIndex] = Dy;
}
}
// Просчитаем нижнюю границу таблицы на данной странице
var CurRow = LastRow;
if ( 0 === CurRow && false === this.RowsInfo[CurRow].FirstPage && 0 === CurPage )
{
// Таблица сразу переносится на следующую страницу
this.Pages[0].MaxBotBorder = 0;
this.Pages[0].BotBorders = [];
}
else
{
// Если последняя строка на данной странице не имеет контента, тогда рассчитываем
// границу у предыдущей строки.
if ( false === this.RowsInfo[CurRow].FirstPage && CurPage === this.RowsInfo[CurRow].StartPage )
CurRow--;
var MaxBotBorder = 0;
var BotBorders = [];
if (CurRow >= this.Pages[CurPage].FirstRow)
{
// Для ряда CurRow вычисляем нижнюю границу
if (this.Content.length - 1 === CurRow)
{
// Для последнего ряда уже есть готовые нижние границы
var Row = this.Content[CurRow];
var CellsCount = Row.Get_CellsCount();
for (var CurCell = 0; CurCell < CellsCount; CurCell++)
{
var Cell = Row.Get_Cell(CurCell);
if (vmerge_Continue === Cell.GetVMerge())
Cell = this.Internal_Get_StartMergedCell(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
var Border_Info = Cell.GetBorderInfo().Bottom;
for (var BorderId = 0; BorderId < Border_Info.length; BorderId++)
{
var Border = Border_Info[BorderId];
if (border_Single === Border.Value && MaxBotBorder < Border.Size)
MaxBotBorder = Border.Size;
BotBorders.push(Border);
}
}
}
else
{
var Row = this.Content[CurRow];
var CellSpacing = Row.Get_CellSpacing();
var CellsCount = Row.Get_CellsCount();
if (null != CellSpacing)
{
// BotBorders можно не заполнять, т.к. у каждой ячейки своя граница,
// нам надо только посчитать максимальную толщину.
for (var CurCell = 0; CurCell < CellsCount; CurCell++)
{
var Cell = Row.Get_Cell(CurCell);
var Border = Cell.Get_Borders().Bottom;
if (border_Single === Border.Value && MaxBotBorder < Border.Size)
MaxBotBorder = Border.Size;
}
}
else
{
// Сравниваем нижнюю границу ячейки и нижнюю границу таблицы
for (var CurCell = 0; CurCell < CellsCount; CurCell++)
{
var Cell = Row.Get_Cell(CurCell);
if (vmerge_Continue === Cell.GetVMerge())
{
Cell = this.Internal_Get_StartMergedCell(CurRow, Row.Get_CellInfo(CurCell).StartGridCol, Cell.Get_GridSpan());
if (null === Cell)
{
BotBorders.push(TableBorders.Bottom);
continue;
}
}
var Border = Cell.Get_Borders().Bottom;
// Сравним границы
var Result_Border = this.private_ResolveBordersConflict(Border, TableBorders.Bottom, false, true);
if (border_Single === Result_Border.Value && MaxBotBorder < Result_Border.Size)
MaxBotBorder = Result_Border.Size;
BotBorders.push(Result_Border);
}
}
}
}
this.Pages[CurPage].MaxBotBorder = MaxBotBorder;
this.Pages[CurPage].BotBorders = BotBorders;
}
this.Pages[CurPage].Bounds.Bottom = this.Pages[CurPage].Bounds.Top + TableHeight;
this.Pages[CurPage].Bounds.Left = X_min + this.Pages[CurPage].X;
this.Pages[CurPage].Bounds.Right = X_max + this.Pages[CurPage].X;
this.Pages[CurPage].Height = TableHeight;
if (true === bNextPage)
{
var LastRow = this.Pages[CurPage].LastRow;
if (false === this.RowsInfo[LastRow].FirstPage)
this.Pages[CurPage].LastRow = LastRow - 1;
else
this.Pages[CurPage].LastRowSplit = true;
}
this.TurnOffRecalc = false;
this.Bounds = this.Pages[this.Pages.length - 1].Bounds;
if ( true == bNextPage )
return recalcresult_NextPage;
else
return recalcresult_NextElement;
};
CTable.prototype.private_RecalculatePrepareHeaderPageRows = function(headerPage)
{
headerPage.Rows = [];
let self = this;
AscCommon.ExecuteNoHistory(function()
{
let drawingObjects = [];
for (var index = 0; index < self.HeaderInfo.Count; ++index)
{
headerPage.Rows[index] = self.Content[index].Copy(self);
headerPage.Rows[index].SetIndex(index);
headerPage.Rows[index].GetAllDrawingObjects(drawingObjects);
}
for (let index = 0, count = drawingObjects.length; index < count; ++index)
{
let drawing = drawingObjects[index];
if (!drawing || !drawing.GraphicObj)
continue;
drawing.GraphicObj.recalculate();
if (drawing.GraphicObj.recalculateText)
drawing.GraphicObj.recalculateText();
}
}, this.LogicDocument);
};
CTable.prototype.private_RecalculatePositionY = function(CurPage)
{
var isHdrFtr = this.Parent.IsHdrFtr();
var nPageRel = this.GetRelativePage(CurPage);
var nPageAbs = this.GetAbsolutePage(CurPage);
var PageLimits = this.Parent.Get_PageLimits(nPageRel);
var PageFields = this.Parent.Get_PageFields(nPageRel, isHdrFtr);
var LD_PageFields = this.LogicDocument.Get_PageFields(nPageAbs, isHdrFtr);
var LD_PageLimits = this.LogicDocument.Get_PageLimits(nPageAbs);
if ( true === this.Is_Inline() && 0 === CurPage )
{
this.AnchorPosition.CalcY = this.Y;
this.AnchorPosition.Set_Y(this.Pages[CurPage].Height, this.Y, LD_PageFields.Y, LD_PageFields.YLimit, LD_PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit);
}
else if ( true != this.Is_Inline() && ( 0 === CurPage || ( 1 === CurPage && false === this.RowsInfo[0].FirstPage ) ) )
{
this.AnchorPosition.Set_Y(this.Pages[CurPage].Height, this.Pages[CurPage].Y, PageFields.Y, PageFields.YLimit, LD_PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit, PageLimits.Y, PageLimits.YLimit);
var OtherFlowTables = !this.bPresentation ? editor.WordControl.m_oLogicDocument.DrawingObjects.getAllFloatTablesOnPage( this.GetAbsoluteStartPage() ) : [];
this.AnchorPosition.Calculate_Y(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);
this.AnchorPosition.Correct_Values( PageLimits.X, PageLimits.Y, PageLimits.XLimit, PageLimits.YLimit, this.AllowOverlap, OtherFlowTables, this );
if ( undefined != this.PositionV_Old )
{
// Восстанови старые значения, чтобы в историю изменений все нормально записалось
this.PositionV.RelativeFrom = this.PositionV_Old.RelativeFrom;
this.PositionV.Align = this.PositionV_Old.Align;
this.PositionV.Value = this.PositionV_Old.Value;
// Рассчитаем сдвиг с учетом старой привязки
var Value = this.AnchorPosition.Calculate_Y_Value(this.PositionV_Old.RelativeFrom);
this.Set_PositionV( this.PositionV_Old.RelativeFrom, false, Value );
// На всякий случай пересчитаем заново координату
this.AnchorPosition.Calculate_Y(this.PositionV.RelativeFrom, this.PositionV.Align, this.PositionV.Value);
this.PositionV_Old = undefined;
}
var NewX = this.AnchorPosition.CalcX;
var NewY = this.AnchorPosition.CalcY;
this.Shift( CurPage, NewX - this.Pages[CurPage].X, NewY - this.Pages[CurPage].Y );
}
};
CTable.prototype.private_RecalculatePercentWidth = function()
{
return this.TableWidthRange - this.GetTableOffsetCorrection() + this.GetRightTableOffsetCorrection();
};
CTable.prototype.private_RecalculateGridCols = function()
{
for (var nCurRow = 0, nRowsCount = this.Content.length; nCurRow < nRowsCount; ++nCurRow)
{
var oRow = this.Content[nCurRow];
var oBeforeInfo = oRow.Get_Before();
var nCurGridCol = oBeforeInfo.GridBefore;
for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
{
var oCell = oRow.GetCell(nCurCell);
oRow.Set_CellInfo(nCurCell, nCurGridCol, 0, 0, 0, 0, 0, 0);
oCell.Set_Metrics(nCurGridCol, 0, 0, 0, 0, 0, 0);
nCurGridCol += oCell.Get_GridSpan();
}
}
};
CTable.prototype.private_GetMaxTopBorderWidth = function(nCurRow, isHeader)
{
var nMax = 0;
var oRow = this.GetRow(nCurRow);
for (var nCurCell = 0, nCellsCount = oRow.GetCellsCount(); nCurCell < nCellsCount; ++nCurCell)
{
var oCell = oRow.GetCell(nCurCell);
var arrBorderInfo = isHeader ? oCell.GetBorderInfo().TopHeader : oCell.GetBorderInfo().Top;
for (var nInfoIndex = 0, nInfosCount = arrBorderInfo.length; nInfoIndex < nInfosCount; ++nInfoIndex)
{
var nBorderW = arrBorderInfo[nInfoIndex].GetWidth();
if (nMax < nBorderW)
nMax = nBorderW;
}
}
return nMax;
};
CTable.prototype.private_IsVMergedRow = function(iRow)
{
let row = this.GetRow(iRow);
let curGridCol = row.GetBefore().Grid;
for (let iCell = 0, nCells = row.GetCellsCount(); iCell < nCells; ++iCell)
{
let cell = row.GetCell(iCell);
let gridSpan = cell.GetGridSpan();
if (this.Internal_GetVertMergeCount(iRow, curGridCol, gridSpan) <= 1)
return false;
curGridCol += gridSpan;
}
return true;
};
//----------------------------------------------------------------------------------------------------------------------
// Класс CTablePage
//----------------------------------------------------------------------------------------------------------------------
function CTablePage(X, Y, XLimit, YLimit, FirstRow, MaxTopBorder)
{
this.X_origin = X;
this.X = X;
this.Y = Y;
this.XLimit = XLimit;
this.YLimit = YLimit;
this.Bounds = new CDocumentBounds(X, Y, XLimit, Y);
this.MaxTopBorder = MaxTopBorder;
this.FirstRow = FirstRow;
this.LastRow = FirstRow;
this.Height = 0;
this.LastRowSplit = false;
this.FootnotesH = 0;
this.MaxBotBorder = 0;
this.BotBorders = [];
}
CTablePage.prototype.Shift = function(Dx, Dy)
{
this.X += Dx;
this.Y += Dy;
this.XLimit += Dx;
this.YLimit += Dy;
this.Bounds.Shift(Dx, Dy);
};
CTablePage.prototype.GetFirstRow = function()
{
return this.FirstRow;
};
CTablePage.prototype.GetLastRow = function()
{
return this.LastRow;
};
//----------------------------------------------------------------------------------------------------------------------
// Класс CTableRecalcInfo
//----------------------------------------------------------------------------------------------------------------------
function CTableRecalcInfo()
{
this.TableGrid = true;
this.TableBorders = true;
this.CellsToRecalc = {};
this.CellsAll = true;
}
CTableRecalcInfo.prototype.RecalcBorders = function()
{
this.TableBorders = true;
};
CTableRecalcInfo.prototype.Add_Cell = function(Cell)
{
this.CellsToRecalc[Cell.Get_Id()] = Cell;
};
CTableRecalcInfo.prototype.Check_Cell = function(Cell)
{
if ( true === this.CellsAll || undefined != this.CellsToRecalc[Cell.Get_Id()] )
return true;
return false;
};
CTableRecalcInfo.prototype.Recalc_AllCells = function()
{
this.CellsAll = true;
};
CTableRecalcInfo.prototype.Reset = function(isNeedRecalculate)
{
this.TableGrid = isNeedRecalculate;
this.TableBorders = isNeedRecalculate;
this.CellsAll = isNeedRecalculate;
this.CellsToRecalc = {};
};
//----------------------------------------------------------------------------------------------------------------------
// Класс CTableRecalculateObject
//----------------------------------------------------------------------------------------------------------------------
function CTableRecalculateObject()
{
this.TableSumGrid = [];
this.TableGridCalc = [];
this.TableRowsBottom = [];
this.HeaderInfo = {};
this.RowsInfo = [];
this.X_origin = 0;
this.X = 0;
this.Y = 0;
this.XLimit = 0;
this.YLimit = 0;
this.Pages = [];
this.MaxTopBorder = [];
this.MaxBotBorder = [];
this.MaxBotMargin = [];
this.Content = [];
}
CTableRecalculateObject.prototype.Save = function(Table)
{
this.TableSumGrid = Table.TableSumGrid;
this.TableGridCalc = Table.TableGridCalc;
this.TableRowsBottom = Table.TableRowsBottom;
this.HeaderInfo = Table.HeaderInfo;
this.RowsInfo = Table.RowsInfo;
this.X_origin = Table.X_origin;
this.X = Table.X;
this.Y = Table.Y;
this.XLimit = Table.XLimit;
this.YLimit = Table.YLimit;
this.Pages = Table.Pages;
this.MaxTopBorder = Table.MaxTopBorder;
this.MaxBotBorder = Table.MaxBotBorder;
this.MaxBotMargin = Table.MaxBotBorder;
var Count = Table.Content.length;
for ( var Index = 0; Index < Count; Index++ )
{
this.Content[Index] = Table.Content[Index].SaveRecalculateObject();
}
};
CTableRecalculateObject.prototype.Load = function(Table)
{
Table.TableSumGrid = this.TableSumGrid;
Table.TableGridCalc = this.TableGridCalc;
Table.TableRowsBottom = this.TableRowsBottom;
Table.HeaderInfo = this.HeaderInfo;
Table.RowsInfo = this.RowsInfo;
Table.X_origin = this.X_origin;
Table.X = this.X;
Table.Y = this.Y;
Table.XLimit = this.XLimit;
Table.YLimit = this.YLimit;
Table.Pages = this.Pages;
Table.MaxTopBorder = this.MaxTopBorder;
Table.MaxBotBorder = this.MaxBotBorder;
Table.MaxBotMargin = this.MaxBotBorder;
var Count = this.Content.length;
for ( var Index = 0; Index < Count; Index++ )
{
Table.Content[Index].LoadRecalculateObject( this.Content[Index] );
}
};
CTableRecalculateObject.prototype.Get_DrawingFlowPos = function(FlowPos)
{
var Count = this.Content.length;
for (var Index = 0; Index < Count; Index++)
{
this.Content[Index].Get_DrawingFlowPos(FlowPos);
}
};