Events Manager - Version 5.9.9

Version Description

  • updated EM_DateTime and EM_DateTimeZone to remove PHP <5.3 backports and also make use of UTC offset support since PHP 5.5.10 (since WP now is requiring 5.6 as a minimum)
  • fixed location dropdown not showing option for no location or a placeholder if physical locations are the only location types enabled
  • fixed front-end event editor showing events list rather than submission form when there's a validation error
  • fixed bug where re-saving multilingual recurring events sets parent ids out of sync and causing booking linking issues with translated events
  • fixed potential minor CSRF vulnerability in oAuth base class where state could be ommitted when verifying/authorizing account, props to @Lenon
  • fixed event times output on bookings table not showing time according to formatting settings
  • added 5th argument with array of segmented placeholder meta to _output_placeholder filters of events, locations, bookings and taxonomies
  • tweaked placeholder regex to allow underscores in placeholder names e.g. #PREVIOUSLY_INVALIDPLACEHOLDER
  • added _SITE time-related placeholder variations which display event time relative to website timezone,
  • added _LOCAL time-related placeholder variations which display event time relative to user's browser timezone (based on JS),
  • fixed EM_Event::output_times() not using custom $all_day_message
  • fixed booking table custom fields with accented names not being displayed or exported properly
  • updated jQuery UI CSS theme
  • updated PHPMailer loading location due to breaks in 5.5
  • added #EVENTDATESLOCAL
  • updated placeholder docs
  • fixed save and status change filters firing before emails are sent which can cause irregular behaviour in add-ons (e.g. Zoom join links)
  • optimized EM_Bookings::has_booking() function to prevent unecessary loading of bookings to event
  • fixed fatal errors on ical generation if mb_string extension disabled in PHP
  • added em_bp_menu_sub_nav and em_bp_menu_main_nav filters to allow easy BuddyPress/BuddyBoss menu overriding
  • added data deletion and warning of deletion when switching location types,
  • moved JS out of location selection template into main JS file
  • changed Event_Location data handling so that event location data is kept within the object EM_Event->event_location rather than in EM_Event->event_location_data
  • fixed Event_Locations::is_enabled() creating fatal errors if add-on event location plugins get deactivated whilst event location is still 'enabled' in settings
  • fixed deletion of previous event location data occurring on get_post() rather than save() and added a temporary event_location_deleted property to EM_Event to contain deletable event location
  • changed recurring table field to require a non-null value and default to 0 to prevent erratic behaviour if recurrences get saved with NULL in random edge cases
  • removed some old migration update code for v4 > v5 update (more to be removed at a later date)
  • added em_event_save_events_exclude_update_meta_keys allowing add-ons to prevent overwriting meta keys when updating recurrences
  • added docs for event location types and a filter for adding custom placeholder docs to the help page
  • fixed dates and possibly other placeholders not showing in site locale if admin triggers emails with a different user locale
  • fixed scope search issues on search form when default scope is not 'future' and search dates left blank
  • fixed template location typo preventing em_get_events_list_grouped() from working
  • fixed admin columns not showing as per screen reader preferences when all cols are chosen to be displayed
  • fixed bp showing booking tab/info when bookings are disabled (props @raruto)
  • fixed display issues on static home page (other than EM events page) containing shortcode showing paginated events/locations/taxonomies
  • fixed broken link for datepicker formatting docs on settings page
  • fixed PHP errors on BuddyPress "my group events" template
  • added #_BOOKINGADMINURL and #_BOOKINGADMINLINK placeholders to booking email templates
  • added alt attribute to event thumbnails in MS Globals mode
  • fixed Polish zloty missing symbols
  • fixed 'no location' option not showing if dropdown option for physical locations enabled
  • fixed booking cutoff times defaulting to 12am rather than event start time
  • fixed booking cutoff times not getting set upon initial recurring event creation
  • fixed trashed events showing up on front-end event editor as pending
  • fixed JS issues causing ticket editor not reflecting changes during edit process before saving
  • fixed Yoast SEO deprecated log warning for usage of WPSEO_Utils::get_title_separator() in > v15.2
  • changed default time to WP format upon installation
  • added my/all events links to front-end events admin for those with admin capabilities
  • updated dev update checker to allow EM add-ons
  • fixed duplication issues for custom event locations due to lack of cloning the event location within the cloned event
  • added organizer property to ical feed and em_locate_template_args_... filter to enable it with (see https://pastebin.com/d2y5qXPy)
  • added better booking button error feedback and a em_booking_button_response JS event
  • changed EM Pro update warning to be dismissible site-wide and persist only on admin/network settings page
  • removed use of date_i18n() in place of EM_DateTime->format() i.e. wp_date()
Download this release

Release Info

Developer netweblogic
Plugin Icon 128x128 Events Manager
Version 5.9.9
Comparing to
See all releases

Code changes from version 5.9.8.1 to 5.9.9

Files changed (56) hide show
  1. admin/bookings/em-events.php +1 -1
  2. admin/em-admin.php +18 -10
  3. admin/em-docs.php +41 -4
  4. admin/em-help.php +3 -1
  5. admin/em-ms-options.php +2 -1
  6. admin/em-options.php +2 -0
  7. admin/settings/tabs/formats.php +1 -1
  8. admin/settings/tabs/general.php +1 -2
  9. buddypress/bp-em-core.php +14 -9
  10. classes/em-admin-notice.php +3 -1
  11. classes/em-booking.php +25 -8
  12. classes/em-bookings-table.php +5 -1
  13. classes/em-bookings.php +9 -6
  14. classes/em-datetime.php +54 -363
  15. classes/em-datetimezone.php +83 -0
  16. classes/em-event-posts-admin.php +7 -7
  17. classes/em-event.php +223 -55
  18. classes/em-location-posts-admin.php +2 -2
  19. classes/em-location.php +22 -11
  20. classes/em-mailer.php +4 -3
  21. classes/em-oauth/oauth-admin-settings.php +1 -1
  22. classes/em-oauth/oauth-api.php +1 -1
  23. classes/em-object.php +3 -3
  24. classes/em-people.php +1 -1
  25. classes/em-permalinks.php +6 -2
  26. classes/em-taxonomy-term.php +4 -2
  27. classes/em-ticket.php +12 -3
  28. classes/event-locations/em-event-location-url.php +4 -4
  29. classes/event-locations/em-event-location.php +51 -18
  30. classes/event-locations/em-event-locations.php +1 -1
  31. em-actions.php +4 -2
  32. em-events.php +2 -2
  33. em-functions.php +3 -3
  34. em-ical.php +1 -1
  35. em-install.php +33 -24
  36. em-template-tags.php +5 -2
  37. events-manager.php +5 -3
  38. includes/css/events_manager.css +16 -3
  39. includes/css/events_manager_admin.css +10 -0
  40. includes/css/jquery-ui.css +384 -297
  41. includes/css/jquery-ui.min.css +5 -5
  42. includes/js/events-manager.js +88 -9
  43. multilingual/em-ml-admin.php +9 -2
  44. multilingual/em-ml-io.php +9 -1
  45. multilingual/em-ml-options.php +1 -1
  46. readme.txt +57 -1
  47. templates/buddypress/my-group-events.php +19 -19
  48. templates/buddypress/profile.php +16 -14
  49. templates/forms/event/bookings.php +1 -1
  50. templates/forms/event/event-locations/url.php +2 -2
  51. templates/forms/event/location.php +20 -20
  52. templates/tables/events.php +25 -16
  53. templates/tables/locations.php +17 -5
  54. templates/templates/calendar-full.php +8 -7
  55. templates/templates/calendar-small.php +6 -7
  56. templates/templates/ical.php +9 -0
admin/bookings/em-events.php CHANGED
@@ -120,7 +120,7 @@ function em_bookings_events_table() {
120
  </td>
121
 
122
  <td>
123
- <?php echo $EM_Event->output_dates(false, " - "). ' @ ' . $EM_Event->output_times('H:i', ' - '); ?>
124
  </td>
125
  </tr>
126
  <?php
120
  </td>
121
 
122
  <td>
123
+ <?php echo $EM_Event->output_dates(false, " - "). ' @ ' . $EM_Event->output_times(false, ' - '); ?>
124
  </td>
125
  </tr>
126
  <?php
admin/em-admin.php CHANGED
@@ -164,14 +164,6 @@ function em_admin_warnings() {
164
  <?php
165
  }
166
  }
167
-
168
- if( defined('EMP_VERSION') && EMP_VERSION < EM_PRO_MIN_VERSION && !defined('EMP_DISABLE_WARNINGS')){
169
- ?>
170
- <div id="em_page_error" class="updated">
171
- <p><?php _e('There is a newer version of Events Manager Pro which is recommended for this current version of Events Manager as new features have been added. Please go to the plugin website and download the latest update.','events-manager'); ?></p>
172
- </div>
173
- <?php
174
- }
175
 
176
  if( is_multisite() && !empty($_REQUEST['page']) && $_REQUEST['page']=='events-manager-options' && em_wp_is_super_admin() && get_option('dbem_ms_update_nag') ){
177
  if( !empty($_GET['disable_dbem_ms_update_nag']) ){
@@ -265,7 +257,7 @@ function em_updates_check( $transient ) {
265
  //only bother if we're checking for dev versions
266
  if( get_option('em_check_dev_version') || get_option('dbem_pro_dev_updates') ){
267
  //check WP repo for trunk version
268
- $request = wp_remote_get('http://plugins.svn.wordpress.org/events-manager/trunk/events-manager.php');
269
 
270
  if( !is_wp_error($request) ){
271
  preg_match('/Version: ([0-9a-z\.]+)/', $request['body'], $matches);
@@ -288,7 +280,7 @@ function em_updates_check( $transient ) {
288
 
289
  return $transient;
290
  }
291
- add_filter('pre_set_site_transient_update_plugins', 'em_updates_check'); // Hook into the plugin update check and mod for dev version
292
 
293
  function em_user_action_links( $actions, $user ){
294
  if ( !is_network_admin() && current_user_can( 'manage_others_bookings' ) ){
@@ -303,4 +295,20 @@ function em_user_action_links( $actions, $user ){
303
  return $actions;
304
  }
305
  add_filter('user_row_actions','em_user_action_links',10,2);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  ?>
164
  <?php
165
  }
166
  }
 
 
 
 
 
 
 
 
167
 
168
  if( is_multisite() && !empty($_REQUEST['page']) && $_REQUEST['page']=='events-manager-options' && em_wp_is_super_admin() && get_option('dbem_ms_update_nag') ){
169
  if( !empty($_GET['disable_dbem_ms_update_nag']) ){
257
  //only bother if we're checking for dev versions
258
  if( get_option('em_check_dev_version') || get_option('dbem_pro_dev_updates') ){
259
  //check WP repo for trunk version
260
+ $request = wp_remote_get('https://plugins.svn.wordpress.org/events-manager/trunk/events-manager.php');
261
 
262
  if( !is_wp_error($request) ){
263
  preg_match('/Version: ([0-9a-z\.]+)/', $request['body'], $matches);
280
 
281
  return $transient;
282
  }
283
+ add_filter('pre_set_site_transient_update_plugins', 'em_updates_check', 100); // Hook into the plugin update check and mod for dev version
284
 
285
  function em_user_action_links( $actions, $user ){
286
  if ( !is_network_admin() && current_user_can( 'manage_others_bookings' ) ){
295
  return $actions;
296
  }
297
  add_filter('user_row_actions','em_user_action_links',10,2);
298
+
299
+ function em_pro_update_notice(){
300
+ // Check EM Pro update min
301
+ if( defined('EMP_VERSION') && EMP_VERSION < EM_PRO_MIN_VERSION && !defined('EMP_DISABLE_WARNINGS') ) {
302
+ $data = get_site_option('dbem_data');
303
+ $possible_notices = is_array($data) && !empty($data['admin_notices']) ? $data['admin_notices'] : array();
304
+ //we may have something to show, so we make sure that there's something to show right now
305
+ if( !isset($possible_notices['em-pro-updates']) ) {
306
+ ?>
307
+ <div id="em_page_error" class="notice notice-warning">
308
+ <p><?php _e('There is a newer version of Events Manager Pro which is recommended for this current version of Events Manager as new features have been added. Please go to the plugin website and download the latest update.','events-manager'); ?></p>
309
+ </div>
310
+ <?php
311
+ }
312
+ }
313
+ }
314
  ?>
admin/em-docs.php CHANGED
@@ -6,10 +6,6 @@ function em_docs_init($force_init = false){
6
  add_action('wp_head', 'emd_head');
7
  //Generate the docs
8
  global $EM_Documentation;
9
- $EM_Event = new EM_Event();
10
- $event_fields = $EM_Event->get_fields(true);
11
- $EM_Location = new EM_Location();
12
- $location_fields = $EM_Location->get_fields(true);
13
  $EM_Documentation = array(
14
  'arguments' => array(
15
  'events' => array(
@@ -103,6 +99,7 @@ function em_docs_init($force_init = false){
103
  '#_EVENTCATEGORIES' => array( 'desc' => 'Shows a list of category links this event belongs to.' ),
104
  '#_EVENTCATEGORIESIMAGES' => array( 'desc' => 'Shows a list of category images this event belongs to. Categories without an image will be ignored.' ),
105
  '#_EVENTTAGS' => array( 'desc' => 'Shows a list of tag links this event belongs to.' ),
 
106
  '#_RECURRINGDATERANGE' => array( 'desc' => 'Range of dates between the start/end of the recurring event pattern for an event recurrence, blank for non-recurrences.' ),
107
  '#_RECURRINGPATTERN' => array( 'desc' => 'Describes the pattern of a recurring event when used on an event recurrence, blank for non-recurrences.' ),
108
  '#_RECURRINGID' => array( 'desc' => 'The event ID of the recurring event template when displayed on a recurrence, blank for non-recurrences.' ),
@@ -126,6 +123,31 @@ function em_docs_init($force_init = false){
126
  '#_{x} or #@_{x}' => array( 'desc' => 'You can also create a date format without prepending # to each character by wrapping a valid php date() format in <code>#_{}</code> or <code>#@_{}</code> (e.g. <code>#_{d/m/Y}</code>). If there is no end date (or is same as start date), the value is not shown. This is useful if you want to show event end dates only on events that are longer than one day, e.g. <code>#j #M #Y #@_{ \u\n\t\i\l j M Y}</code>.' ),
127
  )
128
  ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  'Links/URLs' => array(
130
  'placeholders' => array(
131
  '#_EVENTIMAGEURL' => array( 'desc' => 'Shows the event image url, if available.' ),
@@ -191,6 +213,18 @@ function em_docs_init($force_init = false){
191
  )
192
  ),
193
  ),
 
 
 
 
 
 
 
 
 
 
 
 
194
  'categories' => array(
195
  'Category Details' => array(
196
  'desc' => 'You can use these when displaying categories or for showing the first available category in an event format.',
@@ -345,6 +379,8 @@ function em_docs_init($force_init = false){
345
  '#_BOOKINGFORMCUSTOMREG{field_id}' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Shows booking form custom fields that are used for guest user registration. The field_id value must match that of your custom booking form field.','http://wp-events-plugin.com/features/') ),
346
  '#_BOOKINGFORMCUSTOMFIELDS' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Generates a list of booking form custom fields that are used in the booking.','http://wp-events-plugin.com/features/') ),
347
  '#_BOOKINGATTENDEES' => array('desc' => sprintf('(<a href="%s">pro only</a>) Generates a list of attendee information displaying the filled in form data for each attendee (requires individual attendee forms enabled for the event). This list is split by ticket type, then by individual attendee.','http://wp-events-plugin.com/features/')), //coupons too!
 
 
348
  )
349
  ),
350
  'Pricing Information' => array(
@@ -394,6 +430,7 @@ function em_docs_init($force_init = false){
394
  //TODO add capabilites explanations
395
  'capabilities' => array()
396
  );
 
397
  }
398
  }
399
  add_action('init', 'em_docs_init');
6
  add_action('wp_head', 'emd_head');
7
  //Generate the docs
8
  global $EM_Documentation;
 
 
 
 
9
  $EM_Documentation = array(
10
  'arguments' => array(
11
  'events' => array(
99
  '#_EVENTCATEGORIES' => array( 'desc' => 'Shows a list of category links this event belongs to.' ),
100
  '#_EVENTCATEGORIESIMAGES' => array( 'desc' => 'Shows a list of category images this event belongs to. Categories without an image will be ignored.' ),
101
  '#_EVENTTAGS' => array( 'desc' => 'Shows a list of tag links this event belongs to.' ),
102
+ '#_EVENTLOCATION' => array( 'desc' => 'Displays information about the event location, which is different from a physical location. <a href="https://wp-events-plugin.com/documentation/location-types/">See our documentation for more information</a>, as each location type may display different information and will have different additional placeholders.' ),
103
  '#_RECURRINGDATERANGE' => array( 'desc' => 'Range of dates between the start/end of the recurring event pattern for an event recurrence, blank for non-recurrences.' ),
104
  '#_RECURRINGPATTERN' => array( 'desc' => 'Describes the pattern of a recurring event when used on an event recurrence, blank for non-recurrences.' ),
105
  '#_RECURRINGID' => array( 'desc' => 'The event ID of the recurring event template when displayed on a recurrence, blank for non-recurrences.' ),
123
  '#_{x} or #@_{x}' => array( 'desc' => 'You can also create a date format without prepending # to each character by wrapping a valid php date() format in <code>#_{}</code> or <code>#@_{}</code> (e.g. <code>#_{d/m/Y}</code>). If there is no end date (or is same as start date), the value is not shown. This is useful if you want to show event end dates only on events that are longer than one day, e.g. <code>#j #M #Y #@_{ \u\n\t\i\l j M Y}</code>.' ),
124
  )
125
  ),
126
+ 'WordPress-relative Timezone Date/Time Placeholders' => array(
127
+ 'desc' => 'These placeholders are extensions of the default Date/Time placholders, but instead will display the time of the event relative to your WordPress timezone rather than the local time of the event itself. Your WordPress site timezone is found in your <em><strong>Dashboard > Settings > General</strong></em> settings page.',
128
+ 'placeholders' => array(
129
+ '#_24HSTARTTIME_SITE' => array( 'desc' => 'Sames as <code>#_24HSTARTTIME</code> but displays time relative to your site timezone.' ),
130
+ '#_24HENDTIME_SITE' => array( 'desc' => 'Sames as <code>#_24HENDTIME</code> but displays time relative to your site timezone.' ),
131
+ '#_12HSTARTTIME_SITE' => array( 'desc' => 'Sames as <code>#_12HSTARTTIME</code> but displays time relative to your site timezone.' ),
132
+ '#_12HENDTIME_SITE' => array( 'desc' => 'Sames as <code>#_12HENDTIME</code> but displays time relative to your site timezone.' ),
133
+ '#_EVENTTIMES_SITE' => array( 'desc' => 'Sames as <code>#_EVENTTIMES</code> but displays times relative to your site timezone.' ),
134
+ '#_EVENTDATES_SITE' => array( 'desc' => 'Sames as <code>#_EVENTDATES</code> but displays dates relative to your site timezone (dates can be different for events near midnight in a different timezone).' ),
135
+ '#__{x} or #@__{x}' => array( 'desc' => 'Same as <code>#_{x}</code> or <code>#@_{x}</code> but displays the time of the event relative to your WordPress timezone rather than the local time of the event itself.' ),
136
+ )
137
+ ),
138
+ 'Viewer Timezone Date/Time Placeholders' => array(
139
+ 'desc' => 'These placeholders are extensions of the default Date/Time placholders, but instead will display the time of the event relative to the visitor timezone rather than the local event start time. This time is based on the user browser settings and JavaScript, so this may not always be accurate if a visitor is travelling and does not update their browser timezone, or if they have disabled JS on their browser.',
140
+ 'placeholders' => array(
141
+ '#_24HSTARTTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_24HSTARTTIME</code> but displays time relative to your visitor browser timezone.' ),
142
+ '#_24HENDTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_24HENDTIME</code> but displays time relative to your visitor browser timezone.' ),
143
+ '#_12HSTARTTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_12HSTARTTIME</code> but displays time relative to your visitor browser timezone.' ),
144
+ '#_12HENDTIME_LOCAL' => array( 'desc' => 'Sames as <code>#_12HENDTIME</code> but displays time relative to your visitor browser timezone.' ),
145
+ '#_EVENTTIMES_LOCAL' => array( 'desc' => 'Sames as <code>#_EVENTTIMES</code> but displays time relative to your visitor browser timezone.' ),
146
+ '#_EVENTTIMES_LOCAL{...}' => array( 'desc' => 'Sames as <code>#_EVENTTIMES_LOCAL</code> but displays custom format by replacing <code>...</code> with <a href="https://momentjs.com/docs/#/displaying/"> documented Moment JS formatting syntax</a>.'),
147
+ '#_EVENTDATES_LOCAL' => array( 'desc' => 'Sames as <code>#_EVENTDATES</code> but displays dates relative to your site timezone (dates can be different for events near midnight in a different timezone).' ),
148
+ '#_EVENTDATES_LOCAL{...}' => array( 'desc' => 'Sames as <code>#_EVENTDATES_LOCAL</code> but displays custom format by replacing <code>...</code> with <a href="https://momentjs.com/docs/#/displaying/"> documented Moment JS formatting syntax</a>.'),
149
+ )
150
+ ),
151
  'Links/URLs' => array(
152
  'placeholders' => array(
153
  '#_EVENTIMAGEURL' => array( 'desc' => 'Shows the event image url, if available.' ),
213
  )
214
  ),
215
  ),
216
+ 'event-locations' => array(
217
+ 'Event Location URLs' => array(
218
+ 'placeholders' => array(
219
+ '#_EVENTLOCATION' => array( 'desc' => 'An HTML link, opens in a new tab.' ),
220
+ '#_EVENTLOCATION{url}' => array( 'desc' => 'Just the URL.' ),
221
+ '#_EVENTLOCATION{text}' => array( 'desc' => 'Just the Link Text' ),
222
+ '#_EVENTLOCATION{_self}' => array( 'desc' => 'Regular HTML link' ),
223
+ '#_EVENTLOCATION{_parent}' => array( 'desc' => 'HTML link with target=”_parent”' ),
224
+ '#_EVENTLOCATION{_top}' => array( 'desc' => 'HTML link with target=”_top”' )
225
+ )
226
+ ),
227
+ ),
228
  'categories' => array(
229
  'Category Details' => array(
230
  'desc' => 'You can use these when displaying categories or for showing the first available category in an event format.',
379
  '#_BOOKINGFORMCUSTOMREG{field_id}' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Shows booking form custom fields that are used for guest user registration. The field_id value must match that of your custom booking form field.','http://wp-events-plugin.com/features/') ),
380
  '#_BOOKINGFORMCUSTOMFIELDS' => array( 'desc' => sprintf('(<a href="%s">pro only</a>) Generates a list of booking form custom fields that are used in the booking.','http://wp-events-plugin.com/features/') ),
381
  '#_BOOKINGATTENDEES' => array('desc' => sprintf('(<a href="%s">pro only</a>) Generates a list of attendee information displaying the filled in form data for each attendee (requires individual attendee forms enabled for the event). This list is split by ticket type, then by individual attendee.','http://wp-events-plugin.com/features/')), //coupons too!
382
+ '#_BOOKINGADMINURL' => array( 'desc' => 'URL for admins to view and manage the booking. This should only be used on admin-specific email templates.' ),
383
+ '#_BOOKINGADMINLINK' => array( 'desc' => 'HTML link for admins to view and manage the booking. This should only be used on admin-specific email templates.' ),
384
  )
385
  ),
386
  'Pricing Information' => array(
430
  //TODO add capabilites explanations
431
  'capabilities' => array()
432
  );
433
+ $EM_Documentation = apply_filters('em_documentation', $EM_Documentation);
434
  }
435
  }
436
  add_action('init', 'em_docs_init');
admin/em-help.php CHANGED
@@ -8,7 +8,7 @@ function em_admin_help_page(){
8
  <div class="wrap">
9
  <h1><?php _e('Getting Help for Events Manager','events-manager'); ?></h1>
10
  <div class="em-docs">
11
- <h2>Where To Get Help</h3>
12
  <p>
13
  This page is only a small portion of the event documentation which is here for quick reference. If you're just starting out, we recommend you visit the following places for further support:
14
  </p>
@@ -26,6 +26,8 @@ function em_admin_help_page(){
26
  <a name="event-placeholders"></a>
27
  <h3 style="margin-top:20px;"><?php _e('Event Related Placeholders','events-manager'); ?></h3>
28
  <?php echo em_docs_placeholders( array('type'=>'events') ); ?>
 
 
29
  <a name="category-placeholders"></a>
30
  <h3><?php _e('Category Related Placeholders','events-manager'); ?></h3>
31
  <?php echo em_docs_placeholders( array('type'=>'categories') ); ?>
8
  <div class="wrap">
9
  <h1><?php _e('Getting Help for Events Manager','events-manager'); ?></h1>
10
  <div class="em-docs">
11
+ <h2>Where To Get Help</h2>
12
  <p>
13
  This page is only a small portion of the event documentation which is here for quick reference. If you're just starting out, we recommend you visit the following places for further support:
14
  </p>
26
  <a name="event-placeholders"></a>
27
  <h3 style="margin-top:20px;"><?php _e('Event Related Placeholders','events-manager'); ?></h3>
28
  <?php echo em_docs_placeholders( array('type'=>'events') ); ?>
29
+ <h3 style="margin-top:20px;"><?php _e('Event Location Placeholders','events-manager'); ?></h3>
30
+ <?php echo em_docs_placeholders( array('type'=>'event-locations') ); ?>
31
  <a name="category-placeholders"></a>
32
  <h3><?php _e('Category Related Placeholders','events-manager'); ?></h3>
33
  <?php echo em_docs_placeholders( array('type'=>'categories') ); ?>
admin/em-ms-options.php CHANGED
@@ -63,7 +63,8 @@ function em_ms_admin_options_page() {
63
  if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'reset' ){
64
  em_admin_options_reset_page();
65
  return;
66
- }
 
67
  //TODO place all options into an array
68
  $tabs_enabled = defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS;
69
  $events_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#event-placeholders">'. __('Event Related Placeholders','events-manager') .'</a>';
63
  if( !empty($_REQUEST['action']) && $_REQUEST['action'] == 'reset' ){
64
  em_admin_options_reset_page();
65
  return;
66
+ }
67
+ em_pro_update_notice();
68
  //TODO place all options into an array
69
  $tabs_enabled = defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS;
70
  $events_placeholders = '<a href="'.EM_ADMIN_URL .'&amp;events-manager-help#event-placeholders">'. __('Event Related Placeholders','events-manager') .'</a>';
admin/em-options.php CHANGED
@@ -456,6 +456,8 @@ function em_admin_options_page() {
456
  global $save_button;
457
  $save_button = '<tr><th>&nbsp;</th><td><p class="submit" style="margin:0px; padding:0px; text-align:right;"><input type="submit" class="button-primary" name="Submit" value="'. __( 'Save Changes', 'events-manager') .' ('. __('All','events-manager') .')" /></p></td></tr>';
458
 
 
 
459
  if( defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS ){
460
  $tabs_enabled = true;
461
  $general_tab_link = esc_url(add_query_arg( array('em_tab'=>'general')));
456
  global $save_button;
457
  $save_button = '<tr><th>&nbsp;</th><td><p class="submit" style="margin:0px; padding:0px; text-align:right;"><input type="submit" class="button-primary" name="Submit" value="'. __( 'Save Changes', 'events-manager') .' ('. __('All','events-manager') .')" /></p></td></tr>';
458
 
459
+ if( !is_multisite() ) em_pro_update_notice();
460
+
461
  if( defined('EM_SETTINGS_TABS') && EM_SETTINGS_TABS ){
462
  $tabs_enabled = true;
463
  $general_tab_link = esc_url(add_query_arg( array('em_tab'=>'general')));
admin/settings/tabs/formats.php CHANGED
@@ -142,7 +142,7 @@
142
  <table class="form-table">
143
  <?php
144
  em_options_input_text ( __( 'Date Format', 'events-manager'), 'dbem_date_format', sprintf(__('For use with the %s placeholder','events-manager'),'<code>#_EVENTDATES</code>') );
145
- em_options_input_text ( __( 'Date Picker Format', 'events-manager'), 'dbem_date_format_js', sprintf(__( 'Same as <em>Date Format</em>, but this is used for the datepickers used by Events Manager. This uses a slightly different format to the others on here, for a list of characters to use, visit the <a href="%s">jQuery formatDate reference</a>', 'events-manager'),'http://docs.jquery.com/UI/Datepicker/formatDate') );
146
  em_options_input_text ( __( 'Date Separator', 'events-manager'), 'dbem_dates_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('dates','events-manager')) );
147
  em_options_input_text ( __( 'Time Format', 'events-manager'), 'dbem_time_format', sprintf(__('For use with the %s placeholder','events-manager'),'<code>#_EVENTTIMES</code>') );
148
  em_options_input_text ( __( 'Time Separator', 'events-manager'), 'dbem_times_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('times','events-manager')) );
142
  <table class="form-table">
143
  <?php
144
  em_options_input_text ( __( 'Date Format', 'events-manager'), 'dbem_date_format', sprintf(__('For use with the %s placeholder','events-manager'),'<code>#_EVENTDATES</code>') );
145
+ em_options_input_text ( __( 'Date Picker Format', 'events-manager'), 'dbem_date_format_js', sprintf(__( 'Same as <em>Date Format</em>, but this is used for the datepickers used by Events Manager. This uses a slightly different format to the others on here, for a list of characters to use, visit the <a href="%s">jQuery formatDate reference</a>', 'events-manager'),'https://api.jqueryui.com/datepicker/#utility-formatDate') );
146
  em_options_input_text ( __( 'Date Separator', 'events-manager'), 'dbem_dates_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('dates','events-manager')) );
147
  em_options_input_text ( __( 'Time Format', 'events-manager'), 'dbem_time_format', sprintf(__('For use with the %s placeholder','events-manager'),'<code>#_EVENTTIMES</code>') );
148
  em_options_input_text ( __( 'Time Separator', 'events-manager'), 'dbem_times_separator', sprintf(__( 'For when start/end %s are present, this will separate the two (include spaces here if necessary).', 'events-manager'), __('times','events-manager')) );
admin/settings/tabs/general.php CHANGED
@@ -2,7 +2,7 @@
2
  <!-- GENERAL OPTIONS -->
3
  <div class="em-menu-general em-menu-group">
4
  <div class="postbox " id="em-opt-general" >
5
- <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div><h3><span><?php _e ( 'General Options', 'events-manager'); ?> </span></h3>
6
  <div class="inside">
7
  <table class="form-table">
8
  <?php em_options_radio_binary ( __( 'Disable thumbnails?', 'events-manager'), 'dbem_thumbnails_enabled', __( 'Select yes to disable Events Manager from enabling thumbnails (some themes may already have this enabled, which we cannot be turned off here).','events-manager') ); ?>
@@ -247,7 +247,6 @@
247
  <table class="form-table">
248
  <tr class="em-header"><td colspan="2">
249
  <h4><?php _e('JavaScript Files','events-manager'); ?></h4>
250
- <p><?php echo sprintf(__('If you are not using it already, we recommend you try the <a href="%s" target="_blank">Use Google Libraries</a> plugin, because without further optimization options below it already significantly reduces the number of files needed to display your Event pages and will most likely speed up your overall website loading time.' ,'events-manager'),'http://wordpress.org/extend/plugins/use-google-libraries/'); ?>
251
  </td></tr>
252
  <?php
253
  em_options_radio_binary ( __( 'Limit JS file loading?', 'events-manager'), 'dbem_js_limit', __( 'Prevent unnecessary loading of JavaScript files on pages where they are not needed.', 'events-manager') );
2
  <!-- GENERAL OPTIONS -->
3
  <div class="em-menu-general em-menu-group">
4
  <div class="postbox " id="em-opt-general" >
5
+ <div class="handlediv" title="<?php __('Click to toggle', 'events-manager'); ?>"><br /></div> <h3><span><?php _e ( 'General Options', 'events-manager'); ?> </span></h3>
6
  <div class="inside">
7
  <table class="form-table">
8
  <?php em_options_radio_binary ( __( 'Disable thumbnails?', 'events-manager'), 'dbem_thumbnails_enabled', __( 'Select yes to disable Events Manager from enabling thumbnails (some themes may already have this enabled, which we cannot be turned off here).','events-manager') ); ?>
247
  <table class="form-table">
248
  <tr class="em-header"><td colspan="2">
249
  <h4><?php _e('JavaScript Files','events-manager'); ?></h4>
 
250
  </td></tr>
251
  <?php
252
  em_options_radio_binary ( __( 'Limit JS file loading?', 'events-manager'), 'dbem_js_limit', __( 'Prevent unnecessary loading of JavaScript files on pages where they are not needed.', 'events-manager') );
buddypress/bp-em-core.php CHANGED
@@ -99,15 +99,17 @@ class BP_EM_Component extends BP_Component {
99
  'position' => 10
100
  );
101
 
102
- $sub_nav[] = array(
103
- 'name' => __( 'Events I\'m Attending', 'events-manager'),
104
- 'slug' => 'attending',
105
- 'parent_slug' => em_bp_get_slug(),
106
- 'parent_url' => $em_link,
107
- 'screen_function' => 'bp_em_attending',
108
- 'position' => 20,
109
- 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
110
- );
 
 
111
 
112
  if( $can_manage_events ){
113
  $sub_nav[] = array(
@@ -158,6 +160,9 @@ class BP_EM_Component extends BP_Component {
158
  );
159
  }
160
 
 
 
 
161
  parent::setup_nav( $main_nav, $sub_nav );
162
  add_action( 'bp_init', array(&$this, 'setup_group_nav') );
163
  }
99
  'position' => 10
100
  );
101
 
102
+ if( get_option('dbem_rsvp_enabled') ) { // Only if bookings enabled
103
+ $sub_nav[] = array(
104
+ 'name' => __( 'Events I\'m Attending', 'events-manager'),
105
+ 'slug' => 'attending',
106
+ 'parent_slug' => em_bp_get_slug(),
107
+ 'parent_url' => $em_link,
108
+ 'screen_function' => 'bp_em_attending',
109
+ 'position' => 20,
110
+ 'user_has_access' => bp_is_my_profile() // Only the logged in user can access this on his/her profile
111
+ );
112
+ }
113
 
114
  if( $can_manage_events ){
115
  $sub_nav[] = array(
160
  );
161
  }
162
 
163
+ $main_nav = apply_filters('em_bp_menu_main_nav', $main_nav);
164
+ $sub_nav = apply_filters('em_bp_menu_sub_nav', $sub_nav);
165
+
166
  parent::setup_nav( $main_nav, $sub_nav );
167
  add_action( 'bp_init', array(&$this, 'setup_group_nav') );
168
  }
classes/em-admin-notice.php CHANGED
@@ -144,9 +144,11 @@ class EM_Admin_Notice {
144
  if( $this->where == 'plugin' ) $return = true;
145
  elseif( empty($_REQUEST['page']) && in_array($this->where, array(EM_POST_TYPE_EVENT, EM_POST_TYPE_LOCATION, 'event-recurring')) ) $return = true;
146
  elseif( $this->where == 'settings' && !empty($_REQUEST['page']) && $_REQUEST['page'] == 'events-manager-options' ) $return = true;
147
- elseif( !empty($_REQUEST['page']) && $this->where == $_REQUEST['page'] ) $return = true;
148
  }elseif( is_network_admin() && !empty($_REQUEST['page']) && preg_match('/^events\-manager\-/', $_REQUEST['page']) ){
149
  $return = $this->where == 'plugin' || $this->where == 'settings' || $this->where == 'network_admin';
 
 
150
  }
151
  }
152
  //does this even have a message we can display?
144
  if( $this->where == 'plugin' ) $return = true;
145
  elseif( empty($_REQUEST['page']) && in_array($this->where, array(EM_POST_TYPE_EVENT, EM_POST_TYPE_LOCATION, 'event-recurring')) ) $return = true;
146
  elseif( $this->where == 'settings' && !empty($_REQUEST['page']) && $_REQUEST['page'] == 'events-manager-options' ) $return = true;
147
+ elseif( !empty($_REQUEST['page']) && ($this->where == $_REQUEST['page'] || (is_array($this->where) && in_array($_REQUEST['page'], $this->where))) ) $return = true;
148
  }elseif( is_network_admin() && !empty($_REQUEST['page']) && preg_match('/^events\-manager\-/', $_REQUEST['page']) ){
149
  $return = $this->where == 'plugin' || $this->where == 'settings' || $this->where == 'network_admin';
150
+ }elseif( !empty($_REQUEST['page']) && ($this->where == $_REQUEST['page'] || (is_array($this->where) && in_array($_REQUEST['page'], $this->where))) ){
151
+ $return = true;
152
  }
153
  }
154
  //does this even have a message we can display?
classes/em-booking.php CHANGED
@@ -259,12 +259,14 @@ class EM_Booking extends EM_Object{
259
  $this->add_error( $this->get_tickets_bookings()->get_errors() );
260
  }
261
  }
262
- //Step 3. email if necessary
 
 
 
263
  if ( count($this->errors) == 0 && $mail ) {
264
  $this->email();
265
  }
266
- $this->compat_keys();
267
- return apply_filters('em_booking_save', ( count($this->errors) == 0 ), $this, $update);
268
  }else{
269
  $this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
270
  if( !$this->can_manage() ){
@@ -951,7 +953,8 @@ class EM_Booking extends EM_Object{
951
  $result = $wpdb->query($wpdb->prepare('UPDATE '.EM_BOOKINGS_TABLE.' SET booking_status=%d WHERE booking_id=%d', array($status, $this->booking_id)));
952
  if($result !== false){
953
  $this->feedback_message = sprintf(__('Booking %s.','events-manager'), $action_string);
954
- if( $email && $this->previous_status != $this->booking_status ){ //email if status has changed
 
955
  if( $this->email() ){
956
  if( $this->mails_sent > 0 ){
957
  $this->feedback_message .= " ".__('Email Sent.','events-manager');
@@ -966,9 +969,9 @@ class EM_Booking extends EM_Object{
966
  //errors should be logged by save()
967
  $this->feedback_message = sprintf(__('Booking could not be %s.','events-manager'), $action_string);
968
  $this->add_error(sprintf(__('Booking could not be %s.','events-manager'), $action_string));
969
- $result = false;
970
  }
971
- return apply_filters('em_booking_set_status', $result, $this);
972
  }
973
 
974
  /**
@@ -1041,7 +1044,9 @@ class EM_Booking extends EM_Object{
1041
  $replaces = array();
1042
  foreach($placeholders[1] as $key => $result) {
1043
  $replace = '';
1044
- $full_result = $placeholders[0][$key];
 
 
1045
  switch( $result ){
1046
  case '#_BOOKINGID':
1047
  $replace = $this->booking_id;
@@ -1115,11 +1120,20 @@ class EM_Booking extends EM_Object{
1115
  em_locate_template('emails/bookingsummary.php', true, array('EM_Booking'=>$this));
1116
  $replace = ob_get_clean();
1117
  break;
 
 
 
 
 
 
 
 
 
1118
  default:
1119
  $replace = $full_result;
1120
  break;
1121
  }
1122
- $replaces[$full_result] = apply_filters('em_booking_output_placeholder', $replace, $this, $full_result, $target);
1123
  }
1124
  //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
1125
  krsort($replaces);
@@ -1145,6 +1159,8 @@ class EM_Booking extends EM_Object{
1145
 
1146
  //Make sure event matches booking, and that booking used to be approved.
1147
  if( $this->booking_status !== $this->previous_status || $force_resend ){
 
 
1148
  do_action('em_booking_email_before_send', $this);
1149
  //get event info and refresh all bookings
1150
  $EM_Event = $this->get_event(); //We NEED event details here.
@@ -1197,6 +1213,7 @@ class EM_Booking extends EM_Object{
1197
  }
1198
  }
1199
  do_action('em_booking_email_after_send', $this);
 
1200
  }
1201
  return apply_filters('em_booking_email', $result, $this, $email_admin, $force_resend, $email_attendee);
1202
  //TODO need error checking for booking mail send
259
  $this->add_error( $this->get_tickets_bookings()->get_errors() );
260
  }
261
  }
262
+ // Step 3. Run filter for return value before sending emails
263
+ $this->compat_keys();
264
+ $return = apply_filters('em_booking_save', ( count($this->errors) == 0 ), $this, $update);
265
+ //Final Step: email if necessary after all the saving has been done
266
  if ( count($this->errors) == 0 && $mail ) {
267
  $this->email();
268
  }
269
+ return $return;
 
270
  }else{
271
  $this->feedback_message = __('There was a problem saving the booking.', 'events-manager');
272
  if( !$this->can_manage() ){
953
  $result = $wpdb->query($wpdb->prepare('UPDATE '.EM_BOOKINGS_TABLE.' SET booking_status=%d WHERE booking_id=%d', array($status, $this->booking_id)));
954
  if($result !== false){
955
  $this->feedback_message = sprintf(__('Booking %s.','events-manager'), $action_string);
956
+ $result = apply_filters('em_booking_set_status', $result, $this); // run the filter before emails go out, in case others need to hook in first
957
+ if( $result && $email && $this->previous_status != $this->booking_status ){ //email if status has changed
958
  if( $this->email() ){
959
  if( $this->mails_sent > 0 ){
960
  $this->feedback_message .= " ".__('Email Sent.','events-manager');
969
  //errors should be logged by save()
970
  $this->feedback_message = sprintf(__('Booking could not be %s.','events-manager'), $action_string);
971
  $this->add_error(sprintf(__('Booking could not be %s.','events-manager'), $action_string));
972
+ $result = apply_filters('em_booking_set_status', false, $this);
973
  }
974
+ return $result;
975
  }
976
 
977
  /**
1044
  $replaces = array();
1045
  foreach($placeholders[1] as $key => $result) {
1046
  $replace = '';
1047
+ $full_result = $placeholders[0][$key];
1048
+ $placeholder_atts = array($result);
1049
+ if( !empty($placeholders[3][$key]) ) $placeholder_atts[] = $placeholders[3][$key];
1050
  switch( $result ){
1051
  case '#_BOOKINGID':
1052
  $replace = $this->booking_id;
1120
  em_locate_template('emails/bookingsummary.php', true, array('EM_Booking'=>$this));
1121
  $replace = ob_get_clean();
1122
  break;
1123
+ case '#_BOOKINGADMINURL':
1124
+ case '#_BOOKINGADMINLINK':
1125
+ $bookings_link = esc_url( add_query_arg('booking_id', $this->booking_id, $this->event->get_bookings_url()) );
1126
+ if($result == '#_BOOKINGADMINLINK'){
1127
+ $replace = '<a href="'.$bookings_link.'">'.esc_html__('Edit Booking', 'events-manager'). '</a>';
1128
+ }else{
1129
+ $replace = $bookings_link;
1130
+ }
1131
+ break;
1132
  default:
1133
  $replace = $full_result;
1134
  break;
1135
  }
1136
+ $replaces[$full_result] = apply_filters('em_booking_output_placeholder', $replace, $this, $full_result, $target, $placeholder_atts);
1137
  }
1138
  //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
1139
  krsort($replaces);
1159
 
1160
  //Make sure event matches booking, and that booking used to be approved.
1161
  if( $this->booking_status !== $this->previous_status || $force_resend ){
1162
+ // before we format dates or any other language-specific placeholders, make sure we're translating the site language, not the user profile language in the admin area (e.g. if an admin is sending a booking confirmation email), assuming this isn't a ML-enabled site.
1163
+ if( !EM_ML::$is_ml && is_admin() && EM_ML::$wplang != get_user_locale() ) EM_ML::switch_locale(EM_ML::$wplang);
1164
  do_action('em_booking_email_before_send', $this);
1165
  //get event info and refresh all bookings
1166
  $EM_Event = $this->get_event(); //We NEED event details here.
1213
  }
1214
  }
1215
  do_action('em_booking_email_after_send', $this);
1216
+ if( !EM_ML::$is_ml && is_admin() ) EM_ML::restore_locale(); // restore the locale back for the rest of the site, which will happen if we switched it earlier
1217
  }
1218
  return apply_filters('em_booking_email', $result, $this, $email_admin, $force_resend, $email_attendee);
1219
  //TODO need error checking for booking mail send
classes/em-bookings-table.php CHANGED
@@ -112,7 +112,11 @@ class EM_Bookings_Table{
112
  $this->cols[$k] = sanitize_text_field($col);
113
  }
114
  }else{
115
- $this->cols = explode(',',sanitize_text_field($_REQUEST['cols']));
 
 
 
 
116
  }
117
  }
118
  //load collumn view settings
112
  $this->cols[$k] = sanitize_text_field($col);
113
  }
114
  }else{
115
+ foreach( explode(',',$_REQUEST['cols']) as $k => $col ){
116
+ if( array_key_exists($col, $this->cols_template) ){
117
+ $this->cols[$k] = $col;
118
+ }
119
+ }
120
  }
121
  }
122
  //load collumn view settings
classes/em-bookings.php CHANGED
@@ -546,18 +546,21 @@ class EM_Bookings extends EM_Object implements Iterator{
546
 
547
  /**
548
  * Checks to see if user has a booking for this event
549
- * @param unknown_type $user_id
550
  */
551
  function has_booking( $user_id = false ){
552
  if( $user_id === false ){
553
  $user_id = get_current_user_id();
554
  }
555
  if( is_numeric($user_id) && $user_id > 0 ){
556
- foreach ($this->load() as $EM_Booking){
557
- if( $EM_Booking->person->ID == $user_id && !in_array($EM_Booking->booking_status, array(2,3)) ){
558
- return apply_filters('em_bookings_has_booking', $EM_Booking, $this);
559
- }
560
- }
 
 
 
561
  }
562
  return apply_filters('em_bookings_has_booking', false, $this);
563
  }
546
 
547
  /**
548
  * Checks to see if user has a booking for this event
549
+ * @param int $user_id
550
  */
551
  function has_booking( $user_id = false ){
552
  if( $user_id === false ){
553
  $user_id = get_current_user_id();
554
  }
555
  if( is_numeric($user_id) && $user_id > 0 ){
556
+ global $wpdb;
557
+ // get the first booking ID available and return that
558
+ $sql = $wpdb->prepare('SELECT booking_id FROM '.EM_BOOKINGS_TABLE.' WHERE event_id = %d AND person_id = %d AND booking_status NOT IN (2,3)', $this->event_id, $user_id);
559
+ $booking_id = $wpdb->get_var($sql);
560
+ if( (int) $booking_id > 0 ){
561
+ $EM_Booking = em_get_booking($booking_id);
562
+ return apply_filters('em_bookings_has_booking', $EM_Booking, $this);
563
+ }
564
  }
565
  return apply_filters('em_bookings_has_booking', false, $this);
566
  }
classes/em-datetime.php CHANGED
@@ -2,8 +2,8 @@
2
  /**
3
  * Extends DateTime allowing supplied timezone to be a string, which can also be a UTC offset.
4
  * Also prevents an exception being thrown. Some additional shortcuts added so less coding is required for regular tasks.
5
- * By doing this, we support WP's option to manually offset time without DST, which is not supported by DateTimeZone in PHP <5.5.10
6
- *
7
  * @since 5.8.2
8
  */
9
  class EM_DateTime extends DateTime {
@@ -14,10 +14,9 @@ class EM_DateTime extends DateTime {
14
  */
15
  protected $timezone_name = false;
16
  /**
17
- * Shortcut representing the offset of time in the timezone, if it's a UTC manual offset, false if not.
18
- * @var int
19
  */
20
- protected $timezone_manual_offset = false;
21
  /**
22
  * Flag for validation purposes, so we can still have a real EM_DateTime and extract dates but know if the intended datetime failed validation.
23
  * A completely invalid date and time will become 1970-01-01 00:00:00 in local timezone, however a valid time can still exist with the 1970-01-01 date.
@@ -30,14 +29,13 @@ class EM_DateTime extends DateTime {
30
  * @see DateTime::__construct()
31
  * @param string $time
32
  * @param string|EM_DateTimeZone $timezone Unlike DateTime this also accepts string representation of a valid timezone, as well as UTC offsets in form of 'UTC -3' or just '-3'
33
- * @throws Exception
34
  */
35
  public function __construct( $time = 'now', $timezone = null ){
36
  //get our EM_DateTimeZone
37
  $timezone = EM_DateTimeZone::create($timezone);
38
  //save timezone name for use in getTimezone()
39
  $this->timezone_name = $timezone->getName();
40
- $this->timezone_manual_offset = $timezone->manual_offset;
41
  //fix DateTime error if a regular timestamp is supplied without prepended @ symbol
42
  if( is_numeric($time) ){
43
  $time = '@'.$time;
@@ -51,30 +49,16 @@ class EM_DateTime extends DateTime {
51
  $this->valid = true; //if we get this far, supplied time is valid
52
  }catch( Exception $e ){
53
  //get current date/time in relevant timezone and set valid flag to false
54
- parent::__construct('@0');
55
- $this->setTimezone($timezone);
56
- $this->setDate(1970,1,1);
57
- $this->setTime(0,0,0);
58
- $this->valid = false;
59
- }
60
- //deal with manual UTC offsets, but only if we haven't defaulted to the current timestamp since that would already be a correct relative value
61
- if( $time !== null && $time != 'now' && substr($time,0,1) != '@' ) $this->handleOffsets($timezone);
62
- }
63
-
64
- /**
65
- * If a UTC offset timezone is active, upon object creation or modification of the time, we need to store the actual UTC time relative to
66
- * the offset timezone, whereas initially the saved time will be UTC time relative to the time modified/created.
67
- *
68
- * Example:
69
- * We create an object with local UTC-5 time 12pm which is actually 5pm UTC. However, by default we'll have a 12PM UTC time stored as our internal timestamp.
70
- * What we'll want to do is make sure we're internally storing 5pm UTC time, which is the same value we'd have if we had a PHP native timezone like New York.
71
- * The only exception we don't want to do this is if we're setting the time to NOW, as in the current time which will always be the same value in UTC no matter what timezone.
72
- */
73
- protected function handleOffsets(){
74
- //handle manual UTC offsets
75
- if( $this->timezone_manual_offset !== false ){
76
- //the actual time here needs to be in actual UTC time because offsets are applied to UTC on any output functions
77
- $this->setTimestamp( $this->getTimestamp() - $this->timezone_manual_offset );
78
  }
79
  }
80
 
@@ -84,69 +68,23 @@ class EM_DateTime extends DateTime {
84
  */
85
  public function format( $format = 'Y-m-d H:i:s'){
86
  if( !$this->valid && ($format == 'Y-m-d' || $format == em_get_date_format())) return '';
87
- //if we deal with offsets, then we offset UTC time by that much
88
- if( $this->timezone_manual_offset !== false ){
89
- $format = $this->formatTimezones( $format );
90
- if( function_exists('date_timestamp_get') ){
91
- return date($format, $this->getTimestampWithOffset(true) );
92
- }else{
93
- //PHP < 5.3 fallback :/ Messed up, but it works...
94
- $timestamp = parent::format('U');
95
- $server_offset = date('Z', $timestamp);
96
- return date( $format, $timestamp - ($server_offset * 2) + $this->getOffset() );
97
- }
98
- }
99
  return parent::format($format);
100
  }
101
 
102
  /**
103
- * Formats timezone placeholders when there is a manual offset, which would be passed onto date formatting functions and usually output UTC timezone information.
104
- * The $force_format flag is also useful if passing a format to any date() type of function, such as date_i18n, which will not inherit this function's timezone settings.
105
  * @param string $format The format to be parsed.
106
- * @param bool $force_format If set to true timezone placeholders will be formatted regardless.
107
  * @return string
108
  */
109
- public function formatTimezones($format, $force_format = false ){
110
- $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
111
- $timezone_formats_regex = "/P|I|O|T|Z|e/";
112
- if( $this->timezone_manual_offset !== false ){
113
- if ( preg_match( $timezone_formats_regex, $format ) ) {
114
- foreach ( $timezone_formats as $timezone_format ) {
115
- if ( false !== strpos( $format, $timezone_format ) ) {
116
- switch( $timezone_format ){
117
- case 'P':
118
- case 'O':
119
- $offset = $this->getOffset();
120
- $formatted_format = $timezone_format == 'P' ? 'H:i':'Hi';
121
- $plus_minus = $offset < 0 ? '-':'+';
122
- $formatted = $plus_minus . gmdate($formatted_format, absint($offset));
123
- break;
124
- case 'I':
125
- $formatted = '0';
126
- break;
127
- case 'T':
128
- case 'e':
129
- $formatted = $this->getTimezone()->getName();
130
- break;
131
- case 'Z':
132
- $formatted = $this->getOffset();
133
- break;
134
- }
135
- $format = ' '.$format;
136
- $format = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $format );
137
- $format = substr( $format, 1, strlen( $format ) -1 );
138
- }
139
- }
140
- }
141
- }elseif( $force_format ){
142
- //useful in cases where we may pass a format onto a date() function e.g. date_i18n, where the timezone is not relative to this object
143
- if ( preg_match( $timezone_formats_regex, $format ) ) {
144
- foreach ( $timezone_formats as $timezone_format ) {
145
- if ( false !== strpos( $format, $timezone_format ) ) {
146
- $format = ' '.$format;
147
- $format = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $this->format( $timezone_format ) ), $format );
148
- $format = substr( $format, 1, strlen( $format ) -1 );
149
- }
150
  }
151
  }
152
  }
@@ -165,22 +103,17 @@ class EM_DateTime extends DateTime {
165
  }
166
 
167
  /**
168
- * Provides a translated date and time according to the current blog language.
169
  * Useful if using formats that provide date-related names such as 'Monday' or 'January', which should be translated if displayed in another language.
170
  * @param string $format
171
  * @return string
172
  */
173
  public function i18n( $format = 'Y-m-d H:i:s' ){
174
  if( !$this->valid && $format == em_get_date_format()) return '';
175
- //since we use WP's date functions which don't use DateTime (and if so, don't inherit our timezones), we need to preformat timezone related formats, adapted from date_i18n
176
- $format = $this->formatTimezones( $format, true );
177
- //if we deal with offsets, then we offset UTC time by that much
178
- if( !function_exists('date_timestamp_get') && $this->timezone_manual_offset !== false ){
179
- //PHP < 5.3 fallback :/ Messed up, but it works...
180
- $timestamp = parent::format('U');
181
- $server_offset = date('Z', $timestamp);
182
- return date_i18n( $format, $timestamp - ($server_offset * 2) + $this->getOffset() );
183
- }elseif( function_exists('wp_date') ){
184
  return wp_date( $format, $this->getTimestamp(), $this->getTimezone() );
185
  }else{
186
  return date_i18n( $format, $this->getTimestampWithOffset(true) );
@@ -188,7 +121,7 @@ class EM_DateTime extends DateTime {
188
  }
189
 
190
  /**
191
- * Outputs a default mysql datetime formatted string.
192
  * @return string
193
  */
194
  public function __toString(){
@@ -212,96 +145,52 @@ class EM_DateTime extends DateTime {
212
  }
213
 
214
  /**
215
- * Sets timestamp with PHP 5.2.x fallback.
216
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
217
  * @param int $timestamp
218
  * @see DateTime::setTimestamp()
219
  * @return EM_DateTime
220
  */
221
  public function setTimestamp( $timestamp ){
222
- if( function_exists('date_timestamp_set') ){
223
- $return = parent::setTimestamp( $timestamp );
224
- $this->valid = $return !== false;
225
- }else{
226
- //PHP < 5.3 fallback :/ setting modify() with a timestamp produces unpredictable results, so we play more tricks...
227
- $date = explode(',', date('Y,n,j,G,i,s', $timestamp));
228
- parent::setDate( (int) $date[0], (int) $date[1], (int) $date[2]);
229
- parent::setTime( (int) $date[3], (int) $date[4], (int) $date[5]);
230
- //$this->valid determined in functions above
231
- }
232
  return $this;
233
  }
234
 
235
  /**
236
- * Extends DateTime functionality by accepting a false or string value for a timezone.
237
  * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
238
- * @param string $timezone
239
  * @see DateTime::setTimezone()
240
  * @return EM_DateTime Returns object for chaining.
241
  */
242
- public function setTimezone( $timezone ){
243
  if( $timezone == $this->getTimezone()->getName() ) return $this;
244
  $timezone = EM_DateTimeZone::create($timezone);
245
  $return = parent::setTimezone($timezone);
246
  $this->timezone_name = $timezone->getName();
247
- $this->timezone_manual_offset = $timezone->manual_offset;
248
  $this->valid = $return !== false;
249
  return $this;
250
  }
251
 
252
  /**
253
- * Sets time along with adjusting internal timestamp for manual UTC offsets.
254
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
255
  * {@inheritDoc}
256
  * @see DateTime::setTime()
257
  */
258
  public function setTime( $hour, $minute, $second = NULL, $microseconds = NULL ){
259
- /*
260
- * manual offsets stores internal timestamp and date as UTC and the time is changed in UTC date/time
261
- * this causes problems when UTC time is on a different date to the local time with manual offset.
262
- * example: 2018-01-01 14:00 UTC => 2018-01-02 00:00 UTC+10
263
- * action: set the time to 12:00
264
- * result: 2018-01-01 02:00 UTC => 2018-01-01 12:00 UTC+10 -> after offset handling
265
- * expected: 2018-01-02 02:00 UTC => 2018-01-02 12:00 UTC+10 -> after offset handling
266
- * solution : change date AFTER setting the time and offset handling
267
- */
268
- if( $this->timezone_manual_offset !== false ){
269
- $date_array = explode('-', $this->format('Y-m-d'));
270
- }
271
  $return = parent::setTime( (int) $hour, (int) $minute, (int) $second );
272
- $this->handleOffsets();
273
- //post-handle offsets for time changes where dates change as stated above
274
- if( $this->timezone_manual_offset !== false ){
275
- $this->setDate($date_array[0], $date_array[1], $date_array[2]);
276
- }
277
  $this->valid = $return !== false;
278
  return $this;
279
  }
280
 
281
  /**
282
- * Sets date along with adjusting internal timestamp for manual UTC offsets.
283
- * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
284
  * {@inheritDoc}
285
  * @see DateTime::setDate()
286
  */
287
  public function setDate( $year, $month, $day ){
288
- if( $this->timezone_manual_offset !== false ){
289
- //we run into issues if we're dealing with timezones on the fringe of date changes e.g. 2018-01-01 01:00:00 UTC+2
290
- $DateTime = new DateTime( $this->getDateTime(), new DateTimeZone('UTC'));
291
- $DateTime->setDate( (int) $year, (int) $month, (int) $day ); //$this->valid is determined here
292
- //create a new timestamp based on UTC DateTime and offset it to current timezone
293
- if( function_exists('date_timestamp_get') ){
294
- $timestamp = $DateTime->getTimestamp();
295
- }else{
296
- //PHP < 5.3 fallback :/
297
- $timestamp = $DateTime->format('U');
298
- }
299
- $timestamp -= $this->timezone_manual_offset;
300
- $this->setTimestamp( $timestamp );
301
- $return = $this->valid;
302
- }else{
303
- $return = parent::setDate( $year, $month, $day );
304
- }
305
  $this->valid = $return !== false;
306
  return $this;
307
  }
@@ -318,27 +207,13 @@ class EM_DateTime extends DateTime {
318
  }
319
 
320
  /**
321
- * Handles UTC manual offsets along with providing a PHP 5.2.x fallback.
322
  * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
323
  * {@inheritDoc}
324
  * @see DateTime::modify()
325
  */
326
  public function modify( $modify ){
327
- if( function_exists('date_add') ){
328
- $result = parent::modify($modify);
329
- $this->valid = $result !== false;
330
- }else{
331
- //PHP < 5.3 fallback :/ wierd stuff happens when using the DateTime modify function
332
- if( preg_match('/^(first|last) day of this month$/', $modify, $matches) ){
333
- $format = $matches[1] == 'first' ? 'Y-m-01':'Y-m-t';
334
- $timestamp = strtotime($this->format( $format ), $this->getTimestamp());
335
- }else{
336
- $timestamp = strtotime($modify, $this->getTimestamp());
337
- }
338
- $this->valid = $timestamp !== false;
339
- if( $this->valid ) $this->setTimestamp( $timestamp );
340
- }
341
- $this->handleOffsets();
342
  return $this;
343
  }
344
 
@@ -348,21 +223,15 @@ class EM_DateTime extends DateTime {
348
  * @see DateTime::add()
349
  * @param string|DateInterval
350
  * @return EM_DateTime Returns object for chaining.
 
351
  */
352
  public function add( $DateInterval ){
353
- if( function_exists('date_add') ){
354
- if( is_object($DateInterval) ){
355
- $result = parent::add($DateInterval);
356
- }else{
357
- $result = parent::add( new DateInterval($DateInterval) );
358
- }
359
- $this->valid = $result !== false;
360
  }else{
361
- //PHP < 5.3 fallback :/
362
- $strtotime = $this->dateinterval_fallback($DateInterval, 'add');
363
- $this->setTimestamp( strtotime($strtotime, $this->getTimestamp()) );
364
- //$this->valid determined in setTimestamp
365
  }
 
366
  return $this;
367
  }
368
 
@@ -372,53 +241,18 @@ class EM_DateTime extends DateTime {
372
  * @see DateTime::sub()
373
  * @param string|DateInterval
374
  * @return EM_DateTime
 
375
  */
376
  public function sub( $DateInterval ){
377
- if( function_exists('date_sub') ){
378
- if( is_object($DateInterval) ){
379
- $result = parent::sub($DateInterval);
380
- }else{
381
- $result = parent::sub( new DateInterval($DateInterval) );
382
- }
383
- $this->valid = $result !== false;
384
  }else{
385
- //PHP < 5.3 fallback :/
386
- $strtotime = $this->dateinterval_fallback($DateInterval, 'subtract');
387
- $this->setTimestamp( strtotime($strtotime, $this->getTimestamp()) );
388
- //$this->valid determined in setTimestamp
389
  }
 
390
  return $this;
391
  }
392
 
393
- /**
394
- * Fallback function for PHP versions prior to 5.3, as sub() and add() methods aren't available and therefore we need to generate a valid string we can pass onto modify()
395
- * @param string $dateinteval_string
396
- * @param string $add_or_subtract
397
- * @return string
398
- */
399
- private function dateinterval_fallback( $dateinteval_string, $add_or_subtract ){
400
- $date_time_split = explode('T', $dateinteval_string);
401
- $matches = $modify_string_array = array();
402
- //first parse date then time if available
403
- preg_match_all('/([0-9]+)([YMDW])/', preg_replace('/^P/', '', $date_time_split[0]), $matches['date']);
404
- if( !empty($date_time_split[1]) ){
405
- preg_match_all('/([0-9]+)([HMS])/', $date_time_split[1], $matches['time']);
406
- }
407
- //convert DateInterval into a strtotime() valid string for use in $this->modify();
408
- $modify_conversion = array('Y'=>'years', 'M'=>'months', 'D'=>'days', 'W'=>'weeks', 'H'=>'hours', 'S'=>'seconds');
409
- foreach( $matches as $match_type => $match ){
410
- foreach( $match[1] as $k => $v ){
411
- if( $match[2][$k] == 'M' ){
412
- $modify_string_array[] = $match_type == 'time' ? $v . ' minutes': $v . ' months';
413
- }else{
414
- $modify_string_array[] = $v . ' '. $modify_conversion[$match[2][$k]];
415
- }
416
- }
417
- }
418
- $modifier = $add_or_subtract == 'subtract' ? '-':'+';
419
- return $modifier . implode(' '.$modifier, $modify_string_array);
420
- }
421
-
422
  /**
423
  * Easy chainable cloning function, useful for situations where you may want to manipulate the current date,
424
  * such as adding a month and getting the DATETIME string without changing the original value of this object.
@@ -428,24 +262,6 @@ class EM_DateTime extends DateTime {
428
  return clone $this;
429
  }
430
 
431
- /**
432
- * {@inheritDoc}
433
- * @see DateTime::getTimestamp()
434
- */
435
- public function getTimestamp(){
436
- if( function_exists('date_timestamp_get') ){
437
- return parent::getTimestamp();
438
- }else{
439
- //PHP < 5.3 fallback :/
440
- $strtotime = parent::format('Y-m-d H:i:s');
441
- $timestamp = strtotime($strtotime);
442
- //offset timestamp in case plugins change default timezone
443
- $server_offset = date('Z',$timestamp);
444
- $timestamp += $server_offset;
445
- return $timestamp;
446
- }
447
- }
448
-
449
  /**
450
  * Gets a timestamp with an offset, which will represent the local time equivalent in UTC time.
451
  * If using this to supply to a date() function, set $server_localized to true which will account for any rogue code
@@ -456,24 +272,7 @@ class EM_DateTime extends DateTime {
456
  public function getTimestampWithOffset( $server_localized = false ){
457
  //aside from the actual offset from the timezone, we also have a local server offset we need to deal with here...
458
  $server_offset = $server_localized ? date('Z',$this->getTimestamp()) : 0;
459
- if( function_exists('date_timestamp_get') ){
460
- return $this->getOffset() + $this->getTimestamp() - $server_offset;
461
- }else{
462
- //PHP < 5.3 fallback :/
463
- return $this->getTimestamp() - $server_offset;
464
- }
465
- }
466
-
467
- /**
468
- * Extends DateTime::getOffset() by checking for timezones with manual offsets, such as UTC+3.5
469
- * @see DateTime::getOffset()
470
- * @return int
471
- */
472
- public function getOffset(){
473
- if( $this->timezone_manual_offset !== false ){
474
- return $this->timezone_manual_offset;
475
- }
476
- return parent::getOffset();
477
  }
478
 
479
  /**
@@ -524,10 +323,7 @@ class EM_DateTime extends DateTime {
524
  return $return;
525
  }
526
 
527
- /* PHP 5.3+ functions that are not used and should not be used until 5.3 is a minimum requirement
528
-
529
  /**
530
- * NOT TO BE USED until PHP 5.3 is a minimum requirement in WordPress
531
  * Extends the DateTime::createFromFormat() function by setting the timezone to the default blog timezone if none is provided.
532
  * @param string $format
533
  * @param string $time
@@ -540,109 +336,4 @@ class EM_DateTime extends DateTime {
540
  if( $DateTime === false ) return false;
541
  return new EM_DateTime($DateTime->format('Y-m-d H:i:s'), $timezone);
542
  }
543
-
544
- public function diff( $DateTime, $absolute = null ){
545
- if( function_exists('date_diff') ){
546
- return parent::diff( $DateTime, $absolute );
547
- }else{
548
- //PHP < 5.3 fallback :/ there is no fallback, really
549
- return new stdClass();
550
- }
551
- }
552
- }
553
-
554
- /**
555
- * Extends the native DateTimeZone object by allowing for UTC manual offsets as supported by WordPress, along with eash creation of a DateTimeZone object with the blog's timezone.
556
- * @since 5.8.2
557
- */
558
- class EM_DateTimeZone extends DateTimeZone {
559
-
560
- public $manual_offset = false;
561
-
562
- public function __construct( $timezone ){
563
- //if we're not suppiled a DateTimeZone object, create one from string or implement manual offset
564
- if( $timezone != 'UTC' ){
565
- $timezone = preg_replace('/^UTC ?/', '', $timezone);
566
- if( is_numeric($timezone) ){
567
- if( absint($timezone) == 0 ){
568
- $timezone = 'UTC';
569
- }else{
570
- $this->manual_offset = $timezone * 3600;
571
- $timezone = 'UTC';
572
- }
573
- }
574
- }
575
- parent::__construct($timezone);
576
- }
577
-
578
- /**
579
- * Special function which converts a timezone string, UTC offset or DateTimeZone object into a valid EM_DateTimeZone object.
580
- * If no value supplied, a EM_DateTimezone with the default WP environment timezone is created.
581
- * @param mixed $timezone
582
- * @return EM_DateTimeZone
583
- */
584
- public static function create( $timezone = false ){
585
- //if we're not suppiled a DateTimeZone object, create one from string or implement manual offset
586
- if( !empty($timezone) && !is_object($timezone) ){
587
- //create EM_DateTimeZone object if valid, otherwise allow defaults to override later
588
- try {
589
- $timezone = new EM_DateTimeZone($timezone);
590
- }catch( Exception $e ){
591
- $timezone = null;
592
- }
593
- }elseif( is_object($timezone) && get_class($timezone) == 'DateTimeZone'){
594
- //if supplied a regular DateTimeZone, convert it to EM_DateTimeZone
595
- $timezone = new EM_DateTimeZone($timezone->getName());
596
- }
597
- if( !is_object($timezone) ){
598
- //if no valid timezone supplied, get the default timezone in EM environment, otherwise the WP timezone or offset
599
- $timezone = get_option( 'timezone_string' );
600
- if( !$timezone ) $timezone = get_option('gmt_offset');
601
- $timezone = new EM_DateTimeZone($timezone);
602
- }
603
- return $timezone;
604
- }
605
-
606
- /**
607
- * {@inheritDoc}
608
- * @see DateTimeZone::getOffset()
609
- */
610
- public function getOffset( $datetime ){
611
- if( $this->manual_offset !== false ){
612
- return $this->manual_offset;
613
- }
614
- return parent::getOffset( $datetime );
615
- }
616
-
617
- /**
618
- * {@inheritDoc}
619
- * @see DateTimeZone::getName()
620
- */
621
- public function getName(){
622
- if( $this->manual_offset !== false ){
623
- if( $this->manual_offset > 0 ){
624
- $return = 'UTC+'.$this->manual_offset/3600;
625
- }else{
626
- $return = 'UTC'.$this->manual_offset/3600;
627
- }
628
- return $return;
629
- }
630
- return parent::getName();
631
- }
632
-
633
- /**
634
- * If the timezone has a manual UTC offset, then an empty array of transitions is returned.
635
- * {@inheritDoc}
636
- * @see DateTimeZone::getTransitions()
637
- */
638
- public function getTransitions( $timestamp_begin = null, $timestamp_end = null ){
639
- if( $this->manual_offset !== false ){
640
- return array();
641
- }
642
- if( version_compare(phpversion(), '5.3') < 0 ){
643
- return parent::getTransitions();
644
- }else{
645
- return parent::getTransitions($timestamp_begin, $timestamp_end);
646
- }
647
- }
648
  }
2
  /**
3
  * Extends DateTime allowing supplied timezone to be a string, which can also be a UTC offset.
4
  * Also prevents an exception being thrown. Some additional shortcuts added so less coding is required for regular tasks.
5
+ * By doing this, we support WP's option to manually offset time with a UTC timezone name e.g. UTC+1.5, which isn't supported by PHP (it only supports numerical offsets which represent UTC offsets)
6
+ *
7
  * @since 5.8.2
8
  */
9
  class EM_DateTime extends DateTime {
14
  */
15
  protected $timezone_name = false;
16
  /**
17
+ * @var bool Whether or not string is UTC offset with a UTC+-d timezone name pattern, which isn't supported in PHP normally.
 
18
  */
19
+ protected $timezone_utc = false;
20
  /**
21
  * Flag for validation purposes, so we can still have a real EM_DateTime and extract dates but know if the intended datetime failed validation.
22
  * A completely invalid date and time will become 1970-01-01 00:00:00 in local timezone, however a valid time can still exist with the 1970-01-01 date.
29
  * @see DateTime::__construct()
30
  * @param string $time
31
  * @param string|EM_DateTimeZone $timezone Unlike DateTime this also accepts string representation of a valid timezone, as well as UTC offsets in form of 'UTC -3' or just '-3'
 
32
  */
33
  public function __construct( $time = 'now', $timezone = null ){
34
  //get our EM_DateTimeZone
35
  $timezone = EM_DateTimeZone::create($timezone);
36
  //save timezone name for use in getTimezone()
37
  $this->timezone_name = $timezone->getName();
38
+ $this->timezone_utc = $timezone->utc_offset !== false;
39
  //fix DateTime error if a regular timestamp is supplied without prepended @ symbol
40
  if( is_numeric($time) ){
41
  $time = '@'.$time;
49
  $this->valid = true; //if we get this far, supplied time is valid
50
  }catch( Exception $e ){
51
  //get current date/time in relevant timezone and set valid flag to false
52
+ try {
53
+ parent::__construct('@0');
54
+ }catch( Exception $e ){
55
+ // do nothing
56
+ }finally{
57
+ $this->setTimezone($timezone);
58
+ $this->setDate(1970,1,1);
59
+ $this->setTime(0,0,0);
60
+ $this->valid = false;
61
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  }
63
  }
64
 
68
  */
69
  public function format( $format = 'Y-m-d H:i:s'){
70
  if( !$this->valid && ($format == 'Y-m-d' || $format == em_get_date_format())) return '';
71
+ if( $format !== 'Y-m-d H:i:s' ) $format = $this->formatTimezones($format); // format UTC timezones
 
 
 
 
 
 
 
 
 
 
 
72
  return parent::format($format);
73
  }
74
 
75
  /**
76
+ * Formats timezone name/abbreviation placeholders when there is a manual offset, which would be passed onto date formatting functions and usually output UTC timezone information.
 
77
  * @param string $format The format to be parsed.
 
78
  * @return string
79
  */
80
+ public function formatTimezones($format){
81
+ if( $this->timezone_utc ){
82
+ $timezone_formats = array( 'T', 'e' );
83
+ foreach ( $timezone_formats as $timezone_format ) {
84
+ if ( false !== strpos( $format, $timezone_format ) ) {
85
+ $format = ' '.$format;
86
+ $format = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $this->timezone_name ), $format );
87
+ $format = substr( $format, 1, strlen( $format ) -1 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
  }
90
  }
103
  }
104
 
105
  /**
106
+ * Provides a translated date and time according to the current blog language.
107
  * Useful if using formats that provide date-related names such as 'Monday' or 'January', which should be translated if displayed in another language.
108
  * @param string $format
109
  * @return string
110
  */
111
  public function i18n( $format = 'Y-m-d H:i:s' ){
112
  if( !$this->valid && $format == em_get_date_format()) return '';
113
+ // since we use WP's date functions which don't use DateTime (and if so, don't inherit our timezones), we need to preformat timezone related formats, adapted from date_i18n
114
+ $format = $this->formatTimezones( $format );
115
+ // support for < WP 5.3.0
116
+ if( function_exists('wp_date') ){
 
 
 
 
 
117
  return wp_date( $format, $this->getTimestamp(), $this->getTimezone() );
118
  }else{
119
  return date_i18n( $format, $this->getTimestampWithOffset(true) );
121
  }
122
 
123
  /**
124
+ * Outputs a default mysql datetime formatted string.
125
  * @return string
126
  */
127
  public function __toString(){
145
  }
146
 
147
  /**
148
+ * Sets timestamp and returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
 
149
  * @param int $timestamp
150
  * @see DateTime::setTimestamp()
151
  * @return EM_DateTime
152
  */
153
  public function setTimestamp( $timestamp ){
154
+ $return = parent::setTimestamp( $timestamp );
155
+ $this->valid = $return !== false;
 
 
 
 
 
 
 
 
156
  return $this;
157
  }
158
 
159
  /**
160
+ * Extends DateTime functionality by accepting a false or string value for a timezone. If set to false, default WP timezone will be used.
161
  * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
162
+ * @param string|false $timezone
163
  * @see DateTime::setTimezone()
164
  * @return EM_DateTime Returns object for chaining.
165
  */
166
+ public function setTimezone( $timezone = false ){
167
  if( $timezone == $this->getTimezone()->getName() ) return $this;
168
  $timezone = EM_DateTimeZone::create($timezone);
169
  $return = parent::setTimezone($timezone);
170
  $this->timezone_name = $timezone->getName();
171
+ $this->timezone_utc = $timezone->utc_offset !== false;
172
  $this->valid = $return !== false;
173
  return $this;
174
  }
175
 
176
  /**
177
+ * Sets time along and returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
 
178
  * {@inheritDoc}
179
  * @see DateTime::setTime()
180
  */
181
  public function setTime( $hour, $minute, $second = NULL, $microseconds = NULL ){
 
 
 
 
 
 
 
 
 
 
 
 
182
  $return = parent::setTime( (int) $hour, (int) $minute, (int) $second );
 
 
 
 
 
183
  $this->valid = $return !== false;
184
  return $this;
185
  }
186
 
187
  /**
188
+ * Sets date along and returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
 
189
  * {@inheritDoc}
190
  * @see DateTime::setDate()
191
  */
192
  public function setDate( $year, $month, $day ){
193
+ $return = parent::setDate( $year, $month, $day );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194
  $this->valid = $return !== false;
195
  return $this;
196
  }
207
  }
208
 
209
  /**
 
210
  * Returns EM_DateTime object in all cases, but $this->valid will be set to false if unsuccessful
211
  * {@inheritDoc}
212
  * @see DateTime::modify()
213
  */
214
  public function modify( $modify ){
215
+ $result = parent::modify($modify);
216
+ $this->valid = $result !== false;
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  return $this;
218
  }
219
 
223
  * @see DateTime::add()
224
  * @param string|DateInterval
225
  * @return EM_DateTime Returns object for chaining.
226
+ * @throws Exception
227
  */
228
  public function add( $DateInterval ){
229
+ if( is_object($DateInterval) ){
230
+ $result = parent::add($DateInterval);
 
 
 
 
 
231
  }else{
232
+ $result = parent::add( new DateInterval($DateInterval) );
 
 
 
233
  }
234
+ $this->valid = $result !== false;
235
  return $this;
236
  }
237
 
241
  * @see DateTime::sub()
242
  * @param string|DateInterval
243
  * @return EM_DateTime
244
+ * @throws Exception
245
  */
246
  public function sub( $DateInterval ){
247
+ if( is_object($DateInterval) ){
248
+ $result = parent::sub($DateInterval);
 
 
 
 
 
249
  }else{
250
+ $result = parent::sub( new DateInterval($DateInterval) );
 
 
 
251
  }
252
+ $this->valid = $result !== false;
253
  return $this;
254
  }
255
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
256
  /**
257
  * Easy chainable cloning function, useful for situations where you may want to manipulate the current date,
258
  * such as adding a month and getting the DATETIME string without changing the original value of this object.
262
  return clone $this;
263
  }
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  /**
266
  * Gets a timestamp with an offset, which will represent the local time equivalent in UTC time.
267
  * If using this to supply to a date() function, set $server_localized to true which will account for any rogue code
272
  public function getTimestampWithOffset( $server_localized = false ){
273
  //aside from the actual offset from the timezone, we also have a local server offset we need to deal with here...
274
  $server_offset = $server_localized ? date('Z',$this->getTimestamp()) : 0;
275
+ return $this->getOffset() + $this->getTimestamp() - $server_offset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
276
  }
277
 
278
  /**
323
  return $return;
324
  }
325
 
 
 
326
  /**
 
327
  * Extends the DateTime::createFromFormat() function by setting the timezone to the default blog timezone if none is provided.
328
  * @param string $format
329
  * @param string $time
336
  if( $DateTime === false ) return false;
337
  return new EM_DateTime($DateTime->format('Y-m-d H:i:s'), $timezone);
338
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  }
classes/em-datetimezone.php ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Extends the native DateTimeZone object by allowing for UTC manual offsets as supported by WordPress, along with eash creation of a DateTimeZone object with the blog's timezone.
4
+ * @since 5.8.2
5
+ */
6
+ class EM_DateTimeZone extends DateTimeZone {
7
+
8
+ public $utc_offset = false;
9
+
10
+ public function __construct( $timezone ){
11
+ //if we're not suppiled a DateTimeZone object, create one from string or implement manual offset
12
+ if( $timezone != 'UTC' ){
13
+ $timezone = preg_replace('/^UTC ?/', '', $timezone);
14
+ if( is_numeric($timezone) ){
15
+ if( absint($timezone) == 0 ){
16
+ $timezone = 'UTC';
17
+ }else{
18
+ // convert this to an offset, taken from wp_timezone
19
+ $offset = (float) $timezone;
20
+ $hours = (int) $offset;
21
+ $minutes = ( $offset - $hours );
22
+ $sign = ( $offset < 0 ) ? '-' : '+';
23
+ $abs_hour = abs( $hours );
24
+ $abs_mins = abs( $minutes * 60 );
25
+ $timezone = sprintf( '%s%02d%02d', $sign, $abs_hour, $abs_mins );
26
+ $this->utc_offset = sprintf( 'UTC%s%d', $sign, abs($offset) );
27
+ }
28
+ }
29
+ }
30
+ parent::__construct($timezone);
31
+ }
32
+
33
+ /**
34
+ * Special function which converts a timezone string, UTC offset or DateTimeZone object into a valid EM_DateTimeZone object.
35
+ * If no value supplied, a EM_DateTimezone with the default WP environment timezone is created.
36
+ * @param mixed $timezone
37
+ * @return EM_DateTimeZone
38
+ */
39
+ public static function create( $timezone = false ){
40
+ //if we're not suppiled a DateTimeZone object, create one from string or implement manual offset
41
+ if( !empty($timezone) && !is_object($timezone) ){
42
+ //create EM_DateTimeZone object if valid, otherwise allow defaults to override later
43
+ try {
44
+ $timezone = new EM_DateTimeZone($timezone);
45
+ }catch( Exception $e ){
46
+ $timezone = null;
47
+ }
48
+ }elseif( is_object($timezone) && get_class($timezone) == 'DateTimeZone'){
49
+ //if supplied a regular DateTimeZone, convert it to EM_DateTimeZone
50
+ $timezone = new EM_DateTimeZone($timezone->getName());
51
+ }
52
+ if( !is_object($timezone) ){
53
+ //if no valid timezone supplied, get the default timezone in EM environment, otherwise the WP timezone or offset
54
+ $timezone = get_option( 'timezone_string' );
55
+ if( !$timezone ) $timezone = get_option('gmt_offset');
56
+ $timezone = new EM_DateTimeZone($timezone);
57
+ }
58
+ return $timezone;
59
+ }
60
+
61
+ /**
62
+ * {@inheritDoc}
63
+ * @see DateTimeZone::getName()
64
+ */
65
+ public function getName(){
66
+ if( $this->utc_offset !== false ){
67
+ return $this->utc_offset;
68
+ }
69
+ return parent::getName();
70
+ }
71
+
72
+ /**
73
+ * If the timezone has a manual UTC offset, then an empty array of transitions is returned.
74
+ * {@inheritDoc}
75
+ * @see DateTimeZone::getTransitions()
76
+ */
77
+ public function getTransitions( $timestamp_begin = null, $timestamp_end = null ){
78
+ if( $this->utc_offset !== false ){
79
+ return array();
80
+ }
81
+ return parent::getTransitions($timestamp_begin, $timestamp_end);
82
+ }
83
+ }
classes/em-event-posts-admin.php CHANGED
@@ -14,7 +14,7 @@ class EM_Event_Posts_Admin{
14
  //hide some cols by default:
15
  $screen = 'edit-'.EM_POST_TYPE_EVENT;
16
  $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
17
- if( !$hidden ){
18
  $hidden = array('event-id');
19
  update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
20
  }
@@ -24,8 +24,8 @@ class EM_Event_Posts_Admin{
24
  add_action('admin_head', array('EM_Event_Posts_Admin','admin_head'));
25
  }
26
  //collumns
27
- add_filter('manage_edit-'.EM_POST_TYPE_EVENT.'_columns' , array('EM_Event_Posts_Admin','columns_add'));
28
- add_filter('manage_'.EM_POST_TYPE_EVENT.'_posts_custom_column' , array('EM_Event_Posts_Admin','columns_output'),10,2 );
29
  add_filter('manage_edit-'.EM_POST_TYPE_EVENT.'_sortable_columns', array('EM_Event_Posts_Admin','sortable_columns') );
30
  //clean up the views in the admin selection area - WIP
31
  //add_filter('views_edit-'.EM_POST_TYPE_EVENT, array('EM_Event_Posts_Admin','restrict_views'),10,2);
@@ -297,9 +297,9 @@ class EM_Event_Recurring_Posts_Admin{
297
  global $pagenow;
298
  if( $pagenow == 'edit.php' && !empty($_REQUEST['post_type']) && $_REQUEST['post_type'] == 'event-recurring' ){
299
  //hide some cols by default:
300
- $screen = 'edit-'.EM_POST_TYPE_EVENT;
301
  $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
302
- if( !$hidden ){
303
  $hidden = array('event-id');
304
  update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
305
  }
@@ -311,8 +311,8 @@ class EM_Event_Recurring_Posts_Admin{
311
  add_filter($row_action_type, array('EM_Event_Recurring_Posts_Admin','row_actions'),10,2);
312
  }
313
  //collumns
314
- add_filter('manage_edit-event-recurring_columns' , array('EM_Event_Recurring_Posts_Admin','columns_add'));
315
- add_filter('manage_posts_custom_column' , array('EM_Event_Recurring_Posts_Admin','columns_output'),10,1 );
316
  add_action('restrict_manage_posts', array('EM_Event_Posts_Admin','restrict_manage_posts'));
317
  add_filter( 'manage_edit-event-recurring_sortable_columns', array('EM_Event_Posts_Admin','sortable_columns') );
318
  }
14
  //hide some cols by default:
15
  $screen = 'edit-'.EM_POST_TYPE_EVENT;
16
  $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
17
+ if( $hidden === false ){
18
  $hidden = array('event-id');
19
  update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
20
  }
24
  add_action('admin_head', array('EM_Event_Posts_Admin','admin_head'));
25
  }
26
  //collumns
27
+ add_filter('manage_'.EM_POST_TYPE_EVENT.'_posts_columns' , array('EM_Event_Posts_Admin','columns_add'));
28
+ add_action('manage_'.EM_POST_TYPE_EVENT.'_posts_custom_column' , array('EM_Event_Posts_Admin','columns_output'),10,2 );
29
  add_filter('manage_edit-'.EM_POST_TYPE_EVENT.'_sortable_columns', array('EM_Event_Posts_Admin','sortable_columns') );
30
  //clean up the views in the admin selection area - WIP
31
  //add_filter('views_edit-'.EM_POST_TYPE_EVENT, array('EM_Event_Posts_Admin','restrict_views'),10,2);
297
  global $pagenow;
298
  if( $pagenow == 'edit.php' && !empty($_REQUEST['post_type']) && $_REQUEST['post_type'] == 'event-recurring' ){
299
  //hide some cols by default:
300
+ $screen = 'edit-event-recurring';
301
  $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
302
+ if( $hidden === false ){
303
  $hidden = array('event-id');
304
  update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
305
  }
311
  add_filter($row_action_type, array('EM_Event_Recurring_Posts_Admin','row_actions'),10,2);
312
  }
313
  //collumns
314
+ add_filter('manage_event-recurring_posts_columns' , array('EM_Event_Recurring_Posts_Admin','columns_add'));
315
+ add_filter('manage_event-recurring_posts_custom_column' , array('EM_Event_Recurring_Posts_Admin','columns_output'),10,1 );
316
  add_action('restrict_manage_posts', array('EM_Event_Posts_Admin','restrict_manage_posts'));
317
  add_filter( 'manage_edit-event-recurring_sortable_columns', array('EM_Event_Posts_Admin','sortable_columns') );
318
  }
classes/em-event.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /**
3
  * Get an event in a db friendly way, by checking globals, cache and passed variables to avoid extra class instantiations.
4
  * @param mixed $id can be either a post object, event object, event id or post id
@@ -49,14 +50,23 @@ function em_get_event($id = false, $search_by = 'event_id') {
49
  * The single event might be part of a set of recurring events, but if loaded by specific event id then any operations and saves are
50
  * specifically done on this event. However, if you edit the recurring group, any changes made to single events are overwritten.
51
  *
52
- * @property string $language Language of the event, shorthand for event_language
53
- * @property string $translation Whether or not a event is a translation (i.e. it was translated from an original event), shorthand for event_translation
54
- * @property int $parent Event ID of parent event, shorthand for event_parent
55
- * @property int $id The Event ID, case sensitive, shorthand for event_id
56
- * @property string $slug Event slug, shorthand for event_slug
57
- * @property string name Event name, shorthand for event_name
58
- * @property int owner ID of author/owner, shorthand for event_owner
59
- * @property int status ID of post status, shorthand for event_status
 
 
 
 
 
 
 
 
 
60
  *
61
  */
62
  //TODO Can add more recurring functionality such as "also update all future recurring events" or "edit all events" like google calendar does.
@@ -119,7 +129,7 @@ class EM_Event extends EM_Object{
119
  var $post_content;
120
  var $event_rsvp = 0;
121
  protected $event_rsvp_date;
122
- protected $event_rsvp_time = "00:00:00";
123
  var $event_rsvp_spaces;
124
  var $event_spaces;
125
  var $event_private;
@@ -144,7 +154,7 @@ class EM_Event extends EM_Object{
144
  */
145
  var $event_attributes = array();
146
  /* Recurring Specific Values */
147
- var $recurrence;
148
  var $recurrence_interval;
149
  var $recurrence_freq;
150
  var $recurrence_byday;
@@ -189,7 +199,7 @@ class EM_Event extends EM_Object{
189
  'group_id' => array( 'name'=>'group_id', 'type'=>'%d', 'null'=>true ),
190
  'event_language' => array( 'type'=>'%s', 'null'=>true ),
191
  'event_translation' => array( 'type'=>'%d'),
192
- 'recurrence' => array( 'name'=>'recurrence', 'type'=>'%d', 'null'=>true ), //is this a recurring event template
193
  'recurrence_interval' => array( 'name'=>'interval', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
194
  'recurrence_freq' => array( 'name'=>'freq', 'type'=>'%s', 'null'=>true ), //daily,weekly,monthly?
195
  'recurrence_days' => array( 'name'=>'days', 'type'=>'%d', 'null'=>true ), //each event spans x days
@@ -237,9 +247,14 @@ class EM_Event extends EM_Object{
237
  */
238
  var $location;
239
  /**
240
- * @var array
 
 
 
 
 
241
  */
242
- var $event_location_data = array();
243
  /**
244
  * @var EM_Bookings
245
  */
@@ -354,6 +369,7 @@ class EM_Event extends EM_Object{
354
  if( $id == 0 ) $id = false;
355
  }
356
  if( is_numeric($id) || $is_post ){ //only load info if $id is a number
 
357
  if($search_by == 'event_id' && !$is_post ){
358
  //search by event_id, get post_id and blog_id (if in ms mode) and load the post
359
  $results = $wpdb->get_row($wpdb->prepare("SELECT post_id, blog_id FROM ".EM_EVENTS_TABLE." WHERE event_id=%d",$id), ARRAY_A);
@@ -362,7 +378,7 @@ class EM_Event extends EM_Object{
362
  if( $results['blog_id']=='' ) $results['blog_id'] = get_current_site()->blog_id;
363
  $event_post = get_blog_post($results['blog_id'], $results['post_id']);
364
  $search_by = $this->blog_id = $results['blog_id'];
365
- }else{
366
  $event_post = get_post($results['post_id']);
367
  }
368
  }else{
@@ -483,6 +499,10 @@ class EM_Event extends EM_Object{
483
  public function __clone(){
484
  $this->bookings = null;
485
  $this->location = null;
 
 
 
 
486
  }
487
 
488
  function load_postdata($event_post, $search_by = false){
@@ -502,7 +522,7 @@ class EM_Event extends EM_Object{
502
  //load meta data and other related information
503
  if( $event_post->post_status != 'auto-draft' ){
504
  $event_meta = $this->get_event_meta($search_by);
505
- if( !empty($even_meta['_event_location_type']) ) $this->event_location_type = $even_meta['_event_location_type']; //load this directly so we know further down whether this has an event location type to load
506
  //Get custom fields and post meta
507
  foreach($event_meta as $event_meta_key => $event_meta_val){
508
  $field_name = substr($event_meta_key, 1);
@@ -694,8 +714,12 @@ class EM_Event extends EM_Object{
694
  }else{
695
  // we're dealing with an event location such as a url or webinar
696
  $this->location_id = null; // no location ID
 
 
 
 
697
  $this->event_location_type = $location_type;
698
- if( EM_Event_Locations\Event_Locations::is_enabled($location_type) ){
699
  $this->get_event_location()->get_post();
700
  }
701
  }
@@ -731,8 +755,8 @@ class EM_Event extends EM_Object{
731
  }else{
732
  //if no rsvp cut-off date supplied, make it the event start date
733
  $this->event_rsvp_date = ( !empty($_POST['event_rsvp_date']) ) ? wp_kses_data($_POST['event_rsvp_date']) : $this->event_start_date;
734
- if ( empty($_POST['event_rsvp_date']) || empty($_POST['event_rsvp_time']) ) $this->event_rsvp_time = $this->event_start_time;
735
- if( $this->event_all_day && empty($_POST['event_rsvp_date']) ){ $this->event_rsvp_time = '00:00:00'; } //all-day events start at 0 hour
736
  }
737
  //reset EM_DateTime object
738
  $this->rsvp_end = null;
@@ -874,6 +898,7 @@ class EM_Event extends EM_Object{
874
  foreach( $this->recurrence_fields as $recurrence_field ){
875
  $this->$recurrence_field = null;
876
  }
 
877
  }
878
  //event language
879
  if( EM_ML::$is_ml && !empty($_POST['event_language']) && array_key_exists($_POST['event_language'], EM_ML::$langs) ){
@@ -1136,12 +1161,6 @@ class EM_Event extends EM_Object{
1136
  }
1137
  }
1138
  }
1139
- //update event location via post meta
1140
- if( $this->has_event_location() ){
1141
- $this->get_event_location()->save();
1142
- }else{
1143
- $this->get_event_location()->reset_data();
1144
- }
1145
  //update timestamps, dates and times
1146
  update_post_meta($this->post_id, '_event_start_local', $this->start()->getDateTime());
1147
  update_post_meta($this->post_id, '_event_end_local', $this->end()->getDateTime());
@@ -1214,6 +1233,17 @@ class EM_Event extends EM_Object{
1214
  update_post_meta($this->post_id, '_event_owner_anonymous', 1);
1215
  }
1216
  }
 
 
 
 
 
 
 
 
 
 
 
1217
  //Add/Delete Tickets
1218
  if($this->event_rsvp == 0){
1219
  if( !$this->just_added_event ){
@@ -1267,7 +1297,7 @@ class EM_Event extends EM_Object{
1267
  * @return EM_Event
1268
  */
1269
  function duplicate(){
1270
- global $wpdb, $EZSQL_ERROR;
1271
  //First, duplicate.
1272
  if( $this->can_manage('edit_events','edit_others_events') ){
1273
  $EM_Event = clone $this;
@@ -1379,6 +1409,9 @@ class EM_Event extends EM_Object{
1379
  if( $result !== false ){
1380
  $this->get_bookings()->delete();
1381
  $this->get_tickets()->delete();
 
 
 
1382
  //Delete the recurrences then this recurrence event
1383
  if( $this->is_recurring() ){
1384
  $result = $this->delete_events(); //was true at this point, so false if fails
@@ -1662,15 +1695,15 @@ class EM_Event extends EM_Object{
1662
  /**
1663
  * Gets the event's event location (note, different from a regular event location, which uses get_location())
1664
  * Returns implementation of Event_Location or false if no event location assigned.
1665
- * @return EM_Event_Locations\URL|EM_Event_Locations\Event_Location|false
1666
  */
1667
  public function get_event_location(){
 
 
1668
  if( $this->has_event_location() ){
1669
- $EM_Location_Type = EM_Event_Locations\Event_Locations::get( $this->event_location_type, $this );
1670
- }else{
1671
- $EM_Location_Type = new EM_Event_Locations\Event_Location( $this );
1672
  }
1673
- return apply_filters('em_event_get_event_location', $EM_Location_Type, $this);
1674
  }
1675
 
1676
  /**
@@ -1679,10 +1712,10 @@ class EM_Event extends EM_Object{
1679
  * @return bool
1680
  */
1681
  public function has_event_location( $event_location_type = null ){
1682
- if( !empty($event_location_type) ){
1683
- return !empty($this->event_location_type) && $this->event_location_type === $event_location_type;
1684
  }
1685
- return !empty($this->event_location_type);
1686
  }
1687
 
1688
  /**
@@ -1876,20 +1909,35 @@ class EM_Event extends EM_Object{
1876
  //$format = do_shortcode($format); //parse shortcode first, so that formats within shortcodes are parsed properly, however uncommenting this will break shortcode containing placeholders for arguments
1877
  $event_string = $format;
1878
  //Time place holder that doesn't show if empty.
1879
- preg_match_all('/#@?_\{[^}]+\}/', $format, $results);
1880
  foreach($results[0] as $result) {
1881
  if(substr($result, 0, 3 ) == "#@_"){
1882
  $date = 'end';
1883
- $offset = 4;
 
 
 
 
 
1884
  }else{
1885
  $date = 'start';
1886
- $offset = 3;
 
 
 
 
 
1887
  }
1888
- if( $date == 'end' && $this->event_end_date == $this->event_start_date ){
1889
- $replace = __( apply_filters('em_event_output_placeholder', '', $this, $result, $target) );
1890
  }else{
1891
  $date_format = substr( $result, $offset, (strlen($result)-($offset+1)) );
1892
- $replace = apply_filters('em_event_output_placeholder', $this->$date()->i18n($date_format), $this, $result, $target);
 
 
 
 
 
1893
  }
1894
  $event_string = str_replace($result,$replace,$event_string );
1895
  }
@@ -1905,16 +1953,18 @@ class EM_Event extends EM_Object{
1905
  //Strip string of placeholder and just leave the reference
1906
  $attRef = substr( substr($result, 0, strpos($result, '}')), 6 );
1907
  $attString = '';
 
1908
  if( is_array($this->event_attributes) && array_key_exists($attRef, $this->event_attributes) ){
1909
  $attString = $this->event_attributes[$attRef];
1910
  }elseif( !empty($results[3][$resultKey]) ){
1911
  //Check to see if we have a second set of braces;
 
1912
  $attStringArray = explode('|', $results[3][$resultKey]);
1913
  $attString = $attStringArray[0];
1914
  }elseif( !empty($attributes['values'][$attRef][0]) ){
1915
  $attString = $attributes['values'][$attRef][0];
1916
  }
1917
- $attString = apply_filters('em_event_output_placeholder', $attString, $this, $result, $target);
1918
  $event_string = str_replace($result, $attString ,$event_string );
1919
  }
1920
  //First let's do some conditional placeholder removals
@@ -2091,12 +2141,14 @@ class EM_Event extends EM_Object{
2091
  }
2092
  }
2093
  //Now let's check out the placeholders.
2094
- preg_match_all("/(#@?_?[A-Za-z0-9]+)({([^}]+)})?/", $event_string, $placeholders);
2095
  $replaces = array();
2096
  foreach($placeholders[1] as $key => $result) {
2097
  $match = true;
2098
  $replace = '';
2099
  $full_result = $placeholders[0][$key];
 
 
2100
  switch( $result ){
2101
  //Event Details
2102
  case '#_EVENTID':
@@ -2161,7 +2213,7 @@ class EM_Event extends EM_Object{
2161
  switch_to_blog($this->blog_id);
2162
  $switch_back = true;
2163
  }
2164
- $replace = get_the_post_thumbnail($this->ID, $image_size);
2165
  if( !empty($switch_back) ){ restore_current_blog(); }
2166
  }
2167
  }else{
@@ -2176,24 +2228,110 @@ class EM_Event extends EM_Object{
2176
  case '#_24HENDTIME':
2177
  $replace = ($result == '#_24HSTARTTIME') ? $this->start()->format('H:i'):$this->end()->format('H:i');
2178
  break;
 
 
 
 
 
 
 
 
 
 
 
2179
  case '#_12HSTARTTIME':
2180
  case '#_12HENDTIME':
2181
  $replace = ($result == '#_12HSTARTTIME') ? $this->start()->format('g:i A'):$this->end()->format('g:i A');
2182
  break;
 
 
 
 
 
 
 
 
 
 
 
2183
  case '#_EVENTTIMES':
2184
  //get format of time to show
2185
  $replace = $this->output_times();
2186
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2187
  case '#_EVENTDATES':
2188
  //get format of time to show
2189
  $replace = $this->output_dates();
2190
  break;
 
 
 
 
2191
  case '#_EVENTTIMEZONE':
2192
  $replace = str_replace('_', ' ', $this->event_timezone);
2193
  break;
2194
  case '#_EVENTTIMEZONERAW':
2195
  $replace = $this->event_timezone;
2196
  break;
 
 
 
 
 
 
 
 
 
 
 
2197
  //Recurring Placeholders
2198
  case '#_RECURRINGDATERANGE': //Outputs the #_EVENTDATES equivalent of the recurring event template pattern.
2199
  $replace = $this->get_event_recurrence()->output_dates(); //if not a recurrence, we're running output_dates on $this
@@ -2507,7 +2645,7 @@ class EM_Event extends EM_Object{
2507
  $replace = $full_result;
2508
  break;
2509
  }
2510
- $replaces[$full_result] = apply_filters('em_event_output_placeholder', $replace, $this, $full_result, $target);
2511
  }
2512
  //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
2513
  krsort($replaces);
@@ -2525,13 +2663,13 @@ class EM_Event extends EM_Object{
2525
  // matches all PHP START date and time placeholders
2526
  if (preg_match('/^#[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
2527
  $replace = $this->start()->i18n(ltrim($result, "#"));
2528
- $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target);
2529
  $event_string = str_replace($result, $replace, $event_string );
2530
  }
2531
  // matches all PHP END time placeholders for endtime
2532
  if (preg_match('/^#@[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
2533
  $replace = $this->end()->i18n(ltrim($result, "#@"));
2534
- $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target);
2535
  $event_string = str_replace($result, $replace, $event_string );
2536
  }
2537
  }
@@ -2585,28 +2723,44 @@ class EM_Event extends EM_Object{
2585
  return apply_filters('em_event_output', $event_string, $this, $format, $target);
2586
  }
2587
 
2588
- function output_times( $time_format = false, $time_separator = false , $all_day_message = false ){
2589
  if( !$this->event_all_day ){
2590
  if( empty($time_format) ) $time_format = ( get_option('dbem_time_format') ) ? get_option('dbem_time_format'):get_option('time_format');
2591
  if( empty($time_separator) ) $time_separator = get_option('dbem_times_separator');
2592
  if( $this->event_start_time != $this->event_end_time ){
2593
- $replace = $this->start()->i18n($time_format). $time_separator . $this->end()->i18n($time_format);
 
 
 
 
2594
  }else{
2595
- $replace = $this->start()->i18n($time_format);
 
 
 
 
2596
  }
2597
  }else{
2598
- $replace = get_option('dbem_event_all_day_message');
2599
  }
2600
  return $replace;
2601
  }
2602
 
2603
- function output_dates( $date_format = false, $date_separator = false ){
2604
  if( empty($date_format) ) $date_format = ( get_option('dbem_date_format') ) ? get_option('dbem_date_format'):get_option('date_format');
2605
  if( empty($date_separator) ) $date_separator = get_option('dbem_dates_separator');
2606
  if( $this->event_start_date != $this->event_end_date){
2607
- $replace = $this->start()->i18n($date_format). $date_separator . $this->end()->i18n($date_format);
 
 
 
 
2608
  }else{
2609
- $replace = $this->start()->i18n($date_format);
 
 
 
 
2610
  }
2611
  return $replace;
2612
  }
@@ -2831,6 +2985,9 @@ class EM_Event extends EM_Object{
2831
  unset( $event['event_date_created'], $event['recurrence_id'], $event['recurrence'], $event['event_start_date'], $event['event_end_date'], $event['event_parent'] );
2832
  $event['event_date_modified'] = current_time('mysql'); //since the recurrences are modified but not recreated
2833
  unset( $post_fields['comment_count'], $post_fields['guid'], $post_fields['menu_order']);
 
 
 
2834
  //now we go through the recurrences and check whether things relative to dates need to be changed
2835
  $events = EM_Events::get( array('recurrence'=>$this->event_id, 'scope'=>'all', 'status'=>'everything', 'array' => true ) );
2836
  foreach($events as $event_array){ /* @var $EM_Event EM_Event */
@@ -2878,11 +3035,22 @@ class EM_Event extends EM_Object{
2878
  $meta_inserts[] = $wpdb->prepare("(%d, %s, %s)", array($event_array['post_id'], $meta_key, $meta_val));
2879
  }
2880
  }
2881
- //delete all meta
2882
  if( !empty($post_ids) ){
2883
- $wpdb->query("DELETE FROM {$wpdb->postmeta} WHERE post_id IN (".implode(',', $post_ids).")");
 
 
 
 
 
 
 
 
 
 
 
2884
  }
2885
- //insert the metas in one go, faster than one by one
2886
  if( count($meta_inserts) > 0 ){
2887
  $result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
2888
  if($result === false){
1
  <?php
2
+ use EM_Event_Locations\Event_Location, EM_Event_Locations\Event_Locations;
3
  /**
4
  * Get an event in a db friendly way, by checking globals, cache and passed variables to avoid extra class instantiations.
5
  * @param mixed $id can be either a post object, event object, event id or post id
50
  * The single event might be part of a set of recurring events, but if loaded by specific event id then any operations and saves are
51
  * specifically done on this event. However, if you edit the recurring group, any changes made to single events are overwritten.
52
  *
53
+ * @property string $language Language of the event, shorthand for event_language
54
+ * @property string $translation Whether or not a event is a translation (i.e. it was translated from an original event), shorthand for event_translation
55
+ * @property int $parent Event ID of parent event, shorthand for event_parent
56
+ * @property int $id The Event ID, case sensitive, shorthand for event_id
57
+ * @property string $slug Event slug, shorthand for event_slug
58
+ * @property string name Event name, shorthand for event_name
59
+ * @property int owner ID of author/owner, shorthand for event_owner
60
+ * @property int status ID of post status, shorthand for event_status
61
+ * @property string $event_start_time Start time of event
62
+ * @property string $event_end_time End time of event
63
+ * @property string $event_start_date Start date of event
64
+ * @property string $event_end_date End date of event
65
+ * @property string $event_start The event start date in local time. represented by a mysql DATE format
66
+ * @property string $event_end The event end date in local time. represented by a mysql DATE format
67
+ * @property string $event_timezone Timezone representation in PHP string or WP-style UTC offset
68
+ * @property string $event_rsvp_date Start rsvo date of event
69
+ * @property string $event_rsvp_time End rsvp time of event
70
  *
71
  */
72
  //TODO Can add more recurring functionality such as "also update all future recurring events" or "edit all events" like google calendar does.
129
  var $post_content;
130
  var $event_rsvp = 0;
131
  protected $event_rsvp_date;
132
+ protected $event_rsvp_time;
133
  var $event_rsvp_spaces;
134
  var $event_spaces;
135
  var $event_private;
154
  */
155
  var $event_attributes = array();
156
  /* Recurring Specific Values */
157
+ var $recurrence = 0;
158
  var $recurrence_interval;
159
  var $recurrence_freq;
160
  var $recurrence_byday;
199
  'group_id' => array( 'name'=>'group_id', 'type'=>'%d', 'null'=>true ),
200
  'event_language' => array( 'type'=>'%s', 'null'=>true ),
201
  'event_translation' => array( 'type'=>'%d'),
202
+ 'recurrence' => array( 'name'=>'recurrence', 'type'=>'%d', 'null'=>false ), //is this a recurring event template
203
  'recurrence_interval' => array( 'name'=>'interval', 'type'=>'%d', 'null'=>true ), //every x day(s)/week(s)/month(s)
204
  'recurrence_freq' => array( 'name'=>'freq', 'type'=>'%s', 'null'=>true ), //daily,weekly,monthly?
205
  'recurrence_days' => array( 'name'=>'days', 'type'=>'%d', 'null'=>true ), //each event spans x days
247
  */
248
  var $location;
249
  /**
250
+ * @var Event_Location
251
+ */
252
+ var $event_location;
253
+ /**
254
+ * If we're switching event location types, previous event location is kept here and deleted upon save()
255
+ * @var Event_Location
256
  */
257
+ var $event_location_deleted = null;
258
  /**
259
  * @var EM_Bookings
260
  */
369
  if( $id == 0 ) $id = false;
370
  }
371
  if( is_numeric($id) || $is_post ){ //only load info if $id is a number
372
+ $event_post = null;
373
  if($search_by == 'event_id' && !$is_post ){
374
  //search by event_id, get post_id and blog_id (if in ms mode) and load the post
375
  $results = $wpdb->get_row($wpdb->prepare("SELECT post_id, blog_id FROM ".EM_EVENTS_TABLE." WHERE event_id=%d",$id), ARRAY_A);
378
  if( $results['blog_id']=='' ) $results['blog_id'] = get_current_site()->blog_id;
379
  $event_post = get_blog_post($results['blog_id'], $results['post_id']);
380
  $search_by = $this->blog_id = $results['blog_id'];
381
+ }elseif( !empty($results['post_id']) ){
382
  $event_post = get_post($results['post_id']);
383
  }
384
  }else{
499
  public function __clone(){
500
  $this->bookings = null;
501
  $this->location = null;
502
+ if( is_object($this->event_location) ){
503
+ $this->event_location = clone $this->event_location;
504
+ $this->event_location->event = $this;
505
+ }
506
  }
507
 
508
  function load_postdata($event_post, $search_by = false){
522
  //load meta data and other related information
523
  if( $event_post->post_status != 'auto-draft' ){
524
  $event_meta = $this->get_event_meta($search_by);
525
+ if( !empty($event_meta['_event_location_type']) ) $this->event_location_type = $event_meta['_event_location_type']; //load this directly so we know further down whether this has an event location type to load
526
  //Get custom fields and post meta
527
  foreach($event_meta as $event_meta_key => $event_meta_val){
528
  $field_name = substr($event_meta_key, 1);
714
  }else{
715
  // we're dealing with an event location such as a url or webinar
716
  $this->location_id = null; // no location ID
717
+ if( $this->event_id && $this->has_event_location() && $location_type != $this->event_location_type ){
718
+ // if we're changing location types, then we'll delete all the previous data upon saving
719
+ $this->event_location_deleted = $this->event_location;
720
+ }
721
  $this->event_location_type = $location_type;
722
+ if( Event_Locations::is_enabled($location_type) ){
723
  $this->get_event_location()->get_post();
724
  }
725
  }
755
  }else{
756
  //if no rsvp cut-off date supplied, make it the event start date
757
  $this->event_rsvp_date = ( !empty($_POST['event_rsvp_date']) ) ? wp_kses_data($_POST['event_rsvp_date']) : $this->event_start_date;
758
+ //if no specificed time, default to event start time
759
+ if ( empty($_POST['event_rsvp_time']) ) $this->event_rsvp_time = $this->event_start_time;
760
  }
761
  //reset EM_DateTime object
762
  $this->rsvp_end = null;
898
  foreach( $this->recurrence_fields as $recurrence_field ){
899
  $this->$recurrence_field = null;
900
  }
901
+ $this->recurrence = 0; // to avoid any doubt
902
  }
903
  //event language
904
  if( EM_ML::$is_ml && !empty($_POST['event_language']) && array_key_exists($_POST['event_language'], EM_ML::$langs) ){
1161
  }
1162
  }
1163
  }
 
 
 
 
 
 
1164
  //update timestamps, dates and times
1165
  update_post_meta($this->post_id, '_event_start_local', $this->start()->getDateTime());
1166
  update_post_meta($this->post_id, '_event_end_local', $this->end()->getDateTime());
1233
  update_post_meta($this->post_id, '_event_owner_anonymous', 1);
1234
  }
1235
  }
1236
+ //update event location via post meta
1237
+ if( $this->has_event_location() ){
1238
+ $this->get_event_location()->save();
1239
+ }elseif( !empty($this->event_location) ){
1240
+ // we previously had an event location and then switched to no location or a physical location
1241
+ $this->event_location->delete();
1242
+ }
1243
+ if( !empty($this->event_location_deleted) ){
1244
+ // we've switched event location types
1245
+ $this->event_location_deleted->delete();
1246
+ }
1247
  //Add/Delete Tickets
1248
  if($this->event_rsvp == 0){
1249
  if( !$this->just_added_event ){
1297
  * @return EM_Event
1298
  */
1299
  function duplicate(){
1300
+ global $wpdb;
1301
  //First, duplicate.
1302
  if( $this->can_manage('edit_events','edit_others_events') ){
1303
  $EM_Event = clone $this;
1409
  if( $result !== false ){
1410
  $this->get_bookings()->delete();
1411
  $this->get_tickets()->delete();
1412
+ if( $this->has_event_location() ) {
1413
+ $this->get_event_location()->delete();
1414
+ }
1415
  //Delete the recurrences then this recurrence event
1416
  if( $this->is_recurring() ){
1417
  $result = $this->delete_events(); //was true at this point, so false if fails
1695
  /**
1696
  * Gets the event's event location (note, different from a regular event location, which uses get_location())
1697
  * Returns implementation of Event_Location or false if no event location assigned.
1698
+ * @return EM_Event_Locations\URL|Event_Location|false
1699
  */
1700
  public function get_event_location(){
1701
+ if( is_object($this->event_location) && $this->event_location->type == $this->event_location_type ) return $this->event_location;
1702
+ $Event_Location = false;
1703
  if( $this->has_event_location() ){
1704
+ $this->event_location = $Event_Location = Event_Locations::get( $this->event_location_type, $this );
 
 
1705
  }
1706
+ return apply_filters('em_event_get_event_location', $Event_Location, $this);
1707
  }
1708
 
1709
  /**
1712
  * @return bool
1713
  */
1714
  public function has_event_location( $event_location_type = null ){
1715
+ if( $event_location_type !== null ){
1716
+ return !empty($this->event_location_type) && $this->event_location_type === $event_location_type && Event_Locations::is_enabled($event_location_type);
1717
  }
1718
+ return !empty($this->event_location_type) && Event_Locations::is_enabled($this->event_location_type);
1719
  }
1720
 
1721
  /**
1909
  //$format = do_shortcode($format); //parse shortcode first, so that formats within shortcodes are parsed properly, however uncommenting this will break shortcode containing placeholders for arguments
1910
  $event_string = $format;
1911
  //Time place holder that doesn't show if empty.
1912
+ preg_match_all('/#@?__?\{[^}]+\}/', $format, $results);
1913
  foreach($results[0] as $result) {
1914
  if(substr($result, 0, 3 ) == "#@_"){
1915
  $date = 'end';
1916
+ if( substr($result, 0, 4 ) == "#@__" ){
1917
+ $offset = 5;
1918
+ $show_site_timezone = true;
1919
+ }else{
1920
+ $offset = 4;
1921
+ }
1922
  }else{
1923
  $date = 'start';
1924
+ if( substr($result, 0, 3) == "#__" ){
1925
+ $offset = 4;
1926
+ $show_site_timezone = true;
1927
+ }else{
1928
+ $offset = 3;
1929
+ }
1930
  }
1931
+ if( $date == 'end' && $this->event_end == $this->event_start ){
1932
+ $replace = __( apply_filters('em_event_output_placeholder', '', $this, $result, $target, array($result)) );
1933
  }else{
1934
  $date_format = substr( $result, $offset, (strlen($result)-($offset+1)) );
1935
+ if( !empty($show_site_timezone) ){
1936
+ $date_formatted = $this->$date()->copy()->setTimezone()->i18n($date_format);
1937
+ }else{
1938
+ $date_formatted = $this->$date()->i18n($date_format);
1939
+ }
1940
+ $replace = apply_filters('em_event_output_placeholder', $date_formatted, $this, $result, $target, array($result));
1941
  }
1942
  $event_string = str_replace($result,$replace,$event_string );
1943
  }
1953
  //Strip string of placeholder and just leave the reference
1954
  $attRef = substr( substr($result, 0, strpos($result, '}')), 6 );
1955
  $attString = '';
1956
+ $placeholder_atts = array('#_ATT', $results[1][$resultKey]);
1957
  if( is_array($this->event_attributes) && array_key_exists($attRef, $this->event_attributes) ){
1958
  $attString = $this->event_attributes[$attRef];
1959
  }elseif( !empty($results[3][$resultKey]) ){
1960
  //Check to see if we have a second set of braces;
1961
+ $placeholder_atts[] = $results[3][$resultKey];
1962
  $attStringArray = explode('|', $results[3][$resultKey]);
1963
  $attString = $attStringArray[0];
1964
  }elseif( !empty($attributes['values'][$attRef][0]) ){
1965
  $attString = $attributes['values'][$attRef][0];
1966
  }
1967
+ $attString = apply_filters('em_event_output_placeholder', $attString, $this, $result, $target, $placeholder_atts);
1968
  $event_string = str_replace($result, $attString ,$event_string );
1969
  }
1970
  //First let's do some conditional placeholder removals
2141
  }
2142
  }
2143
  //Now let's check out the placeholders.
2144
+ preg_match_all("/(#@?_?[A-Za-z0-9_]+)({([^}]+)})?/", $event_string, $placeholders);
2145
  $replaces = array();
2146
  foreach($placeholders[1] as $key => $result) {
2147
  $match = true;
2148
  $replace = '';
2149
  $full_result = $placeholders[0][$key];
2150
+ $placeholder_atts = array($result);
2151
+ if( !empty($placeholders[3][$key]) ) $placeholder_atts[] = $placeholders[3][$key];
2152
  switch( $result ){
2153
  //Event Details
2154
  case '#_EVENTID':
2213
  switch_to_blog($this->blog_id);
2214
  $switch_back = true;
2215
  }
2216
+ $replace = get_the_post_thumbnail($this->ID, $image_size, array('alt' => esc_attr($this->event_name)) );
2217
  if( !empty($switch_back) ){ restore_current_blog(); }
2218
  }
2219
  }else{
2228
  case '#_24HENDTIME':
2229
  $replace = ($result == '#_24HSTARTTIME') ? $this->start()->format('H:i'):$this->end()->format('H:i');
2230
  break;
2231
+ case '#_24HSTARTTIME_SITE':
2232
+ case '#_24HENDTIME_SITE':
2233
+ $replace = ($result == '#_24HSTARTTIME_SITE') ? $this->start()->copy()->setTimezone(false)->format('H:i'):$this->end()->copy()->setTimezone(false)->format('H:i');
2234
+ break;
2235
+ case '#_24HSTARTTIME_LOCAL':
2236
+ case '#_24HENDTIME_LOCAL':
2237
+ case '#_24HTIMES_LOCAL':
2238
+ $ts = ($result == '#_24HENDTIME_LOCAL') ? $this->end()->getTimestamp():$this->start()->getTimestamp();
2239
+ $date_end = ($result == '#_24HTIMES_LOCAL' && $this->end()->getTimestamp() !== $ts) ? 'data-time-end="'. esc_attr($this->end()->getTimestamp()) .'" data-separator="'. esc_attr(get_option('dbem_times_separator')) . '"' : '';
2240
+ $replace = '<span class="em-time-localjs" data-time-format="24" data-time="'. esc_attr($ts) .'" '. $date_end .'>JavaScript Disabled</span>';
2241
+ break;
2242
  case '#_12HSTARTTIME':
2243
  case '#_12HENDTIME':
2244
  $replace = ($result == '#_12HSTARTTIME') ? $this->start()->format('g:i A'):$this->end()->format('g:i A');
2245
  break;
2246
+ case '#_12HSTARTTIME_SITE':
2247
+ case '#_12HENDTIME_SITE':
2248
+ $replace = ($result == '#_12HSTARTTIME_SITE') ? $this->start()->copy()->setTimezone(false)->format('g:i A'):$this->end()->copy()->setTimezone(false)->format('g:i A');
2249
+ break;
2250
+ case '#_12HSTARTTIME_LOCAL':
2251
+ case '#_12HENDTIME_LOCAL':
2252
+ case '#_12HTIMES_LOCAL':
2253
+ $ts = ($result == '#_12HENDTIME_LOCAL') ? $this->end()->getTimestamp():$this->start()->getTimestamp();
2254
+ $date_end = ($result == '#_24HTIMES_LOCAL' && $this->end()->getTimestamp() !== $ts) ? 'data-time-end="'. esc_attr($this->end()->getTimestamp()) .'" data-separator="'. esc_attr(get_option('dbem_times_separator')) . '"' : '';
2255
+ $replace = '<span class="em-time-localjs" data-time-format="12" data-time="'. esc_attr($ts) .'" '. $date_end .'>JavaScript Disabled</span>';
2256
+ break;
2257
  case '#_EVENTTIMES':
2258
  //get format of time to show
2259
  $replace = $this->output_times();
2260
  break;
2261
+ case '#_EVENTTIMES_SITE':
2262
+ //get format of time to show but show timezone of site rather than local time
2263
+ $replace = $this->output_times(false, false, false, true);
2264
+ break;
2265
+ case '#_EVENTTIMES_LOCAL':
2266
+ case '#_EVENTDATES_LOCAL':
2267
+ if( !defined('EM_JS_MOMENTJS_PH') || EM_JS_MOMENTJS_PH ){
2268
+ // check for passed parameters, in which case we skip replacements entirely and use pure moment formats
2269
+ $time_format = $separator = null;
2270
+ if( !empty($placeholder_atts[1]) ){
2271
+ $params = explode(',', $placeholder_atts[1]);
2272
+ if( !empty($params[0]) ) $time_format = $params[0];
2273
+ if( !empty($params[1]) ) $separator = $params[1];
2274
+ }
2275
+ if( empty($separator) ) $separator = get_option('dbem_times_separator');
2276
+ // if no moment format provided, we convert the one stored for times in php
2277
+ if( empty($time_format) ){
2278
+ // convert EM format setting to moment formatting, adapted from https://stackoverflow.com/questions/30186611/php-dateformat-to-moment-js-format
2279
+ $replacements = array(
2280
+ /* Day */ 'jS' => 'Do', /*o doesn't exist on its own, so we find/replase jS only*/ 'd' => 'DD', 'D' => 'ddd', 'j' => 'D', 'l' => 'dddd', 'N' => 'E', /*'S' => 'o' - see jS*/ 'w' => 'e', 'z' => 'DDD',
2281
+ /* Week */ 'W' => 'W',
2282
+ /* Month */ 'F' => 'MMMM', 'm' => 'MM', 'M' => 'MMM', 'n' => 'M', 't' => '#t', /* days in the month => moment().daysInMonth(); */
2283
+ /* Year */ 'L' => '#L', /* Leap year? => moment().isLeapYear(); */ 'o' => 'YYYY', 'Y' => 'YYYY', 'y' => 'YY',
2284
+ /* Time */ 'a' => 'a', 'A' => 'A', 'B' => '', /* Swatch internet time (.beats), no equivalent */ 'g' => 'h', 'G' => 'H', 'h' => 'hh', 'H' => 'HH', 'i' => 'mm', 's' => 'ss', 'u' => 'SSSSSS', /* microseconds */ 'v' => 'SSS', /* milliseconds (from PHP 7.0.0) */
2285
+ /* Timezone */ 'e' => '##T', /* Timezone - deprecated since version 1.6.0 of moment.js, we'll use Intl.DateTimeFromat().resolvedOptions().timeZone instead. */ 'I' => '##t', /* Daylight Saving Time? => moment().isDST(); */ 'O' => 'ZZ', 'P' => 'Z', 'T' => '#T', /* deprecated since version 1.6.0 of moment.js, using GMT difference with colon to keep it shorter than full timezone */ 'Z' => '###t', /* time zone offset in seconds => moment().zone() * -60 : the negative is because moment flips that around; */
2286
+ /* Full Date/Time */ 'c' => 'YYYY-MM-DD[T]HH:mm:ssZ', /* ISO 8601 */ 'r' => 'ddd, DD MMM YYYY HH:mm:ss ZZ', /* RFC 2822 */ 'U' => 'X',
2287
+ );
2288
+ // Converts escaped characters.
2289
+ foreach ($replacements as $from => $to) {
2290
+ $replacements['\\' . $from] = '[' . $from . ']';
2291
+ }
2292
+ if( $result === '#_EVENTDATES_LOCAL' ){
2293
+ $time_format = ( get_option('dbem_date_format') ) ? get_option('dbem_date_format'):get_option('date_format');
2294
+ if( empty($separator) ) $separator = get_option('dbem_dates_separator');
2295
+ }else{
2296
+ $time_format = ( get_option('dbem_time_format') ) ? get_option('dbem_time_format'):get_option('time_format');
2297
+ if( empty($separator) ) $separator = get_option('dbem_times_separator');
2298
+ }
2299
+ $time_format = strtr($time_format, $replacements);
2300
+ }
2301
+ wp_enqueue_script('moment', '', array(), false, true); //add to footer if not already
2302
+ // start output
2303
+ ob_start();
2304
+ ?>
2305
+ <span class="em-date-momentjs" data-date-format="<?php echo esc_attr($time_format); ?>" data-date-start="<?php echo $this->start()->getTimestamp() ?>" data-date-end="<?php echo $this->end()->getTimestamp() ?>" data-date-separator="<?php echo esc_attr($separator); ?>">JavaScript Disabled</span>
2306
+ <?php
2307
+ $replace = ob_get_clean();
2308
+ }
2309
+ break;
2310
  case '#_EVENTDATES':
2311
  //get format of time to show
2312
  $replace = $this->output_dates();
2313
  break;
2314
+ case '#_EVENTDATES_SITE':
2315
+ //get format of time to show but use timezone of site rather than event
2316
+ $replace = $this->output_dates(false, false, true);
2317
+ break;
2318
  case '#_EVENTTIMEZONE':
2319
  $replace = str_replace('_', ' ', $this->event_timezone);
2320
  break;
2321
  case '#_EVENTTIMEZONERAW':
2322
  $replace = $this->event_timezone;
2323
  break;
2324
+ case '#_EVENTTIMEZONE_LOCAL':
2325
+ $rand = rand();
2326
+ ob_start();
2327
+ ?>
2328
+ <span id="em-start-local-timezone-<?php echo $rand ?>">JavaScript Disabled</span>
2329
+ <script>
2330
+ document.getElementById("em-start-local-timezone-<?php echo $rand ?>").innerHTML = Intl.DateTimeFormat().resolvedOptions().timeZone;
2331
+ </script>
2332
+ <?php
2333
+ $replace = ob_get_clean();
2334
+ break;
2335
  //Recurring Placeholders
2336
  case '#_RECURRINGDATERANGE': //Outputs the #_EVENTDATES equivalent of the recurring event template pattern.
2337
  $replace = $this->get_event_recurrence()->output_dates(); //if not a recurrence, we're running output_dates on $this
2645
  $replace = $full_result;
2646
  break;
2647
  }
2648
+ $replaces[$full_result] = apply_filters('em_event_output_placeholder', $replace, $this, $full_result, $target, $placeholder_atts);
2649
  }
2650
  //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
2651
  krsort($replaces);
2663
  // matches all PHP START date and time placeholders
2664
  if (preg_match('/^#[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
2665
  $replace = $this->start()->i18n(ltrim($result, "#"));
2666
+ $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target, array($result));
2667
  $event_string = str_replace($result, $replace, $event_string );
2668
  }
2669
  // matches all PHP END time placeholders for endtime
2670
  if (preg_match('/^#@[dDjlNSwzWFmMntLoYyaABgGhHisueIOPTZcrU]$/', $result)) {
2671
  $replace = $this->end()->i18n(ltrim($result, "#@"));
2672
+ $replace = apply_filters('em_event_output_placeholder', $replace, $this, $result, $target, array($result));
2673
  $event_string = str_replace($result, $replace, $event_string );
2674
  }
2675
  }
2723
  return apply_filters('em_event_output', $event_string, $this, $format, $target);
2724
  }
2725
 
2726
+ function output_times( $time_format = false, $time_separator = false , $all_day_message = false, $use_site_timezone = false ){
2727
  if( !$this->event_all_day ){
2728
  if( empty($time_format) ) $time_format = ( get_option('dbem_time_format') ) ? get_option('dbem_time_format'):get_option('time_format');
2729
  if( empty($time_separator) ) $time_separator = get_option('dbem_times_separator');
2730
  if( $this->event_start_time != $this->event_end_time ){
2731
+ if( $use_site_timezone ){
2732
+ $replace = $this->start()->copy()->setTimezone()->i18n($time_format). $time_separator . $this->end()->copy()->setTimezone()->i18n($time_format);
2733
+ }else{
2734
+ $replace = $this->start()->i18n($time_format). $time_separator . $this->end()->i18n($time_format);
2735
+ }
2736
  }else{
2737
+ if( $use_site_timezone ){
2738
+ $replace = $this->start()->copy()->setTimezone()->i18n($time_format);
2739
+ }else{
2740
+ $replace = $this->start()->i18n($time_format);
2741
+ }
2742
  }
2743
  }else{
2744
+ $replace = $all_day_message ? $all_day_message : get_option('dbem_event_all_day_message');
2745
  }
2746
  return $replace;
2747
  }
2748
 
2749
+ function output_dates( $date_format = false, $date_separator = false, $use_site_timezone = false ){
2750
  if( empty($date_format) ) $date_format = ( get_option('dbem_date_format') ) ? get_option('dbem_date_format'):get_option('date_format');
2751
  if( empty($date_separator) ) $date_separator = get_option('dbem_dates_separator');
2752
  if( $this->event_start_date != $this->event_end_date){
2753
+ if( $use_site_timezone ){
2754
+ $replace = $this->start()->copy()->setTimezone()->i18n($date_format). $date_separator . $this->end()->copy()->setTimezone()->i18n($date_format);
2755
+ }else{
2756
+ $replace = $this->start()->i18n($date_format). $date_separator . $this->end()->i18n($date_format);
2757
+ }
2758
  }else{
2759
+ if( $use_site_timezone ){
2760
+ $replace = $this->start()->copy()->setTimezone()->i18n($date_format);
2761
+ }else{
2762
+ $replace = $this->start()->i18n($date_format);
2763
+ }
2764
  }
2765
  return $replace;
2766
  }
2985
  unset( $event['event_date_created'], $event['recurrence_id'], $event['recurrence'], $event['event_start_date'], $event['event_end_date'], $event['event_parent'] );
2986
  $event['event_date_modified'] = current_time('mysql'); //since the recurrences are modified but not recreated
2987
  unset( $post_fields['comment_count'], $post_fields['guid'], $post_fields['menu_order']);
2988
+ unset( $meta_fields['_event_parent'] ); // we'll ignore this and add it manually
2989
+ // clean the meta fields array to contain only the fields we actually need to overwrite i.e. delete and recreate, to avoid deleting unecessary individula recurrence data
2990
+ $exclude_meta_update_keys = apply_filters('em_event_save_events_exclude_update_meta_keys', array('_parent_id'), $this);
2991
  //now we go through the recurrences and check whether things relative to dates need to be changed
2992
  $events = EM_Events::get( array('recurrence'=>$this->event_id, 'scope'=>'all', 'status'=>'everything', 'array' => true ) );
2993
  foreach($events as $event_array){ /* @var $EM_Event EM_Event */
3035
  $meta_inserts[] = $wpdb->prepare("(%d, %s, %s)", array($event_array['post_id'], $meta_key, $meta_val));
3036
  }
3037
  }
3038
+ // delete all meta we'll be updating
3039
  if( !empty($post_ids) ){
3040
+ $sql = "DELETE FROM {$wpdb->postmeta} WHERE post_id IN (".implode(',', $post_ids).")";
3041
+ if( !empty($exclude_meta_update_keys) ){
3042
+ $sql .= " AND meta_key NOT IN (";
3043
+ $i = 0;
3044
+ foreach( $exclude_meta_update_keys as $k ){
3045
+ $sql.= ( $i > 0 ) ? ',%s' : '%s';
3046
+ $i++;
3047
+ }
3048
+ $sql .= ")";
3049
+ $sql = $wpdb->prepare($sql, $exclude_meta_update_keys);
3050
+ }
3051
+ $wpdb->query($sql);
3052
  }
3053
+ // insert the metas in one go, faster than one by one
3054
  if( count($meta_inserts) > 0 ){
3055
  $result = $wpdb->query("INSERT INTO ".$wpdb->postmeta." (post_id,meta_key,meta_value) VALUES ".implode(',',$meta_inserts));
3056
  if($result === false){
classes/em-location-posts-admin.php CHANGED
@@ -6,13 +6,13 @@ class EM_Location_Posts_Admin{
6
  //hide some cols by default:
7
  $screen = 'edit-'.EM_POST_TYPE_LOCATION;
8
  $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
9
- if( !$hidden ){
10
  $hidden = array('location-id');
11
  update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
12
  }
13
  add_action('admin_head', array('EM_Location_Posts_Admin','admin_head'));
14
  }
15
- add_filter('manage_edit-'.EM_POST_TYPE_LOCATION.'_columns' , array('EM_Location_Posts_Admin','columns_add'));
16
  add_filter('manage_'.EM_POST_TYPE_LOCATION.'_posts_custom_column' , array('EM_Location_Posts_Admin','columns_output'),10,2 );
17
  }
18
 
6
  //hide some cols by default:
7
  $screen = 'edit-'.EM_POST_TYPE_LOCATION;
8
  $hidden = get_user_option( 'manage' . $screen . 'columnshidden' );
9
+ if( $hidden === false ){
10
  $hidden = array('location-id');
11
  update_user_option(get_current_user_id(), "manage{$screen}columnshidden", $hidden, true);
12
  }
13
  add_action('admin_head', array('EM_Location_Posts_Admin','admin_head'));
14
  }
15
+ add_filter('manage_'.EM_POST_TYPE_LOCATION.'_posts_columns' , array('EM_Location_Posts_Admin','columns_add'));
16
  add_filter('manage_'.EM_POST_TYPE_LOCATION.'_posts_custom_column' , array('EM_Location_Posts_Admin','columns_output'),10,2 );
17
  }
18
 
classes/em-location.php CHANGED
@@ -50,9 +50,9 @@ function em_get_location($id = false, $search_by = 'location_id') {
50
  * @property int $parent Location ID of parent location, shorthand for location_parent
51
  * @property int $id The Location ID, case sensitive, shorthand for location_id
52
  * @property string $slug Location slug, shorthand for location_slug
53
- * @property string name Location name, shorthand for location_name
54
- * @property int owner ID of author/owner, shorthand for location_owner
55
- * @property int status ID of post status, shorthand for location_status
56
  */
57
  class EM_Location extends EM_Object {
58
  //DB Fields
@@ -111,8 +111,8 @@ class EM_Location extends EM_Object {
111
  'translation' => 'location_translation',
112
  'parent' => 'location_parent',
113
  'id' => 'location_id',
114
- 'slug' => 'locatoin_slug',
115
- 'name' => 'locatoin_name',
116
  'status' => 'location_status',
117
  'owner' => 'location_owner',
118
  );
@@ -692,9 +692,14 @@ class EM_Location extends EM_Object {
692
  return $this->previous_status;
693
  }
694
 
 
 
 
 
 
695
  function load_similar($criteria){
696
  global $wpdb;
697
- if( !empty($criteria['location_name']) && !empty($criteria['location_name']) && !empty($criteria['location_name']) ){
698
  $locations_table = EM_LOCATIONS_TABLE;
699
  $prepared_sql = $wpdb->prepare("SELECT * FROM $locations_table WHERE location_name = %s AND location_address = %s AND location_town = %s AND location_state = %s AND location_postcode = %s AND location_country = %s", stripcslashes($criteria['location_name']), stripcslashes($criteria['location_address']), stripcslashes($criteria['location_town']), stripcslashes($criteria['location_state']), stripcslashes($criteria['location_postcode']), stripcslashes($criteria['location_country']) );
700
  //$wpdb->show_errors(true);
@@ -881,23 +886,27 @@ class EM_Location extends EM_Object {
881
  //Strip string of placeholder and just leave the reference
882
  $attRef = substr( substr($result, 0, strpos($result, '}')), 7 );
883
  $attString = '';
 
884
  if( is_array($this->location_attributes) && array_key_exists($attRef, $this->location_attributes) ){
885
  $attString = $this->location_attributes[$attRef];
886
  }elseif( !empty($results[3][$resultKey]) ){
887
  //Check to see if we have a second set of braces;
 
888
  $attStringArray = explode('|', $results[3][$resultKey]);
889
  $attString = $attStringArray[0];
890
  }elseif( !empty($attributes['values'][$attRef][0]) ){
891
  $attString = $attributes['values'][$attRef][0];
892
  }
893
- $attString = apply_filters('em_location_output_placeholder', $attString, $this, $result, $target);
894
  $location_string = str_replace($result, $attString ,$location_string );
895
  }
896
- preg_match_all("/(#@?_?[A-Za-z0-9]+)({([^}]+)})?/", $location_string, $placeholders);
897
  $replaces = array();
898
  foreach($placeholders[1] as $key => $result) {
899
  $replace = '';
900
  $full_result = $placeholders[0][$key];
 
 
901
  switch( $result ){
902
  case '#_LOCATIONID':
903
  $replace = $this->location_id;
@@ -1010,7 +1019,7 @@ class EM_Location extends EM_Object {
1010
  switch_to_blog($this->blog_id);
1011
  $switch_back = true;
1012
  }
1013
- $replace = get_the_post_thumbnail($this->ID, $image_size);
1014
  if( !empty($switch_back) ){ restore_current_blog(); }
1015
  }
1016
  }else{
@@ -1101,7 +1110,7 @@ class EM_Location extends EM_Object {
1101
  $replace = $full_result;
1102
  break;
1103
  }
1104
- $replaces[$full_result] = apply_filters('em_location_output_placeholder', $replace, $this, $full_result, $target);
1105
  }
1106
  //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
1107
  krsort($replaces);
@@ -1161,4 +1170,6 @@ class EM_Location extends EM_Object {
1161
  $url = add_query_arg( $args, "https://www.google.com/maps/embed/v1/place");
1162
  return apply_filters('em_location_get_google_maps_embed_url', $url, $this);
1163
  }
1164
- }
 
 
50
  * @property int $parent Location ID of parent location, shorthand for location_parent
51
  * @property int $id The Location ID, case sensitive, shorthand for location_id
52
  * @property string $slug Location slug, shorthand for location_slug
53
+ * @property string $name Location name, shorthand for location_name
54
+ * @property int $owner ID of author/owner, shorthand for location_owner
55
+ * @property int $status ID of post status, shorthand for location_status
56
  */
57
  class EM_Location extends EM_Object {
58
  //DB Fields
111
  'translation' => 'location_translation',
112
  'parent' => 'location_parent',
113
  'id' => 'location_id',
114
+ 'slug' => 'location_slug',
115
+ 'name' => 'location_name',
116
  'status' => 'location_status',
117
  'owner' => 'location_owner',
118
  );
692
  return $this->previous_status;
693
  }
694
 
695
+ /**
696
+ * @param $criteria
697
+ * @return mixed|void
698
+ * @deprecated Since 5.9.8.2 - Was never used, assume this may be removed eventually and copy code into your own custom implementation if necessary.
699
+ */
700
  function load_similar($criteria){
701
  global $wpdb;
702
+ if( !empty($criteria['location_name']) && !empty($criteria['location_address']) && !empty($criteria['location_town']) && !empty($criteria['location_state']) && !empty($criteria['location_postcode']) && !empty($criteria['location_country']) ){
703
  $locations_table = EM_LOCATIONS_TABLE;
704
  $prepared_sql = $wpdb->prepare("SELECT * FROM $locations_table WHERE location_name = %s AND location_address = %s AND location_town = %s AND location_state = %s AND location_postcode = %s AND location_country = %s", stripcslashes($criteria['location_name']), stripcslashes($criteria['location_address']), stripcslashes($criteria['location_town']), stripcslashes($criteria['location_state']), stripcslashes($criteria['location_postcode']), stripcslashes($criteria['location_country']) );
705
  //$wpdb->show_errors(true);
886
  //Strip string of placeholder and just leave the reference
887
  $attRef = substr( substr($result, 0, strpos($result, '}')), 7 );
888
  $attString = '';
889
+ $placeholder_atts = array('#_ATT', $results[1][$resultKey]);
890
  if( is_array($this->location_attributes) && array_key_exists($attRef, $this->location_attributes) ){
891
  $attString = $this->location_attributes[$attRef];
892
  }elseif( !empty($results[3][$resultKey]) ){
893
  //Check to see if we have a second set of braces;
894
+ $placeholder_atts[] = $results[3][$resultKey];
895
  $attStringArray = explode('|', $results[3][$resultKey]);
896
  $attString = $attStringArray[0];
897
  }elseif( !empty($attributes['values'][$attRef][0]) ){
898
  $attString = $attributes['values'][$attRef][0];
899
  }
900
+ $attString = apply_filters('em_location_output_placeholder', $attString, $this, $result, $target, $placeholder_atts);
901
  $location_string = str_replace($result, $attString ,$location_string );
902
  }
903
+ preg_match_all("/(#@?_?[A-Za-z0-9_]+)({([^}]+)})?/", $location_string, $placeholders);
904
  $replaces = array();
905
  foreach($placeholders[1] as $key => $result) {
906
  $replace = '';
907
  $full_result = $placeholders[0][$key];
908
+ $placeholder_atts = array($result);
909
+ if( !empty($placeholders[3][$key]) ) $placeholder_atts[] = $placeholders[3][$key];
910
  switch( $result ){
911
  case '#_LOCATIONID':
912
  $replace = $this->location_id;
1019
  switch_to_blog($this->blog_id);
1020
  $switch_back = true;
1021
  }
1022
+ $replace = get_the_post_thumbnail($this->ID, $image_size, array('alt' => esc_attr($this->location_name)) );
1023
  if( !empty($switch_back) ){ restore_current_blog(); }
1024
  }
1025
  }else{
1110
  $replace = $full_result;
1111
  break;
1112
  }
1113
+ $replaces[$full_result] = apply_filters('em_location_output_placeholder', $replace, $this, $full_result, $target, $placeholder_atts);
1114
  }
1115
  //sort out replacements so that during replacements shorter placeholders don't overwrite longer varieties.
1116
  krsort($replaces);
1170
  $url = add_query_arg( $args, "https://www.google.com/maps/embed/v1/place");
1171
  return apply_filters('em_location_get_google_maps_embed_url', $url, $this);
1172
  }
1173
+ }
1174
+
1175
+ $loc = new EM_Location();
classes/em-mailer.php CHANGED
@@ -64,7 +64,7 @@ class EM_Mailer {
64
  return $send;
65
  }elseif( $emails_ok ){
66
  $this->load_phpmailer();
67
- $mail = new PHPMailer();
68
  try{
69
  //$mail->SMTPDebug = true;
70
  if( get_option('dbem_smtp_html') ){
@@ -144,8 +144,9 @@ class EM_Mailer {
144
  * load phpmailer classes
145
  */
146
  public function load_phpmailer(){
147
- require_once ABSPATH . WPINC . '/class-phpmailer.php';
148
- require_once ABSPATH . WPINC . '/class-smtp.php';
 
149
  }
150
 
151
  /**
64
  return $send;
65
  }elseif( $emails_ok ){
66
  $this->load_phpmailer();
67
+ $mail = new PHPMailer\PHPMailer\PHPMailer();
68
  try{
69
  //$mail->SMTPDebug = true;
70
  if( get_option('dbem_smtp_html') ){
144
  * load phpmailer classes
145
  */
146
  public function load_phpmailer(){
147
+ require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
148
+ require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
149
+ require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
150
  }
151
 
152
  /**
classes/em-oauth/oauth-admin-settings.php CHANGED
@@ -171,7 +171,7 @@ class OAuth_API_Admin_Settings {
171
  <p><em><?php esc_html_e('If you are experiencing errors when trying to use any of these accounts, try disconnecting and connecting again.', 'events-manager'); ?></em></p>
172
  <?php else: ?>
173
  <p><em><?php echo sprintf(esc_html__('Connect to import events and locations from %s.','events-manager'), $service_name); ?></em></p>
174
- <a class="<?php echo $button_class; ?> em-oauth-connect-button" href="<?php echo esc_url($button_url); ?>"><?php echo esc_html($button_text); ?></a>
175
  <?php endif; ?>
176
  </div>
177
  <?php
171
  <p><em><?php esc_html_e('If you are experiencing errors when trying to use any of these accounts, try disconnecting and connecting again.', 'events-manager'); ?></em></p>
172
  <?php else: ?>
173
  <p><em><?php echo sprintf(esc_html__('Connect to import events and locations from %s.','events-manager'), $service_name); ?></em></p>
174
+ <p><a class="<?php echo $button_class; ?> em-oauth-connect-button" href="<?php echo esc_url($button_url); ?>"><?php echo esc_html($button_text); ?></a></p>
175
  <?php endif; ?>
176
  </div>
177
  <?php
classes/em-oauth/oauth-api.php CHANGED
@@ -157,7 +157,7 @@ class OAuth_API {
157
  if( !empty($_REQUEST['code']) ){
158
  try{
159
  $client = static::get_client(false);
160
- if( !$client->oauth_state || (!empty($_REQUEST['state']) && !wp_verify_nonce( $_REQUEST['state'], static::$option_name.'_authorize')) ){
161
  $EM_Notices->add_error( sprintf( esc_html__( 'There was an error connecting to %s: %s', 'events-manager' ), static::$service_name, '<code>No State Provided</code>'), true );
162
  }else{
163
  try {
157
  if( !empty($_REQUEST['code']) ){
158
  try{
159
  $client = static::get_client(false);
160
+ if( $client->oauth_state && (empty($_REQUEST['state']) || !wp_verify_nonce( $_REQUEST['state'], static::$option_name.'_authorize')) ){
161
  $EM_Notices->add_error( sprintf( esc_html__( 'There was an error connecting to %s: %s', 'events-manager' ), static::$service_name, '<code>No State Provided</code>'), true );
162
  }else{
163
  try {
classes/em-object.php CHANGED
@@ -164,10 +164,10 @@ class EM_Object {
164
  }
165
  if( is_array($defaults['scope']) ){
166
  //looking for a date range here, so we'll verify the dates validate, if not get the default.
167
- if ( !preg_match("/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/", $defaults['scope'][0]) ){
168
  $defaults['scope'][0] = '';
169
  }
170
- if( !preg_match("/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/", $defaults['scope'][1]) ) {
171
  $defaults['scope'][1] = '';
172
  }
173
  if( empty($defaults['scope'][0]) && empty($defaults['scope'][1]) ){
@@ -1040,7 +1040,7 @@ class EM_Object {
1040
  }
1041
  if($post_value != ',' ){
1042
  $args[$post_key] = $post_value;
1043
- }elseif( $post_value == ',' && $post_key == 'scope' && empty($args['scope']) ){
1044
  //unset the scope if no value is provided - ',' is an empty value
1045
  unset($args['scope']);
1046
  }
164
  }
165
  if( is_array($defaults['scope']) ){
166
  //looking for a date range here, so we'll verify the dates validate, if not get the default.
167
+ if ( empty($defaults['scope'][0]) || !preg_match("/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/", $defaults['scope'][0]) ){
168
  $defaults['scope'][0] = '';
169
  }
170
+ if( empty($defaults['scope'][1]) || !preg_match("/^[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}$/", $defaults['scope'][1]) ) {
171
  $defaults['scope'][1] = '';
172
  }
173
  if( empty($defaults['scope'][0]) && empty($defaults['scope'][1]) ){
1040
  }
1041
  if($post_value != ',' ){
1042
  $args[$post_key] = $post_value;
1043
+ }elseif( $post_value == ',' && $post_key == 'scope' && (empty($args['scope']) || $args['scope'] == array('','')) ){
1044
  //unset the scope if no value is provided - ',' is an empty value
1045
  unset($args['scope']);
1046
  }
classes/em-people.php CHANGED
@@ -14,7 +14,7 @@ class EM_People extends EM_Object {
14
  public static function delete_user( $id ){
15
  global $wpdb;
16
  //if events are set to be deleted, we hook in correctly already, if they're meant to be reassigned, we only need to update our tables as WP updated theirs
17
- if( $_REQUEST['delete_option'] == 'reassign' && is_numeric($_REQUEST['reassign_user']) ){
18
  $wpdb->update(EM_EVENTS_TABLE, array('event_owner'=>$_REQUEST['reassign_user']), array('event_owner'=>$id));
19
  $wpdb->update(EM_LOCATIONS_TABLE, array('location_owner'=>$_REQUEST['reassign_user']), array('location_owner'=>$id));
20
  }else{
14
  public static function delete_user( $id ){
15
  global $wpdb;
16
  //if events are set to be deleted, we hook in correctly already, if they're meant to be reassigned, we only need to update our tables as WP updated theirs
17
+ if( !empty($_REQUEST['delete_option']) && $_REQUEST['delete_option'] == 'reassign' && is_numeric($_REQUEST['reassign_user']) ){
18
  $wpdb->update(EM_EVENTS_TABLE, array('event_owner'=>$_REQUEST['reassign_user']), array('event_owner'=>$id));
19
  $wpdb->update(EM_LOCATIONS_TABLE, array('location_owner'=>$_REQUEST['reassign_user']), array('location_owner'=>$id));
20
  }else{
classes/em-permalinks.php CHANGED
@@ -10,7 +10,7 @@ if( !class_exists('EM_Permalinks') ){
10
  'booking_id',
11
  'category_id', 'category_slug',
12
  'ticket_id',
13
- 'calendar_day', 'pno',
14
  'rss', 'ical','event_categories','event_locations'
15
  );
16
 
@@ -256,14 +256,18 @@ if( !class_exists('EM_Permalinks') ){
256
 
257
  /**
258
  * Not the "WP way" but for now this'll do!
 
 
 
259
  */
260
  public static function init_objects(){
261
  global $wp_rewrite, $wp_query;
262
  //check some homepage conditions
263
  $events_page_id = get_option ( 'dbem_events_page' );
264
  if( is_object($wp_query) && $wp_query->is_home && !$wp_query->is_posts_page && 'page' == get_option('show_on_front') && get_option('page_on_front') == $events_page_id ){
 
265
  $wp_query->is_page = true;
266
- $wp_query->is_home = false;
267
  $wp_query->query_vars['page_id'] = $events_page_id;
268
  }
269
  if ( is_object($wp_query) && is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
10
  'booking_id',
11
  'category_id', 'category_slug',
12
  'ticket_id',
13
+ 'calendar_day',
14
  'rss', 'ical','event_categories','event_locations'
15
  );
16
 
256
 
257
  /**
258
  * Not the "WP way" but for now this'll do!
259
+ * This function tricks WP into thinking an EM static home page is just a page so that query_vars don't prevent the home page from showing properly.
260
+ * This is an old problem described here : https://core.trac.wordpress.org/ticket/25143
261
+ * Since we use these query vars in other areas and need to allow home page static settings to work, this connects the two sides so they can co-exist in different environments
262
  */
263
  public static function init_objects(){
264
  global $wp_rewrite, $wp_query;
265
  //check some homepage conditions
266
  $events_page_id = get_option ( 'dbem_events_page' );
267
  if( is_object($wp_query) && $wp_query->is_home && !$wp_query->is_posts_page && 'page' == get_option('show_on_front') && get_option('page_on_front') == $events_page_id ){
268
+ // comment long after this is written - pretty sure this prevents seach query and pagination issues on the home page when an event page is set as the home static page removing this causes issues with searches and pagination
269
  $wp_query->is_page = true;
270
+ $wp_query->is_home = false; // WP will not technically expect this to be the home page, but the front page only
271
  $wp_query->query_vars['page_id'] = $events_page_id;
272
  }
273
  if ( is_object($wp_query) && is_object($wp_rewrite) && $wp_rewrite->using_permalinks() ) {
classes/em-taxonomy-term.php CHANGED
@@ -160,12 +160,14 @@ class EM_Taxonomy_Term extends EM_Object {
160
  }
161
  }
162
  $taxonomy_string = $format;
163
- preg_match_all("/(#@?_?[A-Za-z0-9]+)({([a-zA-Z0-9,]+)})?/", $format, $placeholders);
164
  $replaces = array();
165
  $ph = strtoupper($this->option_name);
166
  foreach($placeholders[1] as $key => $result) {
167
  $replace = '';
168
  $full_result = $placeholders[0][$key];
 
 
169
  switch( $result ){
170
  case '#_'. $ph .'NAME':
171
  $replace = $this->name;
@@ -290,7 +292,7 @@ class EM_Taxonomy_Term extends EM_Object {
290
  $replace = $full_result;
291
  break;
292
  }
293
- $replaces[$full_result] = apply_filters('em_'. $this->option_name .'_output_placeholder', $replace, $this, $full_result, $target);
294
  }
295
  krsort($replaces);
296
  foreach($replaces as $full_result => $replacement){
160
  }
161
  }
162
  $taxonomy_string = $format;
163
+ preg_match_all("/(#@?_?[A-Za-z0-9_]+)({([^}]+)})?/", $format, $placeholders);
164
  $replaces = array();
165
  $ph = strtoupper($this->option_name);
166
  foreach($placeholders[1] as $key => $result) {
167
  $replace = '';
168
  $full_result = $placeholders[0][$key];
169
+ $placeholder_atts = array($result);
170
+ if( !empty($placeholders[3][$key]) ) $placeholder_atts[] = $placeholders[3][$key];
171
  switch( $result ){
172
  case '#_'. $ph .'NAME':
173
  $replace = $this->name;
292
  $replace = $full_result;
293
  break;
294
  }
295
+ $replaces[$full_result] = apply_filters('em_'. $this->option_name .'_output_placeholder', $replace, $this, $full_result, $target, $placeholder_atts);
296
  }
297
  krsort($replaces);
298
  foreach($replaces as $full_result => $replacement){
classes/em-ticket.php CHANGED
@@ -1,4 +1,14 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
  class EM_Ticket extends EM_Object{
3
  //DB Fields
4
  var $ticket_id;
@@ -48,7 +58,7 @@ class EM_Ticket extends EM_Object{
48
  protected $end;
49
  /**
50
  * is this ticket limited by spaces allotted to this ticket? false if no limit (i.e. the events general limit of seats)
51
- * @var unknown_type
52
  */
53
  var $spaces_limit = true;
54
 
@@ -108,8 +118,7 @@ class EM_Ticket extends EM_Object{
108
  function __get( $var ){
109
  if( $var == 'name' || $var == 'ticket_name' || $var == 'description' || $var == 'ticket_description' ){
110
  $prop = $var == 'name' || $var == 'description' ? 'ticket_'.$var : $var;
111
- $locale = get_locale();
112
- if( EM_ML::$is_ml && !empty($this->ticket_meta['langs'][$locale][$prop]) ){
113
  return $this->ticket_meta['langs'][EM_ML::$current_language][$prop];
114
  }else{
115
  return $this->{$prop};
1
  <?php
2
+
3
+ /**
4
+ * Class EM_Ticket
5
+ * @param string name
6
+ * @param string description
7
+ * @param string ticket_name
8
+ * @param string ticket_description
9
+ * @param string ticket_start
10
+ * @param string ticket_end
11
+ */
12
  class EM_Ticket extends EM_Object{
13
  //DB Fields
14
  var $ticket_id;
58
  protected $end;
59
  /**
60
  * is this ticket limited by spaces allotted to this ticket? false if no limit (i.e. the events general limit of seats)
61
+ * @var bool
62
  */
63
  var $spaces_limit = true;
64
 
118
  function __get( $var ){
119
  if( $var == 'name' || $var == 'ticket_name' || $var == 'description' || $var == 'ticket_description' ){
120
  $prop = $var == 'name' || $var == 'description' ? 'ticket_'.$var : $var;
121
+ if( EM_ML::$is_ml && !$this->ticket_parent && !empty($this->ticket_meta['langs'][EM_ML::$current_language][$prop]) ){
 
122
  return $this->ticket_meta['langs'][EM_ML::$current_language][$prop];
123
  }else{
124
  return $this->{$prop};
classes/event-locations/em-event-location-url.php CHANGED
@@ -16,21 +16,21 @@ class URL extends Event_Location {
16
  public function get_post(){
17
  $return = parent::get_post();
18
  if( !empty($_POST['event_location_url']) ){
19
- $this->event->event_location_data['url'] = esc_url_raw($_POST['event_location_url']);
20
  }
21
  if( !empty($_POST['event_location_url_text']) ){
22
- $this->event->event_location_data['text'] = sanitize_text_field($_POST['event_location_url_text']);
23
  }
24
  return $return;
25
  }
26
 
27
  public function validate(){
28
  $result = false;
29
- if( empty($this->event->event_location_data['url']) ){
30
  $this->event->add_error( __('Please enter a valid URL for this event location.', 'events-manager') );
31
  $result = false;
32
  }
33
- if( empty($this->event->event_location_data['text']) ){
34
  $this->event->add_error( __('Please provide some link text for this event location URL.', 'events-manager') );
35
  $result = false;
36
  }
16
  public function get_post(){
17
  $return = parent::get_post();
18
  if( !empty($_POST['event_location_url']) ){
19
+ $this->data['url'] = esc_url_raw($_POST['event_location_url']);
20
  }
21
  if( !empty($_POST['event_location_url_text']) ){
22
+ $this->data['text'] = sanitize_text_field($_POST['event_location_url_text']);
23
  }
24
  return $return;
25
  }
26
 
27
  public function validate(){
28
  $result = false;
29
+ if( empty($this->data['url']) ){
30
  $this->event->add_error( __('Please enter a valid URL for this event location.', 'events-manager') );
31
  $result = false;
32
  }
33
+ if( empty($this->data['text']) ){
34
  $this->event->add_error( __('Please provide some link text for this event location URL.', 'events-manager') );
35
  $result = false;
36
  }
classes/event-locations/em-event-location.php CHANGED
@@ -4,6 +4,7 @@ namespace EM_Event_Locations;
4
  * Class EM_Event_Location
5
  * This class is to be extended by any event location type. The only time this class is not used when not extended is if
6
  * @property-read string type
 
7
  */
8
  class Event_Location {
9
  /**
@@ -22,6 +23,11 @@ class Event_Location {
22
  * @var array
23
  */
24
  public $properties = array();
 
 
 
 
 
25
  /**
26
  * The admin template path, if there is one.
27
  * @var string
@@ -38,7 +44,7 @@ class Event_Location {
38
  * @param \EM_Event $EM_Event
39
  */
40
  public function __construct( $EM_Event ) {
41
- if( is_object($EM_Event) && property_exists($EM_Event, 'event_id') ){
42
  $this->event = $EM_Event;
43
  }
44
  }
@@ -50,37 +56,46 @@ class Event_Location {
50
  public function __get( $name ) {
51
  if( $name == 'type' ){
52
  return static::$type;
53
- }elseif( in_array($name, $this->properties) ){
54
- return isset($this->event->event_location_data[$name]) ? $this->event->event_location_data[$name] : null;
 
 
55
  }
56
  return null;
57
  }
58
 
59
  public function __set($name, $value) {
60
- if( in_array($name, $this->properties) ){
61
- $this->event->event_location_data[$name] = $value;
 
 
62
  }
63
  }
64
 
65
  public function __isset($name) {
66
  if( in_array($name, $this->properties) ){
67
- return isset($this->event->event_location_data[$name]);
68
  }
69
  return false;
70
  }
71
 
72
- public function load_postdata( $event_meta = array() ){
 
 
 
 
73
  if( empty($event_meta) ) $event_meta = $this->event->get_event_meta();
74
  $base_key = '_event_location_'.static::$type;
75
  foreach( $event_meta as $event_meta_key => $event_meta_val ){
76
  if( $event_meta_key == $base_key ){
77
- $this->event->event_location_data[static::$type] = ( is_array($event_meta_val) ) ? $event_meta_val[0]:$event_meta_val;
78
- $this->event->event_location_data[static::$type] = maybe_unserialize($this->event->event_location_data[static::$type]);
 
79
  }elseif( substr($event_meta_key, 0, strlen($base_key) ) == $base_key ){
80
- //event location data is placed directly into the event_location_data array and referenced via get_event_location()
81
  $key = str_replace('_event_location_'.static::$type.'_', '', $event_meta_key);
82
- $this->event->event_location_data[$key] = ( is_array($event_meta_val) ) ? $event_meta_val[0]:$event_meta_val;
83
- $this->event->event_location_data[$key] = maybe_unserialize($this->event->event_location_data[$key]);
84
  }
85
  }
86
  }
@@ -90,7 +105,7 @@ class Event_Location {
90
  * @return boolean
91
  */
92
  public function get_post(){
93
- $this->event->event_location_data = array();
94
  return true;
95
  }
96
 
@@ -104,10 +119,10 @@ class Event_Location {
104
  public function save(){
105
  if( is_numeric($this->event->post_id) && $this->event->post_id > 0 && static::$type !== null ){
106
  $this->reset_data();
107
- foreach( $this->event->event_location_data as $prop => $value ){
108
  $meta_key = $prop == static::$type ? '_event_location_'.$prop : '_event_location_'.static::$type.'_'.$prop;
109
- if( $value !== null ){
110
- update_post_meta( $this->event->post_id, $meta_key, $value );
111
  }else{
112
  delete_post_meta( $this->event->post_id, $meta_key );
113
  }
@@ -116,10 +131,20 @@ class Event_Location {
116
  return true;
117
  }
118
 
119
- final function reset_data( $preserve_type_data = false ){
 
 
 
 
 
 
 
 
 
 
120
  if( is_numeric($this->event->post_id) && $this->event->post_id > 0 ){
121
  global $wpdb;
122
- $result = $wpdb->query( $wpdb->prepare('DELETE FROM '.$wpdb->postmeta." WHERE post_id=%d AND meta_key LIKE '_event_location_%' AND meta_key != '_event_location_type'", $this->event->post_id) );
123
  wp_cache_delete( $this->event->post_id, 'post_meta' ); //refresh cache to prevent looking at old data
124
  return $result;
125
  }
@@ -149,6 +174,14 @@ class Event_Location {
149
  }
150
  }
151
 
 
 
 
 
 
 
 
 
152
  public static function get_label( $label_type = 'siingular' ){
153
  //override and return plural name.
154
  return static::$type;
4
  * Class EM_Event_Location
5
  * This class is to be extended by any event location type. The only time this class is not used when not extended is if
6
  * @property-read string type
7
+ * @property string event
8
  */
9
  class Event_Location {
10
  /**
23
  * @var array
24
  */
25
  public $properties = array();
26
+ /**
27
+ * Contains associative array of data of this event location. Data is accessed via getters and setters and keys must correspond to values in the $properties property.
28
+ * @var array
29
+ */
30
+ protected $data = array();
31
  /**
32
  * The admin template path, if there is one.
33
  * @var string
44
  * @param \EM_Event $EM_Event
45
  */
46
  public function __construct( $EM_Event ) {
47
+ if( is_object($EM_Event) && property_exists($EM_Event, 'event_id') ){ // we check for the event_id property in case we're dealing with an extended class
48
  $this->event = $EM_Event;
49
  }
50
  }
56
  public function __get( $name ) {
57
  if( $name == 'type' ){
58
  return static::$type;
59
+ }elseif( $name == 'event' ){
60
+ return $this->event;
61
+ }elseif( in_array($name, $this->properties) && array_key_exists($name, $this->data) ){
62
+ return $this->data[$name];
63
  }
64
  return null;
65
  }
66
 
67
  public function __set($name, $value) {
68
+ if( $name === 'event' && is_object($value) && property_exists($value, 'event_id') ){ // we check for the event_id property in case we're dealing with an extended class
69
+ $this->event = $value;
70
+ }elseif( in_array($name, $this->properties) ){
71
+ $this->data[$name] = $value;
72
  }
73
  }
74
 
75
  public function __isset($name) {
76
  if( in_array($name, $this->properties) ){
77
+ return isset($this->data[$name]);
78
  }
79
  return false;
80
  }
81
 
82
+ /**
83
+ * @param array $event_meta Array of event meta, if not supplied meta is obtained from linked event object.
84
+ * @param bool $reload Reloads post meta again into object, by default previously loaded data will be re-used.
85
+ */
86
+ public function load_postdata( $event_meta = array(), $reload = false ){
87
  if( empty($event_meta) ) $event_meta = $this->event->get_event_meta();
88
  $base_key = '_event_location_'.static::$type;
89
  foreach( $event_meta as $event_meta_key => $event_meta_val ){
90
  if( $event_meta_key == $base_key ){
91
+ // in case we have something like _event_location_url which is the actual URL of a Event_Location_URL object/type.
92
+ $this->data[static::$type] = ( is_array($event_meta_val) ) ? $event_meta_val[0]:$event_meta_val;
93
+ $this->data[static::$type] = maybe_unserialize($this->data[static::$type]);
94
  }elseif( substr($event_meta_key, 0, strlen($base_key) ) == $base_key ){
95
+ // event location data is placed directly into the event_location_data array and referenced via get_event_location()
96
  $key = str_replace('_event_location_'.static::$type.'_', '', $event_meta_key);
97
+ $this->data[$key] = ( is_array($event_meta_val) ) ? $event_meta_val[0]:$event_meta_val;
98
+ $this->data[$key] = maybe_unserialize($this->data[$key]);
99
  }
100
  }
101
  }
105
  * @return boolean
106
  */
107
  public function get_post(){
108
+ $this->data = array();
109
  return true;
110
  }
111
 
119
  public function save(){
120
  if( is_numeric($this->event->post_id) && $this->event->post_id > 0 && static::$type !== null ){
121
  $this->reset_data();
122
+ foreach( $this->properties as $prop ){
123
  $meta_key = $prop == static::$type ? '_event_location_'.$prop : '_event_location_'.static::$type.'_'.$prop;
124
+ if( $this->$prop !== null ){
125
+ update_post_meta( $this->event->post_id, $meta_key, $this->$prop );
126
  }else{
127
  delete_post_meta( $this->event->post_id, $meta_key );
128
  }
131
  return true;
132
  }
133
 
134
+ public function delete(){
135
+ $this->reset_data();
136
+ $this->data = array();
137
+ return true;
138
+ }
139
+
140
+ /**
141
+ * Deletes stored information about this location type in the database
142
+ * @return int|false
143
+ */
144
+ final function reset_data(){
145
  if( is_numeric($this->event->post_id) && $this->event->post_id > 0 ){
146
  global $wpdb;
147
+ $result = $wpdb->query( $wpdb->prepare('DELETE FROM '.$wpdb->postmeta." WHERE post_id=%d AND meta_key LIKE %s AND meta_key != '_event_location_type'", $this->event->post_id, "_event_location_{$this->type}_%") );
148
  wp_cache_delete( $this->event->post_id, 'post_meta' ); //refresh cache to prevent looking at old data
149
  return $result;
150
  }
174
  }
175
  }
176
 
177
+ /**
178
+ * Outputs additional warning info to user if they're switching event location types, this may include additional information about what may happen to event location data.
179
+ * For example, webinars on third party platforms may get deleted too, which deserves a mention and should be marked up with surrounding p tags if necessary.
180
+ */
181
+ public function admin_delete_warning(){
182
+ echo '';
183
+ }
184
+
185
  public static function get_label( $label_type = 'siingular' ){
186
  //override and return plural name.
187
  return static::$type;
classes/event-locations/em-event-locations.php CHANGED
@@ -61,7 +61,7 @@ class Event_Locations {
61
  */
62
  public static function is_enabled( $type ){
63
  $location_types = get_option('dbem_location_types', array());
64
- return !empty($location_types[$type]);
65
  }
66
 
67
  }
61
  */
62
  public static function is_enabled( $type ){
63
  $location_types = get_option('dbem_location_types', array());
64
+ return !empty($location_types[$type]) && !empty(self::$types[$type]) && class_exists(self::$types[$type]);
65
  }
66
 
67
  }
em-actions.php CHANGED
@@ -341,7 +341,8 @@ function em_init_actions() {
341
  }else{
342
  $result = false;
343
  $EM_Notices->add_error( $EM_Event->get_bookings()->get_errors() );
344
- $feedback = $EM_Event->get_bookings()->feedback_message;
 
345
  }
346
  }else{
347
  $result = false;
@@ -663,7 +664,8 @@ function em_init_actions() {
663
  if( $EM_Event->location_id > 0 ) echo __('Where','events-manager') . ' - ' . $EM_Event->get_location()->location_name . "\n";
664
  echo __('When','events-manager') . ' : ' . $EM_Event->output('#_EVENTDATES - #_EVENTTIMES') . "\n";
665
  }
666
- echo sprintf(__('Exported booking on %s','events-manager'), date_i18n('D d M Y h:i', current_time('timestamp'))) . "\n";
 
667
  }
668
  $delimiter = !defined('EM_CSV_DELIMITER') ? ',' : EM_CSV_DELIMITER;
669
  $delimiter = apply_filters('em_csv_delimiter', $delimiter);
341
  }else{
342
  $result = false;
343
  $EM_Notices->add_error( $EM_Event->get_bookings()->get_errors() );
344
+ $feedback = $EM_Event->get_bookings()->feedback_message;
345
+ if( empty($feedback) ) $feedback = implode("\r\n", $EM_Event->get_bookings()->get_errors());
346
  }
347
  }else{
348
  $result = false;
664
  if( $EM_Event->location_id > 0 ) echo __('Where','events-manager') . ' - ' . $EM_Event->get_location()->location_name . "\n";
665
  echo __('When','events-manager') . ' : ' . $EM_Event->output('#_EVENTDATES - #_EVENTTIMES') . "\n";
666
  }
667
+ $EM_DateTime = new EM_DateTime(current_time('timestamp'));
668
+ echo sprintf(__('Exported booking on %s','events-manager'), $EM_DateTime->format('D d M Y h:i')) . "\n";
669
  }
670
  $delimiter = !defined('EM_CSV_DELIMITER') ? ',' : EM_CSV_DELIMITER;
671
  $delimiter = apply_filters('em_csv_delimiter', $delimiter);
em-events.php CHANGED
@@ -9,7 +9,7 @@
9
  * @return string
10
  */
11
  function em_content($page_content) {
12
- global $post, $wpdb, $wp_query, $EM_Event, $EM_Location, $EM_Category;
13
  if( empty($post) || empty($post->ID) ) return $page_content; //fix for any other plugins calling the_content outside the loop
14
  $events_page_id = get_option ( 'dbem_events_page' );
15
  $locations_page_id = get_option( 'dbem_locations_page' );
@@ -254,7 +254,7 @@ add_filter ( 'wp_title', 'em_content_wp_title',100,3 ); //override other plugin
254
  * @return string
255
  */
256
  function em_content_wpseo_title($title, $sep = '', $seplocation = ''){
257
- if( class_exists('WPSEO_Utils') && method_exists('WPSEO_Utils', 'get_title_separator') ){
258
  $sep = WPSEO_Utils::get_title_separator();
259
  }elseif( !is_string( $sep ) ){
260
  $sep = '';
9
  * @return string
10
  */
11
  function em_content($page_content) {
12
+ global $post, $EM_Event, $EM_Location, $EM_Notices;
13
  if( empty($post) || empty($post->ID) ) return $page_content; //fix for any other plugins calling the_content outside the loop
14
  $events_page_id = get_option ( 'dbem_events_page' );
15
  $locations_page_id = get_option( 'dbem_locations_page' );
254
  * @return string
255
  */
256
  function em_content_wpseo_title($title, $sep = '', $seplocation = ''){
257
+ if( class_exists('WPSEO_Utils') && method_exists('WPSEO_Utils', 'get_title_separator') && version_compare(WPSEO_VERSION, '15.2', '<') ){
258
  $sep = WPSEO_Utils::get_title_separator();
259
  }elseif( !is_string( $sep ) ){
260
  $sep = '';
em-functions.php CHANGED
@@ -221,8 +221,8 @@ function em_get_scopes(){
221
  function em_get_currencies(){
222
  $currencies = new stdClass();
223
  $currencies->names = array('EUR' => 'EUR - Euros','USD' => 'USD - U.S. Dollars','GBP' => 'GBP - British Pounds','CAD' => 'CAD - Canadian Dollars','AUD' => 'AUD - Australian Dollars','BRL' => 'BRL - Brazilian Reais','CZK' => 'CZK - Czech Koruny','DKK' => 'DKK - Danish Kroner','HKD' => 'HKD - Hong Kong Dollars','HUF' => 'HUF - Hungarian Forints','ILS' => 'ILS - Israeli New Shekels','JPY' => 'JPY - Japanese Yen','MYR' => 'MYR - Malaysian Ringgit','MXN' => 'MXN - Mexican Pesos','TWD' => 'TWD - New Taiwan Dollars','NZD' => 'NZD - New Zealand Dollars','NOK' => 'NOK - Norwegian Kroner','PHP' => 'PHP - Philippine Pesos','PLN' => 'PLN - Polish Zlotys','SGD' => 'SGD - Singapore Dollars','SEK' => 'SEK - Swedish Kronor','CHF' => 'CHF - Swiss Francs','THB' => 'THB - Thai Baht','TRY' => 'TRY - Turkish Liras', 'RUB'=>'RUB - Russian Ruble');
224
- $currencies->symbols = array( 'EUR' => '&euro;','USD' => '$','GBP' => '&pound;','CAD' => '$','AUD' => '$','BRL' => 'R$','DKK' => 'kr','HKD' => '$','HUF' => 'Ft','JPY' => '&#165;','MYR' => 'RM','MXN' => '$','TWD' => '$','NZD' => '$','NOK' => 'kr','PHP' => 'Php','SGD' => '$','SEK' => 'kr','CHF' => 'CHF','TRY' => 'TL','RUB'=>'&#8381;');
225
- $currencies->true_symbols = array( 'EUR' => '€','USD' => '$','GBP' => '£','CAD' => '$','AUD' => '$','BRL' => 'R$','DKK' => 'kr','HKD' => '$','HUF' => 'Ft','JPY' => '¥','MYR' => 'RM','MXN' => '$','TWD' => '$','NZD' => '$','NOK' => 'kr','PHP' => 'Php','SGD' => '$','SEK' => 'kr','CHF' => 'CHF','TRY' => 'TL', 'RUB'=>'₽');
226
  return apply_filters('em_get_currencies',$currencies);
227
  }
228
 
@@ -839,7 +839,7 @@ if( !function_exists( 'is_main_query' ) ){
839
 
840
  /**
841
  * deprecated
842
- * @return unknown
843
  */
844
  function em_get_date_format(){
845
  return get_option('dbem_date_format');
221
  function em_get_currencies(){
222
  $currencies = new stdClass();
223
  $currencies->names = array('EUR' => 'EUR - Euros','USD' => 'USD - U.S. Dollars','GBP' => 'GBP - British Pounds','CAD' => 'CAD - Canadian Dollars','AUD' => 'AUD - Australian Dollars','BRL' => 'BRL - Brazilian Reais','CZK' => 'CZK - Czech Koruny','DKK' => 'DKK - Danish Kroner','HKD' => 'HKD - Hong Kong Dollars','HUF' => 'HUF - Hungarian Forints','ILS' => 'ILS - Israeli New Shekels','JPY' => 'JPY - Japanese Yen','MYR' => 'MYR - Malaysian Ringgit','MXN' => 'MXN - Mexican Pesos','TWD' => 'TWD - New Taiwan Dollars','NZD' => 'NZD - New Zealand Dollars','NOK' => 'NOK - Norwegian Kroner','PHP' => 'PHP - Philippine Pesos','PLN' => 'PLN - Polish Zlotys','SGD' => 'SGD - Singapore Dollars','SEK' => 'SEK - Swedish Kronor','CHF' => 'CHF - Swiss Francs','THB' => 'THB - Thai Baht','TRY' => 'TRY - Turkish Liras', 'RUB'=>'RUB - Russian Ruble');
224
+ $currencies->symbols = array( 'EUR' => '&euro;','USD' => '$','GBP' => '&pound;','CAD' => '$','AUD' => '$','BRL' => 'R$','DKK' => 'kr','HKD' => '$','HUF' => 'Ft','JPY' => '&#165;','MYR' => 'RM','MXN' => '$','TWD' => '$','NZD' => '$','NOK' => 'kr','PHP' => 'Php', 'PLN' => '&#122;&#322;','SGD' => '$','SEK' => 'kr','CHF' => 'CHF','TRY' => 'TL','RUB'=>'&#8381;');
225
+ $currencies->true_symbols = array( 'EUR' => '€','USD' => '$','GBP' => '£','CAD' => '$','AUD' => '$','BRL' => 'R$','DKK' => 'kr','HKD' => '$','HUF' => 'Ft','JPY' => '¥','MYR' => 'RM','MXN' => '$','TWD' => '$','NZD' => '$','NOK' => 'kr','PHP' => 'Php','PLN' => 'zł','SGD' => '$','SEK' => 'kr','CHF' => 'CHF','TRY' => 'TL', 'RUB'=>'₽');
226
  return apply_filters('em_get_currencies',$currencies);
227
  }
228
 
839
 
840
  /**
841
  * deprecated
842
+ * @return string
843
  */
844
  function em_get_date_format(){
845
  return get_option('dbem_date_format');
em-ical.php CHANGED
@@ -72,7 +72,7 @@
72
  * @return string
73
  */
74
  function em_mb_ical_wordwrap($string){
75
- if( !defined('EM_MB_ICAL_WORDWRAP') || EM_MB_ICAL_WORDWRAP ){
76
  $return = '';
77
  for ( $i = 0; strlen($string) > 0; $i++ ) {
78
  $linewidth = ($i == 0? 75 : 74);
72
  * @return string
73
  */
74
  function em_mb_ical_wordwrap($string){
75
+ if( function_exists('mb_strcut') && (!defined('EM_MB_ICAL_WORDWRAP') || EM_MB_ICAL_WORDWRAP) ){
76
  $return = '';
77
  for ( $i = 0; strlen($string) > 0; $i++ ) {
78
  $linewidth = ($i == 0? 75 : 74);
em-install.php CHANGED
@@ -138,7 +138,7 @@ function em_create_events_table() {
138
  event_parent bigint(20) unsigned NULL DEFAULT NULL,
139
  event_slug VARCHAR( 200 ) NULL DEFAULT NULL,
140
  event_owner bigint(20) unsigned DEFAULT NULL,
141
- event_status tinyint(1) unsigned NULL DEFAULT NULL,
142
  event_name text NULL DEFAULT NULL,
143
  event_start_date date NULL DEFAULT NULL,
144
  event_end_date date NULL DEFAULT NULL,
@@ -160,7 +160,7 @@ function em_create_events_table() {
160
  recurrence_id bigint(20) unsigned NULL DEFAULT NULL,
161
  event_date_created datetime NULL DEFAULT NULL,
162
  event_date_modified datetime NULL DEFAULT NULL,
163
- recurrence tinyint(1) unsigned NULL DEFAULT 0,
164
  recurrence_interval int(4) NULL DEFAULT NULL,
165
  recurrence_freq tinytext NULL DEFAULT NULL,
166
  recurrence_byday tinytext NULL DEFAULT NULL,
@@ -176,27 +176,12 @@ function em_create_events_table() {
176
 
177
  if( $wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name ){
178
  dbDelta($sql);
179
- //Add default events
180
- $in_one_week = date('Y-m-d', time() + 60*60*24*7);
181
- $in_four_weeks = date('Y-m-d', time() + 60*60*24*7*4);
182
- $in_one_year = date('Y-m-d', time() + 60*60*24*365);
183
- /*
184
- DEPRICATED - kept here as an example for how migrations from the wp_em_events table is fairly easy
185
- $wpdb->query("INSERT INTO ".$table_name." (event_name, event_start_date, event_end_date, event_start_time, event_end_time, location_id, event_slug, event_owner, event_status, post_id) VALUES ('Orality in James Joyce Conference', '$in_one_week', '$in_one_week', '16:00:00', '18:00:00', 1, 'oralty-in-james-joyce-conference','".get_current_user_id()."',1,0)");
186
- $wpdb->query("INSERT INTO ".$table_name." (event_name, event_start_date, event_end_date, event_start_time, event_end_time, location_id, event_slug, event_owner, event_status, post_id) VALUES ('Traditional music session', '$in_four_weeks', '$in_four_weeks', '20:00:00', '22:00:00', 2, 'traditional-music-session','".get_current_user_id()."',1,0)");
187
- $wpdb->query("INSERT INTO ".$table_name." (event_name, event_start_date, event_end_date, event_start_time, event_end_time, location_id, event_slug, event_owner, event_status, post_id) VALUES ('6 Nations, Italy VS Ireland', '$in_one_year', '$in_one_year', '22:00:00', '23:00:00', 3, '6-nations-italy-vs-ireland','".get_current_user_id()."',1,0)");
188
- em_migrate_events($wpdb->get_results('SELECT * FROM '.$table_name, ARRAY_A));
189
- */
190
- }else{
191
- if( get_option('dbem_version') != '' && get_option('dbem_version') < 4.939 ){
192
- //if updating from version 4 (4.934 is beta v5) then set all statuses to 1 since it's new
193
- $wpdb->query("ALTER TABLE $table_name CHANGE event_notes post_content longtext NULL DEFAULT NULL");
194
- $wpdb->query("ALTER TABLE $table_name CHANGE event_name event_name text NULL DEFAULT NULL");
195
- $wpdb->query("ALTER TABLE $table_name CHANGE location_id location_id bigint(20) unsigned NULL DEFAULT NULL");
196
- $wpdb->query("ALTER TABLE $table_name CHANGE recurrence_id recurrence_id bigint(20) unsigned NULL DEFAULT NULL");
197
- $wpdb->query("ALTER TABLE $table_name CHANGE event_start_time event_start_time time NULL DEFAULT NULL");
198
- $wpdb->query("ALTER TABLE $table_name CHANGE event_end_time event_end_time time NULL DEFAULT NULL");
199
- $wpdb->query("ALTER TABLE $table_name CHANGE event_start_date event_start_date date NULL DEFAULT NULL");
200
  }
201
  dbDelta($sql);
202
  }
@@ -408,7 +393,7 @@ function em_add_options() {
408
  'dbem_data' => array(), //used to store admin-related data such as notice flags and other row keys that may not always exist in the wp_options table
409
  //time formats
410
  'dbem_time_format' => get_option('time_format'),
411
- 'dbem_date_format' => 'd/m/Y',
412
  'dbem_date_format_js' => 'dd/mm/yy',
413
  'dbem_dates_separator' => ' - ',
414
  'dbem_times_separator' => ' - ',
@@ -879,6 +864,15 @@ function em_add_options() {
879
 
880
  function em_upgrade_current_installation(){
881
  global $wpdb, $wp_locale, $EM_Notices;
 
 
 
 
 
 
 
 
 
882
  if( !get_option('dbem_version') ){ add_option('dbem_credits',1); }
883
  if( get_option('dbem_version') != '' && get_option('dbem_version') < 5 ){
884
  //make events, cats and locs pages
@@ -1132,6 +1126,21 @@ function em_upgrade_current_installation(){
1132
  $EM_Admin_Notice = new EM_Admin_Notice(array( 'name' => 'location-types-update', 'who' => 'admin', 'where' => 'all', 'message' => "$message" ));
1133
  EM_Admin_Notices::add($EM_Admin_Notice, is_multisite());
1134
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1135
  }
1136
 
1137
  function em_set_mass_caps( $roles, $caps ){
138
  event_parent bigint(20) unsigned NULL DEFAULT NULL,
139
  event_slug VARCHAR( 200 ) NULL DEFAULT NULL,
140
  event_owner bigint(20) unsigned DEFAULT NULL,
141
+ event_status tinyint(1) NULL DEFAULT NULL,
142
  event_name text NULL DEFAULT NULL,
143
  event_start_date date NULL DEFAULT NULL,
144
  event_end_date date NULL DEFAULT NULL,
160
  recurrence_id bigint(20) unsigned NULL DEFAULT NULL,
161
  event_date_created datetime NULL DEFAULT NULL,
162
  event_date_modified datetime NULL DEFAULT NULL,
163
+ recurrence tinyint(1) unsigned NOT NULL DEFAULT 0,
164
  recurrence_interval int(4) NULL DEFAULT NULL,
165
  recurrence_freq tinytext NULL DEFAULT NULL,
166
  recurrence_byday tinytext NULL DEFAULT NULL,
176
 
177
  if( $wpdb->get_var("SHOW TABLES LIKE '$table_name'") != $table_name ){
178
  dbDelta($sql);
179
+ }elseif( get_option('dbem_version') != '' ){
180
+ if( get_option('dbem_version') < 5.984 ){
181
+ // change the recurrence flag to a required field defaulting to 0, to avoid missing recurrences in EM_Events::get() due to wayward null values
182
+ $wpdb->query("UPDATE $table_name SET recurrence = 0 WHERE recurrence IS NULL");
183
+ $wpdb->query("ALTER TABLE $table_name CHANGE `recurrence` `recurrence` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0'");
184
+ $wpdb->query("ALTER TABLE $table_name CHANGE `event_status` `event_status` TINYINT(1) NULL DEFAULT NULL;");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
185
  }
186
  dbDelta($sql);
187
  }
393
  'dbem_data' => array(), //used to store admin-related data such as notice flags and other row keys that may not always exist in the wp_options table
394
  //time formats
395
  'dbem_time_format' => get_option('time_format'),
396
+ 'dbem_date_format' => get_option('date_format'),
397
  'dbem_date_format_js' => 'dd/mm/yy',
398
  'dbem_dates_separator' => ' - ',
399
  'dbem_times_separator' => ' - ',
864
 
865
  function em_upgrade_current_installation(){
866
  global $wpdb, $wp_locale, $EM_Notices;
867
+
868
+ // Check EM Pro update min
869
+ if( defined('EMP_VERSION') && EMP_VERSION < EM_PRO_MIN_VERSION && !defined('EMP_DISABLE_WARNINGS') ) {
870
+ $message = esc_html__('There is a newer version of Events Manager Pro which is recommended for this current version of Events Manager as new features have been added. Please go to the plugin website and download the latest update.','events-manager');
871
+ $EM_Admin_Notice = new EM_Admin_Notice(array('name' => 'em-pro-updates', 'who' => 'admin', 'where' => 'all', 'message' => "$message"));
872
+ EM_Admin_Notices::add($EM_Admin_Notice, is_multisite());
873
+ }
874
+
875
+
876
  if( !get_option('dbem_version') ){ add_option('dbem_credits',1); }
877
  if( get_option('dbem_version') != '' && get_option('dbem_version') < 5 ){
878
  //make events, cats and locs pages
1126
  $EM_Admin_Notice = new EM_Admin_Notice(array( 'name' => 'location-types-update', 'who' => 'admin', 'where' => 'all', 'message' => "$message" ));
1127
  EM_Admin_Notices::add($EM_Admin_Notice, is_multisite());
1128
  }
1129
+ if( get_option('dbem_version') != '' && get_option('dbem_version') < 5.9821 ){
1130
+ // recreate all event_parent records in post meta
1131
+ $sql = "DELETE FROM {$wpdb->postmeta} WHERE meta_key = '_event_parent' AND post_id IN (SELECT post_id FROM ".EM_EVENTS_TABLE.")";
1132
+ $wpdb->query($sql);
1133
+ $sql = "INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value) SELECT post_id, '_event_parent', event_parent FROM ".EM_EVENTS_TABLE." WHERE event_parent IS NOT NULL";
1134
+ if( EM_MS_GLOBAL ){
1135
+ // do just this blog, other blogs will update themselves when loaded
1136
+ if( is_main_site() ){
1137
+ $sql .= ' AND (blog_id='.absint(get_current_blog_id()).' OR blog_id=0)';
1138
+ }else{
1139
+ $sql .= ' AND blog_id='.absint(get_current_blog_id());
1140
+ }
1141
+ }
1142
+ $wpdb->query($sql);
1143
+ }
1144
  }
1145
 
1146
  function em_set_mass_caps( $roles, $caps ){
em-template-tags.php CHANGED
@@ -113,7 +113,7 @@ function em_get_events_list_grouped( $args = array() ){
113
  if( empty($args['format']) && empty($args['format_header']) && empty($args['format_footer']) ){
114
  ob_start();
115
  if( !empty($args['ajax']) ){ echo '<div class="em-search-ajax">'; } //open AJAX wrapper
116
- em_locate_template('templates/events-grouped.php', true, array('args'=>$args));
117
  if( !empty($args['ajax']) ) echo "</div>"; //close AJAX wrapper
118
  $return = ob_get_clean();
119
  }else{
@@ -223,7 +223,7 @@ function em_get_event_form( $args = array() ){
223
  function em_events_admin($args = array()){
224
  global $EM_Event, $EM_Notices, $bp;
225
  if( is_user_logged_in() && current_user_can('edit_events') ){
226
- if( !empty($_GET['action']) && $_GET['action']=='edit' ){
227
  if( empty($_REQUEST['redirect_to']) ){
228
  $_REQUEST['redirect_to'] = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>null, 'event_id'=>null));
229
  }
@@ -239,6 +239,9 @@ function em_events_admin($args = array()){
239
  //deal with view or scope/status combinations
240
  $show_add_new = isset($args['show_add_new']) ? $args['show_add_new']:true;
241
  $args = array('order' => $order, 'search' => $search, 'owner' => get_current_user_id());
 
 
 
242
  if( !empty($_REQUEST['recurrence_id']) ){
243
  $Event = em_get_event( absint($_REQUEST['recurrence_id']) );
244
  $EM_Notices->add_alert(sprintf(esc_html__('You are viewing individual recurrences of recurring event %s.', 'events-manager'), '<a href="'.$Event->get_edit_url().'">'.$Event->event_name.'</a>'));
113
  if( empty($args['format']) && empty($args['format_header']) && empty($args['format_footer']) ){
114
  ob_start();
115
  if( !empty($args['ajax']) ){ echo '<div class="em-search-ajax">'; } //open AJAX wrapper
116
+ em_locate_template('templates/events-list-grouped.php', true, array('args'=>$args));
117
  if( !empty($args['ajax']) ) echo "</div>"; //close AJAX wrapper
118
  $return = ob_get_clean();
119
  }else{
223
  function em_events_admin($args = array()){
224
  global $EM_Event, $EM_Notices, $bp;
225
  if( is_user_logged_in() && current_user_can('edit_events') ){
226
+ if( (!empty($_GET['action']) && $_GET['action']=='edit') || (!empty($_POST['action']) && $_POST['action']=='event_save') ){
227
  if( empty($_REQUEST['redirect_to']) ){
228
  $_REQUEST['redirect_to'] = em_add_get_params($_SERVER['REQUEST_URI'], array('action'=>null, 'event_id'=>null));
229
  }
239
  //deal with view or scope/status combinations
240
  $show_add_new = isset($args['show_add_new']) ? $args['show_add_new']:true;
241
  $args = array('order' => $order, 'search' => $search, 'owner' => get_current_user_id());
242
+ if( current_user_can('edit_others_events') && !empty($_GET['admin_mode']) ){
243
+ $args['owner'] = false;
244
+ }
245
  if( !empty($_REQUEST['recurrence_id']) ){
246
  $Event = em_get_event( absint($_REQUEST['recurrence_id']) );
247
  $EM_Notices->add_alert(sprintf(esc_html__('You are viewing individual recurrences of recurring event %s.', 'events-manager'), '<a href="'.$Event->get_edit_url().'">'.$Event->event_name.'</a>'));
events-manager.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php
2
  /*
3
  Plugin Name: Events Manager
4
- Version: 5.9.8.1
5
  Plugin URI: http://wp-events-plugin.com
6
- Description: Event registration and booking management for WordPress. Recurring events, locations, google maps, rss, ical, booking registration and more!
7
  Author: Marcus Sykes
8
  Author URI: http://wp-events-plugin.com
9
  Text Domain: events-manager
@@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
28
  */
29
 
30
  // Setting constants
31
- define('EM_VERSION', 5.981); //self expanatory
32
  define('EM_PRO_MIN_VERSION', 2.6712); //self expanatory
33
  define('EM_PRO_MIN_VERSION_CRITICAL', 2.377); //self expanatory
34
  define('EM_DIR', dirname( __FILE__ )); //an absolute path to this directory
@@ -70,6 +70,7 @@ include('classes/em-exception.php');
70
  include('classes/em-options.php');
71
  include('classes/em-object.php');
72
  include('classes/em-datetime.php');
 
73
  include('classes/em-taxonomy-term.php');
74
  include('classes/em-taxonomy-terms.php');
75
  include('classes/em-taxonomy-frontend.php');
@@ -665,6 +666,7 @@ function em_locate_template( $template_name, $load=false, $the_args = array() )
665
  }
666
  $located = apply_filters('em_locate_template', $located, $template_name, $load, $the_args);
667
  if( $located && $load ){
 
668
  if( is_array($the_args) ) extract($the_args);
669
  include($located);
670
  }
1
  <?php
2
  /*
3
  Plugin Name: Events Manager
4
+ Version: 5.9.9
5
  Plugin URI: http://wp-events-plugin.com
6
+ Description: Event registration and booking management for WordPress. Recurring events, locations, webinars, google maps, rss, ical, booking registration and more!
7
  Author: Marcus Sykes
8
  Author URI: http://wp-events-plugin.com
9
  Text Domain: events-manager
28
  */
29
 
30
  // Setting constants
31
+ define('EM_VERSION', 5.99); //self expanatory
32
  define('EM_PRO_MIN_VERSION', 2.6712); //self expanatory
33
  define('EM_PRO_MIN_VERSION_CRITICAL', 2.377); //self expanatory
34
  define('EM_DIR', dirname( __FILE__ )); //an absolute path to this directory
70
  include('classes/em-options.php');
71
  include('classes/em-object.php');
72
  include('classes/em-datetime.php');
73
+ include('classes/em-datetimezone.php');
74
  include('classes/em-taxonomy-term.php');
75
  include('classes/em-taxonomy-terms.php');
76
  include('classes/em-taxonomy-frontend.php');
666
  }
667
  $located = apply_filters('em_locate_template', $located, $template_name, $load, $the_args);
668
  if( $located && $load ){
669
+ $the_args = apply_filters('em_locate_template_args_'.$template_name, $the_args, $located);
670
  if( is_array($the_args) ) extract($the_args);
671
  include($located);
672
  }
includes/css/events_manager.css CHANGED
@@ -79,6 +79,12 @@ div#em-loading { position:absolute; width:100%; height:100%; background:#FFFFFF
79
  div.css-search.no-search-main div.em-search-advanced.visible label { display:none; }
80
  div.css-search div.em-search-options { text-align:right; }
81
 
 
 
 
 
 
 
82
  /* Events List */
83
  .css-events-list table.events-table { border-spacing: 0px; border-collapse: collapse; }
84
  .css-events-list table.events-table td { padding:0px; }
@@ -109,10 +115,14 @@ div#em-loading { position:absolute; width:100%; height:100%; background:#FFFFFF
109
  div.em-booking-login label { display:inline-block; width:90px; }
110
  div.em-booking-login p{ margin:10px 0px !important; padding:0px !important; }
111
  div.em-booking-login input { margin:0px; }
112
-
 
 
 
 
113
  /* Events Admin */
114
- #em-wrapper #posts-filter .subsubsub .current { font-weight:bold; }
115
- #em-wrapper .em-events-admin-list .em-button, #em-wrapper .em-events-admin-list .em-button { float:right; }
116
 
117
  /* Add Event Form */
118
  #event-form h4 { margin:25px 0px 15px 0px; font-weight:bold; }
@@ -161,7 +171,9 @@ div#em-loading { position:absolute; width:100%; height:100%; background:#FFFFFF
161
  /* The editor */
162
  #wp-em-editor-content-wrap table { margin-bottom:0px; }
163
  /* Location form */
 
164
  #event-form .em-location-type { border-top: 1px solid #dedede; margin-top:20px; padding-top:20px; }
 
165
  #event-form .em-location-type.em-location-type-single { border:none; }
166
  #event-form .em-location-type p:first-child { margin-top:0; }
167
  #event-form div.em-location-data table { float:left; margin:0px 15px 0px 0px; }
@@ -170,6 +182,7 @@ div#em-loading { position:absolute; width:100%; height:100%; background:#FFFFFF
170
  #event-form .em-input-field label { display: block; margin-bottom:5px; }
171
  #event-form .em-input-field.em-input-field-boolean label { display: inline-block; }
172
  #event-form .em-input-field em { display: block; margin-top:2px; }
 
173
  #em-location-data table.em-location-data td, #em-location-data table.em-location-data th { vertical-align:top; border:none; }
174
  #em-location-data table.em-location-data select { width:100%; }
175
  #em-location-data table.em-location-data { width:50%; float:left; border:none; }
79
  div.css-search.no-search-main div.em-search-advanced.visible label { display:none; }
80
  div.css-search div.em-search-options { text-align:right; }
81
 
82
+ /* General Notices */
83
+ #event-form .em-notice-warning, #post .em-notice-warning { margin:10px 0px; padding:15px 20px; border-left: 4px solid #ffa500; }
84
+ #event-form .em-notice-warning h4, #post .em-notice-warning h4 { margin-top:0px; }
85
+ #event-form .em-notice-warning div.warning-bold, #post .em-notice-warning div.warning-bold{ color:#c45500; font-weight: bold; }
86
+ #event-form .em-notice-warning div.warning-bold p, #post .em-notice-warning div.warning-bold p { margin-top:0px; font-size:14px; }
87
+
88
  /* Events List */
89
  .css-events-list table.events-table { border-spacing: 0px; border-collapse: collapse; }
90
  .css-events-list table.events-table td { padding:0px; }
115
  div.em-booking-login label { display:inline-block; width:90px; }
116
  div.em-booking-login p{ margin:10px 0px !important; padding:0px !important; }
117
  div.em-booking-login input { margin:0px; }
118
+
119
+ /* Locations Admin */
120
+ #em-wrapper #locations-filter .subsubsub .current { font-weight:bold; }
121
+ #em-wrapper .em-locations-admin-list .em-button { float:right; }
122
+
123
  /* Events Admin */
124
+ #em-wrapper #posts-filter .subsubsub .current { font-weight:bold; }
125
+ #em-wrapper .em-events-admin-list .em-button { float:right; }
126
 
127
  /* Add Event Form */
128
  #event-form h4 { margin:25px 0px 15px 0px; font-weight:bold; }
171
  /* The editor */
172
  #wp-em-editor-content-wrap table { margin-bottom:0px; }
173
  /* Location form */
174
+ #event-form .em-location-types-single { display:none; visibility: hidden; }
175
  #event-form .em-location-type { border-top: 1px solid #dedede; margin-top:20px; padding-top:20px; }
176
+ #event-form .em-location-type-single .em-location-type { border-top:0; margin-top:0; padding-top:0; }
177
  #event-form .em-location-type.em-location-type-single { border:none; }
178
  #event-form .em-location-type p:first-child { margin-top:0; }
179
  #event-form div.em-location-data table { float:left; margin:0px 15px 0px 0px; }
182
  #event-form .em-input-field label { display: block; margin-bottom:5px; }
183
  #event-form .em-input-field.em-input-field-boolean label { display: inline-block; }
184
  #event-form .em-input-field em { display: block; margin-top:2px; }
185
+ #event-form .em-location-type-delete-active-alert { display:none; visibility: hidden; }
186
  #em-location-data table.em-location-data td, #em-location-data table.em-location-data th { vertical-align:top; border:none; }
187
  #em-location-data table.em-location-data select { width:100%; }
188
  #em-location-data table.em-location-data { width:50%; float:left; border:none; }
includes/css/events_manager_admin.css CHANGED
@@ -17,6 +17,12 @@ p.warning { border: 2px solid #FD0000; background: #FF7146; color: #fff; font-we
17
  div#icon-events{ background:url('../images/calendar-32.png') no-repeat center; }
18
  div#icon-bookings{ background:url('../images/bookings-32.png') no-repeat center; }
19
 
 
 
 
 
 
 
20
  /* Events List */
21
  table.events-table tr.pending { background:#FCFFA8 }
22
  table.events-table tr.past { background:#E4E4E4 }
@@ -33,6 +39,7 @@ table.events-table .category { color:#888; }
33
  #event-form .recurrence-reschedule-warning p, #post .recurrence-reschedule-warning p { margin-top:0px; font-size:14px; }
34
  /*Locations*/
35
  .em-location-type { border-top: 1px solid #dedede; margin-top:20px; padding-top:20px; }
 
36
  .em-location-type.em-location-type-single { border:none; margin-top:10px; padding-top:10px; }
37
  .em-location-type p:first-child { margin-top:0; }
38
  div.em-location-data table { float:left; margin:0 15px 0 0; }
@@ -42,6 +49,7 @@ div.em-location-data table { float:left; margin:0 15px 0 0; }
42
  .em-input-field.em-input-field-boolean label { display: inline-block; }
43
  .em-input-field em { display: block; margin-top:2px; }
44
  /* Location form */
 
45
  div.em-location-types-single { display:none; visibility: hidden; }
46
  div.em-location-data table.em-location-data td, div.em-location-data table.em-location-data th { vertical-align:top; border:none; }
47
  div.em-location-data table.em-location-data { width:50%; float:left; border:none; }
@@ -155,6 +163,7 @@ table.em-tickets-bookings-table tbody td { text-align:center; }
155
  #location-balloon-content h3 { background:none; text-shadow:none; }
156
 
157
  /* Options Page */
 
158
  #em-options-form .inside { border-top: 1px solid #dedede; margin-top:0px; padding-top:10px; }
159
  #em-options-form h3 { font-size:16px; }
160
  #em-options-form td, #em-options-form th { vertical-align:top; }
@@ -173,6 +182,7 @@ table.em-caps-table th, table.em-caps-table td { width:auto !important; }
173
  .em-ml-options table td { padding:0px 0px 5px; margin:0px; }
174
  .em-ml-options .lang { width:100px; }
175
  .em-menu-group .postbox.always-open .inside { display:block !important; }
 
176
 
177
  /* Widget Tables CSS */
178
  .em_obj .table-wrap{
17
  div#icon-events{ background:url('../images/calendar-32.png') no-repeat center; }
18
  div#icon-bookings{ background:url('../images/bookings-32.png') no-repeat center; }
19
 
20
+ /* General Notices */
21
+ #event-form .em-notice-warning, #post .em-notice-warning { margin:10px 0px; padding:15px 20px; border-left: 4px solid #ffa500; }
22
+ #event-form .em-notice-warning h4, #post .em-notice-warning h4 { margin-top:0px; }
23
+ #event-form .em-notice-warning div.warning-bold, #post .em-notice-warning div.warning-bold{ color:#c45500; font-weight: bold; }
24
+ #event-form .em-notice-warning div.warning-bold p, #post .em-notice-warning div.warning-bold p { margin-top:0px; font-size:14px; }
25
+
26
  /* Events List */
27
  table.events-table tr.pending { background:#FCFFA8 }
28
  table.events-table tr.past { background:#E4E4E4 }
39
  #event-form .recurrence-reschedule-warning p, #post .recurrence-reschedule-warning p { margin-top:0px; font-size:14px; }
40
  /*Locations*/
41
  .em-location-type { border-top: 1px solid #dedede; margin-top:20px; padding-top:20px; }
42
+ .em-location-type-single .em-location-type { border-top:0; margin-top:0; padding-top:0; }
43
  .em-location-type.em-location-type-single { border:none; margin-top:10px; padding-top:10px; }
44
  .em-location-type p:first-child { margin-top:0; }
45
  div.em-location-data table { float:left; margin:0 15px 0 0; }
49
  .em-input-field.em-input-field-boolean label { display: inline-block; }
50
  .em-input-field em { display: block; margin-top:2px; }
51
  /* Location form */
52
+ div.em-location-type, div.em-location-type-delete-active-alert { display:none; }
53
  div.em-location-types-single { display:none; visibility: hidden; }
54
  div.em-location-data table.em-location-data td, div.em-location-data table.em-location-data th { vertical-align:top; border:none; }
55
  div.em-location-data table.em-location-data { width:50%; float:left; border:none; }
163
  #location-balloon-content h3 { background:none; text-shadow:none; }
164
 
165
  /* Options Page */
166
+ #em-options-form .handlediv { display:none; visibility: hidden; }
167
  #em-options-form .inside { border-top: 1px solid #dedede; margin-top:0px; padding-top:10px; }
168
  #em-options-form h3 { font-size:16px; }
169
  #em-options-form td, #em-options-form th { vertical-align:top; }
182
  .em-ml-options table td { padding:0px 0px 5px; margin:0px; }
183
  .em-ml-options .lang { width:100px; }
184
  .em-menu-group .postbox.always-open .inside { display:block !important; }
185
+ .em-menu-group .postbox.closed { border-bottom:1px solid #ccd0d4; }
186
 
187
  /* Widget Tables CSS */
188
  .em_obj .table-wrap{
includes/css/jquery-ui.css CHANGED
@@ -1,9 +1,13 @@
1
- /*! jQuery UI - v1.11.4 - 2015-03-11
2
  * http://jqueryui.com
3
- * Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
4
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
5
- * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
6
 
 
 
 
 
7
  /* Layout helpers
8
  ----------------------------------*/
9
  .ui-helper-hidden {
@@ -38,9 +42,6 @@
38
  .ui-helper-clearfix:after {
39
  clear: both;
40
  }
41
- .ui-helper-clearfix {
42
- min-height: 0; /* support: IE7 */
43
- }
44
  .ui-helper-zfix {
45
  width: 100%;
46
  height: 100%;
@@ -60,20 +61,27 @@
60
  ----------------------------------*/
61
  .ui-state-disabled {
62
  cursor: default !important;
 
63
  }
64
 
65
 
66
  /* Icons
67
  ----------------------------------*/
68
-
69
- /* states and images */
70
  .ui-icon {
71
- display: block;
 
 
 
72
  text-indent: -99999px;
73
  overflow: hidden;
74
  background-repeat: no-repeat;
75
  }
76
 
 
 
 
 
 
77
 
78
  /* Misc visuals
79
  ----------------------------------*/
@@ -86,27 +94,97 @@
86
  width: 100%;
87
  height: 100%;
88
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  .ui-accordion .ui-accordion-header {
90
  display: block;
91
  cursor: pointer;
92
  position: relative;
93
  margin: 2px 0 0 0;
94
  padding: .5em .5em .5em .7em;
95
- min-height: 0; /* support: IE7 */
96
  font-size: 100%;
97
  }
98
- .ui-accordion .ui-accordion-icons {
99
- padding-left: 2.2em;
100
- }
101
- .ui-accordion .ui-accordion-icons .ui-accordion-icons {
102
- padding-left: 2.2em;
103
- }
104
- .ui-accordion .ui-accordion-header .ui-accordion-header-icon {
105
- position: absolute;
106
- left: .5em;
107
- top: 50%;
108
- margin-top: -8px;
109
- }
110
  .ui-accordion .ui-accordion-content {
111
  padding: 1em 2.2em;
112
  border-top: 0;
@@ -118,17 +196,78 @@
118
  left: 0;
119
  cursor: default;
120
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  .ui-button {
 
122
  display: inline-block;
123
  position: relative;
124
- padding: 0;
125
  line-height: normal;
126
  margin-right: .1em;
127
  cursor: pointer;
128
  vertical-align: middle;
129
  text-align: center;
130
- overflow: visible; /* removes extra width in IE */
 
 
 
 
 
 
131
  }
 
132
  .ui-button,
133
  .ui-button:link,
134
  .ui-button:visited,
@@ -136,91 +275,129 @@
136
  .ui-button:active {
137
  text-decoration: none;
138
  }
 
139
  /* to make room for the icon, a width needs to be set here */
140
  .ui-button-icon-only {
141
- width: 2.2em;
142
- }
143
- /* button elements seem to need a little more width */
144
- button.ui-button-icon-only {
145
- width: 2.4em;
146
  }
147
- .ui-button-icons-only {
148
- width: 3.4em;
 
 
149
  }
150
- button.ui-button-icons-only {
151
- width: 3.7em;
 
 
 
 
 
 
152
  }
153
 
154
- /* button text element */
155
- .ui-button .ui-button-text {
156
- display: block;
157
- line-height: normal;
 
 
 
158
  }
159
- .ui-button-text-only .ui-button-text {
 
 
 
 
 
160
  padding: .4em 1em;
161
  }
162
- .ui-button-icon-only .ui-button-text,
163
- .ui-button-icons-only .ui-button-text {
164
- padding: .4em;
165
- text-indent: -9999999px;
 
 
 
166
  }
167
- .ui-button-text-icon-primary .ui-button-text,
168
- .ui-button-text-icons .ui-button-text {
169
- padding: .4em 1em .4em 2.1em;
170
  }
171
- .ui-button-text-icon-secondary .ui-button-text,
172
- .ui-button-text-icons .ui-button-text {
173
- padding: .4em 2.1em .4em 1em;
 
174
  }
175
- .ui-button-text-icons .ui-button-text {
176
- padding-left: 2.1em;
177
- padding-right: 2.1em;
178
  }
179
- /* no icon support for input elements, provide padding by default */
180
- input.ui-button {
 
 
 
 
 
 
 
 
 
 
181
  padding: .4em 1em;
182
  }
183
-
184
- /* button icon element(s) */
185
- .ui-button-icon-only .ui-icon,
186
- .ui-button-text-icon-primary .ui-icon,
187
- .ui-button-text-icon-secondary .ui-icon,
188
- .ui-button-text-icons .ui-icon,
189
- .ui-button-icons-only .ui-icon {
190
- position: absolute;
191
- top: 50%;
192
- margin-top: -8px;
193
  }
194
- .ui-button-icon-only .ui-icon {
195
- left: 50%;
196
- margin-left: -8px;
197
  }
198
- .ui-button-text-icon-primary .ui-button-icon-primary,
199
- .ui-button-text-icons .ui-button-icon-primary,
200
- .ui-button-icons-only .ui-button-icon-primary {
201
- left: .5em;
202
  }
203
- .ui-button-text-icon-secondary .ui-button-icon-secondary,
204
- .ui-button-text-icons .ui-button-icon-secondary,
205
- .ui-button-icons-only .ui-button-icon-secondary {
206
- right: .5em;
207
  }
 
 
 
 
 
 
208
 
209
- /* button sets */
210
- .ui-buttonset {
211
- margin-right: 7px;
212
  }
213
- .ui-buttonset .ui-button {
214
- margin-left: 0;
215
- margin-right: -.3em;
216
  }
217
 
218
- /* workarounds */
219
- /* reset extra padding in Firefox, see h5bp.com/l */
220
- input.ui-button::-moz-focus-inner,
221
- button.ui-button::-moz-focus-inner {
222
- border: 0;
223
- padding: 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
225
  .ui-datepicker {
226
  width: 17em;
@@ -387,8 +564,17 @@ button.ui-button::-moz-focus-inner {
387
  border-right-width: 0;
388
  border-left-width: 1px;
389
  }
390
- .ui-dialog {
 
 
 
 
391
  overflow: hidden;
 
 
 
 
 
392
  position: absolute;
393
  top: 0;
394
  left: 0;
@@ -437,72 +623,47 @@ button.ui-button::-moz-focus-inner {
437
  margin: .5em .4em .5em 0;
438
  cursor: pointer;
439
  }
440
- .ui-dialog .ui-resizable-se {
441
- width: 12px;
442
- height: 12px;
443
- right: -5px;
444
- bottom: -5px;
445
- background-position: 16px 16px;
446
- }
447
- .ui-draggable .ui-dialog-titlebar {
448
- cursor: move;
449
- }
450
- .ui-draggable-handle {
451
- -ms-touch-action: none;
452
- touch-action: none;
453
  }
454
- .ui-menu {
455
- list-style: none;
456
- padding: 0;
457
- margin: 0;
458
- display: block;
459
- outline: none;
460
  }
461
- .ui-menu .ui-menu {
462
- position: absolute;
 
463
  }
464
- .ui-menu .ui-menu-item {
465
- position: relative;
466
- margin: 0;
467
- padding: 3px 1em 3px .4em;
468
- cursor: pointer;
469
- min-height: 0; /* support: IE7 */
470
- /* support: IE10, see #8844 */
471
- list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
472
  }
473
- .ui-menu .ui-menu-divider {
474
- margin: 5px 0;
475
- height: 0;
476
- font-size: 0;
477
- line-height: 0;
478
- border-width: 1px 0 0 0;
479
  }
480
- .ui-menu .ui-state-focus,
481
- .ui-menu .ui-state-active {
482
- margin: -1px;
483
  }
484
-
485
- /* icon support */
486
- .ui-menu-icons {
487
- position: relative;
488
  }
489
- .ui-menu-icons .ui-menu-item {
490
- padding-left: 2em;
 
491
  }
492
-
493
- /* left-aligned */
494
- .ui-menu .ui-icon {
495
- position: absolute;
496
  top: 0;
497
- bottom: 0;
498
- left: .2em;
499
- margin: auto 0;
500
  }
501
-
502
- /* right-aligned */
503
- .ui-menu .ui-menu-icon {
504
- left: auto;
505
- right: 0;
506
  }
507
  .ui-progressbar {
508
  height: 2em;
@@ -522,85 +683,6 @@ button.ui-button::-moz-focus-inner {
522
  .ui-progressbar-indeterminate .ui-progressbar-value {
523
  background-image: none;
524
  }
525
- .ui-resizable {
526
- position: relative;
527
- }
528
- .ui-resizable-handle {
529
- position: absolute;
530
- font-size: 0.1px;
531
- display: block;
532
- -ms-touch-action: none;
533
- touch-action: none;
534
- }
535
- .ui-resizable-disabled .ui-resizable-handle,
536
- .ui-resizable-autohide .ui-resizable-handle {
537
- display: none;
538
- }
539
- .ui-resizable-n {
540
- cursor: n-resize;
541
- height: 7px;
542
- width: 100%;
543
- top: -5px;
544
- left: 0;
545
- }
546
- .ui-resizable-s {
547
- cursor: s-resize;
548
- height: 7px;
549
- width: 100%;
550
- bottom: -5px;
551
- left: 0;
552
- }
553
- .ui-resizable-e {
554
- cursor: e-resize;
555
- width: 7px;
556
- right: -5px;
557
- top: 0;
558
- height: 100%;
559
- }
560
- .ui-resizable-w {
561
- cursor: w-resize;
562
- width: 7px;
563
- left: -5px;
564
- top: 0;
565
- height: 100%;
566
- }
567
- .ui-resizable-se {
568
- cursor: se-resize;
569
- width: 12px;
570
- height: 12px;
571
- right: 1px;
572
- bottom: 1px;
573
- }
574
- .ui-resizable-sw {
575
- cursor: sw-resize;
576
- width: 9px;
577
- height: 9px;
578
- left: -5px;
579
- bottom: -5px;
580
- }
581
- .ui-resizable-nw {
582
- cursor: nw-resize;
583
- width: 9px;
584
- height: 9px;
585
- left: -5px;
586
- top: -5px;
587
- }
588
- .ui-resizable-ne {
589
- cursor: ne-resize;
590
- width: 9px;
591
- height: 9px;
592
- right: -5px;
593
- top: -5px;
594
- }
595
- .ui-selectable {
596
- -ms-touch-action: none;
597
- touch-action: none;
598
- }
599
- .ui-selectable-helper {
600
- position: absolute;
601
- z-index: 100;
602
- border: 1px dotted black;
603
- }
604
  .ui-selectmenu-menu {
605
  padding: 0;
606
  margin: 0;
@@ -611,7 +693,6 @@ button.ui-button::-moz-focus-inner {
611
  }
612
  .ui-selectmenu-menu .ui-menu {
613
  overflow: auto;
614
- /* Support: IE7 */
615
  overflow-x: hidden;
616
  padding-bottom: 1px;
617
  }
@@ -627,28 +708,20 @@ button.ui-button::-moz-focus-inner {
627
  .ui-selectmenu-open {
628
  display: block;
629
  }
630
- .ui-selectmenu-button {
631
- display: inline-block;
632
- overflow: hidden;
633
- position: relative;
634
- text-decoration: none;
635
- cursor: pointer;
636
- }
637
- .ui-selectmenu-button span.ui-icon {
638
- right: 0.5em;
639
- left: auto;
640
- margin-top: -8px;
641
- position: absolute;
642
- top: 50%;
643
- }
644
- .ui-selectmenu-button span.ui-selectmenu-text {
645
- text-align: left;
646
- padding: 0.4em 2.1em 0.4em 1em;
647
  display: block;
648
- line-height: 1.4;
649
  overflow: hidden;
650
  text-overflow: ellipsis;
 
 
 
651
  white-space: nowrap;
 
 
 
 
 
652
  }
653
  .ui-slider {
654
  position: relative;
@@ -715,10 +788,6 @@ button.ui-button::-moz-focus-inner {
715
  .ui-slider-vertical .ui-slider-range-max {
716
  top: 0;
717
  }
718
- .ui-sortable-handle {
719
- -ms-touch-action: none;
720
- touch-action: none;
721
- }
722
  .ui-spinner {
723
  position: relative;
724
  display: inline-block;
@@ -730,14 +799,14 @@ button.ui-button::-moz-focus-inner {
730
  border: none;
731
  background: none;
732
  color: inherit;
733
- padding: 0;
734
  margin: .2em 0;
735
  vertical-align: middle;
736
  margin-left: .4em;
737
- margin-right: 22px;
738
  }
739
  .ui-spinner-button {
740
- width: 16px;
741
  height: 50%;
742
  font-size: .5em;
743
  padding: 0;
@@ -751,16 +820,9 @@ button.ui-button::-moz-focus-inner {
751
  }
752
  /* more specificity required here to override default borders */
753
  .ui-spinner a.ui-spinner-button {
754
- border-top: none;
755
- border-bottom: none;
756
- border-right: none;
757
- }
758
- /* vertically center icon */
759
- .ui-spinner .ui-icon {
760
- position: absolute;
761
- margin-top: -8px;
762
- top: 50%;
763
- left: 0;
764
  }
765
  .ui-spinner-up {
766
  top: 0;
@@ -768,12 +830,6 @@ button.ui-button::-moz-focus-inner {
768
  .ui-spinner-down {
769
  bottom: 0;
770
  }
771
-
772
- /* TR overrides */
773
- .ui-spinner .ui-icon-triangle-1-s {
774
- /* need to fix icons sprite */
775
- background-position: -65px -16px;
776
- }
777
  .ui-tabs {
778
  position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
779
  padding: .2em;
@@ -820,8 +876,6 @@ button.ui-button::-moz-focus-inner {
820
  position: absolute;
821
  z-index: 9999;
822
  max-width: 300px;
823
- -webkit-box-shadow: 0 0 5px #aaa;
824
- box-shadow: 0 0 5px #aaa;
825
  }
826
  body .ui-tooltip {
827
  border-width: 2px;
@@ -843,6 +897,9 @@ body .ui-tooltip {
843
  font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
844
  font-size: 1em;
845
  }
 
 
 
846
  .ui-widget-content {
847
  border: 1px solid #dddddd;
848
  background: #eeeeee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;
@@ -865,7 +922,13 @@ body .ui-tooltip {
865
  ----------------------------------*/
866
  .ui-state-default,
867
  .ui-widget-content .ui-state-default,
868
- .ui-widget-header .ui-state-default {
 
 
 
 
 
 
869
  border: 1px solid #cccccc;
870
  background: #f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;
871
  font-weight: bold;
@@ -873,7 +936,11 @@ body .ui-tooltip {
873
  }
874
  .ui-state-default a,
875
  .ui-state-default a:link,
876
- .ui-state-default a:visited {
 
 
 
 
877
  color: #1c94c4;
878
  text-decoration: none;
879
  }
@@ -882,7 +949,9 @@ body .ui-tooltip {
882
  .ui-widget-header .ui-state-hover,
883
  .ui-state-focus,
884
  .ui-widget-content .ui-state-focus,
885
- .ui-widget-header .ui-state-focus {
 
 
886
  border: 1px solid #fbcb09;
887
  background: #fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;
888
  font-weight: bold;
@@ -895,18 +964,32 @@ body .ui-tooltip {
895
  .ui-state-focus a,
896
  .ui-state-focus a:hover,
897
  .ui-state-focus a:link,
898
- .ui-state-focus a:visited {
 
 
899
  color: #c77405;
900
  text-decoration: none;
901
  }
 
 
 
 
902
  .ui-state-active,
903
  .ui-widget-content .ui-state-active,
904
- .ui-widget-header .ui-state-active {
 
 
 
905
  border: 1px solid #fbd850;
906
  background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
907
  font-weight: bold;
908
  color: #eb8f00;
909
  }
 
 
 
 
 
910
  .ui-state-active a,
911
  .ui-state-active a:link,
912
  .ui-state-active a:visited {
@@ -923,6 +1006,10 @@ body .ui-tooltip {
923
  background: #ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;
924
  color: #363636;
925
  }
 
 
 
 
926
  .ui-state-highlight a,
927
  .ui-widget-content .ui-state-highlight a,
928
  .ui-widget-header .ui-state-highlight a {
@@ -983,41 +1070,45 @@ body .ui-tooltip {
983
  .ui-widget-header .ui-icon {
984
  background-image: url("images/ui-icons_ffffff_256x240.png");
985
  }
986
- .ui-state-default .ui-icon {
987
- background-image: url("images/ui-icons_ef8c08_256x240.png");
988
- }
989
  .ui-state-hover .ui-icon,
990
- .ui-state-focus .ui-icon {
 
 
991
  background-image: url("images/ui-icons_ef8c08_256x240.png");
992
  }
993
- .ui-state-active .ui-icon {
 
994
  background-image: url("images/ui-icons_ef8c08_256x240.png");
995
  }
996
- .ui-state-highlight .ui-icon {
 
997
  background-image: url("images/ui-icons_228ef1_256x240.png");
998
  }
999
  .ui-state-error .ui-icon,
1000
  .ui-state-error-text .ui-icon {
1001
  background-image: url("images/ui-icons_ffd27a_256x240.png");
1002
  }
 
 
 
1003
 
1004
  /* positioning */
1005
  .ui-icon-blank { background-position: 16px 16px; }
1006
- .ui-icon-carat-1-n { background-position: 0 0; }
1007
- .ui-icon-carat-1-ne { background-position: -16px 0; }
1008
- .ui-icon-carat-1-e { background-position: -32px 0; }
1009
- .ui-icon-carat-1-se { background-position: -48px 0; }
1010
- .ui-icon-carat-1-s { background-position: -64px 0; }
1011
- .ui-icon-carat-1-sw { background-position: -80px 0; }
1012
- .ui-icon-carat-1-w { background-position: -96px 0; }
1013
- .ui-icon-carat-1-nw { background-position: -112px 0; }
1014
- .ui-icon-carat-2-n-s { background-position: -128px 0; }
1015
- .ui-icon-carat-2-e-w { background-position: -144px 0; }
1016
  .ui-icon-triangle-1-n { background-position: 0 -16px; }
1017
  .ui-icon-triangle-1-ne { background-position: -16px -16px; }
1018
  .ui-icon-triangle-1-e { background-position: -32px -16px; }
1019
  .ui-icon-triangle-1-se { background-position: -48px -16px; }
1020
- .ui-icon-triangle-1-s { background-position: -64px -16px; }
1021
  .ui-icon-triangle-1-sw { background-position: -80px -16px; }
1022
  .ui-icon-triangle-1-w { background-position: -96px -16px; }
1023
  .ui-icon-triangle-1-nw { background-position: -112px -16px; }
@@ -1027,7 +1118,7 @@ body .ui-tooltip {
1027
  .ui-icon-arrow-1-ne { background-position: -16px -32px; }
1028
  .ui-icon-arrow-1-e { background-position: -32px -32px; }
1029
  .ui-icon-arrow-1-se { background-position: -48px -32px; }
1030
- .ui-icon-arrow-1-s { background-position: -64px -32px; }
1031
  .ui-icon-arrow-1-sw { background-position: -80px -32px; }
1032
  .ui-icon-arrow-1-w { background-position: -96px -32px; }
1033
  .ui-icon-arrow-1-nw { background-position: -112px -32px; }
@@ -1039,7 +1130,7 @@ body .ui-tooltip {
1039
  .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
1040
  .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
1041
  .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
1042
- .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
1043
  .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
1044
  .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
1045
  .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
@@ -1216,10 +1307,6 @@ body .ui-tooltip {
1216
  filter: Alpha(Opacity=50); /* support: IE8 */
1217
  }
1218
  .ui-widget-shadow {
1219
- margin: -5px 0 0 -5px;
1220
- padding: 5px;
1221
- background: #000000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;
1222
- opacity: .2;
1223
- filter: Alpha(Opacity=20); /* support: IE8 */
1224
- border-radius: 5px;
1225
  }
1
+ /*! jQuery UI - v1.12.1 - 2020-11-25
2
  * http://jqueryui.com
3
+ * Includes: draggable.css, core.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css
4
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=ui-lightness&cornerRadiusShadow=5px&offsetLeftShadow=-5px&offsetTopShadow=-5px&thicknessShadow=5px&opacityShadow=20&bgImgOpacityShadow=10&bgTextureShadow=flat&bgColorShadow=000000&opacityOverlay=50&bgImgOpacityOverlay=20&bgTextureOverlay=diagonals_thick&bgColorOverlay=666666&iconColorError=ffd27a&fcError=ffffff&borderColorError=cd0a0a&bgImgOpacityError=18&bgTextureError=diagonals_thick&bgColorError=b81900&iconColorHighlight=228ef1&fcHighlight=363636&borderColorHighlight=fed22f&bgImgOpacityHighlight=75&bgTextureHighlight=highlight_soft&bgColorHighlight=ffe45c&iconColorActive=ef8c08&fcActive=eb8f00&borderColorActive=fbd850&bgImgOpacityActive=65&bgTextureActive=glass&bgColorActive=ffffff&iconColorHover=ef8c08&fcHover=c77405&borderColorHover=fbcb09&bgImgOpacityHover=100&bgTextureHover=glass&bgColorHover=fdf5ce&iconColorDefault=ef8c08&fcDefault=1c94c4&borderColorDefault=cccccc&bgImgOpacityDefault=100&bgTextureDefault=glass&bgColorDefault=f6f6f6&iconColorContent=222222&fcContent=333333&borderColorContent=dddddd&bgImgOpacityContent=100&bgTextureContent=highlight_soft&bgColorContent=eeeeee&iconColorHeader=ffffff&fcHeader=ffffff&borderColorHeader=e78f08&bgImgOpacityHeader=35&bgTextureHeader=gloss_wave&bgColorHeader=f6a828&cornerRadius=4px&fsDefault=1.1em&fwDefault=bold&ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif
5
+ * Copyright jQuery Foundation and other contributors; Licensed MIT */
6
 
7
+ .ui-draggable-handle {
8
+ -ms-touch-action: none;
9
+ touch-action: none;
10
+ }
11
  /* Layout helpers
12
  ----------------------------------*/
13
  .ui-helper-hidden {
42
  .ui-helper-clearfix:after {
43
  clear: both;
44
  }
 
 
 
45
  .ui-helper-zfix {
46
  width: 100%;
47
  height: 100%;
61
  ----------------------------------*/
62
  .ui-state-disabled {
63
  cursor: default !important;
64
+ pointer-events: none;
65
  }
66
 
67
 
68
  /* Icons
69
  ----------------------------------*/
 
 
70
  .ui-icon {
71
+ display: inline-block;
72
+ vertical-align: middle;
73
+ margin-top: -.25em;
74
+ position: relative;
75
  text-indent: -99999px;
76
  overflow: hidden;
77
  background-repeat: no-repeat;
78
  }
79
 
80
+ .ui-widget-icon-block {
81
+ left: 50%;
82
+ margin-left: -8px;
83
+ display: block;
84
+ }
85
 
86
  /* Misc visuals
87
  ----------------------------------*/
94
  width: 100%;
95
  height: 100%;
96
  }
97
+ .ui-resizable {
98
+ position: relative;
99
+ }
100
+ .ui-resizable-handle {
101
+ position: absolute;
102
+ font-size: 0.1px;
103
+ display: block;
104
+ -ms-touch-action: none;
105
+ touch-action: none;
106
+ }
107
+ .ui-resizable-disabled .ui-resizable-handle,
108
+ .ui-resizable-autohide .ui-resizable-handle {
109
+ display: none;
110
+ }
111
+ .ui-resizable-n {
112
+ cursor: n-resize;
113
+ height: 7px;
114
+ width: 100%;
115
+ top: -5px;
116
+ left: 0;
117
+ }
118
+ .ui-resizable-s {
119
+ cursor: s-resize;
120
+ height: 7px;
121
+ width: 100%;
122
+ bottom: -5px;
123
+ left: 0;
124
+ }
125
+ .ui-resizable-e {
126
+ cursor: e-resize;
127
+ width: 7px;
128
+ right: -5px;
129
+ top: 0;
130
+ height: 100%;
131
+ }
132
+ .ui-resizable-w {
133
+ cursor: w-resize;
134
+ width: 7px;
135
+ left: -5px;
136
+ top: 0;
137
+ height: 100%;
138
+ }
139
+ .ui-resizable-se {
140
+ cursor: se-resize;
141
+ width: 12px;
142
+ height: 12px;
143
+ right: 1px;
144
+ bottom: 1px;
145
+ }
146
+ .ui-resizable-sw {
147
+ cursor: sw-resize;
148
+ width: 9px;
149
+ height: 9px;
150
+ left: -5px;
151
+ bottom: -5px;
152
+ }
153
+ .ui-resizable-nw {
154
+ cursor: nw-resize;
155
+ width: 9px;
156
+ height: 9px;
157
+ left: -5px;
158
+ top: -5px;
159
+ }
160
+ .ui-resizable-ne {
161
+ cursor: ne-resize;
162
+ width: 9px;
163
+ height: 9px;
164
+ right: -5px;
165
+ top: -5px;
166
+ }
167
+ .ui-selectable {
168
+ -ms-touch-action: none;
169
+ touch-action: none;
170
+ }
171
+ .ui-selectable-helper {
172
+ position: absolute;
173
+ z-index: 100;
174
+ border: 1px dotted black;
175
+ }
176
+ .ui-sortable-handle {
177
+ -ms-touch-action: none;
178
+ touch-action: none;
179
+ }
180
  .ui-accordion .ui-accordion-header {
181
  display: block;
182
  cursor: pointer;
183
  position: relative;
184
  margin: 2px 0 0 0;
185
  padding: .5em .5em .5em .7em;
 
186
  font-size: 100%;
187
  }
 
 
 
 
 
 
 
 
 
 
 
 
188
  .ui-accordion .ui-accordion-content {
189
  padding: 1em 2.2em;
190
  border-top: 0;
196
  left: 0;
197
  cursor: default;
198
  }
199
+ .ui-menu {
200
+ list-style: none;
201
+ padding: 0;
202
+ margin: 0;
203
+ display: block;
204
+ outline: 0;
205
+ }
206
+ .ui-menu .ui-menu {
207
+ position: absolute;
208
+ }
209
+ .ui-menu .ui-menu-item {
210
+ margin: 0;
211
+ cursor: pointer;
212
+ /* support: IE10, see #8844 */
213
+ list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
214
+ }
215
+ .ui-menu .ui-menu-item-wrapper {
216
+ position: relative;
217
+ padding: 3px 1em 3px .4em;
218
+ }
219
+ .ui-menu .ui-menu-divider {
220
+ margin: 5px 0;
221
+ height: 0;
222
+ font-size: 0;
223
+ line-height: 0;
224
+ border-width: 1px 0 0 0;
225
+ }
226
+ .ui-menu .ui-state-focus,
227
+ .ui-menu .ui-state-active {
228
+ margin: -1px;
229
+ }
230
+
231
+ /* icon support */
232
+ .ui-menu-icons {
233
+ position: relative;
234
+ }
235
+ .ui-menu-icons .ui-menu-item-wrapper {
236
+ padding-left: 2em;
237
+ }
238
+
239
+ /* left-aligned */
240
+ .ui-menu .ui-icon {
241
+ position: absolute;
242
+ top: 0;
243
+ bottom: 0;
244
+ left: .2em;
245
+ margin: auto 0;
246
+ }
247
+
248
+ /* right-aligned */
249
+ .ui-menu .ui-menu-icon {
250
+ left: auto;
251
+ right: 0;
252
+ }
253
  .ui-button {
254
+ padding: .4em 1em;
255
  display: inline-block;
256
  position: relative;
 
257
  line-height: normal;
258
  margin-right: .1em;
259
  cursor: pointer;
260
  vertical-align: middle;
261
  text-align: center;
262
+ -webkit-user-select: none;
263
+ -moz-user-select: none;
264
+ -ms-user-select: none;
265
+ user-select: none;
266
+
267
+ /* Support: IE <= 11 */
268
+ overflow: visible;
269
  }
270
+
271
  .ui-button,
272
  .ui-button:link,
273
  .ui-button:visited,
275
  .ui-button:active {
276
  text-decoration: none;
277
  }
278
+
279
  /* to make room for the icon, a width needs to be set here */
280
  .ui-button-icon-only {
281
+ width: 2em;
282
+ box-sizing: border-box;
283
+ text-indent: -9999px;
284
+ white-space: nowrap;
 
285
  }
286
+
287
+ /* no icon support for input elements */
288
+ input.ui-button.ui-button-icon-only {
289
+ text-indent: 0;
290
  }
291
+
292
+ /* button icon element(s) */
293
+ .ui-button-icon-only .ui-icon {
294
+ position: absolute;
295
+ top: 50%;
296
+ left: 50%;
297
+ margin-top: -8px;
298
+ margin-left: -8px;
299
  }
300
 
301
+ .ui-button.ui-icon-notext .ui-icon {
302
+ padding: 0;
303
+ width: 2.1em;
304
+ height: 2.1em;
305
+ text-indent: -9999px;
306
+ white-space: nowrap;
307
+
308
  }
309
+
310
+ input.ui-button.ui-icon-notext .ui-icon {
311
+ width: auto;
312
+ height: auto;
313
+ text-indent: 0;
314
+ white-space: normal;
315
  padding: .4em 1em;
316
  }
317
+
318
+ /* workarounds */
319
+ /* Support: Firefox 5 - 40 */
320
+ input.ui-button::-moz-focus-inner,
321
+ button.ui-button::-moz-focus-inner {
322
+ border: 0;
323
+ padding: 0;
324
  }
325
+ .ui-controlgroup {
326
+ vertical-align: middle;
327
+ display: inline-block;
328
  }
329
+ .ui-controlgroup > .ui-controlgroup-item {
330
+ float: left;
331
+ margin-left: 0;
332
+ margin-right: 0;
333
  }
334
+ .ui-controlgroup > .ui-controlgroup-item:focus,
335
+ .ui-controlgroup > .ui-controlgroup-item.ui-visual-focus {
336
+ z-index: 9999;
337
  }
338
+ .ui-controlgroup-vertical > .ui-controlgroup-item {
339
+ display: block;
340
+ float: none;
341
+ width: 100%;
342
+ margin-top: 0;
343
+ margin-bottom: 0;
344
+ text-align: left;
345
+ }
346
+ .ui-controlgroup-vertical .ui-controlgroup-item {
347
+ box-sizing: border-box;
348
+ }
349
+ .ui-controlgroup .ui-controlgroup-label {
350
  padding: .4em 1em;
351
  }
352
+ .ui-controlgroup .ui-controlgroup-label span {
353
+ font-size: 80%;
 
 
 
 
 
 
 
 
354
  }
355
+ .ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item {
356
+ border-left: none;
 
357
  }
358
+ .ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item {
359
+ border-top: none;
 
 
360
  }
361
+ .ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content {
362
+ border-right: none;
 
 
363
  }
364
+ .ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content {
365
+ border-bottom: none;
366
+ }
367
+
368
+ /* Spinner specific style fixes */
369
+ .ui-controlgroup-vertical .ui-spinner-input {
370
 
371
+ /* Support: IE8 only, Android < 4.4 only */
372
+ width: 75%;
373
+ width: calc( 100% - 2.4em );
374
  }
375
+ .ui-controlgroup-vertical .ui-spinner .ui-spinner-up {
376
+ border-top-style: solid;
 
377
  }
378
 
379
+ .ui-checkboxradio-label .ui-icon-background {
380
+ box-shadow: inset 1px 1px 1px #ccc;
381
+ border-radius: .12em;
382
+ border: none;
383
+ }
384
+ .ui-checkboxradio-radio-label .ui-icon-background {
385
+ width: 16px;
386
+ height: 16px;
387
+ border-radius: 1em;
388
+ overflow: visible;
389
+ border: none;
390
+ }
391
+ .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,
392
+ .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon {
393
+ background-image: none;
394
+ width: 8px;
395
+ height: 8px;
396
+ border-width: 4px;
397
+ border-style: solid;
398
+ }
399
+ .ui-checkboxradio-disabled {
400
+ pointer-events: none;
401
  }
402
  .ui-datepicker {
403
  width: 17em;
564
  border-right-width: 0;
565
  border-left-width: 1px;
566
  }
567
+
568
+ /* Icons */
569
+ .ui-datepicker .ui-icon {
570
+ display: block;
571
+ text-indent: -99999px;
572
  overflow: hidden;
573
+ background-repeat: no-repeat;
574
+ left: .5em;
575
+ top: .3em;
576
+ }
577
+ .ui-dialog {
578
  position: absolute;
579
  top: 0;
580
  left: 0;
623
  margin: .5em .4em .5em 0;
624
  cursor: pointer;
625
  }
626
+ .ui-dialog .ui-resizable-n {
627
+ height: 2px;
628
+ top: 0;
 
 
 
 
 
 
 
 
 
 
629
  }
630
+ .ui-dialog .ui-resizable-e {
631
+ width: 2px;
632
+ right: 0;
 
 
 
633
  }
634
+ .ui-dialog .ui-resizable-s {
635
+ height: 2px;
636
+ bottom: 0;
637
  }
638
+ .ui-dialog .ui-resizable-w {
639
+ width: 2px;
640
+ left: 0;
 
 
 
 
 
641
  }
642
+ .ui-dialog .ui-resizable-se,
643
+ .ui-dialog .ui-resizable-sw,
644
+ .ui-dialog .ui-resizable-ne,
645
+ .ui-dialog .ui-resizable-nw {
646
+ width: 7px;
647
+ height: 7px;
648
  }
649
+ .ui-dialog .ui-resizable-se {
650
+ right: 0;
651
+ bottom: 0;
652
  }
653
+ .ui-dialog .ui-resizable-sw {
654
+ left: 0;
655
+ bottom: 0;
 
656
  }
657
+ .ui-dialog .ui-resizable-ne {
658
+ right: 0;
659
+ top: 0;
660
  }
661
+ .ui-dialog .ui-resizable-nw {
662
+ left: 0;
 
 
663
  top: 0;
 
 
 
664
  }
665
+ .ui-draggable .ui-dialog-titlebar {
666
+ cursor: move;
 
 
 
667
  }
668
  .ui-progressbar {
669
  height: 2em;
683
  .ui-progressbar-indeterminate .ui-progressbar-value {
684
  background-image: none;
685
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
686
  .ui-selectmenu-menu {
687
  padding: 0;
688
  margin: 0;
693
  }
694
  .ui-selectmenu-menu .ui-menu {
695
  overflow: auto;
 
696
  overflow-x: hidden;
697
  padding-bottom: 1px;
698
  }
708
  .ui-selectmenu-open {
709
  display: block;
710
  }
711
+ .ui-selectmenu-text {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
712
  display: block;
713
+ margin-right: 20px;
714
  overflow: hidden;
715
  text-overflow: ellipsis;
716
+ }
717
+ .ui-selectmenu-button.ui-button {
718
+ text-align: left;
719
  white-space: nowrap;
720
+ width: 14em;
721
+ }
722
+ .ui-selectmenu-icon.ui-icon {
723
+ float: right;
724
+ margin-top: 0;
725
  }
726
  .ui-slider {
727
  position: relative;
788
  .ui-slider-vertical .ui-slider-range-max {
789
  top: 0;
790
  }
 
 
 
 
791
  .ui-spinner {
792
  position: relative;
793
  display: inline-block;
799
  border: none;
800
  background: none;
801
  color: inherit;
802
+ padding: .222em 0;
803
  margin: .2em 0;
804
  vertical-align: middle;
805
  margin-left: .4em;
806
+ margin-right: 2em;
807
  }
808
  .ui-spinner-button {
809
+ width: 1.6em;
810
  height: 50%;
811
  font-size: .5em;
812
  padding: 0;
820
  }
821
  /* more specificity required here to override default borders */
822
  .ui-spinner a.ui-spinner-button {
823
+ border-top-style: none;
824
+ border-bottom-style: none;
825
+ border-right-style: none;
 
 
 
 
 
 
 
826
  }
827
  .ui-spinner-up {
828
  top: 0;
830
  .ui-spinner-down {
831
  bottom: 0;
832
  }
 
 
 
 
 
 
833
  .ui-tabs {
834
  position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
835
  padding: .2em;
876
  position: absolute;
877
  z-index: 9999;
878
  max-width: 300px;
 
 
879
  }
880
  body .ui-tooltip {
881
  border-width: 2px;
897
  font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
898
  font-size: 1em;
899
  }
900
+ .ui-widget.ui-widget-content {
901
+ border: 1px solid #cccccc;
902
+ }
903
  .ui-widget-content {
904
  border: 1px solid #dddddd;
905
  background: #eeeeee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;
922
  ----------------------------------*/
923
  .ui-state-default,
924
  .ui-widget-content .ui-state-default,
925
+ .ui-widget-header .ui-state-default,
926
+ .ui-button,
927
+
928
+ /* We use html here because we need a greater specificity to make sure disabled
929
+ works properly when clicked or hovered */
930
+ html .ui-button.ui-state-disabled:hover,
931
+ html .ui-button.ui-state-disabled:active {
932
  border: 1px solid #cccccc;
933
  background: #f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;
934
  font-weight: bold;
936
  }
937
  .ui-state-default a,
938
  .ui-state-default a:link,
939
+ .ui-state-default a:visited,
940
+ a.ui-button,
941
+ a:link.ui-button,
942
+ a:visited.ui-button,
943
+ .ui-button {
944
  color: #1c94c4;
945
  text-decoration: none;
946
  }
949
  .ui-widget-header .ui-state-hover,
950
  .ui-state-focus,
951
  .ui-widget-content .ui-state-focus,
952
+ .ui-widget-header .ui-state-focus,
953
+ .ui-button:hover,
954
+ .ui-button:focus {
955
  border: 1px solid #fbcb09;
956
  background: #fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;
957
  font-weight: bold;
964
  .ui-state-focus a,
965
  .ui-state-focus a:hover,
966
  .ui-state-focus a:link,
967
+ .ui-state-focus a:visited,
968
+ a.ui-button:hover,
969
+ a.ui-button:focus {
970
  color: #c77405;
971
  text-decoration: none;
972
  }
973
+
974
+ .ui-visual-focus {
975
+ box-shadow: 0 0 3px 1px rgb(94, 158, 214);
976
+ }
977
  .ui-state-active,
978
  .ui-widget-content .ui-state-active,
979
+ .ui-widget-header .ui-state-active,
980
+ a.ui-button:active,
981
+ .ui-button:active,
982
+ .ui-button.ui-state-active:hover {
983
  border: 1px solid #fbd850;
984
  background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
985
  font-weight: bold;
986
  color: #eb8f00;
987
  }
988
+ .ui-icon-background,
989
+ .ui-state-active .ui-icon-background {
990
+ border: #fbd850;
991
+ background-color: #eb8f00;
992
+ }
993
  .ui-state-active a,
994
  .ui-state-active a:link,
995
  .ui-state-active a:visited {
1006
  background: #ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;
1007
  color: #363636;
1008
  }
1009
+ .ui-state-checked {
1010
+ border: 1px solid #fed22f;
1011
+ background: #ffe45c;
1012
+ }
1013
  .ui-state-highlight a,
1014
  .ui-widget-content .ui-state-highlight a,
1015
  .ui-widget-header .ui-state-highlight a {
1070
  .ui-widget-header .ui-icon {
1071
  background-image: url("images/ui-icons_ffffff_256x240.png");
1072
  }
 
 
 
1073
  .ui-state-hover .ui-icon,
1074
+ .ui-state-focus .ui-icon,
1075
+ .ui-button:hover .ui-icon,
1076
+ .ui-button:focus .ui-icon {
1077
  background-image: url("images/ui-icons_ef8c08_256x240.png");
1078
  }
1079
+ .ui-state-active .ui-icon,
1080
+ .ui-button:active .ui-icon {
1081
  background-image: url("images/ui-icons_ef8c08_256x240.png");
1082
  }
1083
+ .ui-state-highlight .ui-icon,
1084
+ .ui-button .ui-state-highlight.ui-icon {
1085
  background-image: url("images/ui-icons_228ef1_256x240.png");
1086
  }
1087
  .ui-state-error .ui-icon,
1088
  .ui-state-error-text .ui-icon {
1089
  background-image: url("images/ui-icons_ffd27a_256x240.png");
1090
  }
1091
+ .ui-button .ui-icon {
1092
+ background-image: url("images/ui-icons_ef8c08_256x240.png");
1093
+ }
1094
 
1095
  /* positioning */
1096
  .ui-icon-blank { background-position: 16px 16px; }
1097
+ .ui-icon-caret-1-n { background-position: 0 0; }
1098
+ .ui-icon-caret-1-ne { background-position: -16px 0; }
1099
+ .ui-icon-caret-1-e { background-position: -32px 0; }
1100
+ .ui-icon-caret-1-se { background-position: -48px 0; }
1101
+ .ui-icon-caret-1-s { background-position: -65px 0; }
1102
+ .ui-icon-caret-1-sw { background-position: -80px 0; }
1103
+ .ui-icon-caret-1-w { background-position: -96px 0; }
1104
+ .ui-icon-caret-1-nw { background-position: -112px 0; }
1105
+ .ui-icon-caret-2-n-s { background-position: -128px 0; }
1106
+ .ui-icon-caret-2-e-w { background-position: -144px 0; }
1107
  .ui-icon-triangle-1-n { background-position: 0 -16px; }
1108
  .ui-icon-triangle-1-ne { background-position: -16px -16px; }
1109
  .ui-icon-triangle-1-e { background-position: -32px -16px; }
1110
  .ui-icon-triangle-1-se { background-position: -48px -16px; }
1111
+ .ui-icon-triangle-1-s { background-position: -65px -16px; }
1112
  .ui-icon-triangle-1-sw { background-position: -80px -16px; }
1113
  .ui-icon-triangle-1-w { background-position: -96px -16px; }
1114
  .ui-icon-triangle-1-nw { background-position: -112px -16px; }
1118
  .ui-icon-arrow-1-ne { background-position: -16px -32px; }
1119
  .ui-icon-arrow-1-e { background-position: -32px -32px; }
1120
  .ui-icon-arrow-1-se { background-position: -48px -32px; }
1121
+ .ui-icon-arrow-1-s { background-position: -65px -32px; }
1122
  .ui-icon-arrow-1-sw { background-position: -80px -32px; }
1123
  .ui-icon-arrow-1-w { background-position: -96px -32px; }
1124
  .ui-icon-arrow-1-nw { background-position: -112px -32px; }
1130
  .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
1131
  .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
1132
  .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
1133
+ .ui-icon-arrowthick-1-n { background-position: 1px -48px; }
1134
  .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
1135
  .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
1136
  .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
1307
  filter: Alpha(Opacity=50); /* support: IE8 */
1308
  }
1309
  .ui-widget-shadow {
1310
+ -webkit-box-shadow: -5px -5px 5px #000000;
1311
+ box-shadow: -5px -5px 5px #000000;
 
 
 
 
1312
  }
includes/css/jquery-ui.min.css CHANGED
@@ -1,7 +1,7 @@
1
- /*! jQuery UI - v1.11.4 - 2015-03-11
2
  * http://jqueryui.com
3
- * Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
4
- * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
5
- * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
6
 
7
- .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-dialog{overflow:hidden;position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:12px;height:12px;right:-5px;bottom:-5px;background-position:16px 16px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px}
1
+ /*! jQuery UI - v1.12.1 - 2020-11-25
2
  * http://jqueryui.com
3
+ * Includes: draggable.css, core.css, resizable.css, selectable.css, sortable.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, progressbar.css, selectmenu.css, slider.css, spinner.css, tabs.css, tooltip.css, theme.css
4
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?scope=&folderName=ui-lightness&cornerRadiusShadow=5px&offsetLeftShadow=-5px&offsetTopShadow=-5px&thicknessShadow=5px&opacityShadow=20&bgImgOpacityShadow=10&bgTextureShadow=flat&bgColorShadow=000000&opacityOverlay=50&bgImgOpacityOverlay=20&bgTextureOverlay=diagonals_thick&bgColorOverlay=666666&iconColorError=ffd27a&fcError=ffffff&borderColorError=cd0a0a&bgImgOpacityError=18&bgTextureError=diagonals_thick&bgColorError=b81900&iconColorHighlight=228ef1&fcHighlight=363636&borderColorHighlight=fed22f&bgImgOpacityHighlight=75&bgTextureHighlight=highlight_soft&bgColorHighlight=ffe45c&iconColorActive=ef8c08&fcActive=eb8f00&borderColorActive=fbd850&bgImgOpacityActive=65&bgTextureActive=glass&bgColorActive=ffffff&iconColorHover=ef8c08&fcHover=c77405&borderColorHover=fbcb09&bgImgOpacityHover=100&bgTextureHover=glass&bgColorHover=fdf5ce&iconColorDefault=ef8c08&fcDefault=1c94c4&borderColorDefault=cccccc&bgImgOpacityDefault=100&bgTextureDefault=glass&bgColorDefault=f6f6f6&iconColorContent=222222&fcContent=333333&borderColorContent=dddddd&bgImgOpacityContent=100&bgTextureContent=highlight_soft&bgColorContent=eeeeee&iconColorHeader=ffffff&fcHeader=ffffff&borderColorHeader=e78f08&bgImgOpacityHeader=35&bgTextureHeader=gloss_wave&bgColorHeader=f6a828&cornerRadius=4px&fsDefault=1.1em&fwDefault=bold&ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif
5
+ * Copyright jQuery Foundation and other contributors; Licensed MIT */
6
 
7
+ .ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #ccc}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#c77405;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-icon-background,.ui-state-active .ui-icon-background{border:#fbd850;background-color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-checked{border:1px solid #fed22f;background:#ffe45c}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{-webkit-box-shadow:-5px -5px 5px #000;box-shadow:-5px -5px 5px #000}
includes/js/events-manager.js CHANGED
@@ -288,16 +288,16 @@ jQuery(document).ready( function($){
288
  tbody.find('*[name]').each(function(index,el){
289
  el = $(el);
290
  if( el.attr('name') == 'ticket_start_pub'){
291
- tbody.find('span.ticket_start').text(el.attr('value'));
292
  }else if( el.attr('name') == 'ticket_end_pub' ){
293
- tbody.find('span.ticket_end').text(el.attr('value'));
294
  }else if( el.attr('name') == 'em_tickets['+rowNo+'][ticket_type]' ){
295
  if( el.find(':selected').val() == 'members' ){
296
  tbody.find('span.ticket_name').prepend('* ');
297
  }
298
  }else if( el.attr('name') == 'em_tickets['+rowNo+'][ticket_start_recurring_days]' ){
299
- var text = tbody.find('select.ticket-dates-from-recurring-when').val() == 'before' ? '-'+el.attr('value'):el.attr('value');
300
- if( el.attr('value') != '' ){
301
  tbody.find('span.ticket_start_recurring_days').text(text);
302
  tbody.find('span.ticket_start_recurring_days_text, span.ticket_start_time').removeClass('hidden').show();
303
  }else{
@@ -305,8 +305,8 @@ jQuery(document).ready( function($){
305
  tbody.find('span.ticket_start_recurring_days_text, span.ticket_start_time').removeClass('hidden').hide();
306
  }
307
  }else if( el.attr('name') == 'em_tickets['+rowNo+'][ticket_end_recurring_days]' ){
308
- var text = tbody.find('select.ticket-dates-to-recurring-when').val() == 'before' ? '-'+el.attr('value'):el.attr('value');
309
- if( el.attr('value') != '' ){
310
  tbody.find('span.ticket_end_recurring_days').text(text);
311
  tbody.find('span.ticket_end_recurring_days_text, span.ticket_end_time').removeClass('hidden').show();
312
  }else{
@@ -314,7 +314,8 @@ jQuery(document).ready( function($){
314
  tbody.find('span.ticket_end_recurring_days_text, span.ticket_end_time').removeClass('hidden').hide();
315
  }
316
  }else{
317
- tbody.find('.'+el.attr('name').replace('em_tickets['+rowNo+'][','').replace(']','').replace('[]','')).text(el.attr('value'));
 
318
  }
319
  });
320
  //allow for others to hook into this
@@ -575,9 +576,10 @@ jQuery(document).ready( function($){
575
  if(response.result){
576
  button.text(EM.bb_booked);
577
  }else{
578
- button.text(EM.bb_error);
579
  }
580
  if(response.message != '') alert(response.message);
 
581
  },
582
  error : function(){ button.text(EM.bb_error); }
583
  });
@@ -677,6 +679,27 @@ jQuery(document).ready( function($){
677
  if( $('.em-location-map').length > 0 || $('.em-locations-map').length > 0 || $('#em-map').length > 0 || $('.em-search-geo').length > 0 ){
678
  em_maps_load();
679
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
680
 
681
  //Finally, add autocomplete here
682
  //Autocomplete
@@ -737,6 +760,61 @@ jQuery(document).ready( function($){
737
  jQuery('#em-location-search-tip').hide();
738
  }
739
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
  jQuery(document).triggerHandler('em_javascript_loaded');
741
  });
742
 
@@ -793,9 +871,10 @@ function em_setup_datepicker(wrap){
793
  var endDate = startDate.parents('.em-date-range').find('.em-date-end').first();
794
  var startValue = startDate.nextAll('input.em-date-input').first().val();
795
  var endValue = endDate.nextAll('input.em-date-input').first().val();
 
796
  if( startValue > endValue && endValue != '' ){
797
  endDate.datepicker( "setDate" , selectedDate );
798
- endDate.trigger('change');
799
  }
800
  endDate.datepicker( "option", 'minDate', selectedDate );
801
  });
288
  tbody.find('*[name]').each(function(index,el){
289
  el = $(el);
290
  if( el.attr('name') == 'ticket_start_pub'){
291
+ tbody.find('span.ticket_start').text(el.val());
292
  }else if( el.attr('name') == 'ticket_end_pub' ){
293
+ tbody.find('span.ticket_end').text(el.val());
294
  }else if( el.attr('name') == 'em_tickets['+rowNo+'][ticket_type]' ){
295
  if( el.find(':selected').val() == 'members' ){
296
  tbody.find('span.ticket_name').prepend('* ');
297
  }
298
  }else if( el.attr('name') == 'em_tickets['+rowNo+'][ticket_start_recurring_days]' ){
299
+ var text = tbody.find('select.ticket-dates-from-recurring-when').val() == 'before' ? '-'+el.val():el.val();
300
+ if( el.val() != '' ){
301
  tbody.find('span.ticket_start_recurring_days').text(text);
302
  tbody.find('span.ticket_start_recurring_days_text, span.ticket_start_time').removeClass('hidden').show();
303
  }else{
305
  tbody.find('span.ticket_start_recurring_days_text, span.ticket_start_time').removeClass('hidden').hide();
306
  }
307
  }else if( el.attr('name') == 'em_tickets['+rowNo+'][ticket_end_recurring_days]' ){
308
+ var text = tbody.find('select.ticket-dates-to-recurring-when').val() == 'before' ? '-'+el.val():el.val();
309
+ if( el.val() != '' ){
310
  tbody.find('span.ticket_end_recurring_days').text(text);
311
  tbody.find('span.ticket_end_recurring_days_text, span.ticket_end_time').removeClass('hidden').show();
312
  }else{
314
  tbody.find('span.ticket_end_recurring_days_text, span.ticket_end_time').removeClass('hidden').hide();
315
  }
316
  }else{
317
+ var classname = el.attr('name').replace('em_tickets['+rowNo+'][','').replace(']','').replace('[]','');
318
+ tbody.find('.em-tickets-row .'+classname).text(el.val());
319
  }
320
  });
321
  //allow for others to hook into this
576
  if(response.result){
577
  button.text(EM.bb_booked);
578
  }else{
579
+ button.text(EM.bb_error);
580
  }
581
  if(response.message != '') alert(response.message);
582
+ $(document).triggerHandler('em_booking_button_response', [response, button]);
583
  },
584
  error : function(){ button.text(EM.bb_error); }
585
  });
679
  if( $('.em-location-map').length > 0 || $('.em-locations-map').length > 0 || $('#em-map').length > 0 || $('.em-search-geo').length > 0 ){
680
  em_maps_load();
681
  }
682
+
683
+ /* Location Type Selection */
684
+ $('.em-location-types .em-location-types-select').change(function(){
685
+ let el = $(this);
686
+ if( el.val() == 0 ){
687
+ $('.em-location-type').hide();
688
+ }else{
689
+ let location_type = el.find('option:selected').data('display-class');
690
+ $('.em-location-type').hide();
691
+ $('.em-location-type.'+location_type).show();
692
+ if( location_type != 'em-location-type-place' ){
693
+ jQuery('#em-location-reset a').trigger('click');
694
+ }
695
+ }
696
+ if( el.data('active') !== '' && el.val() !== el.data('active') ){
697
+ $('.em-location-type-delete-active-alert').hide();
698
+ $('.em-location-type-delete-active-alert').show();
699
+ }else{
700
+ $('.em-location-type-delete-active-alert').hide();
701
+ }
702
+ }).trigger('change');
703
 
704
  //Finally, add autocomplete here
705
  //Autocomplete
760
  jQuery('#em-location-search-tip').hide();
761
  }
762
  }
763
+ /* Local JS Timezone related placeholders */
764
+ /* Moment JS Timzeone PH */
765
+ if( window.moment ){
766
+ var replace_specials = function( day, string ){
767
+ // replace things not supported by moment
768
+ string = string.replace(/##T/g, Intl.DateTimeFormat().resolvedOptions().timeZone);
769
+ string = string.replace(/#T/g, "GMT"+day.format('Z'));
770
+ string = string.replace(/###t/g, day.utcOffset()*-60);
771
+ string = string.replace(/##t/g, day.isDST());
772
+ string = string.replace(/#t/g, day.daysInMonth());
773
+ return string;
774
+ };
775
+ $('.em-date-momentjs').each( function(){
776
+ // Start Date
777
+ var el = $(this);
778
+ var day_start = moment.unix(el.data('date-start'));
779
+ var date_start_string = replace_specials(day_start, day_start.format(el.data('date-format')));
780
+ if( el.data('date-start') !== el.data('date-end') ){
781
+ // End Date
782
+ var day_end = moment.unix(el.data('date-end'));
783
+ var day_end_string = replace_specials(day_start, day_end.format(el.data('date-format')));
784
+ // Output
785
+ var date_string = date_start_string + el.data('date-separator') + day_end_string;
786
+ }else{
787
+ var date_string = date_start_string;
788
+ }
789
+ el.text(date_string);
790
+ });
791
+ var get_date_string = function(ts, format){
792
+ let date = new Date(ts * 1000);
793
+ let minutes = date.getMinutes();
794
+ if( format == 24 ){
795
+ let hours = date.getHours();
796
+ hours = hours < 10 ? '0' + hours : hours;
797
+ minutes = minutes < 10 ? '0' + minutes : minutes;
798
+ return hours + ':' + minutes;
799
+ }else{
800
+ let hours = date.getHours() % 12;
801
+ let ampm = hours >= 12 ? 'PM' : 'AM';
802
+ if( hours === 0 ) hours = 12; // the hour '0' should be '12'
803
+ minutes = minutes < 10 ? '0'+minutes : minutes;
804
+ return hours + ':' + minutes + ' ' + ampm;
805
+ }
806
+ }
807
+ $('.em-time-localjs').each( function(){
808
+ var el = $(this);
809
+ var strTime = get_date_string( el.data('time'), el.data('time-format') );
810
+ if( el.data('time-end') ){
811
+ var separator = el.data('time-separator') ? el.data('time-separator') : ' - ';
812
+ strTime = strTime + separator + get_date_string( el.data('time-end'), el.data('time-format') );
813
+ }
814
+ el.text(strTime);
815
+ });
816
+ }
817
+ /* Done! */
818
  jQuery(document).triggerHandler('em_javascript_loaded');
819
  });
820
 
871
  var endDate = startDate.parents('.em-date-range').find('.em-date-end').first();
872
  var startValue = startDate.nextAll('input.em-date-input').first().val();
873
  var endValue = endDate.nextAll('input.em-date-input').first().val();
874
+ startDate.trigger('em_datepicker_change');
875
  if( startValue > endValue && endValue != '' ){
876
  endDate.datepicker( "setDate" , selectedDate );
877
+ endDate.trigger('change').trigger('em_datepicker_change');
878
  }
879
  endDate.datepicker( "option", 'minDate', selectedDate );
880
  });
multilingual/em-ml-admin.php CHANGED
@@ -22,8 +22,6 @@ class EM_ML_Admin{
22
  if( !empty($EM_Event) && !EM_ML::is_original($EM_Event) ){
23
  //remove meta boxes for events
24
  remove_meta_box('em-event-when', EM_POST_TYPE_EVENT, 'side');
25
- //if( isset($wp_meta_boxes[convert_to_screen(EM_POST_TYPE_EVENT)->id]['side']['high']['em-event-when']) ) unset($wp_meta_boxes[convert_to_screen(EM_POST_TYPE_EVENT)->id]['side']['high']['em-event-when']);
26
- //if( isset($wp_meta_boxes[convert_to_screen(EM_POST_TYPE_EVENT)->id]['side']['core']['em-event-when']) ) unset($wp_meta_boxes[convert_to_screen(EM_POST_TYPE_EVENT)->id]['side']['core']['em-event-when']);
27
  remove_meta_box('em-event-recurring', 'event-recurring', 'normal');
28
  remove_meta_box('em-event-when-recurring', 'event-recurring', 'side');
29
  remove_meta_box('em-event-where', EM_POST_TYPE_EVENT, 'normal');
@@ -34,6 +32,15 @@ class EM_ML_Admin{
34
  remove_meta_box('em-event-bookings-stats', 'event-recurring', 'side');
35
  remove_meta_box('em-event-group', EM_POST_TYPE_EVENT, 'side');
36
  remove_meta_box('em-event-group', 'event-recurring', 'side');
 
 
 
 
 
 
 
 
 
37
  if( get_option('dbem_attributes_enabled', true) ){
38
  remove_meta_box('em-event-attributes', EM_POST_TYPE_EVENT, 'normal');
39
  remove_meta_box('em-event-attributes', 'event-recurring', 'normal');
22
  if( !empty($EM_Event) && !EM_ML::is_original($EM_Event) ){
23
  //remove meta boxes for events
24
  remove_meta_box('em-event-when', EM_POST_TYPE_EVENT, 'side');
 
 
25
  remove_meta_box('em-event-recurring', 'event-recurring', 'normal');
26
  remove_meta_box('em-event-when-recurring', 'event-recurring', 'side');
27
  remove_meta_box('em-event-where', EM_POST_TYPE_EVENT, 'normal');
32
  remove_meta_box('em-event-bookings-stats', 'event-recurring', 'side');
33
  remove_meta_box('em-event-group', EM_POST_TYPE_EVENT, 'side');
34
  remove_meta_box('em-event-group', 'event-recurring', 'side');
35
+ foreach( array('em-event-when', 'em-event-recurring', 'em-event-when-recurring', 'em-event-where', 'em-event-bookings', 'em-event-bookings-stats', 'em-event-group') as $box_name ){
36
+ foreach( array(EM_POST_TYPE_EVENT, 'event-recurring') as $type ){
37
+ $screen_name = convert_to_screen($type)->id;
38
+ foreach( array('core', 'default', 'high', 'low') as $priority ){
39
+ if( isset($wp_meta_boxes[$screen_name]['side'][$priority][$box_name]) ) unset($wp_meta_boxes[$screen_name]['side'][$priority][$box_name]);
40
+ if( isset($wp_meta_boxes[$screen_name]['normal'][$priority][$box_name]) ) unset($wp_meta_boxes[$screen_name]['normal'][$priority][$box_name]);
41
+ }
42
+ }
43
+ }
44
  if( get_option('dbem_attributes_enabled', true) ){
45
  remove_meta_box('em-event-attributes', EM_POST_TYPE_EVENT, 'normal');
46
  remove_meta_box('em-event-attributes', 'event-recurring', 'normal');
multilingual/em-ml-io.php CHANGED
@@ -30,7 +30,8 @@ class EM_ML_IO {
30
  add_filter('em_ticket_delete', 'EM_ML_IO::ticket_delete', 10, 2);
31
  //Loading
32
  add_filter('em_event_get_location','EM_ML_IO::event_get_location',10,2);
33
- //Duplication link
 
34
  add_filter('em_event_duplicate_url','EM_ML_IO::event_duplicate_url',10, 2);
35
  }
36
 
@@ -187,6 +188,13 @@ class EM_ML_IO {
187
  return $url;
188
  }
189
 
 
 
 
 
 
 
 
190
  /**
191
  * Saves the original event recurring ID into translated recurring events, for easy reference when finding translations to reschedule.
192
  * @param EM_Event $EM_Event
30
  add_filter('em_ticket_delete', 'EM_ML_IO::ticket_delete', 10, 2);
31
  //Loading
32
  add_filter('em_event_get_location','EM_ML_IO::event_get_location',10,2);
33
+ //Duplication
34
+ //add_action('em_event_duplicate_pre', 'EM_ML_IO::em_event_duplicate_pre', 10, 1);
35
  add_filter('em_event_duplicate_url','EM_ML_IO::event_duplicate_url',10, 2);
36
  }
37
 
188
  return $url;
189
  }
190
 
191
+ /*
192
+ * Ensures events lose parent when duplicated if they're a translation.
193
+ */
194
+ public static function em_event_duplicate_pre( $EM_Event ){
195
+ $EM_Event->event_parent = null;
196
+ }
197
+
198
  /**
199
  * Saves the original event recurring ID into translated recurring events, for easy reference when finding translations to reschedule.
200
  * @param EM_Event $EM_Event
multilingual/em-ml-options.php CHANGED
@@ -209,7 +209,7 @@ class EM_ML_Options {
209
  $option_name = str_replace('pre_option_','',$filter_name);
210
  //don't use EM_ML::get_option as it creates an endless loop for options without a translation
211
  $option_langs = get_option($option_name.'_ml', array());
212
- if( !empty($option_langs[EM_ML::$current_language]) ){
213
  return $option_langs[EM_ML::$current_language];
214
  }
215
  }
209
  $option_name = str_replace('pre_option_','',$filter_name);
210
  //don't use EM_ML::get_option as it creates an endless loop for options without a translation
211
  $option_langs = get_option($option_name.'_ml', array());
212
+ if( is_array($option_langs) && !empty($option_langs[EM_ML::$current_language]) ){
213
  return $option_langs[EM_ML::$current_language];
214
  }
215
  }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: bookings, calendar, tickets, events, buddypress, event management, google
5
  Text Domain: events-manager
6
  Requires at least: 5.2
7
  Tested up to: 5.6
8
- Stable tag: 5.9.8.1
9
  Requires PHP: 5.3
10
 
11
  Fully featured event registration management including recurring events, locations management, calendar, Google map integration, booking management
@@ -115,6 +115,62 @@ See our [FAQ](http://wp-events-plugin.com/documentation/faq/) page, which is upd
115
  6. Manage attendees with various booking reports
116
 
117
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  = 5.9.8.1 =
119
  * fixed html structure error in location template breaking editor if location dropdowns are enabled
120
 
5
  Text Domain: events-manager
6
  Requires at least: 5.2
7
  Tested up to: 5.6
8
+ Stable tag: 5.9.9
9
  Requires PHP: 5.3
10
 
11
  Fully featured event registration management including recurring events, locations management, calendar, Google map integration, booking management
115
  6. Manage attendees with various booking reports
116
 
117
  == Changelog ==
118
+ = 5.9.9 =
119
+ * updated EM_DateTime and EM_DateTimeZone to remove PHP <5.3 backports and also make use of UTC offset support since PHP 5.5.10 (since WP now is requiring 5.6 as a minimum)
120
+ * fixed location dropdown not showing option for no location or a placeholder if physical locations are the only location types enabled
121
+ * fixed front-end event editor showing events list rather than submission form when there's a validation error
122
+ * fixed bug where re-saving multilingual recurring events sets parent ids out of sync and causing booking linking issues with translated events
123
+ * fixed potential minor CSRF vulnerability in oAuth base class where state could be ommitted when verifying/authorizing account, props to [@Lenon](https://lenonleite.com.br/en/2020/09/19/explorando-vulnerabilidade-em-operadores-logicos-isset-algumacoisa/)
124
+ * fixed event times output on bookings table not showing time according to formatting settings
125
+ * added 5th argument with array of segmented placeholder meta to _output_placeholder filters of events, locations, bookings and taxonomies
126
+ * tweaked placeholder regex to allow underscores in placeholder names e.g. #_PREVIOUSLY_INVALID_PLACEHOLDER
127
+ * added _SITE time-related placeholder variations which display event time relative to website timezone,
128
+ * added _LOCAL time-related placeholder variations which display event time relative to user's browser timezone (based on JS),
129
+ * fixed EM_Event::output_times() not using custom $all_day_message
130
+ * fixed booking table custom fields with accented names not being displayed or exported properly
131
+ * updated jQuery UI CSS theme
132
+ * updated PHPMailer loading location due to breaks in 5.5
133
+ * added #_EVENTDATES_LOCAL
134
+ * updated placeholder docs
135
+ * fixed save and status change filters firing before emails are sent which can cause irregular behaviour in add-ons (e.g. Zoom join links)
136
+ * optimized EM_Bookings::has_booking() function to prevent unecessary loading of bookings to event
137
+ * fixed fatal errors on ical generation if mb_string extension disabled in PHP
138
+ * added em_bp_menu_sub_nav and em_bp_menu_main_nav filters to allow easy BuddyPress/BuddyBoss menu overriding
139
+ * added data deletion and warning of deletion when switching location types,
140
+ * moved JS out of location selection template into main JS file
141
+ * changed Event_Location data handling so that event location data is kept within the object EM_Event->event_location rather than in EM_Event->event_location_data
142
+ * fixed Event_Locations::is_enabled() creating fatal errors if add-on event location plugins get deactivated whilst event location is still 'enabled' in settings
143
+ * fixed deletion of previous event location data occurring on get_post() rather than save() and added a temporary event_location_deleted property to EM_Event to contain deletable event location
144
+ * changed recurring table field to require a non-null value and default to 0 to prevent erratic behaviour if recurrences get saved with NULL in random edge cases
145
+ * removed some old migration update code for v4 > v5 update (more to be removed at a later date)
146
+ * added em_event_save_events_exclude_update_meta_keys allowing add-ons to prevent overwriting meta keys when updating recurrences
147
+ * added docs for event location types and a filter for adding custom placeholder docs to the help page
148
+ * fixed dates and possibly other placeholders not showing in site locale if admin triggers emails with a different user locale
149
+ * fixed scope search issues on search form when default scope is not 'future' and search dates left blank
150
+ * fixed template location typo preventing em_get_events_list_grouped() from working
151
+ * fixed admin columns not showing as per screen reader preferences when all cols are chosen to be displayed
152
+ * fixed bp showing booking tab/info when bookings are disabled (props @raruto)
153
+ * fixed display issues on static home page (other than EM events page) containing shortcode showing paginated events/locations/taxonomies
154
+ * fixed broken link for datepicker formatting docs on settings page
155
+ * fixed PHP errors on BuddyPress "my group events" template
156
+ * added #_BOOKINGADMINURL and #_BOOKINGADMINLINK placeholders to booking email templates
157
+ * added alt attribute to event thumbnails in MS Globals mode
158
+ * fixed Polish zloty missing symbols
159
+ * fixed 'no location' option not showing if dropdown option for physical locations enabled
160
+ * fixed booking cutoff times defaulting to 12am rather than event start time
161
+ * fixed booking cutoff times not getting set upon initial recurring event creation
162
+ * fixed trashed events showing up on front-end event editor as pending
163
+ * fixed JS issues causing ticket editor not reflecting changes during edit process before saving
164
+ * fixed Yoast SEO deprecated log warning for usage of WPSEO_Utils::get_title_separator() in > v15.2
165
+ * changed default time to WP format upon installation
166
+ * added my/all events links to front-end events admin for those with admin capabilities
167
+ * updated dev update checker to allow EM add-ons
168
+ * fixed duplication issues for custom event locations due to lack of cloning the event location within the cloned event
169
+ * added organizer property to ical feed and em_locate_template_args_... filter to enable it with (see https://pastebin.com/d2y5qXPy)
170
+ * added better booking button error feedback and a em_booking_button_response JS event
171
+ * changed EM Pro update warning to be dismissible site-wide and persist only on admin/network settings page
172
+ * removed use of date_i18n() in place of EM_DateTime->format() i.e. wp_date()
173
+
174
  = 5.9.8.1 =
175
  * fixed html structure error in location template breaking editor if location dropdowns are enabled
176
 
templates/buddypress/my-group-events.php CHANGED
@@ -49,57 +49,57 @@
49
  <?php
50
  $rowno = 0;
51
  $event_count = 0;
52
- foreach ( $EM_Events as $event ) {
53
- /* @var $event EM_Event */
54
  if( ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
55
  $rowno++;
56
  $class = ($rowno % 2) ? 'alternate' : '';
57
- $location_summary = "<b>" . $event->get_location()->name . "</b><br/>" . $event->get_location()->address . " - " . $event->get_location()->town;
58
 
59
  if( $EM_Event->start()->getTimestamp() < time() && $EM_Event->end()->getTimestamp() < time() ){
60
  $class .= " past";
61
  }
62
  //Check pending approval events
63
- if ( !$event->status ){
64
  $class .= " pending";
65
  }
66
  ?>
67
- <tr class="event <?php echo trim($class); ?>" id="event_<?php echo $event->event_id ?>">
68
  <?php /*
69
  <td>
70
- <input type='checkbox' class='row-selector' value='<?php echo $event->event_id; ?>' name='events[]' />
71
  </td>
72
  */ ?>
73
  <td>
74
  <strong>
75
- <a class="row-title" href="<?php echo $event->get_edit_url(); ?>"><?php echo ($event->event_name); ?></a>
76
  </strong>
77
  <?php
78
- if( $event->can_manage('manage_bookings','manage_others_bookings') && get_option('dbem_rsvp_enabled') == 1 && $event->event_rsvp == 1 ){
79
  ?>
80
  <br/>
81
- <a href="<?php echo esc_url($event->get_bookings_url()); ?>"><?php echo __("Bookings",'events-manager'); ?></a> &ndash;
82
- <?php _e("Booked",'events-manager'); ?>: <?php echo $event->get_bookings()->get_booked_spaces()."/".$event->get_spaces(); ?>
83
  <?php if( get_option('dbem_bookings_approval') == 1 ): ?>
84
- | <?php _e("Pending",'events-manager') ?>: <?php echo $event->get_bookings()->get_pending_spaces(); ?>
85
  <?php endif;
86
  }
87
  ?>
88
  <div class="row-actions">
89
  <?php if( current_user_can('delete_events')) : ?>
90
- <span class="trash"><a href="<?php echo $url ?>?action=event_delete&amp;event_id=<?php echo $event->event_id ?>" class="em-event-delete"><?php _e('Delete','events-manager'); ?></a></span>
91
  <?php endif; ?>
92
  </div>
93
  </td>
94
  <td>
95
- <a href="<?php echo $url ?>edit/?action=event_duplicate&amp;event_id=<?php echo $event->event_id ?>" title="<?php _e ( 'Duplicate this event', 'events-manager'); ?>">
96
  <strong>+</strong>
97
  </a>
98
  </td>
99
  <td>
100
  <?php echo $location_summary; ?>
101
- <?php if( is_object($category) && !empty($category->name) ) : ?>
102
- <br/><span class="category"><strong><?php _e( 'Category', 'events-manager'); ?>: </strong><?php echo $category->name ?></span>
103
  <?php endif; ?>
104
  </td>
105
 
@@ -110,14 +110,14 @@
110
  </td>
111
  <td>
112
  <?php
113
- if ( $event->is_recurrence() && $event->can_manage('edit_events','edit_others_events') ) {
114
  $recurrence_delete_confirm = __('WARNING! You will delete ALL recurrences of this event, including booking history associated with any event in this recurrence. To keep booking information, go to the relevant single event and save it to detach it from this recurrence series.','events-manager');
115
  ?>
116
  <strong>
117
- <?php echo $event->get_recurrence_description(); ?> <br />
118
- <a href="<?php echo $url ?>edit/?event_id=<?php echo $event->recurrence_id ?>"><?php _e ( 'Edit Recurring Events', 'events-manager'); ?></a>
119
  <?php if( current_user_can('delete_events')) : ?>
120
- <span class="trash"><a href="<?php echo $url ?>?action=event_delete&amp;event_id=<?php echo $event->event_id ?>" class="em-event-rec-delete" onclick ="if( !confirm('<?php echo $recurrence_delete_confirm; ?>') ){ return false; }"><?php _e('Delete','events-manager'); ?></a></span>
121
  <?php endif; ?>
122
  </strong>
123
  <?php
49
  <?php
50
  $rowno = 0;
51
  $event_count = 0;
52
+ foreach ($EM_Events as $EM_Event ) {
53
+ /* @var $EM_Event EM_Event */
54
  if( ($rowno < $limit || empty($limit)) && ($event_count >= $offset || $offset === 0) ) {
55
  $rowno++;
56
  $class = ($rowno % 2) ? 'alternate' : '';
57
+ $location_summary = "<b>" . $EM_Event->get_location()->name . "</b><br/>" . $EM_Event->get_location()->address . " - " . $EM_Event->get_location()->town;
58
 
59
  if( $EM_Event->start()->getTimestamp() < time() && $EM_Event->end()->getTimestamp() < time() ){
60
  $class .= " past";
61
  }
62
  //Check pending approval events
63
+ if ( !$EM_Event->status ){
64
  $class .= " pending";
65
  }
66
  ?>
67
+ <tr class="event <?php echo trim($class); ?>" id="event_<?php echo $EM_Event->event_id ?>">
68
  <?php /*
69
  <td>
70
+ <input type='checkbox' class='row-selector' value='<?php echo $EM_Event->event_id; ?>' name='events[]' />
71
  </td>
72
  */ ?>
73
  <td>
74
  <strong>
75
+ <a class="row-title" href="<?php echo $EM_Event->get_edit_url(); ?>"><?php echo ($EM_Event->event_name); ?></a>
76
  </strong>
77
  <?php
78
+ if( $EM_Event->can_manage('manage_bookings','manage_others_bookings') && get_option('dbem_rsvp_enabled') == 1 && $EM_Event->event_rsvp == 1 ){
79
  ?>
80
  <br/>
81
+ <a href="<?php echo esc_url($EM_Event->get_bookings_url()); ?>"><?php echo __("Bookings",'events-manager'); ?></a> &ndash;
82
+ <?php _e("Booked",'events-manager'); ?>: <?php echo $EM_Event->get_bookings()->get_booked_spaces()."/".$EM_Event->get_spaces(); ?>
83
  <?php if( get_option('dbem_bookings_approval') == 1 ): ?>
84
+ | <?php _e("Pending",'events-manager') ?>: <?php echo $EM_Event->get_bookings()->get_pending_spaces(); ?>
85
  <?php endif;
86
  }
87
  ?>
88
  <div class="row-actions">
89
  <?php if( current_user_can('delete_events')) : ?>
90
+ <span class="trash"><a href="<?php echo $url ?>?action=event_delete&amp;event_id=<?php echo $EM_Event->event_id ?>" class="em-event-delete"><?php _e('Delete','events-manager'); ?></a></span>
91
  <?php endif; ?>
92
  </div>
93
  </td>
94
  <td>
95
+ <a href="<?php echo $url ?>edit/?action=event_duplicate&amp;event_id=<?php echo $EM_Event->event_id ?>" title="<?php _e ( 'Duplicate this event', 'events-manager'); ?>">
96
  <strong>+</strong>
97
  </a>
98
  </td>
99
  <td>
100
  <?php echo $location_summary; ?>
101
+ <?php if( $EM_Event->get_categories()->count() > 0 ) : ?>
102
+ <br/><span class="category"><strong><?php _e( 'Category', 'events-manager'); ?>: </strong><?php echo $EM_Event->get_categories()->get_first()->name ?></span>
103
  <?php endif; ?>
104
  </td>
105
 
110
  </td>
111
  <td>
112
  <?php
113
+ if ( $EM_Event->is_recurrence() && $EM_Event->can_manage('edit_events','edit_others_events') ) {
114
  $recurrence_delete_confirm = __('WARNING! You will delete ALL recurrences of this event, including booking history associated with any event in this recurrence. To keep booking information, go to the relevant single event and save it to detach it from this recurrence series.','events-manager');
115
  ?>
116
  <strong>
117
+ <?php echo $EM_Event->get_recurrence_description(); ?> <br />
118
+ <a href="<?php echo $url ?>edit/?event_id=<?php echo $EM_Event->recurrence_id ?>"><?php _e ( 'Edit Recurring Events', 'events-manager'); ?></a>
119
  <?php if( current_user_can('delete_events')) : ?>
120
+ <span class="trash"><a href="<?php echo $url ?>?action=event_delete&amp;event_id=<?php echo $EM_Event->event_id ?>" class="em-event-rec-delete" onclick ="if( !confirm('<?php echo $recurrence_delete_confirm; ?>') ){ return false; }"><?php _e('Delete','events-manager'); ?></a></span>
121
  <?php endif; ?>
122
  </strong>
123
  <?php
templates/buddypress/profile.php CHANGED
@@ -27,20 +27,22 @@ if( user_can($bp->displayed_user->id,'edit_events') ){
27
  <?php
28
  }
29
  }
30
- ?>
31
- <h4><?php _e("Events I'm Attending", 'events-manager'); ?></h4>
32
- <?php
33
- $EM_Person = new EM_Person( $bp->displayed_user->id );
34
- $EM_Bookings = $EM_Person->get_bookings( false, apply_filters('em_bp_attending_status',1) );
35
- if(count($EM_Bookings->bookings) > 0){
36
- //Get events here in one query to speed things up
37
- $event_ids = array();
38
- foreach($EM_Bookings as $EM_Booking){
39
- $event_ids[] = $EM_Booking->event_id;
40
- }
41
- echo EM_Events::output(array('event'=>$event_ids));
42
- }else{
43
  ?>
44
- <p><?php _e('Not attending any events yet.','events-manager'); ?></p>
45
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  }
27
  <?php
28
  }
29
  }
30
+ if( get_option('dbem_rsvp_enabled') ){
 
 
 
 
 
 
 
 
 
 
 
 
31
  ?>
32
+ <h4><?php _e("Events I'm Attending", 'events-manager'); ?></h4>
33
  <?php
34
+ $EM_Person = new EM_Person( $bp->displayed_user->id );
35
+ $EM_Bookings = $EM_Person->get_bookings( false, apply_filters('em_bp_attending_status',1) );
36
+ if(count($EM_Bookings->bookings) > 0){
37
+ //Get events here in one query to speed things up
38
+ $event_ids = array();
39
+ foreach($EM_Bookings as $EM_Booking){
40
+ $event_ids[] = $EM_Booking->event_id;
41
+ }
42
+ echo EM_Events::output(array('event'=>$event_ids));
43
+ }else{
44
+ ?>
45
+ <p><?php _e('Not attending any events yet.','events-manager'); ?></p>
46
+ <?php
47
+ }
48
  }
templates/forms/event/bookings.php CHANGED
@@ -190,7 +190,7 @@ $reschedule_warnings = !empty($EM_Event->event_id) && $EM_Event->is_recurring()
190
  </select>
191
  <?php _e('at','events-manager'); ?>
192
  </span>
193
- <input type="text" name="event_rsvp_time" class="em-time-input" maxlength="8" size="8" value="<?php echo $EM_Event->rsvp_end()->format(em_get_hour_format()); ?>" />
194
  <br />
195
  <em><?php esc_html_e('This is the definite date after which bookings will be closed for this event, regardless of individual ticket settings above. Default value will be the event start date.','events-manager'); ?></em>
196
  </p>
190
  </select>
191
  <?php _e('at','events-manager'); ?>
192
  </span>
193
+ <input type="text" name="event_rsvp_time" class="em-time-input" maxlength="8" size="8" value="<?php if (!empty($EM_Event->event_rsvp_time)) echo $EM_Event->rsvp_end()->format(em_get_hour_format()); ?>" />
194
  <br />
195
  <em><?php esc_html_e('This is the definite date after which bookings will be closed for this event, regardless of individual ticket settings above. Default value will be the event start date.','events-manager'); ?></em>
196
  </p>
templates/forms/event/event-locations/url.php CHANGED
@@ -3,9 +3,9 @@ global $EM_Event;
3
  ?>
4
  <div class="em-input-field em-input-field-text em-location-data-url">
5
  <label for="event_location_url"><?php esc_html_e( 'URL', 'events-manager')?></label>
6
- <input id="event_location_url" type="text" name="event_location_url" value="<?php echo esc_attr($EM_Event->get_event_location()->url); ; ?>" />
7
  </div>
8
  <div class="em-input-field em-input-field-text em-location-data-url-text">
9
  <label for="event_location_url_text"><?php esc_html_e( 'Link Text', 'events-manager')?></label>
10
- <input id="event_location_url_text" type="text" name="event_location_url_text" value="<?php echo esc_attr($EM_Event->get_event_location()->text); ; ?>" />
11
  </div>
3
  ?>
4
  <div class="em-input-field em-input-field-text em-location-data-url">
5
  <label for="event_location_url"><?php esc_html_e( 'URL', 'events-manager')?></label>
6
+ <input id="event_location_url" type="text" name="event_location_url" value="<?php if( $EM_Event->has_event_location('url') ) echo esc_attr($EM_Event->get_event_location()->url); ?>" />
7
  </div>
8
  <div class="em-input-field em-input-field-text em-location-data-url-text">
9
  <label for="event_location_url_text"><?php esc_html_e( 'Link Text', 'events-manager')?></label>
10
+ <input id="event_location_url_text" type="text" name="event_location_url_text" value="<?php if( $EM_Event->has_event_location('url') ) echo esc_attr($EM_Event->get_event_location()->text); ; ?>" />
11
  </div>
templates/forms/event/location.php CHANGED
@@ -4,7 +4,7 @@ $required = apply_filters('em_required_html','<i>*</i>');
4
 
5
  //determine location types (if neexed)
6
  $location_types = array();
7
- if( !get_option('dbem_require_location') && !get_option('dbem_use_select_for_locations') ){
8
  $location_types[0] = array(
9
  'selected' => $EM_Event->location_id === '0' || $EM_Event->location_id === 0,
10
  'description' => esc_html__('No Location','events-manager'),
@@ -29,30 +29,21 @@ foreach( EM_Event_Locations\Event_Locations::get_types() as $event_location_type
29
  ?>
30
  <div class="em-input-field em-input-field-select em-location-types <?php if( count($location_types) == 1 ) echo 'em-location-types-single'; ?>">
31
  <label><?php esc_html_e ( 'Location Type', 'events-manager')?></label>
32
- <select name="location_type" class="em-location-types-select">
33
  <?php foreach( $location_types as $location_type => $location_type_option ): ?>
34
  <option value="<?php echo esc_attr($location_type); ?>" <?php if( !empty($location_type_option['selected']) ) echo 'selected="selected"'; ?> data-display-class="<?php if( !empty($location_type_option['display-class']) ) echo esc_attr($location_type_option['display-class']); ?>">
35
  <?php echo esc_html($location_type_option['description']); ?>
36
  </option>
37
  <?php endforeach; ?>
38
  </select>
39
- <script type="text/javascript">
40
- jQuery(document).ready(function($){
41
- $('.em-location-types .em-location-types-select').change(function(){
42
- let el = $(this);
43
- if( el.val() == 0 ){
44
- $('.em-location-type').hide();
45
- }else{
46
- let location_type = el.find('option:selected').data('display-class');
47
- $('.em-location-type').hide();
48
- $('.em-location-type.'+location_type).show();
49
- if( location_type != 'em-location-type-place' ){
50
- jQuery('#em-location-reset a').trigger('click');
51
- }
52
- }
53
- }).trigger('change');
54
- });
55
- </script>
56
  </div>
57
  <?php if( EM_Locations::is_enabled() ): ?>
58
  <div id="em-location-data" class="em-location-data em-location-type em-location-type-place <?php if( count($location_types) == 1 ) echo 'em-location-type-single'; ?>">
@@ -68,6 +59,15 @@ foreach( EM_Event_Locations\Event_Locations::get_types() as $event_location_type
68
  <td>
69
  <select name="location_id" id='location-select-id' size="1">
70
  <?php
 
 
 
 
 
 
 
 
 
71
  $ddm_args = array('private'=>$EM_Event->can_manage('read_private_locations'));
72
  $ddm_args['owner'] = (is_user_logged_in() && !current_user_can('read_others_locations')) ? get_current_user_id() : false;
73
  $locations = EM_Locations::get($ddm_args);
@@ -173,7 +173,7 @@ foreach( EM_Event_Locations\Event_Locations::get_types() as $event_location_type
173
  <div class="em-event-location-data">
174
  <?php foreach( EM_Event_Locations\Event_Locations::get_types() as $event_location_type => $EM_Event_Location_Class ): /* @var EM_Event_Locations\Event_Location $EM_Event_Location_Class */ ?>
175
  <?php if( $EM_Event_Location_Class::is_enabled() ): ?>
176
- <div class="em-location-type em-event-location-type-<?php echo esc_attr($event_location_type); ?>">
177
  <?php $EM_Event_Location_Class::load_admin_template(); ?>
178
  </div>
179
  <?php endif; ?>
4
 
5
  //determine location types (if neexed)
6
  $location_types = array();
7
+ if( !get_option('dbem_require_location') ){
8
  $location_types[0] = array(
9
  'selected' => $EM_Event->location_id === '0' || $EM_Event->location_id === 0,
10
  'description' => esc_html__('No Location','events-manager'),
29
  ?>
30
  <div class="em-input-field em-input-field-select em-location-types <?php if( count($location_types) == 1 ) echo 'em-location-types-single'; ?>">
31
  <label><?php esc_html_e ( 'Location Type', 'events-manager')?></label>
32
+ <select name="location_type" class="em-location-types-select" data-active="<?php echo esc_attr($EM_Event->event_location_type); ?>">
33
  <?php foreach( $location_types as $location_type => $location_type_option ): ?>
34
  <option value="<?php echo esc_attr($location_type); ?>" <?php if( !empty($location_type_option['selected']) ) echo 'selected="selected"'; ?> data-display-class="<?php if( !empty($location_type_option['display-class']) ) echo esc_attr($location_type_option['display-class']); ?>">
35
  <?php echo esc_html($location_type_option['description']); ?>
36
  </option>
37
  <?php endforeach; ?>
38
  </select>
39
+ <?php if( $EM_Event->has_event_location() ): ?>
40
+ <div class="em-location-type-delete-active-alert em-notice-warning">
41
+ <div class="warning-bold">
42
+ <p><em><?php esc_html_e('You are switching location type, if you update this event your event previous location data will be deleted.', 'events-manager'); ?></em></p>
43
+ </div>
44
+ <?php $EM_Event->get_event_location()->admin_delete_warning(); ?>
45
+ </div>
46
+ <?php endif; ?>
 
 
 
 
 
 
 
 
 
47
  </div>
48
  <?php if( EM_Locations::is_enabled() ): ?>
49
  <div id="em-location-data" class="em-location-data em-location-type em-location-type-place <?php if( count($location_types) == 1 ) echo 'em-location-type-single'; ?>">
59
  <td>
60
  <select name="location_id" id='location-select-id' size="1">
61
  <?php
62
+ if ( count($location_types) == 1 && !get_option('dbem_require_location') ){ // we don't consider optional locations as a type for ddm
63
+ ?>
64
+ <option value="0"><?php esc_html_e('No Location','events-manager'); ?></option>
65
+ <?php
66
+ }elseif( empty(get_option('dbem_default_location')) ){
67
+ ?>
68
+ <option value="0"><?php esc_html_e('Select Location','events-manager'); ?></option>
69
+ <?php
70
+ }
71
  $ddm_args = array('private'=>$EM_Event->can_manage('read_private_locations'));
72
  $ddm_args['owner'] = (is_user_logged_in() && !current_user_can('read_others_locations')) ? get_current_user_id() : false;
73
  $locations = EM_Locations::get($ddm_args);
173
  <div class="em-event-location-data">
174
  <?php foreach( EM_Event_Locations\Event_Locations::get_types() as $event_location_type => $EM_Event_Location_Class ): /* @var EM_Event_Locations\Event_Location $EM_Event_Location_Class */ ?>
175
  <?php if( $EM_Event_Location_Class::is_enabled() ): ?>
176
+ <div class="em-location-type em-event-location-type-<?php echo esc_attr($event_location_type); ?> <?php if( count($location_types) == 1 ) echo 'em-location-type-single'; ?>">
177
  <?php $EM_Event_Location_Class::load_admin_template(); ?>
178
  </div>
179
  <?php endif; ?>
templates/tables/events.php CHANGED
@@ -1,33 +1,42 @@
1
  <?php
2
  //TODO Simplify panel for events, use form flags to detect certain actions (e.g. submitted, etc)
3
  global $wpdb, $bp, $EM_Notices;
4
- /* @var $args array */
5
- /* @var $EM_Events array */
6
- /* @var $events_count int */
7
- /* @var $future_count int */
8
- /* @var $past_count int */
9
- /* @var $pending_count int */
10
- /* @var $url string */
11
- /* @var $show_add_new bool */
12
- /* @var $limit int */
13
- //add new button will only appear if called from em_event_admin template tag, or if the $show_add_new var is set
 
14
  ?>
15
  <div class="em-events-admin-list">
16
  <?php
17
  echo $EM_Notices;
 
18
  if(!empty($show_add_new) && current_user_can('edit_events')) echo '<a class="em-button button add-new-h2" href="'.em_add_get_params($_SERVER['REQUEST_URI'],array('action'=>'edit','scope'=>null,'status'=>null,'event_id'=>null, 'success'=>null)).'">'.__('Add New','events-manager').'</a>';
19
  ?>
20
  <form id="posts-filter" action="" method="get">
21
  <div class="subsubsub">
22
- <?php $default_params = array('scope'=>null,'status'=>null,'em_search'=>null,'pno'=>null); //template for cleaning the link for each view below ?>
23
- <a href='<?php echo em_add_get_params($_SERVER['REQUEST_URI'], $default_params + array('view'=>'future')); ?>' <?php echo ( !isset($_GET['view']) ) ? 'class="current"':''; ?>><?php _e ( 'Upcoming', 'events-manager'); ?> <span class="count">(<?php echo $future_count; ?>)</span></a> &nbsp;|&nbsp;
24
  <?php if( $pending_count > 0 ): ?>
25
- <a href='<?php echo em_add_get_params($_SERVER['REQUEST_URI'], $default_params + array('view'=>'pending')); ?>' <?php echo ( isset($_GET['view']) && $_GET['view'] == 'pending' ) ? 'class="current"':''; ?>><?php _e ( 'Pending', 'events-manager'); ?> <span class="count">(<?php echo $pending_count; ?>)</span></a> &nbsp;|&nbsp;
26
  <?php endif; ?>
27
  <?php if( $draft_count > 0 ): ?>
28
- <a href='<?php echo em_add_get_params($_SERVER['REQUEST_URI'], $default_params + array('view'=>'draft')); ?>' <?php echo ( isset($_GET['view']) && $_GET['view'] == 'draft' ) ? 'class="current"':''; ?>><?php _e ( 'Draft', 'events-manager'); ?> <span class="count">(<?php echo $draft_count; ?>)</span></a> &nbsp;|&nbsp;
 
 
 
 
 
 
 
 
29
  <?php endif; ?>
30
- <a href='<?php echo em_add_get_params($_SERVER['REQUEST_URI'], $default_params + array('view'=>'past')); ?>' <?php echo ( isset($_GET['view']) && $_GET['view'] == 'past' ) ? 'class="current"':''; ?>><?php _e ( 'Past Events', 'events-manager'); ?> <span class="count">(<?php echo $past_count; ?>)</span></a>
31
  </div>
32
  <p class="search-box">
33
  <label class="screen-reader-text" for="post-search-input"><?php _e('Search Events','events-manager'); ?>:</label>
@@ -73,7 +82,7 @@
73
  <?php
74
  $rowno = 0;
75
  foreach ( $EM_Events as $EM_Event ) {
76
- /* @var $EM_Event EM_Event */
77
  $rowno++;
78
  $class = ($rowno % 2) ? 'alternate' : '';
79
 
1
  <?php
2
  //TODO Simplify panel for events, use form flags to detect certain actions (e.g. submitted, etc)
3
  global $wpdb, $bp, $EM_Notices;
4
+ /* @var array $args */
5
+ /* @var array $EM_Events */
6
+ /* @var int $events_count */
7
+ /* @var int $future_count */
8
+ /* @var int $past_count */
9
+ /* @var int $draft_count */
10
+ /* @var int $pending_count */
11
+ /* @var bool $show_add_new */
12
+ /* @var int $limit */
13
+ /* @var int $page */
14
+ $url = esc_url(add_query_arg(array('scope' => null, 'status' => null, 'em_search' => null, 'pno' => null, 'admin_mode' => null))); //template for cleaning the link for each view below
15
  ?>
16
  <div class="em-events-admin-list">
17
  <?php
18
  echo $EM_Notices;
19
+ //add new button will only appear if called from em_event_admin template tag, or if the $show_add_new var is set
20
  if(!empty($show_add_new) && current_user_can('edit_events')) echo '<a class="em-button button add-new-h2" href="'.em_add_get_params($_SERVER['REQUEST_URI'],array('action'=>'edit','scope'=>null,'status'=>null,'event_id'=>null, 'success'=>null)).'">'.__('Add New','events-manager').'</a>';
21
  ?>
22
  <form id="posts-filter" action="" method="get">
23
  <div class="subsubsub">
24
+ <?php $url = esc_url(add_query_arg(array('scope'=>null,'status'=>null,'em_search'=>null,'pno'=>null, 'admin_mode'=>null))); //template for cleaning the link for each view below ?>
25
+ <a href='<?php echo add_query_arg('view', 'future', $url); ?>' <?php echo ( !isset($_GET['view']) ) ? 'class="current"':''; ?>><?php _e ( 'Upcoming', 'events-manager'); ?> <span class="count">(<?php echo $future_count; ?>)</span></a> &nbsp;|&nbsp;
26
  <?php if( $pending_count > 0 ): ?>
27
+ <a href='<?php echo add_query_arg('view', 'pending', $url); ?>' <?php echo ( isset($_GET['view']) && $_GET['view'] == 'pending' ) ? 'class="current"':''; ?>><?php _e ( 'Pending', 'events-manager'); ?> <span class="count">(<?php echo $pending_count; ?>)</span></a> &nbsp;|&nbsp;
28
  <?php endif; ?>
29
  <?php if( $draft_count > 0 ): ?>
30
+ <a href='<?php echo add_query_arg('view', 'draft', $url); ?>' <?php echo ( isset($_GET['view']) && $_GET['view'] == 'draft' ) ? 'class="current"':''; ?>><?php _e ( 'Draft', 'events-manager'); ?> <span class="count">(<?php echo $draft_count; ?>)</span></a> &nbsp;|
31
+ <?php endif; ?>
32
+ <a href='<?php echo add_query_arg('view', 'past', $url); ?>' <?php echo ( isset($_GET['view']) && $_GET['view'] == 'past' ) ? 'class="current"':''; ?>><?php _e ( 'Past Events', 'events-manager'); ?> <span class="count">(<?php echo $past_count; ?>)</span></a>
33
+
34
+ <?php if( current_user_can('edit_others_events') ): ?>
35
+ <div class="admin-events-filter">
36
+ <a href='<?php echo add_query_arg('admin_mode', 1, $url); ?>' <?php echo ( !empty($_GET['admin_mode']) ) ? 'class="current"':''; ?>><?php esc_html_e ( 'All Events', 'events-manager'); ?></a> &nbsp;|&nbsp;
37
+ <a href='<?php echo add_query_arg('admin_mode', null, $url); ?>' <?php echo ( empty($_GET['admin_mode']) ) ? 'class="current"':''; ?>><?php esc_html_e ( 'My Events', 'events-manager'); ?></a>
38
+ </div>
39
  <?php endif; ?>
 
40
  </div>
41
  <p class="search-box">
42
  <label class="screen-reader-text" for="post-search-input"><?php _e('Search Events','events-manager'); ?>:</label>
82
  <?php
83
  $rowno = 0;
84
  foreach ( $EM_Events as $EM_Event ) {
85
+ /* @var EM_Event $EM_Event */
86
  $rowno++;
87
  $class = ($rowno % 2) ? 'alternate' : '';
88
 
templates/tables/locations.php CHANGED
@@ -1,19 +1,31 @@
1
  <?php
2
  global $wpdb, $EM_Notices;
3
- //add new button will only appear if called from em_location_admin template tag, or if the $show_add_new var is set
4
- if(!empty($show_add_new) && current_user_can('edit_locations')) echo '<a class="em-button button add-new-h2" href="'.em_add_get_params($_SERVER['REQUEST_URI'],array('action'=>'edit','scope'=>null,'status'=>null,'location_id'=>null)).'">'.__('Add New','events-manager').'</a>';
 
 
 
 
 
 
 
 
5
  ?>
6
  <div class="em-locations-admin-list">
7
  <?php if(!is_admin()) echo $EM_Notices; ?>
8
  <form id='locations-filter' method='post' action=''>
 
 
 
 
9
  <input type='hidden' name='pno' value='<?php echo esc_attr($page) ?>' />
10
  <div class="subsubsub">
11
- <a href='<?php echo em_add_get_params($_SERVER['REQUEST_URI'], array('view'=>null, 'pno'=>null)); ?>' <?php echo ( empty($_REQUEST['view']) ) ? 'class="current"':''; ?>><?php echo sprintf( __( 'My %s', 'events-manager'), __('Locations','events-manager')); ?> <span class="count">(<?php echo $locations_mine_count; ?>)</span></a>
12
  <?php if( current_user_can('read_others_locations') ): ?>
13
  &nbsp;|&nbsp;
14
- <a href='<?php echo em_add_get_params($_SERVER['REQUEST_URI'], array('view'=>'others', 'pno'=>null)); ?>' <?php echo ( !empty($_REQUEST['view']) && $_REQUEST['view'] == 'others' ) ? 'class="current"':''; ?>><?php echo sprintf( __( 'All %s', 'events-manager'), __('Locations','events-manager')); ?><span class="count">(<?php echo $locations_all_count; ?>)</span></a>
15
  <?php endif; ?>
16
- </div>
17
  <?php if ( $locations_count > 0 ) : ?>
18
  <div class='tablenav'>
19
  <?php if( (empty($_REQUEST['view']) && current_user_can('delete_events')) || (!empty($_REQUEST['view']) && $_REQUEST['view'] == 'others' && current_user_can('delete_others_events')) ): ?>
1
  <?php
2
  global $wpdb, $EM_Notices;
3
+ /* @var array $args */
4
+ /* @var array $locations */
5
+ /* @var int $locations_count */
6
+ /* @var int $locations_mine_count */
7
+ /* @var int $locations_all_count */
8
+ /* @var bool $show_add_new */
9
+ /* @var int $limit */
10
+ /* @var int $page */
11
+ /* @var int $offset */
12
+ $url = esc_url(add_query_arg(array('scope'=>null,'status'=>null,'location_id'=>null)));
13
  ?>
14
  <div class="em-locations-admin-list">
15
  <?php if(!is_admin()) echo $EM_Notices; ?>
16
  <form id='locations-filter' method='post' action=''>
17
+ <?php
18
+ //add new button will only appear if called from em_location_admin template tag, or if the $show_add_new var is set
19
+ if(!empty($show_add_new) && current_user_can('edit_locations')) echo '<a class="em-button button add-new-h2" href="'.add_query_arg('action', 'edit', $url).'">'.__('Add New','events-manager').'</a>';
20
+ ?>
21
  <input type='hidden' name='pno' value='<?php echo esc_attr($page) ?>' />
22
  <div class="subsubsub">
23
+ <a href='<?php echo add_query_arg(array('view'=>null, 'pno'=>null), $url); ?>' <?php echo ( empty($_REQUEST['view']) ) ? 'class="current"':''; ?>><?php echo sprintf( __( 'My %s', 'events-manager'), __('Locations','events-manager')); ?> <span class="count">(<?php echo $locations_mine_count; ?>)</span></a>
24
  <?php if( current_user_can('read_others_locations') ): ?>
25
  &nbsp;|&nbsp;
26
+ <a href='<?php echo add_query_arg(array('view'=>'others', 'pno'=>null), $url); ?>' <?php echo ( !empty($_REQUEST['view']) && $_REQUEST['view'] == 'others' ) ? 'class="current"':''; ?>><?php echo sprintf( __( 'All %s', 'events-manager'), __('Locations','events-manager')); ?><span class="count">(<?php echo $locations_all_count; ?>)</span></a>
27
  <?php endif; ?>
28
+ </div>
29
  <?php if ( $locations_count > 0 ) : ?>
30
  <div class='tablenav'>
31
  <?php if( (empty($_REQUEST['view']) && current_user_can('delete_events')) || (!empty($_REQUEST['view']) && $_REQUEST['view'] == 'others' && current_user_can('delete_others_events')) ): ?>
templates/templates/calendar-full.php CHANGED
@@ -1,23 +1,24 @@
1
  <?php
2
  /*
3
  * This file contains the HTML generated for full calendars. You can copy this file to yourthemefolder/plugins/events-manager/templates and modify it in an upgrade-safe manner.
4
- *
5
- * There are two variables made available to you:
6
- *
7
- * $calendar - contains an array of information regarding the calendar and is used to generate the content
8
- * $args - the arguments passed to EM_Calendar::output()
9
- *
10
  * Note that leaving the class names for the previous/next links will keep the AJAX navigation working.
 
 
11
  */
 
 
 
12
  $cal_count = count($calendar['cells']); //to prevent an extra tr
13
  $col_count = $tot_count = 1; //this counts collumns in the $calendar_array['cells'] array
14
  $col_max = count($calendar['row_headers']); //each time this collumn number is reached, we create a new collumn, the number of cells should divide evenly by the number of row_headers
 
15
  ?>
16
  <table class="em-calendar fullcalendar">
17
  <thead>
18
  <tr>
19
  <td><a class="em-calnav full-link em-calnav-prev" href="<?php echo esc_url($calendar['links']['previous_url']); ?>">&lt;&lt;</a></td>
20
- <td class="month_name" colspan="5"><?php echo esc_html(date_i18n(get_option('dbem_full_calendar_month_format'), $calendar['month_start'])); ?></td>
21
  <td><a class="em-calnav full-link em-calnav-next" href="<?php echo esc_url($calendar['links']['next_url']); ?>">&gt;&gt;</a></td>
22
  </tr>
23
  </thead>
1
  <?php
2
  /*
3
  * This file contains the HTML generated for full calendars. You can copy this file to yourthemefolder/plugins/events-manager/templates and modify it in an upgrade-safe manner.
4
+ *
 
 
 
 
 
5
  * Note that leaving the class names for the previous/next links will keep the AJAX navigation working.
6
+ *
7
+ * There are two variables made available to you:
8
  */
9
+ /* @var array $calendar - contains an array of information regarding the calendar and is used to generate the content */
10
+ /* @var array $args - the arguments passed to EM_Calendar::output() */
11
+
12
  $cal_count = count($calendar['cells']); //to prevent an extra tr
13
  $col_count = $tot_count = 1; //this counts collumns in the $calendar_array['cells'] array
14
  $col_max = count($calendar['row_headers']); //each time this collumn number is reached, we create a new collumn, the number of cells should divide evenly by the number of row_headers
15
+ $EM_DateTime = new EM_DateTime($calendar['month_start']);
16
  ?>
17
  <table class="em-calendar fullcalendar">
18
  <thead>
19
  <tr>
20
  <td><a class="em-calnav full-link em-calnav-prev" href="<?php echo esc_url($calendar['links']['previous_url']); ?>">&lt;&lt;</a></td>
21
+ <td class="month_name" colspan="5"><?php echo esc_html($EM_DateTime->format(get_option('dbem_full_calendar_month_format'))); ?></td>
22
  <td><a class="em-calnav full-link em-calnav-next" href="<?php echo esc_url($calendar['links']['next_url']); ?>">&gt;&gt;</a></td>
23
  </tr>
24
  </thead>
templates/templates/calendar-small.php CHANGED
@@ -1,20 +1,19 @@
1
  <?php
2
  /*
3
  * This file contains the HTML generated for small calendars. You can copy this file to yourthemefolder/plugins/events-manager/templates and modify it in an upgrade-safe manner.
4
- *
5
- * There are two variables made available to you:
6
- *
7
- * $calendar - contains an array of information regarding the calendar and is used to generate the content
8
- * $args - the arguments passed to EM_Calendar::output()
9
- *
10
  * Note that leaving the class names for the previous/next links will keep the AJAX navigation working.
 
11
  */
 
 
 
 
12
  ?>
13
  <table class="em-calendar">
14
  <thead>
15
  <tr>
16
  <td><a class="em-calnav em-calnav-prev" href="<?php echo esc_url($calendar['links']['previous_url']); ?>" rel="nofollow">&lt;&lt;</a></td>
17
- <td class="month_name" colspan="5"><?php echo esc_html(date_i18n(get_option('dbem_small_calendar_month_format'), $calendar['month_start'])); ?></td>
18
  <td><a class="em-calnav em-calnav-next" href="<?php echo esc_url($calendar['links']['next_url']); ?>" rel="nofollow">&gt;&gt;</a></td>
19
  </tr>
20
  </thead>
1
  <?php
2
  /*
3
  * This file contains the HTML generated for small calendars. You can copy this file to yourthemefolder/plugins/events-manager/templates and modify it in an upgrade-safe manner.
 
 
 
 
 
 
4
  * Note that leaving the class names for the previous/next links will keep the AJAX navigation working.
5
+ * There are two variables made available to you:
6
  */
7
+ /* @var array $calendar - contains an array of information regarding the calendar and is used to generate the content */
8
+ /* @var array $args - the arguments passed to EM_Calendar::output() */
9
+
10
+ $EM_DateTime = new EM_DateTime($calendar['month_start']);
11
  ?>
12
  <table class="em-calendar">
13
  <thead>
14
  <tr>
15
  <td><a class="em-calnav em-calnav-prev" href="<?php echo esc_url($calendar['links']['previous_url']); ?>" rel="nofollow">&lt;&lt;</a></td>
16
+ <td class="month_name" colspan="5"><?php echo esc_html($EM_DateTime->format(get_option('dbem_small_calendar_month_format'))); ?></td>
17
  <td><a class="em-calnav em-calnav-next" href="<?php echo esc_url($calendar['links']['next_url']); ?>" rel="nofollow">&gt;&gt;</a></td>
18
  </tr>
19
  </thead>
templates/templates/ical.php CHANGED
@@ -145,6 +145,15 @@ if( $location ){
145
  $output .= "\r\n" . $apple_structured_location;
146
  }
147
  }
 
 
 
 
 
 
 
 
 
148
  //end the event
149
  $output .= "
150
  END:VEVENT";
145
  $output .= "\r\n" . $apple_structured_location;
146
  }
147
  }
148
+ // add organizer if specifically requested via $args in locate_template
149
+ if( !empty($include_organizer) ){
150
+ /*
151
+ * Currently unused via settings, can be activated by adding this line of code somewhere e.g. your theme functions.php file
152
+ * add_filter('em_locate_template_args_templates/ical.php', function($args){ $args['include_organizer'] = true; return $args; });
153
+ */
154
+ $EM_Person = new EM_Person($EM_Event->get_owner());
155
+ $output .= "\r\n" . 'ORGANIZER;CN="'. $EM_Person->get_name() .'":MAILTO:'. $EM_Person->user_email;
156
+ }
157
  //end the event
158
  $output .= "
159
  END:VEVENT";