@innovastudio/contentbuilder 1.5.158 → 1.5.160
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 +842 -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,817 @@ 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
|
+
if (!this.builder.isContentBox) {
|
|
51517
|
+
this.renderTool();
|
|
51518
|
+
this.pluginTool.style.display = 'flex';
|
|
51519
|
+
let _toolwidth = this.pluginTool.offsetWidth; //to get value, element must not hidden (display:none). So set display:flex before this.
|
|
51520
|
+
|
|
51521
|
+
let w = plugin.offsetWidth * this.builder.opts.zoom;
|
|
51522
|
+
let top = plugin.getBoundingClientRect().top + this.builder.win.pageYOffset;
|
|
51523
|
+
let left = plugin.getBoundingClientRect().left - 2;
|
|
51524
|
+
left = left + (w - _toolwidth);
|
|
51525
|
+
|
|
51526
|
+
//Adjust left in case an element is outside the screen
|
|
51527
|
+
const _screenwidth = window.innerWidth;
|
|
51528
|
+
if (_toolwidth + left > _screenwidth) left = plugin.getBoundingClientRect().left;
|
|
51529
|
+
this.pluginTool.style.top = top + 'px';
|
|
51530
|
+
this.pluginTool.style.left = left + 'px';
|
|
51531
|
+
}
|
|
51532
|
+
} else {
|
|
51533
|
+
this.builder.activePlugin = null;
|
|
51534
|
+
if (this.pluginTool) this.pluginTool.style.display = '';
|
|
51535
|
+
}
|
|
51536
|
+
}
|
|
51537
|
+
}
|
|
51538
|
+
|
|
50727
51539
|
class Module {
|
|
50728
51540
|
constructor(builder) {
|
|
50729
51541
|
this.builder = builder;
|
|
@@ -52565,6 +53377,7 @@ class Element$1 {
|
|
|
52565
53377
|
this.button = new Button(builder);
|
|
52566
53378
|
this.image = new Image$1(builder);
|
|
52567
53379
|
this.spacer = new Spacer(builder);
|
|
53380
|
+
this.plugin = new Plugin(builder);
|
|
52568
53381
|
this.module = new Module(builder);
|
|
52569
53382
|
this.code = new Code(builder);
|
|
52570
53383
|
this.iframe = new Iframe(builder);
|
|
@@ -52771,6 +53584,9 @@ class Element$1 {
|
|
|
52771
53584
|
|
|
52772
53585
|
// Module
|
|
52773
53586
|
this.module.click(col, e);
|
|
53587
|
+
|
|
53588
|
+
// Plugin
|
|
53589
|
+
this.plugin.click(e);
|
|
52774
53590
|
}
|
|
52775
53591
|
}
|
|
52776
53592
|
|
|
@@ -61926,6 +62742,12 @@ class ElementTool {
|
|
|
61926
62742
|
const btnMore = elementTool.querySelector('.elm-more');
|
|
61927
62743
|
dom.addEventListener(btnMore, 'click', () => {
|
|
61928
62744
|
const viewportHeight = window.innerHeight;
|
|
62745
|
+
const elmSettings = elementMore.querySelector('.elm-settings');
|
|
62746
|
+
if (this.builder.activeElement.hasAttribute('data-cb-type')) {
|
|
62747
|
+
elmSettings.style.display = 'none';
|
|
62748
|
+
} else {
|
|
62749
|
+
elmSettings.style.display = '';
|
|
62750
|
+
}
|
|
61929
62751
|
|
|
61930
62752
|
/*
|
|
61931
62753
|
let top, left;
|
|
@@ -62191,7 +63013,10 @@ class ElementTool {
|
|
|
62191
63013
|
if (dom.parentsHasClass(elm, 'is-subblock')) {
|
|
62192
63014
|
subblock = true;
|
|
62193
63015
|
}
|
|
62194
|
-
|
|
63016
|
+
const plugin = elm.closest('[data-cb-type]');
|
|
63017
|
+
if ((customcode || noedit || _protected) && !subblock) ; else if (plugin) {
|
|
63018
|
+
activeElement = plugin;
|
|
63019
|
+
} else {
|
|
62195
63020
|
const tagName = elm.tagName.toLowerCase();
|
|
62196
63021
|
// LATER: label, code, figcaption ?
|
|
62197
63022
|
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 +63168,8 @@ class ElementTool {
|
|
|
62343
63168
|
let elm = this.builder.activeElement;
|
|
62344
63169
|
if (!elm) return;
|
|
62345
63170
|
if (elm.closest('.is-dock')) return;
|
|
62346
|
-
if
|
|
63171
|
+
// if(elm.closest('[data-cb-type]')) return;
|
|
63172
|
+
|
|
62347
63173
|
let top, left;
|
|
62348
63174
|
if (!this.builder.iframe) {
|
|
62349
63175
|
top = elm.getBoundingClientRect().top + window.pageYOffset;
|
|
@@ -79992,6 +80818,9 @@ class ContentStuff {
|
|
|
79992
80818
|
<div class="is-tool is-iframe-tool">
|
|
79993
80819
|
<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>
|
|
79994
80820
|
</div>
|
|
80821
|
+
<div class="is-tool is-plugin-tool">
|
|
80822
|
+
<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>
|
|
80823
|
+
</div>
|
|
79995
80824
|
<div class="is-tool is-module-tool">
|
|
79996
80825
|
<button class="btn-module-refresh" title="${util.out('Refresh')}" data-title="${util.out('Refresh')}" style="width:40px;height:40px;"><svg class="is-icon-flex"><use xlink:href="#icon-reload"></use></svg></button>
|
|
79997
80826
|
<button class="btn-module-settings" title="${util.out('Settings')}" data-title="${util.out('Settings')}" style="width:40px;height:40px;"><svg class="is-icon-flex"><use xlink:href="#icon-cog"></use></svg></button>
|
|
@@ -80397,20 +81226,24 @@ class ContentStuff {
|
|
|
80397
81226
|
/*
|
|
80398
81227
|
.is-tool.is-video-tool,
|
|
80399
81228
|
.is-tool.is-audio-tool,
|
|
81229
|
+
.is-tool.is-plugin-tool,
|
|
80400
81230
|
.is-tool.is-iframe-tool {
|
|
80401
81231
|
background: rgba(0, 0, 0, 0.15);
|
|
80402
81232
|
border: transparent 1px solid;
|
|
80403
81233
|
}
|
|
80404
81234
|
.is-tool.is-video-tool > div,
|
|
80405
81235
|
.is-tool.is-audio-tool > div,
|
|
81236
|
+
.is-tool.is-plugin-tool > div,
|
|
80406
81237
|
.is-tool.is-iframe-tool > div,
|
|
80407
81238
|
.is-tool.is-video-tool > button,
|
|
80408
81239
|
.is-tool.is-audio-tool > button,
|
|
81240
|
+
.is-tool.is-plugin-tool > button,
|
|
80409
81241
|
.is-tool.is-iframe-tool > button {
|
|
80410
81242
|
background: transparent;
|
|
80411
81243
|
}
|
|
80412
81244
|
.is-tool.is-video-tool svg,
|
|
80413
81245
|
.is-tool.is-audio-tool svg,
|
|
81246
|
+
.is-tool.is-plugin-tool svg,
|
|
80414
81247
|
.is-tool.is-iframe-tool svg {
|
|
80415
81248
|
fill: #fff;
|
|
80416
81249
|
}
|
|
@@ -80420,6 +81253,7 @@ class ContentStuff {
|
|
|
80420
81253
|
.is-tool.is-table-tool,
|
|
80421
81254
|
.is-tool.is-code-tool,
|
|
80422
81255
|
.is-tool.is-module-tool,
|
|
81256
|
+
.is-tool.is-plugin-tool,
|
|
80423
81257
|
.is-tool#divLinkTool,
|
|
80424
81258
|
.is-tool#divButtonTool,
|
|
80425
81259
|
.is-tool.is-svg-tool {
|
|
@@ -80433,6 +81267,7 @@ class ContentStuff {
|
|
|
80433
81267
|
.is-tool.is-table-tool > button,
|
|
80434
81268
|
.is-tool.is-code-tool > button,
|
|
80435
81269
|
.is-tool.is-module-tool > button,
|
|
81270
|
+
.is-tool.is-plugin-tool > button,
|
|
80436
81271
|
.is-tool#divLinkTool > button,
|
|
80437
81272
|
.is-tool#divButtonTool > button,
|
|
80438
81273
|
.is-tool.is-svg-tool > button {
|
|
@@ -80445,6 +81280,7 @@ class ContentStuff {
|
|
|
80445
81280
|
.is-tool.is-table-tool > button svg,
|
|
80446
81281
|
.is-tool.is-code-tool > button svg,
|
|
80447
81282
|
.is-tool.is-module-tool > button svg,
|
|
81283
|
+
.is-tool.is-plugin-tool > button svg,
|
|
80448
81284
|
.is-tool#divLinkTool > button svg,
|
|
80449
81285
|
.is-tool#divButtonTool > button svg,
|
|
80450
81286
|
.is-tool.is-svg-tool > button svg {
|
|
@@ -80459,6 +81295,7 @@ class ContentStuff {
|
|
|
80459
81295
|
|
|
80460
81296
|
.is-tool.is-video-tool,
|
|
80461
81297
|
.is-tool.is-audio-tool,
|
|
81298
|
+
.is-tool.is-plugin-tool,
|
|
80462
81299
|
.is-tool.is-iframe-tool {
|
|
80463
81300
|
background: rgba(255, 255, 255, 0.97) !important;
|
|
80464
81301
|
border: transparent 1px solid;
|
|
@@ -80470,6 +81307,7 @@ class ContentStuff {
|
|
|
80470
81307
|
.is-tool.is-video-tool > button,
|
|
80471
81308
|
.is-tool.is-audio-tool > div,
|
|
80472
81309
|
.is-tool.is-audio-tool > button,
|
|
81310
|
+
.is-tool.is-plugin-tool > div,
|
|
80473
81311
|
.is-tool.is-iframe-tool > div,
|
|
80474
81312
|
.is-tool.is-iframe-tool > button {
|
|
80475
81313
|
width: 35px !important;
|
|
@@ -80479,6 +81317,7 @@ class ContentStuff {
|
|
|
80479
81317
|
|
|
80480
81318
|
.is-tool.is-video-tool svg,
|
|
80481
81319
|
.is-tool.is-audio-tool svg,
|
|
81320
|
+
.is-tool.is-plugin-tool svg,
|
|
80482
81321
|
.is-tool.is-iframe-tool svg {
|
|
80483
81322
|
width: 17px;
|
|
80484
81323
|
height: 17px;
|