/home/vianto5/distritosatelite.mx/wp-content/plugins/advanced-form-integration/assets/js
Edit: /home/vianto5/distritosatelite.mx/wp-content/plugins/advanced-form-integration/assets/js/app.js (35650B)
/**
* Advanced Form Integration - Vue App Initialization
* Handles the main Vue instance and lazy loading of action components
*/
(function() {
'use strict';
// Wait for DOM to be ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initApp);
} else {
initApp();
}
function initApp() {
// Only initialize on pages with the integration form
// Both new and edit pages use id="adfoin-new-integration"
var appElement = document.getElementById('adfoin-new-integration');
if (!appElement) {
// Other handlers (toggle, delete, copy) are in core.js
return;
}
var elementId = '#adfoin-new-integration';
// Create the Vue app
window.adfoinNewIntegration = new Vue({
el: elementId,
data: {
trigger: {
integrationTitle: '',
formProviderId: '',
forms: '',
formId: '',
formName: '',
formFields: [],
extraFields: {}
},
formValidated: 0,
actionValidated: 0,
action: {
actionProviderId: '',
task: '',
cl: {
active: "no",
match: "any",
conditions: []
},
tasks: []
},
formLoading: false,
fieldLoading: false,
actionLoading: false,
actionsComponentsLoading: false,
functionLoading: false,
refreshing: false,
fieldData: {},
componentKey: 0,
// Alphabetically sorted picker option lists, populated from
// window globals set by the integration views. Used by the
//
components in Step 2 (form provider)
// and Step 3 (action provider).
adfoinFormProviders: (typeof window !== 'undefined' && Array.isArray(window.adfoinFormProviders)) ? window.adfoinFormProviders : [],
adfoinActionProviders: (typeof window !== 'undefined' && Array.isArray(window.adfoinActionProviders)) ? window.adfoinActionProviders : [],
// True once the user has typed in the integration title input.
// Programmatic v-model writes don't fire native input events,
// so this flag only gets set on genuine user keystrokes.
// We also flip it true on mount when editing an existing
// record so the saved title is never overwritten.
titleManuallyEdited: false,
// Validation state. Inline errors only render once the user
// has either tried to submit the form or has focused-then-
// blurred a field while it was still empty.
submitAttempted: false,
touched: {
integrationTitle: false,
formProvider: false,
formId: false,
actionProvider: false,
task: false
},
// AJAX save state.
saving: false,
toasts: [],
_toastSeq: 0,
// Dirty tracking via baseline snapshot diff.
//
// _baselineSnapshot is a JSON string of the form state we
// consider "saved" — it auto-refreshes whenever anything
// mutates trigger / action / fieldData *until* the user
// actually interacts. After interaction, the baseline is
// locked and the `dirty` computed reports any divergence.
//
// This means async post-mount writes (form list AJAX,
// platform-component credential fetches, browser autofill,
// password manager probes, etc.) become part of the
// baseline rather than triggering a false dirty state.
//
// _bypassUnloadGuard short-circuits the prompt when the
// user is intentionally submitting / navigating.
_baselineSnapshot: null,
_userInteracted: false,
_bypassUnloadGuard: false
},
methods: {
changeFormProvider: function(event) {
var that = this;
this._userInteracted = true;
this.formValidated = 1;
this.formLoading = true;
this.trigger.formId = '';
if (this.trigger.formProviderId == '') {
this.trigger.forms = '';
this.formValidated = 0;
this.formLoading = false;
return;
}
var formProviderData = {
'action': 'adfoin_get_forms',
'nonce': adfoin.nonce,
'formProviderId': this.trigger.formProviderId
};
jQuery.post(ajaxurl, formProviderData, function(response) {
that.trigger.forms = response.data;
that.formValidated = 0;
that.formLoading = false;
});
},
updateFormProvider: function() {
var that = this;
this.formLoading = true;
var formProviderData = {
'action': 'adfoin_get_forms',
'nonce': adfoin.nonce,
'formProviderId': this.trigger.formProviderId
};
jQuery.post(ajaxurl, formProviderData, function(response) {
that.trigger.forms = response.data;
that.formLoading = false;
});
},
changedForm: function(event) {
var that = this;
this._userInteracted = true;
this.fieldLoading = true;
if (!this.trigger.formFields || typeof this.trigger.formFields !== 'object') {
this.$set(this.trigger, 'formFields', {});
}
var formData = {
'action': 'adfoin_get_form_fields',
'formProviderId': this.trigger.formProviderId,
'nonce': adfoin.nonce,
'formId': this.trigger.formId
};
if (this.trigger.formProviderId === 'webhooksinbound2') {
if (this.trigger.formFields && this.trigger.formFields.webhook_id) {
formData.existingWebhookId = this.trigger.formFields.webhook_id;
}
if (typeof window.adfoinIntegrationId !== 'undefined') {
formData.integrationId = window.adfoinIntegrationId;
}
}
jQuery.post(ajaxurl, formData, function(response) {
that.trigger.formFields = response.data;
that.fieldLoading = false;
that.refreshing = false;
});
},
changeActionProvider: function(event) {
var that = this;
this._userInteracted = true;
this.actionValidated = 1;
this.actionLoading = true;
this.action.task = '';
if (this.action.actionProviderId == '') {
this.action.tasks = '';
this.actionValidated = 0;
this.actionLoading = false;
return;
}
var providerId = this.action.actionProviderId;
// Lazy-load just this platform's component file if it hasn't
// been loaded yet. Each platform now lives in its own file at
// platforms//-component.js (mapped by
// adfoin.platformScripts).
if (!window.adfoinComponentLoader.isPlatformLoaded(providerId)) {
this.actionsComponentsLoading = true;
window.adfoinComponentLoader.loadPlatform(providerId).then(function() {
that.actionsComponentsLoading = false;
// Increment key to force Vue to re-create the dynamic component
that.componentKey++;
that.fetchTasks();
}).catch(function(error) {
// No on-demand component file is registered for this
// provider (e.g. a Pro-only platform that renders its
// fields purely server-side and has no
// -component.js). Log it, then still fetch
// the tasks list — the server-side action provider
// is registered (it appeared in the picker) and the
// task dropdown does not depend on the component.
console.error('Failed to load platform component for', providerId, error);
that.actionsComponentsLoading = false;
that.fetchTasks();
});
} else {
this.fetchTasks();
}
},
fetchTasks: function() {
var that = this;
var actionProviderData = {
'action': 'adfoin_get_tasks',
'nonce': adfoin.nonce,
'actionProviderId': this.action.actionProviderId
};
jQuery.post(ajaxurl, actionProviderData, function(response) {
that.action.tasks = response.data;
that.actionValidated = 0;
that.actionLoading = false;
});
},
refreshForms: function() {
this.refreshing = true;
this.changedForm();
},
// Resolve a value to its display label inside a
// [{value,label}] list (case-insensitive on value).
lookupLabel: function(list, value) {
if (!list || value === '' || value === null || typeof value === 'undefined') return '';
for (var i = 0; i < list.length; i++) {
if (String(list[i].value) === String(value)) {
return list[i].label;
}
}
return '';
},
// Fired by the integration_title input on every native input
// event. v-model assignments done programmatically (e.g. by
// the suggestedTitle watcher) do NOT dispatch native input
// events, so this only flips when the user types.
onTitleInput: function() {
this.titleManuallyEdited = true;
this.touched.integrationTitle = true;
this._userInteracted = true;
},
// Mark a single required field as "touched" so its inline
// error becomes visible. Called from @blur handlers.
markTouched: function(key) {
if (Object.prototype.hasOwnProperty.call(this.touched, key)) {
this.touched[key] = true;
}
},
// Wired to @change on dropdowns whose selection is a real
// user edit but doesn't already have a dedicated handler
// (the task picker, for example). Custom Vue change events
// don't fire native DOM events, so the form-level listener
// doesn't see them.
markUserInteracted: function() {
this._userInteracted = true;
},
// Snapshot the current trigger / action / fieldData as the
// "saved" baseline. Called repeatedly during init (each
// time async data lands) until the user interacts, then
// again after a successful save.
captureBaseline: function() {
try {
this._baselineSnapshot = JSON.stringify({
trigger: this.trigger,
action: this.action,
fieldData: this.fieldData
});
} catch (e) {
this._baselineSnapshot = '';
}
},
// Whether to render the inline error for a given key.
showError: function(key) {
if (!this.errors[key]) return false;
return this.submitAttempted || !!this.touched[key];
},
// Form submit handler. Always intercepts the native submit
// so we can:
// 1. Light up inline errors when the form is incomplete.
// 2. Send the save as an AJAX call instead of a full
// page reload, then react to the JSON response.
// Falls back to the native admin-post.php handler if the
// AJAX request itself fails at the network level.
onSubmitForm: function(e) {
if (e && typeof e.preventDefault === 'function') {
e.preventDefault();
}
this.submitAttempted = true;
if (!this.canSave) {
var that = this;
this.$nextTick(function() {
var first = that.$el.querySelector('.has-error, .afi-input.has-error, [aria-invalid="true"]');
if (first && typeof first.focus === 'function') {
first.focus();
}
});
return false;
}
if (this.saving) return false;
this.saveIntegration();
return false;
},
// Build the payload from current Vue state and POST to the
// AJAX save endpoint. On success: show a toast, reset dirty,
// and (for new integrations) seamlessly upgrade the page
// into edit-mode by updating window.adfoinIntegrationId and
// patching the form's hidden inputs.
//
// We serialize the entire