PATH:
home
/
letacommog
/
ldqm1
/
wp-content
/
plugins
/
facetwp
/
assets
/
js
/
dist
(function () { 'use strict'; ((function ($) { $(function () { init_vue(); init_jquery(); }); function init_vue() { Vue.config.devtools = true; Vue.component('v-select', VueSelect.VueSelect); Vue.filter('i18n', function (str) { return FWP.__(str); }); // Defaults mixin var builder_defaults = { methods: { defaultLayout: function defaultLayout() { return { items: [this.defaultRow()], settings: this.getDefaultSettings('layout') }; }, defaultRow: function defaultRow() { return { type: 'row', items: [this.defaultCol()], settings: this.getDefaultSettings('row') }; }, defaultCol: function defaultCol() { return { type: 'col', items: [], settings: this.getDefaultSettings('col') }; }, defaultItem: function defaultItem(source) { return { type: 'item', source: source, settings: this.getDefaultSettings('item', source) }; }, mergeSettings: function mergeSettings(settings, type, source) { var defaults = this.getDefaultSettings(type, source); var default_keys = Object.keys(defaults); var setting_keys = Object.keys(settings); // Automatically inject new settings var missing_keys = default_keys.filter(function (name) { return !setting_keys.includes(name); }); missing_keys.forEach(function (name, index) { Vue.set(settings, name, defaults[name]); }); return settings; }, cloneObj: function cloneObj(obj) { return JSON.parse(JSON.stringify(obj)); }, getSettingsMeta: function getSettingsMeta() { var settings = { num_columns: { type: 'number', title: FWP.__('Grid columns '), defaultValue: 1 }, grid_gap: { type: 'number', title: FWP.__('Grid gap'), defaultValue: 10 }, text_style: { type: 'text-style', title: FWP.__('Text style'), tab: 'style', defaultValue: { align: '', bold: false, italic: false } }, text_color: { type: 'color', title: FWP.__('Text color'), tab: 'style' }, font_size: { type: 'slider', title: FWP.__('Font size'), tab: 'style', defaultValue: { unit: 'px', size: 0 } }, background_color: { type: 'color', title: FWP.__('Background color'), tab: 'style' }, border: { type: 'border', title: FWP.__('Border'), tab: 'style', defaultValue: { style: 'none', color: '', width: { unit: 'px', top: 0, right: 0, bottom: 0, left: 0 } }, children: { style: { type: 'select', title: FWP.__('Border style'), choices: { 'none': FWP.__('None'), 'solid': FWP.__('Solid'), 'dashed': FWP.__('Dashed'), 'dotted': FWP.__('Dotted'), 'double': FWP.__('Double') } }, color: { type: 'color', title: FWP.__('Border color') }, width: { type: 'utrbl', title: FWP.__('Border width') } } }, button_text: { type: 'text', title: FWP.__('Button text') }, button_text_color: { type: 'color', title: FWP.__('Button text color') }, button_color: { type: 'color', title: FWP.__('Button color') }, button_padding: { type: 'utrbl', title: FWP.__('Button padding'), defaultValue: { unit: 'px', top: 0, right: 0, bottom: 0, left: 0 } }, separator: { type: 'text', title: FWP.__('Separator'), defaultValue: ', ' }, custom_css: { type: 'textarea', title: FWP.__('Custom CSS'), tab: 'style' }, grid_template_columns: { type: 'text', title: FWP.__('Column widths'), defaultValue: '1fr' }, content: { type: 'textarea', title: FWP.__('Content') }, image_size: { type: 'select', title: FWP.__('Image size'), defaultValue: 'thumbnail', choices: FWP.image_sizes, v_show: [ { type: 'source', value: 'featured_image' } ] }, author_field: { type: 'select', title: FWP.__('Author field'), defaultValue: 'display_name', choices: { 'display_name': FWP.__('Display name'), 'user_login': FWP.__('User login'), 'ID': FWP.__('User ID') } }, field_type: { type: 'select', title: FWP.__('Field type'), defaultValue: 'text', choices: { 'text': 'Text', 'date': 'Date', 'number': 'Number' } }, date_format: { type: 'text', title: FWP.__('Date format'), placeholder: 'F j, Y', v_show: [ { type: 'field_type', value: 'date' }, { type: 'source', value: 'post_date' }, { type: 'source', value: 'post_modified' } ] }, input_format: { type: 'text', title: FWP.__('Input format'), placeholder: 'Y-m-d', v_show: [ { type: 'field_type', value: 'date' }, { type: 'source', value: 'post_date' }, { type: 'source', value: 'post_modified' } ] }, number_format: { type: 'select', title: FWP.__('Number format'), choices: { '': FWP.__('None'), 'n': '1234', 'n.n': '1234.5', 'n.nn': '1234.56', 'n,n': '1,234', 'n,n.n': '1,234.5', 'n,n.nn': '1,234.56' }, v_show: [ { type: 'field_type', value: 'number' } ] }, link: { type: 'link', title: FWP.__('Link'), defaultValue: { type: 'none', href: '', target: '' }, children: { type: { type: 'select', title: FWP.__('Link type'), choices: { 'none': FWP.__('None'), 'post': FWP.__('Post URL'), 'custom': FWP.__('Custom URL') } } } }, prefix: { type: 'text', title: FWP.__('Prefix') }, suffix: { type: 'text', title: FWP.__('Suffix') }, is_hidden: { type: 'checkbox', defaultValue: false, suffix: FWP.__('Hide item?') }, padding: { type: 'utrbl', title: FWP.__('Padding'), defaultValue: { unit: 'px', top: 0, right: 0, bottom: 0, left: 0 }, tab: 'style' }, name: { type: 'text', title: FWP.__('Name') }, css_class: { type: 'text', title: FWP.__('CSS class'), tab: 'style' } }; settings.button_border = this.cloneObj(settings.border); settings.button_border.title = FWP.__('Button border'); settings.button_border.tab = 'content'; settings.term_link = this.cloneObj(settings.link); settings.term_link.children.type.choices = { 'none': FWP.__('None'), 'term': FWP.__('Term URL'), 'custom': FWP.__('Custom URL') }; return settings; }, getDefaultFields: function getDefaultFields(type, source) { var fields = []; if ('layout' == type) { fields.push('num_columns', 'grid_gap'); } if ('row' == type) { fields.push('grid_template_columns'); } if ('item' == type) { if ('html' == source) { fields.push('content'); } if ('featured_image' == source) { fields.push('image_size', 'link'); } if ('button' == source) { fields.push('button_text', 'button_text_color', 'button_color', 'button_padding', 'button_border', 'link'); } if ('post_date' == source || 'post_modified' == source) { fields.push('date_format'); } if ('post_title' == source) { fields.push('link'); } if ('post_author' == source) { fields.push('author_field'); } if (0 === source.indexOf('cf/')) { fields.push('field_type', 'date_format', 'input_format', 'number_format', 'link'); } if (0 === source.indexOf('woo/')) { fields.push('field_type', 'date_format', 'input_format', 'number_format'); } if (0 === source.indexOf('tax/')) { fields.push('separator', 'term_link'); } if (!['html', 'button', 'featured_image'].includes(source)) { fields.push('prefix', 'suffix'); } } fields.push('border', 'background_color', 'padding', 'text_color', 'text_style', 'font_size', 'name', 'css_class'); if ('layout' == type) { fields.push('custom_css'); } if ('item' == type) { fields.push('is_hidden'); } return fields; }, getDefaultSettings: function getDefaultSettings(type, source) { var settings = {}; var settings_meta = this.getSettingsMeta(); var fields = this.getDefaultFields(type, source); fields.forEach(function (name) { var defaultValue = settings_meta[name].defaultValue || ''; if ('name' == name) { defaultValue = 'el-' + Math.random().toString(36).substring(7); } settings[name] = defaultValue; }); return settings; } } }; /* ================ query builder ================ */ Vue.component('query-builder', { props: { query_obj: { type: Object, required: true }, template: { type: Object, required: true } }, template: "\n <div class=\"qb-wrap\">\n <div class=\"side-link\">\n <a href=\"javascript:;\" @click=\"$root.getQueryArgs(template)\">{{ 'Convert to query args' | i18n }}</a>\n </div>\n\n <div>\n {{ 'Fetch' | i18n }}\n <v-select\n v-model=\"query_obj.post_type\"\n :options=\"$root.query_data.post_types\"\n :multiple=\"true\"\n :searchable=\"false\"\n :close-on-select=\"false\"\n placeholder=\"All post types\">\n </v-select>\n\n {{ 'and show' | i18n }}\n <input type=\"number\" v-model.number=\"query_obj.posts_per_page\" class=\"qb-posts-per-page\" />\n {{ 'per page' | i18n }}\n </div>\n\n <div class=\"qb-condition\"\n v-show=\"query_obj.orderby.length\">\n {{ 'Sort by' | i18n }}\n </div>\n\n <div v-for=\"(row, index) in query_obj.orderby\" class=\"qb-condition\">\n <fselect :row=\"row\">\n <optgroup label=\"Posts\">\n <option value=\"ID\">ID</option>\n <option value=\"title\">{{ 'Post Title' | i18n }}</option>\n <option value=\"name\">{{ 'Post Name' | i18n }}</option>\n <option value=\"type\">{{ 'Post Type' | i18n }}</option>\n <option value=\"date\">{{ 'Post Date' | i18n }}</option>\n <option value=\"modified\">{{ 'Post Modified' | i18n }}</option>\n <option value=\"menu_order\">{{ 'Menu Order' | i18n }}</option>\n <option value=\"post__in\">post__in</option>\n </optgroup>\n <optgroup label=\"Custom Fields\">\n <option v-for=\"(label, name) in $root.data_sources.custom_fields.choices\" :value=\"name\">{{ label }}</option>\n </optgroup>\n </fselect>\n <select v-model=\"row.type\" v-show=\"row.key.substr(0, 3) == 'cf/'\" class=\"qb-type\">\n <option value=\"CHAR\">TEXT</option>\n <option value=\"NUMERIC\">NUMERIC</option>\n </select>\n <select v-model=\"row.order\" class=\"qb-order\">\n <option value=\"ASC\">ASC</option>\n <option value=\"DESC\">DESC</option>\n </select>\n <span @click=\"deleteSortCriteria(index)\" class=\"qb-remove\" v-html=\"FWP.svg['minus-circle']\"></span>\n </div>\n\n <div class=\"qb-condition\"\n v-show=\"query_obj.filters.length\">\n {{ 'Narrow results by' | i18n }}\n </div>\n\n <div v-for=\"(row, index) in query_obj.filters\" class=\"qb-condition\">\n <fselect :row=\"row\">\n <optgroup v-for=\"data in $root.query_data.filter_by\" :label=\"data.label\">\n <option v-for=\"(label, name) in data.choices\" :value=\"name\" v-html=\"label\"></option>\n </optgroup>\n </fselect>\n\n <select v-model=\"row.type\" v-show=\"row.key.substr(0, 3) == 'cf/'\" class=\"qb-type\">\n <option value=\"CHAR\">TEXT</option>\n <option value=\"NUMERIC\">NUMERIC</option>\n <option value=\"DATE\">DATE</option>\n </select>\n\n <select v-model=\"row.compare\" class=\"qb-compare\">\n <option v-if=\"showCompare('=', row)\" value=\"=\">=</option>\n <option v-if=\"showCompare('!=', row)\" value=\"!=\">!=</option>\n <option v-if=\"showCompare('>', row)\" value=\">\">></option>\n <option v-if=\"showCompare('>=', row)\" value=\">=\">>=</option>\n <option v-if=\"showCompare('<', row)\" value=\"<\"><</option>\n <option v-if=\"showCompare('<=', row)\" value=\"<=\"><=</option>\n <option v-if=\"showCompare('IN', row)\" value=\"IN\">IN</option>\n <option v-if=\"showCompare('NOT IN', row)\" value=\"NOT IN\">NOT IN</option>\n <option v-if=\"showCompare('EXISTS', row)\" value=\"EXISTS\">EXISTS</option>\n <option v-if=\"showCompare('NOT EXISTS', row)\" value=\"NOT EXISTS\">NOT EXISTS</option>\n </select>\n\n <v-select\n v-model=\"row.value\"\n v-show=\"row.compare != 'EXISTS' && row.compare != 'NOT EXISTS'\"\n :options=\"[]\"\n :multiple=\"true\"\n :taggable=\"true\"\n :close-on-select=\"false\"\n :placeholder=\"getPlaceholder(row)\">\n </v-select>\n\n <span @click=\"deleteFilterCriteria(index)\" class=\"qb-remove\" v-html=\"FWP.svg['minus-circle']\"></span>\n </div>\n\n <div class=\"qb-add\">\n <button class=\"button\" @click=\"addSortCriteria\">{{ 'Add sort' | i18n }}</button>\n <button class=\"button\" @click=\"addFilterCriteria\">{{ 'Add filter' | i18n }}</button>\n </div>\n </div>\n ", methods: { addTag: function addTag(newTag, value) { value.push(newTag); }, getPlaceholder: function getPlaceholder(ref) { var key = ref.key; return ('tax/' == key.substr(0, 4)) ? FWP.__('Enter term slugs') : FWP.__('Enter values'); }, showCompare: function showCompare(option, ref) { var key = ref.key; var type = ref.type; if ('tax/' == key.substr(0, 4)) { if (!['IN', 'NOT IN', 'EXISTS', 'NOT EXISTS'].includes(option)) { return false; } } else if (['ID', 'post_author', 'post_status', 'post_name'].includes(key)) { if (option != 'IN' && option != 'NOT IN') { return false; } } else if ('DATE' == type || 'post_date' == key || 'post_modified' == key) { if (!['>', '>=', '<', '<='].includes(option)) { return false; } } else if ('CHAR' == type) { if (['>', '>=', '<', '<='].includes(option)) { return false; } } return true; }, addSortCriteria: function addSortCriteria() { this.query_obj.orderby.push({ key: 'title', order: 'ASC', type: 'CHAR' }); }, addFilterCriteria: function addFilterCriteria() { this.query_obj.filters.push({ key: 'ID', value: [], compare: 'IN', type: 'CHAR' }); }, deleteSortCriteria: function deleteSortCriteria(index) { Vue.delete(this.query_obj.orderby, index); }, deleteFilterCriteria: function deleteFilterCriteria(index) { Vue.delete(this.query_obj.filters, index); } } }); Vue.component('fselect', { props: ['row'], template: "\n <select :id=\"rand\" v-model=\"row.key\" class=\"qb-object\">\n <slot></slot>\n </select>\n ", methods: { fSelectChanged: function fSelectChanged(event, $wrap) { // only update this current instance if (0 < $($wrap).find('#' + this.rand).length) { this.row.key = this.$el.value; } } }, created: function created() { // create a random ID for each fSelect instance this.rand = 'fs-' + Math.random().toString(36).substring(7); }, mounted: function mounted() { $(this.$el).fSelect(); $(document).on('fs:changed', this.fSelectChanged); }, beforeDestroy: function beforeDestroy() { $(document).off('fs:changed', this.fSelectChanged); } }); /* ================ layout builder ================ */ Vue.component('builder', { props: { layout: Object }, template: "\n <div class=\"builder-wrap\">\n <div class=\"builder-canvas-wrap\">\n <div class=\"builder-canvas\">\n <div class=\"builder-edge\"></div>\n <div class=\"builder-edge vertical\"></div>\n <draggable :list=\"layout.items\" handle=\".builder-row-actions.not-child\">\n <builder-row\n v-for=\"(row, index) in layout.items\"\n :row=\"row\"\n :rows=\"layout.items\"\n :index=\"index\"\n :key=\"index\">\n </builder-row>\n </draggable>\n </div>\n <div class=\"builder-intro\">\n In the above canvas, build the layout for an individual result.<br><br>\n Then in <strong>Layout</strong>, choose the number of grid columns.\n </div>\n </div>\n <builder-settings :layout=\"layout\"></builder-settings>\n </div>\n " }); Vue.component('setting-wrap', { mixins: [builder_defaults], props: ['settings', 'name', 'source', 'tab'], template: "\n <div class=\"builder-setting\" v-show=\"isVisible\">\n <div v-html=\"title\"></div>\n <component :is=\"getSettingComponent\" v-bind=\"$props\" :meta=\"meta\"></component>\n </div>\n ", computed: { getSettingComponent: function getSettingComponent() { return 'setting-' + this.type; }, isVisible: function isVisible() { var ret = true; var self = this; if ('undefined' === typeof this.meta.tab) { this.meta.tab = 'content'; } if (this.meta.tab !== this.tab) { ret = false; } else if ('undefined' !== typeof this.meta.v_show) { ret = false; this.meta.v_show.forEach(function (cond, index) { var type = cond.type; var setting_val = ('source' == type) ? self[type] : self.settings[type]; var cond_value = cond.value || ''; var cond_compare = cond.compare || '=='; var is_match = ('==' == cond_compare) ? setting_val == cond_value : setting_val != cond_value; if (is_match) { ret = true; } }); } return ret; } }, created: function created() { this.settings_meta = this.getSettingsMeta(); this.meta = this.settings_meta[this.name]; this.type = this.meta.type; this.title = this.meta.title; } }); Vue.component('setting-text', { props: ['settings', 'name', 'meta'], template: '<input type="text" v-model="settings[name]" :placeholder="meta.placeholder" />' }); Vue.component('setting-number', { props: ['settings', 'name', 'meta'], template: '<input type="number" v-model.number="settings[name]" :placeholder="meta.placeholder" />' }); Vue.component('setting-textarea', { props: ['settings', 'name', 'meta'], template: '<textarea v-model="settings[name]"></textarea>' }); Vue.component('setting-slider', { props: ['settings', 'name', 'meta'], template: "\n <div>\n <input type=\"range\" min=\"0\" max=\"80\" step=\"1\" v-model.number=\"settings[name].size\" />\n <span v-html=\"fontSizeLabel\" style=\"vertical-align:top\"></span>\n </div>\n ", computed: { fontSizeLabel: function fontSizeLabel() { var val = this.settings[this.name]; return (0 === val.size) ? 'none' : val.size + val.unit; } } }); Vue.component('setting-color', { props: ['settings', 'name', 'meta'], template: "\n <div class=\"color-wrap\">\n <div class=\"color-canvas\">\n <span class=\"color-preview\"></span>\n <input type=\"text\" class=\"color-input\" v-model=\"settings[name]\" />\n </div>\n <span class=\"color-clear\">X</span>\n </div>", mounted: function mounted() { var self = this; var $canvas = self.$el.getElementsByClassName('color-canvas')[0]; var $preview = self.$el.getElementsByClassName('color-preview')[0]; var $input = self.$el.getElementsByClassName('color-input')[0]; var $clear = self.$el.getElementsByClassName('color-clear')[0]; $preview.style.backgroundColor = $input.value; var picker = new Picker({ parent: $canvas, popup: 'left', alpha: false, onDone: function onDone(color) { var hex = color.hex().substr(0, 7); self.settings[self.name] = hex; $preview.style.backgroundColor = hex; } }); picker.onOpen = function(color) { picker.setColor($input.value); }; $clear.addEventListener('click', function() { self.settings[self.name] = ''; $preview.style.backgroundColor = ''; }); } }); Vue.component('setting-link', { props: ['settings', 'name', 'meta'], template: "\n <div>\n <setting-select\n :settings=\"settings[name]\"\n name=\"type\"\n :meta=\"meta.children.type\">\n </setting-select>\n\n <div v-show=\"settings[name].type == 'custom'\">\n <input\n type=\"text\"\n v-model=\"settings[name].href\"\n placeholder=\"https://\"\n />\n </div>\n <div v-show=\"settings[name].type != 'none'\">\n <input\n type=\"checkbox\"\n v-model=\"settings[name].target\"\n true-value=\"_blank\"\n false-value=\"\"\n />\n {{ 'Open in new tab?' | i18n }}\n </div>\n </div>\n " }); Vue.component('setting-border', { props: ['settings', 'name', 'meta'], template: "\n <div>\n <setting-select\n :settings=\"settings[name]\"\n name=\"style\"\n :meta=\"meta.children.style\">\n </setting-select>\n\n <div v-show=\"settings[name].style != 'none'\">\n <div v-html=\"meta.children.color.title\" style=\"margin-top:10px\"></div>\n\n <setting-color\n :settings=\"settings[name]\"\n name=\"color\"\n :meta=\"meta.children.color\">\n </setting-color>\n\n <div v-html=\"meta.children.width.title\" style=\"margin-top:10px\"></div>\n\n <setting-utrbl\n :settings=\"settings[name]\"\n name=\"width\"\n :meta=\"meta.children.width\">\n </setting-utrbl>\n </div>\n </div>\n " }); Vue.component('setting-checkbox', { props: ['settings', 'name', 'meta'], template: "\n <div>\n <input type=\"checkbox\" v-model=\"settings[name]\" /> {{ meta.suffix }}\n </div>\n " }); Vue.component('setting-select', { props: ['settings', 'name', 'meta'], template: "\n <select v-model=\"settings[name]\">\n <option v-for=\"(label, value) in meta.choices\" :value=\"value\">{{ label }}</option>\n </select>\n " }); Vue.component('setting-utrbl', { props: ['settings', 'name', 'meta'], template: "\n <div>\n <div class=\"utrbl utrbl-unit\"><input type=\"text\" v-model=\"settings[name].unit\" /><span>unit</span></div>\n <div class=\"utrbl\"><input type=\"number\" v-model.number=\"settings[name].top\" /><span>top</span></div>\n <div class=\"utrbl\"><input type=\"number\" v-model.number=\"settings[name].right\" /><span>right</span></div>\n <div class=\"utrbl\"><input type=\"number\" v-model.number=\"settings[name].bottom\" /><span>bottom</span></div>\n <div class=\"utrbl\"><input type=\"number\" v-model.number=\"settings[name].left\" /><span>left</span></div>\n </div>\n " }); Vue.component('setting-text-style', { props: ['settings', 'name', 'meta'], template: "\n <div class=\"text-style-icons\">\n <span @click=\"toggleChoice('align', 'left')\" :class=\"{ active: isActive('align', 'left') }\" v-html=\"FWP.svg['align-left']\"></span>\n <span @click=\"toggleChoice('align', 'center')\" :class=\"{ active: isActive('align', 'center') }\" v-html=\"FWP.svg['align-center']\"></span>\n <span @click=\"toggleChoice('align', 'right')\" :class=\"{ active: isActive('align', 'right') }\" v-html=\"FWP.svg['align-right']\"></span>\n <span @click=\"toggleChoice('bold')\" :class=\"{ active: isActive('bold') }\" v-html=\"FWP.svg['bold']\"></span>\n <span @click=\"toggleChoice('italic')\" :class=\"{ active: isActive('italic') }\" v-html=\"FWP.svg['italic']\"></span>\n </div>\n ", methods: { toggleChoice: function toggleChoice(opt, val) { var old_val = this.settings[this.name][opt]; if ('undefined' !== typeof val) { this.settings[this.name][opt] = (val !== old_val) ? val : ''; } else { this.settings[this.name][opt] = ! old_val; } }, isActive: function isActive(opt, val) { var new_val = ('undefined' !== typeof val) ? val : true; return this.settings[this.name][opt] === new_val; } } }); Vue.component('builder-settings', { mixins: [builder_defaults], props: { layout: Object }, data: function data() { return { title: '', type: 'layout', settings: this.layout.settings, source: '', active_tab: 'content' } }, template: "\n <div class=\"builder-settings-wrap\">\n <h3>\n <div v-show=\"this.title\" class=\"builder-crumb\">\n <a href=\"javascript:;\" @click=\"$root.$emit('edit-layout')\">{{ 'Layout' | i18n }}</a> »\n </div>\n {{ settingTitle }}\n </h3>\n <div class=\"builder-settings\">\n <div class=\"template-tabs\">\n <span @click=\"setActiveTab('content')\" :class=\"isActiveTab('content')\">{{ 'Content' | i18n }}</span>\n <span @click=\"setActiveTab('style')\" :class=\"isActiveTab('style')\">{{ 'Style' | i18n }}</span>\n </div>\n <setting-wrap\n v-for=\"name in settingsFields\"\n :settings=\"settings\"\n :name=\"name\"\n :source=\"source\"\n :tab=\"active_tab\"\n :key=\"uniqueKey()\">\n </setting-wrap>\n </div>\n </div>\n ", computed: { settingTitle: function settingTitle() { return ('' === this.title) ? FWP.__('Layout') : this.title; }, settingsFields: function settingsFields() { return this.getDefaultFields(this.type, this.source); } }, methods: { uniqueKey: function uniqueKey() { // method to prevent caching return Math.floor(Math.random() * 999999); }, isActiveTab: function isActiveTab(which) { return (this.active_tab === which) ? 'active' : ''; }, setActiveTab: function setActiveTab(which) { this.active_tab = which; } }, created: function created() { var self = this; this.$root.$on('edit-layout', function () { self.title = ''; self.type = 'layout'; self.settings = self.mergeSettings(self.layout.settings, self.type); self.source = ''; }); this.$root.$on('edit-row', function (ref, num) { var settings = ref.settings; self.title = FWP.__('Row') + ' ' + num; self.type = 'row'; self.settings = self.mergeSettings(settings, self.type); self.source = ''; }); this.$root.$on('edit-col', function (ref, num) { var settings = ref.settings; self.title = FWP.__('Column') + ' ' + num; self.type = 'col'; self.settings = self.mergeSettings(settings, self.type); self.source = ''; }); this.$root.$on('edit-item', function (ref) { var source = ref.source; var settings = ref.settings; self.title = self.$root.layout_data[source]; self.type = 'item'; self.settings = self.mergeSettings(settings, self.type, source); self.source = source; }); } }); Vue.component('builder-row', { mixins: [builder_defaults], props: { row: Object, rows: Array, index: Number, is_child: Boolean }, template: "\n <div class=\"builder-row\">\n <div class=\"builder-row-actions\" :class=\"classIsChild\">\n <span @click=\"editRow\" title=\"Edit row\" v-html=\"FWP.svg['cog']\"></span>\n <span @click=\"addCol\" title=\"Add columm\" v-html=\"FWP.svg['columns']\"></span>\n <span @click=\"addRow\" title=\"Add row\" v-html=\"FWP.svg['plus']\"></span>\n <span @click=\"deleteRow\" title=\"Delete row\" v-html=\"FWP.svg['times']\"></span>\n </div>\n <div class=\"builder-row-inner\" :style=\"{ gridTemplateColumns: row.settings.grid_template_columns }\">\n <builder-col\n v-for=\"(col, index) in row.items\"\n :col=\"col\"\n :cols=\"row.items\"\n :index=\"index\"\n :key=\"index\">\n </builder-col>\n </div>\n </div>\n ", computed: { classIsChild: function classIsChild() { return this.is_child ? 'is-child' : 'not-child'; } }, methods: { addRow: function addRow() { this.rows.splice(this.index + 1, 0, this.defaultRow()); if (1 < this.rows.length) { this.$root.$emit('edit-row', this.rows[this.index + 1], this.index + 2); } else { this.$root.$emit('edit-layout'); } }, addCol: function addCol() { var len = this.row.items.push(this.defaultCol()); this.$root.$emit('edit-col', this.row.items[len - 1], len); var grid_str = '1fr '.repeat(this.row.items.length).trim(); this.row.settings.grid_template_columns = grid_str; }, editRow: function editRow() { this.$root.$emit('edit-row', this.row, this.index + 1); }, deleteRow: function deleteRow() { Vue.delete(this.rows, this.index); this.$root.$emit('edit-layout'); // Add default row if (this.rows.length < 1) { if (! this.is_child) { this.addRow(); } } } } }); Vue.component('builder-col', { mixins: [builder_defaults, VueClickaway.mixin], props: { col: Object, cols: Array, index: Number }, data: function data() { return { adding_item: false } }, template: "\n <div class=\"builder-col\">\n <col-resizer :cols=\"cols\" :index=\"index\" v-show=\"index < (cols.length - 1)\"></col-resizer>\n <popover :col=\"col\" v-if=\"adding_item\" v-on-clickaway=\"away\"></popover>\n <div class=\"builder-col-actions\">\n <span @click=\"editCol\" title=\"Edit columm\" v-html=\"FWP.svg['cog']\"></span>\n <span @click=\"deleteCol\" title=\"Delete column\" v-html=\"FWP.svg['times']\"></span>\n </div>\n <div class=\"builder-col-inner\" :class=\"[ !col.items.length ? 'empty-col' : '' ]\">\n <draggable v-model=\"col.items\" handle=\".item-drag\" group=\"drag-across-columns\" class=\"draggable\">\n <div v-for=\"(item, index) in col.items\" :key=\"index\">\n <builder-item\n v-if=\"item.type != 'row'\"\n :item=\"item\"\n :items=\"col.items\"\n :index=\"index\">\n </builder-item>\n <builder-row\n v-if=\"item.type == 'row'\"\n :row=\"item\"\n :rows=\"col.items\"\n :index=\"index\"\n :is_child=\"true\">\n </builder-row>\n </div>\n <div class=\"builder-empty-view\" @click=\"addItem\">\n <div class=\"builder-first-add\">+</div>\n </div>\n </draggable>\n </div>\n </div>\n ", methods: { addItem: function addItem() { this.adding_item = ! this.adding_item; }, editCol: function editCol() { this.$root.$emit('edit-col', this.col, this.index + 1); this.adding_item = false; }, deleteCol: function deleteCol() { // Remove the column this.cols.splice(this.index, 1); // Show the "Layout" settings this.$root.$emit('edit-layout'); // Add default column if (this.cols.length < 1) { this.cols.push(this.defaultCol()); } // Adjust the row's `grid_template_columns` string var grid_str = '1fr '.repeat(this.cols.length).trim(); this.$parent.row.settings.grid_template_columns = grid_str; }, away: function away() { this.adding_item = false; } } }); Vue.component('col-resizer', { props: { cols: Array, index: Number }, data: function data() { return { isResizing: false }; }, template: '<div :class="classNames" @mousedown="onMouseDown"></div>', computed: { classNames: function classNames() { return [ 'resizer', this.isResizing ? 'is-resizing' : '' ]; } }, methods: { onMouseDown: function onMouseDown(ref) { var this$1 = this; var resizer = ref.target; var initialPageX = ref.pageX; var initialPageY = ref.pageY; if (! resizer.classList.contains('resizer')) { return; } var self = this; var pane = resizer.parentElement; var row_inner = pane.parentElement; var initialPaneWidth = pane.offsetWidth; var resize = function (initialSize, offset) { if ( offset === void 0 ) offset = 0; var containerWidth = row_inner.clientWidth; var paneWidth = initialSize + offset; var width = ((paneWidth / containerWidth) * 100).toFixed(1) + '%'; var gridColumns = this$1.$parent.$parent.row.settings.grid_template_columns.split(' '); gridColumns[this$1.index] = width; this$1.$parent.$parent.row.settings.grid_template_columns = gridColumns.join(' '); }; // This adds is-resizing class to container self.isResizing = true; var onMouseMove = function (ref) { var pageX = ref.pageX; var pageY = ref.pageY; resize(initialPaneWidth, pageX - initialPageX); }; var onMouseUp = function () { // Run resize one more time to set computed width/height. resize(pane.clientWidth); // This removes is-resizing class to container self.isResizing = false; window.removeEventListener('mousemove', onMouseMove); window.removeEventListener('mouseup', onMouseUp); }; window.addEventListener('mousemove', onMouseMove); window.addEventListener('mouseup', onMouseUp); } } }); Vue.component('builder-item', { props: { item: Object, items: Array, index: Number }, template: "\n <div class=\"builder-item\">\n <div class=\"builder-item-actions\">\n <span @click=\"deleteItem\" title=\"Delete item\" v-html=\"FWP.svg['times']\"></span>\n </div>\n <div class=\"builder-item-inner\" @click=\"editItem\" :class=\"[ item.settings.is_hidden ? 'is-hidden' : '' ]\">\n <span class=\"item-drag\" v-html=\"$root.layout_data[item.source]\"></span>\n <span v-if=\"item.settings.is_hidden\" v-html=\"FWP.svg['eye-slash']\"></span>\n </div>\n </div>\n ", methods: { editItem: function editItem() { this.$root.$emit('edit-item', this.item); }, deleteItem: function deleteItem() { this.items.splice(this.index, 1); this.$root.$emit('edit-layout'); } } }); Vue.component('popover', { mixins: [builder_defaults], props: { col: Object }, data: function data() { return { keywords: '' } }, template: "\n <div class=\"popover\">\n <div class=\"popover-search\">\n <input\n type=\"text\"\n ref=\"keywords\"\n placeholder=\"Start typing\"\n v-model=\"keywords\"\n />\n </div>\n <div class=\"popover-choices\">\n <div\n @click=\"saveItem(source)\"\n v-for=\"(label, source) in $root.layout_data\"\n v-show=\"isMatch(label)\"\n v-html=\"label\">\n </div>\n </div>\n </div>\n ", methods: { isMatch: function isMatch(label) { var bool = ('' == this.keywords) ? true : false; if (false === bool) { var needle = this.keywords.toLowerCase(); var haystack = label.toLowerCase(); if (haystack.includes(needle)) { bool = true; } } return bool; }, saveItem: function saveItem(source) { if ('row' == source) { var len = this.col.items.push(this.defaultRow()); this.$root.$emit('edit-row', this.col.items[len - 1], len); } else { var len$1 = this.col.items.push(this.defaultItem(source)); this.$root.$emit('edit-item', this.col.items[len$1 - 1]); } this.$parent.adding_item = false; } }, mounted: function mounted() { this.$refs.keywords.focus(); } }); /* ================ facets / templates ================ */ Vue.component('facets', { props: ['facets'], template: "\n <draggable class=\"facetwp-cards\" v-model=\"$root.app.facets\" handle=\".card-drag\">\n <div\n class=\"facetwp-card\"\n v-for=\"(facet, index) in facets\"\n @click=\"$root.editItem('facet', facet)\"\n >\n <div class=\"card-drag\">☰</div>\n <div class=\"card-label\">\n <span class=\"label-text\" :title=\"facet.name\">{{ facet.label }}</span>\n <span v-if=\"facet._code\" v-html=\"FWP.svg['lock']\"></span>\n </div>\n <div class=\"card-delete\" @click.stop=\"$root.deleteItem('facet', index)\"></div>\n <div class=\"card-type\">{{ facet.type }}</div>\n <div class=\"card-source\" v-html=\"getSource(facet.source)\"></div>\n <div class=\"card-rows\">{{ getRowCount(facet.name) }}</div>\n </div>\n </draggable>\n ", methods: { getSource: function getSource(source) { return FWP.layout_data[source] || '-'; }, getRowCount: function getRowCount(facet_name) { if (this.$root.is_indexing) { return '...'; } return this.$root.row_counts[facet_name] || '-'; } } }); Vue.component('templates', { props: ['templates'], template: "\n <draggable class=\"facetwp-cards\" v-model=\"$root.app.templates\" handle=\".card-drag\">\n <div\n class=\"facetwp-card\"\n v-for=\"(template, index) in templates\"\n @click=\"$root.editItem('template', template)\"\n >\n <div class=\"card-drag\">☰</div>\n <div class=\"card-label\">\n <span class=\"label-text\" :title=\"template.name\">{{ template.label }}</span>\n <span v-if=\"template._code\" v-html=\"FWP.svg['lock']\"></span>\n </div>\n <div class=\"card-delete\" @click.stop=\"$root.deleteItem('template', index)\"></div>\n <div class=\"card-display-mode\">{{ getDisplayMode(index) }}</div>\n <div class=\"card-post-types\">{{ getPostTypes(index) }}</div>\n </div>\n </draggable>\n ", methods: { getDisplayMode: function getDisplayMode(index) { var template = this.templates[index]; return ('undefined' !== typeof template.modes) ? template.modes.display : 'advanced'; }, getPostTypes: function getPostTypes(index) { var template = this.templates[index]; if ('undefined' !== typeof template.modes) { if ('visual' == template.modes.query) { var post_types = template.query_obj.post_type; if (0 === post_types.length) { return '<any>'; } else { return post_types.map(function (type) { return type.label; }).join(', '); } } } return '<raw query>'; } } }); Vue.component('facet-edit', { data: function data() { return { facet: {} }; }, created: function created() { this.facet = this.$root.editing; }, methods: { setName: function setName(e) { this.facet.name = this.$root.sanitizeName(e.target.innerHTML); }, unlock: function unlock() { Vue.delete(this.facet, '_code'); } }, template: "\n <div>\n <div class=\"item-locked\" v-if=\"facet._code\">\n This facet is registered in code. Click to allow edits:\n <span @click=\"unlock\" v-html=\"FWP.svg['lock-open']\"></span>\n </div>\n <div class=\"facetwp-content\" :class=\"[ 'type-' + facet.type, { locked: facet._code } ]\">\n <div class=\"facetwp-row\">\n <div>{{ 'Label' | i18n }}:</div>\n <div>\n <input\n type=\"text\"\n v-model=\"facet.label\"\n @focus=\"$root.isNameEditable(facet)\"\n @keyup=\"$root.maybeEditName(facet)\"\n />\n <code class=\"item-name\" contenteditable v-text=\"facet.name\" @blur=\"setName\" @keydown.enter.prevent autocorrect=\"off\"></code>\n <span class=\"facetwp-btn\" @click=\"$root.copyToClipboard(facet.name, 'facet', $event)\">\n {{ 'Copy shortcode' | i18n }}\n </span>\n </div>\n </div>\n <div class=\"facetwp-row\">\n <div>{{ 'Facet type' | i18n }}:</div>\n <div>\n <facet-types\n :facet=\"facet\"\n :selected=\"facet.type\"\n :types=\"$root.facet_types\">\n </facet-types>\n </div>\n </div>\n <div class=\"facetwp-row field-data-source\">\n <div>{{ 'Data source' | i18n }}:</div>\n <div>\n <data-sources\n :facet=\"facet\"\n :selected=\"facet.source\"\n :sources=\"$root.data_sources\">\n </data-sources>\n </div>\n </div>\n <hr />\n <facet-settings :facet=\"facet\"></facet-settings>\n </div>\n </div>\n " }); Vue.component('template-edit', { mixins: [builder_defaults], data: function data() { return { template: {}, tab: 'display' }; }, created: function created() { this.template = this.$root.editing; // Set defaults for the layout builder if (! this.template.layout) { Vue.set(this.template, 'layout', this.defaultLayout()); } // Set defaults for the query builder if (! this.template.query_obj) { Vue.set(this.template, 'query_obj', { post_type: [], posts_per_page: 10, orderby: [], filters: [] }); } // Set the modes if (! this.template.modes) { Vue.set(this.template, 'modes', { display: ('' !== this.template.template) ? 'advanced' : 'visual', query: ('' !== this.template.query) ? 'advanced' : 'visual' }); } }, methods: { setName: function setName(e) { this.template.name = this.$root.sanitizeName(e.target.innerHTML); }, isMode: function isMode(mode) { return this.template.modes[this.tab] === mode; }, switchMode: function switchMode() { var now = this.template.modes[this.tab]; this.template.modes[this.tab] = ('visual' === now) ? 'advanced' : 'visual'; }, unlock: function unlock() { Vue.delete(this.template, '_code'); } }, template: "\n <div>\n <div class=\"item-locked\" v-if=\"template._code\">\n This template is registered in code. Click to allow edits:\n <span @click=\"unlock\" v-html=\"FWP.svg['lock-open']\"></span>\n </div>\n <div class=\"facetwp-content\" :class=\"{ locked: template._code }\">\n <div class=\"table-row\">\n <input\n type=\"text\"\n v-model=\"template.label\"\n @focus=\"$root.isNameEditable(template)\"\n @keyup=\"$root.maybeEditName(template)\"\n />\n <code class=\"item-name\" contenteditable v-text=\"template.name\" @blur=\"setName\" @keydown.enter.prevent autocorrect=\"off\"></code>\n <span class=\"facetwp-btn\" @click=\"$root.copyToClipboard(template.name, 'template', $event)\">\n {{ 'Copy shortcode' | i18n }}\n </span>\n </div>\n\n <div @click=\"switchMode()\" v-show=\"isMode('visual')\" class=\"side-link\">{{ 'Switch to advanced mode' | i18n }}</div>\n <div @click=\"switchMode()\" v-show=\"isMode('advanced')\" class=\"side-link\">{{ 'Switch to visual mode' | i18n }}</div>\n\n <div class=\"template-tabs top-level\">\n <span @click=\"tab = 'display'\" :class=\"{ active: tab == 'display' }\">{{ 'Display' | i18n }}</span>\n <span @click=\"tab = 'query'\" :class=\"{ active: tab == 'query' }\">{{ 'Query' | i18n }}</span>\n </div>\n\n <div v-show=\"tab == 'display'\">\n <div class=\"table-row\" v-show=\"template.modes.display == 'visual'\">\n <builder :layout=\"template.layout\"></builder>\n </div>\n <div class=\"table-row\" v-show=\"template.modes.display == 'advanced'\">\n <div class=\"side-link\">\n <a href=\"https://facetwp.com/documentation/templates/advanced-mode/\" target=\"_blank\">{{ 'Help' | i18n }}</a>\n </div>\n <div class=\"row-label\">{{ 'Display Code' | i18n }}</div>\n <textarea v-model=\"template.template\"></textarea>\n </div>\n </div>\n\n <div v-show=\"tab == 'query'\">\n <div class=\"table-row\" v-show=\"template.modes.query == 'visual'\">\n <query-builder :query_obj=\"template.query_obj\" :template=\"template\"></query-builder>\n </div>\n <div class=\"table-row\" v-show=\"template.modes.query == 'advanced'\">\n <div class=\"side-link\">\n <a href=\"https://facetwp.com/documentation/templates/advanced-mode/\" target=\"_blank\">{{ 'Help' | i18n }}</a>\n </div>\n <div class=\"row-label\">{{ 'Query Arguments' | i18n }}</div>\n <textarea v-model=\"template.query\"></textarea>\n </div>\n </div>\n </div>\n </div>\n " }); Vue.component('facet-types', { props: ['facet', 'selected', 'types'], template: "\n <select v-model=\"facet.type\">\n <option v-for=\"(type, key) in types\" :value=\"key\" :selected=\"selected == key\">{{ type.label }}</option>\n </select>\n " }); Vue.component('facet-settings', { props: ['facet'], data: function data() { return { original_facet_type: '' }; }, template: "\n <div class=\"facet-fields\">\n <component :is=\"dynComponent\" v-bind=\"$props\"></component>\n </div>\n ", computed: { tableToDivs: function tableToDivs() { var this$1 = this; var self = this; var html = this.$root.clone[this.facet.type]; var custom_settings = ['_code']; // Backwards compatibility html = html.replace(/<tr>/g, '<div class="facetwp-row">'); html = html.replace(/<td>/g, '<div class="facetwp-col">'); html = html.replace(/<\/td>/g, '</div>'); html = html.replace(/<\/tr>/g, '</div>'); // Remove default keys var keys = Object.keys(this.facet).filter(function (key) { return !['label', 'name', 'type', 'source', 'source_other'].includes(key); }); // Add setting names by parsing the DOM $(html).find('input, textarea, select').each(function() { var $el = $(this); var setting_name = $el.attr('class').split(' ')[0].replace(/-/g, '_').substr(6); custom_settings.push(setting_name); var is_new_type = (self.facet.type !== self.original_facet_type); var is_new_setting = (!keys.includes(setting_name)); if (is_new_type || is_new_setting) { var val = $el.val(); if ($el.is(':checkbox')) { val = $el.is(':checked') ? 'yes' : 'no'; } if ('[]' === val) { val = []; } Vue.set(self.facet, setting_name, val); } if (is_new_setting) { keys.push(setting_name); } }); keys.forEach(function (key) { // Delete orphan settings if (!custom_settings.includes(key)) { Vue.delete(this$1.facet, key); } // Dynamically add v-models var key_dashed = key.replace(/_/g, '-'); var pattern = new RegExp('(class="facet-' + key_dashed + '")', 'gm'); var replacement = '$1 v-model="facet.' + key + '"'; html = html.replace(pattern, replacement); }); return html; }, // use a dynamic component so the data bindings (e.g. v-model) get compiled dynComponent: function dynComponent() { return { template: '<div>' + this.tableToDivs + '</div>', props: this.$options.props } } }, created: function created() { this.original_facet_type = this.facet.type; }, watch: { 'facet.type': function(val) { if ('search' == val || 'pager' == val) { this.facet.source = ''; } this.facet.source_other = ''; }, 'facet.ghosts': function(val) { if ('no' == val) { this.facet.preserve_ghosts = 'no'; } }, 'facet.hierarchical': function(val) { if ('no' == val) { this.facet.show_expanded = 'no'; } } } }); Vue.component('data-sources', { props: { facet: Object, selected: String, sources: Object, settingName: { type: String, default: 'source' } }, template: "\n <select :id=\"rand\" v-model=\"dataSourcesModel\">\n <option v-if=\"settingName != 'source'\" value=\"\">{{ 'None' | i18n }}</option>\n <optgroup v-for=\"optgroup in sources\" :label=\"optgroup.label\">\n <option v-for=\"(label, key) in optgroup.choices\" :value=\"key\" :selected=\"selected == key\">{{ label }}</option>\n </optgroup>\n </select>\n ", methods: { fSelectChanged: function fSelectChanged(event, $wrap) { // only update this current instance if (0 < $($wrap).find('#' + this.rand).length) { this.facet[this.settingName] = this.$el.value; } } }, computed: { dataSourcesModel: function dataSourcesModel() { // create the setting if needed if ('undefined' === typeof this.facet[this.settingName]) { Vue.set(this.facet, this.settingName, ''); } return this.facet[this.settingName]; } }, created: function created() { // create a random ID for each fSelect instance this.rand = 'fs-' + Math.random().toString(36).substring(7); }, mounted: function mounted() { $(this.$el).fSelect(); $(document).on('fs:changed', this.fSelectChanged); }, beforeDestroy: function beforeDestroy() { $(document).off('fs:changed', this.fSelectChanged); } }); // Vue instance FWP.vue = new Vue({ el: '#app', data: { app: FWP.data, editing: {}, editing_facet: false, editing_template: false, row_counts: {}, facet_types: FWP.facet_types, data_sources: FWP.data_sources, layout_data: FWP.layout_data, query_data: FWP.query_data, support_html: FWP.support_html, clone: FWP.clone, active_tab: 'facets', active_subnav: 'general', is_support_loaded: false, is_name_editable: false, is_rebuild_open: false, is_indexing: false, timeout: null }, methods: { addItem: function addItem(type) { if ('facet' == type) { var index = this.app.facets.push({ 'name': 'new_facet', 'label': 'New Facet', 'type': 'checkboxes', 'source': 'post_type' }); this.editItem('facet', this.app.facets[index-1]); } else { var index = this.app.templates.push({ 'name': 'new_template', 'label': 'New Template', 'query': '', 'template': '' }); this.editItem('template', this.app.templates[index-1]); } }, editItem: function editItem(type, data) { this['editing_' + type] = true; this.editing = data; window.scrollTo(0, 0); }, doneEditing: function doneEditing() { this.editing_template = false; this.editing_facet = false; this.editing = {}; }, tabClick: function tabClick(which) { this.doneEditing(); this.active_tab = which; if ('support' === which) { this.is_support_loaded = true; } }, getItemLabel: function getItemLabel() { return this.editing.label; }, deleteItem: function deleteItem(type, index) { if (confirm(FWP.__('Delete item?'))) { this.app[type + 's'].splice(index, 1); } }, saveChanges: function saveChanges() { $('.facetwp-response').html(FWP.__('Saving') + '...'); $('.facetwp-response').addClass('visible'); var data = JSON.parse(JSON.stringify(FWP.data)); // Remove code-based facets and templates data.facets = data.facets.filter(function (obj) { return 'undefined' === typeof obj['_code']; }); data.templates = data.templates.filter(function (obj) { return 'undefined' === typeof obj['_code']; }); // Settings save hook data = FWP.hooks.applyFilters('facetwp/save_settings', data); $.ajax(ajaxurl, { method: 'POST', dataType: 'json', data: { action: 'facetwp_save_settings', nonce: FWP.nonce, data: JSON.stringify(data) } }).done(function (ref) { var message = ref.message; var reindex = ref.reindex; $('.facetwp-response').html(message); $('.facetwp-rebuild').toggleClass('flux', reindex); }).fail(function (ref, textStatus, errorThrown) { var status = ref.status; $('.facetwp-response').html(status + ' ' + errorThrown); }); }, rebuildAction: function rebuildAction() { this.is_indexing ? this.cancelReindex() : this.rebuildIndex(); }, rebuildIndex: function rebuildIndex() { var self = this; $('.facetwp-rebuild').removeClass('flux'); if (this.is_indexing) { return; } this.is_indexing = true; $.post(ajaxurl, { action: 'facetwp_rebuild_index', nonce: FWP.nonce }); $('.facetwp-response').html(FWP.__('Indexing') + '... 0%'); $('.facetwp-response').addClass('visible'); this.timeout = setTimeout(function () { self.getProgress(); }, 5000); }, cancelReindex: function cancelReindex() { var self = this; $.ajax(ajaxurl, { method: 'POST', dataType: 'json', data: { action: 'facetwp_get_info', type: 'cancel_reindex', nonce: FWP.nonce } }).done(function (ref) { var message = ref.message; self.is_indexing = false; clearTimeout(self.timeout); $('.facetwp-response').html(message); }).fail(function (ref, textStatus, errorThrown) { var status = ref.status; $('.facetwp-response').html(status + ' ' + errorThrown); }); }, getProgress: function getProgress() { var self = this; $.ajax(ajaxurl, { method: 'POST', dataType: 'json', data: { action: 'facetwp_heartbeat', nonce: FWP.nonce } }).done(function(data) { if ('-1' == data.pct) { $('.facetwp-response').html(FWP.__('Indexing complete')); self.is_indexing = false; // Update the row counts $.each(data.rows, function(facet_name, count) { Vue.set(self.row_counts, facet_name, count); }); } else if ($.isNumeric(data.pct)) { $('.facetwp-response').html(FWP.__('Indexing') + '... ' + data.pct + '%'); $('.facetwp-response').addClass('visible'); self.is_indexing = true; self.timeout = setTimeout(function () { self.getProgress(); }, 5000); } else { $('.facetwp-response').html(data); self.is_indexing = false; } }); }, getInfo: function getInfo(type, label) { $('.facetwp-response').html(FWP.__(label) + '...'); $('.facetwp-response').addClass('visible'); $.ajax(ajaxurl, { method: 'POST', dataType: 'json', data: { action: 'facetwp_get_info', type: type, nonce: FWP.nonce } }).done(function (ref) { var message = ref.message; $('.facetwp-response').html(message); }).fail(function (ref, textStatus, errorThrown) { var status = ref.status; $('.facetwp-response').html(status + ' ' + errorThrown); }); }, getQueryArgs: function getQueryArgs(template) { template.modes.query = 'advanced'; template.query = FWP.__('Loading') + '...'; $.post(ajaxurl, { action: 'facetwp_get_query_args', query_obj: template.query_obj, nonce: FWP.nonce }, function (message) { var json = JSON.stringify(message, null, 2); json = "<?php\nreturn " + json + ';'; json = json.replace(/[\{]/g, '['); json = json.replace(/[\}]/g, ']'); json = json.replace(/":/g, '" =>'); template.query = json; }, 'json'); }, showIndexerStats: function showIndexerStats() { this.getInfo('indexer_stats', 'Looking'); }, searchablePostTypes: function searchablePostTypes() { this.getInfo('post_types', 'Looking'); }, purgeIndexTable: function purgeIndexTable() { this.getInfo('purge_index_table', 'Purging'); }, copyToClipboard: function copyToClipboard(name, type, ref) { var target = ref.target; var $this = $(target); var $el = $('.facetwp-clipboard'); var orig_text = $this.text(); try { $el.removeClass('hidden'); $el.val('[facetwp ' + type + '="' + name + '"]'); $el.select(); document.execCommand('copy'); $el.addClass('hidden'); $this.text(FWP.__('Copied!')); } catch(err) { $this.text(FWP.__('Press CTRL+C to copy')); } window.setTimeout(function () { $this.text(orig_text); }, 2000); }, activate: function activate() { $('.facetwp-activation-status').html(FWP.__('Activating') + '...'); $.post(ajaxurl, { action: 'facetwp_license', nonce: FWP.nonce, license: $('.facetwp-license').val() }, function (ref) { var message = ref.message; $('.facetwp-activation-status').html(message); }, 'json'); }, isNameEditable: function isNameEditable(ref) { var name = ref.name; this.is_name_editable = ('' == name || 'new_' == name.substr(0, 4)); }, maybeEditName: function maybeEditName(item) { if (this.is_name_editable) { item.name = this.sanitizeName(item.label); } }, sanitizeName: function sanitizeName(name) { var val = $.trim(name).toLowerCase(); val = val.replace(/[^\w- ]/g, ''); // strip invalid characters val = val.replace(/[- ]/g, '_'); // replace space and hyphen with underscore val = val.replace(/[_]{2,}/g, '_'); // strip consecutive underscores val = ('pager' == val) ? val + '_' : val; // reserved return val; }, documentClick: function documentClick(ref) { var target = ref.target; var el = target; if (! el.classList.contains('btn-caret')) { this.is_rebuild_open = false; } } }, computed: { isEditing: function isEditing() { return this.editing_facet || this.editing_template; }, indexButtonLabel: function indexButtonLabel() { return this.is_indexing ? FWP.__('Stop indexer') : FWP.__('Re-index'); } }, created: function created() { document.addEventListener('click', this.documentClick); }, mounted: function mounted() { this.getProgress(); } }); } function init_jquery() { // Export $(document).on('click', '.export-submit', function () { $('.import-code').val(FWP.__('Loading') + '...'); $.post(ajaxurl, { action: 'facetwp_backup', nonce: FWP.nonce, action_type: 'export', items: $('.export-items').val() }, function (response) { $('.import-code').val(response); }); }); // Import $(document).on('click', '.import-submit', function () { $('.facetwp-response').addClass('visible'); $('.facetwp-response').html(FWP.__('Importing') + '...'); $.post(ajaxurl, { action: 'facetwp_backup', nonce: FWP.nonce, action_type: 'import', import_code: $('.import-code').val(), overwrite: $('.import-overwrite').is(':checked') ? 1 : 0 }, function (response) { $('.facetwp-response').html(response); setTimeout(function () { window.location.reload(); }, 1500); }); }); // Tooltips $(document).on('mouseover', '.facetwp-tooltip', function() { if ('undefined' === typeof $(this).data('powertip')) { var content = $(this).find('.facetwp-tooltip-content').html(); $(this).data('powertip', content); $(this).powerTip({ placement: 'e', mouseOnToPopup: true }); $.powerTip.show(this); } }); $(document).on('mouseover', '.card-label .label-text', function() { if ('undefined' === typeof $(this).data('powertip')) { $(this).powerTip({ placement: 'e' }); $.powerTip.show(this); } }); // fSelect $('.export-items').fSelect(); } }))(jQuery); }());
[+]
..
[-] front.min.js
[edit]
[-] admin.min.js
[edit]