wysiwyg custom dialogs

This commit is contained in:
yuri
2019-08-08 18:18:09 +03:00
parent 3c6e19f4c0
commit 957680a3d0
5 changed files with 377 additions and 4 deletions
@@ -0,0 +1,18 @@
<div class="cell form-group">
<label class="control-label">{{labels.selectFromFiles}}</label>
<div class="field">
<input class="note-image-input form-control-file note-form-control note-input" type="file" data-name="files" accept="image/*" multiple="multiple">
</div>
</div>
<div class="cell form-group">
<label class="control-label">{{labels.url}}</label>
<div class="field">
<div class="input-group">
<input class="note-image-url form-control note-form-control note-input" type="text" data-name="url">
<span class="input-group-btn">
<button class="btn btn-default disabled action" disabled="disabled" data-name="insert" data-action="insert">{{translate 'Insert'}}</button>
</span>
</div>
</div>
</div>
@@ -0,0 +1,19 @@
<div class="cell form-group">
<label class="control-label">{{labels.textToDisplay}}</label>
<div class="field">
<input class="form-control note-form-control note-input" type="text" data-name="text">
</div>
</div>
<div class="cell form-group">
<label class="control-label">{{labels.url}}</label>
<div class="field">
<input class="form-control note-form-control note-input" type="text" data-name="url">
</div>
</div>
<div class="cell form-group">
<label class="control-label">{{labels.openInNewWindow}}</label>
<div class="field">
<input class="" type="checkbox" data-name="openInNewWindow" checked>
</div>
</div>
+130 -4
View File
@@ -47,6 +47,10 @@ Espo.define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], fun
setup: function () {
Dep.prototype.setup.call(this);
if ($.summernote.options && !('espoImage' in $.summernote.options)) {
this.initEspoPlugin();
}
this.hasBodyPlainField = !!~this.getFieldManager().getEntityTypeFieldList(this.model.entityType).indexOf(this.name + 'Plain');
if ('height' in this.params) {
@@ -66,7 +70,7 @@ Espo.define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], fun
['color', ['color']],
['para', ['ul', 'ol', 'paragraph']],
['height', ['height']],
['table', ['table', 'link', 'picture', 'hr']],
['table', ['table', 'espoLink', 'espoImage', 'hr']],
['misc',['codeview', 'fullscreen']]
];
@@ -147,7 +151,7 @@ Espo.define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], fun
return data;
},
getValueForDisplay: function () {
getValueForDisplay: function () {
var value = Dep.prototype.getValueForDisplay.call(this);
return this.sanitizeHtml(value);
},
@@ -349,8 +353,14 @@ Espo.define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], fun
this.$summernote.find('style').remove();
this.$summernote.find('link[ref="stylesheet"]').remove();
var keyMap = Espo.Utils.cloneDeep($.summernote.options.keyMap);
keyMap.pc['CTRL+K'] = 'espoLink.show';
keyMap.mac['CMD+K'] = 'espoLink.show';
var options = {
espoView: this,
lang: this.getConfig().get('language'),
keyMap: keyMap,
callbacks: {
onImageUpload: function (files) {
var file = files[0];
@@ -389,7 +399,7 @@ Espo.define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], fun
},
toolbar: this.toolbar,
buttons: this.buttons,
dialogsInBody: $('body'),
dialogsInBody: this.$el,
codeviewFilter: true,
};
@@ -526,6 +536,122 @@ Espo.define('views/fields/wysiwyg', ['views/fields/text', 'lib!Summernote'], fun
attachFile: function () {
var $form = this.$el.closest('.record');
$form.find('.field[data-name="'+this.params.attachmentField+'"] input.file').click();
}
},
initEspoPlugin: function () {
var langSets = this.getLanguage().get('Global', 'sets', 'summernote') || {
image: {},
link: {},
video: {},
};
$.extend($.summernote.options, {
espoImage: {
icon: '<i class="note-icon-picture"/>',
tooltip: langSets.image.image,
},
espoLink: {
icon: '<i class="note-icon-link"/>',
tooltip: langSets.link.link,
},
});
$.extend($.summernote.plugins, {
'espoImage': function (context) {
var ui = $.summernote.ui;
var options = context.options;
var self = options.espoView;
this.lang = options.langInfo;
context.memo('button.espoImage', function () {
var button = ui.button({
contents: options.espoImage.icon,
tooltip: options.espoImage.tooltip,
click: function (e) {
context.invoke('espoImage.show');
},
});
return button.render();
});
this.initialize = function () {
};
this.destroy = function () {
self.clearView('insertImageDialog');
}
this.show = function () {
self.createView('insertImageDialog', 'views/wysiwyg/modals/insert-image', {
labels: {
insert: this.lang.image.insert,
url: this.lang.image.url,
selectFromFiles: this.lang.image.selectFromFiles,
},
}, function (view) {
view.render();
self.listenToOnce(view, 'upload', function (target) {
self.$summernote.summernote('insertImagesOrCallback', target);
});
self.listenToOnce(view, 'insert', function (target) {
self.$summernote.summernote('insertImage', target);
});
});
}
},
'espoLink': function (context) {
var ui = $.summernote.ui;
var options = context.options;
var self = options.espoView;
this.lang = options.langInfo;
var isMacLike = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
context.memo('button.espoLink', function () {
var button = ui.button({
contents: options.espoLink.icon,
tooltip: options.espoLink.tooltip + ' (' + (isMacLike ? 'CMD+K': 'CTRL+K') +')',
click: function (e) {
context.invoke('espoLink.show');
},
});
return button.render();
});
this.initialize = function () {
};
this.destroy = function () {
self.clearView('dialogInsertLink');
}
this.show = function () {
var linkInfo = context.invoke('editor.getLinkInfo');
self.createView('dialogInsertLink', 'views/wysiwyg/modals/insert-link', {
labels: {
insert: this.lang.link.insert,
openInNewWindow: this.lang.link.openInNewWindow,
url: this.lang.link.url,
textToDisplay: this.lang.link.textToDisplay,
},
linkInfo: linkInfo,
}, function (view) {
view.render();
self.listenToOnce(view, 'insert', function (data) {
self.$summernote.summernote('createLink', data);
});
});
}
},
});
},
});
});
@@ -0,0 +1,94 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/wysiwyg/modals/insert-image', 'views/modal', function (Dep) {
return Dep.extend({
backdrop: true,
template: 'wysiwyg/modals/insert-image',
events: {
'click [data-action="insert"]': function () {
this.actionInsert();
},
'input [data-name="url"]': function () {
this.toggleInsertButton();
},
'paste [data-name="url"]': function () {
this.toggleInsertButton();
},
},
data: function () {
return {
labels: this.options.labels || {},
};
},
setup: function () {
var labels = this.options.labels || {};
var insertLabel = this.getHelper().escapeString(labels.insert);
this.headerHtml = insertLabel;
this.buttonList = [];
},
afterRender: function () {
var $files = this.$el.find('[data-name="files"]');
$files.replaceWith(
$files.clone().on('change', function (e) {
this.trigger('upload', e.target.files || e.target.value);
this.close();
}.bind(this)).val('')
);
},
toggleInsertButton: function () {
var value = this.$el.find('[data-name="url"]').val().trim();
var $button = this.$el.find('[data-name="insert"]')
if (value) {
$button.removeClass('disabled').removeAttr('disabled');
} else {
$button.addClass('disabled').attr('disabled', 'disabled');
}
},
actionInsert: function () {
var url = this.$el.find('[data-name="url"]').val().trim();
this.trigger('insert', url);
this.close();
},
});
});
@@ -0,0 +1,116 @@
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM - Open Source CRM application.
* Copyright (C) 2014-2019 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
* Website: https://www.espocrm.com
*
* EspoCRM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* EspoCRM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU General Public License version 3.
*
* In accordance with Section 7(b) of the GNU General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
define('views/wysiwyg/modals/insert-link', 'views/modal', function (Dep) {
return Dep.extend({
backdrop: true,
template: 'wysiwyg/modals/insert-link',
events: {
'input [data-name="url"]': function () {
this.controlInputs();
},
'paste [data-name="url"]': function () {
this.controlInputs();
},
},
data: function () {
return {
labels: this.options.labels || {},
};
},
setup: function () {
var labels = this.options.labels || {};
var insertLabel = this.getHelper().escapeString(labels.insert);
this.headerHtml = insertLabel;
this.buttonList = [
{
name: 'insert',
html: this.translate('Insert'),
style: 'primary',
disabled: true,
}
];
this.linkInfo = this.options.linkInfo || {};
if (this.linkInfo.url) {
this.enableButton('insert');
}
},
afterRender: function () {
this.$url = this.$el.find('[data-name="url"]');
this.$text = this.$el.find('[data-name="text"]');
this.$openInNewWindow = this.$el.find('[data-name="openInNewWindow"]');
var linkInfo = this.linkInfo;
this.$url.val(linkInfo.url || '');
this.$text.val(linkInfo.text || '');
if ('isNewWindow' in linkInfo) {
this.$openInNewWindow.get(0).checked = !!linkInfo.isNewWindow;
}
},
controlInputs: function () {
var url = this.$url.val().trim();
if (url) {
this.enableButton('insert');
} else {
this.disableButton('insert');
}
},
actionInsert: function () {
var url = this.$url.val().trim();
var text = this.$text.val().trim();
var openInNewWindow = this.$openInNewWindow.get(0).checked;
var data = {
url: url,
text: text || url,
isNewWindow: openInNewWindow,
range: this.linkInfo.range,
};
this.trigger('insert', data);
this.close();
},
});
});