Field.js 22.1 KB
Newer Older
Alexander.Trofimov's avatar
Alexander.Trofimov committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 * (c) Copyright Ascensio System SIA 2010-2016
 *
 * 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 Lubanas st. 125a-25, Riga, Latvia,
 * EU, LV-1021.
 *
 * 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
 *
 */

33 34
"use strict";

35 36
// Import
var History = AscCommon.History;
37 38

var fieldtype_UNKNOWN    = 0x0000;
Alexander.Trofimov's avatar
Alexander.Trofimov committed
39
var fieldtype_MERGEFIELD = 0x0001;
40
var fieldtype_PAGENUM    = 0x0002;
41

42 43 44 45 46 47 48 49
/**
 *
 * @param FieldType
 * @param Arguments
 * @param Switches
 * @constructor
 * @extends {CParagraphContentWithParagraphLikeContent}
 */
50 51 52 53
function ParaField(FieldType, Arguments, Switches)
{
    ParaField.superclass.constructor.call(this);

54
    this.Id = AscCommon.g_oIdCounter.Get_NewId();
55

56
    this.Type    = para_Field;
57 58 59 60 61 62 63 64 65 66

    this.FieldType = (undefined === FieldType ? fieldtype_UNKNOWN : FieldType);
    this.Arguments = (undefined === Arguments ? []                : Arguments);
    this.Switches  = (undefined === Switches  ? []                : Switches);

    this.TemplateContent = this.Content;

    this.Bounds = {};

    // Добавляем данный класс в таблицу Id (обязательно в конце конструктора)
67
    AscCommon.g_oTableId.Add( this, this.Id );
68 69
}

70
AscCommon.extendClass(ParaField, CParagraphContentWithParagraphLikeContent);
71 72 73 74 75 76 77

ParaField.prototype.Get_Id = function()
{
    return this.Id;
};
ParaField.prototype.Copy = function(Selected)
{
78 79 80 81 82 83 84 85 86 87
    var NewField = ParaField.superclass.Copy.apply(this, arguments);

    // TODO: Сделать функциями с иторией
    NewField.FieldType = this.FieldType;
    NewField.Arguments = this.Arguments;
    NewField.Switches  = this.Switches;

    if (editor)
        editor.WordControl.m_oLogicDocument.Register_Field(NewField);

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    return NewField;
};
ParaField.prototype.Get_SelectedElementsInfo = function(Info)
{
    Info.Set_Field(this);
    ParaField.superclass.Get_SelectedElementsInfo.apply(this, arguments);
};
ParaField.prototype.Get_Bounds = function()
{
    var aBounds = [];
    for (var Place in this.Bounds)
    {
        aBounds.push(this.Bounds[Place]);
    }

    return aBounds;
};
ParaField.prototype.Add_ToContent = function(Pos, Item, UpdatePosition)
{
107
    History.Add( this, { Type : AscDFH.historyitem_Field_AddItem, Pos : Pos, EndPos : Pos, Items : [ Item ] } );
108 109 110 111 112 113
    ParaField.superclass.Add_ToContent.apply(this, arguments);
};
ParaField.prototype.Remove_FromContent = function(Pos, Count, UpdatePosition)
{
    // Получим массив удаляемых элементов
    var DeletedItems = this.Content.slice( Pos, Pos + Count );
114
    History.Add( this, { Type : AscDFH.historyitem_Field_RemoveItem, Pos : Pos, EndPos : Pos + Count - 1, Items : DeletedItems } );
115

116
    ParaField.superclass.Remove_FromContent.apply(this, arguments);
117 118 119 120 121
};
ParaField.prototype.Add = function(Item)
{
    switch (Item.Type)
    {
122 123
        case para_Run      :
        case para_Hyperlink:
124
        {
125 126 127 128 129 130 131
            var TextPr = this.Get_FirstTextPr();
            Item.Select_All();
            Item.Apply_TextPr(TextPr);
            Item.Selection_Remove();

            var CurPos = this.State.ContentPos;
            var CurItem = this.Content[CurPos];
132
            if (para_Run === CurItem.Type)
133 134 135 136 137 138 139 140 141 142 143 144 145
            {
                var NewRun = CurItem.Split2(CurItem.State.ContentPos);
                this.Add_ToContent(CurPos + 1, Item);
                this.Add_ToContent(CurPos + 2, NewRun);

                this.State.ContentPos = CurPos + 2;
                this.Content[this.State.ContentPos].Cursor_MoveToStartPos();
            }
            else
                CurItem.Add(Item);

            break;
        }
146
        case para_Math :
147
        {
148
            var ContentPos = new CParagraphContentPos();
149 150
            this.Get_ParaContentPos(false, false, ContentPos);
            var CurPos = ContentPos.Get(0);
151

152
            // Ран формула делит на части, а в остальные элементы добавляется целиком
153
            if (para_Run === this.Content[CurPos].Type)
154
            {
155 156
                // Разделяем текущий элемент (возвращается правая часть)
                var NewElement = this.Content[CurPos].Split(ContentPos, 1);
157

158 159 160 161
                if (null !== NewElement)
                    this.Add_ToContent(CurPos + 1, NewElement, true);

                var Elem = new ParaMath();
162
                Elem.Root.Load_FromMenu(Item.Menu, this.Get_Paragraph());
163 164 165 166 167 168 169 170 171
                Elem.Root.Correct_Content(true);
                this.Add_ToContent(CurPos + 1, Elem, true);

                // Перемещаем кусор в конец формулы
                this.State.ContentPos = CurPos + 1;
                this.Content[this.State.ContentPos].Cursor_MoveToEndPos(false);
            }
            else
                this.Content[CurPos].Add(Item);
172

173 174
            break;
        }
175
        case para_Field:
176 177 178 179 180 181 182 183 184
        {
            // Вместо добавления самого элемента добавляем его содержимое
            var Count = Item.Content.length;

            if (Count > 0)
            {
                var CurPos  = this.State.ContentPos;
                var CurItem = this.Content[CurPos];

185
                var CurContentPos = new CParagraphContentPos();
186 187 188 189
                CurItem.Get_ParaContentPos(false, false, CurContentPos);

                var NewItem = CurItem.Split(CurContentPos, 0);
                for (var Index = 0; Index < Count; Index++)
190
                {
191
                    this.Add_ToContent(CurPos + Index + 1, Item.Content[Index], false);
192
                }
193 194 195
                this.Add_ToContent(CurPos + Count + 1, NewItem, false);
                this.State.ContentPos = CurPos + Count;
                this.Content[this.State.ContentPos].Cursor_MoveToEndPos();
196 197 198 199 200 201
            }

            break;
        }
        default :
        {
202
            this.Content[this.State.ContentPos].Add(Item);
203 204 205 206 207 208
            break;
        }
    }
};
ParaField.prototype.Split = function (ContentPos, Depth)
{
209 210
    // Не даем разделять поле
    return null;
211
};
212 213 214 215
ParaField.prototype.CanSplit = function()
{
	return false;
};
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
ParaField.prototype.Recalculate_Range_Spaces = function(PRSA, _CurLine, _CurRange, _CurPage)
{
    var CurLine  = _CurLine - this.StartLine;
    var CurRange = (0 === _CurLine ? _CurRange - this.StartRange : _CurRange);

    if (0 === CurLine && 0 === CurRange && true !== PRSA.RecalcFast)
        this.Bounds = {};

    var X0 = PRSA.X;
    var Y0 = PRSA.Y0;
    var Y1 = PRSA.Y1;

    ParaField.superclass.Recalculate_Range_Spaces.apply(this, arguments);

    var X1 = PRSA.X;
    this.Bounds[((CurLine << 16) & 0xFFFF0000) | (CurRange & 0x0000FFFF)] = {X0 : X0, X1 : X1, Y0: Y0, Y1 : Y1, PageIndex : _CurPage + PRSA.Paragraph.Get_StartPage_Absolute()};
};
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
ParaField.prototype.Draw_HighLights = function(PDSH)
{
    var X0 = PDSH.X;
    var Y0 = PDSH.Y0;
    var Y1 = PDSH.Y1;

    ParaField.superclass.Draw_HighLights.apply(this, arguments);

    var X1 = PDSH.X;

    if (Math.abs(X0 - X1) > 0.001 && true === PDSH.DrawMMFields)
    {
        PDSH.MMFields.Add(Y0, Y1, X0, X1, 0, 0, 0, 0  );
    }
};
248 249 250 251 252 253 254 255 256 257 258
//----------------------------------------------------------------------------------------------------------------------
// Работа с данными поля
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.Get_Argument = function(Index)
{
    return this.Arguments[Index];
};
ParaField.prototype.Get_FieldType = function()
{
    return this.FieldType;
};
259
ParaField.prototype.Map_MailMerge = function(_Value)
260 261
{
    // Пока у нас в Value может быть только текст, в будущем планируется, чтобы могли быть картинки.
262 263 264
    var Value = _Value;
    if (undefined === Value || null === Value)
        Value = "";
265

266
    History.TurnOff();
267

268 269 270 271 272 273 274 275
    var oRun = this.private_GetMappedRun(Value);

    // Подменяем содержимое поля
    this.Content = [];
    this.Content[0] = oRun;

    this.Cursor_MoveToStartPos();

276
    History.TurnOn();
277
};
278 279 280 281 282
ParaField.prototype.Restore_StandardTemplate = function()
{
    // В любом случае сначала восстанавливаем исходное содержимое.
    this.Restore_Template();

283
    if (fieldtype_MERGEFIELD === this.FieldType && true === AscCommon.CollaborativeEditing.Is_SingleUser() && 1 === this.Arguments.length)
284 285 286 287 288 289 290 291 292
    {
        var oRun = this.private_GetMappedRun("«" + this.Arguments[0] + "»");
        this.Remove_FromContent(0, this.Content.length);
        this.Add_ToContent(0, oRun);
        this.Cursor_MoveToStartPos();

        this.TemplateContent = this.Content;
    }
};
293 294 295 296 297 298
ParaField.prototype.Restore_Template = function()
{
    // Восстанавливаем содержимое поля.
    this.Content = this.TemplateContent;
    this.Cursor_MoveToStartPos();
};
299 300 301 302 303 304 305 306 307 308
ParaField.prototype.Is_NeedRestoreTemplate = function()
{
    if (1 !== this.TemplateContent.length)
        return true;

    var oRun = this.TemplateContent[0];
    if (fieldtype_MERGEFIELD === this.FieldType)
    {
        var sStandardText = "«" + this.Arguments[0] + "»";

309
        var oRunText = new CParagraphGetText();
310 311 312 313 314 315 316 317 318 319
        oRun.Get_Text(oRunText);

        if (sStandardText === oRunText.Text)
            return false;

        return true;
    }

    return false;
};
320
ParaField.prototype.Replace_MailMerge = function(_Value)
321
{
322 323 324 325 326
    // Пока у нас в Value может быть только текст, в будущем планируется, чтобы могли быть картинки.
    var Value = _Value;
    if (undefined === Value || null === Value)
        Value = "";

327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358
    var Paragraph = this.Paragraph;

    if (!Paragraph)
        return false;

    // Получим ран, на который мы подменяем поле
    var oRun = this.private_GetMappedRun(Value);

    // Ищем расположение данного поля в параграфе
    var ParaContentPos = Paragraph.Get_PosByElement(this);

    if (null === ParaContentPos)
        return false;

    var Depth    = ParaContentPos.Get_Depth();
    var FieldPos = ParaContentPos.Get(Depth);

    if (Depth < 0)
        return false;

    ParaContentPos.Decrease_Depth(1);
    var FieldContainer = Paragraph.Get_ElementByPos(ParaContentPos);
    if (!FieldContainer || !FieldContainer.Content || FieldContainer.Content[FieldPos] !== this)
        return false;

    FieldContainer.Remove_FromContent(FieldPos, 1);
    FieldContainer.Add_ToContent(FieldPos, oRun);

    return true;
};
ParaField.prototype.private_GetMappedRun = function(Value)
{
359 360 361 362 363 364 365
    // Создаем ран и набиваем в него заданный текст.
    var oRun = new ParaRun();

    for (var Index = 0, Count = Value.length; Index < Count; Index++)
    {
        var Char = Value[Index], oText;
        if (0x20 === Char)
366
            oText = new ParaSpace();
367
        else
368
            oText = new ParaText(Value[Index]);
369 370 371 372

        oRun.Add_ToContent(Index, oText);
    }

373 374
    oRun.Set_Pr(this.Get_FirstTextPr());

375
    return oRun;
376 377 378 379 380 381 382 383 384
};
//----------------------------------------------------------------------------------------------------------------------
// Undo/Redo функции
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.Undo = function(Data)
{
    var Type = Data.Type;
    switch(Type)
    {
385
        case AscDFH.historyitem_Field_AddItem :
386 387 388
        {
            this.Content.splice( Data.Pos, Data.EndPos - Data.Pos + 1 );
            this.protected_UpdateSpellChecking();
389
            this.private_UpdateTrackRevisions();
390 391 392
            break;
        }

393
        case AscDFH.historyitem_Field_RemoveItem :
394 395 396 397 398 399 400 401
        {
            var Pos = Data.Pos;

            var Array_start = this.Content.slice( 0, Pos );
            var Array_end   = this.Content.slice( Pos );

            this.Content = Array_start.concat( Data.Items, Array_end );
            this.protected_UpdateSpellChecking();
402
            this.private_UpdateTrackRevisions();
403 404 405 406 407 408 409 410 411
            break;
        }
    }
};
ParaField.prototype.Redo = function(Data)
{
    var Type = Data.Type;
    switch(Type)
    {
412
        case AscDFH.historyitem_Field_AddItem :
413 414 415 416 417 418 419
        {
            var Pos = Data.Pos;

            var Array_start = this.Content.slice( 0, Pos );
            var Array_end   = this.Content.slice( Pos );

            this.Content = Array_start.concat( Data.Items, Array_end );
420
            this.private_UpdateTrackRevisions();
421 422 423 424
            this.protected_UpdateSpellChecking();
            break;
        }

425
        case AscDFH.historyitem_Field_RemoveItem :
426 427
        {
            this.Content.splice( Data.Pos, Data.EndPos - Data.Pos + 1 );
428
            this.private_UpdateTrackRevisions();
429 430 431 432 433 434 435 436 437 438 439 440 441 442
            this.protected_UpdateSpellChecking();
            break;
        }
    }
};
//----------------------------------------------------------------------------------------------------------------------
// Функции совместного редактирования
//----------------------------------------------------------------------------------------------------------------------
ParaField.prototype.Save_Changes = function(Data, Writer)
{
    // Сохраняем изменения из тех, которые используются для Undo/Redo в бинарный файл.
    // Long : тип класса
    // Long : тип изменений

443
    Writer.WriteLong(AscDFH.historyitem_type_Field);
444 445 446 447 448 449 450 451

    var Type = Data.Type;

    // Пишем тип
    Writer.WriteLong( Type );

    switch(Type)
    {
452
        case AscDFH.historyitem_Field_AddItem :
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
        {
            // Long     : Количество элементов
            // Array of :
            //  {
            //    Long     : Позиция
            //    Variable : Id элемента
            //  }

            var bArray = Data.UseArray;
            var Count  = Data.Items.length;

            Writer.WriteLong( Count );

            for ( var Index = 0; Index < Count; Index++ )
            {
                if ( true === bArray )
                    Writer.WriteLong( Data.PosArray[Index] );
                else
                    Writer.WriteLong( Data.Pos + Index );

                Writer.WriteString2( Data.Items[Index].Get_Id() );
            }

            break;
        }

479
        case AscDFH.historyitem_Field_RemoveItem :
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
        {
            // Long          : Количество удаляемых элементов
            // Array of Long : позиции удаляемых элементов

            var bArray = Data.UseArray;
            var Count  = Data.Items.length;

            var StartPos = Writer.GetCurPosition();
            Writer.Skip(4);
            var RealCount = Count;

            for ( var Index = 0; Index < Count; Index++ )
            {
                if ( true === bArray )
                {
                    if ( false === Data.PosArray[Index] )
                        RealCount--;
                    else
                        Writer.WriteLong( Data.PosArray[Index] );
                }
                else
                    Writer.WriteLong( Data.Pos );
            }

            var EndPos = Writer.GetCurPosition();
            Writer.Seek( StartPos );
            Writer.WriteLong( RealCount );
            Writer.Seek( EndPos );

            break;
        }
    }
};
ParaField.prototype.Load_Changes = function(Reader)
{
    // Сохраняем изменения из тех, которые используются для Undo/Redo в бинарный файл.
    // Long : тип класса
    // Long : тип изменений

    var ClassType = Reader.GetLong();
520
    if ( AscDFH.historyitem_type_Field != ClassType )
521 522 523 524 525 526
        return;

    var Type = Reader.GetLong();

    switch ( Type )
    {
527
        case AscDFH.historyitem_Field_AddItem :
528 529 530 531 532 533 534 535 536 537 538 539
        {
            // Long     : Количество элементов
            // Array of :
            //  {
            //    Long     : Позиция
            //    Variable : Id Элемента
            //  }

            var Count = Reader.GetLong();

            for ( var Index = 0; Index < Count; Index++ )
            {
540
                var Pos     = this.m_oContentChanges.Check( AscCommon.contentchanges_Add, Reader.GetLong() );
541
                var Element = AscCommon.g_oTableId.Get_ById( Reader.GetString2() );
542 543 544 545

                if ( null != Element )
                {
                    this.Content.splice( Pos, 0, Element );
546
                    AscCommon.CollaborativeEditing.Update_DocumentPositionsOnAdd(this, Pos);
547 548
                }
            }
549
            this.private_UpdateTrackRevisions();
550 551 552 553
            this.protected_UpdateSpellChecking();
            break;
        }

554
        case AscDFH.historyitem_Field_RemoveItem:
555 556 557 558 559 560 561 562
        {
            // Long          : Количество удаляемых элементов
            // Array of Long : позиции удаляемых элементов

            var Count = Reader.GetLong();

            for ( var Index = 0; Index < Count; Index++ )
            {
563
                var ChangesPos = this.m_oContentChanges.Check( AscCommon.contentchanges_Remove, Reader.GetLong() );
564 565 566 567 568 569

                // действие совпало, не делаем его
                if ( false === ChangesPos )
                    continue;

                this.Content.splice( ChangesPos, 1 );
570
                AscCommon.CollaborativeEditing.Update_DocumentPositionsOnRemove(this, ChangesPos, 1);
571
            }
572
            this.private_UpdateTrackRevisions();
573 574 575 576 577 578 579
            this.protected_UpdateSpellChecking();
            break;
        }
    }
};
ParaField.prototype.Write_ToBinary2 = function(Writer)
{
580
    Writer.WriteLong(AscDFH.historyitem_type_Field);
581 582

    // String : Id
583 584 585 586 587
    // Long   : FieldType
    // Long   : Количество аргументов
    // Array of Strings : массив аргументов
    // Long   : Количество переключателей
    // Array of Strings : массив переключателей
588 589 590
    // Long   : Количество элементов
    // Array of Strings : массив с Id элементов

591 592
    Writer.WriteString2(this.Id);
    Writer.WriteLong(this.FieldType);
593

594 595 596 597
    var ArgsCount = this.Arguments.length;
    Writer.WriteLong(ArgsCount);
    for (var Index = 0; Index < ArgsCount; Index++)
        Writer.WriteString2(this.Arguments[Index]);
598

599 600 601 602
    var SwitchesCount = this.Switches.length;
    Writer.WriteLong(SwitchesCount);
    for (var Index = 0; Index < SwitchesCount; Index++)
        Writer.WriteString2(this.Switches[Index]);
603

604 605 606 607
    var Count = this.Content.length;
    Writer.WriteLong(Count);
    for (var Index = 0; Index < Count; Index++)
        Writer.WriteString2(this.Content[Index].Get_Id());
608 609 610 611
};
ParaField.prototype.Read_FromBinary2 = function(Reader)
{
    // String : Id
612 613 614 615 616
    // Long   : FieldType
    // Long   : Количество аргументов
    // Array of Strings : массив аргументов
    // Long   : Количество переключателей
    // Array of Strings : массив переключателей
617 618 619
    // Long   : Количество элементов
    // Array of Strings : массив с Id элементов

620 621
    this.Id = Reader.GetString2();
    this.FieldType = Reader.GetLong();
622 623

    var Count = Reader.GetLong();
624 625 626 627 628 629 630 631
    this.Arguments = [];
    for (var Index = 0; Index < Count; Index++)
        this.Arguments.push(Reader.GetString2());

    Count = Reader.GetLong();
    this.Switches = [];
    for (var Index = 0; Index < Count; Index++)
        this.Switches.push(Reader.GetString2());
632

633 634 635
    Count = Reader.GetLong();
    this.Content = [];
    for (var Index = 0; Index < Count; Index++)
636
    {
637
        var Element = AscCommon.g_oTableId.Get_ById(Reader.GetString2());
638 639
        if (null !== Element)
            this.Content.push(Element);
640
    }
641

642 643
    this.TemplateContent = this.Content;

644 645
    if (editor)
        editor.WordControl.m_oLogicDocument.Register_Field(this);
646
};
647 648 649 650

//--------------------------------------------------------export----------------------------------------------------
window['AscCommonWord'] = window['AscCommonWord'] || {};
window['AscCommonWord'].ParaField = ParaField;