@innovastudio/contentbuilder 1.5.158 → 1.5.159
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/package.json +2 -1
- package/public/contentbuilder/contentbuilder.css +149 -6
- package/public/contentbuilder/contentbuilder.esm.js +827 -3
- package/public/contentbuilder/contentbuilder.min.js +6 -6
- package/public/contentbuilder/themes/colored-blue.css +3 -2
- package/public/contentbuilder/themes/colored-blue2.css +3 -2
- package/public/contentbuilder/themes/colored-blue3.css +3 -2
- package/public/contentbuilder/themes/colored-blue4.css +3 -2
- package/public/contentbuilder/themes/colored-blue5.css +3 -2
- package/public/contentbuilder/themes/colored-blue6.css +3 -2
- package/public/contentbuilder/themes/colored-blue7.css +3 -2
- package/public/contentbuilder/themes/colored-blue8.css +3 -2
- package/public/contentbuilder/themes/colored-darkblue.css +3 -2
- package/public/contentbuilder/themes/colored-gray.css +3 -2
- package/public/contentbuilder/themes/colored-green.css +3 -2
- package/public/contentbuilder/themes/colored-green2.css +3 -2
- package/public/contentbuilder/themes/colored-green3.css +3 -2
- package/public/contentbuilder/themes/colored-green4.css +3 -2
- package/public/contentbuilder/themes/colored-green5.css +3 -2
- package/public/contentbuilder/themes/colored-magenta.css +3 -2
- package/public/contentbuilder/themes/colored-orange.css +3 -2
- package/public/contentbuilder/themes/colored-orange2.css +3 -2
- package/public/contentbuilder/themes/colored-orange3.css +3 -2
- package/public/contentbuilder/themes/colored-pink.css +3 -2
- package/public/contentbuilder/themes/colored-pink2.css +3 -2
- package/public/contentbuilder/themes/colored-pink3.css +3 -2
- package/public/contentbuilder/themes/colored-pink4.css +3 -2
- package/public/contentbuilder/themes/colored-purple.css +3 -2
- package/public/contentbuilder/themes/colored-purple2.css +3 -2
- package/public/contentbuilder/themes/colored-red.css +3 -2
- package/public/contentbuilder/themes/colored-red2.css +3 -2
- package/public/contentbuilder/themes/colored-red3.css +3 -2
- package/public/contentbuilder/themes/colored-red4.css +3 -2
- package/public/contentbuilder/themes/colored-red5.css +3 -2
- package/public/contentbuilder/themes/colored-yellow.css +3 -2
- package/public/contentbuilder/themes/colored-yellow2.css +3 -2
- package/public/contentbuilder/themes/dark-blue.css +3 -2
- package/public/contentbuilder/themes/dark-blue2.css +3 -2
- package/public/contentbuilder/themes/dark-blue3.css +3 -2
- package/public/contentbuilder/themes/dark-gray.css +3 -2
- package/public/contentbuilder/themes/dark-pink.css +3 -2
- package/public/contentbuilder/themes/dark-purple.css +3 -2
- package/public/contentbuilder/themes/dark-red.css +3 -2
- package/public/contentbuilder/themes/dark.css +16 -2
|
@@ -14428,7 +14428,7 @@ class HtmlUtil {
|
|
|
14428
14428
|
this.builder.opts.onRender();
|
|
14429
14429
|
|
|
14430
14430
|
// Re-select
|
|
14431
|
-
if
|
|
14431
|
+
// if(row.firstChild) row.firstChild.click();
|
|
14432
14432
|
//Change to row selection
|
|
14433
14433
|
row.classList.remove('row-outline');
|
|
14434
14434
|
//Hide Column tool (new!)
|
|
@@ -15040,6 +15040,7 @@ class HtmlUtil {
|
|
|
15040
15040
|
|
|
15041
15041
|
// Remove runtime-added attributes
|
|
15042
15042
|
element.removeAttribute('data-cb-original-content');
|
|
15043
|
+
element.removeAttribute('data-cb-loaded');
|
|
15043
15044
|
|
|
15044
15045
|
// element.removeAttribute('data-cb-logo-loop-initialized');
|
|
15045
15046
|
|
|
@@ -50724,6 +50725,815 @@ class Spacer {
|
|
|
50724
50725
|
}
|
|
50725
50726
|
}
|
|
50726
50727
|
|
|
50728
|
+
/**
|
|
50729
|
+
* ContentBox Settings UI Generator
|
|
50730
|
+
* Automatically generates settings form based on plugin schema
|
|
50731
|
+
*
|
|
50732
|
+
* Usage in ContentBox Editor:
|
|
50733
|
+
* const generator = new SettingsUIGenerator(runtime);
|
|
50734
|
+
* const form = generator.generateForm('logo-loop', currentElement);
|
|
50735
|
+
* panel.appendChild(form);
|
|
50736
|
+
*/
|
|
50737
|
+
|
|
50738
|
+
class SettingsUIGenerator {
|
|
50739
|
+
constructor(runtime, builder) {
|
|
50740
|
+
this.runtime = runtime;
|
|
50741
|
+
this.builder = builder;
|
|
50742
|
+
}
|
|
50743
|
+
|
|
50744
|
+
/**
|
|
50745
|
+
* Generate settings form for a plugin
|
|
50746
|
+
* @param {string} pluginName - Plugin name
|
|
50747
|
+
* @param {HTMLElement} element - Current element being edited
|
|
50748
|
+
* @returns {HTMLElement} Form element
|
|
50749
|
+
*/
|
|
50750
|
+
generateForm(pluginName, element, onChange) {
|
|
50751
|
+
const plugin = this.runtime.getPlugin(pluginName);
|
|
50752
|
+
if (!plugin || !plugin.settings) {
|
|
50753
|
+
console.warn(`Plugin "${pluginName}" has no settings schema`);
|
|
50754
|
+
return this.createEmptyForm();
|
|
50755
|
+
}
|
|
50756
|
+
const form = document.createElement('div');
|
|
50757
|
+
form.className = 'cb-settings-form';
|
|
50758
|
+
|
|
50759
|
+
// Get current values from element
|
|
50760
|
+
const currentValues = this.getCurrentValues(element, plugin.settings);
|
|
50761
|
+
|
|
50762
|
+
// Check if plugin has grouped settings
|
|
50763
|
+
if (plugin.settings._groups) {
|
|
50764
|
+
this.generateGroupedForm(form, plugin.settings, currentValues);
|
|
50765
|
+
} else {
|
|
50766
|
+
this.generateFlatForm(form, plugin.settings, currentValues);
|
|
50767
|
+
}
|
|
50768
|
+
|
|
50769
|
+
// Attach listeners for auto-update
|
|
50770
|
+
if (typeof onChange === 'function') {
|
|
50771
|
+
form.addEventListener('input', () => {
|
|
50772
|
+
const values = this.getFormValues(form);
|
|
50773
|
+
onChange(values, element);
|
|
50774
|
+
});
|
|
50775
|
+
form.addEventListener('change', () => {
|
|
50776
|
+
const values = this.getFormValues(form);
|
|
50777
|
+
onChange(values, element);
|
|
50778
|
+
});
|
|
50779
|
+
}
|
|
50780
|
+
return form;
|
|
50781
|
+
}
|
|
50782
|
+
|
|
50783
|
+
/**
|
|
50784
|
+
* Generate flat form (no groups)
|
|
50785
|
+
*/
|
|
50786
|
+
generateFlatForm(container, settings, currentValues) {
|
|
50787
|
+
Object.keys(settings).forEach(key => {
|
|
50788
|
+
if (key.startsWith('_')) return; // Skip meta keys
|
|
50789
|
+
|
|
50790
|
+
const field = settings[key];
|
|
50791
|
+
const fieldElement = this.createField(key, field, currentValues[key]);
|
|
50792
|
+
container.appendChild(fieldElement);
|
|
50793
|
+
});
|
|
50794
|
+
}
|
|
50795
|
+
|
|
50796
|
+
/**
|
|
50797
|
+
* Generate grouped form
|
|
50798
|
+
*/
|
|
50799
|
+
generateGroupedForm(container, settings, currentValues) {
|
|
50800
|
+
const groups = settings._groups || [];
|
|
50801
|
+
groups.forEach(group => {
|
|
50802
|
+
const groupElement = document.createElement('div');
|
|
50803
|
+
groupElement.className = 'cb-settings-group';
|
|
50804
|
+
const groupTitle = document.createElement('h3');
|
|
50805
|
+
groupTitle.className = 'cb-settings-group-title';
|
|
50806
|
+
groupTitle.style.cssText = 'font-size: 17px;font-weight: 500;';
|
|
50807
|
+
groupTitle.textContent = group.label;
|
|
50808
|
+
groupElement.appendChild(groupTitle);
|
|
50809
|
+
group.fields.forEach(fieldKey => {
|
|
50810
|
+
const field = settings[fieldKey];
|
|
50811
|
+
if (!field) return;
|
|
50812
|
+
const fieldElement = this.createField(fieldKey, field, currentValues[fieldKey]);
|
|
50813
|
+
groupElement.appendChild(fieldElement);
|
|
50814
|
+
});
|
|
50815
|
+
container.appendChild(groupElement);
|
|
50816
|
+
});
|
|
50817
|
+
}
|
|
50818
|
+
|
|
50819
|
+
/**
|
|
50820
|
+
* Create a single form field
|
|
50821
|
+
*/
|
|
50822
|
+
createField(name, config, value) {
|
|
50823
|
+
const wrapper = document.createElement('div');
|
|
50824
|
+
wrapper.className = 'cb-settings-field';
|
|
50825
|
+
wrapper.style.marginBottom = '20px';
|
|
50826
|
+
wrapper.setAttribute('data-field', name);
|
|
50827
|
+
|
|
50828
|
+
// Add conditional display logic
|
|
50829
|
+
if (config.dependsOn) {
|
|
50830
|
+
wrapper.setAttribute('data-depends-on', JSON.stringify(config.dependsOn));
|
|
50831
|
+
wrapper.style.display = 'none'; // Hidden by default, shown by JS
|
|
50832
|
+
}
|
|
50833
|
+
|
|
50834
|
+
// Label
|
|
50835
|
+
const label = document.createElement('label');
|
|
50836
|
+
label.className = 'cb-settings-label';
|
|
50837
|
+
label.style.fontWeight = 500;
|
|
50838
|
+
label.textContent = config.label || name;
|
|
50839
|
+
// wrapper.appendChild(label);
|
|
50840
|
+
|
|
50841
|
+
// Input based on type
|
|
50842
|
+
const input = this.createInput(name, config, value);
|
|
50843
|
+
wrapper.appendChild(input);
|
|
50844
|
+
|
|
50845
|
+
// Description
|
|
50846
|
+
// if (config.description) {
|
|
50847
|
+
// const desc = document.createElement('p');
|
|
50848
|
+
// desc.className = 'cb-settings-description';
|
|
50849
|
+
// desc.textContent = config.description;
|
|
50850
|
+
// wrapper.appendChild(desc);
|
|
50851
|
+
// }
|
|
50852
|
+
|
|
50853
|
+
return wrapper;
|
|
50854
|
+
}
|
|
50855
|
+
|
|
50856
|
+
/**
|
|
50857
|
+
* Create input element based on field type
|
|
50858
|
+
*/
|
|
50859
|
+
createInput(name, config, value) {
|
|
50860
|
+
const currentValue = value !== undefined ? value : config.default;
|
|
50861
|
+
switch (config.type) {
|
|
50862
|
+
case 'number':
|
|
50863
|
+
return this.createNumberInput(name, config, currentValue);
|
|
50864
|
+
case 'boolean':
|
|
50865
|
+
return this.createCheckboxInput(name, config, currentValue);
|
|
50866
|
+
case 'select':
|
|
50867
|
+
return this.createSelectInput(name, config, currentValue);
|
|
50868
|
+
case 'radio':
|
|
50869
|
+
return this.createRadioInput(name, config, currentValue);
|
|
50870
|
+
case 'textarea':
|
|
50871
|
+
return this.createTextareaInput(name, config, currentValue);
|
|
50872
|
+
case 'color':
|
|
50873
|
+
return this.createColorInput(name, config, currentValue);
|
|
50874
|
+
case 'range':
|
|
50875
|
+
return this.createRangeInput(name, config, currentValue);
|
|
50876
|
+
case 'text':
|
|
50877
|
+
default:
|
|
50878
|
+
return this.createTextInput(name, config, currentValue);
|
|
50879
|
+
}
|
|
50880
|
+
}
|
|
50881
|
+
createTextInput(name, config, value) {
|
|
50882
|
+
const label = document.createElement('label');
|
|
50883
|
+
label.className = 'label';
|
|
50884
|
+
label.style.fontWeight = 500;
|
|
50885
|
+
const labelText = document.createElement('div');
|
|
50886
|
+
labelText.textContent = config.label || name;
|
|
50887
|
+
label.appendChild(labelText);
|
|
50888
|
+
const input = document.createElement('input');
|
|
50889
|
+
input.type = 'text';
|
|
50890
|
+
input.name = name;
|
|
50891
|
+
input.value = value || '';
|
|
50892
|
+
if (config.placeholder) input.placeholder = config.placeholder;
|
|
50893
|
+
label.appendChild(input);
|
|
50894
|
+
|
|
50895
|
+
// Add description if exists
|
|
50896
|
+
if (config.description) {
|
|
50897
|
+
const desc = document.createElement('small');
|
|
50898
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
50899
|
+
desc.textContent = config.description;
|
|
50900
|
+
label.appendChild(desc);
|
|
50901
|
+
}
|
|
50902
|
+
return label;
|
|
50903
|
+
}
|
|
50904
|
+
createNumberInput(name, config, value) {
|
|
50905
|
+
const label = document.createElement('label');
|
|
50906
|
+
label.className = 'label';
|
|
50907
|
+
label.style.fontWeight = 500;
|
|
50908
|
+
const labelText = document.createElement('div');
|
|
50909
|
+
labelText.textContent = config.label || name;
|
|
50910
|
+
if (config.unit) {
|
|
50911
|
+
labelText.textContent += ` (${config.unit})`;
|
|
50912
|
+
}
|
|
50913
|
+
label.appendChild(labelText);
|
|
50914
|
+
const input = document.createElement('input');
|
|
50915
|
+
input.type = 'number';
|
|
50916
|
+
input.style.cssText = 'width: 100px;';
|
|
50917
|
+
input.name = name;
|
|
50918
|
+
input.value = value !== undefined ? value : config.default;
|
|
50919
|
+
if (config.min !== undefined) input.min = config.min;
|
|
50920
|
+
if (config.max !== undefined) input.max = config.max;
|
|
50921
|
+
if (config.step !== undefined) input.step = config.step;
|
|
50922
|
+
label.appendChild(input);
|
|
50923
|
+
if (config.description) {
|
|
50924
|
+
const desc = document.createElement('small');
|
|
50925
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
50926
|
+
desc.textContent = config.description;
|
|
50927
|
+
label.appendChild(desc);
|
|
50928
|
+
}
|
|
50929
|
+
return label;
|
|
50930
|
+
}
|
|
50931
|
+
createCheckboxInput(name, config, value) {
|
|
50932
|
+
const label = document.createElement('label');
|
|
50933
|
+
label.className = 'label checkbox';
|
|
50934
|
+
const div = document.createElement('div');
|
|
50935
|
+
const input = document.createElement('input');
|
|
50936
|
+
input.type = 'checkbox';
|
|
50937
|
+
input.name = name;
|
|
50938
|
+
input.checked = value !== undefined ? value : config.default;
|
|
50939
|
+
const span = document.createElement('span');
|
|
50940
|
+
span.textContent = config.label || name;
|
|
50941
|
+
label.appendChild(input);
|
|
50942
|
+
label.appendChild(span);
|
|
50943
|
+
div.appendChild(label);
|
|
50944
|
+
if (config.description) {
|
|
50945
|
+
const desc = document.createElement('small');
|
|
50946
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
50947
|
+
desc.textContent = config.description;
|
|
50948
|
+
div.appendChild(desc);
|
|
50949
|
+
}
|
|
50950
|
+
return label;
|
|
50951
|
+
}
|
|
50952
|
+
createSelectInput(name, config, value) {
|
|
50953
|
+
const label = document.createElement('label');
|
|
50954
|
+
label.className = 'label';
|
|
50955
|
+
label.style.fontWeight = 500;
|
|
50956
|
+
const labelText = document.createTextNode((config.label || name) + ':');
|
|
50957
|
+
label.appendChild(labelText);
|
|
50958
|
+
const select = document.createElement('select');
|
|
50959
|
+
select.name = name;
|
|
50960
|
+
config.options.forEach(option => {
|
|
50961
|
+
const opt = document.createElement('option');
|
|
50962
|
+
opt.value = option.value;
|
|
50963
|
+
opt.textContent = option.label;
|
|
50964
|
+
if (option.value === value) opt.selected = true;
|
|
50965
|
+
select.appendChild(opt);
|
|
50966
|
+
});
|
|
50967
|
+
label.appendChild(select);
|
|
50968
|
+
if (config.description) {
|
|
50969
|
+
const desc = document.createElement('small');
|
|
50970
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
50971
|
+
desc.textContent = config.description;
|
|
50972
|
+
label.appendChild(desc);
|
|
50973
|
+
}
|
|
50974
|
+
return label;
|
|
50975
|
+
}
|
|
50976
|
+
createRadioInput(name, config, value) {
|
|
50977
|
+
const wrapper = document.createElement('div');
|
|
50978
|
+
const title = document.createElement('div');
|
|
50979
|
+
title.textContent = config.label || name;
|
|
50980
|
+
title.style.cssText = 'margin-bottom: 8px;font-weight: 590;';
|
|
50981
|
+
wrapper.appendChild(title);
|
|
50982
|
+
config.options.forEach(option => {
|
|
50983
|
+
const label = document.createElement('label');
|
|
50984
|
+
label.className = 'label checkbox';
|
|
50985
|
+
const input = document.createElement('input');
|
|
50986
|
+
input.type = 'radio';
|
|
50987
|
+
input.name = name;
|
|
50988
|
+
input.value = option.value;
|
|
50989
|
+
input.checked = option.value === value;
|
|
50990
|
+
const span = document.createElement('span');
|
|
50991
|
+
span.textContent = option.label;
|
|
50992
|
+
label.appendChild(input);
|
|
50993
|
+
label.appendChild(span);
|
|
50994
|
+
wrapper.appendChild(label);
|
|
50995
|
+
});
|
|
50996
|
+
if (config.description) {
|
|
50997
|
+
const desc = document.createElement('small');
|
|
50998
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
50999
|
+
desc.textContent = config.description;
|
|
51000
|
+
wrapper.appendChild(desc);
|
|
51001
|
+
}
|
|
51002
|
+
return wrapper;
|
|
51003
|
+
}
|
|
51004
|
+
createTextareaInput(name, config, value) {
|
|
51005
|
+
const label = document.createElement('label');
|
|
51006
|
+
label.className = 'label';
|
|
51007
|
+
label.style.fontWeight = 500;
|
|
51008
|
+
const labelText = document.createElement('div');
|
|
51009
|
+
labelText.textContent = config.label || name;
|
|
51010
|
+
label.appendChild(labelText);
|
|
51011
|
+
const textarea = document.createElement('textarea');
|
|
51012
|
+
textarea.name = name;
|
|
51013
|
+
textarea.value = value || '';
|
|
51014
|
+
textarea.rows = config.rows || 4;
|
|
51015
|
+
if (config.placeholder) textarea.placeholder = config.placeholder;
|
|
51016
|
+
label.appendChild(textarea);
|
|
51017
|
+
if (config.description) {
|
|
51018
|
+
const desc = document.createElement('small');
|
|
51019
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
51020
|
+
desc.textContent = config.description;
|
|
51021
|
+
label.appendChild(desc);
|
|
51022
|
+
}
|
|
51023
|
+
return label;
|
|
51024
|
+
}
|
|
51025
|
+
createColorInput(name, config, value) {
|
|
51026
|
+
const container = document.createElement('div');
|
|
51027
|
+
const label = document.createElement('label');
|
|
51028
|
+
label.className = 'label';
|
|
51029
|
+
label.style.fontWeight = 500;
|
|
51030
|
+
label.style.cursor = 'pointer';
|
|
51031
|
+
const labelText = document.createElement('div');
|
|
51032
|
+
labelText.textContent = config.label || name;
|
|
51033
|
+
label.appendChild(labelText);
|
|
51034
|
+
const input = document.createElement('input');
|
|
51035
|
+
input.type = 'hidden';
|
|
51036
|
+
input.name = name;
|
|
51037
|
+
input.value = value || config.default || '#000000';
|
|
51038
|
+
const group = document.createElement('div');
|
|
51039
|
+
group.className = 'group';
|
|
51040
|
+
group.style.cssText = 'width: 52px; margin:0; overflow: visible;';
|
|
51041
|
+
const colorBtn = document.createElement('button');
|
|
51042
|
+
colorBtn.type = 'button';
|
|
51043
|
+
colorBtn.title = config.label || 'Color';
|
|
51044
|
+
colorBtn.className = 'btn-color is-btn-color';
|
|
51045
|
+
colorBtn.style.backgroundColor = input.value;
|
|
51046
|
+
colorBtn.setAttribute('aria-label', `Choose color for ${config.label || name}`);
|
|
51047
|
+
const openPicker = e => {
|
|
51048
|
+
e.preventDefault();
|
|
51049
|
+
this.builder.openColorPicker(input.value, color => {
|
|
51050
|
+
input.value = color;
|
|
51051
|
+
colorBtn.style.backgroundColor = color;
|
|
51052
|
+
input.dispatchEvent(new Event('change', {
|
|
51053
|
+
bubbles: true
|
|
51054
|
+
}));
|
|
51055
|
+
}, colorBtn);
|
|
51056
|
+
};
|
|
51057
|
+
colorBtn.addEventListener('click', openPicker);
|
|
51058
|
+
// Make label click trigger the button
|
|
51059
|
+
label.addEventListener('click', e => {
|
|
51060
|
+
if (e.target === label || e.target === labelText) {
|
|
51061
|
+
colorBtn.click();
|
|
51062
|
+
}
|
|
51063
|
+
});
|
|
51064
|
+
group.appendChild(colorBtn);
|
|
51065
|
+
label.appendChild(input);
|
|
51066
|
+
if (config.description) {
|
|
51067
|
+
const desc = document.createElement('small');
|
|
51068
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
51069
|
+
desc.textContent = config.description;
|
|
51070
|
+
label.appendChild(desc);
|
|
51071
|
+
}
|
|
51072
|
+
container.appendChild(label);
|
|
51073
|
+
container.appendChild(group);
|
|
51074
|
+
return container;
|
|
51075
|
+
}
|
|
51076
|
+
createColorInput2(name, config, value) {
|
|
51077
|
+
const label = document.createElement('label');
|
|
51078
|
+
label.className = 'label';
|
|
51079
|
+
label.style.fontWeight = 500;
|
|
51080
|
+
const labelText = document.createElement('div');
|
|
51081
|
+
labelText.textContent = config.label || name;
|
|
51082
|
+
label.appendChild(labelText);
|
|
51083
|
+
const input = document.createElement('input');
|
|
51084
|
+
input.type = 'color';
|
|
51085
|
+
input.name = name;
|
|
51086
|
+
input.style.cssText = 'width:40px;height:40px';
|
|
51087
|
+
input.value = value || config.default || '#000000';
|
|
51088
|
+
label.appendChild(input);
|
|
51089
|
+
if (config.description) {
|
|
51090
|
+
const desc = document.createElement('small');
|
|
51091
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
51092
|
+
desc.textContent = config.description;
|
|
51093
|
+
label.appendChild(desc);
|
|
51094
|
+
}
|
|
51095
|
+
return label;
|
|
51096
|
+
}
|
|
51097
|
+
createRangeInput(name, config, value) {
|
|
51098
|
+
const label = document.createElement('label');
|
|
51099
|
+
label.className = 'label';
|
|
51100
|
+
label.style.fontWeight = 500;
|
|
51101
|
+
const currentVal = value !== undefined ? value : config.default;
|
|
51102
|
+
const labelText = document.createElement('div');
|
|
51103
|
+
labelText.textContent = (config.label || name) + ': ' + currentVal + (config.unit || '');
|
|
51104
|
+
label.appendChild(labelText);
|
|
51105
|
+
const input = document.createElement('input');
|
|
51106
|
+
input.type = 'range';
|
|
51107
|
+
input.className = 'is-rangeslider';
|
|
51108
|
+
input.name = name;
|
|
51109
|
+
input.value = currentVal;
|
|
51110
|
+
if (config.min !== undefined) input.min = config.min;
|
|
51111
|
+
if (config.max !== undefined) input.max = config.max;
|
|
51112
|
+
if (config.step !== undefined) input.step = config.step;
|
|
51113
|
+
input.addEventListener('input', () => {
|
|
51114
|
+
labelText.textContent = (config.label || name) + ': ' + input.value + (config.unit || '');
|
|
51115
|
+
});
|
|
51116
|
+
label.appendChild(input);
|
|
51117
|
+
if (config.description) {
|
|
51118
|
+
const desc = document.createElement('small');
|
|
51119
|
+
desc.style.cssText = 'display: block;margin-top: 4px;';
|
|
51120
|
+
desc.textContent = config.description;
|
|
51121
|
+
label.appendChild(desc);
|
|
51122
|
+
}
|
|
51123
|
+
return label;
|
|
51124
|
+
}
|
|
51125
|
+
|
|
51126
|
+
/**
|
|
51127
|
+
* Get current values from element attributes
|
|
51128
|
+
*/
|
|
51129
|
+
getCurrentValues(element, settings) {
|
|
51130
|
+
const values = {};
|
|
51131
|
+
Object.keys(settings).forEach(key => {
|
|
51132
|
+
if (key.startsWith('_')) return;
|
|
51133
|
+
const attrName = 'data-cb-' + key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
51134
|
+
const attrValue = element.getAttribute(attrName);
|
|
51135
|
+
if (attrValue !== null) {
|
|
51136
|
+
values[key] = this.parseValue(attrValue, settings[key].type);
|
|
51137
|
+
}
|
|
51138
|
+
});
|
|
51139
|
+
return values;
|
|
51140
|
+
}
|
|
51141
|
+
|
|
51142
|
+
/**
|
|
51143
|
+
* Parse attribute value based on type
|
|
51144
|
+
*/
|
|
51145
|
+
parseValue(value, type) {
|
|
51146
|
+
switch (type) {
|
|
51147
|
+
case 'number':
|
|
51148
|
+
return parseFloat(value);
|
|
51149
|
+
case 'boolean':
|
|
51150
|
+
return value === 'true';
|
|
51151
|
+
default:
|
|
51152
|
+
return value;
|
|
51153
|
+
}
|
|
51154
|
+
}
|
|
51155
|
+
|
|
51156
|
+
/**
|
|
51157
|
+
* Get form values
|
|
51158
|
+
*/
|
|
51159
|
+
getFormValues(form) {
|
|
51160
|
+
const values = {};
|
|
51161
|
+
const inputs = form.querySelectorAll('input, select, textarea');
|
|
51162
|
+
inputs.forEach(input => {
|
|
51163
|
+
const name = input.name;
|
|
51164
|
+
if (!name) return;
|
|
51165
|
+
if (input.type === 'checkbox') {
|
|
51166
|
+
values[name] = input.checked;
|
|
51167
|
+
} else if (input.type === 'radio') {
|
|
51168
|
+
if (input.checked) {
|
|
51169
|
+
values[name] = input.value;
|
|
51170
|
+
}
|
|
51171
|
+
} else {
|
|
51172
|
+
values[name] = input.value;
|
|
51173
|
+
}
|
|
51174
|
+
});
|
|
51175
|
+
return values;
|
|
51176
|
+
}
|
|
51177
|
+
|
|
51178
|
+
/**
|
|
51179
|
+
* Apply form values to element
|
|
51180
|
+
*/
|
|
51181
|
+
applyValues(element, values) {
|
|
51182
|
+
Object.keys(values).forEach(key => {
|
|
51183
|
+
const attrName = 'data-cb-' + key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
51184
|
+
element.setAttribute(attrName, values[key]);
|
|
51185
|
+
});
|
|
51186
|
+
}
|
|
51187
|
+
createEmptyForm() {
|
|
51188
|
+
const form = document.createElement('div');
|
|
51189
|
+
form.className = 'cb-settings-form';
|
|
51190
|
+
form.innerHTML = '<p>This plugin has no configurable settings.</p>';
|
|
51191
|
+
return form;
|
|
51192
|
+
}
|
|
51193
|
+
}
|
|
51194
|
+
|
|
51195
|
+
class Plugin {
|
|
51196
|
+
constructor(builder) {
|
|
51197
|
+
this.builder = builder;
|
|
51198
|
+
}
|
|
51199
|
+
renderTool() {
|
|
51200
|
+
const builderStuff = this.builder.builderStuff;
|
|
51201
|
+
const contentStuff = this.builder.contentStuff;
|
|
51202
|
+
const util = this.builder.util;
|
|
51203
|
+
const dom = this.builder.dom;
|
|
51204
|
+
let pluginTool = builderStuff.querySelector('.is-plugin-tool');
|
|
51205
|
+
if (!pluginTool) {
|
|
51206
|
+
let html = `
|
|
51207
|
+
<div class="is-tool is-plugin-tool">
|
|
51208
|
+
<button title="${util.out('Settings')}" data-title="${util.out('Settings')}" style="width:40px;height:40px;background:none;"><svg class="is-icon-flex"><use xlink:href="#icon-cog"></use></svg></button>
|
|
51209
|
+
</div>
|
|
51210
|
+
`;
|
|
51211
|
+
dom.appendHtml(builderStuff, html);
|
|
51212
|
+
if (!this.builder.iframe) {
|
|
51213
|
+
pluginTool = builderStuff.querySelector('.is-plugin-tool');
|
|
51214
|
+
} else {
|
|
51215
|
+
pluginTool = contentStuff.querySelector('.is-plugin-tool');
|
|
51216
|
+
}
|
|
51217
|
+
this.pluginTool = pluginTool;
|
|
51218
|
+
let btn = pluginTool.querySelector('button');
|
|
51219
|
+
dom.addEventListener(btn, 'click', () => {
|
|
51220
|
+
// old 10317
|
|
51221
|
+
|
|
51222
|
+
if (this.pluginModal && this.pluginModal.classList.contains('active')) {
|
|
51223
|
+
this.hidePluginEditor();
|
|
51224
|
+
} else {
|
|
51225
|
+
this.renderPanel();
|
|
51226
|
+
this.showPluginEditor();
|
|
51227
|
+
}
|
|
51228
|
+
btn.setAttribute('data-focus', true);
|
|
51229
|
+
});
|
|
51230
|
+
}
|
|
51231
|
+
}
|
|
51232
|
+
renderPanel() {
|
|
51233
|
+
const builderStuff = this.builder.builderStuff;
|
|
51234
|
+
const util = this.builder.util;
|
|
51235
|
+
const dom = this.builder.dom;
|
|
51236
|
+
let pluginModal = builderStuff.querySelector('.is-modal.pluginsettings');
|
|
51237
|
+
if (!pluginModal) {
|
|
51238
|
+
let html = `
|
|
51239
|
+
<div class="is-modal is-modal-content pluginsettings" tabindex="-1" role="dialog" aria-modal="true" aria-hidden="true">
|
|
51240
|
+
<div class="is-modal-bar is-draggable">
|
|
51241
|
+
<span>${util.out('Plugin Settings')}</span>
|
|
51242
|
+
<button class="is-modal-close" tabindex="-1" title="${util.out('Close')}">✕</button>
|
|
51243
|
+
</div>
|
|
51244
|
+
<div class="is-modal-controls" style="box-sizing:border-box;padding:30px;overflow-y: auto;height: calc(100% - 30px);">
|
|
51245
|
+
<div class="is-tabs" data-group="table">
|
|
51246
|
+
<a title="${util.out('Style')}" id="tabTableGeneral" href="" data-content="divTableGeneral" class="active">${util.out('Style')}</a>
|
|
51247
|
+
<a title="${util.out('Layout')}" id="tabTableLayout" href="" data-content="divTableLayout">${util.out('Layout')}</a>
|
|
51248
|
+
</div>
|
|
51249
|
+
<div id="divTableGeneral" class="is-tab-content active" tabindex="-1" data-group="table" style="display:block">
|
|
51250
|
+
|
|
51251
|
+
<div style="display:flex;padding-bottom:12px">
|
|
51252
|
+
<div style="padding-right:15px">
|
|
51253
|
+
<div>${util.out('Background')}:</div>
|
|
51254
|
+
<div>
|
|
51255
|
+
<button title="${util.out('Background Color')}" class="input-table-bgcolor is-btn-color"></button>
|
|
51256
|
+
</div>
|
|
51257
|
+
</div>
|
|
51258
|
+
<div>
|
|
51259
|
+
<div>${util.out('Text Color')}:</div>
|
|
51260
|
+
<div>
|
|
51261
|
+
<button title="${util.out('Text Color')}" class="input-table-textcolor is-btn-color"></button>
|
|
51262
|
+
</div>
|
|
51263
|
+
</div>
|
|
51264
|
+
</div>
|
|
51265
|
+
|
|
51266
|
+
<div style="padding-bottom:12px;">
|
|
51267
|
+
<div>${util.out('Border Thickness')}:</div>
|
|
51268
|
+
<div>
|
|
51269
|
+
<select id="selCellBorderWidth" style="width:120px;"><option value="0">No Border</option><option value="1">1</option><option value="2">2</option><option value="3">3</option></select>
|
|
51270
|
+
</div>
|
|
51271
|
+
</div>
|
|
51272
|
+
|
|
51273
|
+
<div style="padding-bottom:12px;">
|
|
51274
|
+
<div>${util.out('Border Color')}:</div>
|
|
51275
|
+
<div>
|
|
51276
|
+
<button title="${util.out('Border Color')}" class="input-table-bordercolor is-btn-color"></button>
|
|
51277
|
+
</div>
|
|
51278
|
+
</div>
|
|
51279
|
+
|
|
51280
|
+
<div style="padding-bottom:12px;">
|
|
51281
|
+
<div>${util.out('Apply To')}:</div>
|
|
51282
|
+
<div>
|
|
51283
|
+
<select id="selTableApplyTo" style="width:120px;">
|
|
51284
|
+
<option value="table">${util.out('Table')}</option>
|
|
51285
|
+
<option value="currentrow">${util.out('Current Row')}</option>
|
|
51286
|
+
<option value="currentcol">${util.out('Current Column')}</option>
|
|
51287
|
+
<option value="evenrows">${util.out('Even Rows')}</option>
|
|
51288
|
+
<option value="oddrows">${util.out('Odd Rows')}</option>
|
|
51289
|
+
<option value="currentcell">${util.out('Current Cell')}</option>
|
|
51290
|
+
</select>
|
|
51291
|
+
</div>
|
|
51292
|
+
</div>
|
|
51293
|
+
|
|
51294
|
+
</div>
|
|
51295
|
+
|
|
51296
|
+
<div id="divTableLayout" class="is-tab-content" tabindex="-1" data-group="table">
|
|
51297
|
+
|
|
51298
|
+
<div style="padding-bottom:12px;">
|
|
51299
|
+
<div>${util.out('Insert Row')}:</div>
|
|
51300
|
+
<div style="display:flex">
|
|
51301
|
+
<button class="classic" title="${util.out('Above')}" data-table-cmd="rowabove" title="${util.out('Above')}" style="margin-right:15px"> ${util.out('Above')} </button>
|
|
51302
|
+
<button class="classic" title="${util.out('Below')}" data-table-cmd="rowbelow" title="${util.out('Below')}" style=""> ${util.out('Below')} </button>
|
|
51303
|
+
</div>
|
|
51304
|
+
</div>
|
|
51305
|
+
|
|
51306
|
+
<div style="padding-bottom:15px;">
|
|
51307
|
+
<div>${util.out('Insert Column')}:</div>
|
|
51308
|
+
<div style="display:flex">
|
|
51309
|
+
<button class="classic" title="${util.out('Left')}" data-table-cmd="columnleft" title="${util.out('Left')}" style="margin-right:15px"> ${util.out('Left')} </button>
|
|
51310
|
+
<button class="classic" title="${util.out('Right')}" data-table-cmd="columnright" title="${util.out('Right')}" style=""> ${util.out('Right')} </button>
|
|
51311
|
+
</div>
|
|
51312
|
+
</div>
|
|
51313
|
+
|
|
51314
|
+
<div style="padding-bottom:15px;">
|
|
51315
|
+
<button class="classic" title="${util.out('Delete Row')}" data-table-cmd="delrow" title="Delete Row" style=""> ${util.out('Delete Row')} </button>
|
|
51316
|
+
</div>
|
|
51317
|
+
|
|
51318
|
+
<div style="padding-bottom:15px;">
|
|
51319
|
+
<button class="classic" title="${util.out('Delete Column')}" data-table-cmd="delcolumn" title="Delete Column" style=""> ${util.out('Delete Column')} </button>
|
|
51320
|
+
</div>
|
|
51321
|
+
|
|
51322
|
+
<div>
|
|
51323
|
+
<button class="classic" title="${util.out('Merge Cell')}" data-table-cmd="mergecell" style="">${util.out('Merge Cell')}</button>
|
|
51324
|
+
</div>
|
|
51325
|
+
</div>
|
|
51326
|
+
</div>
|
|
51327
|
+
</div>
|
|
51328
|
+
`;
|
|
51329
|
+
dom.appendHtml(builderStuff, html);
|
|
51330
|
+
pluginModal = builderStuff.querySelector('.is-modal.pluginsettings');
|
|
51331
|
+
this.pluginModal = pluginModal;
|
|
51332
|
+
let btnOk = pluginModal.querySelector('.input-ok');
|
|
51333
|
+
dom.addEventListener(btnOk, 'click', () => {
|
|
51334
|
+
this.builder.uo.saveForUndo();
|
|
51335
|
+
this.builder.opts.onChange();
|
|
51336
|
+
util.hideModal(pluginModal);
|
|
51337
|
+
});
|
|
51338
|
+
let btnCancel = pluginModal.querySelector('.input-cancel');
|
|
51339
|
+
dom.addEventListener(btnCancel, 'click', () => {
|
|
51340
|
+
util.hideModal(pluginModal);
|
|
51341
|
+
});
|
|
51342
|
+
new Tabs({
|
|
51343
|
+
element: pluginModal
|
|
51344
|
+
});
|
|
51345
|
+
new Draggable$2({
|
|
51346
|
+
selector: '.is-modal.pluginsettings .is-draggable'
|
|
51347
|
+
});
|
|
51348
|
+
}
|
|
51349
|
+
}
|
|
51350
|
+
showPluginEditor() {
|
|
51351
|
+
const pluginModal = this.pluginModal;
|
|
51352
|
+
this.builder.util.showModal(pluginModal);
|
|
51353
|
+
this.realtime();
|
|
51354
|
+
const handlePluginClick = e => {
|
|
51355
|
+
const clrPicker = document.querySelector('.pop-picker.active') || document.querySelector('.pickgradientcolor.active');
|
|
51356
|
+
let elm = e.target;
|
|
51357
|
+
let elmRemoved = !document.contains(elm); // e.g. when deleting a card in card list plugin
|
|
51358
|
+
|
|
51359
|
+
if (this.builder.doc.activeElement) {
|
|
51360
|
+
if (this.builder.doc.activeElement.closest('.is-modal')) {
|
|
51361
|
+
// prevent modal close when mouseup outside the modal
|
|
51362
|
+
return;
|
|
51363
|
+
}
|
|
51364
|
+
}
|
|
51365
|
+
if (!elm) return;
|
|
51366
|
+
if (!elm.closest('.is-plugin-tool') && !elm.closest('.is-sidebar') && !elm.closest('.is-modal') && !elm.closest('.keep-selection') && !elm.closest('[data-cb-type]') && !clrPicker && !elmRemoved) {
|
|
51367
|
+
// click outside
|
|
51368
|
+
|
|
51369
|
+
// hide
|
|
51370
|
+
this.hidePluginEditor();
|
|
51371
|
+
// console.log('HIDE');
|
|
51372
|
+
|
|
51373
|
+
document.removeEventListener('click', handlePluginClick);
|
|
51374
|
+
if (this.builder.iframeDocument) {
|
|
51375
|
+
this.builder.doc.removeEventListener('click', handlePluginClick);
|
|
51376
|
+
}
|
|
51377
|
+
this.builder.handlePluginClick_ = false;
|
|
51378
|
+
}
|
|
51379
|
+
if (elm.closest('[data-cb-type]')) {
|
|
51380
|
+
this.realtime();
|
|
51381
|
+
}
|
|
51382
|
+
};
|
|
51383
|
+
if (!this.builder.handlePluginClick_) {
|
|
51384
|
+
document.addEventListener('click', handlePluginClick);
|
|
51385
|
+
if (this.builder.iframeDocument) {
|
|
51386
|
+
this.builder.doc.addEventListener('click', handlePluginClick);
|
|
51387
|
+
}
|
|
51388
|
+
this.builder.handlePluginClick_ = true;
|
|
51389
|
+
}
|
|
51390
|
+
}
|
|
51391
|
+
hidePluginEditor() {
|
|
51392
|
+
const pluginModal = this.pluginModal;
|
|
51393
|
+
if (pluginModal) this.builder.util.hideModal(pluginModal);
|
|
51394
|
+
}
|
|
51395
|
+
realtime() {
|
|
51396
|
+
const util = this.builder.util;
|
|
51397
|
+
const pluginModal = this.pluginModal;
|
|
51398
|
+
let currentElement = this.builder.activePlugin;
|
|
51399
|
+
const runtime = this.builder.win.builderRuntime;
|
|
51400
|
+
if (currentElement && runtime) {
|
|
51401
|
+
const pluginName = currentElement.getAttribute('data-cb-type');
|
|
51402
|
+
const plugin = runtime.getPlugin(pluginName);
|
|
51403
|
+
let titleHtml = util.out(plugin.displayName || plugin.name);
|
|
51404
|
+
const modalBar = pluginModal.querySelector('.is-modal-bar > span');
|
|
51405
|
+
modalBar.innerHTML = titleHtml;
|
|
51406
|
+
const container = pluginModal.querySelector('.is-modal-controls');
|
|
51407
|
+
|
|
51408
|
+
// Clear panel
|
|
51409
|
+
container.innerHTML = '';
|
|
51410
|
+
const div = document.createElement('div');
|
|
51411
|
+
div.classList.add('submain');
|
|
51412
|
+
container.appendChild(div);
|
|
51413
|
+
|
|
51414
|
+
// Store references
|
|
51415
|
+
this.currentElement = currentElement;
|
|
51416
|
+
this.generator = new SettingsUIGenerator(runtime, this.builder);
|
|
51417
|
+
|
|
51418
|
+
// Check if plugin has custom content editor
|
|
51419
|
+
const hasContentEditor = plugin && plugin.editor && plugin.editor.openContentEditor;
|
|
51420
|
+
if (hasContentEditor) {
|
|
51421
|
+
// Get original content for the editor to work with
|
|
51422
|
+
const originalContent = currentElement.getAttribute('data-cb-original-content');
|
|
51423
|
+
|
|
51424
|
+
// Create a temporary element for editing (so editor can manipulate it)
|
|
51425
|
+
let editableClone = document.querySelector('.editable-clone');
|
|
51426
|
+
if (editableClone) editableClone.remove();
|
|
51427
|
+
// editableClone = document.createElement('div');
|
|
51428
|
+
editableClone = currentElement.cloneNode(false);
|
|
51429
|
+
editableClone.innerHTML = originalContent;
|
|
51430
|
+
editableClone.className = 'editable-clone';
|
|
51431
|
+
editableClone.style.display = 'none'; // Hidden, just for editing
|
|
51432
|
+
document.body.appendChild(editableClone);
|
|
51433
|
+
const originalElement = editableClone.cloneNode(false);
|
|
51434
|
+
|
|
51435
|
+
// Let plugin handle everything - pass the editable clone
|
|
51436
|
+
const editorUI = plugin.editor.openContentEditor(editableClone, this.builder, async () => {
|
|
51437
|
+
this.builder.uo.saveForUndo();
|
|
51438
|
+
|
|
51439
|
+
// Store edited content from clone
|
|
51440
|
+
currentElement.setAttribute('data-cb-original-content', editableClone.innerHTML);
|
|
51441
|
+
|
|
51442
|
+
// Also performs similar value updates like the applyChanges()
|
|
51443
|
+
// currentElement.setAttribute('data-cb-content', editableClone.getAttribute('data-cb-content'));
|
|
51444
|
+
const getChangedDataAttributes = (el1, el2) => {
|
|
51445
|
+
const changed = [];
|
|
51446
|
+
for (const key of Object.keys(el1.dataset)) {
|
|
51447
|
+
if (key in el2.dataset && el1.dataset[key] !== el2.dataset[key]) {
|
|
51448
|
+
changed.push(key);
|
|
51449
|
+
}
|
|
51450
|
+
}
|
|
51451
|
+
return changed;
|
|
51452
|
+
};
|
|
51453
|
+
const changedAttributes = getChangedDataAttributes(originalElement, editableClone);
|
|
51454
|
+
// let hasChange = changedAttributes.length > 0;
|
|
51455
|
+
for (const attrName of changedAttributes) {
|
|
51456
|
+
// console.log(attrName);
|
|
51457
|
+
currentElement.dataset[attrName] = editableClone.dataset[attrName];
|
|
51458
|
+
// update form (not working)
|
|
51459
|
+
// const convertCbKey = (str) => {
|
|
51460
|
+
// return str.replace(/^cb/, '').replace(/^./, c => c.toLowerCase());
|
|
51461
|
+
// }
|
|
51462
|
+
// const name = convertCbKey(attrName);
|
|
51463
|
+
// this.currentForm.querySelector(`[name="${name}"]`).value = editableClone.dataset[attrName];
|
|
51464
|
+
}
|
|
51465
|
+
// console.log(hasChange)
|
|
51466
|
+
// -------
|
|
51467
|
+
|
|
51468
|
+
currentElement.innerHTML = editableClone.innerHTML; // Update current content
|
|
51469
|
+
|
|
51470
|
+
// Remove temporary clone
|
|
51471
|
+
editableClone.remove();
|
|
51472
|
+
|
|
51473
|
+
// update form (working)
|
|
51474
|
+
// currentElement.click();
|
|
51475
|
+
// return;
|
|
51476
|
+
|
|
51477
|
+
// Reinitialize plugin with new content
|
|
51478
|
+
await runtime.reinitialize(currentElement.parentElement);
|
|
51479
|
+
this.builder.onChange();
|
|
51480
|
+
});
|
|
51481
|
+
div.appendChild(editorUI);
|
|
51482
|
+
}
|
|
51483
|
+
|
|
51484
|
+
// Generate form
|
|
51485
|
+
this.currentForm = this.generator.generateForm(pluginName, currentElement, () => {
|
|
51486
|
+
this.builder.uo.saveForUndo();
|
|
51487
|
+
this.applyChanges(runtime);
|
|
51488
|
+
});
|
|
51489
|
+
this.currentForm.style.marginTop = '20px';
|
|
51490
|
+
div.appendChild(this.currentForm);
|
|
51491
|
+
}
|
|
51492
|
+
}
|
|
51493
|
+
async applyChanges(runtime) {
|
|
51494
|
+
if (!this.currentElement || !this.currentForm) return;
|
|
51495
|
+
|
|
51496
|
+
// 1. Get form values
|
|
51497
|
+
const values = this.generator.getFormValues(this.currentForm);
|
|
51498
|
+
|
|
51499
|
+
// 2. Apply to element attributes
|
|
51500
|
+
this.generator.applyValues(this.currentElement, values);
|
|
51501
|
+
|
|
51502
|
+
// 3. Reinitialize component
|
|
51503
|
+
const container = this.currentElement.parentElement || this.currentElement.closest('.is-wrapper');
|
|
51504
|
+
await runtime.reinitialize(container);
|
|
51505
|
+
|
|
51506
|
+
//Trigger Change event
|
|
51507
|
+
this.builder.opts.onChange();
|
|
51508
|
+
|
|
51509
|
+
// console.log('Settings applied and component reinitialized');
|
|
51510
|
+
}
|
|
51511
|
+
|
|
51512
|
+
click(e) {
|
|
51513
|
+
const plugin = e.target.closest('[data-cb-type]');
|
|
51514
|
+
if (plugin) {
|
|
51515
|
+
this.builder.activePlugin = plugin;
|
|
51516
|
+
this.renderTool();
|
|
51517
|
+
this.pluginTool.style.display = 'flex';
|
|
51518
|
+
let _toolwidth = this.pluginTool.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
|
|
51519
|
+
|
|
51520
|
+
let w = plugin.offsetWidth * this.builder.opts.zoom;
|
|
51521
|
+
let top = plugin.getBoundingClientRect().top + this.builder.win.pageYOffset;
|
|
51522
|
+
let left = plugin.getBoundingClientRect().left - 2;
|
|
51523
|
+
left = left + (w - _toolwidth);
|
|
51524
|
+
|
|
51525
|
+
//Adjust left in case an element is outside the screen
|
|
51526
|
+
const _screenwidth = window.innerWidth;
|
|
51527
|
+
if (_toolwidth + left > _screenwidth) left = plugin.getBoundingClientRect().left;
|
|
51528
|
+
this.pluginTool.style.top = top + 'px';
|
|
51529
|
+
this.pluginTool.style.left = left + 'px';
|
|
51530
|
+
} else {
|
|
51531
|
+
this.builder.activePlugin = null;
|
|
51532
|
+
if (this.pluginTool) this.pluginTool.style.display = '';
|
|
51533
|
+
}
|
|
51534
|
+
}
|
|
51535
|
+
}
|
|
51536
|
+
|
|
50727
51537
|
class Module {
|
|
50728
51538
|
constructor(builder) {
|
|
50729
51539
|
this.builder = builder;
|
|
@@ -52565,6 +53375,7 @@ class Element$1 {
|
|
|
52565
53375
|
this.button = new Button(builder);
|
|
52566
53376
|
this.image = new Image$1(builder);
|
|
52567
53377
|
this.spacer = new Spacer(builder);
|
|
53378
|
+
this.plugin = new Plugin(builder);
|
|
52568
53379
|
this.module = new Module(builder);
|
|
52569
53380
|
this.code = new Code(builder);
|
|
52570
53381
|
this.iframe = new Iframe(builder);
|
|
@@ -52771,6 +53582,9 @@ class Element$1 {
|
|
|
52771
53582
|
|
|
52772
53583
|
// Module
|
|
52773
53584
|
this.module.click(col, e);
|
|
53585
|
+
|
|
53586
|
+
// Plugin
|
|
53587
|
+
this.plugin.click(e);
|
|
52774
53588
|
}
|
|
52775
53589
|
}
|
|
52776
53590
|
|
|
@@ -61926,6 +62740,12 @@ class ElementTool {
|
|
|
61926
62740
|
const btnMore = elementTool.querySelector('.elm-more');
|
|
61927
62741
|
dom.addEventListener(btnMore, 'click', () => {
|
|
61928
62742
|
const viewportHeight = window.innerHeight;
|
|
62743
|
+
const elmSettings = elementMore.querySelector('.elm-settings');
|
|
62744
|
+
if (this.builder.activeElement.hasAttribute('data-cb-type')) {
|
|
62745
|
+
elmSettings.style.display = 'none';
|
|
62746
|
+
} else {
|
|
62747
|
+
elmSettings.style.display = '';
|
|
62748
|
+
}
|
|
61929
62749
|
|
|
61930
62750
|
/*
|
|
61931
62751
|
let top, left;
|
|
@@ -62191,7 +63011,10 @@ class ElementTool {
|
|
|
62191
63011
|
if (dom.parentsHasClass(elm, 'is-subblock')) {
|
|
62192
63012
|
subblock = true;
|
|
62193
63013
|
}
|
|
62194
|
-
|
|
63014
|
+
const plugin = elm.closest('[data-cb-type]');
|
|
63015
|
+
if ((customcode || noedit || _protected) && !subblock) ; else if (plugin) {
|
|
63016
|
+
activeElement = plugin;
|
|
63017
|
+
} else {
|
|
62195
63018
|
const tagName = elm.tagName.toLowerCase();
|
|
62196
63019
|
// LATER: label, code, figcaption ?
|
|
62197
63020
|
if (!elm.classList.contains('cell-active') && (tagName === 'h1' || tagName === 'h2' || tagName === 'h3' || tagName === 'h4' || tagName === 'h5' || tagName === 'h6' || tagName === 'p' || tagName === 'div' || tagName === 'pre' || tagName === 'blockquote' || tagName === 'li' || tagName === 'img' || tagName === 'iframe')) {
|
|
@@ -62343,7 +63166,8 @@ class ElementTool {
|
|
|
62343
63166
|
let elm = this.builder.activeElement;
|
|
62344
63167
|
if (!elm) return;
|
|
62345
63168
|
if (elm.closest('.is-dock')) return;
|
|
62346
|
-
if
|
|
63169
|
+
// if(elm.closest('[data-cb-type]')) return;
|
|
63170
|
+
|
|
62347
63171
|
let top, left;
|
|
62348
63172
|
if (!this.builder.iframe) {
|
|
62349
63173
|
top = elm.getBoundingClientRect().top + window.pageYOffset;
|