@themarioga/grid-editor 3.1.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.
Files changed (52) hide show
  1. package/AUTO_SAVE.md +30 -0
  2. package/BUILDING.md +68 -0
  3. package/CHANGELOG.md +362 -0
  4. package/LICENSE +23 -0
  5. package/README.md +521 -0
  6. package/UPGRADING.md +88 -0
  7. package/dist/grideditor.css +3875 -0
  8. package/dist/grideditor.min.css +2 -0
  9. package/dist/grideditor.min.css.map +1 -0
  10. package/dist/jquery.grideditor.js +2996 -0
  11. package/dist/jquery.grideditor.min.js +2 -0
  12. package/dist/jquery.grideditor.min.js.map +1 -0
  13. package/dist/locales/grideditor.es.js +74 -0
  14. package/dist/locales/grideditor.es.min.js +2 -0
  15. package/dist/locales/grideditor.es.min.js.map +1 -0
  16. package/dist/plugins/grideditor.accordion.js +185 -0
  17. package/dist/plugins/grideditor.accordion.min.js +2 -0
  18. package/dist/plugins/grideditor.accordion.min.js.map +1 -0
  19. package/dist/plugins/grideditor.elements.js +141 -0
  20. package/dist/plugins/grideditor.elements.min.js +2 -0
  21. package/dist/plugins/grideditor.elements.min.js.map +1 -0
  22. package/dist/plugins/grideditor.popup.js +143 -0
  23. package/dist/plugins/grideditor.popup.min.js +2 -0
  24. package/dist/plugins/grideditor.popup.min.js.map +1 -0
  25. package/dist/plugins/grideditor.tabs.js +140 -0
  26. package/dist/plugins/grideditor.tabs.min.js +2 -0
  27. package/dist/plugins/grideditor.tabs.min.js.map +1 -0
  28. package/docs/events.md +158 -0
  29. package/docs/locale-keys.md +140 -0
  30. package/docs/plugins.md +163 -0
  31. package/example/autosave.html +89 -0
  32. package/example/basic.html +93 -0
  33. package/example/breakpoints.html +94 -0
  34. package/example/ckeditor.html +104 -0
  35. package/example/containers.html +214 -0
  36. package/example/elements.html +147 -0
  37. package/example/index.html +119 -0
  38. package/example/locale.html +84 -0
  39. package/example/plugins.html +217 -0
  40. package/example/summernote.html +106 -0
  41. package/example/wrap_content.html +44 -0
  42. package/package.json +66 -0
  43. package/src/js/jquery.grideditor.ckeditor.js +77 -0
  44. package/src/js/jquery.grideditor.js +2711 -0
  45. package/src/js/jquery.grideditor.summernote.js +72 -0
  46. package/src/js/jquery.grideditor.tinymce.js +135 -0
  47. package/src/js/locales/grideditor.es.js +74 -0
  48. package/src/js/plugins/grideditor.accordion.js +185 -0
  49. package/src/js/plugins/grideditor.elements.js +141 -0
  50. package/src/js/plugins/grideditor.popup.js +143 -0
  51. package/src/js/plugins/grideditor.tabs.js +140 -0
  52. package/src/less/grideditor.less +594 -0
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Element level controls for grid-editor.
3
+ *
4
+ * A feature plugin: load this file after the editor and the nodes a host
5
+ * marked inside a content area become elements - one movable, deletable thing
6
+ * each, instead of rich text. 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="dist/jquery.grideditor.min.js"></script>
10
+ * <script src="dist/plugins/grideditor.elements.min.js"></script>
11
+ */
12
+ (function($) {
13
+
14
+ $.extend($.fn.gridEditor.locales.en, {
15
+ 'tool.delete_element': 'Remove element',
16
+ 'tool.element_info': 'Element: {name}',
17
+ 'confirm.delete_element': 'Delete element?',
18
+ });
19
+
20
+ $.fn.gridEditor.features.elements = function(ge) {
21
+
22
+ function elementsEnabled() {
23
+ if (ge.settings.elements.enabled !== 'auto') { return !!ge.settings.elements.enabled; }
24
+
25
+ return ge.settings.elements.auto || ge.canvas.find(ge.settings.elements.selector).length > 0;
26
+ }
27
+
28
+ function elementsIn(contentArea) {
29
+ return ge.settings.elements.auto
30
+ ? contentArea.children()
31
+ : contentArea.children(ge.settings.elements.selector);
32
+ }
33
+
34
+ function markElements() {
35
+ if (!elementsEnabled()) { return; }
36
+
37
+ ge.canvas.find('.ge-content').each(function() {
38
+ elementsIn($(this)).each(function() {
39
+ var element = $(this).addClass('ge-element').attr('contenteditable', 'false');
40
+
41
+ if (element.find('> .ge-tools-drawer').length) { return; }
42
+
43
+ createElementControls(element);
44
+ });
45
+ });
46
+ }
47
+
48
+ function unmarkElements() {
49
+ ge.canvas.find('.ge-element').each(function() {
50
+ var element = $(this).removeClass('ge-element').removeAttr('contenteditable');
51
+
52
+ // A host element that had no class of its own should not come
53
+ // back from getHtml carrying an empty one
54
+ if (!element.attr('class')) { element.removeAttr('class'); }
55
+ });
56
+ }
57
+
58
+ function createElementControls(element) {
59
+ // data-mce-bogus="all" is how tinyMCE is told that a node is the
60
+ // editor's furniture rather than content: it leaves the subtree
61
+ // alone and keeps it out of what it serializes. Without it the
62
+ // drawer's tools are inline elements with no text, which is
63
+ // exactly what its cleanup removes, so an element inside an open
64
+ // editor would lose its move and delete tools.
65
+ var drawer = $('<div class="ge-tools-drawer ge-element-drawer" />')
66
+ .attr('data-mce-bogus', 'all')
67
+ .prependTo(element)
68
+ ;
69
+
70
+ ge.createMoveTool(drawer);
71
+ ge.createTool(drawer, ge.t('tool.element_info', { name: elementName(element) }),
72
+ 'ge-element-info', 'bi bi-info-circle');
73
+ ge.addSettingsTool(drawer, element, ge.settings.element_classes);
74
+
75
+ ge.settings.element_tools.forEach(function(hostTool) {
76
+ ge.createTool(drawer, hostTool.title || '', hostTool.className || '',
77
+ hostTool.iconClass || 'bi bi-wrench', hostTool.on);
78
+ });
79
+
80
+ ge.createTool(drawer, ge.t('tool.delete_element'), 'ge-delete-element', 'bi bi-trash', function() {
81
+ ge.deleteNode('element', element, ge.t('confirm.delete_element'), function(removed) {
82
+ element.animate({ opacity: 'hide', height: 'hide' }, 300, removed);
83
+ });
84
+ });
85
+ }
86
+
87
+ function elementName(element) {
88
+ var type = element.attr('data-ge-element');
89
+ var label = element.attr('data-ge-label');
90
+
91
+ if (label && type) { return label + ' (' + type + ')'; }
92
+
93
+ return label || type || element[0].tagName.toLowerCase();
94
+ }
95
+
96
+ function apiCreateElement(content, options) {
97
+ options = options || {};
98
+
99
+ var element = $('<div class="ge-element" />')
100
+ .attr('data-ge-element', options.type || 'element')
101
+ .append(content)
102
+ ;
103
+ if (options.label !== undefined) {
104
+ element.attr('data-ge-label', options.label);
105
+ }
106
+
107
+ return ge.place(element, 'element', options);
108
+ }
109
+
110
+ return {
111
+ methods: {
112
+ createElement: apiCreateElement,
113
+ },
114
+
115
+ /** A node this plugin marked is an element, whatever else it is. */
116
+ kindOf: function(node) {
117
+ return node.hasClass('ge-element') ? 'element' : null;
118
+ },
119
+
120
+ onInit: markElements,
121
+ onDeinit: unmarkElements,
122
+
123
+ /**
124
+ * An editor rewrites the content area as it takes it over, drawers
125
+ * included, so they go back in when it says it is ready.
126
+ */
127
+ onContentReady: markElements,
128
+
129
+ /** Elements move within a content area and between them. */
130
+ onSortable: function(shared) {
131
+ if (!elementsEnabled()) { return; }
132
+
133
+ ge.canvas.find('.ge-content').sortable($.extend({
134
+ items: '> .ge-element',
135
+ connectWith: '.ge-canvas .ge-content',
136
+ }, shared, ge.settings.sortable_options));
137
+ },
138
+ };
139
+ };
140
+
141
+ })(jQuery);
@@ -0,0 +1,2 @@
1
+ (a=>{a.extend(a.fn.gridEditor.locales.en,{"tool.delete_element":"Remove element","tool.element_info":"Element: {name}","confirm.delete_element":"Delete element?"}),a.fn.gridEditor.features.elements=function(l){function t(){return"auto"!==l.settings.elements.enabled?l.settings.elements.enabled:l.settings.elements.auto||0<l.canvas.find(l.settings.elements.selector).length}function e(){t()&&l.canvas.find(".ge-content").each(function(){var e;e=a(this),(l.settings.elements.auto?e.children():e.children(l.settings.elements.selector)).each(function(){var t,n,e=a(this).addClass("ge-element").attr("contenteditable","false");e.find("> .ge-tools-drawer").length||(t=e,n=a('<div class="ge-tools-drawer ge-element-drawer" />').attr("data-mce-bogus","all").prependTo(t),l.createMoveTool(n),l.createTool(n,l.t("tool.element_info",{name:(e=>{var t=e.attr("data-ge-element"),n=e.attr("data-ge-label");return n&&t?n+" ("+t+")":n||t||e[0].tagName.toLowerCase()})(t)}),"ge-element-info","bi bi-info-circle"),l.addSettingsTool(n,t,l.settings.element_classes),l.settings.element_tools.forEach(function(e){l.createTool(n,e.title||"",e.className||"",e.iconClass||"bi bi-wrench",e.on)}),l.createTool(n,l.t("tool.delete_element"),"ge-delete-element","bi bi-trash",function(){l.deleteNode("element",t,l.t("confirm.delete_element"),function(e){t.animate({opacity:"hide",height:"hide"},300,e)})}))})})}return{methods:{createElement:function(e,t){return t=t||{},e=a('<div class="ge-element" />').attr("data-ge-element",t.type||"element").append(e),void 0!==t.label&&e.attr("data-ge-label",t.label),l.place(e,"element",t)}},kindOf:function(e){return e.hasClass("ge-element")?"element":null},onInit:e,onDeinit:function(){l.canvas.find(".ge-element").each(function(){var e=a(this).removeClass("ge-element").removeAttr("contenteditable");e.attr("class")||e.removeAttr("class")})},onContentReady:e,onSortable:function(e){t()&&l.canvas.find(".ge-content").sortable(a.extend({items:"> .ge-element",connectWith:".ge-canvas .ge-content"},e,l.settings.sortable_options))}}}})(jQuery);
2
+ //# sourceMappingURL=grideditor.elements.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grideditor.elements.min.js","sources":["../../src/js/plugins/grideditor.elements.js"],"names":["$","extend","fn","gridEditor","locales","en","tool.delete_element","tool.element_info","confirm.delete_element","features","elements","ge","elementsEnabled","settings","enabled","auto","canvas","find","selector","length","markElements","each","contentArea","this","children","element","drawer","addClass","attr","prependTo","createMoveTool","createTool","t","name","type","label","tagName","toLowerCase","addSettingsTool","element_classes","element_tools","forEach","hostTool","title","className","iconClass","on","deleteNode","removed","animate","opacity","height","methods","createElement","content","options","append","undefined","place","kindOf","node","hasClass","onInit","onDeinit","removeClass","removeAttr","onContentReady","onSortable","shared","sortable","items","connectWith","sortable_options","jQuery"],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Popups for grid-editor.
3
+ *
4
+ * A container plugin: load this file after the editor and the toolbar offers
5
+ * a popup: a bootstrap modal and its trigger. What it can ask the editor for is the handle its factory is
6
+ * called with, described in docs/plugins.md.
7
+ *
8
+ * <script src="dist/jquery.grideditor.min.js"></script>
9
+ * <script src="dist/plugins/grideditor.popup.min.js"></script>
10
+ */
11
+ (function($) {
12
+
13
+ $.extend($.fn.gridEditor.locales.en, {
14
+ 'container.add_popup': 'Popup',
15
+ 'container.popup_title': 'Title',
16
+ 'container.popup_trigger': 'Open',
17
+ 'tool.toggle_popup': 'Fold this popup away while editing',
18
+ });
19
+
20
+ $.fn.gridEditor.containers.popup = function(ge) {
21
+
22
+ function popupIdOf(container) {
23
+ return container.attr('data-ge-popup-id');
24
+ }
25
+
26
+ function wirePopupTriggers() {
27
+ ge.canvas.find('[data-ge-popup-target]').each(function() {
28
+ var trigger = $(this).addClass('ge-popup-trigger');
29
+ var wanted = trigger.attr('data-ge-popup-target');
30
+
31
+ // Bootstrap's own attributes are written at getHtml time, not
32
+ // while editing, so a click here cannot open a real modal
33
+ trigger.removeAttr('data-bs-toggle').removeAttr('data-bs-target');
34
+
35
+ if (ge.canvas.find('[data-ge-popup-id="' + wanted + '"]').length) {
36
+ trigger.removeClass('ge-popup-orphan');
37
+ return;
38
+ }
39
+
40
+ var nearby = trigger.closest('.column').find('[data-ge-popup-id]');
41
+
42
+ if (nearby.length === 1) {
43
+ trigger.attr('data-ge-popup-target', popupIdOf(nearby)).removeClass('ge-popup-orphan');
44
+ return;
45
+ }
46
+
47
+ trigger.addClass('ge-popup-orphan');
48
+
49
+ ge.operate(function() {
50
+ ge.emit('popup-orphan', ge.payloadFor('popup', trigger, {
51
+ parent: trigger.parent(),
52
+ source: 'api',
53
+ missing: wanted,
54
+ }));
55
+ });
56
+ });
57
+ }
58
+
59
+ function writePopupTriggerAttributes() {
60
+ ge.canvas.find('[data-ge-popup-target]').each(function() {
61
+ var trigger = $(this);
62
+ var wanted = trigger.attr('data-ge-popup-target');
63
+
64
+ // The warning marking is editing furniture, whether or not
65
+ // the trigger can be wired up
66
+ trigger.removeClass('ge-popup-orphan');
67
+ if (!trigger.attr('class')) { trigger.removeAttr('class'); }
68
+
69
+ if (!ge.canvas.find('[data-ge-popup-id="' + wanted + '"]').length) { return; }
70
+
71
+ trigger.attr('data-bs-toggle', 'modal').attr('data-bs-target', '#' + wanted);
72
+ });
73
+ }
74
+
75
+ return {
76
+ labelKey: 'container.add_popup',
77
+ paneKind: 'popup',
78
+
79
+ // Triggers are markup the host owns, anywhere in the canvas, so they
80
+ // are looked at whenever the canvas is initialized rather than only
81
+ // when a popup is touched
82
+ onInit: wirePopupTriggers,
83
+ onDeinit: writePopupTriggerAttributes,
84
+
85
+ create: function(options) {
86
+ var id = ge.containerId('popup');
87
+ var container = $('<div />')
88
+ .attr('data-ge-container', 'popup')
89
+ .attr('data-ge-popup-id', id)
90
+ ;
91
+
92
+ if (options.trigger !== false) {
93
+ $('<button type="button" class="btn btn-primary ge-popup-trigger" />')
94
+ .attr('data-ge-popup-target', id)
95
+ .text(options.trigger_label || ge.t('container.popup_trigger'))
96
+ .appendTo(container)
97
+ ;
98
+ }
99
+
100
+ var dialog = $('<div class="modal-dialog" />');
101
+ if (options.size) { dialog.addClass('modal-' + options.size); }
102
+
103
+ $('<div class="modal fade" tabindex="-1" aria-hidden="true" />')
104
+ .attr('id', id)
105
+ .append(dialog.append($('<div class="modal-content" />')
106
+ .append($('<div class="modal-header" />')
107
+ .append($('<h5 class="modal-title" />')
108
+ .append($('<span class="ge-pane-label" />')
109
+ .text(options.title || ge.t('container.popup_title'))))
110
+ .append('<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'))
111
+ .append($('<div class="modal-body" />').append(ge.defaultRegion()))))
112
+ .appendTo(container)
113
+ ;
114
+
115
+ return container;
116
+ },
117
+
118
+ mark: function(container) {
119
+ // Nothing in a popup may reach Bootstrap while editing:
120
+ // the modal is rendered unfolded and static, and a real
121
+ // modal opening over it would be the editor fighting
122
+ // itself
123
+ ge.suspendToggles(container.find('[data-bs-dismiss]'));
124
+ ge.makeLabelEditable(ge.labelIn(container.find('.modal-title')));
125
+ },
126
+
127
+ unmark: function(container) {
128
+ ge.resumeToggles(container);
129
+ container.removeClass('ge-popup-collapsed');
130
+ ge.unwrapLabels(container);
131
+ },
132
+
133
+ /** A page of unfolded modals stays workable if they can be folded away. */
134
+ tools: function(drawer, container) {
135
+ ge.createTool(drawer, ge.t('tool.toggle_popup'), 'ge-toggle-popup', 'bi bi-chevron-bar-contract',
136
+ function() {
137
+ container.toggleClass('ge-popup-collapsed');
138
+ });
139
+ },
140
+ };
141
+ };
142
+
143
+ })(jQuery);
@@ -0,0 +1,2 @@
1
+ (n=>{n.extend(n.fn.gridEditor.locales.en,{"container.add_popup":"Popup","container.popup_title":"Title","container.popup_trigger":"Open","tool.toggle_popup":"Fold this popup away while editing"}),n.fn.gridEditor.containers.popup=function(o){return{labelKey:"container.add_popup",paneKind:"popup",onInit:function(){o.canvas.find("[data-ge-popup-target]").each(function(){var a,t=n(this).addClass("ge-popup-trigger"),p=t.attr("data-ge-popup-target");t.removeAttr("data-bs-toggle").removeAttr("data-bs-target"),o.canvas.find('[data-ge-popup-id="'+p+'"]').length?t.removeClass("ge-popup-orphan"):1===(a=t.closest(".column").find("[data-ge-popup-id]")).length?t.attr("data-ge-popup-target",a.attr("data-ge-popup-id")).removeClass("ge-popup-orphan"):(t.addClass("ge-popup-orphan"),o.operate(function(){o.emit("popup-orphan",o.payloadFor("popup",t,{parent:t.parent(),source:"api",missing:p}))}))})},onDeinit:function(){o.canvas.find("[data-ge-popup-target]").each(function(){var a=n(this),t=a.attr("data-ge-popup-target");a.removeClass("ge-popup-orphan"),a.attr("class")||a.removeAttr("class"),o.canvas.find('[data-ge-popup-id="'+t+'"]').length&&a.attr("data-bs-toggle","modal").attr("data-bs-target","#"+t)})},create:function(a){var t=o.containerId("popup"),p=n("<div />").attr("data-ge-container","popup").attr("data-ge-popup-id",t),e=(!1!==a.trigger&&n('<button type="button" class="btn btn-primary ge-popup-trigger" />').attr("data-ge-popup-target",t).text(a.trigger_label||o.t("container.popup_trigger")).appendTo(p),n('<div class="modal-dialog" />'));return a.size&&e.addClass("modal-"+a.size),n('<div class="modal fade" tabindex="-1" aria-hidden="true" />').attr("id",t).append(e.append(n('<div class="modal-content" />').append(n('<div class="modal-header" />').append(n('<h5 class="modal-title" />').append(n('<span class="ge-pane-label" />').text(a.title||o.t("container.popup_title")))).append('<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>')).append(n('<div class="modal-body" />').append(o.defaultRegion())))).appendTo(p),p},mark:function(a){o.suspendToggles(a.find("[data-bs-dismiss]")),o.makeLabelEditable(o.labelIn(a.find(".modal-title")))},unmark:function(a){o.resumeToggles(a),a.removeClass("ge-popup-collapsed"),o.unwrapLabels(a)},tools:function(a,t){o.createTool(a,o.t("tool.toggle_popup"),"ge-toggle-popup","bi bi-chevron-bar-contract",function(){t.toggleClass("ge-popup-collapsed")})}}}})(jQuery);
2
+ //# sourceMappingURL=grideditor.popup.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grideditor.popup.min.js","sources":["../../src/js/plugins/grideditor.popup.js"],"names":["$","extend","fn","gridEditor","locales","en","container.add_popup","container.popup_title","container.popup_trigger","tool.toggle_popup","containers","popup","ge","labelKey","paneKind","onInit","canvas","find","each","nearby","trigger","this","addClass","wanted","attr","removeAttr","length","removeClass","closest","operate","emit","payloadFor","parent","source","missing","onDeinit","create","options","id","containerId","container","dialog","text","trigger_label","t","appendTo","size","append","title","defaultRegion","mark","suspendToggles","makeLabelEditable","labelIn","unmark","resumeToggles","unwrapLabels","tools","drawer","createTool","toggleClass","jQuery"],"mappings":"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"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Tabs for grid-editor.
3
+ *
4
+ * A container plugin: load this file after the editor and the toolbar offers
5
+ * a tabs container. What it can ask the editor for is the handle its factory is
6
+ * called with, described in docs/plugins.md.
7
+ *
8
+ * <script src="dist/jquery.grideditor.min.js"></script>
9
+ * <script src="dist/plugins/grideditor.tabs.min.js"></script>
10
+ */
11
+ (function($) {
12
+
13
+ $.extend($.fn.gridEditor.locales.en, {
14
+ 'container.add_tabs': 'Tabs',
15
+ 'container.add_tab': 'Add tab',
16
+ 'container.tab_label': 'Tab {number}',
17
+ 'confirm.delete_tab': 'Delete this tab and everything in it?',
18
+ });
19
+
20
+ $.fn.gridEditor.containers.tabs = function(ge) {
21
+
22
+ function addTabTo(container, options) {
23
+ options = options || {};
24
+
25
+ var strip = container.find('> .nav-tabs');
26
+ var content = container.find('> .tab-content');
27
+ var id = ge.containerId('tab');
28
+ var number = strip.children('.nav-item').length + 1;
29
+
30
+ $('<li class="nav-item ge-tab" role="presentation" />')
31
+ .append($('<button class="nav-link" type="button" role="tab" data-bs-toggle="tab" />')
32
+ .attr('data-bs-target', '#' + id)
33
+ .attr('aria-controls', id)
34
+ .append($('<span class="ge-pane-label" />')
35
+ .text(options.label || ge.t('container.tab_label', { number: number })))
36
+ )
37
+ .appendTo(strip)
38
+ ;
39
+
40
+ var pane = $('<div class="tab-pane fade" role="tabpanel" tabindex="0" />')
41
+ .attr('id', id)
42
+ .append(ge.defaultRegion())
43
+ .appendTo(content)
44
+ ;
45
+
46
+ if (options.activate || number === 1) { activatePane(container, pane); }
47
+
48
+ return pane;
49
+ }
50
+
51
+ function activatePane(container, pane) {
52
+ var id = pane.attr('id');
53
+
54
+ container.find('> .tab-content > .tab-pane').removeClass('show active');
55
+ pane.addClass('show active');
56
+
57
+ container.find('> .nav-tabs .nav-link').each(function() {
58
+ var button = $(this);
59
+ var active = button.attr('data-bs-target') === '#' + id;
60
+
61
+ button.toggleClass('active', active).attr('aria-selected', active ? 'true' : 'false');
62
+ });
63
+ }
64
+
65
+ function tabOf(container, pane) {
66
+ return container.find('> .nav-tabs .nav-link[data-bs-target="#' + pane.attr('id') + '"]')
67
+ .closest('.nav-item');
68
+ }
69
+
70
+ function paneOf(container, tab) {
71
+ return container.find(tab.find('.nav-link').attr('data-bs-target'));
72
+ }
73
+
74
+ return {
75
+ labelKey: 'container.add_tabs',
76
+ addPaneKey: 'container.add_tab',
77
+ paneKind: 'tab',
78
+
79
+ create: function(options) {
80
+ var container = $('<div />').attr('data-ge-container', 'tabs');
81
+ var labels = options.labels || [];
82
+ var count = options.tabs || labels.length || 2;
83
+
84
+ $('<ul class="nav nav-tabs" role="tablist" />').appendTo(container);
85
+ $('<div class="tab-content" />').appendTo(container);
86
+
87
+ for (var i = 0; i < count; i++) {
88
+ addTabTo(container, { label: labels[i] });
89
+ }
90
+
91
+ return container;
92
+ },
93
+
94
+ addPane: addTabTo,
95
+
96
+ mark: function(container) {
97
+ container.find('> .tab-content > .tab-pane').addClass('ge-tab-pane');
98
+
99
+ container.find('> .nav-tabs > .nav-item').each(function() {
100
+ var tab = $(this).addClass('ge-tab');
101
+
102
+
103
+ ge.makeLabelEditable(ge.labelIn(tab.find('.nav-link')));
104
+
105
+ if (tab.find('> .ge-tools-drawer').length) { return; }
106
+
107
+ ge.createPaneControls(tab, 'tab', ge.settings.tab_tools, ge.t('confirm.delete_tab'),
108
+ function(removed) {
109
+ var pane = paneOf(container, tab);
110
+ var wasActive = pane.hasClass('active');
111
+
112
+ tab.fadeOut(200, function() {
113
+ pane.remove();
114
+ removed();
115
+
116
+ var first = container.find('> .tab-content > .tab-pane').first();
117
+ if (wasActive && first.length) { activatePane(container, first); }
118
+ });
119
+ });
120
+ });
121
+ },
122
+
123
+ unmark: function(container) {
124
+ ge.resumeToggles(container);
125
+ container.find('.ge-tab-pane').removeClass('ge-tab-pane');
126
+ ge.unwrapLabels(container);
127
+ },
128
+
129
+ /** Panes read in tab order, whatever order they were dropped in. */
130
+ afterPaneMove: function(container) {
131
+ var content = container.find('> .tab-content');
132
+
133
+ container.find('> .nav-tabs > .nav-item').each(function() {
134
+ content.append(paneOf(container, $(this)));
135
+ });
136
+ },
137
+ };
138
+ };
139
+
140
+ })(jQuery);
@@ -0,0 +1,2 @@
1
+ (b=>{b.extend(b.fn.gridEditor.locales.en,{"container.add_tabs":"Tabs","container.add_tab":"Add tab","container.tab_label":"Tab {number}","confirm.delete_tab":"Delete this tab and everything in it?"}),b.fn.gridEditor.containers.tabs=function(d){function r(a,t){t=t||{};var n=a.find("> .nav-tabs"),e=a.find("> .tab-content"),i=d.containerId("tab"),r=n.children(".nav-item").length+1,n=(b('<li class="nav-item ge-tab" role="presentation" />').append(b('<button class="nav-link" type="button" role="tab" data-bs-toggle="tab" />').attr("data-bs-target","#"+i).attr("aria-controls",i).append(b('<span class="ge-pane-label" />').text(t.label||d.t("container.tab_label",{number:r})))).appendTo(n),b('<div class="tab-pane fade" role="tabpanel" tabindex="0" />').attr("id",i).append(d.defaultRegion()).appendTo(e));return!t.activate&&1!==r||s(a,n),n}function s(a,t){var n=t.attr("id");a.find("> .tab-content > .tab-pane").removeClass("show active"),t.addClass("show active"),a.find("> .nav-tabs .nav-link").each(function(){var a=b(this),t=a.attr("data-bs-target")==="#"+n;a.toggleClass("active",t).attr("aria-selected",t?"true":"false")})}function l(a,t){return a.find(t.find(".nav-link").attr("data-bs-target"))}return{labelKey:"container.add_tabs",addPaneKey:"container.add_tab",paneKind:"tab",create:function(a){var t=b("<div />").attr("data-ge-container","tabs"),n=a.labels||[],e=a.tabs||n.length||2;b('<ul class="nav nav-tabs" role="tablist" />').appendTo(t),b('<div class="tab-content" />').appendTo(t);for(var i=0;i<e;i++)r(t,{label:n[i]});return t},addPane:r,mark:function(i){i.find("> .tab-content > .tab-pane").addClass("ge-tab-pane"),i.find("> .nav-tabs > .nav-item").each(function(){var a=b(this).addClass("ge-tab");d.makeLabelEditable(d.labelIn(a.find(".nav-link"))),a.find("> .ge-tools-drawer").length||d.createPaneControls(a,"tab",d.settings.tab_tools,d.t("confirm.delete_tab"),function(t){var n=l(i,a),e=n.hasClass("active");a.fadeOut(200,function(){n.remove(),t();var a=i.find("> .tab-content > .tab-pane").first();e&&a.length&&s(i,a)})})})},unmark:function(a){d.resumeToggles(a),a.find(".ge-tab-pane").removeClass("ge-tab-pane"),d.unwrapLabels(a)},afterPaneMove:function(a){var t=a.find("> .tab-content");a.find("> .nav-tabs > .nav-item").each(function(){t.append(l(a,b(this)))})}}}})(jQuery);
2
+ //# sourceMappingURL=grideditor.tabs.min.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grideditor.tabs.min.js","sources":["../../src/js/plugins/grideditor.tabs.js"],"names":["$","extend","fn","gridEditor","locales","en","container.add_tabs","container.add_tab","container.tab_label","confirm.delete_tab","containers","tabs","ge","addTabTo","container","options","strip","find","content","id","containerId","number","children","length","pane","append","attr","text","label","t","appendTo","defaultRegion","activate","activatePane","removeClass","addClass","each","button","this","active","toggleClass","paneOf","tab","labelKey","addPaneKey","paneKind","create","labels","count","i","addPane","mark","makeLabelEditable","labelIn","createPaneControls","settings","tab_tools","removed","wasActive","hasClass","fadeOut","remove","first","unmark","resumeToggles","unwrapLabels","afterPaneMove","jQuery"],"mappings":"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"}
package/docs/events.md ADDED
@@ -0,0 +1,158 @@
1
+ grid-editor events
2
+ ==================
3
+
4
+ Every operation grid-editor performs is announced, twice: as a jQuery event on
5
+ the canvas, and as a callback in the `callbacks` setting. The event is the
6
+ primary mechanism — several listeners, namespacing, `off()` — and the callback
7
+ is there for hosts that configure the plugin once, from generated or
8
+ server-side code, and cannot easily bind.
9
+
10
+ ```javascript
11
+ // as events
12
+ $('#myGrid').on('grideditor:before-add-row', function(e, payload) {
13
+ if (payload.parent.hasClass('locked')) { e.preventDefault(); }
14
+ });
15
+
16
+ // as callbacks
17
+ $('#myGrid').gridEditor({
18
+ callbacks: {
19
+ before_add_row: function(payload) { return !payload.parent.hasClass('locked'); },
20
+ after_move: function(payload) { console.log(payload.from, payload.to); },
21
+ },
22
+ });
23
+ ```
24
+
25
+ A callback's name is its event name with `grideditor:` dropped and the dashes
26
+ turned into underscores: `before-add-row` → `before_add_row`.
27
+
28
+
29
+ The catalogue
30
+ -------------
31
+
32
+ Adding fires a specific event and then a generic one, so a listener that cares
33
+ about every insertion can bind `grideditor:before-add` and switch on
34
+ `payload.kind`.
35
+
36
+ | Specific | Generic | Cancelable | Fires |
37
+ | --- | --- | --- | --- |
38
+ | `grideditor:before-add-row` | `grideditor:before-add` | yes | before a row is inserted |
39
+ | `grideditor:after-add-row` | `grideditor:after-add` | no | after insertion, once the canvas is up to date |
40
+ | `grideditor:before-add-column` | `grideditor:before-add` | yes | before a column is inserted |
41
+ | `grideditor:after-add-column` | `grideditor:after-add` | no | |
42
+ | `grideditor:before-add-container` | `grideditor:before-add` | yes | before a container is inserted; `payload.kind` is `tabs`, `accordion` or `popup` |
43
+ | `grideditor:after-add-container` | `grideditor:after-add` | no | |
44
+ | `grideditor:before-add-tab` | `grideditor:before-add` | yes | before a tab is added to a tabs container |
45
+ | `grideditor:after-add-tab` | `grideditor:after-add` | no | |
46
+ | `grideditor:before-add-accordion-item` | `grideditor:before-add` | yes | before an item is added to an accordion |
47
+ | `grideditor:after-add-accordion-item` | `grideditor:after-add` | no | |
48
+ | `grideditor:before-add-element` | `grideditor:before-add` | yes | before an element is inserted |
49
+ | `grideditor:after-add-element` | `grideditor:after-add` | no | |
50
+ | `grideditor:before-delete` | — | yes | before any node is removed, whatever its kind |
51
+ | `grideditor:after-delete` | — | no | after removal completes, animation included |
52
+ | `grideditor:before-move` | — | yes | on drag start (see *Canceling*) |
53
+ | `grideditor:after-move` | — | no | on drop, only if the node actually changed position |
54
+ | `grideditor:before-resize` | — | yes | before a column's size changes, from a tool or a drag |
55
+ | `grideditor:after-resize` | — | no | after the size class is written, only if the size changed |
56
+ | `grideditor:before-indent` | — | yes | before a column's offset changes |
57
+ | `grideditor:after-indent` | — | no | after the offset class is written |
58
+ | `grideditor:popup-orphan` | — | no | on `init`, once per trigger whose popup is missing and cannot be re-pointed |
59
+
60
+ Two things here are not in the 3.0 specification's catalogue. The indent pair,
61
+ because the indent tools are an operation like any other and announce
62
+ themselves like one. And the add events for panes — a tab, an accordion item —
63
+ which follow the same pattern as the rest.
64
+
65
+
66
+ The payload
67
+ -----------
68
+
69
+ ```javascript
70
+ {
71
+ kind: 'row', // row | column | content | element
72
+ // tabs | accordion | popup | tab | accordion-item
73
+ node: jQuery, // the node added, deleted, moved or resized
74
+ parent: jQuery, // where it is going, or where it came from on a delete
75
+ canvas: jQuery,
76
+ breakpoint: 'lg', // the view at the time: a breakpoint key, or 'all'
77
+ source: 'tool', // tool | api | dragdrop
78
+
79
+ // move only
80
+ from: { parent: jQuery, index: 2 },
81
+ to: { parent: jQuery, index: 0 },
82
+
83
+ // resize and indent only: units, not pixels
84
+ from: 6,
85
+ to: 7,
86
+
87
+ // a pane inside a container
88
+ container: jQuery,
89
+
90
+ // popup-orphan only
91
+ missing: 'ge-popup-3-a91', // the id the trigger pointed at
92
+ }
93
+ ```
94
+
95
+ `source` matters to a host that both drives the editor from its own palette and
96
+ listens for what the user does: `api` is your own call coming back to you,
97
+ `tool` is a click in the editor, `dragdrop` is a gesture.
98
+
99
+ `kind: 'content'` appears when a content area itself is dragged between
100
+ columns. The kinds for containers are the container's own type, so a listener
101
+ can tell a tabs container from an accordion without reading the markup.
102
+
103
+
104
+ Canceling, and what it can honestly do
105
+ --------------------------------------
106
+
107
+ `preventDefault()` on either event, or returning `false` from the callback,
108
+ cancels a `before-*`. What that means depends on the operation:
109
+
110
+ - **Add.** Nothing is inserted and no `after-*` fires. A `create*` method
111
+ returns `null` instead of the node, so a host can tell.
112
+ - **Delete.** The node is left alone. This is how a host replaces the built-in
113
+ question with a dialog of its own: cancel the event, ask in your own way, and
114
+ then remove the node and call `reset()`. The editor's own confirmation modal
115
+ never appears for a canceled delete — the host's handler runs first, on
116
+ purpose.
117
+ - **Move.** jQuery UI cannot refuse a drag once it has started, so
118
+ `before-move` fires from the sortable's `start` handler and canceling marks
119
+ the drag: on drop the item returns to where it came from and no `after-move`
120
+ fires. The drag is visible and then reverts; it is not prevented outright.
121
+ - **Resize.** From a tool, nothing is written. From a drag, the drag is refused
122
+ at every step, so the column ends where it began — jQuery UI's `resizable`
123
+ ignores `false` from its start handler, unlike its `draggable`.
124
+ - **Indent.** Nothing is written.
125
+
126
+ `after-move` is suppressed when the drop leaves the node in the same parent at
127
+ the same index, and `after-resize` when the snapped size equals the old one, so
128
+ a click-drag that goes nowhere is not reported as an operation.
129
+
130
+
131
+ Ordering
132
+ --------
133
+
134
+ 1. `before-*`, the specific name and then the generic one, then the matching
135
+ callbacks — any of them may cancel
136
+ 2. the DOM change
137
+ 3. `init()`, so drawers and sortables exist for the new markup
138
+ 4. `after-*`, in the same order
139
+
140
+ An `after-*` handler therefore sees a canvas that is ready to be edited.
141
+
142
+
143
+ Calling back into the editor
144
+ ----------------------------
145
+
146
+ A handler may call the editor. `init`, `reset` and the `create*` methods called
147
+ from inside a handler are queued and run when the operation that called them
148
+ has finished, rather than rebuilding the canvas underneath it:
149
+
150
+ ```javascript
151
+ $('#myGrid').on('grideditor:after-add-row', function(e, payload) {
152
+ // runs after this add has finished, not in the middle of it
153
+ $('#myGrid').gridEditor('createRow', [6, 6], { appendTo: payload.canvas });
154
+ });
155
+ ```
156
+
157
+ A `create*` called this way returns the node it made, but cannot say yet
158
+ whether its own `before-add` will be canceled.