PluginProbe
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder / 51.1.83
King Addons for Elementor – 100+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce Builder, Mega Menu, Popup Builder v51.1.83
51.1.84 51.1.85 51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 All 39 releases
← All changes | includes/widgets/Form_Builder/editor-handler.js +253 -149 51.1.3551.1.83 View file →
@@ -1,192 +1,296 @@
1 1 "use strict";
2 2 (function ($) {
3 - $(window).on('elementor:init', () => {
3 + const FLAG = "kingAddonsFormBuilderEditorBound";
4 4
5 - elementor.hooks.addAction('panel/open_editor/widget/king-addons-form-builder', function (panel, model, view) {
6 - var $parent = panel.$el.find('#elementor-panel');
7 - var $element = panel.$el.find('.elementor-repeater-fields');
5 + /**
6 + * Bind Elementor editor handlers once.
7 + *
8 + * @returns {void}
9 + */
10 + const bindOnce = () => {
11 + if (window[FLAG]) {
12 + return;
13 + }
14 + window[FLAG] = true;
8 15
9 - var stepObserver = new MutationObserver(function (mutations) {
10 - mutations.forEach((mutation) => {
11 - // console.log('steps mutation', mutation);
12 - if (mutation.type === 'childList') {
13 - mutation.addedNodes.forEach((node) => {
14 - if (node.nodeType === Node.ELEMENT_NODE) {
15 - // Find the child element with the specific class within the node
16 - const repeaterFields = node.querySelectorAll('.elementor-repeater-fields');
17 - const childElement = node.querySelectorAll('.elementor-repeater-row-tools');
18 - const childElement2 = node.querySelectorAll('.elementor-repeater-row-controls');
16 + $(window).on("elementor:init", () => {
19 17
20 - if (childElement2) {
21 - let selectElement = [];
18 + elementor.hooks.addAction(
19 + "panel/open_editor/widget/king-addons-form-builder",
20 + function (panel, model, view) {
21 + if (view && view._kingAddonsFormBuilderBound) {
22 + return;
23 + }
24 + if (view) {
25 + view._kingAddonsFormBuilderBound = true;
26 + }
22 27
23 - if (selectElement.length == 0) {
24 - childElement2.forEach(function (item) {
25 - selectElement.push(item.querySelector('select'));
26 - });
27 - }
28 + const $panelRoot = $("#elementor-panel");
29 + const $elements = panel.$el.find(".elementor-repeater-fields");
28 30
29 - // If the child element exists and the select value is 'step', add the certain class to it
30 - if (childElement && selectElement.length > 0) {
31 - childElement.forEach(function (item, i) {
32 - if (selectElement[i] && selectElement[i].value == 'king-addons-fb-step') {
33 - item.classList.add('king-addons-fb-step-editor-bg');
34 - }
35 - });
31 + if (!$panelRoot.length) {
32 + return;
33 + }
34 +
35 + if (view && view._kingAddonsStepObserver) {
36 + view._kingAddonsStepObserver.disconnect();
37 + }
38 +
39 + const stepObserver = new MutationObserver(function (mutations) {
40 + mutations.forEach((mutation) => {
41 + if (mutation.type !== "childList") {
42 + return;
43 + }
44 + mutation.addedNodes.forEach((node) => {
45 + if (!(node instanceof Element)) {
46 + return;
47 + }
48 + const rowTools = node.querySelectorAll(".elementor-repeater-row-tools");
49 + const rowControls = node.querySelectorAll(".elementor-repeater-row-controls");
50 + if (!rowControls.length || !rowTools.length) {
51 + return;
52 + }
53 +
54 + const selects = [];
55 + rowControls.forEach(function (item) {
56 + selects.push(item.querySelector("select"));
57 + });
58 +
59 + rowTools.forEach(function (item, i) {
60 + if (selects[i] && selects[i].value === "king-addons-fb-step") {
61 + item.classList.add("king-addons-fb-step-editor-bg");
36 62 }
37 - }
38 - }
63 + });
64 + });
39 65 });
66 + });
67 +
68 + if (view) {
69 + view._kingAddonsStepObserver = stepObserver;
40 70 }
41 - });
42 - });
43 71
44 - stepObserver.observe($('#elementor-panel')[0], {
45 - childList: true,
46 - subtree: true,
47 - });
72 + stepObserver.observe($panelRoot[0], {
73 + childList: true,
74 + subtree: true,
75 + });
48 76
49 - changeStepBackground();
77 + changeStepBackground();
50 78
51 - elementor.channels.editor.on('section:activated', function (sectionName, editor) {
52 - // model.get('settings').attributes.form_fields.models.forEach(function(thisModel, i) {
53 - // if ( thisModel.attributes.field_type == 'step' ) {
54 - // $('.elementor-repeater-fields').eq(i).find('.elementor-repeater-row-tools').addClass('king-addons-fb-step-editor-bg');
55 - // }
56 - // });
57 - updateDynamicOptions(view);
58 - });
79 + elementor.channels.editor.off("section:activated.kingAddonsFormBuilder");
80 + elementor.channels.editor.on("section:activated.kingAddonsFormBuilder", function () {
81 + updateDynamicOptions(view);
82 + });
59 83
60 - function changeStepBackground() {
84 + const formFieldsCollection = view.model.get("settings").get("form_fields");
85 + view.stopListening(formFieldsCollection, "add change remove");
86 + view.listenTo(formFieldsCollection, "add change remove", function () {
87 + updateDynamicOptions(view);
88 + });
61 89
62 - $element.each(function () {
63 - if ($(this).find('select').val() == 'king-addons-fb-step') {
64 - $(this).find('.elementor-repeater-row-tools').addClass('king-addons-fb-step-editor-bg');
65 - }
66 - });
90 + function changeStepBackground() {
91 + $elements.each(function () {
92 + if ($(this).find("select").val() === "king-addons-fb-step") {
93 + $(this)
94 + .find(".elementor-repeater-row-tools")
95 + .addClass("king-addons-fb-step-editor-bg");
96 + }
97 + });
67 98
68 - $('#elementor-panel').off('change', 'select').on('change', 'select', function () {
69 - if ($(this).val() == 'king-addons-fb-step') {
70 - $(this).closest('.elementor-repeater-row-controls').prev('.elementor-repeater-row-tools').addClass('king-addons-fb-step-editor-bg');
71 - } else if ($(this).closest('.elementor-repeater-row-controls').prev('.elementor-repeater-row-tools').hasClass('king-addons-fb-step-editor-bg')) {
72 - $(this).closest('.elementor-repeater-row-controls').prev('.elementor-repeater-row-tools').removeClass('king-addons-fb-step-editor-bg');
99 + $panelRoot.off("change.kingAddonsFormBuilder", "select");
100 + $panelRoot.on("change.kingAddonsFormBuilder", "select", function () {
101 + const $select = $(this);
102 + const $tools = $select
103 + .closest(".elementor-repeater-row-controls")
104 + .prev(".elementor-repeater-row-tools");
105 +
106 + if ($select.val() === "king-addons-fb-step") {
107 + $tools.addClass("king-addons-fb-step-editor-bg");
108 + return;
109 + }
110 + if ($tools.hasClass("king-addons-fb-step-editor-bg")) {
111 + $tools.removeClass("king-addons-fb-step-editor-bg");
112 + }
113 + });
73 114 }
74 - });
75 - }
76 115
116 + function updateDynamicOptions() {
117 + const formFieldsModel = view.model.get("settings").get("form_fields");
77 118
78 - view.listenTo(view.model.get('settings').get('form_fields'), 'add change remove', function (e) {
79 - updateDynamicOptions(view);
80 - });
119 + const emailField = view.model.get("settings").get("email_field");
120 + const firstNameField = view.model.get("settings").get("first_name_field");
121 + const lastNameField = view.model.get("settings").get("last_name_field");
122 + const phoneField = view.model.get("settings").get("phone_field");
123 + const birthdayField = view.model.get("settings").get("birthday_field");
124 + const addressField = view.model.get("settings").get("address_field");
125 + const countryField = view.model.get("settings").get("country_field");
126 + const cityField = view.model.get("settings").get("city_field");
127 + const stateField = view.model.get("settings").get("state_field");
128 + const zipField = view.model.get("settings").get("zip_field");
81 129
82 - function updateDynamicOptions() {
83 - var formFieldsModel = view.model.get('settings').get('form_fields');
130 + const emailSelectControl = panel.$el
131 + .find(".elementor-control-email_field")
132 + .find('select[data-setting="email_field"]');
133 + const firstNameSelectControl = panel.$el
134 + .find(".elementor-control-first_name_field")
135 + .find('select[data-setting="first_name_field"]');
136 + const lastNameSelectControl = panel.$el
137 + .find(".elementor-control-last_name_field")
138 + .find('select[data-setting="last_name_field"]');
139 + const phoneSelectControl = panel.$el
140 + .find(".elementor-control-phone_field")
141 + .find('select[data-setting="phone_field"]');
142 + const birthdaySelectControl = panel.$el
143 + .find(".elementor-control-birthday_field")
144 + .find('select[data-setting="birthday_field"]');
145 + const addressSelectControl = panel.$el
146 + .find(".elementor-control-address_field")
147 + .find('select[data-setting="address_field"]');
148 + const countrySelectControl = panel.$el
149 + .find(".elementor-control-country_field")
150 + .find('select[data-setting="country_field"]');
151 + const citySelectControl = panel.$el
152 + .find(".elementor-control-city_field")
153 + .find('select[data-setting="city_field"]');
154 + const stateSelectControl = panel.$el
155 + .find(".elementor-control-state_field")
156 + .find('select[data-setting="state_field"]');
157 + const zipSelectControl = panel.$el
158 + .find(".elementor-control-zip_field")
159 + .find('select[data-setting="zip_field"]');
84 160
85 - var emailField = view.model.get('settings').get('email_field');
86 - var firstNameField = view.model.get('settings').get('first_name_field');
87 - var lastNameField = view.model.get('settings').get('last_name_field');
88 - var phoneField = view.model.get('settings').get('phone_field');
89 - var birthdayField = view.model.get('settings').get('birthday_field');
90 - var addressField = view.model.get('settings').get('address_field');
91 - var countryField = view.model.get('settings').get('country_field');
92 - var cityField = view.model.get('settings').get('city_field');
93 - var stateField = view.model.get('settings').get('state_field');
94 - var zipField = view.model.get('settings').get('zip_field');
161 + const selectControls = [
162 + emailSelectControl,
163 + firstNameSelectControl,
164 + lastNameSelectControl,
165 + phoneSelectControl,
166 + birthdaySelectControl,
167 + addressSelectControl,
168 + countrySelectControl,
169 + citySelectControl,
170 + stateSelectControl,
171 + zipSelectControl,
172 + ];
173 + const fieldValues = [
174 + emailField,
175 + firstNameField,
176 + lastNameField,
177 + phoneField,
178 + birthdayField,
179 + addressField,
180 + countryField,
181 + cityField,
182 + stateField,
183 + zipField,
184 + ];
95 185
96 - var emailSelectControl = panel.$el.find('.elementor-control-email_field').find('select[data-setting="email_field"]');
97 - var firstNameSelectControl = panel.$el.find('.elementor-control-first_name_field').find('select[data-setting="first_name_field"]');
98 - var lastNameSelectControl = panel.$el.find('.elementor-control-last_name_field').find('select[data-setting="last_name_field"]');
99 - var phoneSelectControl = panel.$el.find('.elementor-control-phone_field').find('select[data-setting="phone_field"]');
100 - var birthdaySelectControl = panel.$el.find('.elementor-control-birthday_field').find('select[data-setting="birthday_field"]');
101 - var addressSelectControl = panel.$el.find('.elementor-control-address_field').find('select[data-setting="address_field"]');
102 - var countrySelectControl = panel.$el.find('.elementor-control-country_field').find('select[data-setting="country_field"]');
103 - var citySelectControl = panel.$el.find('.elementor-control-city_field').find('select[data-setting="city_field"]');
104 - var stateSelectControl = panel.$el.find('.elementor-control-state_field').find('select[data-setting="state_field"]');
105 - var zipSelectControl = panel.$el.find('.elementor-control-zip_field').find('select[data-setting="zip_field"]');
186 + const options = {none: "None"};
187 + const seenIds = {};
188 + $panelRoot.find(".king-addons-field-id-dup-notice").remove();
106 189
107 - var selectControls = [emailSelectControl, firstNameSelectControl, lastNameSelectControl, phoneSelectControl, birthdaySelectControl, addressSelectControl, countrySelectControl, citySelectControl, stateSelectControl, zipSelectControl];
108 - var fieldValues = [emailField, firstNameField, lastNameField, phoneField, birthdayField, addressField, countryField, cityField, stateField, zipField];
190 + formFieldsModel.each(function (field) {
191 + const fieldLabel = field.get("field_label");
192 + let fieldId = (field.get("field_id") || "").toString().trim();
193 + const fallbackId = (field.get("_id") || "").toString();
109 194
110 - var options = {
111 - 'none': 'None'
112 - };
195 + if (!fieldId && fallbackId) {
196 + assignFieldId(field, fallbackId);
197 + fieldId = fallbackId;
198 + }
113 199
114 - var prevFieldId;
200 + if (fieldId && seenIds[fieldId]) {
201 + const $wrap = $panelRoot.find(".elementor-repeater-fields-wrapper").first();
202 + if ($wrap.length && !$panelRoot.find(".king-addons-field-id-dup-notice").length) {
203 + $wrap.prepend(
204 + '<div class="elementor-panel-alert elementor-panel-alert-warning king-addons-field-id-dup-notice">' +
205 + "Two fields share the same Field ID. Each ID must be unique or submitted values will collide." +
206 + "</div>"
207 + );
208 + }
209 + }
115 210
116 - formFieldsModel.each(function (field, index) {
117 - var fieldLabel = field.get('field_label');
118 - var fieldId = field.get('field_id');
211 + if (fieldId) {
212 + seenIds[fieldId] = true;
213 + options[fieldId] = fieldLabel;
214 + }
215 + });
119 216
120 - if (prevFieldId == fieldId) {
121 - $('#elementor-panel').find(':input[value=' + field.attributes._id + ']').closest('.elementor-repeater-fields').find(':input[data-setting="field_id"]').val(field.attributes._id);
122 - $('#elementor-panel').find(':input[value=' + field.attributes._id + ']').closest('.elementor-repeater-fields').find('.king-addons-form-field-shortcode').val('id=["' + field.attributes._id + '"]');
123 - field.attributes.field_id = field.attributes._id;
124 - }
217 + view.model.setSetting("email_field", _.extend(emailField, {options}));
218 + view.model.setSetting("first_name_field", _.extend(firstNameField, {options}));
219 + view.model.setSetting("last_name_field", _.extend(lastNameField, {options}));
220 + view.model.setSetting("phone_field", _.extend(phoneField, {options}));
221 + view.model.setSetting("birthday_field", _.extend(birthdayField, {options}));
222 + view.model.setSetting("address_field", _.extend(addressField, {options}));
223 + view.model.setSetting("country_field", _.extend(countryField, {options}));
224 + view.model.setSetting("city_field", _.extend(cityField, {options}));
225 + view.model.setSetting("state_field", _.extend(stateField, {options}));
226 + view.model.setSetting("zip_field", _.extend(zipField, {options}));
125 227
126 - prevFieldId = fieldId;
228 + _.each(selectControls, function (control) {
229 + control.empty();
230 + });
127 231
128 - if (!fieldId) {
129 - $('#elementor-panel').find(':input[value=' + field.attributes._id + ']').closest('.elementor-repeater-fields').find(':input[data-setting="field_id"]').val(field.attributes._id);
130 - $('#elementor-panel').find(':input[value=' + field.attributes._id + ']').closest('.elementor-repeater-fields').find('.king-addons-form-field-shortcode').val('id=["' + field.attributes._id + '"]');
131 - field.attributes.field_id = field.attributes._id;
232 + _.each(options, function (label, value) {
233 + _.each(selectControls, function (control, i) {
234 + const isSelected = fieldValues[i] === value ? " selected" : "";
235 + control.append(
236 + '<option value="' + value + '"' + isSelected + ">" + label + "</option>"
237 + );
238 + });
239 + });
132 240 }
133 241
134 - options[fieldId] = fieldLabel;
135 - });
242 + function assignFieldId(field, nextId) {
243 + if (!field || !nextId) {
244 + return;
245 + }
136 246
137 - view.model.setSetting('email_field', _.extend(emailField, {options}));
138 - view.model.setSetting('first_name_field', _.extend(firstNameField, {options}));
139 - view.model.setSetting('last_name_field', _.extend(lastNameField, {options}));
140 - view.model.setSetting('phone_field', _.extend(phoneField, {options}));
141 - view.model.setSetting('birthday_field', _.extend(birthdayField, {options}));
142 - view.model.setSetting('address_field', _.extend(addressField, {options}));
143 - view.model.setSetting('country_field', _.extend(countryField, {options}));
144 - view.model.setSetting('city_field', _.extend(cityField, {options}));
145 - view.model.setSetting('state_field', _.extend(stateField, {options}));
146 - view.model.setSetting('zip_field', _.extend(zipField, {options}));
247 + if (typeof field.setSetting === "function") {
248 + field.setSetting("field_id", nextId);
249 + } else if (typeof field.set === "function") {
250 + field.set("field_id", nextId);
251 + } else {
252 + field.attributes.field_id = nextId;
253 + }
147 254
148 - _.each(selectControls, function (control) {
149 - control.empty();
150 - });
255 + const $row = $panelRoot
256 + .find(":input[value=" + field.attributes._id + "]")
257 + .closest(".elementor-repeater-fields");
258 + $row.find(':input[data-setting="field_id"]').val(nextId);
259 + $row.find(".king-addons-form-field-shortcode").val('id=["' + nextId + '"]');
260 + }
151 261
152 - _.each(options, function (label, value) {
153 - _.each(selectControls, function (control, i) {
154 - const isSelected = fieldValues[i] === value ? ' selected' : '';
155 - control.append('<option value="' + value + '"' + isSelected + '>' + label + '</option>');
156 - });
157 - });
158 - };
262 + // Change the selector below to match the field_id field in your repeater.
263 + const customIdFieldSelector = 'input[data-setting="field_id"]';
159 264
160 - // Change the selector below to match the field_id field in your repeater
161 - const customIdFieldSelector = 'input[data-setting="field_id"]';
265 + // Change the selector below to match the shortcode field in your repeater.
266 + const shortcodeFieldSelector = ".king-addons-form-field-shortcode";
162 267
163 - // Change the selector below to match the shortcode field in your repeater
164 - const shortcodeFieldSelector = '.king-addons-form-field-shortcode';
268 + // Listen for changes in the field_id field (namespaced).
269 + $panelRoot.off("input.kingAddonsFormBuilder", customIdFieldSelector);
270 + $panelRoot.on("input.kingAddonsFormBuilder", customIdFieldSelector, function () {
271 + const newCustomId = $(this).val();
165 272
166 - // Listen for changes in the field_id field
167 - $('#elementor-panel').on('input', customIdFieldSelector, function () {
273 + const $shortcodeField = $(this)
274 + .closest(".elementor-repeater-fields")
275 + .find(shortcodeFieldSelector);
168 276
169 - // Get the new field_id value
170 - const newCustomId = $(this).val();
277 + let updatedShortcode;
278 + const currentShortcode = $shortcodeField.val();
279 + const match = currentShortcode.match(/\[id="[^"]*"\]/);
171 280
172 - // Find the corresponding shortcode field in the same repeater item
173 - const $shortcodeField = $(this).closest('.elementor-repeater-fields').find(shortcodeFieldSelector);
281 + if (match) {
282 + updatedShortcode = currentShortcode.replace(match[0], `[id="${newCustomId}"]`);
283 + } else {
284 + updatedShortcode = `[id="${newCustomId}"]`;
285 + }
174 286
175 - // Update the shortcode with the new field_id value
176 - let updatedShortcode;
177 - const currentShortcode = $shortcodeField.val();
178 - const match = currentShortcode.match(/\[id="[^"]*"\]/);
287 + $shortcodeField.val(updatedShortcode);
288 + });
289 + });
290 + ;
291 + });
292 + };
179 293
180 - if (match) {
181 - updatedShortcode = currentShortcode.replace(match[0], `[id="${newCustomId}"]`);
182 - } else {
183 - updatedShortcode = `[id="${newCustomId}"]`;
184 - }
185 294
186 - // Set the updated shortcode in the shortcode field
187 - $shortcodeField.val(updatedShortcode);
188 - });
189 - });
190 -
191 - });
295 + bindOnce();
192 296 }(jQuery));