@themarioga/grid-editor 6.0.0-beta.4 → 6.0.0
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/CHANGELOG.md +31 -0
- package/README.md +60 -6
- package/UPGRADING.md +27 -2
- package/dist/grideditor.css +46 -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 +53 -20
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +4 -2
- 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 +6 -52
- package/dist/plugins/grideditor.ckeditor.min.js +1 -1
- package/dist/plugins/grideditor.ckeditor.min.js.map +1 -1
- package/dist/plugins/grideditor.codemirror-inline.js +190 -0
- package/dist/plugins/grideditor.codemirror-inline.min.js +2 -0
- package/dist/plugins/grideditor.codemirror-inline.min.js.map +1 -0
- package/dist/plugins/grideditor.codemirror.js +79 -0
- package/dist/plugins/grideditor.codemirror.min.js +2 -0
- package/dist/plugins/grideditor.codemirror.min.js.map +1 -0
- package/dist/plugins/grideditor.summernote.js +6 -52
- 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 +6 -52
- package/dist/plugins/grideditor.tinymce.min.js +1 -1
- package/dist/plugins/grideditor.tinymce.min.js.map +1 -1
- package/docs/events.md +6 -0
- package/docs/locale-keys.md +14 -4
- package/docs/plugins.md +20 -5
- package/example/codemirror.html +103 -0
- package/example/index.html +8 -0
- package/package.json +1 -1
- package/src/js/jquery.grideditor.js +53 -20
- package/src/js/locales/grideditor.es.js +4 -2
- package/src/js/plugins/grideditor.ckeditor.js +2 -2
- package/src/js/plugins/grideditor.codemirror-inline.js +190 -0
- package/src/js/plugins/grideditor.codemirror.js +79 -0
- package/src/js/plugins/grideditor.summernote.js +2 -2
- package/src/js/plugins/grideditor.tinymce.js +2 -2
- package/src/js/text/grideditor.text.js +4 -50
- package/src/less/grideditor.less +54 -0
|
@@ -358,6 +358,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
358
358
|
'default_view' : ALL_VIEW,
|
|
359
359
|
'resize' : NESTED_SETTINGS.resize, // Resizing a column by dragging its edge
|
|
360
360
|
'source_textarea' : '',
|
|
361
|
+
'edit_source' : true, // The toolbar's button to edit the canvas as html
|
|
361
362
|
'locale' : 'en', // Code of a locale in $.fn.gridEditor.locales
|
|
362
363
|
'locale_strings' : {}, // Overrides for individual keys
|
|
363
364
|
'callbacks' : {}, // before_*/after_* functions, the events by another route
|
|
@@ -397,6 +398,7 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
397
398
|
var curView = settings.default_view; // Breakpoint key, or 'all'
|
|
398
399
|
var confirmDialog = null; // The delete confirmation, built when first needed
|
|
399
400
|
var sizePicker = null; // The open column size picker, if there is one
|
|
401
|
+
var sourceOpen = false; // Whether the canvas is being edited as html
|
|
400
402
|
var dropMarker = null; // The line showing where a dragged toolbar button would land
|
|
401
403
|
var warnedHere = {}; // Deprecations are worth saying once per instance, not once per call
|
|
402
404
|
var sortables = []; // Every list made sortable, so deinit destroys exactly those
|
|
@@ -1003,27 +1005,23 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1003
1005
|
var btnGroup = $('<div class="btn-group pull-right"/>')
|
|
1004
1006
|
.appendTo(wrapper)
|
|
1005
1007
|
;
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
.val(canvas.html())
|
|
1018
|
-
.show()
|
|
1019
|
-
;
|
|
1020
|
-
canvas.hide();
|
|
1021
|
-
}
|
|
1008
|
+
if (settings.edit_source) {
|
|
1009
|
+
// Built again by setLocale, maybe with the source open
|
|
1010
|
+
var htmlButton = $('<button type="button" class="btn btn-sm btn-primary gm-edit-mode"><i class="bi bi-code-slash"></i></button>')
|
|
1011
|
+
.attr('title', t('tool.edit_source'))
|
|
1012
|
+
.toggleClass('active btn-danger', sourceOpen)
|
|
1013
|
+
.on('click', function() {
|
|
1014
|
+
if (sourceOpen) {
|
|
1015
|
+
closeSource();
|
|
1016
|
+
} else {
|
|
1017
|
+
openSource();
|
|
1018
|
+
}
|
|
1022
1019
|
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1020
|
+
htmlButton.toggleClass('active btn-danger', sourceOpen);
|
|
1021
|
+
})
|
|
1022
|
+
.appendTo(btnGroup)
|
|
1023
|
+
;
|
|
1024
|
+
}
|
|
1027
1025
|
var previewButton = $('<button type="button" class="btn btn-sm btn-primary gm-preview"><i class="bi bi-eye-fill"></i></button>')
|
|
1028
1026
|
.attr('title', t('tool.preview'))
|
|
1029
1027
|
.on('mouseenter', function() {
|
|
@@ -1584,6 +1582,32 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1584
1582
|
init();
|
|
1585
1583
|
}
|
|
1586
1584
|
|
|
1585
|
+
/**
|
|
1586
|
+
* The canvas as html, in the textarea in its place, to edit by hand.
|
|
1587
|
+
* A feature plugin's onSourceOpen may put a code editor over the
|
|
1588
|
+
* textarea; its onSourceClose puts what it holds back in it, which is
|
|
1589
|
+
* what the canvas is made of again.
|
|
1590
|
+
*/
|
|
1591
|
+
function openSource() {
|
|
1592
|
+
deinit();
|
|
1593
|
+
htmlTextArea
|
|
1594
|
+
.height(0.8 * $(window).height())
|
|
1595
|
+
.val(canvas.html())
|
|
1596
|
+
.show()
|
|
1597
|
+
;
|
|
1598
|
+
canvas.hide();
|
|
1599
|
+
sourceOpen = true;
|
|
1600
|
+
plugins('onSourceOpen', htmlTextArea);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
function closeSource() {
|
|
1604
|
+
plugins('onSourceClose', htmlTextArea);
|
|
1605
|
+
sourceOpen = false;
|
|
1606
|
+
canvas.empty().html(htmlTextArea.val()).show();
|
|
1607
|
+
init();
|
|
1608
|
+
htmlTextArea.hide();
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1587
1611
|
function init() {
|
|
1588
1612
|
// The node whose settings were open is gone - deleted, say - and
|
|
1589
1613
|
// its panel with it
|
|
@@ -1662,6 +1686,8 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
1662
1686
|
}
|
|
1663
1687
|
|
|
1664
1688
|
function destroy() {
|
|
1689
|
+
// The html being edited is what the canvas is left with
|
|
1690
|
+
if (sourceOpen) { closeSource(); }
|
|
1665
1691
|
deinit();
|
|
1666
1692
|
removeConfirmModal();
|
|
1667
1693
|
removeSettingsPanels();
|
|
@@ -4581,6 +4607,13 @@ $.fn.gridEditor = function( optionsOrMethod ) {
|
|
|
4581
4607
|
textBlock.addClass('ge-plain-block');
|
|
4582
4608
|
|
|
4583
4609
|
createMoveTool(drawer);
|
|
4610
|
+
|
|
4611
|
+
// The tools a feature plugin gives plain content, which is not
|
|
4612
|
+
// every plugin's drawerTools: no gear, no utilities, no copy
|
|
4613
|
+
$.each(FEATURES, function(name, feature) {
|
|
4614
|
+
if (feature.plainTools) { feature.plainTools(drawer, block); }
|
|
4615
|
+
});
|
|
4616
|
+
|
|
4584
4617
|
createTool(drawer, t('tool.delete_plain'), 'ge-delete-plain', 'bi bi-trash', function() {
|
|
4585
4618
|
deleteNode('plain', block, t('confirm.delete_plain'), function(removed) {
|
|
4586
4619
|
textBlock.slideUp(function() {
|
|
@@ -19,10 +19,11 @@
|
|
|
19
19
|
'tool.move': 'Mover',
|
|
20
20
|
'tool.settings': 'Configuración',
|
|
21
21
|
'tool.add_row': 'Añadir fila',
|
|
22
|
-
'tool.add_text': 'Añadir texto',
|
|
23
|
-
'tool.add_text_type': 'Añadir texto con {editor}',
|
|
24
22
|
'tool.delete_text': 'Quitar texto',
|
|
25
23
|
'tool.delete_plain': 'Quitar contenido',
|
|
24
|
+
'tool.edit_html': 'Editar html',
|
|
25
|
+
'codemirror.apply': 'Aplicar',
|
|
26
|
+
'codemirror.cancel': 'Cancelar',
|
|
26
27
|
'tool.convert_type': 'Editar como texto de {editor}',
|
|
27
28
|
'text.add': 'Texto',
|
|
28
29
|
'text.add_type': 'Texto ({editor})',
|
|
@@ -161,6 +162,7 @@
|
|
|
161
162
|
'warning.setting_removed': 'El ajuste {setting} se eliminó en la 4.0. Usa {replacement} en su lugar.',
|
|
162
163
|
'error.tinymce_missing': '¡tinyMCE no está disponible! Asegúrate de haber cargado el archivo js de tinyMCE.',
|
|
163
164
|
'error.ckeditor_missing': '¡CKEditor no está disponible! Asegúrate de haber cargado los archivos js de ckeditor y del adaptador de jQuery.',
|
|
165
|
+
'error.codemirror_missing': '¡CodeMirror no está disponible! Asegúrate de haber cargado el archivo js de CodeMirror; sin él el código se edita en un textarea normal.',
|
|
164
166
|
'error.summernote_missing': '¡Summernote no está disponible! Asegúrate de haber cargado el archivo js de Summernote.',
|
|
165
167
|
};
|
|
166
168
|
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
14
|
* loaded on its own, like every plugin. The built file starts with what
|
|
15
|
-
* every text editor shares - text blocks, the Text button
|
|
16
|
-
*
|
|
15
|
+
* every text editor shares - text blocks, the Text button, createText,
|
|
16
|
+
* making the host's plain content a text - from
|
|
17
17
|
* src/js/text/grideditor.text.js, installed once however many editors a
|
|
18
18
|
* page loads.
|
|
19
19
|
*/
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A block's html, edited in place with CodeMirror.
|
|
3
|
+
*
|
|
4
|
+
* A feature plugin: load this file after the editor, and CodeMirror 5 with
|
|
5
|
+
* its html mode after or before it, and every drawer of a row, a column, a
|
|
6
|
+
* text, the host's plain content, an element, a section or a container has a
|
|
7
|
+
* </> tool. It opens the block's html - the block itself and everything in
|
|
8
|
+
* it, as getHtml would give it - in CodeMirror where the block was, and
|
|
9
|
+
* Apply puts what was written in the block's place. What it can ask the
|
|
10
|
+
* editor for is the handle its factory is called with, described in
|
|
11
|
+
* docs/plugins.md.
|
|
12
|
+
*
|
|
13
|
+
* <link rel="stylesheet" href="codemirror/lib/codemirror.css">
|
|
14
|
+
* <script src="codemirror/lib/codemirror.js"></script>
|
|
15
|
+
* <script src="codemirror/mode/xml/xml.js"></script>
|
|
16
|
+
* <script src="codemirror/mode/javascript/javascript.js"></script>
|
|
17
|
+
* <script src="codemirror/mode/css/css.js"></script>
|
|
18
|
+
* <script src="codemirror/mode/htmlmixed/htmlmixed.js"></script>
|
|
19
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
20
|
+
* <script src="dist/plugins/grideditor.codemirror-inline.min.js"></script>
|
|
21
|
+
*
|
|
22
|
+
* Without CodeMirror on the page the html is edited in a plain textarea.
|
|
23
|
+
* CodeMirror's options are the codemirror plugin's, codemirror.config.
|
|
24
|
+
*/
|
|
25
|
+
(function($) {
|
|
26
|
+
|
|
27
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
28
|
+
'tool.edit_html': 'Edit html',
|
|
29
|
+
'codemirror.apply': 'Apply',
|
|
30
|
+
'codemirror.cancel': 'Cancel',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/** What has html of its own to edit: a pane's is split between its button and its body. */
|
|
34
|
+
var KINDS = ['row', 'column', 'text', 'plain', 'element', 'section'];
|
|
35
|
+
|
|
36
|
+
$.fn.gridEditor.features['codemirror-inline'] = function(ge) {
|
|
37
|
+
|
|
38
|
+
var open = []; // The blocks being edited: { node, kind, from, wrapper, textarea, editor }
|
|
39
|
+
|
|
40
|
+
function options() {
|
|
41
|
+
var own = (ge.settings.codemirror && ge.settings.codemirror.config) || {};
|
|
42
|
+
|
|
43
|
+
return $.extend({
|
|
44
|
+
mode: 'htmlmixed',
|
|
45
|
+
lineNumbers: true,
|
|
46
|
+
lineWrapping: true,
|
|
47
|
+
tabSize: 2,
|
|
48
|
+
indentUnit: 2,
|
|
49
|
+
// As tall as what it holds, up to the css's limit
|
|
50
|
+
viewportMargin: Infinity,
|
|
51
|
+
}, own);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** What stands for the node in its column: a text's text block, or the node. */
|
|
55
|
+
function anchorOf(node) {
|
|
56
|
+
var textBlock = node.parent('.ge-text-block');
|
|
57
|
+
return textBlock.length ? textBlock : node;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function entryOf(node) {
|
|
61
|
+
return open.filter(function(entry) { return entry.node[0] === node[0]; })[0] || null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function editable(node, kind) {
|
|
65
|
+
return KINDS.indexOf(kind) !== -1 || node.is('[data-ge-container]');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** The editor where the block was, the block hidden behind it. */
|
|
69
|
+
function show(entry) {
|
|
70
|
+
var anchor = anchorOf(entry.node).addClass('ge-code-hidden');
|
|
71
|
+
entry.wrapper.insertAfter(anchor);
|
|
72
|
+
if (entry.editor) { entry.editor.refresh(); }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function hide(entry) {
|
|
76
|
+
entry.wrapper.detach();
|
|
77
|
+
anchorOf(entry.node).removeClass('ge-code-hidden');
|
|
78
|
+
entry.node.removeClass('ge-code-hidden');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function close(entry) {
|
|
82
|
+
hide(entry);
|
|
83
|
+
if (entry.editor) { entry.editor.toTextArea(); }
|
|
84
|
+
entry.wrapper.remove();
|
|
85
|
+
open.splice(open.indexOf(entry), 1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function openEditor(node) {
|
|
89
|
+
if (entryOf(node)) { return; }
|
|
90
|
+
|
|
91
|
+
var entry = {
|
|
92
|
+
node: node,
|
|
93
|
+
kind: ge.kindOf(node),
|
|
94
|
+
// As getHtml gives it: no drawers, no editor open in it
|
|
95
|
+
from: ge.nodeHtml(node),
|
|
96
|
+
// A drawer, to the editor: never content, never a block to move
|
|
97
|
+
wrapper: $('<div class="ge-tools-drawer ge-code-inline" />'),
|
|
98
|
+
editor: null,
|
|
99
|
+
};
|
|
100
|
+
entry.textarea = $('<textarea class="ge-code-inline-source" />').val(entry.from).appendTo(entry.wrapper);
|
|
101
|
+
|
|
102
|
+
var bar = $('<div class="ge-code-inline-bar" />').appendTo(entry.wrapper);
|
|
103
|
+
$('<button type="button" class="btn btn-sm btn-primary ge-code-apply" />')
|
|
104
|
+
.text(ge.t('codemirror.apply'))
|
|
105
|
+
.on('click', function() { apply(entry); })
|
|
106
|
+
.appendTo(bar);
|
|
107
|
+
$('<button type="button" class="btn btn-sm btn-outline-secondary ge-code-cancel" />')
|
|
108
|
+
.text(ge.t('codemirror.cancel'))
|
|
109
|
+
.on('click', function() { close(entry); })
|
|
110
|
+
.appendTo(bar);
|
|
111
|
+
|
|
112
|
+
open.push(entry);
|
|
113
|
+
show(entry);
|
|
114
|
+
|
|
115
|
+
if (window.CodeMirror) {
|
|
116
|
+
entry.editor = window.CodeMirror.fromTextArea(entry.textarea[0], options());
|
|
117
|
+
$(entry.editor.getWrapperElement()).addClass('ge-code-editor');
|
|
118
|
+
entry.editor.focus();
|
|
119
|
+
} else {
|
|
120
|
+
entry.textarea.trigger('focus');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* What was written, in the block's place, through the edit-html events.
|
|
126
|
+
* The canvas leaves editing to take it in and comes back, as it does for
|
|
127
|
+
* getHtml, so what was written is read as the editor reads any markup.
|
|
128
|
+
*/
|
|
129
|
+
function apply(entry) {
|
|
130
|
+
var to = entry.editor ? entry.editor.getValue() : entry.textarea.val();
|
|
131
|
+
var payload = ge.payloadFor(entry.kind, entry.node, { source: 'tool', from: entry.from, to: to });
|
|
132
|
+
|
|
133
|
+
// Canceled, the editor stays open with what was written in it
|
|
134
|
+
if (!ge.emit('before-edit-html', payload)) { return; }
|
|
135
|
+
|
|
136
|
+
close(entry);
|
|
137
|
+
|
|
138
|
+
var instance = ge.canvas.data('grideditor');
|
|
139
|
+
instance.deinit();
|
|
140
|
+
|
|
141
|
+
var made = $('<div />').html(to).contents();
|
|
142
|
+
entry.node.replaceWith(made);
|
|
143
|
+
|
|
144
|
+
instance.init();
|
|
145
|
+
|
|
146
|
+
ge.emit('after-edit-html', ge.payloadFor(entry.kind, made.filter('*'), {
|
|
147
|
+
source: 'tool',
|
|
148
|
+
from: entry.from,
|
|
149
|
+
to: to,
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function tool(drawer, node) {
|
|
154
|
+
ge.createTool(drawer, ge.t('tool.edit_html'), 'ge-edit-html', 'bi bi-code-slash', function() {
|
|
155
|
+
openEditor(node);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return {
|
|
160
|
+
drawerTools: function(drawer, node, kind) {
|
|
161
|
+
if (editable(node, kind)) { tool(drawer, node); }
|
|
162
|
+
},
|
|
163
|
+
|
|
164
|
+
// Plain content has no gear, and so none of the drawerTools: its
|
|
165
|
+
// html is what there is to edit about it
|
|
166
|
+
plainTools: tool,
|
|
167
|
+
|
|
168
|
+
// Every deinit - getHtml's among them - takes the editors off the
|
|
169
|
+
// canvas, whatever is in them, and every init puts them back where
|
|
170
|
+
// their block is. A block that is gone takes its editor with it.
|
|
171
|
+
onBeforeDeinit: function() {
|
|
172
|
+
open.forEach(hide);
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
onInit: function() {
|
|
176
|
+
open.slice().forEach(function(entry) {
|
|
177
|
+
if (!$.contains(document.documentElement, entry.node[0])) {
|
|
178
|
+
if (entry.editor) { entry.editor.toTextArea(); }
|
|
179
|
+
entry.wrapper.remove();
|
|
180
|
+
open.splice(open.indexOf(entry), 1);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
show(entry);
|
|
185
|
+
});
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
})(jQuery);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeMirror for grid-editor's source view.
|
|
3
|
+
*
|
|
4
|
+
* A feature plugin: load this file after the editor, and CodeMirror 5 with
|
|
5
|
+
* its html mode after or before it, and the toolbar's source button edits the
|
|
6
|
+
* canvas's html in CodeMirror - highlighted, with line numbers - rather than
|
|
7
|
+
* in a plain textarea. What it can ask the editor for is the handle its
|
|
8
|
+
* factory is called with, described in docs/plugins.md.
|
|
9
|
+
*
|
|
10
|
+
* <link rel="stylesheet" href="codemirror/lib/codemirror.css">
|
|
11
|
+
* <script src="codemirror/lib/codemirror.js"></script>
|
|
12
|
+
* <script src="codemirror/mode/xml/xml.js"></script>
|
|
13
|
+
* <script src="codemirror/mode/javascript/javascript.js"></script>
|
|
14
|
+
* <script src="codemirror/mode/css/css.js"></script>
|
|
15
|
+
* <script src="codemirror/mode/htmlmixed/htmlmixed.js"></script>
|
|
16
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
17
|
+
* <script src="dist/plugins/grideditor.codemirror.min.js"></script>
|
|
18
|
+
*
|
|
19
|
+
* CodeMirror 5 rather than 6: 6 comes as ES modules only, for a bundler,
|
|
20
|
+
* where 5 loads from a script tag like the rest of the page. Without
|
|
21
|
+
* CodeMirror on the page the source view is the textarea, as before, and
|
|
22
|
+
* the console says why.
|
|
23
|
+
*/
|
|
24
|
+
(function($) {
|
|
25
|
+
|
|
26
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
27
|
+
'error.codemirror_missing': 'CodeMirror not available! Make sure you loaded the CodeMirror js file; the source is edited in a plain textarea without it.',
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
$.fn.gridEditor.features.codemirror = function(ge) {
|
|
31
|
+
|
|
32
|
+
var editor = null;
|
|
33
|
+
var warned = false;
|
|
34
|
+
|
|
35
|
+
function options() {
|
|
36
|
+
var own = (ge.settings.codemirror && ge.settings.codemirror.config) || {};
|
|
37
|
+
|
|
38
|
+
return $.extend({
|
|
39
|
+
mode: 'htmlmixed',
|
|
40
|
+
lineNumbers: true,
|
|
41
|
+
lineWrapping: true,
|
|
42
|
+
tabSize: 2,
|
|
43
|
+
indentUnit: 2,
|
|
44
|
+
}, own);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
// Over the textarea the editor fills with the canvas's html: it goes
|
|
49
|
+
// where the textarea was, as tall as the editor made the textarea
|
|
50
|
+
onSourceOpen: function(textarea) {
|
|
51
|
+
if (!window.CodeMirror) {
|
|
52
|
+
if (!warned) {
|
|
53
|
+
warned = true;
|
|
54
|
+
ge.warn(ge.t('error.codemirror_missing'));
|
|
55
|
+
}
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var height = textarea.height();
|
|
60
|
+
|
|
61
|
+
editor = window.CodeMirror.fromTextArea(textarea[0], options());
|
|
62
|
+
$(editor.getWrapperElement()).addClass('ge-code-editor');
|
|
63
|
+
editor.setSize(null, height);
|
|
64
|
+
editor.focus();
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
// What it holds goes back in the textarea, which is what the canvas
|
|
68
|
+
// is made of again, and the textarea is left as it found it
|
|
69
|
+
onSourceClose: function() {
|
|
70
|
+
if (!editor) { return; }
|
|
71
|
+
|
|
72
|
+
editor.save();
|
|
73
|
+
editor.toTextArea();
|
|
74
|
+
editor = null;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
})(jQuery);
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
14
|
* loaded on its own, like every plugin. The built file starts with what
|
|
15
|
-
* every text editor shares - text blocks, the Text button
|
|
16
|
-
*
|
|
15
|
+
* every text editor shares - text blocks, the Text button, createText,
|
|
16
|
+
* making the host's plain content a text - from
|
|
17
17
|
* src/js/text/grideditor.text.js, installed once however many editors a
|
|
18
18
|
* page loads.
|
|
19
19
|
*/
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Up to 5.x the main bundle carried a copy of this file; since 6.0 it is
|
|
14
14
|
* loaded on its own, like every plugin. The built file starts with what
|
|
15
|
-
* every text editor shares - text blocks, the Text button
|
|
16
|
-
*
|
|
15
|
+
* every text editor shares - text blocks, the Text button, createText,
|
|
16
|
+
* making the host's plain content a text - from
|
|
17
17
|
* src/js/text/grideditor.text.js, installed once however many editors a
|
|
18
18
|
* page loads.
|
|
19
19
|
*/
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
*
|
|
9
9
|
* It is a feature plugin, `text`, that the `plugins` setting does not choose
|
|
10
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
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* text block's drawer, the Text buttons in the toolbar, createText, opening
|
|
12
|
+
* an editor on a click and closing it again with the host's attributes put
|
|
13
|
+
* back, and making the host's plain content a text through the core's
|
|
14
|
+
* `textTypes` hook.
|
|
15
15
|
*
|
|
16
16
|
* Each editor registers under $.fn.gridEditor.texts, which is this file's own
|
|
17
17
|
* registry and not a contract: an editor of a host's own is a feature plugin
|
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
if ($.fn.gridEditor.features.text) { return; }
|
|
23
23
|
|
|
24
24
|
$.extend($.fn.gridEditor.locales.en, {
|
|
25
|
-
'tool.add_text': 'Add text',
|
|
26
|
-
'tool.add_text_type': 'Add {editor} text',
|
|
27
25
|
'text.add': 'Text',
|
|
28
26
|
'text.add_type': 'Text ({editor})',
|
|
29
27
|
'panel.editor': 'Editor',
|
|
@@ -119,11 +117,6 @@
|
|
|
119
117
|
.html(content !== undefined ? content : (text && text.initialContent) || '');
|
|
120
118
|
}
|
|
121
119
|
|
|
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
120
|
/**
|
|
128
121
|
* createText(type?, options?): a content area of a text editor's,
|
|
129
122
|
* detached unless a placement is given. The type is the first one
|
|
@@ -262,44 +255,6 @@
|
|
|
262
255
|
});
|
|
263
256
|
}
|
|
264
257
|
|
|
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
258
|
var texts = offeredTexts();
|
|
304
259
|
|
|
305
260
|
return {
|
|
@@ -354,7 +309,6 @@
|
|
|
354
309
|
|
|
355
310
|
onInit: function() {
|
|
356
311
|
markTexts();
|
|
357
|
-
addTextTools();
|
|
358
312
|
|
|
359
313
|
ge.canvas.off('click.ge-text').on('click.ge-text', '.ge-content', onClick);
|
|
360
314
|
},
|
package/src/less/grideditor.less
CHANGED
|
@@ -94,6 +94,60 @@
|
|
|
94
94
|
display: none;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/* A block's html edited in place, with the codemirror-inline plugin: the
|
|
98
|
+
block is hidden behind its editor while it is open */
|
|
99
|
+
.ge-canvas.ge-editing {
|
|
100
|
+
.ge-code-hidden {
|
|
101
|
+
display: none !important;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ge-tools-drawer.ge-code-inline {
|
|
105
|
+
position: relative;
|
|
106
|
+
width: 100%;
|
|
107
|
+
margin: 0 0 @editGutter;
|
|
108
|
+
padding: 4px;
|
|
109
|
+
background: #f8f9fa;
|
|
110
|
+
border: 1px solid #ced4da;
|
|
111
|
+
border-radius: 4px;
|
|
112
|
+
cursor: auto;
|
|
113
|
+
-webkit-user-select: text;
|
|
114
|
+
user-select: text;
|
|
115
|
+
|
|
116
|
+
> .ge-code-inline-source {
|
|
117
|
+
width: 100%;
|
|
118
|
+
min-height: 120px;
|
|
119
|
+
font-family: monospace;
|
|
120
|
+
font-size: 13px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.CodeMirror {
|
|
124
|
+
height: auto;
|
|
125
|
+
border: 1px solid #ced4da;
|
|
126
|
+
font-size: 13px;
|
|
127
|
+
}
|
|
128
|
+
.CodeMirror-scroll {
|
|
129
|
+
min-height: 120px;
|
|
130
|
+
max-height: 60vh;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
> .ge-code-inline-bar {
|
|
134
|
+
display: flex;
|
|
135
|
+
gap: 4px;
|
|
136
|
+
justify-content: flex-end;
|
|
137
|
+
padding-top: 4px;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* The source view in a code editor, with the codemirror plugin: where the
|
|
143
|
+
textarea was, and as wide */
|
|
144
|
+
.ge-code-editor {
|
|
145
|
+
width: 100%;
|
|
146
|
+
border: 1px solid #ced4da;
|
|
147
|
+
border-radius: 4px;
|
|
148
|
+
font-size: 13px;
|
|
149
|
+
}
|
|
150
|
+
|
|
97
151
|
/* Not editing */
|
|
98
152
|
.ge-canvas {
|
|
99
153
|
.ge-tools-drawer {
|