@themarioga/grid-editor 5.1.2 → 5.3.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/BUILDING.md +6 -0
- package/CHANGELOG.md +58 -0
- package/README.md +46 -9
- package/UPGRADING.md +25 -0
- package/dist/grideditor.css +28 -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 +760 -245
- package/dist/jquery.grideditor.min.js +1 -1
- package/dist/jquery.grideditor.min.js.map +1 -1
- package/dist/locales/grideditor.es.js +11 -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 +120 -0
- package/dist/plugins/grideditor.ckeditor.min.js +2 -0
- package/dist/plugins/grideditor.ckeditor.min.js.map +1 -0
- package/dist/plugins/grideditor.clipboard.js +8 -7
- package/dist/plugins/grideditor.clipboard.min.js +1 -1
- package/dist/plugins/grideditor.clipboard.min.js.map +1 -1
- package/dist/plugins/grideditor.spacing.js +1 -1
- package/dist/plugins/grideditor.spacing.min.js +1 -1
- package/dist/plugins/grideditor.spacing.min.js.map +1 -1
- package/dist/plugins/grideditor.summernote.js +98 -0
- package/dist/plugins/grideditor.summernote.min.js +2 -0
- package/dist/plugins/grideditor.summernote.min.js.map +1 -0
- package/dist/plugins/grideditor.textalign.js +1 -1
- package/dist/plugins/grideditor.textalign.min.js +1 -1
- package/dist/plugins/grideditor.textalign.min.js.map +1 -1
- package/dist/plugins/grideditor.tinymce.js +162 -0
- package/dist/plugins/grideditor.tinymce.min.js +2 -0
- package/dist/plugins/grideditor.tinymce.min.js.map +1 -0
- package/dist/plugins/grideditor.visibility.js +3 -3
- package/dist/plugins/grideditor.visibility.min.js +1 -1
- package/dist/plugins/grideditor.visibility.min.js.map +1 -1
- package/docs/events.md +5 -2
- package/docs/locale-keys.md +23 -1
- package/docs/plugins.md +61 -4
- package/example/attributes.html +4 -2
- package/example/autosave.html +2 -0
- package/example/basic.html +2 -0
- package/example/ckeditor.html +2 -0
- package/example/clipboard.html +2 -0
- package/example/containers.html +2 -0
- package/example/elements.html +2 -0
- package/example/summernote.html +2 -0
- package/example/wrap_content.html +2 -0
- package/package.json +1 -1
- package/src/js/compat/bundled-texts.js +14 -0
- package/src/js/jquery.grideditor.js +444 -33
- package/src/js/locales/grideditor.es.js +11 -0
- package/src/js/plugins/grideditor.ckeditor.js +120 -0
- package/src/js/plugins/grideditor.clipboard.js +8 -7
- package/src/js/plugins/grideditor.spacing.js +1 -1
- package/src/js/plugins/grideditor.summernote.js +98 -0
- package/src/js/plugins/grideditor.textalign.js +1 -1
- package/src/js/plugins/grideditor.tinymce.js +162 -0
- package/src/js/plugins/grideditor.visibility.js +3 -3
- package/src/less/grideditor.less +34 -0
- package/src/js/jquery.grideditor.ckeditor.js +0 -77
- package/src/js/jquery.grideditor.summernote.js +0 -72
- package/src/js/jquery.grideditor.tinymce.js +0 -143
|
@@ -19,6 +19,16 @@
|
|
|
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
|
+
'tool.text_info': 'Texto: {editor}',
|
|
25
|
+
'tool.delete_text': 'Quitar texto',
|
|
26
|
+
'text.add': 'Texto',
|
|
27
|
+
'text.add_type': 'Texto ({editor})',
|
|
28
|
+
'text.no_editor': 'No hay cargado ningún editor de texto "{type}": este texto se puede mover y borrar, pero no editar',
|
|
29
|
+
'text.tinymce': 'tinyMCE',
|
|
30
|
+
'text.ckeditor': 'CKEditor',
|
|
31
|
+
'text.summernote': 'Summernote',
|
|
22
32
|
'tool.add_column': 'Añadir columna\n(mantén pulsado para elegir el ancho)',
|
|
23
33
|
'tool.column_size': '{size} de 12',
|
|
24
34
|
'tool.column_equal': 'Igual: reparte lo que queda de la fila',
|
|
@@ -61,6 +71,7 @@
|
|
|
61
71
|
'confirm.cancel': 'Cancelar',
|
|
62
72
|
'confirm.delete_row': '¿Seguro que quieres borrar esta fila?',
|
|
63
73
|
'confirm.delete_column': '¿Seguro que quieres borrar esta columna?',
|
|
74
|
+
'confirm.delete_text': '¿Seguro que quieres borrar este texto?',
|
|
64
75
|
'confirm.delete_element': '¿Seguro que quieres borrar este elemento?',
|
|
65
76
|
'confirm.delete_container': '¿Seguro que quieres borrar este contenedor y todo su contenido?',
|
|
66
77
|
'confirm.delete_tab': '¿Seguro que quieres borrar esta pestaña y todo su contenido?',
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CKEditor for grid-editor's content areas.
|
|
3
|
+
*
|
|
4
|
+
* A text editor plugin: load this file after the editor, and CKEditor 4
|
|
5
|
+
* after or before it, and content_types: ['ckeditor'] edits each content area
|
|
6
|
+
* with an inline CKEditor. What it can ask the editor for is the handle its
|
|
7
|
+
* factory is called with, described in docs/plugins.md.
|
|
8
|
+
*
|
|
9
|
+
* <script src="ckeditor/ckeditor.js"></script>
|
|
10
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
11
|
+
* <script src="dist/plugins/grideditor.ckeditor.min.js"></script>
|
|
12
|
+
*
|
|
13
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
14
|
+
*/
|
|
15
|
+
(function($) {
|
|
16
|
+
|
|
17
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
18
|
+
'text.ckeditor': 'CKEditor',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
var INITIAL_CONTENT = '<p>Lorem initius... </p>';
|
|
22
|
+
|
|
23
|
+
$.fn.gridEditor.texts.ckeditor = function(ge) {
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The instance editing this content area. Kept in jQuery data when it
|
|
27
|
+
* is made, and looked for among CKEditor's own as a fallback, since
|
|
28
|
+
* an instance made by another version of this file has no data.
|
|
29
|
+
*/
|
|
30
|
+
function instanceOf(contentArea) {
|
|
31
|
+
var kept = contentArea.data('ge-ckeditor');
|
|
32
|
+
if (kept) { return kept; }
|
|
33
|
+
|
|
34
|
+
var found = null;
|
|
35
|
+
$.each(window.CKEDITOR.instances, function(name, instance) {
|
|
36
|
+
if (instance.element && instance.element.$ === contentArea[0]) { found = instance; }
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return found;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
labelKey: 'text.ckeditor',
|
|
44
|
+
initialContent: INITIAL_CONTENT,
|
|
45
|
+
missingKey: 'error.ckeditor_missing',
|
|
46
|
+
|
|
47
|
+
available: function() { return !!window.CKEDITOR; },
|
|
48
|
+
|
|
49
|
+
start: function(contentAreas) {
|
|
50
|
+
var settings = ge.settings;
|
|
51
|
+
|
|
52
|
+
contentAreas.each(function() {
|
|
53
|
+
var contentArea = $(this);
|
|
54
|
+
if (contentArea.hasClass('active')) { return; }
|
|
55
|
+
|
|
56
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
57
|
+
// CKEditor kills this ' ' creating a non usable box :/
|
|
58
|
+
contentArea.html(' ');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Add the .attr('contenteditable',''true') or CKEditor loads readonly
|
|
62
|
+
contentArea.addClass('active').attr('contenteditable', 'true');
|
|
63
|
+
|
|
64
|
+
var configuration = $.extend(
|
|
65
|
+
{},
|
|
66
|
+
(settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
|
|
67
|
+
{
|
|
68
|
+
// Focus editor on creation
|
|
69
|
+
on: {
|
|
70
|
+
instanceReady: function( evt ) {
|
|
71
|
+
// Call original instanceReady function, if one was passed in the config
|
|
72
|
+
var callback;
|
|
73
|
+
try {
|
|
74
|
+
callback = settings.ckeditor.config.on.instanceReady;
|
|
75
|
+
} catch (err) {
|
|
76
|
+
// No callback passed
|
|
77
|
+
}
|
|
78
|
+
if (callback) {
|
|
79
|
+
callback.call(this, evt);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// The editor owns what is inside the
|
|
83
|
+
// content area now, so the grid editor is
|
|
84
|
+
// told to put its own furniture back
|
|
85
|
+
ge.textReady(contentArea);
|
|
86
|
+
|
|
87
|
+
instance.focus();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
var instance = window.CKEDITOR.inline(contentArea.get(0), configuration);
|
|
93
|
+
contentArea.data('ge-ckeditor', instance);
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
stop: function(contentAreas) {
|
|
98
|
+
contentAreas.filter('.active').each(function() {
|
|
99
|
+
var contentArea = $(this);
|
|
100
|
+
|
|
101
|
+
// This content area's instance, and no other: up to 5.x
|
|
102
|
+
// closing one content area destroyed every CKEditor on
|
|
103
|
+
// the page, other editors' and the host's own included
|
|
104
|
+
var instance = window.CKEDITOR ? instanceOf(contentArea) : null;
|
|
105
|
+
if (instance) { instance.destroy(); }
|
|
106
|
+
contentArea.removeData('ge-ckeditor');
|
|
107
|
+
|
|
108
|
+
// Cleanup
|
|
109
|
+
contentArea
|
|
110
|
+
.removeClass('active cke_focus')
|
|
111
|
+
.removeAttr('id')
|
|
112
|
+
.removeAttr('style')
|
|
113
|
+
.removeAttr('spellcheck')
|
|
114
|
+
.removeAttr('contenteditable')
|
|
115
|
+
;
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
};
|
|
120
|
+
})(jQuery);
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Copy and paste for grid-editor.
|
|
3
3
|
*
|
|
4
4
|
* A feature plugin: load this file after the editor and every row, column,
|
|
5
|
-
* section, container and element gets a copy tool, and every
|
|
6
|
-
* them can go gets a paste tool while there is something copied
|
|
5
|
+
* section, text block, container and element gets a copy tool, and every
|
|
6
|
+
* place one of them can go gets a paste tool while there is something copied
|
|
7
|
+
* that fits.
|
|
7
8
|
* What it can ask the editor for is the handle its factory is called with,
|
|
8
9
|
* described in docs/plugins.md.
|
|
9
10
|
*
|
|
@@ -37,10 +38,10 @@ var editors = 0;
|
|
|
37
38
|
/**
|
|
38
39
|
* What each drawer takes when something is pasted into it, by the kind of the
|
|
39
40
|
* node the drawer belongs to. A category is what was copied: a row, a column,
|
|
40
|
-
* a section, a container of any type, an element.
|
|
41
|
+
* a section, a text block, a container of any type, an element.
|
|
41
42
|
*/
|
|
42
43
|
var TARGETS = {
|
|
43
|
-
column: ['row', 'container', 'element'],
|
|
44
|
+
column: ['row', 'text', 'container', 'element'],
|
|
44
45
|
row: ['column'],
|
|
45
46
|
section: ['row'],
|
|
46
47
|
};
|
|
@@ -117,7 +118,7 @@ $.fn.gridEditor.features.clipboard = function(ge) {
|
|
|
117
118
|
function categoryOf(kind) {
|
|
118
119
|
if ($.fn.gridEditor.containers[kind]) { return 'container'; }
|
|
119
120
|
|
|
120
|
-
return ['row', 'column', 'section', 'element'].indexOf(kind) !== -1 ? kind : null;
|
|
121
|
+
return ['row', 'column', 'section', 'text', 'element'].indexOf(kind) !== -1 ? kind : null;
|
|
121
122
|
}
|
|
122
123
|
|
|
123
124
|
function copy(node, kind) {
|
|
@@ -128,7 +129,7 @@ $.fn.gridEditor.features.clipboard = function(ge) {
|
|
|
128
129
|
|
|
129
130
|
// The canvas came back with new drawers: the one to flash is the
|
|
130
131
|
// node's new copy tool
|
|
131
|
-
var tool =
|
|
132
|
+
var tool = ge.drawerOf(node).find('> .ge-copy');
|
|
132
133
|
tool.addClass('ge-copied').find('i').attr('class', 'bi bi-check2');
|
|
133
134
|
setTimeout(function() {
|
|
134
135
|
tool.removeClass('ge-copied').find('i').attr('class', 'bi bi-copy');
|
|
@@ -145,7 +146,7 @@ $.fn.gridEditor.features.clipboard = function(ge) {
|
|
|
145
146
|
// An element goes into the column's last content area. With none,
|
|
146
147
|
// the column's next init wraps it in one of its own
|
|
147
148
|
if (clip.category === 'element') {
|
|
148
|
-
var area = target.
|
|
149
|
+
var area = target.find('> .ge-text-block > .ge-content, > .ge-content').last();
|
|
149
150
|
if (area.length) { into = area; }
|
|
150
151
|
}
|
|
151
152
|
|
|
@@ -252,7 +252,7 @@ $.fn.gridEditor.utilities.spacing = function(ge) {
|
|
|
252
252
|
name: key + side,
|
|
253
253
|
prefix: key + side,
|
|
254
254
|
values: values,
|
|
255
|
-
appliesTo: ['row', 'column', 'element', 'container'],
|
|
255
|
+
appliesTo: ['row', 'column', 'text', 'element', 'container'],
|
|
256
256
|
labelKey: labelKey,
|
|
257
257
|
panel: false,
|
|
258
258
|
choices: function() {
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summernote for grid-editor's content areas.
|
|
3
|
+
*
|
|
4
|
+
* A text editor plugin: load this file after the editor, and summernote
|
|
5
|
+
* after or before it, and content_types: ['summernote'] edits each content
|
|
6
|
+
* area with summernote in air mode. What it can ask the editor for is the
|
|
7
|
+
* handle its factory is called with, described in docs/plugins.md.
|
|
8
|
+
*
|
|
9
|
+
* <script src="summernote/summernote-bs5.min.js"></script>
|
|
10
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
11
|
+
* <script src="dist/plugins/grideditor.summernote.min.js"></script>
|
|
12
|
+
*
|
|
13
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
14
|
+
*/
|
|
15
|
+
(function($) {
|
|
16
|
+
|
|
17
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
18
|
+
'text.summernote': 'Summernote',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
var INITIAL_CONTENT = '<p>Lorem ipsum dolores</p>';
|
|
22
|
+
|
|
23
|
+
$.fn.gridEditor.texts.summernote = function(ge) {
|
|
24
|
+
return {
|
|
25
|
+
labelKey: 'text.summernote',
|
|
26
|
+
initialContent: INITIAL_CONTENT,
|
|
27
|
+
missingKey: 'error.summernote_missing',
|
|
28
|
+
|
|
29
|
+
available: function() { return !!$.fn.summernote; },
|
|
30
|
+
|
|
31
|
+
start: function(contentAreas) {
|
|
32
|
+
var settings = ge.settings;
|
|
33
|
+
|
|
34
|
+
// Summernote 0.9.1 calls $.now(), which jQuery 4 removed, and
|
|
35
|
+
// cannot open without it. Given back only where it is missing,
|
|
36
|
+
// and only once summernote is actually used.
|
|
37
|
+
if (!$.now) { $.now = Date.now; }
|
|
38
|
+
|
|
39
|
+
contentAreas.each(function() {
|
|
40
|
+
var contentArea = $(this);
|
|
41
|
+
if (contentArea.hasClass('active')) { return; }
|
|
42
|
+
|
|
43
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
44
|
+
contentArea.html('');
|
|
45
|
+
}
|
|
46
|
+
contentArea.addClass('active');
|
|
47
|
+
|
|
48
|
+
var configuration = $.extend(
|
|
49
|
+
true, // deep copy
|
|
50
|
+
{},
|
|
51
|
+
(settings.summernote && settings.summernote.config ? settings.summernote.config : {}),
|
|
52
|
+
{
|
|
53
|
+
tabsize: 2,
|
|
54
|
+
airMode: true,
|
|
55
|
+
// Focus editor on creation
|
|
56
|
+
callbacks: {
|
|
57
|
+
onInit: function() {
|
|
58
|
+
|
|
59
|
+
// Call original oninit function, if one was passed in the config
|
|
60
|
+
var callback;
|
|
61
|
+
try {
|
|
62
|
+
callback = settings.summernote.config.callbacks.onInit;
|
|
63
|
+
} catch (err) {
|
|
64
|
+
// No callback passed
|
|
65
|
+
}
|
|
66
|
+
if (callback) {
|
|
67
|
+
callback.call(this);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// The editor owns what is inside the
|
|
71
|
+
// content area now, so the grid editor is
|
|
72
|
+
// told to put its own furniture back
|
|
73
|
+
ge.textReady(contentArea);
|
|
74
|
+
|
|
75
|
+
contentArea.summernote('focus');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
contentArea.summernote(configuration);
|
|
81
|
+
});
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
stop: function(contentAreas) {
|
|
85
|
+
contentAreas.filter('.active').each(function() {
|
|
86
|
+
var contentArea = $(this);
|
|
87
|
+
contentArea.summernote('destroy');
|
|
88
|
+
contentArea
|
|
89
|
+
.removeClass('active')
|
|
90
|
+
.removeAttr('id')
|
|
91
|
+
.removeAttr('style')
|
|
92
|
+
.removeAttr('spellcheck')
|
|
93
|
+
;
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
})(jQuery);
|
|
@@ -39,7 +39,7 @@ $.fn.gridEditor.utilities.textalign = function(ge) {
|
|
|
39
39
|
name: 'text-align',
|
|
40
40
|
prefix: 'text',
|
|
41
41
|
values: ['start', 'center', 'end'],
|
|
42
|
-
appliesTo: ['row', 'column', 'element', 'container'],
|
|
42
|
+
appliesTo: ['row', 'column', 'text', 'element', 'container'],
|
|
43
43
|
labelKey: 'utility.text_align',
|
|
44
44
|
label: label,
|
|
45
45
|
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tinyMCE for grid-editor's content areas.
|
|
3
|
+
*
|
|
4
|
+
* A text editor plugin: load this file after the editor, and tinyMCE 6
|
|
5
|
+
* after or before it, and content_types: ['tinymce'] edits each content area
|
|
6
|
+
* with an inline tinyMCE. What it can ask the editor for is the handle its
|
|
7
|
+
* factory is called with, described in docs/plugins.md.
|
|
8
|
+
*
|
|
9
|
+
* <script src="tinymce/tinymce.min.js"></script>
|
|
10
|
+
* <script src="dist/jquery.grideditor.min.js"></script>
|
|
11
|
+
* <script src="dist/plugins/grideditor.tinymce.min.js"></script>
|
|
12
|
+
*
|
|
13
|
+
* Up to 6.0 the main bundle carries a copy of this file too.
|
|
14
|
+
*/
|
|
15
|
+
(function($) {
|
|
16
|
+
|
|
17
|
+
$.extend($.fn.gridEditor.locales.en, {
|
|
18
|
+
'text.tinymce': 'tinyMCE',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// tinyMCE snapshots the target element's attributes when an inline editor is
|
|
22
|
+
// created and restores them on remove(), so this has to run *after* remove()
|
|
23
|
+
// to keep the grid editor's own class and tinyMCE's leftovers off the element.
|
|
24
|
+
function cleanUp(contentArea) {
|
|
25
|
+
contentArea
|
|
26
|
+
.removeClass('active')
|
|
27
|
+
.removeClass('ge-rte-active')
|
|
28
|
+
.removeAttr('id')
|
|
29
|
+
.removeAttr('style')
|
|
30
|
+
.removeAttr('spellcheck')
|
|
31
|
+
.removeAttr('contenteditable')
|
|
32
|
+
.removeAttr('data-mce-style')
|
|
33
|
+
;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
var INITIAL_CONTENT = '<p>Lorem ipsum dolores</p>';
|
|
37
|
+
|
|
38
|
+
$.fn.gridEditor.texts.tinymce = function(ge) {
|
|
39
|
+
return {
|
|
40
|
+
labelKey: 'text.tinymce',
|
|
41
|
+
initialContent: INITIAL_CONTENT,
|
|
42
|
+
missingKey: 'error.tinymce_missing',
|
|
43
|
+
|
|
44
|
+
available: function() { return !!window.tinymce; },
|
|
45
|
+
|
|
46
|
+
start: function(contentAreas) {
|
|
47
|
+
var settings = ge.settings;
|
|
48
|
+
var userConfig = (settings.tinymce && settings.tinymce.config) ? settings.tinymce.config : {};
|
|
49
|
+
|
|
50
|
+
contentAreas.each(function() {
|
|
51
|
+
var contentArea = $(this);
|
|
52
|
+
if (contentArea.hasClass('active')) { return; }
|
|
53
|
+
|
|
54
|
+
if (contentArea.html() == INITIAL_CONTENT) {
|
|
55
|
+
contentArea.html('');
|
|
56
|
+
}
|
|
57
|
+
contentArea.addClass('active');
|
|
58
|
+
|
|
59
|
+
var configuration = $.extend({
|
|
60
|
+
// tinyMCE's own "Upgrade" badge in the menubar. Off by
|
|
61
|
+
// default because an inline editor here is a column of
|
|
62
|
+
// someone's page, not tinyMCE's own interface; a host that
|
|
63
|
+
// wants it back passes promotion: true.
|
|
64
|
+
promotion: false,
|
|
65
|
+
}, userConfig, {
|
|
66
|
+
target: this,
|
|
67
|
+
inline: true,
|
|
68
|
+
init_instance_callback: function(editor) {
|
|
69
|
+
// deinit ran before this init finished, so tear it down again
|
|
70
|
+
if (contentArea.data('ge-tinymce-pending-remove')) {
|
|
71
|
+
contentArea.removeData('ge-tinymce-pending-remove');
|
|
72
|
+
editor.remove();
|
|
73
|
+
// deinit already ran and cannot clean up after this
|
|
74
|
+
// late remove(), so do it here instead
|
|
75
|
+
cleanUp(contentArea);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
contentArea.data('ge-tinymce', editor);
|
|
80
|
+
|
|
81
|
+
// The editor rewrote what is inside this content area
|
|
82
|
+
// while it took it over, so whatever the grid editor
|
|
83
|
+
// had in there is gone. Saying so lets it put its own
|
|
84
|
+
// furniture back.
|
|
85
|
+
ge.textReady(contentArea);
|
|
86
|
+
|
|
87
|
+
// Undo and redo rewrite it too, from snapshots that
|
|
88
|
+
// leave out whatever is marked data-mce-bogus - an
|
|
89
|
+
// element's drawer among them - so it goes back in
|
|
90
|
+
// after each of those as well
|
|
91
|
+
editor.on('Undo Redo', function() {
|
|
92
|
+
ge.textReady(contentArea);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// The inline toolbar is laid out against the element's
|
|
96
|
+
// geometry at the moment tinyMCE draws it, and an
|
|
97
|
+
// element that has just appeared - a tab pane, an
|
|
98
|
+
// accordion body, a column whose width is still
|
|
99
|
+
// settling - may not have its own width yet. Asking
|
|
100
|
+
// for the ui again once the browser has laid the frame
|
|
101
|
+
// out measures it as it now is, instead of leaving a
|
|
102
|
+
// toolbar wrapped into a narrow column.
|
|
103
|
+
window.requestAnimationFrame(function() {
|
|
104
|
+
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
105
|
+
|
|
106
|
+
editor.ui.show();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// And again whenever the user comes back to this
|
|
110
|
+
// editor: by then the element may have been resized,
|
|
111
|
+
// hidden and shown again - a tab switched away from
|
|
112
|
+
// and back, a column made narrower - and the toolbar
|
|
113
|
+
// is only ever as right as its last measurement.
|
|
114
|
+
editor.on('focus', function() {
|
|
115
|
+
window.requestAnimationFrame(function() {
|
|
116
|
+
if (editor.removed || !editor.ui || !editor.ui.show) { return; }
|
|
117
|
+
|
|
118
|
+
editor.ui.show();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Bring focus to text field
|
|
123
|
+
editor.focus();
|
|
124
|
+
|
|
125
|
+
// Call the original callbacks, if any were passed in the config
|
|
126
|
+
if (userConfig.init_instance_callback) {
|
|
127
|
+
userConfig.init_instance_callback.call(this, editor);
|
|
128
|
+
}
|
|
129
|
+
// 'oninit' is the pre-6 name, honoured so existing configs keep working
|
|
130
|
+
if (userConfig.oninit) {
|
|
131
|
+
userConfig.oninit.call(this, editor);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
// We always edit the element we were handed, so a selector in the
|
|
136
|
+
// user config would only fight with target
|
|
137
|
+
delete configuration.selector;
|
|
138
|
+
|
|
139
|
+
window.tinymce.init(configuration);
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
stop: function(contentAreas) {
|
|
144
|
+
contentAreas.filter('.active').each(function() {
|
|
145
|
+
var contentArea = $(this);
|
|
146
|
+
var editor = contentArea.data('ge-tinymce');
|
|
147
|
+
|
|
148
|
+
if (editor) {
|
|
149
|
+
contentArea.removeData('ge-tinymce');
|
|
150
|
+
editor.remove();
|
|
151
|
+
} else {
|
|
152
|
+
// tinymce.init() is asynchronous, so the editor may not exist
|
|
153
|
+
// yet. Leave a note for init_instance_callback to remove it.
|
|
154
|
+
contentArea.data('ge-tinymce-pending-remove', true);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
cleanUp(contentArea);
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
})(jQuery);
|
|
@@ -32,7 +32,7 @@ $.extend($.fn.gridEditor.locales.en, {
|
|
|
32
32
|
/** A node that carries any class of the family, at any breakpoint. */
|
|
33
33
|
var CLASS_PATTERN = /(?:^|\s)d-(?:(?:sm|md|lg|xl|xxl)-)?(?:none|block|flex)(?:\s|$)/;
|
|
34
34
|
|
|
35
|
-
var NODES = '.row, .column, .ge-element, [data-ge-container]';
|
|
35
|
+
var NODES = '.row, .column, .ge-content, .ge-element, [data-ge-container]';
|
|
36
36
|
|
|
37
37
|
$.fn.gridEditor.utilities.visibility = function(ge) {
|
|
38
38
|
|
|
@@ -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' ||
|
|
47
|
+
return kind === 'row' || kind === 'column' || kind === 'element' || kind === 'text' ||
|
|
48
48
|
node.is('[data-ge-container]');
|
|
49
49
|
}
|
|
50
50
|
|
|
@@ -143,7 +143,7 @@ $.fn.gridEditor.utilities.visibility = function(ge) {
|
|
|
143
143
|
name: 'visibility',
|
|
144
144
|
prefix: 'd',
|
|
145
145
|
values: ['none', 'block', 'flex'],
|
|
146
|
-
appliesTo: ['row', 'column', 'element', 'container'],
|
|
146
|
+
appliesTo: ['row', 'column', 'text', 'element', 'container'],
|
|
147
147
|
labelKey: 'utility.visibility',
|
|
148
148
|
|
|
149
149
|
/** Hidden, or shown the way this kind of node is shown. */
|
package/src/less/grideditor.less
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
@colTextColor: darken(@colColor, 10%);
|
|
6
6
|
@elementColor: #7B5EA7;
|
|
7
7
|
@elementTextColor: darken(@elementColor, 5%);
|
|
8
|
+
@textColor: #5A6F8A;
|
|
9
|
+
@textTextColor: darken(@textColor, 5%);
|
|
8
10
|
@containerColor: #1D8A5E;
|
|
9
11
|
@containerTextColor: darken(@containerColor, 5%);
|
|
10
12
|
|
|
@@ -549,6 +551,38 @@
|
|
|
549
551
|
}
|
|
550
552
|
}
|
|
551
553
|
|
|
554
|
+
/* A text block: a content area and, beside it rather than inside,
|
|
555
|
+
where the text editor would take it, its drawer */
|
|
556
|
+
.ge-text-block {
|
|
557
|
+
position: relative;
|
|
558
|
+
outline: 1px dashed fadeout(@textColor, 40%);
|
|
559
|
+
margin-bottom: @editGutter;
|
|
560
|
+
|
|
561
|
+
> .ge-text-drawer {
|
|
562
|
+
background: fadeout(@textColor, 88%);
|
|
563
|
+
|
|
564
|
+
> a {
|
|
565
|
+
color: @textTextColor;
|
|
566
|
+
padding: 2px 5px;
|
|
567
|
+
}
|
|
568
|
+
> a.ge-text-info {
|
|
569
|
+
cursor: default;
|
|
570
|
+
}
|
|
571
|
+
> a.ge-text-missing {
|
|
572
|
+
color: #b02a37;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
/* A column with nothing in it but its drawer still has room to drop a
|
|
578
|
+
block into */
|
|
579
|
+
.column:not(:has(> :not(.ge-tools-drawer, .ge-resize-handle)))::after {
|
|
580
|
+
content: '';
|
|
581
|
+
display: block;
|
|
582
|
+
min-height: 40px;
|
|
583
|
+
border: 1px dashed fadeout(@colColor, 50%);
|
|
584
|
+
}
|
|
585
|
+
|
|
552
586
|
/* Sorting. The dragged node stays in the list and shows where it would
|
|
553
587
|
land - that is the placeholder - while a copy of it follows the
|
|
554
588
|
pointer. */
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
(function($) {
|
|
2
|
-
$.fn.gridEditor.RTEs.ckeditor = {
|
|
3
|
-
|
|
4
|
-
init: function(settings, contentAreas) {
|
|
5
|
-
|
|
6
|
-
if (!window.CKEDITOR) {
|
|
7
|
-
console.error($.fn.gridEditor.t(settings, 'error.ckeditor_missing'));
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
var self = this;
|
|
11
|
-
contentAreas.each(function() {
|
|
12
|
-
var contentArea = $(this);
|
|
13
|
-
if (!contentArea.hasClass('active')) {
|
|
14
|
-
if (contentArea.html() == self.initialContent) {
|
|
15
|
-
// CKEditor kills this ' ' creating a non usable box :/
|
|
16
|
-
contentArea.html(' ');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Add the .attr('contenteditable',''true') or CKEditor loads readonly
|
|
20
|
-
contentArea.addClass('active').attr('contenteditable', 'true');
|
|
21
|
-
|
|
22
|
-
var configuration = $.extend(
|
|
23
|
-
{},
|
|
24
|
-
(settings.ckeditor && settings.ckeditor.config ? settings.ckeditor.config : {}),
|
|
25
|
-
{
|
|
26
|
-
// Focus editor on creation
|
|
27
|
-
on: {
|
|
28
|
-
instanceReady: function( evt ) {
|
|
29
|
-
// Call original instanceReady function, if one was passed in the config
|
|
30
|
-
var callback;
|
|
31
|
-
try {
|
|
32
|
-
callback = settings.ckeditor.config.on.instanceReady;
|
|
33
|
-
} catch (err) {
|
|
34
|
-
// No callback passed
|
|
35
|
-
}
|
|
36
|
-
if (callback) {
|
|
37
|
-
callback.call(this, evt);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// The editor owns what is inside the
|
|
41
|
-
// content area now, so the grid editor is
|
|
42
|
-
// told to put its own furniture back
|
|
43
|
-
contentArea.trigger('ge-rte-ready');
|
|
44
|
-
|
|
45
|
-
instance.focus();
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
var instance = CKEDITOR.inline(contentArea.get(0), configuration);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
},
|
|
54
|
-
|
|
55
|
-
deinit: function(settings, contentAreas) {
|
|
56
|
-
contentAreas.filter('.active').each(function() {
|
|
57
|
-
var contentArea = $(this);
|
|
58
|
-
|
|
59
|
-
// Destroy all CKEditor instances
|
|
60
|
-
$.each(CKEDITOR.instances, function(_, instance) {
|
|
61
|
-
instance.destroy();
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Cleanup
|
|
65
|
-
contentArea
|
|
66
|
-
.removeClass('active cke_focus')
|
|
67
|
-
.removeAttr('id')
|
|
68
|
-
.removeAttr('style')
|
|
69
|
-
.removeAttr('spellcheck')
|
|
70
|
-
.removeAttr('contenteditable')
|
|
71
|
-
;
|
|
72
|
-
});
|
|
73
|
-
},
|
|
74
|
-
|
|
75
|
-
initialContent: '<p>Lorem initius... </p>',
|
|
76
|
-
};
|
|
77
|
-
})(jQuery);
|