mirror of
https://github.com/ONLYOFFICE/sdkjs.git
synced 2026-04-07 14:09:12 +08:00
1579 lines
60 KiB
JavaScript
1579 lines
60 KiB
JavaScript
/*
|
||
* (c) Copyright Ascensio System SIA 2010-2019
|
||
*
|
||
* 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-12 Ernesta Birznieka-Upisha
|
||
* 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, undefined){
|
||
|
||
var FOREIGN_CURSOR_LABEL_HIDETIME = 1500;
|
||
|
||
function CCollaborativeChanges()
|
||
{
|
||
this.m_pData = null;
|
||
this.m_oColor = null;
|
||
}
|
||
CCollaborativeChanges.prototype.Set_Data = function(pData)
|
||
{
|
||
this.m_pData = pData;
|
||
};
|
||
CCollaborativeChanges.prototype.Set_Color = function(oColor)
|
||
{
|
||
this.m_oColor = oColor;
|
||
};
|
||
CCollaborativeChanges.prototype.Set_FromUndoRedo = function(Class, Data, Binary)
|
||
{
|
||
if (!Class.Get_Id)
|
||
return false;
|
||
|
||
this.m_pData = this.private_SaveData(Binary);
|
||
return true;
|
||
};
|
||
CCollaborativeChanges.prototype.Apply_Data = function()
|
||
{
|
||
var CollaborativeEditing = AscCommon.CollaborativeEditing;
|
||
|
||
var Reader = this.private_LoadData(this.m_pData);
|
||
var ClassId = Reader.GetString2();
|
||
var Class = AscCommon.g_oTableId.Get_ById(ClassId);
|
||
|
||
if (!Class)
|
||
return false;
|
||
|
||
//------------------------------------------------------------------------------------------------------------------
|
||
// Новая схема
|
||
var nReaderPos = Reader.GetCurPos();
|
||
var nChangesType = Reader.GetLong();
|
||
|
||
var fChangesClass = AscDFH.changesFactory[nChangesType];
|
||
if (fChangesClass)
|
||
{
|
||
var oChange = new fChangesClass(Class);
|
||
oChange.ReadFromBinary(Reader);
|
||
|
||
if (true === CollaborativeEditing.private_AddOverallChange(oChange))
|
||
oChange.Load(this.m_oColor);
|
||
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
CollaborativeEditing.private_AddOverallChange(this.m_pData);
|
||
// Сюда мы попадаем, когда у данного изменения нет класса и он все еще работает по старой схеме через объект
|
||
|
||
Reader.Seek2(nReaderPos);
|
||
//\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
|
||
// Старая схема
|
||
|
||
if (!Class.Load_Changes)
|
||
return false;
|
||
|
||
return Class.Load_Changes(Reader, null, this.m_oColor);
|
||
}
|
||
};
|
||
CCollaborativeChanges.prototype.private_LoadData = function(szSrc)
|
||
{
|
||
return this.GetStream(szSrc, 0, szSrc.length);
|
||
};
|
||
CCollaborativeChanges.prototype.GetStream = function(szSrc, offset, srcLen)
|
||
{
|
||
var nWritten = 0;
|
||
|
||
var index = -1 + offset;
|
||
var dst_len = "";
|
||
|
||
while (true)
|
||
{
|
||
index++;
|
||
var _c = szSrc.charCodeAt(index);
|
||
if (_c == ";".charCodeAt(0))
|
||
{
|
||
index++;
|
||
break;
|
||
}
|
||
|
||
dst_len += String.fromCharCode(_c);
|
||
}
|
||
|
||
var dstLen = parseInt(dst_len);
|
||
|
||
var pointer = AscFonts.g_memory.Alloc(dstLen);
|
||
var stream = new AscCommon.FT_Stream2(pointer.data, dstLen);
|
||
stream.obj = pointer.obj;
|
||
|
||
var dstPx = stream.data;
|
||
|
||
if (window.chrome)
|
||
{
|
||
while (index < srcLen)
|
||
{
|
||
var dwCurr = 0;
|
||
var i;
|
||
var nBits = 0;
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
if (index >= srcLen)
|
||
break;
|
||
var nCh = AscFonts.DecodeBase64Char(szSrc.charCodeAt(index++));
|
||
if (nCh == -1)
|
||
{
|
||
i--;
|
||
continue;
|
||
}
|
||
dwCurr <<= 6;
|
||
dwCurr |= nCh;
|
||
nBits += 6;
|
||
}
|
||
|
||
dwCurr <<= 24 - nBits;
|
||
for (i = 0; i < nBits / 8; i++)
|
||
{
|
||
dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
|
||
dwCurr <<= 8;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var p = AscFonts.b64_decode;
|
||
while (index < srcLen)
|
||
{
|
||
var dwCurr = 0;
|
||
var i;
|
||
var nBits = 0;
|
||
for (i = 0; i < 4; i++)
|
||
{
|
||
if (index >= srcLen)
|
||
break;
|
||
var nCh = p[szSrc.charCodeAt(index++)];
|
||
if (nCh == undefined)
|
||
{
|
||
i--;
|
||
continue;
|
||
}
|
||
dwCurr <<= 6;
|
||
dwCurr |= nCh;
|
||
nBits += 6;
|
||
}
|
||
|
||
dwCurr <<= 24 - nBits;
|
||
for (i = 0; i < nBits / 8; i++)
|
||
{
|
||
dstPx[nWritten++] = ((dwCurr & 0x00ff0000) >>> 16);
|
||
dwCurr <<= 8;
|
||
}
|
||
}
|
||
}
|
||
|
||
return stream;
|
||
};
|
||
CCollaborativeChanges.prototype.private_SaveData = function(Binary)
|
||
{
|
||
var Writer = AscCommon.History.BinaryWriter;
|
||
var Pos = Binary.Pos;
|
||
var Len = Binary.Len;
|
||
return Len + ";" + Writer.GetBase64Memory2(Pos, Len);
|
||
};
|
||
|
||
|
||
function CCollaborativeEditingBase()
|
||
{
|
||
this.m_nUseType = 1; // 1 - 1 клиент и мы сохраняем историю, -1 - несколько клиентов, 0 - переход из -1 в 1
|
||
|
||
this.m_aUsers = []; // Список текущих пользователей, редактирующих данный документ
|
||
this.m_aChanges = []; // Массив с изменениями других пользователей
|
||
|
||
this.m_aNeedUnlock = []; // Массив со списком залоченных объектов(которые были залочены другими пользователями)
|
||
this.m_aNeedUnlock2 = []; // Массив со списком залоченных объектов(которые были залочены на данном клиенте)
|
||
this.m_aNeedLock = []; // Массив со списком залоченных объектов(которые были залочены, но еще не были добавлены на данном клиенте)
|
||
|
||
this.m_aLinkData = []; // Массив, указателей, которые нам надо выставить при загрузке чужих изменений
|
||
this.m_aEndActions = []; // Массив действий, которые надо выполнить после принятия чужих изменений
|
||
|
||
|
||
this.m_bGlobalLock = 0; // Запрещаем производить любые "редактирующие" действия (т.е. то, что в историю запишется)
|
||
this.m_bGlobalLockSelection = 0; // Запрещаем изменять селект и курсор
|
||
this.m_aCheckLocks = []; // Массив для проверки залоченности объектов, которые мы собираемся изменять
|
||
|
||
this.m_aNewObjects = []; // Массив со списком чужих новых объектов
|
||
this.m_aNewImages = []; // Массив со списком картинок, которые нужно будет загрузить на сервере
|
||
this.m_aDC = {}; // Массив(ассоциативный) классов DocumentContent
|
||
this.m_aChangedClasses = {}; // Массив(ассоциативный) классов, в которых есть изменения выделенные цветом
|
||
|
||
this.m_oMemory = null; // Глобальные класс для сохранения (создадим позднее, когда понадобится)
|
||
|
||
this.m_aCursorsToUpdate = {}; // Курсоры, которые нужно обновить после принятия изменений
|
||
this.m_aCursorsToUpdateShortId = {};
|
||
|
||
// // CollaborativeEditing LOG
|
||
// this.m_nErrorLog_PointChangesCount = 0;
|
||
// this.m_nErrorLog_SavedPCC = 0;
|
||
// this.m_nErrorLog_CurPointIndex = -1;
|
||
// this.m_nErrorLog_SumIndex = 0;
|
||
|
||
this.m_bFast = false;
|
||
|
||
this.m_oLogicDocument = null;
|
||
this.m_aDocumentPositions = new CDocumentPositionsManager();
|
||
this.m_aForeignCursorsPos = new CDocumentPositionsManager();
|
||
this.m_aForeignCursors = {};
|
||
this.m_aForeignCursorsId = {};
|
||
|
||
|
||
this.m_nAllChangesSavedIndex = 0;
|
||
|
||
this.m_aAllChanges = []; // Список всех изменений
|
||
this.m_aOwnChangesIndexes = []; // Список номеров своих изменений в общем списке, которые мы можем откатить
|
||
|
||
this.m_oOwnChanges = [];
|
||
}
|
||
|
||
CCollaborativeEditingBase.prototype.Clear = function()
|
||
{
|
||
this.m_nUseType = 1;
|
||
|
||
this.m_aUsers = [];
|
||
this.m_aChanges = [];
|
||
this.m_aNeedUnlock = [];
|
||
this.m_aNeedUnlock2 = [];
|
||
this.m_aNeedLock = [];
|
||
this.m_aLinkData = [];
|
||
this.m_aEndActions = [];
|
||
this.m_aCheckLocks = [];
|
||
this.m_aNewObjects = [];
|
||
this.m_aNewImages = [];
|
||
};
|
||
CCollaborativeEditingBase.prototype.Set_Fast = function(bFast)
|
||
{
|
||
this.m_bFast = bFast;
|
||
|
||
if (false === bFast)
|
||
{
|
||
this.Remove_AllForeignCursors();
|
||
this.RemoveMyCursorFromOthers();
|
||
}
|
||
};
|
||
CCollaborativeEditingBase.prototype.Is_Fast = function()
|
||
{
|
||
return this.m_bFast;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Is_SingleUser = function()
|
||
{
|
||
return (1 === this.m_nUseType);
|
||
};
|
||
CCollaborativeEditingBase.prototype.getCollaborativeEditing = function()
|
||
{
|
||
return !this.Is_SingleUser();
|
||
};
|
||
CCollaborativeEditingBase.prototype.Start_CollaborationEditing = function()
|
||
{
|
||
this.m_nUseType = -1;
|
||
};
|
||
CCollaborativeEditingBase.prototype.End_CollaborationEditing = function()
|
||
{
|
||
if (this.m_nUseType <= 0)
|
||
this.m_nUseType = 0;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_User = function(UserId)
|
||
{
|
||
if (-1 === this.Find_User(UserId))
|
||
this.m_aUsers.push(UserId);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Find_User = function(UserId)
|
||
{
|
||
var Len = this.m_aUsers.length;
|
||
for (var Index = 0; Index < Len; Index++)
|
||
{
|
||
if (this.m_aUsers[Index] === UserId)
|
||
return Index;
|
||
}
|
||
|
||
return -1;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Remove_User = function(UserId)
|
||
{
|
||
var Pos = this.Find_User( UserId );
|
||
if ( -1 != Pos )
|
||
this.m_aUsers.splice( Pos, 1 );
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_Changes = function(Changes)
|
||
{
|
||
this.m_aChanges.push(Changes);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_Unlock = function(LockClass)
|
||
{
|
||
this.m_aNeedUnlock.push( LockClass );
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_Unlock2 = function(Lock)
|
||
{
|
||
this.m_aNeedUnlock2.push(Lock);
|
||
editor._onUpdateDocumentCanSave();
|
||
};
|
||
CCollaborativeEditingBase.prototype.Have_OtherChanges = function()
|
||
{
|
||
return (0 < this.m_aChanges.length);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Apply_Changes = function()
|
||
{
|
||
var OtherChanges = (this.m_aChanges.length > 0);
|
||
|
||
// Если нет чужих изменений, тогда и делать ничего не надо
|
||
if (true === OtherChanges)
|
||
{
|
||
AscFonts.IsCheckSymbols = true;
|
||
editor.WordControl.m_oLogicDocument.Stop_Recalculate();
|
||
editor.WordControl.m_oLogicDocument.EndPreview_MailMergeResult();
|
||
|
||
editor.sync_StartAction(Asc.c_oAscAsyncActionType.BlockInteraction, Asc.c_oAscAsyncAction.ApplyChanges);
|
||
|
||
var DocState = this.private_SaveDocumentState();
|
||
this.Clear_NewImages();
|
||
|
||
this.Apply_OtherChanges();
|
||
|
||
// После того как мы приняли чужие изменения, мы должны залочить новые объекты, которые были залочены
|
||
this.Lock_NeedLock();
|
||
this.private_RestoreDocumentState(DocState);
|
||
this.OnStart_Load_Objects();
|
||
AscFonts.IsCheckSymbols = false;
|
||
}
|
||
};
|
||
CCollaborativeEditingBase.prototype.Apply_OtherChanges = function()
|
||
{
|
||
// Чтобы заново созданные параграфы не отображались залоченными
|
||
AscCommon.g_oIdCounter.Set_Load( true );
|
||
|
||
if (this.m_aChanges.length > 0)
|
||
this.private_CollectOwnChanges();
|
||
|
||
// Применяем изменения, пока они есть
|
||
var _count = this.m_aChanges.length;
|
||
for (var i = 0; i < _count; i++)
|
||
{
|
||
if (window["NATIVE_EDITOR_ENJINE"] === true && window["native"]["CheckNextChange"])
|
||
{
|
||
if (!window["native"]["CheckNextChange"]())
|
||
break;
|
||
}
|
||
|
||
var Changes = this.m_aChanges[i];
|
||
Changes.Apply_Data();
|
||
// // CollaborativeEditing LOG
|
||
// this.m_nErrorLog_PointChangesCount++;
|
||
}
|
||
|
||
this.private_ClearChanges();
|
||
|
||
// У новых элементов выставляем указатели на другие классы
|
||
this.Apply_LinkData();
|
||
|
||
// Делаем проверки корректности новых изменений
|
||
this.Check_MergeData();
|
||
|
||
this.OnEnd_ReadForeignChanges();
|
||
|
||
AscCommon.g_oIdCounter.Set_Load( false );
|
||
};
|
||
CCollaborativeEditingBase.prototype.getOwnLocksLength = function()
|
||
{
|
||
return this.m_aNeedUnlock2.length;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Send_Changes = function()
|
||
{
|
||
};
|
||
CCollaborativeEditingBase.prototype.Release_Locks = function()
|
||
{
|
||
};
|
||
|
||
|
||
CCollaborativeEditingBase.prototype.CheckWaitingImages = function (aImages) {
|
||
|
||
};
|
||
|
||
CCollaborativeEditingBase.prototype.SendImagesUrlsFromChanges = function (aImages) {
|
||
var rData = {}, oApi = editor || Asc['editor'], i;
|
||
if(!oApi){
|
||
return;
|
||
}
|
||
rData['id'] = oApi.documentId;
|
||
rData['c'] = 'pathurls';
|
||
rData['data'] = [];
|
||
for(i = 0; i < aImages.length; ++i)
|
||
{
|
||
rData['data'].push(aImages[i]);
|
||
}
|
||
var aImagesToLoad = [].concat(AscCommon.CollaborativeEditing.m_aNewImages);
|
||
this.CheckWaitingImages(aImagesToLoad);
|
||
AscCommon.CollaborativeEditing.m_aNewImages.length = 0;
|
||
if(false === oApi.isSaveFonts_Images){
|
||
oApi.isSaveFonts_Images = true;
|
||
}
|
||
oApi.fCurCallback = function (oRes) {
|
||
var aData, i, oUrls;
|
||
if(oRes['status'] === 'ok')
|
||
{
|
||
aData = oRes['data'];
|
||
oUrls= {};
|
||
for(i = 0; i < aData.length; ++i)
|
||
{
|
||
oUrls[aImages[i]] = aData[i];
|
||
}
|
||
AscCommon.g_oDocumentUrls.addUrls(oUrls);
|
||
}
|
||
AscCommon.CollaborativeEditing.SendImagesCallback(aImagesToLoad);
|
||
};
|
||
AscCommon.sendCommand(oApi, null, rData);
|
||
};
|
||
|
||
CCollaborativeEditingBase.prototype.SendImagesCallback = function (aImages) {
|
||
var oApi = editor || Asc['editor'];
|
||
oApi.pre_Save(aImages);
|
||
};
|
||
|
||
|
||
CCollaborativeEditingBase.prototype.CollectImagesFromChanges = function () {
|
||
var oApi = editor || Asc['editor'];
|
||
var aImages = [], sImagePath, i, sImageFromChanges, oThemeUrls = {};
|
||
var aNewImages = this.m_aNewImages;
|
||
var oMap = {};
|
||
for(i = 0; i < aNewImages.length; ++i)
|
||
{
|
||
sImageFromChanges = aNewImages[i];
|
||
if(oMap[sImageFromChanges])
|
||
{
|
||
continue;
|
||
}
|
||
oMap[sImageFromChanges] = 1;
|
||
if(sImageFromChanges.indexOf('theme') === 0 && oApi.ThemeLoader)
|
||
{
|
||
oThemeUrls[sImageFromChanges] = oApi.ThemeLoader.ThemesUrlAbs + sImageFromChanges;
|
||
}
|
||
else if (0 === sImageFromChanges.indexOf('http:') || 0 === sImageFromChanges.indexOf('data:') || 0 === sImageFromChanges.indexOf('https:') ||
|
||
0 === sImageFromChanges.indexOf('file:') || 0 === sImageFromChanges.indexOf('ftp:'))
|
||
{
|
||
}
|
||
else
|
||
{
|
||
sImagePath = AscCommon.g_oDocumentUrls.mediaPrefix + sImageFromChanges;
|
||
if(!AscCommon.g_oDocumentUrls.getUrl(sImagePath))
|
||
{
|
||
aImages.push(sImagePath);
|
||
}
|
||
}
|
||
}
|
||
AscCommon.g_oDocumentUrls.addUrls(oThemeUrls);
|
||
return aImages;
|
||
};
|
||
|
||
|
||
CCollaborativeEditingBase.prototype.OnStart_Load_Objects = function()
|
||
{
|
||
this.Set_GlobalLock(true);
|
||
this.Set_GlobalLockSelection(true);
|
||
// Вызываем функцию для загрузки необходимых элементов (новые картинки и шрифты)
|
||
var aImages = this.CollectImagesFromChanges();
|
||
if(aImages.length > 0)
|
||
{
|
||
this.SendImagesUrlsFromChanges(aImages);
|
||
}
|
||
else
|
||
{
|
||
this.SendImagesCallback([].concat(this.m_aNewImages));
|
||
this.m_aNewImages.length = 0;
|
||
}
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnEnd_Load_Objects = function()
|
||
{
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с ссылками, у новых объектов
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Clear_LinkData = function()
|
||
{
|
||
this.m_aLinkData.length = 0;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_LinkData = function(Class, LinkData)
|
||
{
|
||
this.m_aLinkData.push( { Class : Class, LinkData : LinkData } );
|
||
};
|
||
CCollaborativeEditingBase.prototype.Apply_LinkData = function()
|
||
{
|
||
var Count = this.m_aLinkData.length;
|
||
for ( var Index = 0; Index < Count; Index++ )
|
||
{
|
||
var Item = this.m_aLinkData[Index];
|
||
Item.Class.Load_LinkData( Item.LinkData );
|
||
}
|
||
|
||
this.Clear_LinkData();
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для проверки корректности новых изменений
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Check_MergeData = function()
|
||
{
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для проверки залоченности объектов
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Get_GlobalLock = function()
|
||
{
|
||
return (0 === this.m_bGlobalLock ? false : true);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Set_GlobalLock = function(isLock)
|
||
{
|
||
if (isLock)
|
||
this.m_bGlobalLock++;
|
||
else
|
||
this.m_bGlobalLock = Math.max(0, this.m_bGlobalLock - 1);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Set_GlobalLockSelection = function(isLock)
|
||
{
|
||
if (isLock)
|
||
this.m_bGlobalLockSelection++;
|
||
else
|
||
this.m_bGlobalLockSelection = Math.max(0, this.m_bGlobalLockSelection - 1);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Get_GlobalLockSelection = function()
|
||
{
|
||
return (0 === this.m_bGlobalLockSelection ? false : true);
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnStart_CheckLock = function()
|
||
{
|
||
this.m_aCheckLocks.length = 0;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_CheckLock = function(oItem)
|
||
{
|
||
this.m_aCheckLocks.push(oItem);
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnEnd_CheckLock = function()
|
||
{
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnCallback_AskLock = function(result)
|
||
{
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с залоченными объектами, которые еще не были добавлены
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Reset_NeedLock = function()
|
||
{
|
||
this.m_aNeedLock = {};
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_NeedLock = function(Id, sUser)
|
||
{
|
||
this.m_aNeedLock[Id] = sUser;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Remove_NeedLock = function(Id)
|
||
{
|
||
delete this.m_aNeedLock[Id];
|
||
};
|
||
CCollaborativeEditingBase.prototype.Lock_NeedLock = function()
|
||
{
|
||
for ( var Id in this.m_aNeedLock )
|
||
{
|
||
var Class = AscCommon.g_oTableId.Get_ById( Id );
|
||
|
||
if ( null != Class )
|
||
{
|
||
var Lock = Class.Lock;
|
||
Lock.Set_Type( AscCommon.locktype_Other, false );
|
||
if(Class.getObjectType && Class.getObjectType() === AscDFH.historyitem_type_Slide)
|
||
{
|
||
editor.WordControl.m_oLogicDocument.DrawingDocument.UnLockSlide && editor.WordControl.m_oLogicDocument.DrawingDocument.UnLockSlide(Class.num);
|
||
}
|
||
Lock.Set_UserId( this.m_aNeedLock[Id] );
|
||
}
|
||
}
|
||
|
||
this.Reset_NeedLock();
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с новыми объектами, созданными на других клиентах
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Clear_NewObjects = function()
|
||
{
|
||
this.m_aNewObjects.length = 0;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_NewObject = function(Class)
|
||
{
|
||
this.m_aNewObjects.push(Class);
|
||
Class.FromBinary = true;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Clear_EndActions = function()
|
||
{
|
||
this.m_aEndActions.length = 0;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_EndActions = function(Class, Data)
|
||
{
|
||
this.m_aEndActions.push({Class : Class, Data : Data});
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnEnd_ReadForeignChanges = function()
|
||
{
|
||
var Count = this.m_aNewObjects.length;
|
||
|
||
for (var Index = 0; Index < Count; Index++)
|
||
{
|
||
var Class = this.m_aNewObjects[Index];
|
||
Class.FromBinary = false;
|
||
}
|
||
|
||
Count = this.m_aEndActions.length;
|
||
for (var Index = 0; Index < Count; Index++)
|
||
{
|
||
var Item = this.m_aEndActions[Index];
|
||
Item.Class.Process_EndLoad(Item.Data);
|
||
}
|
||
|
||
this.Clear_EndActions();
|
||
this.Clear_NewObjects();
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с новыми объектами, созданными на других клиентах
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Clear_NewImages = function()
|
||
{
|
||
this.m_aNewImages.length = 0;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_NewImage = function(Url)
|
||
{
|
||
this.m_aNewImages.push( Url );
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с массивом m_aDC
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Add_NewDC = function(Class)
|
||
{
|
||
var Id = Class.Get_Id();
|
||
this.m_aDC[Id] = Class;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Clear_DCChanges = function()
|
||
{
|
||
for (var Id in this.m_aDC)
|
||
{
|
||
this.m_aDC[Id].Clear_ContentChanges();
|
||
}
|
||
|
||
// Очищаем массив
|
||
this.m_aDC = {};
|
||
};
|
||
CCollaborativeEditingBase.prototype.Refresh_DCChanges = function()
|
||
{
|
||
for (var Id in this.m_aDC)
|
||
{
|
||
this.m_aDC[Id].Refresh_ContentChanges();
|
||
}
|
||
|
||
this.Clear_DCChanges();
|
||
};
|
||
|
||
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с массивами PosExtChangesX, PosExtChangesY
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.AddPosExtChanges = function(Item, ChangeObject){
|
||
|
||
};
|
||
CCollaborativeEditingBase.prototype.RefreshPosExtChanges = function(){
|
||
|
||
};
|
||
CCollaborativeEditingBase.prototype.RewritePosExtChanges = function(changesArr, scale, Binary_Writer)
|
||
{
|
||
};
|
||
|
||
CCollaborativeEditingBase.prototype.RefreshPosExtChanges = function()
|
||
{
|
||
};
|
||
//-----------------------------------------------------------------------------------
|
||
// Функции для работы с отметками изменений
|
||
//-----------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Add_ChangedClass = function(Class)
|
||
{
|
||
var Id = Class.Get_Id();
|
||
this.m_aChangedClasses[Id] = Class;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Clear_CollaborativeMarks = function(bRepaint)
|
||
{
|
||
for ( var Id in this.m_aChangedClasses )
|
||
{
|
||
this.m_aChangedClasses[Id].Clear_CollaborativeMarks();
|
||
}
|
||
|
||
// Очищаем массив
|
||
this.m_aChangedClasses = {};
|
||
|
||
|
||
if (true === bRepaint)
|
||
{
|
||
editor.WordControl.m_oLogicDocument.DrawingDocument.ClearCachePages();
|
||
editor.WordControl.m_oLogicDocument.DrawingDocument.FirePaint();
|
||
}
|
||
};
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
// Функции для работы с обновлением курсоров после принятия изменений
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Add_ForeignCursorToUpdate = function(UserId, CursorInfo, UserShortId)
|
||
{
|
||
this.m_aCursorsToUpdate[UserId] = CursorInfo;
|
||
this.m_aCursorsToUpdateShortId[UserId] = UserShortId;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Refresh_ForeignCursors = function()
|
||
{
|
||
if (!this.m_oLogicDocument)
|
||
return;
|
||
|
||
for (var UserId in this.m_aCursorsToUpdate)
|
||
{
|
||
var CursorInfo = this.m_aCursorsToUpdate[UserId];
|
||
this.m_oLogicDocument.Update_ForeignCursor(CursorInfo, UserId, false, this.m_aCursorsToUpdateShortId[UserId]);
|
||
|
||
if (this.Add_ForeignCursorToShow)
|
||
this.Add_ForeignCursorToShow(UserId);
|
||
}
|
||
this.m_aCursorsToUpdate = {};
|
||
this.m_aCursorsToUpdateShortId = {};
|
||
};
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
// Функции для работы с сохраненными позициями в Word-документах. Они объявлены в базовом классе, потому что вызываются
|
||
// из общих классов Paragraph, Run, Table. Вообщем, для совместимости.
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.Clear_DocumentPositions = function(){
|
||
this.m_aDocumentPositions.Clear_DocumentPositions();
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_DocumentPosition = function(DocumentPos){
|
||
this.m_aDocumentPositions.Add_DocumentPosition(DocumentPos);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Add_ForeignCursor = function(UserId, DocumentPos, UserShortId){
|
||
this.m_aForeignCursorsPos.Remove_DocumentPosition(this.m_aCursorsToUpdate[UserId]);
|
||
this.m_aForeignCursors[UserId] = DocumentPos;
|
||
this.m_aForeignCursorsPos.Add_DocumentPosition(DocumentPos);
|
||
this.m_aForeignCursorsId[UserId] = UserShortId;
|
||
};
|
||
CCollaborativeEditingBase.prototype.Remove_ForeignCursor = function(UserId){
|
||
this.m_aForeignCursorsPos.Remove_DocumentPosition(this.m_aCursorsToUpdate[UserId]);
|
||
delete this.m_aForeignCursors[UserId];
|
||
};
|
||
CCollaborativeEditingBase.prototype.Remove_AllForeignCursors = function(){};
|
||
CCollaborativeEditingBase.prototype.RemoveMyCursorFromOthers = function(){};
|
||
CCollaborativeEditingBase.prototype.Update_DocumentPositionsOnAdd = function(Class, Pos){
|
||
this.m_aDocumentPositions.Update_DocumentPositionsOnAdd(Class, Pos);
|
||
this.m_aForeignCursorsPos.Update_DocumentPositionsOnAdd(Class, Pos);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Update_DocumentPositionsOnRemove = function(Class, Pos, Count){
|
||
this.m_aDocumentPositions.Update_DocumentPositionsOnRemove(Class, Pos, Count);
|
||
this.m_aForeignCursorsPos.Update_DocumentPositionsOnRemove(Class, Pos, Count);
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnStart_SplitRun = function(SplitRun, SplitPos){
|
||
this.m_aDocumentPositions.OnStart_SplitRun(SplitRun, SplitPos);
|
||
this.m_aForeignCursorsPos.OnStart_SplitRun(SplitRun, SplitPos);
|
||
};
|
||
CCollaborativeEditingBase.prototype.OnEnd_SplitRun = function(NewRun){
|
||
this.m_aDocumentPositions.OnEnd_SplitRun(NewRun);
|
||
this.m_aForeignCursorsPos.OnEnd_SplitRun(NewRun);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Update_DocumentPosition = function(DocPos){
|
||
this.m_aDocumentPositions.Update_DocumentPosition(DocPos);
|
||
};
|
||
CCollaborativeEditingBase.prototype.Update_ForeignCursorsPositions = function(){
|
||
|
||
};
|
||
CCollaborativeEditingBase.prototype.InitMemory = function() {
|
||
if (!this.m_oMemory) {
|
||
this.m_oMemory = new AscCommon.CMemory();
|
||
}
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_SaveDocumentState = function()
|
||
{
|
||
var LogicDocument = editor.WordControl.m_oLogicDocument;
|
||
|
||
var DocState;
|
||
if (true !== this.Is_Fast())
|
||
{
|
||
DocState = LogicDocument.Get_SelectionState2();
|
||
this.m_aCursorsToUpdate = {};
|
||
}
|
||
else
|
||
{
|
||
DocState = LogicDocument.Save_DocumentStateBeforeLoadChanges();
|
||
this.Clear_DocumentPositions();
|
||
|
||
if (DocState.Pos)
|
||
this.Add_DocumentPosition(DocState.Pos);
|
||
if (DocState.StartPos)
|
||
this.Add_DocumentPosition(DocState.StartPos);
|
||
if (DocState.EndPos)
|
||
this.Add_DocumentPosition(DocState.EndPos);
|
||
|
||
if (DocState.FootnotesStart && DocState.FootnotesStart.Pos)
|
||
this.Add_DocumentPosition(DocState.FootnotesStart.Pos);
|
||
if (DocState.FootnotesStart && DocState.FootnotesStart.StartPos)
|
||
this.Add_DocumentPosition(DocState.FootnotesStart.StartPos);
|
||
if (DocState.FootnotesStart && DocState.FootnotesStart.EndPos)
|
||
this.Add_DocumentPosition(DocState.FootnotesStart.EndPos);
|
||
if (DocState.FootnotesEnd && DocState.FootnotesEnd.Pos)
|
||
this.Add_DocumentPosition(DocState.FootnotesEnd.Pos);
|
||
if (DocState.FootnotesEnd && DocState.FootnotesEnd.StartPos)
|
||
this.Add_DocumentPosition(DocState.FootnotesEnd.StartPos);
|
||
if (DocState.FootnotesEnd && DocState.FootnotesEnd.EndPos)
|
||
this.Add_DocumentPosition(DocState.FootnotesEnd.EndPos);
|
||
}
|
||
return DocState;
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_RestoreDocumentState = function(DocState)
|
||
{
|
||
var LogicDocument = editor.WordControl.m_oLogicDocument;
|
||
if (true !== this.Is_Fast())
|
||
{
|
||
LogicDocument.Set_SelectionState2(DocState);
|
||
}
|
||
else
|
||
{
|
||
if (DocState.Pos)
|
||
this.Update_DocumentPosition(DocState.Pos);
|
||
if (DocState.StartPos)
|
||
this.Update_DocumentPosition(DocState.StartPos);
|
||
if (DocState.EndPos)
|
||
this.Update_DocumentPosition(DocState.EndPos);
|
||
|
||
if (DocState.FootnotesStart && DocState.FootnotesStart.Pos)
|
||
this.Update_DocumentPosition(DocState.FootnotesStart.Pos);
|
||
if (DocState.FootnotesStart && DocState.FootnotesStart.StartPos)
|
||
this.Update_DocumentPosition(DocState.FootnotesStart.StartPos);
|
||
if (DocState.FootnotesStart && DocState.FootnotesStart.EndPos)
|
||
this.Update_DocumentPosition(DocState.FootnotesStart.EndPos);
|
||
if (DocState.FootnotesEnd && DocState.FootnotesEnd.Pos)
|
||
this.Update_DocumentPosition(DocState.FootnotesEnd.Pos);
|
||
if (DocState.FootnotesEnd && DocState.FootnotesEnd.StartPos)
|
||
this.Update_DocumentPosition(DocState.FootnotesEnd.StartPos);
|
||
if (DocState.FootnotesEnd && DocState.FootnotesEnd.EndPos)
|
||
this.Update_DocumentPosition(DocState.FootnotesEnd.EndPos);
|
||
|
||
|
||
LogicDocument.Load_DocumentStateAfterLoadChanges(DocState);
|
||
this.Refresh_ForeignCursors();
|
||
}
|
||
};
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
// Private area
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.private_ClearChanges = function()
|
||
{
|
||
this.m_aChanges = [];
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_CollectOwnChanges = function()
|
||
{
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_AddOverallChange = function(oChange)
|
||
{
|
||
return true;
|
||
};
|
||
|
||
|
||
//-------------------------------------
|
||
///
|
||
/////----------------------------------------
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
//
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
CCollaborativeEditingBase.prototype.private_ClearChanges = function()
|
||
{
|
||
this.m_aChanges = [];
|
||
this.m_oOwnChanges = [];
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_CollectOwnChanges = function()
|
||
{
|
||
var StartPoint = ( null === AscCommon.History.SavedIndex ? 0 : AscCommon.History.SavedIndex + 1 );
|
||
var LastPoint = -1;
|
||
|
||
if (this.m_nUseType <= 0)
|
||
LastPoint = AscCommon.History.Points.length - 1;
|
||
else
|
||
LastPoint = AscCommon.History.Index;
|
||
|
||
for (var PointIndex = StartPoint; PointIndex <= LastPoint; PointIndex++)
|
||
{
|
||
var Point = AscCommon.History.Points[PointIndex];
|
||
for (var Index = 0; Index < Point.Items.length; Index++)
|
||
{
|
||
var Item = Point.Items[Index];
|
||
|
||
this.m_oOwnChanges.push(Item.Data);
|
||
}
|
||
}
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_AddOverallChange = function(oChange, isSave)
|
||
{
|
||
// Здесь мы должны смержить пришедшее изменение с одним из наших изменений
|
||
for (var nIndex = 0, nCount = this.m_oOwnChanges.length; nIndex < nCount; ++nIndex)
|
||
{
|
||
if (oChange && oChange.Merge && false === oChange.Merge(this.m_oOwnChanges[nIndex]))
|
||
return false;
|
||
}
|
||
|
||
if (false !== isSave)
|
||
this.m_aAllChanges.push(oChange);
|
||
|
||
return true;
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_OnSendOwnChanges = function(arrChanges, nDeleteIndex)
|
||
{
|
||
if (null !== nDeleteIndex)
|
||
{
|
||
this.m_aAllChanges.length = this.m_nAllChangesSavedIndex + nDeleteIndex;
|
||
}
|
||
else
|
||
{
|
||
this.m_nAllChangesSavedIndex = this.m_aAllChanges.length;
|
||
}
|
||
|
||
// TODO: Пока мы делаем это как одну точку, которую надо откатить. Надо пробежаться по массиву и разбить его
|
||
// по отдельным действиям. В принципе, данная схема срабатывает в быстром совместном редактировании,
|
||
// так что как правило две точки не успевают попасть в одно сохранение.
|
||
if (arrChanges.length > 0)
|
||
{
|
||
this.m_aOwnChangesIndexes.push({
|
||
Position : this.m_aAllChanges.length,
|
||
Count : arrChanges.length
|
||
});
|
||
|
||
this.m_aAllChanges = this.m_aAllChanges.concat(arrChanges);
|
||
}
|
||
};
|
||
CCollaborativeEditingBase.prototype.Undo = function()
|
||
{
|
||
if (true === this.Get_GlobalLock())
|
||
return;
|
||
|
||
if (this.m_aOwnChangesIndexes.length <= 0)
|
||
return false;
|
||
|
||
// Формируем новую пачку действий, которые будут откатывать нужные нам действия.
|
||
|
||
// На первом шаге мы заданнуюю пачку изменений коммутируем с последними измениями. Смотрим на то какой набор
|
||
// изменений у нас получается.
|
||
// Объектная модель у нас простая: класс, в котором возможно есть массив элементов(тоже классов), у которого воможно
|
||
// есть набор свойств. Поэтому у нас ровно 2 типа изменений: изменения внутри массива элементов, либо изменения
|
||
// свойств. Изменения этих двух типов коммутируют между собой, изменения разных классов тоже коммутируют.
|
||
var arrChanges = [];
|
||
var oIndexes = this.m_aOwnChangesIndexes[this.m_aOwnChangesIndexes.length - 1];
|
||
var nPosition = oIndexes.Position;
|
||
var nCount = oIndexes.Count;
|
||
|
||
for (var nIndex = nCount - 1; nIndex >= 0; --nIndex)
|
||
{
|
||
var oChange = this.m_aAllChanges[nPosition + nIndex];
|
||
if (!oChange)
|
||
continue;
|
||
|
||
var oClass = oChange.GetClass();
|
||
if (oChange.IsContentChange())
|
||
{
|
||
var _oChange = oChange.Copy();
|
||
|
||
if (this.private_CommutateContentChanges(_oChange, nPosition + nCount))
|
||
arrChanges.push(_oChange);
|
||
|
||
oChange.SetReverted(true);
|
||
}
|
||
else
|
||
{
|
||
var _oChange = oChange; // TODO: Тут надо бы сделать копирование
|
||
|
||
if (this.private_CommutatePropertyChanges(oClass, _oChange, nPosition + nCount))
|
||
arrChanges.push(_oChange);
|
||
}
|
||
}
|
||
|
||
// Удаляем запись о последнем изменении
|
||
this.m_aOwnChangesIndexes.length = this.m_aOwnChangesIndexes.length - 1;
|
||
|
||
var arrReverseChanges = [];
|
||
for (var nIndex = 0, nCount = arrChanges.length; nIndex < nCount; ++nIndex)
|
||
{
|
||
var oReverseChange = arrChanges[nIndex].CreateReverseChange();
|
||
if (oReverseChange)
|
||
{
|
||
arrReverseChanges.push(oReverseChange);
|
||
oReverseChange.SetReverted(true);
|
||
}
|
||
}
|
||
|
||
// Накатываем изменения в данном клиенте
|
||
var oLogicDocument = this.m_oLogicDocument;
|
||
|
||
oLogicDocument.DrawingDocument.EndTrackTable(null, true);
|
||
oLogicDocument.TurnOffCheckChartSelection();
|
||
|
||
var DocState = this.private_SaveDocumentState();
|
||
var mapDrawings = {};
|
||
for (var nIndex = 0, nCount = arrReverseChanges.length; nIndex < nCount; ++nIndex)
|
||
{
|
||
var oClass = arrReverseChanges[nIndex].GetClass();
|
||
if(oClass && oClass.parent && oClass.parent instanceof AscCommonWord.ParaDrawing){
|
||
mapDrawings[oClass.parent.Get_Id()] = oClass.parent;
|
||
}
|
||
arrReverseChanges[nIndex].Load();
|
||
this.m_aAllChanges.push(arrReverseChanges[nIndex]);
|
||
}
|
||
|
||
// Может так случиться, что в каких-то классах DocumentContent удалились все элементы, либо
|
||
// в классе Paragraph удалился знак конца параграфа. Нам необходимо проверить все классы на корректность, и если
|
||
// нужно, добавить дополнительные изменения.
|
||
|
||
var mapDocumentContents = {};
|
||
var mapParagraphs = {};
|
||
var mapRuns = {};
|
||
var mapTables = {};
|
||
var mapGrObjects = {};
|
||
var mapSlides = {};
|
||
var mapLayouts = {};
|
||
var bChangedLayout = false;
|
||
var bAddSlides = false;
|
||
var mapAddedSlides = {};
|
||
for (var nIndex = 0, nCount = arrReverseChanges.length; nIndex < nCount; ++nIndex)
|
||
{
|
||
var oChange = arrReverseChanges[nIndex];
|
||
var oClass = oChange.GetClass();
|
||
if (oClass instanceof AscCommonWord.CDocument || oClass instanceof AscCommonWord.CDocumentContent)
|
||
mapDocumentContents[oClass.Get_Id()] = oClass;
|
||
else if (oClass instanceof AscCommonWord.Paragraph)
|
||
mapParagraphs[oClass.Get_Id()] = oClass;
|
||
else if (oClass.IsParagraphContentElement && true === oClass.IsParagraphContentElement() && true === oChange.IsContentChange() && oClass.GetParagraph())
|
||
{
|
||
mapParagraphs[oClass.GetParagraph().Get_Id()] = oClass.GetParagraph();
|
||
if (oClass instanceof AscCommonWord.ParaRun)
|
||
mapRuns[oClass.Get_Id()] = oClass;
|
||
}
|
||
else if (oClass instanceof AscCommonWord.ParaDrawing)
|
||
mapDrawings[oClass.Get_Id()] = oClass;
|
||
else if (oClass instanceof AscCommonWord.ParaRun)
|
||
mapRuns[oClass.Get_Id()] = oClass;
|
||
else if (oClass instanceof AscCommonWord.CTable)
|
||
mapTables[oClass.Get_Id()] = oClass;
|
||
else if(oClass instanceof AscFormat.CShape || oClass instanceof AscFormat.CImageShape || oClass instanceof AscFormat.CChartSpace || oClass instanceof AscFormat.CGroupShape || oClass instanceof AscFormat.CGraphicFrame)
|
||
mapGrObjects[oClass.Get_Id()] = oClass;
|
||
else if(typeof AscCommonSlide !== "undefined") {
|
||
if (AscCommonSlide.Slide && oClass instanceof AscCommonSlide.Slide) {
|
||
mapSlides[oClass.Get_Id()] = oClass;
|
||
}
|
||
else if(AscCommonSlide.SlideLayout && oClass instanceof AscCommonSlide.SlideLayout){
|
||
mapLayouts[oClass.Get_Id()] = oClass;
|
||
bChangedLayout = true;
|
||
}
|
||
else if(AscCommonSlide.CPresentation && oClass instanceof AscCommonSlide.CPresentation){
|
||
if(oChange.Type === AscDFH.historyitem_Presentation_RemoveSlide || oChange.Type === AscDFH.historyitem_Presentation_AddSlide){
|
||
bAddSlides = true;
|
||
for(var i = 0; i < oChange.Items.length; ++i){
|
||
mapAddedSlides[oChange.Items[i].Get_Id()] = oChange.Items[i];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Создаем точку в истории. Делаем действия через обычные функции (с отключенным пересчетом), которые пишут в
|
||
// историю. Сохраняем список изменений в новой точке, удаляем данную точку.
|
||
var oHistory = AscCommon.History;
|
||
oHistory.CreateNewPointForCollectChanges();
|
||
if(bAddSlides){
|
||
for(var i = oLogicDocument.Slides.length - 1; i > -1; --i){
|
||
if(mapAddedSlides[oLogicDocument.Slides[i].Get_Id()] && !oLogicDocument.Slides[i].Layout){
|
||
oLogicDocument.removeSlide(i);
|
||
}
|
||
}
|
||
}
|
||
|
||
for(var sId in mapSlides){
|
||
if(mapSlides.hasOwnProperty(sId)){
|
||
mapSlides[sId].correctContent();
|
||
}
|
||
}
|
||
|
||
if(bChangedLayout){
|
||
for(var i = oLogicDocument.Slides.length - 1; i > -1 ; --i){
|
||
var Layout = oLogicDocument.Slides[i].Layout;
|
||
if(!Layout || mapLayouts[Layout.Get_Id()]){
|
||
if(!oLogicDocument.Slides[i].CheckLayout()){
|
||
oLogicDocument.removeSlide(i);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
for(var sId in mapGrObjects){
|
||
var oShape = mapGrObjects[sId];
|
||
if(!oShape.checkCorrect()){
|
||
oShape.setBDeleted(true);
|
||
if(oShape.group){
|
||
oShape.group.removeFromSpTree(oShape.Get_Id());
|
||
}
|
||
else if(AscFormat.Slide && (oShape.parent instanceof AscFormat.Slide)){
|
||
oShape.parent.removeFromSpTreeById(oShape.Get_Id());
|
||
}
|
||
else if(AscCommonWord.ParaDrawing && (oShape.parent instanceof AscCommonWord.ParaDrawing)){
|
||
mapDrawings[oShape.parent.Get_Id()] = oShape.parent;
|
||
}
|
||
}
|
||
else{
|
||
if(oShape.resetGroups){
|
||
oShape.resetGroups();
|
||
}
|
||
}
|
||
}
|
||
var oDrawing;
|
||
for (var sId in mapDrawings)
|
||
{
|
||
if (mapDrawings.hasOwnProperty(sId))
|
||
{
|
||
oDrawing = mapDrawings[sId];
|
||
if (!oDrawing.CheckCorrect())
|
||
{
|
||
var oParentParagraph = oDrawing.Get_ParentParagraph();
|
||
oDrawing.PreDelete();
|
||
oDrawing.Remove_FromDocument(false);
|
||
if (oParentParagraph)
|
||
{
|
||
mapParagraphs[oParentParagraph.Get_Id()] = oParentParagraph;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for(var sId in mapRuns){
|
||
if (mapRuns.hasOwnProperty(sId))
|
||
{
|
||
var oRun = mapRuns[sId];
|
||
for(var nIndex = oRun.Content.length - 1; nIndex > - 1; --nIndex){
|
||
if(oRun.Content[nIndex] instanceof AscCommonWord.ParaDrawing){
|
||
if(!oRun.Content[nIndex].CheckCorrect()){
|
||
oRun.Remove_FromContent(nIndex, 1, false);
|
||
if(oRun.Paragraph){
|
||
mapParagraphs[oRun.Paragraph.Get_Id()] = oRun.Paragraph;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
for (var sId in mapTables)
|
||
{
|
||
var oTable = mapTables[sId];
|
||
for (var nCurRow = oTable.Content.length - 1; nCurRow >= 0; --nCurRow)
|
||
{
|
||
var oRow = oTable.Get_Row(nCurRow);
|
||
if (oRow.Get_CellsCount() <= 0)
|
||
oTable.Internal_Remove_Row(nCurRow);
|
||
}
|
||
|
||
if (oTable.Parent instanceof AscCommonWord.CDocument || oTable.Parent instanceof AscCommonWord.CDocumentContent)
|
||
mapDocumentContents[oTable.Parent.Get_Id()] = oTable.Parent;
|
||
}
|
||
|
||
for (var sId in mapDocumentContents)
|
||
{
|
||
var oDocumentContent = mapDocumentContents[sId];
|
||
var nContentLen = oDocumentContent.Content.length;
|
||
for (var nIndex = nContentLen - 1; nIndex >= 0; --nIndex)
|
||
{
|
||
var oElement = oDocumentContent.Content[nIndex];
|
||
if ((AscCommonWord.type_Paragraph === oElement.GetType() || AscCommonWord.type_Table === oElement.GetType()) && oElement.Content.length <= 0)
|
||
{
|
||
oDocumentContent.Remove_FromContent(nIndex, 1);
|
||
}
|
||
}
|
||
|
||
nContentLen = oDocumentContent.Content.length;
|
||
if (nContentLen <= 0 || AscCommonWord.type_Paragraph !== oDocumentContent.Content[nContentLen - 1].GetType())
|
||
{
|
||
var oNewParagraph = new AscCommonWord.Paragraph(oLogicDocument.Get_DrawingDocument(), oDocumentContent, 0, 0, 0, 0, 0, false);
|
||
oDocumentContent.Add_ToContent(nContentLen, oNewParagraph);
|
||
}
|
||
}
|
||
|
||
for (var sId in mapParagraphs)
|
||
{
|
||
var oParagraph = mapParagraphs[sId];
|
||
oParagraph.CheckParaEnd();
|
||
oParagraph.Correct_Content(null, null, true);
|
||
}
|
||
|
||
var oBinaryWriter = AscCommon.History.BinaryWriter;
|
||
var aSendingChanges = [];
|
||
for (var nIndex = 0, nCount = arrReverseChanges.length; nIndex < nCount; ++nIndex)
|
||
{
|
||
var oReverseChange = arrReverseChanges[nIndex];
|
||
var oChangeClass = oReverseChange.GetClass();
|
||
|
||
var nBinaryPos = oBinaryWriter.GetCurPosition();
|
||
oBinaryWriter.WriteString2(oChangeClass.Get_Id());
|
||
oBinaryWriter.WriteLong(oReverseChange.Type);
|
||
oReverseChange.WriteToBinary(oBinaryWriter);
|
||
|
||
var nBinaryLen = oBinaryWriter.GetCurPosition() - nBinaryPos;
|
||
|
||
var oChange = new AscCommon.CCollaborativeChanges();
|
||
oChange.Set_FromUndoRedo(oChangeClass, oReverseChange, {Pos : nBinaryPos, Len : nBinaryLen});
|
||
aSendingChanges.push(oChange.m_pData);
|
||
}
|
||
|
||
var oHistoryPoint = oHistory.Points[oHistory.Points.length - 1];
|
||
for (var nIndex = 0, nCount = oHistoryPoint.Items.length; nIndex < nCount; ++nIndex)
|
||
{
|
||
var oReverseChange = oHistoryPoint.Items[nIndex].Data;
|
||
var oChangeClass = oReverseChange.GetClass();
|
||
|
||
var oChange = new AscCommon.CCollaborativeChanges();
|
||
oChange.Set_FromUndoRedo(oChangeClass, oReverseChange, {Pos : oHistoryPoint.Items[nIndex].Binary.Pos, Len : oHistoryPoint.Items[nIndex].Binary.Len});
|
||
aSendingChanges.push(oChange.m_pData);
|
||
|
||
arrReverseChanges.push(oHistoryPoint.Items[nIndex].Data);
|
||
}
|
||
oHistory.Remove_LastPoint();
|
||
this.Clear_DCChanges();
|
||
|
||
editor.CoAuthoringApi.saveChanges(aSendingChanges, null, null, false, this.getCollaborativeEditing());
|
||
|
||
this.private_RestoreDocumentState(DocState);
|
||
|
||
oLogicDocument.TurnOnCheckChartSelection();
|
||
this.private_RecalculateDocument(AscCommon.History.Get_RecalcData(null, arrReverseChanges));
|
||
|
||
oLogicDocument.Document_UpdateSelectionState();
|
||
oLogicDocument.Document_UpdateInterfaceState();
|
||
oLogicDocument.Document_UpdateRulersState();
|
||
};
|
||
CCollaborativeEditingBase.prototype.CanUndo = function()
|
||
{
|
||
return this.m_aOwnChangesIndexes.length <= 0 ? false : true;
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_CommutateContentChanges = function(oChange, nStartPosition)
|
||
{
|
||
var arrActions = oChange.ConvertToSimpleActions();
|
||
var arrCommutateActions = [];
|
||
|
||
for (var nActionIndex = arrActions.length - 1; nActionIndex >= 0; --nActionIndex)
|
||
{
|
||
var oAction = arrActions[nActionIndex];
|
||
var oResult = oAction;
|
||
|
||
for (var nIndex = nStartPosition, nOverallCount = this.m_aAllChanges.length; nIndex < nOverallCount; ++nIndex)
|
||
{
|
||
var oTempChange = this.m_aAllChanges[nIndex];
|
||
if (!oTempChange)
|
||
continue;
|
||
|
||
if (oChange.IsRelated(oTempChange) && true !== oTempChange.IsReverted())
|
||
{
|
||
var arrOtherActions = oTempChange.ConvertToSimpleActions();
|
||
for (var nIndex2 = 0, nOtherActionsCount2 = arrOtherActions.length; nIndex2 < nOtherActionsCount2; ++nIndex2)
|
||
{
|
||
var oOtherAction = arrOtherActions[nIndex2];
|
||
|
||
if (false === this.private_Commutate(oAction, oOtherAction))
|
||
{
|
||
arrOtherActions.splice(nIndex2, 1);
|
||
oResult = null;
|
||
break;
|
||
}
|
||
}
|
||
|
||
oTempChange.ConvertFromSimpleActions(arrOtherActions);
|
||
}
|
||
|
||
if (!oResult)
|
||
break;
|
||
|
||
}
|
||
|
||
if (null !== oResult)
|
||
arrCommutateActions.push(oResult);
|
||
}
|
||
|
||
if (arrCommutateActions.length > 0)
|
||
oChange.ConvertFromSimpleActions(arrCommutateActions);
|
||
else
|
||
return false;
|
||
|
||
return true;
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_Commutate = function(oActionL, oActionR)
|
||
{
|
||
if (oActionL.Add)
|
||
{
|
||
if (oActionR.Add)
|
||
{
|
||
if (oActionL.Pos >= oActionR.Pos)
|
||
oActionL.Pos++;
|
||
else
|
||
oActionR.Pos--;
|
||
}
|
||
else
|
||
{
|
||
if (oActionL.Pos > oActionR.Pos)
|
||
oActionL.Pos--;
|
||
else if (oActionL.Pos === oActionR.Pos)
|
||
return false;
|
||
else
|
||
oActionR.Pos--;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (oActionR.Add)
|
||
{
|
||
if (oActionL.Pos >= oActionR.Pos)
|
||
oActionL.Pos++;
|
||
else
|
||
oActionR.Pos++;
|
||
}
|
||
else
|
||
{
|
||
if (oActionL.Pos > oActionR.Pos)
|
||
oActionL.Pos--;
|
||
else
|
||
oActionR.Pos++;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
CCollaborativeEditingBase.prototype.private_CommutatePropertyChanges = function(oClass, oChange, nStartPosition)
|
||
{
|
||
// В GoogleDocs если 2 пользователя исправляют одно и тоже свойство у одного и того же класса, тогда Undo работает
|
||
// у обоих. Например, первый выставляет параграф по центру (изначально по левому), второй после этого по правому
|
||
// краю. Тогда на Undo первого пользователя возвращает параграф по левому краю, а у второго по центру, неважно в
|
||
// какой последовательности они вызывают Undo.
|
||
// Далем как у них: т.е. изменения свойств мы всегда откатываем, даже если данное свойсво менялось в последующих
|
||
// изменениях.
|
||
|
||
// Здесь вариант: свойство не откатываем, если оно менялось в одном из последующих действий. (для работы этого
|
||
// варианта нужно реализовать функцию IsRelated у всех изменений).
|
||
|
||
// // Значит это изменение свойства. Пробегаемся по всем следующим изменениям и смотрим, менялось ли такое
|
||
// // свойство у данного класса, если да, тогда данное изменение невозможно скоммутировать.
|
||
// for (var nIndex = nStartPosition, nOverallCount = this.m_aAllChanges.length; nIndex < nOverallCount; ++nIndex)
|
||
// {
|
||
// var oTempChange = this.m_aAllChanges[nIndex];
|
||
// if (!oTempChange || !oTempChange.IsChangesClass || !oTempChangeIsChangesClass())
|
||
// continue;
|
||
//
|
||
// if (oChange.IsRelated(oTempChange))
|
||
// return false;
|
||
// }
|
||
|
||
if(oChange.CheckCorrect && !oChange.CheckCorrect())
|
||
{
|
||
return false;
|
||
}
|
||
return true;
|
||
};
|
||
|
||
|
||
CCollaborativeEditingBase.prototype.private_RecalculateDocument = function(oRecalcData){
|
||
|
||
};
|
||
|
||
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
// Класс для работы с сохраненными позициями документа.
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
// Принцип следующий. Заданная позиция - это Run + Позиция внутри данного Run.
|
||
// Если заданный ран был разбит (операция Split), тогда отслеживаем куда перешла
|
||
// заданная позиция, в новый ран или осталась в старом? Если в новый, тогда сохраняем
|
||
// новый ран как отдельную позицию в массив m_aDocumentPositions, и добавляем мап
|
||
// старой позиции в новую m_aDocumentPositionsMap. В конце действия, когда нам нужно
|
||
// определить где же находистся наша позиция, мы сначала проверяем Map, если в нем есть
|
||
// конечная позиция, проверяем является ли заданная позиция валидной в документе.
|
||
// Если да, тогда выставляем ее, если нет, тогда берем Run исходной позиции, и
|
||
// пытаемся сформировать полную позицию по данному Run. Если и это не получается,
|
||
// тогда восстанавливаем позицию по измененной полной исходной позиции.
|
||
//----------------------------------------------------------------------------------------------------------------------
|
||
function CDocumentPositionsManager()
|
||
{
|
||
this.m_aDocumentPositions = [];
|
||
this.m_aDocumentPositionsSplit = [];
|
||
this.m_aDocumentPositionsMap = [];
|
||
}
|
||
CDocumentPositionsManager.prototype.Clear_DocumentPositions = function()
|
||
{
|
||
this.m_aDocumentPositions = [];
|
||
this.m_aDocumentPositionsSplit = [];
|
||
this.m_aDocumentPositionsMap = [];
|
||
};
|
||
CDocumentPositionsManager.prototype.Add_DocumentPosition = function(Position)
|
||
{
|
||
this.m_aDocumentPositions.push(Position);
|
||
};
|
||
CDocumentPositionsManager.prototype.Update_DocumentPositionsOnAdd = function(Class, Pos)
|
||
{
|
||
for (var PosIndex = 0, PosCount = this.m_aDocumentPositions.length; PosIndex < PosCount; ++PosIndex)
|
||
{
|
||
var DocPos = this.m_aDocumentPositions[PosIndex];
|
||
for (var ClassPos = 0, ClassLen = DocPos.length; ClassPos < ClassLen; ++ClassPos)
|
||
{
|
||
var _Pos = DocPos[ClassPos];
|
||
if (Class === _Pos.Class
|
||
&& undefined !== _Pos.Position
|
||
&& (_Pos.Position > Pos
|
||
|| (_Pos.Position === Pos && !(Class instanceof AscCommonWord.ParaRun))))
|
||
{
|
||
_Pos.Position++;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
CDocumentPositionsManager.prototype.Update_DocumentPositionsOnRemove = function(Class, Pos, Count)
|
||
{
|
||
for (var PosIndex = 0, PosCount = this.m_aDocumentPositions.length; PosIndex < PosCount; ++PosIndex)
|
||
{
|
||
var DocPos = this.m_aDocumentPositions[PosIndex];
|
||
for (var ClassPos = 0, ClassLen = DocPos.length; ClassPos < ClassLen; ++ClassPos)
|
||
{
|
||
var _Pos = DocPos[ClassPos];
|
||
if (Class === _Pos.Class && undefined !== _Pos.Position)
|
||
{
|
||
if (_Pos.Position > Pos + Count)
|
||
{
|
||
_Pos.Position -= Count;
|
||
}
|
||
else if (_Pos.Position >= Pos)
|
||
{
|
||
if (Class instanceof AscCommonWord.CTable)
|
||
{
|
||
_Pos.Position = Pos;
|
||
if (DocPos[ClassPos + 1]
|
||
&& DocPos[ClassPos + 1].Class instanceof AscCommonWord.CTableRow
|
||
&& undefined !== DocPos[ClassPos + 1].Position
|
||
&& Class.Content[Pos])
|
||
{
|
||
DocPos[ClassPos + 1].Position = Math.max(0, Math.min(DocPos[ClassPos + 1].Position, Class.Content.length - 1));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Элемент, в котором находится наша позиция, удаляется. Ставим специальную отметку об этом.
|
||
_Pos.Position = Pos;
|
||
_Pos.Deleted = true;
|
||
}
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
CDocumentPositionsManager.prototype.OnStart_SplitRun = function(SplitRun, SplitPos)
|
||
{
|
||
this.m_aDocumentPositionsSplit = [];
|
||
|
||
for (var PosIndex = 0, PosCount = this.m_aDocumentPositions.length; PosIndex < PosCount; ++PosIndex)
|
||
{
|
||
var DocPos = this.m_aDocumentPositions[PosIndex];
|
||
for (var ClassPos = 0, ClassLen = DocPos.length; ClassPos < ClassLen; ++ClassPos)
|
||
{
|
||
var _Pos = DocPos[ClassPos];
|
||
if (SplitRun === _Pos.Class && _Pos.Position && _Pos.Position >= SplitPos)
|
||
{
|
||
this.m_aDocumentPositionsSplit.push({DocPos : DocPos, NewRunPos : _Pos.Position - SplitPos});
|
||
}
|
||
}
|
||
}
|
||
};
|
||
CDocumentPositionsManager.prototype.OnEnd_SplitRun = function(NewRun)
|
||
{
|
||
if (!NewRun)
|
||
return;
|
||
|
||
for (var PosIndex = 0, PosCount = this.m_aDocumentPositionsSplit.length; PosIndex < PosCount; ++PosIndex)
|
||
{
|
||
var NewDocPos = [];
|
||
NewDocPos.push({Class : NewRun, Position : this.m_aDocumentPositionsSplit[PosIndex].NewRunPos});
|
||
this.m_aDocumentPositions.push(NewDocPos);
|
||
this.m_aDocumentPositionsMap.push({StartPos : this.m_aDocumentPositionsSplit[PosIndex].DocPos, EndPos : NewDocPos});
|
||
}
|
||
};
|
||
CDocumentPositionsManager.prototype.Update_DocumentPosition = function(DocPos)
|
||
{
|
||
// Смотрим куда мапится заданная позиция
|
||
var NewDocPos = DocPos;
|
||
for (var PosIndex = 0, PosCount = this.m_aDocumentPositionsMap.length; PosIndex < PosCount; ++PosIndex)
|
||
{
|
||
if (this.m_aDocumentPositionsMap[PosIndex].StartPos === NewDocPos)
|
||
NewDocPos = this.m_aDocumentPositionsMap[PosIndex].EndPos;
|
||
}
|
||
|
||
// Нашли результирующую позицию. Проверим является ли она валидной для документа.
|
||
if (NewDocPos !== DocPos && NewDocPos.length === 1 && NewDocPos[0].Class instanceof AscCommonWord.ParaRun)
|
||
{
|
||
var Run = NewDocPos[0].Class;
|
||
var Para = Run.GetParagraph();
|
||
if (AscCommonWord.CanUpdatePosition(Para, Run))
|
||
{
|
||
DocPos.length = 0;
|
||
DocPos.push({Class : Run, Position : NewDocPos[0].Position});
|
||
Run.GetDocumentPositionFromObject(DocPos);
|
||
}
|
||
}
|
||
// Возможно ран с позицией переместился в другой класс
|
||
else if (DocPos.length > 0 && DocPos[DocPos.length - 1].Class instanceof AscCommonWord.ParaRun)
|
||
{
|
||
var Run = DocPos[DocPos.length - 1].Class;
|
||
var RunPos = DocPos[DocPos.length - 1].Position;
|
||
var Para = Run.GetParagraph();
|
||
if (AscCommonWord.CanUpdatePosition(Para, Run))
|
||
{
|
||
DocPos.length = 0;
|
||
DocPos.push({Class : Run, Position : RunPos});
|
||
Run.GetDocumentPositionFromObject(DocPos);
|
||
}
|
||
}
|
||
};
|
||
CDocumentPositionsManager.prototype.Remove_DocumentPosition = function(DocPos)
|
||
{
|
||
for (var Pos = 0, Count = this.m_aDocumentPositions.length; Pos < Count; ++Pos)
|
||
{
|
||
if (this.m_aDocumentPositions[Pos] === DocPos)
|
||
{
|
||
this.m_aDocumentPositions.splice(Pos, 1);
|
||
return;
|
||
}
|
||
}
|
||
};
|
||
//--------------------------------------------------------export----------------------------------------------------
|
||
window['AscCommon'] = window['AscCommon'] || {};
|
||
window['AscCommon'].FOREIGN_CURSOR_LABEL_HIDETIME = FOREIGN_CURSOR_LABEL_HIDETIME;
|
||
window['AscCommon'].CCollaborativeChanges = CCollaborativeChanges;
|
||
window['AscCommon'].CCollaborativeEditingBase = CCollaborativeEditingBase;
|
||
window['AscCommon'].CDocumentPositionsManager = CDocumentPositionsManager;
|
||
})(window);
|