diff --git a/apps/api/documents/api.js b/apps/api/documents/api.js index 0c1ec666e..50848e08f 100644 --- a/apps/api/documents/api.js +++ b/apps/api/documents/api.js @@ -199,6 +199,8 @@ _config.editorConfig.canRequestClose = _config.events && !!_config.events.onRequestClose; _config.editorConfig.canRename = _config.events && !!_config.events.onRequestRename; _config.editorConfig.canMakeActionLink = _config.events && !!_config.events.onMakeActionLink; + _config.editorConfig.canRequestUsers = _config.events && !!_config.events.onRequestUsers; + _config.editorConfig.canRequestSendNotify = _config.events && !!_config.events.onRequestSendNotify; _config.editorConfig.mergeFolderUrl = _config.editorConfig.mergeFolderUrl || _config.editorConfig.saveAsUrl; _config.frameEditorId = placeholderId; @@ -537,6 +539,27 @@ }); }; + var _setUsers = function(data) { + _sendCommand({ + command: 'setUsers', + data: data + }); + }; + + var _showSharingSettings = function(data) { + _sendCommand({ + command: 'showSharingSettings', + data: data + }); + }; + + var _setSharingSettings = function(data) { + _sendCommand({ + command: 'setSharingSettings', + data: data + }); + }; + var _processMouse = function(evt) { var r = iframe.getBoundingClientRect(); var data = { @@ -576,7 +599,10 @@ serviceCommand : _serviceCommand, attachMouseEvents : _attachMouseEvents, detachMouseEvents : _detachMouseEvents, - destroyEditor : _destroyEditor + destroyEditor : _destroyEditor, + setUsers : _setUsers, + showSharingSettings : _showSharingSettings, + setSharingSettings : _setSharingSettings } }; diff --git a/apps/common/Gateway.js b/apps/common/Gateway.js index a906dedba..373c41e58 100644 --- a/apps/common/Gateway.js +++ b/apps/common/Gateway.js @@ -98,6 +98,18 @@ if (Common === undefined) { 'resetFocus': function(data) { $me.trigger('resetfocus', data); + }, + + 'setUsers': function(data) { + $me.trigger('setusers', data); + }, + + 'showSharingSettings': function(data) { + $me.trigger('showsharingsettings', data); + }, + + 'setSharingSettings': function(data) { + $me.trigger('setsharingsettings', data); } }; @@ -262,6 +274,14 @@ if (Common === undefined) { _postMessage({event:'onMakeActionLink', data: config}) }, + requestUsers: function () { + _postMessage({event:'onRequestUsers'}) + }, + + requestSendNotify: function (emails) { + _postMessage({event:'onRequestSendNotify', data: emails}) + }, + on: function(event, handler){ var localHandler = function(event, data){ handler.call(me, data) diff --git a/apps/common/main/lib/component/Menu.js b/apps/common/main/lib/component/Menu.js index 2e47fffdb..bb04c6b57 100644 --- a/apps/common/main/lib/component/Menu.js +++ b/apps/common/main/lib/component/Menu.js @@ -504,7 +504,7 @@ define([ return this.offset; }, - alignPosition: function() { + alignPosition: function(fixedAlign, fixedOffset) { var menuRoot = this.menuRoot, menuParent = this.menuAlignEl || menuRoot.parent(), m = this.menuAlign.match(/^([a-z]+)-([a-z]+)/), @@ -553,8 +553,13 @@ define([ } } } else { - if (top + menuH > docH) - top = docH - menuH; + if (top + menuH > docH) { + if (fixedAlign && typeof fixedAlign == 'string') { // how to align if menu height > window height + m = fixedAlign.match(/^([a-z]+)-([a-z]+)/); + top = offset.top - posMenu[m[1]][1] + posParent[m[2]][1] + this.offset[1] + (fixedOffset || 0); + } else + top = docH - menuH; + } if (top < 0) top = 0; diff --git a/apps/common/main/lib/controller/Comments.js b/apps/common/main/lib/controller/Comments.js index cbef9afe9..5831c62b6 100644 --- a/apps/common/main/lib/controller/Comments.js +++ b/apps/common/main/lib/controller/Comments.js @@ -495,6 +495,7 @@ define([ ascComment.asc_addReply(addReply); me.api.asc_changeComment(id, ascComment); + me.mode && me.mode.canRequestUsers && me.view.pickEMail(id, replyVal); return true; } @@ -1125,7 +1126,9 @@ define([ if (_.isUndefined(this.popover)) { this.popover = Common.Views.ReviewPopover.prototype.getPopover({ commentsStore : this.popoverComments, - renderTo : this.sdkViewName + renderTo : this.sdkViewName, + canRequestUsers: (this.mode) ? this.mode.canRequestUsers : undefined, + canRequestSendNotify: (this.mode) ? this.mode.canRequestSendNotify : undefined }); this.popover.setCommentsStore(this.popoverComments); } @@ -1343,9 +1346,9 @@ define([ if (!_.isUndefined(comment.asc_putDocumentFlag)) comment.asc_putDocumentFlag(false); - this.api.asc_addComment(comment); + var commentId = this.api.asc_addComment(comment); this.view.showEditContainer(false); - + this.mode && this.mode.canRequestUsers && this.view.pickEMail(commentId, commentVal); if (!_.isUndefined(this.api.asc_SetDocumentPlaceChangedEnabled)) { this.api.asc_SetDocumentPlaceChangedEnabled(false); } diff --git a/apps/common/main/lib/controller/Fonts.js b/apps/common/main/lib/controller/Fonts.js index 570f000e2..a20c68604 100644 --- a/apps/common/main/lib/controller/Fonts.js +++ b/apps/common/main/lib/controller/Fonts.js @@ -48,10 +48,10 @@ define([ 'common/main/lib/collection/Fonts' ], function () { 'use strict'; Common.Controllers.Fonts = Backbone.Controller.extend((function() { - var FONT_TYPE_USERUSED = 4; + var FONT_TYPE_RECENT = 4; function isFontSaved(store, rec) { - var out = rec.get('type') == FONT_TYPE_USERUSED, + var out = rec.get('type') == FONT_TYPE_RECENT, i = -1, c = store.length, su, @@ -59,7 +59,7 @@ define([ while (!out && ++i < c) { su = store.at(i); - if (su.get('type') != FONT_TYPE_USERUSED) + if (su.get('type') != FONT_TYPE_RECENT) break; out = su.get('name') == n; @@ -78,7 +78,7 @@ define([ // name: data.name, // imgidx: data.imgidx, // cloneid: node.querySelector('img').id, -// type: FONT_TYPE_USERUSED +// type: FONT_TYPE_RECENT // }; // combo.getStore().insert(0,[font]); // @@ -93,7 +93,7 @@ define([ // } // // font = combo.getStore().getAt(5); -// if (font.data.type==FONT_TYPE_USERUSED) { +// if (font.data.type==FONT_TYPE_RECENT) { // combo.getStore().remove(font); // } else { // var plugin = combo.getPlugin('scrollpane'); diff --git a/apps/common/main/lib/template/CommentsPopover.template b/apps/common/main/lib/template/CommentsPopover.template index 45b112b7d..78f0d4a5a 100644 --- a/apps/common/main/lib/template/CommentsPopover.template +++ b/apps/common/main/lib/template/CommentsPopover.template @@ -10,7 +10,7 @@
<%=scope.pickLink(comment)%>
<% } else { %>
- + <% if (hideAddReply) { %> <% } else { %> diff --git a/apps/common/main/lib/util/utils.js b/apps/common/main/lib/util/utils.js index f0efcb44e..b6c6a353b 100644 --- a/apps/common/main/lib/util/utils.js +++ b/apps/common/main/lib/util/utils.js @@ -90,6 +90,7 @@ Common.Utils = _.extend(new(function() { hostnameRe = /^(((https?)|(ftps?)):\/\/)?([\-\wа-яё]*:?[\-\wа-яё]*@)?(([\-\wа-яё]+\.)+[\wа-яё\-]{2,}(:\d+)?(\/[%\-\wа-яё]*(\.[\wа-яё]{2,})?(([\wа-яё\-\.\?\\\/+@&#;:`'~=%!,\(\)]*)(\.[\wа-яё]{2,})?)*)*\/?)/i, localRe = /^(((https?)|(ftps?)):\/\/)([\-\wа-яё]*:?[\-\wа-яё]*@)?(([\-\wа-яё]+)(:\d+)?(\/[%\-\wа-яё]*(\.[\wа-яё]{2,})?(([\wа-яё\-\.\?\\\/+@&#;:`'~=%!,\(\)]*)(\.[\wа-яё]{2,})?)*)*\/?)/i, emailStrongRe = /(mailto:)?([a-z0-9'\._-]+@[a-z0-9\.-]+\.[a-z0-9]{2,4})([a-яё0-9\._%+-=\?:&]*)/ig, + emailAddStrongRe = /(mailto:|\s[@]|\s[+])?([a-z0-9'\._-]+@[a-z0-9\.-]+\.[a-z0-9]{2,4})([a-яё0-9\._%+-=\?:&]*)/ig, ipStrongRe = /(((https?)|(ftps?)):\/\/([\-\wа-яё]*:?[\-\wа-яё]*@)?)(((1[0-9]{2}|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9])\.){3}(1[0-9]{2}|2[0-4][0-9]|25[0-5]|[1-9][0-9]|[0-9]))(:\d+)?(\/[%\-\wа-яё]*(\.[\wа-яё]{2,})?(([\wа-яё\-\.\?\\\/+@&#;:`~=%!,\(\)]*)(\.[\wа-яё]{2,})?)*)*\/?/ig, hostnameStrongRe = /((((https?)|(ftps?)):\/\/([\-\wа-яё]*:?[\-\wа-яё]*@)?)|(([\-\wа-яё]*:?[\-\wа-яё]*@)?www\.))((([\-\wа-яё]+\.)+[\wа-яё\-]{2,}|([\-\wа-яё]+))(:\d+)?(\/[%\-\wа-яё]*(\.[\wа-яё]{2,})?(([\wа-яё\-\.\?\\\/+@&#;:`~=%!,\(\)]*)(\.[\wа-яё]{2,})?)*)*\/?)/ig, documentSettingsType = { @@ -207,6 +208,7 @@ Common.Utils = _.extend(new(function() { hostnameRe: hostnameRe, localRe: localRe, emailStrongRe: emailStrongRe, + emailAddStrongRe: emailAddStrongRe, ipStrongRe: ipStrongRe, hostnameStrongRe: hostnameStrongRe, documentSettingsType: documentSettingsType, diff --git a/apps/common/main/lib/view/Comments.js b/apps/common/main/lib/view/Comments.js index 5d4619ee0..688f756ee 100644 --- a/apps/common/main/lib/view/Comments.js +++ b/apps/common/main/lib/view/Comments.js @@ -700,6 +700,24 @@ define([ return str_res; }, + pickEMail: function (commentId, message) { + var arr = Common.Utils.String.htmlEncode(message).match(/\B[@+][A-Z0-9._%+-]+@[A-Z0-9._]+\.[A-Z]+\b/gi); + arr = _.map(arr, function(str){ + return str.slice(1, str.length); + }); + Common.Gateway.requestSendNotify({ + emails: arr, + actionId: commentId, // comment id + actionLink: { + action: { + type: "comment", + data: commentId + } + }, + message: message //comment text + }); + }, + textComments : 'Comments', textAnonym : 'Guest', textAddCommentToDoc : 'Add Comment to Document', diff --git a/apps/common/main/lib/view/ReviewPopover.js b/apps/common/main/lib/view/ReviewPopover.js index 088842f7a..466226e0d 100644 --- a/apps/common/main/lib/view/ReviewPopover.js +++ b/apps/common/main/lib/view/ReviewPopover.js @@ -100,6 +100,9 @@ define([ this.commentsStore = options.commentsStore; this.reviewStore = options.reviewStore; + this.canRequestUsers = options.canRequestUsers; + this.canRequestSendNotify = options.canRequestSendNotify; + this.externalUsers = []; this._state = {commentsVisible: false, reviewVisible: false}; _options.tpl = _.template(this.template)(_options); @@ -108,6 +111,12 @@ define([ this.sdkBounds = {width: 0, height: 0, padding: 10, paddingTop: 20}; Common.UI.Window.prototype.initialize.call(this, _options); + + if (this.canRequestUsers) { + Common.Gateway.on('setusers', _.bind(this.setUsers, this)); + Common.NotificationCenter.on('mentions:clearusers', _.bind(this.clearUsers, this)); + } + return this; }, render: function (comments, review) { @@ -234,7 +243,8 @@ define([ textEdit: me.textEdit, textReply: me.textReply, textClose: me.textClose, - maxCommLength: Asc.c_oAscMaxCellOrCommentLength + maxCommLength: Asc.c_oAscMaxCellOrCommentLength, + textMention: me.canRequestSendNotify ? me.textMention : '' }) ) }); @@ -457,6 +467,25 @@ define([ } } }); + + this.emailMenu = new Common.UI.Menu({ + maxHeight: 190, + cyclic: false, + items: [] + }).on('render:after', function(mnu) { + this.scroller = new Common.UI.Scroller({ + el: $(this.el).find('.dropdown-menu '), + useKeyboard: this.enableKeyEvents && !this.handleSelect, + minScrollbarLength : 40, + alwaysVisibleY: true + }); + }).on('show:after', function () { + this.scroller.update({alwaysVisibleY: true}); + me.$window.css({zIndex: '1001'}); + }).on('hide:after', function () { + me.$window.css({zIndex: '990'}); + }); + me.on({ 'show': function () { me.commentsView.autoHeightTextBox(); @@ -922,6 +951,47 @@ define([ me.e = event; }); + + if (this.canRequestUsers) { + textBox && textBox.keydown(function (event) { + if ( event.keyCode == Common.UI.Keys.SPACE || + event.keyCode == Common.UI.Keys.HOME || event.keyCode == Common.UI.Keys.END || event.keyCode == Common.UI.Keys.RIGHT || + event.keyCode == Common.UI.Keys.LEFT || event.keyCode == Common.UI.Keys.UP) { + // hide email menu + me.onEmailListMenu(); + } else if (event.keyCode == Common.UI.Keys.DOWN) { + if (me.emailMenu && me.emailMenu.rendered && me.emailMenu.isVisible()) + _.delay(function() { + var selected = me.emailMenu.cmpEl.find('li:not(.divider):first'); + selected = selected.find('a'); + selected.focus(); + }, 10); + } + me.e = event; + }); + textBox && textBox.on('input', function (event) { + var $this = $(this), + start = this.selectionStart, + val = $this.val().replace(/[\n]$/, ""), + left = 0, right = val.length-1; + for (var i=start-1; i>=0; i--) { + if (val.charCodeAt(i) == 32 /*space*/ || val.charCodeAt(i) == 13 || val.charCodeAt(i) == 10 || val.charCodeAt(i) == 9) { + left = i+1; break; + } + } + for (var i=start; i<=right; i++) { + if (val.charCodeAt(i) == 32 || val.charCodeAt(i) == 13 || val.charCodeAt(i) == 10 || val.charCodeAt(i) == 9) { + right = i-1; break; + } + } + var str = val.substring(left, right+1), + res = str.match(/^(?:[@]|[+](?!1))(\S*)/); + if (res && res.length>1) { + str = res[1]; // send to show email menu + me.onEmailListMenu(str, left, right); + } + }); + } }, hideTips: function () { @@ -959,6 +1029,17 @@ define([ this.commentsView.setStore(this.commentsStore); }, + setUsers: function(data) { + this.externalUsers = data.users || []; + this.isUsersLoading = false; + this._state.emailSearch && this.onEmailListMenu(this._state.emailSearch.str, this._state.emailSearch.left, this._state.emailSearch.right); + this._state.emailSearch = null; + }, + + clearUsers: function() { + this.externalUsers = []; + }, + getPopover: function(options) { if (!this.popover) this.popover = new Common.Views.ReviewPopover(options); @@ -983,6 +1064,107 @@ define([ } }, + onEmailListMenu: function(str, left, right, show) { + var me = this, + users = me.externalUsers, + menu = me.emailMenu; + + if (users.length<1) { + this._state.emailSearch = { + str: str, + left: left, + right: right + }; + + if (this.isUsersLoading) return; + + this.isUsersLoading = true; + Common.Gateway.requestUsers(); + return; + } + if (typeof str == 'string') { + var menuContainer = me.$window.find(Common.Utils.String.format('#menu-container-{0}', menu.id)), + textbox = this.commentsView.getTextBox(), + textboxDom = textbox ? textbox[0] : null, + showPoint = textboxDom ? [textboxDom.offsetLeft, textboxDom.offsetTop + textboxDom.clientHeight + 3] : [0, 0]; + + if (!menu.rendered) { + // Prepare menu container + if (menuContainer.length < 1) { + menuContainer = $(Common.Utils.String.format('', menu.id)); + me.$window.append(menuContainer); + } + + menu.render(menuContainer); + menu.cmpEl.css('min-width', textboxDom ? textboxDom.clientWidth : 220); + menu.cmpEl.attr({tabindex: "-1"}); + menu.on('hide:after', function(){ + setTimeout(function(){ + var tb = me.commentsView.getTextBox(); + tb && tb.focus(); + }, 10); + }); + } + + for (var i = 0; i < menu.items.length; i++) { + menu.removeItem(menu.items[i]); + i--; + } + + if (users.length>0) { + str = str.toLowerCase(); + if (str.length>0) { + users = _.filter(users, function(item) { + return (item.email && 0 === item.email.toLowerCase().indexOf(str) || item.name && 0 === item.name.toLowerCase().indexOf(str)) + }); + } + var tpl = _.template('
<%= caption %>
<%= options.value %>
'), + divider = false; + _.each(users, function(menuItem, index) { + if (divider && !menuItem.hasAccess) { + divider = false; + menu.addItem(new Common.UI.MenuItem({caption: '--'})); + } + + if (menuItem.email && menuItem.name) { + var mnu = new Common.UI.MenuItem({ + caption : menuItem.name, + value : menuItem.email, + template : tpl + }).on('click', function(item, e) { + me.insertEmailToTextbox(item.options.value, left, right); + }); + menu.addItem(mnu); + if (menuItem.hasAccess) + divider = true; + } + }); + } + + if (menu.items.length>0) { + menuContainer.css({left: showPoint[0], top : showPoint[1]}); + menu.menuAlignEl = textbox; + menu.show(); + menu.cmpEl.css('display', ''); + menu.alignPosition('bl-tl', -5); + menu.scroller.update({alwaysVisibleY: true}); + } else { + menu.rendered && menu.cmpEl.css('display', 'none'); + } + } else { + menu.rendered && menu.cmpEl.css('display', 'none'); + } + }, + + insertEmailToTextbox: function(str, left, right) { + var textBox = this.commentsView.getTextBox(), + val = textBox.val(); + textBox.val(val.substring(0, left) + '+' + str + val.substring(right+1, val.length)); + setTimeout(function(){ + textBox[0].selectionStart = textBox[0].selectionEnd = left + str.length + 1; + }, 10); + }, + textAddReply : 'Add Reply', textAdd : "Add", textCancel : 'Cancel', @@ -991,6 +1173,7 @@ define([ textClose : 'Close', textResolve : 'Resolve', textOpenAgain : "Open Again", - textFollowMove : 'Follow Move' + textFollowMove : 'Follow Move', + textMention : '+mention will provide access to the document and send an email' }, Common.Views.ReviewPopover || {})) }); \ No newline at end of file diff --git a/apps/documenteditor/main/app/controller/Main.js b/apps/documenteditor/main/app/controller/Main.js index d4f560f53..783563d62 100644 --- a/apps/documenteditor/main/app/controller/Main.js +++ b/apps/documenteditor/main/app/controller/Main.js @@ -195,6 +195,7 @@ define([ Common.NotificationCenter.on('api:disconnect', _.bind(this.onCoAuthoringDisconnect, this)); Common.NotificationCenter.on('goback', _.bind(this.goBack, this)); + Common.NotificationCenter.on('document:ready', _.bind(this.onDocumentReady, this)); this.isShowOpenDialog = false; @@ -232,7 +233,9 @@ define([ if (/form-control/.test(e.target.className)) me.inFormControl = false; if (!e.relatedTarget || - !/area_id/.test(e.target.id) && ($(e.target).parent().find(e.relatedTarget).length<1 || e.target.localName == 'textarea') /* 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 */ + !/area_id/.test(e.target.id) + && !(e.target.localName == 'input' && $(e.target).parent().find(e.relatedTarget).length>0) /* 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.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)) @@ -344,6 +347,8 @@ define([ this.appOptions.canBack = this.appOptions.canBackToFolder === true; this.appOptions.canPlugins = false; this.appOptions.canMakeActionLink = this.editorConfig.canMakeActionLink; + this.appOptions.canRequestUsers = this.editorConfig.canRequestUsers; + this.appOptions.canRequestSendNotify = this.editorConfig.canRequestSendNotify; appHeader = this.getApplication().getController('Viewport').getView('Common.Views.Header'); appHeader.setCanBack(this.appOptions.canBackToFolder === true, (this.appOptions.canBackToFolder) ? this.editorConfig.customization.goback.text : '') @@ -1041,6 +1046,12 @@ define([ Common.Gateway.documentReady(); }, + onDocumentReady: function() { + if (this.editorConfig.actionLink && this.editorConfig.actionLink.action && this.editorConfig.actionLink.action.type == 'comment') { + this.contComments.getView().fireEvent('comment:show', [this.editorConfig.actionLink.action.data, false]); + } + }, + onLicenseChanged: function(params) { var licType = params.asc_getLicenseType(); if (licType !== undefined && this.appOptions.canEdit && this.editorConfig.mode !== 'view' && diff --git a/apps/documenteditor/main/app/view/FileMenuPanels.js b/apps/documenteditor/main/app/view/FileMenuPanels.js index 11191c455..a32be4c16 100644 --- a/apps/documenteditor/main/app/view/FileMenuPanels.js +++ b/apps/documenteditor/main/app/view/FileMenuPanels.js @@ -1204,20 +1204,20 @@ define([ setMode: function(mode) { this.sharingSettingsUrl = mode.sharingSettingsUrl; + !!this.sharingSettingsUrl && this.sharingSettingsUrl.length && Common.Gateway.on('showsharingsettings', _.bind(this.changeAccessRights, this)); + !!this.sharingSettingsUrl && this.sharingSettingsUrl.length && Common.Gateway.on('setsharingsettings', _.bind(this.setSharingSettings, this)); return this; }, changeAccessRights: function(btn,event,opts) { - if (this._docAccessDlg) return; + if (this._docAccessDlg || this._readonlyRights) return; var me = this; me._docAccessDlg = new Common.Views.DocumentAccessDialog({ settingsurl: this.sharingSettingsUrl }); me._docAccessDlg.on('accessrights', function(obj, rights){ - me.doc.info.sharingSettings = rights; - me._ShowHideInfoItem('rights', me.doc.info.sharingSettings!==undefined && me.doc.info.sharingSettings!==null && me.doc.info.sharingSettings.length>0); - me.cntRights.html(me.templateRights({users: me.doc.info.sharingSettings})); + me.updateSharingSettings(rights); }).on('close', function(obj){ me._docAccessDlg = undefined; }); @@ -1225,6 +1225,17 @@ define([ me._docAccessDlg.show(); }, + setSharingSettings: function(data) { + data && this.updateSharingSettings(data.sharingSettings); + }, + + updateSharingSettings: function(rights) { + this.doc.info.sharingSettings = rights; + this._ShowHideInfoItem('rights', this.doc.info.sharingSettings!==undefined && this.doc.info.sharingSettings!==null && this.doc.info.sharingSettings.length>0); + this.cntRights.html(this.templateRights({users: this.doc.info.sharingSettings})); + Common.NotificationCenter.trigger('mentions:clearusers', this); + }, + onLostEditRights: function() { this._readonlyRights = true; if (!this.rendered) diff --git a/apps/documenteditor/main/locale/en.json b/apps/documenteditor/main/locale/en.json index af546d82d..830450879 100644 --- a/apps/documenteditor/main/locale/en.json +++ b/apps/documenteditor/main/locale/en.json @@ -284,6 +284,7 @@ "Common.Views.ReviewPopover.textClose": "Close", "Common.Views.ReviewPopover.textEdit": "OK", "Common.Views.ReviewPopover.textFollowMove": "Follow Move", + "Common.Views.ReviewPopover.textMention": "+mention will provide access to the document and send an email", "Common.Views.ReviewPopover.textOpenAgain": "Open Again", "Common.Views.ReviewPopover.textReply": "Reply", "Common.Views.ReviewPopover.textResolve": "Resolve", diff --git a/apps/presentationeditor/main/app/controller/Main.js b/apps/presentationeditor/main/app/controller/Main.js index cc8c8df46..5e40d717c 100644 --- a/apps/presentationeditor/main/app/controller/Main.js +++ b/apps/presentationeditor/main/app/controller/Main.js @@ -180,6 +180,7 @@ define([ this.api.asc_registerCallback('asc_onSpellCheckInit', _.bind(this.loadLanguages, this)); Common.NotificationCenter.on('api:disconnect', _.bind(this.onCoAuthoringDisconnect, this)); Common.NotificationCenter.on('goback', _.bind(this.goBack, this)); + Common.NotificationCenter.on('document:ready', _.bind(this.onDocumentReady, this)); this.isShowOpenDialog = false; @@ -211,7 +212,9 @@ define([ if (/form-control/.test(e.target.className)) me.inFormControl = false; if (!e.relatedTarget || - !/area_id/.test(e.target.id) && ($(e.target).parent().find(e.relatedTarget).length<1 || e.target.localName == 'textarea') /* 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 */ + !/area_id/.test(e.target.id) + && !(e.target.localName == 'input' && $(e.target).parent().find(e.relatedTarget).length>0) /* 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.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)) @@ -313,6 +316,8 @@ define([ && (typeof (this.editorConfig.customization.goback) == 'object') && !_.isEmpty(this.editorConfig.customization.goback.url); this.appOptions.canBack = this.editorConfig.nativeApp !== true && this.appOptions.canBackToFolder === true; this.appOptions.canPlugins = false; + this.appOptions.canRequestUsers = this.editorConfig.canRequestUsers; + this.appOptions.canRequestSendNotify = this.editorConfig.canRequestSendNotify; appHeader = this.getApplication().getController('Viewport').getView('Common.Views.Header'); appHeader.setCanBack(this.appOptions.canBackToFolder === true, (this.appOptions.canBackToFolder) ? this.editorConfig.customization.goback.text : '') @@ -785,6 +790,12 @@ define([ Common.Gateway.documentReady(); }, + onDocumentReady: function() { + if (this.editorConfig.actionLink && this.editorConfig.actionLink.action && this.editorConfig.actionLink.action.type == 'comment') { + this.getApplication().getController('Common.Controllers.Comments').getView().fireEvent('comment:show', [this.editorConfig.actionLink.action.data, false]); + } + }, + onLicenseChanged: function(params) { var licType = params.asc_getLicenseType(); if (licType !== undefined && this.appOptions.canEdit && this.editorConfig.mode !== 'view' && diff --git a/apps/presentationeditor/main/app/view/FileMenuPanels.js b/apps/presentationeditor/main/app/view/FileMenuPanels.js index c3dd93d24..01bab61b7 100644 --- a/apps/presentationeditor/main/app/view/FileMenuPanels.js +++ b/apps/presentationeditor/main/app/view/FileMenuPanels.js @@ -1021,20 +1021,20 @@ define([ setMode: function(mode) { this.sharingSettingsUrl = mode.sharingSettingsUrl; + !!this.sharingSettingsUrl && this.sharingSettingsUrl.length && Common.Gateway.on('showsharingsettings', _.bind(this.changeAccessRights, this)); + !!this.sharingSettingsUrl && this.sharingSettingsUrl.length && Common.Gateway.on('setsharingsettings', _.bind(this.setSharingSettings, this)); return this; }, changeAccessRights: function(btn,event,opts) { - if (this._docAccessDlg) return; + if (this._docAccessDlg || this._readonlyRights) return; var me = this; me._docAccessDlg = new Common.Views.DocumentAccessDialog({ settingsurl: this.sharingSettingsUrl }); me._docAccessDlg.on('accessrights', function(obj, rights){ - me.doc.info.sharingSettings = rights; - me._ShowHideInfoItem('rights', me.doc.info.sharingSettings!==undefined && me.doc.info.sharingSettings!==null && me.doc.info.sharingSettings.length>0); - me.cntRights.html(me.templateRights({users: me.doc.info.sharingSettings})); + me.updateSharingSettings(rights); }).on('close', function(obj){ me._docAccessDlg = undefined; }); @@ -1042,6 +1042,17 @@ define([ me._docAccessDlg.show(); }, + setSharingSettings: function(data) { + data && this.updateSharingSettings(data.sharingSettings); + }, + + updateSharingSettings: function(rights) { + this.doc.info.sharingSettings = rights; + this._ShowHideInfoItem('rights', this.doc.info.sharingSettings!==undefined && this.doc.info.sharingSettings!==null && this.doc.info.sharingSettings.length>0); + this.cntRights.html(this.templateRights({users: this.doc.info.sharingSettings})); + Common.NotificationCenter.trigger('mentions:clearusers', this); + }, + onLostEditRights: function() { this._readonlyRights = true; if (!this.rendered) diff --git a/apps/presentationeditor/main/locale/en.json b/apps/presentationeditor/main/locale/en.json index df7a78bb2..3038aaa2f 100644 --- a/apps/presentationeditor/main/locale/en.json +++ b/apps/presentationeditor/main/locale/en.json @@ -199,6 +199,7 @@ "Common.Views.ReviewPopover.textCancel": "Cancel", "Common.Views.ReviewPopover.textClose": "Close", "Common.Views.ReviewPopover.textEdit": "OK", + "Common.Views.ReviewPopover.textMention": "+mention will provide access to the document and send an email", "Common.Views.ReviewPopover.textOpenAgain": "Open Again", "Common.Views.ReviewPopover.textReply": "Reply", "Common.Views.ReviewPopover.textResolve": "Resolve", diff --git a/apps/spreadsheeteditor/main/app/controller/Main.js b/apps/spreadsheeteditor/main/app/controller/Main.js index 6f957c497..2761072ef 100644 --- a/apps/spreadsheeteditor/main/app/controller/Main.js +++ b/apps/spreadsheeteditor/main/app/controller/Main.js @@ -168,6 +168,7 @@ define([ Common.NotificationCenter.on('goback', _.bind(this.goBack, this)); Common.NotificationCenter.on('namedrange:locked', _.bind(this.onNamedRangeLocked, this)); Common.NotificationCenter.on('download:cancel', _.bind(this.onDownloadCancel, this)); + Common.NotificationCenter.on('document:ready', _.bind(this.onDocumentReady, this)); this.stackLongActions = new Common.IrregularStack({ strongCompare : this._compareActionStrong, @@ -209,7 +210,9 @@ define([ if (/form-control/.test(e.target.className)) me.inFormControl = false; if (!e.relatedTarget || - !/area_id/.test(e.target.id) && ($(e.target).parent().find(e.relatedTarget).length<1 || e.target.localName == 'textarea') /* 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 */ + !/area_id/.test(e.target.id) + && !(e.target.localName == 'input' && $(e.target).parent().find(e.relatedTarget).length>0) /* 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.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)) @@ -318,6 +321,8 @@ define([ && (typeof (this.editorConfig.customization.goback) == 'object') && !_.isEmpty(this.editorConfig.customization.goback.url); this.appOptions.canBack = this.editorConfig.nativeApp !== true && this.appOptions.canBackToFolder === true; this.appOptions.canPlugins = false; + this.appOptions.canRequestUsers = this.editorConfig.canRequestUsers; + this.appOptions.canRequestSendNotify = this.editorConfig.canRequestSendNotify; this.headerView = this.getApplication().getController('Viewport').getView('Common.Views.Header'); this.headerView.setCanBack(this.appOptions.canBackToFolder === true, (this.appOptions.canBackToFolder) ? this.editorConfig.customization.goback.text : '') @@ -489,7 +494,7 @@ define([ if (type === Asc.c_oAscAsyncActionType.BlockInteraction && id == Asc.c_oAscAsyncAction.Open) { Common.Gateway.internalMessage('documentReady', {}); - this.onDocumentReady(); + this.onDocumentContentReady(); } action = this.stackLongActions.get({type: Asc.c_oAscAsyncActionType.Information}); @@ -610,7 +615,7 @@ define([ } }, - onDocumentReady: function() { + onDocumentContentReady: function() { if (this._isDocReady) return; @@ -797,6 +802,12 @@ define([ Common.Gateway.documentReady(); }, + onDocumentReady: function() { + if (this.editorConfig.actionLink && this.editorConfig.actionLink.action && this.editorConfig.actionLink.action.type == 'comment') { + this.getApplication().getController('Common.Controllers.Comments').getView().fireEvent('comment:show', [this.editorConfig.actionLink.action.data, false]); + } + }, + onLicenseChanged: function(params) { if (this.appOptions.isEditDiagram || this.appOptions.isEditMailMerge) return; diff --git a/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js b/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js index e5e83fbd8..694215470 100644 --- a/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js +++ b/apps/spreadsheeteditor/main/app/view/FileMenuPanels.js @@ -1470,20 +1470,20 @@ define([ setMode: function(mode) { this.sharingSettingsUrl = mode.sharingSettingsUrl; + !!this.sharingSettingsUrl && this.sharingSettingsUrl.length && Common.Gateway.on('showsharingsettings', _.bind(this.changeAccessRights, this)); + !!this.sharingSettingsUrl && this.sharingSettingsUrl.length && Common.Gateway.on('setsharingsettings', _.bind(this.setSharingSettings, this)); return this; }, changeAccessRights: function(btn,event,opts) { - if (this._docAccessDlg) return; + if (this._docAccessDlg || this._readonlyRights) return; var me = this; me._docAccessDlg = new Common.Views.DocumentAccessDialog({ settingsurl: this.sharingSettingsUrl }); me._docAccessDlg.on('accessrights', function(obj, rights){ - me.doc.info.sharingSettings = rights; - me._ShowHideInfoItem('rights', me.doc.info.sharingSettings!==undefined && me.doc.info.sharingSettings!==null && me.doc.info.sharingSettings.length>0); - me.cntRights.html(me.templateRights({users: me.doc.info.sharingSettings})); + me.updateSharingSettings(rights); }).on('close', function(obj){ me._docAccessDlg = undefined; }); @@ -1491,6 +1491,17 @@ define([ me._docAccessDlg.show(); }, + setSharingSettings: function(data) { + data && this.updateSharingSettings(data.sharingSettings); + }, + + updateSharingSettings: function(rights) { + this.doc.info.sharingSettings = rights; + this._ShowHideInfoItem('rights', this.doc.info.sharingSettings!==undefined && this.doc.info.sharingSettings!==null && this.doc.info.sharingSettings.length>0); + this.cntRights.html(this.templateRights({users: this.doc.info.sharingSettings})); + Common.NotificationCenter.trigger('mentions:clearusers', this); + }, + onLostEditRights: function() { this._readonlyRights = true; if (!this.rendered) diff --git a/apps/spreadsheeteditor/main/locale/en.json b/apps/spreadsheeteditor/main/locale/en.json index 9b5d217c6..300c23075 100644 --- a/apps/spreadsheeteditor/main/locale/en.json +++ b/apps/spreadsheeteditor/main/locale/en.json @@ -189,6 +189,7 @@ "Common.Views.ReviewPopover.textCancel": "Cancel", "Common.Views.ReviewPopover.textClose": "Close", "Common.Views.ReviewPopover.textEdit": "OK", + "Common.Views.ReviewPopover.textMention": "+mention will provide access to the document and send an email", "Common.Views.ReviewPopover.textOpenAgain": "Open Again", "Common.Views.ReviewPopover.textReply": "Reply", "Common.Views.ReviewPopover.textResolve": "Resolve",