@themarioga/grid-editor 6.0.0-beta.3 → 6.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BUILDING.md +3 -1
- package/CHANGELOG.md +50 -1
- package/README.md +16 -5
- package/UPGRADING.md +36 -7
- package/dist/grideditor.css +14 -0
- package/dist/grideditor.min.css +1 -1
- package/dist/grideditor.min.css.map +1 -1
- package/dist/jquery.grideditor.bundle.min.js +2 -2
- package/dist/jquery.grideditor.js +303 -385
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +3 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +1 -1
- package/dist/plugins/grideditor.ckeditor.js +397 -3
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +1 -1
- package/dist/plugins/grideditor.summernote.js +397 -3
- package/dist/plugins/grideditor.summernote.min.js +1 -1
- package/dist/plugins/grideditor.summernote.min.js.map +1 -1
- package/dist/plugins/grideditor.tinymce.js +397 -3
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +1 -1
- package/dist/plugins/grideditor.visibility.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js.map +1 -1
- package/docs/events.md +11 -2
- package/docs/locale-keys.md +12 -3
- package/docs/plugins.md +109 -46
- package/example/custom_editor.html +193 -0
- package/example/index.html +8 -0
- package/example/wrap_content.html +5 -3
- package/package.json +1 -1
- package/src/js/jquery.grideditor.js +303 -385
- package/src/js/locales/grideditor.es.js +3 -0
- package/src/js/plugins/grideditor.ckeditor.js +7 -3
- package/src/js/plugins/grideditor.summernote.js +7 -3
- package/src/js/plugins/grideditor.tinymce.js +7 -3
- package/src/js/plugins/grideditor.visibility.js +1 -1
- package/src/js/text/grideditor.text.js +389 -0
- package/src/less/grideditor.less +17 -0
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
'tool.add_text': 'Añadir texto',
|
|
23
23
|
'tool.add_text_type': 'Añadir texto con {editor}',
|
|
24
24
|
'tool.delete_text': 'Quitar texto',
|
|
25
|
+
'tool.delete_plain': 'Quitar contenido',
|
|
26
|
+
'tool.convert_type': 'Editar como texto de {editor}',
|
|
25
27
|
'text.add': 'Texto',
|
|
26
28
|
'text.add_type': 'Texto ({editor})',
|
|
27
29
|
'text.no_editor': 'No hay cargado ningún editor de texto "{type}": este texto se puede mover y borrar, pero no editar',
|
|
@@ -84,6 +86,7 @@
|
|
|
84
86
|
'confirm.delete_row': '¿Seguro que quieres borrar esta fila?',
|
|
85
87
|
'confirm.delete_column': '¿Seguro que quieres borrar esta columna?',
|
|
86
88
|
'confirm.delete_text': '¿Seguro que quieres borrar este texto?',
|
|
89
|
+
'confirm.delete_plain': '¿Seguro que quieres borrar este contenido?',
|
|
87
90
|
'confirm.delete_element': '¿Seguro que quieres borrar este elemento?',
|
|
88
91
|
'confirm.delete_container': '¿Seguro que quieres borrar este contenedor y todo su contenido?',
|
|
89
92
|
'confirm.delete_tab': '¿Seguro que quieres borrar esta pestaña y todo su contenido?',
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* CKEditor for grid-editor's content areas.
|
|
3
3
|
*
|
|
4
4
|
* A text editor plugin: load this file after the editor, and CKEditor 4
|
|
5
|
-
* after or before it, and
|
|
6
|
-
*
|
|
5
|
+
* after or before it, and a text of the ckeditor type is edited with an
|
|
6
|
+
* inline CKEditor. What it can ask the editor for is the handle its
|
|
7
7
|
* factory is called with, described in docs/plugins.md.
|
|
8
8
|
*
|
|
9
9
|
* <script src="ckeditor/ckeditor.js"></script>
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
* <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
|
|
12
12
|
*
|
|
13
13
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
|
-
* loaded on its own, like every plugin.
|
|
14
|
+
* loaded on its own, like every plugin. The built file starts with what
|
|
15
|
+
* every text editor shares - text blocks, the Text button and the Add text
|
|
16
|
+
* tool, createText, making the host's plain content a text - from
|
|
17
|
+
* src/js/text/grideditor.text.js, installed once however many editors a
|
|
18
|
+
* page loads.
|
|
15
19
|
*/
|
|
16
20
|
(function($) {
|
|
17
21
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Summernote for grid-editor's content areas.
|
|
3
3
|
*
|
|
4
4
|
* A text editor plugin: load this file after the editor, and summernote
|
|
5
|
-
* after or before it, and
|
|
6
|
-
*
|
|
5
|
+
* after or before it, and a text of the summernote type is edited with
|
|
6
|
+
* summernote in air mode. What it can ask the editor for is the
|
|
7
7
|
* handle its factory is called with, described in docs/plugins.md.
|
|
8
8
|
*
|
|
9
9
|
* <script src="summernote/summernote-bs5.min.js"></script>
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
* <script src="dist/plugins/grideditor.summernote.min.js"></script>
|
|
12
12
|
*
|
|
13
13
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
|
-
* loaded on its own, like every plugin.
|
|
14
|
+
* loaded on its own, like every plugin. The built file starts with what
|
|
15
|
+
* every text editor shares - text blocks, the Text button and the Add text
|
|
16
|
+
* tool, createText, making the host's plain content a text - from
|
|
17
|
+
* src/js/text/grideditor.text.js, installed once however many editors a
|
|
18
|
+
* page loads.
|
|
15
19
|
*/
|
|
16
20
|
(function($) {
|
|
17
21
|
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* tinyMCE for grid-editor's content areas.
|
|
3
3
|
*
|
|
4
4
|
* A text editor plugin: load this file after the editor, and tinyMCE 6
|
|
5
|
-
* after or before it, and
|
|
6
|
-
*
|
|
5
|
+
* after or before it, and a text of the tinymce type is edited with an
|
|
6
|
+
* inline tinyMCE. What it can ask the editor for is the handle its
|
|
7
7
|
* factory is called with, described in docs/plugins.md.
|
|
8
8
|
*
|
|
9
9
|
* <script src="tinymce/tinymce.min.js"></script>
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
* <script src="dist/plugins/grideditor.tinymce.min.js"></script>
|
|
12
12
|
*
|
|
13
13
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
|
-
* loaded on its own, like every plugin.
|
|
14
|
+
* loaded on its own, like every plugin. The built file starts with what
|
|
15
|
+
* every text editor shares - text blocks, the Text button and the Add text
|
|
16
|
+
* tool, createText, making the host's plain content a text - from
|
|
17
|
+
* src/js/text/grideditor.text.js, installed once however many editors a
|
|
18
|
+
* page loads.
|
|
15
19
|
*/
|
|
16
20
|
(function($) {
|
|
17
21
|
|
|
@@ -44,7 +44,7 @@ $.fn.gridEditor.utilities.visibility = function(ge) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
function applies(node, kind) {
|
|
47
|
-
return kind === 'row' || kind === 'column' || kind === 'element' || kind === 'text' ||
|
|
47
|
+
return kind === 'row' || kind === 'column' || kind === 'element' || kind === 'text' || kind === 'plain' ||
|
|
48
48
|
node.is('[data-ge-container]');
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Text for grid-editor: what the text editor plugins share.
|
|
3
|
+
*
|
|
4
|
+
* Not a file a page loads. The build puts it at the top of each text editor
|
|
5
|
+
* plugin - grideditor.tinymce.js, grideditor.ckeditor.js,
|
|
6
|
+
* grideditor.summernote.js - and whichever of them loads first installs it:
|
|
7
|
+
* a page with two editors has one of these.
|
|
8
|
+
*
|
|
9
|
+
* It is a feature plugin, `text`, that the `plugins` setting does not choose
|
|
10
|
+
* (content_types does), and it is everything a text is to the editor: the
|
|
11
|
+
* text block's drawer, the Text buttons in the toolbar and the Add text tool
|
|
12
|
+
* in each column, createText, opening an editor on a click and closing it
|
|
13
|
+
* again with the host's attributes put back, and making the host's plain
|
|
14
|
+
* content a text through the core's `textTypes` hook.
|
|
15
|
+
*
|
|
16
|
+
* Each editor registers under $.fn.gridEditor.texts, which is this file's own
|
|
17
|
+
* registry and not a contract: an editor of a host's own is a feature plugin
|
|
18
|
+
* of its own, as example/custom_editor.html shows.
|
|
19
|
+
*/
|
|
20
|
+
(function($) {
|
|
21
|
+
|
|
22
|
+
if ($.fn.gridEditor.features.text) { return; }
|
|
23
|
+
|
|
24
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
25
|
+
'tool.add_text': 'Add text',
|
|
26
|
+
'tool.add_text_type': 'Add {editor} text',
|
|
27
|
+
'text.add': 'Text',
|
|
28
|
+
'text.add_type': 'Text ({editor})',
|
|
29
|
+
'panel.editor': 'Editor',
|
|
30
|
+
'panel.kind_text': 'Text',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/** The text editors, by the content type each edits. */
|
|
34
|
+
$.fn.gridEditor.texts = $.fn.gridEditor.texts || {};
|
|
35
|
+
|
|
36
|
+
/** What a text editor puts on a content area while it is open, whenever it likes. */
|
|
37
|
+
var EDITOR_CLASS = /^(mce-|cke|note-)|^(active|ge-rte-active)$/;
|
|
38
|
+
var EDITOR_ATTRIBUTE = /^(data-mce-|contenteditable$|spellcheck$)/;
|
|
39
|
+
|
|
40
|
+
function attributesOf(element) {
|
|
41
|
+
var found = {};
|
|
42
|
+
$.each($.makeArray(element.attributes), function(i, attribute) {
|
|
43
|
+
found[attribute.name] = attribute.value;
|
|
44
|
+
});
|
|
45
|
+
return found;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function classesIn(value) {
|
|
49
|
+
return (value || '').split(/\s+/).filter(function(name) {
|
|
50
|
+
return name !== '' && !EDITOR_CLASS.test(name);
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The host's markup, with what changed from `ready` to `open` played back onto it. */
|
|
55
|
+
function restoreAttributes(block, before, ready, open) {
|
|
56
|
+
var result = $.extend({}, before);
|
|
57
|
+
|
|
58
|
+
$.each($.extend({}, ready, open), function(name) {
|
|
59
|
+
if (name === 'class' || EDITOR_ATTRIBUTE.test(name) || ready[name] === open[name]) { return; }
|
|
60
|
+
|
|
61
|
+
if (open[name] === undefined) {
|
|
62
|
+
delete result[name];
|
|
63
|
+
} else {
|
|
64
|
+
result[name] = open[name];
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
var readyClasses = classesIn(ready['class']);
|
|
69
|
+
var openClasses = classesIn(open['class']);
|
|
70
|
+
var classes = classesIn(before['class']).filter(function(name) {
|
|
71
|
+
return openClasses.indexOf(name) !== -1 || readyClasses.indexOf(name) === -1;
|
|
72
|
+
});
|
|
73
|
+
openClasses.forEach(function(name) {
|
|
74
|
+
if (readyClasses.indexOf(name) === -1 && classes.indexOf(name) === -1) { classes.push(name); }
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// In the host's order, class where it was: getHtml should not
|
|
78
|
+
// shuffle a node's attributes because it was edited
|
|
79
|
+
if (classes.length) { result['class'] = classes.join(' '); } else { delete result['class']; }
|
|
80
|
+
|
|
81
|
+
$.each(attributesOf(block[0]), function(name) { block.removeAttr(name); });
|
|
82
|
+
$.each(result, function(name, value) { block.attr(name, value); });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function textFeature(ge) {
|
|
86
|
+
|
|
87
|
+
var settings = ge.settings;
|
|
88
|
+
var TEXTS = {};
|
|
89
|
+
var warned = {};
|
|
90
|
+
|
|
91
|
+
$.each($.fn.gridEditor.texts, function(type, factory) {
|
|
92
|
+
TEXTS[type] = factory(ge);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Every editor loaded, in the order the page loaded them, unless the
|
|
96
|
+
// host names the ones it wants
|
|
97
|
+
if (!Array.isArray(settings.content_types)) { settings.content_types = Object.keys(TEXTS); }
|
|
98
|
+
if (!Array.isArray(settings.text_tools)) { settings.text_tools = []; }
|
|
99
|
+
if (!Array.isArray(settings.text_classes)) { settings.text_classes = []; }
|
|
100
|
+
|
|
101
|
+
/** The text editors this editor offers, in content_types order: the ones loaded. */
|
|
102
|
+
function offeredTexts() {
|
|
103
|
+
return settings.content_types.filter(function(type) { return !!TEXTS[type]; });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** What a text editor is called: its plugin's label, or its type. */
|
|
107
|
+
function textLabel(type) {
|
|
108
|
+
var text = TEXTS[type];
|
|
109
|
+
return text && text.labelKey ? ge.t(text.labelKey) : type;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** A detached content area of `type`, holding `content` or the editor's initial content. */
|
|
113
|
+
function makeText(type, content) {
|
|
114
|
+
var text = TEXTS[type];
|
|
115
|
+
|
|
116
|
+
return $('<div class="ge-content" />')
|
|
117
|
+
.addClass('ge-content-type-' + type)
|
|
118
|
+
.attr('data-ge-content-type', type)
|
|
119
|
+
.html(content !== undefined ? content : (text && text.initialContent) || '');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** A text block at the end of a column, through the add events. */
|
|
123
|
+
function addTextTo(col, type) {
|
|
124
|
+
return ge.place(makeText(type), 'text', { appendTo: col, source: 'tool' });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* createText(type?, options?): a content area of a text editor's,
|
|
129
|
+
* detached unless a placement is given. The type is the first one
|
|
130
|
+
* offered by default. `options.content` is its html.
|
|
131
|
+
*/
|
|
132
|
+
function apiCreateText(type, options) {
|
|
133
|
+
if (type && typeof type === 'object') {
|
|
134
|
+
options = type;
|
|
135
|
+
type = undefined;
|
|
136
|
+
}
|
|
137
|
+
options = options || {};
|
|
138
|
+
type = type || offeredTexts()[0];
|
|
139
|
+
|
|
140
|
+
if (!type || !TEXTS[type]) {
|
|
141
|
+
if (!warned['createText:' + type]) {
|
|
142
|
+
warned['createText:' + type] = true;
|
|
143
|
+
ge.warn('createText: no text editor "' + type + '" is loaded; ' +
|
|
144
|
+
'load its plugin and name it in content_types');
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return ge.place(makeText(type, options.content), 'text', options);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/** Whether a content area is a text of one of the editors loaded here. */
|
|
153
|
+
function isOurs(block) {
|
|
154
|
+
return !!TEXTS[block.attr('data-ge-content-type')];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** Open the editor on a text, once: until it is closed again. */
|
|
158
|
+
function startText(block) {
|
|
159
|
+
if (block.hasClass('ge-rte-active')) { return; }
|
|
160
|
+
|
|
161
|
+
// A content area nobody can see - a tab that is not the open one,
|
|
162
|
+
// a closed accordion item - has no geometry for an editor to lay
|
|
163
|
+
// its toolbar out against, and nothing anyone can type into
|
|
164
|
+
if (!block.is(':visible')) { return; }
|
|
165
|
+
|
|
166
|
+
// The attribute, not jQuery's cached copy of it: it is markup, and
|
|
167
|
+
// the drawer reads it the same way
|
|
168
|
+
var text = TEXTS[block.attr('data-ge-content-type')];
|
|
169
|
+
if (!text) { return; }
|
|
170
|
+
|
|
171
|
+
// Not marked active, so the next click tries again: the library
|
|
172
|
+
// may be loaded by then
|
|
173
|
+
if (text.available && !text.available()) {
|
|
174
|
+
if (text.missingKey) { console.error(ge.t(text.missingKey)); }
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
block.data('ge-text-before', attributesOf(block[0])).removeData('ge-text-ready');
|
|
179
|
+
block.addClass('ge-rte-active');
|
|
180
|
+
text.start(block);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function onClick() {
|
|
184
|
+
startText($(this));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Close the text editor on one content area, and leave the content
|
|
189
|
+
* area's own attributes as the host left them.
|
|
190
|
+
*
|
|
191
|
+
* An editor adds attributes of its own while it is open, and takes
|
|
192
|
+
* them off again, more or less: CKEditor leaves aria-readonly behind.
|
|
193
|
+
* tinyMCE does worse, and puts back every attribute as it was when it
|
|
194
|
+
* opened, so an id, a class or a plugin's attribute given while it was
|
|
195
|
+
* open is lost. So the attributes are read three times - before the
|
|
196
|
+
* editor opens, once it has opened, and before it closes - and what
|
|
197
|
+
* changed between the second and the third, the host's doing, is
|
|
198
|
+
* played back onto the first, the host's markup. What the editor did
|
|
199
|
+
* is left out either way.
|
|
200
|
+
*/
|
|
201
|
+
function closeText(block) {
|
|
202
|
+
var text = TEXTS[block.attr('data-ge-content-type')];
|
|
203
|
+
var before = block.data('ge-text-before');
|
|
204
|
+
var open = before ? attributesOf(block[0]) : null;
|
|
205
|
+
|
|
206
|
+
// Every content area is told, as in 5.x: one whose editor never
|
|
207
|
+
// started is the plugin's to ignore
|
|
208
|
+
if (text) { text.stop(block); }
|
|
209
|
+
|
|
210
|
+
// After stop, not before: an editor that restores the class
|
|
211
|
+
// attribute it snapshotted would put ge-rte-active back
|
|
212
|
+
block.removeClass('ge-rte-active');
|
|
213
|
+
|
|
214
|
+
if (before) {
|
|
215
|
+
restoreAttributes(block, before, block.data('ge-text-ready') || before, open);
|
|
216
|
+
block.removeData('ge-text-before').removeData('ge-text-ready');
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function createTextControls(textBlock) {
|
|
221
|
+
var block = textBlock.children('.ge-content');
|
|
222
|
+
var type = block.attr('data-ge-content-type');
|
|
223
|
+
var drawer = $('<div class="ge-tools-drawer ge-text-drawer" />').prependTo(textBlock);
|
|
224
|
+
|
|
225
|
+
ge.createMoveTool(drawer);
|
|
226
|
+
|
|
227
|
+
var details = ge.addSettingsTool(drawer, block, settings.text_classes);
|
|
228
|
+
|
|
229
|
+
// Which editor edits it, first in its settings: something to
|
|
230
|
+
// know about it, not something to do with it
|
|
231
|
+
$('<div class="ge-field ge-text-editor" />')
|
|
232
|
+
.append($('<span class="ge-field-label" />').text(ge.t('panel.editor')))
|
|
233
|
+
.append($('<span class="ge-field-value" />').text(textLabel(type)))
|
|
234
|
+
.prependTo(details.children('.ge-details-general'));
|
|
235
|
+
|
|
236
|
+
settings.text_tools.forEach(function(hostTool) {
|
|
237
|
+
ge.createTool(drawer, hostTool.title || '', hostTool.className || '',
|
|
238
|
+
hostTool.iconClass || 'bi bi-wrench', hostTool.on);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
ge.createTool(drawer, ge.t('tool.delete_text'), 'ge-delete-text', 'bi bi-trash', function() {
|
|
242
|
+
ge.deleteNode('text', block, ge.t('confirm.delete_text'), function(removed) {
|
|
243
|
+
// Its editor lets go first: removed while open, it would
|
|
244
|
+
// be left behind, attached to nothing
|
|
245
|
+
closeText(block);
|
|
246
|
+
textBlock.slideUp(function() {
|
|
247
|
+
textBlock.remove();
|
|
248
|
+
removed();
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** A drawer for each text of ours in a text block that has none yet. */
|
|
255
|
+
function markTexts() {
|
|
256
|
+
ge.canvas.find('.ge-text-block').each(function() {
|
|
257
|
+
var textBlock = $(this);
|
|
258
|
+
if (textBlock.children('.ge-tools-drawer').length) { return; }
|
|
259
|
+
if (!isOurs(textBlock.children('.ge-content'))) { return; }
|
|
260
|
+
|
|
261
|
+
createTextControls(textBlock);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* The add text tool, in each column's drawer before its add row tool:
|
|
267
|
+
* a text of the first editor offered, or, held, of the one chosen.
|
|
268
|
+
*/
|
|
269
|
+
function addTextTools() {
|
|
270
|
+
var texts = offeredTexts();
|
|
271
|
+
if (!texts.length) { return; }
|
|
272
|
+
|
|
273
|
+
ge.canvas.find('.column').each(function() {
|
|
274
|
+
var col = $(this);
|
|
275
|
+
var drawer = col.children('.ge-tools-drawer');
|
|
276
|
+
if (!drawer.length || drawer.children('.ge-add-text').length) { return; }
|
|
277
|
+
|
|
278
|
+
ge.createTool(drawer, ge.t('tool.add_text'), 'ge-add-text', 'bi bi-type', function() {
|
|
279
|
+
if (ge.closePicker()) { return; } // The picker was open: that was the answer
|
|
280
|
+
|
|
281
|
+
addTextTo(col, texts[0]);
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
var tool = drawer.children('.ge-add-text');
|
|
285
|
+
var addRow = drawer.children('.ge-add-row');
|
|
286
|
+
if (addRow.length) { tool.insertBefore(addRow); }
|
|
287
|
+
|
|
288
|
+
if (texts.length > 1) {
|
|
289
|
+
ge.attachPicker(tool, function() {
|
|
290
|
+
ge.openPicker(tool, texts.map(function(type) {
|
|
291
|
+
return {
|
|
292
|
+
label: textLabel(type),
|
|
293
|
+
title: ge.t('tool.add_text_type', { editor: textLabel(type) }),
|
|
294
|
+
attributes: { 'data-ge-content-type': type },
|
|
295
|
+
choose: function() { addTextTo(col, type); },
|
|
296
|
+
};
|
|
297
|
+
}), 'ge-text-picker');
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
var texts = offeredTexts();
|
|
304
|
+
|
|
305
|
+
return {
|
|
306
|
+
methods: {
|
|
307
|
+
createText: apiCreateText,
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* The types this plugin edits, for the core: every editor loaded
|
|
312
|
+
* is the owner of its texts, and the ones offered are what the
|
|
313
|
+
* host's plain content can be made.
|
|
314
|
+
*/
|
|
315
|
+
textTypes: function() {
|
|
316
|
+
var offered = offeredTexts();
|
|
317
|
+
var others = Object.keys(TEXTS).filter(function(type) { return offered.indexOf(type) === -1; });
|
|
318
|
+
|
|
319
|
+
return offered.concat(others).map(function(type) {
|
|
320
|
+
var text = TEXTS[type];
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
type: type,
|
|
324
|
+
label: textLabel(type),
|
|
325
|
+
offered: offered.indexOf(type) !== -1,
|
|
326
|
+
available: text.available ? function() { return text.available(); } : null,
|
|
327
|
+
missingKey: text.missingKey,
|
|
328
|
+
edit: function(block) {
|
|
329
|
+
var textBlock = block.parent('.ge-text-block');
|
|
330
|
+
if (textBlock.length && !textBlock.children('.ge-tools-drawer').length) {
|
|
331
|
+
createTextControls(textBlock);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
startText(block);
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
});
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
// A text block of each editor offered. Like a container, it goes
|
|
341
|
+
// into a row of its own when clicked, or where it is dropped
|
|
342
|
+
toolbar: texts.map(function(type) {
|
|
343
|
+
return {
|
|
344
|
+
label: function() {
|
|
345
|
+
return texts.length > 1 ? ge.t('text.add_type', { editor: textLabel(type) }) : ge.t('text.add');
|
|
346
|
+
},
|
|
347
|
+
iconClass: TEXTS[type].iconClass,
|
|
348
|
+
className: 'ge-add-text-button',
|
|
349
|
+
kind: 'text',
|
|
350
|
+
inColumn: true,
|
|
351
|
+
create: function() { return makeText(type); },
|
|
352
|
+
};
|
|
353
|
+
}),
|
|
354
|
+
|
|
355
|
+
onInit: function() {
|
|
356
|
+
markTexts();
|
|
357
|
+
addTextTools();
|
|
358
|
+
|
|
359
|
+
ge.canvas.off('click.ge-text').on('click.ge-text', '.ge-content', onClick);
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
// While the drawers and the text blocks are still there, as the
|
|
363
|
+
// editors left them
|
|
364
|
+
onBeforeDeinit: function() {
|
|
365
|
+
ge.canvas.find('.ge-content').each(function() {
|
|
366
|
+
if (isOurs($(this))) { closeText($(this)); }
|
|
367
|
+
});
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
onDeinit: function() {
|
|
371
|
+
ge.canvas.off('click.ge-text');
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
// The first time only: an undo says ready again, and by then the
|
|
375
|
+
// host may have changed the content area itself
|
|
376
|
+
onContentReady: function(area) {
|
|
377
|
+
if (area.data('ge-text-before') && !area.data('ge-text-ready')) {
|
|
378
|
+
area.data('ge-text-ready', attributesOf(area[0]));
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Whatever the plugins setting says: content_types chooses the editors
|
|
385
|
+
textFeature.always = true;
|
|
386
|
+
|
|
387
|
+
$.fn.gridEditor.features.text = textFeature;
|
|
388
|
+
|
|
389
|
+
})(jQuery);
|
package/src/less/grideditor.less
CHANGED
|
@@ -707,6 +707,23 @@
|
|
|
707
707
|
left: 0;
|
|
708
708
|
border-radius: 0;
|
|
709
709
|
}
|
|
710
|
+
|
|
711
|
+
/* The choice of editor a click on plain content offers hangs off
|
|
712
|
+
the drawer, which sits at the right: so it opens leftwards */
|
|
713
|
+
> .ge-text-drawer > .ge-convert-picker {
|
|
714
|
+
left: auto;
|
|
715
|
+
right: 0;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* The host's plain content: a block to move and delete, edited in the
|
|
720
|
+
source - greyer than a text, which an editor edits in place */
|
|
721
|
+
.ge-text-block.ge-plain-block {
|
|
722
|
+
outline-color: rgba(0, 0, 0, 0.25);
|
|
723
|
+
|
|
724
|
+
> .ge-text-drawer {
|
|
725
|
+
background: #e9ecef;
|
|
726
|
+
}
|
|
710
727
|
}
|
|
711
728
|
|
|
712
729
|
/* A column with nothing in it but its drawer still has room to drop a
|