diff --git a/apps/common/main/lib/component/InputField.js b/apps/common/main/lib/component/InputField.js index 59b2ded54f..fecc5c2922 100644 --- a/apps/common/main/lib/component/InputField.js +++ b/apps/common/main/lib/component/InputField.js @@ -73,7 +73,8 @@ define([ validateOnChange: false, validateOnBlur: true, disabled: false, - editable: true + editable: true, + hideErrorOnInput: false }, template: _.template([ @@ -114,6 +115,7 @@ define([ this.validateOnChange = me.options.validateOnChange; this.validateOnBlur = me.options.validateOnBlur; this.maxLength = me.options.maxLength; + this.hideErrorOnInput = me.options.hideErrorOnInput; me.rendered = me.options.rendered || false; @@ -361,7 +363,12 @@ define([ if (modalParents.length > 0) { errorBadge.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10); } - + if (me.hideErrorOnInput) { + var onInputChanging = function() { + me.showError(); + }; + me._input.one('input', onInputChanging); + } return errors; } } else { @@ -391,6 +398,12 @@ define([ if (modalParents.length > 0) { errorBadge.data('bs.tooltip').tip().css('z-index', parseInt(modalParents.css('z-index')) + 10); } + if (me.hideErrorOnInput) { + var onInputChanging = function() { + me.showError(); + }; + me._input.one('input', onInputChanging); + } } else { me.cmpEl.removeClass('error'); me.cmpEl.removeClass('warning'); @@ -701,6 +714,8 @@ define([ options.btnHint = options.btnHint || this.textDate; Common.UI.InputFieldBtn.prototype.initialize.call(this, options); + + this.dateValue = undefined; }, render: function (parentEl) { @@ -725,18 +740,29 @@ define([ firstday: 1 }); me.cmpCalendar.on('date:click', function (cmp, date) { + me.dateValue = date; me.trigger('date:click', me, date); menu.hide(); }); + me.dateValue && me.cmpCalendar.setDate(me.dateValue); menu.alignPosition(); } me.cmpCalendar.focus(); - }) + }); + this._input.on('input', function() { + me.dateValue = undefined; + }); }, setDate: function(date) { - if (this.cmpCalendar && date && date instanceof Date && !isNaN(date)) + if (date && date instanceof Date && !isNaN(date)) { this.cmpCalendar && this.cmpCalendar.setDate(date); + this.dateValue = date; + } + }, + + getDate: function() { + return this.dateValue; }, textDate: 'Select date' diff --git a/apps/common/main/lib/view/DocumentPropertyDialog.js b/apps/common/main/lib/view/DocumentPropertyDialog.js new file mode 100644 index 0000000000..9768508def --- /dev/null +++ b/apps/common/main/lib/view/DocumentPropertyDialog.js @@ -0,0 +1,324 @@ +/* + * (c) Copyright Ascensio System SIA 2010-2024 + * + * This program is a free software product. You can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License (AGPL) + * version 3 as published by the Free Software Foundation. In accordance with + * Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect + * that Ascensio System SIA expressly excludes the warranty of non-infringement + * of any third-party rights. + * + * This program is distributed WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For + * details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html + * + * You can contact Ascensio System SIA at 20A-6 Ernesta Birznieka-Upish + * street, Riga, Latvia, EU, LV-1050. + * + * The interactive user interfaces in modified source and object code versions + * of the Program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU AGPL version 3. + * + * Pursuant to Section 7(b) of the License you must retain the original Product + * logo when distributing the program. Pursuant to Section 7(e) we decline to + * grant you any rights under trademark law for use of our trademarks. + * + * All the Product's GUI elements, including illustrations and icon sets, as + * well as technical writing content are licensed under the terms of the + * Creative Commons Attribution-ShareAlike 4.0 International. See the License + * terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode + * + */ + +define([], function () { 'use strict'; + + Common.Views.DocumentPropertyDialog = Common.UI.Window.extend(_.extend({ + options: { + width: 320, + cls: 'modal-dlg', + buttons: ['ok', 'cancel'] + }, + + initialize : function(options) { + _.extend(this.options, { + title: this.txtTitle, + defaultValue: {} + }, options); + + this.template = [ + '
', + '
', + '', + '
', + '
', + '
', + '', + '
', + '
', + '
', + '', + '
', + '
', + '
', + '
', + '
' + ].join(''); + + this.options.tpl = _.template(this.template)(this.options); + + this.asc2type = function(ascType) { + if (ascType === AscCommon.c_oVariantTypes.vtLpwstr) { + return 'text'; + } else if (ascType === AscCommon.c_oVariantTypes.vtI4 || ascType === AscCommon.c_oVariantTypes.vtR8) { + return 'number'; + } else if (ascType === AscCommon.c_oVariantTypes.vtBool) { + return 'boolean'; + } else if (ascType === AscCommon.c_oVariantTypes.vtFiletime) { + return 'date'; + } + } + + Common.UI.Window.prototype.initialize.call(this, this.options); + }, + + render: function() { + Common.UI.Window.prototype.render.call(this); + + var me = this; + this.inputTitle = new Common.UI.InputField({ + el: $('#id-dlg-title'), + allowBlank: false, + blankError: this.txtPropertyTitleBlankError, + validateOnBlur: false, + hideErrorOnInput: true, + validation: function(value) { + if (me.options.nameValidator !== undefined) { + return me.options.nameValidator(value); + } + } + }); + if (this.options.defaultValue.name) { + this.inputTitle.setValue(this.options.defaultValue.name); + } + + this.comboboxType = new Common.UI.ComboBox({ + el: $('#id-dlg-type'), + cls: 'input-group-nr', + menuStyle: 'min-width: 85px; width: 100%;', + editable: false, + data: [ + { displayValue: this.txtPropertyTypeText, value: 'text' }, + { displayValue: this.txtPropertyTypeNumber, value: 'number' }, + { displayValue: this.txtPropertyTypeDate, value: 'date' }, + { displayValue: this.txtPropertyTypeBoolean, value: 'boolean' } + ], + dataHint: '1', + dataHintDirection: 'bottom', + dataHintOffset: 'big', + ariaLabel: this.strLineHeight, + takeFocusOnClose: true + }); + var currentType = this.options.defaultValue.type ? this.asc2type(this.options.defaultValue.type) : 'text' + this.comboboxType.setValue(currentType); + this.comboboxType.on('selected', _.bind(function (cmb, record) { + this.inputTextOrNumber.setVisible(record.value === 'text' || record.value === 'number'); + this.comboboxBoolean.setVisible(record.value === 'boolean'); + this.datepicker.setVisible(record.value === 'date'); + }, this)) + + this.inputTextOrNumber = new Common.UI.InputField({ + el: $('#id-dlg-value-input'), + style: 'width: 100%;', + validateOnBlur: false, + hideErrorOnInput: true, + allowBlank: false, + blankError: this.txtPropertyValueBlankError, + validation: function(value) { + if (this.comboboxType.getValue() === 'number' && (typeof value !== 'number' && isNaN(value.replace(',', '.')))) { + return this.txtPropertyTypeNumberInvalid; + } + + return true; + }.bind(this) + }); + if (this.options.defaultValue.value && (currentType === 'text' || currentType === 'number')) { + this.inputTextOrNumber.setValue(this.options.defaultValue.value); + } + this.inputTextOrNumber.setVisible( + this.options.defaultValue.type + ? (this.options.defaultValue.type !== AscCommon.c_oVariantTypes.vtFiletime && this.options.defaultValue.type !== AscCommon.c_oVariantTypes.vtBool) + : (currentType === 'text' || currentType === 'number') + ); + + this.comboboxBoolean = new Common.UI.ComboBox({ + el: $('#id-dlg-value-boolean'), + cls: 'input-group-nr', + menuStyle: 'min-width: 85px; width: 100%;', + editable: false, + data: [ + { displayValue: this.txtPropertyBooleanTrue, value: 1 }, + { displayValue: this.txtPropertyBooleanFalse, value: 0 } + ], + dataHint: '1', + dataHintDirection: 'bottom', + dataHintOffset: 'big', + ariaLabel: this.strLineHeight, + takeFocusOnClose: true + }); + this.comboboxBoolean.setValue(this.options.defaultValue.value !== undefined && currentType === 'boolean' ? (this.options.defaultValue.value ? 1 : 0) : 1); + this.comboboxBoolean.setVisible(this.options.defaultValue.type ? this.options.defaultValue.type === AscCommon.c_oVariantTypes.vtBool : currentType === 'boolean'); + + this.datepicker = new Common.UI.InputFieldBtnCalendar({ + el: $('#id-dlg-value-date'), + allowBlank : false, + blankError : this.txtPropertyValueBlankError, + validateOnBlur: false, + value : '', + hideErrorOnInput: true, + dataHint : '1', + dataHintDirection: 'left', + dataHintOffset: 'small' + }); + if (this.options.defaultValue.value && currentType === 'date') { + this.datepicker.setDate(this.options.defaultValue.value); + this.datepicker.setValue(this.dateToString(this.options.defaultValue.value)); + } + this.datepicker.setVisible(this.options.defaultValue.type ? this.options.defaultValue.type === AscCommon.c_oVariantTypes.vtFiletime : currentType === 'date'); + this.datepicker.on('date:click', function (cmp, date) { + cmp.setValue(this.dateToString(date)); + }.bind(this)); + + var $window = this.getChild(); + $window.find('.dlg-btn').on('click', _.bind(this.onBtnClick, this)); + }, + + getFocusedComponents: function() { + return [this.inputTitle, this.comboboxType, this.inputTextOrNumber, this.comboboxBoolean, this.datepicker].concat(this.getFooterButtons()); + }, + + getDefaultFocusableComponent: function () { + return this.inputTitle; + }, + + show: function() { + Common.UI.Window.prototype.show.apply(this, arguments); + + var me = this; + _.delay(function(){ + me.inputTitle.focus(); + },100); + }, + + 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.inputTitle.checkValidate() !== true) { + this.inputTitle.focus(); + return; + } + + var title = this.inputTitle.getValue(), type = this.comboboxType.getValue(), ascValue, ascType; + if (type === 'boolean') { + ascValue = this.comboboxBoolean.getValue() === 1; + ascType = AscCommon.c_oVariantTypes.vtBool; + } else if (type === 'date') { + if (this.datepicker.checkValidate() !== true) { + this.datepicker.focus(); + return; + } + ascValue = this.datepicker.getDate(); + if (!ascValue) { + ascValue = new Date(this.datepicker.getValue()); + if (!ascValue || !(ascValue instanceof Date) || isNaN(ascValue)) + ascValue = undefined; + } + if (!ascValue) { + var me = this; + Common.UI.warning({ + msg: me.errorDate, + buttons: ['ok', 'cancel'], + callback: function(btn) { + if (btn==='ok') { + me.options.handler.call(this, state, title, AscCommon.c_oVariantTypes.vtLpwstr, me.datepicker.getValue()); + me.close(); + } else + me.datepicker.focus(); + } + }); + return; + } + ascType = AscCommon.c_oVariantTypes.vtFiletime; + } else { + if (this.inputTextOrNumber.checkValidate() !== true) { + this.inputTextOrNumber.focus(); + return; + } + + var value = this.inputTextOrNumber.getValue(); + if (type === 'text') { + ascType = AscCommon.c_oVariantTypes.vtLpwstr; + ascValue = value; + } else { + // note: precisely a numeric value because we validated it + if (typeof value !== 'number') { + value = value.replace(',', '.'); + } + + if (value % 1 === 0) { + ascType = AscCommon.c_oVariantTypes.vtI4; + ascValue = parseInt(value); + } else { + ascType = AscCommon.c_oVariantTypes.vtR8; + ascValue = parseFloat(value); + } + } + } + + this.options.handler.call(this, state, title, ascType, ascValue); + } + } + + this.close(); + }, + + dateToString: function (value) { + var text = ''; + if (value) { + value = new Date(value) + var lang = (this.options.lang || 'en').replace('_', '-').toLowerCase(); + try { + if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}); + } catch (e) { + lang = 'en'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}); + } + } + return text; + }, + + txtTitle: "New Document Property", + txtPropertyTitleLabel: "Title", + txtPropertyTitleBlankError: 'Property should have a title', + txtPropertyTypeLabel: "Type", + txtPropertyValueLabel: "Value", + txtPropertyValueBlankError: 'Property should have a value', + txtPropertyTypeText: "Text", + txtPropertyTypeNumber: "Number", + txtPropertyTypeNumberInvalid: 'Provide a valid number', + txtPropertyTypeDate: "Date", + txtPropertyTypeBoolean: '"Yes" or "no"', + txtPropertyBooleanTrue: 'Yes', + txtPropertyBooleanFalse: 'No', + errorDate: 'You can choose a value from the calendar to store the value as Date.
If you enter a value manually, it will be stored as Text.' + }, Common.Views.DocumentPropertyDialog || {})); +}); \ No newline at end of file diff --git a/apps/documenteditor/main/app/view/FileMenuPanels.js b/apps/documenteditor/main/app/view/FileMenuPanels.js index 90589082b5..662815d94c 100644 --- a/apps/documenteditor/main/app/view/FileMenuPanels.js +++ b/apps/documenteditor/main/app/view/FileMenuPanels.js @@ -1329,141 +1329,147 @@ define([], function () { this.rendered = false; this.template = _.template([ - '
', - '
' + this.txtDocumentInfo + '
', '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', // '', // '', // '', // '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', - '', - '', - '
' + this.txtDocumentInfo + '
', + '
', '', '', - '', + '', '', '
', - '
', - '
', - '
', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', '
', - '
' + '
', + '', + '', + '', + '', + '', + '
', + '', + '
', + '
', ].join('')); this.infoObj = {PageCount: 0, WordsCount: 0, ParagraphCount: 0, SymbolsCount: 0, SymbolsWSCount:0}; @@ -1521,7 +1527,11 @@ define([], function () { dataHintDirection: 'left', dataHintOffset: 'small', ariaLabel: this.txtTitle - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putTitle(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputTags = new Common.UI.InputField({ el : $markup.findById('#id-info-tags'), style : 'width: 200px;', @@ -1531,7 +1541,11 @@ define([], function () { dataHintDirection: 'left', dataHintOffset: 'small', ariaLabel: this.txtTags - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putKeywords(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputSubject = new Common.UI.InputField({ el : $markup.findById('#id-info-subject'), style : 'width: 200px;', @@ -1541,7 +1555,11 @@ define([], function () { dataHintDirection: 'left', dataHintOffset: 'small', ariaLabel: this.txtSubject - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putSubject(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputComment = new Common.UI.InputField({ el : $markup.findById('#id-info-comment'), style : 'width: 200px;', @@ -1551,7 +1569,10 @@ define([], function () { dataHintDirection: 'left', dataHintOffset: 'small', ariaLabel: this.txtComment - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putDescription(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); // modify info this.lblModifyDate = $markup.findById('#id-info-modify-date'); @@ -1562,7 +1583,7 @@ define([], function () { this.lblApplication = $markup.findById('#id-info-appname'); this.tblAuthor = $markup.findById('#id-info-author table'); this.trAuthor = $markup.findById('#id-info-add-author').closest('tr'); - this.authorTpl = '
'; + this.authorTpl = '
'; this.tblAuthor.on('click', function(e) { var btn = $markup.find(e.target); @@ -1571,6 +1592,8 @@ define([], function () { idx = me.tblAuthor.find('tr').index(el); el.remove(); me.authors.splice(idx, 1); + me.coreProps.asc_putCreator(me.authors.join(';')); + me.api.asc_setCoreProps(me.coreProps); me.updateScroller(true); } }); @@ -1603,6 +1626,9 @@ define([], function () { }); !isFromApply && me.inputAuthor.setValue(''); } + + me.coreProps.asc_putCreator(me.authors.join(';')); + me.api.asc_setCoreProps(me.coreProps); }).on('keydown:before', keyDownBefore); // pdf info @@ -1615,13 +1641,10 @@ define([], function () { this.lblPdfProducer = $markup.findById('#id-info-pdf-produce'); this.lblFastWV = $markup.findById('#id-info-fast-wv'); - this.btnApply = new Common.UI.Button({ - el: $markup.findById('#fminfo-btn-apply') + this.btnAddProperty = new Common.UI.Button({ + el: $markup.findById('#fminfo-btn-add-property') }); - this.btnApply.on('click', _.bind(this.applySettings, this)); - - this.pnlInfo = $markup.find('.flex-settings').addBack().filter('.flex-settings'); - this.pnlApply = $markup.findById('#fms-flex-apply'); + this.btnAddProperty.on('click', _.bind(this.onAddPropertyClick, this)); this.rendered = true; @@ -1630,8 +1653,7 @@ define([], function () { this.$el = $(node).html($markup); if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ - el: this.pnlInfo, - suppressScrollX: true, + el: this.$el, alwaysVisibleY: true }); } @@ -1663,7 +1685,7 @@ define([], function () { updateScroller: function(destroy) { if (this.scroller) { this.scroller.update(destroy ? {} : undefined); - this.pnlInfo.toggleClass('bordered', this.scroller.isVisible()); + // this.pnlInfo.toggleClass('bordered', this.scroller.isVisible()); } }, @@ -1707,19 +1729,12 @@ define([], function () { this.coreProps = (this.api) ? this.api.asc_getCoreProps() : null; if (this.coreProps) { var value = this.coreProps.asc_getCreated(); - if (value) { - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + this.lblDate.text(this.dateToString(value)); this._ShowHideInfoItem(this.lblDate, !!value); } else if (pdfProps) this.updatePdfInfo(pdfProps); + + this.renderCustomProperties(); }, updateFileInfo: function() { @@ -1734,17 +1749,7 @@ define([], function () { if (props) { var visible = false; value = props.asc_getModified(); - - if (value) { - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + this.lblModifyDate.text(this.dateToString(value)); visible = this._ShowHideInfoItem(this.lblModifyDate, !!value) || visible; value = props.asc_getLastModifiedBy(); if (value) @@ -1785,32 +1790,14 @@ define([], function () { if (props) { value = props.CreationDate; - if (value) { - value = new Date(value); - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + value && (value = new Date(value)); + this.lblDate.text(this.dateToString(value)); this._ShowHideInfoItem(this.lblDate, !!value); var visible = false; value = props.ModDate; - if (value) { - value = new Date(value); - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + value && (value = new Date(value)); + this.lblModifyDate.text(this.dateToString(value)); visible = this._ShowHideInfoItem(this.lblModifyDate, !!value) || visible; visible = this._ShowHideInfoItem(this.lblModifyBy, false) || visible; $('tr.divider.modify', this.el)[visible?'show':'hide'](); @@ -1910,7 +1897,7 @@ define([], function () { setMode: function(mode) { this.mode = mode; this.inputAuthor.setVisible(mode.isEdit); - this.pnlApply.toggleClass('hidden', !mode.isEdit); + this.btnAddProperty.setVisible(mode.isEdit); this.tblAuthor.find('.close').toggleClass('hidden', !mode.isEdit); this.inputTitle._input.attr('placeholder', mode.isEdit ? this.txtAddText : ''); this.inputTags._input.attr('placeholder', mode.isEdit ? this.txtAddText : ''); @@ -1967,6 +1954,94 @@ define([], function () { this.fillDocInfo(); }, + tplCustomProperty: function(name, type, value) { + if (type === AscCommon.c_oVariantTypes.vtBool) { + value = value ? this.txtYes : this.txtNo; + } else if (type === AscCommon.c_oVariantTypes.vtFiletime) { + value = this.dateToString(new Date(value), true); + } + + return '' + + '' + + '
' + + '' + + '
' + + '
'; + }, + + dateToString: function (value, hideTime) { + var text = ''; + if (value) { + var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); + try { + if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + (!hideTime ? ' ' + value.toLocaleString(lang, {timeStyle: 'short'}) : ''); + } catch (e) { + lang = 'en'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + (!hideTime ? ' ' + value.toLocaleString(lang, {timeStyle: 'short'}) : ''); + } + } + return text; + }, + + renderCustomProperties: function() { + if (!this.api) { + return; + } + + $('tr[data-custom-property]').remove(); + + var properties = this.api.asc_getAllCustomProperties(); + _.each(properties, _.bind(function(prop, idx) { + var me = this, name = prop.asc_getName(), type = prop.asc_getType(), value = prop.asc_getValue(); + var $propertyEl = $(this.tplCustomProperty(name, type, value)); + + $('tbody.properties-tab').append($propertyEl); + + $propertyEl.on('click', function (e) { + if ($propertyEl.find('div.disabled').length) { + return; + } + + var btn = $propertyEl.find(e.target); + if (btn.hasClass('close')) { + me.api.asc_removeCustomProperty(idx); + me.renderCustomProperties(); + } else if (btn.hasClass('form-control')) { + (new Common.Views.DocumentPropertyDialog({ + title: me.txtDocumentPropertyUpdateTitle, + lang: me.mode.lang, + defaultValue: { + name: name, + type: type, + value: value + }, + nameValidator: function(newName) { + if (newName !== name && _.some(properties, function (prop) { return prop.asc_getName() === newName; })) { + return me.txtPropertyTitleConflictError; + } + + return true; + }, + handler: function(result, name, type, value) { + if (result === 'ok') { + me.api.asc_modifyCustomProperty(idx, name, type, value); + me.renderCustomProperties(); + } + } + })).show(); + } + }); + }, this)); + }, + + setDisabledCustomProperties: function(disable) { + _.each($('tr[data-custom-property]'), function(prop) { + $(prop).find('div.custom-property-wrapper')[disable ? 'addClass' : 'removeClass']('disabled'); + $(prop).find('div.close')[disable ? 'hide' : 'show'](); + }) + }, + fillDocInfo: function() { this.lblStatPages.text(this.infoObj.PageCount); this.lblStatWords.text(this.infoObj.WordsCount); @@ -2004,19 +2079,29 @@ define([], function () { this.inputAuthor.setDisabled(disable); this.tblAuthor.find('.close').toggleClass('disabled', this._state._locked); this.tblAuthor.toggleClass('disabled', disable); - this.btnApply.setDisabled(this._state._locked); + this.btnAddProperty.setDisabled(disable); + this.setDisabledCustomProperties(disable); }, - applySettings: function() { - if (this.coreProps && this.api) { - this.coreProps.asc_putTitle(this.inputTitle.getValue()); - this.coreProps.asc_putKeywords(this.inputTags.getValue()); - this.coreProps.asc_putSubject(this.inputSubject.getValue()); - this.coreProps.asc_putDescription(this.inputComment.getValue()); - this.coreProps.asc_putCreator(this.authors.join(';')); - this.api.asc_setCoreProps(this.coreProps); - } - this.menu.hide(); + onAddPropertyClick: function() { + var me = this; + (new Common.Views.DocumentPropertyDialog({ + lang: me.mode.lang, + nameValidator: function(newName) { + var properties = me.api.asc_getAllCustomProperties(); + if (_.some(properties, function (prop) { return prop.asc_getName() === newName; })) { + return me.txtPropertyTitleConflictError; + } + + return true; + }, + handler: function(result, title, type, value) { + if (result === 'ok') { + me.api.asc_addCustomProperty(title, type, value); + me.renderCustomProperties(); + } + } + })).show(); }, txtPlacement: 'Location', @@ -2049,7 +2134,13 @@ define([], function () { txtYes: 'Yes', txtNo: 'No', txtPdfProducer: 'PDF Producer', - txtDocumentInfo: 'Document Info' + txtCommon: 'Common', + txtStatistics: 'Statistics', + txtProperties: 'Properties', + txtDocumentInfo: 'Document Info', + txtDocumentPropertyUpdateTitle: "Document Property", + txtPropertyTitleConflictError: 'Property with this title already exists', + txtAddProperty: 'Add property' }, DE.Views.FileMenuPanels.DocumentInfo || {})); diff --git a/apps/documenteditor/main/app_dev.js b/apps/documenteditor/main/app_dev.js index ca3c8005a2..0985ae77c2 100644 --- a/apps/documenteditor/main/app_dev.js +++ b/apps/documenteditor/main/app_dev.js @@ -222,6 +222,7 @@ require([ 'common/main/lib/view/TextInputDialog', 'common/main/lib/view/DocumentHolderExt', 'common/main/lib/util/define', + 'common/main/lib/view/DocumentPropertyDialog', 'documenteditor/main/app/view/FileMenuPanels', 'documenteditor/main/app/view/DocumentHolderExt', diff --git a/apps/documenteditor/main/app_pack.js b/apps/documenteditor/main/app_pack.js index 9938cf47e4..7dfe624408 100644 --- a/apps/documenteditor/main/app_pack.js +++ b/apps/documenteditor/main/app_pack.js @@ -27,6 +27,7 @@ require([ 'common/main/lib/view/LanguageDialog', 'common/main/lib/view/TextInputDialog', 'common/main/lib/view/DocumentHolderExt', + 'common/main/lib/view/DocumentPropertyDialog', 'documenteditor/main/app/view/FileMenuPanels', 'documenteditor/main/app/view/DocumentHolderExt', diff --git a/apps/documenteditor/main/locale/en.json b/apps/documenteditor/main/locale/en.json index b4f1d6820d..b5104ae9c2 100644 --- a/apps/documenteditor/main/locale/en.json +++ b/apps/documenteditor/main/locale/en.json @@ -827,6 +827,20 @@ "Common.Views.UserNameDialog.textDontShow": "Don't ask me again", "Common.Views.UserNameDialog.textLabel": "Label:", "Common.Views.UserNameDialog.textLabelError": "Label must not be empty.", + "Common.Views.DocumentPropertyDialog.txtTitle": "New Document Property", + "Common.Views.DocumentPropertyDialog.txtPropertyTitleLabel": "Title", + "Common.Views.DocumentPropertyDialog.txtPropertyTitleBlankError": "Property should have a title", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeLabel": "Type", + "Common.Views.DocumentPropertyDialog.txtPropertyValueLabel": "Value", + "Common.Views.DocumentPropertyDialog.txtPropertyValueBlankError": "Property should have a value", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeText": "Text", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeNumber": "Number", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeNumberInvalid": "Provide a valid number", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeDate": "Date", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeBoolean": "\"Yes\" or \"No\"", + "Common.Views.DocumentPropertyDialog.txtPropertyBooleanTrue": "Yes", + "Common.Views.DocumentPropertyDialog.txtPropertyBooleanFalse": "No", + "Common.Views.DocumentPropertyDialog.errorDate": "You can choose a value from the calendar to store the value as Date.
If you enter a value manually, it will be stored as Text.", "DE.Controllers.DocProtection.txtIsProtectedComment": "Document is protected. You may only insert comments to this document.", "DE.Controllers.DocProtection.txtIsProtectedForms": "Document is protected. You may only fill in forms in this document.", "DE.Controllers.DocProtection.txtIsProtectedTrack": "Document is protected. You may edit this document, but all changes will be tracked.", @@ -2176,6 +2190,11 @@ "DE.Views.FileMenuPanels.DocumentInfo.txtUploaded": "Uploaded", "DE.Views.FileMenuPanels.DocumentInfo.txtWords": "Words", "DE.Views.FileMenuPanels.DocumentInfo.txtYes": "Yes", + "DE.Views.FileMenuPanels.DocumentInfo.txtCommon": "Common", + "DE.Views.FileMenuPanels.DocumentInfo.txtProperties": "Properties", + "DE.Views.FileMenuPanels.DocumentInfo.txtDocumentPropertyUpdateTitle": "Document Property", + "DE.Views.FileMenuPanels.DocumentInfo.txtAddProperty": "Add property", + "DE.Views.FileMenuPanels.DocumentInfo.txtPropertyTitleConflictError": "Property with this title already exists", "DE.Views.FileMenuPanels.DocumentRights.txtAccessRights": "Access rights", "DE.Views.FileMenuPanels.DocumentRights.txtBtnAccessRights": "Change access rights", "DE.Views.FileMenuPanels.DocumentRights.txtRights": "Persons who have rights", diff --git a/apps/documenteditor/main/resources/less/filemenu.less b/apps/documenteditor/main/resources/less/filemenu.less index b50dfe6213..88dd527a88 100644 --- a/apps/documenteditor/main/resources/less/filemenu.less +++ b/apps/documenteditor/main/resources/less/filemenu.less @@ -54,7 +54,7 @@ .header { .font-size-very-huge(); - margin-bottom: 20px; + margin-bottom: 24px; } .format-items { @@ -184,8 +184,7 @@ } -#panel-settings, -#panel-info { +#panel-settings { #file-menu-panel & { padding: 0; display: flex; @@ -193,12 +192,148 @@ } } +#panel-info { + #file-menu-panel & { + padding: 30px; + + .flex-settings { + gap: 30px; + display: flex; + flex-direction: column; + } + } + + .header { + .font-size-very-huge(); + height: unset; + line-height: unset; + } + + table { + display: flex; + gap: 24px; + flex-direction: column; + + tr { + display: flex; + gap: 24px; + + td { + .font-size-normal(); + line-height: 16px; + + &.title { + line-height: 20px; + + label { + .font-size-huge(); + font-weight: 700; + } + } + + &.left { + width: 140px; + flex-shrink: 0; + } + + &.right { + flex-grow: 1; + } + } + + &.divider { + height: 10px; + } + } + + tbody { + display: flex; + gap: 12px; + flex-direction: column; + + &.properties-tab { + gap: 10px; + + tr { + gap: 20px; + } + + td { + height: unset; + } + + td.left { + display: flex; + align-items: center; + + label { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + } + } + + tr.author-info { + align-items: flex-start; + + td { + &.left { + height: 22px; + } + + display: flex; + gap: 5px; + align-items: center; + } + } + + .author-info tbody tr:last-child { + margin-bottom: 20px; + } + + &.main { + width: 100%; + } + } + + #fms-flex-add-property { + margin-top: 10px; + td { + height: unset; + } + } + + #fminfo-btn-add-property { + padding: 0; + border: 0; + background-color: transparent; + height: 24px; + + span { + text-decoration: underline dotted; + text-underline-offset: 4px; + } + } + + .custom-property-wrapper { + display: flex; + gap: 5px; + align-items: center; + } + + .tool.close:before, .tool.close:after { + margin-top: 2px; + } +} + #panel-settings { .header { - margin: 30px 0 16px 30px; + margin: 30px 0 18px 30px; .font-size-very-huge(); .rtl & { - margin: 30px 30px 16px 0; + margin: 30px 30px 18px 0; } } @@ -271,7 +406,7 @@ padding: 0 0 0 10px; white-space: nowrap; margin-top: 30px; - margin-bottom: 20px; + margin-bottom: 24px; .rtl & { padding: 0 10px 10px 0; @@ -562,18 +697,6 @@ } } -#panel-info { - .header { - margin: 30px 0 20px 30px; - .font-size-very-huge(); - - .rtl & { - margin: 30px 30px 20px 0; - } - } -} - -#panel-info, #panel-rights { table { tr { @@ -697,7 +820,7 @@ } #fms-btn-invisible-sign { - margin-bottom: 20px; + margin-bottom: 24px; } #id-fms-lbl-protect-header { diff --git a/apps/pdfeditor/main/app/view/FileMenuPanels.js b/apps/pdfeditor/main/app/view/FileMenuPanels.js index 0bdec32400..d1b8901d90 100644 --- a/apps/pdfeditor/main/app/view/FileMenuPanels.js +++ b/apps/pdfeditor/main/app/view/FileMenuPanels.js @@ -1121,130 +1121,129 @@ define([], function () { this.template = _.template([ '
', - '
' + this.txtDocumentInfo + '
', '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '',, + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', // '', // '', // '', // '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', '
' + this.txtDocumentInfo + '
', + '', + '', + '', + '', + '
', + '
', - '', - '', - '', - '', - '
', - '
', '
', '
', @@ -1400,7 +1399,6 @@ define([], function () { }); this.btnApply.on('click', _.bind(this.applySettings, this)); - this.pnlInfo = $markup.find('.flex-settings').addBack().filter('.flex-settings'); this.pnlApply = $markup.findById('#fms-flex-apply'); this.rendered = true; @@ -1410,7 +1408,7 @@ define([], function () { this.$el = $(node).html($markup); if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ - el: this.pnlInfo, + el: this.$el, suppressScrollX: true, alwaysVisibleY: true }); @@ -1443,7 +1441,6 @@ define([], function () { updateScroller: function(destroy) { if (this.scroller) { this.scroller.update(destroy ? {} : undefined); - this.pnlInfo.toggleClass('bordered', this.scroller.isVisible()); } }, @@ -1821,8 +1818,8 @@ define([], function () { txtYes: 'Yes', txtNo: 'No', txtPdfProducer: 'PDF Producer', - txtDocumentInfo: 'Document Info' - + txtDocumentInfo: 'Document Info', + txtCommon: 'Common', }, PDFE.Views.FileMenuPanels.DocumentInfo || {})); PDFE.Views.FileMenuPanels.DocumentRights = Common.UI.BaseView.extend(_.extend({ diff --git a/apps/pdfeditor/main/locale/en.json b/apps/pdfeditor/main/locale/en.json index 46d1f37259..914201154b 100644 --- a/apps/pdfeditor/main/locale/en.json +++ b/apps/pdfeditor/main/locale/en.json @@ -1285,6 +1285,7 @@ "PDFE.Views.FileMenuPanels.DocumentInfo.txtUploaded": "Uploaded", "PDFE.Views.FileMenuPanels.DocumentInfo.txtWords": "Words", "PDFE.Views.FileMenuPanels.DocumentInfo.txtYes": "Yes", + "PDFE.Views.FileMenuPanels.DocumentInfo.txtCommon": "Common", "PDFE.Views.FileMenuPanels.DocumentRights.txtAccessRights": "Access Rights", "PDFE.Views.FileMenuPanels.DocumentRights.txtBtnAccessRights": "Change access rights", "PDFE.Views.FileMenuPanels.DocumentRights.txtRights": "Persons who have rights", diff --git a/apps/pdfeditor/main/resources/less/filemenu.less b/apps/pdfeditor/main/resources/less/filemenu.less index b320f57796..f95520085a 100644 --- a/apps/pdfeditor/main/resources/less/filemenu.less +++ b/apps/pdfeditor/main/resources/less/filemenu.less @@ -59,7 +59,7 @@ .header { .font-size-very-huge(); - margin-bottom: 20px; + margin-bottom: 30px; } .format-items { @@ -188,8 +188,7 @@ } -#panel-settings, -#panel-info { +#panel-settings { #file-menu-panel & { padding: 0; display: flex; @@ -199,10 +198,10 @@ #panel-settings { .header { - margin: 30px 0 16px 30px; + margin: 30px 0 18px 30px; .font-size-very-huge(); .rtl & { - margin: 30px 30px 16px 0; + margin: 30px 30px 18px 0; } } @@ -288,7 +287,7 @@ padding: 0 0 0 10px; white-space: nowrap; margin-top: 30px; - margin-bottom: 20px; + margin-bottom: 30px; .rtl & { padding: 0 10px 10px 0; @@ -520,17 +519,71 @@ } #panel-info { + #file-menu-panel & { + padding: 30px; + + .flex-settings { + gap: 30px; + display: flex; + flex-direction: column; + } + } + .header { - margin: 30px 0 20px 30px; .font-size-very-huge(); + height: unset; + line-height: unset; + } - .rtl & { - margin: 30px 30px 20px 0; + table { + display: flex; + gap: 24px; + flex-direction: column; + + tr { + display: flex; + gap: 24px; + + td { + .font-size-normal(); + line-height: 16px; + + &.title { + line-height: 20px; + + label { + .font-size-huge(); + font-weight: 700; + } + } + + &.left { + width: 140px; + flex-shrink: 0; + } + + &.right { + flex-grow: 1; + } + } + + &.divider { + height: 10px; + } + } + + tbody { + display: flex; + gap: 12px; + flex-direction: column; + } + + &.main { + width: 100%; } } } -#panel-info, #panel-rights { table { tr { diff --git a/apps/presentationeditor/main/app/view/FileMenu.js b/apps/presentationeditor/main/app/view/FileMenu.js index 143ffad529..41c0b81956 100644 --- a/apps/presentationeditor/main/app/view/FileMenu.js +++ b/apps/presentationeditor/main/app/view/FileMenu.js @@ -42,7 +42,8 @@ define([ 'text!presentationeditor/main/app/template/FileMenu.template', 'underscore', 'common/main/lib/component/BaseView', - 'common/main/lib/view/RecentFiles' + 'common/main/lib/view/RecentFiles', + 'common/main/lib/component/Calendar' ], function (tpl, _) { 'use strict'; diff --git a/apps/presentationeditor/main/app/view/FileMenuPanels.js b/apps/presentationeditor/main/app/view/FileMenuPanels.js index b8514d18af..5271bcaa7d 100644 --- a/apps/presentationeditor/main/app/view/FileMenuPanels.js +++ b/apps/presentationeditor/main/app/view/FileMenuPanels.js @@ -1090,81 +1090,81 @@ define([], function () { this.rendered = false; this.template = _.template([ - '
', - '
' + this.txtPresentationInfo + '
', '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', // '', // '', // '', // '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', '
' + this.txtPresentationInfo + '
', - '', - '', - '', - '', - '
', - '
', + '', + '', + '', + '', + '
', + '
', - '
', - '
', - '', - '', + '
', + '
', + '', '', - '', + '', '', '
', + '', + '
', '
' @@ -1205,7 +1205,11 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putTitle(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputTags = new Common.UI.InputField({ el : $markup.findById('#id-info-tags'), style : 'width: 200px;', @@ -1214,7 +1218,11 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putKeywords(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputSubject = new Common.UI.InputField({ el : $markup.findById('#id-info-subject'), style : 'width: 200px;', @@ -1223,7 +1231,11 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putSubject(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputComment = new Common.UI.InputField({ el : $markup.findById('#id-info-comment'), style : 'width: 200px;', @@ -1232,7 +1244,10 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putDescription(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); // modify info this.lblModifyDate = $markup.findById('#id-info-modify-date'); @@ -1243,7 +1258,7 @@ define([], function () { this.lblApplication = $markup.findById('#id-info-appname'); this.tblAuthor = $markup.findById('#id-info-author table'); this.trAuthor = $markup.findById('#id-info-add-author').closest('tr'); - this.authorTpl = '
'; + this.authorTpl = '
'; this.tblAuthor.on('click', function(e) { var btn = $markup.find(e.target); @@ -1252,6 +1267,8 @@ define([], function () { idx = me.tblAuthor.find('tr').index(el); el.remove(); me.authors.splice(idx, 1); + me.coreProps.asc_putCreator(me.authors.join(';')); + me.api.asc_setCoreProps(me.coreProps); me.updateScroller(true); } }); @@ -1283,15 +1300,15 @@ define([], function () { }); !isFromApply && me.inputAuthor.setValue(''); } + + me.coreProps.asc_putCreator(me.authors.join(';')); + me.api.asc_setCoreProps(me.coreProps); }).on('keydown:before', keyDownBefore); - this.btnApply = new Common.UI.Button({ - el: $markup.findById('#fminfo-btn-apply') + this.btnAddProperty = new Common.UI.Button({ + el: $markup.findById('#fminfo-btn-add-property') }); - this.btnApply.on('click', _.bind(this.applySettings, this)); - - this.pnlInfo = $markup.find('.flex-settings').addBack().filter('.flex-settings'); - this.pnlApply = $markup.findById('#fms-flex-apply'); + this.btnAddProperty.on('click', _.bind(this.onAddPropertyClick, this)); this.rendered = true; @@ -1300,8 +1317,7 @@ define([], function () { this.$el = $(node).html($markup); if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ - el: this.pnlInfo, - suppressScrollX: true, + el: this.$el, alwaysVisibleY: true }); } @@ -1330,7 +1346,6 @@ define([], function () { updateScroller: function(destroy) { if (this.scroller) { this.scroller.update(destroy ? {} : undefined); - this.pnlInfo.toggleClass('bordered', this.scroller.isVisible()); } }, @@ -1368,18 +1383,11 @@ define([], function () { this.coreProps = (this.api) ? this.api.asc_getCoreProps() : null; if (this.coreProps) { var value = this.coreProps.asc_getCreated(); - if (value) { - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + this.lblDate.text(this.dateToString(value)); this._ShowHideInfoItem(this.lblDate, !!value); } + + this.renderCustomProperties(); }, updateFileInfo: function() { @@ -1402,16 +1410,7 @@ define([], function () { if (props) { var visible = false; value = props.asc_getModified(); - if (value) { - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + this.lblModifyDate.text(this.dateToString(value)); visible = this._ShowHideInfoItem(this.lblModifyDate, !!value) || visible; value = props.asc_getLastModifiedBy(); if (value) @@ -1443,6 +1442,115 @@ define([], function () { this.SetDisabled(); }, + tplCustomProperty: function(name, type, value) { + if (type === AscCommon.c_oVariantTypes.vtBool) { + value = value ? this.txtYes : this.txtNo; + } else if (type === AscCommon.c_oVariantTypes.vtFiletime) { + value = this.dateToString(new Date(value), true); + } + + return '' + + '' + + '
' + + '' + + '
' + + '
'; + }, + + dateToString: function (value, hideTime) { + var text = ''; + if (value) { + var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); + try { + if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + (!hideTime ? ' ' + value.toLocaleString(lang, {timeStyle: 'short'}) : ''); + } catch (e) { + lang = 'en'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + (!hideTime ? ' ' + value.toLocaleString(lang, {timeStyle: 'short'}) : ''); + } + } + return text; + }, + + renderCustomProperties: function() { + if (!this.api) { + return; + } + + $('tr[data-custom-property]').remove(); + + var properties = this.api.asc_getAllCustomProperties(); + _.each(properties, _.bind(function(prop, idx) { + var me = this, name = prop.asc_getName(), type = prop.asc_getType(), value = prop.asc_getValue(); + var $propertyEl = $(this.tplCustomProperty(name, type, value)); + + $('tbody.properties-tab').append($propertyEl); + + $propertyEl.on('click', function (e) { + if ($propertyEl.find('div.disabled').length) { + return; + } + + var btn = $propertyEl.find(e.target); + if (btn.hasClass('close')) { + me.api.asc_removeCustomProperty(idx); + me.renderCustomProperties(); + } else if (btn.hasClass('form-control')) { + (new Common.Views.DocumentPropertyDialog({ + title: me.txtDocumentPropertyUpdateTitle, + lang: me.mode.lang, + defaultValue: { + name: name, + type: type, + value: value + }, + nameValidator: function(newName) { + if (newName !== name && _.some(properties, function (prop) { return prop.asc_getName() === newName; })) { + return me.txtPropertyTitleConflictError; + } + + return true; + }, + handler: function(result, name, type, value) { + if (result === 'ok') { + me.api.asc_modifyCustomProperty(idx, name, type, value); + me.renderCustomProperties(); + } + } + })).show(); + } + }); + }, this)); + }, + + setDisabledCustomProperties: function(disable) { + _.each($('tr[data-custom-property]'), function(prop) { + $(prop).find('div.custom-property-wrapper')[disable ? 'addClass' : 'removeClass']('disabled'); + $(prop).find('div.close')[disable ? 'hide' : 'show'](); + }) + }, + + onAddPropertyClick: function() { + var me = this; + (new Common.Views.DocumentPropertyDialog({ + lang: me.mode.lang, + nameValidator: function(newName) { + var properties = me.api.asc_getAllCustomProperties(); + if (_.some(properties, function (prop) { return prop.asc_getName() === newName; })) { + return me.txtPropertyTitleConflictError; + } + + return true; + }, + handler: function(result, name, type, value) { + if (result === 'ok') { + me.api.asc_addCustomProperty(name, type, value); + me.renderCustomProperties(); + } + } + })).show(); + }, + _ShowHideInfoItem: function(el, visible) { el.closest('tr')[visible?'show':'hide'](); return visible; @@ -1457,7 +1565,7 @@ define([], function () { setMode: function(mode) { this.mode = mode; this.inputAuthor.setVisible(mode.isEdit); - this.pnlApply.toggleClass('hidden', !mode.isEdit); + this.btnAddProperty.setVisible(mode.isEdit); this.tblAuthor.find('.close').toggleClass('hidden', !mode.isEdit); if (!mode.isEdit) { this.inputTitle._input.attr('placeholder', ''); @@ -1491,19 +1599,8 @@ define([], function () { this.inputAuthor.setDisabled(disable); this.tblAuthor.find('.close').toggleClass('disabled', this._locked); this.tblAuthor.toggleClass('disabled', disable); - this.btnApply.setDisabled(this._locked); - }, - - applySettings: function() { - if (this.coreProps && this.api) { - this.coreProps.asc_putTitle(this.inputTitle.getValue()); - this.coreProps.asc_putKeywords(this.inputTags.getValue()); - this.coreProps.asc_putSubject(this.inputSubject.getValue()); - this.coreProps.asc_putDescription(this.inputComment.getValue()); - this.coreProps.asc_putCreator(this.authors.join(';')); - this.api.asc_setCoreProps(this.coreProps); - } - this.menu.hide(); + this.btnAddProperty.setDisabled(disable); + this.setDisabledCustomProperties(disable); }, txtPlacement: 'Location', @@ -1523,7 +1620,14 @@ define([], function () { txtAddText: 'Add Text', txtMinutes: 'min', okButtonText: 'Apply', - txtPresentationInfo: 'Info' + txtPresentationInfo: 'Presentation Info', + txtCommon: 'Common', + txtProperties: 'Properties', + txtDocumentPropertyUpdateTitle: "Document Property", + txtAddProperty: 'Add property', + txtYes: 'Yes', + txtNo: 'No', + txtPropertyTitleConflictError: 'Property with this title already exists', }, PE.Views.FileMenuPanels.DocumentInfo || {})); PE.Views.FileMenuPanels.DocumentRights = Common.UI.BaseView.extend(_.extend({ diff --git a/apps/presentationeditor/main/app_dev.js b/apps/presentationeditor/main/app_dev.js index ff23c32eed..818135e29f 100644 --- a/apps/presentationeditor/main/app_dev.js +++ b/apps/presentationeditor/main/app_dev.js @@ -219,6 +219,7 @@ require([ 'common/main/lib/util/define', 'common/main/lib/view/SignDialog', 'common/main/lib/view/ListSettingsDialog', + 'common/main/lib/view/DocumentPropertyDialog', 'presentationeditor/main/app/view/FileMenuPanels', 'presentationeditor/main/app/view/DocumentHolderExt', diff --git a/apps/presentationeditor/main/app_pack.js b/apps/presentationeditor/main/app_pack.js index 1894aef73d..22fcbeece5 100644 --- a/apps/presentationeditor/main/app_pack.js +++ b/apps/presentationeditor/main/app_pack.js @@ -25,6 +25,7 @@ require([ 'common/main/lib/view/DocumentHolderExt', 'common/main/lib/view/SignDialog', 'common/main/lib/view/ListSettingsDialog', + 'common/main/lib/view/DocumentPropertyDialog', 'presentationeditor/main/app/view/FileMenuPanels', 'presentationeditor/main/app/view/DocumentHolderExt', diff --git a/apps/presentationeditor/main/locale/en.json b/apps/presentationeditor/main/locale/en.json index 3a41b56f29..43b01850c9 100644 --- a/apps/presentationeditor/main/locale/en.json +++ b/apps/presentationeditor/main/locale/en.json @@ -890,6 +890,20 @@ "Common.Views.UserNameDialog.textDontShow": "Don't ask me again", "Common.Views.UserNameDialog.textLabel": "Label:", "Common.Views.UserNameDialog.textLabelError": "Label must not be empty.", + "Common.Views.DocumentPropertyDialog.txtTitle": "New Document Property", + "Common.Views.DocumentPropertyDialog.txtPropertyTitleLabel": "Title", + "Common.Views.DocumentPropertyDialog.txtPropertyTitleBlankError": "Property should have a title", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeLabel": "Type", + "Common.Views.DocumentPropertyDialog.txtPropertyValueLabel": "Value", + "Common.Views.DocumentPropertyDialog.txtPropertyValueBlankError": "Property should have a value", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeText": "Text", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeNumber": "Number", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeNumberInvalid": "Provide a valid number", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeDate": "Date", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeBoolean": "\"Yes\" or \"No\"", + "Common.Views.DocumentPropertyDialog.txtPropertyBooleanTrue": "Yes", + "Common.Views.DocumentPropertyDialog.txtPropertyBooleanFalse": "No", + "Common.Views.DocumentPropertyDialog.errorDate": "You can choose a value from the calendar to store the value as Date.
If you enter a value manually, it will be stored as Text.", "PE.Controllers.LeftMenu.leavePageText": "All unsaved changes in this document will be lost.
Click \"Cancel\" then \"Save\" to save them. Click \"OK\" to discard all the unsaved changes.", "PE.Controllers.LeftMenu.newDocumentTitle": "Unnamed presentation", "PE.Controllers.LeftMenu.notcriticalErrorTitle": "Warning", @@ -2033,6 +2047,13 @@ "PE.Views.FileMenuPanels.DocumentInfo.txtTags": "Tags", "PE.Views.FileMenuPanels.DocumentInfo.txtTitle": "Title", "PE.Views.FileMenuPanels.DocumentInfo.txtUploaded": "Uploaded", + "PE.Views.FileMenuPanels.DocumentInfo.txtYes": "Yes", + "PE.Views.FileMenuPanels.DocumentInfo.txtNo": "No", + "PE.Views.FileMenuPanels.DocumentInfo.txtCommon": "Common", + "PE.Views.FileMenuPanels.DocumentInfo.txtProperties": "Properties", + "PE.Views.FileMenuPanels.DocumentInfo.txtDocumentPropertyUpdateTitle": "Document Property", + "PE.Views.FileMenuPanels.DocumentInfo.txtAddProperty": "Add property", + "PE.Views.FileMenuPanels.DocumentInfo.txtPropertyTitleConflictError": "Property with this title already exists", "PE.Views.FileMenuPanels.DocumentRights.txtAccessRights": "Access rights", "PE.Views.FileMenuPanels.DocumentRights.txtBtnAccessRights": "Change access rights", "PE.Views.FileMenuPanels.DocumentRights.txtRights": "Persons who have rights", diff --git a/apps/presentationeditor/main/resources/less/app.less b/apps/presentationeditor/main/resources/less/app.less index 95b29c6312..88b31f122c 100644 --- a/apps/presentationeditor/main/resources/less/app.less +++ b/apps/presentationeditor/main/resources/less/app.less @@ -126,6 +126,7 @@ @import "../../../../common/main/resources/less/label.less"; @import "../../../../common/main/resources/less/bigscaling.less"; @import "../../../../common/main/resources/less/updown-picker.less"; +@import "../../../../common/main/resources/less/calendar.less"; // App // -------------------------------------------------- diff --git a/apps/presentationeditor/main/resources/less/leftmenu.less b/apps/presentationeditor/main/resources/less/leftmenu.less index dcdb8a37b5..e40513318f 100644 --- a/apps/presentationeditor/main/resources/less/leftmenu.less +++ b/apps/presentationeditor/main/resources/less/leftmenu.less @@ -145,7 +145,7 @@ .header { .font-size-very-huge(); - margin-bottom: 20px; + margin-bottom: 24px; } .format-items { @@ -177,8 +177,7 @@ } } - #panel-settings, - #panel-info { + #panel-settings { padding: 0; display: flex; flex-direction: column; @@ -186,10 +185,10 @@ #panel-settings { .header { - margin: 30px 0 16px 30px; + margin: 30px 0 18px 30px; .font-size-very-huge(); .rtl & { - margin: 30px 30px 16px 0; + margin: 30px 30px 18px 0; } } @@ -243,7 +242,7 @@ padding: 0 0 0 10px; white-space: nowrap; margin-top: 30px; - margin-bottom: 20px; + margin-bottom: 24px; .rtl & { padding: 0 10px 10px 0; @@ -513,17 +512,133 @@ } #panel-info { + padding: 30px; + .header { - margin: 30px 0 20px 30px; .font-size-very-huge(); + height: unset; + line-height: unset; + } - .rtl & { - margin: 30px 30px 20px 0; + table { + display: flex; + gap: 24px; + flex-direction: column; + + tr { + display: flex; + gap: 24px; + + td { + .font-size-normal(); + line-height: 16px; + + &.title { + line-height: 20px; + + label { + .font-size-huge(); + font-weight: 700; + } + } + + &.left { + width: 140px; + flex-shrink: 0; + } + + &.right { + flex-grow: 1; + } + } + + &.divider { + height: 10px; + } } + + tbody { + display: flex; + gap: 12px; + flex-direction: column; + + &.properties-tab { + gap: 10px; + + tr { + gap: 20px; + } + + td { + height: unset; + } + + td.left { + display: flex; + align-items: center; + + label { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + } + } + + tr.author-info { + align-items: flex-start; + + td { + &.left { + height: 22px; + } + + display: flex; + gap: 5px; + align-items: center; + } + } + + .author-info tbody tr:last-child { + margin-bottom: 20px; + } + + &.main { + width: 100%; + } + } + + #fms-flex-add-property { + margin-top: 10px; + td { + height: unset; + } + } + + #fminfo-btn-add-property { + padding: 0; + border: 0; + background-color: transparent; + height: 24px; + + span { + text-decoration: underline dotted; + text-underline-offset: 4px; + } + } + + .custom-property-wrapper { + display: flex; + gap: 5px; + align-items: center; + } + + .tool.close:before, .tool.close:after { + margin-top: 2px; } } - #panel-info, #panel-rights { table { tr { @@ -623,7 +738,7 @@ } #fms-btn-invisible-sign { - margin-bottom: 20px; + margin-bottom: 24px; } #id-fms-lbl-protect-header { diff --git a/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js b/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js index 2536c5647b..0a02351950 100644 --- a/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js +++ b/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js @@ -1599,9 +1599,10 @@ define([], function () { this.rendered = false; this.template = _.template([ - '
', - '
' + this.txtSpreadsheetInfo + '
', - '', + '
', + '', + '', + '', '', '', '', @@ -1614,26 +1615,6 @@ define([], function () { '', '', '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', - '', '', '', '', @@ -1642,8 +1623,6 @@ define([], function () { '', '', '', - '', - '', '', '', '', @@ -1652,9 +1631,12 @@ define([], function () { '', '', '', - '', - '', - '', + '', + '', + '', + '', + '', '', - '', - '
' + this.txtSpreadsheetInfo + '
', + '
', '', '', '', @@ -1662,17 +1644,34 @@ define([], function () { '
', '
', - '
', - '
', - '', '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '
', + '
', + '', + '', '', - '', + '', '', '
', + '', + '
', - '
' + '
', ].join('')); this.menu = options.menu; @@ -1710,7 +1709,11 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putTitle(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputTags = new Common.UI.InputField({ el : $markup.findById('#id-info-tags'), style : 'width: 200px;', @@ -1719,7 +1722,11 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putKeywords(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputSubject = new Common.UI.InputField({ el : $markup.findById('#id-info-subject'), style : 'width: 200px;', @@ -1728,7 +1735,11 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putSubject(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); + this.inputComment = new Common.UI.InputField({ el : $markup.findById('#id-info-comment'), style : 'width: 200px;', @@ -1737,7 +1748,10 @@ define([], function () { dataHint: '2', dataHintDirection: 'left', dataHintOffset: 'small' - }).on('keydown:before', keyDownBefore); + }).on('keydown:before', keyDownBefore).on('changed:after', function(_, newValue) { + me.coreProps.asc_putDescription(newValue); + me.api.asc_setCoreProps(me.coreProps); + }); // modify info this.lblModifyDate = $markup.findById('#id-info-modify-date'); @@ -1748,7 +1762,7 @@ define([], function () { this.lblApplication = $markup.findById('#id-info-appname'); this.tblAuthor = $markup.findById('#id-info-author table'); this.trAuthor = $markup.findById('#id-info-add-author').closest('tr'); - this.authorTpl = '
'; + this.authorTpl = '
'; this.tblAuthor.on('click', function(e) { var btn = $markup.find(e.target); @@ -1757,6 +1771,8 @@ define([], function () { idx = me.tblAuthor.find('tr').index(el); el.remove(); me.authors.splice(idx, 1); + me.coreProps.asc_putCreator(me.authors.join(';')); + me.api.asc_setCoreProps(me.coreProps); me.updateScroller(true); } }); @@ -1788,15 +1804,15 @@ define([], function () { }); !isFromApply && me.inputAuthor.setValue(''); } + + me.coreProps.asc_putCreator(me.authors.join(';')); + me.api.asc_setCoreProps(me.coreProps); }).on('keydown:before', keyDownBefore); - this.btnApply = new Common.UI.Button({ - el: $markup.findById('#fminfo-btn-apply') + this.btnAddProperty = new Common.UI.Button({ + el: $markup.findById('#fminfo-btn-add-property') }); - this.btnApply.on('click', _.bind(this.applySettings, this)); - - this.pnlInfo = $markup.find('.flex-settings').addBack().filter('.flex-settings'); - this.pnlApply = $markup.findById('#fms-flex-apply'); + this.btnAddProperty.on('click', _.bind(this.onAddPropertyClick, this)); this.rendered = true; @@ -1805,8 +1821,7 @@ define([], function () { this.$el = $(node).html($markup); if (_.isUndefined(this.scroller)) { this.scroller = new Common.UI.Scroller({ - el: this.pnlInfo, - suppressScrollX: true, + el: this.$el, alwaysVisibleY: true }); } @@ -1835,7 +1850,6 @@ define([], function () { updateScroller: function(destroy) { if (this.scroller) { this.scroller.update(destroy ? {} : undefined); - this.pnlInfo.toggleClass('bordered', this.scroller.isVisible()); } }, @@ -1873,18 +1887,11 @@ define([], function () { this.coreProps = (this.api) ? this.api.asc_getCoreProps() : null; if (this.coreProps) { var value = this.coreProps.asc_getCreated(); - if (value) { - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + this.lblDate.text(this.dateToString(value)); this._ShowHideInfoItem(this.lblDate, !!value); } + + this.renderCustomProperties(); }, updateFileInfo: function() { @@ -1907,16 +1914,7 @@ define([], function () { if (props) { var visible = false; value = props.asc_getModified(); - if (value) { - var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); - try { - if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } catch (e) { - lang = 'en'; - this.lblModifyDate.text(value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + ' ' + value.toLocaleString(lang, {timeStyle: 'short'})); - } - } + this.lblModifyDate.text(this.dateToString(value)); visible = this._ShowHideInfoItem(this.lblModifyDate, !!value) || visible; value = props.asc_getLastModifiedBy(); if (value) @@ -1962,7 +1960,7 @@ define([], function () { setMode: function(mode) { this.mode = mode; this.inputAuthor.setVisible(mode.isEdit); - this.pnlApply.toggleClass('hidden', !mode.isEdit); + this.btnAddProperty.setVisible(mode.isEdit); this.tblAuthor.find('.close').toggleClass('hidden', !mode.isEdit); if (!mode.isEdit) { this.inputTitle._input.attr('placeholder', ''); @@ -1987,6 +1985,115 @@ define([], function () { this.updateFileInfo(); }, + tplCustomProperty: function(name, type, value) { + if (type === AscCommon.c_oVariantTypes.vtBool) { + value = value ? this.txtYes : this.txtNo; + } else if (type === AscCommon.c_oVariantTypes.vtFiletime) { + value = this.dateToString(new Date(value), true); + } + + return '' + + '' + + '
' + + '' + + '
' + + '
'; + }, + + dateToString: function (value, hideTime) { + var text = ''; + if (value) { + var lang = (this.mode.lang || 'en').replace('_', '-').toLowerCase(); + try { + if ( lang == 'ar-SA'.toLowerCase() ) lang = lang + '-u-nu-latn-ca-gregory'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + (!hideTime ? ' ' + value.toLocaleString(lang, {timeStyle: 'short'}) : ''); + } catch (e) { + lang = 'en'; + text = value.toLocaleString(lang, {year: 'numeric', month: '2-digit', day: '2-digit'}) + (!hideTime ? ' ' + value.toLocaleString(lang, {timeStyle: 'short'}) : ''); + } + } + return text; + }, + + renderCustomProperties: function() { + if (!this.api) { + return; + } + + $('tr[data-custom-property]').remove(); + + var properties = this.api.asc_getAllCustomProperties(); + _.each(properties, _.bind(function(prop, idx) { + var me = this, name = prop.asc_getName(), type = prop.asc_getType(), value = prop.asc_getValue(); + var $propertyEl = $(this.tplCustomProperty(name, type, value)); + + $('tbody.properties-tab').append($propertyEl); + + $propertyEl.on('click', function (e) { + if ($propertyEl.find('div.disabled').length) { + return; + } + + var btn = $propertyEl.find(e.target); + if (btn.hasClass('close')) { + me.api.asc_removeCustomProperty(idx); + me.renderCustomProperties(); + } else if (btn.hasClass('form-control')) { + (new Common.Views.DocumentPropertyDialog({ + title: me.txtDocumentPropertyUpdateTitle, + lang: me.mode.lang, + defaultValue: { + name: name, + type: type, + value: value + }, + nameValidator: function(newName) { + if (newName !== name && _.some(properties, function (prop) { return prop.asc_getName() === newName; })) { + return me.txtPropertyTitleConflictError; + } + + return true; + }, + handler: function(result, name, type, value) { + if (result === 'ok') { + me.api.asc_modifyCustomProperty(idx, name, type, value); + me.renderCustomProperties(); + } + } + })).show(); + } + }); + }, this)); + }, + + setDisabledCustomProperties: function(disable) { + _.each($('tr[data-custom-property]'), function(prop) { + $(prop).find('div.custom-property-wrapper')[disable ? 'addClass' : 'removeClass']('disabled'); + $(prop).find('div.close')[disable ? 'hide' : 'show'](); + }) + }, + + onAddPropertyClick: function() { + var me = this; + (new Common.Views.DocumentPropertyDialog({ + lang: me.mode.lang, + nameValidator: function(newName) { + var properties = me.api.asc_getAllCustomProperties(); + if (_.some(properties, function (prop) { return prop.asc_getName() === newName; })) { + return me.txtPropertyTitleConflictError; + } + + return true; + }, + handler: function(result, name, type, value) { + if (result === 'ok') { + me.api.asc_addCustomProperty(name, type, value); + me.renderCustomProperties(); + } + } + })).show(); + }, + SetDisabled: function() { var disable = !this.mode.isEdit || this._locked; this.inputTitle.setDisabled(disable); @@ -1996,19 +2103,8 @@ define([], function () { this.inputAuthor.setDisabled(disable); this.tblAuthor.find('.close').toggleClass('disabled', this._locked); this.tblAuthor.toggleClass('disabled', disable); - this.btnApply.setDisabled(this._locked); - }, - - applySettings: function() { - if (this.coreProps && this.api) { - this.coreProps.asc_putTitle(this.inputTitle.getValue()); - this.coreProps.asc_putKeywords(this.inputTags.getValue()); - this.coreProps.asc_putSubject(this.inputSubject.getValue()); - this.coreProps.asc_putDescription(this.inputComment.getValue()); - this.coreProps.asc_putCreator(this.authors.join(';')); - this.api.asc_setCoreProps(this.coreProps); - } - this.menu.hide(); + this.btnAddProperty.setDisabled(disable); + this.setDisabledCustomProperties(disable); }, txtPlacement: 'Location', @@ -2027,7 +2123,14 @@ define([], function () { txtAddText: 'Add Text', txtMinutes: 'min', okButtonText: 'Apply', - txtSpreadsheetInfo: 'Spreadsheet Info' + txtSpreadsheetInfo: 'Spreadsheet Info', + txtCommon: 'Common', + txtProperties: 'Properties', + txtDocumentPropertyUpdateTitle: "Document Property", + txtAddProperty: 'Add property', + txtYes: 'Yes', + txtNo: 'No', + txtPropertyTitleConflictError: 'Property with this title already exists', }, SSE.Views.FileMenuPanels.DocumentInfo || {})); SSE.Views.FileMenuPanels.DocumentRights = Common.UI.BaseView.extend(_.extend({ diff --git a/apps/spreadsheeteditor/main/app_dev.js b/apps/spreadsheeteditor/main/app_dev.js index d2e8c6f946..083f59cacc 100644 --- a/apps/spreadsheeteditor/main/app_dev.js +++ b/apps/spreadsheeteditor/main/app_dev.js @@ -218,6 +218,7 @@ require([ 'common/main/lib/util/define', 'common/main/lib/view/SignDialog', 'common/main/lib/view/SignSettingsDialog', + 'common/main/lib/view/DocumentPropertyDialog', 'spreadsheeteditor/main/app/view/FileMenuPanels', 'spreadsheeteditor/main/app/view/DocumentHolderExt', diff --git a/apps/spreadsheeteditor/main/app_pack.js b/apps/spreadsheeteditor/main/app_pack.js index 7a4013bc3e..fab57163a2 100644 --- a/apps/spreadsheeteditor/main/app_pack.js +++ b/apps/spreadsheeteditor/main/app_pack.js @@ -24,6 +24,7 @@ require([ 'common/main/lib/view/DocumentHolderExt', 'common/main/lib/view/SignDialog', 'common/main/lib/view/SignSettingsDialog', + 'common/main/lib/view/DocumentPropertyDialog', 'spreadsheeteditor/main/app/view/FileMenuPanels', 'spreadsheeteditor/main/app/view/DocumentHolderExt', diff --git a/apps/spreadsheeteditor/main/locale/en.json b/apps/spreadsheeteditor/main/locale/en.json index 29cb15cfe9..c9be6e5766 100644 --- a/apps/spreadsheeteditor/main/locale/en.json +++ b/apps/spreadsheeteditor/main/locale/en.json @@ -749,6 +749,20 @@ "Common.Views.UserNameDialog.textDontShow": "Don't ask me again", "Common.Views.UserNameDialog.textLabel": "Label:", "Common.Views.UserNameDialog.textLabelError": "Label must not be empty.", + "Common.Views.DocumentPropertyDialog.txtTitle": "New Document Property", + "Common.Views.DocumentPropertyDialog.txtPropertyTitleLabel": "Title", + "Common.Views.DocumentPropertyDialog.txtPropertyTitleBlankError": "Property should have a title", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeLabel": "Type", + "Common.Views.DocumentPropertyDialog.txtPropertyValueLabel": "Value", + "Common.Views.DocumentPropertyDialog.txtPropertyValueBlankError": "Property should have a value", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeText": "Text", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeNumber": "Number", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeNumberInvalid": "Provide a valid number", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeDate": "Date", + "Common.Views.DocumentPropertyDialog.txtPropertyTypeBoolean": "\"Yes\" or \"No\"", + "Common.Views.DocumentPropertyDialog.txtPropertyBooleanTrue": "Yes", + "Common.Views.DocumentPropertyDialog.txtPropertyBooleanFalse": "No", + "Common.Views.DocumentPropertyDialog.errorDate": "You can choose a value from the calendar to store the value as Date.
If you enter a value manually, it will be stored as Text.", "SSE.Controllers.DataTab.strSheet": "Sheet", "SSE.Controllers.DataTab.textAddExternalData": "The link to an external source has been added. You can update such links in the Data tab.", "SSE.Controllers.DataTab.textColumns": "Columns", @@ -2640,6 +2654,13 @@ "SSE.Views.FileMenuPanels.DocumentInfo.txtTags": "Tags", "SSE.Views.FileMenuPanels.DocumentInfo.txtTitle": "Title", "SSE.Views.FileMenuPanels.DocumentInfo.txtUploaded": "Uploaded", + "SSE.Views.FileMenuPanels.DocumentInfo.txtYes": "Yes", + "SSE.Views.FileMenuPanels.DocumentInfo.txtNo": "No", + "SSE.Views.FileMenuPanels.DocumentInfo.txtCommon": "Common", + "SSE.Views.FileMenuPanels.DocumentInfo.txtProperties": "Properties", + "SSE.Views.FileMenuPanels.DocumentInfo.txtDocumentPropertyUpdateTitle": "Document Property", + "SSE.Views.FileMenuPanels.DocumentInfo.txtAddProperty": "Add property", + "SSE.Views.FileMenuPanels.DocumentInfo.txtPropertyTitleConflictError": "Property with this title already exists", "SSE.Views.FileMenuPanels.DocumentRights.txtAccessRights": "Access Rights", "SSE.Views.FileMenuPanels.DocumentRights.txtBtnAccessRights": "Change access rights", "SSE.Views.FileMenuPanels.DocumentRights.txtRights": "Persons who have rights", diff --git a/apps/spreadsheeteditor/main/resources/less/leftmenu.less b/apps/spreadsheeteditor/main/resources/less/leftmenu.less index 6f60c576e6..5d6a613446 100644 --- a/apps/spreadsheeteditor/main/resources/less/leftmenu.less +++ b/apps/spreadsheeteditor/main/resources/less/leftmenu.less @@ -148,7 +148,7 @@ .header { .font-size-very-huge(); - margin-bottom: 20px; + margin-bottom: 24px; } .format-items { @@ -181,17 +181,130 @@ } #panel-info { - padding: 0; - display: flex; - flex-direction: column; + padding: 30px; .header { - margin: 30px 0 20px 30px; .font-size-very-huge(); + height: unset; + line-height: unset; + } - .rtl & { - margin: 30px 30px 20px 0; + table { + display: flex; + gap: 24px; + flex-direction: column; + + tr { + display: flex; + gap: 24px; + + td { + .font-size-normal(); + line-height: 16px; + + &.title { + line-height: 20px; + + label { + .font-size-huge(); + font-weight: 700; + } + } + + &.left { + width: 140px; + flex-shrink: 0; + } + + &.right { + flex-grow: 1; + } + } + + &.divider { + height: 10px; + } } + + tbody { + display: flex; + gap: 12px; + flex-direction: column; + + &.properties-tab { + gap: 10px; + + tr { + gap: 20px; + } + + td { + height: unset; + } + + td.left { + display: flex; + align-items: center; + + label { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + } + } + } + + tr.author-info { + align-items: flex-start; + + td { + &.left { + height: 22px; + } + + display: flex; + gap: 5px; + align-items: center; + } + } + + .author-info tbody tr:last-child { + margin-bottom: 20px; + } + + &.main { + width: 100%; + } + } + + #fms-flex-add-property { + margin-top: 10px; + td { + height: unset; + } + } + + #fminfo-btn-add-property { + padding: 0; + border: 0; + background-color: transparent; + height: 24px; + + span { + text-decoration: underline dotted; + text-underline-offset: 4px; + } + } + + .custom-property-wrapper { + display: flex; + gap: 5px; + align-items: center; + } + + .tool.close:before, .tool.close:after { + margin-top: 2px; } } @@ -201,10 +314,10 @@ flex-direction: column; .header { - margin: 30px 0 16px 30px; + margin: 30px 0 18px 30px; .font-size-very-huge(); .rtl & { - margin: 30px 30px 16px 0; + margin: 30px 30px 18px 0; } } @@ -347,7 +460,7 @@ padding: 0 0 0 10px; white-space: nowrap; margin-top: 30px; - margin-bottom: 20px; + margin-bottom: 24px; .rtl & { padding: 0 10px 0 0; @@ -613,7 +726,6 @@ } } - #panel-info, #panel-rights { table { tr { @@ -713,7 +825,7 @@ } #fms-btn-invisible-sign { - margin-bottom: 20px; + margin-bottom: 24px; } #id-fms-lbl-protect-header {