Business Profile - Version 2.1.5

Version Description

(2021-09-30) = - Updated the settings page library. - Updated name of templates folder for consistent prefixing. - Added an option so that, if you offer online ordering, you can enter the URL of your order page (can be on the same site or external) and a link to it will display in your contact card. - Past exceptions no longer show in the schedule/opening hours, and are now automatically removed when the options are saved. - Added "Image URL" field to the list of elements on the schema create/edit screen for the Organization schema type. - Moved contact card block into its own category/section.

Download this release

Release Info

Developer Rustaurius
Plugin Icon 128x128 Business Profile
Version 2.1.5
Comparing to
See all releases

Code changes from version 2.1.4 to 2.1.5

Files changed (82) hide show
  1. assets/css/admin.css +2 -2
  2. assets/css/contact-card.css +5 -0
  3. assets/js/block-contact-card.js +1 -1
  4. assets/js/blocks.build.js +1 -1
  5. {templates → bpfwp-templates}/contact-card.php +0 -0
  6. {templates → bpfwp-templates}/opening-hours.php +0 -0
  7. business-profile.php +13 -5
  8. includes/class-blocks.php +21 -2
  9. includes/class-contact-card-widget.php +2 -0
  10. includes/class-custom-post-types.php +2 -2
  11. includes/class-deactivation-survey.php +2 -2
  12. includes/class-installation-walkthrough.php +12 -1
  13. includes/class-permissions.php +1 -0
  14. includes/class-review-ask.php +1 -1
  15. includes/class-sap-scheduler-meta.php +2 -2
  16. includes/class-schema-cpt.php +9 -1
  17. includes/class-schemas-manager.php +4 -0
  18. includes/class-settings.php +67 -3
  19. includes/class-template-loader.php +1 -1
  20. includes/helper-functions.php +1 -3
  21. includes/schemas/class-schema-organization.php +6 -0
  22. includes/template-functions.php +44 -1
  23. lib/simple-admin-pages/README.md +434 -431
  24. lib/simple-admin-pages/classes/AdminPage.Menu.class.php +32 -32
  25. lib/simple-admin-pages/classes/AdminPage.Submenu.class.php +38 -38
  26. lib/simple-admin-pages/classes/AdminPage.Themes.class.php +15 -15
  27. lib/simple-admin-pages/classes/AdminPage.class.php +232 -232
  28. lib/simple-admin-pages/classes/AdminPageSection.class.php +188 -188
  29. lib/simple-admin-pages/classes/AdminPageSetting.Address.class.php +156 -156
  30. lib/simple-admin-pages/classes/AdminPageSetting.Checkbox.class.php +67 -52
  31. lib/simple-admin-pages/classes/AdminPageSetting.ColorPicker.class.php +39 -39
  32. lib/simple-admin-pages/classes/AdminPageSetting.Count.class.php +117 -111
  33. lib/simple-admin-pages/classes/AdminPageSetting.Editor.class.php +44 -44
  34. lib/simple-admin-pages/classes/AdminPageSetting.FileUpload.class.php +71 -0
  35. lib/simple-admin-pages/classes/AdminPageSetting.HTML.class.php +33 -33
  36. lib/simple-admin-pages/classes/AdminPageSetting.Image.class.php +62 -62
  37. lib/simple-admin-pages/classes/AdminPageSetting.InfiniteTable.class.php +201 -149
  38. lib/simple-admin-pages/classes/AdminPageSetting.McApiKey.class.php +223 -221
  39. lib/simple-admin-pages/classes/AdminPageSetting.McListMerge.class.php +255 -255
  40. lib/simple-admin-pages/classes/AdminPageSetting.Number.class.php +37 -0
  41. lib/simple-admin-pages/classes/AdminPageSetting.OpeningHours.class.php +182 -182
  42. lib/simple-admin-pages/classes/AdminPageSetting.Ordering.class.php +94 -0
  43. lib/simple-admin-pages/classes/AdminPageSetting.Radio.class.php +53 -52
  44. lib/simple-admin-pages/classes/AdminPageSetting.Scheduler.class.php +703 -703
  45. lib/simple-admin-pages/classes/AdminPageSetting.Select.class.php +61 -61
  46. lib/simple-admin-pages/classes/AdminPageSetting.SelectMenu.class.php +57 -57
  47. lib/simple-admin-pages/classes/AdminPageSetting.SelectPost.class.php +65 -65
  48. lib/simple-admin-pages/classes/AdminPageSetting.SelectTaxonomy.class.php +68 -68
  49. lib/simple-admin-pages/classes/AdminPageSetting.Text.class.php +37 -37
  50. lib/simple-admin-pages/classes/AdminPageSetting.Textarea.class.php +58 -58
  51. lib/simple-admin-pages/classes/AdminPageSetting.Toggle.class.php +54 -52
  52. lib/simple-admin-pages/classes/AdminPageSetting.WarningTip.class.php +41 -0
  53. lib/simple-admin-pages/classes/AdminPageSetting.class.php +358 -344
  54. lib/simple-admin-pages/classes/Library.class.php +480 -462
  55. lib/simple-admin-pages/css/admin-settings.css +658 -0
  56. lib/simple-admin-pages/css/admin.css +247 -247
  57. lib/simple-admin-pages/css/infinite_table.css +3 -0
  58. lib/simple-admin-pages/css/ordering.css +27 -0
  59. lib/simple-admin-pages/css/spectrum.css +507 -0
  60. lib/simple-admin-pages/img/options-asset-exclamation.png +0 -0
  61. lib/simple-admin-pages/img/options-asset-info.png +0 -0
  62. lib/simple-admin-pages/img/options-asset-lock.png +0 -0
  63. lib/simple-admin-pages/img/options-asset-star.png +0 -0
  64. lib/simple-admin-pages/img/options-asset-starX2.png +0 -0
  65. lib/simple-admin-pages/js/address.js +116 -116
  66. lib/simple-admin-pages/js/admin-settings.js +81 -0
  67. lib/simple-admin-pages/js/count.js +10 -0
  68. lib/simple-admin-pages/js/file_upload.js +41 -0
  69. lib/simple-admin-pages/js/image.js +53 -53
  70. lib/simple-admin-pages/js/infinite_table.js +85 -0
  71. lib/simple-admin-pages/js/opening-hours.js +20 -20
  72. lib/simple-admin-pages/js/ordering.js +38 -0
  73. lib/simple-admin-pages/js/scheduler.js +403 -403
  74. lib/simple-admin-pages/js/spectrum.js +2317 -0
  75. lib/simple-admin-pages/lib/pickadate/legacy.js +9 -9
  76. lib/simple-admin-pages/lib/pickadate/picker.date.js +4 -4
  77. lib/simple-admin-pages/lib/pickadate/picker.js +6 -6
  78. lib/simple-admin-pages/lib/pickadate/picker.time.js +4 -4
  79. lib/simple-admin-pages/lib/pickadate/themes/default.css +3 -3
  80. lib/simple-admin-pages/lib/pickadate/themes/rtl.css +2 -2
  81. lib/simple-admin-pages/simple-admin-pages.php +52 -52
  82. readme.txt +9 -1
assets/css/admin.css CHANGED
@@ -1864,5 +1864,5 @@ NEW
1864
  .bpfwp-meta-input label {
1865
  display: inline-block;
1866
  vertical-align: text-bottom;
1867
- min-width: 200px;
1868
- }
1864
  .bpfwp-meta-input label {
1865
  display: inline-block;
1866
  vertical-align: text-bottom;
1867
+ min-width: none;
1868
+ }
assets/css/contact-card.css CHANGED
@@ -69,6 +69,7 @@
69
  .bp-directions:before,
70
  .bp-phone:before,
71
  .bp-contact:before,
 
72
  .bp-booking:before,
73
  .bp-opening-hours-brief:before,
74
  .bp-opening-hours .bp-title:before {
@@ -97,6 +98,10 @@
97
  content: "\f470";
98
  }
99
 
 
 
 
 
100
  .bp-contact:before {
101
  content: "\f466";
102
  }
69
  .bp-directions:before,
70
  .bp-phone:before,
71
  .bp-contact:before,
72
+ .bp-ordering-link:before,
73
  .bp-booking:before,
74
  .bp-opening-hours-brief:before,
75
  .bp-opening-hours .bp-title:before {
98
  content: "\f470";
99
  }
100
 
101
+ .bp-ordering-link::before {
102
+ content: "\f116";
103
+ }
104
+
105
  .bp-contact:before {
106
  content: "\f466";
107
  }
assets/js/block-contact-card.js CHANGED
@@ -6,7 +6,7 @@ const { locationOptions } = bpfwp_blocks;
6
 
7
  registerBlockType( 'business-profile/contact-card', {
8
  title: __( 'Contact Card', 'business-profile' ),
9
- category: 'widgets',
10
  icon: 'location',
11
  attributes: {
12
  location: {
6
 
7
  registerBlockType( 'business-profile/contact-card', {
8
  title: __( 'Contact Card', 'business-profile' ),
9
+ category: 'bpfwp-blocks',
10
  icon: 'location',
11
  attributes: {
12
  location: {
assets/js/blocks.build.js CHANGED
@@ -1 +1 @@
1
- !function(e){function n(t){if(o[t])return o[t].exports;var l=o[t]={i:t,l:!1,exports:{}};return e[t].call(l.exports,l,l.exports,n),l.l=!0,l.exports}var o={};n.m=e,n.c=o,n.d=function(e,o,t){n.o(e,o)||Object.defineProperty(e,o,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var o=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(o,"a",o),o},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=0)}([function(e,n,o){e.exports=o(1)},function(e,n){var o=wp.i18n.__,t=wp.blocks.registerBlockType,l=wp.components,s=l.SelectControl,r=l.CheckboxControl,a=l.PanelBody,i=l.ServerSideRender,c=l.Disabled,p=wp.editor.InspectorControls,u=bpfwp_blocks,h=u.locationOptions;t("business-profile/contact-card",{title:o("Contact Card","business-profile"),category:"widgets",icon:"location",attributes:{location:{type:"number",default:0},show_name:{type:"boolean",default:!0},show_address:{type:"boolean",default:!0},show_get_directions:{type:"boolean",default:!0},show_phone:{type:"boolean",default:!0},show_contact:{type:"boolean",default:!0},show_opening_hours:{type:"boolean",default:!0},show_opening_hours_brief:{type:"boolean",default:!1},show_map:{type:"boolean",default:!0}},supports:{html:!1},edit:function(e){var n=e.attributes,t=e.setAttributes;return wp.element.createElement("div",null,wp.element.createElement(p,null,wp.element.createElement(a,null,h.length?wp.element.createElement(s,{label:o("Select a Location","business-profile"),value:n.location,onChange:function(e){return t({location:parseInt(e,10)})},options:h}):"",wp.element.createElement(r,{label:o("Show Name","business-profile"),checked:n.show_name,onChange:function(e){t({show_name:e})}}),wp.element.createElement(r,{label:o("Show Address","business-profile"),checked:n.show_address,onChange:function(e){t({show_address:e})}}),wp.element.createElement(r,{label:o("Show link to get directions on Google Maps","business-profile"),checked:n.show_get_directions,onChange:function(e){t({show_get_directions:e})}}),wp.element.createElement(r,{label:o("Show Phone number","business-profile"),checked:n.show_phone,onChange:function(e){t({show_phone:e})}}),wp.element.createElement(r,{label:o("Show contact details","business-profile"),checked:n.show_contact,onChange:function(e){t({show_contact:e})}}),wp.element.createElement(r,{label:o("Show Opening Hours","business-profile"),checked:n.show_opening_hours,onChange:function(e){t({show_opening_hours:e})}}),wp.element.createElement(r,{label:o("Show brief opening hours on one line","business-profile"),checked:n.show_opening_hours_brief,onChange:function(e){t({show_opening_hours_brief:e})}}),wp.element.createElement(r,{label:o("Show Google Map","business-profile"),checked:n.show_map,onChange:function(e){t({show_map:e})}}))),wp.element.createElement(c,null,wp.element.createElement(i,{block:"business-profile/contact-card",attributes:n})))},save:function(){return null}})}]);
1
+ !function(e){function n(t){if(o[t])return o[t].exports;var l=o[t]={i:t,l:!1,exports:{}};return e[t].call(l.exports,l,l.exports,n),l.l=!0,l.exports}var o={};n.m=e,n.c=o,n.d=function(e,o,t){n.o(e,o)||Object.defineProperty(e,o,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var o=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(o,"a",o),o},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n(n.s=0)}([function(e,n,o){e.exports=o(1)},function(e,n){var o=wp.i18n.__,t=wp.blocks.registerBlockType,l=wp.components,s=l.SelectControl,r=l.CheckboxControl,a=l.PanelBody,i=l.ServerSideRender,c=l.Disabled,p=wp.editor.InspectorControls,u=bpfwp_blocks,h=u.locationOptions;t("business-profile/contact-card",{title:o("Contact Card","business-profile"),category:"bpfwp-blocks",icon:"location",attributes:{location:{type:"number",default:0},show_name:{type:"boolean",default:!0},show_address:{type:"boolean",default:!0},show_get_directions:{type:"boolean",default:!0},show_phone:{type:"boolean",default:!0},show_contact:{type:"boolean",default:!0},show_opening_hours:{type:"boolean",default:!0},show_opening_hours_brief:{type:"boolean",default:!1},show_map:{type:"boolean",default:!0}},supports:{html:!1},edit:function(e){var n=e.attributes,t=e.setAttributes;return wp.element.createElement("div",null,wp.element.createElement(p,null,wp.element.createElement(a,null,h.length?wp.element.createElement(s,{label:o("Select a Location","business-profile"),value:n.location,onChange:function(e){return t({location:parseInt(e,10)})},options:h}):"",wp.element.createElement(r,{label:o("Show Name","business-profile"),checked:n.show_name,onChange:function(e){t({show_name:e})}}),wp.element.createElement(r,{label:o("Show Address","business-profile"),checked:n.show_address,onChange:function(e){t({show_address:e})}}),wp.element.createElement(r,{label:o("Show link to get directions on Google Maps","business-profile"),checked:n.show_get_directions,onChange:function(e){t({show_get_directions:e})}}),wp.element.createElement(r,{label:o("Show Phone number","business-profile"),checked:n.show_phone,onChange:function(e){t({show_phone:e})}}),wp.element.createElement(r,{label:o("Show contact details","business-profile"),checked:n.show_contact,onChange:function(e){t({show_contact:e})}}),wp.element.createElement(r,{label:o("Show Opening Hours","business-profile"),checked:n.show_opening_hours,onChange:function(e){t({show_opening_hours:e})}}),wp.element.createElement(r,{label:o("Show brief opening hours on one line","business-profile"),checked:n.show_opening_hours_brief,onChange:function(e){t({show_opening_hours_brief:e})}}),wp.element.createElement(r,{label:o("Show Google Map","business-profile"),checked:n.show_map,onChange:function(e){t({show_map:e})}}))),wp.element.createElement(c,null,wp.element.createElement(i,{block:"business-profile/contact-card",attributes:n})))},save:function(){return null}})}]);
{templates → bpfwp-templates}/contact-card.php RENAMED
File without changes
{templates → bpfwp-templates}/opening-hours.php RENAMED
File without changes
business-profile.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: Five Star Business Profile and Schema
4
  * Plugin URI: https://www.fivestarplugins.com/plugins/business-profile/
5
  * Description: Add schema structured data to any page or post type. Create an SEO friendly contact card with your business info and associated schema. Supports Google Map, opening hours and more.
6
- * Version: 2.1.4
7
  * Author: Five Star Plugins
8
  * Author URI: https://www.fivestarplugins.com
9
  * License: GPLv3
@@ -123,7 +123,7 @@ if ( ! class_exists( 'bpfwpInit', false ) ) :
123
  define( 'BPFWP_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
124
  define( 'BPFWP_PLUGIN_URL', untrailingslashit( plugin_dir_url( __FILE__ ) ) );
125
  define( 'BPFWP_PLUGIN_FNAME', plugin_basename( __FILE__ ) );
126
- define( 'BPFWP_VERSION', '2.0.4' );
127
  }
128
 
129
  /**
@@ -158,12 +158,14 @@ if ( ! class_exists( 'bpfwpInit', false ) ) :
158
  * @return void
159
  */
160
  protected function instantiate() {
 
161
  new bpfwpCompatibility();
162
  new bpfwpIntegrations(); // Deprecated in v1.1.
163
  new bpfwpDeactivationSurvey();
164
  new bpfwpReviewAsk();
165
  new bpfwpInstallationWalkthrough();
166
- //$this->permissions = new bpfwpPermissions();
 
167
  $this->schemas = new bpfwpSchemasManager();
168
  $this->settings = new bpfwpSettings();
169
  $this->cpts = new bpfwpCustomPostTypes();
@@ -247,7 +249,7 @@ if ( ! class_exists( 'bpfwpInit', false ) ) :
247
  $screen = get_current_screen();
248
  $screenID = $screen->id;
249
  $screenPostType = $screen->post_type;
250
- $settings = get_option( 'bpfwp-settings' );
251
 
252
  if ( $screenID != 'business-profile_page_bpfwp-settings' && $screenID != 'business-profile_page_bpfwp-dashboard' && $screenPostType != 'location' && $screenPostType != 'schema' ) {return;}
253
 
@@ -298,7 +300,13 @@ if ( ! class_exists( 'bpfwpInit', false ) ) :
298
  $screen = get_current_screen();
299
  $screenPostType = $screen->post_type;
300
 
301
- if ( ('post-new.php' === $hook_suffix || 'post.php' === $hook_suffix) || $screenPostType == 'location' || $screenPostType == 'schema' ) {
 
 
 
 
 
 
302
  //if ( $this->settings->get_setting( 'multiple-locations' ) && $this->cpts->location_cpt_slug === $post->post_type ) {
303
  wp_enqueue_style( 'bpfwp-admin-location', BPFWP_PLUGIN_URL . '/assets/css/admin.css', array(), BPFWP_VERSION );
304
  wp_enqueue_script( 'bpfwp-admin-js', BPFWP_PLUGIN_URL . '/assets/js/admin.js', array( 'jquery' ), BPFWP_VERSION, true );
3
  * Plugin Name: Five Star Business Profile and Schema
4
  * Plugin URI: https://www.fivestarplugins.com/plugins/business-profile/
5
  * Description: Add schema structured data to any page or post type. Create an SEO friendly contact card with your business info and associated schema. Supports Google Map, opening hours and more.
6
+ * Version: 2.1.5
7
  * Author: Five Star Plugins
8
  * Author URI: https://www.fivestarplugins.com
9
  * License: GPLv3
123
  define( 'BPFWP_PLUGIN_DIR', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
124
  define( 'BPFWP_PLUGIN_URL', untrailingslashit( plugin_dir_url( __FILE__ ) ) );
125
  define( 'BPFWP_PLUGIN_FNAME', plugin_basename( __FILE__ ) );
126
+ define( 'BPFWP_VERSION', '2.0.5' );
127
  }
128
 
129
  /**
158
  * @return void
159
  */
160
  protected function instantiate() {
161
+
162
  new bpfwpCompatibility();
163
  new bpfwpIntegrations(); // Deprecated in v1.1.
164
  new bpfwpDeactivationSurvey();
165
  new bpfwpReviewAsk();
166
  new bpfwpInstallationWalkthrough();
167
+
168
+ $this->permissions = new bpfwpPermissions();
169
  $this->schemas = new bpfwpSchemasManager();
170
  $this->settings = new bpfwpSettings();
171
  $this->cpts = new bpfwpCustomPostTypes();
249
  $screen = get_current_screen();
250
  $screenID = $screen->id;
251
  $screenPostType = $screen->post_type;
252
+ $settings = get_option( 'bpfwp-settings', [] );
253
 
254
  if ( $screenID != 'business-profile_page_bpfwp-settings' && $screenID != 'business-profile_page_bpfwp-dashboard' && $screenPostType != 'location' && $screenPostType != 'schema' ) {return;}
255
 
300
  $screen = get_current_screen();
301
  $screenPostType = $screen->post_type;
302
 
303
+ if (
304
+ 'post-new.php' === $hook_suffix
305
+ || 'post.php' === $hook_suffix
306
+ || $screenPostType == 'location'
307
+ || $screenPostType == 'schema'
308
+ || $screen->id == 'business-profile_page_bpfwp-settings'
309
+ ) {
310
  //if ( $this->settings->get_setting( 'multiple-locations' ) && $this->cpts->location_cpt_slug === $post->post_type ) {
311
  wp_enqueue_style( 'bpfwp-admin-location', BPFWP_PLUGIN_URL . '/assets/css/admin.css', array(), BPFWP_VERSION );
312
  wp_enqueue_script( 'bpfwp-admin-js', BPFWP_PLUGIN_URL . '/assets/js/admin.js', array( 'jquery' ), BPFWP_VERSION, true );
includes/class-blocks.php CHANGED
@@ -27,7 +27,10 @@ if ( ! class_exists( 'bpfwpBlocks', false ) ) :
27
  * @return void
28
  */
29
  public function run() {
 
30
  add_action( 'init', array( $this, 'register' ) );
 
 
31
  }
32
 
33
  /**
@@ -46,7 +49,8 @@ if ( ! class_exists( 'bpfwpBlocks', false ) ) :
46
  wp_register_script(
47
  'business-profile-blocks',
48
  BPFWP_PLUGIN_URL . '/assets/js/blocks.build.js',
49
- array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' )
 
50
  );
51
 
52
  wp_register_script(
@@ -60,7 +64,8 @@ if ( ! class_exists( 'bpfwpBlocks', false ) ) :
60
  wp_register_style(
61
  'bpfwp-default',
62
  BPFWP_PLUGIN_URL . '/assets/css/contact-card.css',
63
- array()
 
64
  );
65
 
66
  register_block_type( 'business-profile/contact-card', array(
@@ -159,5 +164,19 @@ if ( ! class_exists( 'bpfwpBlocks', false ) ) :
159
  'before'
160
  );
161
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  }
163
  endif;
27
  * @return void
28
  */
29
  public function run() {
30
+
31
  add_action( 'init', array( $this, 'register' ) );
32
+
33
+ add_filter( 'block_categories_all', array( $this, 'add_block_category' ) );
34
  }
35
 
36
  /**
49
  wp_register_script(
50
  'business-profile-blocks',
51
  BPFWP_PLUGIN_URL . '/assets/js/blocks.build.js',
52
+ array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor' ),
53
+ BPFWP_VERSION
54
  );
55
 
56
  wp_register_script(
64
  wp_register_style(
65
  'bpfwp-default',
66
  BPFWP_PLUGIN_URL . '/assets/css/contact-card.css',
67
+ array(),
68
+ BPFWP_VERSION
69
  );
70
 
71
  register_block_type( 'business-profile/contact-card', array(
164
  'before'
165
  );
166
  }
167
+
168
+ /**
169
+ * Create a new category of blocks to hold our block
170
+ * @since 2.0.0
171
+ */
172
+ public function add_block_category( $categories ) {
173
+
174
+ $categories[] = array(
175
+ 'slug' => 'bpfwp-blocks',
176
+ 'title' => __( 'Five Star Business Profile and Schema', 'business-profile' ),
177
+ );
178
+
179
+ return $categories;
180
+ }
181
  }
182
  endif;
includes/class-contact-card-widget.php CHANGED
@@ -40,6 +40,7 @@ if ( ! class_exists( 'bpfwpContactCardWidget', false ) ) :
40
  'show_address' => __( 'Show Address', 'business-profile' ),
41
  'show_get_directions' => __( 'Show link to get directions on Google Maps', 'business-profile' ),
42
  'show_phone' => __( 'Show Phone number', 'business-profile' ),
 
43
  'show_contact' => __( 'Show contact details', 'business-profile' ),
44
  'show_opening_hours' => __( 'Show Opening Hours', 'business-profile' ),
45
  'show_opening_hours_brief' => __( 'Show brief opening hours on one line', 'business-profile' ),
@@ -70,6 +71,7 @@ if ( ! class_exists( 'bpfwpContactCardWidget', false ) ) :
70
  $title = apply_filters( 'widget_title', $instance['title'] );
71
  echo $args['before_title'] . $title . $args['after_title'];
72
  }
 
73
  echo bpwfwp_print_contact_card( $instance );
74
  echo $args['after_widget'];
75
  }
40
  'show_address' => __( 'Show Address', 'business-profile' ),
41
  'show_get_directions' => __( 'Show link to get directions on Google Maps', 'business-profile' ),
42
  'show_phone' => __( 'Show Phone number', 'business-profile' ),
43
+ 'show_ordering_link' => __( 'Show Ordering Link', 'business-profile' ),
44
  'show_contact' => __( 'Show contact details', 'business-profile' ),
45
  'show_opening_hours' => __( 'Show Opening Hours', 'business-profile' ),
46
  'show_opening_hours_brief' => __( 'Show brief opening hours on one line', 'business-profile' ),
71
  $title = apply_filters( 'widget_title', $instance['title'] );
72
  echo $args['before_title'] . $title . $args['after_title'];
73
  }
74
+
75
  echo bpwfwp_print_contact_card( $instance );
76
  echo $args['after_widget'];
77
  }
includes/class-custom-post-types.php CHANGED
@@ -465,7 +465,7 @@ if ( ! class_exists( 'bpfwpCustomPostTypes', false ) ) :
465
  $scheduler = $this->get_scheduler_meta_object( get_post_meta( $post->ID, 'opening_hours', true ) );
466
 
467
  // Load required scripts and styles.
468
- wp_enqueue_style( 'bpfwp-admin-location-sap', BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/css/admin.css' );
469
  foreach ( $scheduler->styles as $handle => $style ) {
470
  wp_enqueue_style( $handle, BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/' . $style['path'], $style['dependencies'], $style['version'], $style['media'] );
471
  }
@@ -528,7 +528,7 @@ if ( ! class_exists( 'bpfwpCustomPostTypes', false ) ) :
528
  $schema_fields = $post_is_set ? $bpfwp_controller->schemas->schema_cpts[$post->ID]->schema_class->fields : array();
529
 
530
  // Add in the schema selector script and pass post_type, post, page, etc. data to javascript
531
- wp_enqueue_script( 'bpfwp-admin-schema-selector', BPFWP_PLUGIN_URL . '/assets/js/admin-schema-selector.js', array( 'jquery' ) );
532
  wp_localize_script(
533
  'bpfwp-admin-schema-selector',
534
  'schema_option_data',
465
  $scheduler = $this->get_scheduler_meta_object( get_post_meta( $post->ID, 'opening_hours', true ) );
466
 
467
  // Load required scripts and styles.
468
+ wp_enqueue_style( 'bpfwp-admin-location-sap', BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/css/admin.css', array(), BPFWP_VERSION );
469
  foreach ( $scheduler->styles as $handle => $style ) {
470
  wp_enqueue_style( $handle, BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/' . $style['path'], $style['dependencies'], $style['version'], $style['media'] );
471
  }
528
  $schema_fields = $post_is_set ? $bpfwp_controller->schemas->schema_cpts[$post->ID]->schema_class->fields : array();
529
 
530
  // Add in the schema selector script and pass post_type, post, page, etc. data to javascript
531
+ wp_enqueue_script( 'bpfwp-admin-schema-selector', BPFWP_PLUGIN_URL . '/assets/js/admin-schema-selector.js', array( 'jquery' ), BPFWP_VERSION );
532
  wp_localize_script(
533
  'bpfwp-admin-schema-selector',
534
  'schema_option_data',
includes/class-deactivation-survey.php CHANGED
@@ -21,8 +21,8 @@ class bpfwpDeactivationSurvey {
21
  }
22
 
23
  public function enqueue_deactivation_scripts() {
24
- wp_enqueue_style( 'bpfwp-deactivation-css', BPFWP_PLUGIN_URL . '/assets/css/plugin-deactivation.css' );
25
- wp_enqueue_script( 'bpfwp-deactivation-js', BPFWP_PLUGIN_URL . '/assets/js/plugin-deactivation.js', array( 'jquery' ) );
26
 
27
  wp_localize_script( 'bpfwp-deactivation-js', 'bpfwp_deactivation_data', array( 'site_url' => site_url() ) );
28
  }
21
  }
22
 
23
  public function enqueue_deactivation_scripts() {
24
+ wp_enqueue_style( 'bpfwp-deactivation-css', BPFWP_PLUGIN_URL . '/assets/css/plugin-deactivation.css', array(), BPFWP_VERSION );
25
+ wp_enqueue_script( 'bpfwp-deactivation-js', BPFWP_PLUGIN_URL . '/assets/js/plugin-deactivation.js', array( 'jquery' ), BPFWP_VERSION );
26
 
27
  wp_localize_script( 'bpfwp-deactivation-js', 'bpfwp_deactivation_data', array( 'site_url' => site_url() ) );
28
  }
includes/class-installation-walkthrough.php CHANGED
@@ -69,7 +69,18 @@ class bpfwpInstallationWalkthrough {
69
  'class' => 'bpfwp-opening-hours'
70
  )
71
  );
72
- $this->scheduler = new sapAdminPageSettingScheduler_2_1_2( $args );
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  add_action('wp_ajax_bpfwp_welcome_add_contact_page', array($this, 'add_contact_page'));
75
  add_action('wp_ajax_bpfwp_welcome_set_contact_information', array($this, 'set_contact_information'));
69
  'class' => 'bpfwp-opening-hours'
70
  )
71
  );
72
+
73
+
74
+ // This is required otherwise SAP_VERSION will throw error.
75
+ require_once BPFWP_PLUGIN_DIR . '/lib/simple-admin-pages/simple-admin-pages.php';
76
+ $sap = sap_initialize_library(
77
+ array(
78
+ 'version' => '2.5.5',
79
+ 'lib_url' => BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/',
80
+ )
81
+ );
82
+
83
+ $this->scheduler = new sapAdminPageSettingScheduler_2_5_5( $args );
84
 
85
  add_action('wp_ajax_bpfwp_welcome_add_contact_page', array($this, 'add_contact_page'));
86
  add_action('wp_ajax_bpfwp_welcome_set_contact_information', array($this, 'set_contact_information'));
includes/class-permissions.php CHANGED
@@ -17,6 +17,7 @@ class bpfwpPermissions {
17
  "premium" => 2,
18
  "locations" => 2,
19
  "integrations" => 2,
 
20
  );
21
  }
22
 
17
  "premium" => 2,
18
  "locations" => 2,
19
  "integrations" => 2,
20
+ "api_usage" => 2
21
  );
22
  }
23
 
includes/class-review-ask.php CHANGED
@@ -68,7 +68,7 @@ class bpfwpReviewAsk {
68
  }
69
 
70
  public function enqueue_review_ask_scripts() {
71
- wp_enqueue_style( 'bpfwp-review-ask-css', BPFWP_PLUGIN_URL . '/assets/css/dashboard-review-ask.css' );
72
  wp_enqueue_script( 'bpfwp-review-ask-js', BPFWP_PLUGIN_URL . '/assets/js/dashboard-review-ask.js', array( 'jquery' ), BPFWP_VERSION, true );
73
  }
74
 
68
  }
69
 
70
  public function enqueue_review_ask_scripts() {
71
+ wp_enqueue_style( 'bpfwp-review-ask-css', BPFWP_PLUGIN_URL . '/assets/css/dashboard-review-ask.css', array(),BPFWP_VERSION );
72
  wp_enqueue_script( 'bpfwp-review-ask-js', BPFWP_PLUGIN_URL . '/assets/js/dashboard-review-ask.js', array( 'jquery' ), BPFWP_VERSION, true );
73
  }
74
 
includes/class-sap-scheduler-meta.php CHANGED
@@ -15,7 +15,7 @@ defined( 'ABSPATH' ) || exit;
15
 
16
  require_once BPFWP_PLUGIN_DIR . '/lib/simple-admin-pages/classes/AdminPageSetting.Scheduler.class.php';
17
 
18
- if ( ! class_exists( 'bpfwpSAPSchedulerMeta', false ) && class_exists( 'sapAdminPageSettingScheduler_2_1_2' ) ) :
19
 
20
  /**
21
  * Class to extend the Simple Admin Pages Scheduler component for use on
@@ -23,7 +23,7 @@ if ( ! class_exists( 'bpfwpSAPSchedulerMeta', false ) && class_exists( 'sapAdmin
23
  *
24
  * @since 1.1
25
  */
26
- class bpfwpSAPSchedulerMeta extends sapAdminPageSettingScheduler_2_1_2 {
27
 
28
  /**
29
  * Generate an option input field name. The default component appends
15
 
16
  require_once BPFWP_PLUGIN_DIR . '/lib/simple-admin-pages/classes/AdminPageSetting.Scheduler.class.php';
17
 
18
+ if ( ! class_exists( 'bpfwpSAPSchedulerMeta', false ) && class_exists( 'sapAdminPageSettingScheduler_2_5_5' ) ) :
19
 
20
  /**
21
  * Class to extend the Simple Admin Pages Scheduler component for use on
23
  *
24
  * @since 1.1
25
  */
26
+ class bpfwpSAPSchedulerMeta extends sapAdminPageSettingScheduler_2_5_5 {
27
 
28
  /**
29
  * Generate an option input field name. The default component appends
includes/class-schema-cpt.php CHANGED
@@ -135,7 +135,7 @@ if ( ! class_exists( 'bpfwpSchemaCPT' ) ) :
135
  add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
136
  add_action( 'save_post', array( $this, 'save_meta' ) );
137
 
138
- wp_enqueue_script( 'schema-cpt', BPFWP_PLUGIN_URL . '/assets/js/schema-cpt.js', array( 'jquery') );
139
  }
140
 
141
 
@@ -345,6 +345,8 @@ if ( ! class_exists( 'bpfwpSchemaCPT' ) ) :
345
  * @return int $post_id The current post ID.
346
  */
347
  public function save_meta( $post_id ) {
 
 
348
  if ( ! isset( $_POST['bpfwp_schema_meta_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['bpfwp_schema_meta_nonce'] ), 'bpfwp_schema_meta' ) ) { // Input var okay.
349
  return $post_id;
350
  }
@@ -356,6 +358,12 @@ if ( ! class_exists( 'bpfwpSchemaCPT' ) ) :
356
  if ( ! current_user_can( 'edit_post', $post_id ) ) {
357
  return $post_id;
358
  }
 
 
 
 
 
 
359
 
360
  if ( ! $this->validate_target( get_post( $post_id ) ) ) {
361
  return $post_id;
135
  add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
136
  add_action( 'save_post', array( $this, 'save_meta' ) );
137
 
138
+ wp_enqueue_script( 'schema-cpt', BPFWP_PLUGIN_URL . '/assets/js/schema-cpt.js', array( 'jquery'), BPFWP_VERSION );
139
  }
140
 
141
 
345
  * @return int $post_id The current post ID.
346
  */
347
  public function save_meta( $post_id ) {
348
+ global $bpfwp_controller;
349
+
350
  if ( ! isset( $_POST['bpfwp_schema_meta_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['bpfwp_schema_meta_nonce'] ), 'bpfwp_schema_meta' ) ) { // Input var okay.
351
  return $post_id;
352
  }
358
  if ( ! current_user_can( 'edit_post', $post_id ) ) {
359
  return $post_id;
360
  }
361
+
362
+ $post = get_post( $post_id );
363
+
364
+ if ($post->post_type !== $bpfwp_controller->cpts->schema_cpt_slug) {
365
+ return;
366
+ }
367
 
368
  if ( ! $this->validate_target( get_post( $post_id ) ) ) {
369
  return $post_id;
includes/class-schemas-manager.php CHANGED
@@ -52,6 +52,10 @@ if ( ! class_exists( 'bpfwpSchemasManager' ) ) :
52
  public function create_schema_cpts() {
53
  global $bpfwp_controller;
54
 
 
 
 
 
55
  require_once BPFWP_PLUGIN_DIR . '/includes/class-schema-cpt.php';
56
  //require_once BPFWP_PLUGIN_DIR . '/includes/class-schema-cpt-post_type.php';
57
 
52
  public function create_schema_cpts() {
53
  global $bpfwp_controller;
54
 
55
+ if( ! is_a( $bpfwp_controller, 'bpfwpInit') ) {
56
+ return;
57
+ }
58
+
59
  require_once BPFWP_PLUGIN_DIR . '/includes/class-schema-cpt.php';
60
  //require_once BPFWP_PLUGIN_DIR . '/includes/class-schema-cpt-post_type.php';
61
 
includes/class-settings.php CHANGED
@@ -58,6 +58,9 @@ if ( ! class_exists( 'bpfwpSettings' ) ) :
58
  add_action( 'init', array( $this, 'set_defaults' ) );
59
 
60
  add_action( 'init', array( $this, 'load_settings_panel' ) );
 
 
 
61
  }
62
 
63
  /**
@@ -102,11 +105,12 @@ if ( ! class_exists( 'bpfwpSettings' ) ) :
102
  'show_address' => true,
103
  'show_get_directions' => true,
104
  'show_phone' => true,
 
105
  'show_contact' => true,
106
  'show_opening_hours' => true,
107
  'show_opening_hours_brief' => false,
108
  'show_map' => true,
109
- 'show_image' => false,
110
  )
111
  );
112
 
@@ -253,7 +257,7 @@ if ( ! class_exists( 'bpfwpSettings' ) ) :
253
  require_once BPFWP_PLUGIN_DIR . '/lib/simple-admin-pages/simple-admin-pages.php';
254
  $sap = sap_initialize_library(
255
  $args = array(
256
- 'version' => '2.1.2',
257
  'lib_url' => BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/',
258
  )
259
  );
@@ -325,6 +329,22 @@ if ( ! class_exists( 'bpfwpSettings' ) ) :
325
  )
326
  );
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  $sap->add_section(
329
  'bpfwp-settings',
330
  array(
@@ -347,7 +367,6 @@ if ( ! class_exists( 'bpfwpSettings' ) ) :
347
  'label_for' => 'bpfwp-settings[name]',
348
  'class' => 'bpfwp-name'
349
  )
350
-
351
  )
352
  );
353
 
@@ -775,6 +794,51 @@ if ( ! class_exists( 'bpfwpSettings' ) ) :
775
 
776
  }
777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
  /**
779
  * Array of schema type options
780
  *
58
  add_action( 'init', array( $this, 'set_defaults' ) );
59
 
60
  add_action( 'init', array( $this, 'load_settings_panel' ) );
61
+
62
+ // Order schedule exceptions and remove past exceptions
63
+ add_filter( 'sanitize_option_bpfwp-settings', array( $this, 'clean_schedule_exceptions' ), 100 );
64
  }
65
 
66
  /**
105
  'show_address' => true,
106
  'show_get_directions' => true,
107
  'show_phone' => true,
108
+ 'show_ordering_link' => true,
109
  'show_contact' => true,
110
  'show_opening_hours' => true,
111
  'show_opening_hours_brief' => false,
112
  'show_map' => true,
113
+ 'show_image' => false
114
  )
115
  );
116
 
257
  require_once BPFWP_PLUGIN_DIR . '/lib/simple-admin-pages/simple-admin-pages.php';
258
  $sap = sap_initialize_library(
259
  $args = array(
260
+ 'version' => '2.5.5',
261
  'lib_url' => BPFWP_PLUGIN_URL . '/lib/simple-admin-pages/',
262
  )
263
  );
329
  )
330
  );
331
 
332
+ $sap->add_setting(
333
+ 'bpfwp-settings',
334
+ 'bpfwp-seo',
335
+ 'text',
336
+ array(
337
+ 'id' => 'ordering-link',
338
+ 'title' => __( 'Ordering Link', 'business-profile' ),
339
+ 'description' => __( 'If you offer online ordering, enter the URL of your order page here (can be on this site or external) and a link to it will display in your contact card.', 'business-profile' ),
340
+ 'placeholder' => 'https://example.com',
341
+ 'args' => array(
342
+ 'label_for' => 'bpfwp-settings[ordering-link]',
343
+ 'class' => 'bpfwp-ordering-link'
344
+ )
345
+ )
346
+ );
347
+
348
  $sap->add_section(
349
  'bpfwp-settings',
350
  array(
367
  'label_for' => 'bpfwp-settings[name]',
368
  'class' => 'bpfwp-name'
369
  )
 
370
  )
371
  );
372
 
794
 
795
  }
796
 
797
+ /**
798
+ * Sort the schedule exceptions and remove past exceptions before saving
799
+ *
800
+ * @since 2.1.5
801
+ */
802
+ public function clean_schedule_exceptions( $val ) {
803
+
804
+ if ( empty( $val['exceptions'] ) ) {
805
+ return $val;
806
+ }
807
+
808
+ // Sort by date
809
+ $exceptions = $val['exceptions'];
810
+ usort( $exceptions, array( $this, 'sort_by_date' ) );
811
+
812
+ // Remove exceptions more than a day old
813
+ $week_ago = time() - 24*3600;
814
+ for( $i = 0; $i < count( $exceptions ); $i++ ) {
815
+ if ( strtotime( $exceptions[$i]['date'] ) > $week_ago ) {
816
+ break;
817
+ }
818
+ }
819
+ if ( $i ) {
820
+ $exceptions = array_slice( $exceptions, $i );
821
+ }
822
+
823
+ $val['exceptions'] = $exceptions;
824
+
825
+ return $val;
826
+ }
827
+
828
+ /**
829
+ * Sort an associative array by the value's date parameter
830
+ *
831
+ * @usedby self::clean_schedule_exceptions()
832
+ * @since 2.1.5
833
+ */
834
+ public function sort_by_date( $a, $b ) {
835
+
836
+ $ad = empty( $a['date'] ) ? 0 : strtotime( $a['date'] );
837
+ $bd = empty( $b['date'] ) ? 0 : strtotime( $b['date'] );
838
+
839
+ return $ad - $bd;
840
+ }
841
+
842
  /**
843
  * Array of schema type options
844
  *
includes/class-template-loader.php CHANGED
@@ -66,5 +66,5 @@ class bpfwpTemplateLoader extends Bpfwp_Gamajo_Template_Loader {
66
  * @access protected
67
  * @var string
68
  */
69
- protected $plugin_template_directory = 'templates';
70
  }
66
  * @access protected
67
  * @var string
68
  */
69
+ protected $plugin_template_directory = 'bpfwp-templates';
70
  }
includes/helper-functions.php CHANGED
@@ -96,6 +96,4 @@ if ( ! function_exists( 'bpfwp_wc_get_most_recent_review_author' ) ) {
96
  return $most_recent_comment->comment_author;
97
  }
98
  }
99
- }
100
-
101
- ?>
96
  return $most_recent_comment->comment_author;
97
  }
98
  }
99
+ }
 
 
includes/schemas/class-schema-organization.php CHANGED
@@ -56,6 +56,12 @@ if ( ! class_exists( 'bpfwpSchemaOrganization' ) ) :
56
  'recommended' => true,
57
  'callback' => apply_filters( 'bpfwp_schema_field_callback', 'option blogname', 'name', $this->slug )
58
  ) ),
 
 
 
 
 
 
59
  new bpfwpSchemaField( array(
60
  'slug' => 'email',
61
  'name' => 'Email',
56
  'recommended' => true,
57
  'callback' => apply_filters( 'bpfwp_schema_field_callback', 'option blogname', 'name', $this->slug )
58
  ) ),
59
+ new bpfwpSchemaField( array(
60
+ 'slug' => 'image',
61
+ 'name' => 'Image',
62
+ 'input' => 'url',
63
+ 'callback' => apply_filters( 'bpfwp_schema_field_callback', 'function bpfwp_get_post_image_url', 'image', $this->slug )
64
+ ) ),
65
  new bpfwpSchemaField( array(
66
  'slug' => 'email',
67
  'name' => 'Email',
includes/template-functions.php CHANGED
@@ -109,11 +109,12 @@ if ( ! function_exists( 'bpwfwp_print_contact_card' ) ) {
109
  'name' => 'bpwfwp_print_name',
110
  'address' => 'bpwfwp_print_address',
111
  'phone' => 'bpwfwp_print_phone',
 
112
  'contact' => 'bpwfwp_print_contact',
113
  'exceptions' => 'bpwfwp_print_exceptions',
114
  'opening_hours' => 'bpwfwp_print_opening_hours', // opening-hours
115
  'map' => 'bpwfwp_print_map',
116
- 'parent_organization' => 'bpfwp_print_parent_organization',
117
  )
118
  );
119
 
@@ -155,6 +156,44 @@ if ( ! function_exists( 'bpwfwp_print_contact_card' ) ) {
155
  }
156
  }
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  if ( ! function_exists( 'bpwfwp_print_name' ) ) {
159
  /**
160
  * Print the name.
@@ -601,6 +640,10 @@ if ( ! function_exists( 'bpwfwp_print_exceptions' ) ) {
601
  );
602
 
603
  foreach ( $exceptions as $exception ) {
 
 
 
 
604
 
605
  if ( array_key_exists( 'time', $exception ) ) {
606
  // special opening-hours
109
  'name' => 'bpwfwp_print_name',
110
  'address' => 'bpwfwp_print_address',
111
  'phone' => 'bpwfwp_print_phone',
112
+ 'ordering-link' => 'bpfwp_print_ordering_link',
113
  'contact' => 'bpwfwp_print_contact',
114
  'exceptions' => 'bpwfwp_print_exceptions',
115
  'opening_hours' => 'bpwfwp_print_opening_hours', // opening-hours
116
  'map' => 'bpwfwp_print_map',
117
+ 'parent_organization' => 'bpfwp_print_parent_organization'
118
  )
119
  );
120
 
156
  }
157
  }
158
 
159
+ if ( ! function_exists( 'bpfwp_print_ordering_link' ) ) {
160
+ /**
161
+ * Print the menu link
162
+ *
163
+ * @since 2.1.5
164
+ * @access public
165
+ * @return array
166
+ */
167
+ function bpfwp_print_ordering_link( $location = false ) {
168
+
169
+ $return_data = array();
170
+
171
+ $link = bpfwp_setting( 'menu', $location );
172
+
173
+ $ordering_link = bpfwp_setting( 'ordering-link', $location );
174
+
175
+ if( ! $link ) {
176
+ $return_data['hasMenu'] = $ordering_link;
177
+ }
178
+ else {
179
+ $return_data['hasMenu'] = get_permalink( $link );
180
+ }
181
+
182
+ if ( bpfwp_get_display( 'show_ordering_link' ) && ! empty( $ordering_link ) ) :
183
+ ?>
184
+ <div class="bp-ordering-link">
185
+ <a href="<?php echo esc_url( $ordering_link ); ?>" target="blank">
186
+ <?php _e( 'Place an Order', 'business-profile' ); ?>
187
+ </a>
188
+ </div>
189
+ <?php
190
+ endif;
191
+
192
+ return $return_data;
193
+ }
194
+ }
195
+
196
+
197
  if ( ! function_exists( 'bpwfwp_print_name' ) ) {
198
  /**
199
  * Print the name.
640
  );
641
 
642
  foreach ( $exceptions as $exception ) {
643
+
644
+ if ( empty( $exception['date'] ) ) { continue; }
645
+
646
+ if ( time() > strtotime( $exception['date'] ) + 24*3600 ) { continue; }
647
 
648
  if ( array_key_exists( 'time', $exception ) ) {
649
  // special opening-hours
lib/simple-admin-pages/README.md CHANGED
@@ -1,431 +1,434 @@
1
- Simple Admin Pages for WordPress
2
- ================================
3
-
4
- Simple Admin Pages is a very small utility library to easily add new admin
5
- pages to the WordPress admin interface. It collects WordPress' useful
6
- Settings API into reuseable classes and implements a set of simple controls.
7
-
8
-
9
- ## Settings Pages Supported
10
-
11
- - Settings sub-page
12
- - Themes sub-page
13
- - Submenu pages for custom menu items
14
-
15
- ## General Controls Supported
16
-
17
- - Text field
18
- - Textarea field
19
- - Image field
20
- - Toggle (checkbox to enable/disable setting)
21
- - Select dropdown with custom options
22
- - Select dropdown of any post type
23
- - Select dropdown of any taxonomy type
24
- - HTML Content (for instructions, links or other inert text)
25
- - WordPress Editor
26
-
27
- ## Controls Supported for Special Use Cases
28
-
29
- - Date and Time Scheduler
30
- - Google Map Address (with GeoLocation)
31
- - Business Opening Hours
32
-
33
- ## Usage
34
-
35
- Here's an example of how you can use this library to create an admin page.
36
-
37
- ```
38
- // Instantiate the Simple Admin Library
39
- require_once( 'path/to/simple-admin-pages/simple-admin-pages.php' );
40
- $sap = sap_initialize_library(
41
- array(
42
- 'version' => '2.1.2', // Version of the library
43
- 'lib_url' => PLUGIN_URL . '/lib/simple-admin-pages/', // URL path to sap library
44
- )
45
- );
46
-
47
- // Create a page for the options under the Settings (options) menu
48
- $sap->add_page(
49
- 'options', // Admin menu which this page should be added to
50
- array( // Array of key/value pairs matching the AdminPage class constructor variables
51
- 'id' => 'basic-settings',
52
- 'title' => __( 'Page Title', 'textdomain' ),
53
- 'menu_title' => __( 'menu Title', 'textdomain' ),
54
- 'description' => '',
55
- 'capability' => 'manage_options' // User permissions access level
56
- )
57
- );
58
-
59
- // Create a basic details section
60
- $sap->add_section(
61
- 'basic-settings', // Page to add this section to
62
- array( // Array of key/value pairs matching the AdminPageSection class constructor variables
63
- 'id' => 'basic-details',
64
- 'title' => __( 'Basic Details', 'textdomain' ),
65
- 'description' => __( 'This section includes some basic details for you to configure.', 'textdomain' )
66
- )
67
- );
68
-
69
- // Create the options fields
70
- $sap->add_setting(
71
- 'basic-settings', // Page to add this setting to
72
- 'basic-details', // Section to add this setting to
73
- 'select', // Type of setting (see sapLibrary::get_setting_classname()
74
- array(
75
- 'id' => 'select-field',
76
- 'title' => __( 'Select Field', 'textdomain' ),
77
- 'description' => __( 'A demonstration of the select field type.', 'textdomain' ),
78
- 'options' => array(
79
- 'one' => __( 'Option 1', 'textdomain' ),
80
- 'two' => __( 'Option 2', 'textdomain' ),
81
- 'three' => __( 'Option 3', 'textdomain' )
82
- )
83
- )
84
- );
85
-
86
- // Allow third-party addons to hook into your settings page
87
- $sap = apply_filters( 'sap_page_setup', $sap );
88
-
89
- // Register all admin pages and settings with WordPress
90
- $sap->add_admin_menus();
91
- ```
92
-
93
- Check out the documentation section below for more examples and explanation.
94
-
95
- ## License
96
-
97
- Simple Admin Pages is released under the GNU GPL 2 or later.
98
-
99
- ## Requirements
100
-
101
- Simple Admin Pages has been tested with WordPress versions 3.5 and above.
102
-
103
- ## Roadmap
104
-
105
- - Better documentation
106
- - Support custom top-level admin pages
107
- - More custom data types
108
-
109
- ## Documentation
110
-
111
- ### sap_initialize_library()
112
- Instantiate the library by loading the simple-admin-pages.php file and calling sap_initialize_library. You'll do everything with the $sap object that is returned.
113
-
114
- **args**
115
- An array of properties to pass to the library.
116
-
117
- *version*
118
- (required)
119
-
120
- This used to ensure that plugins can play well together even if they use different versions of the library. The version will convert . to _ and append that to the class names which are loaded. If version 1.0 is passed, the library will attempt to load a class named sapAdminPage_1_0.
121
-
122
- *lib_url*
123
- (required)
124
-
125
- The lib_url is used to print stylesheets or scripts attached to the library.
126
-
127
- ```
128
- require_once( 'path/to/simple-admin-pages/simple-admin-pages.php' );
129
- $sap = sap_initialize_library(
130
- $args = array(
131
- 'version' => '2.1.2', // Version of the library
132
- 'lib_url' => PLUGIN_URL . '/lib/simple-admin-pages/', // URL path to sap library
133
- )
134
- );
135
- ```
136
-
137
- ### sapLibrary::add_page()
138
- Create a new page with the library by calling the add_page() method. You can attach the page to the options (Settings) or themes (Appearance) menus or any custom menu.
139
-
140
- **type**
141
- (required)
142
-
143
- What type of admin menu page to create. Accepts:
144
-
145
- - "options" - A subpage of the Settings menu
146
- - "themes" - A subpage of the Appearance menu
147
- - "submenu" - A subpage of any top-level menu item
148
-
149
- **args**
150
-
151
- An array of properties to pass to the page.
152
-
153
- *id*
154
- (required)
155
-
156
- All settings attached to this page will be stored with the page ID and can be retrieved with get_options( $page_id ).
157
-
158
- *title*
159
- (required)
160
-
161
- This will be displayed at the top of the page.
162
-
163
- *menu_title*
164
- (required)
165
-
166
- The title to display in the menu.
167
-
168
- *description*
169
- (optional)
170
-
171
- Actually, I think this one isn't used at the moment.
172
-
173
- *capability*
174
- (required)
175
-
176
- The user permissions access level (capability in WP terms) required to access and edit this page.
177
-
178
- *default_tab*
179
- (optional)
180
-
181
- If your page will have multiple tabs, you need to specify a default tab to display when the page is initially loaded. This must match the ID used in the add_section() method. *Leave this parameter out if you don't need any tabs.*
182
-
183
- ```
184
- $sap->add_page(
185
- $type,
186
- $args = array(
187
- 'id' => 'my-settings',
188
- 'title' => __( 'Page Title', 'textdomain' ),
189
- 'menu_title' => __( 'menu Title', 'textdomain' ),
190
- 'description' => '',
191
- 'capability' => 'manage_options'
192
- 'default_tab' => 'tab-one',
193
- )
194
- );
195
- ```
196
-
197
- ### sapLibrary::add_section()
198
- Create a new section to attach it to an existing page.
199
-
200
- Sections can act as Tabs or as internal sections within the normal settings flow of a Tab or Page. In other words, you can define a section as a tab, attach a section to another section which is acting as a tab, or ignore tabs altogether to display all of your sections at once. The example below adds a tab and then adds a sub-section to that tab.
201
-
202
- **page_id**
203
-
204
- Page this section should be attached to. Must match the id passed in add_page().
205
-
206
- **args**
207
-
208
- An array of properties to pass to the section.
209
-
210
- *id*
211
-
212
- (required)
213
- Unique slug to which settings will be attached.
214
-
215
- *title*
216
- (required)
217
-
218
- This will be displayed at the top of the settings section.
219
-
220
- *description*
221
- (optional)
222
-
223
- An optional description to display below the title.
224
-
225
- *is_tab*
226
- (optional)
227
-
228
- Set this to true if this section should act like a tab.
229
-
230
- *tab*
231
- (optional)
232
-
233
- Use this to attach a section to an existing tab.
234
-
235
- #### Add a section to a page with no tabs:
236
- ```
237
- $sap->add_section(
238
- $page_id,
239
- $args = array(
240
- 'id' => 'basic-details-section',
241
- 'title' => __( 'Basic Details', 'textdomain' ),
242
- 'description' => __( 'This section includes some basic details for you to configure.', 'textdomain' )
243
- )
244
- );
245
- ```
246
-
247
- #### Add a tab and a sub-section to a page with tabs:
248
- ```
249
- /**
250
- * Create a section that acts as a tab with the is_tab parameter.
251
- */
252
- $sap->add_section(
253
- $page_id,
254
- $args = array(
255
- 'id' => 'tab-one',
256
- 'title' => __( 'Tab One', 'textdomain' ),
257
- 'description' => __( 'This tab includes some settings for you to configure.', 'textdomain' ),
258
- 'is_tab' => true,
259
- )
260
- );
261
-
262
- /**
263
- * Create a sub-section of the tab we just created with the tab parameter.
264
- */
265
- $sap->add_section(
266
- $page_id,
267
- $args = array(
268
- 'id' => 'section-one-under-tab-one',
269
- 'title' => __( 'Section One', 'textdomain' ),
270
- 'description' => __( 'This section includes some settings for you to configure.', 'textdomain' ),
271
- 'tab' => 'tab-one',
272
- )
273
- );
274
- ```
275
-
276
- ### sapLibrary::add_setting()
277
- Create a new setting and attach to an existing section.
278
-
279
- There are several types of settings, each with their own input arguments. I'll try to document it more in the future. For now, check out the AdminPageSetting.*.class.php files in /classes/.
280
-
281
- **page_id**
282
- (required)
283
-
284
- Page this setting should be attached to. Must match the id passed in add_page().
285
-
286
- **section_id**
287
- (required)
288
-
289
- Section this setting should be attached to. Must match the id passed in add_setting().
290
-
291
- **type**
292
- (required)
293
-
294
- Type of setting to add. There are currently several types supported and you can extend the library with your own. I'll try to document this further. For now, you can see all the types supported by default at sapLibrary::get_setting_classname().
295
-
296
- **args**
297
-
298
- An array of properties to pass to the setting.
299
-
300
- *id*
301
- (required)
302
-
303
- Unique slug under which the setting will be saved. You would then retrieve the setting with:
304
-
305
- ```
306
- $options = get_option( $page_id );
307
- $options[$setting_id];
308
- ```
309
-
310
- *title*
311
- (required)
312
-
313
- Title of the setting. Typically acts as the field label.
314
-
315
- *description*
316
- (optional)
317
-
318
- An optional description to display with the setting. Useful for instructions.
319
-
320
- *...*
321
-
322
- Several setting types have additional parameters. I'll try to document them further.
323
-
324
- ```
325
- $sap->add_setting(
326
- $page_id,
327
- $section_id,
328
- $type,
329
- array(
330
- 'id' => 'my-first-setting',
331
- 'title' => __( 'My First Setting', 'textdomain' ),
332
- 'description' => __( 'A demonstration of my first setting', 'textdomain' );
333
- ...
334
- )
335
- );
336
- ```
337
-
338
- ### sapLibrary::add_admin_menus()
339
- Once everything is configured, run this method to register the pages with WordPress.
340
-
341
- ```
342
- // Before you run add_admin_menus, filter the whole library so that
343
- // third-party addons can hook into your settings page to add new settings
344
- // or adjust existing ones.
345
- $sap = apply_filters( 'sap_page_setup', $sap );
346
-
347
- $sap->add_admin_menus();
348
- ```
349
-
350
- ### Backwards Compatibility
351
- Version 2.0 introduced changes which break backwards compatibility due to the way that the library now stores data in the database. If you are upgrading the version of this library used in your plugin or theme, you must call ```$sap->port_data(2);``` **after** you have declared all of your settings but **before** you call ```$sap->add_admin_menus();```.
352
-
353
- *Note: to ensure all of the old options are found and ported, you shouldn't change any of the structure or ids of your settings. Just drop this method into your existing flow.*
354
-
355
- This changes the way that your settings are stored in the database. Previously, each setting was stored as its own option. Now all the settings on a page are stored in one row.
356
-
357
- You will need to update your plugin to retrieve the settings from their new location. If you previously accessed a setting this way:
358
-
359
- ```
360
- $my_setting = get_option( $my_setting_id );
361
- ```
362
-
363
- You should now access the setting this way:
364
-
365
- ```
366
- $all_page_settings = get_option( $settings_page_id );
367
- $all_page_settings[ $my_setting_id ];
368
- ```
369
-
370
- ## Changelog
371
-
372
- - 2.1.2 - 2019-03-18
373
- - Update pickadate.js to 3.6.1 to fix regression in Chromium
374
- https://github.com/amsul/pickadate.js/issues/1138
375
-
376
- - 2.1.1 - 2018-09-26
377
- - Allow address geolookup field to receive a Google Maps API key
378
- - Use https when requesting google maps lookup
379
-
380
- - 2.1 - 2017-04-21
381
- - Add an Image setting type
382
-
383
- - 2.0.1 - 2017-03-14
384
- - Allow settings to receive $args passed to add_settings_field
385
-
386
- - 2.0 - 2015-10-28
387
- - Allow page capability to be modified after the page class is instantiated
388
-
389
- - 2.0.a.10 - 2015-08-19
390
- - Use h1 tags for page titles, in line with WP 4.3 changes
391
- - Check for has_position before calling on a setting, in case of custom third-party settings being loaded
392
- - Update pickadate.js lib
393
-
394
- - 2.0.a.9 - 2014-11-12
395
- - SelectPost: Use WP_Query instead of get_posts() so that filters can effect the list
396
- - Require translateable strings to be declared when adding the setting so the library can conform to the upcoming single textdomain best practice in the .org repos
397
-
398
- - 2.0.a.7 - 2014-08-20
399
- - Only enqueue assets on appropriate admin pages to prevent version conflicts and be a good citizen
400
- - Enforce stored date/time formats so date format is reliable
401
-
402
- - 2.0.a.6 - 2014-08-12
403
- - Add Google Map Address component
404
- - Custom settings loaded through the extension path should not use versions
405
-
406
- - 2.0.a.5 - 2014-05-15
407
- - Fix a bug with the Textarea component callback
408
-
409
- - 2.0.a.4 - 2014-05-15
410
- - Only load assets when component is called
411
- - Revert adding version number to script handles
412
- - Fix localized script handler for Scheduler
413
- - Fix pickadate CSS rule specificity
414
-
415
- - 2.0.a.3 - 2014-05-14
416
- - Fix undefined function error in Scheduler javascript when using Firefox
417
- - Add version number to style and script handles so different versions will be enqueued
418
-
419
- - 2.0.a.2 - 2014-05-11
420
- - Add support for top-level menus
421
- - Support line breaks in textarea components
422
-
423
- - 2.0.a.1 - 2014-04-03
424
- - Save all data on a page as one row in wp_options
425
-
426
- - 1.1 - never released
427
- - Support themes pages
428
- - Support submenu pages for custom menu items
429
-
430
- - 1.0 - 2013-11-20
431
- - Initial release
 
 
 
1
+ Simple Admin Pages for WordPress
2
+ ================================
3
+
4
+ Simple Admin Pages is a very small utility library to easily add new admin
5
+ pages to the WordPress admin interface. It collects WordPress' useful
6
+ Settings API into reuseable classes and implements a set of simple controls.
7
+
8
+
9
+ ## Settings Pages Supported
10
+
11
+ - Settings sub-page
12
+ - Themes sub-page
13
+ - Submenu pages for custom menu items
14
+
15
+ ## General Controls Supported
16
+
17
+ - Text field
18
+ - Textarea field
19
+ - Image field
20
+ - Toggle (checkbox to enable/disable setting)
21
+ - Select dropdown with custom options
22
+ - Select dropdown of any post type
23
+ - Select dropdown of any taxonomy type
24
+ - HTML Content (for instructions, links or other inert text)
25
+ - WordPress Editor
26
+
27
+ ## Controls Supported for Special Use Cases
28
+
29
+ - Date and Time Scheduler
30
+ - Google Map Address (with GeoLocation)
31
+ - Business Opening Hours
32
+
33
+ ## Usage
34
+
35
+ Here's an example of how you can use this library to create an admin page.
36
+
37
+ ```
38
+ // Instantiate the Simple Admin Library
39
+ require_once( 'path/to/simple-admin-pages/simple-admin-pages.php' );
40
+ $sap = sap_initialize_library(
41
+ array(
42
+ 'version' => '2.4.0', // Version of the library
43
+ 'lib_url' => PLUGIN_URL . '/lib/simple-admin-pages/', // URL path to sap library
44
+ )
45
+ );
46
+
47
+ // Create a page for the options under the Settings (options) menu
48
+ $sap->add_page(
49
+ 'options', // Admin menu which this page should be added to
50
+ array( // Array of key/value pairs matching the AdminPage class constructor variables
51
+ 'id' => 'basic-settings',
52
+ 'title' => __( 'Page Title', 'textdomain' ),
53
+ 'menu_title' => __( 'menu Title', 'textdomain' ),
54
+ 'description' => '',
55
+ 'capability' => 'manage_options' // User permissions access level
56
+ )
57
+ );
58
+
59
+ // Create a basic details section
60
+ $sap->add_section(
61
+ 'basic-settings', // Page to add this section to
62
+ array( // Array of key/value pairs matching the AdminPageSection class constructor variables
63
+ 'id' => 'basic-details',
64
+ 'title' => __( 'Basic Details', 'textdomain' ),
65
+ 'description' => __( 'This section includes some basic details for you to configure.', 'textdomain' )
66
+ )
67
+ );
68
+
69
+ // Create the options fields
70
+ $sap->add_setting(
71
+ 'basic-settings', // Page to add this setting to
72
+ 'basic-details', // Section to add this setting to
73
+ 'select', // Type of setting (see sapLibrary::get_setting_classname()
74
+ array(
75
+ 'id' => 'select-field',
76
+ 'title' => __( 'Select Field', 'textdomain' ),
77
+ 'description' => __( 'A demonstration of the select field type.', 'textdomain' ),
78
+ 'options' => array(
79
+ 'one' => __( 'Option 1', 'textdomain' ),
80
+ 'two' => __( 'Option 2', 'textdomain' ),
81
+ 'three' => __( 'Option 3', 'textdomain' )
82
+ )
83
+ )
84
+ );
85
+
86
+ // Allow third-party addons to hook into your settings page
87
+ $sap = apply_filters( 'sap_page_setup', $sap );
88
+
89
+ // Register all admin pages and settings with WordPress
90
+ $sap->add_admin_menus();
91
+ ```
92
+
93
+ Check out the documentation section below for more examples and explanation.
94
+
95
+ ## License
96
+
97
+ Simple Admin Pages is released under the GNU GPL 2 or later.
98
+
99
+ ## Requirements
100
+
101
+ Simple Admin Pages has been tested with WordPress versions 3.5 and above.
102
+
103
+ ## Roadmap
104
+
105
+ - Better documentation
106
+ - Support custom top-level admin pages
107
+ - More custom data types
108
+
109
+ ## Documentation
110
+
111
+ ### sap_initialize_library()
112
+ Instantiate the library by loading the simple-admin-pages.php file and calling sap_initialize_library. You'll do everything with the $sap object that is returned.
113
+
114
+ **args**
115
+ An array of properties to pass to the library.
116
+
117
+ *version*
118
+ (required)
119
+
120
+ This used to ensure that plugins can play well together even if they use different versions of the library. The version will convert . to _ and append that to the class names which are loaded. If version 1.0 is passed, the library will attempt to load a class named sapAdminPage_1_0.
121
+
122
+ *lib_url*
123
+ (required)
124
+
125
+ The lib_url is used to print stylesheets or scripts attached to the library.
126
+
127
+ ```
128
+ require_once( 'path/to/simple-admin-pages/simple-admin-pages.php' );
129
+ $sap = sap_initialize_library(
130
+ $args = array(
131
+ 'version' => '2.4.0', // Version of the library
132
+ 'lib_url' => PLUGIN_URL . '/lib/simple-admin-pages/', // URL path to sap library
133
+ )
134
+ );
135
+ ```
136
+
137
+ ### sapLibrary::add_page()
138
+ Create a new page with the library by calling the add_page() method. You can attach the page to the options (Settings) or themes (Appearance) menus or any custom menu.
139
+
140
+ **type**
141
+ (required)
142
+
143
+ What type of admin menu page to create. Accepts:
144
+
145
+ - "options" - A subpage of the Settings menu
146
+ - "themes" - A subpage of the Appearance menu
147
+ - "submenu" - A subpage of any top-level menu item
148
+
149
+ **args**
150
+
151
+ An array of properties to pass to the page.
152
+
153
+ *id*
154
+ (required)
155
+
156
+ All settings attached to this page will be stored with the page ID and can be retrieved with get_options( $page_id ).
157
+
158
+ *title*
159
+ (required)
160
+
161
+ This will be displayed at the top of the page.
162
+
163
+ *menu_title*
164
+ (required)
165
+
166
+ The title to display in the menu.
167
+
168
+ *description*
169
+ (optional)
170
+
171
+ Actually, I think this one isn't used at the moment.
172
+
173
+ *capability*
174
+ (required)
175
+
176
+ The user permissions access level (capability in WP terms) required to access and edit this page.
177
+
178
+ *default_tab*
179
+ (optional)
180
+
181
+ If your page will have multiple tabs, you need to specify a default tab to display when the page is initially loaded. This must match the ID used in the add_section() method. *Leave this parameter out if you don't need any tabs.*
182
+
183
+ ```
184
+ $sap->add_page(
185
+ $type,
186
+ $args = array(
187
+ 'id' => 'my-settings',
188
+ 'title' => __( 'Page Title', 'textdomain' ),
189
+ 'menu_title' => __( 'menu Title', 'textdomain' ),
190
+ 'description' => '',
191
+ 'capability' => 'manage_options'
192
+ 'default_tab' => 'tab-one',
193
+ )
194
+ );
195
+ ```
196
+
197
+ ### sapLibrary::add_section()
198
+ Create a new section to attach it to an existing page.
199
+
200
+ Sections can act as Tabs or as internal sections within the normal settings flow of a Tab or Page. In other words, you can define a section as a tab, attach a section to another section which is acting as a tab, or ignore tabs altogether to display all of your sections at once. The example below adds a tab and then adds a sub-section to that tab.
201
+
202
+ **page_id**
203
+
204
+ Page this section should be attached to. Must match the id passed in add_page().
205
+
206
+ **args**
207
+
208
+ An array of properties to pass to the section.
209
+
210
+ *id*
211
+
212
+ (required)
213
+ Unique slug to which settings will be attached.
214
+
215
+ *title*
216
+ (required)
217
+
218
+ This will be displayed at the top of the settings section.
219
+
220
+ *description*
221
+ (optional)
222
+
223
+ An optional description to display below the title.
224
+
225
+ *is_tab*
226
+ (optional)
227
+
228
+ Set this to true if this section should act like a tab.
229
+
230
+ *tab*
231
+ (optional)
232
+
233
+ Use this to attach a section to an existing tab.
234
+
235
+ #### Add a section to a page with no tabs:
236
+ ```
237
+ $sap->add_section(
238
+ $page_id,
239
+ $args = array(
240
+ 'id' => 'basic-details-section',
241
+ 'title' => __( 'Basic Details', 'textdomain' ),
242
+ 'description' => __( 'This section includes some basic details for you to configure.', 'textdomain' )
243
+ )
244
+ );
245
+ ```
246
+
247
+ #### Add a tab and a sub-section to a page with tabs:
248
+ ```
249
+ /**
250
+ * Create a section that acts as a tab with the is_tab parameter.
251
+ */
252
+ $sap->add_section(
253
+ $page_id,
254
+ $args = array(
255
+ 'id' => 'tab-one',
256
+ 'title' => __( 'Tab One', 'textdomain' ),
257
+ 'description' => __( 'This tab includes some settings for you to configure.', 'textdomain' ),
258
+ 'is_tab' => true,
259
+ )
260
+ );
261
+
262
+ /**
263
+ * Create a sub-section of the tab we just created with the tab parameter.
264
+ */
265
+ $sap->add_section(
266
+ $page_id,
267
+ $args = array(
268
+ 'id' => 'section-one-under-tab-one',
269
+ 'title' => __( 'Section One', 'textdomain' ),
270
+ 'description' => __( 'This section includes some settings for you to configure.', 'textdomain' ),
271
+ 'tab' => 'tab-one',
272
+ )
273
+ );
274
+ ```
275
+
276
+ ### sapLibrary::add_setting()
277
+ Create a new setting and attach to an existing section.
278
+
279
+ There are several types of settings, each with their own input arguments. I'll try to document it more in the future. For now, check out the AdminPageSetting.*.class.php files in /classes/.
280
+
281
+ **page_id**
282
+ (required)
283
+
284
+ Page this setting should be attached to. Must match the id passed in add_page().
285
+
286
+ **section_id**
287
+ (required)
288
+
289
+ Section this setting should be attached to. Must match the id passed in add_setting().
290
+
291
+ **type**
292
+ (required)
293
+
294
+ Type of setting to add. There are currently several types supported and you can extend the library with your own. I'll try to document this further. For now, you can see all the types supported by default at sapLibrary::get_setting_classname().
295
+
296
+ **args**
297
+
298
+ An array of properties to pass to the setting.
299
+
300
+ *id*
301
+ (required)
302
+
303
+ Unique slug under which the setting will be saved. You would then retrieve the setting with:
304
+
305
+ ```
306
+ $options = get_option( $page_id );
307
+ $options[$setting_id];
308
+ ```
309
+
310
+ *title*
311
+ (required)
312
+
313
+ Title of the setting. Typically acts as the field label.
314
+
315
+ *description*
316
+ (optional)
317
+
318
+ An optional description to display with the setting. Useful for instructions.
319
+
320
+ *...*
321
+
322
+ Several setting types have additional parameters. I'll try to document them further.
323
+
324
+ ```
325
+ $sap->add_setting(
326
+ $page_id,
327
+ $section_id,
328
+ $type,
329
+ array(
330
+ 'id' => 'my-first-setting',
331
+ 'title' => __( 'My First Setting', 'textdomain' ),
332
+ 'description' => __( 'A demonstration of my first setting', 'textdomain' );
333
+ ...
334
+ )
335
+ );
336
+ ```
337
+
338
+ ### sapLibrary::add_admin_menus()
339
+ Once everything is configured, run this method to register the pages with WordPress.
340
+
341
+ ```
342
+ // Before you run add_admin_menus, filter the whole library so that
343
+ // third-party addons can hook into your settings page to add new settings
344
+ // or adjust existing ones.
345
+ $sap = apply_filters( 'sap_page_setup', $sap );
346
+
347
+ $sap->add_admin_menus();
348
+ ```
349
+
350
+ ### Backwards Compatibility
351
+ Version 2.0 introduced changes which break backwards compatibility due to the way that the library now stores data in the database. If you are upgrading the version of this library used in your plugin or theme, you must call ```$sap->port_data(2);``` **after** you have declared all of your settings but **before** you call ```$sap->add_admin_menus();```.
352
+
353
+ *Note: to ensure all of the old options are found and ported, you shouldn't change any of the structure or ids of your settings. Just drop this method into your existing flow.*
354
+
355
+ This changes the way that your settings are stored in the database. Previously, each setting was stored as its own option. Now all the settings on a page are stored in one row.
356
+
357
+ You will need to update your plugin to retrieve the settings from their new location. If you previously accessed a setting this way:
358
+
359
+ ```
360
+ $my_setting = get_option( $my_setting_id );
361
+ ```
362
+
363
+ You should now access the setting this way:
364
+
365
+ ```
366
+ $all_page_settings = get_option( $settings_page_id );
367
+ $all_page_settings[ $my_setting_id ];
368
+ ```
369
+
370
+ ## Changelog
371
+
372
+ - 2.4.0 - 2020-12-04
373
+ - Updating to make this a more global library that can be used by multiple plugins.
374
+
375
+ - 2.3.0 - 2019-03-18
376
+ - Update pickadate.js to 3.6.1 to fix regression in Chromium
377
+ https://github.com/amsul/pickadate.js/issues/1138
378
+
379
+ - 2.1.1 - 2018-09-26
380
+ - Allow address geolookup field to receive a Google Maps API key
381
+ - Use https when requesting google maps lookup
382
+
383
+ - 2.1 - 2017-04-21
384
+ - Add an Image setting type
385
+
386
+ - 2.0.1 - 2017-03-14
387
+ - Allow settings to receive $args passed to add_settings_field
388
+
389
+ - 2.0 - 2015-10-28
390
+ - Allow page capability to be modified after the page class is instantiated
391
+
392
+ - 2.0.a.10 - 2015-08-19
393
+ - Use h1 tags for page titles, in line with WP 4.3 changes
394
+ - Check for has_position before calling on a setting, in case of custom third-party settings being loaded
395
+ - Update pickadate.js lib
396
+
397
+ - 2.0.a.9 - 2014-11-12
398
+ - SelectPost: Use WP_Query instead of get_posts() so that filters can effect the list
399
+ - Require translateable strings to be declared when adding the setting so the library can conform to the upcoming single textdomain best practice in the .org repos
400
+
401
+ - 2.0.a.7 - 2014-08-20
402
+ - Only enqueue assets on appropriate admin pages to prevent version conflicts and be a good citizen
403
+ - Enforce stored date/time formats so date format is reliable
404
+
405
+ - 2.0.a.6 - 2014-08-12
406
+ - Add Google Map Address component
407
+ - Custom settings loaded through the extension path should not use versions
408
+
409
+ - 2.0.a.5 - 2014-05-15
410
+ - Fix a bug with the Textarea component callback
411
+
412
+ - 2.0.a.4 - 2014-05-15
413
+ - Only load assets when component is called
414
+ - Revert adding version number to script handles
415
+ - Fix localized script handler for Scheduler
416
+ - Fix pickadate CSS rule specificity
417
+
418
+ - 2.0.a.3 - 2014-05-14
419
+ - Fix undefined function error in Scheduler javascript when using Firefox
420
+ - Add version number to style and script handles so different versions will be enqueued
421
+
422
+ - 2.0.a.2 - 2014-05-11
423
+ - Add support for top-level menus
424
+ - Support line breaks in textarea components
425
+
426
+ - 2.0.a.1 - 2014-04-03
427
+ - Save all data on a page as one row in wp_options
428
+
429
+ - 1.1 - never released
430
+ - Support themes pages
431
+ - Support submenu pages for custom menu items
432
+
433
+ - 1.0 - 2013-11-20
434
+ - Initial release
lib/simple-admin-pages/classes/AdminPage.Menu.class.php CHANGED
@@ -1,32 +1,32 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an settings page as a submenu item in the
5
- * WordPress admin menu.
6
- *
7
- * @since 1.1
8
- * @package Simple Admin Pages
9
- */
10
-
11
- class sapAdminPageMenu_2_1_2 extends sapAdminPage_2_1_2 {
12
-
13
- public $setup_function = 'add_menu_page'; // WP function to register the page
14
-
15
- /**
16
- * Add the page to the appropriate menu slot.
17
- * @since 1.0
18
- */
19
- public function add_admin_menu() {
20
-
21
- call_user_func(
22
- $this->setup_function,
23
- $this->title,
24
- $this->menu_title,
25
- $this->capability,
26
- $this->id,
27
- array( $this, 'display_admin_menu' ),
28
- $this->icon,
29
- $this->position
30
- );
31
- }
32
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an settings page as a submenu item in the
5
+ * WordPress admin menu.
6
+ *
7
+ * @since 1.1
8
+ * @package Simple Admin Pages
9
+ */
10
+
11
+ class sapAdminPageMenu_2_5_5 extends sapAdminPage_2_5_5 {
12
+
13
+ public $setup_function = 'add_menu_page'; // WP function to register the page
14
+
15
+ /**
16
+ * Add the page to the appropriate menu slot.
17
+ * @since 1.0
18
+ */
19
+ public function add_admin_menu() {
20
+
21
+ call_user_func(
22
+ $this->setup_function,
23
+ $this->title,
24
+ $this->menu_title,
25
+ $this->capability,
26
+ $this->id,
27
+ array( $this, 'display_admin_menu' ),
28
+ $this->icon,
29
+ $this->position
30
+ );
31
+ }
32
+ }
lib/simple-admin-pages/classes/AdminPage.Submenu.class.php CHANGED
@@ -1,38 +1,38 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an settings page as a submenu item in the
5
- * WordPress admin menu.
6
- *
7
- * @since 1.1
8
- * @package Simple Admin Pages
9
- */
10
-
11
- class sapAdminPageSubmenu_2_1_2 extends sapAdminPage_2_1_2 {
12
-
13
- public $setup_function = 'add_submenu_page'; // WP function to register the page
14
-
15
- public $parent_menu = null; // Which menu to attach this submenu page to
16
-
17
- /**
18
- * Add the page to the appropriate menu slot.
19
- * @since 1.0
20
- */
21
- public function add_admin_menu() {
22
-
23
- // Don't register if no parent menu is specified
24
- if ( !$this->parent_menu ) {
25
- return;
26
- }
27
-
28
- call_user_func(
29
- $this->setup_function,
30
- $this->parent_menu,
31
- $this->title,
32
- $this->menu_title,
33
- $this->capability,
34
- $this->id,
35
- array( $this, 'display_admin_menu' )
36
- );
37
- }
38
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an settings page as a submenu item in the
5
+ * WordPress admin menu.
6
+ *
7
+ * @since 1.1
8
+ * @package Simple Admin Pages
9
+ */
10
+
11
+ class sapAdminPageSubmenu_2_5_5 extends sapAdminPage_2_5_5 {
12
+
13
+ public $setup_function = 'add_submenu_page'; // WP function to register the page
14
+
15
+ public $parent_menu = null; // Which menu to attach this submenu page to
16
+
17
+ /**
18
+ * Add the page to the appropriate menu slot.
19
+ * @since 1.0
20
+ */
21
+ public function add_admin_menu() {
22
+
23
+ // Don't register if no parent menu is specified
24
+ if ( !$this->parent_menu ) {
25
+ return;
26
+ }
27
+
28
+ call_user_func(
29
+ $this->setup_function,
30
+ $this->parent_menu,
31
+ $this->title,
32
+ $this->menu_title,
33
+ $this->capability,
34
+ $this->id,
35
+ array( $this, 'display_admin_menu' )
36
+ );
37
+ }
38
+ }
lib/simple-admin-pages/classes/AdminPage.Themes.class.php CHANGED
@@ -1,15 +1,15 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a settings page in the WordPress admin Appearance
5
- * menu.
6
- *
7
- * @since 1.0
8
- * @package Simple Admin Pages
9
- */
10
-
11
- class sapAdminPageThemes_2_1_2 extends sapAdminPage_2_1_2 {
12
-
13
- public $setup_function = 'add_theme_page'; // WP function to register the page
14
-
15
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a settings page in the WordPress admin Appearance
5
+ * menu.
6
+ *
7
+ * @since 1.0
8
+ * @package Simple Admin Pages
9
+ */
10
+
11
+ class sapAdminPageThemes_2_5_5 extends sapAdminPage_2_5_5 {
12
+
13
+ public $setup_function = 'add_theme_page'; // WP function to register the page
14
+
15
+ }
lib/simple-admin-pages/classes/AdminPage.class.php CHANGED
@@ -1,232 +1,232 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a settings page in the WordPress admin menu.
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPage_2_1_2 {
11
-
12
- public $title;
13
- public $menu_title;
14
- public $description; // optional description for this page
15
- public $capability; // user permissions needed to edit this panel
16
- public $id; // id of this page
17
- public $sections = array(); // array of sections to display on this page
18
- public $show_button = true; // whether or not to show the Save Changes button
19
-
20
- public $setup_function = 'add_options_page'; // WP function to register the page
21
-
22
-
23
- /**
24
- * Initialize the page
25
- * @since 1.0
26
- */
27
- public function __construct( $args ) {
28
-
29
- // Parse the values passed
30
- $this->parse_args( $args );
31
- }
32
-
33
- /**
34
- * Parse the arguments passed in the construction and assign them to
35
- * internal variables.
36
- * @since 1.1
37
- */
38
- private function parse_args( $args ) {
39
- foreach ( $args as $key => $val ) {
40
- switch ( $key ) {
41
-
42
- case 'id' :
43
- $this->{$key} = esc_attr( $val );
44
-
45
- default :
46
- $this->{$key} = $val;
47
-
48
- }
49
- }
50
- }
51
-
52
- /**
53
- * Modify the capability required to save settings on this page
54
- * @since 2.0
55
- */
56
- public function modify_required_capability( $cap ) {
57
- return $this->capability;
58
- }
59
-
60
- /**
61
- * Add the page to the appropriate menu slot.
62
- * @note The default will be to post to the options page, but other classes
63
- * should override this function.
64
- * @since 1.0
65
- */
66
- public function add_admin_menu() {
67
- call_user_func( $this->setup_function, $this->title, $this->menu_title, $this->capability, $this->id, array( $this, 'display_admin_menu' ) );
68
- }
69
-
70
- /**
71
- * Add a section to the page
72
- * @since 1.0
73
- */
74
- public function add_section( $section ) {
75
-
76
- if ( !$section ) {
77
- return;
78
- }
79
-
80
- $this->sections[ $section->id ] = $section;
81
-
82
- }
83
-
84
- /**
85
- * Register the settings and sanitization callbacks for each setting
86
- * @since 1.0
87
- */
88
- public function register_admin_menu() {
89
-
90
- foreach ( $this->sections as $section ) {
91
- $section->add_settings_section();
92
-
93
- foreach ( $section->settings as $setting ) {
94
- $setting->add_settings_field( $section->id );
95
- }
96
- }
97
-
98
- register_setting( $this->id, $this->id, array( $this, 'sanitize_callback' ) );
99
-
100
- // Modify capability required to save the settings if it's not
101
- // the default `manage_options`
102
- if ( !empty( $this->capability ) && $this->capability !== 'manage_options') {
103
- add_filter( 'option_page_capability_' . $this->id, array( $this, 'modify_required_capability' ) );
104
- }
105
- }
106
-
107
- /**
108
- * Loop through the settings and sanitize the data
109
- * @since 2.0
110
- */
111
- public function sanitize_callback( $value ) {
112
-
113
- if ( empty( $_POST['_wp_http_referer'] ) ) {
114
- return $value;
115
- }
116
-
117
- // Get the current page/tab so we only update those settings
118
- parse_str( $_POST['_wp_http_referer'], $referrer );
119
- $current_page = $this->get_current_page( $referrer );
120
-
121
- // Use a new empty value so only values for settings that were added are
122
- // passed to the db.
123
- $new_value = array();
124
-
125
- foreach ( $this->sections as $section ) {
126
- foreach ( $section->settings as $setting ) {
127
- if ( $setting->tab == $current_page ) {
128
- $setting_value = isset( $value[$setting->id] ) ? $value[$setting->id] : '';
129
- $new_value[$setting->id] = $setting->sanitize_callback_wrapper( $setting_value );
130
- }
131
- }
132
- }
133
-
134
- // Pull in the existing values so we never overwrite values that were
135
- // on a different tab
136
- $old_value = get_option( $this->id );
137
-
138
- if ( is_array( $old_value ) ) {
139
- return array_merge( $old_value, $new_value );
140
- } else {
141
- return $new_value;
142
- }
143
-
144
- }
145
-
146
- /**
147
- * Get the current page/tab being viewed
148
- * @since 2.0
149
- */
150
- public function get_current_page( $request ) {
151
-
152
- if ( !empty( $request['tab'] ) ) {
153
- return $request['tab'];
154
- } elseif ( !empty( $this->default_tab ) ) {
155
- return $this->default_tab;
156
- } else {
157
- return $this->id;
158
- }
159
-
160
- }
161
-
162
- /**
163
- * Output the settings passed to this page
164
- * @since 1.0
165
- */
166
- public function display_admin_menu() {
167
-
168
- if ( !$this->title && !count( $this->settings ) ) {
169
- return;
170
- }
171
-
172
- if ( !current_user_can( $this->capability ) ) {
173
- wp_die( __('You do not have sufficient permissions to access this page.') );
174
- }
175
-
176
- $current_page = $this->get_current_page( $_GET );
177
-
178
- ?>
179
-
180
- <div class="wrap">
181
-
182
- <?php $this->display_page_title(); ?>
183
-
184
- <?php if ( isset( $this->default_tab ) ) : ?>
185
- <h2 class="nav-tab-wrapper">
186
- <?php
187
- foreach( $this->sections as $section ) {
188
-
189
- if ( isset( $section->is_tab ) && $section->is_tab === true ) {
190
-
191
- $tab_url = add_query_arg(
192
- array(
193
- 'settings-updated' => false,
194
- 'tab' => $section->id
195
- )
196
- );
197
-
198
- $active = $current_page == $section->id ? ' nav-tab-active' : '';
199
- echo '<a href="' . esc_url( $tab_url ) . '" title="' . esc_attr( $section->title ) . '" class="nav-tab' . $active . '">';
200
- echo esc_html( $section->title );
201
- echo '</a>';
202
- }
203
- }
204
- ?>
205
- </h2>
206
- <?php endif; ?>
207
-
208
- <form method="post" action="options.php">
209
- <?php settings_fields( $this->id ); ?>
210
- <?php do_settings_sections( $current_page ); ?>
211
- <?php if ( $this->show_button ) { submit_button(); } ?>
212
- </form>
213
- </div>
214
-
215
- <?php
216
- }
217
-
218
- /**
219
- * Output the title of the page
220
- * @since 1.0
221
- */
222
- public function display_page_title() {
223
-
224
- if ( empty( $this->title ) ) {
225
- return;
226
- }
227
- ?>
228
- <h1><?php echo $this->title; ?></h1>
229
- <?php
230
- }
231
-
232
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a settings page in the WordPress admin menu.
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPage_2_5_5 {
11
+
12
+ public $title;
13
+ public $menu_title;
14
+ public $description; // optional description for this page
15
+ public $capability; // user permissions needed to edit this panel
16
+ public $id; // id of this page
17
+ public $sections = array(); // array of sections to display on this page
18
+ public $show_button = true; // whether or not to show the Save Changes button
19
+
20
+ public $setup_function = 'add_options_page'; // WP function to register the page
21
+
22
+
23
+ /**
24
+ * Initialize the page
25
+ * @since 1.0
26
+ */
27
+ public function __construct( $args ) {
28
+
29
+ // Parse the values passed
30
+ $this->parse_args( $args );
31
+ }
32
+
33
+ /**
34
+ * Parse the arguments passed in the construction and assign them to
35
+ * internal variables.
36
+ * @since 1.1
37
+ */
38
+ private function parse_args( $args ) {
39
+ foreach ( $args as $key => $val ) {
40
+ switch ( $key ) {
41
+
42
+ case 'id' :
43
+ $this->{$key} = esc_attr( $val );
44
+
45
+ default :
46
+ $this->{$key} = $val;
47
+
48
+ }
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Modify the capability required to save settings on this page
54
+ * @since 2.0
55
+ */
56
+ public function modify_required_capability( $cap ) {
57
+ return $this->capability;
58
+ }
59
+
60
+ /**
61
+ * Add the page to the appropriate menu slot.
62
+ * @note The default will be to post to the options page, but other classes
63
+ * should override this function.
64
+ * @since 1.0
65
+ */
66
+ public function add_admin_menu() {
67
+ call_user_func( $this->setup_function, $this->title, $this->menu_title, $this->capability, $this->id, array( $this, 'display_admin_menu' ) );
68
+ }
69
+
70
+ /**
71
+ * Add a section to the page
72
+ * @since 1.0
73
+ */
74
+ public function add_section( $section ) {
75
+
76
+ if ( !$section ) {
77
+ return;
78
+ }
79
+
80
+ $this->sections[ $section->id ] = $section;
81
+
82
+ }
83
+
84
+ /**
85
+ * Register the settings and sanitization callbacks for each setting
86
+ * @since 1.0
87
+ */
88
+ public function register_admin_menu() {
89
+
90
+ foreach ( $this->sections as $section ) {
91
+ $section->add_settings_section();
92
+
93
+ foreach ( $section->settings as $setting ) {
94
+ $setting->add_settings_field( $section->id );
95
+ }
96
+ }
97
+
98
+ register_setting( $this->id, $this->id, array( $this, 'sanitize_callback' ) );
99
+
100
+ // Modify capability required to save the settings if it's not
101
+ // the default `manage_options`
102
+ if ( !empty( $this->capability ) && $this->capability !== 'manage_options') {
103
+ add_filter( 'option_page_capability_' . $this->id, array( $this, 'modify_required_capability' ) );
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Loop through the settings and sanitize the data
109
+ * @since 2.0
110
+ */
111
+ public function sanitize_callback( $value ) {
112
+
113
+ if ( empty( $_POST['_wp_http_referer'] ) ) {
114
+ return $value;
115
+ }
116
+
117
+ // Get the current page/tab so we only update those settings
118
+ parse_str( $_POST['_wp_http_referer'], $referrer );
119
+ $current_page = $this->get_current_page( $referrer );
120
+
121
+ // Use a new empty value so only values for settings that were added are
122
+ // passed to the db.
123
+ $new_value = array();
124
+
125
+ foreach ( $this->sections as $section ) {
126
+ foreach ( $section->settings as $setting ) {
127
+ if ( $setting->tab == $current_page ) {
128
+ $setting_value = isset( $value[$setting->id] ) ? $value[$setting->id] : '';
129
+ $new_value[$setting->id] = $setting->sanitize_callback_wrapper( $setting_value );
130
+ }
131
+ }
132
+ }
133
+
134
+ // Pull in the existing values so we never overwrite values that were
135
+ // on a different tab
136
+ $old_value = get_option( $this->id );
137
+
138
+ if ( is_array( $old_value ) ) {
139
+ return array_merge( $old_value, $new_value );
140
+ } else {
141
+ return $new_value;
142
+ }
143
+
144
+ }
145
+
146
+ /**
147
+ * Get the current page/tab being viewed
148
+ * @since 2.0
149
+ */
150
+ public function get_current_page( $request ) {
151
+
152
+ if ( !empty( $request['tab'] ) ) {
153
+ return $request['tab'];
154
+ } elseif ( !empty( $this->default_tab ) ) {
155
+ return $this->default_tab;
156
+ } else {
157
+ return $this->id;
158
+ }
159
+
160
+ }
161
+
162
+ /**
163
+ * Output the settings passed to this page
164
+ * @since 1.0
165
+ */
166
+ public function display_admin_menu() {
167
+
168
+ if ( !$this->title && !count( $this->settings ) ) {
169
+ return;
170
+ }
171
+
172
+ if ( !current_user_can( $this->capability ) ) {
173
+ wp_die( __('You do not have sufficient permissions to access this page.') );
174
+ }
175
+
176
+ $current_page = $this->get_current_page( $_GET );
177
+
178
+ ?>
179
+
180
+ <div class="wrap sap-settings-page">
181
+
182
+ <?php $this->display_page_title(); ?>
183
+
184
+ <?php if ( isset( $this->default_tab ) ) : ?>
185
+ <h2 class="nav-tab-wrapper">
186
+ <?php
187
+ foreach( $this->sections as $section ) {
188
+
189
+ if ( isset( $section->is_tab ) && $section->is_tab === true ) {
190
+
191
+ $tab_url = add_query_arg(
192
+ array(
193
+ 'settings-updated' => false,
194
+ 'tab' => $section->id
195
+ )
196
+ );
197
+
198
+ $active = $current_page == $section->id ? ' nav-tab-active' : '';
199
+ echo '<a href="' . esc_url( $tab_url ) . '" title="' . esc_attr( $section->title ) . '" class="nav-tab' . $active . '">';
200
+ echo esc_html( $section->title );
201
+ echo '</a>';
202
+ }
203
+ }
204
+ ?>
205
+ </h2>
206
+ <?php endif; ?>
207
+
208
+ <form method="post" action="options.php" class="sap-parent-form">
209
+ <?php settings_fields( $this->id ); ?>
210
+ <?php do_settings_sections( $current_page ); ?>
211
+ <?php if ( $this->show_button ) { submit_button(); } ?>
212
+ </form>
213
+ </div>
214
+
215
+ <?php
216
+ }
217
+
218
+ /**
219
+ * Output the title of the page
220
+ * @since 1.0
221
+ */
222
+ public function display_page_title() {
223
+
224
+ if ( empty( $this->title ) ) {
225
+ return;
226
+ }
227
+ ?>
228
+ <h1><?php echo $this->title; ?></h1>
229
+ <?php
230
+ }
231
+
232
+ }
lib/simple-admin-pages/classes/AdminPageSection.class.php CHANGED
@@ -1,188 +1,188 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a section on a custom admin menu
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPageSection_2_1_2 {
11
-
12
- // Page defaults
13
- public $id; // unique id for this section
14
- public $title; // optional title to display above this section
15
- public $description; // optional description of the section
16
- public $settings = array(); // Array of settings to display in this option set
17
- public $disabled = false; // whether a setting should be disabled
18
-
19
- // Array to store errors
20
- public $errors = array();
21
-
22
- /**
23
- * Initialize the section
24
- * @since 1.0
25
- */
26
- public function __construct( $args ) {
27
-
28
- // Parse the values passed
29
- $this->parse_args( $args );
30
-
31
- // Set an error if there is no id for this section
32
- if ( !isset( $this->id ) ) {
33
- $this->set_error(
34
- array(
35
- 'type' => 'missing_data',
36
- 'data' => 'id'
37
- )
38
- );
39
- }
40
-
41
- }
42
-
43
- /**
44
- * Parse the arguments passed in the construction and assign them to
45
- * internal variables.
46
- * @since 1.0
47
- */
48
- private function parse_args( $args ) {
49
- foreach ( $args as $key => $val ) {
50
- switch ( $key ) {
51
-
52
- case 'id' :
53
- $this->{$key} = esc_attr( $val );
54
-
55
- default :
56
- $this->{$key} = $val;
57
-
58
- }
59
- }
60
- }
61
-
62
- /**
63
- * Add a setting to this section
64
- * @since 1.0
65
- */
66
- public function add_setting( $setting ) {
67
-
68
- if ( !$setting ) {
69
- return;
70
- }
71
-
72
- if ( $this->disabled ) {
73
- $setting->disabled = true;
74
- }
75
-
76
- if ( method_exists( $setting, 'has_position' ) && $setting->has_position() ) {
77
-
78
- // Top
79
- if ( $setting->position[0] == 'top' ) {
80
- $this->settings = array_merge( array( $setting->id => $setting ), $this->settings );
81
- return;
82
- }
83
-
84
- // Position setting relative to another setting
85
- if ( !empty( $setting->position[1] ) ) {
86
-
87
- $new_settings = array();
88
- foreach( $this->settings as $id => $current ) {
89
-
90
- // Above
91
- if ( $setting->position[1] == $id && $setting->position[0] == 'above' ) {
92
- $new_settings[ $setting->id ] = $setting;
93
- }
94
-
95
- $new_settings[ $id ] = $current;
96
-
97
- // Below
98
- if ( $setting->position[1] == $id && $setting->position[0] == 'below' ) {
99
- $new_settings[ $setting->id ] = $setting;
100
- }
101
- }
102
-
103
- $this->settings = $new_settings;
104
-
105
- return;
106
- }
107
- }
108
-
109
- // Fallback to appending it at the end
110
- $this->settings[ $setting->id ] = $setting;
111
- }
112
-
113
- /**
114
- * Display the description for this section
115
- * @since 1.0
116
- */
117
- public function display_section() {
118
-
119
- if ( !count( $this->settings ) ) {
120
- return;
121
- }
122
-
123
- if ( !empty( $this->description ) ) :
124
- ?>
125
-
126
- <p class="description"><?php echo $this->description; ?></p>
127
-
128
- <?php
129
- endif;
130
-
131
- if ( $this->disabled and isset($this->disabled_image) ) {
132
-
133
- ?>
134
-
135
- <?php echo ( isset($this->purchase_link ) ? "<div class='bpfwp-premium-options-table-overlay'>" : '' ); ?>
136
- <div class="section-disabled">
137
- <img src="<?php echo BPFWP_PLUGIN_URL; ?>/assets/img/options-asset-lock.png" alt="Upgrade to Five-Star Business Profile Premium">
138
- <p>Access this section by by upgrading to premium</p>
139
- <a href="https://www.fivestarplugins.com/plugins/five-star-business-profile/" class="bpfwp-dashboard-get-premium-widget-button" target="_blank">UPGRADE NOW</a>
140
- </div>
141
- <?php echo ( isset($this->purchase_link ) ? "</div>" : '' ); ?>
142
-
143
- <?php
144
-
145
- }
146
- }
147
-
148
- /**
149
- * Add the settings section to the page in WordPress
150
- * @since 1.0
151
- */
152
- public function add_settings_section() {
153
- add_settings_section( $this->id, $this->title, array( $this, 'display_section' ), $this->get_page_slug() );
154
- }
155
-
156
- /**
157
- * Determine the page slug to use when calling add_settings_section.
158
- *
159
- * Tabs should use their own ID and settings that are attached to tabs
160
- * should use that tab's ID.
161
- * @since 2.0
162
- */
163
- public function get_page_slug() {
164
- if ( isset( $this->is_tab ) && $this->is_tab === true ) {
165
- return $this->id;
166
- } elseif ( isset( $this->tab ) ) {
167
- return $this->tab;
168
- } else {
169
- return $this->page;
170
- }
171
- }
172
-
173
- /**
174
- * Set an error
175
- * @since 1.0
176
- */
177
- public function set_error( $error ) {
178
- $this->errors[] = array_merge(
179
- $error,
180
- array(
181
- 'class' => get_class( $this ),
182
- 'id' => $this->id,
183
- 'backtrace' => debug_backtrace()
184
- )
185
- );
186
- }
187
-
188
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a section on a custom admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSection_2_5_5 {
11
+
12
+ // Page defaults
13
+ public $id; // unique id for this section
14
+ public $title; // optional title to display above this section
15
+ public $description; // optional description of the section
16
+ public $settings = array(); // Array of settings to display in this option set
17
+ public $disabled = false; // whether a setting should be disabled
18
+
19
+ // Array to store errors
20
+ public $errors = array();
21
+
22
+ /**
23
+ * Initialize the section
24
+ * @since 1.0
25
+ */
26
+ public function __construct( $args ) {
27
+
28
+ // Parse the values passed
29
+ $this->parse_args( $args );
30
+
31
+ // Set an error if there is no id for this section
32
+ if ( !isset( $this->id ) ) {
33
+ $this->set_error(
34
+ array(
35
+ 'type' => 'missing_data',
36
+ 'data' => 'id'
37
+ )
38
+ );
39
+ }
40
+
41
+ }
42
+
43
+ /**
44
+ * Parse the arguments passed in the construction and assign them to
45
+ * internal variables.
46
+ * @since 1.0
47
+ */
48
+ private function parse_args( $args ) {
49
+ foreach ( $args as $key => $val ) {
50
+ switch ( $key ) {
51
+
52
+ case 'id' :
53
+ $this->{$key} = esc_attr( $val );
54
+
55
+ default :
56
+ $this->{$key} = $val;
57
+
58
+ }
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Add a setting to this section
64
+ * @since 1.0
65
+ */
66
+ public function add_setting( $setting ) {
67
+
68
+ if ( !$setting ) {
69
+ return;
70
+ }
71
+
72
+ if ( $this->disabled ) {
73
+ $setting->disabled = true;
74
+ }
75
+
76
+ if ( method_exists( $setting, 'has_position' ) && $setting->has_position() ) {
77
+
78
+ // Top
79
+ if ( $setting->position[0] == 'top' ) {
80
+ $this->settings = array_merge( array( $setting->id => $setting ), $this->settings );
81
+ return;
82
+ }
83
+
84
+ // Position setting relative to another setting
85
+ if ( !empty( $setting->position[1] ) ) {
86
+
87
+ $new_settings = array();
88
+ foreach( $this->settings as $id => $current ) {
89
+
90
+ // Above
91
+ if ( $setting->position[1] == $id && $setting->position[0] == 'above' ) {
92
+ $new_settings[ $setting->id ] = $setting;
93
+ }
94
+
95
+ $new_settings[ $id ] = $current;
96
+
97
+ // Below
98
+ if ( $setting->position[1] == $id && $setting->position[0] == 'below' ) {
99
+ $new_settings[ $setting->id ] = $setting;
100
+ }
101
+ }
102
+
103
+ $this->settings = $new_settings;
104
+
105
+ return;
106
+ }
107
+ }
108
+
109
+ // Fallback to appending it at the end
110
+ $this->settings[ $setting->id ] = $setting;
111
+ }
112
+
113
+ /**
114
+ * Display the description for this section
115
+ * @since 1.0
116
+ */
117
+ public function display_section() {
118
+
119
+ if ( !count( $this->settings ) ) {
120
+ return;
121
+ }
122
+
123
+ if ( !empty( $this->description ) ) :
124
+ ?>
125
+
126
+ <p class="description"><?php echo $this->description; ?></p>
127
+
128
+ <?php
129
+ endif;
130
+
131
+ if ( $this->disabled and isset($this->disabled_image) ) {
132
+
133
+ ?>
134
+
135
+ <?php echo ( isset($this->purchase_link ) ? "<div class='sap-premium-options-table-overlay'>" : '' ); ?>
136
+ <div class="section-disabled">
137
+ <img src="<?php echo plugins_url( '../img/options-asset-lock.png', __FILE__ ); ?>" alt="Upgrade to Premium">
138
+ <p>Access this section by upgrading to premium</p>
139
+ <a href="<?php echo $this->purchase_link; ?>" class="sap-dashboard-get-premium-widget-button" target="_blank">UPGRADE NOW</a>
140
+ </div>
141
+ <?php echo ( isset( $this->purchase_link ) ? "</div>" : '' ); ?>
142
+
143
+ <?php
144
+
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Add the settings section to the page in WordPress
150
+ * @since 1.0
151
+ */
152
+ public function add_settings_section() {
153
+ add_settings_section( $this->id, $this->title, array( $this, 'display_section' ), $this->get_page_slug() );
154
+ }
155
+
156
+ /**
157
+ * Determine the page slug to use when calling add_settings_section.
158
+ *
159
+ * Tabs should use their own ID and settings that are attached to tabs
160
+ * should use that tab's ID.
161
+ * @since 2.0
162
+ */
163
+ public function get_page_slug() {
164
+ if ( isset( $this->is_tab ) && $this->is_tab === true ) {
165
+ return $this->id;
166
+ } elseif ( isset( $this->tab ) ) {
167
+ return $this->tab;
168
+ } else {
169
+ return $this->page;
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Set an error
175
+ * @since 1.0
176
+ */
177
+ public function set_error( $error ) {
178
+ $this->errors[] = array_merge(
179
+ $error,
180
+ array(
181
+ 'class' => get_class( $this ),
182
+ 'id' => $this->id,
183
+ 'backtrace' => debug_backtrace()
184
+ )
185
+ );
186
+ }
187
+
188
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Address.class.php CHANGED
@@ -1,156 +1,156 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a textarea field setting in the admin menu
5
- *
6
- * @since 2.0.a.5
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPageSettingAddress_2_1_2 extends sapAdminPageSetting_2_1_2 {
11
-
12
- /*
13
- * Size of this textarea
14
- *
15
- * This is put directly into a css class [size]-text,
16
- * and setting this to 'large' will link into WordPress's existing textarea
17
- * style for full-width textareas.
18
- */
19
- public $size = 'small';
20
-
21
- /*
22
- * A Google Maps API key for geolocating addresses
23
- */
24
- public $api_key = '';
25
-
26
- /*
27
- * A jQuery selector pointing to the input element where the Google Maps API
28
- * key can be retrieved.
29
- */
30
- public $api_key_selector = '';
31
-
32
- /**
33
- * Scripts that must be loaded for this component
34
- * @since 2.0.a.5
35
- */
36
- public $scripts = array(
37
- 'sap-address' => array(
38
- 'path' => 'js/address.js',
39
- 'dependencies' => array( 'jquery' ),
40
- 'version' => '2.1.1',
41
- 'footer' => true,
42
- ),
43
- );
44
-
45
- public $sanitize_callback = 'sanitize_text_field';
46
-
47
- /**
48
- * Translateable strings required for this component
49
- * @since 2.0.a.8
50
- */
51
- public $strings = array(
52
- 'sep-action-links' => null, // _x( ' | ', 'separator between admin action links in address component', 'textdomain' ),
53
- 'sep-lat-lon' => null, // _x( ', ', 'separates latitude and longitude', 'textdomain' ),
54
- 'no-setting' => null, // __( 'No map coordinates set.', 'textdomain' ),
55
- 'retrieving' => null, // __( 'Requesting new coordinates', 'textdomain' ),
56
- 'select' => null, // __( 'Select a match below', 'textdomain' ),
57
- 'view' => null, // __( 'View', 'textdomain' ),
58
- 'retrieve' => null, // __( 'Retrieve map coordinates', 'textdomain' ),
59
- 'remove' => null, // __( 'Remove map coordinates', 'textdomain' ),
60
- 'try_again' => null, // __( 'Try again?', 'textdomain' ),
61
- 'result_error' => null, // __( 'Error', 'textdomain' ),
62
- 'result_invalid' => null, // __( 'Invalid request. Be sure to fill out the address field before retrieving coordinates.', 'textdomain' ),
63
- 'result_denied' => null, // __( 'Request denied.', 'textdomain' ),
64
- 'result_limit' => null, // __( 'Request denied because you are over your request quota.', 'textdomain' ),
65
- 'result_empty' => null, // __( 'Nothing was found at that address', 'textdomain' ),
66
- );
67
-
68
- /**
69
- * Escape the value to display it safely HTML textarea fields
70
- * @since 2.0.a.5
71
- */
72
- public function esc_value( $val ) {
73
-
74
- $escaped = array();
75
- $escaped['text'] = empty( $val['text'] ) ? '' : esc_textarea( $val['text'] );
76
- $escaped['lat'] = empty( $val['lat'] ) ? '' : esc_textarea( $val['lat'] );
77
- $escaped['lon'] = empty( $val['lon'] ) ? '' : esc_textarea( $val['lon'] );
78
-
79
- return $escaped;
80
- }
81
-
82
- /**
83
- * Set the size of this textarea field
84
- * @since 1.0
85
- */
86
- public function set_size( $size ) {
87
- $this->size = esc_attr( $size );
88
- }
89
-
90
- /**
91
- * Wrapper for the sanitization callback function.
92
- *
93
- * This just reduces code duplication for child classes that need a custom
94
- * callback function.
95
- * @since 2.0.a.5
96
- */
97
- public function sanitize_callback_wrapper( $value ) {
98
-
99
- $sanitized = array();
100
- $sanitized['text'] = empty( $value['text'] ) ? '' : wp_kses_post( $value['text'] );
101
- $sanitized['lat'] = empty( $value['lat'] ) ? '' : sanitize_text_field( $value['lat'] );
102
- $sanitized['lon'] = empty( $value['lon'] ) ? '' : sanitize_text_field( $value['lon'] );
103
-
104
- return $sanitized;
105
- }
106
-
107
- /**
108
- * Display this setting
109
- * @since 2.0.a.5
110
- */
111
- public function display_setting() {
112
-
113
- wp_localize_script(
114
- 'sap-address',
115
- 'sap_address',
116
- array(
117
- 'strings' => $this->strings,
118
- 'api_key' => $this->api_key,
119
- 'api_key_selector' => $this->api_key_selector,
120
- )
121
- );
122
-
123
- $this->display_description();
124
-
125
- ?>
126
-
127
- <div class="sap-address" id="<?php echo $this->id; ?>">
128
- <textarea name="<?php echo $this->get_input_name(); ?>[text]" id="<?php echo $this->get_input_name(); ?>" class="<?php echo $this->size; ?>-text"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>><?php echo $this->value['text']; ?></textarea>
129
- <p class="sap-map-coords-wrapper">
130
- <span class="dashicons dashicons-location-alt"></span>
131
- <span class="sap-map-coords">
132
- <?php if ( empty( $this->value['lat'] ) || empty( $this->value['lon'] ) ) : ?>
133
- <?php echo $this->strings['no-setting']; ?>
134
- <?php else : ?>
135
- <?php echo $this->value['lat'] . $this->strings['sep-lat-lon'] . $this->value['lon']; ?>
136
- <a href="//maps.google.com/maps?q=<?php echo esc_attr( $this->value['lat'] ) . ',' . esc_attr( $this->value['lon'] ); ?>" class="sap-view-coords" target="_blank"><?php echo $this->strings['view']; ?></a>
137
- <?php endif; ?>
138
- </span>
139
- </p>
140
- <p class="sap-coords-action-wrapper">
141
- <a href="#" class="sap-get-coords">
142
- <?php echo $this->strings['retrieve']; ?>
143
- </a>
144
- <?php echo $this->strings['sep-action-links']; ?>
145
- <a href="#" class="sap-remove-coords">
146
- <?php echo $this->strings['remove']; ?>
147
- </a>
148
- </p>
149
- <input type="hidden" class="lat" name="<?php echo $this->get_input_name(); ?>[lat]" value="<?php echo $this->value['lat']; ?>">
150
- <input type="hidden" class="lon" name="<?php echo $this->get_input_name(); ?>[lon]" value="<?php echo $this->value['lon']; ?>">
151
- </div>
152
-
153
- <?php
154
- }
155
-
156
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a textarea field setting in the admin menu
5
+ *
6
+ * @since 2.0.a.5
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingAddress_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ /*
13
+ * Size of this textarea
14
+ *
15
+ * This is put directly into a css class [size]-text,
16
+ * and setting this to 'large' will link into WordPress's existing textarea
17
+ * style for full-width textareas.
18
+ */
19
+ public $size = 'small';
20
+
21
+ /*
22
+ * A Google Maps API key for geolocating addresses
23
+ */
24
+ public $api_key = '';
25
+
26
+ /*
27
+ * A jQuery selector pointing to the input element where the Google Maps API
28
+ * key can be retrieved.
29
+ */
30
+ public $api_key_selector = '';
31
+
32
+ /**
33
+ * Scripts that must be loaded for this component
34
+ * @since 2.0.a.5
35
+ */
36
+ public $scripts = array(
37
+ 'sap-address' => array(
38
+ 'path' => 'js/address.js',
39
+ 'dependencies' => array( 'jquery' ),
40
+ 'version' => SAP_VERSION,
41
+ 'footer' => true,
42
+ ),
43
+ );
44
+
45
+ public $sanitize_callback = 'sanitize_text_field';
46
+
47
+ /**
48
+ * Translateable strings required for this component
49
+ * @since 2.0.a.8
50
+ */
51
+ public $strings = array(
52
+ 'sep-action-links' => null, // _x( ' | ', 'separator between admin action links in address component', 'textdomain' ),
53
+ 'sep-lat-lon' => null, // _x( ', ', 'separates latitude and longitude', 'textdomain' ),
54
+ 'no-setting' => null, // __( 'No map coordinates set.', 'textdomain' ),
55
+ 'retrieving' => null, // __( 'Requesting new coordinates', 'textdomain' ),
56
+ 'select' => null, // __( 'Select a match below', 'textdomain' ),
57
+ 'view' => null, // __( 'View', 'textdomain' ),
58
+ 'retrieve' => null, // __( 'Retrieve map coordinates', 'textdomain' ),
59
+ 'remove' => null, // __( 'Remove map coordinates', 'textdomain' ),
60
+ 'try_again' => null, // __( 'Try again?', 'textdomain' ),
61
+ 'result_error' => null, // __( 'Error', 'textdomain' ),
62
+ 'result_invalid' => null, // __( 'Invalid request. Be sure to fill out the address field before retrieving coordinates.', 'textdomain' ),
63
+ 'result_denied' => null, // __( 'Request denied.', 'textdomain' ),
64
+ 'result_limit' => null, // __( 'Request denied because you are over your request quota.', 'textdomain' ),
65
+ 'result_empty' => null, // __( 'Nothing was found at that address', 'textdomain' ),
66
+ );
67
+
68
+ /**
69
+ * Escape the value to display it safely HTML textarea fields
70
+ * @since 2.0.a.5
71
+ */
72
+ public function esc_value( $val ) {
73
+
74
+ $escaped = array();
75
+ $escaped['text'] = empty( $val['text'] ) ? '' : esc_textarea( $val['text'] );
76
+ $escaped['lat'] = empty( $val['lat'] ) ? '' : esc_textarea( $val['lat'] );
77
+ $escaped['lon'] = empty( $val['lon'] ) ? '' : esc_textarea( $val['lon'] );
78
+
79
+ return $escaped;
80
+ }
81
+
82
+ /**
83
+ * Set the size of this textarea field
84
+ * @since 1.0
85
+ */
86
+ public function set_size( $size ) {
87
+ $this->size = esc_attr( $size );
88
+ }
89
+
90
+ /**
91
+ * Wrapper for the sanitization callback function.
92
+ *
93
+ * This just reduces code duplication for child classes that need a custom
94
+ * callback function.
95
+ * @since 2.0.a.5
96
+ */
97
+ public function sanitize_callback_wrapper( $value ) {
98
+
99
+ $sanitized = array();
100
+ $sanitized['text'] = empty( $value['text'] ) ? '' : wp_kses_post( $value['text'] );
101
+ $sanitized['lat'] = empty( $value['lat'] ) ? '' : sanitize_text_field( $value['lat'] );
102
+ $sanitized['lon'] = empty( $value['lon'] ) ? '' : sanitize_text_field( $value['lon'] );
103
+
104
+ return $sanitized;
105
+ }
106
+
107
+ /**
108
+ * Display this setting
109
+ * @since 2.0.a.5
110
+ */
111
+ public function display_setting() {
112
+
113
+ wp_localize_script(
114
+ 'sap-address',
115
+ 'sap_address',
116
+ array(
117
+ 'strings' => $this->strings,
118
+ 'api_key' => $this->api_key,
119
+ 'api_key_selector' => $this->api_key_selector,
120
+ )
121
+ );
122
+
123
+ $this->display_description();
124
+
125
+ ?>
126
+
127
+ <div class="sap-address" id="<?php echo $this->id; ?>">
128
+ <textarea name="<?php echo $this->get_input_name(); ?>[text]" id="<?php echo $this->get_input_name(); ?>" class="<?php echo $this->size; ?>-text"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>><?php echo $this->value['text']; ?></textarea>
129
+ <p class="sap-map-coords-wrapper">
130
+ <span class="dashicons dashicons-location-alt"></span>
131
+ <span class="sap-map-coords">
132
+ <?php if ( empty( $this->value['lat'] ) || empty( $this->value['lon'] ) ) : ?>
133
+ <?php echo $this->strings['no-setting']; ?>
134
+ <?php else : ?>
135
+ <?php echo $this->value['lat'] . $this->strings['sep-lat-lon'] . $this->value['lon']; ?>
136
+ <a href="//maps.google.com/maps?q=<?php echo esc_attr( $this->value['lat'] ) . ',' . esc_attr( $this->value['lon'] ); ?>" class="sap-view-coords" target="_blank"><?php echo $this->strings['view']; ?></a>
137
+ <?php endif; ?>
138
+ </span>
139
+ </p>
140
+ <p class="sap-coords-action-wrapper">
141
+ <a href="#" class="sap-get-coords">
142
+ <?php echo $this->strings['retrieve']; ?>
143
+ </a>
144
+ <?php echo $this->strings['sep-action-links']; ?>
145
+ <a href="#" class="sap-remove-coords">
146
+ <?php echo $this->strings['remove']; ?>
147
+ </a>
148
+ </p>
149
+ <input type="hidden" class="lat" name="<?php echo $this->get_input_name(); ?>[lat]" value="<?php echo $this->value['lat']; ?>">
150
+ <input type="hidden" class="lon" name="<?php echo $this->get_input_name(); ?>[lon]" value="<?php echo $this->value['lon']; ?>">
151
+ </div>
152
+
153
+ <?php
154
+ }
155
+
156
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Checkbox.class.php CHANGED
@@ -1,52 +1,67 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an option with multiple checkboxes.
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'options' => array(
13
- * 'value' => 'Name'
14
- * ), // The checkbox values and text
15
- * );
16
- * );
17
- *
18
- * @since 2.0
19
- * @package Simple Admin Pages
20
- */
21
-
22
- class sapAdminPageSettingCheckbox_2_1_2 extends sapAdminPageSetting_2_1_2 {
23
-
24
- //public $sanitize_callback = 'sanitize_text_field';
25
-
26
- /**
27
- * Display this setting
28
- * @since 2.0
29
- */
30
- public function display_setting() {
31
-
32
- $input_name = $this->get_input_name();
33
- $values = (is_array($this->value) ? $this->value : array());
34
-
35
- ?>
36
- <fieldset>
37
- <?php foreach ( $this->options as $id => $title ) : ?>
38
- <label title="<?php echo $title; ?>" class="bpfwp-admin-input-container">
39
- <input type="checkbox" name="<?php echo $input_name; ?>[]" id="<?php echo $input_name . "-" . $id; ?>" value="<?php echo $id; ?>" <?php echo ( in_array($id, $values) ? 'checked="checked"' : '' ) ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
40
- <span class='bpfwp-admin-checkbox'></span> <span><?php echo $title; ?></span>
41
- </label>
42
- <br />
43
- <?php endforeach; ?>
44
- <?php $this->display_disabled(); ?>
45
- </fieldset>
46
- <?php
47
-
48
- $this->display_description();
49
-
50
- }
51
-
52
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an option with multiple checkboxes.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'options' => array(
13
+ * 'value' => 'Name'
14
+ * ), // The checkbox values and text
15
+ * );
16
+ * );
17
+ *
18
+ * @since 2.0
19
+ * @package Simple Admin Pages
20
+ */
21
+
22
+ class sapAdminPageSettingCheckbox_2_5_5 extends sapAdminPageSetting_2_5_5 {
23
+
24
+ //public $sanitize_callback = 'sanitize_text_field';
25
+
26
+ /**
27
+ * Display this setting
28
+ * @since 2.0
29
+ */
30
+ public function display_setting() {
31
+
32
+ $input_name = $this->get_input_name();
33
+ $values = ( is_array( $this->value ) ? $this->value : array() );
34
+
35
+ ?>
36
+ <fieldset <?php echo ( isset( $this->columns ) ? 'class="sap-setting-columns-' . $this->columns . '"' : '' ); ?>>
37
+ <?php foreach ( $this->options as $id => $title ) : ?>
38
+ <label title="<?php echo ( strpos( $title, '<' ) === false ? $title : ''); ?>" class="sap-admin-input-container">
39
+ <input type="checkbox" name="<?php echo $input_name; ?>[]" id="<?php echo $input_name . "-" . $id; ?>" value="<?php echo $id; ?>" <?php echo ( in_array($id, $values) ? 'checked="checked"' : '' ) ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
40
+ <span class='sap-admin-checkbox'></span> <span><?php echo $title; ?></span>
41
+ </label>
42
+ <?php endforeach; ?>
43
+ <?php $this->display_disabled(); ?>
44
+ </fieldset>
45
+ <?php
46
+
47
+ $this->display_description();
48
+
49
+ }
50
+
51
+ public function sanitize_callback_wrapper( $values ) {
52
+
53
+ return is_array( $values ) ? array_map( $this->sanitize_callback, $values ) : array();
54
+ }
55
+
56
+ /**
57
+ * Escape the value to display it safely HTML textarea fields
58
+ */
59
+ public function esc_value( $values ) {
60
+
61
+ $return = is_array( $values ) ? array_map( 'esc_attr', $values ) : $values;
62
+ $return = is_string( $return ) ? esc_attr( $return ) : $return;
63
+
64
+ return $return;
65
+ }
66
+
67
+ }
lib/simple-admin-pages/classes/AdminPageSetting.ColorPicker.class.php CHANGED
@@ -1,39 +1,39 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a color picker field setting in the admin menu
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPageSettingColorPicker_2_1_2 extends sapAdminPageSetting_2_1_2 {
11
-
12
- public $sanitize_callback = 'sanitize_text_field';
13
-
14
- /**
15
- * Placeholder string for the input field
16
- * @since 2.0
17
- */
18
- public $placeholder = '';
19
-
20
- /**
21
- * Display this setting
22
- * @since 1.0
23
- */
24
- public function display_setting() {
25
- ?>
26
-
27
- <fieldset>
28
- <input class="bpfwpspectrum" name="<?php echo $this->get_input_name(); ?>" type="text" id="<?php echo $this->get_input_name(); ?>" value="<?php echo $this->value; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text" <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
29
-
30
- <?php $this->display_disabled(); ?>
31
- </fieldset>
32
-
33
- <?php
34
-
35
- $this->display_description();
36
-
37
- }
38
-
39
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a color picker field setting in the admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingColorPicker_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ public $sanitize_callback = 'sanitize_text_field';
13
+
14
+ /**
15
+ * Placeholder string for the input field
16
+ * @since 2.0
17
+ */
18
+ public $placeholder = '';
19
+
20
+ /**
21
+ * Display this setting
22
+ * @since 1.0
23
+ */
24
+ public function display_setting() {
25
+ ?>
26
+
27
+ <fieldset class="sap-colorpicker">
28
+ <input class="sap-spectrum" name="<?php echo $this->get_input_name(); ?>" type="text" id="<?php echo $this->get_input_name(); ?>" value="<?php echo $this->value; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text" <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
29
+
30
+ <?php $this->display_disabled(); ?>
31
+ </fieldset>
32
+
33
+ <?php
34
+
35
+ $this->display_description();
36
+
37
+ }
38
+
39
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Count.class.php CHANGED
@@ -1,111 +1,117 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a count/unit option with drop-down menus.
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'blank_option' => true, // Whether or not to show a blank option
13
- * 'min_value' => 0, // The lowest value to include
14
- * 'max_value' => 10, // The highest value to include
15
- * 'increment' => 1, // How many values to increase by each loop
16
- * 'units' => array( // An array of key/value pairs which
17
- * 'unit_one' => 'Unit 1', // Define the units.
18
- * 'unit_two' => 'Unit 2',
19
- * ...
20
- * );
21
- * );
22
- *
23
- * @since 2.0
24
- * @package Simple Admin Pages
25
- */
26
-
27
- class sapAdminPageSettingCount_2_1_2 extends sapAdminPageSetting_2_1_2 {
28
-
29
- public $sanitize_callback = 'sanitize_text_field';
30
-
31
- /**
32
- * Add in the JS requried for rows to be added and the values to be stored
33
- * @since 2.0
34
- */
35
- public $scripts = array(
36
- 'sap-infinite-table' => array(
37
- 'path' => 'js/count.js',
38
- 'dependencies' => array( 'jquery' ),
39
- 'version' => '2.1.2',
40
- 'footer' => true,
41
- ),
42
- );
43
-
44
- // Whether or not to display a blank option
45
- public $blank_option = true;
46
-
47
- // The default value for the field when none has been set
48
- public $default;
49
-
50
- // The lowest value to include
51
- public $min_value = 0;
52
-
53
- // The lowest value to include
54
- public $max_value = 10;
55
-
56
- // The lowest value to include
57
- public $increment = 1;
58
-
59
- // An array of options for this select field, accepted as a key/value pair.
60
- public $units = array();
61
-
62
- /**
63
- * Display this setting
64
- * @since 1.0
65
- */
66
- public function display_setting() {
67
-
68
- $this->value = $this->value ? $this->value : $this->default;
69
-
70
- $count = substr( $this->value, 0, strpos( $this->value, '_' ) );
71
- $unit = substr( $this->value, strpos( $this->value, '_' ) + 1 );
72
-
73
- ?>
74
-
75
- <fieldset>
76
- <input id='<?php echo $this->id; ?>' type='hidden' name='<?php echo $this->get_input_name(); ?>' value='<?php echo $this->value; ?>' />
77
- <select id="<?php echo $this->id; ?>_count" <?php echo ( $this->disabled ? 'disabled' : ''); ?> class='sap-count-count' data-id='<?php echo $this->id; ?>'>
78
-
79
- <?php if ( $this->blank_option === true ) : ?>
80
- <option></option>
81
- <?php endif; ?>
82
-
83
- <?php for ( $i = $this->min_value; $i <= $this->max_value; $i = $i + $this->increment ) : ?>
84
- <option value="<?php echo $i; ?>"<?php if( $count == $i ) : ?> selected="selected"<?php endif; ?>><?php echo $i; ?></option>
85
- <?php endfor; ?>
86
-
87
- </select>
88
-
89
- <?php if ( ! empty($this->units) ) { ?>
90
- <select id="<?php echo $this->id; ?>_unit" <?php echo ( $this->disabled ? 'disabled' : ''); ?> class='sap-count-unit' data-id='<?php echo $this->id; ?>'>
91
-
92
- <?php if ( $this->blank_option === true ) : ?>
93
- <option></option>
94
- <?php endif; ?>
95
-
96
- <?php foreach ( $this->units as $id => $title ) : ?>
97
- <option value="<?php echo esc_attr( $id ); ?>"<?php if( $unit == $id ) : ?> selected="selected"<?php endif; ?>><?php echo esc_html( $title ); ?></option>
98
- <?php endforeach; ?>
99
-
100
- </select>
101
- <?php } ?>
102
- <?php $this->display_disabled(); ?>
103
- </fieldset>
104
-
105
- <?php
106
-
107
- $this->display_description();
108
-
109
- }
110
-
111
- }
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a count/unit option with drop-down menus.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'blank_option' => true, // Whether or not to show a blank option
13
+ * 'min_value' => 0, // The lowest value to include
14
+ * 'max_value' => 10, // The highest value to include
15
+ * 'increment' => 1, // How many values to increase by each loop
16
+ * 'units' => array( // An array of key/value pairs which
17
+ * 'unit_one' => 'Unit 1', // Define the units.
18
+ * 'unit_two' => 'Unit 2',
19
+ * ...
20
+ * );
21
+ * );
22
+ *
23
+ * @since 2.0
24
+ * @package Simple Admin Pages
25
+ */
26
+
27
+ class sapAdminPageSettingCount_2_5_5 extends sapAdminPageSetting_2_5_5 {
28
+
29
+ public $sanitize_callback = 'sanitize_text_field';
30
+
31
+ /**
32
+ * Add in the JS requried for rows to be added and the values to be stored
33
+ * @since 2.0
34
+ */
35
+ public $scripts = array(
36
+ 'sap-count' => array(
37
+ 'path' => 'js/count.js',
38
+ 'dependencies' => array( 'jquery' ),
39
+ 'version' => SAP_VERSION,
40
+ 'footer' => true,
41
+ ),
42
+ );
43
+
44
+ // Whether or not to display a blank option
45
+ public $blank_option = true;
46
+
47
+ // The default value for the field when none has been set
48
+ public $default;
49
+
50
+ // The lowest value to include
51
+ public $min_value = 0;
52
+
53
+ // The lowest value to include
54
+ public $max_value = 10;
55
+
56
+ // The lowest value to include
57
+ public $increment = 1;
58
+
59
+ // An array of options for this select field, accepted as a key/value pair.
60
+ public $units = array();
61
+
62
+ /**
63
+ * Display this setting
64
+ * @since 1.0
65
+ */
66
+ public function display_setting() {
67
+
68
+ $this->value = $this->value ? $this->value : $this->default;
69
+
70
+ $count = strpos( $this->value, '_' ) !== false ? substr( $this->value, 0, strpos( $this->value, '_' ) ) : $this->value;
71
+ $unit = substr( $this->value, strpos( $this->value, '_' ) + 1 );
72
+
73
+ ?>
74
+
75
+ <fieldset>
76
+ <input id='<?php echo $this->id; ?>' type='hidden' name='<?php echo $this->get_input_name(); ?>' value='<?php echo $this->value; ?>' />
77
+ <select id="<?php echo $this->id; ?>_count" <?php echo ( $this->disabled ? 'disabled' : ''); ?> class='sap-count-count' data-id='<?php echo $this->id; ?>'>
78
+
79
+ <?php if ( $this->blank_option === true ) : ?>
80
+ <option></option>
81
+ <?php endif; ?>
82
+
83
+ <?php for ( $i = $this->min_value; $i <= $this->max_value; $i = $i + $this->increment ) : ?>
84
+ <option value="<?php echo $i; ?>"<?php if( $count == $i ) : ?> selected="selected"<?php endif; ?>><?php echo $i; ?></option>
85
+ <?php endfor; ?>
86
+
87
+ </select>
88
+
89
+ <?php if ( ! empty($this->units) ) { ?>
90
+
91
+ <?php if ( sizeof( $this->units ) == 1 ) { ?>
92
+ <input type='hidden' id='<?php echo $this->id; ?>_unit' data-id='<?php echo $this->id; ?>' /><span><?php echo esc_html( reset( $this->units ) ); ?></span>
93
+ <?php } else { ?>
94
+ <select id='<?php echo $this->id; ?>_unit' <?php echo ( $this->disabled ? 'disabled' : ''); ?> class='sap-count-unit' data-id='<?php echo $this->id; ?>'>
95
+
96
+ <?php if ( $this->blank_option === true ) : ?>
97
+ <option></option>
98
+ <?php endif; ?>
99
+
100
+ <?php foreach ( $this->units as $id => $title ) : ?>
101
+ <option value='<?php echo esc_attr( $id ); ?>' <?php if( $unit == $id ) : ?> selected="selected"<?php endif; ?>><?php echo esc_html( $title ); ?></option>
102
+ <?php endforeach; ?>
103
+
104
+ </select>
105
+ <?php } ?>
106
+
107
+ <?php } ?>
108
+ <?php $this->display_disabled(); ?>
109
+ </fieldset>
110
+
111
+ <?php
112
+
113
+ $this->display_description();
114
+
115
+ }
116
+
117
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Editor.class.php CHANGED
@@ -1,44 +1,44 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a TinyMC Editor field setting in the admin menu
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPageSettingEditor_2_1_2 extends sapAdminPageSetting_2_1_2 {
11
-
12
- public $sanitize_callback = 'wp_kses_post';
13
-
14
- /**
15
- * List of arguments accepted by wp_editor
16
- * @since 2.0
17
- */
18
- public $args = array();
19
-
20
- /**
21
- * wp_editor() will handle the escaping
22
- * @since 2.0
23
- */
24
- public function esc_value( $val ) {
25
- return $val;
26
- }
27
-
28
- /**
29
- * Display this setting
30
- * @since 2.0
31
- */
32
- public function display_setting() {
33
-
34
- $this->args['textarea_name'] = $this->get_input_name();
35
-
36
- $value = empty( $this->value ) && !empty( $this->default ) ? $this->default : $this->value;
37
-
38
- wp_editor( $value, preg_replace( '/[^\da-z]/i', '', $this->id), $this->args );
39
-
40
- $this->display_description();
41
-
42
- }
43
-
44
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a TinyMC Editor field setting in the admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingEditor_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ public $sanitize_callback = 'wp_kses_post';
13
+
14
+ /**
15
+ * List of arguments accepted by wp_editor
16
+ * @since 2.0
17
+ */
18
+ public $args = array();
19
+
20
+ /**
21
+ * wp_editor() will handle the escaping
22
+ * @since 2.0
23
+ */
24
+ public function esc_value( $val ) {
25
+ return $val;
26
+ }
27
+
28
+ /**
29
+ * Display this setting
30
+ * @since 2.0
31
+ */
32
+ public function display_setting() {
33
+
34
+ $this->args['textarea_name'] = $this->get_input_name();
35
+
36
+ $value = empty( $this->value ) && !empty( $this->default ) ? $this->default : $this->value;
37
+
38
+ wp_editor( $value, preg_replace( '/[^\da-z]/i', '', $this->id), $this->args );
39
+
40
+ $this->display_description();
41
+
42
+ }
43
+
44
+ }
lib/simple-admin-pages/classes/AdminPageSetting.FileUpload.class.php ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an option for uploading an image/file.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * );
13
+ *
14
+ * @since 2.5
15
+ * @package Simple Admin Pages
16
+ */
17
+
18
+ class sapAdminPageSettingFileUpload_2_5_5 extends sapAdminPageSetting_2_5_5 {
19
+
20
+ public $sanitize_callback = 'esc_url_raw';
21
+
22
+ /**
23
+ * Add in the JS requried to allow file uploading
24
+ * @since 2.5
25
+ */
26
+ public $scripts = array(
27
+ 'sap-file-upload' => array(
28
+ 'path' => 'js/file_upload.js',
29
+ 'dependencies' => array( 'jquery' ),
30
+ 'version' => SAP_VERSION,
31
+ 'footer' => true,
32
+ ),
33
+ );
34
+
35
+ /**
36
+ * Display this setting
37
+ * @since 2.5
38
+ */
39
+ public function display_setting() {
40
+
41
+ ?>
42
+
43
+ <span class="sap-file-upload-preview">
44
+
45
+ <span class="sap-file-upload-preview-label">
46
+ <?php _e( 'Current image:', 'simple-admin-pages' ); ?>
47
+ </span>
48
+
49
+ <span class="sap-file-upload-preview-value">
50
+ <?php echo $this->value; ?>
51
+ </span>
52
+
53
+ </span>
54
+
55
+ <?php echo ( $this->value != '' ? '<br /><br />' : '' ); ?>
56
+
57
+ <input name="<?php echo $this->get_input_name(); ?>" type="hidden" id="<?php echo $this->get_input_name(); ?>" class="file-upload" value="<?php echo $this->value; ?>" />
58
+
59
+ <input class="button sap-file-upload-button" type="button" value="<?php _e( 'Upload Image', 'simple-admin-pages' ); ?>" />
60
+
61
+ <br /><br />
62
+
63
+ <?php $this->display_disabled(); ?>
64
+
65
+ <?php
66
+
67
+ $this->display_description();
68
+
69
+ }
70
+
71
+ }
lib/simple-admin-pages/classes/AdminPageSetting.HTML.class.php CHANGED
@@ -1,33 +1,33 @@
1
- <?php
2
-
3
- /**
4
- * Register and save an arbitrary HTML chunk in the admin menu
5
- *
6
- * This allows you to easily add in a dummy "setting" with any arbitrary HTML
7
- * code. It's good for displaying a link to documentation, upgrades or anything
8
- * else you can think of.
9
- *
10
- * Data in this field will not be saved or passed. It's purely for presenting
11
- * information.
12
- *
13
- * @since 1.0
14
- * @package Simple Admin Pages
15
- */
16
-
17
- class sapAdminPageSettingHTML_2_1_2 extends sapAdminPageSetting_2_1_2 {
18
-
19
- public $sanitize_callback = 'sanitize_text_field';
20
-
21
- /**
22
- * Display this setting
23
- * @since 1.0
24
- */
25
- public function display_setting() {
26
-
27
- echo $this->html;
28
-
29
- $this->display_description();
30
-
31
- }
32
-
33
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register and save an arbitrary HTML chunk in the admin menu
5
+ *
6
+ * This allows you to easily add in a dummy "setting" with any arbitrary HTML
7
+ * code. It's good for displaying a link to documentation, upgrades or anything
8
+ * else you can think of.
9
+ *
10
+ * Data in this field will not be saved or passed. It's purely for presenting
11
+ * information.
12
+ *
13
+ * @since 1.0
14
+ * @package Simple Admin Pages
15
+ */
16
+
17
+ class sapAdminPageSettingHTML_2_5_5 extends sapAdminPageSetting_2_5_5 {
18
+
19
+ public $sanitize_callback = 'sanitize_text_field';
20
+
21
+ /**
22
+ * Display this setting
23
+ * @since 1.0
24
+ */
25
+ public function display_setting() {
26
+
27
+ echo $this->html;
28
+
29
+ $this->display_description();
30
+
31
+ }
32
+
33
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Image.class.php CHANGED
@@ -1,62 +1,62 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an image field setting in the admin menu
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPageSettingImage_2_1_2 extends sapAdminPageSetting_2_1_2 {
11
-
12
- public $sanitize_callback = 'absint';
13
-
14
- /**
15
- * Scripts that must be loaded for this component
16
- * @since 2.1.0
17
- */
18
- public $scripts = array(
19
- 'sap-image' => array(
20
- 'path' => 'js/image.js',
21
- 'dependencies' => array( 'jquery' ),
22
- 'version' => '2.1.0',
23
- 'footer' => true,
24
- ),
25
- );
26
-
27
- /**
28
- * Translateable strings required for this component
29
- * @since 2.1.0
30
- */
31
- public $strings = array(
32
- 'add_image' => null, // __( 'Add Image', 'textdomain' ),
33
- 'change_image' => null, // __( 'Change Image', 'textdomain' ),
34
- 'remove_image' => null, // __( 'Remove Image', 'textdomain' ),
35
- );
36
-
37
- /**
38
- * Display this setting
39
- * @since 1.0
40
- */
41
- public function display_setting() {
42
- $image_url = $this->value ? wp_get_attachment_url( $this->value ) : '';
43
- ?>
44
-
45
- <div class="sap-image-wrapper <?php echo $this->value ? 'sap-image-wrapper-has-image' : 'sap-image-wrapper-no-image'; ?>" data-id="sap-<?php echo $this->id; ?>">
46
- <input name="<?php echo $this->get_input_name(); ?>" type="hidden" id="sap-<?php echo $this->id; ?>" value="<?php echo $this->value; ?>">
47
- <img src="<?php echo esc_attr( $image_url ); ?>">
48
- <button class="button sap-image-btn-add" id="sap-<?php echo $this->id; ?>-add"><?php echo esc_html( $this->strings['add_image'] ); ?></button>
49
- <button class="button sap-image-btn-change" id="sap-<?php echo $this->id; ?>-change"><?php echo esc_html( $this->strings['change_image'] ); ?></button>
50
- <button class="button sap-image-btn-remove" id="sap-<?php echo $this->id; ?>-remove"><?php echo esc_html( $this->strings['remove_image'] ); ?></button>
51
- </div>
52
-
53
- <?php
54
-
55
- // global $wp_scripts;
56
- // print_r( $wp_scripts );
57
-
58
- $this->display_description();
59
-
60
- }
61
-
62
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an image field setting in the admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingImage_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ public $sanitize_callback = 'absint';
13
+
14
+ /**
15
+ * Scripts that must be loaded for this component
16
+ * @since 2.1.0
17
+ */
18
+ public $scripts = array(
19
+ 'sap-image' => array(
20
+ 'path' => 'js/image.js',
21
+ 'dependencies' => array( 'jquery' ),
22
+ 'version' => SAP_VERSION,
23
+ 'footer' => true,
24
+ ),
25
+ );
26
+
27
+ /**
28
+ * Translateable strings required for this component
29
+ * @since 2.1.0
30
+ */
31
+ public $strings = array(
32
+ 'add_image' => null, // __( 'Add Image', 'textdomain' ),
33
+ 'change_image' => null, // __( 'Change Image', 'textdomain' ),
34
+ 'remove_image' => null, // __( 'Remove Image', 'textdomain' ),
35
+ );
36
+
37
+ /**
38
+ * Display this setting
39
+ * @since 1.0
40
+ */
41
+ public function display_setting() {
42
+ $image_url = $this->value ? wp_get_attachment_url( $this->value ) : '';
43
+ ?>
44
+
45
+ <div class="sap-image-wrapper <?php echo $this->value ? 'sap-image-wrapper-has-image' : 'sap-image-wrapper-no-image'; ?>" data-id="sap-<?php echo $this->id; ?>">
46
+ <input name="<?php echo $this->get_input_name(); ?>" type="hidden" id="sap-<?php echo $this->id; ?>" value="<?php echo $this->value; ?>">
47
+ <img src="<?php echo esc_attr( $image_url ); ?>">
48
+ <button class="button sap-image-btn-add" id="sap-<?php echo $this->id; ?>-add"><?php echo esc_html( $this->strings['add_image'] ); ?></button>
49
+ <button class="button sap-image-btn-change" id="sap-<?php echo $this->id; ?>-change"><?php echo esc_html( $this->strings['change_image'] ); ?></button>
50
+ <button class="button sap-image-btn-remove" id="sap-<?php echo $this->id; ?>-remove"><?php echo esc_html( $this->strings['remove_image'] ); ?></button>
51
+ </div>
52
+
53
+ <?php
54
+
55
+ // global $wp_scripts;
56
+ // print_r( $wp_scripts );
57
+
58
+ $this->display_description();
59
+
60
+ }
61
+
62
+ }
lib/simple-admin-pages/classes/AdminPageSetting.InfiniteTable.class.php CHANGED
@@ -1,149 +1,201 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an option with multiple checkboxes.
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'add_label' => 'Add Row', // Text for the "Add Row" button
12
- * 'description' => 'Description', // Help text description
13
- * 'fields' => array(
14
- * 'field' => array(
15
- * 'type' => 'text' //text, select
16
- * 'label' => 'Name'
17
- * 'required' => false,
18
- * 'options' => array()
19
- * )
20
- * ) // The attributes and labels for the fields
21
- * );
22
- *
23
- * @since 2.0
24
- * @package Simple Admin Pages
25
- */
26
-
27
- class sapAdminPageSettingInfiniteTable_2_1_2 extends sapAdminPageSetting_2_1_2 {
28
-
29
- public $sanitize_callback = 'sanitize_text_field';
30
-
31
- /**
32
- * Add in the JS requried for rows to be added and the values to be stored
33
- * @since 2.0
34
- */
35
- public $scripts = array(
36
- 'sap-infinite-table' => array(
37
- 'path' => 'js/infinite_table.js',
38
- 'dependencies' => array( 'jquery' ),
39
- 'version' => '2.0.a.5',
40
- 'footer' => true,
41
- ),
42
- );
43
-
44
- /**
45
- * Add in the CSS requried for rows to be displayed correctly
46
- * @since 2.0
47
- */
48
- public $styles = array(
49
- 'sap-infinite-table' => array(
50
- 'path' => 'css/infinite_table.css',
51
- 'dependencies' => array( ),
52
- 'version' => '2.0.a.5',
53
- 'media' => 'all',
54
- ),
55
- );
56
-
57
- /**
58
- * Display this setting
59
- * @since 2.0
60
- */
61
- public function display_setting() {
62
-
63
- $row_count = 0;
64
-
65
- $input_name = $this->get_input_name();
66
- $values = json_decode( html_entity_decode( $this->value ) );
67
-
68
- if ( ! is_array( $values ) )
69
- $values = array();
70
-
71
- $fields = '';
72
- foreach ($this->fields as $field_id => $field) {
73
- $fields .= $field_id . ",";
74
- }
75
- $fields = trim($fields, ',');
76
-
77
- ?>
78
-
79
- <fieldset>
80
- <div class='sap-infinite-table <?php echo ( $this->disabled ? 'disabled' : ''); ?>' data-fieldids='<?php echo $fields; ?>'>
81
- <input type='hidden' name='<?php echo $input_name; ?>' value='<?php echo $this->value; ?>' />
82
- <table>
83
- <thead>
84
- <tr>
85
- <?php foreach ($this->fields as $field) { ?>
86
- <th><?php echo $field['label']; ?></th>
87
- <?php } ?>
88
- <th></th>
89
- </tr>
90
- </thead>
91
- <tbody>
92
- <?php foreach ($values as $row) { ?>
93
- <tr class='sap-inifinite-table-row' data-rowid='<?php echo $row_count; ?>'>
94
- <?php foreach ($this->fields as $field_id => $field) { ?>
95
- <td>
96
- <?php if ($field['type'] == 'text') : ?>
97
- <input type='text' name='<?php echo $field_id . "_" . $row_count; ?>' value='<?php echo $row->$field_id; ?>' />
98
- <?php endif; ?>
99
- <?php if ($field['type'] == 'select') : ?>
100
- <select name='<?php echo $field_id . "_" . $row_count; ?>'>
101
- <?php foreach ($field['options'] as $option_value => $option_name) { ?>
102
- <option value='<?php echo $option_value; ?>' <?php echo ($row->$field_id == $option_value ? 'selected="selected"' : ''); ?>><?php echo $option_name; ?></option>
103
- <?php }?>
104
- </select>
105
- <?php endif; ?>
106
- </td>
107
- <?php } ?>
108
- <td class='sap-infinite-table-row-delete'><?php _e('Delete'); ?></td>
109
- </tr>
110
- <?php $row_count++; ?>
111
- <?php } ?>
112
- </tbody>
113
- <tfoot>
114
- <tr class='sap-inifite-table-row-template sap-hidden'>
115
- <?php foreach ($this->fields as $field_id => $field) { ?>
116
- <td>
117
- <?php if ($field['type'] == 'text') : ?>
118
- <input type='text' name='<?php echo $field_id; ?>' value='' />
119
- <?php endif; ?>
120
- <?php if ($field['type'] == 'select') : ?>
121
- <select name='<?php echo $field_id; ?>'>
122
- <?php foreach ($field['options'] as $option_value => $option_name) { ?>
123
- <option value='<?php echo $option_value; ?>'><?php echo $option_name; ?></option>
124
- <?php }?>
125
- </select>
126
- <?php endif; ?>
127
- </td>
128
- <?php } ?>
129
- <td class='sap-infinite-table-row-delete'><?php _e('Delete'); ?></td>
130
- </tr>
131
- <tr class='sap-infinite-table-add-row'>
132
- <td colspan="4">
133
- <a class="bpfwpnew-admin-add-button">&plus; <?php _e('ADD ROW'); ?></a>
134
- </td>
135
- </tr>
136
- </tfoot>
137
- </table>
138
- </div>
139
-
140
- <?php $this->display_disabled(); ?>
141
- </fieldset>
142
-
143
- <?php
144
-
145
- $this->display_description();
146
-
147
- }
148
-
149
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an option with multiple checkboxes.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'add_label' => 'Add Row', // Text for the "Add Row" button
12
+ * 'description' => 'Description', // Help text description
13
+ * 'fields' => array(
14
+ * 'field' => array(
15
+ * 'type' => 'text' //text, select
16
+ * 'label' => 'Name'
17
+ * 'required' => false,
18
+ * 'options' => array()
19
+ * )
20
+ * ) // The attributes and labels for the fields
21
+ * );
22
+ *
23
+ * @since 2.0
24
+ * @package Simple Admin Pages
25
+ */
26
+
27
+ class sapAdminPageSettingInfiniteTable_2_5_5 extends sapAdminPageSetting_2_5_5 {
28
+
29
+ public $sanitize_callback = 'sanitize_textarea_field';
30
+
31
+ /**
32
+ * Add in the JS requried for rows to be added and the values to be stored
33
+ * @since 2.0
34
+ */
35
+ public $scripts = array(
36
+ 'sap-infinite-table' => array(
37
+ 'path' => 'js/infinite_table.js',
38
+ 'dependencies' => array( 'jquery' ),
39
+ 'version' => SAP_VERSION,
40
+ 'footer' => true,
41
+ ),
42
+ );
43
+
44
+ /**
45
+ * Add in the CSS requried for rows to be displayed correctly
46
+ * @since 2.0
47
+ */
48
+ public $styles = array(
49
+ 'sap-infinite-table' => array(
50
+ 'path' => 'css/infinite_table.css',
51
+ 'dependencies' => array( ),
52
+ 'version' => SAP_VERSION,
53
+ 'media' => 'all',
54
+ ),
55
+ );
56
+
57
+ /**
58
+ * Display this setting
59
+ * @since 2.0
60
+ */
61
+ public function display_setting() {
62
+
63
+ $input_name = $this->get_input_name();
64
+ $values = json_decode( html_entity_decode( $this->value ) );
65
+
66
+ if ( ! is_array( $values ) )
67
+ $values = array();
68
+
69
+ $fields = '';
70
+ foreach ($this->fields as $field_id => $field) {
71
+ $fields .= $field_id . ",";
72
+ }
73
+ $fields = trim($fields, ',');
74
+
75
+ ?>
76
+
77
+ <fieldset>
78
+ <div class='sap-infinite-table <?php echo ( $this->disabled ? 'disabled' : ''); ?>' data-fieldids='<?php echo $fields; ?>'>
79
+ <input type='hidden' id="sap-infinite-table-main-input" name='<?php echo $input_name; ?>' value='<?php echo $this->value; ?>' />
80
+ <table>
81
+ <thead>
82
+ <tr>
83
+ <?php foreach ($this->fields as $field) { ?>
84
+ <th><?php echo $field['label']; ?></th>
85
+ <?php } ?>
86
+ <th></th>
87
+ </tr>
88
+ </thead>
89
+ <tbody>
90
+ <?php foreach ($values as $row) { ?>
91
+ <tr class='sap-infinite-table-row'>
92
+ <?php foreach ($this->fields as $field_id => $field) { ?>
93
+ <td>
94
+ <?php if ($field['type'] == 'text') : ?>
95
+ <input type='text' data-name='<?php echo $field_id; ?>' value='<?php echo $row->$field_id; ?>' />
96
+ <?php endif; ?>
97
+ <?php if ($field['type'] == 'textarea') : ?>
98
+ <textarea data-name='<?php echo $field_id; ?>'><?php echo $row->$field_id; ?></textarea>
99
+ <?php endif; ?>
100
+ <?php if ($field['type'] == 'hidden') : ?>
101
+ <span class='sap-infinite-table-hidden-value'><?php echo $row->$field_id; ?></span>
102
+ <input type='hidden' data-name='<?php echo $field_id; ?>' value='<?php echo $row->$field_id; ?>' />
103
+ <?php endif; ?>
104
+ <?php if ($field['type'] == 'select') : ?>
105
+ <select data-name='<?php echo $field_id; ?>'>
106
+ <?php if ( ! empty( $field['blank_option'] ) ) { ?><option></option><?php } ?>
107
+ <?php $this->print_options( $field['options'], $row, $field_id ); ?>
108
+ </select>
109
+ <?php endif; ?>
110
+ <?php if ($field['type'] == 'toggle') : ?>
111
+ <label class="sap-admin-switch">
112
+ <input type="checkbox" class="sap-admin-option-toggle" data-name="<?php echo $field_id; ?>" <?php if( $row->$field_id == '1' ) {echo "checked='checked'";} ?> >
113
+ <span class="sap-admin-switch-slider round"></span>
114
+ </label>
115
+ <?php endif; ?>
116
+ </td>
117
+ <?php } ?>
118
+ <td class='sap-infinite-table-row-delete'><?php echo $this->del_label; ?></td>
119
+ </tr>
120
+ <?php } ?>
121
+ </tbody>
122
+ <tfoot>
123
+ <tr class='sap-infinite-table-row-template sap-hidden'>
124
+ <?php foreach ($this->fields as $field_id => $field) { ?>
125
+ <td>
126
+ <?php if ($field['type'] == 'text') : ?>
127
+ <input type='text' data-name='<?php echo $field_id; ?>' value='' />
128
+ <?php endif; ?>
129
+ <?php if ($field['type'] == 'textarea') : ?>
130
+ <textarea data-name='<?php echo $field_id; ?>'></textarea>
131
+ <?php endif; ?>
132
+ <?php if ($field['type'] == 'hidden') : ?>
133
+ <span class='sap-infinite-table-hidden-value'></span>
134
+ <input type='hidden' data-name='<?php echo $field_id; ?>' value='' />
135
+ <?php endif; ?>
136
+ <?php if ($field['type'] == 'select') : ?>
137
+ <select data-name='<?php echo $field_id; ?>'>
138
+ <?php if ( ! empty( $field['blank_option'] ) ) { ?><option></option><?php } ?>
139
+ <?php $this->print_options( $field['options'] ); ?>
140
+ </select>
141
+ <?php endif; ?>
142
+ <?php if ($field['type'] == 'toggle') : ?>
143
+ <label class="sap-admin-switch">
144
+ <input type="checkbox" class="sap-admin-option-toggle" data-name="<?php echo $field_id; ?>" checked >
145
+ <span class="sap-admin-switch-slider round"></span>
146
+ </label>
147
+ <?php endif; ?>
148
+ </td>
149
+ <?php } ?>
150
+ <td class='sap-infinite-table-row-delete'><?php echo $this->del_label; ?></td>
151
+ </tr>
152
+ <tr class='sap-infinite-table-add-row'>
153
+ <td colspan="4">
154
+ <a class="sap-new-admin-add-button"><?php echo $this->add_label; ?></a>
155
+ </td>
156
+ </tr>
157
+ </tfoot>
158
+ </table>
159
+ </div>
160
+
161
+ <?php $this->display_disabled(); ?>
162
+ </fieldset>
163
+
164
+ <?php
165
+
166
+ $this->display_description();
167
+
168
+ }
169
+
170
+ /**
171
+ * Recursively print out select options
172
+ * @since 2.5.3
173
+ */
174
+ public function print_options( $options, $row = false, $field_id = 0 ) {
175
+
176
+ foreach ( $options as $option_value => $option_name ) {
177
+
178
+ if ( is_array( $option_name ) ) { ?>
179
+
180
+ <optgroup label='<?php echo esc_attr( $option_value ); ?>'>
181
+ <?php $this->print_options( $option_name, $row, $field_id ); ?>
182
+ </optgroup>
183
+
184
+ <?php
185
+
186
+ continue;
187
+ }
188
+
189
+ $selected_value = $row ? $row->$field_id : false;
190
+
191
+ ?>
192
+
193
+ <option value='<?php echo $option_value; ?>' <?php echo ($selected_value == $option_value ? 'selected="selected"' : ''); ?>>
194
+ <?php echo $option_name; ?>
195
+ </option>
196
+
197
+ <?php
198
+ }
199
+ }
200
+
201
+ }
lib/simple-admin-pages/classes/AdminPageSetting.McApiKey.class.php CHANGED
@@ -1,221 +1,223 @@
1
- <?php
2
-
3
- /**
4
- * Add a setting to Simple Admin Pages to register and verify a
5
- * MailChimp API key
6
- *
7
- * This class is modelled on AdminPageSetting.class.php in the Simple
8
- * Admin Pages library. It should work just like an extended class, but
9
- * due to the way the library embeds the version into the class name,
10
- * that could cause problems if the library is updated in the parent
11
- * plugin.
12
- *
13
- * See: https://github.com/NateWr/simple-admin-pages
14
- *
15
- */
16
-
17
- class mcfrtbAdminPageSettingMcApiKey_2_1_2 {
18
-
19
- /**
20
- * Scripts and styles to load for this component
21
- * (not used but required as part of the library)
22
- */
23
- public $scripts = array();
24
- public $styles = array();
25
-
26
- /**
27
- * Initialize the setting
28
- */
29
- public function __construct( $args ) {
30
-
31
- // Parse the values passed
32
- $this->parse_args( $args );
33
-
34
- // Get any existing value
35
- $this->set_value();
36
-
37
- // Set an error if the object is missing necessary data
38
- if ( $this->missing_data() ) {
39
- $this->set_error();
40
- }
41
- }
42
-
43
- /**
44
- * Parse the arguments passed in the construction and assign them to
45
- * internal variables. This function will be overwritten for most subclasses
46
- */
47
- private function parse_args( $args ) {
48
- foreach ( $args as $key => $val ) {
49
- switch ( $key ) {
50
-
51
- case 'id' :
52
- $this->{$key} = esc_attr( $val );
53
-
54
- case 'title' :
55
- $this->{$key} = esc_attr( $val );
56
-
57
- default :
58
- $this->{$key} = $val;
59
-
60
- }
61
- }
62
- }
63
-
64
- /**
65
- * Check for missing data when setup.
66
- */
67
- private function missing_data() {
68
-
69
- // Required fields
70
- if ( empty( $this->id ) ) {
71
- $this->set_error(
72
- array(
73
- 'type' => 'missing_data',
74
- 'data' => 'id'
75
- )
76
- );
77
- }
78
- if ( empty( $this->title ) ) {
79
- $this->set_error(
80
- array(
81
- 'type' => 'missing_data',
82
- 'data' => 'title'
83
- )
84
- );
85
- }
86
- }
87
-
88
- /**
89
- * Set a value
90
- */
91
- public function set_value( $val = null ) {
92
-
93
- if ( $val === null ) {
94
- $option_group_value = get_option( $this->page );
95
- $val = isset( $option_group_value[ $this->id ] ) ? $option_group_value[ $this->id ] : '';
96
- }
97
-
98
- $this->value = $this->esc_value( $val );
99
- }
100
-
101
- /**
102
- * Escape the value to display it in text fields and other input fields
103
- */
104
- public function esc_value( $val ) {
105
-
106
- $value = array(
107
- 'api_key' => '',
108
- 'status' => false,
109
- );
110
-
111
- if ( empty( $val ) || empty( $val['api_key'] ) ) {
112
- return $value;
113
- }
114
-
115
- $value['api_key'] = esc_attr( $val['api_key'] );
116
- $value['status'] = (bool) $val['status'];
117
-
118
- return $value;
119
- }
120
-
121
- /**
122
- * Display this setting
123
- */
124
- public function display_setting() {
125
- ?>
126
-
127
- <input name="<?php echo $this->get_input_name(); ?>[api_key]" type="text" id="<?php echo $this->get_input_name(); ?>[api_key]" value="<?php echo $this->value['api_key']; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text">
128
-
129
- <?php if ( !empty( $this->value['api_key'] ) && $this->value['status'] === true ) : ?>
130
- <span class="mcfrtb-status mcfrtb-status-connected"><?php echo $this->string_status_connected; ?></span>
131
- <?php elseif( !empty( $this->value['api_key'] ) ) : ?>
132
- <span class="mcfrtb-status mcfrtb-status-error"><?php echo $this->string_status_error; ?></span>
133
- <?php endif; ?>
134
-
135
- <input name="<?php echo $this->get_input_name(); ?>[status]" type="hidden" id="<?php echo $this->get_input_name(); ?>[status]" value="<?php echo $this->value['status']; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?>>
136
-
137
- <?php
138
-
139
- $this->display_description();
140
- }
141
-
142
- /**
143
- * Display a description for this setting
144
- */
145
- public function display_description() {
146
-
147
- if ( !empty( $this->description ) ) : ?>
148
-
149
- <p class="description"><?php echo $this->description; ?></p>
150
-
151
- <?php endif;
152
- }
153
-
154
- /**
155
- * Generate an option input field name, using the grouped schema.
156
- */
157
- public function get_input_name() {
158
- return esc_attr( $this->page ) . '[' . esc_attr( $this->id ) . ']';
159
- }
160
-
161
-
162
- /**
163
- * Sanitize the array of text inputs for this setting
164
- */
165
- public function sanitize_callback_wrapper( $values ) {
166
- global $bpfwp_controller;
167
-
168
- $output = array(
169
- 'api_key' => '',
170
- 'status' => false,
171
- );
172
-
173
- // Return an empty key and status if the values don't look right
174
- if ( !is_array( $values ) || empty( $values ) || empty( $values['api_key'] ) ) {
175
- return $output;
176
- }
177
-
178
- // Sanitize the API key
179
- $output['api_key'] = sanitize_text_field( $values['api_key'] );
180
-
181
- $bpfwp_controller->mailchimp->load_api( $output['api_key'] );
182
-
183
- // Check for a valid API key
184
- $output['status'] = $bpfwp_controller->mailchimp->is_valid_api_key();
185
-
186
- return $output;
187
- }
188
-
189
- /**
190
- * Add and register this setting
191
- *
192
- * @since 1.0
193
- */
194
- public function add_settings_field( $section_id ) {
195
-
196
- add_settings_field(
197
- $this->id,
198
- $this->title,
199
- array( $this, 'display_setting' ),
200
- $this->tab,
201
- $section_id
202
- );
203
-
204
- }
205
-
206
- /**
207
- * Set an error
208
- * @since 1.0
209
- */
210
- public function set_error( $error ) {
211
- $this->errors[] = array_merge(
212
- $error,
213
- array(
214
- 'class' => get_class( $this ),
215
- 'id' => $this->id,
216
- 'backtrace' => debug_backtrace()
217
- )
218
- );
219
- }
220
-
221
- }
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Add a setting to Simple Admin Pages to register and verify a
5
+ * MailChimp API key
6
+ *
7
+ * This class is modelled on AdminPageSetting.class.php in the Simple
8
+ * Admin Pages library. It should work just like an extended class, but
9
+ * due to the way the library embeds the version into the class name,
10
+ * that could cause problems if the library is updated in the parent
11
+ * plugin.
12
+ *
13
+ * See: https://github.com/NateWr/simple-admin-pages
14
+ *
15
+ */
16
+
17
+ class mcfrtbAdminPageSettingMcApiKey_2_5_5 {
18
+
19
+ /**
20
+ * Scripts and styles to load for this component
21
+ * (not used but required as part of the library)
22
+ */
23
+ public $scripts = array();
24
+ public $styles = array();
25
+
26
+ /**
27
+ * Initialize the setting
28
+ */
29
+ public function __construct( $args ) {
30
+
31
+ // Parse the values passed
32
+ $this->parse_args( $args );
33
+
34
+ // Get any existing value
35
+ $this->set_value();
36
+
37
+ // Set an error if the object is missing necessary data
38
+ if ( $this->missing_data() ) {
39
+ $this->set_error();
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Parse the arguments passed in the construction and assign them to
45
+ * internal variables. This function will be overwritten for most subclasses
46
+ */
47
+ private function parse_args( $args ) {
48
+ foreach ( $args as $key => $val ) {
49
+ switch ( $key ) {
50
+
51
+ case 'id' :
52
+ $this->{$key} = esc_attr( $val );
53
+
54
+ case 'title' :
55
+ $this->{$key} = esc_attr( $val );
56
+
57
+ default :
58
+ $this->{$key} = $val;
59
+
60
+ }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Check for missing data when setup.
66
+ */
67
+ private function missing_data() {
68
+
69
+ // Required fields
70
+ if ( empty( $this->id ) ) {
71
+ $this->set_error(
72
+ array(
73
+ 'type' => 'missing_data',
74
+ 'data' => 'id'
75
+ )
76
+ );
77
+ }
78
+ if ( empty( $this->title ) ) {
79
+ $this->set_error(
80
+ array(
81
+ 'type' => 'missing_data',
82
+ 'data' => 'title'
83
+ )
84
+ );
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Set a value
90
+ */
91
+ public function set_value( $val = null ) {
92
+
93
+ if ( $val === null ) {
94
+ $option_group_value = get_option( $this->page );
95
+ $val = isset( $option_group_value[ $this->id ] ) ? $option_group_value[ $this->id ] : '';
96
+ }
97
+
98
+ $this->value = $this->esc_value( $val );
99
+ }
100
+
101
+ /**
102
+ * Escape the value to display it in text fields and other input fields
103
+ */
104
+ public function esc_value( $val ) {
105
+
106
+ $value = array(
107
+ 'api_key' => '',
108
+ 'status' => false,
109
+ );
110
+
111
+ if ( empty( $val ) || empty( $val['api_key'] ) ) {
112
+ return $value;
113
+ }
114
+
115
+ $value['api_key'] = esc_attr( $val['api_key'] );
116
+ $value['status'] = (bool) $val['status'];
117
+
118
+ return $value;
119
+ }
120
+
121
+ /**
122
+ * Display this setting
123
+ */
124
+ public function display_setting() {
125
+ ?>
126
+
127
+ <input name="<?php echo $this->get_input_name(); ?>[api_key]" type="text" id="<?php echo $this->get_input_name(); ?>[api_key]" value="<?php echo $this->value['api_key']; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text">
128
+
129
+ <?php if ( !empty( $this->value['api_key'] ) && $this->value['status'] === true ) : ?>
130
+ <span class="mcfrtb-status mcfrtb-status-connected"><?php echo $this->string_status_connected; ?></span>
131
+ <?php elseif( !empty( $this->value['api_key'] ) ) : ?>
132
+ <span class="mcfrtb-status mcfrtb-status-error"><?php echo $this->string_status_error; ?></span>
133
+ <?php endif; ?>
134
+
135
+ <input name="<?php echo $this->get_input_name(); ?>[status]" type="hidden" id="<?php echo $this->get_input_name(); ?>[status]" value="<?php echo $this->value['status']; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?>>
136
+
137
+ <?php
138
+
139
+ $this->display_description();
140
+ }
141
+
142
+ /**
143
+ * Display a description for this setting
144
+ */
145
+ public function display_description() {
146
+
147
+ if ( !empty( $this->description ) ) : ?>
148
+
149
+ <p class="description"><?php echo $this->description; ?></p>
150
+
151
+ <?php endif;
152
+ }
153
+
154
+ /**
155
+ * Generate an option input field name, using the grouped schema.
156
+ */
157
+ public function get_input_name() {
158
+ return esc_attr( $this->page ) . '[' . esc_attr( $this->id ) . ']';
159
+ }
160
+
161
+
162
+ /**
163
+ * Sanitize the array of text inputs for this setting
164
+ */
165
+ public function sanitize_callback_wrapper( $values ) {
166
+ // global $ulb_controller;
167
+
168
+ $output = array(
169
+ 'api_key' => '',
170
+ 'status' => false,
171
+ );
172
+
173
+ // Return an empty key and status if the values don't look right
174
+ if ( !is_array( $values ) || empty( $values ) || empty( $values['api_key'] ) ) {
175
+ return $output;
176
+ }
177
+
178
+ // Sanitize the API key
179
+ $output['api_key'] = sanitize_text_field( $values['api_key'] );
180
+
181
+ // $ulb_controller->mailchimp->load_api( $output['api_key'] );
182
+
183
+ // Check for a valid API key
184
+ // $output['status'] = $ulb_controller->mailchimp->is_valid_api_key();
185
+
186
+ $output['status'] = strpos( $output['api_key'], '-' ) === false ? false : true;
187
+
188
+ return $output;
189
+ }
190
+
191
+ /**
192
+ * Add and register this setting
193
+ *
194
+ * @since 1.0
195
+ */
196
+ public function add_settings_field( $section_id ) {
197
+
198
+ add_settings_field(
199
+ $this->id,
200
+ $this->title,
201
+ array( $this, 'display_setting' ),
202
+ $this->tab,
203
+ $section_id
204
+ );
205
+
206
+ }
207
+
208
+ /**
209
+ * Set an error
210
+ * @since 1.0
211
+ */
212
+ public function set_error( $error ) {
213
+ $this->errors[] = array_merge(
214
+ $error,
215
+ array(
216
+ 'class' => get_class( $this ),
217
+ 'id' => $this->id,
218
+ 'backtrace' => debug_backtrace()
219
+ )
220
+ );
221
+ }
222
+
223
+ }
lib/simple-admin-pages/classes/AdminPageSetting.McListMerge.class.php CHANGED
@@ -1,255 +1,255 @@
1
- <?php
2
-
3
- /**
4
- * Add a setting to Simple Admin Pages to select a list and define
5
- * merge fields for that list.
6
- *
7
- * This class is modelled on AdminPageSetting.class.php in the Simple
8
- * Admin Pages library. It should work just like an extended class, but
9
- * due to the way the library embeds the version into the class name,
10
- * that could cause problems if the library is updated in the parent
11
- * plugin.
12
- *
13
- * See: https://github.com/NateWr/simple-admin-pages
14
- *
15
- */
16
-
17
- class mcfrtbAdminPageSettingMcListMerge_2_1_2 {
18
-
19
- /**
20
- * Scripts and styles to load for this component
21
- * (not used but required as part of the library)
22
- */
23
- public $scripts = array();
24
- public $styles = array();
25
-
26
- /**
27
- * List of fields available for merging
28
- */
29
- public $fields = array();
30
-
31
- /**
32
- * Initialize the setting
33
- */
34
- public function __construct( $args ) {
35
-
36
- // Parse the values passed
37
- $this->parse_args( $args );
38
-
39
- // Get any existing value
40
- $this->set_value();
41
-
42
- // Set an error if the object is missing necessary data
43
- if ( $this->missing_data() ) {
44
- $this->set_error();
45
- }
46
- }
47
-
48
- /**
49
- * Parse the arguments passed in the construction and assign them to
50
- * internal variables. This function will be overwritten for most subclasses
51
- */
52
- private function parse_args( $args ) {
53
- foreach ( $args as $key => $val ) {
54
- switch ( $key ) {
55
-
56
- case 'id' :
57
- $this->{$key} = esc_attr( $val );
58
-
59
- case 'title' :
60
- $this->{$key} = esc_attr( $val );
61
-
62
- case 'fields' :
63
- $this->{$key} = is_array( $val ) ? $val : array();
64
-
65
- default :
66
- $this->{$key} = $val;
67
-
68
- }
69
- }
70
- }
71
-
72
- /**
73
- * Check for missing data when setup.
74
- */
75
- private function missing_data() {
76
-
77
- // Required fields
78
- if ( empty( $this->id ) ) {
79
- $this->set_error(
80
- array(
81
- 'type' => 'missing_data',
82
- 'data' => 'id'
83
- )
84
- );
85
- }
86
- if ( empty( $this->title ) ) {
87
- $this->set_error(
88
- array(
89
- 'type' => 'missing_data',
90
- 'data' => 'title'
91
- )
92
- );
93
- }
94
- if ( empty( $this->fields ) ) {
95
- $this->set_error(
96
- array(
97
- 'type' => 'missing_data',
98
- 'data' => 'fields'
99
- )
100
- );
101
- }
102
- if ( empty( $this->string_loading ) ) {
103
- $this->set_error(
104
- array(
105
- 'type' => 'missing_data',
106
- 'data' => 'string_loading'
107
- )
108
- );
109
- }
110
- }
111
-
112
- /**
113
- * Set a value
114
- */
115
- public function set_value( $val = null ) {
116
-
117
- if ( $val === null ) {
118
- $option_group_value = get_option( $this->page );
119
- $val = isset( $option_group_value[ $this->id ] ) ? $option_group_value[ $this->id ] : '';
120
- }
121
-
122
- $this->value = $this->esc_value( $val );
123
- }
124
-
125
- /**
126
- * Escape the value to display it in text fields and other input fields
127
- */
128
- public function esc_value( $val ) {
129
-
130
- $value = array(
131
- 'list' => '',
132
- 'fields' => array(),
133
- );
134
-
135
- if ( empty( $val ) || empty( $val['list'] ) ) {
136
- return $value;
137
- }
138
-
139
- $value['list'] = esc_attr( $val['list'] );
140
-
141
- // Escape the id/title of each merge field
142
- foreach( $val['fields'] as $id => $val ) {
143
- $value['fields'][$id] = esc_html( $val );
144
- }
145
-
146
- return $value;
147
- }
148
-
149
- /**
150
- * Display this setting
151
- */
152
- public function display_setting() {
153
-
154
- ?>
155
-
156
- <span class="mcfrtb-list-select"></span>
157
-
158
- <span class="mcfbpfwp_loading">
159
- <span class="spinner"></span>
160
- <span><?php echo $this->string_loading; ?></span>
161
- </span>
162
-
163
- <?php $this->display_description(); ?>
164
-
165
- <div id="mcfrtb-merge-controls" data-input-name="<?php echo $this->get_input_name(); ?>"></div>
166
-
167
- <?php
168
- }
169
-
170
- /**
171
- * Display a description for this setting
172
- */
173
- public function display_description() {
174
-
175
- if ( !empty( $this->description ) ) : ?>
176
-
177
- <p class="description"><?php echo $this->description; ?></p>
178
-
179
- <?php endif;
180
- }
181
-
182
- /**
183
- * Generate an option input field name, using the grouped schema.
184
- */
185
- public function get_input_name() {
186
- return esc_attr( $this->page ) . '[' . esc_attr( $this->id ) . ']';
187
- }
188
-
189
-
190
- /**
191
- * Sanitize the array of text inputs for this setting
192
- */
193
- public function sanitize_callback_wrapper( $values ) {
194
-
195
- $output = array(
196
- 'list' => '',
197
- 'fields' => array(),
198
- );
199
-
200
- // Return an empty value if we're missing anything important
201
- if ( !is_array( $values ) || empty( $values ) || empty( $values['list'] ) ) {
202
- return $output;
203
- }
204
-
205
- // Sanitize the list
206
- $output['list'] = sanitize_text_field( $values['list'] );
207
-
208
- // Sanitize each merge field
209
- $val_log = array();
210
- foreach( $values['fields'] as $id => $val ) {
211
-
212
- // Make sure that a merge field isn't assigned to multiple data
213
- if ( !in_array( $val, $val_log ) ) {
214
- $output['fields'][$id] = sanitize_text_field( $val );
215
- }
216
-
217
- $val_log[] = $val;
218
- }
219
-
220
- return $output;
221
- }
222
-
223
- /**
224
- * Add and register this setting
225
- *
226
- * @since 1.0
227
- */
228
- public function add_settings_field( $section_id ) {
229
-
230
- add_settings_field(
231
- $this->id,
232
- $this->title,
233
- array( $this, 'display_setting' ),
234
- $this->tab,
235
- $section_id
236
- );
237
-
238
- }
239
-
240
- /**
241
- * Set an error
242
- * @since 1.0
243
- */
244
- public function set_error( $error ) {
245
- $this->errors[] = array_merge(
246
- $error,
247
- array(
248
- 'class' => get_class( $this ),
249
- 'id' => $this->id,
250
- 'backtrace' => debug_backtrace()
251
- )
252
- );
253
- }
254
-
255
- }
1
+ <?php
2
+
3
+ /**
4
+ * Add a setting to Simple Admin Pages to select a list and define
5
+ * merge fields for that list.
6
+ *
7
+ * This class is modelled on AdminPageSetting.class.php in the Simple
8
+ * Admin Pages library. It should work just like an extended class, but
9
+ * due to the way the library embeds the version into the class name,
10
+ * that could cause problems if the library is updated in the parent
11
+ * plugin.
12
+ *
13
+ * See: https://github.com/NateWr/simple-admin-pages
14
+ *
15
+ */
16
+
17
+ class mcfrtbAdminPageSettingMcListMerge_2_5_5 {
18
+
19
+ /**
20
+ * Scripts and styles to load for this component
21
+ * (not used but required as part of the library)
22
+ */
23
+ public $scripts = array();
24
+ public $styles = array();
25
+
26
+ /**
27
+ * List of fields available for merging
28
+ */
29
+ public $fields = array();
30
+
31
+ /**
32
+ * Initialize the setting
33
+ */
34
+ public function __construct( $args ) {
35
+
36
+ // Parse the values passed
37
+ $this->parse_args( $args );
38
+
39
+ // Get any existing value
40
+ $this->set_value();
41
+
42
+ // Set an error if the object is missing necessary data
43
+ if ( $this->missing_data() ) {
44
+ $this->set_error();
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Parse the arguments passed in the construction and assign them to
50
+ * internal variables. This function will be overwritten for most subclasses
51
+ */
52
+ private function parse_args( $args ) {
53
+ foreach ( $args as $key => $val ) {
54
+ switch ( $key ) {
55
+
56
+ case 'id' :
57
+ $this->{$key} = esc_attr( $val );
58
+
59
+ case 'title' :
60
+ $this->{$key} = esc_attr( $val );
61
+
62
+ case 'fields' :
63
+ $this->{$key} = is_array( $val ) ? $val : array();
64
+
65
+ default :
66
+ $this->{$key} = $val;
67
+
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Check for missing data when setup.
74
+ */
75
+ private function missing_data() {
76
+
77
+ // Required fields
78
+ if ( empty( $this->id ) ) {
79
+ $this->set_error(
80
+ array(
81
+ 'type' => 'missing_data',
82
+ 'data' => 'id'
83
+ )
84
+ );
85
+ }
86
+ if ( empty( $this->title ) ) {
87
+ $this->set_error(
88
+ array(
89
+ 'type' => 'missing_data',
90
+ 'data' => 'title'
91
+ )
92
+ );
93
+ }
94
+ if ( empty( $this->fields ) ) {
95
+ $this->set_error(
96
+ array(
97
+ 'type' => 'missing_data',
98
+ 'data' => 'fields'
99
+ )
100
+ );
101
+ }
102
+ if ( empty( $this->string_loading ) ) {
103
+ $this->set_error(
104
+ array(
105
+ 'type' => 'missing_data',
106
+ 'data' => 'string_loading'
107
+ )
108
+ );
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Set a value
114
+ */
115
+ public function set_value( $val = null ) {
116
+
117
+ if ( $val === null ) {
118
+ $option_group_value = get_option( $this->page );
119
+ $val = isset( $option_group_value[ $this->id ] ) ? $option_group_value[ $this->id ] : '';
120
+ }
121
+
122
+ $this->value = $this->esc_value( $val );
123
+ }
124
+
125
+ /**
126
+ * Escape the value to display it in text fields and other input fields
127
+ */
128
+ public function esc_value( $val ) {
129
+
130
+ $value = array(
131
+ 'list' => '',
132
+ 'fields' => array(),
133
+ );
134
+
135
+ if ( empty( $val ) || empty( $val['list'] ) ) {
136
+ return $value;
137
+ }
138
+
139
+ $value['list'] = esc_attr( $val['list'] );
140
+
141
+ // Escape the id/title of each merge field
142
+ foreach( $val['fields'] as $id => $val ) {
143
+ $value['fields'][$id] = esc_html( $val );
144
+ }
145
+
146
+ return $value;
147
+ }
148
+
149
+ /**
150
+ * Display this setting
151
+ */
152
+ public function display_setting() {
153
+
154
+ ?>
155
+
156
+ <span class="mcf-list-select"></span>
157
+
158
+ <span class="mcf-sap_loading">
159
+ <span class="spinner"></span>
160
+ <span><?php echo $this->string_loading; ?></span>
161
+ </span>
162
+
163
+ <?php $this->display_description(); ?>
164
+
165
+ <div id="mcfrtb-merge-controls" data-input-name="<?php echo $this->get_input_name(); ?>"></div>
166
+
167
+ <?php
168
+ }
169
+
170
+ /**
171
+ * Display a description for this setting
172
+ */
173
+ public function display_description() {
174
+
175
+ if ( !empty( $this->description ) ) : ?>
176
+
177
+ <p class="description"><?php echo $this->description; ?></p>
178
+
179
+ <?php endif;
180
+ }
181
+
182
+ /**
183
+ * Generate an option input field name, using the grouped schema.
184
+ */
185
+ public function get_input_name() {
186
+ return esc_attr( $this->page ) . '[' . esc_attr( $this->id ) . ']';
187
+ }
188
+
189
+
190
+ /**
191
+ * Sanitize the array of text inputs for this setting
192
+ */
193
+ public function sanitize_callback_wrapper( $values ) {
194
+
195
+ $output = array(
196
+ 'list' => '',
197
+ 'fields' => array(),
198
+ );
199
+
200
+ // Return an empty value if we're missing anything important
201
+ if ( !is_array( $values ) || empty( $values ) || empty( $values['list'] ) ) {
202
+ return $output;
203
+ }
204
+
205
+ // Sanitize the list
206
+ $output['list'] = sanitize_text_field( $values['list'] );
207
+
208
+ // Sanitize each merge field
209
+ $val_log = array();
210
+ foreach( $values['fields'] as $id => $val ) {
211
+
212
+ // Make sure that a merge field isn't assigned to multiple data
213
+ if ( !in_array( $val, $val_log ) ) {
214
+ $output['fields'][$id] = sanitize_text_field( $val );
215
+ }
216
+
217
+ $val_log[] = $val;
218
+ }
219
+
220
+ return $output;
221
+ }
222
+
223
+ /**
224
+ * Add and register this setting
225
+ *
226
+ * @since 1.0
227
+ */
228
+ public function add_settings_field( $section_id ) {
229
+
230
+ add_settings_field(
231
+ $this->id,
232
+ $this->title,
233
+ array( $this, 'display_setting' ),
234
+ $this->tab,
235
+ $section_id
236
+ );
237
+
238
+ }
239
+
240
+ /**
241
+ * Set an error
242
+ * @since 1.0
243
+ */
244
+ public function set_error( $error ) {
245
+ $this->errors[] = array_merge(
246
+ $error,
247
+ array(
248
+ 'class' => get_class( $this ),
249
+ 'id' => $this->id,
250
+ 'backtrace' => debug_backtrace()
251
+ )
252
+ );
253
+ }
254
+
255
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Number.class.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a text field setting in the admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingNumber_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ public $sanitize_callback = 'sanitize_text_field';
13
+
14
+ /**
15
+ * Placeholder string for the input field
16
+ * @since 2.0
17
+ */
18
+ public $placeholder = '';
19
+
20
+ /**
21
+ * Display this setting
22
+ * @since 1.0
23
+ */
24
+ public function display_setting() {
25
+ ?>
26
+
27
+ <input name="<?php echo $this->get_input_name(); ?>" type="number" id="<?php echo $this->get_input_name(); ?>" value="<?php echo $this->value; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text" <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
28
+
29
+ <?php $this->display_disabled(); ?>
30
+
31
+ <?php
32
+
33
+ $this->display_description();
34
+
35
+ }
36
+
37
+ }
lib/simple-admin-pages/classes/AdminPageSetting.OpeningHours.class.php CHANGED
@@ -1,182 +1,182 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a series of fields to specify the opening hours
5
- * of a business/company.
6
- *
7
- * This setting accepts the following arguments in its constructor function.
8
- *
9
- * $args = array(
10
- * 'id' => 'setting_id', // Unique id
11
- * 'title' => 'My Setting', // Title or label for the setting
12
- * 'description' => 'Description', // Help text description
13
- * 'weekday_names' => array( // Optional array of custom
14
- * 'monday' => 'Monday', // weekday names. These can be
15
- * 'tuesday' => 'Tuesday', // passed in any order to
16
- * 'wednesday' => 'Wednesday', // set a new start of the week.
17
- * 'thursday' => 'Thursday',
18
- * 'friday' => 'Friday',
19
- * 'saturday' => 'Saturday',
20
- * 'sunday' => 'Sunday'
21
- * );
22
- * );
23
- *
24
- * @since 1.0
25
- * @package Simple Admin Pages
26
- */
27
-
28
- class sapAdminPageSettingOpeningHours_2_1_2 extends sapAdminPageSetting_2_1_2 {
29
-
30
- public $sanitize_callback = 'sanitize_text_field';
31
-
32
- /**
33
- * Scripts that must be loaded for this component
34
- * @since 2.0.a.4
35
- */
36
- public $scripts = array(
37
- 'sap-opening-hours' => array(
38
- 'path' => 'js/opening-hours.js',
39
- 'dependencies' => array( 'jquery' ),
40
- 'version' => '2.0.a.5',
41
- 'footer' => true,
42
- ),
43
- );
44
-
45
- // Array of days of the week
46
- public $weekdays = array(
47
- 'monday' => 'Monday',
48
- 'tuesday' => 'Tuesday',
49
- 'wednesday' => 'Wednesday',
50
- 'thursday' => 'Thursday',
51
- 'friday' => 'Friday',
52
- 'saturday' => 'Saturday',
53
- 'sunday' => 'Sunday'
54
- );
55
-
56
- /**
57
- * Parse the arguments passed in the construction and assign them to
58
- * internal variables.
59
- * @since 1.0
60
- */
61
- private function parse_args( $args ) {
62
- foreach ( $args as $key => $val ) {
63
- switch ( $key ) {
64
-
65
- case 'id' :
66
- $this->{$key} = esc_attr( $val );
67
-
68
- case 'weekdays' :
69
-
70
- $this->weekdays = $val;
71
-
72
- default :
73
- $this->{$key} = $val;
74
-
75
- }
76
- }
77
- }
78
-
79
- /**
80
- * Escape the value to display it in text fields and other input fields
81
- *
82
- * @since 1.0
83
- */
84
- public function esc_value( $val ) {
85
-
86
- $value = array();
87
-
88
- // Loop over the values and sanitize them
89
- for ( $i = 0; $i < 7; $i++ ) {
90
- $value[$i]['day'] = isset( $val[$i] ) && isset( $val[$i]['day'] ) ? esc_attr( $val[$i]['day'] ) : '';
91
- $value[$i]['hours'] = isset( $val[$i] ) && isset( $val[$i]['hours'] ) ? esc_attr( $val[$i]['hours'] ) : '';
92
- }
93
-
94
- return $value;
95
- }
96
-
97
- /**
98
- * Get a day's display name
99
- * @since 1.0
100
- */
101
- private function get_day_name( $day ) {
102
- foreach ( $this->weekdays as $id => $name ) {
103
- if ( $day == $id ) {
104
- return $name;
105
- }
106
- }
107
-
108
- return '';
109
- }
110
-
111
- /**
112
- * Display this setting
113
- * @since 1.0
114
- * @todo integrate time picker
115
- */
116
- public function display_setting() {
117
-
118
- $this->display_description();
119
-
120
- for ($i = 0; $i < 7; $i++) {
121
-
122
- ?>
123
-
124
- <table class="sap-opening-hours <?php echo ( $this->disabled ? 'disabled' : ''); ?>">
125
- <tr>
126
- <td>
127
- <input type="hidden" id="sap-opening-hours-day-<?php echo $i; ?>-name" name="<?php echo $this->get_input_name(); ?>[<?php echo $i; ?>][day_name]" value="<?php echo esc_attr( $this->get_day_name( $this->value[$i]['day'] ) ); ?>">
128
- <select name="<?php echo $this->get_input_name(); ?>[<?php echo $i; ?>][day]" id="<?php echo $this->id . '-' . $i; ?>-day" class="sap-opening-hours-day" data-target="#sap-opening-hours-day-<?php echo $i; ?>-name">
129
- <option value=""></option>
130
-
131
- <?php foreach ( $this->weekdays as $id => $name ) : ?>
132
-
133
- <option value="<?php echo $id; ?>" data-name="<?php echo esc_attr( $name ); ?>"<?php if ( $this->value[$i]['day'] == $id ) : ?> selected<?php endif; ?>>
134
- <?php echo $name; ?>
135
- </option>
136
-
137
- <?php endforeach; ?>
138
-
139
- </select>
140
- </td>
141
- <td>
142
- <input name="<?php echo $this->get_input_name(); ?>[<?php echo $i; ?>][hours]" type="text" id="<?php echo $this->id . '-' . $i; ?>-hours" value="<?php echo $this->value[$i]['hours']; ?>" class="regular-text sap-opening-hours-hours" />
143
- </td>
144
- </tr>
145
- </table>
146
-
147
- <?php $this->display_disabled(); ?>
148
-
149
- <?php
150
-
151
- }
152
-
153
- }
154
-
155
- /**
156
- * Sanitize the array of text inputs for this setting
157
- * @since 1.0
158
- */
159
- public function sanitize_callback_wrapper( $values ) {
160
-
161
- // If no sanitization callback exists, don't register the setting.
162
- if ( !isset( $this->sanitize_callback ) || !trim( $this->sanitize_callback ) ) {
163
- return;
164
- }
165
-
166
- // If this isn't an array, just sanitize it as a string
167
- if (!is_array( $values ) ) {
168
- return call_user_func( $this->sanitize_callback, $values );
169
- }
170
-
171
- // Loop over the values and sanitize them
172
- for ( $i = 0; $i < 7; $i++ ) {
173
- if ( isset( $values[ $i ] ) && is_array( $values[ $i ] ) ) {
174
- $values[$i]['day'] = call_user_func( $this->sanitize_callback, $values[$i]['day'] );
175
- $values[$i]['hours'] = call_user_func( $this->sanitize_callback, $values[$i]['hours'] );
176
- }
177
- }
178
-
179
- return $values;
180
- }
181
-
182
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a series of fields to specify the opening hours
5
+ * of a business/company.
6
+ *
7
+ * This setting accepts the following arguments in its constructor function.
8
+ *
9
+ * $args = array(
10
+ * 'id' => 'setting_id', // Unique id
11
+ * 'title' => 'My Setting', // Title or label for the setting
12
+ * 'description' => 'Description', // Help text description
13
+ * 'weekday_names' => array( // Optional array of custom
14
+ * 'monday' => 'Monday', // weekday names. These can be
15
+ * 'tuesday' => 'Tuesday', // passed in any order to
16
+ * 'wednesday' => 'Wednesday', // set a new start of the week.
17
+ * 'thursday' => 'Thursday',
18
+ * 'friday' => 'Friday',
19
+ * 'saturday' => 'Saturday',
20
+ * 'sunday' => 'Sunday'
21
+ * );
22
+ * );
23
+ *
24
+ * @since 1.0
25
+ * @package Simple Admin Pages
26
+ */
27
+
28
+ class sapAdminPageSettingOpeningHours_2_5_5 extends sapAdminPageSetting_2_5_5 {
29
+
30
+ public $sanitize_callback = 'sanitize_text_field';
31
+
32
+ /**
33
+ * Scripts that must be loaded for this component
34
+ * @since 2.0.a.4
35
+ */
36
+ public $scripts = array(
37
+ 'sap-opening-hours' => array(
38
+ 'path' => 'js/opening-hours.js',
39
+ 'dependencies' => array( 'jquery' ),
40
+ 'version' => SAP_VERSION,
41
+ 'footer' => true,
42
+ ),
43
+ );
44
+
45
+ // Array of days of the week
46
+ public $weekdays = array(
47
+ 'monday' => 'Monday',
48
+ 'tuesday' => 'Tuesday',
49
+ 'wednesday' => 'Wednesday',
50
+ 'thursday' => 'Thursday',
51
+ 'friday' => 'Friday',
52
+ 'saturday' => 'Saturday',
53
+ 'sunday' => 'Sunday'
54
+ );
55
+
56
+ /**
57
+ * Parse the arguments passed in the construction and assign them to
58
+ * internal variables.
59
+ * @since 1.0
60
+ */
61
+ private function parse_args( $args ) {
62
+ foreach ( $args as $key => $val ) {
63
+ switch ( $key ) {
64
+
65
+ case 'id' :
66
+ $this->{$key} = esc_attr( $val );
67
+
68
+ case 'weekdays' :
69
+
70
+ $this->weekdays = $val;
71
+
72
+ default :
73
+ $this->{$key} = $val;
74
+
75
+ }
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Escape the value to display it in text fields and other input fields
81
+ *
82
+ * @since 1.0
83
+ */
84
+ public function esc_value( $val ) {
85
+
86
+ $value = array();
87
+
88
+ // Loop over the values and sanitize them
89
+ for ( $i = 0; $i < 7; $i++ ) {
90
+ $value[$i]['day'] = isset( $val[$i] ) && isset( $val[$i]['day'] ) ? esc_attr( $val[$i]['day'] ) : '';
91
+ $value[$i]['hours'] = isset( $val[$i] ) && isset( $val[$i]['hours'] ) ? esc_attr( $val[$i]['hours'] ) : '';
92
+ }
93
+
94
+ return $value;
95
+ }
96
+
97
+ /**
98
+ * Get a day's display name
99
+ * @since 1.0
100
+ */
101
+ private function get_day_name( $day ) {
102
+ foreach ( $this->weekdays as $id => $name ) {
103
+ if ( $day == $id ) {
104
+ return $name;
105
+ }
106
+ }
107
+
108
+ return '';
109
+ }
110
+
111
+ /**
112
+ * Display this setting
113
+ * @since 1.0
114
+ * @todo integrate time picker
115
+ */
116
+ public function display_setting() {
117
+
118
+ $this->display_description();
119
+
120
+ for ($i = 0; $i < 7; $i++) {
121
+
122
+ ?>
123
+
124
+ <table class="sap-opening-hours <?php echo ( $this->disabled ? 'disabled' : ''); ?>">
125
+ <tr>
126
+ <td>
127
+ <input type="hidden" id="sap-opening-hours-day-<?php echo $i; ?>-name" name="<?php echo $this->get_input_name(); ?>[<?php echo $i; ?>][day_name]" value="<?php echo esc_attr( $this->get_day_name( $this->value[$i]['day'] ) ); ?>">
128
+ <select name="<?php echo $this->get_input_name(); ?>[<?php echo $i; ?>][day]" id="<?php echo $this->id . '-' . $i; ?>-day" class="sap-opening-hours-day" data-target="#sap-opening-hours-day-<?php echo $i; ?>-name">
129
+ <option value=""></option>
130
+
131
+ <?php foreach ( $this->weekdays as $id => $name ) : ?>
132
+
133
+ <option value="<?php echo $id; ?>" data-name="<?php echo esc_attr( $name ); ?>"<?php if ( $this->value[$i]['day'] == $id ) : ?> selected<?php endif; ?>>
134
+ <?php echo $name; ?>
135
+ </option>
136
+
137
+ <?php endforeach; ?>
138
+
139
+ </select>
140
+ </td>
141
+ <td>
142
+ <input name="<?php echo $this->get_input_name(); ?>[<?php echo $i; ?>][hours]" type="text" id="<?php echo $this->id . '-' . $i; ?>-hours" value="<?php echo $this->value[$i]['hours']; ?>" class="regular-text sap-opening-hours-hours" />
143
+ </td>
144
+ </tr>
145
+ </table>
146
+
147
+ <?php $this->display_disabled(); ?>
148
+
149
+ <?php
150
+
151
+ }
152
+
153
+ }
154
+
155
+ /**
156
+ * Sanitize the array of text inputs for this setting
157
+ * @since 1.0
158
+ */
159
+ public function sanitize_callback_wrapper( $values ) {
160
+
161
+ // If no sanitization callback exists, don't register the setting.
162
+ if ( !isset( $this->sanitize_callback ) || !trim( $this->sanitize_callback ) ) {
163
+ return;
164
+ }
165
+
166
+ // If this isn't an array, just sanitize it as a string
167
+ if (!is_array( $values ) ) {
168
+ return call_user_func( $this->sanitize_callback, $values );
169
+ }
170
+
171
+ // Loop over the values and sanitize them
172
+ for ( $i = 0; $i < 7; $i++ ) {
173
+ if ( isset( $values[ $i ] ) && is_array( $values[ $i ] ) ) {
174
+ $values[$i]['day'] = call_user_func( $this->sanitize_callback, $values[$i]['day'] );
175
+ $values[$i]['hours'] = call_user_func( $this->sanitize_callback, $values[$i]['hours'] );
176
+ }
177
+ }
178
+
179
+ return $values;
180
+ }
181
+
182
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Ordering.class.php ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register and display a table for saving the order of a list of items.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'items' => array(
13
+ * 'item' => 'Label' // The items to be re-ordered
14
+ * )
15
+ * );
16
+ *
17
+ * @since 2.5
18
+ * @package Simple Admin Pages
19
+ */
20
+
21
+ class sapAdminPageSettingOrdering_2_5_5 extends sapAdminPageSetting_2_5_5 {
22
+
23
+ public $sanitize_callback = 'sanitize_text_field';
24
+
25
+ /**
26
+ * Add in the JS requried for the values to be stored
27
+ * @since 2.5
28
+ */
29
+ public $scripts = array(
30
+ 'sap-ordering-table' => array(
31
+ 'path' => 'js/ordering.js',
32
+ 'dependencies' => array( 'jquery' ),
33
+ 'version' => SAP_VERSION,
34
+ 'footer' => true,
35
+ ),
36
+ );
37
+
38
+ /**
39
+ * Add in the CSS requried for rows to be displayed correctly
40
+ * @since 2.5
41
+ */
42
+ public $styles = array(
43
+ 'sap-ordering-table' => array(
44
+ 'path' => 'css/ordering.css',
45
+ 'dependencies' => array( ),
46
+ 'version' => SAP_VERSION,
47
+ 'media' => 'all',
48
+ ),
49
+ );
50
+
51
+ /**
52
+ * Display this setting
53
+ * @since 2.0
54
+ */
55
+ public function display_setting() {
56
+
57
+ $input_name = $this->get_input_name();
58
+ $values = is_array( $this->value ) ? $this->value : json_decode( html_entity_decode( $this->value ), true );
59
+
60
+ if ( ! is_array( $values ) )
61
+ $values = array();
62
+
63
+ if ( empty( $values ) and is_string( $this->items ) )
64
+ $values = array_merge( $values, json_decode( $this->items, true ) );
65
+
66
+ ?>
67
+
68
+ <fieldset>
69
+ <div class='sap-ordering-table <?php echo ( $this->disabled ? 'disabled' : ''); ?>'>
70
+ <input type='hidden' id="sap-ordering-table-main-input" name='<?php echo $input_name; ?>' value='<?php echo esc_attr( json_encode( $values ) ); ?>' />
71
+ <table>
72
+ <tbody>
73
+ <?php foreach ( $values as $value => $label ) { ?>
74
+ <tr class='sap-ordering-table-row'>
75
+ <td>
76
+ <input type='hidden' value='<?php echo esc_attr( $value ); ?>' />
77
+ <span><?php echo esc_html( $label ); ?></span>
78
+ </td>
79
+ </tr>
80
+ <?php } ?>
81
+ </tbody>
82
+ </table>
83
+ </div>
84
+
85
+ <?php $this->display_disabled(); ?>
86
+ </fieldset>
87
+
88
+ <?php
89
+
90
+ $this->display_description();
91
+
92
+ }
93
+
94
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Radio.class.php CHANGED
@@ -1,52 +1,53 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an option with radio buttons.
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'options' => array(
13
- * 'value' => 'Name'
14
- * ), // The radio buttons values and text
15
- * );
16
- * );
17
- *
18
- * @since 2.0
19
- * @package Simple Admin Pages
20
- */
21
-
22
- class sapAdminPageSettingRadio_2_1_2 extends sapAdminPageSetting_2_1_2 {
23
-
24
- public $sanitize_callback = 'sanitize_text_field';
25
-
26
- /**
27
- * Display this setting
28
- * @since 2.0
29
- */
30
- public function display_setting() {
31
-
32
- $input_name = $this->get_input_name();
33
-
34
- ?>
35
- <fieldset>
36
- <?php foreach ( $this->options as $id => $title ) : ?>
37
- <label title="<?php echo $title; ?>" class="bpfwp-admin-input-container">
38
- <input type="radio" name="<?php echo $input_name; ?>" id="<?php echo $input_name . "-" . $id; ?>" value="<?php echo $id; ?>" <?php echo ( $id == $this->value ? 'checked="checked"' : '' ) ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
39
- <span class='bpfwp-admin-radio-button'></span> <span><?php echo $title; ?></span>
40
- </label>
41
- <br />
42
- <?php endforeach; ?>
43
-
44
- <?php $this->display_disabled(); ?>
45
- </fieldset>
46
- <?php
47
-
48
- $this->display_description();
49
-
50
- }
51
-
52
- }
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an option with radio buttons.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'options' => array(
13
+ * 'value' => 'Name'
14
+ * ), // The radio buttons values and text
15
+ * );
16
+ * );
17
+ *
18
+ * @since 2.0
19
+ * @package Simple Admin Pages
20
+ */
21
+
22
+ class sapAdminPageSettingRadio_2_5_5 extends sapAdminPageSetting_2_5_5 {
23
+
24
+ public $sanitize_callback = 'sanitize_text_field';
25
+
26
+ /**
27
+ * Display this setting
28
+ * @since 2.0
29
+ */
30
+ public function display_setting() {
31
+
32
+ $input_name = $this->get_input_name();
33
+
34
+ if ( empty( $this->value ) ) { $this->value = $this->get_default_setting(); }
35
+
36
+ ?>
37
+ <fieldset <?php echo ( isset( $this->columns ) ? 'class="sap-setting-columns-' . $this->columns . '"' : '' ); ?>>
38
+ <?php foreach ( $this->options as $id => $title ) : ?>
39
+ <label title="<?php echo ( strpos( $title, '<' ) === false ? $title : ''); ?>" class="sap-admin-input-container">
40
+ <input type="radio" name="<?php echo $input_name; ?>" id="<?php echo $input_name . "-" . $id; ?>" value="<?php echo $id; ?>" <?php echo ( $id == $this->value ? 'checked="checked"' : '' ) ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
41
+ <span class='sap-admin-radio-button'></span> <span><?php echo $title; ?></span>
42
+ </label>
43
+ <?php endforeach; ?>
44
+
45
+ <?php $this->display_disabled(); ?>
46
+ </fieldset>
47
+ <?php
48
+
49
+ $this->display_description();
50
+
51
+ }
52
+
53
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Scheduler.class.php CHANGED
@@ -1,703 +1,703 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a schedule of dates and times.
5
- *
6
- * This is designed for use for opening hours, a booking schedule or anything
7
- * that requires recurring dates and times.
8
- *
9
- * @since 2.0
10
- * @package Simple Admin Pages
11
- */
12
-
13
- class sapAdminPageSettingScheduler_2_1_2 extends sapAdminPageSetting_2_1_2 {
14
-
15
- public $sanitize_callback = 'sanitize_text_field';
16
-
17
- /**
18
- * Scripts that must be loaded for this component
19
- * @since 2.0.a.4
20
- */
21
- public $scripts = array(
22
- 'pickadate' => array(
23
- 'path' => 'lib/pickadate/picker.js',
24
- 'dependencies' => array( 'jquery' ),
25
- 'version' => '3.5.5',
26
- 'footer' => true,
27
- ),
28
- 'pickadate-date' => array(
29
- 'path' => 'lib/pickadate/picker.date.js',
30
- 'dependencies' => array( 'jquery' ),
31
- 'version' => '3.5.5',
32
- 'footer' => true,
33
- ),
34
- 'pickadate-time' => array(
35
- 'path' => 'lib/pickadate/picker.time.js',
36
- 'dependencies' => array( 'jquery' ),
37
- 'version' => '3.5.5',
38
- 'footer' => true,
39
- ),
40
- 'pickadate-legacy' => array(
41
- 'path' => 'lib/pickadate/legacy.js',
42
- 'dependencies' => array( 'jquery' ),
43
- 'version' => '3.5.5',
44
- 'footer' => true,
45
- ),
46
- 'sap-scheduler' => array(
47
- 'path' => 'js/scheduler.js',
48
- 'dependencies' => array( 'jquery' ),
49
- 'version' => '2.0.a.9',
50
- 'footer' => true,
51
- ),
52
- // @todo there should be some way to load alternate language .js files
53
- // and RTL CSS scripts
54
- );
55
-
56
- /**
57
- * Styles that must be loaded for this component
58
- * @since 2.0.a.4
59
- */
60
- public $styles = array(
61
- 'pickadate-default' => array(
62
- 'path' => 'lib/pickadate/themes/default.css',
63
- 'dependencies' => '',
64
- 'version' => '3.5.0',
65
- 'media' => null,
66
- ),
67
- 'pickadate-date' => array(
68
- 'path' => 'lib/pickadate/themes/default.date.css',
69
- 'dependencies' => '',
70
- 'version' => '3.5.0',
71
- 'media' => null,
72
- ),
73
- 'pickadate-time' => array(
74
- 'path' => 'lib/pickadate/themes/default.time.css',
75
- 'dependencies' => '',
76
- 'version' => '3.5.0',
77
- 'media' => null,
78
- ),
79
- );
80
-
81
- /**
82
- * Used for data storage. Not translated
83
- */
84
- public $weekdays = array(
85
- 'monday' => 'Mo',
86
- 'tuesday' => 'Tu',
87
- 'wednesday' => 'We',
88
- 'thursday' => 'Th',
89
- 'friday' => 'Fr',
90
- 'saturday' => 'Sa',
91
- 'sunday' => 'Su',
92
- );
93
-
94
- /**
95
- * Used for data storage. Not translated
96
- */
97
- public $weeks = array(
98
- 'first' => '1st',
99
- 'second' => '2nd',
100
- 'third' => '3rd',
101
- 'fourth' => '4th',
102
- 'last' => 'last',
103
- );
104
-
105
- /**
106
- * Translateable strings required for this component
107
- * @since 2.0.a.8
108
- */
109
- public $strings = array(
110
- 'add_rule' => null, // __( 'Add new scheduling rule', 'textdomain' ),
111
- 'weekly' => null, // _x( 'Weekly', 'Format of a scheduling rule', 'textdomain' ),
112
- 'monthly' => null, // _x( 'Monthly', 'Format of a scheduling rule', 'textdomain' ),
113
- 'date' => null, // _x( 'Date', 'Format of a scheduling rule', 'textdomain' ),
114
- 'weekdays' => null, // _x( 'Days of the week', 'Label for selecting days of the week in a scheduling rule', 'textdomain' ),
115
- 'month_weeks' => null, // _x( 'Weeks of the month', 'Label for selecting weeks of the month in a scheduling rule', 'textdomain' ),
116
- 'date_label' => null, // _x( 'Date', 'Label to select a date for a scheduling rule', 'textdomain' ),
117
- 'time_label' => null, // _x( 'Time', 'Label to select a time slot for a scheduling rule', 'textdomain' ),
118
- 'allday' => null, // _x( 'All day', 'Label to set a scheduling rule to last all day', 'textdomain' ),
119
- 'start' => null, // _x( 'Start', 'Label for the starting time of a scheduling rule', 'textdomain' ),
120
- 'end' => null, // _x( 'End', 'Label for the ending time of a scheduling rule', 'textdomain' ),
121
- 'set_time_prompt' => null, // _x( 'All day long. Want to %sset a time slot%s?', 'Prompt displayed when a scheduling rule is set without any time restrictions', 'textdomain' ),
122
- 'toggle' => null, // _x( 'Open and close this rule', 'Toggle a scheduling rule open and closed', 'textdomain' ),
123
- 'delete' => null, // _x( 'Delete rule', 'Delete a scheduling rule', 'textdomain' ),
124
- 'delete_schedule' => null, // __( 'Delete scheduling rule', 'textdomain' ),
125
- 'never' => null, // _x( 'Never', 'Brief default description of a scheduling rule when no weekdays or weeks are included in the rule', 'textdomain' ),
126
- 'weekly_always' => null, // _x( 'Every day', 'Brief default description of a scheduling rule when all the weekdays/weeks are included in the rule', 'textdomain' ),
127
- 'monthly_weekdays' => null, // _x( '%s on the %s week of the month', 'Brief default description of a scheduling rule when some weekdays are included on only some weeks of the month. %s should be left alone and will be replaced by a comma-separated list of days and weeks in the following format: M, T, W on the first, second week of the month', 'textdomain' ),
128
- 'monthly_weeks' => null, // _x( '%s week of the month', 'Brief default description of a scheduling rule when some weeks of the month are included but all or no weekdays are selected. %s should be left alone and will be replaced by a comma-separated list of weeks in the following format: First, second week of the month', 'textdomain' ),
129
- 'all_day' => null, // _x( 'All day', 'Brief default description of a scheduling rule when no times are set', 'textdomain' ),
130
- 'before' => null, // _x( 'Ends at', 'Brief default description of a scheduling rule when an end time is set but no start time. If the end time is 6pm, it will read: Ends at 6pm', 'textdomain' ),
131
- 'after' => null, // _x( 'Starts at', 'Brief default description of a scheduling rule when a start time is set but no end time. If the start time is 6pm, it will read: Starts at 6pm', 'textdomain' ),
132
- 'separator' => null, // _x( '&mdash;', 'Separator between times of a scheduling rule', 'textdomain' ),
133
- );
134
-
135
- /**
136
- * Number of minutes between time selection intervals
137
- */
138
- public $time_interval = 15;
139
-
140
- /**
141
- * Display format for time selection
142
- * See http://amsul.ca/pickadate.js/ for formatting options
143
- */
144
- public $time_format = 'h:i A';
145
-
146
- /**
147
- * Display format for date selection
148
- * See http://amsul.ca/pickadate.js/ for formatting options
149
- */
150
- public $date_format = 'd mmmm, yyyy';
151
-
152
- /**
153
- * Boolean to disable the weekday selection option
154
- */
155
- public $disable_weekdays = false;
156
-
157
- /**
158
- * Boolean to disable the weeks selection option
159
- */
160
- public $disable_weeks = false;
161
-
162
- /**
163
- * Boolean to disable the date selection option
164
- */
165
- public $disable_date = false;
166
-
167
- /**
168
- * Boolean to disable the time selection option
169
- */
170
- public $disable_time = false;
171
-
172
- /**
173
- * Boolean to disable the end time selection option
174
- */
175
- public $disable_end_time = false;
176
-
177
- /**
178
- * Boolean to disable multiple rules per component
179
- */
180
- public $disable_multiple = false;
181
-
182
- /**
183
- * Escape the value to display it in text fields and other input fields
184
- * @since 2.0
185
- */
186
- public function esc_value( $val ) {
187
-
188
- $value = array();
189
-
190
- if ( empty( $val ) ) {
191
- return $value;
192
- }
193
-
194
- foreach ( $val as $i => $rule ) {
195
-
196
- if ( !empty( $rule['weekdays'] ) ) {
197
- $value[$i]['weekdays'] = array();
198
- foreach ( $rule['weekdays'] as $day => $flag ) {
199
- if ( $flag !== '1' ) {
200
- continue;
201
- }
202
-
203
- $value[$i]['weekdays'][$day] = $flag;
204
- }
205
- }
206
-
207
- if ( !empty( $rule['weeks'] ) ) {
208
- $value[$i]['weeks'] = array();
209
- foreach ( $rule['weeks'] as $week => $flag ) {
210
- if ( $flag !== '1' ) {
211
- continue;
212
- }
213
-
214
- $value[$i]['weeks'][$week] = $flag;
215
- }
216
- }
217
-
218
- if ( !empty( $rule['date'] ) ) {
219
- $value[$i]['date'] = esc_attr( $rule['date'] );
220
- }
221
-
222
- if ( !empty( $rule['time']['start'] ) ) {
223
- $value[$i]['time']['start'] = esc_attr( $rule['time']['start'] );
224
- }
225
- if ( !empty( $rule['time']['end'] ) ) {
226
- $value[$i]['time']['end'] = esc_attr( $rule['time']['end'] );
227
- }
228
- }
229
-
230
- return $value;
231
- }
232
-
233
- /**
234
- * Compile and pass configurable variables to the javascript file, so they
235
- * can be used when we initialize the pickadate components
236
- * @since 2.0
237
- */
238
- public function pass_to_scripts() {
239
-
240
- // Create a global variable containing settings for all schedulers
241
- // that are being rendered on the page. This allows us to pass different
242
- // settings for different schedulers on the same page.
243
- global $sap_scheduler_settings;
244
-
245
- if ( !isset( $sap_scheduler_settings ) ) {
246
- $sap_scheduler_settings = array();
247
- }
248
-
249
- $sap_scheduler_settings[ $this->id ] = array(
250
- 'time_interval' => $this->time_interval,
251
- 'time_format' => $this->time_format,
252
- 'date_format' => $this->date_format,
253
- 'template' => $this->get_template(),
254
- 'weekdays' => $this->weekdays,
255
- 'weeks' => $this->weeks,
256
- 'disable_weekdays' => $this->disable_weekdays,
257
- 'disable_weeks' => $this->disable_weeks,
258
- 'disable_date' => $this->disable_date,
259
- 'disable_time' => $this->disable_time,
260
- 'disable_multiple' => $this->disable_multiple,
261
- 'summaries' => $this->schedule_summaries,
262
- );
263
-
264
- // This gets called multiple times, but only the last call is actually
265
- // pushed to the script.
266
- wp_localize_script(
267
- 'sap-scheduler',
268
- 'sap_scheduler',
269
- array(
270
- 'settings' => $sap_scheduler_settings
271
- )
272
- );
273
-
274
- }
275
-
276
- /**
277
- * Display this setting
278
- * @since 2.0
279
- */
280
- public function display_setting() {
281
-
282
- $this->display_description();
283
-
284
- // Define summary text to use when a rule is displayed in brief
285
- $this->set_schedule_summaries();
286
-
287
- // Pass data to the script files to handle js interactions
288
- $this->pass_to_scripts();
289
-
290
- ?>
291
-
292
- <div class="sap-scheduler <?php echo ( $this->disabled ? 'disabled' : ''); ?>" id="<?php echo $this->id; ?>">
293
- <?php
294
- foreach ( $this->value as $id => $rule ) {
295
- echo $this->get_template( $id, $rule, true );
296
- }
297
- ?>
298
- </div>
299
-
300
- <div class="sap-add-scheduler<?php if ( $this->disable_multiple && count( $this->value ) ) : ?> disabled<?php endif; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>">
301
- <a href="#" class="button">
302
- <?php echo $this->strings['add_rule']; ?>
303
- </a>
304
- </div>
305
-
306
- <?php $this->display_disabled(); ?>
307
-
308
- <?php
309
- }
310
-
311
- /**
312
- * Retrieve the template for a scheduling rule
313
- * @since 2.0
314
- */
315
- public function get_template( $id = 0, $values = array(), $list = false ) {
316
-
317
- $date_format = $this->get_date_format( $values );
318
- $time_format = $this->get_time_format( $values );
319
-
320
- ob_start();
321
- ?>
322
-
323
- <div class="sap-scheduler-rule clearfix<?php echo $list ? ' list' : ''; ?>">
324
- <div class="sap-scheduler-date <?php echo $date_format; echo $this->disable_time === true ? ' full-width' : ''; ?>">
325
- <ul class="sap-selector">
326
-
327
- <?php if ( !$this->has_multiple_date_formats() ) : ?>
328
- <li>
329
- <div class="dashicons dashicons-calendar"></div>
330
- <?php if ( $date_format == 'weekly' ) : ?>
331
- <?php echo $this->strings['weekly']; ?>
332
- <?php elseif ( $date_format == 'monthly' ) : ?>
333
- <?php echo $this->strings['monthly']; ?>
334
- <?php elseif ( $date_format == 'date' ) : ?>
335
- <?php echo $this->strings['date']; ?>
336
- <?php endif; ?>
337
- </li>
338
- <?php else : ?>
339
-
340
- <?php if ( $this->disable_weekdays === false ) : ?>
341
- <li>
342
- <div class="dashicons dashicons-calendar"></div>
343
- <a href="#" data-format="weekly"<?php echo $date_format == 'weekly' ? ' class="selected"' : ''; ?>>
344
- <?php echo $this->strings['weekly']; ?>
345
- </a>
346
- </li>
347
- <?php endif; ?>
348
-
349
- <?php if ( $this->disable_weeks === false ) : ?>
350
- <li>
351
- <a href="#" data-format="monthly"<?php echo $date_format == 'monthly' ? ' class="selected"' : ''; ?>>
352
- <?php echo $this->strings['monthly']; ?>
353
- </a>
354
- </li>
355
- <?php endif; ?>
356
-
357
- <?php if ( $this->disable_date === false ) : ?>
358
- <li>
359
- <a href="#" data-format="date"<?php echo $date_format == 'date' ? ' class="selected"' : ''; ?>>
360
- <?php echo $this->strings['date']; ?>
361
- </a>
362
- </li>
363
- <?php endif; ?>
364
-
365
- <?php endif; ?>
366
- </ul>
367
-
368
- <?php if ( $this->disable_weekdays === false ) : ?>
369
- <ul class="sap-scheduler-weekdays">
370
- <li class="label">
371
- <?php echo $this->strings['weekdays']; ?>
372
- </li>
373
- <?php
374
- foreach ( $this->weekdays as $slug => $label ) :
375
- $input_name = $this->get_input_name() . '[' . $id . '][weekdays][' . esc_attr( $slug ) . ']';
376
- ?>
377
- <li>
378
- &nbsp;<input type="checkbox" name="<?php echo $input_name; ?>" id="<?php echo $input_name; ?>" value="1"<?php echo empty( $values['weekdays'][$slug] ) ? '' : ' checked="checked"'; ?> data-day="<?php echo esc_attr( $slug ); ?>"><label for="<?php echo $input_name; ?>"><?php echo ucfirst( $label ); ?></label>
379
- </li>
380
- <?php endforeach; ?>
381
- </ul>
382
- <?php endif; ?>
383
-
384
- <?php if ( $this->disable_weeks === false ) : ?>
385
- <ul class="sap-scheduler-weeks">
386
- <li class="label">
387
- <?php echo $this->strings['month_weeks']; ?>
388
- </li>
389
- <?php
390
- foreach ( $this->weeks as $slug => $label ) :
391
- $input_name = $this->get_input_name() . '[' . $id . '][weeks][' . esc_attr( $slug ) . ']';
392
- ?>
393
- <li>
394
- &nbsp;<input type="checkbox" name="<?php echo $input_name; ?>" id="<?php echo $input_name; ?>" value="1"<?php echo empty( $values['weeks'][$slug] ) ? '' : ' checked="checked"'; ?> data-week="<?php echo esc_attr( $slug ); ?>"><label for="<?php echo $input_name; ?>"><?php echo ucfirst( $label ); ?></label>
395
- </li>
396
- <?php endforeach; ?>
397
- </ul>
398
- <?php endif; ?>
399
-
400
- <?php if ( $this->disable_date === false ) : ?>
401
- <div class="sap-scheduler-date-input">
402
- <label for="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][date]">
403
- <?php echo $this->strings['date_label']; ?>
404
- </label>
405
- <input type="text" name="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][date]" id="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][date]" value="<?php echo empty( $values['date'] ) ? '' : $values['date']; ?>">
406
- </div>
407
- <?php endif; ?>
408
-
409
- </div>
410
-
411
- <?php if ( $this->disable_time === false ) : ?>
412
- <div class="sap-scheduler-time <?php echo $time_format; ?>">
413
-
414
- <ul class="sap-selector">
415
- <li>
416
- <div class="dashicons dashicons-clock"></div>
417
- <a href="#" data-format="time-slot"<?php echo $time_format == 'time-slot' ? ' class="selected"' : ''; ?>>
418
- <?php echo $this->strings['time_label']; ?>
419
- </a>
420
- </li>
421
- <li>
422
- <a href="#" data-format="all-day"<?php echo $time_format == 'all-day' ? ' class="selected"' : ''; ?>>
423
- <?php echo $this->strings['allday']; ?>
424
- </a>
425
- </li>
426
- </ul>
427
-
428
- <div class="sap-scheduler-time-input clearfix">
429
-
430
- <div class="start">
431
- <label for="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][time][start]">
432
- <?php echo $this->strings['start']; ?>
433
- </label>
434
- <input type="text" name="<?php echo $this->get_input_name() . '[' . $id . '][time][start]'; ?>" id="<?php echo $this->get_input_name() . '[' . $id . '][time][start]'; ?>" value="<?php echo empty( $values['time']['start'] ) ? '' : $values['time']['start']; ?>">
435
- </div>
436
-
437
- <?php if ( $this->disable_end_time === false ) : ?>
438
- <div class="end">
439
- <label for="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][time][end]">
440
- <?php echo $this->strings['end']; ?>
441
- </label>
442
- <input type="text" name="<?php echo $this->get_input_name() . '[' . $id . '][time][end]'; ?>" id="<?php echo $this->get_input_name() . '[' . $id . '][time][end]'; ?>" value="<?php echo empty( $values['time']['end'] ) ? '' : $values['time']['end']; ?>">
443
- </div>
444
- <?php endif; ?>
445
-
446
- </div>
447
-
448
- <div class="sap-scheduler-all-day">
449
- <?php printf( $this->strings['set_time_prompt'], '<a href="#" data-format="time-slot">', '</a>' ); ?>
450
- </div>
451
-
452
- </div>
453
- <?php endif; ?>
454
-
455
- <div class="sap-scheduler-brief">
456
- <div class="date">
457
- <div class="dashicons dashicons-calendar"></div>
458
- <span class="value"><?php echo $this->get_date_summary( $values ); ?></span>
459
- </div>
460
- <?php if ( $this->disable_time === false ) : ?>
461
- <div class="time">
462
- <div class="dashicons dashicons-clock"></div>
463
- <span class="value"><?php echo $this->get_time_summary( $values ); ?></span>
464
- </div>
465
- <?php endif; ?>
466
- </div>
467
- <div class="sap-scheduler-control">
468
- <a href="#" class="toggle" title="<?php echo $this->strings['toggle']; ?>">
469
- <div class="dashicons dashicons-<?php echo $list ? 'edit' : 'arrow-up-alt2'; ?>"></div>
470
- <span class="screen-reader-text">
471
- <?php echo $this->strings['toggle']; ?>
472
- </span>
473
- </a>
474
- <a href="#" class="delete" title="<?php echo $this->strings['delete']; ?>">
475
- <div class="dashicons dashicons-dismiss"></div>
476
- <span class="screen-reader-text">
477
- <?php echo $this->strings['delete_schedule']; ?>
478
- </span>
479
- </a>
480
- </div>
481
- </div>
482
-
483
- <?php
484
- $output = ob_get_clean();
485
-
486
- return $output;
487
- }
488
-
489
- /**
490
- * Determine the date format of a rule (weeky/monthly/date)
491
- * @since 2.0
492
- */
493
- public function get_date_format( $values ) {
494
-
495
- if ( !empty( $values['date'] ) ) {
496
- return 'date';
497
- } elseif ( !empty( $values['weeks'] ) ) {
498
- return 'monthly';
499
- } elseif ( !empty( $values['weekdays'] ) ) {
500
- return 'weekly';
501
- }
502
-
503
- if ( $this->disable_weekdays === false ) {
504
- return 'weekly';
505
- }
506
- if ( $this->disable_weeks === false ) {
507
- return 'monthly';
508
- }
509
- if ( $this->disable_date === false ) {
510
- return 'date';
511
- }
512
- }
513
-
514
- /**
515
- * Determine the time format of a rule (time-slot/all-day)
516
- * @since 2.0
517
- */
518
- public function get_time_format( $values ) {
519
- if ( empty( $values['time']['start'] ) && empty( $values['time']['end'] ) ) {
520
- return 'all-day';
521
- }
522
-
523
- return 'time-slot';
524
- }
525
-
526
- /**
527
- * Determine if multiple date formats are enabled
528
- * @since 2.0
529
- */
530
- public function has_multiple_date_formats() {
531
- $i = 0;
532
- if ( $this->disable_weekdays === false ) {
533
- $i++;
534
- }
535
- if ( $this->disable_weeks === false ) {
536
- $i++;
537
- }
538
- if ( $this->disable_date === false ) {
539
- $i++;
540
- }
541
-
542
- if ( $i > 1 ) {
543
- return true;
544
- } else {
545
- return false;
546
- }
547
- }
548
-
549
- /**
550
- * Set some default summary strings that can be used when the scheduler
551
- * rule is shown in brief
552
- * @since 2.0
553
- */
554
- public function set_schedule_summaries() {
555
-
556
- if ( !empty( $this->schedule_summaries ) ) {
557
- return;
558
- }
559
-
560
- $this->schedule_summaries = array(
561
- 'never' => $this->strings['never'],
562
- 'weekly_always' => $this->strings['weekly_always'],
563
- 'monthly_weekdays' => sprintf( $this->strings['monthly_weekdays'], '{days}', '{weeks}' ),
564
- 'monthly_weeks' => sprintf( $this->strings['monthly_weeks'], '{weeks}' ),
565
- 'all_day' => $this->strings['all_day'],
566
- 'before' => $this->strings['before'],
567
- 'after' => $this->strings['after'],
568
- 'separator' => $this->strings['separator'],
569
- );
570
- }
571
-
572
- /**
573
- * Print the date phrase, a brief description of the date settings
574
- * @since 2.0
575
- */
576
- public function get_date_summary( $values = array() ) {
577
-
578
- if ( !empty( $values['date'] ) ) {
579
- return $values['date'];
580
- }
581
-
582
- if ( empty( $values['weekdays'] ) && $this->disable_weekdays === false ) {
583
- return $this->schedule_summaries['never'];
584
- }
585
-
586
- if ( empty( $values['weekdays'] ) ) {
587
- $weekdays = '';
588
- } elseif ( count( $values['weekdays'] ) == 7 ) {
589
- $weekdays = $this->schedule_summaries['weekly_always'];
590
- } else {
591
- $arr = array();
592
- foreach ( $values['weekdays'] as $weekday => $state ) {
593
- $arr[] = $this->weekdays[$weekday];
594
- }
595
- $weekdays = join( ', ', $arr );
596
- }
597
-
598
- if ( ( empty( $values['weeks'] ) || count( $values['weeks'] ) == 5 ) && $this->disable_weekdays === false ) {
599
- return $weekdays;
600
- }
601
-
602
- if ( empty( $values['weeks'] ) ) {
603
- return $this->schedule_summaries['never'];
604
- }
605
-
606
- $arr = array();
607
- foreach ( $values['weeks'] as $weeks => $state ) {
608
- $arr[] = $this->weeks[$weeks];
609
- }
610
- $weeks = join( ', ', $arr );
611
-
612
- if ( !empty( $weekdays ) ) {
613
- return str_replace( array( '{days}', '{weeks}' ), array( $weekdays, $weeks ), $this->schedule_summaries['monthly_weekdays'] );
614
- } else {
615
- return str_replace( '{weeks}', ucfirst( $weeks ), $this->schedule_summaries['monthly_weeks'] );
616
- }
617
-
618
- }
619
-
620
- /**
621
- * Print the time phrase, a brief description of the time settings
622
- * @since 2.0
623
- */
624
- public function get_time_summary( $values = array() ) {
625
-
626
- if ( empty( $values['time']['start'] ) && empty( $values['time']['end'] ) ) {
627
- return $this->schedule_summaries['all_day'];
628
- }
629
-
630
- if ( empty( $values['time']['start'] ) ) {
631
- return $this->schedule_summaries['before'] . ' ' . $values['time']['end'];
632
- }
633
-
634
- if ( empty( $values['time']['end'] ) ) {
635
- return $this->schedule_summaries['after'] . ' ' . $values['time']['start'];
636
- }
637
-
638
- return $values['time']['start'] . $this->schedule_summaries['separator'] . $values['time']['end'];
639
-
640
- }
641
-
642
- /**
643
- * Sanitize the array of text inputs for this setting
644
- * @since 2.0
645
- */
646
- public function sanitize_callback_wrapper( $values ) {
647
-
648
- $output = array();
649
-
650
- if ( !is_array( $values ) || !count( $values ) ) {
651
- return $output;
652
- }
653
-
654
- foreach ( $values as $i => $rule ) {
655
-
656
- if ( !empty( $rule['weekdays'] ) ) {
657
- $output[$i]['weekdays'] = array();
658
- foreach ( $rule['weekdays'] as $day => $flag ) {
659
- if ( $flag !== '1' ||
660
- ( $day !== 'monday' && $day !== 'tuesday' && $day !== 'wednesday' && $day !== 'thursday' && $day !== 'friday' && $day !== 'saturday' && $day !== 'sunday' ) ) {
661
- continue;
662
- }
663
-
664
- $output[$i]['weekdays'][$day] = $flag;
665
- }
666
- }
667
-
668
- if ( !empty( $rule['weeks'] ) ) {
669
- $output[$i]['weeks'] = array();
670
- foreach ( $rule['weeks'] as $week => $flag ) {
671
- if ( $flag !== '1' ||
672
- ( $week !== 'first' && $week !== 'second' && $week !== 'third' && $week !== 'fourth' && $week !== 'last' ) ) {
673
- continue;
674
- }
675
-
676
- $output[$i]['weeks'][$week] = $flag;
677
- }
678
- }
679
-
680
- if ( !empty( $rule['date'] ) ) {
681
- $date = new DateTime( $rule['date'] );
682
- if ( checkdate( $date->format( 'n' ), $date->format( 'j' ), $date->format( 'Y' ) ) ) {
683
- $output[$i]['date'] = call_user_func( $this->sanitize_callback, $rule['date'] );
684
- }
685
- }
686
-
687
- if ( !empty( $rule['time']['start'] ) ) {
688
- $output[$i]['time']['start'] = call_user_func( $this->sanitize_callback, $rule['time']['start'] );
689
- }
690
- if ( !empty( $rule['time']['end'] ) ) {
691
- $output[$i]['time']['end'] = call_user_func( $this->sanitize_callback, $rule['time']['end'] );
692
- }
693
- }
694
-
695
- // Only return the first rule if multiple rules are disabled
696
- if ( $this->disable_multiple && count( $output ) > 1 ) {
697
- $output = array( array_shift( $output ) );
698
- }
699
-
700
- return $output;
701
- }
702
-
703
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a schedule of dates and times.
5
+ *
6
+ * This is designed for use for opening hours, a booking schedule or anything
7
+ * that requires recurring dates and times.
8
+ *
9
+ * @since 2.0
10
+ * @package Simple Admin Pages
11
+ */
12
+
13
+ class sapAdminPageSettingScheduler_2_5_5 extends sapAdminPageSetting_2_5_5 {
14
+
15
+ public $sanitize_callback = 'sanitize_text_field';
16
+
17
+ /**
18
+ * Scripts that must be loaded for this component
19
+ * @since 2.0.a.4
20
+ */
21
+ public $scripts = array(
22
+ 'pickadate' => array(
23
+ 'path' => 'lib/pickadate/picker.js',
24
+ 'dependencies' => array( 'jquery' ),
25
+ 'version' => '3.6.1',
26
+ 'footer' => true,
27
+ ),
28
+ 'pickadate-date' => array(
29
+ 'path' => 'lib/pickadate/picker.date.js',
30
+ 'dependencies' => array( 'jquery' ),
31
+ 'version' => '3.6.1',
32
+ 'footer' => true,
33
+ ),
34
+ 'pickadate-time' => array(
35
+ 'path' => 'lib/pickadate/picker.time.js',
36
+ 'dependencies' => array( 'jquery' ),
37
+ 'version' => '3.6.1',
38
+ 'footer' => true,
39
+ ),
40
+ 'pickadate-legacy' => array(
41
+ 'path' => 'lib/pickadate/legacy.js',
42
+ 'dependencies' => array( 'jquery' ),
43
+ 'version' => '3.6.1',
44
+ 'footer' => true,
45
+ ),
46
+ 'sap-scheduler' => array(
47
+ 'path' => 'js/scheduler.js',
48
+ 'dependencies' => array( 'jquery' ),
49
+ 'version' => SAP_VERSION,
50
+ 'footer' => true,
51
+ ),
52
+ // @todo there should be some way to load alternate language .js files
53
+ // and RTL CSS scripts
54
+ );
55
+
56
+ /**
57
+ * Styles that must be loaded for this component
58
+ * @since 2.0.a.4
59
+ */
60
+ public $styles = array(
61
+ 'pickadate-default' => array(
62
+ 'path' => 'lib/pickadate/themes/default.css',
63
+ 'dependencies' => '',
64
+ 'version' => '3.6.1',
65
+ 'media' => null,
66
+ ),
67
+ 'pickadate-date' => array(
68
+ 'path' => 'lib/pickadate/themes/default.date.css',
69
+ 'dependencies' => '',
70
+ 'version' => '3.6.1',
71
+ 'media' => null,
72
+ ),
73
+ 'pickadate-time' => array(
74
+ 'path' => 'lib/pickadate/themes/default.time.css',
75
+ 'dependencies' => '',
76
+ 'version' => '3.6.1',
77
+ 'media' => null,
78
+ ),
79
+ );
80
+
81
+ /**
82
+ * Used for data storage. Not translated
83
+ */
84
+ public $weekdays = array(
85
+ 'monday' => 'Mo',
86
+ 'tuesday' => 'Tu',
87
+ 'wednesday' => 'We',
88
+ 'thursday' => 'Th',
89
+ 'friday' => 'Fr',
90
+ 'saturday' => 'Sa',
91
+ 'sunday' => 'Su',
92
+ );
93
+
94
+ /**
95
+ * Used for data storage. Not translated
96
+ */
97
+ public $weeks = array(
98
+ 'first' => '1st',
99
+ 'second' => '2nd',
100
+ 'third' => '3rd',
101
+ 'fourth' => '4th',
102
+ 'last' => 'last',
103
+ );
104
+
105
+ /**
106
+ * Translateable strings required for this component
107
+ * @since 2.0.a.8
108
+ */
109
+ public $strings = array(
110
+ 'add_rule' => null, // __( 'Add new scheduling rule', 'textdomain' ),
111
+ 'weekly' => null, // _x( 'Weekly', 'Format of a scheduling rule', 'textdomain' ),
112
+ 'monthly' => null, // _x( 'Monthly', 'Format of a scheduling rule', 'textdomain' ),
113
+ 'date' => null, // _x( 'Date', 'Format of a scheduling rule', 'textdomain' ),
114
+ 'weekdays' => null, // _x( 'Days of the week', 'Label for selecting days of the week in a scheduling rule', 'textdomain' ),
115
+ 'month_weeks' => null, // _x( 'Weeks of the month', 'Label for selecting weeks of the month in a scheduling rule', 'textdomain' ),
116
+ 'date_label' => null, // _x( 'Date', 'Label to select a date for a scheduling rule', 'textdomain' ),
117
+ 'time_label' => null, // _x( 'Time', 'Label to select a time slot for a scheduling rule', 'textdomain' ),
118
+ 'allday' => null, // _x( 'All day', 'Label to set a scheduling rule to last all day', 'textdomain' ),
119
+ 'start' => null, // _x( 'Start', 'Label for the starting time of a scheduling rule', 'textdomain' ),
120
+ 'end' => null, // _x( 'End', 'Label for the ending time of a scheduling rule', 'textdomain' ),
121
+ 'set_time_prompt' => null, // _x( 'All day long. Want to %sset a time slot%s?', 'Prompt displayed when a scheduling rule is set without any time restrictions', 'textdomain' ),
122
+ 'toggle' => null, // _x( 'Open and close this rule', 'Toggle a scheduling rule open and closed', 'textdomain' ),
123
+ 'delete' => null, // _x( 'Delete rule', 'Delete a scheduling rule', 'textdomain' ),
124
+ 'delete_schedule' => null, // __( 'Delete scheduling rule', 'textdomain' ),
125
+ 'never' => null, // _x( 'Never', 'Brief default description of a scheduling rule when no weekdays or weeks are included in the rule', 'textdomain' ),
126
+ 'weekly_always' => null, // _x( 'Every day', 'Brief default description of a scheduling rule when all the weekdays/weeks are included in the rule', 'textdomain' ),
127
+ 'monthly_weekdays' => null, // _x( '%s on the %s week of the month', 'Brief default description of a scheduling rule when some weekdays are included on only some weeks of the month. %s should be left alone and will be replaced by a comma-separated list of days and weeks in the following format: M, T, W on the first, second week of the month', 'textdomain' ),
128
+ 'monthly_weeks' => null, // _x( '%s week of the month', 'Brief default description of a scheduling rule when some weeks of the month are included but all or no weekdays are selected. %s should be left alone and will be replaced by a comma-separated list of weeks in the following format: First, second week of the month', 'textdomain' ),
129
+ 'all_day' => null, // _x( 'All day', 'Brief default description of a scheduling rule when no times are set', 'textdomain' ),
130
+ 'before' => null, // _x( 'Ends at', 'Brief default description of a scheduling rule when an end time is set but no start time. If the end time is 6pm, it will read: Ends at 6pm', 'textdomain' ),
131
+ 'after' => null, // _x( 'Starts at', 'Brief default description of a scheduling rule when a start time is set but no end time. If the start time is 6pm, it will read: Starts at 6pm', 'textdomain' ),
132
+ 'separator' => null, // _x( '&mdash;', 'Separator between times of a scheduling rule', 'textdomain' ),
133
+ );
134
+
135
+ /**
136
+ * Number of minutes between time selection intervals
137
+ */
138
+ public $time_interval = 15;
139
+
140
+ /**
141
+ * Display format for time selection
142
+ * See http://amsul.ca/pickadate.js/ for formatting options
143
+ */
144
+ public $time_format = 'h:i A';
145
+
146
+ /**
147
+ * Display format for date selection
148
+ * See http://amsul.ca/pickadate.js/ for formatting options
149
+ */
150
+ public $date_format = 'd mmmm, yyyy';
151
+
152
+ /**
153
+ * Boolean to disable the weekday selection option
154
+ */
155
+ public $disable_weekdays = false;
156
+
157
+ /**
158
+ * Boolean to disable the weeks selection option
159
+ */
160
+ public $disable_weeks = false;
161
+
162
+ /**
163
+ * Boolean to disable the date selection option
164
+ */
165
+ public $disable_date = false;
166
+
167
+ /**
168
+ * Boolean to disable the time selection option
169
+ */
170
+ public $disable_time = false;
171
+
172
+ /**
173
+ * Boolean to disable the end time selection option
174
+ */
175
+ public $disable_end_time = false;
176
+
177
+ /**
178
+ * Boolean to disable multiple rules per component
179
+ */
180
+ public $disable_multiple = false;
181
+
182
+ /**
183
+ * Escape the value to display it in text fields and other input fields
184
+ * @since 2.0
185
+ */
186
+ public function esc_value( $val ) {
187
+
188
+ $value = array();
189
+
190
+ if ( empty( $val ) ) {
191
+ return $value;
192
+ }
193
+
194
+ foreach ( $val as $i => $rule ) {
195
+
196
+ if ( !empty( $rule['weekdays'] ) ) {
197
+ $value[$i]['weekdays'] = array();
198
+ foreach ( $rule['weekdays'] as $day => $flag ) {
199
+ if ( $flag !== '1' ) {
200
+ continue;
201
+ }
202
+
203
+ $value[$i]['weekdays'][$day] = $flag;
204
+ }
205
+ }
206
+
207
+ if ( !empty( $rule['weeks'] ) ) {
208
+ $value[$i]['weeks'] = array();
209
+ foreach ( $rule['weeks'] as $week => $flag ) {
210
+ if ( $flag !== '1' ) {
211
+ continue;
212
+ }
213
+
214
+ $value[$i]['weeks'][$week] = $flag;
215
+ }
216
+ }
217
+
218
+ if ( !empty( $rule['date'] ) ) {
219
+ $value[$i]['date'] = esc_attr( $rule['date'] );
220
+ }
221
+
222
+ if ( !empty( $rule['time']['start'] ) ) {
223
+ $value[$i]['time']['start'] = esc_attr( $rule['time']['start'] );
224
+ }
225
+ if ( !empty( $rule['time']['end'] ) ) {
226
+ $value[$i]['time']['end'] = esc_attr( $rule['time']['end'] );
227
+ }
228
+ }
229
+
230
+ return $value;
231
+ }
232
+
233
+ /**
234
+ * Compile and pass configurable variables to the javascript file, so they
235
+ * can be used when we initialize the pickadate components
236
+ * @since 2.0
237
+ */
238
+ public function pass_to_scripts() {
239
+
240
+ // Create a global variable containing settings for all schedulers
241
+ // that are being rendered on the page. This allows us to pass different
242
+ // settings for different schedulers on the same page.
243
+ global $sap_scheduler_settings;
244
+
245
+ if ( !isset( $sap_scheduler_settings ) ) {
246
+ $sap_scheduler_settings = array();
247
+ }
248
+
249
+ $sap_scheduler_settings[ $this->id ] = array(
250
+ 'time_interval' => $this->time_interval,
251
+ 'time_format' => $this->time_format,
252
+ 'date_format' => $this->date_format,
253
+ 'template' => $this->get_template(),
254
+ 'weekdays' => $this->weekdays,
255
+ 'weeks' => $this->weeks,
256
+ 'disable_weekdays' => $this->disable_weekdays,
257
+ 'disable_weeks' => $this->disable_weeks,
258
+ 'disable_date' => $this->disable_date,
259
+ 'disable_time' => $this->disable_time,
260
+ 'disable_multiple' => $this->disable_multiple,
261
+ 'summaries' => $this->schedule_summaries,
262
+ );
263
+
264
+ // This gets called multiple times, but only the last call is actually
265
+ // pushed to the script.
266
+ wp_localize_script(
267
+ 'sap-scheduler',
268
+ 'sap_scheduler',
269
+ array(
270
+ 'settings' => $sap_scheduler_settings
271
+ )
272
+ );
273
+
274
+ }
275
+
276
+ /**
277
+ * Display this setting
278
+ * @since 2.0
279
+ */
280
+ public function display_setting() {
281
+
282
+ $this->display_description();
283
+
284
+ // Define summary text to use when a rule is displayed in brief
285
+ $this->set_schedule_summaries();
286
+
287
+ // Pass data to the script files to handle js interactions
288
+ $this->pass_to_scripts();
289
+
290
+ ?>
291
+
292
+ <div class="sap-scheduler <?php echo ( $this->disabled ? 'disabled' : ''); ?>" id="<?php echo $this->id; ?>">
293
+ <?php
294
+ foreach ( $this->value as $id => $rule ) {
295
+ echo $this->get_template( $id, $rule, true );
296
+ }
297
+ ?>
298
+ </div>
299
+
300
+ <div class="sap-add-scheduler<?php if ( $this->disable_multiple && count( $this->value ) ) : ?> disabled<?php endif; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>">
301
+ <a href="#" class="button">
302
+ <?php echo $this->strings['add_rule']; ?>
303
+ </a>
304
+ </div>
305
+
306
+ <?php $this->display_disabled(); ?>
307
+
308
+ <?php
309
+ }
310
+
311
+ /**
312
+ * Retrieve the template for a scheduling rule
313
+ * @since 2.0
314
+ */
315
+ public function get_template( $id = 0, $values = array(), $list = false ) {
316
+
317
+ $date_format = $this->get_date_format( $values );
318
+ $time_format = $this->get_time_format( $values );
319
+
320
+ ob_start();
321
+ ?>
322
+
323
+ <div class="sap-scheduler-rule clearfix<?php echo $list ? ' list' : ''; ?>">
324
+ <div class="sap-scheduler-date <?php echo $date_format; echo $this->disable_time === true ? ' full-width' : ''; ?>">
325
+ <ul class="sap-selector">
326
+
327
+ <?php if ( !$this->has_multiple_date_formats() ) : ?>
328
+ <li>
329
+ <div class="dashicons dashicons-calendar"></div>
330
+ <?php if ( $date_format == 'weekly' ) : ?>
331
+ <?php echo $this->strings['weekly']; ?>
332
+ <?php elseif ( $date_format == 'monthly' ) : ?>
333
+ <?php echo $this->strings['monthly']; ?>
334
+ <?php elseif ( $date_format == 'date' ) : ?>
335
+ <?php echo $this->strings['date']; ?>
336
+ <?php endif; ?>
337
+ </li>
338
+ <?php else : ?>
339
+
340
+ <?php if ( $this->disable_weekdays === false ) : ?>
341
+ <li>
342
+ <div class="dashicons dashicons-calendar"></div>
343
+ <a href="#" data-format="weekly"<?php echo $date_format == 'weekly' ? ' class="selected"' : ''; ?>>
344
+ <?php echo $this->strings['weekly']; ?>
345
+ </a>
346
+ </li>
347
+ <?php endif; ?>
348
+
349
+ <?php if ( $this->disable_weeks === false ) : ?>
350
+ <li>
351
+ <a href="#" data-format="monthly"<?php echo $date_format == 'monthly' ? ' class="selected"' : ''; ?>>
352
+ <?php echo $this->strings['monthly']; ?>
353
+ </a>
354
+ </li>
355
+ <?php endif; ?>
356
+
357
+ <?php if ( $this->disable_date === false ) : ?>
358
+ <li>
359
+ <a href="#" data-format="date"<?php echo $date_format == 'date' ? ' class="selected"' : ''; ?>>
360
+ <?php echo $this->strings['date']; ?>
361
+ </a>
362
+ </li>
363
+ <?php endif; ?>
364
+
365
+ <?php endif; ?>
366
+ </ul>
367
+
368
+ <?php if ( $this->disable_weekdays === false ) : ?>
369
+ <ul class="sap-scheduler-weekdays">
370
+ <li class="label">
371
+ <?php echo $this->strings['weekdays']; ?>
372
+ </li>
373
+ <?php
374
+ foreach ( $this->weekdays as $slug => $label ) :
375
+ $input_name = $this->get_input_name() . '[' . $id . '][weekdays][' . esc_attr( $slug ) . ']';
376
+ ?>
377
+ <li>
378
+ &nbsp;<input type="checkbox" name="<?php echo $input_name; ?>" id="<?php echo $input_name; ?>" value="1"<?php echo empty( $values['weekdays'][$slug] ) ? '' : ' checked="checked"'; ?> data-day="<?php echo esc_attr( $slug ); ?>"><label for="<?php echo $input_name; ?>"><?php echo ucfirst( $label ); ?></label>
379
+ </li>
380
+ <?php endforeach; ?>
381
+ </ul>
382
+ <?php endif; ?>
383
+
384
+ <?php if ( $this->disable_weeks === false ) : ?>
385
+ <ul class="sap-scheduler-weeks">
386
+ <li class="label">
387
+ <?php echo $this->strings['month_weeks']; ?>
388
+ </li>
389
+ <?php
390
+ foreach ( $this->weeks as $slug => $label ) :
391
+ $input_name = $this->get_input_name() . '[' . $id . '][weeks][' . esc_attr( $slug ) . ']';
392
+ ?>
393
+ <li>
394
+ &nbsp;<input type="checkbox" name="<?php echo $input_name; ?>" id="<?php echo $input_name; ?>" value="1"<?php echo empty( $values['weeks'][$slug] ) ? '' : ' checked="checked"'; ?> data-week="<?php echo esc_attr( $slug ); ?>"><label for="<?php echo $input_name; ?>"><?php echo ucfirst( $label ); ?></label>
395
+ </li>
396
+ <?php endforeach; ?>
397
+ </ul>
398
+ <?php endif; ?>
399
+
400
+ <?php if ( $this->disable_date === false ) : ?>
401
+ <div class="sap-scheduler-date-input">
402
+ <label for="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][date]">
403
+ <?php echo $this->strings['date_label']; ?>
404
+ </label>
405
+ <input type="text" name="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][date]" id="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][date]" value="<?php echo empty( $values['date'] ) ? '' : $values['date']; ?>">
406
+ </div>
407
+ <?php endif; ?>
408
+
409
+ </div>
410
+
411
+ <?php if ( $this->disable_time === false ) : ?>
412
+ <div class="sap-scheduler-time <?php echo $time_format; ?>">
413
+
414
+ <ul class="sap-selector">
415
+ <li>
416
+ <div class="dashicons dashicons-clock"></div>
417
+ <a href="#" data-format="time-slot"<?php echo $time_format == 'time-slot' ? ' class="selected"' : ''; ?>>
418
+ <?php echo $this->strings['time_label']; ?>
419
+ </a>
420
+ </li>
421
+ <li>
422
+ <a href="#" data-format="all-day"<?php echo $time_format == 'all-day' ? ' class="selected"' : ''; ?>>
423
+ <?php echo $this->strings['allday']; ?>
424
+ </a>
425
+ </li>
426
+ </ul>
427
+
428
+ <div class="sap-scheduler-time-input clearfix">
429
+
430
+ <div class="start">
431
+ <label for="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][time][start]">
432
+ <?php echo $this->strings['start']; ?>
433
+ </label>
434
+ <input type="text" name="<?php echo $this->get_input_name() . '[' . $id . '][time][start]'; ?>" id="<?php echo $this->get_input_name() . '[' . $id . '][time][start]'; ?>" value="<?php echo empty( $values['time']['start'] ) ? '' : $values['time']['start']; ?>">
435
+ </div>
436
+
437
+ <?php if ( $this->disable_end_time === false ) : ?>
438
+ <div class="end">
439
+ <label for="<?php echo $this->get_input_name(); ?>[<?php echo $id; ?>][time][end]">
440
+ <?php echo $this->strings['end']; ?>
441
+ </label>
442
+ <input type="text" name="<?php echo $this->get_input_name() . '[' . $id . '][time][end]'; ?>" id="<?php echo $this->get_input_name() . '[' . $id . '][time][end]'; ?>" value="<?php echo empty( $values['time']['end'] ) ? '' : $values['time']['end']; ?>">
443
+ </div>
444
+ <?php endif; ?>
445
+
446
+ </div>
447
+
448
+ <div class="sap-scheduler-all-day">
449
+ <?php printf( $this->strings['set_time_prompt'], '<a href="#" data-format="time-slot">', '</a>' ); ?>
450
+ </div>
451
+
452
+ </div>
453
+ <?php endif; ?>
454
+
455
+ <div class="sap-scheduler-brief">
456
+ <div class="date">
457
+ <div class="dashicons dashicons-calendar"></div>
458
+ <span class="value"><?php echo $this->get_date_summary( $values ); ?></span>
459
+ </div>
460
+ <?php if ( $this->disable_time === false ) : ?>
461
+ <div class="time">
462
+ <div class="dashicons dashicons-clock"></div>
463
+ <span class="value"><?php echo $this->get_time_summary( $values ); ?></span>
464
+ </div>
465
+ <?php endif; ?>
466
+ </div>
467
+ <div class="sap-scheduler-control">
468
+ <a href="#" class="toggle" title="<?php echo $this->strings['toggle']; ?>">
469
+ <div class="dashicons dashicons-<?php echo $list ? 'edit' : 'arrow-up-alt2'; ?>"></div>
470
+ <span class="screen-reader-text">
471
+ <?php echo $this->strings['toggle']; ?>
472
+ </span>
473
+ </a>
474
+ <a href="#" class="delete" title="<?php echo $this->strings['delete']; ?>">
475
+ <div class="dashicons dashicons-dismiss"></div>
476
+ <span class="screen-reader-text">
477
+ <?php echo $this->strings['delete_schedule']; ?>
478
+ </span>
479
+ </a>
480
+ </div>
481
+ </div>
482
+
483
+ <?php
484
+ $output = ob_get_clean();
485
+
486
+ return $output;
487
+ }
488
+
489
+ /**
490
+ * Determine the date format of a rule (weeky/monthly/date)
491
+ * @since 2.0
492
+ */
493
+ public function get_date_format( $values ) {
494
+
495
+ if ( !empty( $values['date'] ) ) {
496
+ return 'date';
497
+ } elseif ( !empty( $values['weeks'] ) ) {
498
+ return 'monthly';
499
+ } elseif ( !empty( $values['weekdays'] ) ) {
500
+ return 'weekly';
501
+ }
502
+
503
+ if ( $this->disable_weekdays === false ) {
504
+ return 'weekly';
505
+ }
506
+ if ( $this->disable_weeks === false ) {
507
+ return 'monthly';
508
+ }
509
+ if ( $this->disable_date === false ) {
510
+ return 'date';
511
+ }
512
+ }
513
+
514
+ /**
515
+ * Determine the time format of a rule (time-slot/all-day)
516
+ * @since 2.0
517
+ */
518
+ public function get_time_format( $values ) {
519
+ if ( empty( $values['time']['start'] ) && empty( $values['time']['end'] ) ) {
520
+ return 'all-day';
521
+ }
522
+
523
+ return 'time-slot';
524
+ }
525
+
526
+ /**
527
+ * Determine if multiple date formats are enabled
528
+ * @since 2.0
529
+ */
530
+ public function has_multiple_date_formats() {
531
+ $i = 0;
532
+ if ( $this->disable_weekdays === false ) {
533
+ $i++;
534
+ }
535
+ if ( $this->disable_weeks === false ) {
536
+ $i++;
537
+ }
538
+ if ( $this->disable_date === false ) {
539
+ $i++;
540
+ }
541
+
542
+ if ( $i > 1 ) {
543
+ return true;
544
+ } else {
545
+ return false;
546
+ }
547
+ }
548
+
549
+ /**
550
+ * Set some default summary strings that can be used when the scheduler
551
+ * rule is shown in brief
552
+ * @since 2.0
553
+ */
554
+ public function set_schedule_summaries() {
555
+
556
+ if ( !empty( $this->schedule_summaries ) ) {
557
+ return;
558
+ }
559
+
560
+ $this->schedule_summaries = array(
561
+ 'never' => $this->strings['never'],
562
+ 'weekly_always' => $this->strings['weekly_always'],
563
+ 'monthly_weekdays' => sprintf( $this->strings['monthly_weekdays'], '{days}', '{weeks}' ),
564
+ 'monthly_weeks' => sprintf( $this->strings['monthly_weeks'], '{weeks}' ),
565
+ 'all_day' => $this->strings['all_day'],
566
+ 'before' => $this->strings['before'],
567
+ 'after' => $this->strings['after'],
568
+ 'separator' => $this->strings['separator'],
569
+ );
570
+ }
571
+
572
+ /**
573
+ * Print the date phrase, a brief description of the date settings
574
+ * @since 2.0
575
+ */
576
+ public function get_date_summary( $values = array() ) {
577
+
578
+ if ( !empty( $values['date'] ) ) {
579
+ return $values['date'];
580
+ }
581
+
582
+ if ( empty( $values['weekdays'] ) && $this->disable_weekdays === false ) {
583
+ return $this->schedule_summaries['never'];
584
+ }
585
+
586
+ if ( empty( $values['weekdays'] ) ) {
587
+ $weekdays = '';
588
+ } elseif ( count( $values['weekdays'] ) == 7 ) {
589
+ $weekdays = $this->schedule_summaries['weekly_always'];
590
+ } else {
591
+ $arr = array();
592
+ foreach ( $values['weekdays'] as $weekday => $state ) {
593
+ $arr[] = $this->weekdays[$weekday];
594
+ }
595
+ $weekdays = join( ', ', $arr );
596
+ }
597
+
598
+ if ( ( empty( $values['weeks'] ) || count( $values['weeks'] ) == 5 ) && $this->disable_weekdays === false ) {
599
+ return $weekdays;
600
+ }
601
+
602
+ if ( empty( $values['weeks'] ) ) {
603
+ return $this->schedule_summaries['never'];
604
+ }
605
+
606
+ $arr = array();
607
+ foreach ( $values['weeks'] as $weeks => $state ) {
608
+ $arr[] = $this->weeks[$weeks];
609
+ }
610
+ $weeks = join( ', ', $arr );
611
+
612
+ if ( !empty( $weekdays ) ) {
613
+ return str_replace( array( '{days}', '{weeks}' ), array( $weekdays, $weeks ), $this->schedule_summaries['monthly_weekdays'] );
614
+ } else {
615
+ return str_replace( '{weeks}', ucfirst( $weeks ), $this->schedule_summaries['monthly_weeks'] );
616
+ }
617
+
618
+ }
619
+
620
+ /**
621
+ * Print the time phrase, a brief description of the time settings
622
+ * @since 2.0
623
+ */
624
+ public function get_time_summary( $values = array() ) {
625
+
626
+ if ( empty( $values['time']['start'] ) && empty( $values['time']['end'] ) ) {
627
+ return $this->schedule_summaries['all_day'];
628
+ }
629
+
630
+ if ( empty( $values['time']['start'] ) ) {
631
+ return $this->schedule_summaries['before'] . ' ' . $values['time']['end'];
632
+ }
633
+
634
+ if ( empty( $values['time']['end'] ) ) {
635
+ return $this->schedule_summaries['after'] . ' ' . $values['time']['start'];
636
+ }
637
+
638
+ return $values['time']['start'] . $this->schedule_summaries['separator'] . $values['time']['end'];
639
+
640
+ }
641
+
642
+ /**
643
+ * Sanitize the array of text inputs for this setting
644
+ * @since 2.0
645
+ */
646
+ public function sanitize_callback_wrapper( $values ) {
647
+
648
+ $output = array();
649
+
650
+ if ( !is_array( $values ) || !count( $values ) ) {
651
+ return $output;
652
+ }
653
+
654
+ foreach ( $values as $i => $rule ) {
655
+
656
+ if ( !empty( $rule['weekdays'] ) ) {
657
+ $output[$i]['weekdays'] = array();
658
+ foreach ( $rule['weekdays'] as $day => $flag ) {
659
+ if ( $flag !== '1' ||
660
+ ( $day !== 'monday' && $day !== 'tuesday' && $day !== 'wednesday' && $day !== 'thursday' && $day !== 'friday' && $day !== 'saturday' && $day !== 'sunday' ) ) {
661
+ continue;
662
+ }
663
+
664
+ $output[$i]['weekdays'][$day] = $flag;
665
+ }
666
+ }
667
+
668
+ if ( !empty( $rule['weeks'] ) ) {
669
+ $output[$i]['weeks'] = array();
670
+ foreach ( $rule['weeks'] as $week => $flag ) {
671
+ if ( $flag !== '1' ||
672
+ ( $week !== 'first' && $week !== 'second' && $week !== 'third' && $week !== 'fourth' && $week !== 'last' ) ) {
673
+ continue;
674
+ }
675
+
676
+ $output[$i]['weeks'][$week] = $flag;
677
+ }
678
+ }
679
+
680
+ if ( !empty( $rule['date'] ) ) {
681
+ $date = new DateTime( $rule['date'] );
682
+ if ( checkdate( $date->format( 'n' ), $date->format( 'j' ), $date->format( 'Y' ) ) ) {
683
+ $output[$i]['date'] = call_user_func( $this->sanitize_callback, $rule['date'] );
684
+ }
685
+ }
686
+
687
+ if ( !empty( $rule['time']['start'] ) ) {
688
+ $output[$i]['time']['start'] = call_user_func( $this->sanitize_callback, $rule['time']['start'] );
689
+ }
690
+ if ( !empty( $rule['time']['end'] ) ) {
691
+ $output[$i]['time']['end'] = call_user_func( $this->sanitize_callback, $rule['time']['end'] );
692
+ }
693
+ }
694
+
695
+ // Only return the first rule if multiple rules are disabled
696
+ if ( $this->disable_multiple && count( $output ) > 1 ) {
697
+ $output = array( array_shift( $output ) );
698
+ }
699
+
700
+ return $output;
701
+ }
702
+
703
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Select.class.php CHANGED
@@ -1,61 +1,61 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a selection option with a drop-down menu.
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'blank_option' => true, // Whether or not to show a blank option
13
- * 'options' => array( // An array of key/value pairs which
14
- * 'option1' => 'Option 1', // define the options.
15
- * 'option2' => 'Option 2',
16
- * ...
17
- * );
18
- * );
19
- *
20
- * @since 1.0
21
- * @package Simple Admin Pages
22
- */
23
-
24
- class sapAdminPageSettingSelect_2_1_2 extends sapAdminPageSetting_2_1_2 {
25
-
26
- public $sanitize_callback = 'sanitize_text_field';
27
-
28
- // Whether or not to display a blank option
29
- public $blank_option = true;
30
-
31
- // An array of options for this select field, accepted as a key/value pair.
32
- public $options = array();
33
-
34
- /**
35
- * Display this setting
36
- * @since 1.0
37
- */
38
- public function display_setting() {
39
-
40
- ?>
41
-
42
- <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->id; ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
43
-
44
- <?php if ( $this->blank_option === true ) : ?>
45
- <option></option>
46
- <?php endif; ?>
47
-
48
- <?php foreach ( $this->options as $id => $title ) : ?>
49
- <option value="<?php echo esc_attr( $id ); ?>"<?php if( $this->value == $id ) : ?> selected="selected"<?php endif; ?>><?php echo esc_html( $title ); ?></option>
50
- <?php endforeach; ?>
51
-
52
- </select>
53
- <?php $this->display_disabled(); ?>
54
-
55
- <?php
56
-
57
- $this->display_description();
58
-
59
- }
60
-
61
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a selection option with a drop-down menu.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'blank_option' => true, // Whether or not to show a blank option
13
+ * 'options' => array( // An array of key/value pairs which
14
+ * 'option1' => 'Option 1', // define the options.
15
+ * 'option2' => 'Option 2',
16
+ * ...
17
+ * );
18
+ * );
19
+ *
20
+ * @since 1.0
21
+ * @package Simple Admin Pages
22
+ */
23
+
24
+ class sapAdminPageSettingSelect_2_5_5 extends sapAdminPageSetting_2_5_5 {
25
+
26
+ public $sanitize_callback = 'sanitize_text_field';
27
+
28
+ // Whether or not to display a blank option
29
+ public $blank_option = true;
30
+
31
+ // An array of options for this select field, accepted as a key/value pair.
32
+ public $options = array();
33
+
34
+ /**
35
+ * Display this setting
36
+ * @since 1.0
37
+ */
38
+ public function display_setting() {
39
+
40
+ ?>
41
+
42
+ <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->id; ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
43
+
44
+ <?php if ( $this->blank_option === true ) : ?>
45
+ <option></option>
46
+ <?php endif; ?>
47
+
48
+ <?php foreach ( $this->options as $id => $title ) : ?>
49
+ <option value="<?php echo esc_attr( $id ); ?>"<?php if( $this->value == $id ) : ?> selected="selected"<?php endif; ?>><?php echo esc_html( $title ); ?></option>
50
+ <?php endforeach; ?>
51
+
52
+ </select>
53
+ <?php $this->display_disabled(); ?>
54
+
55
+ <?php
56
+
57
+ $this->display_description();
58
+
59
+ }
60
+
61
+ }
lib/simple-admin-pages/classes/AdminPageSetting.SelectMenu.class.php CHANGED
@@ -1,57 +1,57 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a selection with a drop-down list of any post type
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'blank_option' => true, // Whether or not to show a blank option
13
- * 'args' => array(); // Arguments to pass to WordPress's get_post() function
14
- * );
15
- *
16
- * @since 1.0
17
- * @package Simple Admin Pages
18
- */
19
-
20
- class sapAdminPageSettingSelectMenu_2_1_2 extends sapAdminPageSetting_2_1_2 {
21
-
22
- public $sanitize_callback = 'intval';
23
-
24
- // Whether or not to display a blank option
25
- public $blank_option = true;
26
-
27
- /**
28
- * An array of arguments accepted by get_posts().
29
- * See: http://codex.wordpress.org/Template_Tags/get_posts
30
- */
31
- public $args = array();
32
-
33
- /**
34
- * Display this setting
35
- * @since 1.0
36
- */
37
- public function display_setting() {
38
-
39
- $menus = get_terms( 'nav_menu', array( 'hide_empty' => true ) );
40
- ?>
41
- <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>">
42
-
43
- <?php if ( $this->blank_option === true ) : ?>
44
- <option></option>
45
- <?php endif; ?>
46
-
47
- <?php foreach($menus as $menu){ ?>
48
- <option value="<?php echo absint( $menu->term_id ); ?>" <?php selected( $this->value, $menu->term_id ); ?>><?php echo esc_attr( $menu->name ); ?></option>
49
- <?php } ?>
50
-
51
- </select>
52
- <?php
53
- $this->display_description();
54
-
55
- }
56
-
57
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a selection with a drop-down list of any post type
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'blank_option' => true, // Whether or not to show a blank option
13
+ * 'args' => array(); // Arguments to pass to WordPress's get_post() function
14
+ * );
15
+ *
16
+ * @since 1.0
17
+ * @package Simple Admin Pages
18
+ */
19
+
20
+ class sapAdminPageSettingSelectMenu_2_5_5 extends sapAdminPageSetting_2_5_5 {
21
+
22
+ public $sanitize_callback = 'intval';
23
+
24
+ // Whether or not to display a blank option
25
+ public $blank_option = true;
26
+
27
+ /**
28
+ * An array of arguments accepted by get_posts().
29
+ * See: http://codex.wordpress.org/Template_Tags/get_posts
30
+ */
31
+ public $args = array();
32
+
33
+ /**
34
+ * Display this setting
35
+ * @since 1.0
36
+ */
37
+ public function display_setting() {
38
+
39
+ $menus = get_terms( 'nav_menu', array( 'hide_empty' => true ) );
40
+ ?>
41
+ <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>">
42
+
43
+ <?php if ( $this->blank_option === true ) : ?>
44
+ <option></option>
45
+ <?php endif; ?>
46
+
47
+ <?php foreach($menus as $menu){ ?>
48
+ <option value="<?php echo absint( $menu->term_id ); ?>" <?php selected( $this->value, $menu->term_id ); ?>><?php echo esc_attr( $menu->name ); ?></option>
49
+ <?php } ?>
50
+
51
+ </select>
52
+ <?php
53
+ $this->display_description();
54
+
55
+ }
56
+
57
+ }
lib/simple-admin-pages/classes/AdminPageSetting.SelectPost.class.php CHANGED
@@ -1,65 +1,65 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a selection with a drop-down list of any post type
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'blank_option' => true, // Whether or not to show a blank option
13
- * 'args' => array(); // Arguments to pass to WordPress's get_post() function
14
- * );
15
- *
16
- * @since 1.0
17
- * @package Simple Admin Pages
18
- */
19
-
20
- class sapAdminPageSettingSelectPost_2_1_2 extends sapAdminPageSetting_2_1_2 {
21
-
22
- public $sanitize_callback = 'intval';
23
-
24
- // Whether or not to display a blank option
25
- public $blank_option = true;
26
-
27
- /**
28
- * An array of arguments accepted by get_posts().
29
- * See: http://codex.wordpress.org/Template_Tags/get_posts
30
- */
31
- public $args = array();
32
-
33
- /**
34
- * Display this setting
35
- * @since 1.0
36
- */
37
- public function display_setting() {
38
-
39
- $posts = new WP_Query( $this->args );
40
-
41
- ?>
42
-
43
- <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
44
-
45
- <?php if ( $this->blank_option === true ) : ?>
46
- <option></option>
47
- <?php endif; ?>
48
-
49
- <?php while( $posts->have_posts() ) : $posts->next_post(); ?>
50
- <option value="<?php echo absint( $posts->post->ID ); ?>" <?php selected( $this->value, $posts->post->ID ); ?>><?php echo esc_attr( $posts->post->post_title ); ?></option>
51
- <?php endwhile; ?>
52
-
53
- </select>
54
-
55
- <?php $this->display_disabled(); ?>
56
-
57
- <?php
58
-
59
- wp_reset_postdata();
60
-
61
- $this->display_description();
62
-
63
- }
64
-
65
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a selection with a drop-down list of any post type
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'blank_option' => true, // Whether or not to show a blank option
13
+ * 'args' => array(); // Arguments to pass to WordPress's get_post() function
14
+ * );
15
+ *
16
+ * @since 1.0
17
+ * @package Simple Admin Pages
18
+ */
19
+
20
+ class sapAdminPageSettingSelectPost_2_5_5 extends sapAdminPageSetting_2_5_5 {
21
+
22
+ public $sanitize_callback = 'intval';
23
+
24
+ // Whether or not to display a blank option
25
+ public $blank_option = true;
26
+
27
+ /**
28
+ * An array of arguments accepted by get_posts().
29
+ * See: http://codex.wordpress.org/Template_Tags/get_posts
30
+ */
31
+ public $args = array();
32
+
33
+ /**
34
+ * Display this setting
35
+ * @since 1.0
36
+ */
37
+ public function display_setting() {
38
+
39
+ $posts = new WP_Query( $this->args );
40
+
41
+ ?>
42
+
43
+ <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
44
+
45
+ <?php if ( $this->blank_option === true ) : ?>
46
+ <option></option>
47
+ <?php endif; ?>
48
+
49
+ <?php while( $posts->have_posts() ) : $posts->next_post(); ?>
50
+ <option value="<?php echo absint( $posts->post->ID ); ?>" <?php selected( $this->value, $posts->post->ID ); ?>><?php echo esc_attr( $posts->post->post_title ); ?></option>
51
+ <?php endwhile; ?>
52
+
53
+ </select>
54
+
55
+ <?php $this->display_disabled(); ?>
56
+
57
+ <?php
58
+
59
+ wp_reset_postdata();
60
+
61
+ $this->display_description();
62
+
63
+ }
64
+
65
+ }
lib/simple-admin-pages/classes/AdminPageSetting.SelectTaxonomy.class.php CHANGED
@@ -1,68 +1,68 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a selection with a drop-down list of any taxonomy
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'taxonomies' => array(); // Array of taxonomies to fetch (required)
13
- * 'blank_option' => true, // Whether or not to show a blank option
14
- * 'args' => array(); // Arguments to pass to WordPress's get_terms() function
15
- * );
16
- * type
17
- *
18
- * @since 1.0
19
- * @package Simple Admin Pages
20
- */
21
-
22
- class sapAdminPageSettingSelectTaxonomy_2_1_2 extends sapAdminPageSetting_2_1_2 {
23
-
24
- public $sanitize_callback = 'intval';
25
-
26
- // Whether or not to display a blank option
27
- public $blank_option = true;
28
-
29
- // Arrays of taxonomies to fetch (required)
30
- public $taxonomies;
31
-
32
- /**
33
- * Array of options accepted by get_terms()
34
- * See: http://codex.wordpress.org/Function_Reference/get_terms
35
- */
36
- public $args = array();
37
-
38
- /**
39
- * Display this setting
40
- * @since 1.0
41
- */
42
- public function display_setting() {
43
-
44
- $terms = get_terms( $this->taxonomies, $this->args );
45
-
46
- ?>
47
-
48
- <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
49
-
50
- <?php if ( $this->blank_option === true ) : ?>
51
- <option></option>
52
- <?php endif; ?>
53
-
54
- <?php foreach ( $terms as $term ) : ?>
55
- <option value="<?php echo esc_attr( $term->term_id ); ?>"<?php if( $this->value == $term->term_id ) : ?> selected="selected"<?php endif; ?>><?php echo esc_html( $term->name ); ?></option>
56
- <?php endforeach; ?>
57
-
58
- </select>
59
-
60
- <?php $this->display_disabled(); ?>
61
-
62
- <?php
63
-
64
- $this->display_description();
65
-
66
- }
67
-
68
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a selection with a drop-down list of any taxonomy
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'taxonomies' => array(); // Array of taxonomies to fetch (required)
13
+ * 'blank_option' => true, // Whether or not to show a blank option
14
+ * 'args' => array(); // Arguments to pass to WordPress's get_terms() function
15
+ * );
16
+ * type
17
+ *
18
+ * @since 1.0
19
+ * @package Simple Admin Pages
20
+ */
21
+
22
+ class sapAdminPageSettingSelectTaxonomy_2_5_5 extends sapAdminPageSetting_2_5_5 {
23
+
24
+ public $sanitize_callback = 'intval';
25
+
26
+ // Whether or not to display a blank option
27
+ public $blank_option = true;
28
+
29
+ // Arrays of taxonomies to fetch (required)
30
+ public $taxonomies;
31
+
32
+ /**
33
+ * Array of options accepted by get_terms()
34
+ * See: http://codex.wordpress.org/Function_Reference/get_terms
35
+ */
36
+ public $args = array();
37
+
38
+ /**
39
+ * Display this setting
40
+ * @since 1.0
41
+ */
42
+ public function display_setting() {
43
+
44
+ $terms = get_terms( $this->taxonomies, $this->args );
45
+
46
+ ?>
47
+
48
+ <select name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
49
+
50
+ <?php if ( $this->blank_option === true ) : ?>
51
+ <option></option>
52
+ <?php endif; ?>
53
+
54
+ <?php foreach ( $terms as $term ) : ?>
55
+ <option value="<?php echo esc_attr( $term->term_id ); ?>"<?php if( $this->value == $term->term_id ) : ?> selected="selected"<?php endif; ?>><?php echo esc_html( $term->name ); ?></option>
56
+ <?php endforeach; ?>
57
+
58
+ </select>
59
+
60
+ <?php $this->display_disabled(); ?>
61
+
62
+ <?php
63
+
64
+ $this->display_description();
65
+
66
+ }
67
+
68
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Text.class.php CHANGED
@@ -1,37 +1,37 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a text field setting in the admin menu
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- */
9
-
10
- class sapAdminPageSettingText_2_1_2 extends sapAdminPageSetting_2_1_2 {
11
-
12
- public $sanitize_callback = 'sanitize_text_field';
13
-
14
- /**
15
- * Placeholder string for the input field
16
- * @since 2.0
17
- */
18
- public $placeholder = '';
19
-
20
- /**
21
- * Display this setting
22
- * @since 1.0
23
- */
24
- public function display_setting() {
25
- ?>
26
-
27
- <input name="<?php echo $this->get_input_name(); ?>" type="text" id="<?php echo $this->get_input_name(); ?>" value="<?php echo $this->value; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text" <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
28
-
29
- <?php $this->display_disabled(); ?>
30
-
31
- <?php
32
-
33
- $this->display_description();
34
-
35
- }
36
-
37
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a text field setting in the admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingText_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ public $sanitize_callback = 'sanitize_text_field';
13
+
14
+ /**
15
+ * Placeholder string for the input field
16
+ * @since 2.0
17
+ */
18
+ public $placeholder = '';
19
+
20
+ /**
21
+ * Display this setting
22
+ * @since 1.0
23
+ */
24
+ public function display_setting() {
25
+ ?>
26
+
27
+ <input name="<?php echo $this->get_input_name(); ?>" type="text" id="<?php echo $this->get_input_name(); ?>" value="<?php echo $this->value; ?>"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> class="regular-text<?php echo ( $this->small ? ' sap-small-text-input' : '' ); ?>" <?php echo ( $this->disabled ? 'disabled' : ''); ?> />
28
+
29
+ <?php $this->display_disabled(); ?>
30
+
31
+ <?php
32
+
33
+ $this->display_description();
34
+
35
+ }
36
+
37
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Textarea.class.php CHANGED
@@ -1,58 +1,58 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a textarea field setting in the admin menu
5
- *
6
- * @since 1.0
7
- * @package Simple Admin Pages
8
- *
9
- * @todo textareas should have an option to swap new lines for <br>s
10
- */
11
-
12
- class sapAdminPageSettingTextarea_2_1_2 extends sapAdminPageSetting_2_1_2 {
13
-
14
- /*
15
- * Size of this textarea
16
- *
17
- * This is put directly into a css class [size]-text,
18
- * and setting this to 'large' will link into WordPress's existing textarea
19
- * style for full-width textareas.
20
- */
21
- public $size = 'small';
22
-
23
- public $sanitize_callback = 'wp_kses_post';
24
-
25
- /**
26
- * Escape the value to display it safely HTML textarea fields
27
- * @since 1.0
28
- */
29
- public function esc_value( $val ) {
30
- return esc_textarea( $val );
31
- }
32
-
33
- /**
34
- * Set the size of this textarea field
35
- * @since 1.0
36
- */
37
- public function set_size( $size ) {
38
- $this->size = esc_attr( $size );
39
- }
40
-
41
- /**
42
- * Display this setting
43
- * @since 1.0
44
- */
45
- public function display_setting() {
46
- ?>
47
-
48
- <textarea name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>" class="<?php echo $this->size; ?>-text"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>><?php echo $this->value; ?></textarea>
49
-
50
- <?php $this->display_disabled(); ?>
51
-
52
- <?php
53
-
54
- $this->display_description();
55
-
56
- }
57
-
58
- }
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a textarea field setting in the admin menu
5
+ *
6
+ * @since 1.0
7
+ * @package Simple Admin Pages
8
+ *
9
+ * @todo textareas should have an option to swap new lines for <br>s
10
+ */
11
+
12
+ class sapAdminPageSettingTextarea_2_5_5 extends sapAdminPageSetting_2_5_5 {
13
+
14
+ /*
15
+ * Size of this textarea
16
+ *
17
+ * This is put directly into a css class [size]-text,
18
+ * and setting this to 'large' will link into WordPress's existing textarea
19
+ * style for full-width textareas.
20
+ */
21
+ public $size = 'small';
22
+
23
+ public $sanitize_callback = 'wp_kses_post';
24
+
25
+ /**
26
+ * Escape the value to display it safely HTML textarea fields
27
+ * @since 1.0
28
+ */
29
+ public function esc_value( $val ) {
30
+ return esc_textarea( $val );
31
+ }
32
+
33
+ /**
34
+ * Set the size of this textarea field
35
+ * @since 1.0
36
+ */
37
+ public function set_size( $size ) {
38
+ $this->size = esc_attr( $size );
39
+ }
40
+
41
+ /**
42
+ * Display this setting
43
+ * @since 1.0
44
+ */
45
+ public function display_setting() {
46
+ ?>
47
+
48
+ <textarea name="<?php echo $this->get_input_name(); ?>" id="<?php echo $this->get_input_name(); ?>" class="<?php echo $this->size; ?>-text"<?php echo !empty( $this->placeholder ) ? ' placeholder="' . esc_attr( $this->placeholder ) . '"' : ''; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>><?php echo $this->value; ?></textarea>
49
+
50
+ <?php $this->display_disabled(); ?>
51
+
52
+ <?php
53
+
54
+ $this->display_description();
55
+
56
+ }
57
+
58
+ }
lib/simple-admin-pages/classes/AdminPageSetting.Toggle.class.php CHANGED
@@ -1,52 +1,54 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save an option with a single checkbox.
5
- *
6
- * This setting accepts the following arguments in its constructor function.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description', // Help text description
12
- * 'label' => 'Label', // Checkbox label text
13
- * );
14
- * );
15
- *
16
- * @since 1.0
17
- * @package Simple Admin Pages
18
- */
19
-
20
- class sapAdminPageSettingToggle_2_1_2 extends sapAdminPageSetting_2_1_2 {
21
-
22
- public $sanitize_callback = 'sanitize_text_field';
23
-
24
- /**
25
- * Display this setting
26
- * @since 1.0
27
- */
28
- public function display_setting() {
29
-
30
- $input_name = $this->get_input_name();
31
-
32
- ?>
33
-
34
- <fieldset>
35
- <div class="bpfwp-admin-hide-radios">
36
- <input type="checkbox" name="<?php echo $input_name; ?>" id="<?php echo $input_name; ?>" value="1"<?php if( $this->value == '1' ) : ?> checked="checked"<?php endif; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
37
- <label for="<?php echo $input_name; ?>"><?php echo $this->label; ?></label>
38
- </div>
39
- <label class="bpfwp-admin-switch">
40
- <input type="checkbox" class="bpfwp-admin-option-toggle" data-inputname="<?php echo $input_name; ?>" <?php if($this->value == '1') {echo "checked='checked'";} ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
41
- <span class="bpfwp-admin-switch-slider round"></span>
42
- </label>
43
- <?php $this->display_disabled(); ?>
44
- </fieldset>
45
-
46
- <?php
47
-
48
- $this->display_description();
49
-
50
- }
51
-
52
- }
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save an option with a single checkbox.
5
+ *
6
+ * This setting accepts the following arguments in its constructor function.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description', // Help text description
12
+ * 'label' => 'Label', // Checkbox label text
13
+ * );
14
+ * );
15
+ *
16
+ * @since 1.0
17
+ * @package Simple Admin Pages
18
+ */
19
+
20
+ class sapAdminPageSettingToggle_2_5_5 extends sapAdminPageSetting_2_5_5 {
21
+
22
+ public $sanitize_callback = 'sanitize_text_field';
23
+
24
+ /**
25
+ * Display this setting
26
+ * @since 1.0
27
+ */
28
+ public function display_setting() {
29
+
30
+ $input_name = $this->get_input_name();
31
+
32
+ if ( ! isset( $this->value ) ) { $this->value = $this->get_default_setting(); }
33
+
34
+ ?>
35
+
36
+ <fieldset>
37
+ <div class="sap-admin-hide-radios">
38
+ <input type="checkbox" name="<?php echo $input_name; ?>" id="<?php echo $input_name; ?>" value="1"<?php if( $this->value == '1' ) : ?> checked="checked"<?php endif; ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
39
+ <label for="<?php echo $input_name; ?>"><?php echo $this->title; ?></label>
40
+ </div>
41
+ <label class="sap-admin-switch">
42
+ <input type="checkbox" class="sap-admin-option-toggle" data-inputname="<?php echo $input_name; ?>" <?php if($this->value == '1') {echo "checked='checked'";} ?> <?php echo ( $this->disabled ? 'disabled' : ''); ?>>
43
+ <span class="sap-admin-switch-slider round"></span>
44
+ </label>
45
+ <?php $this->display_disabled(); ?>
46
+ </fieldset>
47
+
48
+ <?php
49
+
50
+ $this->display_description();
51
+
52
+ }
53
+
54
+ }
lib/simple-admin-pages/classes/AdminPageSetting.WarningTip.class.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a warning/tip in the admin menu
5
+ *
6
+ * @since 2.3.0
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ class sapAdminPageSettingWarningTip_2_5_5 extends sapAdminPageSetting_2_5_5 {
11
+
12
+ public $sanitize_callback = 'sanitize_text_field';
13
+
14
+ /**
15
+ * Placeholder string for the input field
16
+ * @since 2.0
17
+ */
18
+ public $placeholder = '';
19
+
20
+ /**
21
+ * Display this setting
22
+ * @since 1.0
23
+ */
24
+ public function display_setting() {
25
+ ?>
26
+
27
+ <fieldset class="fdm-warning-tip">
28
+ <div class="fdm-shortcode-reminder">
29
+ <?php echo '<strong>' . $this->title . '</strong> ' . $this->placeholder; ?>
30
+ </div>
31
+
32
+ <?php $this->display_disabled(); ?>
33
+ </fieldset>
34
+
35
+ <?php
36
+
37
+ $this->display_description();
38
+
39
+ }
40
+
41
+ }
lib/simple-admin-pages/classes/AdminPageSetting.class.php CHANGED
@@ -1,344 +1,358 @@
1
- <?php
2
-
3
- /**
4
- * Register, display and save a setting on a custom admin menu
5
- *
6
- * All settings accept the following arguments in their constructor functions.
7
- *
8
- * $args = array(
9
- * 'id' => 'setting_id', // Unique id
10
- * 'title' => 'My Setting', // Title or label for the setting
11
- * 'description' => 'Description' // Help text description
12
- * 'args' => array(); // Arguments to pass to WordPress's add_settings_field() function
13
- * );
14
- *
15
- * @since 1.0
16
- * @package Simple Admin Pages
17
- */
18
-
19
- abstract class sapAdminPageSetting_2_1_2 {
20
-
21
- // Page defaults
22
- public $id; // used in form fields and database to track and store setting
23
- public $title; // setting label
24
- public $description; // optional description of the setting
25
- public $value; // value of the setting, if a value exists
26
- public $disabled = false; // whether a setting should be disabled
27
-
28
- /**
29
- * An array of arguments accepted by add_settings_field.
30
- * See: https://codex.wordpress.org/Function_Reference/add_settings_field
31
- */
32
- public $args = array();
33
-
34
- // Array to store errors
35
- public $errors = array();
36
-
37
- /**
38
- * Position in section
39
- *
40
- * An array with two elements describing where this setting should
41
- * be placed in its section. The first element describes a position
42
- * and the second (optional) element identifies the id of an
43
- * existing setting. Examples:
44
- *
45
- * array( 'bottom' ) // Default. bottom of section
46
- * array( 'top' ) // top of section
47
- * array( 'before', 'my-setting' ) // before a specific setting
48
- * array( 'after', 'my-setting' ) // after a specific setting
49
- *
50
- * This setting is intended for use when you have to hook in after
51
- * the settings page has been defined, such as adding a new setting
52
- * from a third-party plugin.
53
- */
54
- public $position;
55
-
56
- /**
57
- * Function to use when sanitizing the data
58
- *
59
- * We set this to a strict sanitization function as a default, but a
60
- * setting should override this in an extended class when needed.
61
- *
62
- * @since 1.0
63
- */
64
- public $sanitize_callback = 'sanitize_text_field';
65
-
66
- /**
67
- * Scripts that must be loaded for this component
68
- * @since 2.0.a.4
69
- */
70
- public $scripts = array(
71
- /**
72
- * Example
73
- * See: http://codex.wordpress.org/Function_Reference/wp_enqueue_script
74
- *
75
- 'handle' => array(
76
- 'path' => 'path/from/simple-admin-pages/file.js',
77
- 'dependencies' => array( 'jquery' ),
78
- 'version' => '3.5.0',
79
- 'footer' => true,
80
- ),
81
- */
82
- );
83
-
84
- /**
85
- * Styles that must be loaded for this component
86
- * @since 2.0.a.4
87
- */
88
- public $styles = array(
89
- /**
90
- * Example
91
- * See: http://codex.wordpress.org/Function_Reference/wp_enqueue_style
92
- *
93
- 'handle' => array(
94
- 'path' => 'path/from/simple-admin-pages/file.css',
95
- 'dependencies' => 'array( 'another-handle')', // or empty string
96
- 'version' => '3.5.0',
97
- 'media' => null,
98
- ),
99
- */
100
- );
101
-
102
- /**
103
- * Translateable strings required for this component
104
- *
105
- * Settings classes which require translateable strings should be
106
- * defined with string id's pointing to null values. The actual
107
- * strings should be passed with the $sap->add_setting() call.
108
- *
109
- * @since 2.0.a.8
110
- */
111
- public $strings = array(
112
- /**
113
- * Example
114
- *
115
- 'string_id' => null
116
- */
117
- );
118
-
119
- /**
120
- * Initialize the setting
121
- *
122
- * By default, every setting takes an id, title and description in the $args
123
- * array.
124
- *
125
- * @since 1.0
126
- */
127
- public function __construct( $args ) {
128
-
129
- // Parse the values passed
130
- $this->parse_args( $args );
131
-
132
- // Get any existing value
133
- $this->set_value();
134
-
135
- // Check for missing data
136
- $this->missing_data();
137
- }
138
-
139
- /**
140
- * Parse the arguments passed in the construction and assign them to
141
- * internal variables. This function will be overwritten for most subclasses
142
- * @since 1.0
143
- */
144
- private function parse_args( $args ) {
145
- foreach ( $args as $key => $val ) {
146
- switch ( $key ) {
147
-
148
- case 'id' :
149
- $this->{$key} = esc_attr( $val );
150
-
151
- default :
152
- $this->{$key} = $val;
153
-
154
- }
155
- }
156
- }
157
-
158
- /**
159
- * Check for missing data when setup.
160
- * @since 1.0
161
- */
162
- private function missing_data() {
163
-
164
- $error_type = 'missing_data';
165
-
166
- // Required fields
167
- if ( empty( $this->id ) ) {
168
- $this->set_error(
169
- array(
170
- 'type' => $error_type,
171
- 'data' => 'id'
172
- )
173
- );
174
- }
175
- if ( empty( $this->title ) ) {
176
- $this->set_error(
177
- array(
178
- 'type' => $error_type,
179
- 'data' => 'title'
180
- )
181
- );
182
- }
183
-
184
- // Check for strings
185
- foreach ( $this->strings as $id => $string ) {
186
-
187
- if ( $string === null ) {
188
- $this->set_error(
189
- array(
190
- 'type' => $error_type,
191
- 'data' => 'string: ' . $id,
192
- )
193
- );
194
- }
195
- }
196
- }
197
-
198
- /**
199
- * Set a value
200
- * @since 2.0
201
- */
202
- public function set_value( $val = null ) {
203
-
204
- if ( $val === null && isset( $this->page ) ) {
205
- $option_group_value = get_option( $this->page );
206
- $val = isset( $option_group_value[ $this->id ] ) ? $option_group_value[ $this->id ] : '';
207
- }
208
-
209
- $this->value = $this->esc_value( $val );
210
- }
211
-
212
- /**
213
- * Escape the value to display it in text fields and other input fields
214
- *
215
- * We use esc_attr() here so that the default is quite strict, but other
216
- * setting types should override this function with the appropriate escape
217
- * function. See: http://codex.wordpress.org/Data_Validation
218
- *
219
- * @since 1.0
220
- */
221
- public function esc_value( $val ) {
222
- return esc_attr( $val );
223
- }
224
-
225
- /**
226
- * Wrapper for the sanitization callback function.
227
- *
228
- * This just reduces code duplication for child classes that need a custom
229
- * callback function.
230
- * @since 1.0
231
- */
232
- public function sanitize_callback_wrapper( $value ) {
233
- return call_user_func( $this->sanitize_callback, $value );
234
- }
235
-
236
- /**
237
- * Display this setting
238
- * @since 1.0
239
- */
240
- abstract public function display_setting();
241
-
242
- /**
243
- * Display a description for this setting
244
- * @since 1.0
245
- */
246
- public function display_description() {
247
-
248
- if ( !empty( $this->description ) ) {
249
-
250
- ?>
251
-
252
- <p class="description<?php echo ( $this->disabled ? ' disabled' : ''); ?>"><?php echo $this->description; ?></p>
253
-
254
- <?php
255
-
256
- }
257
- }
258
-
259
- /**
260
- * Display a disabled image for this section and possibly a link to upgrade
261
- * @since 2.0
262
- */
263
- public function display_disabled() {
264
-
265
- if ( $this->disabled and isset($this->disabled_image) ) {
266
-
267
- ?>
268
-
269
- <?php echo ( isset($this->purchase_link ) ? "<a href='" . $this->purchase_link . "'>" : '' ); ?>
270
- <div class="disabled"><img src='<?php echo $this->disabled_image; ?>;' /></div>
271
- <?php echo ( isset($this->purchase_link ) ? "</a>" : '' ); ?>
272
-
273
- <?php
274
-
275
- }
276
- }
277
-
278
- /**
279
- * Generate an option input field name, using the grouped schema:
280
- * "page[option_name]"
281
- * @since 1.2
282
- */
283
- public function get_input_name() {
284
- return esc_attr( $this->page ) . '[' . esc_attr( $this->id ) . ']';
285
- }
286
-
287
- /**
288
- * Add and register this setting
289
- *
290
- * @since 1.0
291
- */
292
- public function add_settings_field( $section_id ) {
293
-
294
- // If no sanitization callback exists, don't register the setting.
295
- if ( !$this->has_sanitize_callback() ) {
296
- return;
297
- }
298
-
299
- add_settings_field(
300
- $this->id,
301
- $this->title,
302
- array( $this, 'display_setting' ),
303
- $this->tab,
304
- $section_id,
305
- $this->args
306
- );
307
-
308
- }
309
-
310
- /**
311
- * Check if this field has a sanitization callback set
312
- * @since 1.2
313
- */
314
- public function has_sanitize_callback() {
315
- if ( isset( $this->sanitize_callback ) && trim( $this->sanitize_callback ) ) {
316
- return true;
317
- }
318
-
319
- return false;
320
- }
321
-
322
- /**
323
- * Set an error
324
- * @since 1.0
325
- */
326
- public function set_error( $error ) {
327
- $this->errors[] = array_merge(
328
- $error,
329
- array(
330
- 'class' => get_class( $this ),
331
- 'id' => $this->id,
332
- 'backtrace' => debug_backtrace()
333
- )
334
- );
335
- }
336
-
337
- /**
338
- * Check if a setting has a position
339
- * @since 2.0.a.9
340
- */
341
- public function has_position() {
342
- return !empty( $this->position ) && is_array( $this->position ) && !empty( $this->position[0] );
343
- }
344
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Register, display and save a setting on a custom admin menu
5
+ *
6
+ * All settings accept the following arguments in their constructor functions.
7
+ *
8
+ * $args = array(
9
+ * 'id' => 'setting_id', // Unique id
10
+ * 'title' => 'My Setting', // Title or label for the setting
11
+ * 'description' => 'Description' // Help text description
12
+ * 'args' => array(); // Arguments to pass to WordPress's add_settings_field() function
13
+ * );
14
+ *
15
+ * @since 1.0
16
+ * @package Simple Admin Pages
17
+ */
18
+
19
+ abstract class sapAdminPageSetting_2_5_5 {
20
+
21
+ // Page defaults
22
+ public $id; // used in form fields and database to track and store setting
23
+ public $title; // setting label
24
+ public $description; // optional description of the setting
25
+ public $value; // value of the setting, if a value exists
26
+ public $disabled = false; // whether a setting should be disabled
27
+ public $small = false; // whether a text input should use the small styling
28
+ public $columns; // to be used for the number of columns for settings, like radio and checkbox, with lots of options/values
29
+
30
+ /**
31
+ * An array of arguments accepted by add_settings_field.
32
+ * See: https://codex.wordpress.org/Function_Reference/add_settings_field
33
+ */
34
+ public $args = array();
35
+
36
+ // Array to store errors
37
+ public $errors = array();
38
+
39
+ /**
40
+ * Position in section
41
+ *
42
+ * An array with two elements describing where this setting should
43
+ * be placed in its section. The first element describes a position
44
+ * and the second (optional) element identifies the id of an
45
+ * existing setting. Examples:
46
+ *
47
+ * array( 'bottom' ) // Default. bottom of section
48
+ * array( 'top' ) // top of section
49
+ * array( 'before', 'my-setting' ) // before a specific setting
50
+ * array( 'after', 'my-setting' ) // after a specific setting
51
+ *
52
+ * This setting is intended for use when you have to hook in after
53
+ * the settings page has been defined, such as adding a new setting
54
+ * from a third-party plugin.
55
+ */
56
+ public $position;
57
+
58
+ /**
59
+ * Function to use when sanitizing the data
60
+ *
61
+ * We set this to a strict sanitization function as a default, but a
62
+ * setting should override this in an extended class when needed.
63
+ *
64
+ * @since 1.0
65
+ */
66
+ public $sanitize_callback = 'sanitize_text_field';
67
+
68
+ /**
69
+ * Scripts that must be loaded for this component
70
+ * @since 2.0.a.4
71
+ */
72
+ public $scripts = array(
73
+ /**
74
+ * Example
75
+ * See: http://codex.wordpress.org/Function_Reference/wp_enqueue_script
76
+ *
77
+ 'handle' => array(
78
+ 'path' => 'path/from/simple-admin-pages/file.js',
79
+ 'dependencies' => array( 'jquery' ),
80
+ 'version' => '3.5.0',
81
+ 'footer' => true,
82
+ ),
83
+ */
84
+ );
85
+
86
+ /**
87
+ * Styles that must be loaded for this component
88
+ * @since 2.0.a.4
89
+ */
90
+ public $styles = array(
91
+ /**
92
+ * Example
93
+ * See: http://codex.wordpress.org/Function_Reference/wp_enqueue_style
94
+ *
95
+ 'handle' => array(
96
+ 'path' => 'path/from/simple-admin-pages/file.css',
97
+ 'dependencies' => 'array( 'another-handle')', // or empty string
98
+ 'version' => '3.5.0',
99
+ 'media' => null,
100
+ ),
101
+ */
102
+ );
103
+
104
+ /**
105
+ * Translateable strings required for this component
106
+ *
107
+ * Settings classes which require translateable strings should be
108
+ * defined with string id's pointing to null values. The actual
109
+ * strings should be passed with the $sap->add_setting() call.
110
+ *
111
+ * @since 2.0.a.8
112
+ */
113
+ public $strings = array(
114
+ /**
115
+ * Example
116
+ *
117
+ 'string_id' => null
118
+ */
119
+ );
120
+
121
+ /**
122
+ * Initialize the setting
123
+ *
124
+ * By default, every setting takes an id, title and description in the $args
125
+ * array.
126
+ *
127
+ * @since 1.0
128
+ */
129
+ public function __construct( $args ) {
130
+
131
+ // Parse the values passed
132
+ $this->parse_args( $args );
133
+
134
+ // Get any existing value
135
+ $this->set_value();
136
+
137
+ // Check for missing data
138
+ $this->missing_data();
139
+ }
140
+
141
+ /**
142
+ * Parse the arguments passed in the construction and assign them to
143
+ * internal variables. This function will be overwritten for most subclasses
144
+ * @since 1.0
145
+ */
146
+ private function parse_args( $args ) {
147
+ foreach ( $args as $key => $val ) {
148
+ switch ( $key ) {
149
+
150
+ case 'id' :
151
+ $this->{$key} = esc_attr( $val );
152
+
153
+ default :
154
+ $this->{$key} = $val;
155
+
156
+ }
157
+ }
158
+ }
159
+
160
+ /**
161
+ * Check for missing data when setup.
162
+ * @since 1.0
163
+ */
164
+ private function missing_data() {
165
+
166
+ $error_type = 'missing_data';
167
+
168
+ // Required fields
169
+ if ( empty( $this->id ) ) {
170
+ $this->set_error(
171
+ array(
172
+ 'type' => $error_type,
173
+ 'data' => 'id'
174
+ )
175
+ );
176
+ }
177
+ if ( empty( $this->title ) ) {
178
+ $this->set_error(
179
+ array(
180
+ 'type' => $error_type,
181
+ 'data' => 'title'
182
+ )
183
+ );
184
+ }
185
+
186
+ // Check for strings
187
+ foreach ( $this->strings as $id => $string ) {
188
+
189
+ if ( $string === null ) {
190
+ $this->set_error(
191
+ array(
192
+ 'type' => $error_type,
193
+ 'data' => 'string: ' . $id,
194
+ )
195
+ );
196
+ }
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Set a value
202
+ * @since 2.0
203
+ */
204
+ public function set_value( $val = null ) {
205
+
206
+ if ( $val === null ) {
207
+ $option_group_value = get_option( $this->page );
208
+ $val = isset( $option_group_value[ $this->id ] ) ? $option_group_value[ $this->id ] : '';
209
+ }
210
+
211
+ $this->value = $this->esc_value( $val );
212
+ }
213
+
214
+ /**
215
+ * Escape the value to display it in text fields and other input fields
216
+ *
217
+ * We use esc_attr() here so that the default is quite strict, but other
218
+ * setting types should override this function with the appropriate escape
219
+ * function. See: http://codex.wordpress.org/Data_Validation
220
+ *
221
+ * @since 1.0
222
+ */
223
+ public function esc_value( $val ) {
224
+
225
+ if ( is_array( $val ) ) { return array_map( 'esc_attr', $val );}
226
+
227
+ return esc_attr( $val );
228
+ }
229
+
230
+ /**
231
+ * Wrapper for the sanitization callback function.
232
+ *
233
+ * This just reduces code duplication for child classes that need a custom
234
+ * callback function.
235
+ * @since 1.0
236
+ */
237
+ public function sanitize_callback_wrapper( $value ) {
238
+ return call_user_func( $this->sanitize_callback, $value );
239
+ }
240
+
241
+ /**
242
+ * Display this setting
243
+ * @since 1.0
244
+ */
245
+ abstract public function display_setting();
246
+
247
+ /**
248
+ * Display a description for this setting
249
+ * @since 1.0
250
+ */
251
+ public function display_description() {
252
+
253
+ if ( !empty( $this->description ) ) {
254
+
255
+ ?>
256
+
257
+ <p class="description<?php echo ( $this->disabled ? ' disabled' : ''); ?>"><?php echo $this->description; ?></p>
258
+
259
+ <?php
260
+
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Display a disabled image for this section and possibly a link to upgrade
266
+ * @since 2.0
267
+ */
268
+ public function display_disabled() {
269
+
270
+ if ( $this->disabled and isset($this->disabled_image) ) {
271
+
272
+ ?>
273
+
274
+ <?php echo ( isset($this->purchase_link ) ? "<a href='" . $this->purchase_link . "'>" : '' ); ?>
275
+ <div class="disabled"><img src='<?php echo $this->disabled_image; ?>;' /></div>
276
+ <?php echo ( isset($this->purchase_link ) ? "</a>" : '' ); ?>
277
+
278
+ <?php
279
+
280
+ }
281
+ }
282
+
283
+ /**
284
+ * Generate an option input field name, using the grouped schema:
285
+ * "page[option_name]"
286
+ * @since 1.2
287
+ */
288
+ public function get_input_name() {
289
+ return esc_attr( $this->page ) . '[' . esc_attr( $this->id ) . ']';
290
+ }
291
+
292
+ /**
293
+ * Get the default value for a setting if value is currently empty
294
+ *
295
+ * @since 2.4.1
296
+ */
297
+ public function get_default_setting() {
298
+ return ! empty( $this->default ) ? $this->default : $this->value;
299
+ }
300
+
301
+ /**
302
+ * Add and register this setting
303
+ *
304
+ * @since 1.0
305
+ */
306
+ public function add_settings_field( $section_id ) {
307
+
308
+ // If no sanitization callback exists, don't register the setting.
309
+ if ( !$this->has_sanitize_callback() ) {
310
+ return;
311
+ }
312
+
313
+ add_settings_field(
314
+ $this->id,
315
+ $this->title,
316
+ array( $this, 'display_setting' ),
317
+ $this->tab,
318
+ $section_id,
319
+ $this->args
320
+ );
321
+
322
+ }
323
+
324
+ /**
325
+ * Check if this field has a sanitization callback set
326
+ * @since 1.2
327
+ */
328
+ public function has_sanitize_callback() {
329
+ if ( isset( $this->sanitize_callback ) && trim( $this->sanitize_callback ) ) {
330
+ return true;
331
+ }
332
+
333
+ return false;
334
+ }
335
+
336
+ /**
337
+ * Set an error
338
+ * @since 1.0
339
+ */
340
+ public function set_error( $error ) {
341
+ $this->errors[] = array_merge(
342
+ $error,
343
+ array(
344
+ 'class' => get_class( $this ),
345
+ 'id' => $this->id,
346
+ 'backtrace' => debug_backtrace()
347
+ )
348
+ );
349
+ }
350
+
351
+ /**
352
+ * Check if a setting has a position
353
+ * @since 2.0.a.9
354
+ */
355
+ public function has_position() {
356
+ return !empty( $this->position ) && is_array( $this->position ) && !empty( $this->position[0] );
357
+ }
358
+ }
lib/simple-admin-pages/classes/Library.class.php CHANGED
@@ -1,462 +1,480 @@
1
- <?php
2
- if ( !class_exists( 'sapLibrary_2_1_2' ) ) {
3
- /**
4
- * This library class loads and provides access to the correct version of the
5
- * Simple Admin Pages library.
6
- *
7
- * @since 1.0
8
- * @package Simple Admin Pages
9
- */
10
- class sapLibrary_2_1_2 {
11
-
12
- // Version of the library
13
- private $version = '2.1.2';
14
-
15
- // A full URL to the library which is used to correctly link scripts and
16
- // stylesheets.
17
- public $lib_url;
18
-
19
- // A relative path to any custom library extension classes. When
20
- // instantiating a custom setting class, the library will search in its own
21
- // directory of classes adn also the $lib_extension_path. This way,
22
- // developers can add on their own classes without mixing them with the
23
- // default classes.
24
- public $lib_extension_path;
25
-
26
- // An array of pages to add to the admin menus
27
- public $pages = array();
28
-
29
- // Collects errors for debugging
30
- public $errors = array();
31
-
32
- // Set debug mode to true to stop and print errors found while processing.
33
- // @note This is not related to your PHP error reporting setting, but is an
34
- // internal error tracking mechanism to catch missing or malformed data
35
- // during development.
36
- public $debug_mode = false;
37
-
38
- /**
39
- * Initialize the library with the appropriate version
40
- * @since 1.0
41
- */
42
- public function __construct( $args ) {
43
-
44
- // If no URL path to the library is passed, we won't be able to add the
45
- // CSS and Javascript to the admin panel
46
- if ( !isset( $args['lib_url'] ) ) {
47
- $this->set_error(
48
- array(
49
- 'id' => 'no-lib-url',
50
- 'desc' => 'No URL path to the library provided when the libary was created.',
51
- 'var' => $args,
52
- 'line' => __LINE__,
53
- 'function' => __FUNCTION__
54
- )
55
- );
56
- } else {
57
- $this->lib_url = $args['lib_url'];
58
- }
59
-
60
- // Set a library extension path if passed
61
- if ( isset( $args['lib_extension_path'] ) ) {
62
- $this->lib_extension_path = $args['lib_extension_path'];
63
- }
64
-
65
- // Set the debug mode
66
- if ( isset( $args['debug_mode'] ) && $args['debug_mode'] === true ) {
67
- $this->debug_mode = true;
68
- }
69
-
70
- // Ensure we have access to WordPress' plugin functions
71
- require_once(ABSPATH . '/wp-admin/includes/plugin.php');
72
-
73
- // Load the required classes
74
- $this->load_class( 'sapAdminPage', 'AdminPage.class.php' );
75
- $this->load_class( 'sapAdminPageSection', 'AdminPageSection.class.php' );
76
- $this->load_class( 'sapAdminPageSetting', 'AdminPageSetting.class.php' );
77
-
78
- // Add the scripts to the admin pages
79
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
80
-
81
- }
82
-
83
- /**
84
- * Load the class if it isn't already loaded
85
- * @since 1.0
86
- */
87
- private function load_class( $class, $file ) {
88
-
89
- if ( !class_exists( $this->get_versioned_classname( $class ) ) ) {
90
- require_once( $file );
91
- }
92
- }
93
-
94
- /**
95
- * Return the version suffix for a class
96
- * @since 1.0
97
- */
98
- private function get_versioned_classname( $class ) {
99
- return $class . '_' . str_replace( '.', '_', $this->version );
100
- }
101
-
102
- /**
103
- * Check if the correct version of a class exists
104
- * @since 1.0
105
- */
106
- private function versioned_class_exists( $class ) {
107
- if ( class_exists( $this->get_versioned_classname( $class ) ) ) {
108
- return true;
109
- } else {
110
- return false;
111
- }
112
- }
113
-
114
- /**
115
- * Load the files for a specific setting type and return the class
116
- * to use when instantiating the setting object.
117
- *
118
- * @since 1.0
119
- */
120
- private function get_setting_classname( $type ) {
121
-
122
- switch( $type ) {
123
-
124
- case 'text' :
125
- require_once('AdminPageSetting.Text.class.php');
126
- return $this->get_versioned_classname( 'sapAdminPageSettingText' );
127
-
128
- case 'colorpicker' :
129
- require_once('AdminPageSetting.ColorPicker.class.php');
130
- return $this->get_versioned_classname( 'sapAdminPageSettingColorPicker' );
131
-
132
- case 'textarea' :
133
- require_once('AdminPageSetting.Textarea.class.php');
134
- return $this->get_versioned_classname( 'sapAdminPageSettingTextarea' );
135
-
136
- case 'select' :
137
- require_once('AdminPageSetting.Select.class.php');
138
- return $this->get_versioned_classname( 'sapAdminPageSettingSelect' );
139
-
140
- case 'toggle' :
141
- require_once('AdminPageSetting.Toggle.class.php');
142
- return $this->get_versioned_classname( 'sapAdminPageSettingToggle' );
143
-
144
- case 'image' :
145
- require_once('AdminPageSetting.Image.class.php');
146
- return $this->get_versioned_classname( 'sapAdminPageSettingImage' );
147
-
148
- case 'radio' :
149
- require_once('AdminPageSetting.Radio.class.php');
150
- return $this->get_versioned_classname( 'sapAdminPageSettingRadio' );
151
-
152
- case 'checkbox' :
153
- require_once('AdminPageSetting.Checkbox.class.php');
154
- return $this->get_versioned_classname( 'sapAdminPageSettingCheckbox' );
155
-
156
- case 'infinite_table' :
157
- require_once('AdminPageSetting.InfiniteTable.class.php');
158
- return $this->get_versioned_classname( 'sapAdminPageSettingInfiniteTable' );
159
-
160
- case 'count' :
161
- require_once('AdminPageSetting.Count.class.php');
162
- return $this->get_versioned_classname( 'sapAdminPageSettingCount' );
163
-
164
- case 'post' :
165
- require_once('AdminPageSetting.SelectPost.class.php');
166
- return $this->get_versioned_classname( 'sapAdminPageSettingSelectPost' );
167
-
168
- case 'menu' :
169
- require_once('AdminPageSetting.SelectMenu.class.php');
170
- return $this->get_versioned_classname( 'sapAdminPageSettingSelectMenu' );
171
-
172
- case 'taxonomy' :
173
- require_once('AdminPageSetting.SelectTaxonomy.class.php');
174
- return $this->get_versioned_classname( 'sapAdminPageSettingSelectTaxonomy' );
175
-
176
- case 'editor' :
177
- require_once('AdminPageSetting.Editor.class.php');
178
- return $this->get_versioned_classname( 'sapAdminPageSettingEditor' );
179
-
180
- case 'html' :
181
- require_once('AdminPageSetting.HTML.class.php');
182
- return $this->get_versioned_classname( 'sapAdminPageSettingHTML' );
183
-
184
- case 'scheduler' :
185
- require_once('AdminPageSetting.Scheduler.class.php');
186
- return $this->get_versioned_classname( 'sapAdminPageSettingScheduler' );
187
-
188
- case 'opening-hours' :
189
- require_once('AdminPageSetting.OpeningHours.class.php');
190
- return $this->get_versioned_classname( 'sapAdminPageSettingOpeningHours' );
191
-
192
- case 'address' :
193
- require_once('AdminPageSetting.Address.class.php');
194
- return $this->get_versioned_classname( 'sapAdminPageSettingAddress' );
195
-
196
- case 'mcapikey' :
197
- require_once('AdminPageSetting.McApiKey.class.php');
198
- return $this->get_versioned_classname( 'mcfrtbAdminPageSettingMcApiKey' );
199
-
200
- case 'mclistmerge' :
201
- require_once('AdminPageSetting.McListMerge.class.php');
202
- return $this->get_versioned_classname( 'mcfrtbAdminPageSettingMcListMerge' );
203
-
204
- default :
205
-
206
- // Exit early if a custom type is declared without providing the
207
- // details to find the type class
208
- if ( ( !is_array( $type ) || !isset( $type['id'] ) ) ||
209
- ( !isset( $type['class'] ) || !isset( $type['filename'] ) ) ) {
210
- return false;
211
- }
212
-
213
- // Load the custom type file. Look for the file in the library's
214
- // folder or check the custom library extension path.
215
- if ( file_exists( $type['filename'] ) ) {
216
- require_once( $type['filename'] );
217
- } elseif ( isset( $this->lib_extension_path ) && file_exists( $this->lib_extension_path . $type['filename'] ) ) {
218
- require_once( $this->lib_extension_path . '/' . $type['filename'] );
219
- if ( !class_exists( $type['class'] ) ) {
220
- return false;
221
- } else {
222
- return $type['class'];
223
- }
224
- } else {
225
- return false;
226
- }
227
-
228
-
229
- // Check that we've loaded the appropriate class
230
- if ( !$this->versioned_class_exists( $type['class'] ) ) {
231
- return false;
232
- }
233
-
234
- return $this->get_versioned_classname( $type['class'] );
235
-
236
- }
237
-
238
- }
239
-
240
- /**
241
- * Initialize a page
242
- * @since 1.0
243
- *
244
- * @todo perform some checks on args to ensure a valid page can be constructed
245
- */
246
- public function add_page( $menu_location, $args = array() ) {
247
-
248
- // default should be 'options'
249
- $class = $this->get_versioned_classname( 'sapAdminPage' );
250
-
251
- if ( $menu_location == 'themes' ) {
252
- $this->load_class( 'sapAdminPageThemes', 'AdminPage.Themes.class.php' );
253
- $class = $this->get_versioned_classname( 'sapAdminPageThemes' );
254
- } elseif ( $menu_location == 'menu' ) {
255
- $this->load_class( 'sapAdminPageMenu', 'AdminPage.Menu.class.php' );
256
- $class = $this->get_versioned_classname( 'sapAdminPageMenu' );
257
- } elseif ( $menu_location == 'submenu' ) {
258
- $this->load_class( 'sapAdminPageSubmenu', 'AdminPage.Submenu.class.php' );
259
- $class = $this->get_versioned_classname( 'sapAdminPageSubmenu' );
260
- }
261
-
262
- if ( class_exists( $class ) ) {
263
- $this->pages[ $args['id'] ] = new $class( $args );
264
- }
265
-
266
- }
267
-
268
- /**
269
- * Initialize a section
270
- * @since 1.0
271
- *
272
- * @todo perform some checks on args to ensure a valid section can be constructed
273
- */
274
- public function add_section( $page, $args = array() ) {
275
-
276
- if ( !isset( $this->pages[ $page ] ) ) {
277
- return false;
278
- } else {
279
- $args['page'] = $page;
280
- }
281
-
282
- $class = $this->get_versioned_classname( 'sapAdminPageSection' );
283
- if ( class_exists( $class ) ) {
284
- $this->pages[ $page ]->add_section( new $class( $args ) );
285
- }
286
-
287
- }
288
-
289
- /**
290
- * Initialize a setting
291
- *
292
- * The type variable can be a string pointing to a pre-defined setting type,
293
- * or an array consisting of an id, classname and filename which references
294
- * a custom setting type. @sa get_setting_classname()
295
- *
296
- * @since 1.0
297
- */
298
- public function add_setting( $page, $section, $type, $args = array() ) {
299
-
300
- if ( !isset( $this->pages[ $page ] ) || !isset( $this->pages[ $page ]->sections[ $section ] ) ) {
301
- return false;
302
- } else {
303
- $args['page'] = $page;
304
- $args['tab'] = $this->pages[$page]->sections[ $section ]->get_page_slug();
305
- }
306
-
307
- $class = $this->get_setting_classname( $type );
308
- if ( $class && class_exists( $class ) ) {
309
- $this->pages[ $page ]->sections[ $section ]->add_setting( new $class( $args ) );
310
- }
311
-
312
- }
313
-
314
- /**
315
- * Register all page, section and settings content with WordPress
316
- * @since 1.0
317
- */
318
- public function add_admin_menus() {
319
-
320
- // If the library is run in debug mode, check for any errors in content,
321
- // print any errors found, and don't add the menu if there are errors
322
- if ( $this->debug_mode ) {
323
- $errors = array();
324
- foreach ( $this->pages as $page ) {
325
- foreach ( $page->sections as $section ) {
326
- if ( count( $section->errors ) ) {
327
- array_merge( $errors, $section->errors );
328
- }
329
- foreach ( $section->settings as $setting ) {
330
- if ( count( $setting->errors ) ) {
331
- $errors = array_merge( $errors, $setting->errors );
332
- }
333
- }
334
- }
335
- }
336
- if ( count( $errors ) ) {
337
- print_r( $errors );
338
- return;
339
- }
340
- }
341
-
342
- // Add the action hooks
343
- foreach ( $this->pages as $id => $page ) {
344
- add_action( 'admin_menu', array( $page, 'add_admin_menu' ) );
345
- add_action( 'admin_init', array( $page, 'register_admin_menu' ) );
346
- }
347
- }
348
-
349
- /**
350
- * Port data from a previous version to the current version
351
- *
352
- * Version 2.0 of the library changes the structure of how it stores data.
353
- * In order to upgrade the version of the library your plugin/theme is
354
- * using, this method must be called after all of your pages and settings
355
- * have been declared but before you run add_admin_menus().
356
- *
357
- * This method will loop over all of the settings data and port any existing
358
- * data to the new data structure. It will check if the data has been ported
359
- * first before it updates the data. The old data will be removed to keep
360
- * the database clean.
361
- *
362
- * @var int target_version Which data version the library should update to.
363
- * @since 2.0
364
- */
365
- public function port_data( $target_version, $delete_old_data = true ) {
366
-
367
- // Port data to the storage structure in version 2
368
- if ( $target_version == 2 ) {
369
-
370
- foreach ( $this->pages as $page_id => $page ) {
371
-
372
- // Skip if this page has already been ported
373
- if ( get_option( $page_id ) !== false ) {
374
- continue;
375
- }
376
-
377
- $page_values = array();
378
-
379
- foreach ( $page->sections as $section ) {
380
- foreach ( $section->settings as $setting ) {
381
- $value = get_option( $setting->id );
382
- if ( $value !== false ) {
383
- $page_values[ $setting->id ] = $value;
384
- }
385
- }
386
- }
387
-
388
- if ( count( $page_values ) ) {
389
- $result = add_option( $page_id, $page_values );
390
-
391
- // Delete old data if the flag is set and the new data was
392
- // saved successfully.
393
- if ( $delete_old_data === true && $result !== false ) {
394
- foreach( $page_values as $setting_id => $setting_value ) {
395
- delete_option( $setting_id );
396
- }
397
- }
398
-
399
- // Reset settings values
400
- if ( $result === true ) {
401
-
402
- foreach ( $page->sections as $section ) {
403
- foreach ( $section->settings as $setting ) {
404
- $setting->set_value();
405
- }
406
- }
407
-
408
- }
409
- }
410
- }
411
- }
412
-
413
- }
414
-
415
- /**
416
- * Enqueue the stylesheets and scripts
417
- * @since 1.0
418
- */
419
- public function enqueue_scripts() {
420
-
421
- $screen = get_current_screen();
422
-
423
- foreach ( $this->pages as $page_id => $page ) {
424
-
425
- // Only enqueue assets for the current page
426
- if ( strpos( $screen->base, $page_id ) !== false ) {
427
- wp_enqueue_style( 'sap-admin-style-' . $this->version, $this->lib_url . 'css/admin.css', array(), BPFWP_VERSION );
428
- wp_enqueue_style( 'bpfwp-admin-css' . $this->version, plugins_url('business-profile/assets/css/admin.css'), array(), BPFWP_VERSION );
429
- wp_enqueue_script( 'bpfwp-admin-js' . $this->version, plugins_url('business-profile/assets/js/admin.js'), array('jquery'), BPFWP_VERSION );
430
- wp_enqueue_media();
431
-
432
- foreach ( $page->sections as $section ) {
433
- foreach ( $section->settings as $setting ) {
434
- foreach( $setting->scripts as $handle => $script ) {
435
- wp_enqueue_script( $handle, $this->lib_url . $script['path'], $script['dependencies'], $script['version'], $script['footer'] );
436
- }
437
- foreach( $setting->styles as $handle => $style ) {
438
- wp_enqueue_style( $handle, $this->lib_url . $style['path'], $style['dependencies'], $style['version'], $style['media'] );
439
- }
440
- }
441
- }
442
- }
443
- }
444
- }
445
-
446
- /**
447
- * Set an error
448
- * @since 1.0
449
- */
450
- public function set_error( $error ) {
451
- $this->errors[] = array_merge(
452
- $error,
453
- array(
454
- 'class' => get_class( $this ),
455
- 'id' => $this->id,
456
- 'backtrace' => debug_backtrace()
457
- )
458
- );
459
- }
460
-
461
- }
462
- } // endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ if ( !class_exists( 'sapLibrary_2_5_5' ) ) {
3
+ /**
4
+ * This library class loads and provides access to the correct version of the
5
+ * Simple Admin Pages library.
6
+ *
7
+ * @since 1.0
8
+ * @package Simple Admin Pages
9
+ */
10
+ class sapLibrary_2_5_5 {
11
+
12
+ // Version of the library
13
+ private $version = '2.5.5';
14
+
15
+ // A full URL to the library which is used to correctly link scripts and
16
+ // stylesheets.
17
+ public $lib_url;
18
+
19
+ // A relative path to any custom library extension classes. When
20
+ // instantiating a custom setting class, the library will search in its own
21
+ // directory of classes adn also the $lib_extension_path. This way,
22
+ // developers can add on their own classes without mixing them with the
23
+ // default classes.
24
+ public $lib_extension_path;
25
+
26
+ // An array of pages to add to the admin menus
27
+ public $pages = array();
28
+
29
+ // Collects errors for debugging
30
+ public $errors = array();
31
+
32
+ // Set debug mode to true to stop and print errors found while processing.
33
+ // @note This is not related to your PHP error reporting setting, but is an
34
+ // internal error tracking mechanism to catch missing or malformed data
35
+ // during development.
36
+ public $debug_mode = false;
37
+
38
+ /**
39
+ * Initialize the library with the appropriate version
40
+ * @since 1.0
41
+ */
42
+ public function __construct( $args ) {
43
+
44
+ if ( ! defined( 'SAP_VERSION' ) ) {
45
+ define( 'SAP_VERSION', '2.5.5' );
46
+ }
47
+
48
+ // If no URL path to the library is passed, we won't be able to add the
49
+ // CSS and Javascript to the admin panel
50
+ if ( !isset( $args['lib_url'] ) ) {
51
+ $this->set_error(
52
+ array(
53
+ 'id' => 'no-lib-url',
54
+ 'desc' => 'No URL path to the library provided when the libary was created.',
55
+ 'var' => $args,
56
+ 'line' => __LINE__,
57
+ 'function' => __FUNCTION__
58
+ )
59
+ );
60
+ } else {
61
+ $this->lib_url = $args['lib_url'];
62
+ }
63
+
64
+ // Set a library extension path if passed
65
+ if ( isset( $args['lib_extension_path'] ) ) {
66
+ $this->lib_extension_path = $args['lib_extension_path'];
67
+ }
68
+
69
+ // Set the debug mode
70
+ if ( isset( $args['debug_mode'] ) && $args['debug_mode'] === true ) {
71
+ $this->debug_mode = true;
72
+ }
73
+
74
+ // Ensure we have access to WordPress' plugin functions
75
+ require_once(ABSPATH . '/wp-admin/includes/plugin.php');
76
+
77
+ // Load the required classes
78
+ $this->load_class( 'sapAdminPage', 'AdminPage.class.php' );
79
+ $this->load_class( 'sapAdminPageSection', 'AdminPageSection.class.php' );
80
+ $this->load_class( 'sapAdminPageSetting', 'AdminPageSetting.class.php' );
81
+
82
+ // Add the scripts to the admin pages
83
+ add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
84
+
85
+ }
86
+
87
+ /**
88
+ * Load the class if it isn't already loaded
89
+ * @since 1.0
90
+ */
91
+ private function load_class( $class, $file ) {
92
+
93
+ if ( !class_exists( $this->get_versioned_classname( $class ) ) ) {
94
+ require_once( $file );
95
+ }
96
+ }
97
+
98
+ /**
99
+ * Return the version suffix for a class
100
+ * @since 1.0
101
+ */
102
+ private function get_versioned_classname( $class ) {
103
+ return $class . '_' . str_replace( '.', '_', $this->version );
104
+ }
105
+
106
+ /**
107
+ * Check if the correct version of a class exists
108
+ * @since 1.0
109
+ */
110
+ private function versioned_class_exists( $class ) {
111
+ if ( class_exists( $this->get_versioned_classname( $class ) ) ) {
112
+ return true;
113
+ } else {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Load the files for a specific setting type and return the class
120
+ * to use when instantiating the setting object.
121
+ *
122
+ * @since 1.0
123
+ */
124
+ public function get_setting_classname( $type ) {
125
+
126
+ switch( $type ) {
127
+
128
+ case 'text' :
129
+ require_once('AdminPageSetting.Text.class.php');
130
+ return $this->get_versioned_classname( 'sapAdminPageSettingText' );
131
+
132
+ case 'number' :
133
+ require_once('AdminPageSetting.Number.class.php');
134
+ return $this->get_versioned_classname( 'sapAdminPageSettingNumber' );
135
+
136
+ case 'colorpicker' :
137
+ require_once('AdminPageSetting.ColorPicker.class.php');
138
+ return $this->get_versioned_classname( 'sapAdminPageSettingColorPicker' );
139
+
140
+ case 'textarea' :
141
+ require_once('AdminPageSetting.Textarea.class.php');
142
+ return $this->get_versioned_classname( 'sapAdminPageSettingTextarea' );
143
+
144
+ case 'select' :
145
+ require_once('AdminPageSetting.Select.class.php');
146
+ return $this->get_versioned_classname( 'sapAdminPageSettingSelect' );
147
+
148
+ case 'toggle' :
149
+ require_once('AdminPageSetting.Toggle.class.php');
150
+ return $this->get_versioned_classname( 'sapAdminPageSettingToggle' );
151
+
152
+ case 'image' :
153
+ require_once('AdminPageSetting.Image.class.php');
154
+ return $this->get_versioned_classname( 'sapAdminPageSettingImage' );
155
+
156
+ case 'radio' :
157
+ require_once('AdminPageSetting.Radio.class.php');
158
+ return $this->get_versioned_classname( 'sapAdminPageSettingRadio' );
159
+
160
+ case 'checkbox' :
161
+ require_once('AdminPageSetting.Checkbox.class.php');
162
+ return $this->get_versioned_classname( 'sapAdminPageSettingCheckbox' );
163
+
164
+ case 'infinite_table' :
165
+ require_once('AdminPageSetting.InfiniteTable.class.php');
166
+ return $this->get_versioned_classname( 'sapAdminPageSettingInfiniteTable' );
167
+
168
+ case 'count' :
169
+ require_once('AdminPageSetting.Count.class.php');
170
+ return $this->get_versioned_classname( 'sapAdminPageSettingCount' );
171
+
172
+ case 'post' :
173
+ require_once('AdminPageSetting.SelectPost.class.php');
174
+ return $this->get_versioned_classname( 'sapAdminPageSettingSelectPost' );
175
+
176
+ case 'menu' :
177
+ require_once('AdminPageSetting.SelectMenu.class.php');
178
+ return $this->get_versioned_classname( 'sapAdminPageSettingSelectMenu' );
179
+
180
+ case 'taxonomy' :
181
+ require_once('AdminPageSetting.SelectTaxonomy.class.php');
182
+ return $this->get_versioned_classname( 'sapAdminPageSettingSelectTaxonomy' );
183
+
184
+ case 'editor' :
185
+ require_once('AdminPageSetting.Editor.class.php');
186
+ return $this->get_versioned_classname( 'sapAdminPageSettingEditor' );
187
+
188
+ case 'html' :
189
+ require_once('AdminPageSetting.HTML.class.php');
190
+ return $this->get_versioned_classname( 'sapAdminPageSettingHTML' );
191
+
192
+ case 'scheduler' :
193
+ require_once('AdminPageSetting.Scheduler.class.php');
194
+ return $this->get_versioned_classname( 'sapAdminPageSettingScheduler' );
195
+
196
+ case 'opening-hours' :
197
+ require_once('AdminPageSetting.OpeningHours.class.php');
198
+ return $this->get_versioned_classname( 'sapAdminPageSettingOpeningHours' );
199
+
200
+ case 'address' :
201
+ require_once('AdminPageSetting.Address.class.php');
202
+ return $this->get_versioned_classname( 'sapAdminPageSettingAddress' );
203
+
204
+ case 'file-upload' :
205
+ require_once('AdminPageSetting.FileUpload.class.php');
206
+ return $this->get_versioned_classname( 'sapAdminPageSettingFileUpload' );
207
+
208
+ case 'ordering-table' :
209
+ require_once('AdminPageSetting.Ordering.class.php');
210
+ return $this->get_versioned_classname( 'sapAdminPageSettingOrdering' );
211
+
212
+ case 'mcapikey' :
213
+ require_once('AdminPageSetting.McApiKey.class.php');
214
+ return $this->get_versioned_classname( 'mcfrtbAdminPageSettingMcApiKey' );
215
+
216
+ case 'mclistmerge' :
217
+ require_once('AdminPageSetting.McListMerge.class.php');
218
+ return $this->get_versioned_classname( 'mcfrtbAdminPageSettingMcListMerge' );
219
+
220
+ default :
221
+
222
+ // Exit early if a custom type is declared without providing the
223
+ // details to find the type class
224
+ if ( ( !is_array( $type ) || !isset( $type['id'] ) ) ||
225
+ ( !isset( $type['class'] ) || !isset( $type['filename'] ) ) ) {
226
+ return false;
227
+ }
228
+
229
+ // Load the custom type file. Look for the file in the library's
230
+ // folder or check the custom library extension path.
231
+ if ( file_exists( $type['filename'] ) ) {
232
+ require_once( $type['filename'] );
233
+ } elseif ( isset( $this->lib_extension_path ) && file_exists( $this->lib_extension_path . $type['filename'] ) ) {
234
+ require_once( $this->lib_extension_path . '/' . $type['filename'] );
235
+ if ( !class_exists( $type['class'] ) ) {
236
+ return false;
237
+ } else {
238
+ return $type['class'];
239
+ }
240
+ } else {
241
+ return false;
242
+ }
243
+
244
+
245
+ // Check that we've loaded the appropriate class
246
+ if ( !$this->versioned_class_exists( $type['class'] ) ) {
247
+ return false;
248
+ }
249
+
250
+ return $this->get_versioned_classname( $type['class'] );
251
+
252
+ }
253
+
254
+ }
255
+
256
+ /**
257
+ * Initialize a page
258
+ * @since 1.0
259
+ *
260
+ * @todo perform some checks on args to ensure a valid page can be constructed
261
+ */
262
+ public function add_page( $menu_location, $args = array() ) {
263
+
264
+ // default should be 'options'
265
+ $class = $this->get_versioned_classname( 'sapAdminPage' );
266
+
267
+ if ( $menu_location == 'themes' ) {
268
+ $this->load_class( 'sapAdminPageThemes', 'AdminPage.Themes.class.php' );
269
+ $class = $this->get_versioned_classname( 'sapAdminPageThemes' );
270
+ } elseif ( $menu_location == 'menu' ) {
271
+ $this->load_class( 'sapAdminPageMenu', 'AdminPage.Menu.class.php' );
272
+ $class = $this->get_versioned_classname( 'sapAdminPageMenu' );
273
+ } elseif ( $menu_location == 'submenu' ) {
274
+ $this->load_class( 'sapAdminPageSubmenu', 'AdminPage.Submenu.class.php' );
275
+ $class = $this->get_versioned_classname( 'sapAdminPageSubmenu' );
276
+ }
277
+
278
+ if ( class_exists( $class ) ) {
279
+ $this->pages[ $args['id'] ] = new $class( $args );
280
+ }
281
+
282
+ }
283
+
284
+ /**
285
+ * Initialize a section
286
+ * @since 1.0
287
+ *
288
+ * @todo perform some checks on args to ensure a valid section can be constructed
289
+ */
290
+ public function add_section( $page, $args = array() ) {
291
+
292
+ if ( !isset( $this->pages[ $page ] ) ) {
293
+ return false;
294
+ } else {
295
+ $args['page'] = $page;
296
+ }
297
+
298
+ $class = $this->get_versioned_classname( 'sapAdminPageSection' );
299
+ if ( class_exists( $class ) ) {
300
+ $this->pages[ $page ]->add_section( new $class( $args ) );
301
+ }
302
+
303
+ }
304
+
305
+ /**
306
+ * Initialize a setting
307
+ *
308
+ * The type variable can be a string pointing to a pre-defined setting type,
309
+ * or an array consisting of an id, classname and filename which references
310
+ * a custom setting type. @sa get_setting_classname()
311
+ *
312
+ * @since 1.0
313
+ */
314
+ public function add_setting( $page, $section, $type, $args = array() ) {
315
+
316
+ if ( !isset( $this->pages[ $page ] ) || !isset( $this->pages[ $page ]->sections[ $section ] ) ) {
317
+ return false;
318
+ } else {
319
+ $args['page'] = $page;
320
+ $args['tab'] = $this->pages[$page]->sections[ $section ]->get_page_slug();
321
+ }
322
+
323
+ $class = $this->get_setting_classname( $type );
324
+ if ( $class && class_exists( $class ) ) {
325
+ $this->pages[ $page ]->sections[ $section ]->add_setting( new $class( $args ) );
326
+ }
327
+
328
+ }
329
+
330
+ /**
331
+ * Register all page, section and settings content with WordPress
332
+ * @since 1.0
333
+ */
334
+ public function add_admin_menus() {
335
+
336
+ // If the library is run in debug mode, check for any errors in content,
337
+ // print any errors found, and don't add the menu if there are errors
338
+ if ( $this->debug_mode ) {
339
+ $errors = array();
340
+ foreach ( $this->pages as $page ) {
341
+ foreach ( $page->sections as $section ) {
342
+ if ( count( $section->errors ) ) {
343
+ array_merge( $errors, $section->errors );
344
+ }
345
+ foreach ( $section->settings as $setting ) {
346
+ if ( count( $setting->errors ) ) {
347
+ $errors = array_merge( $errors, $setting->errors );
348
+ }
349
+ }
350
+ }
351
+ }
352
+ if ( count( $errors ) ) {
353
+ print_r( $errors );
354
+ return;
355
+ }
356
+ }
357
+
358
+ // Add the action hooks
359
+ foreach ( $this->pages as $id => $page ) {
360
+ add_action( 'admin_menu', array( $page, 'add_admin_menu' ) );
361
+ add_action( 'admin_init', array( $page, 'register_admin_menu' ) );
362
+ }
363
+ }
364
+
365
+ /**
366
+ * Port data from a previous version to the current version
367
+ *
368
+ * Version 2.0 of the library changes the structure of how it stores data.
369
+ * In order to upgrade the version of the library your plugin/theme is
370
+ * using, this method must be called after all of your pages and settings
371
+ * have been declared but before you run add_admin_menus().
372
+ *
373
+ * This method will loop over all of the settings data and port any existing
374
+ * data to the new data structure. It will check if the data has been ported
375
+ * first before it updates the data. The old data will be removed to keep
376
+ * the database clean.
377
+ *
378
+ * @var int target_version Which data version the library should update to.
379
+ * @since 2.0
380
+ */
381
+ public function port_data( $target_version, $delete_old_data = true ) {
382
+
383
+ // Port data to the storage structure in version 2
384
+ if ( $target_version == 2 ) {
385
+
386
+ foreach ( $this->pages as $page_id => $page ) {
387
+
388
+ // Skip if this page has already been ported
389
+ if ( get_option( $page_id ) !== false ) {
390
+ continue;
391
+ }
392
+
393
+ $page_values = array();
394
+
395
+ foreach ( $page->sections as $section ) {
396
+ foreach ( $section->settings as $setting ) {
397
+ $value = get_option( $setting->id );
398
+ if ( $value !== false ) {
399
+ $page_values[ $setting->id ] = $value;
400
+ }
401
+ }
402
+ }
403
+
404
+ if ( count( $page_values ) ) {
405
+ $result = add_option( $page_id, $page_values );
406
+
407
+ // Delete old data if the flag is set and the new data was
408
+ // saved successfully.
409
+ if ( $delete_old_data === true && $result !== false ) {
410
+ foreach( $page_values as $setting_id => $setting_value ) {
411
+ delete_option( $setting_id );
412
+ }
413
+ }
414
+
415
+ // Reset settings values
416
+ if ( $result === true ) {
417
+
418
+ foreach ( $page->sections as $section ) {
419
+ foreach ( $section->settings as $setting ) {
420
+ $setting->set_value();
421
+ }
422
+ }
423
+
424
+ }
425
+ }
426
+ }
427
+ }
428
+
429
+ }
430
+
431
+ /**
432
+ * Enqueue the stylesheets and scripts
433
+ * @since 1.0
434
+ */
435
+ public function enqueue_scripts() {
436
+
437
+ $screen = get_current_screen();
438
+
439
+ foreach ( $this->pages as $page_id => $page ) {
440
+
441
+ // Only enqueue assets for the current page
442
+ if ( strpos( $screen->base, $page_id ) !== false ) {
443
+ wp_enqueue_style( 'sap-admin-style-' . $this->version, $this->lib_url . 'css/admin.css', array(), $this->version );
444
+ wp_enqueue_style( 'sap-spectrum-css-' . $this->version, $this->lib_url . 'css/spectrum.css', array(), $this->version );
445
+ wp_enqueue_style( 'sap-admin-settings-css-' . $this->version, $this->lib_url . 'css/admin-settings.css', array(), $this->version );
446
+ wp_enqueue_script( 'sap-spectrum-js-' . $this->version, $this->lib_url . 'js/spectrum.js', array( 'jquery' ), $this->version );
447
+ wp_enqueue_script( 'sap-admin-settings-js-' . $this->version, $this->lib_url . 'js/admin-settings.js', array( 'jquery', 'sap-spectrum-js-' . $this->version ), $this->version );
448
+ wp_enqueue_media();
449
+
450
+ foreach ( $page->sections as $section ) {
451
+ foreach ( $section->settings as $setting ) {
452
+ foreach( $setting->scripts as $handle => $script ) {
453
+ wp_enqueue_script( $handle, $this->lib_url . $script['path'], $script['dependencies'], $script['version'], $script['footer'] );
454
+ }
455
+ foreach( $setting->styles as $handle => $style ) {
456
+ wp_enqueue_style( $handle, $this->lib_url . $style['path'], $style['dependencies'], $style['version'], $style['media'] );
457
+ }
458
+ }
459
+ }
460
+ }
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Set an error
466
+ * @since 1.0
467
+ */
468
+ public function set_error( $error ) {
469
+ $this->errors[] = array_merge(
470
+ $error,
471
+ array(
472
+ 'class' => get_class( $this ),
473
+ 'id' => $this->id,
474
+ 'backtrace' => debug_backtrace()
475
+ )
476
+ );
477
+ }
478
+
479
+ }
480
+ } // endif;
lib/simple-admin-pages/css/admin-settings.css ADDED
@@ -0,0 +1,658 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /************************/
2
+ /***** OPTIONS PAGE *****/
3
+ /************************/
4
+
5
+ .wrap.sap-settings-page h1 {
6
+ width: 100%;
7
+ }
8
+
9
+ /* Side Menu */
10
+ .wrap.sap-settings-page h2.nav-tab-wrapper {
11
+ position: relative;
12
+ float: left;
13
+ border: none;
14
+ width: 180px;
15
+ box-shadow: -1px 1px 8px #ccc;
16
+ overflow: hidden;
17
+ padding-top: 0;
18
+ margin-top: 20px;
19
+ }
20
+ .wrap.sap-settings-page h2.nav-tab-wrapper a {
21
+ clear: both;
22
+ display: block;
23
+ position: relative;
24
+ float: left;
25
+ background-color: #e2e2e2;
26
+ border: none;
27
+ border-bottom: 1px solid #f1f1f1;
28
+ color: #555;
29
+ font-weight: bold;
30
+ padding-left: 20px;
31
+ width: calc(100% - 20px);
32
+ text-align: left;
33
+ margin: 0;
34
+ height: 34px;
35
+ line-height: 34px;
36
+ font-size: 13px;
37
+ }
38
+ .wrap.sap-settings-page h2.nav-tab-wrapper a:last-of-type {
39
+ border-bottom: none;
40
+ }
41
+ .wrap.sap-settings-page h2.nav-tab-wrapper a.nav-tab-active {
42
+ box-shadow: none;
43
+ background-color: #fff !important;
44
+ color: #1b335f;
45
+ border-left: 4px solid #1b335f;
46
+ }
47
+ .wrap.sap-settings-page h2.nav-tab-wrapper a:hover {
48
+ color: #1b335f;
49
+ background-color: rgba(199,199,199, 0.5);
50
+ box-shadow: none;
51
+ border-left: 4px solid #1b335f;
52
+ }
53
+ .wrap.sap-settings-page h2.nav-tab-wrapper a.nav-tab-active:hover {
54
+ color: #1b335f;
55
+ background-color: #fff;
56
+ border-left: 4px solid #1b335f;
57
+ }
58
+
59
+ /* Right side */
60
+ .wrap.sap-settings-page form {
61
+ display: block;
62
+ position: relative;
63
+ float: left;
64
+ width: calc(100% - 276px);
65
+ padding: 32px 48px;
66
+ z-index: 999;
67
+ background:#fff;
68
+ margin: 20px 0 0 !important;
69
+ min-height: 400px;
70
+ border: none;
71
+ }
72
+
73
+ .wrap.sap-settings-page form h2:first-of-type {
74
+ font-size: 18px;
75
+ color: #1b335f;
76
+ margin: 0 0 32px !important;
77
+ }
78
+
79
+ .wrap.sap-settings-page form h2:nth-of-type(1n+2) {
80
+ position: relative;
81
+ float: left;
82
+ background: #1b335f;
83
+ margin: 8px 0 0;
84
+ font-size: 15px;
85
+ font-weight: bold;
86
+ color: #fff;
87
+ padding: 12px 2%;
88
+ width: 96%;
89
+ text-transform: uppercase;
90
+ z-index: 2;
91
+ }
92
+ .wrap.sap-settings-page form .form-table {
93
+ width: 100%;
94
+ box-sizing: border-box;
95
+ margin: 0 auto 16px;
96
+ box-shadow: 0 1px 12px #ddd;
97
+ display: block;
98
+ padding: 11px 5%;
99
+ }
100
+ .wrap.sap-settings-page form .form-table tr {
101
+ width: 20%;
102
+ }
103
+ .wrap.sap-settings-page form .form-table td {
104
+ width: 80%;
105
+ }
106
+
107
+ .wrap.sap-settings-page form p.description {
108
+ display: none;
109
+ }
110
+ .wrap.sap-settings-page form .form-table p.description {
111
+ display: block;
112
+ }
113
+ .wrap.sap-settings-page form .form-table p.description.disabled {
114
+ color: #b5b5b5;
115
+ }
116
+
117
+
118
+ .ulb-premium-options-table-overlay + table th,
119
+ .ulb-premium-options-table-overlay + table td {
120
+ color: #b5b5b5;
121
+ }
122
+
123
+
124
+
125
+ /************************
126
+ TOGGLE SWITCHES
127
+ ************************/
128
+ .sap-admin-hide-radios {
129
+ display: none;
130
+ }
131
+
132
+ /* The switch - the box around the slider */
133
+ .sap-admin-switch {
134
+ position: relative;
135
+ display: inline-block;
136
+ width: 40px;
137
+ height: 22px;
138
+ }
139
+
140
+ /* Hide default HTML checkbox */
141
+ .sap-admin-switch input {
142
+ display: none;
143
+ }
144
+
145
+ /* The slider */
146
+ .sap-admin-switch-slider {
147
+ position: absolute;
148
+ cursor: pointer;
149
+ top: 0;
150
+ left: 0;
151
+ right: 0;
152
+ bottom: 0;
153
+ background-color: #ccc;
154
+ -webkit-transition: .4s;
155
+ transition: .4s;
156
+ }
157
+
158
+ .sap-admin-switch-slider:before {
159
+ position: absolute;
160
+ content: "";
161
+ height: 14px;
162
+ width: 14px;
163
+ left: 4px;
164
+ bottom: 4px;
165
+ background-color: white;
166
+ -webkit-transition: .4s;
167
+ transition: .4s;
168
+ }
169
+
170
+ input:checked + .sap-admin-switch-slider {
171
+ background-color: #1b335f;
172
+ }
173
+
174
+ input:focus + .sap-admin-switch-slider {
175
+ box-shadow: 0 0 1px #1b335f;
176
+ }
177
+
178
+ input:checked + .sap-admin-switch-slider:before {
179
+ -webkit-transform: translateX(18px);
180
+ -ms-transform: translateX(18px);
181
+ transform: translateX(18px);
182
+ }
183
+
184
+ /* Rounded sliders */
185
+ .sap-admin-switch-slider.round {
186
+ border-radius: 34px;
187
+ }
188
+
189
+ .sap-admin-switch-slider.round:before {
190
+ border-radius: 50%;
191
+ }
192
+
193
+
194
+ /* RADIO BUTTON AND CHECKBOX */
195
+ .wrap.sap-settings-page form .form-table fieldset label {
196
+ line-height: 1.4em;
197
+ margin: .25em 0 .5em;
198
+ display: inline-block;
199
+ font-size: 14px;
200
+ }
201
+
202
+ .sap-admin-input-container input, .sap-admin-input-container input:disabled {
203
+ position: absolute;
204
+ opacity: 0;
205
+ }
206
+ .sap-admin-radio-button {
207
+ position: relative;
208
+ float: left;
209
+ height: 14px;
210
+ width: 14px;
211
+ top: 1px;
212
+ margin-right: 12px;
213
+ background-color: #fff;
214
+ border: 2px solid #aaa;
215
+ border-radius: 50%;
216
+ }
217
+ .sap-admin-input-container:hover input ~ .sap-admin-radio-button {
218
+ background-color: #E6FFFB;
219
+ border-color: #1b335f;
220
+ }
221
+ .sap-admin-input-container input:checked ~ .sap-admin-radio-button {
222
+ border-color: #1b335f;
223
+ background-color: #fff;
224
+ }
225
+ .sap-admin-radio-button:after {
226
+ content: "";
227
+ position: absolute;
228
+ display: none;
229
+ }
230
+ .sap-admin-input-container input:checked ~ .sap-admin-radio-button:after {
231
+ display: block;
232
+ }
233
+ .sap-admin-input-container .sap-admin-radio-button:after {
234
+ top: 3px;
235
+ left: 3px;
236
+ width: 8px;
237
+ height: 8px;
238
+ border-radius: 50%;
239
+ background: #1b335f;
240
+ }
241
+
242
+ .sap-admin-checkbox {
243
+ position: relative;
244
+ float: left;
245
+ height: 14px;
246
+ width: 14px;
247
+ top: 1px;
248
+ margin-right: 12px;
249
+ background-color: #fff;
250
+ border: 2px solid #aaa;
251
+ }
252
+ .sap-admin-input-container:hover input ~ .sap-admin-checkbox {
253
+ background-color: #E6FFFB;
254
+ border-color: #1b335f;
255
+ }
256
+ .sap-admin-input-container input:checked ~ .sap-admin-checkbox {
257
+ border-color: #1b335f;
258
+ background-color: #fff;
259
+ }
260
+ .sap-admin-checkbox:after {
261
+ content: "";
262
+ position: absolute;
263
+ display: none;
264
+ }
265
+ .sap-admin-input-container input:checked ~ .sap-admin-checkbox:after {
266
+ display: block;
267
+ }
268
+ .sap-admin-input-container .sap-admin-checkbox:after {
269
+ left: 4px;
270
+ top: 1px;
271
+ width: 4px;
272
+ height: 8px;
273
+ border: solid #1b335f;
274
+ border-width: 0 2px 2px 0;
275
+ -webkit-transform: rotate(45deg);
276
+ -ms-transform: rotate(45deg);
277
+ transform: rotate(45deg);
278
+ }
279
+
280
+ /* Textbox and Text Area and Select boxes */
281
+ .wrap.sap-settings-page form .form-table input[type=text],
282
+ .wrap.sap-settings-page form .form-table input[type=search],
283
+ .wrap.sap-settings-page form .form-table input[type=tel],
284
+ .wrap.sap-settings-page form .form-table input[type=url],
285
+ .wrap.sap-settings-page form .form-table input[type=week],
286
+ .wrap.sap-settings-page form .form-table input[type=password],
287
+ .wrap.sap-settings-page form .form-table input[type=color],
288
+ .wrap.sap-settings-page form .form-table input[type=email],
289
+ .wrap.sap-settings-page form .form-table input[type=number],
290
+ .wrap.sap-settings-page form .form-table textarea,
291
+ .wrap.sap-settings-page form .form-table select {
292
+ border: 2px solid #ccc;
293
+ border-radius: 5px;
294
+ box-shadow: none;
295
+ }
296
+ .wrap.sap-settings-page form .form-table select,
297
+ .wrap.sap-settings-page form .form-table textarea {
298
+ width: auto !important;
299
+ min-width: 50%;
300
+ max-width: 100% !important;
301
+ }
302
+ #sap-dining-block-length_count,
303
+ #sap-dining-block-length_unit {
304
+ min-width: 0;
305
+ }
306
+
307
+ .wrap.sap-settings-page form .form-table textarea {
308
+ min-width: 300px;
309
+ min-height: 200px;
310
+ }
311
+ .wrap.sap-settings-page form .form-table .wp-editor-wrap textarea {
312
+ border: none;
313
+ border-radius: 0;
314
+ min-width: 0;
315
+ max-width: 100%;
316
+ min-height: 0;
317
+ }
318
+
319
+
320
+ /*SMALL TEXT INPUTS*/
321
+ .sap-small-text-input {
322
+ border-radius: 2px !important;
323
+ width: 100px;
324
+ }
325
+
326
+
327
+ /*SETTINGS COLUMNS*/
328
+ .sap-admin-input-container {
329
+ position: relative;
330
+ float: left;
331
+ width: 100%;
332
+ }
333
+ .sap-setting-columns-2 .sap-admin-input-container {
334
+ width: 50%;
335
+ }
336
+ .sap-setting-columns-3 .sap-admin-input-container {
337
+ width: 33.33333%;
338
+ width: calc(100% / 3);
339
+ }
340
+ .sap-setting-columns-8 .sap-admin-input-container {
341
+ width: 12.5%;
342
+ }
343
+
344
+
345
+ /*COLOUR PICKERS*/
346
+ fieldset.sap-colorpicker {
347
+ position: relative;
348
+ }
349
+ .sap-colorpicker input.sap-spectrum {
350
+ position: absolute;
351
+ right: 0;
352
+ bottom: 0;
353
+ border: none !important;
354
+ margin: 0 !important;
355
+ width: calc(100% - 42px);
356
+ border-radius: 0;
357
+ background: transparent !important;
358
+ color: #888 !important;
359
+ padding: 0;
360
+ font-size: 12px;
361
+ }
362
+ .sap-colorpicker .sp-replacer {
363
+ padding: 0 !important;
364
+ margin-right: 8px !important;
365
+ border-radius: 2px;
366
+ }
367
+ .sap-colorpicker .sp-preview {
368
+ width: 32px !important;
369
+ height: 32px !important;
370
+ margin: 0 !important;
371
+ border: none !important
372
+ }
373
+ .sap-colorpicker .sp-dd {
374
+ display: none !important;
375
+ }
376
+
377
+
378
+ /**************************
379
+ OTHER OPTION PAGE STYLING
380
+ **************************/
381
+
382
+ /*LOCK PREMIUM CONTENT*/
383
+ .sap-premium-options-table {
384
+ position: relative;
385
+ min-height: 240px;
386
+ }
387
+ .sap-premium-options-table.Yes {
388
+ min-height: 0;
389
+ }
390
+ .sap-premium-options-table-overlay {
391
+ position: absolute;
392
+ top: 0;
393
+ left: 0;
394
+ width: 1000px;
395
+ height: 500px;
396
+ background: rgba(0,0,0,.45);
397
+ z-index: 2;
398
+ }
399
+ .section-disabled {
400
+ position: absolute;
401
+ margin-top: 16px;
402
+ width: 200px;
403
+ height: 200px;
404
+ padding: 16px;
405
+ background: #fff;
406
+ left: calc(50% - 116px);
407
+ }
408
+ .section-disabled img {
409
+ position: relative;
410
+ float: left;
411
+ width: 40px;
412
+ height: auto;
413
+ margin: 16px 80px 24px;
414
+ }
415
+ .section-disabled p {
416
+ margin: 16px 0;
417
+ text-align: center;
418
+ color: #888;
419
+ }
420
+ .section-disabled .sap-dashboard-get-premium-widget-button {
421
+ clear: both;
422
+ position: relative;
423
+ float: left;
424
+ width: calc(100% - 20px);
425
+ margin: 16px 8px;
426
+ border: 2px solid #1b335f;
427
+ background-color: #1b335f;
428
+ color: #fff;
429
+ padding: 6px 0;
430
+ font-size: 12px;
431
+ text-decoration: none;
432
+ text-align: center;
433
+ font-weight: bold;
434
+ border-radius: 2px;
435
+ }
436
+ .section-disabled .sap-dashboard-get-premium-widget-button:hover {
437
+ background-color: #6f2fc9;
438
+ border-color: #6f2fc9;
439
+ color: #fff;
440
+ }
441
+
442
+
443
+ /*************
444
+ RESPONSIVE
445
+ *************/
446
+ @media screen and (max-width: 1099px) {
447
+ .wrap.sap-settings-page h2.nav-tab-wrapper {
448
+ clear: both;
449
+ width: 100%;
450
+ }
451
+ .wrap.sap-settings-page form {
452
+ clear: both;
453
+ width: calc(100% - 96px);
454
+ }
455
+ }
456
+ @media screen and (max-width: 782px) {
457
+ .wrap.sap-settings-page h2.nav-tab-wrapper {
458
+ margin: 0 0 20px 0;
459
+ }
460
+ .wrap.sap-settings-page form {
461
+ width: calc(100% - 96px);
462
+ }
463
+ .sap-admin-section-heading {
464
+ text-align: center;
465
+ }
466
+ .wrap.sap-settings-page form .form-table {
467
+ box-shadow: none;
468
+ }
469
+ .wrap.sap-settings-page form .form-table,
470
+ .wrap.sap-settings-page form .form-table tbody,
471
+ .wrap.sap-settings-page form .form-table tr,
472
+ .wrap.sap-settings-page form .form-table th,
473
+ .wrap.sap-settings-page form .form-table td {
474
+ clear: both;
475
+ float: left;
476
+ width: 100%;
477
+ }
478
+ .wrap.sap-settings-page form .form-table {
479
+ padding: 11px 0;
480
+ }
481
+ .wrap.sap-settings-page form .form-table th {
482
+ padding: 20px 5% 8px;
483
+ width: 90%;
484
+ height: auto;
485
+ margin: 0;
486
+ background-image: url(../images/options-asset-info.png);
487
+ background-position: 95% 20px;
488
+ background-size: 18px 18px;
489
+ background-repeat: no-repeat;
490
+ cursor: pointer;
491
+ }
492
+ .wrap.sap-settings-page form .form-table td {
493
+ padding-top: 4px;
494
+ }
495
+ .wrap.sap-settings-page form .form-table td fieldset {
496
+ position: relative;
497
+ }
498
+ .wrap.sap-settings-page form .form-table td label {
499
+ position: relative;
500
+ clear: both;
501
+ float: left;
502
+ width: 90%;
503
+ margin-left: 5% !important;
504
+ }
505
+ .wrap.sap-settings-page form .form-table td label.sap-admin-switch {
506
+ position: absolute;
507
+ width: 40px;
508
+ top: -35px;
509
+ right: 5%;
510
+ }
511
+ .wrap.sap-settings-page form .form-table td p {
512
+ display: none;
513
+ position: relative;
514
+ float: left;
515
+ width: 90%;
516
+ padding: 10px 5% 24px;
517
+ background: #f3f3f3;
518
+ border-bottom: 1px solid #ccc;
519
+ font-size: 13px;
520
+ }
521
+ .wrap.sap-settings-page form .form-table td input[type="button"] {
522
+ display: block;
523
+ margin: 10px auto 4px;
524
+ }
525
+ .sap-admin-input-container {
526
+ width: calc(100% - 16px);
527
+ padding-left: 16px;
528
+ }
529
+ }
530
+
531
+
532
+
533
+ /******************************************************************
534
+ NEW STYLING FOR ADD/DELETE AREAS LIKE CUSTOM FIELDS
535
+ ******************************************************************/
536
+ .sap-infinite-table table th {
537
+ padding: 0 10px !important;
538
+ }
539
+ .sap-new-admin-add-button {
540
+ position: relative;
541
+ float: left;
542
+ width: calc(100% - 4px);
543
+ border: 2px dotted #bbb;
544
+ text-align: center;
545
+ padding: 12px 0;
546
+ color: #999;
547
+ }
548
+ .sap-new-admin-add-button:hover {
549
+ background: #f5f5f5;
550
+ color: #888;
551
+ }
552
+ .sap-infinite-table-row-delete,
553
+ .sap-custom-fields-add-nutrional-information {
554
+ cursor: pointer;
555
+ color: #1b335f;
556
+ }
557
+ .sap-infinite-table-row-delete:hover,
558
+ .sap-custom-fields-add-nutrional-information:hover {
559
+ color: #4366A6;
560
+ }
561
+
562
+
563
+ /******************************************************************
564
+ EXPORT BUTTON
565
+ ******************************************************************/
566
+ .sap-export-button {
567
+ position: relative;
568
+ width: 150px;
569
+ padding: 0 !important;
570
+ }
571
+ .sap-export-button span {
572
+ position: absolute;
573
+ top: 4px;
574
+ left: 8px;
575
+ }
576
+ input[name="sap_export"] {
577
+ position: absolute;
578
+ top: 0;
579
+ left: 0;
580
+ width: 100%;
581
+ height: 100%;
582
+ box-sizing: border-box;
583
+ background: none;
584
+ border: none;
585
+ cursor: pointer;
586
+ color: #0071a1;
587
+ padding: 0 0 0 32px;
588
+ text-align: left;
589
+ }
590
+
591
+
592
+
593
+ /******************************************************************
594
+ CONTROLS AND ICONS SCREENS
595
+ ******************************************************************/
596
+
597
+ /*
598
+ Lightbox control element selection
599
+ */
600
+ .ulb-admin-one-third,
601
+ .ulb-admin-one-sixth {
602
+ float: left;
603
+ margin-bottom: 18px;
604
+ }
605
+ .ulb-admin-one-third {
606
+ width: 30%;
607
+ }
608
+ .ulb-admin-one-sixth {
609
+ width: auto;
610
+ }
611
+
612
+ .ulb-toolbar-control {
613
+ width: 40px;
614
+ float: left;
615
+ cursor: pointer;
616
+ }
617
+ .ewd-ulb-selected-control {
618
+ background: #333333;
619
+ color: #FFFFFF;
620
+ }
621
+
622
+ .ulb-add-button,
623
+ .ulb-remove-button {
624
+ width: 96px;
625
+ padding: 6px 0;
626
+ margin: 0 auto;
627
+ margin-bottom: 8px;
628
+ background: #111;
629
+ color: #fff;
630
+ border: 2px solid #111;
631
+ border-radius: 2px;
632
+ text-align: center;
633
+ cursor: pointer;
634
+ transition: background .3s, color .3s;
635
+ }
636
+ .ulb-add-button:hover,
637
+ .ulb-remove-button:hover {
638
+ background: transparent;
639
+ color: #111;
640
+ }
641
+
642
+ /*
643
+ Lightbox Icon Selection
644
+ */
645
+
646
+ .ewd-ulb-control-icons span {
647
+ font-size: 1.8em;
648
+ letter-spacing: 3px;
649
+ }
650
+
651
+ /*TOOLBAR SELECT ITEMS*/
652
+ .ulb-toolbar-controls {
653
+ background: #f4f4f4;
654
+ padding: 8px;
655
+ margin-right: 8px;
656
+ margin-left: 8px;
657
+ height: 60px;
658
+ }
lib/simple-admin-pages/css/admin.css CHANGED
@@ -1,247 +1,247 @@
1
- /*
2
- * CSS Stylesheet for Simple Admin Pages library
3
- *
4
- * This stylesheet formats the display components placed into the WordPress
5
- * admin menu. It attempts to replicate WordPress's existing admin menu style.
6
- *
7
- * @package Simple Admin Pages
8
- */
9
-
10
- /**
11
- * Clear floats
12
- */
13
- .clearfix:before,
14
- .clearfix:after {
15
- content: " ";
16
- display: table;
17
- }
18
- .clearfix:after {
19
- clear: both;
20
- }
21
-
22
- /**
23
- * Textarea
24
- */
25
- textarea.small-text {
26
- width: 25em;
27
- height: 10em;
28
- }
29
- textarea.large-text {
30
- height: 30em;
31
- }
32
-
33
- /**
34
- * Image
35
- */
36
- .sap-image-wrapper img {
37
- display: block;
38
- width: 100%;
39
- height: auto;
40
- max-width: 500px;
41
- margin-bottom: 1em;
42
- }
43
- .sap-image-wrapper-no-image .sap-image-btn-change,
44
- .sap-image-wrapper-no-image .sap-image-btn-remove,
45
- .sap-image-wrapper-no-image img {
46
- display: none;
47
- }
48
- .sap-image-wrapper-has-image .sap-image-btn-add {
49
- display: none;
50
- }
51
-
52
- /*
53
- * Opening Hours
54
- */
55
- .sap-opening-hours td {
56
- padding-left: 0;
57
- padding-right: 1em;
58
- padding-top: 0;
59
- }
60
- input.sap-opening-hours-day {
61
- width: 15em;
62
- }
63
- input.sap-opening-hours-hours {
64
- width: 9em;
65
- }
66
-
67
- /*
68
- * Scheduler
69
- */
70
- .sap-add-scheduler {
71
- margin-top: 1em;
72
- }
73
- .sap-scheduler-rule {
74
- position: relative;
75
- padding: 1em;
76
- margin: 1em 0;
77
- max-width: 800px;
78
- background: #fff;
79
- -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
80
- box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
81
- }
82
- .sap-selector {
83
- display: inline-block;
84
- margin-top: 0;
85
- margin-right: 1em;
86
- border-bottom: 1px solid #ccc;
87
- }
88
- .sap-selector li {
89
- display: inline-block;
90
- margin-right: 1em;
91
- line-height: 20px;
92
- }
93
- .sap-selector a {
94
- text-decoration: none;
95
- }
96
- .sap-selector .selected {
97
- font-weight: 600;
98
- color: #666;
99
- }
100
- .sap-scheduler-weekdays li,
101
- .sap-scheduler-weeks li {
102
- display: inline-block;
103
- margin-right: 0.5em;
104
- text-align: center;
105
- }
106
- .sap-scheduler-date .label,
107
- .sap-scheduler-date-input label {
108
- display: block;
109
- font-style: italic;
110
- text-align: left;
111
- margin-bottom: 0;
112
- }
113
- .sap-scheduler-weekdays input,
114
- .sap-scheduler-weeks input {
115
- margin-top: 6px;
116
- margin-bottom: 7px;
117
- }
118
- .sap-scheduler-date label {
119
- display: block;
120
- }
121
- .sap-scheduler-date-input {
122
- display: none;
123
- margin-top: 1em;
124
- }
125
- .sap-scheduler-date.date .sap-scheduler-weeks,
126
- .sap-scheduler-date.date .sap-scheduler-weekdays {
127
- display: none;
128
- }
129
- .sap-scheduler-date.weekly .sap-scheduler-weeks,
130
- .sap-scheduler-date.date .sap-scheduler-weeks {
131
- display: none;
132
- }
133
- .sap-scheduler-date.date .sap-scheduler-date-input {
134
- display: block;
135
- }
136
- .sap-scheduler-time {
137
- margin-top: 4em;
138
- }
139
- .sap-scheduler-time.all-day .sap-scheduler-time-input {
140
- display: none;
141
- }
142
- .sap-scheduler-time-input .start,
143
- .sap-scheduler-time-input .end {
144
- margin-top: 1em;
145
- display: inline-block;
146
- }
147
- .sap-scheduler-time-input .start {
148
- margin-right: 1em;
149
- }
150
- .sap-scheduler-time-input label {
151
- display: block;
152
- font-style: italic;
153
- }
154
- .sap-scheduler-time-input input {
155
- max-width: 8em;
156
- }
157
- .sap-scheduler-all-day {
158
- display: block;
159
- margin-top: 1.7em;
160
- font-style: italic;
161
- padding: 1em;
162
- background: #eee;
163
- }
164
- .sap-scheduler-all-day p {
165
- margin-top: 0;
166
- }
167
- .sap-scheduler-time.time-slot .sap-scheduler-all-day {
168
- display: none;
169
- }
170
- .sap-scheduler-control {
171
- clear: both;
172
- line-height: 1.5em;
173
- }
174
- .sap-scheduler-control {
175
- position: absolute;
176
- top: 1em;
177
- right: 1em;
178
- }
179
- .sap-scheduler-control a {
180
- text-decoration: none;
181
- }
182
- .sap-scheduler-control .delete {
183
- color: #a00;
184
- }
185
- .sap-scheduler-control .delete:hover,
186
- .sap-scheduler-control .delete:focus {
187
- color: red;
188
- }
189
- .sap-scheduler-rule.list .sap-scheduler-date,
190
- .sap-scheduler-rule.list .sap-scheduler-time {
191
- display: none;
192
- }
193
- .sap-scheduler-rule .sap-scheduler-brief {
194
- display: none;
195
- clear: both;
196
- }
197
- .sap-scheduler-rule.list .sap-scheduler-brief {
198
- display: block;
199
- }
200
- .sap-scheduler-brief {
201
- margin-right: 4em;
202
- line-height: 1.5em;
203
- }
204
- .sap-scheduler-brief .date,
205
- .sap-scheduler-brief .time {
206
- display: inline-block;
207
- }
208
- .sap-scheduler-brief .date {
209
- margin-right: 1em;
210
- }
211
- .sap-add-scheduler.disabled {
212
- display: none;
213
- }
214
- @media (min-width: 783px) {
215
- .sap-selector li {
216
- font-size: 13px;
217
- }
218
- .sap-scheduler-time {
219
- margin-top: 0;
220
- }
221
- .sap-scheduler-date {
222
- float: left;
223
- width: 50%;
224
- }
225
- .sap-scheduler-date.full-width {
226
- float: none;
227
- width: 100%;
228
- }
229
- .sap-scheduler-time {
230
- float: right;
231
- width: 50%;
232
- }
233
- }
234
-
235
- /**
236
- * Adjustements to pickadate library css to override WP admin styles
237
- */
238
- .picker .picker__table {
239
- table-layout: auto;
240
- }
241
- .picker .picker__table th,
242
- .picker .picker__table td {
243
- text-align: center;
244
- display: table-cell;
245
- padding: 0.5em;
246
- font-size: 1em;
247
- }
1
+ /*
2
+ * CSS Stylesheet for Simple Admin Pages library
3
+ *
4
+ * This stylesheet formats the display components placed into the WordPress
5
+ * admin menu. It attempts to replicate WordPress's existing admin menu style.
6
+ *
7
+ * @package Simple Admin Pages
8
+ */
9
+
10
+ /**
11
+ * Clear floats
12
+ */
13
+ .clearfix:before,
14
+ .clearfix:after {
15
+ content: " ";
16
+ display: table;
17
+ }
18
+ .clearfix:after {
19
+ clear: both;
20
+ }
21
+
22
+ /**
23
+ * Textarea
24
+ */
25
+ textarea.small-text {
26
+ width: 25em;
27
+ height: 10em;
28
+ }
29
+ textarea.large-text {
30
+ height: 30em;
31
+ }
32
+
33
+ /**
34
+ * Image
35
+ */
36
+ .sap-image-wrapper img {
37
+ display: block;
38
+ width: 100%;
39
+ height: auto;
40
+ max-width: 500px;
41
+ margin-bottom: 1em;
42
+ }
43
+ .sap-image-wrapper-no-image .sap-image-btn-change,
44
+ .sap-image-wrapper-no-image .sap-image-btn-remove,
45
+ .sap-image-wrapper-no-image img {
46
+ display: none;
47
+ }
48
+ .sap-image-wrapper-has-image .sap-image-btn-add {
49
+ display: none;
50
+ }
51
+
52
+ /*
53
+ * Opening Hours
54
+ */
55
+ .sap-opening-hours td {
56
+ padding-left: 0;
57
+ padding-right: 1em;
58
+ padding-top: 0;
59
+ }
60
+ input.sap-opening-hours-day {
61
+ width: 15em;
62
+ }
63
+ input.sap-opening-hours-hours {
64
+ width: 9em;
65
+ }
66
+
67
+ /*
68
+ * Scheduler
69
+ */
70
+ .sap-add-scheduler {
71
+ margin-top: 1em;
72
+ }
73
+ .sap-scheduler-rule {
74
+ position: relative;
75
+ padding: 1em;
76
+ margin: 1em 0;
77
+ max-width: 800px;
78
+ background: #fff;
79
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
80
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
81
+ }
82
+ .sap-selector {
83
+ display: inline-block;
84
+ margin-top: 0;
85
+ margin-right: 1em;
86
+ border-bottom: 1px solid #ccc;
87
+ }
88
+ .sap-selector li {
89
+ display: inline-block;
90
+ margin-right: 1em;
91
+ line-height: 20px;
92
+ }
93
+ .sap-selector a {
94
+ text-decoration: none;
95
+ }
96
+ .sap-selector .selected {
97
+ font-weight: 600;
98
+ color: #666;
99
+ }
100
+ .sap-scheduler-weekdays li,
101
+ .sap-scheduler-weeks li {
102
+ display: inline-block;
103
+ margin-right: 0.5em;
104
+ text-align: center;
105
+ }
106
+ .sap-scheduler-date .label,
107
+ .sap-scheduler-date-input label {
108
+ display: block;
109
+ font-style: italic;
110
+ text-align: left;
111
+ margin-bottom: 0;
112
+ }
113
+ .sap-scheduler-weekdays input,
114
+ .sap-scheduler-weeks input {
115
+ margin-top: 6px;
116
+ margin-bottom: 7px;
117
+ }
118
+ .sap-scheduler-date label {
119
+ display: block;
120
+ }
121
+ .sap-scheduler-date-input {
122
+ display: none;
123
+ margin-top: 1em;
124
+ }
125
+ .sap-scheduler-date.date .sap-scheduler-weeks,
126
+ .sap-scheduler-date.date .sap-scheduler-weekdays {
127
+ display: none;
128
+ }
129
+ .sap-scheduler-date.weekly .sap-scheduler-weeks,
130
+ .sap-scheduler-date.date .sap-scheduler-weeks {
131
+ display: none;
132
+ }
133
+ .sap-scheduler-date.date .sap-scheduler-date-input {
134
+ display: block;
135
+ }
136
+ .sap-scheduler-time {
137
+ margin-top: 4em;
138
+ }
139
+ .sap-scheduler-time.all-day .sap-scheduler-time-input {
140
+ display: none;
141
+ }
142
+ .sap-scheduler-time-input .start,
143
+ .sap-scheduler-time-input .end {
144
+ margin-top: 1em;
145
+ display: inline-block;
146
+ }
147
+ .sap-scheduler-time-input .start {
148
+ margin-right: 1em;
149
+ }
150
+ .sap-scheduler-time-input label {
151
+ display: block;
152
+ font-style: italic;
153
+ }
154
+ .sap-scheduler-time-input input {
155
+ max-width: 8em;
156
+ }
157
+ .sap-scheduler-all-day {
158
+ display: block;
159
+ margin-top: 1.7em;
160
+ font-style: italic;
161
+ padding: 1em;
162
+ background: #eee;
163
+ }
164
+ .sap-scheduler-all-day p {
165
+ margin-top: 0;
166
+ }
167
+ .sap-scheduler-time.time-slot .sap-scheduler-all-day {
168
+ display: none;
169
+ }
170
+ .sap-scheduler-control {
171
+ clear: both;
172
+ line-height: 1.5em;
173
+ }
174
+ .sap-scheduler-control {
175
+ position: absolute;
176
+ top: 1em;
177
+ right: 1em;
178
+ }
179
+ .sap-scheduler-control a {
180
+ text-decoration: none;
181
+ }
182
+ .sap-scheduler-control .delete {
183
+ color: #a00;
184
+ }
185
+ .sap-scheduler-control .delete:hover,
186
+ .sap-scheduler-control .delete:focus {
187
+ color: red;
188
+ }
189
+ .sap-scheduler-rule.list .sap-scheduler-date,
190
+ .sap-scheduler-rule.list .sap-scheduler-time {
191
+ display: none;
192
+ }
193
+ .sap-scheduler-rule .sap-scheduler-brief {
194
+ display: none;
195
+ clear: both;
196
+ }
197
+ .sap-scheduler-rule.list .sap-scheduler-brief {
198
+ display: block;
199
+ }
200
+ .sap-scheduler-brief {
201
+ margin-right: 4em;
202
+ line-height: 1.5em;
203
+ }
204
+ .sap-scheduler-brief .date,
205
+ .sap-scheduler-brief .time {
206
+ display: inline-block;
207
+ }
208
+ .sap-scheduler-brief .date {
209
+ margin-right: 1em;
210
+ }
211
+ .sap-add-scheduler.disabled {
212
+ display: none;
213
+ }
214
+ @media (min-width: 783px) {
215
+ .sap-selector li {
216
+ font-size: 13px;
217
+ }
218
+ .sap-scheduler-time {
219
+ margin-top: 0;
220
+ }
221
+ .sap-scheduler-date {
222
+ float: left;
223
+ width: 50%;
224
+ }
225
+ .sap-scheduler-date.full-width {
226
+ float: none;
227
+ width: 100%;
228
+ }
229
+ .sap-scheduler-time {
230
+ float: right;
231
+ width: 50%;
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Adjustements to pickadate library css to override WP admin styles
237
+ */
238
+ .picker .picker__table {
239
+ table-layout: auto;
240
+ }
241
+ .picker .picker__table th,
242
+ .picker .picker__table td {
243
+ text-align: center;
244
+ display: table-cell;
245
+ padding: 0.5em;
246
+ font-size: 1em;
247
+ }
lib/simple-admin-pages/css/infinite_table.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ .sap-hidden {
2
+ display: none;
3
+ }
lib/simple-admin-pages/css/ordering.css ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /****************************
2
+ ORDERING TABLE
3
+ ****************************/
4
+ .sap-ordering-table table {
5
+ width: 100%;
6
+ border-collapse: collapse;
7
+ }
8
+ .sap-ordering-table table th, .sap-ordering-table table td {
9
+ background: #f1f1f1;
10
+ padding: 8px 16px;
11
+ width: calc(100% - 32px);
12
+ }
13
+ .sap-ordering-table table td {
14
+ border-bottom: 1px solid #ccc;
15
+ cursor: move;
16
+ }
17
+ .sap-ordering-table table td:first-of-type {
18
+ border-top: 1px solid #ccc;
19
+ }
20
+ .sap-ordering-table table tr:nth-of-type(2n+2) td {
21
+ background: #fafafa;
22
+ }
23
+ .sap-ordering-table table th {
24
+ background: #662D91;
25
+ color: #fff;
26
+ text-align: left;
27
+ }
lib/simple-admin-pages/css/spectrum.css ADDED
@@ -0,0 +1,507 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /***
2
+ Spectrum Colorpicker v1.7.1
3
+ https://github.com/bgrins/spectrum
4
+ Author: Brian Grinstead
5
+ License: MIT
6
+ ***/
7
+
8
+ .sp-container {
9
+ position:absolute;
10
+ top:0;
11
+ left:0;
12
+ display:inline-block;
13
+ *display: inline;
14
+ *zoom: 1;
15
+ /* https://github.com/bgrins/spectrum/issues/40 */
16
+ z-index: 9999994;
17
+ overflow: hidden;
18
+ }
19
+ .sp-container.sp-flat {
20
+ position: relative;
21
+ }
22
+
23
+ /* Fix for * { box-sizing: border-box; } */
24
+ .sp-container,
25
+ .sp-container * {
26
+ -webkit-box-sizing: content-box;
27
+ -moz-box-sizing: content-box;
28
+ box-sizing: content-box;
29
+ }
30
+
31
+ /* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */
32
+ .sp-top {
33
+ position:relative;
34
+ width: 100%;
35
+ display:inline-block;
36
+ }
37
+ .sp-top-inner {
38
+ position:absolute;
39
+ top:0;
40
+ left:0;
41
+ bottom:0;
42
+ right:0;
43
+ }
44
+ .sp-color {
45
+ position: absolute;
46
+ top:0;
47
+ left:0;
48
+ bottom:0;
49
+ right:20%;
50
+ }
51
+ .sp-hue {
52
+ position: absolute;
53
+ top:0;
54
+ right:0;
55
+ bottom:0;
56
+ left:84%;
57
+ height: 100%;
58
+ }
59
+
60
+ .sp-clear-enabled .sp-hue {
61
+ top:33px;
62
+ height: 77.5%;
63
+ }
64
+
65
+ .sp-fill {
66
+ padding-top: 80%;
67
+ }
68
+ .sp-sat, .sp-val {
69
+ position: absolute;
70
+ top:0;
71
+ left:0;
72
+ right:0;
73
+ bottom:0;
74
+ }
75
+
76
+ .sp-alpha-enabled .sp-top {
77
+ margin-bottom: 18px;
78
+ }
79
+ .sp-alpha-enabled .sp-alpha {
80
+ display: block;
81
+ }
82
+ .sp-alpha-handle {
83
+ position:absolute;
84
+ top:-4px;
85
+ bottom: -4px;
86
+ width: 6px;
87
+ left: 50%;
88
+ cursor: pointer;
89
+ border: 1px solid black;
90
+ background: white;
91
+ opacity: .8;
92
+ }
93
+ .sp-alpha {
94
+ display: none;
95
+ position: absolute;
96
+ bottom: -14px;
97
+ right: 0;
98
+ left: 0;
99
+ height: 8px;
100
+ }
101
+ .sp-alpha-inner {
102
+ border: solid 1px #333;
103
+ }
104
+
105
+ .sp-clear {
106
+ display: none;
107
+ }
108
+
109
+ .sp-clear.sp-clear-display {
110
+ background-position: center;
111
+ }
112
+
113
+ .sp-clear-enabled .sp-clear {
114
+ display: block;
115
+ position:absolute;
116
+ top:0px;
117
+ right:0;
118
+ bottom:0;
119
+ left:84%;
120
+ height: 28px;
121
+ }
122
+
123
+ /* Don't allow text selection */
124
+ .sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button {
125
+ -webkit-user-select:none;
126
+ -moz-user-select: -moz-none;
127
+ -o-user-select:none;
128
+ user-select: none;
129
+ }
130
+
131
+ .sp-container.sp-input-disabled .sp-input-container {
132
+ display: none;
133
+ }
134
+ .sp-container.sp-buttons-disabled .sp-button-container {
135
+ display: none;
136
+ }
137
+ .sp-container.sp-palette-buttons-disabled .sp-palette-button-container {
138
+ display: none;
139
+ }
140
+ .sp-palette-only .sp-picker-container {
141
+ display: none;
142
+ }
143
+ .sp-palette-disabled .sp-palette-container {
144
+ display: none;
145
+ }
146
+
147
+ .sp-initial-disabled .sp-initial {
148
+ display: none;
149
+ }
150
+
151
+
152
+ /* Gradients for hue, saturation and value instead of images. Not pretty... but it works */
153
+ .sp-sat {
154
+ background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0)));
155
+ background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
156
+ background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
157
+ background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
158
+ background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
159
+ background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0));
160
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)";
161
+ filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81');
162
+ }
163
+ .sp-val {
164
+ background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0)));
165
+ background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
166
+ background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
167
+ background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
168
+ background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
169
+ background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0));
170
+ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)";
171
+ filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000');
172
+ }
173
+
174
+ .sp-hue {
175
+ background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
176
+ background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
177
+ background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
178
+ background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000));
179
+ background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
180
+ background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
181
+ }
182
+
183
+ /* IE filters do not support multiple color stops.
184
+ Generate 6 divs, line them up, and do two color gradients for each.
185
+ Yes, really.
186
+ */
187
+ .sp-1 {
188
+ height:17%;
189
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00');
190
+ }
191
+ .sp-2 {
192
+ height:16%;
193
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00');
194
+ }
195
+ .sp-3 {
196
+ height:17%;
197
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff');
198
+ }
199
+ .sp-4 {
200
+ height:17%;
201
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff');
202
+ }
203
+ .sp-5 {
204
+ height:16%;
205
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff');
206
+ }
207
+ .sp-6 {
208
+ height:17%;
209
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000');
210
+ }
211
+
212
+ .sp-hidden {
213
+ display: none !important;
214
+ }
215
+
216
+ /* Clearfix hack */
217
+ .sp-cf:before, .sp-cf:after { content: ""; display: table; }
218
+ .sp-cf:after { clear: both; }
219
+ .sp-cf { *zoom: 1; }
220
+
221
+ /* Mobile devices, make hue slider bigger so it is easier to slide */
222
+ @media (max-device-width: 480px) {
223
+ .sp-color { right: 40%; }
224
+ .sp-hue { left: 63%; }
225
+ .sp-fill { padding-top: 60%; }
226
+ }
227
+ .sp-dragger {
228
+ border-radius: 5px;
229
+ height: 5px;
230
+ width: 5px;
231
+ border: 1px solid #fff;
232
+ background: #000;
233
+ cursor: pointer;
234
+ position:absolute;
235
+ top:0;
236
+ left: 0;
237
+ }
238
+ .sp-slider {
239
+ position: absolute;
240
+ top:0;
241
+ cursor:pointer;
242
+ height: 3px;
243
+ left: -1px;
244
+ right: -1px;
245
+ border: 1px solid #000;
246
+ background: white;
247
+ opacity: .8;
248
+ }
249
+
250
+ /*
251
+ Theme authors:
252
+ Here are the basic themeable display options (colors, fonts, global widths).
253
+ See http://bgrins.github.io/spectrum/themes/ for instructions.
254
+ */
255
+
256
+ .sp-container {
257
+ border-radius: 0;
258
+ background-color: #ECECEC;
259
+ border: solid 1px #f0c49B;
260
+ padding: 0;
261
+ }
262
+ .sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear {
263
+ font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
264
+ -webkit-box-sizing: border-box;
265
+ -moz-box-sizing: border-box;
266
+ -ms-box-sizing: border-box;
267
+ box-sizing: border-box;
268
+ }
269
+ .sp-top {
270
+ margin-bottom: 3px;
271
+ }
272
+ .sp-color, .sp-hue, .sp-clear {
273
+ border: solid 1px #666;
274
+ }
275
+
276
+ /* Input */
277
+ .sp-input-container {
278
+ float:right;
279
+ width: 100px;
280
+ margin-bottom: 4px;
281
+ }
282
+ .sp-initial-disabled .sp-input-container {
283
+ width: 100%;
284
+ }
285
+ .sp-input {
286
+ font-size: 12px !important;
287
+ border: 1px inset;
288
+ padding: 4px 5px;
289
+ margin: 0;
290
+ width: 100%;
291
+ background:transparent;
292
+ border-radius: 3px;
293
+ color: #222;
294
+ }
295
+ .sp-input:focus {
296
+ border: 1px solid orange;
297
+ }
298
+ .sp-input.sp-validation-error {
299
+ border: 1px solid red;
300
+ background: #fdd;
301
+ }
302
+ .sp-picker-container , .sp-palette-container {
303
+ float:left;
304
+ position: relative;
305
+ padding: 10px;
306
+ padding-bottom: 300px;
307
+ margin-bottom: -290px;
308
+ }
309
+ .sp-picker-container {
310
+ width: 172px;
311
+ border-left: solid 1px #fff;
312
+ }
313
+
314
+ /* Palettes */
315
+ .sp-palette-container {
316
+ border-right: solid 1px #ccc;
317
+ }
318
+
319
+ .sp-palette-only .sp-palette-container {
320
+ border: 0;
321
+ }
322
+
323
+ .sp-palette .sp-thumb-el {
324
+ display: block;
325
+ position:relative;
326
+ float:left;
327
+ width: 24px;
328
+ height: 15px;
329
+ margin: 3px;
330
+ cursor: pointer;
331
+ border:solid 2px transparent;
332
+ }
333
+ .sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active {
334
+ border-color: orange;
335
+ }
336
+ .sp-thumb-el {
337
+ position:relative;
338
+ }
339
+
340
+ /* Initial */
341
+ .sp-initial {
342
+ float: left;
343
+ border: solid 1px #333;
344
+ }
345
+ .sp-initial span {
346
+ width: 30px;
347
+ height: 25px;
348
+ border:none;
349
+ display:block;
350
+ float:left;
351
+ margin:0;
352
+ }
353
+
354
+ .sp-initial .sp-clear-display {
355
+ background-position: center;
356
+ }
357
+
358
+ /* Buttons */
359
+ .sp-palette-button-container,
360
+ .sp-button-container {
361
+ float: right;
362
+ }
363
+
364
+ /* Replacer (the little preview div that shows up instead of the <input>) */
365
+ .sp-replacer {
366
+ margin:0;
367
+ overflow:hidden;
368
+ cursor:pointer;
369
+ padding: 4px;
370
+ display:inline-block;
371
+ *zoom: 1;
372
+ *display: inline;
373
+ border: solid 1px #91765d;
374
+ background: #eee;
375
+ color: #333;
376
+ vertical-align: middle;
377
+ }
378
+ .sp-replacer:hover, .sp-replacer.sp-active {
379
+ border-color: #F0C49B;
380
+ color: #111;
381
+ }
382
+ .sp-replacer.sp-disabled {
383
+ cursor:default;
384
+ border-color: silver;
385
+ color: silver;
386
+ }
387
+ .sp-dd {
388
+ padding: 2px 0;
389
+ height: 16px;
390
+ line-height: 16px;
391
+ float:left;
392
+ font-size:10px;
393
+ }
394
+ .sp-preview {
395
+ position:relative;
396
+ width:25px;
397
+ height: 20px;
398
+ border: solid 1px #222;
399
+ margin-right: 5px;
400
+ float:left;
401
+ z-index: 0;
402
+ }
403
+
404
+ .sp-palette {
405
+ *width: 220px;
406
+ max-width: 220px;
407
+ }
408
+ .sp-palette .sp-thumb-el {
409
+ width:16px;
410
+ height: 16px;
411
+ margin:2px 1px;
412
+ border: solid 1px #d0d0d0;
413
+ }
414
+
415
+ .sp-container {
416
+ padding-bottom:0;
417
+ }
418
+
419
+
420
+ /* Buttons: http://hellohappy.org/css3-buttons/ */
421
+ .sp-container button {
422
+ background-color: #eeeeee;
423
+ background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
424
+ background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
425
+ background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
426
+ background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
427
+ background-image: linear-gradient(to bottom, #eeeeee, #cccccc);
428
+ border: 1px solid #ccc;
429
+ border-bottom: 1px solid #bbb;
430
+ border-radius: 3px;
431
+ color: #333;
432
+ font-size: 14px;
433
+ line-height: 1;
434
+ padding: 5px 4px;
435
+ text-align: center;
436
+ text-shadow: 0 1px 0 #eee;
437
+ vertical-align: middle;
438
+ }
439
+ .sp-container button:hover {
440
+ background-color: #dddddd;
441
+ background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb);
442
+ background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb);
443
+ background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
444
+ background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
445
+ background-image: linear-gradient(to bottom, #dddddd, #bbbbbb);
446
+ border: 1px solid #bbb;
447
+ border-bottom: 1px solid #999;
448
+ cursor: pointer;
449
+ text-shadow: 0 1px 0 #ddd;
450
+ }
451
+ .sp-container button:active {
452
+ border: 1px solid #aaa;
453
+ border-bottom: 1px solid #888;
454
+ -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
455
+ -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
456
+ -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
457
+ -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
458
+ box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
459
+ }
460
+ .sp-cancel {
461
+ font-size: 11px;
462
+ color: #d93f3f !important;
463
+ margin:0;
464
+ padding:2px;
465
+ margin-right: 5px;
466
+ vertical-align: middle;
467
+ text-decoration:none;
468
+
469
+ }
470
+ .sp-cancel:hover {
471
+ color: #d93f3f !important;
472
+ text-decoration: underline;
473
+ }
474
+
475
+
476
+ .sp-palette span:hover, .sp-palette span.sp-thumb-active {
477
+ border-color: #000;
478
+ }
479
+
480
+ .sp-preview, .sp-alpha, .sp-thumb-el {
481
+ position:relative;
482
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
483
+ }
484
+ .sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner {
485
+ display:block;
486
+ position:absolute;
487
+ top:0;left:0;bottom:0;right:0;
488
+ }
489
+
490
+ .sp-palette .sp-thumb-inner {
491
+ background-position: 50% 50%;
492
+ background-repeat: no-repeat;
493
+ }
494
+
495
+ .sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner {
496
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=);
497
+ }
498
+
499
+ .sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner {
500
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=);
501
+ }
502
+
503
+ .sp-clear-display {
504
+ background-repeat:no-repeat;
505
+ background-position: center;
506
+ background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==);
507
+ }
lib/simple-admin-pages/img/options-asset-exclamation.png ADDED
Binary file
lib/simple-admin-pages/img/options-asset-info.png ADDED
Binary file
lib/simple-admin-pages/img/options-asset-lock.png ADDED
Binary file
lib/simple-admin-pages/img/options-asset-star.png ADDED
Binary file
lib/simple-admin-pages/img/options-asset-starX2.png ADDED
Binary file
lib/simple-admin-pages/js/address.js CHANGED
@@ -1,116 +1,116 @@
1
- /**
2
- * Javascript functions for Address component
3
- *
4
- * @package Simple Admin Pages
5
- */
6
-
7
- jQuery(document).ready(function ($) {
8
-
9
- /**
10
- * Set coordinate that have been received
11
- */
12
- function sap_address_set_coords( control, lat, lon ) {
13
- control.find( '.sap-coords-result' ).remove();
14
- control.find( 'input.lat' ).val( lat );
15
- control.find( 'input.lon' ).val( lon );
16
-
17
- if ( lat == '' && lon == '' ) {
18
- control.find( '.sap-map-coords' ).text( lat + sap_address.strings['no-setting'] + lon ).attr( 'style', '' );
19
- } else {
20
- control.find( '.sap-map-coords' ).text( lat + sap_address.strings['sep-lat-lon'] + lon ).attr( 'style', '' );
21
- }
22
-
23
- var url = 'https://maps.google.com/maps?q=' + lat + ',' + lon;
24
- if ( control.find( '.sap-view-coords' ).length ) {
25
- control.find( '.sap-view-coords' ).attr( 'href', url );
26
- } else {
27
- control.find( '.sap-map-coords-wrapper' ).append( '<a class="sap-view-coords" href="' + url + '" target="_blank">' + sap_address.strings.view + '</a>' );
28
- }
29
- }
30
-
31
- /**
32
- * Retrieve coordinates
33
- */
34
- $('.sap-get-coords').click( function(e) {
35
-
36
- e.stopPropagation();
37
- e.preventDefault();
38
-
39
- var control = $(this).parent().parent();
40
- var address = control.find( 'textarea' ).val();
41
- var params = {
42
- sensor: false,
43
- address: address,
44
- };
45
- if ( sap_address.api_key_selector ) {
46
- var $input = $( sap_address.api_key_selector );
47
- if ( $input.length && $input.val() ) {
48
- params.key = $input.val();
49
- }
50
- } else if ( sap_address.api_key ) {
51
- params.key = sap_address.api_key;
52
- }
53
-
54
- // Reset messages
55
- control.find( '.sap-coords-result' ).remove();
56
- control.find( '.error' ).remove();
57
- control.find( '.sap-view-coords' ).remove();
58
- control.find( '.sap-map-coords' ).text( sap_address.strings.retrieving ).attr( 'style', 'opacity: 0.3' );
59
-
60
- // Call Google Maps geocoding API
61
- // See: https://developers.google.com/maps/documentation/geocoding/
62
- var req = $.get(
63
- 'https://maps.googleapis.com/maps/api/geocode/json',
64
- params,
65
- function( data ) {
66
-
67
- if ( data.status == 'OK' ) {
68
- if ( data.results.length == 1 ) {
69
- sap_address_set_coords( control, data.results[0].geometry.location.lat, data.results[0].geometry.location.lng );
70
-
71
- } else {
72
- for ( var key in data.results ) {
73
- control.append( '<p class="sap-coords-result">' + data.results[key].formatted_address + ' <span class="dashicons dashicons-arrow-right"></span> <a href="#" data-lat="' + data.results[key].geometry.location.lat + '" data-lon="' + data.results[key].geometry.location.lng + '">Set</a></p>' );
74
- }
75
- control.find( '.sap-map-coords' ).text( sap_address.strings.select ).attr( 'style', '' );
76
-
77
- control.find( '.sap-coords-result a' ).click( function() {
78
- sap_address_set_coords( control, $(this).data( 'lat' ), $(this).data( 'lon' ) );
79
- });
80
-
81
- }
82
-
83
- } else {
84
- sap_address_set_coords( control, control.find( 'input.lat' ).val(), control.find( 'input.lon' ).val() );
85
-
86
- if ( data.status == 'UNKNOWN_ERROR' ) {
87
- control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_error + '</div>' );
88
- } else if ( data.status == 'INVALID_REQUEST' ) {
89
- control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_invalid + '</div>' );
90
- } else if ( data.status == 'INVALID_REQUEST' ) {
91
- control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_error + '</div>' );
92
- } else if ( data.status == 'REQUEST_DENIED' ) {
93
- control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_denied + '</div>' );
94
- } else if ( data.status == 'OVER_QUERY_LIMIT' ) {
95
- control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_limit + '</div>' );
96
- } else if ( data.status == 'ZERO_RESULTS' ) {
97
- control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_empty + '</div>' );
98
- }
99
- }
100
- }
101
- )
102
- });
103
-
104
- /**
105
- * Remove coordinates from settings
106
- */
107
- $('.sap-remove-coords').click( function(e) {
108
-
109
- e.stopPropagation();
110
- e.preventDefault();
111
-
112
- var control = $(this).parent().parent();
113
- sap_address_set_coords( control, '', '' );
114
- });
115
-
116
- });
1
+ /**
2
+ * Javascript functions for Address component
3
+ *
4
+ * @package Simple Admin Pages
5
+ */
6
+
7
+ jQuery(document).ready(function ($) {
8
+
9
+ /**
10
+ * Set coordinate that have been received
11
+ */
12
+ function sap_address_set_coords( control, lat, lon ) {
13
+ control.find( '.sap-coords-result' ).remove();
14
+ control.find( 'input.lat' ).val( lat );
15
+ control.find( 'input.lon' ).val( lon );
16
+
17
+ if ( lat == '' && lon == '' ) {
18
+ control.find( '.sap-map-coords' ).text( lat + sap_address.strings['no-setting'] + lon ).attr( 'style', '' );
19
+ } else {
20
+ control.find( '.sap-map-coords' ).text( lat + sap_address.strings['sep-lat-lon'] + lon ).attr( 'style', '' );
21
+ }
22
+
23
+ var url = 'https://maps.google.com/maps?q=' + lat + ',' + lon;
24
+ if ( control.find( '.sap-view-coords' ).length ) {
25
+ control.find( '.sap-view-coords' ).attr( 'href', url );
26
+ } else {
27
+ control.find( '.sap-map-coords-wrapper' ).append( '<a class="sap-view-coords" href="' + url + '" target="_blank">' + sap_address.strings.view + '</a>' );
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Retrieve coordinates
33
+ */
34
+ $('.sap-get-coords').click( function(e) {
35
+
36
+ e.stopPropagation();
37
+ e.preventDefault();
38
+
39
+ var control = $(this).parent().parent();
40
+ var address = control.find( 'textarea' ).val();
41
+ var params = {
42
+ sensor: false,
43
+ address: address,
44
+ };
45
+ if ( sap_address.api_key_selector ) {
46
+ var $input = $( sap_address.api_key_selector );
47
+ if ( $input.length && $input.val() ) {
48
+ params.key = $input.val();
49
+ }
50
+ } else if ( sap_address.api_key ) {
51
+ params.key = sap_address.api_key;
52
+ }
53
+
54
+ // Reset messages
55
+ control.find( '.sap-coords-result' ).remove();
56
+ control.find( '.error' ).remove();
57
+ control.find( '.sap-view-coords' ).remove();
58
+ control.find( '.sap-map-coords' ).text( sap_address.strings.retrieving ).attr( 'style', 'opacity: 0.3' );
59
+
60
+ // Call Google Maps geocoding API
61
+ // See: https://developers.google.com/maps/documentation/geocoding/
62
+ var req = $.get(
63
+ 'https://maps.googleapis.com/maps/api/geocode/json',
64
+ params,
65
+ function( data ) {
66
+
67
+ if ( data.status == 'OK' ) {
68
+ if ( data.results.length == 1 ) {
69
+ sap_address_set_coords( control, data.results[0].geometry.location.lat, data.results[0].geometry.location.lng );
70
+
71
+ } else {
72
+ for ( var key in data.results ) {
73
+ control.append( '<p class="sap-coords-result">' + data.results[key].formatted_address + ' <span class="dashicons dashicons-arrow-right"></span> <a href="#" data-lat="' + data.results[key].geometry.location.lat + '" data-lon="' + data.results[key].geometry.location.lng + '">Set</a></p>' );
74
+ }
75
+ control.find( '.sap-map-coords' ).text( sap_address.strings.select ).attr( 'style', '' );
76
+
77
+ control.find( '.sap-coords-result a' ).click( function() {
78
+ sap_address_set_coords( control, $(this).data( 'lat' ), $(this).data( 'lon' ) );
79
+ });
80
+
81
+ }
82
+
83
+ } else {
84
+ sap_address_set_coords( control, control.find( 'input.lat' ).val(), control.find( 'input.lon' ).val() );
85
+
86
+ if ( data.status == 'UNKNOWN_ERROR' ) {
87
+ control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_error + '</div>' );
88
+ } else if ( data.status == 'INVALID_REQUEST' ) {
89
+ control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_invalid + '</div>' );
90
+ } else if ( data.status == 'INVALID_REQUEST' ) {
91
+ control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_error + '</div>' );
92
+ } else if ( data.status == 'REQUEST_DENIED' ) {
93
+ control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_denied + '</div>' );
94
+ } else if ( data.status == 'OVER_QUERY_LIMIT' ) {
95
+ control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_limit + '</div>' );
96
+ } else if ( data.status == 'ZERO_RESULTS' ) {
97
+ control.find( '.sap-coords-action-wrapper' ).prepend( '<div class="error">' + sap_address.strings.result_empty + '</div>' );
98
+ }
99
+ }
100
+ }
101
+ )
102
+ });
103
+
104
+ /**
105
+ * Remove coordinates from settings
106
+ */
107
+ $('.sap-remove-coords').click( function(e) {
108
+
109
+ e.stopPropagation();
110
+ e.preventDefault();
111
+
112
+ var control = $(this).parent().parent();
113
+ sap_address_set_coords( control, '', '' );
114
+ });
115
+
116
+ });
lib/simple-admin-pages/js/admin-settings.js ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function() {
2
+
3
+ if ( ! jQuery.isFunction( jQuery.fn.spectrum ) ) { return; }
4
+
5
+ jQuery('.sap-spectrum').spectrum({
6
+ showInput: true,
7
+ showInitial: true,
8
+ preferredFormat: "hex",
9
+ allowEmpty: true
10
+ });
11
+
12
+ jQuery('.sap-spectrum').css('display', 'inline');
13
+
14
+ jQuery('.sap-spectrum').on('change', function() {
15
+ if (jQuery(this).val() != "") {
16
+ jQuery(this).css('background', jQuery(this).val());
17
+ var rgb = EWD_SAP_hexToRgb(jQuery(this).val());
18
+ var Brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
19
+ if (Brightness < 100) {jQuery(this).css('color', '#ffffff');}
20
+ else {jQuery(this).css('color', '#000000');}
21
+ }
22
+ else {
23
+ jQuery(this).css('background', 'none');
24
+ }
25
+ });
26
+
27
+ jQuery('.sap-spectrum').each(function() {
28
+ if (jQuery(this).val() != "") {
29
+ jQuery(this).css('background', jQuery(this).val());
30
+ var rgb = EWD_SAP_hexToRgb(jQuery(this).val());
31
+ var Brightness = (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
32
+ if (Brightness < 100) {jQuery(this).css('color', '#ffffff');}
33
+ else {jQuery(this).css('color', '#000000');}
34
+ }
35
+ });
36
+ });
37
+
38
+ function EWD_SAP_hexToRgb(hex) {
39
+ var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
40
+ return result ? {
41
+ r: parseInt(result[1], 16),
42
+ g: parseInt(result[2], 16),
43
+ b: parseInt(result[3], 16)
44
+ } : null;
45
+ }
46
+
47
+ //OPTIONS PAGE YES/NO TOGGLE SWITCHES
48
+ jQuery(document).ready(function($){
49
+ $('.sap-admin-option-toggle').on('change', function() {
50
+ var Input_Name = $(this).data('inputname'); console.log(Input_Name);
51
+ if ($(this).is(':checked')) {
52
+ $('input[name="' + Input_Name + '"][value="1"]').prop('checked', true).trigger('change');
53
+ $('input[name="' + Input_Name + '"][value=""]').prop('checked', false);
54
+ }
55
+ else {
56
+ $('input[name="' + Input_Name + '"][value="1"]').prop('checked', false).trigger('change');
57
+ $('input[name="' + Input_Name + '"][value=""]').prop('checked', true);
58
+ }
59
+ });
60
+ });
61
+
62
+ /*LOCK BOXES*/
63
+ jQuery( document ).ready( function() {
64
+ setTimeout( resizeLockdownBoxes, 750 );
65
+ jQuery( window ).on( 'resize', resizeLockdownBoxes );
66
+ });
67
+
68
+ function resizeLockdownBoxes() {
69
+ jQuery('.sap-premium-options-table-overlay').each(function(){
70
+
71
+ var eachProTableOverlay = jQuery( this );
72
+ var associatedTable = eachProTableOverlay.next();
73
+ associatedTable.css('min-height', '260px');
74
+ var tablePosition = associatedTable.position();
75
+
76
+ eachProTableOverlay.css( 'width', associatedTable.outerWidth(true) + 'px' );
77
+ eachProTableOverlay.css( 'height', associatedTable.outerHeight() + 'px' );
78
+ eachProTableOverlay.css( 'left', tablePosition.left + 'px' );
79
+ eachProTableOverlay.css( 'top', tablePosition.top + 'px' );
80
+ });
81
+ }
lib/simple-admin-pages/js/count.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function() {
2
+ jQuery('.sap-count-count, .sap-count-unit').on('change', function() {
3
+ var id = jQuery(this).data('id');
4
+
5
+ var count = jQuery('#' + id + '_count').val();
6
+ var unit = jQuery('#' + id + '_unit').val();
7
+
8
+ jQuery('#' + id).val(count + '_' + unit);
9
+ })
10
+ })
lib/simple-admin-pages/js/file_upload.js ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function($){
2
+
3
+ var custom_uploader;
4
+ var input_field;
5
+ var preview_value;
6
+
7
+ jQuery( '.sap-file-upload-button' ).click(function(e) {
8
+
9
+ e.preventDefault();
10
+
11
+ input_field = jQuery( this ).parent().find( 'input[type="hidden"]' );
12
+ preview_value = jQuery( this ).parent().find( '.sap-file-upload-preview-value' );
13
+
14
+ //If the uploader object has already been created, reopen the dialog
15
+ if ( custom_uploader ) {
16
+ custom_uploader.open();
17
+ return;
18
+ }
19
+
20
+ //Extend the wp.media object
21
+ custom_uploader = wp.media.frames.file_frame = wp.media({
22
+ title: 'Choose File',
23
+ button: {
24
+ text: 'Choose File'
25
+ },
26
+ multiple: false
27
+ });
28
+
29
+ //When a file is selected, grab the URL and set it as the text field's value
30
+ custom_uploader.on( 'select', function() {
31
+
32
+ attachment = custom_uploader.state().get( 'selection' ).first().toJSON();
33
+ input_field.val( attachment.url );
34
+ preview_value.html( attachment.url );
35
+ });
36
+
37
+ //Open the uploader dialog
38
+ custom_uploader.open();
39
+
40
+ });
41
+ });
lib/simple-admin-pages/js/image.js CHANGED
@@ -1,53 +1,53 @@
1
- /**
2
- * Javascript functions for Image component
3
- *
4
- * @package Simple Admin Pages
5
- */
6
-
7
- jQuery(document).ready(function ($) {
8
-
9
- var current_setting_id;
10
-
11
- function openMediaManager(e) {
12
- e.stopPropagation();
13
- e.preventDefault();
14
- current_setting_id = $( this ).parents( '.sap-image-wrapper' ).data( 'id' );
15
- wp.media.frames.bpfwp_frame.open();
16
- }
17
-
18
- function setImage( setting_id, image_id, image_url ) {
19
- var $control = $( '.sap-image-wrapper[data-id="' + setting_id + '"]' );
20
- $control.find( 'img' ).attr( 'src', image_url );
21
- $control.find( '#' + setting_id ).val( image_id );
22
- $control.removeClass( 'sap-image-wrapper-no-image' ).addClass( 'sap-image-wrapper-has-image' );
23
- }
24
-
25
- function removeImage(e) {
26
- e.stopPropagation();
27
- e.preventDefault();
28
- var $control = $( this ).parents( '.sap-image-wrapper' );
29
- $control.find( 'img' ).attr( 'src', '' );
30
- $control.find( '#' + $control.data( 'id' ) ).val( '' );
31
- $control.removeClass( 'sap-image-wrapper-has-image' ).addClass( 'sap-image-wrapper-no-image' );
32
- }
33
-
34
- wp.media.frames.bpfwp_frame = wp.media( {
35
- title: 'Select image',
36
- multiple: false,
37
- library: {
38
- type: 'image',
39
- },
40
- button: {
41
- text: 'Use selected image',
42
- },
43
- } );
44
-
45
- wp.media.frames.bpfwp_frame.on( 'select', function() {
46
- var image = wp.media.frames.bpfwp_frame.state().get( 'selection' ).first().toJSON();
47
- setImage( current_setting_id, image.id, image.url );
48
- });
49
-
50
- $( '.sap-image-wrapper .sap-image-btn-add, .sap-image-wrapper .sap-image-btn-change' ).click(openMediaManager);
51
-
52
- $( '.sap-image-wrapper .sap-image-btn-remove' ).click(removeImage);
53
- });
1
+ /**
2
+ * Javascript functions for Image component
3
+ *
4
+ * @package Simple Admin Pages
5
+ */
6
+
7
+ jQuery(document).ready(function ($) {
8
+
9
+ var current_setting_id;
10
+
11
+ function openMediaManager(e) {
12
+ e.stopPropagation();
13
+ e.preventDefault();
14
+ current_setting_id = $( this ).parents( '.sap-image-wrapper' ).data( 'id' );
15
+ wp.media.frames.sap_frame.open();
16
+ }
17
+
18
+ function setImage( setting_id, image_id, image_url ) {
19
+ var $control = $( '.sap-image-wrapper[data-id="' + setting_id + '"]' );
20
+ $control.find( 'img' ).attr( 'src', image_url );
21
+ $control.find( '#' + setting_id ).val( image_id );
22
+ $control.removeClass( 'sap-image-wrapper-no-image' ).addClass( 'sap-image-wrapper-has-image' );
23
+ }
24
+
25
+ function removeImage(e) {
26
+ e.stopPropagation();
27
+ e.preventDefault();
28
+ var $control = $( this ).parents( '.sap-image-wrapper' );
29
+ $control.find( 'img' ).attr( 'src', '' );
30
+ $control.find( '#' + $control.data( 'id' ) ).val( '' );
31
+ $control.removeClass( 'sap-image-wrapper-has-image' ).addClass( 'sap-image-wrapper-no-image' );
32
+ }
33
+
34
+ wp.media.frames.sap_frame = wp.media( {
35
+ title: 'Select image',
36
+ multiple: false,
37
+ library: {
38
+ type: 'image',
39
+ },
40
+ button: {
41
+ text: 'Use selected image',
42
+ },
43
+ } );
44
+
45
+ wp.media.frames.sap_frame.on( 'select', function() {
46
+ var image = wp.media.frames.sap_frame.state().get( 'selection' ).first().toJSON();
47
+ setImage( current_setting_id, image.id, image.url );
48
+ });
49
+
50
+ $( '.sap-image-wrapper .sap-image-btn-add, .sap-image-wrapper .sap-image-btn-change' ).click( openMediaManager );
51
+
52
+ $( '.sap-image-wrapper .sap-image-btn-remove' ).click( removeImage );
53
+ });
lib/simple-admin-pages/js/infinite_table.js ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Javascript functions for Infinite Table
3
+ *
4
+ * @package Simple Admin Pages
5
+ */
6
+
7
+ jQuery(document).ready(function ($) {
8
+
9
+ // disable options where not required initially
10
+ $('.sap-infinite-table table tbody tr').each((idx_tr, tr) => {
11
+ let val = $(tr).find('[data-name="cf_type"]').val();
12
+
13
+ if(!['dropdown', 'checkbox', 'radio'].includes(val)) {
14
+ $(tr).find('[data-name="cf_options"]').val('').prop('readonly', true);
15
+ }
16
+ });
17
+
18
+ // process fields
19
+ $('.sap-parent-form').on('submit', function (ev) {
20
+ var _form = $(this), ignore;
21
+
22
+ $('.sap-infinite-table').each( function() {
23
+
24
+ var main_input = $(this).find('#sap-infinite-table-main-input');
25
+
26
+ var main_input_val = [];
27
+
28
+ $(this).find('table tbody tr').each((idx_tr, tr) => {
29
+ let record = {}; ignore = false;
30
+
31
+ $(tr).find('td').each((idx_td, td) => {
32
+ let elm = $(td).find('select, input, textarea, checkbox');
33
+
34
+ ignore = 'cf_field_name' == elm.data('name') && elm.val().length < 1 ? true : ignore;
35
+
36
+ if(!ignore) {
37
+
38
+ if ( elm.prop( 'type' ) == 'checkbox' ) { record[ elm.data('name') ] = elm.is( ':checked' ); }
39
+ else { record[elm.data('name')] = elm.val(); }
40
+ }
41
+ });
42
+
43
+ !ignore ? main_input_val.push(record) : null;
44
+ });
45
+
46
+ main_input.val(JSON.stringify(main_input_val));
47
+
48
+ });
49
+ });
50
+
51
+ // Add new field
52
+ $('.sap-infinite-table-add-row .sap-new-admin-add-button').on('click', function (ev) {
53
+ let _template_tr = $( this ).parents( 'tfoot' ).find( '.sap-infinite-table-row-template' ).clone();
54
+ _template_tr
55
+ .hide()
56
+ .removeClass()
57
+ .addClass('sap-infinite-table-row');
58
+ $( this ).parents( 'table' ).first().find( 'tbody' ).append(_template_tr);
59
+ _template_tr.fadeIn('fast');
60
+ _template_tr.find('[data-name="cf_options"]').prop('readonly', true);
61
+ });
62
+
63
+ // update options field
64
+ $(document).on('change', '.sap-infinite-table-row [data-name="cf_type"]', function (ev) {
65
+ let parent_tr = $(this).parents('tr').eq(0);
66
+
67
+ if(!['dropdown', 'checkbox', 'radio'].includes($(this).val())) {
68
+ parent_tr.find('[data-name="cf_options"]').val('').prop('readonly', true);
69
+ }
70
+ else {
71
+ parent_tr.find('[data-name="cf_options"]').prop('readonly', false);
72
+ }
73
+ });
74
+
75
+ // Remvoe field
76
+ $(document).on('click', '.sap-infinite-table-row .sap-infinite-table-row-delete', function (ev) {
77
+ let parent_tr = $(this).parents('tr').eq(0);
78
+ parent_tr.fadeOut('fast', () => parent_tr.remove());
79
+ });
80
+
81
+ $('.sap-infinite-table table tbody').sortable({
82
+ axis: 'y'
83
+ });
84
+
85
+ })
lib/simple-admin-pages/js/opening-hours.js CHANGED
@@ -1,20 +1,20 @@
1
- /**
2
- * Javascript functions for Opening Hours component
3
- *
4
- * @package Simple Admin Pages
5
- */
6
-
7
- jQuery(document).ready(function ($) {
8
-
9
- /**
10
- * Opening Hours
11
- ***************/
12
-
13
- /**
14
- * Update the name of each day when the select option is changed
15
- */
16
- $( '.sap-opening-hours-day' ).change( function() {
17
- $( $(this).data( 'target' ) ).val( $(this).children( 'option:selected' ).data( 'name' ) );
18
- });
19
-
20
- });
1
+ /**
2
+ * Javascript functions for Opening Hours component
3
+ *
4
+ * @package Simple Admin Pages
5
+ */
6
+
7
+ jQuery(document).ready(function ($) {
8
+
9
+ /**
10
+ * Opening Hours
11
+ ***************/
12
+
13
+ /**
14
+ * Update the name of each day when the select option is changed
15
+ */
16
+ $( '.sap-opening-hours-day' ).change( function() {
17
+ $( $(this).data( 'target' ) ).val( $(this).children( 'option:selected' ).data( 'name' ) );
18
+ });
19
+
20
+ });
lib/simple-admin-pages/js/ordering.js ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Javascript functions for Ordering Table
3
+ *
4
+ * @package Simple Admin Pages
5
+ */
6
+
7
+ jQuery(document).ready(function ($) {
8
+
9
+ // process fields
10
+ $('.sap-parent-form').on('submit', function (ev) {
11
+ var _form = $(this), ignore;
12
+
13
+ $('.sap-ordering-table').each( function() {
14
+
15
+ var main_input = $(this).find('#sap-ordering-table-main-input');
16
+
17
+ var main_input_val = {};
18
+
19
+ $(this).find('table tbody tr').each((idx_tr, tr) => {
20
+
21
+ $(tr).find('td').each((idx_td, td) => {
22
+ let elm = $(td).find('input');
23
+
24
+ main_input_val[elm.val()] = $(td).find('span').html();
25
+ });
26
+
27
+ });
28
+
29
+ main_input.val(JSON.stringify(main_input_val));
30
+
31
+ });
32
+ });
33
+
34
+ $('.sap-ordering-table table tbody').sortable({
35
+ axis: 'y'
36
+ });
37
+
38
+ })
lib/simple-admin-pages/js/scheduler.js CHANGED
@@ -1,403 +1,403 @@
1
- /**
2
- * Javascript functions for the Scheduler component
3
- *
4
- * @package Simple Admin Pages
5
- */
6
-
7
- jQuery(document).ready(function ($) {
8
-
9
- /**
10
- * Scheduler
11
- ***********/
12
-
13
- if ( typeof sap_scheduler != 'undefined' ) {
14
-
15
- /**
16
- * Register event handlers on the scheduler rules. This is run on page load
17
- * and every time a rule is added.
18
- */
19
- function sap_scheduler_register_events() {
20
-
21
- /**
22
- * Open and close the full view of a scheduling rule
23
- */
24
- $( '.sap-scheduler-rule .toggle' ).off( 'click' ).click( function() {
25
-
26
- var controls = $(this).parent();
27
-
28
- if ( $(this).parent().parent().hasClass( 'list' ) ) {
29
- controls.hide();
30
- $(this).children( '.dashicons-edit' ).removeClass( 'dashicons-edit' ).addClass( 'dashicons-arrow-up-alt2' );
31
- controls.siblings( '.sap-scheduler-brief' ).hide();
32
- controls.siblings( '.sap-scheduler-date, .sap-scheduler-time' ).slideDown( function() {
33
- $(this).parent().removeClass( 'list' );
34
- controls.fadeIn();
35
- });
36
-
37
- } else {
38
- controls.hide();
39
- $(this).children( '.dashicons-arrow-up-alt2' ).removeClass( 'dashicons-arrow-up-alt2' ).addClass( 'dashicons-edit' );
40
- controls.siblings( '.sap-scheduler-brief' ).fadeIn();
41
- controls.siblings( '.sap-scheduler-time' ).slideUp();
42
- controls.siblings( '.sap-scheduler-date' ).slideUp( function() {
43
-
44
- var scheduler_rule = $(this).parent();
45
- var scheduler_id = scheduler_rule.parent().attr( 'id' );
46
-
47
- scheduler_rule.addClass( 'list' );
48
- controls.fadeIn();
49
-
50
- sap_scheduler_set_date_phrase( scheduler_rule, scheduler_id );
51
- sap_scheduler_set_time_phrase( scheduler_rule, scheduler_id );
52
- });
53
- }
54
-
55
- return false;
56
- });
57
-
58
- /**
59
- * Update current selection for selector lists
60
- */
61
- $( '.sap-selector a' ).off( 'switch.sap' ).on( 'switch.sap', function() {
62
- $(this).parent().parent().find( 'a' ).removeClass( 'selected' );
63
- $(this).addClass( 'selected' );
64
-
65
- return false;
66
- });
67
-
68
- /**
69
- * Switch between weekly, monthly and date options
70
- */
71
- $( '.sap-scheduler-date .sap-selector a' ).off( 'click' ).click( function() {
72
-
73
- $(this).trigger( 'switch.sap' );
74
-
75
- var date = $(this).closest( '.sap-scheduler-date' );
76
-
77
- if ( $(this).data( 'format' ) == 'weekly' && date.hasClass( 'weekly' ) === false ) {
78
- date.children( '.sap-scheduler-weeks' ).slideUp( function() {
79
- $(this).find( 'input' ).prop('checked', false);
80
- });
81
- date.children( '.sap-scheduler-date-input' ).slideUp( function() {
82
- $(this).find( 'input' ).val( '' );
83
- });
84
- date.children( '.sap-scheduler-weekdays' ).slideDown( function() {
85
- date.removeClass( 'monthly date' );
86
- date.addClass( 'weekly' );
87
- });
88
-
89
- } else if ( $(this).data( 'format' ) == 'monthly' && date.hasClass( 'monthly' ) === false ) {
90
- date.children( '.sap-scheduler-date-input' ).slideUp( function() {
91
- $(this).find( 'input' ).val( '' );
92
- });
93
- date.children( '.sap-scheduler-weekdays' ).slideDown();
94
- date.children( '.sap-scheduler-weeks' ).slideDown( function() {
95
- date.removeClass( 'weekly date' );
96
- date.addClass( 'monthly' );
97
- });
98
-
99
- } else if ( $(this).data( 'format' ) == 'date' && date.hasClass( 'date' ) === false ) {
100
- date.children( '.sap-scheduler-weekdays' ).slideUp( function() {
101
- $(this).find( 'input' ).prop('checked', false);
102
- });
103
- date.children( '.sap-scheduler-weeks' ).slideUp( function() {
104
- $(this).find( 'input' ).prop('checked', false);
105
- });
106
- date.children( '.sap-scheduler-date-input' ).slideDown( function() {
107
- date.removeClass( 'weekly monthly' );
108
- date.addClass( 'date' );
109
- });
110
- }
111
-
112
- return false;
113
- });
114
-
115
- /**
116
- * Show or hide time slot options
117
- */
118
- $( '.sap-scheduler-time .sap-selector a' ).off( 'click' ).click( function() {
119
-
120
- $(this).trigger( 'switch.sap' );
121
-
122
- var time = $(this).closest( '.sap-scheduler-time' );
123
-
124
- if ( $(this).data( 'format' ) == 'time-slot' && time.hasClass( 'time-slot' ) === false ) {
125
- time.children( '.sap-scheduler-time-input' ).slideDown();
126
- time.children( '.sap-scheduler-all-day' ).slideUp( function() {
127
- time.removeClass( 'all-day' );
128
- time.addClass( 'time-slot' );
129
- });
130
-
131
- } else if ( $(this).data( 'format' ) == 'all-day' && time.hasClass( 'all-day' ) === false ) {
132
- time.children( '.sap-scheduler-all-day' ).slideDown();
133
- time.children( '.sap-scheduler-time-input' ).slideUp( function() {
134
- time.removeClass( 'time-slot' );
135
- time.addClass( 'all-day' );
136
- time.find( 'input' ).val( '' );
137
- });
138
- }
139
-
140
- return false;
141
- });
142
-
143
- /**
144
- * Show time slot options from the link in the all-day notice
145
- */
146
- $( '.sap-scheduler-all-day a' ).off( 'click' ).click( function() {
147
- $(this).closest( '.sap-scheduler-time' ).children( '.sap-selector' ).find( 'a[data-format="time-slot"]' ).trigger( 'click' );
148
-
149
- return false;
150
- });
151
-
152
- /**
153
- * Delete a scheduling rule panel
154
- */
155
- $( '.sap-scheduler-control .delete' ).off( 'click' ).click( function() {
156
- var scheduler = $(this).closest( '.sap-scheduler' );
157
- $(this).parent().parent().fadeOut( function() {
158
- $(this).remove();
159
-
160
- // Reset the index of each rule
161
- // @todo optimize this excessive use of regex (32x per rule).
162
- // maybe set a data-slug attribute on .sap-scheduler-rule and a
163
- // data-slug prop on each input/select/label, then use these to
164
- // construct the new attributes: rule-slug[index][input-slug]
165
- scheduler.children( '.sap-scheduler-rule' ).each( function( i ) {
166
- var index = i.toString();
167
- $(this).find( 'input' ).each( function() {
168
- var name = $(this).attr( 'name' ).replace( /\[\d*\]/g, '[' + index + ']' );
169
- $(this).attr( 'name', name );
170
- $(this).attr( 'id', name );
171
- var aria_owns = $(this).attr( 'aria-owns' );
172
- if ( typeof aria_owns !== 'undefined' && aria_owns !== false) {
173
- $(this).attr( 'aria-owns', name );
174
- }
175
- });
176
- $(this).find( 'label' ).each( function() {
177
- var name = $(this).attr( 'for' ).replace( /\[\d*\]/g, '[' + index + ']' );
178
- $(this).attr( 'for', name );
179
- });
180
- $(this).find( '.picker' ).each( function() {
181
- var name = $(this).attr( 'id' ).replace( /\[\d*\]/g, '[' + index + ']' );
182
- $(this).attr( 'id', name );
183
- });
184
- });
185
-
186
- // Show the add rule button when multiple rules are
187
- // disabled and there are no more children
188
- var scheduler_id = scheduler.attr( 'id' );
189
- if ( sap_scheduler.settings[scheduler_id].disable_multiple && !scheduler.children().length ) {
190
- sap_scheduler_toggle_button( true, scheduler );
191
- }
192
- });
193
-
194
- return false;
195
- });
196
- }
197
-
198
- /**
199
- * Set the summary phrase for a scheduler rule's date. This phrase is shown
200
- * when the rule's view is minimized.
201
- */
202
- function sap_scheduler_set_date_phrase( scheduler_rule, scheduler_id ) {
203
-
204
- var date_value = scheduler_rule.find( '.sap-scheduler-date-input input' ).val();
205
- if ( typeof date_value !== 'undefined' && date_value != '' ) {
206
- scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( date_value );
207
-
208
- return;
209
- }
210
-
211
- var weekdays = 0;
212
- var weekday_arr = new Array();
213
- scheduler_rule.find( '.sap-scheduler-weekdays input' ).each( function() {
214
- if ( $(this).prop( 'checked' ) !== false ) {
215
- weekdays += 1;
216
- weekday_arr.push( sap_scheduler.settings[scheduler_id]['weekdays'][ $(this).data( 'day' ) ] );
217
- }
218
- });
219
-
220
- if ( weekdays == 0 && sap_scheduler.settings[ scheduler_id ].disable_weekdays === false ) {
221
- scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['never'] );
222
-
223
- return;
224
-
225
- } else if ( weekdays == 7 ) {
226
- var weekday_string = sap_scheduler.settings[scheduler_id].summaries['weekly_always'];
227
-
228
- } else {
229
- var weekday_string = weekday_arr.join( ', ' );
230
- }
231
-
232
- var weeks = 0;
233
- var weeks_arr = new Array();
234
- scheduler_rule.find( '.sap-scheduler-weeks input' ).each( function() {
235
- if ( $(this).prop( 'checked' ) !== false ) {
236
- weeks +=1;
237
- weeks_arr.push( sap_scheduler.settings[scheduler_id]['weeks'][ $(this).data( 'week' ) ] );
238
- }
239
- });
240
-
241
- if ( ( weeks == 0 || weeks == 5 ) && sap_scheduler.settings[ scheduler_id ].disable_weekdays === false ) {
242
- scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( weekday_string );
243
-
244
- return;
245
- }
246
-
247
- if ( weeks == 0 ) {
248
- scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['never'] );
249
-
250
- return;
251
- }
252
-
253
- if ( weekday_string != '' ) {
254
- scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['monthly_weekdays'].replace( '{days}', weekday_arr.join( ', ' ) ).replace( '{weeks}', weeks_arr.join( ', ' ) ) );
255
- } else {
256
- scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['monthly_weeks'].replace( '{weeks}', weeks_arr.join( ', ' ) ) );
257
- }
258
- }
259
-
260
- /**
261
- * Set the summary phrase for a scheduler rule's time. This phrase is shown
262
- * when the rule's view is minimized.
263
- */
264
- function sap_scheduler_set_time_phrase( scheduler_rule, scheduler_id ) {
265
-
266
- var start = scheduler_rule.find( '.sap-scheduler-time-input .start input' ).val();
267
- var end = scheduler_rule.find( '.sap-scheduler-time-input .end input' ).val();
268
-
269
- if ( start == '' && ( end == '' || typeof end == 'undefined' ) ) {
270
- scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( sap_scheduler.settings[scheduler_id].summaries['all_day'] );
271
-
272
- return;
273
- }
274
-
275
- if ( start == '' ) {
276
- scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( sap_scheduler.settings[scheduler_id].summaries['before'] + ' ' + end );
277
-
278
- return;
279
- }
280
-
281
- if ( end == '' || typeof end == 'undefined' ) {
282
- scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( sap_scheduler.settings[scheduler_id].summaries['after'] + ' ' + start );
283
-
284
- return;
285
- }
286
-
287
- if ( typeof end == 'undefined' ) {
288
- return scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( start );
289
- } else {
290
- return scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( start + sap_scheduler.settings[scheduler_id].summaries['separator'] + end );
291
- }
292
- }
293
-
294
- /**
295
- * Register a new datepicker on an element
296
- */
297
- function sap_scheduler_register_datepicker( el ) {
298
-
299
- el.pickadate({
300
- format: obj.date_format,
301
- formatSubmit: 'yyyy/mm/dd',
302
- hiddenName: true,
303
-
304
- // Select the value when loaded if a value has been set
305
- onStart: function() {
306
- if ( this.get() !== '' ) {
307
- var date = new Date( this.get() );
308
- if ( Object.prototype.toString.call( date ) === "[object Date]" ) {
309
- this.set( 'select', date );
310
- }
311
- }
312
- }
313
- });
314
- }
315
-
316
- /**
317
- * Register a new timepicker on an element
318
- */
319
- function sap_scheduler_register_timepicker( el ) {
320
-
321
- el.pickatime({
322
- interval: obj.time_interval,
323
- format: obj.time_format,
324
- formatSubmit: 'h:i A',
325
- hiddenName: true,
326
-
327
- // Select the value when loaded if a value has been set
328
- onStart: function() {
329
- if ( this.get() !== '' ) {
330
- var today = new Date();
331
- var today_date = today.getFullYear() + '/' + ( today.getMonth() + 1 ) + '/' + today.getDate();
332
- var time = new Date( today_date + ' ' + this.get() );
333
- if ( Object.prototype.toString.call( time ) === "[object Date]" ) {
334
- this.set( 'select', time );
335
- }
336
- }
337
- }
338
- });
339
- }
340
-
341
-
342
- /**
343
- * Register click events on load
344
- */
345
- sap_scheduler_register_events();
346
-
347
- /**
348
- * Enable datepickers on load
349
- */
350
- if ( typeof sap_scheduler.settings != 'undefined' ) {
351
- for ( var key in sap_scheduler.settings ) {
352
- var obj = sap_scheduler.settings[key];
353
- sap_scheduler_register_datepicker( $( '#' + key + ' .sap-scheduler-date-input input[type="text"]' ) );
354
- sap_scheduler_register_timepicker( $( '#' + key + ' .sap-scheduler-time-input input[type="text"]' ) );
355
-
356
- $( '#' + key + ' .sap-scheduler-rule' ).each( function() {
357
- sap_scheduler_set_date_phrase( $(this), $( '#' + key ).attr( 'id' ) );
358
- sap_scheduler_set_time_phrase( $(this), $( '#' + key ).attr( 'id' ) );
359
- });
360
- }
361
- }
362
-
363
- /**
364
- * Add a new scheduler panel
365
- */
366
- $( '.sap-add-scheduler a' ).click( function(e) {
367
-
368
- if ( $(this).parent().hasClass( 'disabled' ) ) {
369
- e.preventDefault();
370
- return;
371
- }
372
-
373
- var scheduler = $(this).parent().siblings( '.sap-scheduler' );
374
- var scheduler_id = scheduler.attr( 'id' );
375
- var scheduler_settings = sap_scheduler.settings[ scheduler_id ];
376
- scheduler.append( scheduler_settings.template.replace( /\[0\]/g, '[' + scheduler.children( '.sap-scheduler-rule' ).length + ']' ) );
377
- sap_scheduler_register_datepicker( scheduler.last( '#' + scheduler_id + ' .sap-scheduler-rule' ).find( '.sap-scheduler-date-input input[type="text"]' ) );
378
- sap_scheduler_register_timepicker( scheduler.last( '#' + scheduler_id + ' .sap-scheduler-rule' ).find( '.sap-scheduler-time-input input[type="text"]' ) );
379
- sap_scheduler_register_events();
380
-
381
- // Hide the add rule button if we've disabled multiple rules
382
- if ( sap_scheduler.settings[scheduler_id].disable_multiple ) {
383
- sap_scheduler_toggle_button( false, scheduler );
384
- }
385
-
386
- return false;
387
- });
388
-
389
- /**
390
- * Enable/disable the add new rule button
391
- */
392
- function sap_scheduler_toggle_button( on, scheduler ) {
393
- if ( on ) {
394
- scheduler.siblings( '.sap-add-scheduler' ).removeClass( 'disabled' );
395
- } else {
396
- scheduler.siblings( '.sap-add-scheduler' ).addClass( 'disabled' );
397
- }
398
- }
399
-
400
-
401
- }
402
-
403
- });
1
+ /**
2
+ * Javascript functions for the Scheduler component
3
+ *
4
+ * @package Simple Admin Pages
5
+ */
6
+
7
+ jQuery(document).ready(function ($) {
8
+
9
+ /**
10
+ * Scheduler
11
+ ***********/
12
+
13
+ if ( typeof sap_scheduler != 'undefined' ) {
14
+
15
+ /**
16
+ * Register event handlers on the scheduler rules. This is run on page load
17
+ * and every time a rule is added.
18
+ */
19
+ function sap_scheduler_register_events() {
20
+
21
+ /**
22
+ * Open and close the full view of a scheduling rule
23
+ */
24
+ $( '.sap-scheduler-rule .toggle' ).off( 'click' ).click( function() {
25
+
26
+ var controls = $(this).parent();
27
+
28
+ if ( $(this).parent().parent().hasClass( 'list' ) ) {
29
+ controls.hide();
30
+ $(this).children( '.dashicons-edit' ).removeClass( 'dashicons-edit' ).addClass( 'dashicons-arrow-up-alt2' );
31
+ controls.siblings( '.sap-scheduler-brief' ).hide();
32
+ controls.siblings( '.sap-scheduler-date, .sap-scheduler-time' ).slideDown( function() {
33
+ $(this).parent().removeClass( 'list' );
34
+ controls.fadeIn();
35
+ });
36
+
37
+ } else {
38
+ controls.hide();
39
+ $(this).children( '.dashicons-arrow-up-alt2' ).removeClass( 'dashicons-arrow-up-alt2' ).addClass( 'dashicons-edit' );
40
+ controls.siblings( '.sap-scheduler-brief' ).fadeIn();
41
+ controls.siblings( '.sap-scheduler-time' ).slideUp();
42
+ controls.siblings( '.sap-scheduler-date' ).slideUp( function() {
43
+
44
+ var scheduler_rule = $(this).parent();
45
+ var scheduler_id = scheduler_rule.parent().attr( 'id' );
46
+
47
+ scheduler_rule.addClass( 'list' );
48
+ controls.fadeIn();
49
+
50
+ sap_scheduler_set_date_phrase( scheduler_rule, scheduler_id );
51
+ sap_scheduler_set_time_phrase( scheduler_rule, scheduler_id );
52
+ });
53
+ }
54
+
55
+ return false;
56
+ });
57
+
58
+ /**
59
+ * Update current selection for selector lists
60
+ */
61
+ $( '.sap-selector a' ).off( 'switch.sap' ).on( 'switch.sap', function() {
62
+ $(this).parent().parent().find( 'a' ).removeClass( 'selected' );
63
+ $(this).addClass( 'selected' );
64
+
65
+ return false;
66
+ });
67
+
68
+ /**
69
+ * Switch between weekly, monthly and date options
70
+ */
71
+ $( '.sap-scheduler-date .sap-selector a' ).off( 'click' ).click( function() {
72
+
73
+ $(this).trigger( 'switch.sap' );
74
+
75
+ var date = $(this).closest( '.sap-scheduler-date' );
76
+
77
+ if ( $(this).data( 'format' ) == 'weekly' && date.hasClass( 'weekly' ) === false ) {
78
+ date.children( '.sap-scheduler-weeks' ).slideUp( function() {
79
+ $(this).find( 'input' ).prop('checked', false);
80
+ });
81
+ date.children( '.sap-scheduler-date-input' ).slideUp( function() {
82
+ $(this).find( 'input' ).val( '' );
83
+ });
84
+ date.children( '.sap-scheduler-weekdays' ).slideDown( function() {
85
+ date.removeClass( 'monthly date' );
86
+ date.addClass( 'weekly' );
87
+ });
88
+
89
+ } else if ( $(this).data( 'format' ) == 'monthly' && date.hasClass( 'monthly' ) === false ) {
90
+ date.children( '.sap-scheduler-date-input' ).slideUp( function() {
91
+ $(this).find( 'input' ).val( '' );
92
+ });
93
+ date.children( '.sap-scheduler-weekdays' ).slideDown();
94
+ date.children( '.sap-scheduler-weeks' ).slideDown( function() {
95
+ date.removeClass( 'weekly date' );
96
+ date.addClass( 'monthly' );
97
+ });
98
+
99
+ } else if ( $(this).data( 'format' ) == 'date' && date.hasClass( 'date' ) === false ) {
100
+ date.children( '.sap-scheduler-weekdays' ).slideUp( function() {
101
+ $(this).find( 'input' ).prop('checked', false);
102
+ });
103
+ date.children( '.sap-scheduler-weeks' ).slideUp( function() {
104
+ $(this).find( 'input' ).prop('checked', false);
105
+ });
106
+ date.children( '.sap-scheduler-date-input' ).slideDown( function() {
107
+ date.removeClass( 'weekly monthly' );
108
+ date.addClass( 'date' );
109
+ });
110
+ }
111
+
112
+ return false;
113
+ });
114
+
115
+ /**
116
+ * Show or hide time slot options
117
+ */
118
+ $( '.sap-scheduler-time .sap-selector a' ).off( 'click' ).click( function() {
119
+
120
+ $(this).trigger( 'switch.sap' );
121
+
122
+ var time = $(this).closest( '.sap-scheduler-time' );
123
+
124
+ if ( $(this).data( 'format' ) == 'time-slot' && time.hasClass( 'time-slot' ) === false ) {
125
+ time.children( '.sap-scheduler-time-input' ).slideDown();
126
+ time.children( '.sap-scheduler-all-day' ).slideUp( function() {
127
+ time.removeClass( 'all-day' );
128
+ time.addClass( 'time-slot' );
129
+ });
130
+
131
+ } else if ( $(this).data( 'format' ) == 'all-day' && time.hasClass( 'all-day' ) === false ) {
132
+ time.children( '.sap-scheduler-all-day' ).slideDown();
133
+ time.children( '.sap-scheduler-time-input' ).slideUp( function() {
134
+ time.removeClass( 'time-slot' );
135
+ time.addClass( 'all-day' );
136
+ time.find( 'input' ).val( '' );
137
+ });
138
+ }
139
+
140
+ return false;
141
+ });
142
+
143
+ /**
144
+ * Show time slot options from the link in the all-day notice
145
+ */
146
+ $( '.sap-scheduler-all-day a' ).off( 'click' ).click( function() {
147
+ $(this).closest( '.sap-scheduler-time' ).children( '.sap-selector' ).find( 'a[data-format="time-slot"]' ).trigger( 'click' );
148
+
149
+ return false;
150
+ });
151
+
152
+ /**
153
+ * Delete a scheduling rule panel
154
+ */
155
+ $( '.sap-scheduler-control .delete' ).off( 'click' ).click( function() {
156
+ var scheduler = $(this).closest( '.sap-scheduler' );
157
+ $(this).parent().parent().fadeOut( function() {
158
+ $(this).remove();
159
+
160
+ // Reset the index of each rule
161
+ // @todo optimize this excessive use of regex (32x per rule).
162
+ // maybe set a data-slug attribute on .sap-scheduler-rule and a
163
+ // data-slug prop on each input/select/label, then use these to
164
+ // construct the new attributes: rule-slug[index][input-slug]
165
+ scheduler.children( '.sap-scheduler-rule' ).each( function( i ) {
166
+ var index = i.toString();
167
+ $(this).find( 'input' ).each( function() {
168
+ var name = $(this).attr( 'name' ).replace( /\[\d*\]/g, '[' + index + ']' );
169
+ $(this).attr( 'name', name );
170
+ $(this).attr( 'id', name );
171
+ var aria_owns = $(this).attr( 'aria-owns' );
172
+ if ( typeof aria_owns !== 'undefined' && aria_owns !== false) {
173
+ $(this).attr( 'aria-owns', name );
174
+ }
175
+ });
176
+ $(this).find( 'label' ).each( function() {
177
+ var name = $(this).attr( 'for' ).replace( /\[\d*\]/g, '[' + index + ']' );
178
+ $(this).attr( 'for', name );
179
+ });
180
+ $(this).find( '.picker' ).each( function() {
181
+ var name = $(this).attr( 'id' ).replace( /\[\d*\]/g, '[' + index + ']' );
182
+ $(this).attr( 'id', name );
183
+ });
184
+ });
185
+
186
+ // Show the add rule button when multiple rules are
187
+ // disabled and there are no more children
188
+ var scheduler_id = scheduler.attr( 'id' );
189
+ if ( sap_scheduler.settings[scheduler_id].disable_multiple && !scheduler.children().length ) {
190
+ sap_scheduler_toggle_button( true, scheduler );
191
+ }
192
+ });
193
+
194
+ return false;
195
+ });
196
+ }
197
+
198
+ /**
199
+ * Set the summary phrase for a scheduler rule's date. This phrase is shown
200
+ * when the rule's view is minimized.
201
+ */
202
+ function sap_scheduler_set_date_phrase( scheduler_rule, scheduler_id ) {
203
+
204
+ var date_value = scheduler_rule.find( '.sap-scheduler-date-input input' ).val();
205
+ if ( typeof date_value !== 'undefined' && date_value != '' ) {
206
+ scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( date_value );
207
+
208
+ return;
209
+ }
210
+
211
+ var weekdays = 0;
212
+ var weekday_arr = new Array();
213
+ scheduler_rule.find( '.sap-scheduler-weekdays input' ).each( function() {
214
+ if ( $(this).prop( 'checked' ) !== false ) {
215
+ weekdays += 1;
216
+ weekday_arr.push( sap_scheduler.settings[scheduler_id]['weekdays'][ $(this).data( 'day' ) ] );
217
+ }
218
+ });
219
+
220
+ if ( weekdays == 0 && sap_scheduler.settings[ scheduler_id ].disable_weekdays === false ) {
221
+ scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['never'] );
222
+
223
+ return;
224
+
225
+ } else if ( weekdays == 7 ) {
226
+ var weekday_string = sap_scheduler.settings[scheduler_id].summaries['weekly_always'];
227
+
228
+ } else {
229
+ var weekday_string = weekday_arr.join( ', ' );
230
+ }
231
+
232
+ var weeks = 0;
233
+ var weeks_arr = new Array();
234
+ scheduler_rule.find( '.sap-scheduler-weeks input' ).each( function() {
235
+ if ( $(this).prop( 'checked' ) !== false ) {
236
+ weeks +=1;
237
+ weeks_arr.push( sap_scheduler.settings[scheduler_id]['weeks'][ $(this).data( 'week' ) ] );
238
+ }
239
+ });
240
+
241
+ if ( ( weeks == 0 || weeks == 5 ) && sap_scheduler.settings[ scheduler_id ].disable_weekdays === false ) {
242
+ scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( weekday_string );
243
+
244
+ return;
245
+ }
246
+
247
+ if ( weeks == 0 ) {
248
+ scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['never'] );
249
+
250
+ return;
251
+ }
252
+
253
+ if ( weekday_string != '' ) {
254
+ scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['monthly_weekdays'].replace( '{days}', weekday_arr.join( ', ' ) ).replace( '{weeks}', weeks_arr.join( ', ' ) ) );
255
+ } else {
256
+ scheduler_rule.find( '.sap-scheduler-brief .date .value' ).html( sap_scheduler.settings[scheduler_id].summaries['monthly_weeks'].replace( '{weeks}', weeks_arr.join( ', ' ) ) );
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Set the summary phrase for a scheduler rule's time. This phrase is shown
262
+ * when the rule's view is minimized.
263
+ */
264
+ function sap_scheduler_set_time_phrase( scheduler_rule, scheduler_id ) {
265
+
266
+ var start = scheduler_rule.find( '.sap-scheduler-time-input .start input' ).val();
267
+ var end = scheduler_rule.find( '.sap-scheduler-time-input .end input' ).val();
268
+
269
+ if ( start == '' && ( end == '' || typeof end == 'undefined' ) ) {
270
+ scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( sap_scheduler.settings[scheduler_id].summaries['all_day'] );
271
+
272
+ return;
273
+ }
274
+
275
+ if ( start == '' ) {
276
+ scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( sap_scheduler.settings[scheduler_id].summaries['before'] + ' ' + end );
277
+
278
+ return;
279
+ }
280
+
281
+ if ( end == '' || typeof end == 'undefined' ) {
282
+ scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( sap_scheduler.settings[scheduler_id].summaries['after'] + ' ' + start );
283
+
284
+ return;
285
+ }
286
+
287
+ if ( typeof end == 'undefined' ) {
288
+ return scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( start );
289
+ } else {
290
+ return scheduler_rule.find( '.sap-scheduler-brief .time .value' ).html( start + sap_scheduler.settings[scheduler_id].summaries['separator'] + end );
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Register a new datepicker on an element
296
+ */
297
+ function sap_scheduler_register_datepicker( el ) {
298
+
299
+ el.pickadate({
300
+ format: obj.date_format,
301
+ formatSubmit: 'yyyy/mm/dd',
302
+ hiddenName: true,
303
+
304
+ // Select the value when loaded if a value has been set
305
+ onStart: function() {
306
+ if ( this.get() !== '' ) {
307
+ var date = new Date( this.get() );
308
+ if ( Object.prototype.toString.call( date ) === "[object Date]" ) {
309
+ this.set( 'select', date );
310
+ }
311
+ }
312
+ }
313
+ });
314
+ }
315
+
316
+ /**
317
+ * Register a new timepicker on an element
318
+ */
319
+ function sap_scheduler_register_timepicker( el ) {
320
+
321
+ el.pickatime({
322
+ interval: obj.time_interval,
323
+ format: obj.time_format,
324
+ formatSubmit: 'h:i A',
325
+ hiddenName: true,
326
+
327
+ // Select the value when loaded if a value has been set
328
+ onStart: function() {
329
+ if ( this.get() !== '' ) {
330
+ var today = new Date();
331
+ var today_date = today.getFullYear() + '/' + ( today.getMonth() + 1 ) + '/' + today.getDate();
332
+ var time = new Date( today_date + ' ' + this.get() );
333
+ if ( Object.prototype.toString.call( time ) === "[object Date]" ) {
334
+ this.set( 'select', time );
335
+ }
336
+ }
337
+ }
338
+ });
339
+ }
340
+
341
+
342
+ /**
343
+ * Register click events on load
344
+ */
345
+ sap_scheduler_register_events();
346
+
347
+ /**
348
+ * Enable datepickers on load
349
+ */
350
+ if ( typeof sap_scheduler.settings != 'undefined' ) {
351
+ for ( var key in sap_scheduler.settings ) {
352
+ var obj = sap_scheduler.settings[key];
353
+ sap_scheduler_register_datepicker( $( '#' + key + ' .sap-scheduler-date-input input[type="text"]' ) );
354
+ sap_scheduler_register_timepicker( $( '#' + key + ' .sap-scheduler-time-input input[type="text"]' ) );
355
+
356
+ $( '#' + key + ' .sap-scheduler-rule' ).each( function() {
357
+ sap_scheduler_set_date_phrase( $(this), $( '#' + key ).attr( 'id' ) );
358
+ sap_scheduler_set_time_phrase( $(this), $( '#' + key ).attr( 'id' ) );
359
+ });
360
+ }
361
+ }
362
+
363
+ /**
364
+ * Add a new scheduler panel
365
+ */
366
+ $( '.sap-add-scheduler a' ).click( function(e) {
367
+
368
+ if ( $(this).parent().hasClass( 'disabled' ) ) {
369
+ e.preventDefault();
370
+ return;
371
+ }
372
+
373
+ var scheduler = $(this).parent().siblings( '.sap-scheduler' );
374
+ var scheduler_id = scheduler.attr( 'id' );
375
+ var scheduler_settings = sap_scheduler.settings[ scheduler_id ];
376
+ scheduler.append( scheduler_settings.template.replace( /\[0\]/g, '[' + scheduler.children( '.sap-scheduler-rule' ).length + ']' ) );
377
+ sap_scheduler_register_datepicker( scheduler.last( '#' + scheduler_id + ' .sap-scheduler-rule' ).find( '.sap-scheduler-date-input input[type="text"]' ) );
378
+ sap_scheduler_register_timepicker( scheduler.last( '#' + scheduler_id + ' .sap-scheduler-rule' ).find( '.sap-scheduler-time-input input[type="text"]' ) );
379
+ sap_scheduler_register_events();
380
+
381
+ // Hide the add rule button if we've disabled multiple rules
382
+ if ( sap_scheduler.settings[scheduler_id].disable_multiple ) {
383
+ sap_scheduler_toggle_button( false, scheduler );
384
+ }
385
+
386
+ return false;
387
+ });
388
+
389
+ /**
390
+ * Enable/disable the add new rule button
391
+ */
392
+ function sap_scheduler_toggle_button( on, scheduler ) {
393
+ if ( on ) {
394
+ scheduler.siblings( '.sap-add-scheduler' ).removeClass( 'disabled' );
395
+ } else {
396
+ scheduler.siblings( '.sap-add-scheduler' ).addClass( 'disabled' );
397
+ }
398
+ }
399
+
400
+
401
+ }
402
+
403
+ });
lib/simple-admin-pages/js/spectrum.js ADDED
@@ -0,0 +1,2317 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Spectrum Colorpicker v1.7.1
2
+ // https://github.com/bgrins/spectrum
3
+ // Author: Brian Grinstead
4
+ // License: MIT
5
+
6
+ (function (factory) {
7
+ "use strict";
8
+
9
+ if (typeof define === 'function' && define.amd) { // AMD
10
+ define(['jquery'], factory);
11
+ }
12
+ else if (typeof exports == "object" && typeof module == "object") { // CommonJS
13
+ module.exports = factory;
14
+ }
15
+ else { // Browser
16
+ factory(jQuery);
17
+ }
18
+ })(function($, undefined) {
19
+ "use strict";
20
+
21
+ var defaultOpts = {
22
+
23
+ // Callbacks
24
+ beforeShow: noop,
25
+ move: noop,
26
+ change: noop,
27
+ show: noop,
28
+ hide: noop,
29
+
30
+ // Options
31
+ color: false,
32
+ flat: false,
33
+ showInput: false,
34
+ allowEmpty: false,
35
+ showButtons: true,
36
+ clickoutFiresChange: true,
37
+ showInitial: false,
38
+ showPalette: false,
39
+ showPaletteOnly: false,
40
+ hideAfterPaletteSelect: false,
41
+ togglePaletteOnly: false,
42
+ showSelectionPalette: true,
43
+ localStorageKey: false,
44
+ appendTo: "body",
45
+ maxSelectionSize: 7,
46
+ cancelText: "cancel",
47
+ chooseText: "choose",
48
+ togglePaletteMoreText: "more",
49
+ togglePaletteLessText: "less",
50
+ clearText: "Clear Color Selection",
51
+ noColorSelectedText: "No Color Selected",
52
+ preferredFormat: false,
53
+ className: "", // Deprecated - use containerClassName and replacerClassName instead.
54
+ containerClassName: "",
55
+ replacerClassName: "",
56
+ showAlpha: false,
57
+ theme: "sp-light",
58
+ palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]],
59
+ selectionPalette: [],
60
+ disabled: false,
61
+ offset: null
62
+ },
63
+ spectrums = [],
64
+ IE = !!/msie/i.exec( window.navigator.userAgent ),
65
+ rgbaSupport = (function() {
66
+ function contains( str, substr ) {
67
+ return !!~('' + str).indexOf(substr);
68
+ }
69
+
70
+ var elem = document.createElement('div');
71
+ var style = elem.style;
72
+ style.cssText = 'background-color:rgba(0,0,0,.5)';
73
+ return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
74
+ })(),
75
+ replaceInput = [
76
+ "<div class='sp-replacer'>",
77
+ "<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
78
+ "<div class='sp-dd'>&#9660;</div>",
79
+ "</div>"
80
+ ].join(''),
81
+ markup = (function () {
82
+
83
+ // IE does not support gradients with multiple stops, so we need to simulate
84
+ // that for the rainbow slider with 8 divs that each have a single gradient
85
+ var gradientFix = "";
86
+ if (IE) {
87
+ for (var i = 1; i <= 6; i++) {
88
+ gradientFix += "<div class='sp-" + i + "'></div>";
89
+ }
90
+ }
91
+
92
+ return [
93
+ "<div class='sp-container sp-hidden'>",
94
+ "<div class='sp-palette-container'>",
95
+ "<div class='sp-palette sp-thumb sp-cf'></div>",
96
+ "<div class='sp-palette-button-container sp-cf'>",
97
+ "<button type='button' class='sp-palette-toggle'></button>",
98
+ "</div>",
99
+ "</div>",
100
+ "<div class='sp-picker-container'>",
101
+ "<div class='sp-top sp-cf'>",
102
+ "<div class='sp-fill'></div>",
103
+ "<div class='sp-top-inner'>",
104
+ "<div class='sp-color'>",
105
+ "<div class='sp-sat'>",
106
+ "<div class='sp-val'>",
107
+ "<div class='sp-dragger'></div>",
108
+ "</div>",
109
+ "</div>",
110
+ "</div>",
111
+ "<div class='sp-clear sp-clear-display'>",
112
+ "</div>",
113
+ "<div class='sp-hue'>",
114
+ "<div class='sp-slider'></div>",
115
+ gradientFix,
116
+ "</div>",
117
+ "</div>",
118
+ "<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
119
+ "</div>",
120
+ "<div class='sp-input-container sp-cf'>",
121
+ "<input class='sp-input' type='text' spellcheck='false' />",
122
+ "</div>",
123
+ "<div class='sp-initial sp-thumb sp-cf'></div>",
124
+ "<div class='sp-button-container sp-cf'>",
125
+ "<a class='sp-cancel' href='#'></a>",
126
+ "<button type='button' class='sp-choose'></button>",
127
+ "</div>",
128
+ "</div>",
129
+ "</div>"
130
+ ].join("");
131
+ })();
132
+
133
+ function paletteTemplate (p, color, className, opts) {
134
+ var html = [];
135
+ for (var i = 0; i < p.length; i++) {
136
+ var current = p[i];
137
+ if(current) {
138
+ var tiny = tinycolor(current);
139
+ var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
140
+ c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : "";
141
+ var formattedString = tiny.toString(opts.preferredFormat || "rgb");
142
+ var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
143
+ html.push('<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
144
+ } else {
145
+ var cls = 'sp-clear-display';
146
+ html.push($('<div />')
147
+ .append($('<span data-color="" style="background-color:transparent;" class="' + cls + '"></span>')
148
+ .attr('title', opts.noColorSelectedText)
149
+ )
150
+ .html()
151
+ );
152
+ }
153
+ }
154
+ return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
155
+ }
156
+
157
+ function hideAll() {
158
+ for (var i = 0; i < spectrums.length; i++) {
159
+ if (spectrums[i]) {
160
+ spectrums[i].hide();
161
+ }
162
+ }
163
+ }
164
+
165
+ function instanceOptions(o, callbackContext) {
166
+ var opts = $.extend({}, defaultOpts, o);
167
+ opts.callbacks = {
168
+ 'move': bind(opts.move, callbackContext),
169
+ 'change': bind(opts.change, callbackContext),
170
+ 'show': bind(opts.show, callbackContext),
171
+ 'hide': bind(opts.hide, callbackContext),
172
+ 'beforeShow': bind(opts.beforeShow, callbackContext)
173
+ };
174
+
175
+ return opts;
176
+ }
177
+
178
+ function spectrum(element, o) {
179
+
180
+ var opts = instanceOptions(o, element),
181
+ flat = opts.flat,
182
+ showSelectionPalette = opts.showSelectionPalette,
183
+ localStorageKey = opts.localStorageKey,
184
+ theme = opts.theme,
185
+ callbacks = opts.callbacks,
186
+ resize = throttle(reflow, 10),
187
+ visible = false,
188
+ isDragging = false,
189
+ dragWidth = 0,
190
+ dragHeight = 0,
191
+ dragHelperHeight = 0,
192
+ slideHeight = 0,
193
+ slideWidth = 0,
194
+ alphaWidth = 0,
195
+ alphaSlideHelperWidth = 0,
196
+ slideHelperHeight = 0,
197
+ currentHue = 0,
198
+ currentSaturation = 0,
199
+ currentValue = 0,
200
+ currentAlpha = 1,
201
+ palette = [],
202
+ paletteArray = [],
203
+ paletteLookup = {},
204
+ selectionPalette = opts.selectionPalette.slice(0),
205
+ maxSelectionSize = opts.maxSelectionSize,
206
+ draggingClass = "sp-dragging",
207
+ shiftMovementDirection = null;
208
+
209
+ var doc = element.ownerDocument,
210
+ body = doc.body,
211
+ boundElement = $(element),
212
+ disabled = false,
213
+ container = $(markup, doc).addClass(theme),
214
+ pickerContainer = container.find(".sp-picker-container"),
215
+ dragger = container.find(".sp-color"),
216
+ dragHelper = container.find(".sp-dragger"),
217
+ slider = container.find(".sp-hue"),
218
+ slideHelper = container.find(".sp-slider"),
219
+ alphaSliderInner = container.find(".sp-alpha-inner"),
220
+ alphaSlider = container.find(".sp-alpha"),
221
+ alphaSlideHelper = container.find(".sp-alpha-handle"),
222
+ textInput = container.find(".sp-input"),
223
+ paletteContainer = container.find(".sp-palette"),
224
+ initialColorContainer = container.find(".sp-initial"),
225
+ cancelButton = container.find(".sp-cancel"),
226
+ clearButton = container.find(".sp-clear"),
227
+ chooseButton = container.find(".sp-choose"),
228
+ toggleButton = container.find(".sp-palette-toggle"),
229
+ isInput = boundElement.is("input"),
230
+ isInputTypeColor = isInput && boundElement.attr("type") === "color" && inputTypeColorSupport(),
231
+ shouldReplace = isInput && !flat,
232
+ replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]),
233
+ offsetElement = (shouldReplace) ? replacer : boundElement,
234
+ previewElement = replacer.find(".sp-preview-inner"),
235
+ initialColor = opts.color || (isInput && boundElement.val()),
236
+ colorOnShow = false,
237
+ preferredFormat = opts.preferredFormat,
238
+ currentPreferredFormat = preferredFormat,
239
+ clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
240
+ isEmpty = !initialColor,
241
+ allowEmpty = opts.allowEmpty && !isInputTypeColor;
242
+
243
+ function applyOptions() {
244
+
245
+ if (opts.showPaletteOnly) {
246
+ opts.showPalette = true;
247
+ }
248
+
249
+ toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
250
+
251
+ if (opts.palette) {
252
+ palette = opts.palette.slice(0);
253
+ paletteArray = $.isArray(palette[0]) ? palette : [palette];
254
+ paletteLookup = {};
255
+ for (var i = 0; i < paletteArray.length; i++) {
256
+ for (var j = 0; j < paletteArray[i].length; j++) {
257
+ var rgb = tinycolor(paletteArray[i][j]).toRgbString();
258
+ paletteLookup[rgb] = true;
259
+ }
260
+ }
261
+ }
262
+
263
+ container.toggleClass("sp-flat", flat);
264
+ container.toggleClass("sp-input-disabled", !opts.showInput);
265
+ container.toggleClass("sp-alpha-enabled", opts.showAlpha);
266
+ container.toggleClass("sp-clear-enabled", allowEmpty);
267
+ container.toggleClass("sp-buttons-disabled", !opts.showButtons);
268
+ container.toggleClass("sp-palette-buttons-disabled", !opts.togglePaletteOnly);
269
+ container.toggleClass("sp-palette-disabled", !opts.showPalette);
270
+ container.toggleClass("sp-palette-only", opts.showPaletteOnly);
271
+ container.toggleClass("sp-initial-disabled", !opts.showInitial);
272
+ container.addClass(opts.className).addClass(opts.containerClassName);
273
+
274
+ reflow();
275
+ }
276
+
277
+ function initialize() {
278
+
279
+ if (IE) {
280
+ container.find("*:not(input)").attr("unselectable", "on");
281
+ }
282
+
283
+ applyOptions();
284
+
285
+ if (shouldReplace) {
286
+ boundElement.after(replacer).hide();
287
+ }
288
+
289
+ if (!allowEmpty) {
290
+ clearButton.hide();
291
+ }
292
+
293
+ if (flat) {
294
+ boundElement.after(container).hide();
295
+ }
296
+ else {
297
+
298
+ var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo);
299
+ if (appendTo.length !== 1) {
300
+ appendTo = $("body");
301
+ }
302
+
303
+ appendTo.append(container);
304
+ }
305
+
306
+ updateSelectionPaletteFromStorage();
307
+
308
+ offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
309
+ if (!disabled) {
310
+ toggle();
311
+ }
312
+
313
+ e.stopPropagation();
314
+
315
+ if (!$(e.target).is("input")) {
316
+ e.preventDefault();
317
+ }
318
+ });
319
+
320
+ if(boundElement.is(":disabled") || (opts.disabled === true)) {
321
+ disable();
322
+ }
323
+
324
+ // Prevent clicks from bubbling up to document. This would cause it to be hidden.
325
+ container.click(stopPropagation);
326
+
327
+ // Handle user typed input
328
+ textInput.change(setFromTextInput);
329
+ textInput.bind("paste", function () {
330
+ setTimeout(setFromTextInput, 1);
331
+ });
332
+ textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
333
+
334
+ cancelButton.text(opts.cancelText);
335
+ cancelButton.bind("click.spectrum", function (e) {
336
+ e.stopPropagation();
337
+ e.preventDefault();
338
+ revert();
339
+ hide();
340
+ });
341
+
342
+ clearButton.attr("title", opts.clearText);
343
+ clearButton.bind("click.spectrum", function (e) {
344
+ e.stopPropagation();
345
+ e.preventDefault();
346
+ isEmpty = true;
347
+ move();
348
+
349
+ if(flat) {
350
+ //for the flat style, this is a change event
351
+ updateOriginalInput(true);
352
+ }
353
+ });
354
+
355
+ chooseButton.text(opts.chooseText);
356
+ chooseButton.bind("click.spectrum", function (e) {
357
+ e.stopPropagation();
358
+ e.preventDefault();
359
+
360
+ if (IE && textInput.is(":focus")) {
361
+ textInput.trigger('change');
362
+ }
363
+
364
+ if (isValid()) {
365
+ updateOriginalInput(true);
366
+ hide();
367
+ }
368
+ });
369
+
370
+ toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
371
+ toggleButton.bind("click.spectrum", function (e) {
372
+ e.stopPropagation();
373
+ e.preventDefault();
374
+
375
+ opts.showPaletteOnly = !opts.showPaletteOnly;
376
+
377
+ // To make sure the Picker area is drawn on the right, next to the
378
+ // Palette area (and not below the palette), first move the Palette
379
+ // to the left to make space for the picker, plus 5px extra.
380
+ // The 'applyOptions' function puts the whole container back into place
381
+ // and takes care of the button-text and the sp-palette-only CSS class.
382
+ if (!opts.showPaletteOnly && !flat) {
383
+ container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5));
384
+ }
385
+ applyOptions();
386
+ });
387
+
388
+ draggable(alphaSlider, function (dragX, dragY, e) {
389
+ currentAlpha = (dragX / alphaWidth);
390
+ isEmpty = false;
391
+ if (e.shiftKey) {
392
+ currentAlpha = Math.round(currentAlpha * 10) / 10;
393
+ }
394
+
395
+ move();
396
+ }, dragStart, dragStop);
397
+
398
+ draggable(slider, function (dragX, dragY) {
399
+ currentHue = parseFloat(dragY / slideHeight);
400
+ isEmpty = false;
401
+ if (!opts.showAlpha) {
402
+ currentAlpha = 1;
403
+ }
404
+ move();
405
+ }, dragStart, dragStop);
406
+
407
+ draggable(dragger, function (dragX, dragY, e) {
408
+
409
+ // shift+drag should snap the movement to either the x or y axis.
410
+ if (!e.shiftKey) {
411
+ shiftMovementDirection = null;
412
+ }
413
+ else if (!shiftMovementDirection) {
414
+ var oldDragX = currentSaturation * dragWidth;
415
+ var oldDragY = dragHeight - (currentValue * dragHeight);
416
+ var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
417
+
418
+ shiftMovementDirection = furtherFromX ? "x" : "y";
419
+ }
420
+
421
+ var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x";
422
+ var setValue = !shiftMovementDirection || shiftMovementDirection === "y";
423
+
424
+ if (setSaturation) {
425
+ currentSaturation = parseFloat(dragX / dragWidth);
426
+ }
427
+ if (setValue) {
428
+ currentValue = parseFloat((dragHeight - dragY) / dragHeight);
429
+ }
430
+
431
+ isEmpty = false;
432
+ if (!opts.showAlpha) {
433
+ currentAlpha = 1;
434
+ }
435
+
436
+ move();
437
+
438
+ }, dragStart, dragStop);
439
+
440
+ if (!!initialColor) {
441
+ set(initialColor);
442
+
443
+ // In case color was black - update the preview UI and set the format
444
+ // since the set function will not run (default color is black).
445
+ updateUI();
446
+ currentPreferredFormat = preferredFormat || tinycolor(initialColor).format;
447
+
448
+ addColorToSelectionPalette(initialColor);
449
+ }
450
+ else {
451
+ updateUI();
452
+ }
453
+
454
+ if (flat) {
455
+ show();
456
+ }
457
+
458
+ function paletteElementClick(e) {
459
+ if (e.data && e.data.ignore) {
460
+ set($(e.target).closest(".sp-thumb-el").data("color"));
461
+ move();
462
+ }
463
+ else {
464
+ set($(e.target).closest(".sp-thumb-el").data("color"));
465
+ move();
466
+ updateOriginalInput(true);
467
+ if (opts.hideAfterPaletteSelect) {
468
+ hide();
469
+ }
470
+ }
471
+
472
+ return false;
473
+ }
474
+
475
+ var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
476
+ paletteContainer.delegate(".sp-thumb-el", paletteEvent, paletteElementClick);
477
+ initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, paletteElementClick);
478
+ }
479
+
480
+ function updateSelectionPaletteFromStorage() {
481
+
482
+ if (localStorageKey && window.localStorage) {
483
+
484
+ // Migrate old palettes over to new format. May want to remove this eventually.
485
+ try {
486
+ var oldPalette = window.localStorage[localStorageKey].split(",#");
487
+ if (oldPalette.length > 1) {
488
+ delete window.localStorage[localStorageKey];
489
+ $.each(oldPalette, function(i, c) {
490
+ addColorToSelectionPalette(c);
491
+ });
492
+ }
493
+ }
494
+ catch(e) { }
495
+
496
+ try {
497
+ selectionPalette = window.localStorage[localStorageKey].split(";");
498
+ }
499
+ catch (e) { }
500
+ }
501
+ }
502
+
503
+ function addColorToSelectionPalette(color) {
504
+ if (showSelectionPalette) {
505
+ var rgb = tinycolor(color).toRgbString();
506
+ if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
507
+ selectionPalette.push(rgb);
508
+ while(selectionPalette.length > maxSelectionSize) {
509
+ selectionPalette.shift();
510
+ }
511
+ }
512
+
513
+ if (localStorageKey && window.localStorage) {
514
+ try {
515
+ window.localStorage[localStorageKey] = selectionPalette.join(";");
516
+ }
517
+ catch(e) { }
518
+ }
519
+ }
520
+ }
521
+
522
+ function getUniqueSelectionPalette() {
523
+ var unique = [];
524
+ if (opts.showPalette) {
525
+ for (var i = 0; i < selectionPalette.length; i++) {
526
+ var rgb = tinycolor(selectionPalette[i]).toRgbString();
527
+
528
+ if (!paletteLookup[rgb]) {
529
+ unique.push(selectionPalette[i]);
530
+ }
531
+ }
532
+ }
533
+
534
+ return unique.reverse().slice(0, opts.maxSelectionSize);
535
+ }
536
+
537
+ function drawPalette() {
538
+
539
+ var currentColor = get();
540
+
541
+ var html = $.map(paletteArray, function (palette, i) {
542
+ return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts);
543
+ });
544
+
545
+ updateSelectionPaletteFromStorage();
546
+
547
+ if (selectionPalette) {
548
+ html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts));
549
+ }
550
+
551
+ paletteContainer.html(html.join(""));
552
+ }
553
+
554
+ function drawInitial() {
555
+ if (opts.showInitial) {
556
+ var initial = colorOnShow;
557
+ var current = get();
558
+ initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts));
559
+ }
560
+ }
561
+
562
+ function dragStart() {
563
+ if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
564
+ reflow();
565
+ }
566
+ isDragging = true;
567
+ container.addClass(draggingClass);
568
+ shiftMovementDirection = null;
569
+ boundElement.trigger('dragstart.spectrum', [ get() ]);
570
+ }
571
+
572
+ function dragStop() {
573
+ isDragging = false;
574
+ container.removeClass(draggingClass);
575
+ boundElement.trigger('dragstop.spectrum', [ get() ]);
576
+ }
577
+
578
+ function setFromTextInput() {
579
+
580
+ var value = textInput.val();
581
+
582
+ if ((value === null || value === "") && allowEmpty) {
583
+ set(null);
584
+ updateOriginalInput(true);
585
+ }
586
+ else {
587
+ var tiny = tinycolor(value);
588
+ if (tiny.isValid()) {
589
+ set(tiny);
590
+ updateOriginalInput(true);
591
+ }
592
+ else {
593
+ textInput.addClass("sp-validation-error");
594
+ }
595
+ }
596
+ }
597
+
598
+ function toggle() {
599
+ if (visible) {
600
+ hide();
601
+ }
602
+ else {
603
+ show();
604
+ }
605
+ }
606
+
607
+ function show() {
608
+ var event = $.Event('beforeShow.spectrum');
609
+
610
+ if (visible) {
611
+ reflow();
612
+ return;
613
+ }
614
+
615
+ boundElement.trigger(event, [ get() ]);
616
+
617
+ if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
618
+ return;
619
+ }
620
+
621
+ hideAll();
622
+ visible = true;
623
+
624
+ $(doc).bind("keydown.spectrum", onkeydown);
625
+ $(doc).bind("click.spectrum", clickout);
626
+ $(window).bind("resize.spectrum", resize);
627
+ replacer.addClass("sp-active");
628
+ container.removeClass("sp-hidden");
629
+
630
+ reflow();
631
+ updateUI();
632
+
633
+ colorOnShow = get();
634
+
635
+ drawInitial();
636
+ callbacks.show(colorOnShow);
637
+ boundElement.trigger('show.spectrum', [ colorOnShow ]);
638
+ }
639
+
640
+ function onkeydown(e) {
641
+ // Close on ESC
642
+ if (e.keyCode === 27) {
643
+ hide();
644
+ }
645
+ }
646
+
647
+ function clickout(e) {
648
+ // Return on right click.
649
+ if (e.button == 2) { return; }
650
+
651
+ // If a drag event was happening during the mouseup, don't hide
652
+ // on click.
653
+ if (isDragging) { return; }
654
+
655
+ if (clickoutFiresChange) {
656
+ updateOriginalInput(true);
657
+ }
658
+ else {
659
+ revert();
660
+ }
661
+ hide();
662
+ }
663
+
664
+ function hide() {
665
+ // Return if hiding is unnecessary
666
+ if (!visible || flat) { return; }
667
+ visible = false;
668
+
669
+ $(doc).unbind("keydown.spectrum", onkeydown);
670
+ $(doc).unbind("click.spectrum", clickout);
671
+ $(window).unbind("resize.spectrum", resize);
672
+
673
+ replacer.removeClass("sp-active");
674
+ container.addClass("sp-hidden");
675
+
676
+ callbacks.hide(get());
677
+ boundElement.trigger('hide.spectrum', [ get() ]);
678
+ }
679
+
680
+ function revert() {
681
+ set(colorOnShow, true);
682
+ }
683
+
684
+ function set(color, ignoreFormatChange) {
685
+ if (tinycolor.equals(color, get())) {
686
+ // Update UI just in case a validation error needs
687
+ // to be cleared.
688
+ updateUI();
689
+ return;
690
+ }
691
+
692
+ var newColor, newHsv;
693
+ if (!color && allowEmpty) {
694
+ isEmpty = true;
695
+ } else {
696
+ isEmpty = false;
697
+ newColor = tinycolor(color);
698
+ newHsv = newColor.toHsv();
699
+
700
+ currentHue = (newHsv.h % 360) / 360;
701
+ currentSaturation = newHsv.s;
702
+ currentValue = newHsv.v;
703
+ currentAlpha = newHsv.a;
704
+ }
705
+ updateUI();
706
+
707
+ if (newColor && newColor.isValid() && !ignoreFormatChange) {
708
+ currentPreferredFormat = preferredFormat || newColor.getFormat();
709
+ }
710
+ }
711
+
712
+ function get(opts) {
713
+ opts = opts || { };
714
+
715
+ if (allowEmpty && isEmpty) {
716
+ return null;
717
+ }
718
+
719
+ return tinycolor.fromRatio({
720
+ h: currentHue,
721
+ s: currentSaturation,
722
+ v: currentValue,
723
+ a: Math.round(currentAlpha * 100) / 100
724
+ }, { format: opts.format || currentPreferredFormat });
725
+ }
726
+
727
+ function isValid() {
728
+ return !textInput.hasClass("sp-validation-error");
729
+ }
730
+
731
+ function move() {
732
+ updateUI();
733
+
734
+ callbacks.move(get());
735
+ boundElement.trigger('move.spectrum', [ get() ]);
736
+ }
737
+
738
+ function updateUI() {
739
+
740
+ textInput.removeClass("sp-validation-error");
741
+
742
+ updateHelperLocations();
743
+
744
+ // Update dragger background color (gradients take care of saturation and value).
745
+ var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
746
+ dragger.css("background-color", flatColor.toHexString());
747
+
748
+ // Get a format that alpha will be included in (hex and names ignore alpha)
749
+ var format = currentPreferredFormat;
750
+ if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) {
751
+ if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") {
752
+ format = "rgb";
753
+ }
754
+ }
755
+
756
+ var realColor = get({ format: format }),
757
+ displayColor = '';
758
+
759
+ //reset background info for preview element
760
+ previewElement.removeClass("sp-clear-display");
761
+ previewElement.css('background-color', 'transparent');
762
+
763
+ if (!realColor && allowEmpty) {
764
+ // Update the replaced elements background with icon indicating no color selection
765
+ previewElement.addClass("sp-clear-display");
766
+ }
767
+ else {
768
+ var realHex = realColor.toHexString(),
769
+ realRgb = realColor.toRgbString();
770
+
771
+ // Update the replaced elements background color (with actual selected color)
772
+ if (rgbaSupport || realColor.alpha === 1) {
773
+ previewElement.css("background-color", realRgb);
774
+ }
775
+ else {
776
+ previewElement.css("background-color", "transparent");
777
+ previewElement.css("filter", realColor.toFilter());
778
+ }
779
+
780
+ if (opts.showAlpha) {
781
+ var rgb = realColor.toRgb();
782
+ rgb.a = 0;
783
+ var realAlpha = tinycolor(rgb).toRgbString();
784
+ var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
785
+
786
+ if (IE) {
787
+ alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
788
+ }
789
+ else {
790
+ alphaSliderInner.css("background", "-webkit-" + gradient);
791
+ alphaSliderInner.css("background", "-moz-" + gradient);
792
+ alphaSliderInner.css("background", "-ms-" + gradient);
793
+ // Use current syntax gradient on unprefixed property.
794
+ alphaSliderInner.css("background",
795
+ "linear-gradient(to right, " + realAlpha + ", " + realHex + ")");
796
+ }
797
+ }
798
+
799
+ displayColor = realColor.toString(format);
800
+ }
801
+
802
+ // Update the text entry input as it changes happen
803
+ if (opts.showInput) {
804
+ textInput.val(displayColor);
805
+ }
806
+
807
+ if (opts.showPalette) {
808
+ drawPalette();
809
+ }
810
+
811
+ drawInitial();
812
+ }
813
+
814
+ function updateHelperLocations() {
815
+ var s = currentSaturation;
816
+ var v = currentValue;
817
+
818
+ if(allowEmpty && isEmpty) {
819
+ //if selected color is empty, hide the helpers
820
+ alphaSlideHelper.hide();
821
+ slideHelper.hide();
822
+ dragHelper.hide();
823
+ }
824
+ else {
825
+ //make sure helpers are visible
826
+ alphaSlideHelper.show();
827
+ slideHelper.show();
828
+ dragHelper.show();
829
+
830
+ // Where to show the little circle in that displays your current selected color
831
+ var dragX = s * dragWidth;
832
+ var dragY = dragHeight - (v * dragHeight);
833
+ dragX = Math.max(
834
+ -dragHelperHeight,
835
+ Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
836
+ );
837
+ dragY = Math.max(
838
+ -dragHelperHeight,
839
+ Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
840
+ );
841
+ dragHelper.css({
842
+ "top": dragY + "px",
843
+ "left": dragX + "px"
844
+ });
845
+
846
+ var alphaX = currentAlpha * alphaWidth;
847
+ alphaSlideHelper.css({
848
+ "left": (alphaX - (alphaSlideHelperWidth / 2)) + "px"
849
+ });
850
+
851
+ // Where to show the bar that displays your current selected hue
852
+ var slideY = (currentHue) * slideHeight;
853
+ slideHelper.css({
854
+ "top": (slideY - slideHelperHeight) + "px"
855
+ });
856
+ }
857
+ }
858
+
859
+ function updateOriginalInput(fireCallback) {
860
+ var color = get(),
861
+ displayColor = '',
862
+ hasChanged = !tinycolor.equals(color, colorOnShow);
863
+
864
+ if (color) {
865
+ displayColor = color.toString(currentPreferredFormat);
866
+ // Update the selection palette with the current color
867
+ addColorToSelectionPalette(color);
868
+ }
869
+
870
+ if (isInput) {
871
+ boundElement.val(displayColor);
872
+ }
873
+
874
+ if (fireCallback && hasChanged) {
875
+ callbacks.change(color);
876
+ boundElement.trigger('change', [ color ]);
877
+ }
878
+ }
879
+
880
+ function reflow() {
881
+ dragWidth = dragger.width();
882
+ dragHeight = dragger.height();
883
+ dragHelperHeight = dragHelper.height();
884
+ slideWidth = slider.width();
885
+ slideHeight = slider.height();
886
+ slideHelperHeight = slideHelper.height();
887
+ alphaWidth = alphaSlider.width();
888
+ alphaSlideHelperWidth = alphaSlideHelper.width();
889
+
890
+ if (!flat) {
891
+ container.css("position", "absolute");
892
+ if (opts.offset) {
893
+ container.offset(opts.offset);
894
+ } else {
895
+ container.offset(getOffset(container, offsetElement));
896
+ }
897
+ }
898
+
899
+ updateHelperLocations();
900
+
901
+ if (opts.showPalette) {
902
+ drawPalette();
903
+ }
904
+
905
+ boundElement.trigger('reflow.spectrum');
906
+ }
907
+
908
+ function destroy() {
909
+ boundElement.show();
910
+ offsetElement.unbind("click.spectrum touchstart.spectrum");
911
+ container.remove();
912
+ replacer.remove();
913
+ spectrums[spect.id] = null;
914
+ }
915
+
916
+ function option(optionName, optionValue) {
917
+ if (optionName === undefined) {
918
+ return $.extend({}, opts);
919
+ }
920
+ if (optionValue === undefined) {
921
+ return opts[optionName];
922
+ }
923
+
924
+ opts[optionName] = optionValue;
925
+ applyOptions();
926
+ }
927
+
928
+ function enable() {
929
+ disabled = false;
930
+ boundElement.attr("disabled", false);
931
+ offsetElement.removeClass("sp-disabled");
932
+ }
933
+
934
+ function disable() {
935
+ hide();
936
+ disabled = true;
937
+ boundElement.attr("disabled", true);
938
+ offsetElement.addClass("sp-disabled");
939
+ }
940
+
941
+ function setOffset(coord) {
942
+ opts.offset = coord;
943
+ reflow();
944
+ }
945
+
946
+ initialize();
947
+
948
+ var spect = {
949
+ show: show,
950
+ hide: hide,
951
+ toggle: toggle,
952
+ reflow: reflow,
953
+ option: option,
954
+ enable: enable,
955
+ disable: disable,
956
+ offset: setOffset,
957
+ set: function (c) {
958
+ set(c);
959
+ updateOriginalInput();
960
+ },
961
+ get: get,
962
+ destroy: destroy,
963
+ container: container
964
+ };
965
+
966
+ spect.id = spectrums.push(spect) - 1;
967
+
968
+ return spect;
969
+ }
970
+
971
+ /**
972
+ * checkOffset - get the offset below/above and left/right element depending on screen position
973
+ * Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
974
+ */
975
+ function getOffset(picker, input) {
976
+ var extraY = 0;
977
+ var dpWidth = picker.outerWidth();
978
+ var dpHeight = picker.outerHeight();
979
+ var inputHeight = input.outerHeight();
980
+ var doc = picker[0].ownerDocument;
981
+ var docElem = doc.documentElement;
982
+ var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
983
+ var viewHeight = docElem.clientHeight + $(doc).scrollTop();
984
+ var offset = input.offset();
985
+ offset.top += inputHeight;
986
+
987
+ offset.left -=
988
+ Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
989
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
990
+
991
+ offset.top -=
992
+ Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
993
+ Math.abs(dpHeight + inputHeight - extraY) : extraY));
994
+
995
+ return offset;
996
+ }
997
+
998
+ /**
999
+ * noop - do nothing
1000
+ */
1001
+ function noop() {
1002
+
1003
+ }
1004
+
1005
+ /**
1006
+ * stopPropagation - makes the code only doing this a little easier to read in line
1007
+ */
1008
+ function stopPropagation(e) {
1009
+ e.stopPropagation();
1010
+ }
1011
+
1012
+ /**
1013
+ * Create a function bound to a given object
1014
+ * Thanks to underscore.js
1015
+ */
1016
+ function bind(func, obj) {
1017
+ var slice = Array.prototype.slice;
1018
+ var args = slice.call(arguments, 2);
1019
+ return function () {
1020
+ return func.apply(obj, args.concat(slice.call(arguments)));
1021
+ };
1022
+ }
1023
+
1024
+ /**
1025
+ * Lightweight drag helper. Handles containment within the element, so that
1026
+ * when dragging, the x is within [0,element.width] and y is within [0,element.height]
1027
+ */
1028
+ function draggable(element, onmove, onstart, onstop) {
1029
+ onmove = onmove || function () { };
1030
+ onstart = onstart || function () { };
1031
+ onstop = onstop || function () { };
1032
+ var doc = document;
1033
+ var dragging = false;
1034
+ var offset = {};
1035
+ var maxHeight = 0;
1036
+ var maxWidth = 0;
1037
+ var hasTouch = ('ontouchstart' in window);
1038
+
1039
+ var duringDragEvents = {};
1040
+ duringDragEvents["selectstart"] = prevent;
1041
+ duringDragEvents["dragstart"] = prevent;
1042
+ duringDragEvents["touchmove mousemove"] = move;
1043
+ duringDragEvents["touchend mouseup"] = stop;
1044
+
1045
+ function prevent(e) {
1046
+ if (e.stopPropagation) {
1047
+ e.stopPropagation();
1048
+ }
1049
+ if (e.preventDefault) {
1050
+ e.preventDefault();
1051
+ }
1052
+ e.returnValue = false;
1053
+ }
1054
+
1055
+ function move(e) {
1056
+ if (dragging) {
1057
+ // Mouseup happened outside of window
1058
+ if (IE && doc.documentMode < 9 && !e.button) {
1059
+ return stop();
1060
+ }
1061
+
1062
+ var t0 = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0];
1063
+ var pageX = t0 && t0.pageX || e.pageX;
1064
+ var pageY = t0 && t0.pageY || e.pageY;
1065
+
1066
+ var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
1067
+ var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
1068
+
1069
+ if (hasTouch) {
1070
+ // Stop scrolling in iOS
1071
+ prevent(e);
1072
+ }
1073
+
1074
+ onmove.apply(element, [dragX, dragY, e]);
1075
+ }
1076
+ }
1077
+
1078
+ function start(e) {
1079
+ var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
1080
+
1081
+ if (!rightclick && !dragging) {
1082
+ if (onstart.apply(element, arguments) !== false) {
1083
+ dragging = true;
1084
+ maxHeight = $(element).height();
1085
+ maxWidth = $(element).width();
1086
+ offset = $(element).offset();
1087
+
1088
+ $(doc).bind(duringDragEvents);
1089
+ $(doc.body).addClass("sp-dragging");
1090
+
1091
+ move(e);
1092
+
1093
+ prevent(e);
1094
+ }
1095
+ }
1096
+ }
1097
+
1098
+ function stop() {
1099
+ if (dragging) {
1100
+ $(doc).unbind(duringDragEvents);
1101
+ $(doc.body).removeClass("sp-dragging");
1102
+
1103
+ // Wait a tick before notifying observers to allow the click event
1104
+ // to fire in Chrome.
1105
+ setTimeout(function() {
1106
+ onstop.apply(element, arguments);
1107
+ }, 0);
1108
+ }
1109
+ dragging = false;
1110
+ }
1111
+
1112
+ $(element).bind("touchstart mousedown", start);
1113
+ }
1114
+
1115
+ function throttle(func, wait, debounce) {
1116
+ var timeout;
1117
+ return function () {
1118
+ var context = this, args = arguments;
1119
+ var throttler = function () {
1120
+ timeout = null;
1121
+ func.apply(context, args);
1122
+ };
1123
+ if (debounce) clearTimeout(timeout);
1124
+ if (debounce || !timeout) timeout = setTimeout(throttler, wait);
1125
+ };
1126
+ }
1127
+
1128
+ function inputTypeColorSupport() {
1129
+ return $.fn.spectrum.inputTypeColorSupport();
1130
+ }
1131
+
1132
+ /**
1133
+ * Define a jQuery plugin
1134
+ */
1135
+ var dataID = "spectrum.id";
1136
+ $.fn.spectrum = function (opts, extra) {
1137
+
1138
+ if (typeof opts == "string") {
1139
+
1140
+ var returnValue = this;
1141
+ var args = Array.prototype.slice.call( arguments, 1 );
1142
+
1143
+ this.each(function () {
1144
+ var spect = spectrums[$(this).data(dataID)];
1145
+ if (spect) {
1146
+ var method = spect[opts];
1147
+ if (!method) {
1148
+ throw new Error( "Spectrum: no such method: '" + opts + "'" );
1149
+ }
1150
+
1151
+ if (opts == "get") {
1152
+ returnValue = spect.get();
1153
+ }
1154
+ else if (opts == "container") {
1155
+ returnValue = spect.container;
1156
+ }
1157
+ else if (opts == "option") {
1158
+ returnValue = spect.option.apply(spect, args);
1159
+ }
1160
+ else if (opts == "destroy") {
1161
+ spect.destroy();
1162
+ $(this).removeData(dataID);
1163
+ }
1164
+ else {
1165
+ method.apply(spect, args);
1166
+ }
1167
+ }
1168
+ });
1169
+
1170
+ return returnValue;
1171
+ }
1172
+
1173
+ // Initializing a new instance of spectrum
1174
+ return this.spectrum("destroy").each(function () {
1175
+ var options = $.extend({}, opts, $(this).data());
1176
+ var spect = spectrum(this, options);
1177
+ $(this).data(dataID, spect.id);
1178
+ });
1179
+ };
1180
+
1181
+ $.fn.spectrum.load = true;
1182
+ $.fn.spectrum.loadOpts = {};
1183
+ $.fn.spectrum.draggable = draggable;
1184
+ $.fn.spectrum.defaults = defaultOpts;
1185
+ $.fn.spectrum.inputTypeColorSupport = function inputTypeColorSupport() {
1186
+ if (typeof inputTypeColorSupport._cachedResult === "undefined") {
1187
+ var colorInput = $("<input type='color'/>")[0]; // if color element is supported, value will default to not null
1188
+ inputTypeColorSupport._cachedResult = colorInput.type === "color" && colorInput.value !== "";
1189
+ }
1190
+ return inputTypeColorSupport._cachedResult;
1191
+ };
1192
+
1193
+ $.spectrum = { };
1194
+ $.spectrum.localization = { };
1195
+ $.spectrum.palettes = { };
1196
+
1197
+ $.fn.spectrum.processNativeColorInputs = function () {
1198
+ var colorInputs = $("input[type=color]");
1199
+ if (colorInputs.length && !inputTypeColorSupport()) {
1200
+ colorInputs.spectrum({
1201
+ preferredFormat: "hex6"
1202
+ });
1203
+ }
1204
+ };
1205
+
1206
+ // TinyColor v1.1.2
1207
+ // https://github.com/bgrins/TinyColor
1208
+ // Brian Grinstead, MIT License
1209
+
1210
+ (function() {
1211
+
1212
+ var trimLeft = /^[\s,#]+/,
1213
+ trimRight = /\s+$/,
1214
+ tinyCounter = 0,
1215
+ math = Math,
1216
+ mathRound = math.round,
1217
+ mathMin = math.min,
1218
+ mathMax = math.max,
1219
+ mathRandom = math.random;
1220
+
1221
+ var tinycolor = function(color, opts) {
1222
+
1223
+ color = (color) ? color : '';
1224
+ opts = opts || { };
1225
+
1226
+ // If input is already a tinycolor, return itself
1227
+ if (color instanceof tinycolor) {
1228
+ return color;
1229
+ }
1230
+ // If we are called as a function, call using new instead
1231
+ if (!(this instanceof tinycolor)) {
1232
+ return new tinycolor(color, opts);
1233
+ }
1234
+
1235
+ var rgb = inputToRGB(color);
1236
+ this._originalInput = color,
1237
+ this._r = rgb.r,
1238
+ this._g = rgb.g,
1239
+ this._b = rgb.b,
1240
+ this._a = rgb.a,
1241
+ this._roundA = mathRound(100*this._a) / 100,
1242
+ this._format = opts.format || rgb.format;
1243
+ this._gradientType = opts.gradientType;
1244
+
1245
+ // Don't let the range of [0,255] come back in [0,1].
1246
+ // Potentially lose a little bit of precision here, but will fix issues where
1247
+ // .5 gets interpreted as half of the total, instead of half of 1
1248
+ // If it was supposed to be 128, this was already taken care of by `inputToRgb`
1249
+ if (this._r < 1) { this._r = mathRound(this._r); }
1250
+ if (this._g < 1) { this._g = mathRound(this._g); }
1251
+ if (this._b < 1) { this._b = mathRound(this._b); }
1252
+
1253
+ this._ok = rgb.ok;
1254
+ this._tc_id = tinyCounter++;
1255
+ };
1256
+
1257
+ tinycolor.prototype = {
1258
+ isDark: function() {
1259
+ return this.getBrightness() < 128;
1260
+ },
1261
+ isLight: function() {
1262
+ return !this.isDark();
1263
+ },
1264
+ isValid: function() {
1265
+ return this._ok;
1266
+ },
1267
+ getOriginalInput: function() {
1268
+ return this._originalInput;
1269
+ },
1270
+ getFormat: function() {
1271
+ return this._format;
1272
+ },
1273
+ getAlpha: function() {
1274
+ return this._a;
1275
+ },
1276
+ getBrightness: function() {
1277
+ var rgb = this.toRgb();
1278
+ return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
1279
+ },
1280
+ setAlpha: function(value) {
1281
+ this._a = boundAlpha(value);
1282
+ this._roundA = mathRound(100*this._a) / 100;
1283
+ return this;
1284
+ },
1285
+ toHsv: function() {
1286
+ var hsv = rgbToHsv(this._r, this._g, this._b);
1287
+ return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
1288
+ },
1289
+ toHsvString: function() {
1290
+ var hsv = rgbToHsv(this._r, this._g, this._b);
1291
+ var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
1292
+ return (this._a == 1) ?
1293
+ "hsv(" + h + ", " + s + "%, " + v + "%)" :
1294
+ "hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
1295
+ },
1296
+ toHsl: function() {
1297
+ var hsl = rgbToHsl(this._r, this._g, this._b);
1298
+ return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
1299
+ },
1300
+ toHslString: function() {
1301
+ var hsl = rgbToHsl(this._r, this._g, this._b);
1302
+ var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
1303
+ return (this._a == 1) ?
1304
+ "hsl(" + h + ", " + s + "%, " + l + "%)" :
1305
+ "hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
1306
+ },
1307
+ toHex: function(allow3Char) {
1308
+ return rgbToHex(this._r, this._g, this._b, allow3Char);
1309
+ },
1310
+ toHexString: function(allow3Char) {
1311
+ return '#' + this.toHex(allow3Char);
1312
+ },
1313
+ toHex8: function() {
1314
+ return rgbaToHex(this._r, this._g, this._b, this._a);
1315
+ },
1316
+ toHex8String: function() {
1317
+ return '#' + this.toHex8();
1318
+ },
1319
+ toRgb: function() {
1320
+ return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
1321
+ },
1322
+ toRgbString: function() {
1323
+ return (this._a == 1) ?
1324
+ "rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
1325
+ "rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
1326
+ },
1327
+ toPercentageRgb: function() {
1328
+ return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
1329
+ },
1330
+ toPercentageRgbString: function() {
1331
+ return (this._a == 1) ?
1332
+ "rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
1333
+ "rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
1334
+ },
1335
+ toName: function() {
1336
+ if (this._a === 0) {
1337
+ return "transparent";
1338
+ }
1339
+
1340
+ if (this._a < 1) {
1341
+ return false;
1342
+ }
1343
+
1344
+ return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
1345
+ },
1346
+ toFilter: function(secondColor) {
1347
+ var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
1348
+ var secondHex8String = hex8String;
1349
+ var gradientType = this._gradientType ? "GradientType = 1, " : "";
1350
+
1351
+ if (secondColor) {
1352
+ var s = tinycolor(secondColor);
1353
+ secondHex8String = s.toHex8String();
1354
+ }
1355
+
1356
+ return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
1357
+ },
1358
+ toString: function(format) {
1359
+ var formatSet = !!format;
1360
+ format = format || this._format;
1361
+
1362
+ var formattedString = false;
1363
+ var hasAlpha = this._a < 1 && this._a >= 0;
1364
+ var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
1365
+
1366
+ if (needsAlphaFormat) {
1367
+ // Special case for "transparent", all other non-alpha formats
1368
+ // will return rgba when there is transparency.
1369
+ if (format === "name" && this._a === 0) {
1370
+ return this.toName();
1371
+ }
1372
+ return this.toRgbString();
1373
+ }
1374
+ if (format === "rgb") {
1375
+ formattedString = this.toRgbString();
1376
+ }
1377
+ if (format === "prgb") {
1378
+ formattedString = this.toPercentageRgbString();
1379
+ }
1380
+ if (format === "hex" || format === "hex6") {
1381
+ formattedString = this.toHexString();
1382
+ }
1383
+ if (format === "hex3") {
1384
+ formattedString = this.toHexString(true);
1385
+ }
1386
+ if (format === "hex8") {
1387
+ formattedString = this.toHex8String();
1388
+ }
1389
+ if (format === "name") {
1390
+ formattedString = this.toName();
1391
+ }
1392
+ if (format === "hsl") {
1393
+ formattedString = this.toHslString();
1394
+ }
1395
+ if (format === "hsv") {
1396
+ formattedString = this.toHsvString();
1397
+ }
1398
+
1399
+ return formattedString || this.toHexString();
1400
+ },
1401
+
1402
+ _applyModification: function(fn, args) {
1403
+ var color = fn.apply(null, [this].concat([].slice.call(args)));
1404
+ this._r = color._r;
1405
+ this._g = color._g;
1406
+ this._b = color._b;
1407
+ this.setAlpha(color._a);
1408
+ return this;
1409
+ },
1410
+ lighten: function() {
1411
+ return this._applyModification(lighten, arguments);
1412
+ },
1413
+ brighten: function() {
1414
+ return this._applyModification(brighten, arguments);
1415
+ },
1416
+ darken: function() {
1417
+ return this._applyModification(darken, arguments);
1418
+ },
1419
+ desaturate: function() {
1420
+ return this._applyModification(desaturate, arguments);
1421
+ },
1422
+ saturate: function() {
1423
+ return this._applyModification(saturate, arguments);
1424
+ },
1425
+ greyscale: function() {
1426
+ return this._applyModification(greyscale, arguments);
1427
+ },
1428
+ spin: function() {
1429
+ return this._applyModification(spin, arguments);
1430
+ },
1431
+
1432
+ _applyCombination: function(fn, args) {
1433
+ return fn.apply(null, [this].concat([].slice.call(args)));
1434
+ },
1435
+ analogous: function() {
1436
+ return this._applyCombination(analogous, arguments);
1437
+ },
1438
+ complement: function() {
1439
+ return this._applyCombination(complement, arguments);
1440
+ },
1441
+ monochromatic: function() {
1442
+ return this._applyCombination(monochromatic, arguments);
1443
+ },
1444
+ splitcomplement: function() {
1445
+ return this._applyCombination(splitcomplement, arguments);
1446
+ },
1447
+ triad: function() {
1448
+ return this._applyCombination(triad, arguments);
1449
+ },
1450
+ tetrad: function() {
1451
+ return this._applyCombination(tetrad, arguments);
1452
+ }
1453
+ };
1454
+
1455
+ // If input is an object, force 1 into "1.0" to handle ratios properly
1456
+ // String input requires "1.0" as input, so 1 will be treated as 1
1457
+ tinycolor.fromRatio = function(color, opts) {
1458
+ if (typeof color == "object") {
1459
+ var newColor = {};
1460
+ for (var i in color) {
1461
+ if (color.hasOwnProperty(i)) {
1462
+ if (i === "a") {
1463
+ newColor[i] = color[i];
1464
+ }
1465
+ else {
1466
+ newColor[i] = convertToPercentage(color[i]);
1467
+ }
1468
+ }
1469
+ }
1470
+ color = newColor;
1471
+ }
1472
+
1473
+ return tinycolor(color, opts);
1474
+ };
1475
+
1476
+ // Given a string or object, convert that input to RGB
1477
+ // Possible string inputs:
1478
+ //
1479
+ // "red"
1480
+ // "#f00" or "f00"
1481
+ // "#ff0000" or "ff0000"
1482
+ // "#ff000000" or "ff000000"
1483
+ // "rgb 255 0 0" or "rgb (255, 0, 0)"
1484
+ // "rgb 1.0 0 0" or "rgb (1, 0, 0)"
1485
+ // "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
1486
+ // "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
1487
+ // "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
1488
+ // "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
1489
+ // "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
1490
+ //
1491
+ function inputToRGB(color) {
1492
+
1493
+ var rgb = { r: 0, g: 0, b: 0 };
1494
+ var a = 1;
1495
+ var ok = false;
1496
+ var format = false;
1497
+
1498
+ if (typeof color == "string") {
1499
+ color = stringInputToObject(color);
1500
+ }
1501
+
1502
+ if (typeof color == "object") {
1503
+ if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
1504
+ rgb = rgbToRgb(color.r, color.g, color.b);
1505
+ ok = true;
1506
+ format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
1507
+ }
1508
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
1509
+ color.s = convertToPercentage(color.s);
1510
+ color.v = convertToPercentage(color.v);
1511
+ rgb = hsvToRgb(color.h, color.s, color.v);
1512
+ ok = true;
1513
+ format = "hsv";
1514
+ }
1515
+ else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
1516
+ color.s = convertToPercentage(color.s);
1517
+ color.l = convertToPercentage(color.l);
1518
+ rgb = hslToRgb(color.h, color.s, color.l);
1519
+ ok = true;
1520
+ format = "hsl";
1521
+ }
1522
+
1523
+ if (color.hasOwnProperty("a")) {
1524
+ a = color.a;
1525
+ }
1526
+ }
1527
+
1528
+ a = boundAlpha(a);
1529
+
1530
+ return {
1531
+ ok: ok,
1532
+ format: color.format || format,
1533
+ r: mathMin(255, mathMax(rgb.r, 0)),
1534
+ g: mathMin(255, mathMax(rgb.g, 0)),
1535
+ b: mathMin(255, mathMax(rgb.b, 0)),
1536
+ a: a
1537
+ };
1538
+ }
1539
+
1540
+
1541
+ // Conversion Functions
1542
+ // --------------------
1543
+
1544
+ // `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
1545
+ // <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
1546
+
1547
+ // `rgbToRgb`
1548
+ // Handle bounds / percentage checking to conform to CSS color spec
1549
+ // <http://www.w3.org/TR/css3-color/>
1550
+ // *Assumes:* r, g, b in [0, 255] or [0, 1]
1551
+ // *Returns:* { r, g, b } in [0, 255]
1552
+ function rgbToRgb(r, g, b){
1553
+ return {
1554
+ r: bound01(r, 255) * 255,
1555
+ g: bound01(g, 255) * 255,
1556
+ b: bound01(b, 255) * 255
1557
+ };
1558
+ }
1559
+
1560
+ // `rgbToHsl`
1561
+ // Converts an RGB color value to HSL.
1562
+ // *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
1563
+ // *Returns:* { h, s, l } in [0,1]
1564
+ function rgbToHsl(r, g, b) {
1565
+
1566
+ r = bound01(r, 255);
1567
+ g = bound01(g, 255);
1568
+ b = bound01(b, 255);
1569
+
1570
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1571
+ var h, s, l = (max + min) / 2;
1572
+
1573
+ if(max == min) {
1574
+ h = s = 0; // achromatic
1575
+ }
1576
+ else {
1577
+ var d = max - min;
1578
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
1579
+ switch(max) {
1580
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1581
+ case g: h = (b - r) / d + 2; break;
1582
+ case b: h = (r - g) / d + 4; break;
1583
+ }
1584
+
1585
+ h /= 6;
1586
+ }
1587
+
1588
+ return { h: h, s: s, l: l };
1589
+ }
1590
+
1591
+ // `hslToRgb`
1592
+ // Converts an HSL color value to RGB.
1593
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
1594
+ // *Returns:* { r, g, b } in the set [0, 255]
1595
+ function hslToRgb(h, s, l) {
1596
+ var r, g, b;
1597
+
1598
+ h = bound01(h, 360);
1599
+ s = bound01(s, 100);
1600
+ l = bound01(l, 100);
1601
+
1602
+ function hue2rgb(p, q, t) {
1603
+ if(t < 0) t += 1;
1604
+ if(t > 1) t -= 1;
1605
+ if(t < 1/6) return p + (q - p) * 6 * t;
1606
+ if(t < 1/2) return q;
1607
+ if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
1608
+ return p;
1609
+ }
1610
+
1611
+ if(s === 0) {
1612
+ r = g = b = l; // achromatic
1613
+ }
1614
+ else {
1615
+ var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
1616
+ var p = 2 * l - q;
1617
+ r = hue2rgb(p, q, h + 1/3);
1618
+ g = hue2rgb(p, q, h);
1619
+ b = hue2rgb(p, q, h - 1/3);
1620
+ }
1621
+
1622
+ return { r: r * 255, g: g * 255, b: b * 255 };
1623
+ }
1624
+
1625
+ // `rgbToHsv`
1626
+ // Converts an RGB color value to HSV
1627
+ // *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
1628
+ // *Returns:* { h, s, v } in [0,1]
1629
+ function rgbToHsv(r, g, b) {
1630
+
1631
+ r = bound01(r, 255);
1632
+ g = bound01(g, 255);
1633
+ b = bound01(b, 255);
1634
+
1635
+ var max = mathMax(r, g, b), min = mathMin(r, g, b);
1636
+ var h, s, v = max;
1637
+
1638
+ var d = max - min;
1639
+ s = max === 0 ? 0 : d / max;
1640
+
1641
+ if(max == min) {
1642
+ h = 0; // achromatic
1643
+ }
1644
+ else {
1645
+ switch(max) {
1646
+ case r: h = (g - b) / d + (g < b ? 6 : 0); break;
1647
+ case g: h = (b - r) / d + 2; break;
1648
+ case b: h = (r - g) / d + 4; break;
1649
+ }
1650
+ h /= 6;
1651
+ }
1652
+ return { h: h, s: s, v: v };
1653
+ }
1654
+
1655
+ // `hsvToRgb`
1656
+ // Converts an HSV color value to RGB.
1657
+ // *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
1658
+ // *Returns:* { r, g, b } in the set [0, 255]
1659
+ function hsvToRgb(h, s, v) {
1660
+
1661
+ h = bound01(h, 360) * 6;
1662
+ s = bound01(s, 100);
1663
+ v = bound01(v, 100);
1664
+
1665
+ var i = math.floor(h),
1666
+ f = h - i,
1667
+ p = v * (1 - s),
1668
+ q = v * (1 - f * s),
1669
+ t = v * (1 - (1 - f) * s),
1670
+ mod = i % 6,
1671
+ r = [v, q, p, p, t, v][mod],
1672
+ g = [t, v, v, q, p, p][mod],
1673
+ b = [p, p, t, v, v, q][mod];
1674
+
1675
+ return { r: r * 255, g: g * 255, b: b * 255 };
1676
+ }
1677
+
1678
+ // `rgbToHex`
1679
+ // Converts an RGB color to hex
1680
+ // Assumes r, g, and b are contained in the set [0, 255]
1681
+ // Returns a 3 or 6 character hex
1682
+ function rgbToHex(r, g, b, allow3Char) {
1683
+
1684
+ var hex = [
1685
+ pad2(mathRound(r).toString(16)),
1686
+ pad2(mathRound(g).toString(16)),
1687
+ pad2(mathRound(b).toString(16))
1688
+ ];
1689
+
1690
+ // Return a 3 character hex if possible
1691
+ if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
1692
+ return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
1693
+ }
1694
+
1695
+ return hex.join("");
1696
+ }
1697
+ // `rgbaToHex`
1698
+ // Converts an RGBA color plus alpha transparency to hex
1699
+ // Assumes r, g, b and a are contained in the set [0, 255]
1700
+ // Returns an 8 character hex
1701
+ function rgbaToHex(r, g, b, a) {
1702
+
1703
+ var hex = [
1704
+ pad2(convertDecimalToHex(a)),
1705
+ pad2(mathRound(r).toString(16)),
1706
+ pad2(mathRound(g).toString(16)),
1707
+ pad2(mathRound(b).toString(16))
1708
+ ];
1709
+
1710
+ return hex.join("");
1711
+ }
1712
+
1713
+ // `equals`
1714
+ // Can be called with any tinycolor input
1715
+ tinycolor.equals = function (color1, color2) {
1716
+ if (!color1 || !color2) { return false; }
1717
+ return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
1718
+ };
1719
+ tinycolor.random = function() {
1720
+ return tinycolor.fromRatio({
1721
+ r: mathRandom(),
1722
+ g: mathRandom(),
1723
+ b: mathRandom()
1724
+ });
1725
+ };
1726
+
1727
+
1728
+ // Modification Functions
1729
+ // ----------------------
1730
+ // Thanks to less.js for some of the basics here
1731
+ // <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
1732
+
1733
+ function desaturate(color, amount) {
1734
+ amount = (amount === 0) ? 0 : (amount || 10);
1735
+ var hsl = tinycolor(color).toHsl();
1736
+ hsl.s -= amount / 100;
1737
+ hsl.s = clamp01(hsl.s);
1738
+ return tinycolor(hsl);
1739
+ }
1740
+
1741
+ function saturate(color, amount) {
1742
+ amount = (amount === 0) ? 0 : (amount || 10);
1743
+ var hsl = tinycolor(color).toHsl();
1744
+ hsl.s += amount / 100;
1745
+ hsl.s = clamp01(hsl.s);
1746
+ return tinycolor(hsl);
1747
+ }
1748
+
1749
+ function greyscale(color) {
1750
+ return tinycolor(color).desaturate(100);
1751
+ }
1752
+
1753
+ function lighten (color, amount) {
1754
+ amount = (amount === 0) ? 0 : (amount || 10);
1755
+ var hsl = tinycolor(color).toHsl();
1756
+ hsl.l += amount / 100;
1757
+ hsl.l = clamp01(hsl.l);
1758
+ return tinycolor(hsl);
1759
+ }
1760
+
1761
+ function brighten(color, amount) {
1762
+ amount = (amount === 0) ? 0 : (amount || 10);
1763
+ var rgb = tinycolor(color).toRgb();
1764
+ rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
1765
+ rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
1766
+ rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
1767
+ return tinycolor(rgb);
1768
+ }
1769
+
1770
+ function darken (color, amount) {
1771
+ amount = (amount === 0) ? 0 : (amount || 10);
1772
+ var hsl = tinycolor(color).toHsl();
1773
+ hsl.l -= amount / 100;
1774
+ hsl.l = clamp01(hsl.l);
1775
+ return tinycolor(hsl);
1776
+ }
1777
+
1778
+ // Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
1779
+ // Values outside of this range will be wrapped into this range.
1780
+ function spin(color, amount) {
1781
+ var hsl = tinycolor(color).toHsl();
1782
+ var hue = (mathRound(hsl.h) + amount) % 360;
1783
+ hsl.h = hue < 0 ? 360 + hue : hue;
1784
+ return tinycolor(hsl);
1785
+ }
1786
+
1787
+ // Combination Functions
1788
+ // ---------------------
1789
+ // Thanks to jQuery xColor for some of the ideas behind these
1790
+ // <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
1791
+
1792
+ function complement(color) {
1793
+ var hsl = tinycolor(color).toHsl();
1794
+ hsl.h = (hsl.h + 180) % 360;
1795
+ return tinycolor(hsl);
1796
+ }
1797
+
1798
+ function triad(color) {
1799
+ var hsl = tinycolor(color).toHsl();
1800
+ var h = hsl.h;
1801
+ return [
1802
+ tinycolor(color),
1803
+ tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
1804
+ tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
1805
+ ];
1806
+ }
1807
+
1808
+ function tetrad(color) {
1809
+ var hsl = tinycolor(color).toHsl();
1810
+ var h = hsl.h;
1811
+ return [
1812
+ tinycolor(color),
1813
+ tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
1814
+ tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
1815
+ tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
1816
+ ];
1817
+ }
1818
+
1819
+ function splitcomplement(color) {
1820
+ var hsl = tinycolor(color).toHsl();
1821
+ var h = hsl.h;
1822
+ return [
1823
+ tinycolor(color),
1824
+ tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
1825
+ tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
1826
+ ];
1827
+ }
1828
+
1829
+ function analogous(color, results, slices) {
1830
+ results = results || 6;
1831
+ slices = slices || 30;
1832
+
1833
+ var hsl = tinycolor(color).toHsl();
1834
+ var part = 360 / slices;
1835
+ var ret = [tinycolor(color)];
1836
+
1837
+ for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
1838
+ hsl.h = (hsl.h + part) % 360;
1839
+ ret.push(tinycolor(hsl));
1840
+ }
1841
+ return ret;
1842
+ }
1843
+
1844
+ function monochromatic(color, results) {
1845
+ results = results || 6;
1846
+ var hsv = tinycolor(color).toHsv();
1847
+ var h = hsv.h, s = hsv.s, v = hsv.v;
1848
+ var ret = [];
1849
+ var modification = 1 / results;
1850
+
1851
+ while (results--) {
1852
+ ret.push(tinycolor({ h: h, s: s, v: v}));
1853
+ v = (v + modification) % 1;
1854
+ }
1855
+
1856
+ return ret;
1857
+ }
1858
+
1859
+ // Utility Functions
1860
+ // ---------------------
1861
+
1862
+ tinycolor.mix = function(color1, color2, amount) {
1863
+ amount = (amount === 0) ? 0 : (amount || 50);
1864
+
1865
+ var rgb1 = tinycolor(color1).toRgb();
1866
+ var rgb2 = tinycolor(color2).toRgb();
1867
+
1868
+ var p = amount / 100;
1869
+ var w = p * 2 - 1;
1870
+ var a = rgb2.a - rgb1.a;
1871
+
1872
+ var w1;
1873
+
1874
+ if (w * a == -1) {
1875
+ w1 = w;
1876
+ } else {
1877
+ w1 = (w + a) / (1 + w * a);
1878
+ }
1879
+
1880
+ w1 = (w1 + 1) / 2;
1881
+
1882
+ var w2 = 1 - w1;
1883
+
1884
+ var rgba = {
1885
+ r: rgb2.r * w1 + rgb1.r * w2,
1886
+ g: rgb2.g * w1 + rgb1.g * w2,
1887
+ b: rgb2.b * w1 + rgb1.b * w2,
1888
+ a: rgb2.a * p + rgb1.a * (1 - p)
1889
+ };
1890
+
1891
+ return tinycolor(rgba);
1892
+ };
1893
+
1894
+
1895
+ // Readability Functions
1896
+ // ---------------------
1897
+ // <http://www.w3.org/TR/AERT#color-contrast>
1898
+
1899
+ // `readability`
1900
+ // Analyze the 2 colors and returns an object with the following properties:
1901
+ // `brightness`: difference in brightness between the two colors
1902
+ // `color`: difference in color/hue between the two colors
1903
+ tinycolor.readability = function(color1, color2) {
1904
+ var c1 = tinycolor(color1);
1905
+ var c2 = tinycolor(color2);
1906
+ var rgb1 = c1.toRgb();
1907
+ var rgb2 = c2.toRgb();
1908
+ var brightnessA = c1.getBrightness();
1909
+ var brightnessB = c2.getBrightness();
1910
+ var colorDiff = (
1911
+ Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r) +
1912
+ Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g) +
1913
+ Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b)
1914
+ );
1915
+
1916
+ return {
1917
+ brightness: Math.abs(brightnessA - brightnessB),
1918
+ color: colorDiff
1919
+ };
1920
+ };
1921
+
1922
+ // `readable`
1923
+ // http://www.w3.org/TR/AERT#color-contrast
1924
+ // Ensure that foreground and background color combinations provide sufficient contrast.
1925
+ // *Example*
1926
+ // tinycolor.isReadable("#000", "#111") => false
1927
+ tinycolor.isReadable = function(color1, color2) {
1928
+ var readability = tinycolor.readability(color1, color2);
1929
+ return readability.brightness > 125 && readability.color > 500;
1930
+ };
1931
+
1932
+ // `mostReadable`
1933
+ // Given a base color and a list of possible foreground or background
1934
+ // colors for that base, returns the most readable color.
1935
+ // *Example*
1936
+ // tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
1937
+ tinycolor.mostReadable = function(baseColor, colorList) {
1938
+ var bestColor = null;
1939
+ var bestScore = 0;
1940
+ var bestIsReadable = false;
1941
+ for (var i=0; i < colorList.length; i++) {
1942
+
1943
+ // We normalize both around the "acceptable" breaking point,
1944
+ // but rank brightness constrast higher than hue.
1945
+
1946
+ var readability = tinycolor.readability(baseColor, colorList[i]);
1947
+ var readable = readability.brightness > 125 && readability.color > 500;
1948
+ var score = 3 * (readability.brightness / 125) + (readability.color / 500);
1949
+
1950
+ if ((readable && ! bestIsReadable) ||
1951
+ (readable && bestIsReadable && score > bestScore) ||
1952
+ ((! readable) && (! bestIsReadable) && score > bestScore)) {
1953
+ bestIsReadable = readable;
1954
+ bestScore = score;
1955
+ bestColor = tinycolor(colorList[i]);
1956
+ }
1957
+ }
1958
+ return bestColor;
1959
+ };
1960
+
1961
+
1962
+ // Big List of Colors
1963
+ // ------------------
1964
+ // <http://www.w3.org/TR/css3-color/#svg-color>
1965
+ var names = tinycolor.names = {
1966
+ aliceblue: "f0f8ff",
1967
+ antiquewhite: "faebd7",
1968
+ aqua: "0ff",
1969
+ aquamarine: "7fffd4",
1970
+ azure: "f0ffff",
1971
+ beige: "f5f5dc",
1972
+ bisque: "ffe4c4",
1973
+ black: "000",
1974
+ blanchedalmond: "ffebcd",
1975
+ blue: "00f",
1976
+ blueviolet: "8a2be2",
1977
+ brown: "a52a2a",
1978
+ burlywood: "deb887",
1979
+ burntsienna: "ea7e5d",
1980
+ cadetblue: "5f9ea0",
1981
+ chartreuse: "7fff00",
1982
+ chocolate: "d2691e",
1983
+ coral: "ff7f50",
1984
+ cornflowerblue: "6495ed",
1985
+ cornsilk: "fff8dc",
1986
+ crimson: "dc143c",
1987
+ cyan: "0ff",
1988
+ darkblue: "00008b",
1989
+ darkcyan: "008b8b",
1990
+ darkgoldenrod: "b8860b",
1991
+ darkgray: "a9a9a9",
1992
+ darkgreen: "006400",
1993
+ darkgrey: "a9a9a9",
1994
+ darkkhaki: "bdb76b",
1995
+ darkmagenta: "8b008b",
1996
+ darkolivegreen: "556b2f",
1997
+ darkorange: "ff8c00",
1998
+ darkorchid: "9932cc",
1999
+ darkred: "8b0000",
2000
+ darksalmon: "e9967a",
2001
+ darkseagreen: "8fbc8f",
2002
+ darkslateblue: "483d8b",
2003
+ darkslategray: "2f4f4f",
2004
+ darkslategrey: "2f4f4f",
2005
+ darkturquoise: "00ced1",
2006
+ darkviolet: "9400d3",
2007
+ deeppink: "ff1493",
2008
+ deepskyblue: "00bfff",
2009
+ dimgray: "696969",
2010
+ dimgrey: "696969",
2011
+ dodgerblue: "1e90ff",
2012
+ firebrick: "b22222",
2013
+ floralwhite: "fffaf0",
2014
+ forestgreen: "228b22",
2015
+ fuchsia: "f0f",
2016
+ gainsboro: "dcdcdc",
2017
+ ghostwhite: "f8f8ff",
2018
+ gold: "ffd700",
2019
+ goldenrod: "daa520",
2020
+ gray: "808080",
2021
+ green: "008000",
2022
+ greenyellow: "adff2f",
2023
+ grey: "808080",
2024
+ honeydew: "f0fff0",
2025
+ hotpink: "ff69b4",
2026
+ indianred: "cd5c5c",
2027
+ indigo: "4b0082",
2028
+ ivory: "fffff0",
2029
+ khaki: "f0e68c",
2030
+ lavender: "e6e6fa",
2031
+ lavenderblush: "fff0f5",
2032
+ lawngreen: "7cfc00",
2033
+ lemonchiffon: "fffacd",
2034
+ lightblue: "add8e6",
2035
+ lightcoral: "f08080",
2036
+ lightcyan: "e0ffff",
2037
+ lightgoldenrodyellow: "fafad2",
2038
+ lightgray: "d3d3d3",
2039
+ lightgreen: "90ee90",
2040
+ lightgrey: "d3d3d3",
2041
+ lightpink: "ffb6c1",
2042
+ lightsalmon: "ffa07a",
2043
+ lightseagreen: "20b2aa",
2044
+ lightskyblue: "87cefa",
2045
+ lightslategray: "789",
2046
+ lightslategrey: "789",
2047
+ lightsteelblue: "b0c4de",
2048
+ lightyellow: "ffffe0",
2049
+ lime: "0f0",
2050
+ limegreen: "32cd32",
2051
+ linen: "faf0e6",
2052
+ magenta: "f0f",
2053
+ maroon: "800000",
2054
+ mediumaquamarine: "66cdaa",
2055
+ mediumblue: "0000cd",
2056
+ mediumorchid: "ba55d3",
2057
+ mediumpurple: "9370db",
2058
+ mediumseagreen: "3cb371",
2059
+ mediumslateblue: "7b68ee",
2060
+ mediumspringgreen: "00fa9a",
2061
+ mediumturquoise: "48d1cc",
2062
+ mediumvioletred: "c71585",
2063
+ midnightblue: "191970",
2064
+ mintcream: "f5fffa",
2065
+ mistyrose: "ffe4e1",
2066
+ moccasin: "ffe4b5",
2067
+ navajowhite: "ffdead",
2068
+ navy: "000080",
2069
+ oldlace: "fdf5e6",
2070
+ olive: "808000",
2071
+ olivedrab: "6b8e23",
2072
+ orange: "ffa500",
2073
+ orangered: "ff4500",
2074
+ orchid: "da70d6",
2075
+ palegoldenrod: "eee8aa",
2076
+ palegreen: "98fb98",
2077
+ paleturquoise: "afeeee",
2078
+ palevioletred: "db7093",
2079
+ papayawhip: "ffefd5",
2080
+ peachpuff: "ffdab9",
2081
+ peru: "cd853f",
2082
+ pink: "ffc0cb",
2083
+ plum: "dda0dd",
2084
+ powderblue: "b0e0e6",
2085
+ purple: "800080",
2086
+ rebeccapurple: "663399",
2087
+ red: "f00",
2088
+ rosybrown: "bc8f8f",
2089
+ royalblue: "4169e1",
2090
+ saddlebrown: "8b4513",
2091
+ salmon: "fa8072",
2092
+ sandybrown: "f4a460",
2093
+ seagreen: "2e8b57",
2094
+ seashell: "fff5ee",
2095
+ sienna: "a0522d",
2096
+ silver: "c0c0c0",
2097
+ skyblue: "87ceeb",
2098
+ slateblue: "6a5acd",
2099
+ slategray: "708090",
2100
+ slategrey: "708090",
2101
+ snow: "fffafa",
2102
+ springgreen: "00ff7f",
2103
+ steelblue: "4682b4",
2104
+ tan: "d2b48c",
2105
+ teal: "008080",
2106
+ thistle: "d8bfd8",
2107
+ tomato: "ff6347",
2108
+ turquoise: "40e0d0",
2109
+ violet: "ee82ee",
2110
+ wheat: "f5deb3",
2111
+ white: "fff",
2112
+ whitesmoke: "f5f5f5",
2113
+ yellow: "ff0",
2114
+ yellowgreen: "9acd32"
2115
+ };
2116
+
2117
+ // Make it easy to access colors via `hexNames[hex]`
2118
+ var hexNames = tinycolor.hexNames = flip(names);
2119
+
2120
+
2121
+ // Utilities
2122
+ // ---------
2123
+
2124
+ // `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
2125
+ function flip(o) {
2126
+ var flipped = { };
2127
+ for (var i in o) {
2128
+ if (o.hasOwnProperty(i)) {
2129
+ flipped[o[i]] = i;
2130
+ }
2131
+ }
2132
+ return flipped;
2133
+ }
2134
+
2135
+ // Return a valid alpha value [0,1] with all invalid values being set to 1
2136
+ function boundAlpha(a) {
2137
+ a = parseFloat(a);
2138
+
2139
+ if (isNaN(a) || a < 0 || a > 1) {
2140
+ a = 1;
2141
+ }
2142
+
2143
+ return a;
2144
+ }
2145
+
2146
+ // Take input from [0, n] and return it as [0, 1]
2147
+ function bound01(n, max) {
2148
+ if (isOnePointZero(n)) { n = "100%"; }
2149
+
2150
+ var processPercent = isPercentage(n);
2151
+ n = mathMin(max, mathMax(0, parseFloat(n)));
2152
+
2153
+ // Automatically convert percentage into number
2154
+ if (processPercent) {
2155
+ n = parseInt(n * max, 10) / 100;
2156
+ }
2157
+
2158
+ // Handle floating point rounding errors
2159
+ if ((math.abs(n - max) < 0.000001)) {
2160
+ return 1;
2161
+ }
2162
+
2163
+ // Convert into [0, 1] range if it isn't already
2164
+ return (n % max) / parseFloat(max);
2165
+ }
2166
+
2167
+ // Force a number between 0 and 1
2168
+ function clamp01(val) {
2169
+ return mathMin(1, mathMax(0, val));
2170
+ }
2171
+
2172
+ // Parse a base-16 hex value into a base-10 integer
2173
+ function parseIntFromHex(val) {
2174
+ return parseInt(val, 16);
2175
+ }
2176
+
2177
+ // Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
2178
+ // <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
2179
+ function isOnePointZero(n) {
2180
+ return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
2181
+ }
2182
+
2183
+ // Check to see if string passed in is a percentage
2184
+ function isPercentage(n) {
2185
+ return typeof n === "string" && n.indexOf('%') != -1;
2186
+ }
2187
+
2188
+ // Force a hex value to have 2 characters
2189
+ function pad2(c) {
2190
+ return c.length == 1 ? '0' + c : '' + c;
2191
+ }
2192
+
2193
+ // Replace a decimal with it's percentage value
2194
+ function convertToPercentage(n) {
2195
+ if (n <= 1) {
2196
+ n = (n * 100) + "%";
2197
+ }
2198
+
2199
+ return n;
2200
+ }
2201
+
2202
+ // Converts a decimal to a hex value
2203
+ function convertDecimalToHex(d) {
2204
+ return Math.round(parseFloat(d) * 255).toString(16);
2205
+ }
2206
+ // Converts a hex value to a decimal
2207
+ function convertHexToDecimal(h) {
2208
+ return (parseIntFromHex(h) / 255);
2209
+ }
2210
+
2211
+ var matchers = (function() {
2212
+
2213
+ // <http://www.w3.org/TR/css3-values/#integers>
2214
+ var CSS_INTEGER = "[-\\+]?\\d+%?";
2215
+
2216
+ // <http://www.w3.org/TR/css3-values/#number-value>
2217
+ var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
2218
+
2219
+ // Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
2220
+ var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
2221
+
2222
+ // Actual matching.
2223
+ // Parentheses and commas are optional, but not required.
2224
+ // Whitespace can take the place of commas or opening paren
2225
+ var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2226
+ var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
2227
+
2228
+ return {
2229
+ rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
2230
+ rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
2231
+ hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
2232
+ hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
2233
+ hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
2234
+ hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
2235
+ hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
2236
+ hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
2237
+ hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
2238
+ };
2239
+ })();
2240
+
2241
+ // `stringInputToObject`
2242
+ // Permissive string parsing. Take in a number of formats, and output an object
2243
+ // based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
2244
+ function stringInputToObject(color) {
2245
+
2246
+ color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase();
2247
+ var named = false;
2248
+ if (names[color]) {
2249
+ color = names[color];
2250
+ named = true;
2251
+ }
2252
+ else if (color == 'transparent') {
2253
+ return { r: 0, g: 0, b: 0, a: 0, format: "name" };
2254
+ }
2255
+
2256
+ // Try to match string input using regular expressions.
2257
+ // Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
2258
+ // Just return an object and let the conversion functions handle that.
2259
+ // This way the result will be the same whether the tinycolor is initialized with string or object.
2260
+ var match;
2261
+ if ((match = matchers.rgb.exec(color))) {
2262
+ return { r: match[1], g: match[2], b: match[3] };
2263
+ }
2264
+ if ((match = matchers.rgba.exec(color))) {
2265
+ return { r: match[1], g: match[2], b: match[3], a: match[4] };
2266
+ }
2267
+ if ((match = matchers.hsl.exec(color))) {
2268
+ return { h: match[1], s: match[2], l: match[3] };
2269
+ }
2270
+ if ((match = matchers.hsla.exec(color))) {
2271
+ return { h: match[1], s: match[2], l: match[3], a: match[4] };
2272
+ }
2273
+ if ((match = matchers.hsv.exec(color))) {
2274
+ return { h: match[1], s: match[2], v: match[3] };
2275
+ }
2276
+ if ((match = matchers.hsva.exec(color))) {
2277
+ return { h: match[1], s: match[2], v: match[3], a: match[4] };
2278
+ }
2279
+ if ((match = matchers.hex8.exec(color))) {
2280
+ return {
2281
+ a: convertHexToDecimal(match[1]),
2282
+ r: parseIntFromHex(match[2]),
2283
+ g: parseIntFromHex(match[3]),
2284
+ b: parseIntFromHex(match[4]),
2285
+ format: named ? "name" : "hex8"
2286
+ };
2287
+ }
2288
+ if ((match = matchers.hex6.exec(color))) {
2289
+ return {
2290
+ r: parseIntFromHex(match[1]),
2291
+ g: parseIntFromHex(match[2]),
2292
+ b: parseIntFromHex(match[3]),
2293
+ format: named ? "name" : "hex"
2294
+ };
2295
+ }
2296
+ if ((match = matchers.hex3.exec(color))) {
2297
+ return {
2298
+ r: parseIntFromHex(match[1] + '' + match[1]),
2299
+ g: parseIntFromHex(match[2] + '' + match[2]),
2300
+ b: parseIntFromHex(match[3] + '' + match[3]),
2301
+ format: named ? "name" : "hex"
2302
+ };
2303
+ }
2304
+
2305
+ return false;
2306
+ }
2307
+
2308
+ window.tinycolor = tinycolor;
2309
+ })();
2310
+
2311
+ $(function () {
2312
+ if ($.fn.spectrum.load) {
2313
+ $.fn.spectrum.processNativeColorInputs();
2314
+ }
2315
+ });
2316
+
2317
+ });
lib/simple-admin-pages/lib/pickadate/legacy.js CHANGED
@@ -1,10 +1,10 @@
1
- /*!
2
- * Legacy browser support
3
- */
4
- [].map||(Array.prototype.map=function(a,b){for(var c=this,d=c.length,e=new Array(d),f=0;f<d;f++)f in c&&(e[f]=a.call(b,c[f],f,c));return e}),[].filter||(Array.prototype.filter=function(a){if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if("function"!=typeof a)throw new TypeError;for(var d=[],e=arguments[1],f=0;f<c;f++)if(f in b){var g=b[f];a.call(e,g,f,b)&&d.push(g)}return d}),[].indexOf||(Array.prototype.indexOf=function(a){if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!==d&&d!=1/0&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);e<c;e++)if(e in b&&b[e]===a)return e;return-1});/*!
5
- * Cross-Browser Split 1.1.1
6
- * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
7
- * Available under the MIT License
8
- * http://blog.stevenlevithan.com/archives/cross-browser-split
9
- */
10
  var nativeSplit=String.prototype.split,compliantExecNpcg=void 0===/()??/.exec("")[1];String.prototype.split=function(a,b){var c=this;if("[object RegExp]"!==Object.prototype.toString.call(a))return nativeSplit.call(c,a,b);var d,e,f,g,h=[],i=(a.ignoreCase?"i":"")+(a.multiline?"m":"")+(a.extended?"x":"")+(a.sticky?"y":""),j=0;for(a=new RegExp(a.source,i+"g"),c+="",compliantExecNpcg||(d=new RegExp("^"+a.source+"$(?!\\s)",i)),b=void 0===b?-1>>>0:b>>>0;(e=a.exec(c))&&!((f=e.index+e[0].length)>j&&(h.push(c.slice(j,e.index)),!compliantExecNpcg&&e.length>1&&e[0].replace(d,function(){for(var a=1;a<arguments.length-2;a++)void 0===arguments[a]&&(e[a]=void 0)}),e.length>1&&e.index<c.length&&Array.prototype.push.apply(h,e.slice(1)),g=e[0].length,j=f,h.length>=b));)a.lastIndex===e.index&&a.lastIndex++;return j===c.length?!g&&a.test("")||h.push(""):h.push(c.slice(j)),h.length>b?h.slice(0,b):h};
1
+ /*!
2
+ * Legacy browser support
3
+ */
4
+ [].map||(Array.prototype.map=function(a,b){for(var c=this,d=c.length,e=new Array(d),f=0;f<d;f++)f in c&&(e[f]=a.call(b,c[f],f,c));return e}),[].filter||(Array.prototype.filter=function(a){if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if("function"!=typeof a)throw new TypeError;for(var d=[],e=arguments[1],f=0;f<c;f++)if(f in b){var g=b[f];a.call(e,g,f,b)&&d.push(g)}return d}),[].indexOf||(Array.prototype.indexOf=function(a){if(null==this)throw new TypeError;var b=Object(this),c=b.length>>>0;if(0===c)return-1;var d=0;if(arguments.length>1&&(d=Number(arguments[1]),d!=d?d=0:0!==d&&d!=1/0&&d!=-1/0&&(d=(d>0||-1)*Math.floor(Math.abs(d)))),d>=c)return-1;for(var e=d>=0?d:Math.max(c-Math.abs(d),0);e<c;e++)if(e in b&&b[e]===a)return e;return-1});/*!
5
+ * Cross-Browser Split 1.1.1
6
+ * Copyright 2007-2012 Steven Levithan <stevenlevithan.com>
7
+ * Available under the MIT License
8
+ * http://blog.stevenlevithan.com/archives/cross-browser-split
9
+ */
10
  var nativeSplit=String.prototype.split,compliantExecNpcg=void 0===/()??/.exec("")[1];String.prototype.split=function(a,b){var c=this;if("[object RegExp]"!==Object.prototype.toString.call(a))return nativeSplit.call(c,a,b);var d,e,f,g,h=[],i=(a.ignoreCase?"i":"")+(a.multiline?"m":"")+(a.extended?"x":"")+(a.sticky?"y":""),j=0;for(a=new RegExp(a.source,i+"g"),c+="",compliantExecNpcg||(d=new RegExp("^"+a.source+"$(?!\\s)",i)),b=void 0===b?-1>>>0:b>>>0;(e=a.exec(c))&&!((f=e.index+e[0].length)>j&&(h.push(c.slice(j,e.index)),!compliantExecNpcg&&e.length>1&&e[0].replace(d,function(){for(var a=1;a<arguments.length-2;a++)void 0===arguments[a]&&(e[a]=void 0)}),e.length>1&&e.index<c.length&&Array.prototype.push.apply(h,e.slice(1)),g=e[0].length,j=f,h.length>=b));)a.lastIndex===e.index&&a.lastIndex++;return j===c.length?!g&&a.test("")||h.push(""):h.push(c.slice(j)),h.length>b?h.slice(0,b):h};
lib/simple-admin-pages/lib/pickadate/picker.date.js CHANGED
@@ -1,5 +1,5 @@
1
- /*!
2
- * Date picker for pickadate.js v3.6.1
3
- * http://amsul.github.io/pickadate.js/date.htm
4
- */
5
  !function(a){"function"==typeof define&&define.amd?define(["./picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0],e=d.value,f=a.$node.data("value"),g=f||e,h=f?b.formatSubmit:b.format,i=function(){return d.currentStyle?"rtl"==d.currentStyle.direction:"rtl"==getComputedStyle(a.$root[0]).direction};c.settings=b,c.$node=a.$node,c.queue={min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse navigate create validate",view:"parse create validate viewset",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return!0===a[0]?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),g?c.set("select",g,{format:h,defaultValue:!0}):c.set("select",null).set("highlight",c.item.now),c.key={40:7,38:-7,39:function(){return i()?-1:1},37:function(){return i()?1:-1},go:function(a){var b=c.item.highlight,d=new Date(b.year,b.month,b.date+a);c.set("highlight",d,{interval:a}),this.render()}},a.on("render",function(){a.$root.find("."+b.klass.selectMonth).on("change",function(){var c=this.value;c&&(a.set("highlight",[a.get("view").year,c,a.get("highlight").date]),a.$root.find("."+b.klass.selectMonth).trigger("focus"))}),a.$root.find("."+b.klass.selectYear).on("change",function(){var c=this.value;c&&(a.set("highlight",[c,a.get("view").month,a.get("highlight").date]),a.$root.find("."+b.klass.selectYear).trigger("focus"))})},1).on("open",function(){var d="";c.disabled(c.get("now"))&&(d=":not(."+b.klass.buttonToday+")"),a.$root.find("button"+d+", select").attr("disabled",!1)},1).on("close",function(){a.$root.find("button, select").attr("disabled",!0)},1)}var d=7,e=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",e.select,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",e.highlight,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,d){var f,g=this;return c=void 0===c?a:c,c==-1/0||c==1/0?f=c:b.isPlainObject(c)&&e.isInteger(c.pick)?c=c.obj:b.isArray(c)?(c=new Date(c[0],c[1],c[2]),c=e.isDate(c)?c:g.create().obj):c=e.isInteger(c)||e.isDate(c)?g.normalize(new Date(c),d):g.now(a,c,d),{year:f||c.getFullYear(),month:f||c.getMonth(),date:f||c.getDate(),day:f||c.getDay(),obj:f||c,pick:f||c.getTime()}},c.prototype.createRange=function(a,c){var d=this,f=function(a){return!0===a||b.isArray(a)||e.isDate(a)?d.create(a):a};return e.isInteger(a)||(a=f(a)),e.isInteger(c)||(c=f(c)),e.isInteger(a)&&b.isPlainObject(c)?a=[c.year,c.month,c.date+a]:e.isInteger(c)&&b.isPlainObject(a)&&(c=[a.year,a.month,a.date+c]),{from:f(a),to:f(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b,c){return b=new Date,c&&c.rel&&b.setDate(b.getDate()+c.rel),this.normalize(b,c)},c.prototype.navigate=function(a,c,d){var e,f,g,h,i=b.isArray(c),j=b.isPlainObject(c),k=this.item.view;if(i||j){for(j?(f=c.year,g=c.month,h=c.date):(f=+c[0],g=+c[1],h=+c[2]),d&&d.nav&&k&&k.month!==g&&(f=k.year,g=k.month),e=new Date(f,g+(d&&d.nav?d.nav:0),1),f=e.getFullYear(),g=e.getMonth();new Date(f,g,h).getMonth()!==g;)h-=1;c=[f,g,h]}return c},c.prototype.normalize=function(a){return a.setHours(0,0,0,0),a},c.prototype.measure=function(a,b){var c=this;return e.isInteger(b)?b=c.now(a,b,{rel:b}):b?"string"==typeof b&&(b=c.parse(a,b)):b="min"==a?-1/0:1/0,b},c.prototype.viewset=function(a,b){return this.create([b.year,b.month,1])},c.prototype.validate=function(a,c,d){var f,g,h,i,j=this,k=c,l=d&&d.interval?d.interval:1,m=-1===j.item.enable,n=j.item.min,o=j.item.max,p=m&&j.item.disable.filter(function(a){if(b.isArray(a)){var d=j.create(a).pick;d<c.pick?f=!0:d>c.pick&&(g=!0)}return e.isInteger(a)}).length;if((!d||!d.nav&&!d.defaultValue)&&(!m&&j.disabled(c)||m&&j.disabled(c)&&(p||f||g)||!m&&(c.pick<=n.pick||c.pick>=o.pick)))for(m&&!p&&(!g&&l>0||!f&&l<0)&&(l*=-1);j.disabled(c)&&(Math.abs(l)>1&&(c.month<k.month||c.month>k.month)&&(c=k,l=l>0?1:-1),c.pick<=n.pick?(h=!0,l=1,c=j.create([n.year,n.month,n.date+(c.pick===n.pick?0:-1)])):c.pick>=o.pick&&(i=!0,l=-1,c=j.create([o.year,o.month,o.date+(c.pick===o.pick?0:1)])),!h||!i);)c=j.create([c.year,c.month,c.date+l]);return c},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return e.isInteger(d)?a.day===(c.settings.firstDay?d:d-1)%7:b.isArray(d)||e.isDate(d)?a.pick===c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[3]||b.isPlainObject(a)&&a.inverted}).length,-1===c.item.enable?!d:d||a.pick<c.item.min.pick||a.pick>c.item.max.pick},c.prototype.parse=function(a,b,c){var d=this,f={};return b&&"string"==typeof b?(c&&c.format||(c=c||{},c.format=d.settings.format),d.formats.toArray(c.format).map(function(a){var c=d.formats[a],g=c?e.trigger(c,d,[b,f]):a.replace(/^!/,"").length;c&&(f[a]=b.substr(0,g)),b=b.substr(g)}),[f.yyyy||f.yy,+(f.mm||f.m)-1,f.dd||f.d]):b},c.prototype.formats=function(){function a(a,b,c){var d=a.match(/[^\x00-\x7F]+|\w+/)[0];return c.mm||c.m||(c.m=b.indexOf(d)+1),d.length}function b(a){return a.match(/\w+/)[0].length}return{d:function(a,b){return a?e.digits(a):b.date},dd:function(a,b){return a?2:e.lead(b.date)},ddd:function(a,c){return a?b(a):this.settings.weekdaysShort[c.day]},dddd:function(a,c){return a?b(a):this.settings.weekdaysFull[c.day]},m:function(a,b){return a?e.digits(a):b.month+1},mm:function(a,b){return a?2:e.lead(b.month+1)},mmm:function(b,c){var d=this.settings.monthsShort;return b?a(b,d,c):d[c.month]},mmmm:function(b,c){var d=this.settings.monthsFull;return b?a(b,d,c):d[c.month]},yy:function(a,b){return a?2:(""+b.year).slice(2)},yyyy:function(a,b){return a?4:b.year},toArray:function(a){return a.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return e.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}}}(),c.prototype.isDateExact=function(a,c){var d=this;return e.isInteger(a)&&e.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(e.isDate(a)||b.isArray(a))&&(e.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.isDateExact(a.from,c.from)&&d.isDateExact(a.to,c.to)},c.prototype.isDateOverlap=function(a,c){var d=this,f=d.settings.firstDay?1:0;return e.isInteger(a)&&(e.isDate(c)||b.isArray(c))?(a=a%7+f)===d.create(c).day+1:e.isInteger(c)&&(e.isDate(a)||b.isArray(a))?(c=c%7+f)===d.create(a).day+1:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.overlapRanges(a,c)},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(-1==b.enable?1:-1)},c.prototype.deactivate=function(a,c){var d=this,f=d.item.disable.slice(0);return"flip"==c?d.flipEnable():!1===c?(d.flipEnable(1),f=[]):!0===c?(d.flipEnable(-1),f=[]):c.map(function(a){for(var c,g=0;g<f.length;g+=1)if(d.isDateExact(a,f[g])){c=!0;break}c||(e.isInteger(a)||e.isDate(a)||b.isArray(a)||b.isPlainObject(a)&&a.from&&a.to)&&f.push(a)}),f},c.prototype.activate=function(a,c){var d=this,f=d.item.disable,g=f.length;return"flip"==c?d.flipEnable():!0===c?(d.flipEnable(1),f=[]):!1===c?(d.flipEnable(-1),f=[]):c.map(function(a){var c,h,i,j;for(i=0;i<g;i+=1){if(h=f[i],d.isDateExact(h,a)){c=f[i]=null,j=!0;break}if(d.isDateOverlap(h,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[3]||c.push("inverted")):e.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;i<g;i+=1)if(d.isDateExact(f[i],a)){f[i]=null;break}if(j)for(i=0;i<g;i+=1)if(d.isDateOverlap(f[i],a)){f[i]=null;break}c&&f.push(c)}),f.filter(function(a){return null!=a})},c.prototype.nodes=function(a){var b=this,c=b.settings,f=b.item,g=f.now,h=f.select,i=f.highlight,j=f.view,k=f.disable,l=f.min,m=f.max,n=function(a,b){return c.firstDay&&(a.push(a.shift()),b.push(b.shift())),e.node("thead",e.node("tr",e.group({min:0,max:d-1,i:1,node:"th",item:function(d){return[a[d],c.klass.weekdays,'scope=col title="'+b[d]+'"']}})))}((c.showWeekdaysFull?c.weekdaysFull:c.weekdaysShort).slice(0),c.weekdaysFull.slice(0)),o=function(a){return e.node("div"," ",c.klass["nav"+(a?"Next":"Prev")]+(a&&j.year>=m.year&&j.month>=m.month||!a&&j.year<=l.year&&j.month<=l.month?" "+c.klass.navDisabled:""),"data-nav="+(a||-1)+" "+e.ariaAttr({role:"button",controls:b.$node[0].id+"_table"})+' title="'+(a?c.labelMonthNext:c.labelMonthPrev)+'"')},p=function(){var d=c.showMonthsShort?c.monthsShort:c.monthsFull;return c.selectMonths?e.node("select",e.group({min:0,max:11,i:1,node:"option",item:function(a){return[d[a],0,"value="+a+(j.month==a?" selected":"")+(j.year==l.year&&a<l.month||j.year==m.year&&a>m.month?" disabled":"")]}}),c.klass.selectMonth,(a?"":"disabled")+" "+e.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelMonthSelect+'"'):e.node("div",d[j.month],c.klass.month)},q=function(){var d=j.year,f=!0===c.selectYears?5:~~(c.selectYears/2);if(f){var g=l.year,h=m.year,i=d-f,k=d+f;if(g>i&&(k+=g-i,i=g),h<k){var n=i-g,o=k-h;i-=n>o?o:n,k=h}return e.node("select",e.group({min:i,max:k,i:1,node:"option",item:function(a){return[a,0,"value="+a+(d==a?" selected":"")]}}),c.klass.selectYear,(a?"":"disabled")+" "+e.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelYearSelect+'"')}return e.node("div",d,c.klass.year)};return e.node("div",(c.selectYears?q()+p():p()+q())+o()+o(1),c.klass.header)+e.node("table",n+e.node("tbody",e.group({min:0,max:5,i:1,node:"tr",item:function(a){var f=c.firstDay&&0===b.create([j.year,j.month,1]).day?-7:0;return[e.group({min:d*a-j.day+f+1,max:function(){return this.min+d-1},i:1,node:"td",item:function(a){a=b.create([j.year,j.month,a+(c.firstDay?1:0)]);var d=h&&h.pick==a.pick,f=i&&i.pick==a.pick,n=k&&b.disabled(a)||a.pick<l.pick||a.pick>m.pick,o=e.trigger(b.formats.toString,b,[c.format,a]);return[e.node("div",a.date,function(b){return b.push(j.month==a.month?c.klass.infocus:c.klass.outfocus),g.pick==a.pick&&b.push(c.klass.now),d&&b.push(c.klass.selected),f&&b.push(c.klass.highlighted),n&&b.push(c.klass.disabled),b.join(" ")}([c.klass.day]),"data-pick="+a.pick+" "+e.ariaAttr({role:"gridcell",label:o,selected:!(!d||b.$node.val()!==o)||null,activedescendant:!!f||null,disabled:!!n||null})),"",e.ariaAttr({role:"presentation"})]}})]}})),c.klass.table,'id="'+b.$node[0].id+'_table" '+e.ariaAttr({role:"grid",controls:b.$node[0].id,readonly:!0}))+e.node("div",e.node("button",c.today,c.klass.buttonToday,"type=button data-pick="+g.pick+(a&&!b.disabled(g)?"":" disabled")+" "+e.ariaAttr({controls:b.$node[0].id}))+e.node("button",c.clear,c.klass.buttonClear,"type=button data-clear=1"+(a?"":" disabled")+" "+e.ariaAttr({controls:b.$node[0].id}))+e.node("button",c.close,c.klass.buttonClose,"type=button data-close=true "+(a?"":" disabled")+" "+e.ariaAttr({controls:b.$node[0].id})),c.klass.footer)},c.defaults=function(a){return{labelMonthNext:"Next month",labelMonthPrev:"Previous month",labelMonthSelect:"Select a month",labelYearSelect:"Select a year",monthsFull:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdaysFull:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],today:"Today",clear:"Clear",close:"Close",closeOnSelect:!0,closeOnClear:!0,updateInput:!0,format:"d mmmm, yyyy",klass:{table:a+"table",header:a+"header",navPrev:a+"nav--prev",navNext:a+"nav--next",navDisabled:a+"nav--disabled",month:a+"month",year:a+"year",selectMonth:a+"select--month",selectYear:a+"select--year",weekdays:a+"weekday",day:a+"day",disabled:a+"day--disabled",selected:a+"day--selected",highlighted:a+"day--highlighted",now:a+"day--today",infocus:a+"day--infocus",outfocus:a+"day--outfocus",footer:a+"footer",buttonClear:a+"button--clear",buttonToday:a+"button--today",buttonClose:a+"button--close"}}}(a.klasses().picker+"__"),a.extend("pickadate",c)});
1
+ /*!
2
+ * Date picker for pickadate.js v3.6.1
3
+ * http://amsul.github.io/pickadate.js/date.htm
4
+ */
5
  !function(a){"function"==typeof define&&define.amd?define(["./picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0],e=d.value,f=a.$node.data("value"),g=f||e,h=f?b.formatSubmit:b.format,i=function(){return d.currentStyle?"rtl"==d.currentStyle.direction:"rtl"==getComputedStyle(a.$root[0]).direction};c.settings=b,c.$node=a.$node,c.queue={min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse navigate create validate",view:"parse create validate viewset",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return!0===a[0]?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),g?c.set("select",g,{format:h,defaultValue:!0}):c.set("select",null).set("highlight",c.item.now),c.key={40:7,38:-7,39:function(){return i()?-1:1},37:function(){return i()?1:-1},go:function(a){var b=c.item.highlight,d=new Date(b.year,b.month,b.date+a);c.set("highlight",d,{interval:a}),this.render()}},a.on("render",function(){a.$root.find("."+b.klass.selectMonth).on("change",function(){var c=this.value;c&&(a.set("highlight",[a.get("view").year,c,a.get("highlight").date]),a.$root.find("."+b.klass.selectMonth).trigger("focus"))}),a.$root.find("."+b.klass.selectYear).on("change",function(){var c=this.value;c&&(a.set("highlight",[c,a.get("view").month,a.get("highlight").date]),a.$root.find("."+b.klass.selectYear).trigger("focus"))})},1).on("open",function(){var d="";c.disabled(c.get("now"))&&(d=":not(."+b.klass.buttonToday+")"),a.$root.find("button"+d+", select").attr("disabled",!1)},1).on("close",function(){a.$root.find("button, select").attr("disabled",!0)},1)}var d=7,e=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",e.select,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",e.highlight,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,d){var f,g=this;return c=void 0===c?a:c,c==-1/0||c==1/0?f=c:b.isPlainObject(c)&&e.isInteger(c.pick)?c=c.obj:b.isArray(c)?(c=new Date(c[0],c[1],c[2]),c=e.isDate(c)?c:g.create().obj):c=e.isInteger(c)||e.isDate(c)?g.normalize(new Date(c),d):g.now(a,c,d),{year:f||c.getFullYear(),month:f||c.getMonth(),date:f||c.getDate(),day:f||c.getDay(),obj:f||c,pick:f||c.getTime()}},c.prototype.createRange=function(a,c){var d=this,f=function(a){return!0===a||b.isArray(a)||e.isDate(a)?d.create(a):a};return e.isInteger(a)||(a=f(a)),e.isInteger(c)||(c=f(c)),e.isInteger(a)&&b.isPlainObject(c)?a=[c.year,c.month,c.date+a]:e.isInteger(c)&&b.isPlainObject(a)&&(c=[a.year,a.month,a.date+c]),{from:f(a),to:f(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b,c){return b=new Date,c&&c.rel&&b.setDate(b.getDate()+c.rel),this.normalize(b,c)},c.prototype.navigate=function(a,c,d){var e,f,g,h,i=b.isArray(c),j=b.isPlainObject(c),k=this.item.view;if(i||j){for(j?(f=c.year,g=c.month,h=c.date):(f=+c[0],g=+c[1],h=+c[2]),d&&d.nav&&k&&k.month!==g&&(f=k.year,g=k.month),e=new Date(f,g+(d&&d.nav?d.nav:0),1),f=e.getFullYear(),g=e.getMonth();new Date(f,g,h).getMonth()!==g;)h-=1;c=[f,g,h]}return c},c.prototype.normalize=function(a){return a.setHours(0,0,0,0),a},c.prototype.measure=function(a,b){var c=this;return e.isInteger(b)?b=c.now(a,b,{rel:b}):b?"string"==typeof b&&(b=c.parse(a,b)):b="min"==a?-1/0:1/0,b},c.prototype.viewset=function(a,b){return this.create([b.year,b.month,1])},c.prototype.validate=function(a,c,d){var f,g,h,i,j=this,k=c,l=d&&d.interval?d.interval:1,m=-1===j.item.enable,n=j.item.min,o=j.item.max,p=m&&j.item.disable.filter(function(a){if(b.isArray(a)){var d=j.create(a).pick;d<c.pick?f=!0:d>c.pick&&(g=!0)}return e.isInteger(a)}).length;if((!d||!d.nav&&!d.defaultValue)&&(!m&&j.disabled(c)||m&&j.disabled(c)&&(p||f||g)||!m&&(c.pick<=n.pick||c.pick>=o.pick)))for(m&&!p&&(!g&&l>0||!f&&l<0)&&(l*=-1);j.disabled(c)&&(Math.abs(l)>1&&(c.month<k.month||c.month>k.month)&&(c=k,l=l>0?1:-1),c.pick<=n.pick?(h=!0,l=1,c=j.create([n.year,n.month,n.date+(c.pick===n.pick?0:-1)])):c.pick>=o.pick&&(i=!0,l=-1,c=j.create([o.year,o.month,o.date+(c.pick===o.pick?0:1)])),!h||!i);)c=j.create([c.year,c.month,c.date+l]);return c},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return e.isInteger(d)?a.day===(c.settings.firstDay?d:d-1)%7:b.isArray(d)||e.isDate(d)?a.pick===c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[3]||b.isPlainObject(a)&&a.inverted}).length,-1===c.item.enable?!d:d||a.pick<c.item.min.pick||a.pick>c.item.max.pick},c.prototype.parse=function(a,b,c){var d=this,f={};return b&&"string"==typeof b?(c&&c.format||(c=c||{},c.format=d.settings.format),d.formats.toArray(c.format).map(function(a){var c=d.formats[a],g=c?e.trigger(c,d,[b,f]):a.replace(/^!/,"").length;c&&(f[a]=b.substr(0,g)),b=b.substr(g)}),[f.yyyy||f.yy,+(f.mm||f.m)-1,f.dd||f.d]):b},c.prototype.formats=function(){function a(a,b,c){var d=a.match(/[^\x00-\x7F]+|\w+/)[0];return c.mm||c.m||(c.m=b.indexOf(d)+1),d.length}function b(a){return a.match(/\w+/)[0].length}return{d:function(a,b){return a?e.digits(a):b.date},dd:function(a,b){return a?2:e.lead(b.date)},ddd:function(a,c){return a?b(a):this.settings.weekdaysShort[c.day]},dddd:function(a,c){return a?b(a):this.settings.weekdaysFull[c.day]},m:function(a,b){return a?e.digits(a):b.month+1},mm:function(a,b){return a?2:e.lead(b.month+1)},mmm:function(b,c){var d=this.settings.monthsShort;return b?a(b,d,c):d[c.month]},mmmm:function(b,c){var d=this.settings.monthsFull;return b?a(b,d,c):d[c.month]},yy:function(a,b){return a?2:(""+b.year).slice(2)},yyyy:function(a,b){return a?4:b.year},toArray:function(a){return a.split(/(d{1,4}|m{1,4}|y{4}|yy|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return e.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}}}(),c.prototype.isDateExact=function(a,c){var d=this;return e.isInteger(a)&&e.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(e.isDate(a)||b.isArray(a))&&(e.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.isDateExact(a.from,c.from)&&d.isDateExact(a.to,c.to)},c.prototype.isDateOverlap=function(a,c){var d=this,f=d.settings.firstDay?1:0;return e.isInteger(a)&&(e.isDate(c)||b.isArray(c))?(a=a%7+f)===d.create(c).day+1:e.isInteger(c)&&(e.isDate(a)||b.isArray(a))?(c=c%7+f)===d.create(a).day+1:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.overlapRanges(a,c)},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(-1==b.enable?1:-1)},c.prototype.deactivate=function(a,c){var d=this,f=d.item.disable.slice(0);return"flip"==c?d.flipEnable():!1===c?(d.flipEnable(1),f=[]):!0===c?(d.flipEnable(-1),f=[]):c.map(function(a){for(var c,g=0;g<f.length;g+=1)if(d.isDateExact(a,f[g])){c=!0;break}c||(e.isInteger(a)||e.isDate(a)||b.isArray(a)||b.isPlainObject(a)&&a.from&&a.to)&&f.push(a)}),f},c.prototype.activate=function(a,c){var d=this,f=d.item.disable,g=f.length;return"flip"==c?d.flipEnable():!0===c?(d.flipEnable(1),f=[]):!1===c?(d.flipEnable(-1),f=[]):c.map(function(a){var c,h,i,j;for(i=0;i<g;i+=1){if(h=f[i],d.isDateExact(h,a)){c=f[i]=null,j=!0;break}if(d.isDateOverlap(h,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[3]||c.push("inverted")):e.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;i<g;i+=1)if(d.isDateExact(f[i],a)){f[i]=null;break}if(j)for(i=0;i<g;i+=1)if(d.isDateOverlap(f[i],a)){f[i]=null;break}c&&f.push(c)}),f.filter(function(a){return null!=a})},c.prototype.nodes=function(a){var b=this,c=b.settings,f=b.item,g=f.now,h=f.select,i=f.highlight,j=f.view,k=f.disable,l=f.min,m=f.max,n=function(a,b){return c.firstDay&&(a.push(a.shift()),b.push(b.shift())),e.node("thead",e.node("tr",e.group({min:0,max:d-1,i:1,node:"th",item:function(d){return[a[d],c.klass.weekdays,'scope=col title="'+b[d]+'"']}})))}((c.showWeekdaysFull?c.weekdaysFull:c.weekdaysShort).slice(0),c.weekdaysFull.slice(0)),o=function(a){return e.node("div"," ",c.klass["nav"+(a?"Next":"Prev")]+(a&&j.year>=m.year&&j.month>=m.month||!a&&j.year<=l.year&&j.month<=l.month?" "+c.klass.navDisabled:""),"data-nav="+(a||-1)+" "+e.ariaAttr({role:"button",controls:b.$node[0].id+"_table"})+' title="'+(a?c.labelMonthNext:c.labelMonthPrev)+'"')},p=function(){var d=c.showMonthsShort?c.monthsShort:c.monthsFull;return c.selectMonths?e.node("select",e.group({min:0,max:11,i:1,node:"option",item:function(a){return[d[a],0,"value="+a+(j.month==a?" selected":"")+(j.year==l.year&&a<l.month||j.year==m.year&&a>m.month?" disabled":"")]}}),c.klass.selectMonth,(a?"":"disabled")+" "+e.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelMonthSelect+'"'):e.node("div",d[j.month],c.klass.month)},q=function(){var d=j.year,f=!0===c.selectYears?5:~~(c.selectYears/2);if(f){var g=l.year,h=m.year,i=d-f,k=d+f;if(g>i&&(k+=g-i,i=g),h<k){var n=i-g,o=k-h;i-=n>o?o:n,k=h}return e.node("select",e.group({min:i,max:k,i:1,node:"option",item:function(a){return[a,0,"value="+a+(d==a?" selected":"")]}}),c.klass.selectYear,(a?"":"disabled")+" "+e.ariaAttr({controls:b.$node[0].id+"_table"})+' title="'+c.labelYearSelect+'"')}return e.node("div",d,c.klass.year)};return e.node("div",(c.selectYears?q()+p():p()+q())+o()+o(1),c.klass.header)+e.node("table",n+e.node("tbody",e.group({min:0,max:5,i:1,node:"tr",item:function(a){var f=c.firstDay&&0===b.create([j.year,j.month,1]).day?-7:0;return[e.group({min:d*a-j.day+f+1,max:function(){return this.min+d-1},i:1,node:"td",item:function(a){a=b.create([j.year,j.month,a+(c.firstDay?1:0)]);var d=h&&h.pick==a.pick,f=i&&i.pick==a.pick,n=k&&b.disabled(a)||a.pick<l.pick||a.pick>m.pick,o=e.trigger(b.formats.toString,b,[c.format,a]);return[e.node("div",a.date,function(b){return b.push(j.month==a.month?c.klass.infocus:c.klass.outfocus),g.pick==a.pick&&b.push(c.klass.now),d&&b.push(c.klass.selected),f&&b.push(c.klass.highlighted),n&&b.push(c.klass.disabled),b.join(" ")}([c.klass.day]),"data-pick="+a.pick+" "+e.ariaAttr({role:"gridcell",label:o,selected:!(!d||b.$node.val()!==o)||null,activedescendant:!!f||null,disabled:!!n||null})),"",e.ariaAttr({role:"presentation"})]}})]}})),c.klass.table,'id="'+b.$node[0].id+'_table" '+e.ariaAttr({role:"grid",controls:b.$node[0].id,readonly:!0}))+e.node("div",e.node("button",c.today,c.klass.buttonToday,"type=button data-pick="+g.pick+(a&&!b.disabled(g)?"":" disabled")+" "+e.ariaAttr({controls:b.$node[0].id}))+e.node("button",c.clear,c.klass.buttonClear,"type=button data-clear=1"+(a?"":" disabled")+" "+e.ariaAttr({controls:b.$node[0].id}))+e.node("button",c.close,c.klass.buttonClose,"type=button data-close=true "+(a?"":" disabled")+" "+e.ariaAttr({controls:b.$node[0].id})),c.klass.footer)},c.defaults=function(a){return{labelMonthNext:"Next month",labelMonthPrev:"Previous month",labelMonthSelect:"Select a month",labelYearSelect:"Select a year",monthsFull:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],weekdaysFull:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],weekdaysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],today:"Today",clear:"Clear",close:"Close",closeOnSelect:!0,closeOnClear:!0,updateInput:!0,format:"d mmmm, yyyy",klass:{table:a+"table",header:a+"header",navPrev:a+"nav--prev",navNext:a+"nav--next",navDisabled:a+"nav--disabled",month:a+"month",year:a+"year",selectMonth:a+"select--month",selectYear:a+"select--year",weekdays:a+"weekday",day:a+"day",disabled:a+"day--disabled",selected:a+"day--selected",highlighted:a+"day--highlighted",now:a+"day--today",infocus:a+"day--infocus",outfocus:a+"day--outfocus",footer:a+"footer",buttonClear:a+"button--clear",buttonToday:a+"button--today",buttonClose:a+"button--close"}}}(a.klasses().picker+"__"),a.extend("pickadate",c)});
lib/simple-admin-pages/lib/pickadate/picker.js CHANGED
@@ -1,7 +1,7 @@
1
- /*!
2
- * pickadate.js v3.6.1, 2019/03/15
3
- * By Amsul, http://amsul.ca
4
- * Hosted on http://amsul.github.io/pickadate.js
5
- * Licensed under MIT
6
- */
7
  !function(a){"function"==typeof define&&define.amd?define("picker",["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):this.Picker=a(jQuery)}(function(a){function b(h,i,k,m){function o(){return b._.node("div",b._.node("div",b._.node("div",b._.node("div",C.component.nodes(x.open),z.box),z.wrap),z.frame),z.holder,'tabindex="-1"')}function p(){A.data(i,C).addClass(z.input).val(A.data("value")?C.get("select",y.format):h.value).on("focus."+x.id+" click."+x.id,f(function(a){a.preventDefault(),C.open()},50)),y.editable||A.on("keydown."+x.id,v),g(h,{haspopup:!0,expanded:!1,readonly:!1,owns:h.id+"_root"})}function q(){g(C.$root[0],"hidden",!0)}function r(){C.$holder.on({keydown:v,"focus.toOpen":u,blur:function(){A.removeClass(z.target)},focusin:function(a){C.$root.removeClass(z.focused),a.stopPropagation()},"mousedown click":function(b){var c=e(b,h);c!=C.$holder[0]&&(b.stopPropagation(),"mousedown"!=b.type||a(c).is("input, select, textarea, button, option")||(b.preventDefault(),C.$holder.eq(0).focus()))}}).on("click","[data-pick], [data-nav], [data-clear], [data-close]",function(){var b=a(this),c=b.data(),d=b.hasClass(z.navDisabled)||b.hasClass(z.disabled),e=j();e=e&&(e.type||e.href?e:null),(d||e&&!a.contains(C.$root[0],e))&&C.$holder.eq(0).focus(),!d&&c.nav?C.set("highlight",C.component.item.highlight,{nav:c.nav}):!d&&"pick"in c?(C.set("select",c.pick),y.closeOnSelect&&C.close(!0)):c.clear?(C.clear(),y.closeOnClear&&C.close(!0)):c.close&&C.close(!0)})}function s(){var b;!0===y.hiddenName?(b=h.name,h.name=""):(b=["string"==typeof y.hiddenPrefix?y.hiddenPrefix:"","string"==typeof y.hiddenSuffix?y.hiddenSuffix:"_submit"],b=b[0]+h.name+b[1]),C._hidden=a('<input type=hidden name="'+b+'"'+(A.data("value")||h.value?' value="'+C.get("select",y.formatSubmit)+'"':"")+">")[0],A.on("change."+x.id,function(){C._hidden.value=h.value?C.get("select",y.formatSubmit):""})}function t(){w&&n?C.$holder.find("."+z.frame).one("transitionend",function(){C.$holder.eq(0).focus()}):setTimeout(function(){C.$holder.eq(0).focus()},0)}function u(a){a.stopPropagation(),A.addClass(z.target),C.$root.addClass(z.focused),C.open()}function v(a){var b=a.keyCode,c=/^(8|46)$/.test(b);if(27==b)return C.close(!0),!1;(32==b||c||!x.open&&C.component.key[b])&&(a.preventDefault(),a.stopPropagation(),c?C.clear().close():C.open())}if(!h)return b;var w=!1,x={id:h.id||"P"+Math.abs(~~(Math.random()*new Date))},y=k?a.extend(!0,{},k.defaults,m):m||{},z=a.extend({},b.klasses(),y.klass),A=a(h),B=function(){return this.start()},C=B.prototype={constructor:B,$node:A,start:function(){return x&&x.start?C:(x.methods={},x.start=!0,x.open=!1,x.type=h.type,h.autofocus=h==j(),h.readOnly=!y.editable,h.id=h.id||x.id,"text"!=h.type&&(h.type="text"),C.component=new k(C,y),C.$root=a('<div class="'+z.picker+'" id="'+h.id+'_root" />'),q(),C.$holder=a(o()).appendTo(C.$root),r(),y.formatSubmit&&s(),p(),y.containerHidden?a(y.containerHidden).append(C._hidden):A.after(C._hidden),y.container?a(y.container).append(C.$root):A.after(C.$root),C.on({start:C.component.onStart,render:C.component.onRender,stop:C.component.onStop,open:C.component.onOpen,close:C.component.onClose,set:C.component.onSet}).on({start:y.onStart,render:y.onRender,stop:y.onStop,open:y.onOpen,close:y.onClose,set:y.onSet}),w=c(C.$holder[0]),h.autofocus&&C.open(),C.trigger("start").trigger("render"))},render:function(b){return b?(C.$holder=a(o()),r(),C.$root.html(C.$holder)):C.$root.find("."+z.box).html(C.component.nodes(x.open)),C.trigger("render")},stop:function(){return x.start?(C.close(),C._hidden&&C._hidden.parentNode.removeChild(C._hidden),C.$root.remove(),A.removeClass(z.input).removeData(i),setTimeout(function(){A.off("."+x.id)},0),h.type=x.type,h.readOnly=!1,C.trigger("stop"),x.methods={},x.start=!1,C):C},open:function(c){return x.open?C:(A.addClass(z.active),g(h,"expanded",!0),setTimeout(function(){C.$root.addClass(z.opened),g(C.$root[0],"hidden",!1)},0),!1!==c&&(x.open=!0,w&&a("body").css("overflow","hidden").css("padding-right","+="+d()),t(),l.on("click."+x.id+" focusin."+x.id,function(a){var b=e(a,h);a.isSimulated||b==h||b==document||3==a.which||C.close(b===C.$holder[0])}).on("keydown."+x.id,function(c){var d=c.keyCode,f=C.component.key[d],g=e(c,h);27==d?C.close(!0):g!=C.$holder[0]||!f&&13!=d?a.contains(C.$root[0],g)&&13==d&&(c.preventDefault(),g.click()):(c.preventDefault(),f?b._.trigger(C.component.key.go,C,[b._.trigger(f)]):C.$root.find("."+z.highlighted).hasClass(z.disabled)||(C.set("select",C.component.item.highlight),y.closeOnSelect&&C.close(!0)))})),C.trigger("open"))},close:function(b){return b&&(y.editable?h.focus():(C.$holder.off("focus.toOpen").focus(),setTimeout(function(){C.$holder.on("focus.toOpen",u)},0))),A.removeClass(z.active),g(h,"expanded",!1),setTimeout(function(){C.$root.removeClass(z.opened+" "+z.focused),g(C.$root[0],"hidden",!0)},0),x.open?(x.open=!1,w&&a("body").css("overflow","").css("padding-right","-="+d()),l.off("."+x.id),C.trigger("close")):C},clear:function(a){return C.set("clear",null,a)},set:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(d=g&&a.isPlainObject(c)?c:d||{},b){g||(h[b]=c);for(e in h)f=h[e],e in C.component.item&&(void 0===f&&(f=null),C.component.set(e,f,d)),"select"!=e&&"clear"!=e||!y.updateInput||A.val("clear"==e?"":C.get(e,y.format)).trigger("change");C.render()}return d.muted?C:C.trigger("set",h)},get:function(a,c){if(a=a||"value",null!=x[a])return x[a];if("valueSubmit"==a){if(C._hidden)return C._hidden.value;a="value"}if("value"==a)return h.value;if(a in C.component.item){if("string"==typeof c){var d=C.component.get(a);return d?b._.trigger(C.component.formats.toString,C.component,[c,d]):""}return C.component.get(a)}},on:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(b){g||(h[b]=c);for(e in h)f=h[e],d&&(e="_"+e),x.methods[e]=x.methods[e]||[],x.methods[e].push(f)}return C},off:function(){var a,b,c=arguments;for(a=0,namesCount=c.length;a<namesCount;a+=1)(b=c[a])in x.methods&&delete x.methods[b];return C},trigger:function(a,c){var d=function(a){var d=x.methods[a];d&&d.map(function(a){b._.trigger(a,C,[c])})};return d("_"+a),d(a),C}};return new B}function c(a){var b,c="position";return a.currentStyle?b=a.currentStyle[c]:window.getComputedStyle&&(b=getComputedStyle(a)[c]),"fixed"==b}function d(){if(m.height()<=k.height())return 0;var b=a('<div style="visibility:hidden;width:100px" />').appendTo("body"),c=b[0].offsetWidth;b.css("overflow","scroll");var d=a('<div style="width:100%" />').appendTo(b),e=d[0].offsetWidth;return b.remove(),c-e}function e(a,b){var c=[];return a.path&&(c=a.path),a.originalEvent&&a.originalEvent.path&&(c=a.originalEvent.path),c&&c.length>0?b&&c.indexOf(b)>=0?b:c[0]:a.target}function f(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,c||a.apply(e,f)},h=c&&!d;clearTimeout(d),d=setTimeout(g,b),h&&a.apply(e,f)}}function g(b,c,d){if(a.isPlainObject(c))for(var e in c)h(b,e,c[e]);else h(b,c,d)}function h(a,b,c){a.setAttribute(("role"==b?"":"aria-")+b,c)}function i(b,c){a.isPlainObject(b)||(b={attribute:c}),c="";for(var d in b){var e=("role"==d?"":"aria-")+d;c+=null==b[d]?"":e+'="'+b[d]+'"'}return c}function j(){try{return document.activeElement}catch(a){}}var k=a(window),l=a(document),m=a(document.documentElement),n=null!=document.documentElement.style.transition;return b.klasses=function(a){return a=a||"picker",{picker:a,opened:a+"--opened",focused:a+"--focused",input:a+"__input",active:a+"__input--active",target:a+"__input--target",holder:a+"__holder",frame:a+"__frame",wrap:a+"__wrap",box:a+"__box"}},b._={group:function(a){for(var c,d="",e=b._.trigger(a.min,a);e<=b._.trigger(a.max,a,[e]);e+=a.i)c=b._.trigger(a.item,a,[e]),d+=b._.node(a.node,c[0],c[1],c[2]);return d},node:function(b,c,d,e){return c?(c=a.isArray(c)?c.join(""):c,d=d?' class="'+d+'"':"",e=e?" "+e:"","<"+b+d+e+">"+c+"</"+b+">"):""},lead:function(a){return(a<10?"0":"")+a},trigger:function(a,b,c){return"function"==typeof a?a.apply(b,c||[]):a},digits:function(a){return/\d/.test(a[1])?2:1},isDate:function(a){return{}.toString.call(a).indexOf("Date")>-1&&this.isInteger(a.getDate())},isInteger:function(a){return{}.toString.call(a).indexOf("Number")>-1&&a%1==0},ariaAttr:i},b.extend=function(c,d){a.fn[c]=function(e,f){var g=this.data(c);return"picker"==e?g:g&&"string"==typeof e?b._.trigger(g[e],g,[f]):this.each(function(){a(this).data(c)||new b(this,c,d,e)})},a.fn[c].defaults=d.defaults},b});
1
+ /*!
2
+ * pickadate.js v3.6.1, 2019/03/15
3
+ * By Amsul, http://amsul.ca
4
+ * Hosted on http://amsul.github.io/pickadate.js
5
+ * Licensed under MIT
6
+ */
7
  !function(a){"function"==typeof define&&define.amd?define("picker",["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):this.Picker=a(jQuery)}(function(a){function b(h,i,k,m){function o(){return b._.node("div",b._.node("div",b._.node("div",b._.node("div",C.component.nodes(x.open),z.box),z.wrap),z.frame),z.holder,'tabindex="-1"')}function p(){A.data(i,C).addClass(z.input).val(A.data("value")?C.get("select",y.format):h.value).on("focus."+x.id+" click."+x.id,f(function(a){a.preventDefault(),C.open()},50)),y.editable||A.on("keydown."+x.id,v),g(h,{haspopup:!0,expanded:!1,readonly:!1,owns:h.id+"_root"})}function q(){g(C.$root[0],"hidden",!0)}function r(){C.$holder.on({keydown:v,"focus.toOpen":u,blur:function(){A.removeClass(z.target)},focusin:function(a){C.$root.removeClass(z.focused),a.stopPropagation()},"mousedown click":function(b){var c=e(b,h);c!=C.$holder[0]&&(b.stopPropagation(),"mousedown"!=b.type||a(c).is("input, select, textarea, button, option")||(b.preventDefault(),C.$holder.eq(0).focus()))}}).on("click","[data-pick], [data-nav], [data-clear], [data-close]",function(){var b=a(this),c=b.data(),d=b.hasClass(z.navDisabled)||b.hasClass(z.disabled),e=j();e=e&&(e.type||e.href?e:null),(d||e&&!a.contains(C.$root[0],e))&&C.$holder.eq(0).focus(),!d&&c.nav?C.set("highlight",C.component.item.highlight,{nav:c.nav}):!d&&"pick"in c?(C.set("select",c.pick),y.closeOnSelect&&C.close(!0)):c.clear?(C.clear(),y.closeOnClear&&C.close(!0)):c.close&&C.close(!0)})}function s(){var b;!0===y.hiddenName?(b=h.name,h.name=""):(b=["string"==typeof y.hiddenPrefix?y.hiddenPrefix:"","string"==typeof y.hiddenSuffix?y.hiddenSuffix:"_submit"],b=b[0]+h.name+b[1]),C._hidden=a('<input type=hidden name="'+b+'"'+(A.data("value")||h.value?' value="'+C.get("select",y.formatSubmit)+'"':"")+">")[0],A.on("change."+x.id,function(){C._hidden.value=h.value?C.get("select",y.formatSubmit):""})}function t(){w&&n?C.$holder.find("."+z.frame).one("transitionend",function(){C.$holder.eq(0).focus()}):setTimeout(function(){C.$holder.eq(0).focus()},0)}function u(a){a.stopPropagation(),A.addClass(z.target),C.$root.addClass(z.focused),C.open()}function v(a){var b=a.keyCode,c=/^(8|46)$/.test(b);if(27==b)return C.close(!0),!1;(32==b||c||!x.open&&C.component.key[b])&&(a.preventDefault(),a.stopPropagation(),c?C.clear().close():C.open())}if(!h)return b;var w=!1,x={id:h.id||"P"+Math.abs(~~(Math.random()*new Date))},y=k?a.extend(!0,{},k.defaults,m):m||{},z=a.extend({},b.klasses(),y.klass),A=a(h),B=function(){return this.start()},C=B.prototype={constructor:B,$node:A,start:function(){return x&&x.start?C:(x.methods={},x.start=!0,x.open=!1,x.type=h.type,h.autofocus=h==j(),h.readOnly=!y.editable,h.id=h.id||x.id,"text"!=h.type&&(h.type="text"),C.component=new k(C,y),C.$root=a('<div class="'+z.picker+'" id="'+h.id+'_root" />'),q(),C.$holder=a(o()).appendTo(C.$root),r(),y.formatSubmit&&s(),p(),y.containerHidden?a(y.containerHidden).append(C._hidden):A.after(C._hidden),y.container?a(y.container).append(C.$root):A.after(C.$root),C.on({start:C.component.onStart,render:C.component.onRender,stop:C.component.onStop,open:C.component.onOpen,close:C.component.onClose,set:C.component.onSet}).on({start:y.onStart,render:y.onRender,stop:y.onStop,open:y.onOpen,close:y.onClose,set:y.onSet}),w=c(C.$holder[0]),h.autofocus&&C.open(),C.trigger("start").trigger("render"))},render:function(b){return b?(C.$holder=a(o()),r(),C.$root.html(C.$holder)):C.$root.find("."+z.box).html(C.component.nodes(x.open)),C.trigger("render")},stop:function(){return x.start?(C.close(),C._hidden&&C._hidden.parentNode.removeChild(C._hidden),C.$root.remove(),A.removeClass(z.input).removeData(i),setTimeout(function(){A.off("."+x.id)},0),h.type=x.type,h.readOnly=!1,C.trigger("stop"),x.methods={},x.start=!1,C):C},open:function(c){return x.open?C:(A.addClass(z.active),g(h,"expanded",!0),setTimeout(function(){C.$root.addClass(z.opened),g(C.$root[0],"hidden",!1)},0),!1!==c&&(x.open=!0,w&&a("body").css("overflow","hidden").css("padding-right","+="+d()),t(),l.on("click."+x.id+" focusin."+x.id,function(a){var b=e(a,h);a.isSimulated||b==h||b==document||3==a.which||C.close(b===C.$holder[0])}).on("keydown."+x.id,function(c){var d=c.keyCode,f=C.component.key[d],g=e(c,h);27==d?C.close(!0):g!=C.$holder[0]||!f&&13!=d?a.contains(C.$root[0],g)&&13==d&&(c.preventDefault(),g.click()):(c.preventDefault(),f?b._.trigger(C.component.key.go,C,[b._.trigger(f)]):C.$root.find("."+z.highlighted).hasClass(z.disabled)||(C.set("select",C.component.item.highlight),y.closeOnSelect&&C.close(!0)))})),C.trigger("open"))},close:function(b){return b&&(y.editable?h.focus():(C.$holder.off("focus.toOpen").focus(),setTimeout(function(){C.$holder.on("focus.toOpen",u)},0))),A.removeClass(z.active),g(h,"expanded",!1),setTimeout(function(){C.$root.removeClass(z.opened+" "+z.focused),g(C.$root[0],"hidden",!0)},0),x.open?(x.open=!1,w&&a("body").css("overflow","").css("padding-right","-="+d()),l.off("."+x.id),C.trigger("close")):C},clear:function(a){return C.set("clear",null,a)},set:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(d=g&&a.isPlainObject(c)?c:d||{},b){g||(h[b]=c);for(e in h)f=h[e],e in C.component.item&&(void 0===f&&(f=null),C.component.set(e,f,d)),"select"!=e&&"clear"!=e||!y.updateInput||A.val("clear"==e?"":C.get(e,y.format)).trigger("change");C.render()}return d.muted?C:C.trigger("set",h)},get:function(a,c){if(a=a||"value",null!=x[a])return x[a];if("valueSubmit"==a){if(C._hidden)return C._hidden.value;a="value"}if("value"==a)return h.value;if(a in C.component.item){if("string"==typeof c){var d=C.component.get(a);return d?b._.trigger(C.component.formats.toString,C.component,[c,d]):""}return C.component.get(a)}},on:function(b,c,d){var e,f,g=a.isPlainObject(b),h=g?b:{};if(b){g||(h[b]=c);for(e in h)f=h[e],d&&(e="_"+e),x.methods[e]=x.methods[e]||[],x.methods[e].push(f)}return C},off:function(){var a,b,c=arguments;for(a=0,namesCount=c.length;a<namesCount;a+=1)(b=c[a])in x.methods&&delete x.methods[b];return C},trigger:function(a,c){var d=function(a){var d=x.methods[a];d&&d.map(function(a){b._.trigger(a,C,[c])})};return d("_"+a),d(a),C}};return new B}function c(a){var b,c="position";return a.currentStyle?b=a.currentStyle[c]:window.getComputedStyle&&(b=getComputedStyle(a)[c]),"fixed"==b}function d(){if(m.height()<=k.height())return 0;var b=a('<div style="visibility:hidden;width:100px" />').appendTo("body"),c=b[0].offsetWidth;b.css("overflow","scroll");var d=a('<div style="width:100%" />').appendTo(b),e=d[0].offsetWidth;return b.remove(),c-e}function e(a,b){var c=[];return a.path&&(c=a.path),a.originalEvent&&a.originalEvent.path&&(c=a.originalEvent.path),c&&c.length>0?b&&c.indexOf(b)>=0?b:c[0]:a.target}function f(a,b,c){var d;return function(){var e=this,f=arguments,g=function(){d=null,c||a.apply(e,f)},h=c&&!d;clearTimeout(d),d=setTimeout(g,b),h&&a.apply(e,f)}}function g(b,c,d){if(a.isPlainObject(c))for(var e in c)h(b,e,c[e]);else h(b,c,d)}function h(a,b,c){a.setAttribute(("role"==b?"":"aria-")+b,c)}function i(b,c){a.isPlainObject(b)||(b={attribute:c}),c="";for(var d in b){var e=("role"==d?"":"aria-")+d;c+=null==b[d]?"":e+'="'+b[d]+'"'}return c}function j(){try{return document.activeElement}catch(a){}}var k=a(window),l=a(document),m=a(document.documentElement),n=null!=document.documentElement.style.transition;return b.klasses=function(a){return a=a||"picker",{picker:a,opened:a+"--opened",focused:a+"--focused",input:a+"__input",active:a+"__input--active",target:a+"__input--target",holder:a+"__holder",frame:a+"__frame",wrap:a+"__wrap",box:a+"__box"}},b._={group:function(a){for(var c,d="",e=b._.trigger(a.min,a);e<=b._.trigger(a.max,a,[e]);e+=a.i)c=b._.trigger(a.item,a,[e]),d+=b._.node(a.node,c[0],c[1],c[2]);return d},node:function(b,c,d,e){return c?(c=a.isArray(c)?c.join(""):c,d=d?' class="'+d+'"':"",e=e?" "+e:"","<"+b+d+e+">"+c+"</"+b+">"):""},lead:function(a){return(a<10?"0":"")+a},trigger:function(a,b,c){return"function"==typeof a?a.apply(b,c||[]):a},digits:function(a){return/\d/.test(a[1])?2:1},isDate:function(a){return{}.toString.call(a).indexOf("Date")>-1&&this.isInteger(a.getDate())},isInteger:function(a){return{}.toString.call(a).indexOf("Number")>-1&&a%1==0},ariaAttr:i},b.extend=function(c,d){a.fn[c]=function(e,f){var g=this.data(c);return"picker"==e?g:g&&"string"==typeof e?b._.trigger(g[e],g,[f]):this.each(function(){a(this).data(c)||new b(this,c,d,e)})},a.fn[c].defaults=d.defaults},b});
lib/simple-admin-pages/lib/pickadate/picker.time.js CHANGED
@@ -1,5 +1,5 @@
1
- /*!
2
- * Time picker for pickadate.js v3.6.1
3
- * http://amsul.github.io/pickadate.js/time.htm
4
- */
5
  !function(a){"function"==typeof define&&define.amd?define(["./picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0].value,e=a.$node.data("value"),f=e||d,g=e?b.formatSubmit:b.format;c.settings=b,c.$node=a.$node,c.queue={interval:"i",min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse create validate",view:"parse create validate",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.interval=b.interval||30,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return!0===a[0]?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),f?c.set("select",f,{format:g}):c.set("select",null).set("highlight",c.item.now),c.key={40:1,38:-1,39:1,37:-1,go:function(a){c.set("highlight",c.item.highlight.pick+a*c.item.interval,{interval:a*c.item.interval}),this.render()}},a.on("render",function(){var c=a.$root.children(),d=c.find("."+b.klass.viewset),e=function(a){return["webkit","moz","ms","o",""].map(function(b){return(b?"-"+b+"-":"")+a})},f=function(a,b){e("transform").map(function(c){a.css(c,b)}),e("transition").map(function(c){a.css(c,b)})};d.length&&(f(c,"none"),c[0].scrollTop=~~d.position().top-2*d[0].clientHeight,f(c,""))},1).on("open",function(){a.$root.find("button").attr("disabled",!1)},1).on("close",function(){a.$root.find("button").attr("disabled",!0)},1)}var d=24,e=60,f=12,g=d*e,h=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):"interval"==a?d.set("min",e.min,c).set("max",e.max,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",b,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",b,c),"min"==a&&d.set("max",e.max,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,f){var i=this;return c=void 0===c?a:c,h.isDate(c)&&(c=[c.getHours(),c.getMinutes()]),b.isPlainObject(c)&&h.isInteger(c.pick)?c=c.pick:b.isArray(c)?c=+c[0]*e+ +c[1]:h.isInteger(c)||(c=i.now(a,c,f)),"max"==a&&c<i.item.min.pick&&(c+=g),"min"!=a&&"max"!=a&&(c-i.item.min.pick)%i.item.interval!=0&&(c+=i.item.interval),c=i.normalize(a,c,f),{hour:~~(d+c/e)%d,mins:(e+c%e)%e,time:(g+c)%g,pick:c%g}},c.prototype.createRange=function(a,c){var d=this,e=function(a){return!0===a||b.isArray(a)||h.isDate(a)?d.create(a):a};return h.isInteger(a)||(a=e(a)),h.isInteger(c)||(c=e(c)),h.isInteger(a)&&b.isPlainObject(c)?a=[c.hour,c.mins+a*d.settings.interval]:h.isInteger(c)&&b.isPlainObject(a)&&(c=[a.hour,a.mins+c*d.settings.interval]),{from:e(a),to:e(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b){var c,d=this.item.interval,f=new Date,g=f.getHours()*e+f.getMinutes(),i=h.isInteger(b);return g-=g%d,c=b<0&&d*b+g<=-d,g+="min"==a&&c?0:d,i&&(g+=d*(c&&"max"!=a?b+1:b)),g},c.prototype.normalize=function(a,b){var c=this.item.interval,d=this.item.min&&this.item.min.pick||0;return b-="min"==a?0:(b-d)%c},c.prototype.measure=function(a,c,f){var g=this;return c||(c="min"==a?[0,0]:[d-1,e-1]),"string"==typeof c?c=g.parse(a,c):!0===c||h.isInteger(c)?c=g.now(a,c,f):b.isPlainObject(c)&&h.isInteger(c.pick)&&(c=g.normalize(a,c.pick,f)),c},c.prototype.validate=function(a,b,c){var d=this,e=c&&c.interval?c.interval:d.item.interval;return d.disabled(b)&&(b=d.shift(b,e)),b=d.scope(b),d.disabled(b)&&(b=d.shift(b,-1*e)),b},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return h.isInteger(d)?a.hour==d:b.isArray(d)||h.isDate(d)?a.pick==c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[2]||b.isPlainObject(a)&&a.inverted}).length,-1===c.item.enable?!d:d||a.pick<c.item.min.pick||a.pick>c.item.max.pick},c.prototype.shift=function(a,b){var c=this,d=c.item.min.pick,e=c.item.max.pick;for(b=b||c.item.interval;c.disabled(a)&&(a=c.create(a.pick+=b),!(a.pick<=d||a.pick>=e)););return a},c.prototype.scope=function(a){var b=this.item.min.pick,c=this.item.max.pick;return this.create(a.pick>c?c:a.pick<b?b:a)},c.prototype.parse=function(a,b,c){var d,f,g,i,j,k=this,l={};if(!b||"string"!=typeof b)return b;c&&c.format||(c=c||{},c.format=k.settings.format),k.formats.toArray(c.format).map(function(a){var c,d=k.formats[a],e=d?h.trigger(d,k,[b,l]):a.replace(/^!/,"").length;d&&(c=b.substr(0,e),l[a]=c.match(/^\d+$/)?+c:c),b=b.substr(e)});for(i in l)j=l[i],h.isInteger(j)?i.match(/^(h|hh)$/i)?(d=j,"h"!=i&&"hh"!=i||(d%=12)):"i"==i&&(f=j):i.match(/^a$/i)&&j.match(/^p/i)&&("h"in l||"hh"in l)&&(g=!0);return(g?d+12:d)*e+f},c.prototype.formats={h:function(a,b){return a?h.digits(a):b.hour%f||f},hh:function(a,b){return a?2:h.lead(b.hour%f||f)},H:function(a,b){return a?h.digits(a):""+b.hour%24},HH:function(a,b){return a?h.digits(a):h.lead(b.hour%24)},i:function(a,b){return a?2:h.lead(b.mins)},a:function(a,b){return a?4:g/2>b.time%g?"a.m.":"p.m."},A:function(a,b){return a?2:g/2>b.time%g?"AM":"PM"},toArray:function(a){return a.split(/(h{1,2}|H{1,2}|i|a|A|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return h.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}},c.prototype.isTimeExact=function(a,c){var d=this;return h.isInteger(a)&&h.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(h.isDate(a)||b.isArray(a))&&(h.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&(d.isTimeExact(a.from,c.from)&&d.isTimeExact(a.to,c.to))},c.prototype.isTimeOverlap=function(a,c){var d=this;return h.isInteger(a)&&(h.isDate(c)||b.isArray(c))?a===d.create(c).hour:h.isInteger(c)&&(h.isDate(a)||b.isArray(a))?c===d.create(a).hour:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.overlapRanges(a,c)},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(-1==b.enable?1:-1)},c.prototype.deactivate=function(a,c){var d=this,e=d.item.disable.slice(0);return"flip"==c?d.flipEnable():!1===c?(d.flipEnable(1),e=[]):!0===c?(d.flipEnable(-1),e=[]):c.map(function(a){for(var c,f=0;f<e.length;f+=1)if(d.isTimeExact(a,e[f])){c=!0;break}c||(h.isInteger(a)||h.isDate(a)||b.isArray(a)||b.isPlainObject(a)&&a.from&&a.to)&&e.push(a)}),e},c.prototype.activate=function(a,c){var d=this,e=d.item.disable,f=e.length;return"flip"==c?d.flipEnable():!0===c?(d.flipEnable(1),e=[]):!1===c?(d.flipEnable(-1),e=[]):c.map(function(a){var c,g,i,j;for(i=0;i<f;i+=1){if(g=e[i],d.isTimeExact(g,a)){c=e[i]=null,j=!0;break}if(d.isTimeOverlap(g,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[2]||c.push("inverted")):h.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;i<f;i+=1)if(d.isTimeExact(e[i],a)){e[i]=null;break}if(j)for(i=0;i<f;i+=1)if(d.isTimeOverlap(e[i],a)){e[i]=null;break}c&&e.push(c)}),e.filter(function(a){return null!=a})},c.prototype.i=function(a,b){return h.isInteger(b)&&b>0?b:this.item.interval},c.prototype.nodes=function(a){var b=this,c=b.settings,d=b.item.select,e=b.item.highlight,f=b.item.view,g=b.item.disable;return h.node("ul",h.group({min:b.item.min.pick,max:b.item.max.pick,i:b.item.interval,node:"li",item:function(a){a=b.create(a);var i=a.pick,j=d&&d.pick==i,k=e&&e.pick==i,l=g&&b.disabled(a),m=h.trigger(b.formats.toString,b,[c.format,a]);return[h.trigger(b.formats.toString,b,[h.trigger(c.formatLabel,b,[a])||c.format,a]),function(a){return j&&a.push(c.klass.selected),k&&a.push(c.klass.highlighted),f&&f.pick==i&&a.push(c.klass.viewset),l&&a.push(c.klass.disabled),a.join(" ")}([c.klass.listItem]),"data-pick="+a.pick+" "+h.ariaAttr({role:"option",label:m,selected:!(!j||b.$node.val()!==m)||null,activedescendant:!!k||null,disabled:!!l||null})]}})+h.node("li",h.node("button",c.clear,c.klass.buttonClear,"type=button data-clear=1"+(a?"":" disabled")+" "+h.ariaAttr({controls:b.$node[0].id})),"",h.ariaAttr({role:"presentation"})),c.klass.list,h.ariaAttr({role:"listbox",controls:b.$node[0].id}))},c.defaults=function(a){return{clear:"Clear",format:"h:i A",interval:30,closeOnSelect:!0,closeOnClear:!0,updateInput:!0,klass:{picker:a+" "+a+"--time",holder:a+"__holder",list:a+"__list",listItem:a+"__list-item",disabled:a+"__list-item--disabled",selected:a+"__list-item--selected",highlighted:a+"__list-item--highlighted",viewset:a+"__list-item--viewset",now:a+"__list-item--now",buttonClear:a+"__button--clear"}}}(a.klasses().picker),a.extend("pickatime",c)});
1
+ /*!
2
+ * Time picker for pickadate.js v3.6.1
3
+ * http://amsul.github.io/pickadate.js/time.htm
4
+ */
5
  !function(a){"function"==typeof define&&define.amd?define(["./picker","jquery"],a):"object"==typeof exports?module.exports=a(require("./picker.js"),require("jquery")):a(Picker,jQuery)}(function(a,b){function c(a,b){var c=this,d=a.$node[0].value,e=a.$node.data("value"),f=e||d,g=e?b.formatSubmit:b.format;c.settings=b,c.$node=a.$node,c.queue={interval:"i",min:"measure create",max:"measure create",now:"now create",select:"parse create validate",highlight:"parse create validate",view:"parse create validate",disable:"deactivate",enable:"activate"},c.item={},c.item.clear=null,c.item.interval=b.interval||30,c.item.disable=(b.disable||[]).slice(0),c.item.enable=-function(a){return!0===a[0]?a.shift():-1}(c.item.disable),c.set("min",b.min).set("max",b.max).set("now"),f?c.set("select",f,{format:g}):c.set("select",null).set("highlight",c.item.now),c.key={40:1,38:-1,39:1,37:-1,go:function(a){c.set("highlight",c.item.highlight.pick+a*c.item.interval,{interval:a*c.item.interval}),this.render()}},a.on("render",function(){var c=a.$root.children(),d=c.find("."+b.klass.viewset),e=function(a){return["webkit","moz","ms","o",""].map(function(b){return(b?"-"+b+"-":"")+a})},f=function(a,b){e("transform").map(function(c){a.css(c,b)}),e("transition").map(function(c){a.css(c,b)})};d.length&&(f(c,"none"),c[0].scrollTop=~~d.position().top-2*d[0].clientHeight,f(c,""))},1).on("open",function(){a.$root.find("button").attr("disabled",!1)},1).on("close",function(){a.$root.find("button").attr("disabled",!0)},1)}var d=24,e=60,f=12,g=d*e,h=a._;c.prototype.set=function(a,b,c){var d=this,e=d.item;return null===b?("clear"==a&&(a="select"),e[a]=b,d):(e["enable"==a?"disable":"flip"==a?"enable":a]=d.queue[a].split(" ").map(function(e){return b=d[e](a,b,c)}).pop(),"select"==a?d.set("highlight",e.select,c):"highlight"==a?d.set("view",e.highlight,c):"interval"==a?d.set("min",e.min,c).set("max",e.max,c):a.match(/^(flip|min|max|disable|enable)$/)&&(e.select&&d.disabled(e.select)&&d.set("select",b,c),e.highlight&&d.disabled(e.highlight)&&d.set("highlight",b,c),"min"==a&&d.set("max",e.max,c)),d)},c.prototype.get=function(a){return this.item[a]},c.prototype.create=function(a,c,f){var i=this;return c=void 0===c?a:c,h.isDate(c)&&(c=[c.getHours(),c.getMinutes()]),b.isPlainObject(c)&&h.isInteger(c.pick)?c=c.pick:b.isArray(c)?c=+c[0]*e+ +c[1]:h.isInteger(c)||(c=i.now(a,c,f)),"max"==a&&c<i.item.min.pick&&(c+=g),"min"!=a&&"max"!=a&&(c-i.item.min.pick)%i.item.interval!=0&&(c+=i.item.interval),c=i.normalize(a,c,f),{hour:~~(d+c/e)%d,mins:(e+c%e)%e,time:(g+c)%g,pick:c%g}},c.prototype.createRange=function(a,c){var d=this,e=function(a){return!0===a||b.isArray(a)||h.isDate(a)?d.create(a):a};return h.isInteger(a)||(a=e(a)),h.isInteger(c)||(c=e(c)),h.isInteger(a)&&b.isPlainObject(c)?a=[c.hour,c.mins+a*d.settings.interval]:h.isInteger(c)&&b.isPlainObject(a)&&(c=[a.hour,a.mins+c*d.settings.interval]),{from:e(a),to:e(c)}},c.prototype.withinRange=function(a,b){return a=this.createRange(a.from,a.to),b.pick>=a.from.pick&&b.pick<=a.to.pick},c.prototype.overlapRanges=function(a,b){var c=this;return a=c.createRange(a.from,a.to),b=c.createRange(b.from,b.to),c.withinRange(a,b.from)||c.withinRange(a,b.to)||c.withinRange(b,a.from)||c.withinRange(b,a.to)},c.prototype.now=function(a,b){var c,d=this.item.interval,f=new Date,g=f.getHours()*e+f.getMinutes(),i=h.isInteger(b);return g-=g%d,c=b<0&&d*b+g<=-d,g+="min"==a&&c?0:d,i&&(g+=d*(c&&"max"!=a?b+1:b)),g},c.prototype.normalize=function(a,b){var c=this.item.interval,d=this.item.min&&this.item.min.pick||0;return b-="min"==a?0:(b-d)%c},c.prototype.measure=function(a,c,f){var g=this;return c||(c="min"==a?[0,0]:[d-1,e-1]),"string"==typeof c?c=g.parse(a,c):!0===c||h.isInteger(c)?c=g.now(a,c,f):b.isPlainObject(c)&&h.isInteger(c.pick)&&(c=g.normalize(a,c.pick,f)),c},c.prototype.validate=function(a,b,c){var d=this,e=c&&c.interval?c.interval:d.item.interval;return d.disabled(b)&&(b=d.shift(b,e)),b=d.scope(b),d.disabled(b)&&(b=d.shift(b,-1*e)),b},c.prototype.disabled=function(a){var c=this,d=c.item.disable.filter(function(d){return h.isInteger(d)?a.hour==d:b.isArray(d)||h.isDate(d)?a.pick==c.create(d).pick:b.isPlainObject(d)?c.withinRange(d,a):void 0});return d=d.length&&!d.filter(function(a){return b.isArray(a)&&"inverted"==a[2]||b.isPlainObject(a)&&a.inverted}).length,-1===c.item.enable?!d:d||a.pick<c.item.min.pick||a.pick>c.item.max.pick},c.prototype.shift=function(a,b){var c=this,d=c.item.min.pick,e=c.item.max.pick;for(b=b||c.item.interval;c.disabled(a)&&(a=c.create(a.pick+=b),!(a.pick<=d||a.pick>=e)););return a},c.prototype.scope=function(a){var b=this.item.min.pick,c=this.item.max.pick;return this.create(a.pick>c?c:a.pick<b?b:a)},c.prototype.parse=function(a,b,c){var d,f,g,i,j,k=this,l={};if(!b||"string"!=typeof b)return b;c&&c.format||(c=c||{},c.format=k.settings.format),k.formats.toArray(c.format).map(function(a){var c,d=k.formats[a],e=d?h.trigger(d,k,[b,l]):a.replace(/^!/,"").length;d&&(c=b.substr(0,e),l[a]=c.match(/^\d+$/)?+c:c),b=b.substr(e)});for(i in l)j=l[i],h.isInteger(j)?i.match(/^(h|hh)$/i)?(d=j,"h"!=i&&"hh"!=i||(d%=12)):"i"==i&&(f=j):i.match(/^a$/i)&&j.match(/^p/i)&&("h"in l||"hh"in l)&&(g=!0);return(g?d+12:d)*e+f},c.prototype.formats={h:function(a,b){return a?h.digits(a):b.hour%f||f},hh:function(a,b){return a?2:h.lead(b.hour%f||f)},H:function(a,b){return a?h.digits(a):""+b.hour%24},HH:function(a,b){return a?h.digits(a):h.lead(b.hour%24)},i:function(a,b){return a?2:h.lead(b.mins)},a:function(a,b){return a?4:g/2>b.time%g?"a.m.":"p.m."},A:function(a,b){return a?2:g/2>b.time%g?"AM":"PM"},toArray:function(a){return a.split(/(h{1,2}|H{1,2}|i|a|A|!.)/g)},toString:function(a,b){var c=this;return c.formats.toArray(a).map(function(a){return h.trigger(c.formats[a],c,[0,b])||a.replace(/^!/,"")}).join("")}},c.prototype.isTimeExact=function(a,c){var d=this;return h.isInteger(a)&&h.isInteger(c)||"boolean"==typeof a&&"boolean"==typeof c?a===c:(h.isDate(a)||b.isArray(a))&&(h.isDate(c)||b.isArray(c))?d.create(a).pick===d.create(c).pick:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&(d.isTimeExact(a.from,c.from)&&d.isTimeExact(a.to,c.to))},c.prototype.isTimeOverlap=function(a,c){var d=this;return h.isInteger(a)&&(h.isDate(c)||b.isArray(c))?a===d.create(c).hour:h.isInteger(c)&&(h.isDate(a)||b.isArray(a))?c===d.create(a).hour:!(!b.isPlainObject(a)||!b.isPlainObject(c))&&d.overlapRanges(a,c)},c.prototype.flipEnable=function(a){var b=this.item;b.enable=a||(-1==b.enable?1:-1)},c.prototype.deactivate=function(a,c){var d=this,e=d.item.disable.slice(0);return"flip"==c?d.flipEnable():!1===c?(d.flipEnable(1),e=[]):!0===c?(d.flipEnable(-1),e=[]):c.map(function(a){for(var c,f=0;f<e.length;f+=1)if(d.isTimeExact(a,e[f])){c=!0;break}c||(h.isInteger(a)||h.isDate(a)||b.isArray(a)||b.isPlainObject(a)&&a.from&&a.to)&&e.push(a)}),e},c.prototype.activate=function(a,c){var d=this,e=d.item.disable,f=e.length;return"flip"==c?d.flipEnable():!0===c?(d.flipEnable(1),e=[]):!1===c?(d.flipEnable(-1),e=[]):c.map(function(a){var c,g,i,j;for(i=0;i<f;i+=1){if(g=e[i],d.isTimeExact(g,a)){c=e[i]=null,j=!0;break}if(d.isTimeOverlap(g,a)){b.isPlainObject(a)?(a.inverted=!0,c=a):b.isArray(a)?(c=a,c[2]||c.push("inverted")):h.isDate(a)&&(c=[a.getFullYear(),a.getMonth(),a.getDate(),"inverted"]);break}}if(c)for(i=0;i<f;i+=1)if(d.isTimeExact(e[i],a)){e[i]=null;break}if(j)for(i=0;i<f;i+=1)if(d.isTimeOverlap(e[i],a)){e[i]=null;break}c&&e.push(c)}),e.filter(function(a){return null!=a})},c.prototype.i=function(a,b){return h.isInteger(b)&&b>0?b:this.item.interval},c.prototype.nodes=function(a){var b=this,c=b.settings,d=b.item.select,e=b.item.highlight,f=b.item.view,g=b.item.disable;return h.node("ul",h.group({min:b.item.min.pick,max:b.item.max.pick,i:b.item.interval,node:"li",item:function(a){a=b.create(a);var i=a.pick,j=d&&d.pick==i,k=e&&e.pick==i,l=g&&b.disabled(a),m=h.trigger(b.formats.toString,b,[c.format,a]);return[h.trigger(b.formats.toString,b,[h.trigger(c.formatLabel,b,[a])||c.format,a]),function(a){return j&&a.push(c.klass.selected),k&&a.push(c.klass.highlighted),f&&f.pick==i&&a.push(c.klass.viewset),l&&a.push(c.klass.disabled),a.join(" ")}([c.klass.listItem]),"data-pick="+a.pick+" "+h.ariaAttr({role:"option",label:m,selected:!(!j||b.$node.val()!==m)||null,activedescendant:!!k||null,disabled:!!l||null})]}})+h.node("li",h.node("button",c.clear,c.klass.buttonClear,"type=button data-clear=1"+(a?"":" disabled")+" "+h.ariaAttr({controls:b.$node[0].id})),"",h.ariaAttr({role:"presentation"})),c.klass.list,h.ariaAttr({role:"listbox",controls:b.$node[0].id}))},c.defaults=function(a){return{clear:"Clear",format:"h:i A",interval:30,closeOnSelect:!0,closeOnClear:!0,updateInput:!0,klass:{picker:a+" "+a+"--time",holder:a+"__holder",list:a+"__list",listItem:a+"__list-item",disabled:a+"__list-item--disabled",selected:a+"__list-item--selected",highlighted:a+"__list-item--highlighted",viewset:a+"__list-item--viewset",now:a+"__list-item--now",buttonClear:a+"__button--clear"}}}(a.klasses().picker),a.extend("pickatime",c)});
lib/simple-admin-pages/lib/pickadate/themes/default.css CHANGED
@@ -1,4 +1,4 @@
1
- .picker{font-size:16px;text-align:left;line-height:1.2;color:#000;position:absolute;z-index:10000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:0}.picker__input{cursor:default}.picker__input.picker__input--active{border-color:#0089ec}.picker__holder{width:100%;overflow-y:auto;-webkit-overflow-scrolling:touch;position:fixed;transition:background .15s ease-out,transform 0s .15s;-webkit-backface-visibility:hidden}/*!
2
- * Default mobile-first, responsive styling for pickadate.js
3
- * Demo: http://amsul.github.io/pickadate.js
4
  */.picker__frame,.picker__holder{top:0;bottom:0;left:0;right:0;-ms-transform:translateY(100%);transform:translateY(100%)}.picker__frame{position:absolute;margin:0 auto;min-width:256px;max-width:666px;width:100%;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);-moz-opacity:0;opacity:0;transition:all .15s ease-out}.picker__wrap{display:table;width:100%;height:100%}@media (min-height:33.875em){.picker__frame{overflow:visible;top:auto;bottom:-100%;max-height:80%}.picker__wrap{display:block}}.picker__box{background:#fff;display:table-cell;vertical-align:middle}@media (min-height:26.5em){.picker__box{font-size:1.25em}}@media (min-height:33.875em){.picker__box{display:block;font-size:1.33em;border:1px solid #777;border-top-color:#898989;border-bottom-width:0;border-radius:5px 5px 0 0;box-shadow:0 12px 36px 16px rgba(0,0,0,.24)}.picker--opened .picker__frame{top:auto;bottom:0}}@media (min-height:40.125em){.picker__frame{margin-bottom:7.5%}.picker__box{font-size:1.5em;border-bottom-width:1px;border-radius:5px}}.picker--opened .picker__holder{-ms-transform:translateY(0);transform:translateY(0);zoom:1;background:rgba(0,0,0,.32);transition:background .15s ease-out}.picker--opened .picker__frame{-ms-transform:translateY(0);transform:translateY(0);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);-moz-opacity:1;opacity:1}
1
+ .picker{font-size:16px;text-align:left;line-height:1.2;color:#000;position:absolute;z-index:10000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:0}.picker__input{cursor:default}.picker__input.picker__input--active{border-color:#0089ec}.picker__holder{width:100%;overflow-y:auto;-webkit-overflow-scrolling:touch;position:fixed;transition:background .15s ease-out,transform 0s .15s;-webkit-backface-visibility:hidden}/*!
2
+ * Default mobile-first, responsive styling for pickadate.js
3
+ * Demo: http://amsul.github.io/pickadate.js
4
  */.picker__frame,.picker__holder{top:0;bottom:0;left:0;right:0;-ms-transform:translateY(100%);transform:translateY(100%)}.picker__frame{position:absolute;margin:0 auto;min-width:256px;max-width:666px;width:100%;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);-moz-opacity:0;opacity:0;transition:all .15s ease-out}.picker__wrap{display:table;width:100%;height:100%}@media (min-height:33.875em){.picker__frame{overflow:visible;top:auto;bottom:-100%;max-height:80%}.picker__wrap{display:block}}.picker__box{background:#fff;display:table-cell;vertical-align:middle}@media (min-height:26.5em){.picker__box{font-size:1.25em}}@media (min-height:33.875em){.picker__box{display:block;font-size:1.33em;border:1px solid #777;border-top-color:#898989;border-bottom-width:0;border-radius:5px 5px 0 0;box-shadow:0 12px 36px 16px rgba(0,0,0,.24)}.picker--opened .picker__frame{top:auto;bottom:0}}@media (min-height:40.125em){.picker__frame{margin-bottom:7.5%}.picker__box{font-size:1.5em;border-bottom-width:1px;border-radius:5px}}.picker--opened .picker__holder{-ms-transform:translateY(0);transform:translateY(0);zoom:1;background:rgba(0,0,0,.32);transition:background .15s ease-out}.picker--opened .picker__frame{-ms-transform:translateY(0);transform:translateY(0);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);-moz-opacity:1;opacity:1}
lib/simple-admin-pages/lib/pickadate/themes/rtl.css CHANGED
@@ -1,3 +1,3 @@
1
- /*!
2
- * Styling for RTL (right-to-left) languages using pickadate.js
3
  */.picker{direction:rtl}.picker__nav--next{right:auto;left:-1em}.picker__nav--prev{left:auto;right:-1em}.picker__nav--next:before{border-left:0;border-right:.75em solid #000}.picker__nav--prev:before{border-right:0;border-left:.75em solid #000}
1
+ /*!
2
+ * Styling for RTL (right-to-left) languages using pickadate.js
3
  */.picker{direction:rtl}.picker__nav--next{right:auto;left:-1em}.picker__nav--prev{left:auto;right:-1em}.picker__nav--next:before{border-left:0;border-right:.75em solid #000}.picker__nav--prev:before{border-right:0;border-left:.75em solid #000}
lib/simple-admin-pages/simple-admin-pages.php CHANGED
@@ -1,52 +1,52 @@
1
- <?php
2
-
3
- /**
4
- * Simple Admin Pages
5
- *
6
- * This is a very small utility library to easily add new admin pages to the
7
- * WordPress admin interface. It simply collects WordPress' useful Settings API
8
- * into reuseable classes.
9
- *
10
- * Created by Nate Wright
11
- *
12
- *
13
- * @since 1.0
14
- * @package Simple Admin Pages
15
- * @license GNU GPL 2 or later
16
- */
17
-
18
- /**
19
- * Always load the library files attached to this copy of SAP
20
- *
21
- * This fixes a compatibility bug if two versions of the library are being
22
- * loaded by different plugins/themes. However, versions prior to 2.0 do not
23
- * include this and can cause compatibility issues.
24
- */
25
- require_once( 'classes/Library.class.php' );
26
-
27
- /**
28
- * Initialize the appropriate version of the libary.
29
- *
30
- * This function should remain backwards compatible at all times, so that the
31
- * initialization function from version 1.0 will still be able to initialize
32
- * the library appropriately for version 2.0. This way, if two plugins exist
33
- * with different versions, the plugin creator will still be able to initialize
34
- * their library.
35
- *
36
- * @since 1.0
37
- */
38
- if ( !function_exists( 'sap_initialize_library' ) ) {
39
-
40
- function sap_initialize_library( $args = array() ) {
41
-
42
- // Exit early if no version was provided
43
- if ( !isset( $args['version'] ) ) {
44
- return null;
45
- }
46
-
47
- $lib_class_name = 'sapLibrary_' . str_replace( '.', '_', $args['version'] );
48
-
49
- return new $lib_class_name( $args );
50
- }
51
-
52
- }
1
+ <?php
2
+
3
+ /**
4
+ * Simple Admin Pages
5
+ *
6
+ * This is a very small utility library to easily add new admin pages to the
7
+ * WordPress admin interface. It simply collects WordPress' useful Settings API
8
+ * into reuseable classes.
9
+ *
10
+ * Created by Nate Wright
11
+ *
12
+ *
13
+ * @since 1.0
14
+ * @package Simple Admin Pages
15
+ * @license GNU GPL 2 or later
16
+ */
17
+
18
+ /**
19
+ * Always load the library files attached to this copy of SAP
20
+ *
21
+ * This fixes a compatibility bug if two versions of the library are being
22
+ * loaded by different plugins/themes. However, versions prior to 2.0 do not
23
+ * include this and can cause compatibility issues.
24
+ */
25
+ require_once( 'classes/Library.class.php' );
26
+
27
+ /**
28
+ * Initialize the appropriate version of the libary.
29
+ *
30
+ * This function should remain backwards compatible at all times, so that the
31
+ * initialization function from version 1.0 will still be able to initialize
32
+ * the library appropriately for version 2.0. This way, if two plugins exist
33
+ * with different versions, the plugin creator will still be able to initialize
34
+ * their library.
35
+ *
36
+ * @since 1.0
37
+ */
38
+ if ( !function_exists( 'sap_initialize_library' ) ) {
39
+
40
+ function sap_initialize_library( $args = array() ) {
41
+
42
+ // Exit early if no version was provided
43
+ if ( !isset( $args['version'] ) ) {
44
+ return null;
45
+ }
46
+
47
+ $lib_class_name = 'sapLibrary_' . str_replace( '.', '_', $args['version'] );
48
+
49
+ return new $lib_class_name( $args );
50
+ }
51
+
52
+ }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Plugin URL: https://www.fivestarplugins.com/plugins/business-profile/
5
  Requires at Least: 5.3
6
  Tested Up To: 5.8
7
  Tags: business profile, seo, local seo, schema, address, google map, contact, phone, contact card, vcard, contact info, business location, business address, business map, business schema, organization schema, corporation schema, contact schema, address schema, location schema, map schema, business structured data, business microdata, address microdata, location structured data, location microdata, contact shortcode, location shortcode, address shortcode, schema shortcode, gutenberg schema, gutenberg address
8
- Stable tag: 2.1.4
9
  License: GPLv3
10
  License URI:http://www.gnu.org/licenses/gpl-3.0.html
11
 
@@ -192,6 +192,14 @@ You'll find more help in the [User Guide](http://doc.themeofthecrop.com/plugins/
192
 
193
  == Changelog ==
194
 
 
 
 
 
 
 
 
 
195
  = 2.1.4 (2021-07-21) =
196
  - The plugin has been tested up to WordPress version 5.8.
197
 
5
  Requires at Least: 5.3
6
  Tested Up To: 5.8
7
  Tags: business profile, seo, local seo, schema, address, google map, contact, phone, contact card, vcard, contact info, business location, business address, business map, business schema, organization schema, corporation schema, contact schema, address schema, location schema, map schema, business structured data, business microdata, address microdata, location structured data, location microdata, contact shortcode, location shortcode, address shortcode, schema shortcode, gutenberg schema, gutenberg address
8
+ Stable tag: 2.1.5
9
  License: GPLv3
10
  License URI:http://www.gnu.org/licenses/gpl-3.0.html
11
 
192
 
193
  == Changelog ==
194
 
195
+ = 2.1.5 (2021-09-30) =
196
+ - Updated the settings page library.
197
+ - Updated name of templates folder for consistent prefixing.
198
+ - Added an option so that, if you offer online ordering, you can enter the URL of your order page (can be on the same site or external) and a link to it will display in your contact card.
199
+ - Past exceptions no longer show in the schedule/opening hours, and are now automatically removed when the options are saved.
200
+ - Added "Image URL" field to the list of elements on the schema create/edit screen for the Organization schema type.
201
+ - Moved contact card block into its own category/section.
202
+
203
  = 2.1.4 (2021-07-21) =
204
  - The plugin has been tested up to WordPress version 5.8.
205