387 lines
11 KiB
JavaScript
387 lines
11 KiB
JavaScript
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2024
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
(function(window)
|
|
{
|
|
/**
|
|
* Класс представляющий нумерацию в документе
|
|
* @constructor
|
|
*/
|
|
function CNumbering()
|
|
{
|
|
this.AbstractNum = {}; // all abstract nums
|
|
this.Num = {};
|
|
|
|
this.AbstractNumByNsid = {};
|
|
}
|
|
|
|
/**
|
|
* Копируем все нумерации и абстрактные нумерации. Возвращаем новые объекты с мапом из старых Id в новые
|
|
* @param oNumbering {CNumbering}
|
|
* @returns {{AbstractNum: {}, AbstractMap: {}, Num: {}, NumMap: {}}}
|
|
*/
|
|
CNumbering.prototype.CopyAllNums = function(oNumbering)
|
|
{
|
|
if (!oNumbering)
|
|
oNumbering = this;
|
|
|
|
var oAbstractMap = {};
|
|
var oNumMap = {};
|
|
var oNewAbstractNums = {};
|
|
var oNewNums = {}
|
|
|
|
for (var sOldId in this.AbstractNum)
|
|
{
|
|
var oOldAbstractNum = this.AbstractNum[sOldId];
|
|
var oNewAbstractNum = new CAbstractNum();
|
|
|
|
var sNewId = oNewAbstractNum.GetId();
|
|
oNewAbstractNum.Copy(oOldAbstractNum);
|
|
|
|
oNewAbstractNums[sNewId] = oNewAbstractNum;
|
|
oAbstractMap[sOldId] = sNewId;
|
|
}
|
|
|
|
for (var sOldId in this.Num)
|
|
{
|
|
var oOldNum = this.Num[sOldId];
|
|
var oNewNum = new CNum(oNumbering, oAbstractMap[oOldNum.AbstractNumId]);
|
|
|
|
for (var nLvl = 0; nLvl < 9; ++nLvl)
|
|
{
|
|
if (oOldNum.LvlOverride[nLvl] && oOldNum.LvlOverride[nLvl].NumberingLvl)
|
|
oNewNum.SetLvlOverride(oOldNum.LvlOverride[nLvl].GetLvl().Copy(), nLvl, oOldNum.LvlOverride[nLvl].GetStartOverride());
|
|
}
|
|
|
|
var sNewId = oNewNum.GetId();
|
|
|
|
oNewNums[sNewId] = oNewNum;
|
|
oNumMap[sOldId] = sNewId;
|
|
}
|
|
|
|
return {
|
|
AbstractNum : oNewAbstractNums,
|
|
AbstractMap : oAbstractMap,
|
|
Num : oNewNums,
|
|
NumMap : oNumMap
|
|
};
|
|
};
|
|
/**
|
|
* Удаляем все нумерации
|
|
*/
|
|
CNumbering.prototype.Clear = function()
|
|
{
|
|
this.AbstractNum = {};
|
|
this.Num = {};
|
|
this.AbstractNumByNsid = {};
|
|
};
|
|
/**
|
|
* Добавляем к текущим абстрактным нумерациям новые
|
|
* @param {AscWord.CAbstractNum[]} abstractNums
|
|
*/
|
|
CNumbering.prototype.AppendAbstractNums = function(abstractNums)
|
|
{
|
|
for (let numId in abstractNums)
|
|
{
|
|
if (undefined === this.AbstractNum[numId])
|
|
this._AddAbstractNum(abstractNums[numId], numId);
|
|
}
|
|
};
|
|
/**
|
|
* Добавляем к текущим нумерациям новые
|
|
* @param oNums
|
|
*/
|
|
CNumbering.prototype.AppendNums = function(oNums)
|
|
{
|
|
for (var sId in oNums)
|
|
{
|
|
if (undefined === this.Num[sId])
|
|
this.Num[sId] = oNums[sId];
|
|
}
|
|
};
|
|
/**
|
|
* Создаем новую абстрактную нумерацию
|
|
* @returns {AscWord.CAbstractNum}
|
|
*/
|
|
CNumbering.prototype.CreateAbstractNum = function()
|
|
{
|
|
let abstractNum = this._CreateAbstractNumWithUniqueNsid();
|
|
this._AddAbstractNum(abstractNum, abstractNum.GetId());
|
|
return abstractNum;
|
|
};
|
|
/**
|
|
* Добавляем абстрактную нумерацию
|
|
* @param abstractNum {CAbstractNum}
|
|
* @returns {string} идентификатор нумерации
|
|
*/
|
|
CNumbering.prototype.AddAbstractNum = function(abstractNum)
|
|
{
|
|
if (!(abstractNum instanceof CAbstractNum))
|
|
return;
|
|
|
|
let numId = abstractNum.GetId();
|
|
this._AddAbstractNum(abstractNum, numId);
|
|
return numId;
|
|
};
|
|
/**
|
|
* Добавляем абстрактную нумерацию
|
|
* @param oNum {CNum}
|
|
* @returns {string} идентификатор нумерации
|
|
*/
|
|
CNumbering.prototype.AddNum = function(oNum)
|
|
{
|
|
if (!(oNum instanceof CNum))
|
|
return;
|
|
|
|
var sNumId = oNum.GetId();
|
|
this.Num[sNumId] = oNum;
|
|
|
|
return sNumId;
|
|
};
|
|
/**
|
|
* Доступ к абстрактной нумерации по Id
|
|
* @param sId
|
|
* @returns {CAbstractNum}
|
|
*/
|
|
CNumbering.prototype.GetAbstractNum = function(sId)
|
|
{
|
|
let abstractNum = this.AbstractNum[sId];
|
|
let nsid = abstractNum ? abstractNum.GetNsid() : null;
|
|
if (nsid && this.AbstractNumByNsid[nsid])
|
|
abstractNum = this.AbstractNumByNsid[nsid];
|
|
|
|
if (!abstractNum)
|
|
return null;
|
|
|
|
if (abstractNum.GetNumStyleLink())
|
|
{
|
|
var oStyles = editor.WordControl.m_oLogicDocument.GetStyles();
|
|
var oNumStyle = oStyles.Get(abstractNum.GetNumStyleLink());
|
|
|
|
if (oNumStyle && oNumStyle.ParaPr.NumPr && undefined !== oNumStyle.ParaPr.NumPr.NumId)
|
|
{
|
|
var oStyleNum = this.GetNum(oNumStyle.ParaPr.NumPr.NumId);
|
|
if (!oStyleNum)
|
|
return null;
|
|
|
|
return oStyleNum.GetAbstractNum();
|
|
}
|
|
}
|
|
|
|
return abstractNum;
|
|
};
|
|
/**
|
|
* Создаем новую нумерацию
|
|
* @returns {CNum}
|
|
*/
|
|
CNumbering.prototype.CreateNum = function()
|
|
{
|
|
let abstractNum = this._CreateAbstractNumWithUniqueNsid();
|
|
this._AddAbstractNum(abstractNum, abstractNum.GetId());
|
|
|
|
var oNum = new CNum(this, abstractNum.GetId());
|
|
this.Num[oNum.GetId()] = oNum;
|
|
|
|
return oNum;
|
|
};
|
|
/**
|
|
* @param sId
|
|
* @returns {CNum}
|
|
*/
|
|
CNumbering.prototype.GetNum = function(sId)
|
|
{
|
|
if (this.Num[sId])
|
|
return this.Num[sId];
|
|
|
|
return null;
|
|
};
|
|
/**
|
|
* Получаем настройки параграфа для заданного уровня заданной нумерации
|
|
* @param sNumId {string}
|
|
* @param nLvl {number} 0..8
|
|
* @returns {CParaPr}
|
|
*/
|
|
CNumbering.prototype.GetParaPr = function(sNumId, nLvl)
|
|
{
|
|
var oNum = this.GetNum(sNumId);
|
|
if (oNum)
|
|
return oNum.GetLvl(nLvl).GetParaPr();
|
|
|
|
return new CParaPr();
|
|
};
|
|
/**
|
|
* Получаем формат заданного уровня заданной нумерации
|
|
* @param sNumId
|
|
* @param nLvl
|
|
* @returns {Asc.c_oAscNumberingFormat}
|
|
*/
|
|
CNumbering.prototype.GetNumFormat = function(sNumId, nLvl)
|
|
{
|
|
var oNum = this.GetNum(sNumId);
|
|
if (!oNum)
|
|
return Asc.c_oAscNumberingFormat.Bullet;
|
|
|
|
var oLvl = oNum.GetLvl(nLvl);
|
|
if (!oLvl)
|
|
return Asc.c_oAscNumberingFormat.Bullet;
|
|
|
|
return oLvl.Format;
|
|
};
|
|
/**
|
|
* Проверяем по типам Numbered и Bullet
|
|
* @param numId {string}
|
|
* @param iLvl {number}
|
|
* @param format {Asc.c_oAscNumberingFormat}
|
|
* @returns {boolean}
|
|
*/
|
|
CNumbering.prototype.CheckFormat = function(numId, iLvl, format)
|
|
{
|
|
let numFormat = this.GetNumFormat(numId, iLvl);
|
|
|
|
return !!((AscWord.IsBulletedNumbering(format) && AscWord.IsBulletedNumbering(numFormat))
|
|
|| (AscWord.IsNumberedNumbering(format) && AscWord.IsNumberedNumbering(numFormat)));
|
|
};
|
|
CNumbering.prototype.Draw = function(sNumId, nLvl, nX, nY, oContext, oNumInfo, oTextPr, oTheme, isRtl)
|
|
{
|
|
var oNum = this.GetNum(sNumId);
|
|
return oNum.Draw(nX, nY, oContext, nLvl, oNumInfo, oTextPr, oTheme, isRtl);
|
|
};
|
|
CNumbering.prototype.Measure = function(sNumId, nLvl, oContext, oNumInfo, oTextPr, oTheme)
|
|
{
|
|
var oNum = this.GetNum(sNumId);
|
|
return oNum.Measure(oContext, nLvl, oNumInfo, oTextPr, oTheme);
|
|
};
|
|
/**
|
|
* Получаем список всех символов используемых в заданном уровне заданной нумерации
|
|
* @param oFontCharMap
|
|
* @param oNumTextPr
|
|
* @param oNumPr
|
|
* @param oNumInfo
|
|
*/
|
|
CNumbering.prototype.CreateFontCharMap = function(oFontCharMap, oNumTextPr, oNumPr, oNumInfo)
|
|
{
|
|
var oNum = this.GetNum(oNumPr.NumId);
|
|
oNum.CreateFontCharMap(oFontCharMap, oNumPr.Lvl, oNumInfo, oNumTextPr);
|
|
};
|
|
/**
|
|
* Получаем список всех используемых шрифтов
|
|
* @param arrAllFonts {array}
|
|
*/
|
|
CNumbering.prototype.GetAllFontNames = function(arrAllFonts)
|
|
{
|
|
for (var sNumId in this.Num)
|
|
{
|
|
var oNum = this.GetNum(sNumId);
|
|
oNum.GetAllFontNames(arrAllFonts);
|
|
}
|
|
|
|
arrAllFonts["Symbol"] = true;
|
|
arrAllFonts["Courier New"] = true;
|
|
arrAllFonts["Wingdings"] = true;
|
|
};
|
|
/**
|
|
* Получаем текст нумерации для заданного уровня
|
|
* @param sNumId {string}
|
|
* @param nLvl {number} 0..8
|
|
* @param oNumInfo
|
|
* @param bWithoutLastLvlText {?boolean}
|
|
* @param [oLang] {AscCommonWord.CLang}
|
|
* @returns {string}
|
|
*/
|
|
CNumbering.prototype.GetText = function(sNumId, nLvl, oNumInfo, bWithoutLastLvlText, oLang)
|
|
{
|
|
var oNum = this.GetNum(sNumId);
|
|
return oNum.GetText(nLvl, oNumInfo, bWithoutLastLvlText, oLang);
|
|
};
|
|
/**
|
|
* Проверяем, есть ли обьекты на которые можно ссылаться
|
|
* @returns {boolean}
|
|
*/
|
|
CNumbering.prototype.IsEmpty = function()
|
|
{
|
|
return 0 === Object.keys(this.Num).length;
|
|
};
|
|
/**
|
|
* Получаем список идентификаторов всех нумераций, который основаны на заданной абстрактной
|
|
* @param abstractNum {AscWord.CAbstractNum}
|
|
* @returns {AscWord.CNum[]}
|
|
*/
|
|
CNumbering.prototype.GetAllNumsByAbstractNum = function(abstractNum)
|
|
{
|
|
if (!abstractNum)
|
|
return [];
|
|
|
|
let abstractNumId = abstractNum.GetId();
|
|
let result = [];
|
|
for (let numId in this.Num)
|
|
{
|
|
let num = this.Num[numId];
|
|
if (abstractNumId === num.GetAbstractNumId())
|
|
result.push(num);
|
|
}
|
|
return result;
|
|
};
|
|
CNumbering.prototype._AddAbstractNum = function(abstractNum, numId)
|
|
{
|
|
this.AbstractNum[numId] = abstractNum;
|
|
abstractNum.SetParent(this);
|
|
|
|
let nsid = abstractNum.GetNsid();
|
|
if (nsid && !this.AbstractNumByNsid[nsid])
|
|
this.AbstractNumByNsid[nsid] = abstractNum;
|
|
};
|
|
CNumbering.prototype._CreateAbstractNumWithUniqueNsid = function()
|
|
{
|
|
let abstractNum = new AscWord.CAbstractNum();
|
|
let nsid = abstractNum.GetNsid();
|
|
|
|
// TODO: Need to create a general scheme for obtaining DurableId with check of existing ones
|
|
let attempts = 100;
|
|
while (!nsid || (this.AbstractNumByNsid[nsid] && attempts >= 0))
|
|
{
|
|
nsid = AscCommon.CreateDurableId();
|
|
attempts -= 1;
|
|
}
|
|
|
|
if (nsid !== abstractNum.GetNsid())
|
|
abstractNum.SetNsid(nsid);
|
|
|
|
return abstractNum;
|
|
};
|
|
//---------------------------------------------------------export---------------------------------------------------
|
|
window["AscWord"].CNumbering = CNumbering;
|
|
window["AscWord"].DEFAULT_NUMBERING = new CNumbering();
|
|
|
|
})(window);
|