| 1 |
if (!Array.prototype.hasOwnProperty('swap')) { |
| 2 |
Array.prototype.swap = function (from, to) { |
| 3 |
this.splice(to, 0, this.splice(from, 1)[0]); |
| 4 |
}; |
| 5 |
} |
| 6 |
|
| 7 |
Vue.component('datepicker', { |
| 8 |
template: '<input type="text" v-bind:value="value" />', |
| 9 |
props: ['value'], |
| 10 |
mounted: function() { |
| 11 |
var self = this; |
| 12 |
|
| 13 |
$(this.$el).datetimepicker({ |
| 14 |
dateFormat: 'yy-mm-dd', |
| 15 |
timeFormat: "HH:mm:ss", |
| 16 |
onClose: this.onClose |
| 17 |
}); |
| 18 |
}, |
| 19 |
|
| 20 |
methods: { |
| 21 |
onClose: function(date) { |
| 22 |
this.$emit('input', date); |
| 23 |
} |
| 24 |
}, |
| 25 |
}); |
| 26 |
|
| 27 |
Vue.component('weforms-colorpicker', { |
| 28 |
template: '<input type="text" v-bind:value="value" />', |
| 29 |
props: ['value'], |
| 30 |
mounted: function() { |
| 31 |
var self = this; |
| 32 |
|
| 33 |
$(this.$el).wpColorPicker({ |
| 34 |
change: this.onChange |
| 35 |
}); |
| 36 |
}, |
| 37 |
|
| 38 |
methods: { |
| 39 |
onChange: function(event, ui) { |
| 40 |
this.$emit('input', ui.color.toString()); |
| 41 |
} |
| 42 |
}, |
| 43 |
}); |
| 44 |
|
| 45 |
// check if an element is visible in browser viewport |
| 46 |
function is_element_in_viewport (el) { |
| 47 |
if (typeof jQuery === "function" && el instanceof jQuery) { |
| 48 |
el = el[0]; |
| 49 |
} |
| 50 |
|
| 51 |
var rect = el.getBoundingClientRect(); |
| 52 |
|
| 53 |
return ( |
| 54 |
rect.top >= 0 && |
| 55 |
rect.left >= 0 && |
| 56 |
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ |
| 57 |
rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ |
| 58 |
); |
| 59 |
} |
| 60 |
|
| 61 |
/** |
| 62 |
* Vuex Store data |
| 63 |
*/ |
| 64 |
var wpuf_form_builder_store = new Vuex.Store({ |
| 65 |
state: { |
| 66 |
post: {}, |
| 67 |
form_fields: [], |
| 68 |
panel_sections: wpuf_form_builder.panel_sections, |
| 69 |
field_settings: wpuf_form_builder.field_settings, |
| 70 |
notifications: [], |
| 71 |
settings: {}, |
| 72 |
integrations: {}, |
| 73 |
current_panel: 'form-fields', |
| 74 |
editing_field_id: 0, // editing form field id |
| 75 |
}, |
| 76 |
|
| 77 |
mutations: { |
| 78 |
set_form_fields: function (state, form_fields) { |
| 79 |
Vue.set(state, 'form_fields', form_fields); |
| 80 |
}, |
| 81 |
|
| 82 |
set_form_post: function (state, post) { |
| 83 |
Vue.set(state, 'post', post); |
| 84 |
}, |
| 85 |
|
| 86 |
set_form_notification: function (state, value) { |
| 87 |
Vue.set(state, 'notifications', value); |
| 88 |
}, |
| 89 |
|
| 90 |
set_form_integrations: function (state, value) { |
| 91 |
Vue.set(state, 'integrations', value); |
| 92 |
}, |
| 93 |
|
| 94 |
set_form_settings: function (state, value) { |
| 95 |
Vue.set(state, 'settings', value); |
| 96 |
}, |
| 97 |
|
| 98 |
// set the current panel |
| 99 |
set_current_panel: function (state, panel) { |
| 100 |
if ('field-options' !== state.current_panel && |
| 101 |
'field-options' === panel && |
| 102 |
state.form_fields.length |
| 103 |
) { |
| 104 |
state.editing_field_id = state.form_fields[0].id; |
| 105 |
} |
| 106 |
|
| 107 |
state.current_panel = panel; |
| 108 |
|
| 109 |
// reset editing field id |
| 110 |
if ('form-fields' === panel) { |
| 111 |
state.editing_field_id = 0; |
| 112 |
} |
| 113 |
}, |
| 114 |
|
| 115 |
// add show property to every panel section |
| 116 |
panel_add_show_prop: function (state) { |
| 117 |
state.panel_sections.map(function (section, index) { |
| 118 |
if (!section.hasOwnProperty('show')) { |
| 119 |
Vue.set(state.panel_sections[index], 'show', true); |
| 120 |
} |
| 121 |
}); |
| 122 |
}, |
| 123 |
|
| 124 |
// toggle panel sections |
| 125 |
panel_toggle: function (state, index) { |
| 126 |
state.panel_sections[index].show = !state.panel_sections[index].show; |
| 127 |
}, |
| 128 |
|
| 129 |
// open field settings panel |
| 130 |
open_field_settings: function (state, field_id) { |
| 131 |
var field = state.form_fields.filter(function(item) { |
| 132 |
return parseInt(field_id) === parseInt(item.id); |
| 133 |
}); |
| 134 |
|
| 135 |
if ('field-options' === state.current_panel && field[0].id === state.editing_field_id) { |
| 136 |
return; |
| 137 |
} |
| 138 |
|
| 139 |
if (field.length) { |
| 140 |
state.editing_field_id = 0; |
| 141 |
state.current_panel = 'field-options'; |
| 142 |
|
| 143 |
setTimeout(function () { |
| 144 |
state.editing_field_id = field[0].id; |
| 145 |
}, 400); |
| 146 |
} |
| 147 |
}, |
| 148 |
|
| 149 |
update_editing_form_field: function (state, payload) { |
| 150 |
var i = 0; |
| 151 |
|
| 152 |
for (i = 0; i < state.form_fields.length; i++) { |
| 153 |
// check if the editing field exist in normal fields |
| 154 |
if (state.form_fields[i].id === parseInt(payload.editing_field_id)) { |
| 155 |
state.form_fields[i][payload.field_name] = payload.value; |
| 156 |
} |
| 157 |
|
| 158 |
// check if the editing field belong to a column field |
| 159 |
if (state.form_fields[i].template === 'column_field') { |
| 160 |
var innerColumnFields = state.form_fields[i].inner_fields; |
| 161 |
|
| 162 |
for (const columnFields in innerColumnFields) { |
| 163 |
if (innerColumnFields.hasOwnProperty(columnFields)) { |
| 164 |
var columnFieldIndex = 0; |
| 165 |
|
| 166 |
while (columnFieldIndex < innerColumnFields[columnFields].length) { |
| 167 |
if (innerColumnFields[columnFields][columnFieldIndex].id === parseInt(payload.editing_field_id)) { |
| 168 |
innerColumnFields[columnFields][columnFieldIndex][payload.field_name] = payload.value; |
| 169 |
} |
| 170 |
columnFieldIndex++; |
| 171 |
} |
| 172 |
} |
| 173 |
} |
| 174 |
} |
| 175 |
} |
| 176 |
}, |
| 177 |
|
| 178 |
// add new form field element |
| 179 |
add_form_field_element: function (state, payload) { |
| 180 |
state.form_fields.splice(payload.toIndex, 0, payload.field); |
| 181 |
|
| 182 |
// bring newly added element into viewport |
| 183 |
Vue.nextTick(function () { |
| 184 |
var el = $('#form-preview-stage .wpuf-form .field-items').eq(payload.toIndex); |
| 185 |
|
| 186 |
if (el && !is_element_in_viewport(el.get(0))) { |
| 187 |
$('#builder-stage section').scrollTo(el, 800, {offset: -50}); |
| 188 |
} |
| 189 |
}); |
| 190 |
}, |
| 191 |
|
| 192 |
// sorting inside stage |
| 193 |
swap_form_field_elements: function (state, payload) { |
| 194 |
state.form_fields.swap(payload.fromIndex, payload.toIndex); |
| 195 |
}, |
| 196 |
|
| 197 |
clone_form_field_element: function (state, payload) { |
| 198 |
var field = _.find(state.form_fields, function (item) { |
| 199 |
return parseInt(item.id) === parseInt(payload.field_id); |
| 200 |
}); |
| 201 |
|
| 202 |
var clone = $.extend(true, {}, field), |
| 203 |
index = parseInt(payload.index) + 1; |
| 204 |
|
| 205 |
clone.id = payload.new_id; |
| 206 |
clone.name = clone.name + '_copy'; |
| 207 |
clone.is_new = true; |
| 208 |
|
| 209 |
state.form_fields.splice(index, 0, clone); |
| 210 |
}, |
| 211 |
|
| 212 |
// delete a field |
| 213 |
delete_form_field_element: function (state, index) { |
| 214 |
state.current_panel = 'form-fields'; |
| 215 |
state.form_fields.splice(index, 1); |
| 216 |
}, |
| 217 |
|
| 218 |
// set fields for a panel section |
| 219 |
set_panel_section_fields: function (state, payload) { |
| 220 |
var section = _.find(state.panel_sections, function (item) { |
| 221 |
return item.id === payload.id; |
| 222 |
}); |
| 223 |
|
| 224 |
section.fields = payload.fields; |
| 225 |
}, |
| 226 |
|
| 227 |
// notifications |
| 228 |
addNotification: function(state, payload) { |
| 229 |
state.notifications.push(_.clone(payload)); |
| 230 |
}, |
| 231 |
|
| 232 |
deleteNotification: function(state, index) { |
| 233 |
state.notifications.splice(index, 1); |
| 234 |
}, |
| 235 |
|
| 236 |
cloneNotification: function(state, index) { |
| 237 |
var clone = $.extend(true, {}, state.notifications[index]); |
| 238 |
|
| 239 |
index = parseInt(index) + 1; |
| 240 |
state.notifications.splice(index, 0, clone); |
| 241 |
}, |
| 242 |
|
| 243 |
// update by it's property |
| 244 |
updateNotificationProperty: function(state, payload) { |
| 245 |
state.notifications[payload.index][payload.property] = payload.value; |
| 246 |
}, |
| 247 |
|
| 248 |
updateNotification: function(state, payload) { |
| 249 |
state.notifications[payload.index] = payload.value; |
| 250 |
}, |
| 251 |
|
| 252 |
updateIntegration: function(state, payload) { |
| 253 |
// console.log(payload); |
| 254 |
// console.log(state.integrations[payload.index]); |
| 255 |
// state.integrations[payload.index] = payload.value; |
| 256 |
Vue.set(state.integrations, payload.index, payload.value) |
| 257 |
|
| 258 |
// state.integrations.splice(payload.index, 0, payload.value); |
| 259 |
}, |
| 260 |
|
| 261 |
// add new form field element to column field |
| 262 |
add_column_inner_field_element: function (state, payload) { |
| 263 |
var columnFieldIndex = state.form_fields.findIndex(field => field.id === payload.toWhichColumnField); |
| 264 |
|
| 265 |
if (state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn] === undefined) { |
| 266 |
state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn] = []; |
| 267 |
} |
| 268 |
|
| 269 |
if (state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn] !== undefined) { |
| 270 |
var innerColumnFields = state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn]; |
| 271 |
|
| 272 |
if ( innerColumnFields.filter(innerField => innerField.name === payload.field.name).length <= 0 ) { |
| 273 |
state.form_fields[columnFieldIndex].inner_fields[payload.toWhichColumn].splice(payload.toIndex, 0, payload.field); |
| 274 |
} |
| 275 |
} |
| 276 |
}, |
| 277 |
|
| 278 |
move_column_inner_fields: function(state, payload) { |
| 279 |
var columnFieldIndex = state.form_fields.findIndex(field => field.id === payload.field_id), |
| 280 |
innerFields = payload.inner_fields, |
| 281 |
mergedFields = []; |
| 282 |
|
| 283 |
Object.keys(innerFields).forEach(function (column) { |
| 284 |
// clear column-1, column-2 and column-3 fields if move_to specified column-1 |
| 285 |
// add column-1, column-2 and column-3 fields to mergedFields, later mergedFields will move to column-1 field |
| 286 |
if (payload.move_to === "column-1") { |
| 287 |
innerFields[column].forEach(function(field){ |
| 288 |
mergedFields.push(field); |
| 289 |
}); |
| 290 |
|
| 291 |
// clear current column inner fields |
| 292 |
state.form_fields[columnFieldIndex].inner_fields[column].splice(0, innerFields[column].length); |
| 293 |
} |
| 294 |
|
| 295 |
// clear column-2 and column-3 fields if move_to specified column-2 |
| 296 |
// add column-2 and column-3 fields to mergedFields, later mergedFields will move to column-2 field |
| 297 |
if (payload.move_to === "column-2") { |
| 298 |
if ( column === "column-2" || column === "column-3" ) { |
| 299 |
innerFields[column].forEach(function(field){ |
| 300 |
mergedFields.push(field); |
| 301 |
}); |
| 302 |
|
| 303 |
// clear current column inner fields |
| 304 |
state.form_fields[columnFieldIndex].inner_fields[column].splice(0, innerFields[column].length); |
| 305 |
} |
| 306 |
} |
| 307 |
}); |
| 308 |
|
| 309 |
// move inner fields to specified column |
| 310 |
if (mergedFields.length !== 0) { |
| 311 |
mergedFields.forEach(function(field){ |
| 312 |
state.form_fields[columnFieldIndex].inner_fields[payload.move_to].splice(0, 0, field); |
| 313 |
}); |
| 314 |
} |
| 315 |
}, |
| 316 |
|
| 317 |
// sorting inside column field |
| 318 |
swap_column_field_elements: function (state, payload) { |
| 319 |
var columnFieldIndex = state.form_fields.findIndex(field => field.id === payload.field_id), |
| 320 |
fieldObj = state.form_fields[columnFieldIndex].inner_fields[payload.fromColumn][payload.fromIndex]; |
| 321 |
|
| 322 |
if( payload.fromColumn !== payload.toColumn) { |
| 323 |
// add the field object to the target column |
| 324 |
state.form_fields[columnFieldIndex].inner_fields[payload.toColumn].splice(payload.toIndex, 0, fieldObj); |
| 325 |
|
| 326 |
// remove the field index from the source column |
| 327 |
state.form_fields[columnFieldIndex].inner_fields[payload.fromColumn].splice(payload.fromIndex, 1); |
| 328 |
}else{ |
| 329 |
state.form_fields[columnFieldIndex].inner_fields[payload.toColumn].swap(payload.fromIndex, payload.toIndex); |
| 330 |
} |
| 331 |
}, |
| 332 |
|
| 333 |
// open field settings panel |
| 334 |
open_column_field_settings: function (state, payload) { |
| 335 |
var field = payload.column_field; |
| 336 |
|
| 337 |
if ('field-options' === state.current_panel && field.id === state.editing_field_id) { |
| 338 |
return; |
| 339 |
} |
| 340 |
|
| 341 |
if (field) { |
| 342 |
state.editing_field_id = 0; |
| 343 |
state.current_panel = 'field-options'; |
| 344 |
state.editing_field_type = 'column_field'; |
| 345 |
state.editing_column_field_id = payload.field_id; |
| 346 |
state.edting_field_column = payload.column; |
| 347 |
state.editing_inner_field_index = payload.index; |
| 348 |
|
| 349 |
setTimeout(function () { |
| 350 |
state.editing_field_id = field.id; |
| 351 |
}, 400); |
| 352 |
} |
| 353 |
}, |
| 354 |
|
| 355 |
clone_column_field_element: function (state, payload) { |
| 356 |
var columnFieldIndex = state.form_fields.findIndex(field => field.id === payload.field_id); |
| 357 |
|
| 358 |
var field = _.find(state.form_fields[columnFieldIndex].inner_fields[payload.toColumn], function (item) { |
| 359 |
return parseInt(item.id) === parseInt(payload.column_field_id); |
| 360 |
}); |
| 361 |
|
| 362 |
var clone = $.extend(true, {}, field), |
| 363 |
index = parseInt(payload.index) + 1; |
| 364 |
|
| 365 |
clone.id = payload.new_id; |
| 366 |
clone.name = clone.name + '_copy'; |
| 367 |
clone.is_new = true; |
| 368 |
|
| 369 |
state.form_fields[columnFieldIndex].inner_fields[payload.toColumn].splice(index, 0, clone); |
| 370 |
}, |
| 371 |
|
| 372 |
// delete a column field |
| 373 |
delete_column_field_element: function (state, payload) { |
| 374 |
var columnFieldIndex = state.form_fields.findIndex(field => field.id === payload.field_id); |
| 375 |
|
| 376 |
state.current_panel = 'form-fields'; |
| 377 |
state.form_fields[columnFieldIndex].inner_fields[payload.fromColumn].splice(payload.index, 1); |
| 378 |
}, |
| 379 |
} |
| 380 |
}); |
| 381 |
|
| 382 |
// 1. Define route components. |
| 383 |
weForms.routeComponents.FormHome = { template: '<div><router-view class="child"></router-view></div>' }; |
| 384 |
weForms.routeComponents.SingleForm = { template: '#tmpl-wpuf-form-editor' }; |
| 385 |
weForms.routeComponents.FormEntriesHome = { |
| 386 |
template: '<div><router-view class="grand-child"></router-view></div>', |
| 387 |
}; |
| 388 |
|
| 389 |
/** |
| 390 |
* Parse the route array and bind required components |
| 391 |
* |
| 392 |
* This changes the weForms.routes array and changes the components |
| 393 |
* so we can use weForms.routeComponents.{compontent} component. |
| 394 |
* |
| 395 |
* @param {array} routes |
| 396 |
* |
| 397 |
* @return {void} |
| 398 |
*/ |
| 399 |
function parseRouteComponent(routes) { |
| 400 |
|
| 401 |
for (var i = 0; i < routes.length; i++) { |
| 402 |
if ( typeof routes[i].children === 'object' ) { |
| 403 |
|
| 404 |
parseRouteComponent( routes[i].children ); |
| 405 |
|
| 406 |
if ( typeof routes[i].component !== 'undefined' ) { |
| 407 |
routes[i].component = weForms.routeComponents[ routes[i].component ]; |
| 408 |
} |
| 409 |
|
| 410 |
} else { |
| 411 |
routes[i].component = weForms.routeComponents[ routes[i].component ]; |
| 412 |
} |
| 413 |
} |
| 414 |
} |
| 415 |
|
| 416 |
// mutate the localized array |
| 417 |
parseRouteComponent(weForms.routes); |
| 418 |
|
| 419 |
// 3. Create the router instance and pass the `routes` option |
| 420 |
var router = new VueRouter({ |
| 421 |
routes: weForms.routes, |
| 422 |
scrollBehavior: function (to, from, savedPosition) { |
| 423 |
if (savedPosition) { |
| 424 |
return savedPosition |
| 425 |
} else { |
| 426 |
return { x: 0, y: 0 } |
| 427 |
} |
| 428 |
} |
| 429 |
}); |
| 430 |
|
| 431 |
window.weFormsBuilderisDirty = false; |
| 432 |
|
| 433 |
router.beforeEach((to, from, next) => { |
| 434 |
// show warning if builder has unsaved changes |
| 435 |
if ( window.weFormsBuilderisDirty ) { |
| 436 |
if ( confirm( wpuf_form_builder.i18n.unsaved_changes + ' ' +wpuf_form_builder.i18n.areYouSureToLeave ) ) { |
| 437 |
window.weFormsBuilderisDirty = false; |
| 438 |
} else { |
| 439 |
next(from.path); |
| 440 |
return false; |
| 441 |
} |
| 442 |
} |
| 443 |
|
| 444 |
next(); |
| 445 |
}); |
| 446 |
|
| 447 |
|
| 448 |
var app = new Vue({ |
| 449 |
router: router, |
| 450 |
store: wpuf_form_builder_store |
| 451 |
}).$mount('#wpuf-contact-form-app') |
| 452 |
|
| 453 |
// Admin menu hack |
| 454 |
var menuRoot = $('#toplevel_page_weforms'); |
| 455 |
|
| 456 |
menuRoot.on('click', 'a', function() { |
| 457 |
var self = $(this); |
| 458 |
|
| 459 |
$('ul.wp-submenu li', menuRoot).removeClass('current'); |
| 460 |
|
| 461 |
if ( self.hasClass('wp-has-submenu') ) { |
| 462 |
$('li.wp-first-item', menuRoot).addClass('current'); |
| 463 |
} else { |
| 464 |
self.parents('li').addClass('current'); |
| 465 |
} |
| 466 |
}); |
| 467 |
|
| 468 |
$(function() { |
| 469 |
|
| 470 |
// select the current sub menu on page load |
| 471 |
var current_url = window.location.href; |
| 472 |
var current_path = current_url.substr( current_url.indexOf('admin.php') ); |
| 473 |
|
| 474 |
$('ul.wp-submenu a', menuRoot).each(function(index, el) { |
| 475 |
if ( $(el).attr( 'href' ) === current_path ) { |
| 476 |
$(el).parent().addClass('current'); |
| 477 |
return; |
| 478 |
} |
| 479 |
}); |
| 480 |
}); |
| 481 |
|