@themarioga/grid-editor 8.8.2 → 8.10.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 +24 -0
- package/README.md +18 -0
- package/dist/grideditor.bundle.min.js +3 -3
- package/dist/grideditor.css +51 -0
- package/dist/grideditor.d.ts +28 -1
- package/dist/grideditor.esm.js +381 -20
- package/dist/grideditor.jquery.js +3 -1
- package/dist/grideditor.jquery.min.js +1 -1
- package/dist/grideditor.jquery.min.js.map +2 -2
- package/dist/grideditor.js +381 -20
- package/dist/grideditor.min.css +1 -1
- package/dist/grideditor.min.css.map +1 -1
- package/dist/grideditor.min.js +2 -2
- package/dist/grideditor.min.js.map +3 -3
- package/dist/locales/grideditor.es.esm.js +4 -0
- package/dist/locales/grideditor.es.js +4 -0
- package/dist/locales/grideditor.es.min.js +1 -1
- package/dist/locales/grideditor.es.min.js.map +2 -2
- package/dist/plugins/grideditor.clipboard.esm.js +2 -95
- package/dist/plugins/grideditor.clipboard.js +2 -95
- package/dist/plugins/grideditor.clipboard.min.js +1 -1
- package/dist/plugins/grideditor.clipboard.min.js.map +3 -3
- package/docs/events.md +6 -0
- package/docs/locale-keys.md +4 -0
- package/docs/plugins.md +16 -1
- package/example/utilities.html +3 -1
- package/package.json +1 -1
- package/src/js/grideditor.jquery.js +2 -0
- package/src/js/grideditor.js +433 -29
- package/src/js/locales/grideditor.es.js +4 -0
- package/src/js/plugins/grideditor.clipboard.js +2 -72
- package/src/less/grideditor.less +59 -0
- package/types/grideditor.d.ts +28 -1
|
@@ -46,17 +46,6 @@ var TARGETS = {
|
|
|
46
46
|
section: ['row'],
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
* The attributes that point at an id, as the id itself or as a #selector.
|
|
51
|
-
* A pasted copy that has to take new ids takes them here too, so its tabs,
|
|
52
|
-
* its accordion and its popups still point at their own panes.
|
|
53
|
-
*/
|
|
54
|
-
var REFERENCES = ['data-bs-target', 'data-bs-parent', 'href', 'aria-controls', 'aria-labelledby',
|
|
55
|
-
'aria-describedby', 'for', 'data-ge-popup-id', 'data-ge-popup-target'];
|
|
56
|
-
|
|
57
|
-
/** An id grid-editor generated: ge-{type}-{counter}-{random}. */
|
|
58
|
-
var GENERATED_ID = /^ge-([a-z][a-z-]*?)-\d+-[a-z0-9]+$/;
|
|
59
|
-
|
|
60
49
|
function read() {
|
|
61
50
|
var raw;
|
|
62
51
|
|
|
@@ -150,66 +139,7 @@ GridEditor.features.clipboard = function(ge) {
|
|
|
150
139
|
var clip = read();
|
|
151
140
|
if (!fits(clip, categories)) { return; }
|
|
152
141
|
|
|
153
|
-
ge.place(
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* The copied markup as a node, with new ids where the page already has
|
|
158
|
-
* them: two copies of a tab strip pointing at one set of panes is a tab
|
|
159
|
-
* strip that opens the other copy's tabs. An id the page does not have
|
|
160
|
-
* is kept, so pasting into another page changes nothing.
|
|
161
|
-
*
|
|
162
|
-
* Parsed the way innerHTML parses, so a <script> in what was copied is
|
|
163
|
-
* markup, pasted like the rest, and does not run in the editor.
|
|
164
|
-
*/
|
|
165
|
-
function fresh(html) {
|
|
166
|
-
var node = dom.create(html);
|
|
167
|
-
var renamed = {};
|
|
168
|
-
var taken = function(id) {
|
|
169
|
-
return !!document.getElementById(id) || Object.keys(renamed).some(function(old) {
|
|
170
|
-
return renamed[old] === id;
|
|
171
|
-
});
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
dom.selfAndAll(node, '[id]').forEach(function(element) {
|
|
175
|
-
var id = element.id;
|
|
176
|
-
if (!document.getElementById(id)) { return; }
|
|
177
|
-
|
|
178
|
-
var generated = GENERATED_ID.exec(id);
|
|
179
|
-
var next;
|
|
180
|
-
|
|
181
|
-
if (generated) {
|
|
182
|
-
do { next = ge.containerId(generated[1]); } while (taken(next));
|
|
183
|
-
} else {
|
|
184
|
-
var n = 2;
|
|
185
|
-
while (taken(id + '-' + n)) { n++; }
|
|
186
|
-
next = id + '-' + n;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
renamed[id] = next;
|
|
190
|
-
element.id = next;
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
if (!Object.keys(renamed).length) { return node; }
|
|
194
|
-
|
|
195
|
-
dom.selfAndAll(node, '*').forEach(function(element) {
|
|
196
|
-
REFERENCES.forEach(function(name) {
|
|
197
|
-
var value = element.getAttribute(name);
|
|
198
|
-
if (value === null) { return; }
|
|
199
|
-
if (name === 'href' && value.charAt(0) !== '#') { return; }
|
|
200
|
-
|
|
201
|
-
var rewritten = value.split(/(\s+)/).map(function(token) {
|
|
202
|
-
if (renamed[token]) { return renamed[token]; }
|
|
203
|
-
if (token.charAt(0) === '#' && renamed[token.slice(1)]) { return '#' + renamed[token.slice(1)]; }
|
|
204
|
-
|
|
205
|
-
return token;
|
|
206
|
-
}).join('');
|
|
207
|
-
|
|
208
|
-
if (rewritten !== value) { element.setAttribute(name, rewritten); }
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
return node;
|
|
142
|
+
ge.place(ge.freshNode(clip.html), clip.kind, { appendTo: target, source: 'paste' });
|
|
213
143
|
}
|
|
214
144
|
|
|
215
145
|
/** Show the paste tools, and the toolbar's paste buttons, that fit what is copied. */
|
|
@@ -240,7 +170,7 @@ GridEditor.features.clipboard = function(ge) {
|
|
|
240
170
|
source: 'paste',
|
|
241
171
|
// What the button showed, even if another tab has copied
|
|
242
172
|
// something else since
|
|
243
|
-
create: function() { return
|
|
173
|
+
create: function() { return ge.freshNode(shown.html); },
|
|
244
174
|
});
|
|
245
175
|
});
|
|
246
176
|
|
package/src/less/grideditor.less
CHANGED
|
@@ -585,6 +585,65 @@
|
|
|
585
585
|
--bs-offcanvas-height: 60vh;
|
|
586
586
|
}
|
|
587
587
|
|
|
588
|
+
/* The sidebar: always there while editing, with the page making room for it
|
|
589
|
+
(html.ge-sidebar-open) where the window is wide enough. Narrower than
|
|
590
|
+
Bootstrap's sm it covers the page instead. */
|
|
591
|
+
.ge-settings-sidebar {
|
|
592
|
+
--bs-offcanvas-width: 340px;
|
|
593
|
+
|
|
594
|
+
.ge-sidebar-empty {
|
|
595
|
+
margin: 0;
|
|
596
|
+
color: var(--bs-secondary-color, #6c757d);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
html.ge-sidebar-open {
|
|
601
|
+
padding-right: 340px;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/* On the panel's left edge, centred; folded away, on the window's right edge.
|
|
605
|
+
Its own element, so the panel can slide out from under it. */
|
|
606
|
+
.ge-sidebar-toggle {
|
|
607
|
+
position: fixed;
|
|
608
|
+
top: 50%;
|
|
609
|
+
right: 340px;
|
|
610
|
+
z-index: 1045;
|
|
611
|
+
display: flex;
|
|
612
|
+
align-items: center;
|
|
613
|
+
justify-content: center;
|
|
614
|
+
width: 1.5rem;
|
|
615
|
+
height: 3rem;
|
|
616
|
+
padding: 0;
|
|
617
|
+
transform: translateY(-50%);
|
|
618
|
+
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
619
|
+
border-right: 0;
|
|
620
|
+
border-radius: 0.375rem 0 0 0.375rem;
|
|
621
|
+
background: var(--bs-body-bg, #fff);
|
|
622
|
+
color: var(--bs-body-color, #212529);
|
|
623
|
+
transition: right 0.3s ease-in-out;
|
|
624
|
+
|
|
625
|
+
&[aria-expanded="false"] {
|
|
626
|
+
right: 0;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
.ge-sidebar-toggle.ge-under-dialog {
|
|
631
|
+
z-index: 1040;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
@media (max-width: 575.98px) {
|
|
635
|
+
.ge-settings-sidebar {
|
|
636
|
+
--bs-offcanvas-width: 100vw;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.ge-sidebar-toggle[aria-expanded="true"] {
|
|
640
|
+
right: calc(100vw - 1.5rem);
|
|
641
|
+
border: 1px solid var(--bs-border-color, #dee2e6);
|
|
642
|
+
border-left: 0;
|
|
643
|
+
border-radius: 0 0.375rem 0.375rem 0;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
588
647
|
.ge-settings-popover {
|
|
589
648
|
/* Popper would position it; without Popper that is the editor's job */
|
|
590
649
|
position: absolute;
|
package/types/grideditor.d.ts
CHANGED
|
@@ -121,6 +121,18 @@ export interface InlineStyleOptions {
|
|
|
121
121
|
visibility?: { drawer?: boolean };
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
+
/** What the sidebar shows while nothing is selected, instead of its message. */
|
|
125
|
+
export interface SidebarContent {
|
|
126
|
+
/** Text, not html. Default the sidebar's own title. */
|
|
127
|
+
title?: string;
|
|
128
|
+
body: Element;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface SidebarSettings {
|
|
132
|
+
/** Called whenever the sidebar is left with nothing selected. Null gives the message. */
|
|
133
|
+
empty?: ((ge: GridEditor) => SidebarContent | null) | null;
|
|
134
|
+
}
|
|
135
|
+
|
|
124
136
|
export type CustomFilter = ((canvas: HTMLElement, isInit: boolean) => void) | string;
|
|
125
137
|
|
|
126
138
|
/** The settings. Every one is optional. */
|
|
@@ -183,7 +195,10 @@ export interface GridEditorOptions {
|
|
|
183
195
|
locale_strings?: Record<string, string>;
|
|
184
196
|
callbacks?: Partial<GridEditorCallbacks>;
|
|
185
197
|
confirm_delete?: boolean;
|
|
186
|
-
|
|
198
|
+
/** Where a node's settings open. 'sidebar' is a panel that stays on the right while editing, showing the selected node's; one editor per page has it. */
|
|
199
|
+
settings_panel?: 'offcanvas' | 'popover' | 'modal' | 'inline' | 'sidebar';
|
|
200
|
+
/** The 'sidebar' panel. */
|
|
201
|
+
sidebar?: SidebarSettings;
|
|
187
202
|
drag?: { delay?: number; touch_delay?: number; threshold?: number; animation?: number; scroll?: boolean };
|
|
188
203
|
tinymce?: { config?: Record<string, unknown> };
|
|
189
204
|
ckeditor?: { config?: Record<string, unknown> };
|
|
@@ -317,6 +332,13 @@ export interface TargetChangePayload {
|
|
|
317
332
|
from: HTMLElement | null;
|
|
318
333
|
}
|
|
319
334
|
|
|
335
|
+
/** The selection changed, with settings_panel 'sidebar': the node whose settings the sidebar shows, or null. */
|
|
336
|
+
export interface SelectionChangePayload {
|
|
337
|
+
canvas: HTMLElement;
|
|
338
|
+
node: HTMLElement | null;
|
|
339
|
+
from: HTMLElement | null;
|
|
340
|
+
}
|
|
341
|
+
|
|
320
342
|
/** The events, by name, with their payloads. Adding fires a specific name and the generic one. */
|
|
321
343
|
export interface GridEditorEventMap {
|
|
322
344
|
'grideditor:before-add': Payload;
|
|
@@ -357,6 +379,7 @@ export interface GridEditorEventMap {
|
|
|
357
379
|
'grideditor:popup-orphan': PopupOrphanPayload;
|
|
358
380
|
'grideditor:view-change': ViewChangePayload;
|
|
359
381
|
'grideditor:target-change': TargetChangePayload;
|
|
382
|
+
'grideditor:selection-change': SelectionChangePayload;
|
|
360
383
|
'grideditor:after-autosave': AutosavePayload;
|
|
361
384
|
'grideditor:after-restore-draft': RestoreDraftPayload;
|
|
362
385
|
'grideditor:autosave-error': AutosaveErrorPayload;
|
|
@@ -468,6 +491,10 @@ export declare class GridEditor {
|
|
|
468
491
|
getActiveTarget(): HTMLElement | null;
|
|
469
492
|
/** Make a column or region, or the first a selector matches, where the toolbar adds; null for none. */
|
|
470
493
|
setActiveTarget(target: HTMLElement | string | null): this;
|
|
494
|
+
/** The node whose settings the sidebar shows, or null. Null unless settings_panel is 'sidebar'. */
|
|
495
|
+
getSelected(): HTMLElement | null;
|
|
496
|
+
/** Select a node with settings, or the first a selector matches, or null for none. Does nothing unless settings_panel is 'sidebar'. */
|
|
497
|
+
setSelected(node: HTMLElement | string | null): this;
|
|
471
498
|
getView(): View;
|
|
472
499
|
setLocale(code: string): this;
|
|
473
500
|
createRow(layout?: RowLayout, options?: Placement): HTMLElement | null;
|