├── .gitignore
├── README.md
├── assets
├── css
│ ├── wpjsfsp-admin.css
│ ├── wpjsfsp-admin.css.map
│ └── wpjsfsp-admin.min.css
├── images
│ ├── ahoy1.png
│ └── ahoy2.png
├── js
│ ├── src
│ │ └── admin
│ │ │ ├── general.js
│ │ │ ├── plugins
│ │ │ ├── colorpicker.js
│ │ │ ├── conditions.js
│ │ │ ├── forms.js
│ │ │ ├── js-wp-editor.js
│ │ │ ├── links.js
│ │ │ ├── modals.js
│ │ │ ├── models.js
│ │ │ ├── rangesliders.js
│ │ │ ├── select2.js
│ │ │ ├── selectors.js
│ │ │ ├── serialize-object.js
│ │ │ ├── settings.js
│ │ │ ├── tabs.js
│ │ │ ├── templates.js
│ │ │ └── utils.js
│ │ │ └── vendor
│ │ │ └── select2.full.custom.js
│ ├── wpjsfsp-admin.js
│ └── wpjsfsp-admin.min.js
└── sass
│ ├── admin.scss
│ ├── modules
│ ├── _fields.scss
│ ├── _general.scss
│ ├── _modal.scss
│ ├── _select2.scss
│ └── _tabs.scss
│ ├── partials
│ └── admin
│ │ └── _settings.scss
│ └── vendor
│ └── select2
│ ├── _dropdown.scss
│ ├── _multiple.scss
│ ├── _single.scss
│ ├── core.scss
│ ├── mixins
│ └── _gradients.scss
│ └── theme
│ ├── classic
│ ├── _defaults.scss
│ ├── _multiple.scss
│ ├── _single.scss
│ └── layout.scss
│ └── default
│ ├── _multiple.scss
│ ├── _single.scss
│ └── layout.scss
├── classes
├── Admin.php
├── Admin
│ ├── Ajax.php
│ ├── Assets.php
│ ├── Footer_Templates.php
│ └── Settings.php
├── Conditions.php
├── Helpers.php
└── Options.php
├── gulpfile.js
├── includes
├── compat.php
└── options.php
├── index.php
├── languages
└── wpjsfsp.pot
├── package.json
├── readme.txt
├── screenshots
├── 1.png
├── 2.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── 8.png
└── 9.png
└── wp-js-form-sample-plugin.php
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | release
3 | build
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | Having built many interfaces in WordPress over the past 7 years I recently built this as a quick start to any project when admin forms are needed. It is built mostly in JavaScript but fields are easily passed from PHP as in this example. Features are too many to name but include:
4 |
5 | - Easy form / settings management. Add fields with a few extra lines in an array.
6 | - If you already manage fields in an array (EDD, Popup Maker) you can easily port to this new rendering method.
7 | - Lots of powerful custom fields including post type search fields, link pickers, license keys, color pickers, rangesliders and even a boolean based targerting/conditions manager.
8 | - Includes modal forms that also allow tab/subtab combinations (example coming soon). These are generated on the fly from the same types of field arrays as this form.
9 | - Field dependency management, inline documentation and great default styles mean you spend less time crafting forms and more time creating awesome features.
10 | - Also included is a simple to use Options class for storing and retrieving your settings in single wp_option row. Though this interface can easily be manipulated for post meta boxes as well.
11 |
12 | ## Tabbed Forms
13 |
14 | Besides offering field management, this library offers multiple variations of tabs, subtabs and sections to organize your forms.
15 |
16 | - Tabs and Subtabs can be set as vertical, horizontal or link tabs.
17 | - Styled to match the WordPress Admin interface, but can easily be customized to match your existing setup.
18 | - Forms can be organized with just fields, tabs of fields or tabs of subtabs of fields etc.
19 |
20 |
21 | ## Credits
22 |
23 | This is the culmination of work put in over the last year to build or rebuild the interfaces of several plugins including:
24 |
25 | - [@daniel_iser](https://twitter.com/daniel_iser)
26 | - Popup Maker
27 | - Ahoy!
--------------------------------------------------------------------------------
/assets/images/ahoy1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/assets/images/ahoy1.png
--------------------------------------------------------------------------------
/assets/images/ahoy2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/assets/images/ahoy2.png
--------------------------------------------------------------------------------
/assets/js/src/admin/general.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | var $document = $(document);
9 |
10 | window.WPJSFSP = window.WPJSFSP || {};
11 | window.WPJSFSP.I10n = wpjsfsp_admin_vars.I10n;
12 |
13 | $.fn.wp_editor = WPJSFSP.wp_editor || {};
14 |
15 | // Kick things off & initialize various modules.
16 | $document
17 | .ready(function () {
18 | $document.trigger('wpjsfsp_init');
19 |
20 | // TODO Can't figure out why this is needed, but it looks stupid otherwise when the first condition field defaults to something other than the placeholder.
21 | $('#wpjsfsp-first-condition')
22 | .val(null)
23 | .trigger('change');
24 | })
25 | .on('keydown', '#message-headline', function (event) {
26 | var keyCode = event.keyCode || event.which;
27 | if (9 === keyCode) {
28 | event.preventDefault();
29 | $('#title').focus();
30 | }
31 | })
32 | .on('keydown', '#title, #message-headline', function (event) {
33 | var keyCode = event.keyCode || event.which,
34 | target;
35 | if (!event.shiftKey && 9 === keyCode) {
36 | event.preventDefault();
37 | target = $(this).attr('id') === 'title' ? '#message-headline' : '#insert-media-button';
38 | $(target).focus();
39 | }
40 | })
41 | .on('keydown', '#message-headline, #insert-media-button', function (event) {
42 | var keyCode = event.keyCode || event.which,
43 | target;
44 | if (event.shiftKey && 9 === keyCode) {
45 | event.preventDefault();
46 | target = $(this).attr('id') === 'message-headline' ? '#title' : '#message-headline';
47 | $(target).focus();
48 | }
49 | });
50 |
51 |
52 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/colorpicker.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | var colorpicker = {
9 | init: function () {
10 | $('.wpjsfsp-color-picker').filter(':not(.wpjsfsp-color-picker-initialized)')
11 | .addClass('wpjsfsp-color-picker-initialized')
12 | .wpColorPicker({
13 | change: function (event, ui) {
14 | $(event.target).trigger('colorchange', ui);
15 | },
16 | clear: function (event) {
17 | $(event.target).prev().trigger('colorchange').wpColorPicker('close');
18 | }
19 | });
20 | }
21 | };
22 |
23 | // Import this module.
24 | window.WPJSFSP = window.WPJSFSP || {};
25 | window.WPJSFSP.colorpicker = colorpicker;
26 |
27 | $(document)
28 | .on('click', '.iris-palette', function () {
29 | $(this).parents('.wp-picker-active').find('input.wpjsfsp-color-picker').trigger('change');
30 | })
31 | .on('colorchange', function (event, ui) {
32 | var $input = $(event.target),
33 | $opacity = $input.parents('tr').next('tr.background-opacity'),
34 | color = '';
35 |
36 | if (ui !== undefined && ui.color !== undefined) {
37 | color = ui.color.toString();
38 | }
39 |
40 | if ($input.hasClass('background-color')) {
41 | if (typeof color === 'string' && color.length) {
42 | $opacity.show();
43 | } else {
44 | $opacity.hide();
45 | }
46 | }
47 |
48 | $input.val(color);
49 | })
50 | .on('wpjsfsp_init', colorpicker.init);
51 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/conditions.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | var conditions = {
9 | get_conditions: function () {
10 | return window.wpjsfsp_settings_editor.conditions_selectlist;
11 | },
12 | not_operand_checkbox: function ($element) {
13 |
14 | $element = $element || $('.wpjsfsp-not-operand');
15 |
16 | return $element.each(function () {
17 | var $this = $(this),
18 | $input = $this.find('input');
19 |
20 | $input.prop('checked', !$input.is(':checked'));
21 |
22 | WPJSFSP.conditions.toggle_not_operand($this);
23 | });
24 |
25 | },
26 | toggle_not_operand: function ($element) {
27 | $element = $element || $('.wpjsfsp-not-operand');
28 |
29 | return $element.each(function () {
30 | var $this = $(this),
31 | $input = $this.find('input'),
32 | $is = $this.find('.is'),
33 | $not = $this.find('.not'),
34 | $container = $this.parents('.facet-target');
35 |
36 | if ($input.is(':checked')) {
37 | $is.hide();
38 | $not.show();
39 | $container.addClass('not-operand-checked');
40 | } else {
41 | $is.show();
42 | $not.hide();
43 | $container.removeClass('not-operand-checked');
44 | }
45 | });
46 | },
47 | template: {
48 | editor: function (args) {
49 | var data = $.extend(true, {}, {
50 | groups: []
51 | }, args);
52 |
53 | data.groups = WPJSFSP.utils.object_to_array(data.groups);
54 |
55 | return WPJSFSP.templates.render('wpjsfsp-condition-editor', data);
56 | },
57 | group: function (args) {
58 | var data = $.extend(true, {}, {
59 | index: '',
60 | facets: []
61 | }, args),
62 | i;
63 |
64 | data.facets = WPJSFSP.utils.object_to_array(data.facets);
65 |
66 | for (i = 0; data.facets.length > i; i++) {
67 | data.facets[i].index = i;
68 | data.facets[i].group = data.index;
69 | }
70 |
71 | return WPJSFSP.templates.render('wpjsfsp-condition-group', data);
72 | },
73 | facet: function (args) {
74 | var data = $.extend(true, {}, {
75 | group: '',
76 | index: '',
77 | target: '',
78 | not_operand: false,
79 | settings: {}
80 | }, args);
81 |
82 | return WPJSFSP.templates.render('wpjsfsp-condition-facet', data);
83 | },
84 | settings: function (args, values) {
85 | var fields = [],
86 | data = $.extend(true, {}, {
87 | index: '',
88 | group: '',
89 | target: null,
90 | fields: []
91 | }, args);
92 |
93 | if (!data.fields.length && wpjsfsp_settings_editor.conditions[args.target] !== undefined) {
94 | data.fields = wpjsfsp_settings_editor.conditions[args.target].fields;
95 | }
96 |
97 | if (undefined === values) {
98 | values = {};
99 | }
100 |
101 | // Replace the array with rendered fields.
102 | _.each(data.fields, function (field, fieldID) {
103 |
104 | field = WPJSFSP.models.field(field);
105 |
106 | if (typeof field.meta !== 'object') {
107 | field.meta = {};
108 | }
109 |
110 | if (undefined !== values[fieldID]) {
111 | field.value = values[fieldID];
112 | }
113 |
114 | field.name = 'wpjsfsp_settings[conditions][' + data.group + '][' + data.index + '][settings][' + fieldID + ']';
115 |
116 | if (field.id === '') {
117 | field.id = 'conditions_' + data.group + '_' + data.index + '_settings_' + fieldID;
118 | }
119 |
120 | fields.push(WPJSFSP.templates.field(field));
121 | });
122 |
123 | // Render the section.
124 | return WPJSFSP.templates.section({
125 | fields: fields
126 | });
127 | },
128 | selectbox: function (args) {
129 | var data = $.extend(true, {}, {
130 | id: null,
131 | name: null,
132 | type: 'select',
133 | group: '',
134 | index: '',
135 | value: null,
136 | select2: true,
137 | classes: ['facet-target', 'facet-select'],
138 | options: WPJSFSP.conditions.get_conditions()
139 | }, args);
140 |
141 | if (data.id === null) {
142 | data.id = 'conditions_' + data.group + '_' + data.index + '_target';
143 | }
144 |
145 | if (data.name === null) {
146 | data.name = 'wpjsfsp_settings[conditions][' + data.group + '][' + data.index + '][target]';
147 | }
148 |
149 | return WPJSFSP.templates.field(data);
150 | }
151 | },
152 | groups: {
153 | add: function (editor, target, not_operand) {
154 | var $editor = $(editor),
155 | data = {
156 | index: $editor.find('.facet-group-wrap').length,
157 | facets: [
158 | {
159 | target: target || null,
160 | not_operand: not_operand || false,
161 | settings: {}
162 | }
163 | ]
164 | };
165 |
166 |
167 | $editor.find('.facet-groups').append(WPJSFSP.conditions.template.group(data));
168 | $editor.addClass('has-conditions');
169 | },
170 | remove: function ($group) {
171 | var $editor = $group.parents('.facet-builder');
172 |
173 | $group.prev('.facet-group-wrap').find('.and .add-facet').removeClass('disabled');
174 | $group.remove();
175 |
176 | WPJSFSP.conditions.renumber();
177 |
178 | if ($editor.find('.facet-group-wrap').length === 0) {
179 | $editor.removeClass('has-conditions');
180 |
181 | $('#wpjsfsp-first-condition')
182 | .val(null)
183 | .trigger('change');
184 | }
185 | }
186 | },
187 | facets: {
188 | add: function ($group, target, not_operand) {
189 | var data = {
190 | group: $group.data('index'),
191 | index: $group.find('.facet').length,
192 | target: target || null,
193 | not_operand: not_operand || false,
194 | settings: {}
195 | };
196 |
197 | $group.find('.facet-list').append(WPJSFSP.conditions.template.facet(data));
198 | },
199 | remove: function ($facet) {
200 | var $group = $facet.parents('.facet-group-wrap');
201 |
202 | $facet.remove();
203 |
204 | if ($group.find('.facet').length === 0) {
205 | WPJSFSP.conditions.groups.remove($group);
206 | } else {
207 | WPJSFSP.conditions.renumber();
208 | }
209 | }
210 | },
211 | renumber: function () {
212 | $('.facet-builder .facet-group-wrap').each(function () {
213 | var $group = $(this),
214 | groupIndex = $group.parent().children().index($group);
215 |
216 | $group
217 | .data('index', groupIndex)
218 | .find('.facet').each(function () {
219 | var $facet = $(this),
220 | facetIndex = $facet.parent().children().index($facet);
221 |
222 | $facet
223 | .data('index', facetIndex)
224 | .find('[name]').each(function () {
225 | var replace_with = "wpjsfsp_settings[conditions][" + groupIndex + "][" + facetIndex + "]";
226 | this.name = this.name.replace(/wpjsfsp_settings\[conditions\]\[\d*?\]\[\d*?\]/, replace_with);
227 | this.id = this.name;
228 | });
229 | });
230 | });
231 | }
232 | };
233 |
234 | // Import this module.
235 | window.WPJSFSP = window.WPJSFSP || {};
236 | window.WPJSFSP.conditions = conditions;
237 |
238 | $(document)
239 | .on('wpjsfsp_init', function () {
240 | WPJSFSP.conditions.renumber();
241 | WPJSFSP.conditions.toggle_not_operand();
242 | })
243 | .on('select2:select wpjsfselect2:select', '#wpjsfsp-first-condition', function (event) {
244 | var $field = $(this),
245 | $editor = $field.parents('.facet-builder').eq(0),
246 | target = $field.val(),
247 | $operand = $editor.find('#wpjsfsp-first-facet-operand'),
248 | not_operand = $operand.is(':checked');
249 |
250 | WPJSFSP.conditions.groups.add($editor, target, not_operand);
251 |
252 | $field
253 | .val(null)
254 | .trigger('change');
255 |
256 | $operand.prop('checked', false).parents('.facet-target').removeClass('not-operand-checked');
257 | $(document).trigger('wpjsfsp_init');
258 | })
259 | .on('click', '.facet-builder .wpjsfsp-not-operand', function () {
260 | WPJSFSP.conditions.not_operand_checkbox($(this));
261 | })
262 | .on('change', '.facet-builder .facet-target select', function (event) {
263 | var $this = $(this),
264 | $facet = $this.parents('.facet'),
265 | target = $this.val(),
266 | data = {
267 | target: target
268 | };
269 |
270 | if (target === '' || target === $facet.data('target')) {
271 | return;
272 | }
273 |
274 | $facet.data('target', target).find('.facet-settings').html(WPJSFSP.conditions.template.settings(data));
275 | $(document).trigger('wpjsfsp_init');
276 | })
277 | .on('click', '.facet-builder .facet-group-wrap:last-child .and .add-facet', function () {
278 | WPJSFSP.conditions.groups.add($(this).parents('.facet-builder').eq(0));
279 | $(document).trigger('wpjsfsp_init');
280 | })
281 | .on('click', '.facet-builder .add-or .add-facet:not(.disabled)', function () {
282 | WPJSFSP.conditions.facets.add($(this).parents('.facet-group-wrap').eq(0));
283 | $(document).trigger('wpjsfsp_init');
284 | })
285 | .on('click', '.facet-builder .remove-facet', function () {
286 | WPJSFSP.conditions.facets.remove($(this).parents('.facet').eq(0));
287 | $(document).trigger('wpjsfsp_init');
288 | });
289 |
290 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/forms.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | (function ($) {
3 |
4 | var forms = {
5 | init: function () {
6 | forms.checkDependencies();
7 | },
8 | /**
9 | * dependencies should look like this:
10 | *
11 | * {
12 | * field_name_1: value, // Select, radio etc.
13 | * field_name_2: true // Checkbox
14 | * }
15 | *
16 | * Support for Multiple possible values of one field
17 | *
18 | * {
19 | * field_name_1: [ value_1, value_2 ]
20 | * }
21 | *
22 | */
23 | checkDependencies: function ($dependent_fields) {
24 | var _fields = $($dependent_fields);
25 |
26 | // If no fields passed, only do those not already initialized.
27 | $dependent_fields = _fields.length ? _fields : $("[data-wpjsfsp-dependencies]:not([data-wpjsfsp-processed-dependencies])");
28 |
29 | $dependent_fields.each(function () {
30 | var $dependent = $(this),
31 | dependentID = $dependent.data('id'),
32 | // The dependency object for this field.
33 | dependencies = $dependent.data("wpjsfsp-processed-dependencies") || {},
34 | // Total number of fields this :input is dependent on.
35 | requiredCount = Object.keys(dependencies).length,
36 | // Current count of fields this :input matched properly.
37 | count = 0,
38 | // An array of fields this :input is dependent on.
39 | dependentFields = $dependent.data("wpjsfsp-dependent-fields"),
40 | // Early declarations.
41 | key;
42 |
43 | // Clean up & pre-process dependencies so we don't need to rebuild each time.
44 | if (!$dependent.data("wpjsfsp-processed-dependencies")) {
45 | dependencies = $dependent.data("wpjsfsp-dependencies");
46 | if (typeof dependencies === 'string') {
47 | dependencies = JSON.parse(dependencies);
48 | }
49 |
50 | // Convert each key to an array of acceptable values.
51 | for (key in dependencies) {
52 | if (dependencies.hasOwnProperty(key)) {
53 | if (typeof dependencies[key] === "string") {
54 | // Leave boolean values alone as they are for checkboxes or checking if an input has any value.
55 |
56 | if (dependencies[key].indexOf(',') !== -1) {
57 | dependencies[key] = dependencies[key].split(',');
58 | } else {
59 | dependencies[key] = [dependencies[key]];
60 | }
61 | }
62 | }
63 | }
64 |
65 | // Update cache & counts.
66 | requiredCount = Object.keys(dependencies).length;
67 | $dependent.data("wpjsfsp-processed-dependencies", dependencies).attr("data-wpjsfsp-processed-dependencies", dependencies);
68 | }
69 |
70 | if (!dependentFields) {
71 | dependentFields = $.map(dependencies, function (value, index) {
72 | var $wrapper = $('.wpjsfsp-field[data-id="' + index + '"]');
73 |
74 | return $wrapper.length ? $wrapper.eq(0) : null;
75 | });
76 |
77 | $dependent.data("wpjsfsp-dependent-fields", dependentFields);
78 | }
79 |
80 | $(dependentFields).each(function () {
81 | var $wrapper = $(this),
82 | $field = $wrapper.find(':input:first'),
83 | id = $wrapper.data("id"),
84 | value = $field.val(),
85 | required = dependencies[id],
86 | matched,
87 | // Used for limiting the fields that get updated when this field is changed.
88 | all_this_fields_dependents = $wrapper.data('wpjsfsp-field-dependents') || [];
89 |
90 | if (all_this_fields_dependents.indexOf(dependentID) === -1) {
91 | all_this_fields_dependents.push(dependentID);
92 | $wrapper.data('wpjsfsp-field-dependents', all_this_fields_dependents);
93 | }
94 |
95 | // If no required values found bail early.
96 | if (typeof required === 'undefined' || required === null) {
97 | $dependent.hide();
98 | // Effectively breaks the .each for this $dependent and hides it.
99 | return false;
100 | }
101 |
102 | if ($wrapper.hasClass('wpjsfsp-field-radio')) {
103 | value = $wrapper.find(':input:checked').val();
104 | }
105 |
106 | // Check if the value matches required values.
107 | if ($wrapper.hasClass('wpjsfsp-field-select') || $wrapper.hasClass('wpjsfsp-field-radio')) {
108 | matched = required && required.indexOf(value) !== -1;
109 | } else if ($wrapper.hasClass('wpjsfsp-field-checkbox')) {
110 | matched = required === $field.is(':checked');
111 | } else {
112 | matched = Array.isArray(required) ? required.indexOf(value) !== -1 : required == value;
113 | }
114 |
115 | if (matched) {
116 | count++;
117 | } else {
118 | $dependent.hide();
119 | // Effectively breaks the .each for this $dependent and hides it.
120 | return false;
121 | }
122 |
123 | if (count === requiredCount) {
124 | $dependent.show();
125 | }
126 | });
127 | });
128 | },
129 | form_check: function () {
130 | $(document).trigger('wpjsfsp_form_check');
131 | },
132 | is_field: function (data) {
133 | if (typeof data !== 'object') {
134 | return false;
135 | }
136 |
137 | var field_tests = [
138 | data.id !== undefined,
139 | data.label !== undefined,
140 | data.type !== undefined,
141 | data.options !== undefined,
142 | data.desc !== undefined
143 | ];
144 |
145 | return field_tests.indexOf(true) >= 0;
146 | },
147 | parseFields: function (fields, values) {
148 |
149 | values = values || {};
150 |
151 | _.each(fields, function (field, fieldID) {
152 |
153 | fields[fieldID] = WPJSFSP.models.field(field);
154 |
155 | if (typeof fields[fieldID].meta !== 'object') {
156 | fields[fieldID].meta = {};
157 | }
158 |
159 | if (undefined !== values[fieldID]) {
160 | fields[fieldID].value = values[fieldID];
161 | }
162 |
163 | if (fields[fieldID].id === '') {
164 | fields[fieldID].id = fieldID;
165 | }
166 | });
167 |
168 | return fields;
169 | },
170 | renderTab: function () {
171 |
172 | },
173 | renderSection: function () {
174 |
175 | },
176 | render: function (args, values, $container) {
177 | var form,
178 | sections = {},
179 | section = [],
180 | form_fields = {},
181 | data = $.extend(true, {
182 | id: "",
183 | tabs: {},
184 | sections: {},
185 | fields: {},
186 | maintabs: {},
187 | subtabs: {}
188 | }, args),
189 | maintabs = $.extend({
190 | id: data.id,
191 | classes: [],
192 | tabs: {},
193 | vertical: true,
194 | form: true,
195 | meta: {
196 | 'data-min-height': 250
197 | }
198 | }, data.maintabs),
199 | subtabs = $.extend({
200 | classes: ['link-tabs', 'sub-tabs'],
201 | tabs: {}
202 | }, data.subtabs),
203 | container_classes = ['wpjsfsp-dynamic-form'];
204 |
205 | values = values || {};
206 |
207 | if (Object.keys(data.tabs).length && Object.keys(data.sections).length) {
208 | container_classes.push('tabbed-content');
209 |
210 | // Loop Tabs
211 | _.each(data.fields, function (subTabs, tabID) {
212 |
213 | // If not a valid tab or no subsections skip it.
214 | if (typeof subTabs !== 'object' || !Object.keys(subTabs).length) {
215 | return;
216 | }
217 |
218 | // Define this tab.
219 | if (undefined === maintabs.tabs[tabID]) {
220 | maintabs.tabs[tabID] = {
221 | label: data.tabs[tabID],
222 | content: ''
223 | };
224 | }
225 |
226 | // Define the sub tabs model.
227 | subtabs = $.extend(subtabs, {
228 | id: data.id + '-' + tabID + '-subtabs',
229 | tabs: {}
230 | });
231 |
232 | // Loop Tab Sections
233 | _.each(subTabs, function (subTabFields, subTabID) {
234 |
235 | // If not a valid subtab or no fields skip it.
236 | if (typeof subTabFields !== 'object' || !Object.keys(subTabFields).length) {
237 | return;
238 | }
239 |
240 | // Move single fields into the main subtab.
241 | if (forms.is_field(subTabFields)) {
242 | var newSubTabFields = {};
243 | newSubTabFields[subTabID] = subTabFields;
244 | subTabID = 'main';
245 | subTabFields = newSubTabFields;
246 | }
247 |
248 | // Define this subtab model.
249 | if (undefined === subtabs.tabs[subTabID]) {
250 | subtabs.tabs[subTabID] = {
251 | label: data.sections[tabID][subTabID],
252 | content: ''
253 | };
254 | }
255 |
256 | subTabFields = forms.parseFields(subTabFields, values);
257 |
258 | // Loop Tab Section Fields
259 | _.each(subTabFields, function (field) {
260 | // Store the field by id for easy lookup later.
261 | form_fields[field.id] = field;
262 |
263 | // Push rendered fields into the subtab content.
264 | subtabs.tabs[subTabID].content += WPJSFSP.templates.field(field);
265 | });
266 |
267 | // Remove any empty tabs.
268 | if ("" === subtabs.tabs[subTabID].content) {
269 | delete subtabs.tabs[subTabID];
270 | }
271 | });
272 |
273 | // If there are subtabs, then render them into the main tabs content, otherwise remove this main tab.
274 | if (Object.keys(subtabs.tabs).length) {
275 | maintabs.tabs[tabID].content = WPJSFSP.templates.tabs(subtabs);
276 | } else {
277 | delete maintabs.tabs[tabID];
278 | }
279 | });
280 |
281 | if (Object.keys(maintabs.tabs).length) {
282 | form = WPJSFSP.templates.tabs(maintabs);
283 | }
284 | }
285 | else if (Object.keys(data.tabs).length) {
286 | container_classes.push('tabbed-content');
287 |
288 | // Loop Tabs
289 | _.each(data.fields, function (tabFields, tabID) {
290 |
291 | // If not a valid tab or no subsections skip it.
292 | if (typeof tabFields !== 'object' || !Object.keys(tabFields).length) {
293 | return;
294 | }
295 |
296 | // Define this tab.
297 | if (undefined === maintabs.tabs[tabID]) {
298 | maintabs.tabs[tabID] = {
299 | label: data.tabs[tabID],
300 | content: ''
301 | };
302 | }
303 |
304 | section = [];
305 |
306 | tabFields = forms.parseFields(tabFields, values);
307 |
308 | // Loop Tab Fields
309 | _.each(tabFields, function (field) {
310 | // Store the field by id for easy lookup later.
311 | form_fields[field.id] = field;
312 |
313 | // Push rendered fields into the subtab content.
314 | section.push(WPJSFSP.templates.field(field));
315 | });
316 |
317 | // Push rendered tab into the tab.
318 | if (section.length) {
319 | // Push rendered sub tabs into the main tabs if not empty.
320 | maintabs.tabs[tabID].content = WPJSFSP.templates.section({
321 | fields: section
322 | });
323 | } else {
324 | delete (maintabs.tabs[tabID]);
325 | }
326 | });
327 |
328 | if (Object.keys(maintabs.tabs).length) {
329 | form = WPJSFSP.templates.tabs(maintabs);
330 | }
331 | }
332 | else if (Object.keys(data.sections).length) {
333 |
334 | // Loop Sections
335 | _.each(data.fields, function (sectionFields, sectionID) {
336 | section = [];
337 |
338 | section.push(WPJSFSP.templates.field({
339 | type: 'heading',
340 | desc: data.sections[sectionID] || ''
341 | }));
342 |
343 | sectionFields = forms.parseFields(sectionFields, values);
344 |
345 | // Loop Tab Section Fields
346 | _.each(sectionFields, function (field) {
347 | // Store the field by id for easy lookup later.
348 | form_fields[field.id] = field;
349 |
350 | // Push rendered fields into the section.
351 | section.push(WPJSFSP.templates.field(field));
352 | });
353 |
354 | // Push rendered sections into the form.
355 | form += WPJSFSP.templates.section({
356 | fields: section
357 | });
358 | });
359 | }
360 | else {
361 | data.fields = forms.parseFields(data.fields, values);
362 |
363 | // Replace the array with rendered fields.
364 | _.each(data.fields, function (field) {
365 | // Store the field by id for easy lookup later.
366 | form_fields[field.id] = field;
367 |
368 | // Push rendered fields into the section.
369 | section.push(WPJSFSP.templates.field(field));
370 | });
371 |
372 | // Render the section.
373 | form = WPJSFSP.templates.section({
374 | fields: section
375 | });
376 | }
377 |
378 | if ($container !== undefined && $container.length) {
379 | $container
380 | .addClass(container_classes.join(' '))
381 | .data('form_fields', form_fields)
382 | .html(form)
383 | .trigger('wpjsfsp_init');
384 | }
385 |
386 | return form;
387 |
388 | }
389 | };
390 |
391 | // Import this module.
392 | window.WPJSFSP = window.WPJSFSP || {};
393 | window.WPJSFSP.forms = forms;
394 |
395 | $(document)
396 | .on('wpjsfsp_init wpjsfsp_form_check', function () {
397 | WPJSFSP.forms.init();
398 | })
399 | .on('wpjsfspFieldChanged', '.wpjsfsp-field', function () {
400 | var $wrapper = $(this),
401 | dependent_field_ids = $wrapper.data('wpjsfsp-field-dependents') || [],
402 | $dependent_fields = $(),
403 | i;
404 |
405 | if (!dependent_field_ids || dependent_field_ids.length <= 0) {
406 | return;
407 | }
408 |
409 | for (i = 0; i < dependent_field_ids.length; i++) {
410 | $dependent_fields = $dependent_fields.add('.wpjsfsp-field[data-id="' + dependent_field_ids[i] + '"]');
411 | }
412 |
413 | WPJSFSP.forms.checkDependencies($dependent_fields);
414 | })
415 | .on('wpjsfspFieldChanged', '.wpjsfsp-field-dynamic-desc', function () {
416 | var $this = $(this),
417 | $input = $this.find(':input'),
418 | $container = $this.parents('.wpjsfsp-dynamic-form:first'),
419 | val = $input.val(),
420 | form_fields = $container.data('form_fields') || {},
421 | field = form_fields[$this.data('id')] || {},
422 | $desc = $this.find('.wpjsfsp-desc'),
423 | desc = $this.data('wpjsfsp-dynamic-desc');
424 |
425 | switch (field.type) {
426 | case 'radio':
427 | val = $this.find(':input:checked').val();
428 | break;
429 | }
430 |
431 | field.value = val;
432 |
433 | if (desc && desc.length) {
434 | $desc.html(WPJSFSP.templates.renderInline(desc, field));
435 | }
436 | })
437 | .on('change', '.wpjsfsp-field-select select', function () {
438 | $(this).parents('.wpjsfsp-field').trigger('wpjsfspFieldChanged');
439 | })
440 | .on('click', '.wpjsfsp-field-checkbox input', function () {
441 | $(this).parents('.wpjsfsp-field').trigger('wpjsfspFieldChanged');
442 | })
443 | .on('click', '.wpjsfsp-field-radio input', function (event) {
444 | var $this = $(this),
445 | $selected = $this.parents('li'),
446 | $wrapper = $this.parents('.wpjsfsp-field');
447 |
448 | $wrapper.trigger('wpjsfspFieldChanged');
449 |
450 | $wrapper.find('li.wpjsfsp-selected').removeClass('wpjsfsp-selected');
451 |
452 | $selected.addClass('wpjsfsp-selected');
453 | });
454 |
455 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/js-wp-editor.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | var wpActiveEditor = true;
6 | (function ($) {
7 | "use strict";
8 |
9 | var wp_editor = function (options) {
10 |
11 | var default_options,
12 | id_regexp = new RegExp('wpjsfsp_id', 'g');
13 |
14 | if (typeof tinyMCEPreInit === 'undefined' || typeof QTags === 'undefined' || typeof wpjsfsp_wpeditor_vars === 'undefined') {
15 | console.warn('js_wp_editor( $settings ); must be loaded');
16 | return this;
17 | }
18 |
19 | default_options = {
20 | 'mode': 'html',
21 | 'mceInit': {
22 | "theme": "modern",
23 | "skin": "lightgray",
24 | "language": "en",
25 | "formats": {
26 | "alignleft": [
27 | {
28 | "selector": "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",
29 | "styles": {"textAlign": "left"},
30 | "deep": false,
31 | "remove": "none"
32 | },
33 | {
34 | "selector": "img,table,dl.wp-caption",
35 | "classes": ["alignleft"],
36 | "deep": false,
37 | "remove": "none"
38 | }
39 | ],
40 | "aligncenter": [
41 | {
42 | "selector": "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",
43 | "styles": {"textAlign": "center"},
44 | "deep": false,
45 | "remove": "none"
46 | },
47 | {
48 | "selector": "img,table,dl.wp-caption",
49 | "classes": ["aligncenter"],
50 | "deep": false,
51 | "remove": "none"
52 | }
53 | ],
54 | "alignright": [
55 | {
56 | "selector": "p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",
57 | "styles": {"textAlign": "right"},
58 | "deep": false,
59 | "remove": "none"
60 | },
61 | {
62 | "selector": "img,table,dl.wp-caption",
63 | "classes": ["alignright"],
64 | "deep": false,
65 | "remove": "none"
66 | }
67 | ],
68 | "strikethrough": {"inline": "del", "deep": true, "split": true}
69 | },
70 | "relative_urls": false,
71 | "remove_script_host": false,
72 | "convert_urls": false,
73 | "browser_spellcheck": true,
74 | "fix_list_elements": true,
75 | "entities": "38,amp,60,lt,62,gt",
76 | "entity_encoding": "raw",
77 | "keep_styles": false,
78 | "paste_webkit_styles": "font-weight font-style color",
79 | "preview_styles": "font-family font-size font-weight font-style text-decoration text-transform",
80 | "wpeditimage_disable_captions": false,
81 | "wpeditimage_html5_captions": false,
82 | "plugins": "charmap,hr,media,paste,tabfocus,textcolor,fullscreen,wordpress,wpeditimage,wpgallery,wplink,wpdialogs,wpview,image",
83 | "content_css": wpjsfsp_wpeditor_vars.includes_url + "css/dashicons.css?ver=3.9," + wpjsfsp_wpeditor_vars.includes_url + "js/mediaelement/mediaelementplayer.min.css?ver=3.9," + wpjsfsp_wpeditor_vars.includes_url + "js/mediaelement/wp-mediaelement.css?ver=3.9," + wpjsfsp_wpeditor_vars.includes_url + "js/tinymce/skins/wordpress/wp-content.css?ver=3.9",
84 | "selector": "#wpjsfsp_id",
85 | "resize": "vertical",
86 | "menubar": false,
87 | "wpautop": true,
88 | "indent": false,
89 | "toolbar1": "bold,italic,strikethrough,bullist,numlist,blockquote,hr,alignleft,aligncenter,alignright,link,unlink,wp_more,spellchecker,fullscreen,wp_adv",
90 | "toolbar2": "formatselect,underline,alignjustify,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help",
91 | "toolbar3": "",
92 | "toolbar4": "",
93 | "tabfocus_elements": ":prev,:next",
94 | "body_class": "wpjsfsp_id"
95 | }
96 | };
97 |
98 | if (tinyMCEPreInit.mceInit.wpjsfsp_id) {
99 | default_options.mceInit = tinyMCEPreInit.mceInit.wpjsfsp_id;
100 | }
101 |
102 | options = $.extend(true, {}, default_options, options);
103 |
104 | return this.each(function () {
105 | var $this = $(this),
106 | current_id = $this.attr('id'),
107 | temp = {};
108 |
109 | if (tinyMCE.editors[current_id] !== undefined) {
110 | tinyMCE.remove(tinymce.editors[current_id]);
111 | }
112 |
113 | if (!$this.is('textarea')) {
114 | console.warn('Element must be a textarea');
115 | if ($this.closest('.wp-editor-wrap').length) {
116 | temp.editor_wrap = $this.closest('.wp-editor-wrap');
117 | temp.field_parent = temp.editor_wrap.parent();
118 |
119 | temp.editor_wrap.before($this.clone());
120 | temp.editor_wrap.remove();
121 |
122 | $this = temp.field_parent.find('textarea[id="' + current_id + '"]');
123 | }
124 | }
125 | $this.addClass('wp-editor-area').show();
126 |
127 |
128 | $.each(options.mceInit, function (key, value) {
129 | if ($.type(value) === 'string') {
130 | options.mceInit[key] = value.replace(id_regexp, current_id);
131 | }
132 | });
133 |
134 | options.mode = options.mode === 'tmce' ? 'tmce' : 'html';
135 |
136 | tinyMCEPreInit.mceInit[current_id] = options.mceInit;
137 |
138 | var wrap = $('
'),
139 | editor_tools = $(''),
140 | editor_tabs = $(''),
141 | switch_editor_html = $('Text'),
142 | switch_editor_tmce = $('Visual'),
143 | media_buttons = $(''),
144 | insert_media_button = $(' Add Media'),
145 | editor_container = $(''),
146 | content_css = /*Object.prototype.hasOwnProperty.call(tinyMCEPreInit.mceInit[current_id], 'content_css') ? tinyMCEPreInit.mceInit[current_id]['content_css'].split(',') :*/ false;
147 |
148 | insert_media_button.appendTo(media_buttons);
149 | media_buttons.appendTo(editor_tools);
150 |
151 | switch_editor_html.appendTo(editor_tabs);
152 | switch_editor_tmce.appendTo(editor_tabs);
153 | editor_tabs.appendTo(editor_tools);
154 |
155 | editor_tools.appendTo(wrap);
156 | editor_container.appendTo(wrap);
157 |
158 | editor_container.append($this.clone().addClass('wp-editor-area'));
159 |
160 | if (content_css !== false)
161 | $.each(content_css, function () {
162 | if (!$('link[href="' + this + '"]').length)
163 | $this.before('');
164 | });
165 |
166 | $this.before('');
167 |
168 | $this.before(wrap);
169 | $this.remove();
170 |
171 | new QTags(current_id);
172 | QTags._buttonsInit();
173 | switchEditors.go(current_id, options.mode);
174 |
175 | $('.insert-media', wrap).on('click', function (event) {
176 | var elem = $(event.currentTarget),
177 | options = {
178 | frame: 'post',
179 | state: 'insert',
180 | title: wp.media.view.l10n.addMedia,
181 | multiple: true
182 | };
183 |
184 | event.preventDefault();
185 |
186 | elem.blur();
187 |
188 | if (elem.hasClass('gallery')) {
189 | options.state = 'gallery';
190 | options.title = wp.media.view.l10n.createGalleryTitle;
191 | }
192 |
193 | wp.media.editor.open(current_id, options);
194 | });
195 |
196 | });
197 | };
198 |
199 | // Import this module.
200 | window.WPJSFSP = window.WPJSFSP || {};
201 | window.WPJSFSP.wp_editor = wp_editor;
202 |
203 | $.fn.wp_editor = WPJSFSP.wp_editor;
204 |
205 | $(document)
206 | .on('wpjsfsp_init', function () {
207 |
208 | $('.wpjsfsp-field-editor textarea:not(.initialized)').each(function () {
209 | var $this = $(this).addClass('initialized');
210 | $this.wp_editor({
211 | mode: 'tmce'
212 | });
213 | });
214 | })
215 | .on('mousedown', '.wpjsfsp-submit button', function (event) {
216 | var $form = $(event.target).parents('form').eq(0);
217 |
218 | tinyMCE.triggerSave();
219 |
220 | $form.trigger('wpjsfsp_before_submit');
221 | });
222 |
223 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/links.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | var wpActiveEditor = true;
6 | (function ($) {
7 | "use strict";
8 |
9 | var current_link_field;
10 |
11 | // Import this module.
12 | window.WPJSFSP = window.WPJSFSP || {};
13 |
14 | $(document)
15 | .on('click', '.wpjsfsp-field-link button', function (event) {
16 | var $input = $(this).next().select(),
17 | id = $input.attr('id');
18 |
19 | current_link_field = $input;
20 |
21 | wpLink.open(id, $input.val(), ""); //open the link popup
22 |
23 | WPJSFSP.selectors('#wp-link-wrap').removeClass('has-text-field');
24 | WPJSFSP.selectors('#wp-link-target').hide();
25 |
26 | event.preventDefault();
27 | event.stopPropagation();
28 | return false;
29 | })
30 | .on('click', '#wp-link-submit, #wp-link-cancel button, #wp-link-close', function (event) {
31 | var linkAtts = wpLink.getAttrs();
32 |
33 | // If not for our fields then ignore it.
34 | if (current_link_field === undefined || !current_link_field) {
35 | return;
36 | }
37 |
38 | // If not the close buttons then its the save button.
39 | if (event.target.id === 'wp-link-submit') {
40 | current_link_field.val(linkAtts.href);
41 | }
42 |
43 | wpLink.textarea = current_link_field;
44 | wpLink.close();
45 |
46 | // Clear the current_link_field
47 | current_link_field = false;
48 |
49 | //trap any other events
50 | event.preventDefault ? event.preventDefault() : event.returnValue = false;
51 | event.stopPropagation();
52 | return false;
53 | });
54 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/modals.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | var $html = $('html'),
9 | $document = $(document),
10 | $top_level_elements,
11 | focusableElementsString = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]",
12 | previouslyFocused,
13 | modals = {
14 | _current: null,
15 | // Accessibility: Checks focus events to ensure they stay inside the modal.
16 | forceFocus: function (event) {
17 | if (WPJSFSP.modals._current && !WPJSFSP.modals._current.contains(event.target)) {
18 | event.stopPropagation();
19 | WPJSFSP.modals._current.focus();
20 | }
21 | },
22 | trapEscapeKey: function (e) {
23 | if (e.keyCode === 27) {
24 | WPJSFSP.modals.closeAll();
25 | e.preventDefault();
26 | }
27 | },
28 | trapTabKey: function (e) {
29 | // if tab or shift-tab pressed
30 | if (e.keyCode === 9) {
31 | // get list of focusable items
32 | var focusableItems = WPJSFSP.modals._current.find('*').filter(focusableElementsString).filter(':visible'),
33 | // get currently focused item
34 | focusedItem = $(':focus'),
35 | // get the number of focusable items
36 | numberOfFocusableItems = focusableItems.length,
37 | // get the index of the currently focused item
38 | focusedItemIndex = focusableItems.index(focusedItem);
39 |
40 | if (e.shiftKey) {
41 | //back tab
42 | // if focused on first item and user preses back-tab, go to the last focusable item
43 | if (focusedItemIndex === 0) {
44 | focusableItems.get(numberOfFocusableItems - 1).focus();
45 | e.preventDefault();
46 | }
47 | } else {
48 | //forward tab
49 | // if focused on the last item and user preses tab, go to the first focusable item
50 | if (focusedItemIndex === numberOfFocusableItems - 1) {
51 | focusableItems.get(0).focus();
52 | e.preventDefault();
53 | }
54 | }
55 | }
56 | },
57 | setFocusToFirstItem: function () {
58 | // set focus to first focusable item
59 | WPJSFSP.modals._current.find('.wpjsfsp-modal-content *').filter(focusableElementsString).filter(':visible').first().focus();
60 | },
61 | closeAll: function (callback) {
62 | $('.wpjsfsp-modal-background')
63 | .off('keydown.wpjsfsp_modal')
64 | .hide(0, function () {
65 | $('html').css({overflow: 'visible', width: 'auto'});
66 |
67 | if ($top_level_elements) {
68 | $top_level_elements.attr('aria-hidden', 'false');
69 | $top_level_elements = null;
70 | }
71 |
72 | // Accessibility: Focus back on the previously focused element.
73 | if (previouslyFocused.length) {
74 | previouslyFocused.focus();
75 | }
76 |
77 | // Accessibility: Clears the WPJSFSP.modals._current var.
78 | WPJSFSP.modals._current = null;
79 |
80 | // Accessibility: Removes the force focus check.
81 | $document.off('focus.wpjsfsp_modal');
82 | if (undefined !== callback) {
83 | callback();
84 | }
85 | })
86 | .attr('aria-hidden', 'true');
87 |
88 | },
89 | show: function (modal, callback) {
90 | $('.wpjsfsp-modal-background')
91 | .off('keydown.wpjsfsp_modal')
92 | .hide(0)
93 | .attr('aria-hidden', 'true');
94 |
95 | $html
96 | .data('origwidth', $html.innerWidth())
97 | .css({overflow: 'hidden', 'width': $html.innerWidth()});
98 |
99 | // Accessibility: Sets the previous focus element.
100 |
101 | var $focused = $(':focus');
102 | if (!$focused.parents('.wpjsfsp-modal-wrap').length) {
103 | previouslyFocused = $focused;
104 | }
105 |
106 | // Accessibility: Sets the current modal for focus checks.
107 | WPJSFSP.modals._current = $(modal);
108 |
109 | // Accessibility: Close on esc press.
110 | WPJSFSP.modals._current
111 | .on('keydown.wpjsfsp_modal', function (e) {
112 | WPJSFSP.modals.trapEscapeKey(e);
113 | WPJSFSP.modals.trapTabKey(e);
114 | })
115 | .show(0, function () {
116 | $top_level_elements = $('body > *').filter(':visible').not(WPJSFSP.modals._current);
117 | $top_level_elements.attr('aria-hidden', 'true');
118 |
119 | WPJSFSP.modals._current
120 | .trigger('wpjsfsp_init')
121 | // Accessibility: Add focus check that prevents tabbing outside of modal.
122 | .on('focus.wpjsfsp_modal', WPJSFSP.modals.forceFocus);
123 |
124 | // Accessibility: Focus on the modal.
125 | WPJSFSP.modals.setFocusToFirstItem();
126 |
127 | if (undefined !== callback) {
128 | callback();
129 | }
130 | })
131 | .attr('aria-hidden', 'false');
132 |
133 | },
134 | remove: function (modal) {
135 | $(modal).remove();
136 | },
137 | replace: function (modal, replacement) {
138 | WPJSFSP.modals.remove($.trim(modal));
139 | $('body').append($.trim(replacement));
140 | },
141 | reload: function (modal, replacement, callback) {
142 | WPJSFSP.modals.replace(modal, replacement);
143 | WPJSFSP.modals.show(modal, callback);
144 | $(modal).trigger('wpjsfsp_init');
145 | }
146 | };
147 |
148 | // Import this module.
149 | window.WPJSFSP = window.WPJSFSP || {};
150 | window.WPJSFSP.modals = modals;
151 |
152 | $(document).on('click', '.wpjsfsp-modal-background, .wpjsfsp-modal-wrap .cancel, .wpjsfsp-modal-wrap .wpjsfsp-modal-close', function (e) {
153 | var $target = $(e.target);
154 | if (/*$target.hasClass('wpjsfsp-modal-background') || */$target.hasClass('cancel') || $target.hasClass('wpjsfsp-modal-close') || $target.hasClass('submitdelete')) {
155 | WPJSFSP.modals.closeAll();
156 | e.preventDefault();
157 | e.stopPropagation();
158 | }
159 | });
160 |
161 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/models.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | var models = {
9 | field: function (args) {
10 | return $.extend(true, {}, {
11 | type: 'text',
12 | id: '',
13 | id_prefix: '',
14 | name: '',
15 | label: null,
16 | placeholder: '',
17 | desc: null,
18 | dynamic_desc: null,
19 | size: 'regular',
20 | classes: [],
21 | dependencies: "",
22 | value: null,
23 | select2: false,
24 | multiple: false,
25 | as_array: false,
26 | options: [],
27 | object_type: null,
28 | object_key: null,
29 | std: null,
30 | min: 0,
31 | max: 50,
32 | step: 1,
33 | unit: 'px',
34 | units: {},
35 | required: false,
36 | desc_position: 'bottom',
37 | meta: {}
38 | }, args);
39 | }
40 | };
41 |
42 | // Import this module.
43 | window.WPJSFSP = window.WPJSFSP || {};
44 | window.WPJSFSP.models = models;
45 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/rangesliders.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | 'use strict';
7 |
8 | var rangesliders = {
9 | cloneables: {
10 | slider: $(''),
11 | plus: $(''),
12 | minus: $('')
13 | },
14 | init: function () {
15 | $('.wpjsfsp-field-rangeslider:not(.wpjsfsp-rangeslider-initialized)').each(function () {
16 | var $this = $(this).addClass('wpjsfsp-rangeslider-initialized'),
17 | $input = $this.find('input.wpjsfsp-range-manual'),
18 | $slider = rangesliders.cloneables.slider.clone(),
19 | $plus = rangesliders.cloneables.plus.clone(),
20 | $minus = rangesliders.cloneables.minus.clone(),
21 | settings = {
22 | force: $input.data('force-minmax'),
23 | min: parseInt($input.attr('min'), 10) || 0,
24 | max: parseInt($input.attr('max'), 10) || 100,
25 | step: parseInt($input.attr('step'), 10) || 1,
26 | value: parseInt($input.attr('value'), 10) || 0
27 | };
28 |
29 | if (settings.force && settings.value > settings.max) {
30 | settings.value = settings.max;
31 | $input.val(settings.value);
32 | }
33 |
34 | $slider.prop({
35 | min: settings.min || 0,
36 | max: ( settings.force || (settings.max && settings.max > settings.value) ) ? settings.max : settings.value *
37 | 1.5,
38 | step: settings.step || settings.value * 1.5 / 100,
39 | value: settings.value
40 | }).on('change input', function () {
41 | $input.trigger('input');
42 | });
43 |
44 | $input.next().after($minus, $plus);
45 | $input.before($slider);
46 |
47 | });
48 | }
49 | };
50 |
51 | // Import this module.
52 | window.WPJSFSP = window.WPJSFSP || {};
53 | window.WPJSFSP.rangesliders = rangesliders;
54 |
55 | $(document)
56 | .on('wpjsfsp_init', WPJSFSP.rangesliders.init)
57 | /**
58 | * Updates the input field when the slider is used.
59 | */
60 | .on('input', '.wpjsfsp-field-rangeslider.wpjsfsp-rangeslider-initialized .wpjsfsp-range-slider', function () {
61 | var $slider = $(this);
62 | $slider.siblings('.wpjsfsp-range-manual').val($slider.val());
63 | })
64 | /**
65 | * Update sliders value, min, & max when manual entry is detected.
66 | */
67 | .on('change', '.wpjsfsp-range-manual', function () {
68 | var $input = $(this),
69 | max = parseInt($input.prop('max'), 0),
70 | min = parseInt($input.prop('min'), 0),
71 | step = parseInt($input.prop('step'), 0),
72 | force = $input.data('force-minmax'),
73 | value = parseInt($input.val(), 0),
74 | $slider = $input.prev();
75 |
76 | if (isNaN(value)) {
77 | value = $slider.val();
78 | }
79 |
80 | if (force && value > max) {
81 | value = max;
82 | } else if (force && value < min) {
83 | value = min;
84 | }
85 |
86 | $input.val(value).trigger('input');
87 |
88 | $slider.prop({
89 | 'max': force || (max && max > value) ? max : value * 1.5,
90 | 'step': step || value * 1.5 / 100,
91 | 'value': value
92 | });
93 | })
94 | .on('click', '.wpjsfsp-range-plus', function (event) {
95 | var $input = $(this).siblings('.wpjsfsp-range-manual'),
96 | max = parseInt($input.prop('max'), 0),
97 | step = parseInt($input.prop('step'), 0),
98 | force = $input.data('force-minmax'),
99 | value = parseInt($input.val(), 0),
100 | $slider = $input.prev();
101 |
102 | event.preventDefault();
103 |
104 | value += step;
105 |
106 | if (isNaN(value)) {
107 | value = $slider.val();
108 | }
109 |
110 | if (force && value > max) {
111 | value = max;
112 | }
113 |
114 | $input.val(value).trigger('input');
115 | $slider.val(value);
116 | })
117 | .on('click', '.wpjsfsp-range-minus', function (event) {
118 | var $input = $(this).siblings('.wpjsfsp-range-manual'),
119 | min = parseInt($input.prop('min'), 0),
120 | step = parseInt($input.prop('step'), 0),
121 | force = $input.data('force-minmax'),
122 | value = parseInt($input.val(), 0),
123 | $slider = $input.prev();
124 |
125 | event.preventDefault();
126 |
127 | value -= step;
128 |
129 | if (isNaN(value)) {
130 | value = $slider.val();
131 | }
132 |
133 | if (force && value < min) {
134 | value = min;
135 | }
136 |
137 | $input.val(value).trigger('input');
138 | $slider.val(value);
139 | });
140 |
141 | }(jQuery, document));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/select2.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | var select2 = {
9 | init: function () {
10 | $('.wpjsfsp-field-select2 select').filter(':not(.select2-initialized)').each(function () {
11 |
12 | var $this = $(this),
13 | current = $this.data('current') || $this.find('option[selected="selected"]').attr('value'),
14 | object_type = $this.data('objecttype'),
15 | object_key = $this.data('objectkey'),
16 | options = {
17 | width: '100%',
18 | multiple: false,
19 | dropdownParent: $this.parent()
20 | };
21 |
22 | if ($this.attr('multiple')) {
23 | options.multiple = true;
24 | }
25 |
26 | if (object_type && object_key) {
27 | options = $.extend(options, {
28 | ajax: {
29 | url: ajaxurl,
30 | dataType: 'json',
31 | delay: 250,
32 | data: function (params) {
33 | return {
34 | s: params.term, // search term
35 | page: params.page,
36 | action: "wpjsfsp_object_search",
37 | object_type: object_type,
38 | object_key: object_key
39 | };
40 | },
41 | processResults: function (data, params) {
42 | // parse the results into the format expected by Select2
43 | // since we are using custom formatting functions we do not need to
44 | // alter the remote JSON data, except to indicate that infinite
45 | // scrolling can be used
46 | params.page = params.page || 1;
47 |
48 | return {
49 | results: data.items,
50 | pagination: {
51 | more: (params.page * 10) < data.total_count
52 | }
53 | };
54 | },
55 | cache: true
56 | },
57 | cache: true,
58 | escapeMarkup: function (markup) {
59 | return markup;
60 | }, // let our custom formatter work
61 | maximumInputLength: 20,
62 | closeOnSelect: !options.multiple,
63 | templateResult: WPJSFSP.select2.formatObject,
64 | templateSelection: WPJSFSP.select2.formatObjectSelection
65 | });
66 | }
67 |
68 |
69 | $this
70 | .addClass('select2-initialized')
71 | .wpjsfselect2(options);
72 |
73 | if (current !== null && current !== undefined) {
74 |
75 | if (options.multiple && 'object' !== typeof current && current !== "") {
76 | current = [current];
77 | } else if (!options.multiple && current === '') {
78 | current = null;
79 | }
80 | } else {
81 | current = null;
82 | }
83 |
84 | if (object_type && object_key && current !== null && (typeof current === 'number' || current.length)) {
85 | $.ajax({
86 | url: ajaxurl,
87 | data: {
88 | action: "wpjsfsp_object_search",
89 | object_type: object_type,
90 | object_key: object_key,
91 | include: current && current.length ? ((typeof current === 'string' || typeof current === 'number') ? current : [current]) : null
92 | },
93 | dataType: "json",
94 | success: function (data) {
95 | $.each(data.items, function (key, item) {
96 | // Add any option that doesn't already exist
97 | if (!$this.find('option[value="' + item.id + '"]').length) {
98 | $this.prepend('');
99 | }
100 | });
101 | // Update the options
102 | $this.val(current).trigger('change');
103 | }
104 | });
105 | } else if (current && ((options.multiple && current.length) || (!options.multiple && current !== ""))) {
106 | $this.val(current).trigger('change');
107 | } else if (current === null) {
108 | $this.val(current).trigger('change');
109 | }
110 | });
111 | },
112 | formatObject: function (object) {
113 | return object.text;
114 | },
115 | formatObjectSelection: function (object) {
116 | return object.text || object.text;
117 | }
118 | };
119 |
120 | // Import this module.
121 | window.WPJSFSP = window.WPJSFSP || {};
122 | window.WPJSFSP.select2 = select2;
123 |
124 | $(document)
125 | .on('wpjsfsp_init', function () {
126 | WPJSFSP.select2.init();
127 | });
128 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/selectors.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | function Selector_Cache() {
9 | var elementCache = {};
10 |
11 | var get_from_cache = function (selector, $ctxt, reset) {
12 |
13 | if ('boolean' === typeof $ctxt) {
14 | reset = $ctxt;
15 | $ctxt = false;
16 | }
17 | var cacheKey = $ctxt ? $ctxt.selector + ' ' + selector : selector;
18 |
19 | if (undefined === elementCache[cacheKey] || reset) {
20 | elementCache[cacheKey] = $ctxt ? $ctxt.find(selector) : jQuery(selector);
21 | }
22 |
23 | return elementCache[cacheKey];
24 | };
25 |
26 | get_from_cache.elementCache = elementCache;
27 | return get_from_cache;
28 | }
29 |
30 | var selectors = new Selector_Cache();
31 |
32 | // Import this module.
33 | window.WPJSFSP = window.WPJSFSP || {};
34 | window.WPJSFSP.selectors = selectors;
35 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/serialize-object.js:
--------------------------------------------------------------------------------
1 | /**
2 | * jQuery serializeObject
3 | * @copyright 2014, macek
4 | * @link https://github.com/macek/jquery-serialize-object
5 | * @license BSD
6 | * @version 2.5.0
7 | */
8 | (function (root, factory) {
9 |
10 | // AMD
11 | if (typeof define === "function" && define.amd) {
12 | define(["exports", "jquery"], function (exports, $) {
13 | return factory(exports, $);
14 | });
15 | }
16 |
17 | // CommonJS
18 | else if (typeof exports !== "undefined") {
19 | var $ = require("jquery");
20 | factory(exports, $);
21 | }
22 |
23 | // Browser
24 | else {
25 | factory(root, (root.jQuery || root.Zepto || root.ender || root.$));
26 | }
27 |
28 | }(this, function (exports, $) {
29 |
30 | var patterns = {
31 | validate: /^[a-z_][a-z0-9_]*(?:\[(?:\d*|[a-z0-9_]+)\])*$/i,
32 | key: /[a-z0-9_]+|(?=\[\])/gi,
33 | push: /^$/,
34 | fixed: /^\d+$/,
35 | named: /^[a-z0-9_]+$/i
36 | };
37 |
38 | function FormSerializer(helper, $form) {
39 |
40 | // private variables
41 | var data = {},
42 | pushes = {};
43 |
44 | // private API
45 | function build(base, key, value) {
46 | base[key] = value;
47 | return base;
48 | }
49 |
50 | function makeObject(root, value) {
51 |
52 | var keys = root.match(patterns.key), k;
53 |
54 | try {
55 | value = JSON.parse(value);
56 | } catch (Error) {
57 | }
58 |
59 | // nest, nest, ..., nest
60 | while ((k = keys.pop()) !== undefined) {
61 | // foo[]
62 | if (patterns.push.test(k)) {
63 | var idx = incrementPush(root.replace(/\[\]$/, ''));
64 | value = build([], idx, value);
65 | }
66 |
67 | // foo[n]
68 | else if (patterns.fixed.test(k)) {
69 | value = build([], k, value);
70 | }
71 |
72 | // foo; foo[bar]
73 | else if (patterns.named.test(k)) {
74 | value = build({}, k, value);
75 | }
76 | }
77 |
78 | return value;
79 | }
80 |
81 | function incrementPush(key) {
82 | if (pushes[key] === undefined) {
83 | pushes[key] = 0;
84 | }
85 | return pushes[key]++;
86 | }
87 |
88 | function encode(pair) {
89 | switch ($('[name="' + pair.name + '"]', $form).attr("type")) {
90 | case "checkbox":
91 | return pair.value === "on" ? true : pair.value;
92 | default:
93 | return pair.value;
94 | }
95 | }
96 |
97 | function addPair(pair) {
98 | if (!patterns.validate.test(pair.name)) return this;
99 | var obj = makeObject(pair.name, encode(pair));
100 |
101 | data = helper.extend(true, data, obj);
102 | return this;
103 | }
104 |
105 | function addPairs(pairs) {
106 | if (!helper.isArray(pairs)) {
107 | throw new Error("formSerializer.addPairs expects an Array");
108 | }
109 | for (var i = 0, len = pairs.length; i < len; i++) {
110 | this.addPair(pairs[i]);
111 | }
112 | return this;
113 | }
114 |
115 | function serialize() {
116 | return data;
117 | }
118 |
119 | function serializeJSON() {
120 | return JSON.stringify(serialize());
121 | }
122 |
123 | // public API
124 | this.addPair = addPair;
125 | this.addPairs = addPairs;
126 | this.serialize = serialize;
127 | this.serializeJSON = serializeJSON;
128 | }
129 |
130 | FormSerializer.patterns = patterns;
131 |
132 | FormSerializer.serializeObject = function serializeObject() {
133 | var serialized;
134 |
135 | if (this.is('form')) {
136 | serialized = this.serializeArray();
137 | } else {
138 | serialized = this.find(':input').serializeArray();
139 | }
140 |
141 | return new FormSerializer($, this)
142 | .addPairs(serialized)
143 | .serialize();
144 | };
145 |
146 | FormSerializer.serializeJSON = function serializeJSON() {
147 | var serialized;
148 |
149 | if (this.is('form')) {
150 | serialized = this.serializeArray();
151 | } else {
152 | serialized = this.find(':input').serializeArray();
153 | }
154 |
155 | return new FormSerializer($, this)
156 | .addPairs(serialized)
157 | .serializeJSON();
158 | };
159 |
160 | if (typeof $.fn !== "undefined") {
161 | $.fn.serializeObject = FormSerializer.serializeObject;
162 | $.fn.serializeJSON = FormSerializer.serializeJSON;
163 | }
164 |
165 | exports.FormSerializer = FormSerializer;
166 |
167 | return FormSerializer;
168 | }));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/settings.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 | window.wpjsfsp_settings_editor = window.wpjsfsp_settings_editor || {
8 | form_args: {},
9 | current_values: {}
10 | };
11 |
12 | $(document)
13 | .ready(function () {
14 | var $container = $('#wpjsfsp-settings-container'),
15 | args = wpjsfsp_settings_editor.form_args || {},
16 | values = wpjsfsp_settings_editor.current_values || {};
17 |
18 | if ($container.length) {
19 | WPJSFSP.forms.render(args, values, $container);
20 | }
21 | });
22 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/tabs.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 | var tabs = {
8 | init: function () {
9 | $('.wpjsfsp-tabs-container').filter(':not(.wpjsfsp-tabs-initialized)').each(function () {
10 | var $this = $(this).addClass('wpjsfsp-tabs-initialized'),
11 | $tabList = $this.find('> ul.tabs'),
12 | $firstTab = $tabList.find('> li:first'),
13 | forceMinHeight = $this.data('min-height');
14 |
15 | if ($this.hasClass('vertical-tabs')) {
16 | var minHeight = forceMinHeight && forceMinHeight > 0 ? forceMinHeight : $tabList.eq(0).outerHeight(true);
17 |
18 | $this.css({
19 | minHeight: minHeight + 'px'
20 | });
21 |
22 | if ($this.parent().innerHeight < minHeight) {
23 | $this.parent().css({
24 | minHeight: minHeight + 'px'
25 | });
26 | }
27 | }
28 |
29 | // Trigger first tab.
30 | $firstTab.trigger('click');
31 | });
32 | }
33 | };
34 |
35 | // Import this module.
36 | window.WPJSFSP = window.WPJSFSP || {};
37 | window.WPJSFSP.tabs = tabs;
38 |
39 | $(document)
40 | .on('wpjsfsp_init', function () {
41 | WPJSFSP.tabs.init();
42 | })
43 | .on('click', '.wpjsfsp-tabs-initialized li.tab', function (e) {
44 | var $this = $(this),
45 | $container = $this.parents('.wpjsfsp-tabs-container:first'),
46 | $tabs = $container.find('> ul.tabs > li.tab'),
47 | $tab_contents = $container.find('> div.tab-content'),
48 | link = $this.find('a').attr('href');
49 |
50 | $tabs.removeClass('active');
51 | $tab_contents.removeClass('active');
52 |
53 | $this.addClass('active');
54 | $container.find('> div.tab-content' + link).addClass('active');
55 |
56 | e.preventDefault();
57 | });
58 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/templates.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 | var templates = {
8 | render: function (template, data) {
9 | var _template = wp.template(template);
10 |
11 | data = data || {};
12 |
13 | if (data.classes !== undefined && Array.isArray(data.classes)) {
14 | data.classes = data.classes.join(' ');
15 | }
16 |
17 | // Prepare the meta data for templates.
18 | data = WPJSFSP.templates.prepareMeta(data);
19 |
20 | return _template(data);
21 | },
22 | renderInline: function (content, data) {
23 | var options = {
24 | evaluate: /<#([\s\S]+?)#>/g,
25 | interpolate: /\{\{\{([\s\S]+?)\}\}\}/g,
26 | escape: /\{\{([^\}]+?)\}\}(?!\})/g,
27 | variable: 'data'
28 | },
29 | template = _.template(content, null, options);
30 |
31 | return template(data);
32 | },
33 | shortcode: function (args) {
34 | var data = $.extend(true, {}, {
35 | tag: '',
36 | meta: {},
37 | has_content: false,
38 | content: ''
39 | }, args),
40 | template = data.has_content ? 'wpjsfsp-shortcode-w-content' : 'wpjsfsp-shortcode';
41 |
42 | return WPJSFSP.templates.render(template, data);
43 | },
44 | modal: function (args) {
45 | var data = $.extend(true, {}, {
46 | id: '',
47 | title: '',
48 | description: '',
49 | classes: '',
50 | save_button: window.WPJSFSP.I10n.save,
51 | cancel_button: window.WPJSFSP.I10n.cancel,
52 | content: ''
53 | }, args);
54 |
55 | return WPJSFSP.templates.render('wpjsfsp-modal', data);
56 | },
57 | tabs: function (data) {
58 | data = $.extend(true, {}, {
59 | id: '',
60 | vertical: false,
61 | form: false,
62 | classes: [],
63 | tabs: {},
64 | meta: {}
65 | }, data);
66 |
67 | if (typeof data.classes === 'string') {
68 | data.classes = [data.classes];
69 | }
70 |
71 | if (data.form) {
72 | data.classes.push('wpjsfsp-tabbed-form');
73 | }
74 |
75 | data.meta['data-tab-count'] = Object.keys(data.tabs).length;
76 |
77 | data.classes.push(data.vertical ? 'vertical-tabs' : 'horizontal-tabs');
78 |
79 | data.classes = data.classes.join(' ');
80 |
81 | return WPJSFSP.templates.render('wpjsfsp-tabs', data);
82 | },
83 | section: function (args) {
84 | var data = $.extend(true, {}, {
85 | classes: [],
86 | fields: []
87 | }, args);
88 |
89 |
90 | return WPJSFSP.templates.render('wpjsfsp-field-section', data);
91 | },
92 | fieldArgs: function (args) {
93 | var options = [],
94 | data = $.extend(true, {}, WPJSFSP.models.field(args));
95 |
96 | if (!data.value && args.std !== undefined) {
97 | data.value = args.std;
98 | }
99 |
100 | if ('string' === typeof data.classes) {
101 | data.classes = data.classes.split(' ');
102 | }
103 |
104 | if (args.class !== undefined) {
105 | data.classes.push(args.class);
106 | }
107 |
108 | if (args.dependencies !== undefined && typeof args.dependencies === 'object') {
109 | data.dependencies = JSON.stringify(args.dependencies);
110 | }
111 |
112 | if (data.required) {
113 | data.meta.required = true;
114 | data.classes.push('wpjsfsp-required');
115 | }
116 |
117 | if (typeof data.dynamic_desc === 'string' && data.dynamic_desc.length) {
118 | data.classes.push('wpjsfsp-field-dynamic-desc');
119 | data.desc = WPJSFSP.templates.renderInline(data.dynamic_desc, data);
120 | }
121 |
122 | switch (args.type) {
123 | case 'select':
124 | case 'objectselect':
125 | case 'postselect':
126 | case 'taxonomyselect':
127 | if (data.options !== undefined) {
128 | _.each(data.options, function (label, value) {
129 | var selected = false,
130 | optgroup,
131 | optgroup_options;
132 |
133 | // Check if the label is an object. If so this is a optgroup and the label is sub options array.
134 | // NOTE: The value in the case its an optgroup is the optgroup label.
135 | if (typeof label !== 'object') {
136 |
137 | if (data.value !== null) {
138 | if (data.multiple && ((typeof data.value === 'object' && Object.keys(data.value).length && data.value[value] !== undefined) || (Array.isArray(data.value) && data.value.indexOf(value) !== -1))) {
139 | selected = 'selected';
140 | } else if (!data.multiple && data.value == value) {
141 | selected = 'selected';
142 | }
143 | }
144 |
145 | options.push(
146 | WPJSFSP.templates.prepareMeta({
147 | label: label,
148 | value: value,
149 | meta: {
150 | selected: selected
151 | }
152 | })
153 | );
154 |
155 | } else {
156 | // Process Option Groups
157 |
158 | // Swap label & value due to group labels being used as keys.
159 | optgroup = value;
160 | optgroup_options = [];
161 |
162 | _.each(label, function (label, value) {
163 | var selected = false;
164 |
165 | if (data.value !== null) {
166 | if (data.multiple && ((typeof data.value === 'object' && Object.keys(data.value).length && data.value[value] !== undefined) || (Array.isArray(data.value) && data.value.indexOf(value) !== -1))) {
167 | selected = 'selected';
168 | } else if (!data.multiple && data.value == value) {
169 | selected = 'selected';
170 | }
171 | }
172 | optgroup_options.push(
173 | WPJSFSP.templates.prepareMeta({
174 | label: label,
175 | value: value,
176 | meta: {
177 | selected: selected
178 | }
179 | })
180 | );
181 |
182 | });
183 |
184 | options.push({
185 | label: optgroup,
186 | options: optgroup_options
187 | });
188 |
189 | }
190 |
191 | });
192 |
193 | data.options = options;
194 |
195 | }
196 |
197 | if (data.multiple) {
198 |
199 | data.meta.multiple = true;
200 |
201 | if (data.as_array) {
202 | data.name += '[]';
203 | }
204 |
205 | if (!data.value || !data.value.length) {
206 | data.value = [];
207 | }
208 |
209 | if (typeof data.value === 'string') {
210 | data.value = [data.value];
211 | }
212 |
213 | }
214 |
215 | if (args.type !== 'select') {
216 | data.select2 = true;
217 | data.classes.push('wpjsfsp-field-objectselect');
218 | data.classes.push(args.type === 'postselect' ? 'wpjsfsp-field-postselect' : 'wpjsfsp-field-taxonomyselect');
219 | data.meta['data-objecttype'] = args.type === 'postselect' ? 'post_type' : 'taxonomy';
220 | data.meta['data-objectkey'] = args.type === 'postselect' ? args.post_type : args.taxonomy;
221 | data.meta['data-current'] = typeof data.value === 'object' || Array.isArray(data.value) ? JSON.stringify(data.value) : data.value;
222 | }
223 |
224 | if (data.select2) {
225 | data.classes.push('wpjsfsp-field-select2');
226 |
227 | if (data.placeholder) {
228 | data.meta['data-placeholder'] = data.placeholder;
229 | }
230 | }
231 |
232 | break;
233 | case 'radio':
234 | if (data.options !== undefined) {
235 | _.each(data.options, function (label, value) {
236 |
237 | options.push(
238 | WPJSFSP.templates.prepareMeta({
239 | label: label,
240 | value: value,
241 | meta: {
242 | checked: data.value === value
243 | }
244 | })
245 | );
246 |
247 | });
248 |
249 | data.options = options;
250 | }
251 | break;
252 | case 'multicheck':
253 | if (data.options !== undefined) {
254 |
255 | if (!data.value) {
256 | data.value = [];
257 | }
258 |
259 | if (data.as_array) {
260 | data.name += '[]';
261 | }
262 |
263 | _.each(data.options, function (label, value) {
264 |
265 | options.push(
266 | WPJSFSP.templates.prepareMeta({
267 | label: label,
268 | value: value,
269 | meta: {
270 | checked: (typeof data.value === 'object' && data.value[value] !== undefined) || (typeof data.value === 'array' && data.value.indexOf(value) >= 0)
271 | }
272 | })
273 | );
274 |
275 | });
276 |
277 | data.options = options;
278 | }
279 | break;
280 | case 'checkbox':
281 | if (parseInt(data.value, 10) === 1) {
282 | data.meta.checked = true;
283 | }
284 | break;
285 | case 'rangeslider':
286 | // data.meta.readonly = true;
287 | data.meta.step = data.step;
288 | data.meta.min = data.min;
289 | data.meta.max = data.max;
290 | break;
291 | case 'textarea':
292 | data.meta.cols = data.cols;
293 | data.meta.rows = data.rows;
294 | break;
295 | case 'measure':
296 | if (typeof data.value === 'string' && data.value !== '') {
297 | data.number = parseInt(data.value);
298 | data.unitValue = data.value.replace(data.number, "");
299 | data.value = data.number;
300 | } else {
301 | data.unitValue = null;
302 | }
303 |
304 | if (data.units !== undefined) {
305 | _.each(data.units, function (label, value) {
306 | var selected = false;
307 |
308 | if (data.unitValue == value) {
309 | selected = 'selected';
310 | }
311 |
312 | options.push(
313 | WPJSFSP.templates.prepareMeta({
314 | label: label,
315 | value: value,
316 | meta: {
317 | selected: selected
318 | }
319 | })
320 | );
321 |
322 | });
323 |
324 | data.units = options;
325 | }
326 | break;
327 | case 'license_key':
328 |
329 | data.value = $.extend({
330 | key: '',
331 | license: {},
332 | messages: [],
333 | status: 'empty',
334 | expires: false,
335 | classes: false
336 | }, data.value);
337 |
338 | data.classes.push('wpjsfsp-license-' + data.value.status + '-notice');
339 |
340 | if (data.value.classes) {
341 | data.classes.push(data.value.classes);
342 | }
343 | break;
344 | }
345 |
346 | return data;
347 | },
348 | field: function (args) {
349 | var fieldTemplate,
350 | data = WPJSFSP.templates.fieldArgs(args);
351 |
352 | fieldTemplate = 'wpjsfsp-field-' + data.type;
353 |
354 | if (!$('#tmpl-' + fieldTemplate).length) {
355 | if (data.type === 'objectselfect' || data.type === 'postselect' || data.type === 'taxonomyselect') {
356 | fieldTemplate = 'wpjsfsp-field-select';
357 | }
358 | if (!$('#tmpl-' + fieldTemplate).length) {
359 | return '';
360 | }
361 | }
362 |
363 | data.field = WPJSFSP.templates.render(fieldTemplate, data);
364 |
365 | return WPJSFSP.templates.render('wpjsfsp-field-wrapper', data);
366 | },
367 | prepareMeta: function (data) {
368 | // Convert meta JSON to attribute string.
369 | var _meta = [],
370 | key;
371 |
372 | for (key in data.meta) {
373 | if (data.meta.hasOwnProperty(key)) {
374 | // Boolean attributes can only require attribute key, not value.
375 | if ('boolean' === typeof data.meta[key]) {
376 | // Only set truthy boolean attributes.
377 | if (data.meta[key]) {
378 | _meta.push(_.escape(key));
379 | }
380 | } else {
381 | _meta.push(_.escape(key) + '="' + _.escape(data.meta[key]) + '"');
382 | }
383 | }
384 | }
385 |
386 | data.meta = _meta.join(' ');
387 | return data;
388 | }
389 | };
390 |
391 | // Import this module.
392 | window.WPJSFSP = window.WPJSFSP || {};
393 | window.WPJSFSP.templates = templates;
394 | }(jQuery));
--------------------------------------------------------------------------------
/assets/js/src/admin/plugins/utils.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 | (function ($) {
6 | "use strict";
7 |
8 | String.prototype.capitalize = function () {
9 | return this.charAt(0).toUpperCase() + this.slice(1);
10 | };
11 |
12 | var root = this,
13 | inputTypes = 'color,date,datetime,datetime-local,email,hidden,month,number,password,range,search,tel,text,time,url,week'.split(','),
14 | inputNodes = 'select,textarea'.split(','),
15 | rName = /\[([^\]]*)\]/g;
16 |
17 | // ugly hack for IE7-8
18 | function isInArray(array, needle) {
19 | return $.inArray(needle, array) !== -1;
20 | }
21 |
22 | function storeValue(container, parsedName, value) {
23 |
24 | var part = parsedName[0];
25 |
26 | if (parsedName.length > 1) {
27 | if (!container[part]) {
28 | // If the next part is eq to '' it means we are processing complex name (i.e. `some[]`)
29 | // for this case we need to use Array instead of an Object for the index increment purpose
30 | container[part] = parsedName[1] ? {} : [];
31 | }
32 | storeValue(container[part], parsedName.slice(1), value);
33 | } else {
34 |
35 | // Increment Array index for `some[]` case
36 | if (!part) {
37 | part = container.length;
38 | }
39 |
40 | container[part] = value;
41 | }
42 | }
43 |
44 | var utils = {
45 | convert_meta_to_object: function (data) {
46 | var converted_data = {},
47 | element,
48 | property,
49 | key;
50 |
51 | for (key in data) {
52 | if (data.hasOwnProperty(key)) {
53 | element = key.split(/_(.+)?/)[0];
54 | property = key.split(/_(.+)?/)[1];
55 | if (converted_data[element] === undefined) {
56 | converted_data[element] = {};
57 | }
58 | converted_data[element][property] = data[key];
59 | }
60 | }
61 | return converted_data;
62 | },
63 | object_to_array: function (object) {
64 | var array = [],
65 | i;
66 |
67 | // Convert facets to array (JSON.stringify breaks arrays).
68 | if (typeof object === 'object') {
69 | for (i in object) {
70 | array.push(object[i]);
71 | }
72 | object = array;
73 | }
74 |
75 | return object;
76 | },
77 | checked: function (val1, val2, print) {
78 | "use strict";
79 |
80 | var checked = false;
81 | if (typeof val1 === 'object' && typeof val2 === 'string' && jQuery.inArray(val2, val1) !== -1) {
82 | checked = true;
83 | } else if (typeof val2 === 'object' && typeof val1 === 'string' && jQuery.inArray(val1, val2) !== -1) {
84 | checked = true;
85 | } else if (val1 === val2) {
86 | checked = true;
87 | } else if (val1 == val2) {
88 | checked = true;
89 | }
90 |
91 | if (print !== undefined && print) {
92 | return checked ? ' checked="checked"' : '';
93 | }
94 | return checked;
95 | },
96 | selected: function (val1, val2, print) {
97 | "use strict";
98 |
99 | var selected = false;
100 | if (typeof val1 === 'object' && typeof val2 === 'string' && jQuery.inArray(val2, val1) !== -1) {
101 | selected = true;
102 | } else if (typeof val2 === 'object' && typeof val1 === 'string' && jQuery.inArray(val1, val2) !== -1) {
103 | selected = true;
104 | } else if (val1 === val2) {
105 | selected = true;
106 | }
107 |
108 | if (print !== undefined && print) {
109 | return selected ? ' selected="selected"' : '';
110 | }
111 | return selected;
112 | },
113 | convert_hex: function (hex, opacity) {
114 | if (undefined === hex) {
115 | return '';
116 | }
117 | if (undefined === opacity) {
118 | opacity = 100;
119 | }
120 |
121 | hex = hex.replace('#', '');
122 | var r = parseInt(hex.substring(0, 2), 16),
123 | g = parseInt(hex.substring(2, 4), 16),
124 | b = parseInt(hex.substring(4, 6), 16),
125 | result = 'rgba(' + r + ',' + g + ',' + b + ',' + opacity / 100 + ')';
126 | return result;
127 | },
128 | debounce: function (callback, threshold) {
129 | var timeout;
130 | return function () {
131 | var context = this, params = arguments;
132 | window.clearTimeout(timeout);
133 | timeout = window.setTimeout(function () {
134 | callback.apply(context, params);
135 | }, threshold);
136 | };
137 | },
138 | throttle: function (callback, threshold) {
139 | var suppress = false,
140 | clear = function () {
141 | suppress = false;
142 | };
143 | return function () {
144 | if (!suppress) {
145 | callback();
146 | window.setTimeout(clear, threshold);
147 | suppress = true;
148 | }
149 | };
150 | },
151 | serializeForm: function (options) {
152 | $.extend({}, options);
153 |
154 | var values = {},
155 | settings = $.extend(true, {
156 | include: [],
157 | exclude: [],
158 | includeByClass: ''
159 | }, options);
160 |
161 | this.find(':input').each(function () {
162 |
163 | var parsedName;
164 |
165 | // Apply simple checks and filters
166 | if (!this.name || this.disabled ||
167 | isInArray(settings.exclude, this.name) ||
168 | (settings.include.length && !isInArray(settings.include, this.name)) ||
169 | this.className.indexOf(settings.includeByClass) === -1) {
170 | return;
171 | }
172 |
173 | // Parse complex names
174 | // JS RegExp doesn't support "positive look behind" :( that's why so weird parsing is used
175 | parsedName = this.name.replace(rName, '[$1').split('[');
176 | if (!parsedName[0]) {
177 | return;
178 | }
179 |
180 | if (this.checked ||
181 | isInArray(inputTypes, this.type) ||
182 | isInArray(inputNodes, this.nodeName.toLowerCase())) {
183 |
184 | // Simulate control with a complex name (i.e. `some[]`)
185 | // as it handled in the same way as Checkboxes should
186 | if (this.type === 'checkbox') {
187 | parsedName.push('');
188 | }
189 |
190 | // jQuery.val() is used to simplify of getting values
191 | // from the custom controls (which follow jQuery .val() API) and Multiple Select
192 | storeValue(values, parsedName, $(this).val());
193 | }
194 | });
195 |
196 | return values;
197 | }
198 |
199 | };
200 |
201 | // Import this module.
202 | window.WPJSFSP = window.WPJSFSP || {};
203 | window.WPJSFSP.utils = utils;
204 |
205 | $.fn.wpjsfspSerializeForm = utils.serializeForm;
206 | }(jQuery));
--------------------------------------------------------------------------------
/assets/sass/admin.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 |
6 | $plugin_prefix: 'wpjsfsp';
7 | $custom_select2_selector: 'wpjsfselect2';
8 | $tab-color: #E4E4E4;
9 |
10 | // Shared modules.
11 | @import 'modules/general';
12 | @import 'modules/fields';
13 | @import 'modules/select2';
14 | @import 'modules/tabs';
15 | @import 'modules/modal';
16 |
17 | // Custom pages.
18 | @import 'partials/admin/settings';
19 |
--------------------------------------------------------------------------------
/assets/sass/modules/_fields.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 |
6 | $plugin_prefix: 'plugin' !default;
7 | $custom_select2_selector: 'select2' !default;
8 |
9 | .#{$plugin_prefix}-field {
10 | position: relative;
11 |
12 | margin-bottom: 1em;
13 |
14 | > label {
15 | display: block;
16 | font-weight: bold;
17 | }
18 |
19 | .#{$plugin_prefix}-doclink {
20 | font-size: 16px;
21 | line-height: 20px;
22 | }
23 |
24 | }
25 |
26 | /**
27 | * Sections
28 | */
29 | .#{$plugin_prefix}-field-section {
30 |
31 | }
32 |
33 | /**
34 | * Heading & separator fields
35 | */
36 | .#{$plugin_prefix}-field-heading,
37 | .#{$plugin_prefix}-field-separator {
38 | h3 {
39 | //font-size: 1.2em;
40 | // margin-top: 0;
41 | // margin-bottom: 0;
42 | }
43 |
44 | .#{$plugin_prefix}-desc {
45 | display: none;
46 | }
47 |
48 | h3 + hr {
49 | // margin-top: 1em; // Reset
50 | // margin-bottom: 2em;
51 | }
52 |
53 | hr + h3 {
54 | // margin-top: 1em; // Reset to wp default.
55 | // margin-bottom: 1em; // Reset to wp default.
56 | }
57 | }
58 |
59 | .#{$plugin_prefix}-field-hidden {
60 | display: none;
61 | }
62 |
63 | .#{$plugin_prefix}-field-editor {
64 | #insert-media-button {
65 | display: none;
66 | }
67 | }
68 |
69 | .#{$plugin_prefix}-field-link {
70 |
71 | max-width: 400;
72 |
73 | input {
74 | margin-right: 24px;
75 | display: block;
76 | width: 100%;
77 | }
78 |
79 | button.dashicons {
80 | position: absolute;
81 | right: 0;
82 | width: 1.5em;
83 | height: 1.5em;
84 | line-height: 1;
85 | padding: 0;
86 | font-size: 16px;
87 | vertical-align: sub;
88 | margin-top: 1px;
89 | box-shadow: 0 0 0 #cccccc;
90 | }
91 | }
92 |
93 | /**
94 | * Select fields
95 | */
96 | .#{$plugin_prefix}-field-select {
97 | option.bold {
98 | font-weight: bold;
99 | font-size: 1.125em;
100 | }
101 | }
102 |
103 | /**
104 | * Checkbox fields
105 | */
106 | .#{$plugin_prefix}-field-checkbox {
107 | position: relative;
108 |
109 | label {
110 | margin-left: 1.5em;
111 |
112 | &.#{$plugin_prefix}-desc {
113 | display: inline;
114 | font-weight: inherit;
115 | font-size: inherit;
116 | margin: 0 0 1em;
117 | }
118 | }
119 |
120 | input[type="checkbox"] {
121 | position: absolute;
122 | top: .25em;
123 | }
124 | }
125 |
126 | /**
127 | * Multicheck & Radio fields
128 | */
129 | .#{$plugin_prefix}-field-multicheck,
130 | .#{$plugin_prefix}-field-radio {
131 |
132 | input, label {
133 | line-height: 1em;
134 | margin-bottom: 10px;
135 | }
136 |
137 | input[type="radio"] {
138 | display: inline-block;
139 | margin-right: .25em;
140 | }
141 |
142 | input + label {
143 | font-weight: normal;
144 | display: inline-block;
145 | }
146 |
147 | label:first-child {
148 | font-weight: bold;
149 | margin: 0 0 10px;
150 | }
151 |
152 | > p.#{$plugin_prefix}-desc {
153 | margin: 0 0 .5em;
154 | }
155 |
156 | }
157 |
158 | /**
159 | * Range & range slider fields
160 | */
161 | .#{$plugin_prefix}-field-range,
162 | .#{$plugin_prefix}-field-rangeslider {
163 | input[type="range"] {
164 | vertical-align: middle;
165 | }
166 |
167 | .#{$plugin_prefix}-range-manual {
168 | padding-right: 25px;
169 | text-align: right;
170 | width: 80px;
171 | }
172 |
173 | .#{$plugin_prefix}-range-value-unit {
174 | position: relative;
175 | display: inline-block;
176 | margin-left: -30px;
177 | margin-right: 10px;
178 | width: 20px;
179 | text-align: left;
180 | top: .125em;
181 | }
182 | }
183 |
184 | /**
185 | * Image fields
186 | */
187 | .#{$plugin_prefix}-image-field {
188 | .#{$plugin_prefix}-image-field .#{$plugin_prefix}-image-select,
189 | &.#{$plugin_prefix}-image-empty .#{$plugin_prefix}-image-preview {
190 | display: none;
191 | }
192 |
193 | &.#{$plugin_prefix}-image-empty .#{$plugin_prefix}-image-select {
194 | display: block;
195 | }
196 |
197 | .#{$plugin_prefix}-image-preview-img {
198 | float: left;
199 | line-height: 0;
200 | margin: 5px 0;
201 | }
202 |
203 | .#{$plugin_prefix}-image-preview-img img {
204 | max-width: 60px;
205 | }
206 |
207 | .#{$plugin_prefix}-image-preview select {
208 | margin: 8px 0 8px 10px;
209 | width: 200px;
210 | }
211 |
212 | .#{$plugin_prefix}-image-edit {
213 | margin: 0 0 0 11px;
214 | }
215 |
216 | .#{$plugin_prefix}-image-replace,
217 | .#{$plugin_prefix}-image-remove {
218 | margin: 0 0 0 8px;
219 | }
220 | }
221 |
222 | /**
223 | * Conditions field
224 | */
225 | .#{$plugin_prefix}-field-conditions {
226 |
227 | .facet-builder {
228 |
229 | .#{$plugin_prefix}-doclink {
230 | display: none;
231 | }
232 |
233 |
234 | p {
235 | margin: 0 0 1em;
236 | }
237 | a {
238 | text-decoration: none;
239 | }
240 |
241 | .facet-groups {
242 |
243 | display: none;
244 |
245 | .facet-group-wrap {
246 |
247 | .facet-group {
248 | box-shadow: 0 1px 0 #ccc;
249 | color: #555;
250 | border: 1px solid #ccc;
251 | background: #f7f7f7;
252 | }
253 |
254 | &:last-child .and,
255 | .add-or {
256 | em,
257 | a,
258 | button {
259 | color: #0073aa;
260 | cursor: pointer;
261 |
262 | &::before {
263 | content: "+ ";
264 | }
265 |
266 | }
267 |
268 | }
269 |
270 | }
271 |
272 | }
273 |
274 | .facet-list {
275 | }
276 |
277 | .facet {
278 | position: relative;
279 | padding: 12px 30px 6px 10px;
280 | border-bottom: 1px solid #e1e1e1;
281 | border-top: 1px solid #fff;
282 |
283 | &:first-child {
284 | border-top: 0;
285 |
286 | .or {
287 | display: none;
288 | }
289 | }
290 |
291 | &::before,
292 | &::after {
293 | display: table;
294 | content: "";
295 | line-height: 0;
296 | }
297 |
298 | &::after {
299 | clear: both;
300 | }
301 |
302 | }
303 |
304 | .#{$plugin_prefix}-field {
305 | margin-bottom: 0.5em;
306 | }
307 |
308 | .facet-col {
309 | float: left;
310 | margin-right: 20px;
311 | padding-bottom: 6px;
312 | position: relative;
313 | min-width: 175px;
314 |
315 | select,
316 | input {
317 | margin: 0;
318 | max-width: 100%;
319 | }
320 | }
321 |
322 | .facet-target {
323 |
324 | position: relative;
325 | //max-width: 240px;
326 |
327 | * {
328 | box-sizing: border-box;
329 | }
330 |
331 |
332 | select,
333 | .#{$custom_select2_selector}-container .#{$custom_select2_selector}-selection {
334 | padding-left: 28px;
335 |
336 | // Rendered Option
337 | .#{$custom_select2_selector}-selection__rendered {
338 | padding-left: 3px;
339 | }
340 |
341 | }
342 |
343 | .#{$plugin_prefix}-not-operand {
344 | cursor: pointer;
345 | position: absolute;
346 | left: 2px;
347 | top: 2px;
348 | z-index: 10;
349 | //width: 23px;
350 | line-height: 24px;
351 | height: 25px;
352 |
353 | //padding: 0;
354 | background: #f7f7f7;
355 | border: 1px solid transparent;
356 | border-radius: 2px 0 0 2px;
357 | border-right: 1px solid #ddd;
358 | text-align: center;
359 |
360 | span {
361 | font-size: 1.25em;
362 | }
363 |
364 | &::before {
365 | color: #555;
366 | font-size: 16px;
367 | line-height: 24px;
368 | }
369 |
370 | input[type="checkbox"] {
371 | display: none;
372 | }
373 |
374 | &:focus {
375 | outline: none;
376 | border: 1px solid #5b9dd9;
377 | box-shadow: 0 0 2px rgba(30, 140, 190, 0.8);
378 | }
379 |
380 | }
381 |
382 | &.not-operand-checked {
383 |
384 | .#{$plugin_prefix}-not-operand {
385 | span,
386 | &::before {
387 | color: #a00;
388 |
389 | }
390 | }
391 |
392 | select,
393 | .#{$custom_select2_selector}-container .#{$custom_select2_selector}-selection {
394 | padding-left: 58px;
395 | }
396 |
397 | }
398 |
399 | .#{$custom_select2_selector}-container-active {
400 | .#{$custom_select2_selector}-choices,
401 | .#{$custom_select2_selector}-single {
402 | border-color: #5b9dd9;
403 | box-shadow: 0 0 2px rgba(30, 140, 190, 0.8);
404 | }
405 | }
406 |
407 | }
408 |
409 | .facet-actions {
410 | position: absolute;
411 | right: 6px;
412 | top: 18px;
413 |
414 | button {
415 | border: 0;
416 | padding: 0;
417 | background: none;
418 | margin-left: 5px;
419 | }
420 | }
421 |
422 | .dashicons-plus-alt,
423 | .dashicons-dismiss {
424 | color: #999;
425 | }
426 |
427 | /* + AND + OR link stylings */
428 | .or {
429 | color: #484848;
430 | font-weight: 500;
431 | margin-left: -21px;
432 | left: 50%;
433 | position: absolute;
434 | top: -6px;
435 | font-style: normal;
436 | line-height: 10px;
437 | text-transform: uppercase;
438 | }
439 |
440 | .add-or {
441 | border-top: 1px solid #fff;
442 | text-align: center;
443 |
444 | > .add {
445 | left: -6.5px;
446 | position: relative;
447 | top: -9px;
448 | }
449 | }
450 |
451 | .and {
452 | border-bottom: 1px dashed #e1e1e1;
453 | margin: .5em 0 1.7em;
454 | text-align: center;
455 | }
456 |
457 | .or,
458 | .add-or > .add {
459 | background: #f7f7f7;
460 | font-size: 1.1em;
461 | padding: 0 10px;
462 | }
463 |
464 | .and, .add-or {
465 | em,
466 | a,
467 | button,
468 | label {
469 | background: transparent;
470 | font-size: 1.1em;
471 | font-style: normal;
472 | margin: 0 10px;
473 | padding: 0 10px;
474 | position: relative;
475 | top: 9px;
476 | text-transform: uppercase;
477 | box-shadow: none;
478 | color: #484848;
479 | cursor: default;
480 | border: 0;
481 |
482 | }
483 |
484 | em {
485 | color: #484848;
486 | }
487 | }
488 |
489 | }
490 |
491 | .no-facet-groups {
492 | display: block;
493 | .facet-target {
494 | max-width: 100%;
495 | }
496 | }
497 |
498 | /* Conditionals */
499 | .has-conditions {
500 |
501 | .facet-groups {
502 | display: block;
503 | }
504 |
505 | .no-facet-groups {
506 | display: none;
507 | }
508 |
509 | }
510 |
511 | .#{$plugin_prefix}-field-select2 {
512 | select {
513 | width: 100% !important;
514 | }
515 | }
516 |
517 | }
518 |
519 | /**
520 | * License fields.
521 | */
522 | .#{$plugin_prefix}-field-license_key {
523 | background: #fafafa;
524 | padding: 14px;
525 | border-top: 2px solid #999;
526 | border-bottom: 2px solid #999;
527 | margin: 0 -14px 14px;
528 |
529 | p {
530 | font-size: 13px;
531 | margin-top: 0;
532 | }
533 |
534 | a {
535 | color: #444;
536 | }
537 |
538 | a:hover {
539 | text-decoration: none;
540 | }
541 |
542 | span.wpjsfsp-license-status {
543 | margin-left: 5px;
544 | margin-right: 5px;
545 | }
546 |
547 | .#{$plugin_prefix}-license-messages {
548 | p:last-child {
549 | margin-bottom: 0;
550 | }
551 | }
552 |
553 | &.#{$plugin_prefix}-license-expires-soon-notice {
554 | //background-color: #00a0d2;
555 | //color: #fff;
556 | //border-color: #00a0d2;
557 | border-color: #dc3232;
558 | }
559 |
560 | &.#{$plugin_prefix}-license-valid-notice {
561 | //background-color: #60c560;
562 | border-color: #46b450;
563 | //color: #fff;
564 | .wpjsfsp-license-status {
565 | color: #46b450;
566 | }
567 | }
568 |
569 | &.#{$plugin_prefix}-license-inactive-notice {
570 | //background-color: #0073aa;
571 | border-color: #0073aa;
572 | //color: #fff;
573 | }
574 |
575 | &.#{$plugin_prefix}-license-expiration-date-notice {
576 |
577 | }
578 |
579 | &.#{$plugin_prefix}-license-expired-notice {
580 | background-color: #e24e4e;
581 | color: #fff;
582 | border-color: #dc3232;
583 | }
584 |
585 | &.#{$plugin_prefix}-license-error-notice,
586 | &.#{$plugin_prefix}-license-missing-notice,
587 | &.#{$plugin_prefix}-license-invalid-notice,
588 | &.#{$plugin_prefix}-license-site_inactive-notice,
589 | &.#{$plugin_prefix}-license-item_name_mismatch-notice {
590 | background-color: #ffebcd;
591 | border-color: #dc3232;
592 | }
593 |
594 | &.#{$plugin_prefix}-license-expired-notice {
595 | a {
596 | color: #fff;
597 |
598 | &:hover {
599 | text-decoration: none;
600 | }
601 | }
602 | }
603 |
604 | }
605 |
606 | [data-#{$plugin_prefix}-dependencies] {
607 | display: none;
608 | }
--------------------------------------------------------------------------------
/assets/sass/modules/_general.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 |
6 | button.no-button {
7 | border: 0;
8 | padding: 0;
9 | background: none;
10 | cursor: pointer;
11 |
12 | &.link-button {
13 | color: #0073aa;
14 | &:hover {
15 | color: #00a0d2;
16 | }
17 | }
18 |
19 | &.delete-button {
20 | color: #a00;
21 | &:hover {
22 | color: #f00;
23 | }
24 | }
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/assets/sass/modules/_modal.scss:
--------------------------------------------------------------------------------
1 | $plugin_prefix: 'plugin' !default;
2 |
3 | .#{$plugin_prefix}-modal-background {
4 |
5 | &, &:before, &:after,
6 | & *, & *:before, & *:after {
7 | -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
8 | -moz-box-sizing: border-box; /* Firefox, other Gecko */
9 | box-sizing: border-box;
10 | }
11 |
12 |
13 | display: none;
14 | position: fixed;
15 | top: 0;
16 | left: 0;
17 | right: 0;
18 | bottom: 0;
19 | height: 100%;
20 | width: 100%;
21 | background: rgba(0,0,0,0.70);
22 | z-index: 100100;
23 | overflow-y: scroll;
24 |
25 | .#{$plugin_prefix}-modal-wrap {
26 | position: absolute;
27 | top: 60px;
28 | margin-bottom: 60px;
29 | left: 50%;
30 | width: 550px;
31 | margin-left: -300px;
32 | background-color: #fff;
33 | box-shadow: 0 3px 6px rgba(0,0,0,.3);
34 | z-index: 100105;
35 | transition: height .2s, margin-top .2s;
36 |
37 | @media screen and ( max-width: 520px ) {
38 | width: auto;
39 | margin-left: 0;
40 | top: 10px;
41 | right: 10px;
42 | bottom: 10px;
43 | left: 10px;
44 | }
45 | }
46 |
47 | .#{$plugin_prefix}-modal-header {
48 | position: absolute;
49 | top: 0;
50 | right: 0;
51 | left: 0;
52 | height: 36px;
53 | padding: 0 36px 0 16px;
54 | font-size: 18px;
55 | font-weight: 600;
56 | line-height: 36px;
57 | background: #fcfcfc;
58 | border-bottom: 1px solid #dfdfdf;
59 |
60 | .#{$plugin_prefix}-modal-close {
61 | position: absolute;
62 | top: 0;
63 | right: 0;
64 | width: 36px;
65 | height: 36px;
66 | padding: 0;
67 | color: #666;
68 | text-align: center;
69 | background: 0 0;
70 | border: none;
71 | cursor: pointer;
72 |
73 | &::before {
74 | font: 400 20px/36px dashicons;
75 | vertical-align: top;
76 | speak: none;
77 | -webkit-font-smoothing: antialiased;
78 | -moz-osx-font-smoothing: grayscale;
79 | width: 36px;
80 | height: 36px;
81 | content: '\f158';
82 | }
83 | }
84 |
85 | }
86 |
87 | .#{$plugin_prefix}-modal-content {
88 | padding: 52px 16px 60px;
89 |
90 | div.error {
91 | margin: 0 0 10px;
92 | }
93 | p {
94 | margin-top: 0;
95 | }
96 | textarea {
97 | width: 100%;
98 | }
99 |
100 | @media screen and (max-width: 782px) {
101 | padding: 50px 16px 60px;
102 | }
103 | }
104 |
105 | .#{$plugin_prefix}-modal-footer {
106 | position: absolute;
107 | bottom: 0;
108 | left: 0;
109 | right: 0;
110 | padding: 8px 16px;
111 | background: #fcfcfc;
112 | border-top: 1px solid #dfdfdf;
113 |
114 | .cancel {
115 | line-height: 25px;
116 | float: left;
117 |
118 | .no-button {
119 | border: 0;
120 | padding: 0;
121 | background: none;
122 | cursor: pointer;
123 |
124 | &.link-button {
125 | color: #0073aa;
126 | text-decoration: underline;
127 | }
128 |
129 | }
130 |
131 | .submitdelete {
132 | text-decoration: none;
133 | padding: 1px 2px;
134 | }
135 |
136 | @media screen and (max-width: 782px) {
137 | line-height: 32px;
138 | }
139 | }
140 |
141 | .#{$plugin_prefix}-submit {
142 | line-height: 23px;
143 | float: right;
144 |
145 | button {
146 | float: right;
147 | margin-bottom: 0;
148 |
149 | }
150 |
151 | .spinner {
152 | float: left;
153 | vertical-align: middle;
154 | }
155 |
156 | }
157 | }
158 |
159 | &.tabbed-content {
160 |
161 | .#{$plugin_prefix}-modal-content {
162 | padding: 36px 0 44px;
163 | }
164 | }
165 |
166 | }
--------------------------------------------------------------------------------
/assets/sass/modules/_select2.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 |
6 | $plugin_prefix: 'plugin' !default;
7 | $custom_select2_selector: 'select2' !default;
8 |
9 | /* jQuery select2 Styles.
10 | The bulk of this is to style jquery select2 to better resemble the default WP dashboard inputs.
11 | */
12 |
13 | .#{$plugin_prefix}-field-select2 {
14 |
15 | //region Select2 Core Styles
16 |
17 | // These are here for the namespaced #{$custom_select2_selector} and so that we can properly address issues when other plugins do things wrong.
18 | .#{$custom_select2_selector}-container {
19 | box-sizing: border-box;
20 |
21 | display: inline-block;
22 | margin: 0;
23 | position: relative;
24 | vertical-align: middle;
25 |
26 | @import "../vendor/select2/single";
27 | @import "../vendor/select2/multiple";
28 | }
29 |
30 | @import "../vendor/select2/dropdown";
31 |
32 | .#{$custom_select2_selector}-close-mask {
33 | border: 0;
34 | margin: 0;
35 | padding: 0;
36 | display: block;
37 | position: fixed;
38 | left: 0;
39 | top: 0;
40 | min-height: 100%;
41 | min-width: 100%;
42 | height: auto;
43 | width: auto;
44 | opacity: 0;
45 | z-index: 99;
46 |
47 | // styles required for IE to work
48 |
49 | background-color: #fff;
50 | filter: alpha(opacity=0);
51 | }
52 |
53 | .#{$custom_select2_selector}-hidden-accessible {
54 | border: 0 !important;
55 | clip: rect(0 0 0 0) !important;
56 | height: 1px !important;
57 | margin: -1px !important;
58 | overflow: hidden !important;
59 | padding: 0 !important;
60 | position: absolute !important;
61 | width: 1px !important;
62 | }
63 |
64 | @import "../vendor/select2/theme/default/layout";
65 | @import "../vendor/select2/theme/classic/layout";
66 | //endregion Select2 Core Styles
67 |
68 | > .#{$custom_select2_selector}-container--below.#{$custom_select2_selector}-container--open + .#{$custom_select2_selector}-container--open,
69 | > .#{$custom_select2_selector}-container--below.#{$custom_select2_selector}-container--open + .#{$plugin_prefix}-desc + .#{$custom_select2_selector}-container--open {
70 | position: absolute !important;
71 | }
72 |
73 | position: relative;
74 |
75 | // All Select2 Containers - Wraps Both Selectbox & Dropdown Elements
76 | .#{$custom_select2_selector}-container {
77 |
78 | // Selectbox
79 | .#{$custom_select2_selector}-selection {
80 | margin: 1px;
81 | font-size: 14px;
82 | border-radius: 0;
83 | box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.07);
84 | border-color: #ddd;
85 | transition: 0.05s border-color ease-in-out;
86 |
87 | }
88 | &.#{$custom_select2_selector}-container--focus {
89 |
90 | .#{$custom_select2_selector}-selection {
91 | outline: none;
92 | border-color: #5b9dd9;
93 | box-shadow: 0 0 2px rgba(30, 140, 190, 0.8);
94 | }
95 | }
96 | // Single Select
97 | .#{$custom_select2_selector}-selection--single {
98 |
99 | // Rendered Option
100 | .#{$custom_select2_selector}-selection__rendered {
101 | //padding-left: 0;
102 | }
103 |
104 | }
105 |
106 | // Multiple Select
107 | .#{$custom_select2_selector}-selection--multiple {
108 | overflow-y: auto;
109 | max-height: 150px;
110 | min-height: 28px;
111 | line-height: 16px;
112 | font-size: 12px;
113 |
114 | .#{$custom_select2_selector}-selection__clear {
115 | margin-right: 3px;
116 | }
117 |
118 | .#{$custom_select2_selector}-selection__rendered {
119 |
120 | }
121 |
122 | .#{$custom_select2_selector}-search--inline {
123 | margin: 0;
124 | // Search Field
125 | .#{$custom_select2_selector}-search__field {
126 | border-color: #ddd;
127 | padding: 3px 5px 0;
128 | min-width: 5em;
129 | width: 100% !important;
130 | }
131 | }
132 |
133 | .#{$custom_select2_selector}-selection__choice {
134 | margin-top: 4px;
135 | margin-bottom: 0;
136 | }
137 |
138 | }
139 |
140 | // Dropdown
141 | .#{$custom_select2_selector}-dropdown {
142 | margin: 0 1px;
143 | border-color: #ddd;
144 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);
145 | // Compensate for the margin applied to the Selectbox.
146 | max-width: calc(100% - 4px);
147 | position: relative;
148 |
149 | // Search Field
150 | .#{$custom_select2_selector}-search__field {
151 | border-color: #ddd;
152 | padding: 3px 5px;
153 | min-width: 5em;
154 | }
155 |
156 | // Results
157 | .#{$custom_select2_selector}-results {
158 |
159 | // Each result set. Can be nested.
160 | .#{$custom_select2_selector}-results__option {
161 | padding: 3px 6px;
162 | margin: 0;
163 |
164 | &[aria-selected=true] {
165 | }
166 |
167 | }
168 | .#{$custom_select2_selector}-results__option[role=group] {
169 | padding: 3px 0 0;
170 |
171 | .#{$custom_select2_selector}-results__group {
172 | padding: 0 6px;
173 | }
174 | }
175 |
176 | .#{$custom_select2_selector}-results__options--nested {
177 | padding: 3px 6px 0;
178 | }
179 |
180 | // Hover
181 | .#{$custom_select2_selector}-results__option--highlighted {
182 | background: #3e86d0;
183 | }
184 |
185 | }
186 |
187 | }
188 |
189 | }
190 |
191 | .#{$custom_select2_selector}-container + .#{$custom_select2_selector}-container--open {
192 | top: inherit !important;
193 | }
194 |
195 | }
--------------------------------------------------------------------------------
/assets/sass/modules/_tabs.scss:
--------------------------------------------------------------------------------
1 | $tab-color: #E4E4E4 !default;
2 | $plugin_prefix: 'plugin' !default;
3 |
4 | .#{$plugin_prefix}-tabs-container {
5 | box-sizing: border-box;
6 |
7 | > * {
8 | box-sizing: border-box;
9 | }
10 |
11 | position: relative;
12 |
13 | > ul.tabs {
14 | margin: 0;
15 |
16 | .tab {
17 | font-size: 1.2em;
18 |
19 | a {
20 | padding: 8px 16px;
21 | border: 0;
22 | display: block;
23 | text-decoration: none;
24 | &:focus {
25 | box-shadow: none;
26 | }
27 | }
28 |
29 | }
30 | }
31 |
32 | > .tab-content {
33 |
34 | display: none;
35 | padding: 16px;
36 |
37 | &.active {
38 | display: block;
39 | }
40 |
41 | .form-table {
42 | display: block;
43 |
44 | &:first-child {
45 | margin-top: 0;
46 | }
47 | }
48 | }
49 |
50 | &.horizontal-tabs {
51 | display: block;
52 |
53 | > ul.tabs {
54 | > li.tab {
55 |
56 | display: inline-block;
57 | padding: 0;
58 | margin: 0;
59 |
60 | a {
61 | padding: .5em 1em;
62 |
63 | }
64 |
65 | }
66 |
67 | }
68 |
69 | > .tab-content {
70 | padding-top: 16px;
71 | }
72 | }
73 |
74 | &.vertical-tabs {
75 | min-height: 100px;
76 | //padding-left: 150px;
77 | //width: calc(100% - 150px);
78 | padding-left: 140px;
79 | width: 100%;
80 |
81 | > ul.tabs {
82 | width: 140px;
83 | min-height: 100%;
84 | display: block;
85 | position: absolute;
86 | left: 0;
87 | top: 0;
88 | margin: 0;
89 | //background: #23282D;
90 | border-top: 0;
91 | border-right: 1px solid #DFDFDF;
92 |
93 | > .tab {
94 | margin: 0;
95 | display: block;
96 | border-bottom: 1px solid #eee;
97 |
98 | a {
99 | background: #FCFCFC;
100 | color: #000;
101 | display: block;
102 | }
103 |
104 | &:hover a, a:focus {
105 | background-color: #0073AA;
106 | }
107 |
108 | &.active {
109 |
110 | a {
111 | background-color: #32373C;
112 | color: #fff;
113 | }
114 | }
115 |
116 | &:first-child {
117 | margin-top: 8px;
118 | }
119 |
120 | }
121 | }
122 |
123 | > .tab-content {
124 | }
125 |
126 | }
127 |
128 | &.link-tabs {
129 |
130 | > ul.tabs {
131 | display: block;
132 |
133 | > li.tab {
134 | display: inline-block;
135 |
136 | a {
137 | display: inline;
138 | padding: 0 0.25em;
139 | color: #0073aa;
140 | }
141 |
142 | &.active a,
143 | a:active {
144 | color: #000;
145 | }
146 |
147 | &.active a,
148 | &:hover a,
149 | a:active {
150 | text-decoration: underline;
151 | }
152 |
153 | &::after {
154 | display: inline-block;
155 | content: "|";
156 | margin: 0 0.25em;
157 | }
158 |
159 | &:last-child::after {
160 | content: "";
161 | }
162 |
163 | }
164 | }
165 |
166 | }
167 |
168 | &.sub-tabs {
169 | > .tab-content {
170 | padding: 16px 0 0;
171 | }
172 | }
173 |
174 |
175 | &[data-tab-count="0"],
176 | &[data-tab-count="1"] {
177 | &.horizontal-tabs {
178 | > ul.tabs {
179 | display: none;
180 | }
181 | }
182 |
183 | &.sub-tabs {
184 | > .tab-content {
185 | padding-top: 0;
186 | }
187 | }
188 | }
189 |
190 |
191 | }
--------------------------------------------------------------------------------
/assets/sass/partials/admin/_settings.scss:
--------------------------------------------------------------------------------
1 | /*!
2 | * @copyright Copyright (c) 2017, Code Atlantic
3 | * @author Daniel Iser
4 | */
5 |
6 | #wpjsfsp-settings {
7 |
8 | // Custom styles here.
9 |
10 | }
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/_dropdown.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-dropdown {
2 | background-color: white;
3 |
4 | border: 1px solid #aaa;
5 | border-radius: 4px;
6 |
7 | box-sizing: border-box;
8 |
9 | display: block;
10 |
11 | position: absolute;
12 | left: -100000px;
13 |
14 | width: 100%;
15 |
16 | z-index: 1051;
17 | }
18 |
19 | .wpjsfselect2-results {
20 | display: block;
21 | }
22 |
23 | .wpjsfselect2-results__options {
24 | list-style: none;
25 | margin: 0;
26 | padding: 0;
27 | }
28 |
29 | .wpjsfselect2-results__option {
30 | padding: 6px;
31 |
32 | user-select: none;
33 | -webkit-user-select: none;
34 |
35 | &[aria-selected] {
36 | cursor: pointer;
37 | }
38 | }
39 |
40 | .wpjsfselect2-container--open .wpjsfselect2-dropdown {
41 | left: 0;
42 | }
43 |
44 | .wpjsfselect2-container--open .wpjsfselect2-dropdown--above {
45 | border-bottom: none;
46 | border-bottom-left-radius: 0;
47 | border-bottom-right-radius: 0;
48 | }
49 |
50 | .wpjsfselect2-container--open .wpjsfselect2-dropdown--below {
51 | border-top: none;
52 | border-top-left-radius: 0;
53 | border-top-right-radius: 0;
54 | }
55 |
56 | .wpjsfselect2-search--dropdown {
57 | display: block;
58 | padding: 4px;
59 |
60 | .wpjsfselect2-search__field {
61 | padding: 4px;
62 | width: 100%;
63 | box-sizing: border-box;
64 |
65 | &::-webkit-search-cancel-button {
66 | -webkit-appearance: none;
67 | }
68 | }
69 |
70 | &.wpjsfselect2-search--hide {
71 | display: none;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/_multiple.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-selection--multiple {
2 | box-sizing: border-box;
3 |
4 | cursor: pointer;
5 | display: block;
6 |
7 | min-height: 32px;
8 |
9 | user-select: none;
10 | -webkit-user-select: none;
11 |
12 | .wpjsfselect2-selection__rendered {
13 | display: inline-block;
14 | overflow: hidden;
15 | padding-left: 8px;
16 | text-overflow: ellipsis;
17 | white-space: nowrap;
18 | }
19 | }
20 |
21 | .wpjsfselect2-search--inline {
22 | float: left;
23 |
24 | .wpjsfselect2-search__field {
25 | box-sizing: border-box;
26 | border: none;
27 | font-size: 100%;
28 | margin-top: 5px;
29 | padding: 0;
30 |
31 | &::-webkit-search-cancel-button {
32 | -webkit-appearance: none;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/_single.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-selection--single {
2 | box-sizing: border-box;
3 |
4 | cursor: pointer;
5 | display: block;
6 |
7 | height: 28px;
8 |
9 | user-select: none;
10 | -webkit-user-select: none;
11 |
12 | .wpjsfselect2-selection__rendered {
13 | display: block;
14 | padding-left: 8px;
15 | padding-right: 20px;
16 |
17 | overflow: hidden;
18 | text-overflow: ellipsis;
19 | white-space: nowrap;
20 | }
21 |
22 | .wpjsfselect2-selection__clear {
23 | position: relative;
24 | }
25 | }
26 |
27 | &[dir="rtl"] {
28 | .wpjsfselect2-selection--single {
29 | .wpjsfselect2-selection__rendered {
30 | padding-right: 8px;
31 | padding-left: 20px;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/core.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-container {
2 | box-sizing: border-box;
3 |
4 | display: inline-block;
5 | margin: 0;
6 | position: relative;
7 | vertical-align: middle;
8 |
9 | @import "single";
10 | @import "multiple";
11 | }
12 |
13 | @import "dropdown";
14 |
15 | .wpjsfselect2-close-mask {
16 | border: 0;
17 | margin: 0;
18 | padding: 0;
19 | display: block;
20 | position: fixed;
21 | left: 0;
22 | top: 0;
23 | min-height: 100%;
24 | min-width: 100%;
25 | height: auto;
26 | width: auto;
27 | opacity: 0;
28 | z-index: 99;
29 |
30 | // styles required for IE to work
31 |
32 | background-color: #fff;
33 | filter: alpha(opacity=0);
34 | }
35 |
36 | .wpjsfselect2-hidden-accessible {
37 | border: 0 !important;
38 | clip: rect(0 0 0 0) !important;
39 | height: 1px !important;
40 | margin: -1px !important;
41 | overflow: hidden !important;
42 | padding: 0 !important;
43 | position: absolute !important;
44 | width: 1px !important;
45 | }
46 |
47 | @import "theme/default/layout";
48 | @import "theme/classic/layout";
49 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/mixins/_gradients.scss:
--------------------------------------------------------------------------------
1 | // https://github.com/twbs/bootstrap-sass/blob/3.3-stable/assets/stylesheets/bootstrap/mixins/_gradients.scss#L17-L27
2 |
3 | // Vertical gradient, from top to bottom
4 | //
5 | // Creates two color stops, start and end, by specifying a color and position for each color stop.
6 | // Color stops are not available in IE9 and below.
7 | @mixin gradient-vertical($start-color: #555, $end-color: #333, $start-percent: 0%, $end-percent: 100%) {
8 | background-image: -webkit-linear-gradient(top, $start-color $start-percent, $end-color $end-percent); // Safari 5.1-6, Chrome 10+
9 | background-image: -o-linear-gradient(top, $start-color $start-percent, $end-color $end-percent); // Opera 12
10 | background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+
11 | background-repeat: repeat-x;
12 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#{ie-hex-str($start-color)}', endColorstr='#{ie-hex-str($end-color)}', GradientType=0); // IE9 and down
13 | }
14 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/classic/_defaults.scss:
--------------------------------------------------------------------------------
1 | $remove-color: #888 !default;
2 | $remove-hover-color: #555 !default;
3 | $remove-width: 20px !default;
4 |
5 | $selection-color: #444 !default;
6 |
7 | $border-color: #aaa !default;
8 | $border-radius: 4px !default;
9 |
10 | $focus-border-color: #5897fb !default;
11 |
12 | $container-height: 28px !default;
13 |
14 | $selection-bg-top-color: white !default;
15 | $selection-bg-bottom-color: #eeeeee !default;
16 |
17 | $container-placeholder-color: #999 !default;
18 |
19 | $container-focus-border-color: blue !default;
20 |
21 | $selection-opened-bg-top-color: $selection-bg-bottom-color !default;
22 | $selection-opened-bg-bottom-color: $selection-bg-top-color !default;
23 |
24 | $dropdown-z-index: 1 !default;
25 |
26 | $dropdown-bg-color: $selection-bg-top-color !default;
27 |
28 | $results-max-height: 200px !default;
29 | $results-nested-padding: 20px !default;
30 |
31 | $results-choice-bg-hover-color: #3875d7 !default;
32 | $results-choice-fg-hover-color: white !default;
33 |
34 | $results-choice-fg-unselectable-color: grey !default;
35 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/classic/_multiple.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-selection--multiple {
2 | background-color: white;
3 |
4 | border: 1px solid $border-color;
5 | border-radius: $border-radius;
6 |
7 | cursor: text;
8 |
9 | outline: 0;
10 |
11 | &:focus {
12 | border: 1px solid $focus-border-color;
13 | }
14 |
15 | .wpjsfselect2-selection__rendered {
16 | list-style: none;
17 | margin: 0;
18 | padding: 0 5px;
19 | }
20 |
21 | .wpjsfselect2-selection__clear {
22 | display: none;
23 | }
24 |
25 | .wpjsfselect2-selection__choice {
26 | background-color: #e4e4e4;
27 |
28 | border: 1px solid $border-color;
29 | border-radius: $border-radius;
30 |
31 | cursor: default;
32 |
33 | float: left;
34 |
35 | margin-right: 5px;
36 | margin-top: 5px;
37 | padding: 0 5px;
38 | }
39 |
40 | .wpjsfselect2-selection__choice__remove {
41 | color: $remove-color;
42 | cursor: pointer;
43 |
44 | display: inline-block;
45 | font-weight: bold;
46 |
47 | margin-right: 2px;
48 |
49 | &:hover {
50 | color: $remove-hover-color;
51 | }
52 | }
53 | }
54 |
55 | &[dir="rtl"] {
56 | .wpjsfselect2-selection--multiple {
57 | .wpjsfselect2-selection__choice {
58 | float: right;
59 | }
60 |
61 | .wpjsfselect2-selection__choice {
62 | margin-left: 5px;
63 | margin-right: auto;
64 | }
65 |
66 | .wpjsfselect2-selection__choice__remove {
67 | margin-left: 2px;
68 | margin-right: auto;
69 | }
70 | }
71 | }
72 |
73 | &.wpjsfselect2-container--open {
74 | .wpjsfselect2-selection--multiple {
75 | border: 1px solid $focus-border-color;
76 | }
77 |
78 | &.wpjsfselect2-container--above {
79 | .wpjsfselect2-selection--multiple {
80 | border-top: none;
81 | border-top-left-radius: 0;
82 | border-top-right-radius: 0;
83 | }
84 | }
85 |
86 | &.wpjsfselect2-container--below {
87 | .wpjsfselect2-selection--multiple {
88 | border-bottom: none;
89 | border-bottom-left-radius: 0;
90 | border-bottom-right-radius: 0;
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/classic/_single.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-selection--single {
2 | background-color: mix($selection-bg-top-color, $selection-bg-bottom-color);
3 |
4 | border: 1px solid $border-color;
5 | border-radius: $border-radius;
6 |
7 | outline: 0;
8 |
9 | @include gradient-vertical($selection-bg-top-color, $selection-bg-bottom-color, 50%, 100%);
10 |
11 | &:focus {
12 | border: 1px solid $focus-border-color;
13 | }
14 |
15 | .wpjsfselect2-selection__rendered {
16 | color: #444;
17 | line-height: 28px;
18 | }
19 |
20 | .wpjsfselect2-selection__clear {
21 | cursor: pointer;
22 | float: right;
23 | font-weight: bold;
24 | margin-right: 10px;
25 | }
26 |
27 | .wpjsfselect2-selection__placeholder {
28 | color: #999;
29 | }
30 |
31 | .wpjsfselect2-selection__arrow {
32 | background-color: #ddd;
33 |
34 | border: none;
35 | border-left: 1px solid $border-color;
36 | border-top-right-radius: $border-radius;
37 | border-bottom-right-radius: $border-radius;
38 |
39 | height: 26px;
40 |
41 | position: absolute;
42 |
43 | top: 1px;
44 | right: 1px;
45 |
46 | width: 20px;
47 |
48 | @include gradient-vertical(#eeeeee, #cccccc, 50%, 100%);
49 |
50 | b {
51 | border-color: #888 transparent transparent transparent;
52 | border-style: solid;
53 | border-width: 5px 4px 0 4px;
54 |
55 | height: 0;
56 | left: 50%;
57 |
58 | margin-left: -4px;
59 | margin-top: -2px;
60 |
61 | position: absolute;
62 |
63 | top: 50%;
64 | width: 0;
65 | }
66 | }
67 | }
68 |
69 | &[dir="rtl"] {
70 | .wpjsfselect2-selection--single {
71 | .wpjsfselect2-selection__clear {
72 | float: left;
73 | }
74 |
75 | .wpjsfselect2-selection__arrow {
76 | border: none;
77 | border-right: 1px solid $border-color;
78 |
79 | border-radius: 0;
80 | border-top-left-radius: $border-radius;
81 | border-bottom-left-radius: $border-radius;
82 |
83 | left: 1px;
84 | right: auto;
85 | }
86 | }
87 | }
88 |
89 | &.wpjsfselect2-container--open {
90 | .wpjsfselect2-selection--single {
91 | border: 1px solid $focus-border-color;
92 |
93 | .wpjsfselect2-selection__arrow {
94 | background: transparent;
95 |
96 | border: none;
97 |
98 | b {
99 | border-color: transparent transparent #888 transparent;
100 | border-width: 0 4px 5px 4px;
101 | }
102 | }
103 | }
104 |
105 | &.wpjsfselect2-container--above {
106 | .wpjsfselect2-selection--single {
107 | border-top: none;
108 | border-top-left-radius: 0;
109 | border-top-right-radius: 0;
110 |
111 | @include gradient-vertical($selection-opened-bg-bottom-color, $selection-opened-bg-top-color, 0%, 50%);
112 | }
113 | }
114 |
115 | &.wpjsfselect2-container--below {
116 | .wpjsfselect2-selection--single {
117 | border-bottom: none;
118 | border-bottom-left-radius: 0;
119 | border-bottom-right-radius: 0;
120 |
121 | @include gradient-vertical($selection-opened-bg-top-color, $selection-opened-bg-bottom-color, 50%, 100%);
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/classic/layout.scss:
--------------------------------------------------------------------------------
1 | @import "defaults";
2 | @import "../../mixins/gradients";
3 |
4 | .wpjsfselect2-container--classic {
5 | @import "single";
6 | @import "multiple";
7 |
8 | .wpjsfselect2-search--dropdown {
9 | .wpjsfselect2-search__field {
10 | border: 1px solid $border-color;
11 | outline: 0;
12 | }
13 | }
14 |
15 | .wpjsfselect2-search--inline {
16 | .wpjsfselect2-search__field {
17 | outline: 0;
18 | box-shadow: none;
19 | }
20 | }
21 |
22 | .wpjsfselect2-dropdown {
23 | background-color: $dropdown-bg-color;
24 | border: 1px solid transparent;
25 | }
26 |
27 | .wpjsfselect2-dropdown--above {
28 | border-bottom: none;
29 | }
30 |
31 | .wpjsfselect2-dropdown--below {
32 | border-top: none;
33 | }
34 |
35 | .wpjsfselect2-results > .wpjsfselect2-results__options {
36 | max-height: $results-max-height;
37 | overflow-y: auto;
38 | }
39 |
40 | .wpjsfselect2-results__option {
41 | &[role=group] {
42 | padding: 0;
43 | }
44 |
45 | &[aria-disabled=true] {
46 | color: $results-choice-fg-unselectable-color;
47 | }
48 | }
49 |
50 | .wpjsfselect2-results__option--highlighted[aria-selected] {
51 | background-color: $results-choice-bg-hover-color;
52 | color: $results-choice-fg-hover-color;
53 | }
54 |
55 | .wpjsfselect2-results__group {
56 | cursor: default;
57 | display: block;
58 | padding: 6px;
59 | }
60 |
61 | &.wpjsfselect2-container--open .wpjsfselect2-dropdown {
62 | border-color: $focus-border-color;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/default/_multiple.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-selection--multiple {
2 | background-color: white;
3 | border: 1px solid #aaa;
4 | border-radius: 4px;
5 | cursor: text;
6 |
7 | .wpjsfselect2-selection__rendered {
8 | box-sizing: border-box;
9 | list-style: none;
10 | margin: 0;
11 | padding: 0 5px;
12 | width: 100%;
13 |
14 | li {
15 | list-style: none;
16 | }
17 | }
18 |
19 | .wpjsfselect2-selection__placeholder {
20 | color: #999;
21 |
22 | margin-top: 5px;
23 |
24 | float: left;
25 | }
26 |
27 | .wpjsfselect2-selection__clear {
28 | cursor: pointer;
29 | float: right;
30 | font-weight: bold;
31 | margin-top: 5px;
32 | margin-right: 10px;
33 | }
34 |
35 | .wpjsfselect2-selection__choice {
36 | background-color: #e4e4e4;
37 |
38 | border: 1px solid #aaa;
39 | border-radius: 4px;
40 | cursor: default;
41 |
42 | float: left;
43 |
44 | margin-right: 5px;
45 | margin-top: 5px;
46 | padding: 0 5px;
47 | }
48 |
49 | .wpjsfselect2-selection__choice__remove {
50 | color: #999;
51 | cursor: pointer;
52 |
53 | display: inline-block;
54 | font-weight: bold;
55 |
56 | margin-right: 2px;
57 |
58 | &:hover {
59 | color: #333;
60 | }
61 | }
62 | }
63 |
64 | &[dir="rtl"] {
65 | .wpjsfselect2-selection--multiple {
66 | .wpjsfselect2-selection__choice, .wpjsfselect2-selection__placeholder, .wpjsfselect2-search--inline {
67 | float: right;
68 | }
69 |
70 | .wpjsfselect2-selection__choice {
71 | margin-left: 5px;
72 | margin-right: auto;
73 | }
74 |
75 | .wpjsfselect2-selection__choice__remove {
76 | margin-left: 2px;
77 | margin-right: auto;
78 | }
79 | }
80 | }
81 |
82 | &.wpjsfselect2-container--focus {
83 | .wpjsfselect2-selection--multiple {
84 | border: solid black 1px;
85 | outline: 0;
86 | }
87 | }
88 |
89 | &.wpjsfselect2-container--disabled {
90 | .wpjsfselect2-selection--multiple {
91 | background-color: #eee;
92 | cursor: default;
93 | }
94 |
95 | .wpjsfselect2-selection__choice__remove {
96 | display: none;
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/default/_single.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-selection--single {
2 | background-color: #fff;
3 | border: 1px solid #aaa;
4 | border-radius: 4px;
5 |
6 | .wpjsfselect2-selection__rendered {
7 | color: #444;
8 | line-height: 28px;
9 | }
10 |
11 | .wpjsfselect2-selection__clear {
12 | cursor: pointer;
13 | float: right;
14 | font-weight: bold;
15 | }
16 |
17 | .wpjsfselect2-selection__placeholder {
18 | color: #999;
19 | }
20 |
21 | .wpjsfselect2-selection__arrow {
22 | height: 26px;
23 |
24 | position: absolute;
25 |
26 | top: 1px;
27 | right: 1px;
28 |
29 | width: 20px;
30 |
31 | b {
32 | border-color: #888 transparent transparent transparent;
33 | border-style: solid;
34 | border-width: 5px 4px 0 4px;
35 |
36 | height: 0;
37 | left: 50%;
38 |
39 | margin-left: -4px;
40 | margin-top: -2px;
41 |
42 | position: absolute;
43 |
44 | top: 50%;
45 | width: 0;
46 | }
47 | }
48 | }
49 |
50 | &[dir="rtl"] {
51 | .wpjsfselect2-selection--single {
52 | .wpjsfselect2-selection__clear {
53 | float: left;
54 | }
55 |
56 | .wpjsfselect2-selection__arrow {
57 | left: 1px;
58 | right: auto;
59 | }
60 | }
61 | }
62 |
63 | &.wpjsfselect2-container--disabled {
64 | .wpjsfselect2-selection--single {
65 | background-color: #eee;
66 | cursor: default;
67 |
68 | .wpjsfselect2-selection__clear {
69 | display: none;
70 | }
71 | }
72 | }
73 |
74 | &.wpjsfselect2-container--open {
75 | .wpjsfselect2-selection--single {
76 | .wpjsfselect2-selection__arrow {
77 | b {
78 | border-color: transparent transparent #888 transparent;
79 | border-width: 0 4px 5px 4px;
80 | }
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/assets/sass/vendor/select2/theme/default/layout.scss:
--------------------------------------------------------------------------------
1 | .wpjsfselect2-container--default {
2 | @import "single";
3 | @import "multiple";
4 |
5 | &.wpjsfselect2-container--open.wpjsfselect2-container--above {
6 | .wpjsfselect2-selection--single, .wpjsfselect2-selection--multiple {
7 | border-top-left-radius: 0;
8 | border-top-right-radius: 0;
9 | }
10 | }
11 |
12 | &.wpjsfselect2-container--open.wpjsfselect2-container--below {
13 | .wpjsfselect2-selection--single, .wpjsfselect2-selection--multiple {
14 | border-bottom-left-radius: 0;
15 | border-bottom-right-radius: 0;
16 | }
17 | }
18 |
19 | .wpjsfselect2-search--dropdown {
20 | .wpjsfselect2-search__field {
21 | border: 1px solid #aaa;
22 | }
23 | }
24 |
25 | .wpjsfselect2-search--inline {
26 | .wpjsfselect2-search__field {
27 | background: transparent;
28 | border: none;
29 | outline: 0;
30 | box-shadow: none;
31 | -webkit-appearance: textfield;
32 | }
33 | }
34 |
35 | .wpjsfselect2-results > .wpjsfselect2-results__options {
36 | max-height: 200px;
37 | overflow-y: auto;
38 | }
39 |
40 | .wpjsfselect2-results__option {
41 | &[role=group] {
42 | padding: 0;
43 | }
44 |
45 | &[aria-disabled=true] {
46 | color: #999;
47 | }
48 |
49 | &[aria-selected=true] {
50 | background-color: #ddd;
51 | }
52 |
53 | .wpjsfselect2-results__option {
54 | padding-left: 1em;
55 |
56 | .wpjsfselect2-results__group {
57 | padding-left: 0;
58 | }
59 |
60 | .wpjsfselect2-results__option {
61 | margin-left: -1em;
62 | padding-left: 2em;
63 |
64 | .wpjsfselect2-results__option {
65 | margin-left: -2em;
66 | padding-left: 3em;
67 |
68 | .wpjsfselect2-results__option {
69 | margin-left: -3em;
70 | padding-left: 4em;
71 |
72 | .wpjsfselect2-results__option {
73 | margin-left: -4em;
74 | padding-left: 5em;
75 |
76 | .wpjsfselect2-results__option {
77 | margin-left: -5em;
78 | padding-left: 6em;
79 | }
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
87 | .wpjsfselect2-results__option--highlighted[aria-selected] {
88 | background-color: #5897fb;
89 | color: white;
90 | }
91 |
92 | .wpjsfselect2-results__group {
93 | cursor: default;
94 | display: block;
95 | padding: 6px;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/classes/Admin.php:
--------------------------------------------------------------------------------
1 | array(),
49 | 'total_count' => 0,
50 | );
51 | switch ( $_REQUEST['object_type'] ) {
52 | case 'post_type':
53 | $post_type = ! empty( $_REQUEST['object_key'] ) ? $_REQUEST['object_key'] : 'post';
54 | $args = array(
55 | 's' => ! empty( $_REQUEST['s'] ) ? $_REQUEST['s'] : null,
56 | 'post__in' => ! empty( $_REQUEST['include'] ) ? array_map( 'intval', (array) $_REQUEST['include'] ) : null,
57 | 'page' => ! empty( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : null,
58 | 'posts_per_page' => 10,
59 | );
60 | $query = Helpers::post_type_selectlist( $post_type, $args, true );
61 | foreach ( $query['items'] as $name => $id ) {
62 | $results['items'][] = array(
63 | 'id' => $id,
64 | 'text' => $name,
65 | );
66 | }
67 | $results['total_count'] = $query['total_count'];
68 | break;
69 | case 'taxonomy':
70 | $taxonomy = ! empty( $_REQUEST['object_key'] ) ? $_REQUEST['object_key'] : 'category';
71 | $args = array(
72 | 'search' => ! empty( $_REQUEST['s'] ) ? $_REQUEST['s'] : '',
73 | 'include' => ! empty( $_REQUEST['include'] ) ? $_REQUEST['include'] : null,
74 | 'page' => ! empty( $_REQUEST['page'] ) ? absint( $_REQUEST['page'] ) : null,
75 | 'number' => 10,
76 | );
77 | $query = Helpers::taxonomy_selectlist( $taxonomy, $args, true );
78 | foreach ( $query['items'] as $name => $id ) {
79 | $results['items'][] = array(
80 | 'id' => $id,
81 | 'text' => $name,
82 | );
83 | }
84 | $results['total_count'] = $query['total_count'];
85 | break;
86 | }
87 | echo json_encode( $results );
88 | die();
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/classes/Admin/Assets.php:
--------------------------------------------------------------------------------
1 | wp_create_nonce( 'wpjsfsp-admin-nonce' ),
49 | 'I10n' => array(
50 | 'conditions' => array(
51 | 'not_operand' => array(
52 | 'is' => __( 'Is', 'wp-js-form-sample-plugin' ),
53 | 'not' => __( 'Not', 'wp-js-form-sample-plugin' ),
54 | ),
55 | ),
56 | 'save' => __( 'Save', 'wp-js-form-sample-plugin' ),
57 | 'cancel' => __( 'Cancel', 'wp-js-form-sample-plugin' ),
58 | 'add' => __( 'Add', 'wp-js-form-sample-plugin' ),
59 | 'update' => __( 'Update', 'wp-js-form-sample-plugin' ),
60 | ),
61 | ) ) );
62 | }
63 |
64 |
65 | }
66 |
67 | /**
68 | * JavaScript Wordpress editor
69 | * Author: Ante Primorac
70 | * Author URI: http://anteprimorac.from.hr
71 | * Version: 1.1
72 | * License:
73 | * Copyright (c) 2013 Ante Primorac
74 | * Permission is hereby granted, free of charge, to any person obtaining a copy
75 | * of this software and associated documentation files (the "Software"), to deal
76 | * in the Software without restriction, including without limitation the rights
77 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
78 | * copies of the Software, and to permit persons to whom the Software is
79 | * furnished to do so, subject to the following conditions:
80 | *
81 | * The above copyright notice and this permission notice shall be included in
82 | * all copies or substantial portions of the Software.
83 | *
84 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
89 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
90 | * THE SOFTWARE.
91 | * Usage:
92 | * server side(WP):
93 | * js_wp_editor( $settings );
94 | * client side(jQuery):
95 | * $('textarea').wp_editor( options );
96 | */
97 | public static function js_wp_editor() {
98 | if ( ! class_exists( '\_WP_Editors' ) ) {
99 | require( ABSPATH . WPINC . '/class-wp-editor.php' );
100 | }
101 |
102 | $set = \_WP_Editors::parse_settings( 'wpjsfsp_id', array() );
103 |
104 | if ( ! current_user_can( 'upload_files' ) ) {
105 | $set['media_buttons'] = false;
106 | }
107 |
108 | if ( $set['media_buttons'] ) {
109 | wp_enqueue_style( 'buttons' );
110 | wp_enqueue_script( 'thickbox' );
111 | wp_enqueue_style( 'thickbox' );
112 | wp_enqueue_script( 'media-upload' );
113 | wp_enqueue_script( 'wp-embed' );
114 |
115 | $post = get_post( 1 );
116 | if ( ! $post && ! empty( $GLOBALS['post_ID'] ) ) {
117 | $post = $GLOBALS['post_ID'];
118 | }
119 | wp_enqueue_media( array(
120 | 'post' => $post,
121 | ) );
122 | }
123 |
124 | \_WP_Editors::editor_settings( 'wpjsfsp_id', $set );
125 |
126 | wp_localize_script( 'wpjsfsp-admin', 'wpjsfsp_wpeditor_vars', array(
127 | 'url' => get_home_url(),
128 | 'includes_url' => includes_url(),
129 | ) );
130 | }
131 |
132 | }
--------------------------------------------------------------------------------
/classes/Admin/Footer_Templates.php:
--------------------------------------------------------------------------------
1 |
29 |
32 |
33 |
36 |
37 |
58 |
59 |
69 |
70 |
73 |
74 |
84 |
85 |
88 |
89 |
92 |
97 |
100 |
101 |
104 |
105 |
108 |
109 |
112 |
113 |
116 |
117 |
120 |
125 |
128 |
129 |
132 |
133 |
137 |
138 |
141 |
142 |
149 |
150 |
172 |
173 |
179 |
180 |
186 |
191 |
198 |
199 |
219 |
220 |
223 |
224 |
227 |
228 |
237 |
242 |
283 |
284 |
301 |
302 |
305 |
306 |
309 |
314 |
317 |
318 |
353 |
354 |
374 |
375 |
399 | preload_posts = isset( $_GET['page'] ) && $_GET['page'] == 'wpjsfsp-settings';
49 | }
50 |
51 | return self::$instance;
52 | }
53 |
54 | /**
55 | * @param array $conditions
56 | */
57 | public function add_conditions( $conditions = array() ) {
58 | foreach ( $conditions as $key => $condition ) {
59 | if ( empty( $condition['id'] ) && ! is_numeric( $key ) ) {
60 | $condition['id'] = $key;
61 | }
62 |
63 | $this->add_condition( $condition );
64 | }
65 | }
66 |
67 | /**
68 | * @param array $condition
69 | */
70 | public function add_condition( $condition = array() ) {
71 | if ( ! empty( $condition['id'] ) && ! isset ( $this->conditions[ $condition['id'] ] ) ) {
72 | $condition = wp_parse_args( $condition, array(
73 | 'id' => '',
74 | 'callback' => null,
75 | 'group' => '',
76 | 'name' => '',
77 | 'priority' => 10,
78 | 'fields' => array(),
79 | 'advanced' => false,
80 | ) );
81 |
82 | $this->conditions[ $condition['id'] ] = $condition;
83 | }
84 |
85 | return;
86 | }
87 |
88 | /**
89 | * @return array
90 | */
91 | public function get_conditions() {
92 | if ( ! isset( $this->conditions ) ) {
93 | $this->register_conditions();
94 | }
95 |
96 |
97 | return $this->conditions;
98 | }
99 |
100 | /**
101 | * @return array|mixed
102 | */
103 | public function condition_sort_order() {
104 | if ( ! $this->condition_sort_order ) {
105 |
106 | $order = apply_filters( 'wpjsfsp_condition_group_sort_order', array(
107 | __( 'General', 'wp-js-form-sample-plugin' ) => 1,
108 | __( 'Pages', 'wp-js-form-sample-plugin' ) => 5,
109 | __( 'Posts', 'wp-js-form-sample-plugin' ) => 5,
110 | __( 'Categories', 'wp-js-form-sample-plugin' ) => 14,
111 | __( 'Tags', 'wp-js-form-sample-plugin' ) => 14,
112 | __( 'Format', 'wp-js-form-sample-plugin' ) => 16,
113 | ) );
114 |
115 | $post_types = get_post_types( array( 'public' => true, '_builtin' => false ), 'objects' );
116 | foreach ( $post_types as $name => $post_type ) {
117 | $order[ $post_type->labels->name ] = 10;
118 | }
119 |
120 | $taxonomies = get_taxonomies( array( 'public' => true, '_builtin' => false ), 'objects' );
121 | foreach ( $taxonomies as $tax_name => $taxonomy ) {
122 | $order[ $taxonomy->labels->name ] = 15;
123 | }
124 |
125 | $this->condition_sort_order = apply_filters( 'wpjsfsp_condition_sort_order', $order );
126 |
127 | }
128 |
129 | return $this->condition_sort_order;
130 | }
131 |
132 | /**
133 | * @param $a
134 | * @param $b
135 | *
136 | * @return int
137 | */
138 | public function sort_condition_groups( $a, $b ) {
139 |
140 | $order = $this->condition_sort_order();
141 |
142 | $ai = isset( $order[ $a ] ) ? intval( $order[ $a ] ) : 10;
143 | $bi = isset( $order[ $b ] ) ? intval( $order[ $b ] ) : 10;
144 |
145 | if ( $ai == $bi ) {
146 | return 0;
147 | }
148 |
149 | // Compare their positions in line.
150 | return $ai > $bi ? 1 : - 1;
151 | }
152 |
153 | /**
154 | * @return array
155 | */
156 | public function get_conditions_by_group() {
157 |
158 | static $groups;
159 |
160 | if ( ! isset( $groups ) ) {
161 |
162 | $groups = array();
163 |
164 | foreach ( $this->get_conditions() as $condition ) {
165 | $groups[ $condition['group'] ][ $condition['id'] ] = $condition;
166 | }
167 |
168 | uksort( $groups, array( $this, 'sort_condition_groups' ) );
169 |
170 | }
171 |
172 | return $groups;
173 | }
174 |
175 | /**
176 | * @return array
177 | */
178 | public function dropdown_list() {
179 | $groups = array();
180 |
181 | $conditions_by_group = $this->get_conditions_by_group();
182 |
183 | foreach ( $conditions_by_group as $group => $_conditions ) {
184 |
185 | $conditions = array();
186 |
187 | foreach ( $_conditions as $id => $condition ) {
188 | $conditions[ $id ] = $condition['name'];
189 | }
190 |
191 | $groups[ $group ] = $conditions;
192 | }
193 |
194 | return $groups;
195 | }
196 |
197 | /**
198 | * @param null $condition
199 | *
200 | * @return mixed|null
201 | */
202 | public function get_condition( $condition = null ) {
203 | $conditions = $this->get_conditions();
204 |
205 | return isset( $conditions[ $condition ] ) ? $conditions[ $condition ] : null;
206 | }
207 |
208 | /**
209 | * @return array
210 | */
211 | public function generate_post_type_conditions() {
212 | $conditions = array();
213 | $post_types = get_post_types( array( 'public' => true ), 'objects' );
214 |
215 | foreach ( $post_types as $name => $post_type ) {
216 |
217 | if ( $post_type->has_archive ) {
218 | $conditions[ $name . '_index' ] = array(
219 | 'group' => $post_type->labels->name,
220 | 'name' => sprintf( _x( '%s Archive', 'condition: post type plural label ie. Posts: All', 'wp-js-form-sample-plugin' ), $post_type->labels->name ),
221 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'post_type' ),
222 | 'priority' => 5,
223 | );
224 | }
225 |
226 | $conditions[ $name . '_all' ] = array(
227 | 'group' => $post_type->labels->name,
228 | 'name' => sprintf( _x( 'A %s', 'condition: post type singular label ie. Posts: All', 'wp-js-form-sample-plugin' ), $post_type->labels->singular_name ),
229 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'post_type' ),
230 | );
231 |
232 | $conditions[ $name . '_selected' ] = array(
233 | 'group' => $post_type->labels->name,
234 | 'name' => sprintf( _x( 'A Selected %s', 'condition: post type singular label ie. Posts: Selected', 'wp-js-form-sample-plugin' ), $post_type->labels->singular_name ),
235 | 'fields' => array(
236 | 'selected' => array(
237 | 'placeholder' => sprintf( _x( 'Select %s.', 'condition: post type singular label ie. Select Posts', 'wp-js-form-sample-plugin' ), strtolower( $post_type->labels->singular_name ) ),
238 | 'type' => 'postselect',
239 | 'post_type' => $name,
240 | 'multiple' => true,
241 | 'as_array' => true,
242 | 'options' => $this->preload_posts ? Helpers::post_type_selectlist( $name ) : array(),
243 | ),
244 | ),
245 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'post_type' ),
246 | );
247 |
248 | $conditions[ $name . '_ID' ] = array(
249 | 'group' => $post_type->labels->name,
250 | 'name' => sprintf( _x( 'A %s with ID', 'condition: post type singular label ie. Posts: ID', 'wp-js-form-sample-plugin' ), $post_type->labels->singular_name ),
251 | 'fields' => array(
252 | 'selected' => array(
253 | 'placeholder' => sprintf( _x( '%s IDs: 128, 129', 'condition: post type singular label ie. Posts IDs', 'wp-js-form-sample-plugin' ), strtolower( $post_type->labels->singular_name ) ),
254 | 'type' => 'text',
255 | ),
256 | ),
257 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'post_type' ),
258 | );
259 |
260 | $templates = wp_get_theme()->get_page_templates();
261 |
262 | if ( $name == 'page' && ! empty( $templates ) ) {
263 | $conditions[ $name . '_template' ] = array(
264 | 'group' => $post_type->labels->name,
265 | 'name' => sprintf( _x( 'A %s: With Template', 'condition: post type plural label ie. Pages: With Template', 'wp-js-form-sample-plugin' ), $post_type->labels->name ),
266 | 'fields' => array(
267 | 'selected' => array(
268 | 'type' => 'select',
269 | 'select2' => true,
270 | 'multiple' => true,
271 | 'as_array' => true,
272 | 'options' => array_flip( array_merge( array( 'default' => __( 'Default', 'wp-js-form-sample-plugin' ) ), $templates ) ),
273 | ),
274 | ),
275 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'post_type' ),
276 | );
277 | }
278 |
279 | $conditions = array_merge( $conditions, $this->generate_post_type_tax_conditions( $name ) );
280 |
281 | }
282 |
283 | return $conditions;
284 | }
285 |
286 | /**
287 | * @param $name
288 | *
289 | * @return array
290 | */
291 | public function generate_post_type_tax_conditions( $name ) {
292 | $post_type = get_post_type_object( $name );
293 | $taxonomies = get_object_taxonomies( $name, 'object' );
294 | $conditions = array();
295 | foreach ( $taxonomies as $tax_name => $taxonomy ) {
296 |
297 | $conditions[ $name . '_w_' . $tax_name ] = array(
298 | 'group' => $post_type->labels->name,
299 | 'name' => sprintf( _x( 'A %1$s with %2$s', 'condition: post type plural and taxonomy singular label ie. Posts: With Category', 'wp-js-form-sample-plugin' ), $post_type->labels->singular_name, $taxonomy->labels->singular_name ),
300 | 'fields' => array(
301 | 'selected' => array(
302 | 'placeholder' => sprintf( _x( 'Select %s.', 'condition: post type plural label ie. Select categories', 'wp-js-form-sample-plugin' ), strtolower( $taxonomy->labels->name ) ),
303 | 'type' => 'taxonomyselect',
304 | 'taxonomy' => $tax_name,
305 | 'multiple' => true,
306 | 'as_array' => true,
307 | 'options' => $this->preload_posts ? Helpers::taxonomy_selectlist( $tax_name ) : array(),
308 | ),
309 | ),
310 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'post_type_tax' ),
311 | );
312 | }
313 |
314 | return $conditions;
315 | }
316 |
317 | /**
318 | * Generates conditions for all public taxonomies.
319 | *
320 | * @return array
321 | */
322 | public function generate_taxonomy_conditions() {
323 | $conditions = array();
324 | $taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
325 |
326 | foreach ( $taxonomies as $tax_name => $taxonomy ) {
327 |
328 | $conditions[ 'tax_' . $tax_name . '_all' ] = array(
329 | 'group' => $taxonomy->labels->name,
330 | 'name' => sprintf( _x( 'A %s', 'condition: taxonomy plural label ie. Categories: All', 'wp-js-form-sample-plugin' ), $taxonomy->labels->name ),
331 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'taxonomy' ),
332 | );
333 |
334 | $conditions[ 'tax_' . $tax_name . '_selected' ] = array(
335 | 'group' => $taxonomy->labels->name,
336 | 'name' => sprintf( _x( '%s: Selected', 'condition: taxonomy plural label ie. Categories: Selected', 'wp-js-form-sample-plugin' ), $taxonomy->labels->name ),
337 | 'fields' => array(
338 | 'selected' => array(
339 | 'placeholder' => sprintf( _x( 'Select %s.', 'condition: taxonomy plural label ie. Select Categories', 'wp-js-form-sample-plugin' ), strtolower( $taxonomy->labels->name ) ),
340 | 'type' => 'taxonomyselect',
341 | 'taxonomy' => $tax_name,
342 | 'multiple' => true,
343 | 'as_array' => true,
344 | 'options' => $this->preload_posts ? Helpers::taxonomy_selectlist( $tax_name ) : array(),
345 | ),
346 | ),
347 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'taxonomy' ),
348 | );
349 |
350 | $conditions[ 'tax_' . $tax_name . '_ID' ] = array(
351 | 'group' => $taxonomy->labels->name,
352 | 'name' => sprintf( _x( 'A %s with IDs', 'condition: taxonomy plural label ie. Categories: Selected', 'wp-js-form-sample-plugin' ), $taxonomy->labels->name ),
353 | 'fields' => array(
354 | 'selected' => array(
355 | 'placeholder' => sprintf( _x( '%s IDs: 128, 129', 'condition: taxonomy plural label ie. Category IDs', 'wp-js-form-sample-plugin' ), strtolower( $taxonomy->labels->singular_name ) ),
356 | 'type' => 'text',
357 | ),
358 | ),
359 | 'callback' => array( '\\WPJSFSP\Condition_Callbacks', 'taxonomy' ),
360 | );
361 |
362 | }
363 |
364 | return $conditions;
365 | }
366 |
367 | /**
368 | * Registers all known conditions when called.
369 | */
370 | public function register_conditions() {
371 |
372 | $conditions['is_front_page'] = array(
373 | 'group' => __( 'General', 'wp-js-form-sample-plugin' ),
374 | 'name' => __( 'The Home Page', 'wp-js-form-sample-plugin' ),
375 | 'callback' => 'is_front_page',
376 | 'priority' => 2,
377 | );
378 | $conditions['is_home'] = array(
379 | 'group' => __( 'Posts', 'wp-js-form-sample-plugin' ),
380 | 'name' => __( 'The Blog Index', 'wp-js-form-sample-plugin' ),
381 | 'callback' => 'is_home',
382 | 'priority' => 1,
383 | );
384 | $conditions['is_search'] = array(
385 | 'group' => __( 'General', 'wp-js-form-sample-plugin' ),
386 | 'name' => __( 'A Search Result Page', 'wp-js-form-sample-plugin' ),
387 | 'callback' => 'is_search',
388 | );
389 | $conditions['is_404'] = array(
390 | 'group' => __( 'General', 'wp-js-form-sample-plugin' ),
391 | 'name' => __( 'A 404 Error Page', 'wp-js-form-sample-plugin' ),
392 | 'callback' => 'is_404',
393 | );
394 |
395 | $conditions = array_merge( $this->generate_post_type_conditions(), $this->generate_taxonomy_conditions() );
396 |
397 | $conditions = apply_filters( 'wpjsfsp_registered_conditions', $conditions );
398 |
399 | $this->add_conditions( $conditions );
400 | }
401 |
402 | }
403 |
--------------------------------------------------------------------------------
/classes/Helpers.php:
--------------------------------------------------------------------------------
1 | $value ) {
40 | $array[ $key ] = is_object( $value ) || is_array( $value ) ? self::object_to_array( $value ) : $value;
41 | }
42 |
43 | return $array;
44 | }
45 |
46 | public static function post_type_selectlist( $post_type, $args = array(), $include_total = false ) {
47 |
48 | $args = wp_parse_args( $args, array(
49 | 'posts_per_page' => 10,
50 | 'post_type' => $post_type,
51 | 'post__in' => null,
52 | 'post__not_in' => null,
53 | 'post_status' => null,
54 | 'page' => 1,
55 | // Performance Optimization.
56 | 'no_found_rows' => ! $include_total ? true : false,
57 | 'update_post_term_cache' => false,
58 | 'update_post_meta_cache' => false,
59 | ) );
60 |
61 | if ( $post_type == 'attachment' ) {
62 | $args['post_status'] = 'inherit';
63 | }
64 |
65 | // Query Caching.
66 | static $queries = array();
67 |
68 | $key = md5( serialize( $args ) );
69 |
70 | if ( ! isset( $queries[ $key ] ) ) {
71 | $query = new \WP_Query( $args );
72 |
73 | $posts = array();
74 | foreach ( $query->posts as $post ) {
75 | $posts[ $post->post_title ] = $post->ID;
76 | }
77 |
78 | $results = array(
79 | 'items' => $posts,
80 | 'total_count' => $query->found_posts,
81 | );
82 |
83 | $queries[ $key ] = $results;
84 | } else {
85 | $results = $queries[ $key ];
86 | }
87 |
88 | return ! $include_total ? $results['items'] : $results;
89 | }
90 |
91 | public static function taxonomy_selectlist( $taxonomies = array(), $args = array(), $include_total = false ) {
92 | if ( empty ( $taxonomies ) ) {
93 | $taxonomies = array( 'category' );
94 | }
95 |
96 | $args = wp_parse_args( $args, array(
97 | 'hide_empty' => false,
98 | 'number' => 10,
99 | 'search' => '',
100 | 'include' => null,
101 | 'offset' => 0,
102 | 'page' => null,
103 | ) );
104 |
105 | if ( $args['page'] ) {
106 | $args['offset'] = ( $args['page'] - 1 ) * $args['number'];
107 | }
108 |
109 | // Query Caching.
110 | static $queries = array();
111 |
112 | $key = md5( serialize( $args ) );
113 |
114 | if ( ! isset( $queries[ $key ] ) ) {
115 | $terms = array();
116 |
117 | foreach ( get_terms( $taxonomies, $args ) as $term ) {
118 | $terms[ $term->name ] = $term->term_id;
119 | }
120 |
121 | $total_args = $args;
122 | unset( $total_args['number'] );
123 | unset( $total_args['offset'] );
124 |
125 | $results = array(
126 | 'items' => $terms,
127 | 'total_count' => $include_total ? wp_count_terms( $taxonomies, $total_args ) : null,
128 | );
129 |
130 | $queries[ $key ] = $results;
131 | } else {
132 | $results = $queries[ $key ];
133 | }
134 |
135 | return ! $include_total ? $results['items'] : $results;
136 | }
137 |
138 | public static function is_customize_preview() {
139 | global $wp_customize;
140 |
141 | return ( $wp_customize instanceof \WP_Customize_Manager ) && $wp_customize->is_preview();
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/classes/Options.php:
--------------------------------------------------------------------------------
1 | '
8 | })
9 | },
10 | pkg = require('./package.json');
11 |
12 | //region JavaScript
13 | gulp.task('js:admin', function() {
14 | return gulp.src(['assets/js/src/admin/vendor/*.js', 'assets/js/src/admin/plugins/**/*.js', 'assets/js/src/admin/general.js'])
15 | .pipe($fn.plumber(plumberErrorHandler))
16 | .pipe($fn.jshint())
17 | .pipe($fn.jshint.reporter('default'))
18 | .pipe($fn.order([
19 | "vendor/**/*.js",
20 | "plugins/**/*.js",
21 | 'general.js'
22 | ], { base: 'assets/js/src/admin/' }))
23 | .pipe($fn.concat('admin.js'))
24 | // Prefix with the plugin name-
25 | .pipe($fn.rename({ prefix: pkg.name + '-' }))
26 | .pipe(gulp.dest('assets/js'))
27 | .pipe($fn.uglify())
28 | .pipe($fn.rename({extname: '.min.js'}))
29 | .pipe(gulp.dest('assets/js'))
30 | .pipe($fn.livereload());
31 | });
32 |
33 | gulp.task('js:site', function() {
34 | return gulp.src(['assets/js/src/site/plugins/**/*.js', 'assets/js/src/site/general.js'])
35 | .pipe($fn.plumber(plumberErrorHandler))
36 | .pipe($fn.jshint())
37 | .pipe($fn.jshint.reporter('default'))
38 | .pipe($fn.order([
39 | "plugins/compatibility.js",
40 | "plugins/pum.js",
41 | "plugins/**/*.js",
42 | 'general.js'
43 | ], { base: 'assets/js/src/site/' }))
44 | .pipe($fn.concat('site.js'))
45 | // Prefix with the plugin name-
46 | .pipe($fn.rename({ prefix: pkg.name + '-' }))
47 | .pipe(gulp.dest('assets/js'))
48 | .pipe($fn.uglify())
49 | .pipe($fn.rename({extname: '.min.js'}))
50 | .pipe(gulp.dest('assets/js'))
51 | .pipe($fn.livereload());
52 | });
53 |
54 | gulp.task('js:other', function() {
55 | return gulp.src('assets/js/src/*.js')
56 | .pipe($fn.plumber(plumberErrorHandler))
57 | .pipe($fn.jshint())
58 | .pipe($fn.jshint.reporter('default'))
59 | .pipe(gulp.dest('assets/js'))
60 | .pipe($fn.uglify())
61 | .pipe($fn.rename({extname: '.min.js'}))
62 | .pipe(gulp.dest('assets/js'))
63 | .pipe($fn.livereload());
64 | });
65 |
66 | gulp.task('js', ['js:admin', 'js:site', 'js:other']);
67 | //endregion JavaScript
68 |
69 | //region Language Files
70 | gulp.task('langpack', function () {
71 | return gulp.src(['**/*.php', '!build/**/*.*'])
72 | .pipe($fn.plumber(plumberErrorHandler))
73 | .pipe($fn.sort())
74 | .pipe($fn.wpPot( {
75 | domain: pkg.name,
76 | bugReport: 'danieliser@wizardinternetsolutions.com',
77 | team: 'Daniel Iser '
78 | } ))
79 | .pipe(gulp.dest('languages'));
80 | });
81 | //endregion Language Files
82 |
83 | //region SASS & CSS
84 | gulp.task('css', function() {
85 | return gulp.src(['assets/sass/admin.scss', 'assets/sass/site.scss'])
86 | .pipe($fn.plumber(plumberErrorHandler))
87 | // Prefix with the plugin name-
88 | .pipe($fn.rename({ prefix: pkg.name + '-' }))
89 | .pipe($fn.sourcemaps.init())
90 | .pipe($fn.sass({
91 | errLogToConsole: true,
92 | outputStyle: 'expanded',
93 | precision: 10
94 | }))
95 | .pipe($fn.sourcemaps.write())
96 | .pipe($fn.sourcemaps.init({
97 | loadMaps: true
98 | }))
99 | .pipe($fn.autoprefixer('last 2 version', '> 1%', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
100 | .pipe($fn.sourcemaps.write('.'))
101 | .pipe($fn.plumber.stop())
102 | .pipe(gulp.dest('assets/css'))
103 | .pipe($fn.filter('**/*.css')) // Filtering stream to only css files
104 | .pipe($fn.combineMq()) // Combines Media Queries
105 | .pipe($fn.livereload())
106 | .pipe($fn.rename({ suffix: '.min' }))
107 | .pipe($fn.csso({
108 | //sourceMap: true,
109 | }))
110 | .pipe(gulp.dest('assets/css'))
111 | .pipe($fn.livereload())
112 | .pipe(gulp.dest('assets/css'));
113 | });
114 | gulp.task('css:other', function() {
115 | return gulp.src(['assets/sass/*.scss', '!assets/sass/admin.scss', '!assets/sass/site.scss'])
116 | .pipe($fn.plumber(plumberErrorHandler))
117 | .pipe($fn.sourcemaps.init())
118 | .pipe($fn.sass({
119 | errLogToConsole: true,
120 | outputStyle: 'expanded',
121 | precision: 10
122 | }))
123 | .pipe($fn.sourcemaps.write())
124 | .pipe($fn.sourcemaps.init({
125 | loadMaps: true
126 | }))
127 | .pipe($fn.autoprefixer('last 2 version', '> 1%', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
128 | .pipe($fn.sourcemaps.write('.'))
129 | .pipe($fn.plumber.stop())
130 | // Prefix with the plugin name-
131 | .pipe(gulp.dest('assets/css'))
132 | .pipe($fn.filter('**/*.css')) // Filtering stream to only css files
133 | .pipe($fn.combineMq()) // Combines Media Queries
134 | .pipe($fn.livereload())
135 | .pipe($fn.rename({ suffix: '.min' }))
136 | .pipe($fn.csso({
137 | //sourceMap: true,
138 | }))
139 | .pipe(gulp.dest('assets/css'))
140 | .pipe($fn.livereload())
141 | .pipe(gulp.dest('assets/css'));
142 | });
143 | //endregion SASS & CSS
144 |
145 | //region Cleaners
146 | gulp.task('clean-js:site', function () {
147 | return gulp.src('assets/js/site*.js', {read: false})
148 | .pipe($fn.plumber(plumberErrorHandler))
149 | .pipe($fn.clean());
150 | });
151 | gulp.task('clean-js:admin', function () {
152 | return gulp.src('assets/js/admin*.js', {read: false})
153 | .pipe($fn.plumber(plumberErrorHandler))
154 | .pipe($fn.clean());
155 | });
156 | gulp.task('clean-js:other', function () {
157 | return gulp.src(['assets/js/*.js', '!assets/js/site*.js', '!assets/js/admin*.js'], {read: false})
158 | .pipe($fn.plumber(plumberErrorHandler))
159 | .pipe($fn.clean());
160 | });
161 | gulp.task('clean-css', function () {
162 | return gulp.src(['assets/css/*.css', 'assets/css/*.css.map'], {read: false})
163 | .pipe($fn.plumber(plumberErrorHandler))
164 | .pipe($fn.clean());
165 | });
166 | gulp.task('clean-langpack', function () {
167 | return gulp.src(['languages/*.pot'], {read: false})
168 | .pipe($fn.plumber(plumberErrorHandler))
169 | .pipe($fn.clean());
170 | });
171 | gulp.task('clean-build', function () {
172 | return gulp.src('build/*', {read: false})
173 | .pipe($fn.plumber(plumberErrorHandler))
174 | .pipe($fn.clean());
175 | });
176 | gulp.task('clean-package', function () {
177 | return gulp.src('release/'+pkg.name+'_v'+pkg.version+'.zip', {read: false})
178 | .pipe($fn.plumber(plumberErrorHandler))
179 | .pipe($fn.clean({force: true}));
180 | });
181 |
182 | // Cleaning Routines
183 | gulp.task('clean-js', function (done) {
184 | runSequence(
185 | ['clean-js:site', 'clean-js:admin', 'clean-js:other'],
186 | done
187 | );
188 | });
189 | gulp.task('clean-all', function (done) {
190 | runSequence(
191 | ['clean-js', 'clean-css', 'clean-langpack'],
192 | ['clean-build', 'clean-package'],
193 | done
194 | );
195 | });
196 | //endregion Cleaners
197 |
198 | //region Watch & Build
199 | gulp.task('watch', function () {
200 | $fn.livereload.listen();
201 | gulp.watch('assets/sass/**/*.scss', ['css', 'css:other']);
202 | gulp.watch('assets/js/src/admin/**/*.js', ['js:admin']);
203 | gulp.watch('assets/js/src/site/**/*.js', ['js:site']);
204 | gulp.watch(['assets/js/src/**/*.js', '!assets/js/src/site/**/*.js', '!assets/js/src/admin/**/*.js'], ['js:other']);
205 | gulp.watch('**/*.php', ['langpack']);
206 | });
207 |
208 | // Cleans & Rebuilds Assets Prior to Builds
209 | gulp.task('prebuild', function (done) {
210 | runSequence(
211 | 'clean-all',
212 | ['css', 'css:other', 'js', 'langpack'],
213 | done
214 | );
215 | });
216 |
217 | // Copies a clean set of build files into the build folder
218 | gulp.task('build', ['prebuild'], function () {
219 | return gulp.src(['./**/*.*', '!./build/**', '!./release/**', '!./node_modules/**', '!./gulpfile.js', '!./package.json', '!./assets/js/src/**'])
220 | .pipe($fn.plumber(plumberErrorHandler))
221 | .pipe(gulp.dest('build/'+pkg.name));
222 | });
223 |
224 | // Generates a release package with the current version from package.json
225 | gulp.task('package', ['clean-package'], function () {
226 | return gulp.src('build/**/*.*')
227 | .pipe($fn.plumber(plumberErrorHandler))
228 | .pipe($fn.zip(pkg.name+'_v'+pkg.version+'.zip'))
229 | .pipe(gulp.dest('release'));
230 | });
231 |
232 | // Runs all build routines and generates a release.
233 | gulp.task('release', function (done) {
234 | runSequence(
235 | 'build',
236 | 'package',
237 | done
238 | );
239 | });
240 |
241 | // Runs a release and cleans up afterwards.
242 | gulp.task('release:clean', ['release'], function (done) {
243 | runSequence(
244 | 'clean-build',
245 | done
246 | );
247 | });
248 | //endregion Watch & Build
249 |
250 | gulp.task('default', function (done) {
251 | runSequence(
252 | 'prebuild',
253 | 'watch',
254 | done
255 | );
256 | });
--------------------------------------------------------------------------------
/includes/compat.php:
--------------------------------------------------------------------------------
1 | \n"
12 | "X-Poedit-Basepath: ..\n"
13 | "X-Poedit-SourceCharset: UTF-8\n"
14 | "X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
15 | "X-Poedit-SearchPath-0: .\n"
16 | "X-Poedit-SearchPathExcluded-0: *.js\n"
17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
18 |
19 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wpjsfsp",
3 | "version": "1.0.0",
4 | "description": "",
5 | "scripts": {
6 | "test": "echo \"Error: no test specified\" && exit 1"
7 | },
8 | "repository": {
9 | "type": "git",
10 | "url": "git+https://github.com/danieliser/WP-JS-Form-Sample-Plugin.git"
11 | },
12 | "author": "Daniel Iser",
13 | "license": "GPL-3.0",
14 | "bugs": {
15 | "url": "https://github.com/danieliser/WP-JS-Form-Sample-Plugin/issues"
16 | },
17 | "homepage": "https://github.com/danieliser/WP-JS-Form-Sample-Plugin#readme",
18 | "devDependencies": {
19 | "gulp": "^3.9.1",
20 | "gulp-autoprefixer": "^3.1.0",
21 | "gulp-clean": "^0.3.2",
22 | "gulp-combine-mq": "^0.4.0",
23 | "gulp-concat": "^2.6.0",
24 | "gulp-csso": "^1.1.0",
25 | "gulp-filter": "^4.0.0",
26 | "gulp-jshint": "^2.0.0",
27 | "gulp-livereload": "^3.8.1",
28 | "gulp-load-plugins": "^1.2.0",
29 | "gulp-notify": "^2.2.0",
30 | "gulp-order": "^1.1.1",
31 | "gulp-plumber": "^1.1.0",
32 | "gulp-rename": "^1.2.2",
33 | "gulp-sass": "^2.2.0",
34 | "gulp-sort": "^2.0.0",
35 | "gulp-sourcemaps": "^1.6.0",
36 | "gulp-todo": "^5.1.0",
37 | "gulp-uglify": "^1.5.3",
38 | "gulp-watch": "^4.3.5",
39 | "gulp-wp-pot": "^1.1.1",
40 | "gulp-zip": "^3.2.0",
41 | "jshint": "^2.9.1",
42 | "run-sequence": "^1.1.5"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | === WPJSFSP ===
2 | Contributors: danieliser
3 | Author URI: https://twitter.com/daniel_iser
4 | Plugin URI: https://github.com/danieliser/WP-JS-Form-Sample-Plugin
5 | Donate link:
6 | Tags:
7 | Requires at least: 3.4.0
8 | Tested up to: 4.8.3
9 | Stable tag: 1.0.0
10 | Minimum PHP: 5.3
11 | License: GNU Version 3 or Any Later Version
12 |
13 | == Description ==
14 |
15 | Increase user engagement and grow your business with automated marketing messages
16 |
17 | == Installation ==
18 |
19 | = Minimum Requirements =
20 |
21 | * WordPress 3.6 or greater
22 | * PHP version 5.3 or greater
23 |
24 | == Changelog ==
25 | = v1.0.0 =
26 | * Initial Release
--------------------------------------------------------------------------------
/screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/1.png
--------------------------------------------------------------------------------
/screenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/2.png
--------------------------------------------------------------------------------
/screenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/3.png
--------------------------------------------------------------------------------
/screenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/4.png
--------------------------------------------------------------------------------
/screenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/5.png
--------------------------------------------------------------------------------
/screenshots/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/6.png
--------------------------------------------------------------------------------
/screenshots/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/7.png
--------------------------------------------------------------------------------
/screenshots/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/8.png
--------------------------------------------------------------------------------
/screenshots/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/danieliser/WP-JS-Form-Sample-Plugin/ce1a1d62979b884110ac2b47edac0b6e4f0d5e70/screenshots/9.png
--------------------------------------------------------------------------------
/wp-js-form-sample-plugin.php:
--------------------------------------------------------------------------------
1 | setup_constants();
132 | self::$instance->load_textdomain();
133 | self::$instance->includes();
134 | self::$instance->init();
135 | }
136 |
137 | return self::$instance;
138 | }
139 |
140 | /**
141 | * Setup plugin constants
142 | */
143 | private function setup_constants() {
144 | self::$DIR = plugin_dir_path( __FILE__ );
145 | self::$URL = plugins_url( '/', __FILE__ );
146 | self::$FILE = __FILE__;
147 | }
148 |
149 | /**
150 | * Include necessary files
151 | */
152 | private function includes() {
153 | require_once self::$DIR . '/includes/options.php';
154 | }
155 |
156 | /**
157 | * Initialize everything
158 | */
159 | private function init() {
160 | \WPJSFSP\Options::init();
161 | \WPJSFSP\Admin::init();
162 | \WPJSFSP\Conditions::instance();
163 | }
164 |
165 | /**
166 | * Internationalization
167 | */
168 | private function load_textdomain() {
169 | load_plugin_textdomain( 'wp-js-form-sample-plugin' );
170 | }
171 |
172 | /**
173 | * Get the template path.
174 | * @return string
175 | */
176 | public function template_path() {
177 | return apply_filters( 'wpjsfsp_template_path', self::$TEMPLATE_PATH );
178 | }
179 | }
180 |
181 | /**
182 | * The main function responsible for returning the one true WPJSFSP
183 | * Instance to functions everywhere.
184 | *
185 | * Use this function like you would a global variable, except without needing
186 | * to declare the global.
187 | *
188 | * Example:
189 | *
190 | * @since 1.0.0
191 | * @return object The one true WPJSFSP Instance
192 | */
193 | function wpjsfsp() {
194 | return WPJSFSP::instance();
195 | }
196 |
197 | // Get Recipe Manager Running
198 | add_action( 'plugins_loaded', 'wpjsfsp', 9 );
199 |
200 | /**
201 | * Plugin Activation hook function to check for Minimum PHP and WordPress versions
202 | *
203 | * Cannot use static:: in case php 5.2 is used.
204 | */
205 | function wpjsfsp_activation_check() {
206 | global $wp_version;
207 |
208 | if ( version_compare( PHP_VERSION, WPJSFSP::$MIN_PHP_VER, '<' ) ) {
209 | $flag = 'PHP';
210 | } elseif ( version_compare( $wp_version, WPJSFSP::$MIN_WP_VER, '<' ) ) {
211 | $flag = 'WordPress';
212 | } else {
213 | return;
214 | }
215 |
216 | $version = 'PHP' == $flag ? WPJSFSP::$MIN_PHP_VER : WPJSFSP::$MIN_WP_VER;
217 |
218 | // Deactivate automatically due to insufficient PHP or WP Version.
219 | deactivate_plugins( basename( __FILE__ ) );
220 |
221 | $notice = sprintf( __( 'The %4$s %1$s %5$s plugin requires %2$s version %3$s or greater.', 'wp-js-form-sample-plugin' ), WPJSFSP::$NAME, $flag, $version, "", "" );
222 |
223 | wp_die( "$notice
", __( 'Plugin Activation Error', 'wp-js-form-sample-plugin' ), array(
224 | 'response' => 200,
225 | 'back_link' => true,
226 | ) );
227 | }
228 |
229 | // Ensure plugin & environment compatibility.
230 | register_activation_hook( __FILE__, 'wpjsfsp_activation_check' );
231 |
--------------------------------------------------------------------------------