diff --git a/Readme.md b/Readme.md index 56395225d..747cb8437 100644 --- a/Readme.md +++ b/Readme.md @@ -1,25 +1,29 @@ -[![License](https://img.shields.io/badge/License-GNU%20AGPL%20V3-green.svg?style=flat)](https://www.gnu.org/licenses/agpl-3.0.en.html) - -## web-apps - -The frontend for [ONLYOFFICE Document Server][2]. Builds the program interface and allows the user create, edit, save and export text, spreadsheet and presentation documents using the common interface of a document editor. - -## Project Information - -Official website: [http://www.onlyoffice.org](http://onlyoffice.org "http://www.onlyoffice.org") - -Code repository: [https://github.com/ONLYOFFICE/web-apps](https://github.com/ONLYOFFICE/web-apps "https://github.com/ONLYOFFICE/web-apps") - -SaaS version: [http://www.onlyoffice.com](http://www.onlyoffice.com "http://www.onlyoffice.com") - -## User Feedback and Support - -If you have any problems with or questions about [ONLYOFFICE Document Server][2], please visit our official forum to find answers to your questions: [dev.onlyoffice.org][1] or you can ask and answer ONLYOFFICE development questions on [Stack Overflow][3]. - - [1]: http://dev.onlyoffice.org - [2]: https://github.com/ONLYOFFICE/DocumentServer - [3]: http://stackoverflow.com/questions/tagged/onlyoffice - -## License - -web-apps is released under an GNU AGPL v3.0 license. See the LICENSE file for more information. +[![License](https://img.shields.io/badge/License-GNU%20AGPL%20V3-green.svg?style=flat)](https://www.gnu.org/licenses/agpl-3.0.en.html) + +## web-apps + +The frontend for [ONLYOFFICE Document Server][2]. Builds the program interface and allows the user create, edit, save and export text, spreadsheet and presentation documents using the common interface of a document editor. + +## Previos versions + +Until 2019-10-23 the repository was called web-apps-pro + +## Project Information + +Official website: [http://www.onlyoffice.org](http://onlyoffice.org "http://www.onlyoffice.org") + +Code repository: [https://github.com/ONLYOFFICE/web-apps](https://github.com/ONLYOFFICE/web-apps "https://github.com/ONLYOFFICE/web-apps") + +SaaS version: [http://www.onlyoffice.com](http://www.onlyoffice.com "http://www.onlyoffice.com") + +## User Feedback and Support + +If you have any problems with or questions about [ONLYOFFICE Document Server][2], please visit our official forum to find answers to your questions: [dev.onlyoffice.org][1] or you can ask and answer ONLYOFFICE development questions on [Stack Overflow][3]. + + [1]: http://dev.onlyoffice.org + [2]: https://github.com/ONLYOFFICE/DocumentServer + [3]: http://stackoverflow.com/questions/tagged/onlyoffice + +## License + +web-apps is released under an GNU AGPL v3.0 license. See the LICENSE file for more information. diff --git a/apps/api/documents/api.js b/apps/api/documents/api.js index 0bc80b97d..25ea36fad 100644 --- a/apps/api/documents/api.js +++ b/apps/api/documents/api.js @@ -109,7 +109,8 @@ goback: { url: 'http://...', text: 'Go to London', - blank: true + blank: true, + requestClose: false // if true - goback send onRequestClose event instead opening url }, chat: true, comments: true, @@ -129,7 +130,8 @@ toolbarNoTabs: false, toolbarHideFileName: false, reviewDisplay: 'original', - spellcheck: true + spellcheck: true, + compatibleFeatures: false }, plugins: { autostart: ['asc.{FFE1F462-1EA2-4391-990D-4CC84940B754}'], @@ -730,17 +732,24 @@ } } + var userAgent = navigator.userAgent.toLowerCase(), + check = function(regex){ return regex.test(userAgent); }, + isIE = !check(/opera/) && (check(/msie/) || check(/trident/) || check(/edge/)), + isChrome = !isIE && check(/\bchrome\b/), + isSafari_mobile = !isIE && !isChrome && check(/safari/) && (navigator.maxTouchPoints>0); + path += app + "/"; - path += config.type === "mobile" + path += (config.type === "mobile" || isSafari_mobile) ? "mobile" : config.type === "embedded" ? "embed" : "main"; var index = "/index.html"; - if (config.editorConfig && config.editorConfig.targetApp!=='desktop') { + if (config.editorConfig) { var customization = config.editorConfig.customization; - if ( typeof(customization) == 'object' && (customization.loaderName || customization.loaderLogo)) { + if ( typeof(customization) == 'object' && ( customization.toolbarNoTabs || + (config.editorConfig.targetApp!=='desktop') && (customization.loaderName || customization.loaderLogo))) { index = "/index_loader.html"; } } @@ -769,9 +778,19 @@ } } + if (config.editorConfig && (config.editorConfig.mode == 'editdiagram' || config.editorConfig.mode == 'editmerge')) + params += "&internal=true"; + if (config.frameEditorId) params += "&frameEditorId=" + config.frameEditorId; - + + if (config.editorConfig && config.editorConfig.mode == 'view' || + config.document && config.document.permissions && (config.document.permissions.edit === false && !config.document.permissions.review )) + params += "&mode=view"; + + if (config.editorConfig && config.editorConfig.customization && !!config.editorConfig.customization.compactHeader) + params += "&compact=true"; + return params; } @@ -787,7 +806,8 @@ iframe.allowFullscreen = true; iframe.setAttribute("allowfullscreen",""); // for IE11 iframe.setAttribute("onmousewheel",""); // for Safari on Mac - + iframe.setAttribute("allow", "autoplay"); + if (config.type == "mobile") { iframe.style.position = "fixed"; diff --git a/apps/common/main/lib/component/Button.js b/apps/common/main/lib/component/Button.js index e097848f9..2e9a4e3ee 100644 --- a/apps/common/main/lib/component/Button.js +++ b/apps/common/main/lib/component/Button.js @@ -710,7 +710,7 @@ define([ this.caption = caption; if (this.rendered) { - var captionNode = this.cmpEl.find('button:first > .caption').addBack().filter('button > .caption'); + var captionNode = this.cmpEl.find('.caption'); if (captionNode.length > 0) { captionNode.text(caption); diff --git a/apps/common/main/lib/component/Calendar.js b/apps/common/main/lib/component/Calendar.js new file mode 100644 index 000000000..71b282a13 --- /dev/null +++ b/apps/common/main/lib/component/Calendar.js @@ -0,0 +1,491 @@ +/* + * + * (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 + * +*/ +if (Common === undefined) + var Common = {}; + +define([ + 'common/main/lib/component/BaseView', + 'common/main/lib/util/utils' +], function () { + 'use strict'; + + Common.UI.Calendar = Common.UI.BaseView.extend(_.extend({ + + template : + _.template([ + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
', + '
' + ].join('')), + + options: { + date: undefined, + firstday: 0 // 0 - sunday, 1 - monday + }, + + initialize : function(options) { + Common.UI.BaseView.prototype.initialize.call(this, options); + + var me = this; + + this.monthNames = [this.textJanuary, this.textFebruary, this.textMarch, this.textApril, this.textMay, this.textJune, this.textJuly, this.textAugust, this.textSeptember, this.textOctober, this.textNovember, this.textDecember]; + this.dayNamesShort = [this.textShortSunday, this.textShortMonday, this.textShortTuesday, this.textShortWednesday, this.textShortThursday, this.textShortFriday, this.textShortSaturday]; + this.monthShortNames = [this.textShortJanuary, this.textShortFebruary, this.textShortMarch, this.textShortApril, this.textShortMay, this.textShortJune, this.textShortJuly, this.textShortAugust, this.textShortSeptember, this.textShortOctober, this.textShortNovember, this.textShortDecember]; + + me.options.date = options.date; + if (!_.isUndefined(options.firstday) && (options.firstday === 0 || options.firstday === 1)) { + me.options.firstday = options.firstday; + } + + me.enableKeyEvents= me.options.enableKeyEvents; + + me._state = undefined; // 0 - month, 1 - months, 2 - years + + me.render(); + }, + + render: function () { + var me = this; + me.cmpEl = me.$el || $(this.el); + me.cmpEl.html(this.template()); + + me.currentDate = me.options.date || new Date(); + + me.btnPrev = new Common.UI.Button({ + cls: '', + iconCls: 'arrow-prev img-commonctrl' + }); + me.btnPrev.render(me.cmpEl.find('#prev-arrow')); + me.btnPrev.on('click', _.bind(me.onClickPrev, me)); + + me.btnNext = new Common.UI.Button({ + cls: '', + iconCls: 'arrow-next img-commonctrl' + }); + me.btnNext.render(me.cmpEl.find('#next-arrow')); + me.btnNext.on('click', _.bind(me.onClickNext, me)); + + me.cmpEl.on('keydown', function(e) { + me.trigger('calendar:keydown', me, e); + }); + + me.renderMonth(me.currentDate); + + this.trigger('render:after', this); + return this; + }, + + onClickPrev: function () { + var me = this; + if (me._state === 0) { + var d = new Date(me.currentDate); + d.setMonth(d.getMonth() - 1); + if (d.getFullYear() > 0) { + me.renderMonth(d); + } + } else if (me._state === 1) { + var d = new Date(me.currentDate); + d.setFullYear(d.getFullYear() - 1); + if (d.getFullYear() > 0) { + me.renderMonths(d); + } + } else if (me._state === 2) { + var year = me.currentDate.getFullYear(), + newYear; + if (year % 10 !== 0) { + newYear = String(year); + newYear = Number(newYear.slice(0, -1) + '0') - 1; + } else { + newYear = year - 1; + } + if (newYear > 0) { + me.currentDate.setFullYear(newYear); + me.renderYears(newYear); + } + } + }, + + onClickNext: function () { + var me = this; + if (me._state === 0) { + var d = new Date(me.currentDate); + d.setMonth(d.getMonth() + 1); + if (d.getFullYear() > 0) { + me.renderMonth(d); + } + } else if (me._state === 1) { + var d = new Date(me.currentDate); + d.setFullYear(d.getFullYear() + 1); + if (d.getFullYear() > 0) { + me.renderMonths(d); + } + } else if (me._state === 2) { + var year = me.currentDate.getFullYear(), + newYear; + if (year % 10 !== 9) { + newYear = String(year); + newYear = Number(newYear.slice(0, -1) + '9') + 1; + } else { + newYear = year + 1; + } + if (newYear > 0) { + me.currentDate.setFullYear(newYear); + me.renderYears(newYear); + } + } + }, + + renderYears: function (year) { + var me = this, + year = _.isNumber(year) ? year : (me.currentDate ? me.currentDate.getFullYear() : new Date().getFullYear()); + + me._state = 2; + + var firstYear = year, + lastYear = year; + if ((firstYear % 10) !== 0) { + var strYear = String(year); + firstYear = Number(strYear.slice(0, -1) + '0'); + } + if ((lastYear % 10) !== 9) { + var strYear = String(year); + lastYear = Number(strYear.slice(0, -1) + '9'); + } + + me.topTitle = _.template([ + '' + ].join('')); + me.cmpEl.find('.calendar-header .title').html(me.topTitle); + + me.bottomTitle = _.template([ + '' + ].join('')); + me.cmpEl.find('.calendar-header .bottom-row').html(me.bottomTitle); + + var arrYears = []; + var tmpYear = firstYear - 3; + + for (var i = 0; i < 16; i++) { + arrYears.push({ + year: (tmpYear > 0) ? tmpYear : '', + isCurrentDecade: ((tmpYear >= firstYear) && (tmpYear <= lastYear)) ? true : false, + disabled: (tmpYear > 0) ? false : true, + selected: (_.isDate(me.selectedDate)) ? + (tmpYear === me.selectedDate.getFullYear()) : + (tmpYear === new Date().getFullYear()) + }); + tmpYear++; + } + + if (!me.yearPicker) { + me.yearPicker = new Common.UI.DataView({ + el: me.cmpEl.find('.calendar-content'), + store: new Common.UI.DataViewStore(arrYears), + itemTemplate: _.template('
<%= year %>
') + }); + me.yearPicker.on('item:click', function (picker, item, record, e) { + var year = record.get('year'), + date = new Date(); + date.setFullYear(year); + me.renderMonths(date); + }); + me.enableKeyEvents && this.yearPicker.on('item:keydown', function(view, record, e) { + if (e.keyCode==Common.UI.Keys.ESC) { + Common.NotificationCenter.trigger('dataview:blur'); + } + }); + } else + me.yearPicker.store.reset(arrYears); + + me.enableKeyEvents && _.delay(function() { + me.monthPicker.cmpEl.find('.dataview').focus(); + }, 10); + }, + + renderMonths: function (date) { + var me = this, + curDate = (_.isDate(date)) ? date : (me.currentDate ? me.currentDate : new Date()), + year = curDate.getFullYear(); + + me._state = 1; + me.currentDate = curDate; + + // Number of year + me.topTitle = _.template([ + '
' + ].join('')); + me.cmpEl.find('.calendar-header .title').html(me.topTitle); + me.cmpEl.find('.calendar-header .title').off(); + me.cmpEl.find('.calendar-header .title').on('click', _.bind(me.renderYears, me)); + + me.bottomTitle = _.template([ + '' + ].join('')); + me.cmpEl.find('.calendar-header .bottom-row').html(me.bottomTitle); + + var arrMonths = []; + var today = new Date(); + + for (var ind = 0; ind < 12; ind++) { + arrMonths.push({ + indexMonth: ind, + nameMonth: me.monthShortNames[ind], + year: year, + curYear: true, + isCurrentMonth: (ind === curDate.getMonth()), + selected: (_.isDate(me.selectedDate)) ? + (ind === me.selectedDate.getMonth() && year === me.selectedDate.getFullYear()) : + (ind === today.getMonth() && year === today.getFullYear()) + }); + } + year = year + 1; + for (var ind = 0; ind < 4; ind++) { + arrMonths.push({ + indexMonth: ind, + nameMonth: me.monthShortNames[ind], + year: year, + curYear: false, + selected: (_.isDate(me.selectedDate)) ? + (ind === me.selectedDate.getMonth() && year === me.selectedDate.getFullYear()) : + (ind === today.getMonth() && year === today.getFullYear()) + }); + } + + if (!me.monthsPicker) { + me.monthsPicker = new Common.UI.DataView({ + el: me.cmpEl.find('.calendar-content'), + store: new Common.UI.DataViewStore(arrMonths), + itemTemplate: _.template('
<%= nameMonth %>
') + }); + me.monthsPicker.on('item:click', function (picker, item, record, e) { + var month = record.get('indexMonth'), + year = record.get('year'), + date = new Date(); + date.setFullYear(year, month); + me.renderMonth(date); + }); + me.enableKeyEvents && this.monthsPicker.on('item:keydown', function(view, record, e) { + if (e.keyCode==Common.UI.Keys.ESC) { + Common.NotificationCenter.trigger('dataview:blur'); + } + }); + } else + me.monthsPicker.store.reset(arrMonths); + + me.enableKeyEvents && _.delay(function() { + me.monthPicker.cmpEl.find('.dataview').focus(); + }, 10); + }, + + renderMonth: function (date) { + var me = this; + me._state = 0; + var firstDay = me.options.firstday; + + // Current date + var curDate = date || new Date(), + curMonth = curDate.getMonth(), + curIndexDayInWeek = curDate.getDay(), + curNumberDayInMonth = curDate.getDate(), + curYear = curDate.getFullYear(); + + me.currentDate = curDate; + + // Name month + me.topTitle = _.template([ + '
', + '', + '
' + ].join('')); + me.cmpEl.find('.calendar-header .title').html(me.topTitle); + me.cmpEl.find('.calendar-header .title').off(); + me.cmpEl.find('.calendar-header .title').on('click', _.bind(me.renderMonths, me)); + + // Name days of week + var dayNamesTemplate = ''; + for (var i = firstDay; i < 7; i++) { + dayNamesTemplate += ''; + } + if (firstDay > 0) { + dayNamesTemplate += ''; + } + me.cmpEl.find('.calendar-header .bottom-row').html(_.template(dayNamesTemplate)); + + // Month + var rows = 6, + cols = 7; + + var arrDays = []; + + var d = new Date(curDate); + d.setDate(1); + var firstDayOfMonthIndex = d.getDay(); + + var daysInPrevMonth = me.daysInMonth(d.getTime() - (10 * 24 * 60 * 60 * 1000)), + numberDay, + month, + year; + if (firstDay === 0) { + numberDay = (firstDayOfMonthIndex > 0) ? (daysInPrevMonth - (firstDayOfMonthIndex - 1)) : 1; + } else { + if (firstDayOfMonthIndex === 0) { + numberDay = daysInPrevMonth - 5; + } else { + numberDay = daysInPrevMonth - (firstDayOfMonthIndex - 2); + } + } + if ((firstDayOfMonthIndex > 0 && firstDay === 0) || firstDay === 1) { + if (curMonth - 1 >= 0) { + month = curMonth - 1; + year = curYear; + } else { + month = 11; + year = curYear - 1; + } + } else { + month = curMonth; + year = curYear; + } + + var tmp = new Date(); + tmp.setFullYear(year, month, numberDay); + var today = new Date(); + + for(var r = 0; r < rows; r++) { + for(var c = 0; c < cols; c++) { + var tmpDay = tmp.getDay(), + tmpNumber = tmp.getDate(), + tmpMonth = tmp.getMonth(), + tmpYear = tmp.getFullYear(); + arrDays.push({ + indexInWeek: tmpDay, + dayNumber: tmpNumber, + month: tmpMonth, + year: tmpYear, + isCurrentMonth: tmpMonth === curMonth, + selected: (_.isDate(me.selectedDate)) ? + (tmpNumber === me.selectedDate.getDate() && tmpMonth === me.selectedDate.getMonth() && tmpYear === me.selectedDate.getFullYear()) : + (tmpNumber === today.getDate() && tmpMonth === today.getMonth() && tmpYear === today.getFullYear()) + }); + tmp.setDate(tmpNumber + 1); + } + } + + if (!me.monthPicker) { + me.monthPicker = new Common.UI.DataView({ + el: me.cmpEl.find('.calendar-content'), + store: new Common.UI.DataViewStore(arrDays), + itemTemplate: _.template('
<%= dayNumber %>
') + }); + me.monthPicker.on('item:click', function(picker, item, record, e) { + var day = record.get('dayNumber'), + month = record.get('month'), + year = record.get('year'); + if (_.isUndefined(me.selectedDate)) { + me.selectedDate = new Date(); + } + me.selectedDate.setFullYear(year, month, day); + me.trigger('date:click', me, me.selectedDate); + }); + me.enableKeyEvents && this.monthPicker.on('item:keydown', function(view, record, e) { + if (e.keyCode==Common.UI.Keys.ESC) { + Common.NotificationCenter.trigger('dataview:blur'); + } + }); + } else + me.monthPicker.store.reset(arrDays); + + me.enableKeyEvents && _.delay(function() { + me.monthPicker.cmpEl.find('.dataview').focus(); + }, 10); + }, + + daysInMonth: function (date) { + var d; + d = date ? new Date(date) : new Date(); + var result = new Date(); + result.setFullYear(d.getFullYear(), d.getMonth() + 1, 0); + return result.getDate(); + }, + + setDate: function (date) { + if (_.isDate(date)) { + this.selectedDate = new Date(date); + this.renderMonth(this.selectedDate); + } + }, + + textJanuary: 'January', + textFebruary: 'February', + textMarch: 'March', + textApril: 'April', + textMay: 'May', + textJune: 'June', + textJuly: 'July', + textAugust: 'August', + textSeptember: 'September', + textOctober: 'October', + textNovember: 'November', + textDecember: 'December', + textShortJanuary: 'Jan', + textShortFebruary: 'Feb', + textShortMarch: 'Mar', + textShortApril: 'Apr', + textShortMay: 'May', + textShortJune: 'Jun', + textShortJuly: 'Jul', + textShortAugust: 'Aug', + textShortSeptember: 'Sep', + textShortOctober: 'Oct', + textShortNovember: 'Nov', + textShortDecember: 'Dec', + textShortSunday: 'Su', + textShortMonday: 'Mo', + textShortTuesday: 'Tu', + textShortWednesday: 'We', + textShortThursday: 'Th', + textShortFriday: 'Fr', + textShortSaturday: 'Sa', + textMonths: 'Months', + textYears: 'Years' + }, Common.UI.Calendar || {})); +}); \ No newline at end of file diff --git a/apps/common/main/lib/component/ComboBox.js b/apps/common/main/lib/component/ComboBox.js index 486790967..b634bc5c4 100644 --- a/apps/common/main/lib/component/ComboBox.js +++ b/apps/common/main/lib/component/ComboBox.js @@ -311,11 +311,13 @@ define([ if ($selected.length) { var itemTop = $selected.position().top, - itemHeight = $selected.height(), - listHeight = $list.height(); + itemHeight = $selected.outerHeight(), + listHeight = $list.outerHeight(); if (itemTop < 0 || itemTop + itemHeight > listHeight) { - $list.scrollTop($list.scrollTop() + itemTop + itemHeight - (listHeight/2)); + var height = $list.scrollTop() + itemTop + (itemHeight - listHeight)/2; + height = (Math.floor(height/itemHeight) * itemHeight); + $list.scrollTop(height); } setTimeout(function(){$selected.find('a').focus();}, 1); } @@ -400,10 +402,12 @@ define([ this.scroller.update({alwaysVisibleY: this.scrollAlwaysVisible}); var $list = $(this.el).find('ul'); var itemTop = item.position().top, - itemHeight = item.height(), - listHeight = $list.height(); + itemHeight = item.outerHeight(), + listHeight = $list.outerHeight(); if (itemTop < 0 || itemTop + itemHeight > listHeight) { - $list.scrollTop($list.scrollTop() + itemTop + itemHeight - (listHeight/2)); + var height = $list.scrollTop() + itemTop; + height = (Math.floor(height/itemHeight) * itemHeight); + $list.scrollTop(height); } } item.focus(); diff --git a/apps/common/main/lib/component/ComboBoxFonts.js b/apps/common/main/lib/component/ComboBoxFonts.js index 6acff6762..8ef57414a 100644 --- a/apps/common/main/lib/component/ComboBoxFonts.js +++ b/apps/common/main/lib/component/ComboBoxFonts.js @@ -430,7 +430,7 @@ define([ }, addItemToRecent: function(record, silent) { - if (this.recent<1) return; + if (!record || this.recent<1) return; var font = this.store.findWhere({name: record.get('name'),type:FONT_TYPE_RECENT}); font && this.store.remove(font); diff --git a/apps/common/main/lib/component/DimensionPicker.js b/apps/common/main/lib/component/DimensionPicker.js index dab30a9d2..c508a90e9 100644 --- a/apps/common/main/lib/component/DimensionPicker.js +++ b/apps/common/main/lib/component/DimensionPicker.js @@ -47,31 +47,6 @@ define([ 'use strict'; Common.UI.DimensionPicker = Common.UI.BaseView.extend((function(){ - var me, - rootEl, - areaMouseCatcher, - areaUnHighLighted, - areaHighLighted, - areaStatus, - curColumns = 0, - curRows = 0; - - var onMouseMove = function(event){ - me.setTableSize( - Math.ceil((event.offsetX === undefined ? event.originalEvent.layerX : event.offsetX*Common.Utils.zoom()) / me.itemSize), - Math.ceil((event.offsetY === undefined ? event.originalEvent.layerY : event.offsetY*Common.Utils.zoom()) / me.itemSize), - event - ); - }; - - var onMouseLeave = function(event){ - me.setTableSize(0, 0, event); - }; - - var onHighLightedMouseClick = function(e){ - me.trigger('select', me, curColumns, curRows, e); - }; - return { options: { itemSize : 18, @@ -95,9 +70,13 @@ define([ initialize : function(options) { Common.UI.BaseView.prototype.initialize.call(this, options); - me = this; + var me = this; - rootEl = me.$el || $(this.el); + this.render(); + + this.cmpEl = me.$el || $(this.el); + + var rootEl = this.cmpEl; me.itemSize = me.options.itemSize; me.minRows = me.options.minRows; @@ -105,31 +84,48 @@ define([ me.maxRows = me.options.maxRows; me.maxColumns = me.options.maxColumns; - this.render(); + me.curColumns = 0; + me.curRows = 0; + + var onMouseMove = function(event){ + me.setTableSize( + Math.ceil((event.offsetX === undefined ? event.originalEvent.layerX : event.offsetX*Common.Utils.zoom()) / me.itemSize), + Math.ceil((event.offsetY === undefined ? event.originalEvent.layerY : event.offsetY*Common.Utils.zoom()) / me.itemSize), + event + ); + }; + + var onMouseLeave = function(event){ + me.setTableSize(0, 0, event); + }; + + var onHighLightedMouseClick = function(e){ + me.trigger('select', me, me.curColumns, me.curRows, e); + }; if (rootEl){ - areaMouseCatcher = rootEl.find('.dimension-picker-mousecatcher'); - areaUnHighLighted = rootEl.find('.dimension-picker-unhighlighted'); - areaHighLighted = rootEl.find('.dimension-picker-highlighted'); - areaStatus = rootEl.find('.dimension-picker-status'); + var areaMouseCatcher = rootEl.find('.dimension-picker-mousecatcher'); + me.areaUnHighLighted = rootEl.find('.dimension-picker-unhighlighted'); + me.areaHighLighted = rootEl.find('.dimension-picker-highlighted'); + me.areaStatus = rootEl.find('.dimension-picker-status'); rootEl.css({width: me.minColumns + 'em'}); areaMouseCatcher.css('z-index', 1); areaMouseCatcher.width(me.maxColumns + 'em').height(me.maxRows + 'em'); - areaUnHighLighted.width(me.minColumns + 'em').height(me.minRows + 'em'); - areaStatus.html(curColumns + ' x ' + curRows); - areaStatus.width(areaUnHighLighted.width()); - } + me.areaUnHighLighted.width(me.minColumns + 'em').height(me.minRows + 'em'); + me.areaStatus.html(me.curColumns + ' x ' + me.curRows); + me.areaStatus.width(me.areaUnHighLighted.width()); - areaMouseCatcher.on('mousemove', onMouseMove); - areaHighLighted.on('mousemove', onMouseMove); - areaUnHighLighted.on('mousemove', onMouseMove); - areaMouseCatcher.on('mouseleave', onMouseLeave); - areaHighLighted.on('mouseleave', onMouseLeave); - areaUnHighLighted.on('mouseleave', onMouseLeave); - areaMouseCatcher.on('click', onHighLightedMouseClick); - areaHighLighted.on('click', onHighLightedMouseClick); - areaUnHighLighted.on('click', onHighLightedMouseClick); + areaMouseCatcher.on('mousemove', onMouseMove); + me.areaHighLighted.on('mousemove', onMouseMove); + me.areaUnHighLighted.on('mousemove', onMouseMove); + areaMouseCatcher.on('mouseleave', onMouseLeave); + me.areaHighLighted.on('mouseleave', onMouseLeave); + me.areaUnHighLighted.on('mouseleave', onMouseLeave); + areaMouseCatcher.on('click', onHighLightedMouseClick); + me.areaHighLighted.on('click', onHighLightedMouseClick); + me.areaUnHighLighted.on('click', onHighLightedMouseClick); + } }, render: function() { @@ -142,38 +138,38 @@ define([ if (columns > this.maxColumns) columns = this.maxColumns; if (rows > this.maxRows) rows = this.maxRows; - if (curColumns != columns || curRows != rows){ - curColumns = columns; - curRows = rows; + if (this.curColumns != columns || this.curRows != rows){ + this.curColumns = columns; + this.curRows = rows; - areaHighLighted.width(curColumns + 'em').height(curRows + 'em'); - areaUnHighLighted.width( - ((curColumns < me.minColumns) - ? me.minColumns - : ((curColumns + 1 > me.maxColumns) - ? me.maxColumns - : curColumns + 1)) + 'em' - ).height(((curRows < me.minRows) - ? me.minRows - : ((curRows + 1 > me.maxRows) - ? me.maxRows - : curRows + 1)) + 'em' + this.areaHighLighted.width(this.curColumns + 'em').height(this.curRows + 'em'); + this.areaUnHighLighted.width( + ((this.curColumns < this.minColumns) + ? this.minColumns + : ((this.curColumns + 1 > this.maxColumns) + ? this.maxColumns + : this.curColumns + 1)) + 'em' + ).height(((this.curRows < this.minRows) + ? this.minRows + : ((this.curRows + 1 > this.maxRows) + ? this.maxRows + : this.curRows + 1)) + 'em' ); - rootEl.width(areaUnHighLighted.width()); - areaStatus.html(curColumns + ' x ' + curRows); - areaStatus.width(areaUnHighLighted.width()); + this.cmpEl.width(this.areaUnHighLighted.width()); + this.areaStatus.html(this.curColumns + ' x ' + this.curRows); + this.areaStatus.width(this.areaUnHighLighted.width()); - me.trigger('change', me, curColumns, curRows, event); + this.trigger('change', this, this.curColumns, this.curRows, event); } }, getColumnsCount: function() { - return curColumns; + return this.curColumns; }, getRowsCount: function() { - return curRows; + return this.curRows; } } })()) diff --git a/apps/common/main/lib/component/Menu.js b/apps/common/main/lib/component/Menu.js index a0664d062..95b35b4e9 100644 --- a/apps/common/main/lib/component/Menu.js +++ b/apps/common/main/lib/component/Menu.js @@ -380,15 +380,23 @@ define([ onAfterShowMenu: function(e) { this.trigger('show:after', this, e); if (this.scroller) { - this.scroller.update({alwaysVisibleY: this.scrollAlwaysVisible}); - var menuRoot = this.menuRoot, - $selected = menuRoot.find('> li .checked'); + var menuRoot = this.menuRoot; + if (this.wheelSpeed===undefined) { + var item = menuRoot.find('> li:first'), + itemHeight = (item.length) ? item.outerHeight() : 1; + this.wheelSpeed = Math.min((Math.floor(menuRoot.height()/itemHeight) * itemHeight)/10, 20); + } + this.scroller.update({alwaysVisibleY: this.scrollAlwaysVisible, wheelSpeed: this.wheelSpeed}); + + var $selected = menuRoot.find('> li .checked'); if ($selected.length) { var itemTop = $selected.position().top, - itemHeight = $selected.height(), - listHeight = menuRoot.height(); + itemHeight = $selected.outerHeight(), + listHeight = menuRoot.outerHeight(); if (itemTop < 0 || itemTop + itemHeight > listHeight) { - menuRoot.scrollTop(menuRoot.scrollTop() + itemTop + itemHeight - (listHeight/2)); + var height = menuRoot.scrollTop() + itemTop + (itemHeight - listHeight)/2; + height = (Math.floor(height/itemHeight) * itemHeight); + menuRoot.scrollTop(height); } setTimeout(function(){$selected.focus();}, 1); } @@ -469,12 +477,14 @@ define([ this._search.index = idxCandidate; var item = itemCandidate.cmpEl.find('a'); if (this.scroller) { - this.scroller.update({alwaysVisibleY: this.scrollAlwaysVisible}); + this.scroller.update({alwaysVisibleY: this.scrollAlwaysVisible, wheelSpeed: this.wheelSpeed}); var itemTop = item.position().top, - itemHeight = item.height(), - listHeight = this.menuRoot.height(); + itemHeight = item.outerHeight(), + listHeight = this.menuRoot.outerHeight(); if (itemTop < 0 || itemTop + itemHeight > listHeight) { - this.menuRoot.scrollTop(this.menuRoot.scrollTop() + itemTop + itemHeight - (listHeight/2)); + var height = this.menuRoot.scrollTop() + itemTop; + height = (Math.floor(height/itemHeight) * itemHeight); + this.menuRoot.scrollTop(height); } } item.focus(); @@ -552,8 +562,10 @@ define([ suppressScrollX: true, alwaysVisibleY: this.scrollAlwaysVisible })); + this.wheelSpeed = undefined; } else if ( top + menuH < docH && menuRoot.height() < this.options.restoreHeight) { menuRoot.css('max-height', (Math.min(docH - top, this.options.restoreHeight)) + 'px'); + this.wheelSpeed = undefined; } } } else { @@ -568,7 +580,6 @@ define([ if (top < 0) top = 0; } - if (this.options.additionalAlign) this.options.additionalAlign.call(this, menuRoot, left, top); else @@ -848,10 +859,12 @@ define([ $selected = menuRoot.find('> li .checked'); if ($selected.length) { var itemTop = $selected.position().top, - itemHeight = $selected.height(), - listHeight = menuRoot.height(); + itemHeight = $selected.outerHeight(), + listHeight = menuRoot.outerHeight(); if (itemTop < 0 || itemTop + itemHeight > listHeight) { - menuRoot.scrollTop(menuRoot.scrollTop() + itemTop + itemHeight - (listHeight/2)); + var height = menuRoot.scrollTop() + itemTop + (itemHeight - listHeight)/2; + height = (Math.floor(height/itemHeight) * itemHeight); + menuRoot.scrollTop(height); } setTimeout(function(){$selected.focus();}, 1); } @@ -936,10 +949,12 @@ define([ if (this.scroller) { this.scroller.update({alwaysVisibleY: this.scrollAlwaysVisible}); var itemTop = item.position().top, - itemHeight = item.height(), - listHeight = this.menuRoot.height(); + itemHeight = item.outerHeight(), + listHeight = this.menuRoot.outerHeight(); if (itemTop < 0 || itemTop + itemHeight > listHeight) { - this.menuRoot.scrollTop(this.menuRoot.scrollTop() + itemTop + itemHeight - (listHeight/2)); + var height = this.menuRoot.scrollTop() + itemTop; + height = (Math.floor(height/itemHeight) * itemHeight); + this.menuRoot.scrollTop(height); } } item.focus(); diff --git a/apps/common/main/lib/component/MultiSliderGradient.js b/apps/common/main/lib/component/MultiSliderGradient.js index 8ad11eaff..71a5bf3a6 100644 --- a/apps/common/main/lib/component/MultiSliderGradient.js +++ b/apps/common/main/lib/component/MultiSliderGradient.js @@ -159,11 +159,21 @@ define([ me.changeSliderStyle(); }, + addNewThumb: function(index, color) { + var me = this; + me.thumbs[index].thumbcolor = me.thumbs[index].thumb.find('> div'); + (index>0) && this.setColorValue(color, index); + me.sortThumbs(); + me.changeSliderStyle(); + me.changeGradientStyle(); + }, + removeThumb: function(index) { if (index===undefined) index = this.thumbs.length-1; - if (index>0) { + if (this.thumbs.length > 2) { this.thumbs[index].thumb.remove(); this.thumbs.splice(index, 1); + this.sortThumbs(); this.changeSliderStyle(); } }, diff --git a/apps/common/main/lib/component/Slider.js b/apps/common/main/lib/component/Slider.js index 0ee059b7e..00e54d0d0 100644 --- a/apps/common/main/lib/component/Slider.js +++ b/apps/common/main/lib/component/Slider.js @@ -347,17 +347,28 @@ define([ pos = Math.max(0, Math.min(100, position)), value = pos/me.delta + me.minValue; - me.setThumbPosition(index, pos); - me.thumbs[index].value = value; + if (me.isRemoveThumb) { + if (me.thumbs.length < 3) { + $(document).off('mouseup', me.binding.onMouseUp); + $(document).off('mousemove', me.binding.onMouseMove); + return; + } + me.trigger('removethumb', me, _.findIndex(me.thumbs, {index: index})); + me.trigger('changecomplete', me, value, lastValue); + } else { + me.setThumbPosition(index, pos); + me.thumbs[index].value = value; - if (need_sort) - me.sortThumbs(); + if (need_sort) + me.sortThumbs(); + } $(document).off('mouseup', me.binding.onMouseUp); $(document).off('mousemove', me.binding.onMouseMove); me._dragstart = undefined; - me.trigger('changecomplete', me, value, lastValue); + !me.isRemoveThumb && me.trigger('changecomplete', me, value, lastValue); + me.isRemoveThumb = undefined; }; var onMouseMove = function (e) { @@ -382,6 +393,10 @@ define([ if (need_sort) me.sortThumbs(); + var positionY = e.pageY*Common.Utils.zoom() - me.cmpEl.offset().top; + me.isRemoveThumb = positionY > me.cmpEl.height() || positionY < 0; + me.setRemoveThumb(index, me.isRemoveThumb); + if (Math.abs(value-lastValue)>0.001) me.trigger('change', me, value, lastValue); }; @@ -403,7 +418,25 @@ define([ $(document).on('mousemove', null, e.data, me.binding.onMouseMove); }; - var onTrackMouseDown = function (e) { + var onTrackMouseUp = function (e) { + if ( me.disabled || !_.isUndefined(me._dragstart) || me.thumbs.length > 9) return; + + var pos = Math.max(0, Math.min(100, (Math.round((e.pageX*Common.Utils.zoom() - me.cmpEl.offset().left) / me.width * 100)))), + nearIndex = findThumb(pos), + thumbColor = me.thumbs[nearIndex].colorValue, + thumbValue = me.thumbs[nearIndex].value, + value = pos/me.delta + me.minValue; + me.addThumb(); + var index = me.thumbs.length - 1; + me.setThumbPosition(index, pos); + me.thumbs[index].value = value; + me.trigger('addthumb', me, index, nearIndex, thumbColor); + + me.trigger('change', me); + me.trigger('changecomplete', me); + }; + + /*var onTrackMouseDown = function (e) { if ( me.disabled ) return; var pos = Math.max(0, Math.min(100, (Math.round((e.pageX*Common.Utils.zoom() - me.cmpEl.offset().left) / me.width * 100)))), @@ -416,7 +449,7 @@ define([ me.trigger('change', me, value, lastValue); me.trigger('changecomplete', me, value, lastValue); - }; + };*/ var findThumb = function(pos) { var nearest = 100, @@ -462,7 +495,8 @@ define([ me.setActiveThumb(0, true); if (!me.rendered) { - el.on('mousedown', '.track', onTrackMouseDown); + /*el.on('mousedown', '.track', onTrackMouseDown);*/ + el.on('mouseup', '.track', onTrackMouseUp); } me.rendered = true; @@ -472,11 +506,23 @@ define([ setActiveThumb: function(index, suspend) { this.currentThumb = index; + this.$thumbs = this.cmpEl.find('.thumb'); this.$thumbs.removeClass('active'); this.thumbs[index].thumb.addClass('active'); if (suspend!==true) this.trigger('thumbclick', this, index); }, + setRemoveThumb: function(index, remove) { + var ind = _.findIndex(this.thumbs, {index: index}); + if (ind !== -1) { + if (remove && this.thumbs.length > 2) { + this.$el.find('.active').addClass('remove'); + } else { + this.$el.find('.remove').removeClass('remove'); + } + } + }, + setThumbPosition: function(index, x) { this.thumbs[index].position = x; this.thumbs[index].thumb.css({left: x + '%'}); diff --git a/apps/common/main/lib/component/Tab.js b/apps/common/main/lib/component/Tab.js index 29e93b32c..b3b5644ef 100644 --- a/apps/common/main/lib/component/Tab.js +++ b/apps/common/main/lib/component/Tab.js @@ -51,7 +51,7 @@ define([ this.active = false; this.label = 'Tab'; this.cls = ''; - this.template = _.template(['
  • ', + this.template = _.template(['
  • ', '<%- label %>', '
  • '].join('')); @@ -82,6 +82,10 @@ define([ this.$el.addClass('active'); }, + isSelected: function() { + return this.$el.hasClass('selected'); + }, + deactivate: function(){ this.$el.removeClass('active'); }, @@ -110,6 +114,11 @@ define([ this.$el.removeClass(cls); }, + toggleClass: function(cls) { + if (cls.length) + this.$el.toggleClass(cls); + }, + hasClass: function(cls) { return this.$el.hasClass(cls); }, diff --git a/apps/common/main/lib/component/TabBar.js b/apps/common/main/lib/component/TabBar.js index 0c6868add..44e58de0b 100644 --- a/apps/common/main/lib/component/TabBar.js +++ b/apps/common/main/lib/component/TabBar.js @@ -69,12 +69,28 @@ define([ }; StateManager.prototype.attach = function (tab) { - tab.changeState = $.proxy(function () { - this.trigger('tab:change', tab); - this.bar.$el.find('ul > li.active').removeClass('active'); - tab.activate(); + tab.changeState = $.proxy(function (select) { + if (select) { + tab.toggleClass('selected'); + var selectTab = _.find(this.bar.selectTabs, function (item) {return item.sheetindex === tab.sheetindex;}); + if (selectTab) { + this.bar.selectTabs = _.without(this.bar.selectTabs, selectTab); + } else { + this.bar.selectTabs.push(tab); + } + } else { + if (!tab.isSelected()) { + this.bar.$el.find('ul > li.selected').removeClass('selected'); + tab.addClass('selected'); + this.bar.selectTabs.length = 0; + this.bar.selectTabs.push(tab); + } + this.trigger('tab:change', tab); + this.bar.$el.find('ul > li.active').removeClass('active'); + tab.activate(); - this.bar.trigger('tab:changed', this.bar, this.bar.tabs.indexOf(tab), tab); + this.bar.trigger('tab:changed', this.bar, this.bar.tabs.indexOf(tab), tab); + } }, this); var dragHelper = new (function() { @@ -87,6 +103,8 @@ define([ var me = this, length = me.bar.tabs.length, barBounds = me.bar.$bar.get(0).getBoundingClientRect(); + me.leftBorder = barBounds.left; + me.rightBorder = barBounds.right; if (barBounds) { me.bounds = []; @@ -97,6 +115,8 @@ define([ this.bounds.push(me.bar.tabs[i].$el.get(0).getBoundingClientRect()); } + me.lastTabRight = me.bounds[length - 1].right; + me.tabBarLeft = me.bounds[0].left; me.tabBarRight = me.bounds[length - 1].right; me.tabBarRight = Math.min(me.tabBarRight, barBounds.right - 1); @@ -278,17 +298,105 @@ define([ document.removeEventListener('dragstart',dragDropText); }); } + }, + + setHookTabs: function (e, bar, tabs) { + var me = this; + function dragComplete() { + if (!_.isUndefined(me.drag)) { + bar.dragging = false; + bar.$el.find('li.mousemove').removeClass('mousemove right'); + var arrSelectIndex = []; + tabs.forEach(function (item) { + arrSelectIndex.push(item.sheetindex); + }); + if (!_.isUndefined(me.drag.place)) { + me.bar.trigger('tab:move', arrSelectIndex, me.drag.place); + me.bar.$bar.scrollLeft(me.scrollLeft); + me.bar.scrollX = undefined; + } else { + me.bar.trigger('tab:move', arrSelectIndex); + me.bar.$bar.scrollLeft(me.scrollLeft); + me.bar.scrollX = undefined; + } + + me.drag = undefined; + } + } + function dragMove (event) { + if (!_.isUndefined(me.drag)) { + me.drag.moveX = event.clientX*Common.Utils.zoom(); + if (me.drag.moveX < me.leftBorder) { + me.scrollLeft -= 20; + me.bar.$bar.scrollLeft(me.scrollLeft); + me.calculateBounds(); + } else if (me.drag.moveX < me.tabBarRight && me.drag.moveX > me.tabBarLeft) { + var name = $(event.target).parent().data('label'), + currentTab = _.findIndex(bar.tabs, {label: name}); + if (currentTab === -1) { + bar.$el.find('li.mousemove').removeClass('mousemove right'); + me.drag.place = undefined; + } else if (me.bounds[currentTab].left - me.scrollLeft >= me.tabBarLeft) { + me.drag.place = currentTab; + $(event.target).parent().parent().find('li.mousemove').removeClass('mousemove right'); + $(event.target).parent().addClass('mousemove'); + } + } else if (me.drag.moveX > me.lastTabRight && Math.abs(me.tabBarRight - me.bounds[me.bar.tabs.length - 1].right) < 1) { //move to end of list, right border of the right tab is visible + bar.$el.find('li.mousemove').removeClass('mousemove right'); + bar.tabs[bar.tabs.length - 1].$el.addClass('mousemove right'); + me.drag.place = bar.tabs.length; + } else if (me.drag.moveX - me.rightBorder > 3) { + me.scrollLeft += 20; + me.bar.$bar.scrollLeft(me.scrollLeft); + me.calculateBounds(); + } + } + } + if (!_.isUndefined(bar) && !_.isUndefined(tabs) && bar.tabs.length > 1) { + me.bar = bar; + me.drag = {tabs: tabs}; + bar.dragging = true; + this.calculateBounds(); + + $(document).on('mousemove.tabbar', dragMove); + $(document).on('mouseup.tabbar', function (e) { + dragComplete(e); + $(document).off('mouseup.tabbar'); + $(document).off('mousemove.tabbar', dragMove); + }); + } } } }); tab.$el.on({ - click: $.proxy(function () { - if (!tab.disabled && !tab.$el.hasClass('active')) { - if (tab.control == 'manual') { - this.bar.trigger('tab:manual', this.bar, this.bar.tabs.indexOf(tab), tab); - } else { - tab.changeState(); + click: $.proxy(function (event) { + if (!tab.disabled) { + if (event.ctrlKey || event.metaKey) { + if (!tab.isActive()) { + tab.changeState(true); + } + } else if (event.shiftKey) { + this.bar.$el.find('ul > li.selected').removeClass('selected'); + this.bar.selectTabs.length = 0; + var $active = this.bar.$el.find('ul > li.active'), + indexAct = $active.index(), + indexCur = this.bar.tabs.indexOf(tab); + var startIndex = (indexCur > indexAct) ? indexAct : indexCur, + endIndex = (indexCur > indexAct) ? indexCur : indexAct; + for (var i = startIndex; i <= endIndex; i++) { + this.bar.tabs[i].changeState(true); + } + } else if (!tab.$el.hasClass('active')) { + if (this.bar.tabs.length === this.bar.selectTabs.length) { + this.bar.$el.find('ul > li.selected').removeClass('selected'); + this.bar.selectTabs.length = 0; + } + if (tab.control == 'manual') { + this.bar.trigger('tab:manual', this.bar, this.bar.tabs.indexOf(tab), tab); + } else { + tab.changeState(); + } } } !tab.disabled && Common.NotificationCenter.trigger('edit:complete', this.bar); @@ -297,12 +405,16 @@ define([ this.trigger('tab:dblclick', this, this.tabs.indexOf(tab), tab); }, this.bar), contextmenu: $.proxy(function () { - this.trigger('tab:contextmenu', this, this.tabs.indexOf(tab), tab); + this.trigger('tab:contextmenu', this, this.tabs.indexOf(tab), tab, this.selectTabs); }, this.bar), mousedown: $.proxy(function (e) { if (this.bar.options.draggable && !_.isUndefined(dragHelper) && (3 !== e.which)) { if (!tab.isLockTheDrag) { - dragHelper.setHook(e, this.bar, tab); + if (this.bar.selectTabs.length > 1) { + dragHelper.setHookTabs(e, this.bar, this.bar.selectTabs); + } else { + dragHelper.setHook(e, this.bar, tab); + } } } }, this) @@ -322,6 +434,7 @@ define([ tabs: [], template: _.template('', '' ].join('')), @@ -133,9 +148,15 @@ define([ themeColors[row].push(effect); }); + // custom color + this.dynamicColors = Common.localStorage.getItem('asc.'+Common.localStorage.getId()+'.colors.custom'); + this.dynamicColors = this.dynamicColors ? this.dynamicColors.toLowerCase().split(',') : []; + + $(me.el).append(me.template({ themeColors: themeColors, - standartColors: standartColors + standartColors: standartColors, + dynamicColors: me.dynamicColors })); return me; @@ -157,29 +178,26 @@ define([ el = $(me.el), $target = $(e.currentTarget); - el.find('.color-palette a').removeClass('active'); - $target.addClass('active'); - var color = $target.data('color').toString(), effectId = $target.data('effectid'); - me.currentColor = color; - - if (effectId) { - me.currentColor = {color: color, effectId: effectId}; + if (color !== 'empty') { + el.find('.color-palette a').removeClass('active'); + $target.addClass('active'); + me.currentColor = color; + if (effectId) { + me.currentColor = {color: color, effectId: effectId}; + } + me.trigger('select', me, me.currentColor); + } else { + me.fireEvent('customcolor', me); } - - me.trigger('select', me, me.currentColor); }, select: function(color) { var me = this, el = $(me.el); - if (color == me.currentColor) { - return; - } - me.currentColor = color; me.clearSelection(); @@ -195,11 +213,10 @@ define([ color = /#?([a-fA-F0-9]{6})/.exec(color)[1]; } - if (/^[a-fA-F0-9]{6}|transparent$/.test(color) || _.indexOf(Common.Utils.ThemeColor.getStandartColors(), color) > -1) { - el.find('.standart-colors a[data-color=' + color + ']').addClass('active'); - } else { - el.find('.custom-colors a[data-color=' + color + ']').addClass('active'); + if (/^[a-fA-F0-9]{6}|transparent$/.test(color) || _.indexOf(Common.Utils.ThemeColor.getStandartColors(), color) > -1 || _.indexOf(this.dynamicColors, color) > -1) { + el.find('.color-palette a[data-color=' + color + ']').first().addClass('active'); } + } }, @@ -208,7 +225,43 @@ define([ $(this.el).find('.color-palette a').removeClass('active'); }, + saveDynamicColor: function(color) { + var key_name = 'asc.'+Common.localStorage.getId()+'.colors.custom'; + var colors = Common.localStorage.getItem(key_name); + colors = colors ? colors.split(',') : []; + if (colors.push(color) > this.options.dynamiccolors) colors.shift(); + this.dynamicColors = colors; + Common.localStorage.setItem(key_name, colors.join().toUpperCase()); + }, + + updateDynamicColors: function() { + var me = this; + var dynamicColors = Common.localStorage.getItem('asc.'+Common.localStorage.getId()+'.colors.custom'); + dynamicColors = dynamicColors ? dynamicColors.toLowerCase().split(',') : []; + var templateColors = ''; + _.each(dynamicColors, function(color) { + templateColors += ''; + }); + if (dynamicColors.length < this.options.dynamiccolors) { + for (var i = dynamicColors.length; i < this.options.dynamiccolors; i++) { + templateColors += ''; + } + } + $(this.el).find('.dynamic-colors .item-inner').html(_.template(templateColors)); + $(this.el).find('.color-palette .dynamic-colors a').on('click', _.bind(this.onColorClick, this)); + }, + + addNewDynamicColor: function(colorPicker, color) { + if (color) { + this.saveDynamicColor(color); + this.updateDynamicColors(); + this.trigger('select', this, color); + this.select(color); + } + }, + textThemeColors: 'Theme Colors', - textStandartColors: 'Standard Colors' + textStandartColors: 'Standard Colors', + textCustomColors: 'Custom Colors' }, Common.UI.ThemeColorPalette || {})); }); \ No newline at end of file diff --git a/apps/common/mobile/resources/less/ios/_color-palette.less b/apps/common/mobile/resources/less/ios/_color-palette.less index 2fa543df4..f243b1ef6 100644 --- a/apps/common/mobile/resources/less/ios/_color-palette.less +++ b/apps/common/mobile/resources/less/ios/_color-palette.less @@ -35,9 +35,132 @@ } } - .standart-colors { + .standart-colors, .dynamic-colors { .item-inner { overflow: visible; } } -} \ No newline at end of file +} + +.custom-colors { + display: flex; + justify-content: space-around; + align-items: center; + margin: 15px; + &.phone { + max-width: 300px; + margin: 0 auto; + margin-top: 4px; + .button-round { + margin-top: 20px; + } + } + .right-block { + margin-left: 20px; + } + .button-round { + height: 72px; + width: 72px; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + border-radius: 100px; + background-color: #ffffff; + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); + border-color: transparent; + margin-top: 25px; + &.active-state { + background-color: rgba(0, 0, 0, 0.1); + } + } + .color-hsb-preview { + width: 72px; + height: 72px; + border-radius: 100px; + overflow: hidden; + border: 1px solid #c4c4c4; + } + .new-color-hsb-preview { + width: 100%; + height: 36px; + } + .current-color-hsb-preview { + width: 100%; + height: 36px; + } + .list-block ul:before, .list-block ul:after { + content: none; + } + .list-block ul li { + border: 1px solid rgba(0, 0, 0, 0.3); + } + .color-picker-wheel { + position: relative; + width: 290px; + max-width: 100%; + height: auto; + font-size: 0; + + svg { + width: 100%; + height: auto; + } + + .color-picker-wheel-handle { + width: calc(100% / 6); + height: calc(100% / 6); + position: absolute; + box-sizing: border-box; + border: 2px solid #fff; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.5); + background: red; + border-radius: 50%; + left: 0; + top: 0; + } + + .color-picker-sb-spectrum { + background-color: #000; + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 100%), linear-gradient(to left, rgba(255, 255, 255, 0) 0%, #fff 100%); + position: relative; + width: 45%; + height: 45%; + left: 50%; + top: 50%; + transform: translate3d(-50%, -50%, 0); + position: absolute; + } + + .color-picker-sb-spectrum-handle { + width: 4px; + height: 4px; + position: absolute; + left: -2px; + top: -2px; + z-index: 1; + + &:after { + background-color: inherit; + content: ''; + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.5); + box-sizing: border-box; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + transition: 150ms; + transition-property: transform; + transform-origin: center; + } + + &.color-picker-sb-spectrum-handle-pressed:after { + transform: scale(1.5) translate(-33.333%, -33.333%); + } + } + } +} diff --git a/apps/common/mobile/resources/less/material/_color-palette.less b/apps/common/mobile/resources/less/material/_color-palette.less index 49fa72501..511765221 100644 --- a/apps/common/mobile/resources/less/material/_color-palette.less +++ b/apps/common/mobile/resources/less/material/_color-palette.less @@ -35,7 +35,7 @@ } } - .standart-colors { + .standart-colors, .dynamic-colors { .item-inner { overflow: visible; } @@ -44,4 +44,128 @@ &.list-block:last-child li:last-child a { border-radius: 0; } + +} + +.custom-colors { + display: flex; + justify-content: space-around; + align-items: center; + margin: 15px; + &.phone { + max-width: 300px; + margin: 0 auto; + margin-top: 4px; + .button-round { + margin-top: 20px; + } + } + .right-block { + margin-left: 20px; + } + .button-round { + height: 72px; + width: 72px; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + border-radius: 100px; + background-color: @themeColor; + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); + border-color: transparent; + margin-top: 25px; + &.active-state { + background-color: rgba(0, 0, 0, 0.1); + } + } + .color-hsb-preview { + width: 72px; + height: 72px; + border-radius: 100px; + overflow: hidden; + border: 1px solid #ededed; + } + .new-color-hsb-preview { + width: 100%; + height: 36px; + } + .current-color-hsb-preview { + width: 100%; + height: 36px; + } + .list-block ul:before, .list-block ul:after { + content: none; + } + .list-block ul li { + border: 1px solid rgba(0, 0, 0, 0.3); + } + .color-picker-wheel { + position: relative; + width: 290px; + max-width: 100%; + height: auto; + font-size: 0; + + svg { + width: 100%; + height: auto; + } + + .color-picker-wheel-handle { + width: calc(100% / 6); + height: calc(100% / 6); + position: absolute; + box-sizing: border-box; + border: 2px solid #fff; + box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.5); + background: red; + border-radius: 50%; + left: 0; + top: 0; + } + + .color-picker-sb-spectrum { + background-color: #000; + background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 0%, #000 100%), linear-gradient(to left, rgba(255, 255, 255, 0) 0%, #fff 100%); + position: relative; + width: 45%; + height: 45%; + left: 50%; + top: 50%; + transform: translate3d(-50%, -50%, 0); + position: absolute; + } + + .color-picker-sb-spectrum-handle { + width: 4px; + height: 4px; + position: absolute; + left: -2px; + top: -2px; + z-index: 1; + + &:after { + background-color: inherit; + content: ''; + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.5); + box-sizing: border-box; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + transition: 150ms; + transition-property: transform; + transform-origin: center; + } + + &.color-picker-sb-spectrum-handle-pressed:after { + transform: scale(1.5) translate(-33.333%, -33.333%); + } + } + } } \ No newline at end of file diff --git a/apps/documenteditor/embed/js/ApplicationController.js b/apps/documenteditor/embed/js/ApplicationController.js index f8baf5891..877d5a0dc 100644 --- a/apps/documenteditor/embed/js/ApplicationController.js +++ b/apps/documenteditor/embed/js/ApplicationController.js @@ -75,7 +75,7 @@ DE.ApplicationController = new(function(){ $('#editor_sdk').addClass('top'); } - if (config.canBackToFolder === false || !(config.customization && config.customization.goback && config.customization.goback.url)) { + if (config.canBackToFolder === false || !(config.customization && config.customization.goback && (config.customization.goback.url || config.customization.goback.requestClose && config.canRequestClose))) { $('#id-btn-close').hide(); // Hide last separator @@ -266,8 +266,12 @@ DE.ApplicationController = new(function(){ }); $('#id-btn-close').on('click', function(){ - if (config.customization && config.customization.goback && config.customization.goback.url) - window.parent.location.href = config.customization.goback.url; + if (config.customization && config.customization.goback) { + if (config.customization.goback.requestClose && config.canRequestClose) + Common.Gateway.requestClose(); + else if (config.customization.goback.url) + window.parent.location.href = config.customization.goback.url; + } }); $('#id-btn-zoom-in').on('click', api.zoomIn.bind(this)); @@ -402,6 +406,10 @@ DE.ApplicationController = new(function(){ message = me.errorFileSizeExceed; break; + case Asc.c_oAscError.ID.UpdateVersion: + message = me.errorUpdateVersionOnDisconnect; + break; + default: message = me.errorDefaultMessage.replace('%1', id); break; @@ -558,6 +566,7 @@ DE.ApplicationController = new(function(){ waitText: 'Please, wait...', textLoadingDocument: 'Loading document', txtClose: 'Close', - errorFileSizeExceed: 'The file size exceeds the limitation set for your server.
    Please contact your Document Server administrator for details.' + errorFileSizeExceed: 'The file size exceeds the limitation set for your server.
    Please contact your Document Server administrator for details.', + errorUpdateVersionOnDisconnect: 'Internet connection has been restored, and the file version has been changed.
    Before you can continue working, you need to download the file or copy its content to make sure nothing is lost, and then reload this page.' } })(); \ No newline at end of file diff --git a/apps/documenteditor/embed/locale/en.json b/apps/documenteditor/embed/locale/en.json index 91cd7c4b4..a36be77b1 100644 --- a/apps/documenteditor/embed/locale/en.json +++ b/apps/documenteditor/embed/locale/en.json @@ -22,6 +22,7 @@ "DE.ApplicationController.unknownErrorText": "Unknown error.", "DE.ApplicationController.unsupportedBrowserErrorText": "Your browser is not supported.", "DE.ApplicationController.waitText": "Please, wait...", + "DE.ApplicationController.errorUpdateVersionOnDisconnect": "Internet connection has been restored, and the file version has been changed.
    Before you can continue working, you need to download the file or copy its content to make sure nothing is lost, and then reload this page.", "DE.ApplicationView.txtDownload": "Download", "DE.ApplicationView.txtEmbed": "Embed", "DE.ApplicationView.txtFullScreen": "Full Screen", diff --git a/apps/documenteditor/embed/locale/fr.json b/apps/documenteditor/embed/locale/fr.json index 1145973e3..f06efef7c 100644 --- a/apps/documenteditor/embed/locale/fr.json +++ b/apps/documenteditor/embed/locale/fr.json @@ -12,6 +12,7 @@ "DE.ApplicationController.errorAccessDeny": "Vous tentez d'exéсuter une action pour laquelle vous ne disposez pas des droits.
    Veuillez contacter l'administrateur de Document Server.", "DE.ApplicationController.errorDefaultMessage": "Code d'erreur: %1", "DE.ApplicationController.errorFilePassProtect": "Le fichier est protégé par le mot de passe et ne peut pas être ouvert.", + "DE.ApplicationController.errorFileSizeExceed": "La taille du fichier dépasse les limites établies sur votre serveur.
    Veuillez contacter votre administrateur de Document Server pour obtenir plus d'information. ", "DE.ApplicationController.errorUserDrop": "Impossible d'accéder au fichier.", "DE.ApplicationController.notcriticalErrorTitle": "Avertissement", "DE.ApplicationController.scriptLoadError": "La connexion est trop lente, certains éléments ne peuvent pas être chargés. Veuillez recharger la page.", diff --git a/apps/documenteditor/embed/locale/it.json b/apps/documenteditor/embed/locale/it.json index 327a968e2..f35b88f9b 100644 --- a/apps/documenteditor/embed/locale/it.json +++ b/apps/documenteditor/embed/locale/it.json @@ -12,6 +12,7 @@ "DE.ApplicationController.errorAccessDeny": "Stai tentando di eseguire un'azione per la quale non disponi di permessi sufficienti.
    Si prega di contattare l'amministratore del Server dei Documenti.", "DE.ApplicationController.errorDefaultMessage": "Codice errore: %1", "DE.ApplicationController.errorFilePassProtect": "Il file è protetto da una password. Impossibile aprirlo.", + "DE.ApplicationController.errorFileSizeExceed": "La dimensione del file supera la limitazione impostata per il tuo server.
    Per i dettagli, contatta l'amministratore del Document server.", "DE.ApplicationController.errorUserDrop": "Impossibile accedere al file subito.", "DE.ApplicationController.notcriticalErrorTitle": "Avviso", "DE.ApplicationController.scriptLoadError": "La connessione è troppo lenta, alcuni componenti non possono essere caricati. Si prega di ricaricare la pagina.", diff --git a/apps/documenteditor/embed/locale/ru.json b/apps/documenteditor/embed/locale/ru.json index ea575e0d1..6fc73f817 100644 --- a/apps/documenteditor/embed/locale/ru.json +++ b/apps/documenteditor/embed/locale/ru.json @@ -12,6 +12,7 @@ "DE.ApplicationController.errorAccessDeny": "Вы пытаетесь выполнить действие, на которое у вас нет прав.
    Пожалуйста, обратитесь к администратору Сервера документов.", "DE.ApplicationController.errorDefaultMessage": "Код ошибки: %1", "DE.ApplicationController.errorFilePassProtect": "Файл защищен паролем и не может быть открыт.", + "DE.ApplicationController.errorFileSizeExceed": "Размер файла превышает ограничение, установленное для вашего сервера.
    Обратитесь к администратору Сервера документов для получения дополнительной информации.", "DE.ApplicationController.errorUserDrop": "В настоящий момент файл недоступен.", "DE.ApplicationController.notcriticalErrorTitle": "Внимание", "DE.ApplicationController.scriptLoadError": "Слишком медленное подключение, некоторые компоненты не удалось загрузить. Пожалуйста, обновите страницу.", diff --git a/apps/documenteditor/main/app/controller/LeftMenu.js b/apps/documenteditor/main/app/controller/LeftMenu.js index fd86037ef..6ebac79fd 100644 --- a/apps/documenteditor/main/app/controller/LeftMenu.js +++ b/apps/documenteditor/main/app/controller/LeftMenu.js @@ -62,7 +62,6 @@ define([ 'hide': _.bind(this.onHideChat, this) }, 'Common.Views.Header': { - 'click:users': _.bind(this.clickStatusbarUsers, this), 'file:settings': _.bind(this.clickToolbarSettings,this), 'history:show': function () { if ( !this.leftMenu.panelHistory.isVisible() ) @@ -468,6 +467,7 @@ define([ if (this.mode.canViewComments && this.leftMenu.panelComments.isVisible()) value = resolved = true; (value) ? this.api.asc_showComments(resolved) : this.api.asc_hideComments(); + this.getApplication().getController('Common.Controllers.ReviewChanges').commentsShowHide(value ? 'show' : 'hide'); /** coauthoring end **/ value = Common.localStorage.getItem("de-settings-fontrender"); @@ -532,10 +532,6 @@ define([ }, /** coauthoring begin **/ - clickStatusbarUsers: function() { - this.leftMenu.menuFile.panels['rights'].changeAccessRights(); - }, - onHideChat: function() { $(this.leftMenu.btnChat.el).blur(); Common.NotificationCenter.trigger('layout:changed', 'leftmenu'); diff --git a/apps/documenteditor/main/app/controller/Links.js b/apps/documenteditor/main/app/controller/Links.js index f6d37fd4c..e4a30288b 100644 --- a/apps/documenteditor/main/app/controller/Links.js +++ b/apps/documenteditor/main/app/controller/Links.js @@ -41,6 +41,7 @@ define([ 'core', + 'common/main/lib/component/Calendar', 'documenteditor/main/app/view/Links', 'documenteditor/main/app/view/NoteSettingsDialog', 'documenteditor/main/app/view/HyperlinkSettingsDialog', @@ -129,7 +130,8 @@ define([ in_header = false, in_equation = false, in_image = false, - in_table = false; + in_table = false, + frame_pr = null; while (++i < selectedObjects.length) { type = selectedObjects[i].get_ObjectType(); @@ -137,6 +139,7 @@ define([ if (type === Asc.c_oAscTypeSelectElement.Paragraph) { paragraph_locked = pr.get_Locked(); + frame_pr = pr; } else if (type === Asc.c_oAscTypeSelectElement.Header) { header_locked = pr.get_Locked(); in_header = true; @@ -153,12 +156,19 @@ define([ var control_props = this.api.asc_IsContentControl() ? this.api.asc_GetContentControlProperties() : null, control_plain = (control_props) ? (control_props.get_ContentControlType()==Asc.c_oAscSdtLevelType.Inline) : false; + var rich_del_lock = (frame_pr) ? !frame_pr.can_DeleteBlockContentControl() : true, + rich_edit_lock = (frame_pr) ? !frame_pr.can_EditBlockContentControl() : true, + plain_del_lock = (frame_pr) ? !frame_pr.can_DeleteInlineContentControl() : true, + plain_edit_lock = (frame_pr) ? !frame_pr.can_EditInlineContentControl() : true; - var need_disable = paragraph_locked || in_equation || in_image || in_header || control_plain; + var need_disable = paragraph_locked || in_equation || in_image || in_header || control_plain || rich_edit_lock || plain_edit_lock; this.view.btnsNotes.setDisabled(need_disable); need_disable = paragraph_locked || header_locked || in_header || control_plain; this.view.btnBookmarks.setDisabled(need_disable); + + need_disable = in_header || rich_edit_lock || plain_edit_lock || rich_del_lock || plain_del_lock; + this.view.btnsContents.setDisabled(need_disable); }, onApiCanAddHyperlink: function(value) { @@ -351,8 +361,9 @@ define([ })).show(); }, - onShowContentControlsActions: function(action, x, y) { - var menu = (action==1) ? this.view.contentsUpdateMenu : this.view.contentsMenu, + onShowTOCActions: function(obj, x, y) { + var action = obj.button, + menu = (action==AscCommon.CCButtonType.Toc) ? this.view.contentsUpdateMenu : this.view.contentsMenu, documentHolderView = this.getApplication().getController('DocumentHolder').documentHolder, menuContainer = documentHolderView.cmpEl.find(Common.Utils.String.format('#menu-container-{0}', menu.id)), me = this; @@ -391,6 +402,150 @@ define([ onHideContentControlsActions: function() { this.view.contentsMenu && this.view.contentsMenu.hide(); this.view.contentsUpdateMenu && this.view.contentsUpdateMenu.hide(); + this.view.listControlMenu && this.view.listControlMenu.isVisible() && this.view.listControlMenu.hide(); + var controlsContainer = this.getApplication().getController('DocumentHolder').documentHolder.cmpEl.find('#calendar-control-container'); + if (controlsContainer.is(':visible')) + controlsContainer.hide(); + }, + + onShowDateActions: function(obj, x, y) { + var props = obj.pr, + specProps = props.get_DateTimePr(), + id = props.get_InternalId(), + documentHolderView = this.getApplication().getController('DocumentHolder').documentHolder, + controlsContainer = documentHolderView.cmpEl.find('#calendar-control-container'), + me = this; + + if (controlsContainer.length < 1) { + controlsContainer = $('
    '); + documentHolderView.cmpEl.append(controlsContainer); + } + + Common.UI.Menu.Manager.hideAll(); + + controlsContainer.css({left: x, top : y}); + controlsContainer.show(); + + if (!this.cmpCalendar) { + this.cmpCalendar = new Common.UI.Calendar({ + el: documentHolderView.cmpEl.find('#id-document-calendar-control'), + enableKeyEvents: true, + firstday: 1 + }); + this.cmpCalendar.on('date:click', function (cmp, date) { + specProps.put_FullDate(new Date(date)); + me.api.asc_SetContentControlProperties(props, id); + controlsContainer.hide(); + me.api.asc_UncheckContentControlButtons(); + }); + this.cmpCalendar.on('calendar:keydown', function (cmp, e) { + if (e.keyCode==Common.UI.Keys.ESC) { + controlsContainer.hide(); + me.api.asc_UncheckContentControlButtons(); + } + }); + } + this.cmpCalendar.setDate(new Date(specProps ? specProps.get_FullDate() : undefined)); + + // align + var offset = controlsContainer.offset(), + docW = Common.Utils.innerWidth(), + docH = Common.Utils.innerHeight() - 10, // Yep, it's magic number + menuW = this.cmpCalendar.cmpEl.outerWidth(), + menuH = this.cmpCalendar.cmpEl.outerHeight(), + buttonOffset = 22, + left = offset.left - menuW, + top = offset.top; + if (top + menuH > docH) { + top = docH - menuH; + left -= buttonOffset; + } + if (top < 0) + top = 0; + if (left + menuW > docW) + left = docW - menuW; + this.cmpCalendar.cmpEl.css({left: left, top : top}); + + documentHolderView._preventClick = true; + }, + + onShowListActions: function(obj, x, y) { + var type = obj.type, + props = obj.pr, + id = props.get_InternalId(), + specProps = (type == Asc.c_oAscContentControlSpecificType.ComboBox) ? props.get_ComboBoxPr() : props.get_DropDownListPr(), + menu = this.view.listControlMenu, + documentHolderView = this.getApplication().getController('DocumentHolder').documentHolder, + menuContainer = menu ? documentHolderView.cmpEl.find(Common.Utils.String.format('#menu-container-{0}', menu.id)) : null, + me = this; + + this._fromShowContentControls = true; + Common.UI.Menu.Manager.hideAll(); + + if (!menu) { + this.view.listControlMenu = menu = new Common.UI.Menu({ + menuAlign: 'tr-bl', + items: [] + }); + menu.on('item:click', function(menu, item) { + setTimeout(function(){ + me.api.asc_SelectContentControlListItem(item.value, id); + }, 1); + }); + + // Prepare menu container + if (!menuContainer || menuContainer.length < 1) { + menuContainer = $(Common.Utils.String.format('', menu.id)); + documentHolderView.cmpEl.append(menuContainer); + } + + menu.render(menuContainer); + menu.cmpEl.attr({tabindex: "-1"}); + menu.on('hide:after', function(){ + me.view.listControlMenu.removeAll(); + if (!me._fromShowContentControls) + me.api.asc_UncheckContentControlButtons(); + }); + } + if (specProps) { + var count = specProps.get_ItemsCount(); + for (var i=0; i0) /* Check if focus in combobox goes from input to it's menu button or menu items, or from comment editing area to Ok/Cancel button */ - && !(e.target.localName == 'textarea' && $(e.target).closest('.asc-window').find(e.relatedTarget).length>0) /* Check if focus in comment goes from textarea to it's email menu */ + && !(e.target.localName == 'textarea' && $(e.target).closest('.asc-window').find('.dropdown-menu').find(e.relatedTarget).length>0) /* Check if focus in comment goes from textarea to it's email menu */ && (e.relatedTarget.localName != 'input' || !/form-control/.test(e.relatedTarget.className)) /* Check if focus goes to text input with class "form-control" */ && (e.relatedTarget.localName != 'textarea' || /area_id/.test(e.relatedTarget.id))) /* Check if focus goes to textarea, but not to "area_id" */ { if (Common.Utils.isIE && e.originalEvent && e.originalEvent.target && /area_id/.test(e.originalEvent.target.id) && (e.originalEvent.target === e.originalEvent.srcElement)) @@ -337,9 +341,10 @@ define([ this.appOptions.mergeFolderUrl = this.editorConfig.mergeFolderUrl; this.appOptions.saveAsUrl = this.editorConfig.saveAsUrl; this.appOptions.canAnalytics = false; + this.appOptions.canRequestClose = this.editorConfig.canRequestClose; this.appOptions.customization = this.editorConfig.customization; - this.appOptions.canBackToFolder = (this.editorConfig.canBackToFolder!==false) && (typeof (this.editorConfig.customization) == 'object') - && (typeof (this.editorConfig.customization.goback) == 'object') && !_.isEmpty(this.editorConfig.customization.goback.url); + this.appOptions.canBackToFolder = (this.editorConfig.canBackToFolder!==false) && (typeof (this.editorConfig.customization) == 'object') && (typeof (this.editorConfig.customization.goback) == 'object') + && (!_.isEmpty(this.editorConfig.customization.goback.url) || this.editorConfig.customization.goback.requestClose && this.appOptions.canRequestClose); this.appOptions.canBack = this.appOptions.canBackToFolder === true; this.appOptions.canPlugins = false; this.appOptions.canMakeActionLink = this.editorConfig.canMakeActionLink; @@ -348,6 +353,7 @@ define([ this.appOptions.canRequestSaveAs = this.editorConfig.canRequestSaveAs; this.appOptions.canRequestInsertImage = this.editorConfig.canRequestInsertImage; this.appOptions.canRequestMailMergeRecipients = this.editorConfig.canRequestMailMergeRecipients; + this.appOptions.compatibleFeatures = (typeof (this.appOptions.customization) == 'object') && !!this.appOptions.customization.compatibleFeatures; appHeader = this.getApplication().getController('Viewport').getView('Common.Views.Header'); appHeader.setCanBack(this.appOptions.canBackToFolder === true, (this.appOptions.canBackToFolder) ? this.editorConfig.customization.goback.text : '') @@ -359,8 +365,11 @@ define([ if (this.appOptions.location == 'us' || this.appOptions.location == 'ca') Common.Utils.Metric.setDefaultMetric(Common.Utils.Metric.c_MetricUnits.inch); - if (!this.editorConfig.customization || !(this.editorConfig.customization.loaderName || this.editorConfig.customization.loaderLogo)) - $('#editor_sdk').append('
    ' + '
    '.repeat(20) + '
    '); + if (!( this.editorConfig.customization && ( this.editorConfig.customization.toolbarNoTabs || + (this.editorConfig.targetApp!=='desktop') && (this.editorConfig.customization.loaderName || this.editorConfig.customization.loaderLogo)))) { + $('#editor-container').css('overflow', 'hidden'); + $('#editor-container').append('
    ' + '
    '.repeat(20) + '
    '); + } Common.Controllers.Desktop.init(this.appOptions); }, @@ -640,11 +649,16 @@ define([ goBack: function(current) { if ( !Common.Controllers.Desktop.process('goback') ) { - var href = this.appOptions.customization.goback.url; - if (!current && this.appOptions.customization.goback.blank!==false) { - window.open(href, "_blank"); + if (this.appOptions.customization.goback.requestClose && this.appOptions.canRequestClose) { + Common.Gateway.requestClose(); + // Common.Controllers.Desktop.requestClose(); } else { - parent.location.href = href; + var href = this.appOptions.customization.goback.url; + if (!current && this.appOptions.customization.goback.blank!==false) { + window.open(href, "_blank"); + } else { + parent.location.href = href; + } } } }, @@ -1048,6 +1062,7 @@ define([ $(document).on('contextmenu', _.bind(me.onContextMenu, me)); Common.Gateway.documentReady(); + $('#editor-container').css('overflow', ''); $('.doc-placeholder').remove(); }, @@ -1146,7 +1161,6 @@ define([ this.appOptions.isOffline = this.api.asc_isOffline(); this.appOptions.isReviewOnly = this.permissions.review === true && this.permissions.edit === false; this.appOptions.canRequestEditRights = this.editorConfig.canRequestEditRights; - this.appOptions.canRequestClose = this.editorConfig.canRequestClose; this.appOptions.canEdit = (this.permissions.edit !== false || this.permissions.review === true) && // can edit or review (this.editorConfig.canRequestEditRights || this.editorConfig.mode !== 'view') && // if mode=="view" -> canRequestEditRights must be defined (!this.appOptions.isReviewOnly || this.appOptions.canLicense); // if isReviewOnly==true -> canLicense must be true @@ -1254,13 +1268,13 @@ define([ var me = this, application = this.getApplication(), reviewController = application.getController('Common.Controllers.ReviewChanges'); - reviewController.setMode(me.appOptions).setConfig({config: me.editorConfig}, me.api); + reviewController.setMode(me.appOptions).setConfig({config: me.editorConfig}, me.api).loadDocument({doc:me.document}); if (this.appOptions.isEdit || this.appOptions.isRestrictedEdit) { // set api events for toolbar in the Restricted Editing mode var toolbarController = application.getController('Toolbar'); toolbarController && toolbarController.setApi(me.api); - if (this.appOptions.isRestrictedEdit) return; + if (!this.appOptions.isEdit) return; var rightmenuController = application.getController('RightMenu'), fontsControllers = application.getController('Common.Controllers.Fonts'); @@ -1441,7 +1455,7 @@ define([ break; case Asc.c_oAscError.ID.Warning: - config.msg = this.errorConnectToServer.replace('%1', '{{API_URL_EDITING_CALLBACK}}'); + config.msg = this.errorConnectToServer; config.closable = false; break; @@ -1490,6 +1504,11 @@ define([ config.msg = this.errorFileSizeExceed; break; + case Asc.c_oAscError.ID.UpdateVersion: + config.msg = this.errorUpdateVersionOnDisconnect; + config.maxwidth = 600; + break; + default: config.msg = (typeof id == 'string') ? id : this.errorDefaultMessage.replace('%1', id); break; @@ -2067,7 +2086,8 @@ define([ var filemenu = this.getApplication().getController('LeftMenu').getView('LeftMenu').getMenu('file'); filemenu.loadDocument({doc:this.document}); - filemenu.panels['info'].updateInfo(this.document); + filemenu.panels && filemenu.panels['info'] && filemenu.panels['info'].updateInfo(this.document); + this.getApplication().getController('Common.Controllers.ReviewChanges').loadDocument({doc:this.document}); Common.Gateway.metaChange(meta); }, @@ -2210,15 +2230,14 @@ define([ sendMergeTitle: 'Sending Merge', sendMergeText: 'Sending Merge...', txtArt: 'Your text here', - errorConnectToServer: 'The document could not be saved. Please check connection settings or contact your administrator.
    When you click the \'OK\' button, you will be prompted to download the document.

    ' + - 'Find more information about connecting Document Server here', + errorConnectToServer: 'The document could not be saved. Please check connection settings or contact your administrator.
    When you click the \'OK\' button, you will be prompted to download the document.', textTryUndoRedo: 'The Undo/Redo functions are disabled for the Fast co-editing mode.
    Click the \'Strict mode\' button to switch to the Strict co-editing mode to edit the file without other users interference and send your changes only after you save them. You can switch between the co-editing modes using the editor Advanced settings.', textStrict: 'Strict mode', txtErrorLoadHistory: 'Loading history failed', textBuyNow: 'Visit website', textNoLicenseTitle: '%1 connection limitation', textContactUs: 'Contact sales', - errorViewerDisconnect: 'Connection is lost. You can still view the document,
    but will not be able to download or print until the connection is restored.', + errorViewerDisconnect: 'Connection is lost. You can still view the document,
    but will not be able to download or print until the connection is restored and page is reloaded.', warnLicenseExp: 'Your license has expired.
    Please update your license and refresh the page.', titleLicenseExp: 'License expired', openErrorText: 'An error has occurred while opening the file', @@ -2463,7 +2482,11 @@ define([ textCustomLoader: 'Please note that according to the terms of the license you are not entitled to change the loader.
    Please contact our Sales Department to get a quote.', txtHyperlink: 'Hyperlink', waitText: 'Please, wait...', - errorFileSizeExceed: 'The file size exceeds the limitation set for your server.
    Please contact your Document Server administrator for details.' + errorFileSizeExceed: 'The file size exceeds the limitation set for your server.
    Please contact your Document Server administrator for details.', + txtMainDocOnly: 'Error! Main Document Only.', + txtNotValidBookmark: 'Error! Not a valid bookmark self-reference.', + txtNoText: 'Error! No text of specified style in document.', + errorUpdateVersionOnDisconnect: 'Internet connection has been restored, and the file version has been changed.
    Before you can continue working, you need to download the file or copy its content to make sure nothing is lost, and then reload this page.' } })(), DE.Controllers.Main || {})) }); \ No newline at end of file diff --git a/apps/documenteditor/main/app/controller/Toolbar.js b/apps/documenteditor/main/app/controller/Toolbar.js index 5b500ddc2..1affbdbd8 100644 --- a/apps/documenteditor/main/app/controller/Toolbar.js +++ b/apps/documenteditor/main/app/controller/Toolbar.js @@ -47,6 +47,7 @@ define([ 'common/main/lib/view/ImageFromUrlDialog', 'common/main/lib/view/InsertTableDialog', 'common/main/lib/view/SelectFileDlg', + 'common/main/lib/view/SymbolTableDialog', 'common/main/lib/util/define', 'documenteditor/main/app/view/Toolbar', 'documenteditor/main/app/view/DropcapSettingsAdvanced', @@ -324,6 +325,7 @@ define([ toolbar.listStyles.on('contextmenu', _.bind(this.onListStyleContextMenu, this)); toolbar.styleMenu.on('hide:before', _.bind(this.onListStyleBeforeHide, this)); toolbar.btnInsertEquation.on('click', _.bind(this.onInsertEquationClick, this)); + toolbar.btnInsertSymbol.on('click', _.bind(this.onInsertSymbolClick, this)); toolbar.mnuNoControlsColor.on('click', _.bind(this.onNoControlsColor, this)); toolbar.mnuControlsColorPicker.on('select', _.bind(this.onSelectControlsColor, this)); Common.Gateway.on('insertimage', _.bind(this.insertImage, this)); @@ -378,7 +380,10 @@ define([ this.api.asc_registerCallback('asc_onContextMenu', _.bind(this.onContextMenu, this)); this.api.asc_registerCallback('asc_onShowParaMarks', _.bind(this.onShowParaMarks, this)); this.api.asc_registerCallback('asc_onChangeSdtGlobalSettings', _.bind(this.onChangeSdtGlobalSettings, this)); + this.api.asc_registerCallback('asc_onTextLanguage', _.bind(this.onTextLanguage, this)); Common.NotificationCenter.on('fonts:change', _.bind(this.onApiChangeFont, this)); + this.api.asc_registerCallback('asc_onTableDrawModeChanged', _.bind(this.onTableDraw, this)); + this.api.asc_registerCallback('asc_onTableEraseModeChanged', _.bind(this.onTableErase, this)); } else if (this.mode.isRestrictedEdit) { this.api.asc_registerCallback('asc_onFocusObject', _.bind(this.onApiFocusObjectRestrictedEdit, this)); this.api.asc_registerCallback('asc_onCoAuthoringDisconnect', _.bind(this.onApiCoAuthoringDisconnect, this)); @@ -653,7 +658,8 @@ define([ var i = -1, type, paragraph_locked = false, header_locked = false, - image_locked = false; + image_locked = false, + in_image = false; while (++i < selectedObjects.length) { type = selectedObjects[i].get_ObjectType(); @@ -663,11 +669,15 @@ define([ } else if (type === Asc.c_oAscTypeSelectElement.Header) { header_locked = selectedObjects[i].get_ObjectValue().get_Locked(); } else if (type === Asc.c_oAscTypeSelectElement.Image) { + in_image = true; image_locked = selectedObjects[i].get_ObjectValue().get_Locked(); } } var need_disable = !this.api.can_AddQuotedComment() || paragraph_locked || header_locked || image_locked; + if (this.mode.compatibleFeatures) { + need_disable = need_disable || in_image; + } if ( this.btnsComment && this.btnsComment.length > 0 ) this.btnsComment.setDisabled(need_disable); }, @@ -690,7 +700,8 @@ define([ in_equation = false, btn_eq_state = false, in_image = false, - in_control = false; + in_control = false, + in_para = false; while (++i < selectedObjects.length) { type = selectedObjects[i].get_ObjectType(); @@ -702,6 +713,7 @@ define([ can_add_image = pr.get_CanAddImage(); frame_pr = pr; sh = pr.get_Shade(); + in_para = true; } else if (type === Asc.c_oAscTypeSelectElement.Header) { header_locked = pr.get_Locked(); in_header = true; @@ -727,7 +739,11 @@ define([ if (sh) this.onParagraphColor(sh); - var need_disable = paragraph_locked || header_locked; + var rich_del_lock = (frame_pr) ? !frame_pr.can_DeleteBlockContentControl() : true, + rich_edit_lock = (frame_pr) ? !frame_pr.can_EditBlockContentControl() : true, + plain_del_lock = (frame_pr) ? !frame_pr.can_DeleteInlineContentControl() : true, + plain_edit_lock = (frame_pr) ? !frame_pr.can_EditInlineContentControl() : true; + var need_disable = paragraph_locked || header_locked || rich_edit_lock || plain_edit_lock; if (this._state.prcontrolsdisable != need_disable) { if (this._state.activated) this._state.prcontrolsdisable = need_disable; @@ -741,15 +757,18 @@ define([ lock_type = (in_control&&control_props) ? control_props.get_Lock() : Asc.c_oAscSdtLockType.Unlocked, control_plain = (in_control&&control_props) ? (control_props.get_ContentControlType()==Asc.c_oAscSdtLevelType.Inline) : false; (lock_type===undefined) && (lock_type = Asc.c_oAscSdtLockType.Unlocked); + var content_locked = lock_type==Asc.c_oAscSdtLockType.SdtContentLocked || lock_type==Asc.c_oAscSdtLockType.ContentLocked; - if (!paragraph_locked && !header_locked) { - toolbar.btnContentControls.menu.items[0].setDisabled(control_plain || lock_type==Asc.c_oAscSdtLockType.SdtContentLocked || lock_type==Asc.c_oAscSdtLockType.ContentLocked); - toolbar.btnContentControls.menu.items[1].setDisabled(control_plain || lock_type==Asc.c_oAscSdtLockType.SdtContentLocked || lock_type==Asc.c_oAscSdtLockType.ContentLocked); - toolbar.btnContentControls.menu.items[3].setDisabled(!in_control || lock_type==Asc.c_oAscSdtLockType.SdtContentLocked || lock_type==Asc.c_oAscSdtLockType.SdtLocked); - toolbar.btnContentControls.menu.items[5].setDisabled(!in_control); + toolbar.btnContentControls.setDisabled(paragraph_locked || header_locked); + if (!(paragraph_locked || header_locked)) { + var control_disable = control_plain || content_locked; + for (var i=0; i<7; i++) + toolbar.btnContentControls.menu.items[i].setDisabled(control_disable); + toolbar.btnContentControls.menu.items[8].setDisabled(!in_control || lock_type==Asc.c_oAscSdtLockType.SdtContentLocked || lock_type==Asc.c_oAscSdtLockType.SdtLocked); + toolbar.btnContentControls.menu.items[10].setDisabled(!in_control); } - var need_text_disable = paragraph_locked || header_locked || in_chart; + var need_text_disable = paragraph_locked || header_locked || in_chart || rich_edit_lock || plain_edit_lock; if (this._state.textonlycontrolsdisable != need_text_disable) { if (this._state.activated) this._state.textonlycontrolsdisable = need_text_disable; if (!need_disable) { @@ -757,7 +776,7 @@ define([ item.setDisabled(need_text_disable); }, this); } - toolbar.btnCopyStyle.setDisabled(need_text_disable); + // toolbar.btnCopyStyle.setDisabled(need_text_disable); toolbar.btnClearStyle.setDisabled(need_text_disable); } @@ -783,50 +802,55 @@ define([ if ( !toolbar.btnDropCap.isDisabled() ) toolbar.mnuDropCapAdvanced.setDisabled(disable_dropcapadv); - need_disable = !can_add_table || header_locked || in_equation || control_plain; + need_disable = !can_add_table || header_locked || in_equation || control_plain || rich_edit_lock || plain_edit_lock || rich_del_lock || plain_del_lock; toolbar.btnInsertTable.setDisabled(need_disable); need_disable = toolbar.mnuPageNumCurrentPos.isDisabled() && toolbar.mnuPageNumberPosPicker.isDisabled() || control_plain; toolbar.mnuInsertPageNum.setDisabled(need_disable); var in_footnote = this.api.asc_IsCursorInFootnote(); - need_disable = paragraph_locked || header_locked || in_header || in_image || in_equation && !btn_eq_state || in_footnote || in_control; + need_disable = paragraph_locked || header_locked || in_header || in_image || in_equation && !btn_eq_state || in_footnote || in_control || rich_edit_lock || plain_edit_lock || rich_del_lock; toolbar.btnsPageBreak.setDisabled(need_disable); toolbar.btnBlankPage.setDisabled(need_disable); - need_disable = paragraph_locked || header_locked || in_equation || control_plain; + need_disable = paragraph_locked || header_locked || in_equation || control_plain || content_locked; toolbar.btnInsertShape.setDisabled(need_disable); toolbar.btnInsertText.setDisabled(need_disable); - need_disable = paragraph_locked || header_locked || !can_add_image || in_equation || control_plain; + need_disable = paragraph_locked || header_locked || in_para && !can_add_image || in_equation || control_plain || rich_del_lock || plain_del_lock || content_locked; toolbar.btnInsertImage.setDisabled(need_disable); - toolbar.btnInsertTextArt.setDisabled(need_disable || in_image || in_footnote); + toolbar.btnInsertTextArt.setDisabled(need_disable || in_footnote); if (in_chart !== this._state.in_chart) { toolbar.btnInsertChart.updateHint(in_chart ? toolbar.tipChangeChart : toolbar.tipInsertChart); this._state.in_chart = in_chart; } - need_disable = in_chart && image_locked || !in_chart && need_disable || control_plain; + need_disable = in_chart && image_locked || !in_chart && need_disable || control_plain || rich_del_lock || plain_del_lock || content_locked; toolbar.btnInsertChart.setDisabled(need_disable); - need_disable = paragraph_locked || header_locked || in_chart || !can_add_image&&!in_equation || control_plain; + need_disable = paragraph_locked || header_locked || in_chart || !can_add_image&&!in_equation || control_plain || rich_edit_lock || plain_edit_lock || rich_del_lock || plain_del_lock; toolbar.btnInsertEquation.setDisabled(need_disable); - need_disable = paragraph_locked || header_locked || in_equation; + toolbar.btnInsertSymbol.setDisabled(!in_para || paragraph_locked || header_locked || rich_edit_lock || plain_edit_lock || rich_del_lock || plain_del_lock); + + need_disable = paragraph_locked || header_locked || in_equation || rich_edit_lock || plain_edit_lock; toolbar.btnSuperscript.setDisabled(need_disable); toolbar.btnSubscript.setDisabled(need_disable); toolbar.btnEditHeader.setDisabled(in_equation); - need_disable = paragraph_locked || header_locked || in_image || control_plain; + need_disable = paragraph_locked || header_locked || in_image || control_plain || rich_edit_lock || plain_edit_lock; if (need_disable != toolbar.btnColumns.isDisabled()) toolbar.btnColumns.setDisabled(need_disable); if (toolbar.listStylesAdditionalMenuItem && (frame_pr===undefined) !== toolbar.listStylesAdditionalMenuItem.isDisabled()) toolbar.listStylesAdditionalMenuItem.setDisabled(frame_pr===undefined); - need_disable = !this.api.can_AddQuotedComment() || paragraph_locked || header_locked || image_locked; + need_disable = !this.api.can_AddQuotedComment() || paragraph_locked || header_locked || image_locked || rich_del_lock || rich_edit_lock || plain_del_lock || plain_edit_lock; + if (this.mode.compatibleFeatures) { + need_disable = need_disable || in_image; + } if ( this.btnsComment && this.btnsComment.length > 0 ) this.btnsComment.setDisabled(need_disable); @@ -840,6 +864,13 @@ define([ this.modeAlwaysSetStyle = false; }, + onTableDraw: function(v) { + this.toolbar.mnuInsertTable && this.toolbar.mnuInsertTable.items[2].setChecked(!!v, true); + }, + onTableErase: function(v) { + this.toolbar.mnuInsertTable && this.toolbar.mnuInsertTable.items[3].setChecked(!!v, true); + }, + onApiParagraphStyleChange: function(name) { if (this._state.prstyle != name) { var listStyle = this.toolbar.listStyles, @@ -1396,6 +1427,12 @@ define([ Common.NotificationCenter.trigger('edit:complete', me.toolbar); } })).show(); + } else if (item.value == 'draw') { + item.isChecked() && menu.items[3].setChecked(false, true); + this.api.SetTableDrawMode(item.isChecked()); + } else if (item.value == 'erase') { + item.isChecked() && menu.items[2].setChecked(false, true); + this.api.SetTableEraseMode(item.isChecked()); } }, @@ -1719,6 +1756,8 @@ define([ (new DE.Views.ControlSettingsDialog({ props: props, api: me.api, + controlLang: me._state.lang, + interfaceLang: me.mode.lang, handler: function(result, value) { if (result == 'ok') { me.api.asc_SetContentControlProperties(value, id); @@ -1735,7 +1774,17 @@ define([ } } } else { - this.api.asc_AddContentControl(item.value); + if (item.value == 'plain' || item.value == 'rich') + this.api.asc_AddContentControl((item.value=='plain') ? Asc.c_oAscSdtLevelType.Inline : Asc.c_oAscSdtLevelType.Block); + else if (item.value == 'picture') + this.api.asc_AddContentControlPicture(); + else if (item.value == 'checkbox') + this.api.asc_AddContentControlCheckBox(); + else if (item.value == 'date') + this.api.asc_AddContentControlDatePicker(); + else if (item.value == 'combobox' || item.value == 'dropdown') + this.api.asc_AddContentControlList(item.value == 'combobox'); + Common.component.Analytics.trackEvent('ToolBar', 'Add Content Control'); } @@ -2460,6 +2509,31 @@ define([ Common.NotificationCenter.trigger('edit:complete', this.toolbar, this.toolbar.btnInsertEquation); }, + onInsertSymbolClick: function() { + if (this.dlgSymbolTable && this.dlgSymbolTable.isVisible()) return; + + if (this.api) { + var me = this; + me.dlgSymbolTable = new Common.Views.SymbolTableDialog({ + api: me.api, + lang: me.mode.lang, + modal: false, + type: 1, + buttons: [{value: 'ok', caption: this.textInsert}, 'close'], + handler: function(dlg, result, settings) { + if (result == 'ok') { + me.api.asc_insertSymbol(settings.font, settings.code); + } else + Common.NotificationCenter.trigger('edit:complete', me.toolbar); + } + }); + me.dlgSymbolTable.show(); + me.dlgSymbolTable.on('symbol:dblclick', function(cmp, result, settings) { + me.api.asc_insertSymbol(settings.font, settings.code); + }); + } + }, + onApiMathTypes: function(equation) { this._equationTemp = equation; var me = this; @@ -2825,45 +2899,43 @@ define([ compactview = true; } - setTimeout(function () { - me.toolbar.render(_.extend({isCompactView: compactview}, config)); + me.toolbar.render(_.extend({isCompactView: compactview}, config)); - var tab = {action: 'review', caption: me.toolbar.textTabCollaboration}; - var $panel = me.application.getController('Common.Controllers.ReviewChanges').createToolbarPanel(); - if ( $panel ) - me.toolbar.addTab(tab, $panel, 4); + var tab = {action: 'review', caption: me.toolbar.textTabCollaboration}; + var $panel = me.application.getController('Common.Controllers.ReviewChanges').createToolbarPanel(); + if ( $panel ) + me.toolbar.addTab(tab, $panel, 4); - if ( config.isEdit ) { - me.toolbar.setMode(config); + if ( config.isEdit ) { + me.toolbar.setMode(config); - me.toolbar.btnSave.on('disabled', _.bind(me.onBtnChangeState, me, 'save:disabled')); + me.toolbar.btnSave.on('disabled', _.bind(me.onBtnChangeState, me, 'save:disabled')); - if (!(config.customization && config.customization.compactHeader)) { - // hide 'print' and 'save' buttons group and next separator - me.toolbar.btnPrint.$el.parents('.group').hide().next().hide(); + if (!(config.customization && config.customization.compactHeader)) { + // hide 'print' and 'save' buttons group and next separator + me.toolbar.btnPrint.$el.parents('.group').hide().next().hide(); - // hide 'undo' and 'redo' buttons and retrieve parent container - var $box = me.toolbar.btnUndo.$el.hide().next().hide().parent(); + // hide 'undo' and 'redo' buttons and retrieve parent container + var $box = me.toolbar.btnUndo.$el.hide().next().hide().parent(); - // move 'paste' button to the container instead of 'undo' and 'redo' - me.toolbar.btnPaste.$el.detach().appendTo($box); - me.toolbar.btnCopy.$el.removeClass('split'); - } - - if ( config.isDesktopApp ) { - if ( config.canProtect ) { - tab = {action: 'protect', caption: me.toolbar.textTabProtect}; - $panel = me.getApplication().getController('Common.Controllers.Protection').createToolbarPanel(); - - if ($panel) me.toolbar.addTab(tab, $panel, 5); - } - } - - var links = me.getApplication().getController('Links'); - links.setApi(me.api).setConfig({toolbar: me}); - Array.prototype.push.apply(me.toolbar.toolbarControls, links.getView('Links').getButtons()); + // move 'paste' button to the container instead of 'undo' and 'redo' + me.toolbar.btnPaste.$el.detach().appendTo($box); + me.toolbar.btnCopy.$el.removeClass('split'); } - }, 0); + + if ( config.isDesktopApp ) { + if ( config.canProtect ) { + tab = {action: 'protect', caption: me.toolbar.textTabProtect}; + $panel = me.getApplication().getController('Common.Controllers.Protection').createToolbarPanel(); + + if ($panel) me.toolbar.addTab(tab, $panel, 5); + } + } + + var links = me.getApplication().getController('Links'); + links.setApi(me.api).setConfig({toolbar: me}); + Array.prototype.push.apply(me.toolbar.toolbarControls, links.getView('Links').getButtons()); + } }, onAppReady: function (config) { @@ -2879,6 +2951,8 @@ define([ btn.on('click', function (btn, e) { Common.NotificationCenter.trigger('app:comment:add', 'toolbar'); }); + if (btn.cmpEl.closest('#review-changes-panel').length>0) + btn.setCaption(me.toolbar.capBtnAddComment); }, this); } } @@ -2913,6 +2987,10 @@ define([ } }, + onTextLanguage: function(langId) { + this._state.lang = langId; + }, + textEmptyImgUrl : 'You need to specify image URL.', textWarning : 'Warning', textFontSizeErr : 'The entered value is incorrect.
    Please enter a numeric value between 1 and 100', @@ -3260,7 +3338,8 @@ define([ confirmAddFontName: 'The font you are going to save is not available on the current device.
    The text style will be displayed using one of the device fonts, the saved font will be used when it is available.
    Do you want to continue?', notcriticalErrorTitle: 'Warning', txtMarginsW: 'Left and right margins are too high for a given page wight', - txtMarginsH: 'Top and bottom margins are too high for a given page height' + txtMarginsH: 'Top and bottom margins are too high for a given page height', + textInsert: 'Insert' }, DE.Controllers.Toolbar || {})); }); \ No newline at end of file diff --git a/apps/documenteditor/main/app/template/ControlSettingsDialog.template b/apps/documenteditor/main/app/template/ControlSettingsDialog.template new file mode 100644 index 000000000..70df12159 --- /dev/null +++ b/apps/documenteditor/main/app/template/ControlSettingsDialog.template @@ -0,0 +1,151 @@ +
    +
    + + + + + + + + + + +
    + +
    +
    + +
    +
    +
    +
    + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +
    + + + + + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + +
    + + +
    +
    +
    + + + + + +
    +
    +
    +
    +
    + + + + + + + + + + + + + + + + +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    + + + + + + + + + + + +
    + + +
    +
    + +
    + + +
    +
    + +
    +
    +
    \ No newline at end of file diff --git a/apps/documenteditor/main/app/template/ImageSettings.template b/apps/documenteditor/main/app/template/ImageSettings.template index 8abc9eaf0..9fae4b54e 100644 --- a/apps/documenteditor/main/app/template/ImageSettings.template +++ b/apps/documenteditor/main/app/template/ImageSettings.template @@ -14,17 +14,17 @@ - + - + -
    +
    diff --git a/apps/documenteditor/main/app/template/Toolbar.template b/apps/documenteditor/main/app/template/Toolbar.template index c50e0c0e7..aba5de34a 100644 --- a/apps/documenteditor/main/app/template/Toolbar.template +++ b/apps/documenteditor/main/app/template/Toolbar.template @@ -108,6 +108,7 @@
    +
    diff --git a/apps/documenteditor/main/app/template/Viewport.template b/apps/documenteditor/main/app/template/Viewport.template index 40c1ea100..8d56d214c 100644 --- a/apps/documenteditor/main/app/template/Viewport.template +++ b/apps/documenteditor/main/app/template/Viewport.template @@ -9,7 +9,7 @@
    -
    +
    diff --git a/apps/documenteditor/main/app/view/AddNewCaptionLabelDialog.js b/apps/documenteditor/main/app/view/AddNewCaptionLabelDialog.js new file mode 100644 index 000000000..4ca86915e --- /dev/null +++ b/apps/documenteditor/main/app/view/AddNewCaptionLabelDialog.js @@ -0,0 +1,126 @@ +/* + * + * (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 + * +*/ +/** + * AddNewCaptionLabelDialog.js + * + * Created by Julia Svinareva on 03/10/19 + * Copyright (c) 2019 Ascensio System SIA. All rights reserved. + * + */ + +define([ + 'common/main/lib/component/Window', + 'common/main/lib/component/InputField' +], function () { 'use strict'; + + DE.Views.AddNewCaptionLabelDialog = Common.UI.Window.extend(_.extend({ + options: { + width: 330, + header: false, + cls: 'modal-dlg', + buttons: ['ok', 'cancel'] + }, + + initialize : function(options) { + _.extend(this.options, options || {}); + + this.template = [ + '
    ', + '
    ', + '', + '
    ', + '
    ', + '
    ' + ].join(''); + + this.options.tpl = _.template(this.template)(this.options); + + Common.UI.Window.prototype.initialize.call(this, this.options); + }, + + render: function() { + Common.UI.Window.prototype.render.call(this); + + var me = this; + me.inputLabel = new Common.UI.InputField({ + el : $('#id-dlg-label-caption'), + allowBlank : false, + blankError : me.textLabelError, + style : 'width: 100%;', + validateOnBlur: false, + validation : function(value) { + return value ? true : ''; + } + }); + + var $window = this.getChild(); + $window.find('.btn').on('click', _.bind(this.onBtnClick, this)); + }, + + show: function() { + Common.UI.Window.prototype.show.apply(this, arguments); + + var me = this; + _.delay(function(){ + me.getChild('input').focus(); + },50); + }, + + onPrimary: function(event) { + this._handleInput('ok'); + return false; + }, + + onBtnClick: function(event) { + this._handleInput(event.currentTarget.attributes['result'].value); + }, + + _handleInput: function(state) { + if (this.options.handler) { + if (state == 'ok') { + if (this.inputLabel.checkValidate() !== true) { + this.inputLabel.cmpEl.find('input').focus(); + return; + } + } + + this.options.handler.call(this, state, this.inputLabel.getValue()); + } + + this.close(); + }, + + textLabel: 'Label:', + textLabelError: 'Label must not be empty.' + }, DE.Views.AddNewCaptionLabelDialog || {})); +}); \ No newline at end of file diff --git a/apps/documenteditor/main/app/view/BookmarksDialog.js b/apps/documenteditor/main/app/view/BookmarksDialog.js index 60dea4536..9210e9648 100644 --- a/apps/documenteditor/main/app/view/BookmarksDialog.js +++ b/apps/documenteditor/main/app/view/BookmarksDialog.js @@ -110,7 +110,7 @@ define([ '
    ', '', '', - '