1function booklyAlert(alert) { 2 // Check if there are messages in alert. 3 let not_empty = false; 4 for (let type in alert) { 5 if (['success', 'error'].includes(type) && alert[type].length) { 6 not_empty = true; 7 break; 8 } 9 } 10 11 if (not_empty) { 12 let $container = jQuery('#bookly-alert'); 13 if ($container.length === 0) { 14 $container = jQuery('<div id="bookly-alert" class="bookly-alert" style="max-width:600px"></div>').appendTo('#bookly-tbs'); 15 } 16 for (let type in alert) { 17 alert[type].forEach(function (message) { 18 const $alert = jQuery('<div class="alert"><button type="button" class="close" data-dismiss="alert">×</button></div>'); 19 20 switch (type) { 21 case 'success': 22 $alert 23 .addClass('alert-success') 24 .prepend('<i class="fas fa-check-circle fa-fw fa-lg text-success align-middle mr-1"></i>'); 25 setTimeout(function () { 26 $alert.remove(); 27 }, 10000); 28 break; 29 case 'error': 30 $alert 31 .addClass('alert-danger') 32 .prepend('<i class="fas fa-times-circle fa-fw fa-lg text-danger align-middle mr-1"></i>'); 33 break; 34 } 35 36 $alert 37 .append('<b>' + message + '</b>') 38 .appendTo($container); 39 }); 40 } 41 } 42} 43 44function booklyModal(title, text, closeCaption, mainActionCaption) { 45 let $mainButton = '', 46 $modal = jQuery('<div>', {class: 'bookly-modal bookly-fade', tabindex: -1, role: 'dialog'}); 47 if (mainActionCaption) { 48 $mainButton = jQuery('<button>', { 49 class: 'btn ladda-button btn-success', 50 type: 'button', 51 title: mainActionCaption, 52 'data-spinner-size': 40, 53 'data-style': 'zoom-in' 54 }) 55 .append('<span>', {class: 'ladda-label'}).text(mainActionCaption); 56 $mainButton.on('click', function (e) { 57 e.stopPropagation(); 58 $modal.trigger('bs.click.main.button', [$modal, $mainButton.get(0)]); 59 }); 60 } 61 62 $modal 63 .append( 64 jQuery('<div>', {class: 'modal-dialog'}) 65 .append( 66 jQuery('<div>', {class: 'modal-content'}) 67 .append( 68 jQuery('<div>', {class: 'modal-header'}) 69 .append(jQuery('<h5>', {class: 'modal-title', html: title})) 70 .append( 71 jQuery('<button>', {class: 'close', 'data-dismiss': 'bookly-modal', type: 'button'}) 72 .append('<span>').text('Ã') 73 ) 74 ) 75 .append( 76 text ? jQuery('<div>', {class: 'modal-body', html: text}) : '' 77 ) 78 .append( 79 jQuery('<div>', {class: 'modal-footer'}) 80 .append($mainButton) 81 .append( 82 jQuery('<button>', { 83 class: 'btn ladda-button btn-default', 84 'data-dismiss': 'bookly-modal', 85 type: 'button' 86 }) 87 .append('<span>').text(closeCaption) 88 ) 89 ) 90 ) 91 ); 92 jQuery('#bookly-tbs').append($modal); 93 94 $modal.on('hide.bs.modal', function () { 95 setTimeout(function () {$modal.remove();}, 2000) 96 }); 97 setTimeout(function () {$modal.booklyModal('show')}, 0); 98 99 return $modal; 100} 101 102function getBooklyModalContainer(id) { 103 if (!document.getElementsByClassName('bookly-modals-container').length) { 104 let modalsContainer = document.createElement('div'); 105 modalsContainer.setAttribute('id', 'bookly-tbs'); 106 modalsContainer.className = 'bookly-modals-container'; 107 document.body.appendChild(modalsContainer); 108 } 109 if (!document.getElementById(id)) { 110 let container = document.createElement('div'); 111 container.setAttribute('id', id); 112 document.getElementsByClassName('bookly-modals-container')[0].appendChild(container); 113 } 114 115 return document.getElementById(id); 116} 117 118function requiredBooklyPro() { 119 jQuery.ajax({ 120 url: ajaxurl, 121 type: 'POST', 122 data: { 123 action: 'bookly_required_bookly_pro', 124 csrf_token: BooklyL10nGlobal.csrf_token 125 }, 126 success: function (response) { 127 if (response.success) { 128 let $features = jQuery('<div>', {class: 'col-12'}), 129 $content = jQuery('<div>') 130 ;
131 response.data.features.forEach(function (feature, f) { 132 $features.append(jQuery('<div>', {html: feature}).prepend(jQuery('<i>', {class: 'fa-fw mr-1 fas fa-check text-success'}))); 133 }); 134 135 $content 136 .append(jQuery('<div>', {class: 'm-n3'}) 137 .append( 138 jQuery('<img/>', {src: response.data.image, alt: 'Bookly Pro', class: 'img-fluid'}) 139 ) 140 ).append(jQuery('<div>', {class: 'row'}) 141 .append(jQuery('<div>', {class: 'mx-auto h4 mt-4 text-bookly', html: response.data.caption})) 142 ).append(jQuery('<div>', {class: 'row'}) 143 .append(jQuery('<div>', {class: 'col text-center', html: response.data.body})) 144 ).append(jQuery('<div>', {class: 'form-row mt-3'}) 145 .append($features) 146 ); 147 148 booklyModal('', $content, response.data.close, response.data.upgrade) 149 .on('bs.click.main.button', function (event, modal, mainButton) { 150 Ladda.create(mainButton).start(); 151 window.location.href = 'https://www.booking-wp-plugin.com/pricing'; 152 modal.booklyModal('hide'); 153 }) 154 .on('show.bs.modal', function () { 155 jQuery('.modal-header', jQuery(this)).remove(); 156 }); 157 } 158 }, 159 }); 160} 161 162(function ($) { 163 window.booklyDataTables = { 164 settings: {}, 165 init: function ($container, settings, initial_settings) { 166 this.settings = settings; 167 if (initial_settings.hasOwnProperty('add_checkbox_column') && initial_settings.add_checkbox_column) { 168 this._addCheckboxColumn($container, initial_settings); 169 delete initial_settings.add_checkbox_column; 170 } 171 const default_settings = { 172 order: this.getOrder(initial_settings.columns), 173 pageLength: this.getPageLength(), 174 language: this.getLocalization(initial_settings), 175 layout: { 176 bottomStart: { 177 paging: { 178 type: 'numbers' 179 } 180 }, 181 bottomEnd: null, 182 topEnd: null, 183 topStart: null, 184 }, 185 searching: false, 186 info: false, 187 processing: true, 188 responsive: true, 189 paging: true, 190 serverSide: true, 191 }; 192 193 return $container.DataTable($.extend({}, default_settings, initial_settings)); 194 }, 195 getOrder: function (columns) { 196 let order = []; 197 $.each(this.settings.order, function (_, value) { 198 const index = columns.findIndex(function (c) { 199 return c.data === value.column; 200 }); 201 if (index !== -1) { 202 order.push([index, value.order]); 203 } 204 }); 205 206 return order; 207 }, 208 getPageLength: function () { 209 return this.settings.hasOwnProperty('page_length') ? this.settings.page_length : 25; 210 }, 211 getLocalization: function (initial_settings) { 212 let language = initial_settings.hasOwnProperty('language') 213 ? initial_settings.language 214 : {}; 215 if (window.BooklyL10n !== undefined) { 216 ['zeroRecords', 'processing', 'emptyTable', 'loadingRecords'].forEach(function (value) { 217 if (!language.hasOwnProperty(value)) { 218 language[value] = BooklyL10n[value]; 219 } 220 }); 221 } 222 223 return language; 224 }, 225 getRowData: function (element, dt) { 226 const $el = $(element).closest('td'); 227 const dataTable = dt || $el.closest('table').DataTable(); 228 return $el.hasClass('child') 229 ? dataTable.row($el.closest('tr').prev()).data() 230 : dataTable.row($el).data(); 231 }, 232 233 _addCheckboxColumn: function ($container, initial_settings) { 234 const self = this; 235 const tableId = $container.prop('id'); 236 const $deleteButton = $('#' + tableId + '-delete-button'); 237 238 const $checkAll = $('<input>', {type: 'checkbox', id: 'bookly-check-all', class: 'custom-control-input'}); 239 const $label = $('<label>', {class: 'custom-control-label', for: 'bookly-check-all'}); 240 const $th = $('<th width="16px">').append($('<div>', {class: 'custom-control custom-checkbox'}).append($checkAll, $label)); 241 $('thead tr', $container).append($th); 242 243 initial_settings.columns.push({ 244 data: null, 245 responsivePriority: 1, 246 orderable: false, 247 render: function (data, type, row, meta) { 248 const prefix = meta.settings.sInstance + '-'; 249 return ` 250 <div class="custom-control custom-checkbox mt-1"> 251 <input value="${row.id}" id="${prefix}${row.id}" type="checkbox" class="custom-control-input"> 252 <label for="${prefix}${row.id}" class="custom-control-label"></label> 253 </div>`; 254 } 255 }); 256 257 $checkAll.on('change', function () { 258 $container.find('tbody input:checkbox').prop('checked', this.checked); 259 self._updateDeleteButtonState($deleteButton, $container); 260 }); 261 262 $container.on('change', 'tbody input:checkbox', function () { 263 $checkAll.prop('checked', $container.find('tbody input:not(:checked)').length === 0); 264 self._updateDeleteButtonState($deleteButton, $container); 265 }); 266 267 this._updateDeleteButtonState($deleteButton, $container); 268 }, 269 _updateDeleteButtonState: function ($deleteButton, $container) { 270 $deleteButton.prop('disabled', $container.find('input
270:checked').length === 0); 271 }, 272 }; 273 274 window.booklySerialize = { 275 form: function ($form) { 276 let data = {}, 277 serialized = $form.serializeArray(); 278 $('input[type=radio]:not(:checked)', $form).each(function () { 279 if (this.name) { 280 let find = false, 281 that = this; 282 serialized.forEach(function (item) { 283 if (!find && item.name === that.name) { 284 find = true; 285 } 286 }); 287 if (!find) { 288 serialized.push({name: this.name, value: null}); 289 } 290 } 291 }); 292 $('input[type=checkbox]:not(:checked)', $form).each(function () { 293 if (this.name) { 294 serialized.push({name: this.name, value: null}); 295 } 296 }); 297 $.map(serialized, function (n) { 298 const keys = n.name.match(/[a-zA-Z0-9_-]+|(?=\[\])/g); 299 if (keys.length > 1) { 300 let tmp = data, key = keys.pop(); 301 for (let i = 0; i < keys.length, j = keys[i]; i++) { 302 tmp[j] = (!tmp[j] 303 ? (key == '' && i == keys.length - 1) ? [] : {} 304 : tmp[j] 305 ); 306 tmp = tmp[j]; 307 } 308 if (n.value !== null) { 309 if (Array.isArray(tmp)) { 310 tmp.push(n.value); 311 } else { 312 tmp[key] = n.value; 313 } 314 } 315 } else data[keys.pop()] = n.value; 316 }); 317 318 return data; 319 }, 320 buildRequestDataFromForm: function (action, $form) { 321 return this.buildRequestData(action, this.form($form)); 322 }, 323 buildRequestData: function (action, data) { 324 return { 325 action: action, 326 csrf_token: BooklyL10nGlobal.csrf_token, 327 json_data: JSON.stringify(data), 328 } 329 } 330 } 331 332 window.booklyRequest = { 333 objectToQueryString: function (initialObj) { 334 const reducer = (obj, parentPrefix = null) => (prev, key) => { 335 const val = obj[key]; 336 key = encodeURIComponent(key); 337 const prefix = parentPrefix ? `${parentPrefix}[${key}]` : key; 338 339 if (val == null || typeof val === 'function') { 340 prev.push(`${prefix}=`); 341 return prev; 342 } 343 344 if (['number', 'boolean', 'string'].includes(typeof val)) { 345 prev.push(`${prefix}=${encodeURIComponent(val)}`); 346 return prev; 347 } 348 349 prev.push(Object.keys(val).reduce(reducer(val, prefix), []).join('&')); 350 return prev; 351 }; 352 353 return Object.keys(initialObj).reduce(reducer(initialObj), []).join('&'); 354 }, 355 /** 356 * @param data 357 * @returns {Promise<unknown>} 358 */ 359 send: function (data) { 360 return new Promise((resolve, reject) => { 361 fetch(ajaxurl, { 362 method: 'POST', 363 body: this.objectToQueryString(data), 364 headers: { 365 'Content-Type': 'application/x-www-form-urlencoded' 366 } 367 }) 368 .then(response => { 369 if (!response.ok) { 370 return response.json().then(err => { 371 throw new Error(err.message || 'Something went wrong'); 372 }); 373 } 374 375 return response.json(); 376 }) 377 .then(data => resolve(data)) 378 .catch(error => { 379 console.log('Invalid response for ' + (data?.action || 'request') + '. Reason ' + error.message); 380 reject(error); 381 }); 382 }); 383 } 384 } 385})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.