446 lines
18 KiB
JavaScript
446 lines
18 KiB
JavaScript
/*
|
|
*
|
|
* (c) Copyright Ascensio System SIA 2010-2021
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at 20A-12 Ernesta Birznieka-Upisha
|
|
* street, Riga, Latvia, EU, LV-1050.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
/**
|
|
*
|
|
* ProtectRangesDlg.js
|
|
*
|
|
* Created by Julia.Radzhabova on 22.06.21
|
|
* Copyright (c) 2021 Ascensio System SIA. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
define([ 'text!spreadsheeteditor/main/app/template/ProtectRangesDlg.template',
|
|
'common/main/lib/view/AdvancedSettingsWindow',
|
|
'common/main/lib/component/ListView'
|
|
], function (contentTemplate) {
|
|
'use strict';
|
|
|
|
SSE.Views = SSE.Views || {};
|
|
|
|
SSE.Views.ProtectRangesDlg = Common.Views.AdvancedSettingsWindow.extend(_.extend({
|
|
options: {
|
|
alias: 'ProtectRangesDlg',
|
|
contentWidth: 480,
|
|
height: 353
|
|
},
|
|
|
|
initialize: function (options) {
|
|
var me = this;
|
|
_.extend(this.options, {
|
|
title: this.txtTitle,
|
|
template: [
|
|
'<div class="box" style="height:' + (this.options.height-85) + 'px;">',
|
|
'<div class="content-panel" style="padding: 0;">' + _.template(contentTemplate)({scope: this}) + '</div>',
|
|
'</div>',
|
|
'<div class="separator horizontal"></div>'
|
|
].join(''),
|
|
buttons: [{
|
|
value: 'protect-sheet',
|
|
caption: this.textProtect
|
|
}, 'ok','cancel'],
|
|
primary: 'protect-sheet'
|
|
}, options);
|
|
|
|
this.api = options.api;
|
|
this.handler = options.handler;
|
|
this.props = options.props;
|
|
this.locked = options.locked || false;
|
|
this.userTooltip = true;
|
|
this.currentRange = undefined;
|
|
this.deletedArr = [];
|
|
|
|
this.wrapEvents = {
|
|
onLockProtectedRangeManager: _.bind(this.onLockProtectedRangeManager, this),
|
|
onUnLockProtectedRangeManager: _.bind(this.onUnLockProtectedRangeManager, this),
|
|
onLockProtectedRange: _.bind(this.onLockProtectedRange, this),
|
|
onUnLockProtectedRange: _.bind(this.onUnLockProtectedRange, this)
|
|
};
|
|
|
|
Common.Views.AdvancedSettingsWindow.prototype.initialize.call(this, this.options);
|
|
},
|
|
render: function () {
|
|
Common.Views.AdvancedSettingsWindow.prototype.render.call(this);
|
|
var me = this;
|
|
|
|
this.rangeList = new Common.UI.ListView({
|
|
el: $('#protect-ranges-list', this.$window),
|
|
store: new Common.UI.DataViewStore(),
|
|
simpleAddMode: true,
|
|
emptyText: this.textEmpty,
|
|
itemTemplate: _.template([
|
|
'<div id="<%= id %>" class="list-item" style="width: 100%;display:inline-block;<% if (!lock) { %>pointer-events:none;<% } %>">',
|
|
'<div style="width:184px;padding-right: 5px;"><%= Common.Utils.String.htmlEncode(name) %></div>',
|
|
'<div style="width:191px;padding-right: 5px;"><%= range %></div>',
|
|
'<div style="width:70px;"><% if (pwd) { %>', me.txtYes, '<% } else { %>', me.txtNo, '<% } %></div>',
|
|
'<% if (lock) { %>',
|
|
'<div class="lock-user"><%=lockuser%></div>',
|
|
'<% } %>',
|
|
'</div>'
|
|
].join('')),
|
|
tabindex: 1
|
|
});
|
|
this.rangeList.store.comparator = function(item1, item2) {
|
|
var n1 = item1.get('name').toLowerCase(),
|
|
n2 = item2.get('name').toLowerCase();
|
|
if (n1==n2) return 0;
|
|
return (n1<n2) ? -1 : 1;
|
|
};
|
|
this.rangeList.on('item:select', _.bind(this.onSelectRangeItem, this))
|
|
.on('item:keydown', _.bind(this.onKeyDown, this))
|
|
.on('item:dblclick', _.bind(this.onDblClickItem, this))
|
|
.on('entervalue', _.bind(this.onDblClickItem, this));
|
|
|
|
this.btnNewRange = new Common.UI.Button({
|
|
el: $('#protect-ranges-btn-new')
|
|
});
|
|
this.btnNewRange.on('click', _.bind(this.onEditRange, this, false));
|
|
|
|
this.btnEditRange = new Common.UI.Button({
|
|
el: $('#protect-ranges-btn-edit')
|
|
});
|
|
this.btnEditRange.on('click', _.bind(this.onEditRange, this, true));
|
|
|
|
this.btnDeleteRange = new Common.UI.Button({
|
|
el: $('#protect-ranges-btn-delete')
|
|
});
|
|
this.btnDeleteRange.on('click', _.bind(this.onDeleteRange, this));
|
|
|
|
this.afterRender();
|
|
},
|
|
|
|
getFocusedComponents: function() {
|
|
return [ this.rangeList, this.btnNewRange, this.btnEditRange, this.btnDeleteRange ];
|
|
},
|
|
|
|
getDefaultFocusableComponent: function () {
|
|
return this.rangeList;
|
|
},
|
|
|
|
afterRender: function() {
|
|
this._setDefaults(this.props);
|
|
},
|
|
|
|
_setDefaults: function (props) {
|
|
this.refreshRangeList(props, 0);
|
|
this.currentSheet = this.api.asc_getActiveWorksheetIndex();
|
|
this.api.asc_registerCallback('asc_onLockProtectedRangeManager', this.wrapEvents.onLockProtectedRangeManager);
|
|
this.api.asc_registerCallback('asc_onUnLockProtectedRangeManager', this.wrapEvents.onUnLockProtectedRangeManager);
|
|
this.api.asc_registerCallback('asc_onLockProtectedRange', this.wrapEvents.onLockProtectedRange);
|
|
this.api.asc_registerCallback('asc_onUnLockProtectedRange', this.wrapEvents.onUnLockProtectedRange);
|
|
},
|
|
|
|
refreshRangeList: function(ranges, selectedItem) {
|
|
if (ranges) {
|
|
var arr = [];
|
|
for (var i=0; i<ranges.length; i++) {
|
|
var id = ranges[i].asc_getIsLock();
|
|
arr.push({
|
|
name: ranges[i].asc_getName() || '',
|
|
pwd: ranges[i].asc_isPassword(),
|
|
range: ranges[i].asc_getSqref() || '',
|
|
rangeId: ranges[i].asc_getId(),
|
|
props: ranges[i],
|
|
lock: (id!==null && id!==undefined),
|
|
lockuser: (id) ? this.getUserName(id) : this.guestText
|
|
});
|
|
}
|
|
this.rangeList.store.reset(arr);
|
|
}
|
|
|
|
var me = this,
|
|
store = this.rangeList.store,
|
|
val = store.length;
|
|
if (val>0) {
|
|
if (selectedItem===undefined || selectedItem===null) selectedItem = 0;
|
|
if (_.isNumber(selectedItem)) {
|
|
if (selectedItem>val-1) selectedItem = val-1;
|
|
this.rangeList.selectByIndex(selectedItem);
|
|
setTimeout(function() {
|
|
me.rangeList.scrollToRecord(store.at(selectedItem));
|
|
}, 50);
|
|
|
|
} else if (selectedItem){ // object
|
|
var rec = store.findWhere({name: selectedItem.asc_getName(true)});
|
|
if (rec) {
|
|
this.rangeList.selectRecord(rec);
|
|
setTimeout(function() {
|
|
me.rangeList.scrollToRecord(rec);
|
|
}, 50);
|
|
}
|
|
}
|
|
|
|
if (this.userTooltip===true && this.rangeList.cmpEl.find('.lock-user').length>0)
|
|
this.rangeList.cmpEl.on('mouseover', _.bind(me.onMouseOverLock, me)).on('mouseout', _.bind(me.onMouseOutLock, me));
|
|
}
|
|
this.updateButtons();
|
|
_.delay(function () {
|
|
me.rangeList.scroller.update({alwaysVisibleY: true});
|
|
}, 100, this);
|
|
},
|
|
|
|
onMouseOverLock: function (evt, el, opt) {
|
|
if (this.userTooltip===true && $(evt.target).hasClass('lock-user')) {
|
|
var me = this,
|
|
tipdata = $(evt.target).tooltip({title: this.tipIsLocked,trigger:'manual'}).data('bs.tooltip');
|
|
|
|
this.userTooltip = tipdata.tip();
|
|
this.userTooltip.css('z-index', parseInt(this.$window.css('z-index')) + 10);
|
|
tipdata.show();
|
|
|
|
setTimeout(function() { me.userTipHide(); }, 5000);
|
|
}
|
|
},
|
|
|
|
userTipHide: function () {
|
|
if (typeof this.userTooltip == 'object') {
|
|
this.userTooltip.remove();
|
|
this.userTooltip = undefined;
|
|
this.rangeList.cmpEl.off('mouseover').off('mouseout');
|
|
}
|
|
},
|
|
|
|
onMouseOutLock: function (evt, el, opt) {
|
|
if (typeof this.userTooltip == 'object') this.userTipHide();
|
|
},
|
|
|
|
onEditRange: function (isEdit) {
|
|
if (this._isWarningVisible) return;
|
|
|
|
if (this.locked) {
|
|
Common.NotificationCenter.trigger('namedrange:locked');
|
|
return;
|
|
}
|
|
var me = this,
|
|
xy = me.$window.offset(),
|
|
rec = this.rangeList.getSelectedRec(),
|
|
props;
|
|
if (isEdit)
|
|
props = rec.get('props');
|
|
else {
|
|
props = new Asc.CProtectedRange();
|
|
props.asc_setSqref(me.api.asc_getActiveRangeStr(Asc.referenceType.A));
|
|
}
|
|
var names = [];
|
|
this.rangeList.store.each(function(item){
|
|
names.push(item.get('name').toLowerCase());
|
|
});
|
|
|
|
var win = new SSE.Views.ProtectDialog({
|
|
title : isEdit ? me.txtEditRange : me.txtNewRange,
|
|
type : 'range',
|
|
props : props,
|
|
names : names,
|
|
isEdit : isEdit,
|
|
api : me.api,
|
|
buttons : ['ok', 'cancel'],
|
|
handler : function(result, value, props) {
|
|
if (result == 'ok') {
|
|
value && props.asc_setPassword(value);
|
|
if (isEdit) {
|
|
rec.set('props', props);
|
|
rec.set('name', props.asc_getName());
|
|
rec.set('range', props.asc_getSqref());
|
|
rec.set('pwd', props.asc_isPassword());
|
|
} else {
|
|
rec = me.rangeList.store.add({
|
|
name: props.asc_getName(),
|
|
pwd: props.asc_isPassword(),
|
|
range: props.asc_getSqref(),
|
|
props: props,
|
|
isNew: true,
|
|
lock: false,
|
|
lockuser: this.guestText
|
|
});
|
|
me.rangeList.selectRecord(rec);
|
|
me.rangeList.scrollToRecord(me.rangeList.getSelectedRec());
|
|
me.updateButtons();
|
|
}
|
|
}
|
|
}
|
|
}).on('close', function() {
|
|
me.show();
|
|
setTimeout(function(){ me.getDefaultFocusableComponent().focus(); }, 100);
|
|
});
|
|
|
|
me.hide();
|
|
win.show(xy.left + 65, xy.top + 77);
|
|
},
|
|
|
|
onDeleteRange: function () {
|
|
var store = this.rangeList.store,
|
|
rec = this.rangeList.getSelectedRec();
|
|
if (rec) {
|
|
!rec.get('isNew') && this.deletedArr.push(rec.get('props'));
|
|
var index = store.indexOf(rec);
|
|
store.remove(rec);
|
|
(store.length>0) && this.rangeList.selectByIndex(index);
|
|
this.rangeList.scrollToRecord(this.rangeList.getSelectedRec());
|
|
}
|
|
this.updateButtons();
|
|
},
|
|
|
|
getSettings: function() {
|
|
var arr = [];
|
|
this.rangeList.store.each(function(item){
|
|
arr.push(item.get('props'));
|
|
});
|
|
return {arr: arr, deletedArr: this.deletedArr};
|
|
},
|
|
|
|
onPrimary: function() {
|
|
return true;
|
|
},
|
|
|
|
onDlgBtnClick: function(event) {
|
|
this.handler && this.handler.call(this, event.currentTarget.attributes['result'].value, this.getSettings());
|
|
this.close();
|
|
},
|
|
|
|
getUserName: function(id){
|
|
var usersStore = SSE.getCollection('Common.Collections.Users');
|
|
if (usersStore){
|
|
var rec = usersStore.findUser(id);
|
|
if (rec)
|
|
return AscCommon.UserInfoParser.getParsedName(rec.get('username'));
|
|
}
|
|
return this.guestText;
|
|
},
|
|
|
|
onSelectRangeItem: function(listView, itemView, record) {
|
|
if (!record) return;
|
|
|
|
this.userTipHide();
|
|
var rawData = {},
|
|
isViewSelect = _.isFunction(record.toJSON);
|
|
|
|
if (isViewSelect){
|
|
if (record.get('selected')) {
|
|
rawData = record.toJSON();
|
|
} else {// record deselected
|
|
return;
|
|
}
|
|
this.currentNamedRange = _.indexOf(this.rangeList.store.models, record);
|
|
}
|
|
this.updateButtons();
|
|
},
|
|
|
|
hide: function () {
|
|
this.userTipHide();
|
|
Common.UI.Window.prototype.hide.call(this);
|
|
},
|
|
|
|
close: function () {
|
|
this.userTipHide();
|
|
this.api.asc_unregisterCallback('asc_onLockProtectedRangeManager', this.wrapEvents.onLockProtectedRangeManager);
|
|
this.api.asc_unregisterCallback('asc_onUnLockProtectedRangeManager', this.wrapEvents.onUnLockProtectedRangeManager);
|
|
this.api.asc_unregisterCallback('asc_onLockProtectedRange', this.wrapEvents.onLockProtectedRange);
|
|
this.api.asc_unregisterCallback('asc_onUnLockProtectedRange', this.wrapEvents.onUnLockProtectedRange);
|
|
Common.UI.Window.prototype.close.call(this);
|
|
},
|
|
|
|
onKeyDown: function (lisvView, record, e) {
|
|
if (e.keyCode==Common.UI.Keys.DELETE && !this.btnDeleteRange.isDisabled())
|
|
this.onDeleteRange();
|
|
},
|
|
|
|
onDblClickItem: function (lisvView, record, e) {
|
|
if (!this.btnEditRange.isDisabled())
|
|
this.onEditRange(true);
|
|
},
|
|
|
|
onLockProtectedRangeManager: function(index) {
|
|
if (this.currentSheet !== index) return;
|
|
this.locked = true;
|
|
this.updateButtons();
|
|
if (this.userTooltip===true && this.rangeList.cmpEl.find('.lock-user').length>0)
|
|
this.rangeList.cmpEl.on('mouseover', _.bind(this.onMouseOverLock, this)).on('mouseout', _.bind(this.onMouseOutLock, this));
|
|
},
|
|
|
|
onUnLockProtectedRangeManager: function(index) {
|
|
if (this.currentSheet !== index) return;
|
|
this.locked = false;
|
|
this.updateButtons();
|
|
},
|
|
|
|
onLockProtectedRange: function(index, rangeId, userId) {
|
|
if (this.currentSheet !== index) return;
|
|
var store = this.rangeList.store,
|
|
rec = store.findWhere({rangeId: rangeId});
|
|
if (rec) {
|
|
rec.set('lockuser', (userId) ? this.getUserName(userId) : this.guestText);
|
|
rec.set('lock', true);
|
|
this.updateButtons();
|
|
}
|
|
if (this.userTooltip===true && this.rangeList.cmpEl.find('.lock-user').length>0)
|
|
this.rangeList.cmpEl.on('mouseover', _.bind(this.onMouseOverLock, this)).on('mouseout', _.bind(this.onMouseOutLock, this));
|
|
},
|
|
|
|
onUnLockProtectedRange: function(index, rangeId) {
|
|
if (this.currentSheet !== index) return;
|
|
var store = this.rangeList.store,
|
|
rec = store.findWhere({rangeId: rangeId});
|
|
if (rec) {
|
|
rec.set('lockuser', '');
|
|
rec.set('lock', false);
|
|
this.updateButtons();
|
|
}
|
|
},
|
|
|
|
updateButtons: function() {
|
|
var rec = this.rangeList.getSelectedRec(),
|
|
lock = rec ? rec.get('lock') : false,
|
|
length = this.rangeList.store.length;
|
|
this.btnDeleteRange.setDisabled(length<1 || lock);
|
|
this.btnEditRange.setDisabled(length<1 || lock);
|
|
},
|
|
|
|
txtTitle: 'Allow Users to Edit Ranges',
|
|
textRangesDesc: 'Ranges unlocked by a password when sheet is protected (this works only for locked cells)',
|
|
textTitle: 'Title',
|
|
textRange: 'Range',
|
|
textPwd: 'Password',
|
|
textNew: 'New',
|
|
textEdit: 'Edit',
|
|
textDelete: 'Delete',
|
|
textEmpty: 'No ranges allowed for edit.',
|
|
guestText: 'Guest',
|
|
tipIsLocked: 'This element is being edited by another user.',
|
|
warnDelete: 'Are you sure you want to delete the name {0}?',
|
|
textProtect: 'Protect Sheet',
|
|
txtYes: 'Yes',
|
|
txtNo: 'No',
|
|
txtEditRange: 'Edit Range',
|
|
txtNewRange: 'New Range'
|
|
|
|
}, SSE.Views.ProtectRangesDlg || {}));
|
|
}); |