WordPress Online Booking and Scheduling Plugin – Bookly - Version 17.9

Version Description

Download this release

Release Info

Developer Ladela
Plugin Icon 128x128 WordPress Online Booking and Scheduling Plugin – Bookly
Version 17.9
Comparing to
See all releases

Code changes from version 17.8 to 17.9

Files changed (158) hide show
  1. backend/Backend.php +1 -1
  2. backend/components/appearance/Editable.php +12 -8
  3. backend/components/controls/Buttons.php +95 -84
  4. backend/components/controls/Container.php +1 -3
  5. backend/components/controls/Elements.php +22 -0
  6. backend/components/controls/Inputs.php +102 -0
  7. backend/components/controls/resources/js/buttons.js +0 -5
  8. backend/components/controls/templates/container.php +2 -2
  9. backend/components/dashboard/appointments/Widget.php +1 -4
  10. backend/components/dashboard/appointments/templates/block.php +31 -35
  11. backend/components/dialogs/appointment/customer_details/templates/customer_details.php +9 -9
  12. backend/components/dialogs/appointment/delete/templates/delete.php +12 -12
  13. backend/components/dialogs/appointment/edit/Ajax.php +3 -2
  14. backend/components/dialogs/appointment/edit/Dialog.php +10 -10
  15. backend/components/dialogs/appointment/edit/resources/js/ng-appointment.js +75 -73
  16. backend/components/dialogs/appointment/edit/templates/edit.php +105 -124
  17. backend/components/dialogs/common/templates/delete_cascade.php +7 -7
  18. backend/components/dialogs/common/templates/unsaved_changes.php +7 -7
  19. backend/components/dialogs/customer/delete/resources/js/delete-customers.js +7 -6
  20. backend/components/dialogs/customer/delete/templates/dialog.php +11 -23
  21. backend/components/dialogs/customer/edit/Dialog.php +9 -8
  22. backend/components/dialogs/customer/edit/resources/js/ng-customer.js +8 -18
  23. backend/components/dialogs/customer/edit/templates/edit.php +6 -6
  24. backend/components/dialogs/notifications/Dialog.php +2 -2
  25. backend/components/dialogs/notifications/templates/_attach.php +4 -6
  26. backend/components/dialogs/notifications/templates/_codes.php +1 -1
  27. backend/components/dialogs/notifications/templates/_editor.php +1 -0
  28. backend/components/dialogs/notifications/templates/_subject.php +2 -2
  29. backend/components/dialogs/notifications/templates/_types.php +3 -3
  30. backend/components/dialogs/payment/resources/js/ng-payment_details.js +2 -5
  31. backend/components/dialogs/payment/templates/details.php +6 -6
  32. backend/components/dialogs/payment/templates/dialog.php +5 -5
  33. backend/components/dialogs/queue/Dialog.php +1 -1
  34. backend/components/dialogs/queue/resources/js/queue-dialog.js +4 -6
  35. backend/components/dialogs/queue/templates/dialog.php +9 -9
  36. backend/components/dialogs/service/categories/Dialog.php +4 -3
  37. backend/components/dialogs/service/categories/resources/js/service-categories-dialog.js +2 -4
  38. backend/components/dialogs/service/categories/templates/dialog.php +12 -16
  39. backend/components/dialogs/service/create/Dialog.php +3 -3
  40. backend/components/dialogs/service/create/resources/js/service-create-dialog.js +9 -9
  41. backend/components/dialogs/service/create/templates/dialog.php +15 -19
  42. backend/components/dialogs/service/edit/Dialog.php +5 -3
  43. backend/components/dialogs/service/edit/resources/js/service-edit-dialog.js +47 -44
  44. backend/components/dialogs/service/edit/templates/dialog.php +20 -20
  45. backend/components/dialogs/service/order/resources/js/service-order-dialog.js +2 -4
  46. backend/components/dialogs/service/order/templates/dialog.php +11 -10
  47. backend/components/dialogs/sms/Dialog.php +9 -10
  48. backend/components/dialogs/sms/resources/js/notification-dialog.js +14 -16
  49. backend/components/dialogs/sms/templates/_codes.php +1 -1
  50. backend/components/dialogs/sms/templates/_editor.php +1 -1
  51. backend/components/dialogs/sms/templates/_modal_body.php +8 -11
  52. backend/components/dialogs/sms/templates/_settings.php +102 -79
  53. backend/components/dialogs/sms/templates/_types.php +3 -3
  54. backend/components/dialogs/sms/templates/dialog.php +5 -5
  55. backend/components/dialogs/staff/edit/Ajax.php +45 -40
  56. backend/components/dialogs/staff/edit/Dialog.php +11 -10
  57. backend/components/dialogs/staff/edit/resources/js/staff-days-off.js +2 -2
  58. backend/components/dialogs/staff/edit/resources/js/staff-details.js +6 -13
  59. backend/components/dialogs/staff/edit/resources/js/staff-edit-dialog.js +19 -12
  60. backend/components/dialogs/staff/edit/resources/js/staff-schedule.js +126 -217
  61. backend/components/dialogs/staff/edit/resources/js/staff-services.js +20 -20
  62. backend/components/dialogs/staff/edit/templates/_break.php +0 -37
  63. backend/components/dialogs/staff/edit/templates/_breaks.php +0 -41
  64. backend/components/dialogs/staff/edit/templates/details.php +47 -44
  65. backend/components/dialogs/staff/edit/templates/dialog.php +17 -11
  66. backend/components/dialogs/staff/edit/templates/dialog_body.php +21 -23
  67. backend/components/dialogs/staff/edit/templates/holidays.php +10 -15
  68. backend/components/dialogs/staff/edit/templates/schedule.php +9 -104
  69. backend/components/dialogs/staff/edit/templates/services.php +83 -97
  70. backend/components/dialogs/staff/order/Dialog.php +3 -2
  71. backend/components/dialogs/staff/order/resources/js/staff-order-dialog.js +8 -11
  72. backend/components/dialogs/staff/order/templates/dialog.php +10 -9
  73. backend/components/dialogs/table_settings/Dialog.php +9 -5
  74. backend/components/dialogs/table_settings/resources/js/table-settings-dialog.js +15 -10
  75. backend/components/dialogs/table_settings/templates/button.php +2 -2
  76. backend/components/dialogs/table_settings/templates/dialog.php +20 -23
  77. backend/components/notices/CollectStats.php +11 -1
  78. backend/components/notices/LiteRebranding.php +10 -1
  79. backend/components/notices/Nps.php +12 -5
  80. backend/components/notices/PoweredBy.php +6 -0
  81. backend/components/notices/Subscribe.php +12 -1
  82. backend/components/notices/resources/css/bootstrap-stars.css +0 -38
  83. backend/components/notices/resources/js/collect-stats.js +7 -3
  84. backend/components/notices/resources/js/jquery.barrating.min.js +0 -1
  85. backend/components/notices/resources/js/lite-rebranding.js +2 -2
  86. backend/components/notices/resources/js/nps.js +23 -18
  87. backend/components/notices/resources/js/powered-by.js +5 -5
  88. backend/components/notices/resources/js/subscribe.js +4 -4
  89. backend/components/notices/templates/collect_stats.php +13 -11
  90. backend/components/notices/templates/limitation.php +1 -1
  91. backend/components/notices/templates/lite_rebranding.php +5 -5
  92. backend/components/notices/templates/nps.php +15 -18
  93. backend/components/notices/templates/powered_by.php +11 -9
  94. backend/components/notices/templates/subscribe.php +18 -16
  95. backend/components/schedule/BreakItem.php +76 -0
  96. backend/components/schedule/Component.php +242 -0
  97. backend/components/schedule/Range.php +48 -0
  98. backend/components/schedule/Select.php +141 -0
  99. backend/components/schedule/templates/break.php +12 -0
  100. backend/components/schedule/templates/break_dialog.php +27 -0
  101. backend/components/schedule/templates/schedule.php +38 -0
  102. backend/components/settings/Inputs.php +3 -2
  103. backend/components/settings/Menu.php +2 -2
  104. backend/components/settings/Selects.php +24 -32
  105. backend/components/settings/templates/image.php +6 -10
  106. backend/components/settings/templates/price_correction.php +22 -16
  107. backend/components/support/resources/js/support.js +63 -61
  108. backend/components/support/templates/buttons.php +163 -134
  109. backend/components/tiny_mce/templates/bookly_form.php +3 -3
  110. backend/modules/appearance/Ajax.php +0 -4
  111. backend/modules/appearance/Page.php +5 -5
  112. backend/modules/appearance/proxy/Pro.php +1 -0
  113. backend/modules/appearance/proxy/Shared.php +0 -1
  114. backend/modules/appearance/resources/css/appearance.css +66 -0
  115. backend/modules/appearance/resources/css/bootstrap-editable.css +0 -663
  116. backend/modules/appearance/resources/js/appearance.js +31 -27
  117. backend/modules/appearance/resources/js/bootstrap-editable.bookly.js +0 -125
  118. backend/modules/appearance/resources/js/bootstrap-editable.min.js +0 -7
  119. backend/modules/appearance/resources/js/editable.js +172 -0
  120. backend/modules/appearance/templates/_1_service.php +5 -0
  121. backend/modules/appearance/templates/_7_payment.php +2 -14
  122. backend/modules/appearance/templates/_card_payment.php +0 -40
  123. backend/modules/appearance/templates/_custom_css.php +8 -7
  124. backend/modules/appearance/templates/index.php +136 -205
  125. backend/modules/appointments/Ajax.php +2 -7
  126. backend/modules/appointments/Page.php +2 -6
  127. backend/modules/appointments/resources/js/appointments.js +50 -61
  128. backend/modules/appointments/templates/index.php +92 -104
  129. backend/modules/calendar/Page.php +1 -1
  130. backend/modules/calendar/resources/js/calendar-common.js +54 -72
  131. backend/modules/calendar/resources/js/calendar.js +12 -12
  132. backend/modules/calendar/resources/js/fullcalendar.min.js +3 -3
  133. backend/modules/calendar/templates/calendar.php +86 -84
  134. backend/modules/customers/Page.php +1 -1
  135. backend/modules/customers/proxy/CustomerGroups.php +0 -1
  136. backend/modules/customers/resources/js/customers.js +30 -22
  137. backend/modules/customers/templates/index.php +60 -61
  138. backend/modules/dashboard/Page.php +6 -8
  139. backend/modules/dashboard/resources/js/dashboard.js +4 -19
  140. backend/modules/dashboard/templates/index.php +24 -30
  141. backend/modules/debug/Ajax.php +249 -249
  142. backend/modules/debug/Page.php +7 -2
  143. backend/modules/debug/lib/QueryBuilder.php +179 -179
  144. backend/modules/debug/lib/Schema.php +13 -7
  145. backend/modules/debug/lib/tools/Plugins.php +1 -1
  146. backend/modules/debug/resources/css/style.css +0 -19
  147. backend/modules/debug/resources/js/debug.js +14 -13
  148. backend/modules/debug/templates/index.php +162 -170
  149. backend/modules/messages/Page.php +1 -1
  150. backend/modules/messages/resources/js/message.js +4 -8
  151. backend/modules/messages/templates/index.php +16 -20
  152. backend/modules/notifications/Page.php +1 -1
  153. backend/modules/notifications/lib/Codes.php +4 -4
  154. backend/modules/notifications/templates/_common_settings.php +1 -1
  155. backend/modules/notifications/templates/_general_settings_modal.php +5 -5
  156. backend/modules/notifications/templates/_test_email_modal.php +20 -26
  157. backend/modules/notifications/templates/index.php +53 -57
  158. backend/modules/payments/Page.php +0 -0
backend/Backend.php CHANGED
@@ -133,7 +133,7 @@ abstract class Backend
133
  Modules\Debug\Page::pageSlug(), function () { Modules\Debug\Page::render(); } );
134
  }
135
  if ( ! Lib\Config::proActive() ) {
136
- $submenu['bookly-menu'][] = array( esc_attr__( 'Get Bookly Pro', 'bookly' ) . ' <i class="fas fa-certificate" style="color: #f4662f"></i>', 'read', Lib\Utils\Common::prepareUrlReferrers( 'https://codecanyon.net/item/bookly/7226091?ref=ladela', 'admin_menu' ), );
137
  }
138
  }
139
 
133
  Modules\Debug\Page::pageSlug(), function () { Modules\Debug\Page::render(); } );
134
  }
135
  if ( ! Lib\Config::proActive() ) {
136
+ $submenu['bookly-menu'][] = array( esc_attr__( 'Get Bookly Pro', 'bookly' ) . ' <i class="fas fa-fw fa-certificate" style="color: #f4662f"></i>', 'read', Lib\Utils\Common::prepareUrlReferrers( 'https://codecanyon.net/item/bookly/7226091?ref=ladela', 'admin_menu' ), );
137
  }
138
  }
139
 
backend/components/appearance/Editable.php CHANGED
@@ -14,9 +14,9 @@ class Editable
14
  * @param bool $echo
15
  * @return string
16
  */
17
- public static function renderString( array $options, $echo = true )
18
  {
19
- return self::_renderEditable( $options, 'span', $echo );
20
  }
21
 
22
  /**
@@ -26,9 +26,9 @@ class Editable
26
  * @param bool $echo
27
  * @return string
28
  */
29
- public static function renderLabel( array $options, $echo = true )
30
  {
31
- return self::_renderEditable( $options, 'label', $echo );
32
  }
33
 
34
  /**
@@ -43,7 +43,7 @@ class Editable
43
  {
44
  $option_value = get_option( $option_name );
45
 
46
- printf( '<span class="bookly-js-editable bookly-js-option %s editable-pre-wrapped" data-type="bookly" data-fieldType="textarea" data-values="%s" data-codes="%s" data-title="%s" data-placement="%s" data-option="%s">%s</span>',
47
  $option_name,
48
  esc_attr( json_encode( array( $option_name => $option_value ) ) ),
49
  esc_attr( $codes ),
@@ -65,7 +65,7 @@ class Editable
65
  {
66
  $option_value = get_option( $option_name );
67
 
68
- printf( '<span class="bookly-js-editable bookly-js-option %s editable-pre-wrapped" data-type="bookly" data-fieldType="number" data-values="%s" data-min="%s" data-step="%s" data-option="%s">%s</span>',
69
  $option_name,
70
  esc_attr( json_encode( array( $option_name => $option_value ) ) ),
71
  esc_attr( $min ),
@@ -83,7 +83,7 @@ class Editable
83
  * @param bool $echo
84
  * @return string|void
85
  */
86
- private static function _renderEditable( array $options, $tag, $echo = true )
87
  {
88
  $data = array();
89
  foreach ( $options as $option_name ) {
@@ -94,13 +94,17 @@ class Editable
94
  $class = implode( ' ', $options );
95
  $data_values = esc_attr( json_encode( $data ) );
96
  $content = esc_html( $data[ $options[0] ] );
 
 
 
97
 
98
- $template = '<{tag} class="bookly-js-editable bookly-js-option {class}" data-type="bookly" data-values="{data-values}" data-option="{data-option}">{content}</{tag}>';
99
  $html = strtr( $template, array(
100
  '{tag}' => $tag,
101
  '{class}' => $class,
102
  '{data-values}' => $data_values,
103
  '{data-option}' => $main_option,
 
104
  '{content}' => $content,
105
  ) );
106
 
14
  * @param bool $echo
15
  * @return string
16
  */
17
+ public static function renderString( array $options, $title = '', $echo = true )
18
  {
19
+ return self::_renderEditable( $options, 'span', $title, $echo );
20
  }
21
 
22
  /**
26
  * @param bool $echo
27
  * @return string
28
  */
29
+ public static function renderLabel( array $options, $title = '', $echo = true )
30
  {
31
+ return self::_renderEditable( $options, 'label', $title, $echo );
32
  }
33
 
34
  /**
43
  {
44
  $option_value = get_option( $option_name );
45
 
46
+ printf( '<span class="bookly-editable bookly-js-editable bookly-js-option %s text-pre-wrap" data-type="bookly" data-fieldType="textarea" data-values="%s" data-codes="%s" data-title="%s" data-placement="%s" data-option="%s">%s</span>',
47
  $option_name,
48
  esc_attr( json_encode( array( $option_name => $option_value ) ) ),
49
  esc_attr( $codes ),
65
  {
66
  $option_value = get_option( $option_name );
67
 
68
+ printf( '<span class="bookly-editable bookly-js-editable bookly-js-option %s text-pre-wrap" data-type="bookly" data-fieldType="number" data-values="%s" data-min="%s" data-step="%s" data-option="%s">%s</span>',
69
  $option_name,
70
  esc_attr( json_encode( array( $option_name => $option_value ) ) ),
71
  esc_attr( $min ),
83
  * @param bool $echo
84
  * @return string|void
85
  */
86
+ private static function _renderEditable( array $options, $tag, $title = '', $echo = true )
87
  {
88
  $data = array();
89
  foreach ( $options as $option_name ) {
94
  $class = implode( ' ', $options );
95
  $data_values = esc_attr( json_encode( $data ) );
96
  $content = esc_html( $data[ $options[0] ] );
97
+ $data_title = $title
98
+ ? ' data-title="' .esc_attr__( $title ) . '"'
99
+ : '';
100
 
101
+ $template = '<{tag} class="bookly-editable bookly-js-editable bookly-js-option {class}" data-type="bookly" data-values="{data-values}" data-option="{data-option}"{data-title}>{content}</{tag}>';
102
  $html = strtr( $template, array(
103
  '{tag}' => $tag,
104
  '{class}' => $class,
105
  '{data-values}' => $data_values,
106
  '{data-option}' => $main_option,
107
+ '{data-title}' => $data_title,
108
  '{content}' => $content,
109
  ) );
110
 
backend/components/controls/Buttons.php CHANGED
@@ -10,46 +10,38 @@ use Bookly\Lib\Plugin;
10
  class Buttons
11
  {
12
  /**
13
- * Render custom button.
14
  *
15
  * @param string $id
16
  * @param string $class
17
  * @param string $caption
18
- * @param array $attributes
19
  * @param string $caption_template
20
  */
21
- public static function renderCustom( $id = null, $class = 'btn-success', $caption = null, array $attributes = array(), $caption_template = '{caption}' )
22
  {
23
- if ( $caption === null ) {
24
- $caption = __( 'Save', 'bookly' );
25
- }
26
-
27
- $caption = strtr( $caption_template, array( '{caption}' => esc_html( $caption ) ) );
28
-
29
- echo self::_createButton( 'button', $id, $class, null, $caption, $attributes );
30
  }
31
 
32
  /**
33
- * Render delete button.
34
  *
35
  * @param string $id
36
  * @param string $extra_class
37
  * @param string $caption
38
- * @param array $attributes
 
39
  */
40
- public static function renderDelete( $id = 'bookly-delete', $extra_class = null, $caption = null, array $attributes = array() )
41
  {
42
- if ( $caption === null ) {
43
- $caption = __( 'Delete', 'bookly' ) . '...';
44
- }
45
-
46
  echo self::_createButton(
47
  'button',
48
  $id,
49
- 'btn-danger',
50
  $extra_class,
51
- '<i class="fa fa-fw fa-trash"></i> ' . esc_html( $caption ),
52
- $attributes
 
53
  );
54
  }
55
 
@@ -59,85 +51,106 @@ class Buttons
59
  * @param string $id
60
  * @param string $extra_class
61
  * @param string $caption
62
- * @param array $attributes
 
63
  */
64
- public static function renderAdd( $id = 'bookly-add', $extra_class = null, $caption = null, array $attributes = array() )
65
  {
66
- if ( $caption === null ) {
67
- $caption = __( 'Add...', 'bookly' );
68
- }
69
-
70
  echo self::_createButton(
71
  'button',
72
  $id,
73
  'btn-success',
74
  $extra_class,
75
- '<i class="fa fa-fw fa-plus"></i> ' . esc_html( $caption ),
76
- $attributes
 
77
  );
78
  }
79
 
80
  /**
81
- * Render reset button.
82
  *
83
  * @param string $id
84
  * @param string $extra_class
85
  * @param string $caption
86
- * @param array $attributes
 
87
  */
88
- public static function renderReset( $id = null, $extra_class = null, $caption = null, array $attributes = array() )
89
  {
90
- if ( $caption === null ) {
91
- $caption = __( 'Reset', 'bookly' );
92
- }
93
-
94
- echo self::_createButton( 'reset', $id, 'btn-lg btn-default', $extra_class, esc_html( $caption ), $attributes );
 
 
 
 
95
  }
96
 
97
  /**
98
- * Render submit button.
99
  *
100
  * @param string $id
101
  * @param string $extra_class
102
  * @param string $caption
103
- * @param array $attributes
 
104
  */
105
- public static function renderSubmit( $id = 'bookly-save', $extra_class = null, $caption = null, array $attributes = array() )
106
  {
107
- if ( $caption === null ) {
108
- $caption = __( 'Save', 'bookly' );
109
- }
110
-
111
- echo self::_createButton( 'submit', $id, 'btn-lg btn-success', $extra_class, esc_html( $caption ), $attributes );
 
 
 
 
112
  }
113
 
114
  /**
115
- * Render button for open modal window.
116
  *
117
- * @param string $modal_id
118
- * @param string $class
119
- * @param string $caption
120
- * @param array $attributes
121
- * @param string $caption_template
122
- * @param string $ellipsis
123
  */
124
- public static function renderModalActivator( $modal_id = null, $class = null, $caption = null, array $attributes = array(), $caption_template = '{caption}', $ellipsis = '...' )
125
  {
126
- $attributes += array(
127
- 'for-modal' => $modal_id,
 
 
 
 
 
 
 
128
  );
129
- if ( ! $class ) {
130
- $class = 'btn-default';
131
- }
132
 
133
- wp_enqueue_script(
134
- 'bookly-buttons',
135
- plugins_url( '/backend/components/controls/resources/js/buttons.js', Plugin::getBasename() ),
136
- array( 'jquery' ),
137
- Plugin::getVersion()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  );
139
-
140
- self::renderCustom( $modal_id . '-activator', $class, $caption . $ellipsis, $attributes, $caption_template );
141
  }
142
 
143
  /**
@@ -147,35 +160,33 @@ class Buttons
147
  * @param string $id
148
  * @param string $class
149
  * @param string $extra_class
150
- * @param string $caption_html
151
- * @param array $attributes
 
152
  * @return string
153
  */
154
- private static function _createButton( $type, $id, $class, $extra_class, $caption_html, array $attributes )
155
  {
156
- $classes = array( 'btn ladda-button' );
157
- if ( $class != '' ) {
158
- $classes[] = $class;
159
- }
160
- if ( $extra_class != '' ) {
161
- $classes[] = $extra_class;
 
 
 
 
162
  }
163
 
164
- if ( $id !== null ) {
165
- $attributes['id'] = $id;
166
- }
167
- $attributes_str = '';
168
- foreach ( $attributes as $attr => $value ) {
169
- $attributes_str .= sprintf( ' %s="%s"', $attr, esc_attr( $value ) );
170
- }
171
 
172
  return strtr(
173
- '<button type="{type}" class="{class}" data-spinner-size="40" data-style="zoom-in"{attributes}><span class="ladda-label">{caption}</span></button>',
174
  array(
175
  '{type}' => $type,
176
- '{class}' => implode( ' ', $classes ),
177
- '{attributes}' => $attributes_str,
178
- '{caption}' => $caption_html,
179
  )
180
  );
181
  }
10
  class Buttons
11
  {
12
  /**
13
+ * Render button.
14
  *
15
  * @param string $id
16
  * @param string $class
17
  * @param string $caption
18
+ * @param array $attrs
19
  * @param string $caption_template
20
  */
21
+ public static function render( $id = null, $class = null, $caption = null, array $attrs = array(), $caption_template = '{caption}' )
22
  {
23
+ echo self::_createButton( 'button', $id, $class, null, $attrs, $caption, $caption_template );
 
 
 
 
 
 
24
  }
25
 
26
  /**
27
+ * Render default.
28
  *
29
  * @param string $id
30
  * @param string $extra_class
31
  * @param string $caption
32
+ * @param array $attrs
33
+ * @param bool $ellipsis
34
  */
35
+ public static function renderDefault( $id = null, $extra_class = null, $caption = null, array $attrs = array(), $ellipsis = false )
36
  {
 
 
 
 
37
  echo self::_createButton(
38
  'button',
39
  $id,
40
+ 'btn-default',
41
  $extra_class,
42
+ $attrs,
43
+ $caption,
44
+ '{caption}' . ( $ellipsis ? '…' : '' )
45
  );
46
  }
47
 
51
  * @param string $id
52
  * @param string $extra_class
53
  * @param string $caption
54
+ * @param array $attrs
55
+ * @param bool $ellipsis
56
  */
57
+ public static function renderAdd( $id = 'bookly-add', $extra_class = null, $caption = null, array $attrs = array(), $ellipsis = true )
58
  {
 
 
 
 
59
  echo self::_createButton(
60
  'button',
61
  $id,
62
  'btn-success',
63
  $extra_class,
64
+ $attrs,
65
+ $caption !== null ? $caption : __( 'Add', 'bookly' ),
66
+ '<i class="fas fa-fw fa-plus mr-1"></i>{caption}' . ( $ellipsis ? '…' : '' )
67
  );
68
  }
69
 
70
  /**
71
+ * Render delete button.
72
  *
73
  * @param string $id
74
  * @param string $extra_class
75
  * @param string $caption
76
+ * @param array $attrs
77
+ * @param bool $ellipsis
78
  */
79
+ public static function renderDelete( $id = 'bookly-delete', $extra_class = null, $caption = null, array $attrs = array(), $ellipsis = true )
80
  {
81
+ echo self::_createButton(
82
+ 'button',
83
+ $id,
84
+ 'btn-danger',
85
+ $extra_class,
86
+ $attrs,
87
+ $caption !== null ? $caption : __( 'Delete', 'bookly' ),
88
+ '<i class="far fa-fw fa-trash-alt mr-1"></i>{caption}' . ( $ellipsis ? '…' : '' )
89
+ );
90
  }
91
 
92
  /**
93
+ * Render reset button.
94
  *
95
  * @param string $id
96
  * @param string $extra_class
97
  * @param string $caption
98
+ * @param array $attrs
99
+ * @param bool $ellipsis
100
  */
101
+ public static function renderReset( $id = null, $extra_class = null, $caption = null, array $attrs = array(), $ellipsis = false )
102
  {
103
+ echo self::_createButton(
104
+ 'reset',
105
+ $id,
106
+ 'btn-default',
107
+ $extra_class,
108
+ $attrs,
109
+ $caption !== null ? $caption : __( 'Reset', 'bookly' ),
110
+ '{caption}' . ( $ellipsis ? '…' : '' )
111
+ );
112
  }
113
 
114
  /**
115
+ * Render cancel button.
116
  *
117
+ * @param array $attrs
118
+ * @param bool $ellipsis
 
 
 
 
119
  */
120
+ public static function renderCancel( $caption = null, array $attrs = array(), $ellipsis = false )
121
  {
122
+ $attrs += array( 'data-dismiss' => 'bookly-modal' );
123
+ echo self::_createButton(
124
+ 'button',
125
+ null,
126
+ 'btn-default',
127
+ '',
128
+ $attrs,
129
+ $caption ?: __( 'Cancel' ),
130
+ '{caption}' . ( $ellipsis ? '…' : '' )
131
  );
132
+ }
 
 
133
 
134
+ /**
135
+ * Render submit button.
136
+ *
137
+ * @param string $id
138
+ * @param string $extra_class
139
+ * @param string $caption
140
+ * @param array $attrs
141
+ * @param bool $ellipsis
142
+ */
143
+ public static function renderSubmit( $id = 'bookly-save', $extra_class = null, $caption = null, array $attrs = array(), $ellipsis = false )
144
+ {
145
+ echo self::_createButton(
146
+ 'submit',
147
+ $id,
148
+ 'btn-success',
149
+ $extra_class,
150
+ $attrs,
151
+ $caption !== null ? $caption : __( 'Save', 'bookly' ),
152
+ '{caption}' . ( $ellipsis ? '…' : '' )
153
  );
 
 
154
  }
155
 
156
  /**
160
  * @param string $id
161
  * @param string $class
162
  * @param string $extra_class
163
+ * @param array $attrs
164
+ * @param string $caption
165
+ * @param string $caption_template
166
  * @return string
167
  */
168
+ private static function _createButton( $type, $id, $class, $extra_class, array $attrs, $caption, $caption_template )
169
  {
170
+ $attrs['id'] = $id;
171
+ $attrs['class'] = implode( ' ', array_filter( array( 'btn ladda-button', $class, $extra_class ) ) );
172
+ $attrs['data-spinner-size'] = '40';
173
+ $attrs['data-style'] = 'zoom-in';
174
+
175
+ $attrs_str = '';
176
+ foreach ( $attrs as $attr => $value ) {
177
+ if ( $value !== null ) {
178
+ $attrs_str .= sprintf( ' %s="%s"', $attr, esc_attr( $value ) );
179
+ }
180
  }
181
 
182
+ $caption = strtr( $caption_template, array( '{caption}' => esc_html( $caption ) ) );
 
 
 
 
 
 
183
 
184
  return strtr(
185
+ '<button type="{type}"{attributes}><span class="ladda-label">{caption}</span></button>',
186
  array(
187
  '{type}' => $type,
188
+ '{attributes}' => $attrs_str,
189
+ '{caption}' => $caption,
 
190
  )
191
  );
192
  }
backend/components/controls/Container.php CHANGED
@@ -1,12 +1,10 @@
1
  <?php
2
-
3
  namespace Bookly\Backend\Components\Controls;
4
 
5
  use Bookly\Lib as BooklyLib;
6
 
7
  /**
8
  * Class Container
9
- *
10
  * @package Bookly\Backend\Components\Controls
11
  */
12
  class Container extends BooklyLib\Base\Component
@@ -23,7 +21,7 @@ class Container extends BooklyLib\Base\Component
23
  if ( empty( $id ) ) {
24
  $id = 'container_' . mt_rand( 10000, 99999 );
25
  }
26
-
27
  self::renderTemplate( 'container', compact( 'title', 'id', 'opened' ) );
28
  }
29
 
1
  <?php
 
2
  namespace Bookly\Backend\Components\Controls;
3
 
4
  use Bookly\Lib as BooklyLib;
5
 
6
  /**
7
  * Class Container
 
8
  * @package Bookly\Backend\Components\Controls
9
  */
10
  class Container extends BooklyLib\Base\Component
21
  if ( empty( $id ) ) {
22
  $id = 'container_' . mt_rand( 10000, 99999 );
23
  }
24
+ $opened = (boolean) $opened;
25
  self::renderTemplate( 'container', compact( 'title', 'id', 'opened' ) );
26
  }
27
 
backend/components/controls/Elements.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Bookly\Backend\Components\Controls;
3
+
4
+ /**
5
+ * Class Elements
6
+ * @package Bookly\Backend\Components\Controls
7
+ */
8
+ class Elements
9
+ {
10
+ /**
11
+ * Render reorder.
12
+ * @param string $class
13
+ */
14
+ public static function renderReorder( $class = '' )
15
+ {
16
+ printf(
17
+ '<i class="fas fa-fw fa-bars text-muted bookly-cursor-move bookly-js-draghandle %s" title="%s"></i>',
18
+ $class,
19
+ esc_attr__( 'Reorder', 'bookly' )
20
+ );
21
+ }
22
+ }
backend/components/controls/Inputs.php CHANGED
@@ -19,4 +19,106 @@ class Inputs
19
  esc_attr( Common::getCsrfToken() )
20
  );
21
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  }
19
  esc_attr( Common::getCsrfToken() )
20
  );
21
  }
22
+
23
+ /**
24
+ * Render custom checkbox
25
+ *
26
+ * @param string $label
27
+ * @param string $value
28
+ * @param bool $checked
29
+ * @param array $attrs
30
+ */
31
+ public static function renderCheckBox( $label, $value = null, $checked = null, $attrs = array() )
32
+ {
33
+ $attributes = array_merge( array(
34
+ 'id' => array_key_exists( 'id', $attrs ) ? $attrs['id'] : 'bookly-ch-' . mt_rand( 0, PHP_INT_MAX ),
35
+ 'checked' => $checked ? 'checked' : null,
36
+ 'value' => $value,
37
+ ), $attrs );
38
+
39
+ self::renderCustom( 'checkbox', $label, $attributes );
40
+ }
41
+
42
+ /**
43
+ * Render radio group
44
+ *
45
+ * @param string $label
46
+ * @param string $help
47
+ * @param array $radios
48
+ * @param string $value
49
+ * @param array $attrs
50
+ */
51
+ public static function renderRadioGroup( $label = null, $help = null, array $radios, $value, $attrs = array() )
52
+ {
53
+ if ( empty( $radios ) ) {
54
+ $radios = array(
55
+ //value => data
56
+ 0 => array( 'title' => __( 'Disabled', 'bookly' ) ),
57
+ 1 => array( 'title' => __( 'Enabled', 'bookly' ) ),
58
+ );
59
+ }
60
+
61
+ echo '<div class="form-group">';
62
+ if ( $label ) {
63
+ printf( '<label>%s</label>', esc_html( $label ) );
64
+ }
65
+ foreach ( $radios as $r_value => $r_data ) {
66
+ $attributes = array_merge( array(
67
+ 'id' => array_key_exists( 'id', $attrs ) ? $attrs['id'] : 'bookly-ra-' . mt_rand( 0, PHP_INT_MAX ),
68
+ 'checked' => $r_value == $value ? 'checked' : null,
69
+ 'value' => $r_value,
70
+ ), $attrs );
71
+
72
+ self::renderCustom( 'radio', $r_data['title'], $attributes );
73
+ }
74
+ if ( $help ) {
75
+ printf( '<small class="text-muted form-text">%s</small>', esc_html( $help ) );
76
+ }
77
+ echo '</div>';
78
+ }
79
+
80
+ /**
81
+ * Render radio
82
+ *
83
+ * @param string $label
84
+ * @param null $value
85
+ * @param null $checked
86
+ * @param array $attrs
87
+ */
88
+ public static function renderRadio( $label, $value = null, $checked = null, $attrs = array() )
89
+ {
90
+ $attributes = array_merge( array(
91
+ 'id' => array_key_exists( 'id', $attrs ) ? $attrs['id'] : 'bookly-ra-' . mt_rand( 0, PHP_INT_MAX ),
92
+ 'checked' => $checked ? 'checked' : null,
93
+ 'value' => $value,
94
+ ), $attrs );
95
+
96
+ self::renderCustom( 'radio', $label, $attributes );
97
+ }
98
+
99
+ /**
100
+ * Render custom input
101
+ *
102
+ * @param string $type
103
+ * @param string $label
104
+ * @param array $attributes
105
+ */
106
+ private static function renderCustom( $type, $label, $attributes = array() )
107
+ {
108
+ $attrs_str = '';
109
+ if ( array_key_exists( 'class', $attributes ) ) {
110
+ $attributes['class'] = 'custom-control-input ' . $attributes['class'];
111
+ } else {
112
+ $attributes['class'] = 'custom-control-input';
113
+ }
114
+ foreach ( $attributes as $n => $v ) {
115
+ if( $v !== null ) {
116
+ $attrs_str .= sprintf( ' %s="%s"', $n, esc_attr( $v ) );
117
+ }
118
+ }
119
+
120
+ printf( '<div class="custom-control custom-%1$s"><input type="%1$s"%2$s><label class="custom-control-label" for="%3$s">%4$s</label></div>',
121
+ $type, $attrs_str, $attributes['id'], esc_html( $label )
122
+ );
123
+ }
124
  }
backend/components/controls/resources/js/buttons.js DELETED
@@ -1,5 +0,0 @@
1
- jQuery(function($) {
2
- $('[for-modal]').on('click', function () {
3
- $('#' + $(this).attr('for-modal')).modal('show');
4
- });
5
- });
 
 
 
 
 
backend/components/controls/templates/container.php CHANGED
@@ -1,4 +1,4 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
  <div class="bookly-collapse">
3
- <a class="h4" href="#<?php echo $id ?>" data-toggle="collapse" role="button" aria-expanded="true"><?php echo esc_html( $title ) ?></a>
4
- <div id="<?php echo $id ?>" class="bookly-margin-top-lg collapse in" aria-expanded="true">
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
  <div class="bookly-collapse">
3
+ <a class="h5" href="#<?php echo $id ?>" data-toggle="collapse" role="button" aria-expanded="<?php echo (string) $opened ?>"><?php echo esc_html( $title ) ?></a>
4
+ <div id="<?php echo $id ?>" class="collapse<?php if ( $opened ) : ?> show<?php endif ?>">
backend/components/dashboard/appointments/Widget.php CHANGED
@@ -53,11 +53,8 @@ class Widget extends Lib\Base\Component
53
  'module' => array(
54
  'js/Chart.min.js',
55
  'js/Chart.bundle.min.js' => array( 'bookly-Chart.min.js' ),
56
- 'js/appointments-dashboard.js' => array( 'bookly-Chart.bundle.min.js', 'bookly-help.js' ),
57
  ),
58
- 'backend' => array(
59
- 'js/help.js' => array( 'jquery' ),
60
- )
61
  ) );
62
 
63
  $currencies = Lib\Utils\Price::getCurrencies();
53
  'module' => array(
54
  'js/Chart.min.js',
55
  'js/Chart.bundle.min.js' => array( 'bookly-Chart.min.js' ),
56
+ 'js/appointments-dashboard.js' => array( 'bookly-Chart.bundle.min.js' ),
57
  ),
 
 
 
58
  ) );
59
 
60
  $currencies = Lib\Utils\Price::getCurrencies();
backend/components/dashboard/appointments/templates/block.php CHANGED
@@ -1,56 +1,52 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
  <div class="bookly-js-dashboard-appointments">
3
- <div class="row bookly-padding-bottom-lg">
4
- <div class="col-sm-6 col-md-3">
5
- <div class="row">
6
- <div class="col-xs-4 text-right">
7
- <i class="far fa-calendar-check fa-w-14 fa-5x text-muted"></i>
8
  </div>
9
- <div class="col-xs-8">
10
- <div style="font-size: 40px" class="bookly-js-approved">&nbsp;</div>
11
- <span style="font-size: 20px"><a href="#" class="bookly-js-href-approved"><?php esc_html_e( 'Approved appointments', 'bookly' ) ?></a></span>
12
  </div>
13
  </div>
14
  </div>
15
- <div class="col-sm-6 col-md-3">
16
- <div class="row">
17
- <div class="col-xs-4 text-right">
18
- <i class="fas fa-hourglass-half fa-w-14 fa-5x text-muted"></i>
19
  </div>
20
- <div class="col-xs-8">
21
- <div style="font-size: 40px" class="bookly-js-pending">&nbsp;</div>
22
- <span style="font-size: 20px"><a href="#" class="bookly-js-href-pending"><?php esc_html_e( 'Pending appointments', 'bookly' ) ?></a></span>
23
  </div>
24
  </div>
25
  </div>
26
- <div class="col-sm-6 col-md-3">
27
- <div class="row">
28
- <div class="col-xs-4 text-right">
29
- <i class="far fa-calendar fa-w-14 fa-5x text-muted"></i>
30
  </div>
31
- <div class="col-xs-8">
32
- <div style="font-size: 40px" class="bookly-js-total">&nbsp;</div>
33
- <span style="font-size: 20px"><a href="#" class="bookly-js-href-total"><?php esc_html_e( 'Total appointments', 'bookly' ) ?></a></span>
34
  </div>
35
  </div>
36
  </div>
37
- <div class="col-sm-6 col-md-3">
38
- <div class="row">
39
- <div class="col-xs-4 text-right">
40
- <i class="far fa-money-bill-alt fa-w-14 fa-5x text-muted"></i>
41
  </div>
42
- <div class="col-xs-8">
43
- <div style="font-size: 40px" class="bookly-js-revenue">&nbsp;</div>
44
- <span style="font-size: 20px"><a href="#" class="bookly-js-href-revenue"><?php esc_html_e( 'Revenue', 'bookly' ) ?></a></span>
45
  </div>
46
  </div>
47
  </div>
48
  </div>
49
- <div class="panel panel-default bookly-margin-top-md">
50
- <div class="panel-body">
51
- <div>
52
- <canvas id="canvas" style="width:100%;height: 500px"></canvas>
53
- </div>
54
- </div>
55
  </div>
56
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
  <div class="bookly-js-dashboard-appointments">
3
+ <div class="row pb-3">
4
+ <div class="col-md-6 col-lg-3">
5
+ <div class="form-row">
6
+ <div class="col-4 text-right d-none d-md-block">
7
+ <i class="far fa-calendar-check fa-4x fa-fw text-muted"></i>
8
  </div>
9
+ <div class="col-md-6 col-lg-8">
10
+ <span style="font-size: 30px" class="bookly-js-approved d-md-block">&nbsp;</span>
11
+ <span style="font-size: 20px"><a href="#" class="bookly-js-href-approved text-wrap"><?php esc_html_e( 'Approved appointments', 'bookly' ) ?></a></span>
12
  </div>
13
  </div>
14
  </div>
15
+ <div class="col-md-6 col-lg-3">
16
+ <div class="form-row">
17
+ <div class="col-4 text-right d-none d-md-block">
18
+ <i class="far fa-hourglass fa-4x fa-fw text-muted"></i>
19
  </div>
20
+ <div class="col-md-6 col-lg-8">
21
+ <span style="font-size: 30px" class="bookly-js-pending d-md-block">&nbsp;</span>
22
+ <span style="font-size: 20px"><a href="#" class="bookly-js-href-pending text-wrap"><?php esc_html_e( 'Pending appointments', 'bookly' ) ?></a></span>
23
  </div>
24
  </div>
25
  </div>
26
+ <div class="col-md-6 col-lg-3">
27
+ <div class="form-row">
28
+ <div class="col-4 text-right d-none d-md-block">
29
+ <i class="far fa-calendar fa-4x fa-fw text-muted"></i>
30
  </div>
31
+ <div class="col-md-6 col-lg-8">
32
+ <span style="font-size: 30px" class="bookly-js-total d-md-block">&nbsp;</span>
33
+ <span style="font-size: 20px"><a href="#" class="bookly-js-href-total text-wrap"><?php esc_html_e( 'Total appointments', 'bookly' ) ?></a></span>
34
  </div>
35
  </div>
36
  </div>
37
+ <div class="col-md-6 col-lg-3">
38
+ <div class="form-row">
39
+ <div class="col-4 text-right pr-3 d-none d-md-block">
40
+ <i class="far fa-money-bill-alt fa-4x fa-fw text-muted"></i>
41
  </div>
42
+ <div class="col-md-6 col-lg-8">
43
+ <span style="font-size: 30px" class="bookly-js-revenue d-md-block">&nbsp;</span>
44
+ <span style="font-size: 20px"><a href="#" class="bookly-js-href-revenue text-wrap"><?php esc_html_e( 'Revenue', 'bookly' ) ?></a></span>
45
  </div>
46
  </div>
47
  </div>
48
  </div>
49
+ <div>
50
+ <canvas id="canvas" class="w-100" style="height: 500px"></canvas>
 
 
 
 
51
  </div>
52
  </div>
backend/components/dialogs/appointment/customer_details/templates/customer_details.php CHANGED
@@ -5,26 +5,26 @@ use Bookly\Lib\Entities\CustomerAppointment;
5
  use Bookly\Lib\Utils\Common;
6
  use Bookly\Lib\Config;
7
  ?>
8
- <div id="bookly-customer-details-dialog" class="modal fade" tabindex=-1 role="dialog">
9
  <div class="modal-dialog">
10
  <div class="modal-content">
11
  <div class="modal-header">
12
- <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
13
- <div class="modal-title h2"><?php _e( 'Edit booking details', 'bookly' ) ?></div>
14
  </div>
15
  <form ng-hide=loading style="z-index: 1050">
16
  <div class="modal-body">
17
  <div class="form-group">
18
- <label for="bookly-appointment-status"><?php _e( 'Status', 'bookly' ) ?></label>
19
- <select class="bookly-custom-field form-control" id="bookly-appointment-status">
20
  <?php foreach ( CustomerAppointment::getStatuses() as $status ): ?>
21
  <option value="<?php echo $status ?>"><?php echo esc_html( CustomerAppointment::statusToString( $status ) ) ?></option>
22
  <?php endforeach ?>
23
  </select>
24
  </div>
25
  <div class="form-group" <?php if ( ! Config::groupBookingActive() ) echo ' style="display:none"' ?>>
26
- <label for="bookly-number-of-persons"><?php _e( 'Number of persons', 'bookly' ) ?></label>
27
- <select class="bookly-custom-field form-control" id="bookly-number-of-persons"></select>
28
  </div>
29
  <?php Proxy\Pro::renderTimeZoneSwitcher() ?>
30
  <?php if ( Config::showNotes() ): ?>
@@ -38,8 +38,8 @@ use Bookly\Lib\Config;
38
 
39
  </div>
40
  <div class="modal-footer">
41
- <?php Buttons::renderCustom( null, 'btn-lg btn-success', __( 'Apply', 'bookly' ), array( 'ng-click' => 'saveCustomFields()' ) ) ?>
42
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', __( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
43
  </div>
44
  </form>
45
  </div>
5
  use Bookly\Lib\Utils\Common;
6
  use Bookly\Lib\Config;
7
  ?>
8
+ <div id="bookly-customer-details-dialog" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
9
  <div class="modal-dialog">
10
  <div class="modal-content">
11
  <div class="modal-header">
12
+ <h5 class="modal-title"><?php esc_html_e( 'Edit booking details', 'bookly' ) ?></h5>
13
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-hidden="true" aria-label="Close">×</button>
14
  </div>
15
  <form ng-hide=loading style="z-index: 1050">
16
  <div class="modal-body">
17
  <div class="form-group">
18
+ <label for="bookly-appointment-status"><?php esc_html_e( 'Status', 'bookly' ) ?></label>
19
+ <select class="bookly-custom-field form-control custom-select" id="bookly-appointment-status">
20
  <?php foreach ( CustomerAppointment::getStatuses() as $status ): ?>
21
  <option value="<?php echo $status ?>"><?php echo esc_html( CustomerAppointment::statusToString( $status ) ) ?></option>
22
  <?php endforeach ?>
23
  </select>
24
  </div>
25
  <div class="form-group" <?php if ( ! Config::groupBookingActive() ) echo ' style="display:none"' ?>>
26
+ <label for="bookly-number-of-persons"><?php esc_html_e( 'Number of persons', 'bookly' ) ?></label>
27
+ <select class="bookly-custom-field form-control custom-select" id="bookly-number-of-persons"></select>
28
  </div>
29
  <?php Proxy\Pro::renderTimeZoneSwitcher() ?>
30
  <?php if ( Config::showNotes() ): ?>
38
 
39
  </div>
40
  <div class="modal-footer">
41
+ <?php Buttons::render( null, 'btn-success', __( 'Apply', 'bookly' ), array( 'ng-click' => 'saveCustomFields()' ) ) ?>
42
+ <?php Buttons::renderCancel() ?>
43
  </div>
44
  </form>
45
  </div>
backend/components/dialogs/appointment/delete/templates/delete.php CHANGED
@@ -1,29 +1,29 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
- <div id="bookly-delete-dialog" class="modal fade" tabindex=-1 role="dialog">
5
  <div class="modal-dialog">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
- <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
9
- <div class="modal-title h2"><?php _e( 'Delete', 'bookly' ) ?></div>
10
  </div>
11
  <div class="modal-body">
12
  <p><?php esc_html_e( 'You are going to delete appointment(s). Notifications will be sent in accordance with your settings.', 'bookly' ) ?></p>
13
- <div class="checkbox">
14
- <label>
15
- <input id="bookly-delete-notify" type="checkbox" />
16
- <?php _e( 'Send notifications', 'bookly' ) ?>
17
- </label>
18
  </div>
 
19
  <div class="form-group" style="display: none;" id="bookly-delete-reason-cover">
20
- <input class="form-control" type="text" id="bookly-delete-reason" placeholder="<?php _e( 'Cancellation reason (optional)', 'bookly' ) ?>" />
21
  </div>
22
  </div>
23
  <div class="modal-footer">
24
- <?php Buttons::renderCustom( 'bookly-delete', 'btn-danger', esc_html__( 'Delete', 'bookly' ), array(), '<i class="fa fa-fw fa-trash"></i> {caption}' ) ?>
25
- <?php Buttons::renderCustom( null, 'btn-default', esc_html__( 'Cancel', 'bookly' ), array( 'ng-click' => 'closeDialog()', 'data-dismiss' => 'modal' ) ) ?>
26
  </div>
27
  </div>
28
  </div>
29
- </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
+ <div id="bookly-delete-dialog" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
5
  <div class="modal-dialog">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
+ <h5 class="modal-title"><?php esc_html_e( 'Delete', 'bookly' ) ?></h5>
9
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
10
  </div>
11
  <div class="modal-body">
12
  <p><?php esc_html_e( 'You are going to delete appointment(s). Notifications will be sent in accordance with your settings.', 'bookly' ) ?></p>
13
+
14
+ <div class="custom-control custom-checkbox">
15
+ <input class="custom-control-input" id="bookly-delete-notify" type="checkbox"/>
16
+ <label class="custom-control-label" for="bookly-delete-notify"><?php esc_html_e( 'Send notifications', 'bookly' ) ?>
 
17
  </div>
18
+
19
  <div class="form-group" style="display: none;" id="bookly-delete-reason-cover">
20
+ <input class="form-control" type="text" id="bookly-delete-reason" placeholder="<?php esc_attr_e( 'Cancellation reason (optional)', 'bookly' ) ?>" />
21
  </div>
22
  </div>
23
  <div class="modal-footer">
24
+ <?php Buttons::render( 'bookly-delete', 'btn-danger', __( 'Delete', 'bookly' ), array(), '<i class="far fa-fw fa-trash-alt mr-1"></i>{caption}' ) ?>
25
+ <?php Buttons::renderCancel( null, array( 'ng-click' => 'closeDialog()' ) ) ?>
26
  </div>
27
  </div>
28
  </div>
29
+ </div>
backend/components/dialogs/appointment/edit/Ajax.php CHANGED
@@ -4,6 +4,7 @@ namespace Bookly\Backend\Components\Dialogs\Appointment\Edit;
4
  use Bookly\Lib;
5
  use Bookly\Lib\DataHolders\Booking as DataHolders;
6
  use Bookly\Backend\Modules\Calendar;
 
7
 
8
  /**
9
  * Class Ajax
@@ -61,7 +62,7 @@ class Ajax extends Lib\Base\Ajax
61
  // Staff list.
62
  $staff = Lib\Entities\Staff::query()->findOne();
63
  /** @var Lib\Entities\Staff[] $staff_members */
64
- $staff_members = $staff ? Lib\Config::proActive() ? Lib\Utils\Common::isCurrentUserSupervisor() ? Lib\Entities\Staff::query()->sortBy( 'position' )->find() : Lib\Entities\Staff::query()->where( 'wp_user_id', get_current_user_id() )->find() : array( $staff ) : array();
65
  $postfix_archived = sprintf( ' (%s)', __( 'Archived', 'bookly' ) );
66
 
67
  $max_duration = 0;
@@ -456,7 +457,7 @@ class Ajax extends Lib\Base\Ajax
456
  $series = new Lib\Entities\Series();
457
  $series
458
  ->setRepeat( self::parameter( 'repeat' ) )
459
- ->setToken( Lib\Utils\Common::generateToken( get_class( $series ), 'token' ) )
460
  ->save();
461
 
462
  // Create order
4
  use Bookly\Lib;
5
  use Bookly\Lib\DataHolders\Booking as DataHolders;
6
  use Bookly\Backend\Modules\Calendar;
7
+ use Bookly\Lib\Utils\Common;
8
 
9
  /**
10
  * Class Ajax
62
  // Staff list.
63
  $staff = Lib\Entities\Staff::query()->findOne();
64
  /** @var Lib\Entities\Staff[] $staff_members */
65
+ $staff_members = $staff ? Lib\Config::proActive() ? Common::isCurrentUserSupervisor() ? Lib\Entities\Staff::query()->sortBy( 'position' )->find() : Lib\Entities\Staff::query()->where( 'wp_user_id', get_current_user_id() )->find() : array( $staff ) : array();
66
  $postfix_archived = sprintf( ' (%s)', __( 'Archived', 'bookly' ) );
67
 
68
  $max_duration = 0;
457
  $series = new Lib\Entities\Series();
458
  $series
459
  ->setRepeat( self::parameter( 'repeat' ) )
460
+ ->setToken( Common::generateToken( get_class( $series ), 'token' ) )
461
  ->save();
462
 
463
  // Create order
backend/components/dialogs/appointment/edit/Dialog.php CHANGED
@@ -15,25 +15,25 @@ class Dialog extends Lib\Base\Component
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
- 'backend' => array( 'css/jquery-ui-theme/jquery-ui.min.css', 'css/select2.min.css', 'css/fontawesome-all.min.css' ),
19
  'frontend' => array( 'css/ladda.min.css', ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
23
- 'backend' => array(
24
- 'js/angular.min.js' => array( 'jquery-ui-datepicker' ),
25
- 'js/angular-ui-date-0.0.8.js' => array( 'bookly-angular.min.js' ),
26
- 'js/moment.min.js' => array( 'jquery' ),
27
- 'js/select2.full.min.js' => array( 'jquery' ),
28
- 'js/help.js' => array( 'jquery' ),
29
  ),
30
  'frontend' => array(
31
  'js/spin.min.js' => array( 'jquery' ),
32
  'js/ladda.min.js' => array( 'jquery' ),
33
  ),
34
- 'module' => array(
35
- 'js/ng-appointment.js' => array( 'bookly-angular-ui-date-0.0.8.js' ),
36
- )
37
  ) );
38
 
39
  wp_localize_script( 'bookly-ng-appointment.js', 'BooklyL10nAppDialog', array(
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
+ 'backend' => array( 'css/fontawesome-all.min.css' ),
19
  'frontend' => array( 'css/ladda.min.css', ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
23
+ 'backend' => array(
24
+ 'js/angular.min.js' => array( 'jquery' ),
25
+ 'js/moment.min.js' => array( 'jquery' ),
26
+ 'js/daterangepicker.js' => array( 'bookly-moment.min.js' ),
27
+ 'js/angular-daterangepicker.js' => array( 'bookly-angular.min.js', 'bookly-daterangepicker.js' ),
28
+ 'js/select2.min.js' => array( 'jquery' ),
29
  ),
30
  'frontend' => array(
31
  'js/spin.min.js' => array( 'jquery' ),
32
  'js/ladda.min.js' => array( 'jquery' ),
33
  ),
34
+ 'module' => array(
35
+ 'js/ng-appointment.js' => array( 'bookly-angular-daterangepicker.js' ),
36
+ ),
37
  ) );
38
 
39
  wp_localize_script( 'bookly-ng-appointment.js', 'BooklyL10nAppDialog', array(
backend/components/dialogs/appointment/edit/resources/js/ng-appointment.js CHANGED
@@ -1,6 +1,6 @@
1
  ;(function() {
2
 
3
- var module = angular.module('appointmentDialog', ['ui.date', 'customerDialog', 'paymentDetailsDialog']);
4
 
5
  /**
6
  * DataSource service.
@@ -80,10 +80,10 @@
80
  ds.data.customers_remote = true;
81
  // Init select2 remote.
82
  jQuery('#bookly-appointment-dialog-select2').select2({
83
- width : '100%',
84
- theme : 'bootstrap',
85
  allowClear: false,
86
- language : {
87
  noResults: function () {
88
  return BooklyL10nAppDialog.no_result_found;
89
  },
@@ -91,7 +91,7 @@
91
  return BooklyL10nAppDialog.searching;
92
  }
93
  },
94
- ajax : {
95
  url : ajaxurl,
96
  dataType : 'json',
97
  delay : 250,
@@ -122,10 +122,10 @@
122
  },
123
  }).on("select2:selecting", function (data) {
124
  data.preventDefault();
125
- var $scope = angular.element(jQuery('#bookly-appointment-dialog')).scope();
126
  $scope.$apply(function ($scope) {
127
  let clone = {};
128
- angular.copy($scope.dataSource.data.customers.find(x => x.id === data.params.args.data.id), clone);
129
  $scope.dataSource.resetCustomer(clone);
130
  $scope.form.customers.push(clone);
131
  $scope.onCustomersChange();
@@ -134,19 +134,19 @@
134
  });
135
  } else {
136
  jQuery('#bookly-appointment-dialog-select2').select2({
137
- width : '100%',
138
- theme : 'bootstrap',
139
  allowClear: false,
140
- language : {
141
  noResults: function () {
142
  return BooklyL10nAppDialog.no_result_found;
143
  }
144
  }
145
  }).on('select2:select select2:unselect', function (data) {
146
- var $scope = angular.element(jQuery('#bookly-appointment-dialog')).scope();
147
  $scope.$apply(function ($scope) {
148
  let clone = {};
149
- angular.copy($scope.dataSource.data.customers.find(x => x.id === data.params.data.id), clone);
150
  $scope.dataSource.resetCustomer(clone);
151
  $scope.form.customers.push(clone);
152
  $scope.onCustomersChange();
@@ -324,8 +324,8 @@
324
  end_date : null
325
  }
326
  } else if (ds.form.date) {
327
- var start_date = moment(ds.form.date.getTime()),
328
- end_date = moment(ds.form.date.getTime()),
329
  start_time = [0,0],
330
  end_time = [0,0]
331
  ;
@@ -438,7 +438,7 @@
438
  custom_service_name : null,
439
  custom_service_price : 0,
440
  location : location,
441
- date : start_date.clone().local().toDate(),
442
  skip_date : null,
443
  start_time : dataSource.findTime('start', start_date.format('HH:mm')),
444
  end_time : null,
@@ -451,7 +451,7 @@
451
  weekly : { on : [weekday] },
452
  biweekly : { on : [weekday] },
453
  monthly : { on : 'day', day : start_date.format('D'), weekday : weekday },
454
- until : start_date.clone().add(1, 'month').format('YYYY-MM-DD')
455
  },
456
  schedule : {
457
  items : [],
@@ -516,7 +516,7 @@
516
  weekly : {on: []},
517
  biweekly: {on: []},
518
  monthly : {on: 'day', day: '1', weekday: 'mon'},
519
- until : start_date === null ? moment().add(1, 'month').format('YYYY-MM-DD') : start_date.clone().add(1, 'month').format('YYYY-MM-DD')
520
  },
521
  schedule : {
522
  items : [],
@@ -531,14 +531,14 @@
531
  });
532
  $scope.form.end_time_data = $scope.dataSource.getDataForEndTime();
533
  if (start_date !== null) {
534
- $scope.form.date = start_date.clone().local().toDate();
535
  $scope.form.start_time = $scope.dataSource.findTime('start', start_date.format('HH:mm'));
536
  $scope.dataSource.setEndTimeBasedOnService();
537
  $scope.form.end_time = start_date.format('YYYY-MM-DD') == end_date.format('YYYY-MM-DD')
538
  ? $scope.dataSource.findTime('end', end_date.format('HH:mm'))
539
  : $scope.dataSource.findTime('end', (Math.floor((end_date - start_date) / 3600000) + start_date.hour()) + end_date.format(':mm'));
540
  } else {
541
- $scope.form.date = moment().local().toDate();
542
  $scope.form.start_time = $scope.dataSource.findTime('start', moment().format('HH:mm'));
543
  $scope.dataSource.setEndTimeBasedOnService();
544
  }
@@ -558,7 +558,7 @@
558
  clone = customer;
559
  } else {
560
  // For Error: ngRepeat:dupes & chosen directive
561
- angular.copy(customer, clone);
562
  }
563
  clone.ca_id = item.ca_id;
564
  clone.series_id = item.series_id;
@@ -604,7 +604,7 @@
604
  $scope.form.customers.forEach(function (item, i, arr) {
605
  var customer_extras = {};
606
  if ($scope.form.service) {
607
- jQuery('#bookly-extras .service_' + $scope.form.service.id + ' input.extras-count').each(function () {
608
  var extra_id = jQuery(this).data('id');
609
  if (item.extras[extra_id] !== undefined) {
610
  customer_extras[extra_id] = item.extras[extra_id];
@@ -644,7 +644,7 @@
644
  },
645
  function (response) {
646
  $scope.$apply(function ($scope) {
647
- angular.forEach(response, function (value, error) {
648
  $scope.errors[error] = value;
649
  });
650
  });
@@ -700,12 +700,12 @@
700
  checkAppointmentErrors();
701
  };
702
 
703
- $scope.onDateChange = function () {
704
- if ($scope.form.date) {
705
  checkAppointmentErrors();
706
  $scope.onRepeatChange();
707
  }
708
- };
709
 
710
  $scope.onCustomersChange = function() {
711
  $scope.errors.customers_appointments_limit = [];
@@ -729,7 +729,7 @@
729
  customers = []
730
  ;
731
 
732
- angular.forEach($scope.form.schedule.items, function (item) {
733
  if (!item.deleted) {
734
  schedule.push(item.slots);
735
  }
@@ -738,7 +738,7 @@
738
  $scope.form.customers.forEach(function (item, i, arr) {
739
  var customer_extras = {};
740
  if ($scope.form.service) {
741
- jQuery('#bookly-extras .service_' + $scope.form.service.id + ' input.extras-count').each(function () {
742
  var extra_id = jQuery(this).data('id');
743
  if (item.extras[extra_id] !== undefined) {
744
  customer_extras[extra_id] = item.extras[extra_id];
@@ -797,7 +797,7 @@
797
  $scope.form.screen = 'queue';
798
  } else {
799
  // Close the dialog.
800
- $element.children().modal('hide');
801
  }
802
  } else {
803
  $scope.errors = response.errors;
@@ -829,7 +829,7 @@
829
  );
830
  }
831
  // Close the dialog.
832
- $element.children().modal('hide');
833
  };
834
  // On 'Cancel' button click in queue window.
835
  $scope.queueSend = function () {
@@ -860,7 +860,7 @@
860
  $scope.$apply(function ($scope) {
861
  if (response.success) {
862
  // Close the dialog.
863
- $element.children().modal('hide');
864
  } else {
865
  $scope.errors = response.errors;
866
  }
@@ -932,9 +932,9 @@
932
  checkAppointmentErrors();
933
  };
934
 
935
- $scope.openNewCustomerDialog = function() {
936
  var $dialog = jQuery('#bookly-customer-dialog');
937
- $dialog.modal({show: true});
938
  };
939
 
940
  /**************************************************************************************************************
@@ -968,9 +968,9 @@
968
  }
969
  });
970
 
971
- $dialog.find('#bookly-extras .extras-count').val(0);
972
- angular.forEach(customer.extras, function (extra_count, extra_id) {
973
- $dialog.find('#bookly-extras .extras-count[data-id="' + extra_id + '"]').val(extra_count);
974
  });
975
 
976
  // Prepare select for number of persons.
@@ -995,10 +995,7 @@
995
  $dialog.find('#bookly-customer-time-zone').val(customer.timezone ? customer.timezone : '');
996
  $scope.edit_customer = customer;
997
 
998
- $dialog.modal({show: true})
999
- .on('hidden.bs.modal', function () {
1000
- jQuery('body').addClass('modal-open');
1001
- });
1002
  jQuery(document.body).trigger('bookly.edit.customer_details', [$dialog, $scope.edit_customer]);
1003
  };
1004
 
@@ -1077,7 +1074,7 @@
1077
  });
1078
 
1079
  if ($scope.form.service) {
1080
- $extras.find(' .service_' + $scope.form.service.id + ' input.extras-count').each(function () {
1081
  if (this.value > 0) {
1082
  extras[jQuery(this).data('id')] = this.value;
1083
  }
@@ -1091,7 +1088,7 @@
1091
  $scope.edit_customer.custom_fields = result;
1092
  $scope.edit_customer.extras = extras;
1093
 
1094
- jQuery('#bookly-customer-details-dialog').modal('hide');
1095
  if ($extras.length > 0) {
1096
  // Check if intersection with another appointment exists.
1097
  checkAppointmentErrors();
@@ -1112,17 +1109,13 @@
1112
  payment_tax : null,
1113
  payment_id : null
1114
  };
1115
- $dialog.modal({show: true}).on('hidden.bs.modal', function () {
1116
- jQuery('body').addClass('modal-open');
1117
- });
1118
  };
1119
 
1120
  $scope.attachPayment = function (attach_method, price, tax, payment_id, customer_id, customer_index) {
1121
  var $dialog = jQuery('#bookly-payment-details-modal');
1122
  if (attach_method == 'search') {
1123
- $dialog.data('payment_id', payment_id).data('payment_bind', true).data('customer_id', customer_id).data('customer_index', customer_index).modal({show: true}).on('hidden.bs.modal', function () {
1124
- jQuery('body').addClass('modal-open');
1125
- });
1126
  } else {
1127
  jQuery.each($scope.dataSource.form.customers, function (key, item) {
1128
  if (item.id == customer_id && key == customer_index) {
@@ -1179,13 +1172,13 @@
1179
  var current_day = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'][current_date.format('d')];
1180
  switch ($scope.form.repeat.repeat) {
1181
  case 'daily':
1182
- if (($scope.form.repeat.daily.every > 6 || jQuery.inArray(current_day, $scope.dataSource.data.week_days) != -1) && (current_date.diff(moment($scope.dataSource.form.date.getTime()), 'days') % $scope.form.repeat.daily.every == 0)) {
1183
  return true;
1184
  }
1185
  break;
1186
  case 'weekly':
1187
  case 'biweekly':
1188
- if (($scope.form.repeat.repeat == 'weekly' || current_date.diff(moment($scope.dataSource.form.date.getTime()).startOf('isoWeek'), 'weeks') % 2 == 0) && (jQuery.inArray(current_day, $scope.form.repeat.weekly.on) != -1)) {
1189
  return true;
1190
  }
1191
  break;
@@ -1215,11 +1208,18 @@
1215
 
1216
  return false;
1217
  };
 
 
 
 
 
 
 
1218
  $scope.onRepeatChange = function () {
1219
  if (jQuery('#bookly-repeat-enabled').length && !$scope.form.skip_date) {
1220
  var number_of_times = 0,
1221
- date_until = moment($scope.form.repeat.until).add(1, 'days'),
1222
- current_date = moment($scope.dataSource.form.date.getTime());
1223
  do {
1224
  if ($scope.isDateMatchesSelections(current_date)) {
1225
  number_of_times++;
@@ -1231,15 +1231,15 @@
1231
  };
1232
  $scope.onRepeatChangeTimes = function () {
1233
  var number_of_times = 0,
1234
- date_until = moment($scope.dataSource.form.date.getTime()).add(5, 'years'),
1235
- current_date = moment($scope.dataSource.form.date.getTime());
1236
  do {
1237
  if ($scope.isDateMatchesSelections(current_date)) {
1238
  number_of_times++
1239
  }
1240
  current_date.add(1, 'days');
1241
  } while (number_of_times < $scope.form.repeat.times && current_date.isBefore(date_until));
1242
- $scope.form.repeat.until = current_date.subtract(1, 'days').format('YYYY-MM-DD');
1243
  };
1244
 
1245
  /**************************************************************************************************************
@@ -1271,7 +1271,7 @@
1271
  service_id : $scope.form.service.id,
1272
  location_id : $scope.form.location ? $scope.form.location.id : null,
1273
  datetime : dates.start_date,
1274
- until : $scope.form.repeat.until,
1275
  repeat : $scope.form.repeat.repeat,
1276
  params : $scope.form.repeat[$scope.form.repeat.repeat],
1277
  extras : extras,
@@ -1283,7 +1283,8 @@
1283
  $scope.form.schedule.items = response.data;
1284
  $scope.form.schedule.page = 0;
1285
  $scope.form.schedule.another_time = [];
1286
- angular.forEach($scope.form.schedule.items, function (item) {
 
1287
  if (item.another_time) {
1288
  var page = parseInt( ( item.index - 1 ) / 10 ) + 1;
1289
  if ($scope.form.schedule.another_time.indexOf(page) < 0) {
@@ -1355,7 +1356,7 @@
1355
  });
1356
 
1357
  var exclude = [];
1358
- angular.forEach($scope.form.schedule.items, function (_item) {
1359
  if (item.slots != _item.slots && !_item.deleted) {
1360
  exclude.push(_item.slots);
1361
  }
@@ -1368,8 +1369,8 @@
1368
  staff_id : $scope.form.staff.id,
1369
  service_id : $scope.form.service.id,
1370
  location_id : $scope.form.location ? $scope.form.location.id : null,
1371
- datetime : item.date + ' 00:00',
1372
- until : item.date,
1373
  repeat : 'daily',
1374
  params : {every: 1},
1375
  with_options : 1,
@@ -1411,6 +1412,9 @@
1411
  });
1412
  };
1413
  $scope.schDatePickerOptions = jQuery.extend({}, BooklyL10nAppDialog.datePicker, {dateFormat: 'D, M dd, yy'});
 
 
 
1414
  $scope.schViewSeries = function ( customer ) {
1415
  jQuery(document.body).trigger( 'recurring_appointments.series_dialog', [ customer.series_id, function (event) {
1416
  // Switch to the event owner tab.
@@ -1446,12 +1450,13 @@
1446
  */
1447
  module.directive('popover', function() {
1448
  return function(scope, element, attrs) {
1449
- element.popover({
1450
  trigger : 'hover',
 
1451
  content : function() { return this.getAttribute('popover'); },
1452
  html : true,
1453
  placement: 'top',
1454
- template: '<div class="popover bookly-font-xs" style="width: 220px" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
1455
  });
1456
  };
1457
  });
@@ -1485,11 +1490,8 @@
1485
  * @param function callback
1486
  */
1487
  var showAppointmentDialog = function (appointment_id, staff_id, start_date, callback) {
1488
- if (jQuery.fn.tooltip.Constructor.VERSION !== undefined && jQuery.fn.tooltip.Constructor.VERSION.split('.')[0] === '4') {
1489
- jQuery('#bookly-tbs .modal.fade').removeClass('fade');
1490
- }
1491
  var $dialog = jQuery('#bookly-appointment-dialog');
1492
- var $scope = angular.element($dialog[0]).scope();
1493
  $scope.$apply(function ($scope) {
1494
  $scope.loading = true;
1495
  $scope.form.titles = {
@@ -1510,27 +1512,27 @@ var showAppointmentDialog = function (appointment_id, staff_id, start_date, call
1510
  });
1511
 
1512
  // hide customer details dialog, if it remained opened.
1513
- if (jQuery('#bookly-customer-details-dialog').hasClass('in')) {
1514
- jQuery('#bookly-customer-details-dialog').modal('hide');
1515
  }
1516
 
1517
  // hide new customer dialog, if it remained opened.
1518
- if (jQuery('#bookly-customer-dialog').hasClass('in')) {
1519
- jQuery('#bookly-customer-dialog').modal('hide');
1520
  }
1521
 
1522
- $dialog.modal('show');
1523
  };
1524
 
1525
  jQuery(function($) {
1526
  $('#bookly-appointment-dialog')
1527
  .on('click', '[data-action=show-payment]', function () {
1528
- jQuery('#bookly-payment-details-modal').modal('show', this);
1529
  })
1530
  .on('click', '[data-action=show-collaborative]', function () {
1531
- jQuery('#bookly-collaborative-services-dialog').modal('show', this);
1532
  })
1533
  .on('click', '[data-action=show-compound]', function () {
1534
- jQuery('#bookly-compound-services-dialog').modal('show', this);
1535
  });
1536
  });
1
  ;(function() {
2
 
3
+ var module = booklyAngular.module('appointmentDialog', ['daterangepicker', 'customerDialog', 'paymentDetailsDialog']);
4
 
5
  /**
6
  * DataSource service.
80
  ds.data.customers_remote = true;
81
  // Init select2 remote.
82
  jQuery('#bookly-appointment-dialog-select2').select2({
83
+ theme: 'bootstrap4',
84
+ dropdownParent: '#bookly-tbs',
85
  allowClear: false,
86
+ language: {
87
  noResults: function () {
88
  return BooklyL10nAppDialog.no_result_found;
89
  },
91
  return BooklyL10nAppDialog.searching;
92
  }
93
  },
94
+ ajax: {
95
  url : ajaxurl,
96
  dataType : 'json',
97
  delay : 250,
122
  },
123
  }).on("select2:selecting", function (data) {
124
  data.preventDefault();
125
+ var $scope = booklyAngular.element(jQuery('#bookly-appointment-dialog')).scope();
126
  $scope.$apply(function ($scope) {
127
  let clone = {};
128
+ booklyAngular.copy($scope.dataSource.data.customers.find(x => x.id === data.params.args.data.id), clone);
129
  $scope.dataSource.resetCustomer(clone);
130
  $scope.form.customers.push(clone);
131
  $scope.onCustomersChange();
134
  });
135
  } else {
136
  jQuery('#bookly-appointment-dialog-select2').select2({
137
+ theme: 'bootstrap4',
138
+ dropdownParent: '#bookly-tbs',
139
  allowClear: false,
140
+ language: {
141
  noResults: function () {
142
  return BooklyL10nAppDialog.no_result_found;
143
  }
144
  }
145
  }).on('select2:select select2:unselect', function (data) {
146
+ var $scope = booklyAngular.element(jQuery('#bookly-appointment-dialog')).scope();
147
  $scope.$apply(function ($scope) {
148
  let clone = {};
149
+ booklyAngular.copy($scope.dataSource.data.customers.find(x => x.id === data.params.data.id), clone);
150
  $scope.dataSource.resetCustomer(clone);
151
  $scope.form.customers.push(clone);
152
  $scope.onCustomersChange();
324
  end_date : null
325
  }
326
  } else if (ds.form.date) {
327
+ var start_date = ds.form.date.clone(),
328
+ end_date = ds.form.date.clone(),
329
  start_time = [0,0],
330
  end_time = [0,0]
331
  ;
438
  custom_service_name : null,
439
  custom_service_price : 0,
440
  location : location,
441
+ date : start_date.clone().local(),
442
  skip_date : null,
443
  start_time : dataSource.findTime('start', start_date.format('HH:mm')),
444
  end_time : null,
451
  weekly : { on : [weekday] },
452
  biweekly : { on : [weekday] },
453
  monthly : { on : 'day', day : start_date.format('D'), weekday : weekday },
454
+ until : start_date.clone().add(1, 'month')
455
  },
456
  schedule : {
457
  items : [],
516
  weekly : {on: []},
517
  biweekly: {on: []},
518
  monthly : {on: 'day', day: '1', weekday: 'mon'},
519
+ until : start_date === null ? moment().add(1, 'month') : start_date.clone().add(1, 'month')
520
  },
521
  schedule : {
522
  items : [],
531
  });
532
  $scope.form.end_time_data = $scope.dataSource.getDataForEndTime();
533
  if (start_date !== null) {
534
+ $scope.form.date = start_date.clone().local();
535
  $scope.form.start_time = $scope.dataSource.findTime('start', start_date.format('HH:mm'));
536
  $scope.dataSource.setEndTimeBasedOnService();
537
  $scope.form.end_time = start_date.format('YYYY-MM-DD') == end_date.format('YYYY-MM-DD')
538
  ? $scope.dataSource.findTime('end', end_date.format('HH:mm'))
539
  : $scope.dataSource.findTime('end', (Math.floor((end_date - start_date) / 3600000) + start_date.hour()) + end_date.format(':mm'));
540
  } else {
541
+ $scope.form.date = moment().local();
542
  $scope.form.start_time = $scope.dataSource.findTime('start', moment().format('HH:mm'));
543
  $scope.dataSource.setEndTimeBasedOnService();
544
  }
558
  clone = customer;
559
  } else {
560
  // For Error: ngRepeat:dupes & chosen directive
561
+ booklyAngular.copy(customer, clone);
562
  }
563
  clone.ca_id = item.ca_id;
564
  clone.series_id = item.series_id;
604
  $scope.form.customers.forEach(function (item, i, arr) {
605
  var customer_extras = {};
606
  if ($scope.form.service) {
607
+ jQuery('#bookly-extras .service_' + $scope.form.service.id + ' input.bookly-js-extras-count').each(function () {
608
  var extra_id = jQuery(this).data('id');
609
  if (item.extras[extra_id] !== undefined) {
610
  customer_extras[extra_id] = item.extras[extra_id];
644
  },
645
  function (response) {
646
  $scope.$apply(function ($scope) {
647
+ booklyAngular.forEach(response, function (value, error) {
648
  $scope.errors[error] = value;
649
  });
650
  });
700
  checkAppointmentErrors();
701
  };
702
 
703
+ $scope.$watch('form.date', function(newDate) {
704
+ if (newDate !== null) {
705
  checkAppointmentErrors();
706
  $scope.onRepeatChange();
707
  }
708
+ }, false);
709
 
710
  $scope.onCustomersChange = function() {
711
  $scope.errors.customers_appointments_limit = [];
729
  customers = []
730
  ;
731
 
732
+ booklyAngular.forEach($scope.form.schedule.items, function (item) {
733
  if (!item.deleted) {
734
  schedule.push(item.slots);
735
  }
738
  $scope.form.customers.forEach(function (item, i, arr) {
739
  var customer_extras = {};
740
  if ($scope.form.service) {
741
+ jQuery('#bookly-extras .service_' + $scope.form.service.id + ' input.bookly-js-extras-count').each(function () {
742
  var extra_id = jQuery(this).data('id');
743
  if (item.extras[extra_id] !== undefined) {
744
  customer_extras[extra_id] = item.extras[extra_id];
797
  $scope.form.screen = 'queue';
798
  } else {
799
  // Close the dialog.
800
+ $element.children().booklyModal('hide');
801
  }
802
  } else {
803
  $scope.errors = response.errors;
829
  );
830
  }
831
  // Close the dialog.
832
+ $element.children().booklyModal('hide');
833
  };
834
  // On 'Cancel' button click in queue window.
835
  $scope.queueSend = function () {
860
  $scope.$apply(function ($scope) {
861
  if (response.success) {
862
  // Close the dialog.
863
+ $element.children().booklyModal('hide');
864
  } else {
865
  $scope.errors = response.errors;
866
  }
932
  checkAppointmentErrors();
933
  };
934
 
935
+ $scope.openNewCustomerDialog = function () {
936
  var $dialog = jQuery('#bookly-customer-dialog');
937
+ $dialog.booklyModal({show: true});
938
  };
939
 
940
  /**************************************************************************************************************
968
  }
969
  });
970
 
971
+ $dialog.find('#bookly-extras .bookly-js-extras-count').val(0);
972
+ booklyAngular.forEach(customer.extras, function (extra_count, extra_id) {
973
+ $dialog.find('#bookly-extras .bookly-js-extras-count[data-id="' + extra_id + '"]').val(extra_count);
974
  });
975
 
976
  // Prepare select for number of persons.
995
  $dialog.find('#bookly-customer-time-zone').val(customer.timezone ? customer.timezone : '');
996
  $scope.edit_customer = customer;
997
 
998
+ $dialog.booklyModal({show: true});
 
 
 
999
  jQuery(document.body).trigger('bookly.edit.customer_details', [$dialog, $scope.edit_customer]);
1000
  };
1001
 
1074
  });
1075
 
1076
  if ($scope.form.service) {
1077
+ $extras.find(' .service_' + $scope.form.service.id + ' input.bookly-js-extras-count').each(function () {
1078
  if (this.value > 0) {
1079
  extras[jQuery(this).data('id')] = this.value;
1080
  }
1088
  $scope.edit_customer.custom_fields = result;
1089
  $scope.edit_customer.extras = extras;
1090
 
1091
+ jQuery('#bookly-customer-details-dialog').booklyModal('hide');
1092
  if ($extras.length > 0) {
1093
  // Check if intersection with another appointment exists.
1094
  checkAppointmentErrors();
1109
  payment_tax : null,
1110
  payment_id : null
1111
  };
1112
+ $dialog.booklyModal({show: true});
 
 
1113
  };
1114
 
1115
  $scope.attachPayment = function (attach_method, price, tax, payment_id, customer_id, customer_index) {
1116
  var $dialog = jQuery('#bookly-payment-details-modal');
1117
  if (attach_method == 'search') {
1118
+ $dialog.data('payment_id', payment_id).data('payment_bind', true).data('customer_id', customer_id).data('customer_index', customer_index).booklyModal({show: true});
 
 
1119
  } else {
1120
  jQuery.each($scope.dataSource.form.customers, function (key, item) {
1121
  if (item.id == customer_id && key == customer_index) {
1172
  var current_day = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'][current_date.format('d')];
1173
  switch ($scope.form.repeat.repeat) {
1174
  case 'daily':
1175
+ if (($scope.form.repeat.daily.every > 6 || jQuery.inArray(current_day, $scope.dataSource.data.week_days) != -1) && (current_date.diff($scope.dataSource.form.date, 'days') % $scope.form.repeat.daily.every == 0)) {
1176
  return true;
1177
  }
1178
  break;
1179
  case 'weekly':
1180
  case 'biweekly':
1181
+ if (($scope.form.repeat.repeat == 'weekly' || current_date.diff($scope.dataSource.form.date.clone().startOf('isoWeek'), 'weeks') % 2 == 0) && (jQuery.inArray(current_day, $scope.form.repeat.weekly.on) != -1)) {
1182
  return true;
1183
  }
1184
  break;
1208
 
1209
  return false;
1210
  };
1211
+
1212
+ $scope.$watch('form.repeat.until', function(newDate) {
1213
+ if (newDate !== null) {
1214
+ $scope.onRepeatChange();
1215
+ }
1216
+ }, false);
1217
+
1218
  $scope.onRepeatChange = function () {
1219
  if (jQuery('#bookly-repeat-enabled').length && !$scope.form.skip_date) {
1220
  var number_of_times = 0,
1221
+ date_until = $scope.form.repeat.until.clone().add(1, 'days'),
1222
+ current_date = $scope.dataSource.form.date.clone();
1223
  do {
1224
  if ($scope.isDateMatchesSelections(current_date)) {
1225
  number_of_times++;
1231
  };
1232
  $scope.onRepeatChangeTimes = function () {
1233
  var number_of_times = 0,
1234
+ date_until = $scope.dataSource.form.date.clone().add(5, 'years'),
1235
+ current_date = $scope.dataSource.form.date.clone();
1236
  do {
1237
  if ($scope.isDateMatchesSelections(current_date)) {
1238
  number_of_times++
1239
  }
1240
  current_date.add(1, 'days');
1241
  } while (number_of_times < $scope.form.repeat.times && current_date.isBefore(date_until));
1242
+ $scope.form.repeat.until = current_date.subtract(1, 'days');
1243
  };
1244
 
1245
  /**************************************************************************************************************
1271
  service_id : $scope.form.service.id,
1272
  location_id : $scope.form.location ? $scope.form.location.id : null,
1273
  datetime : dates.start_date,
1274
+ until : $scope.form.repeat.until.format('YYYY-MM-DD'),
1275
  repeat : $scope.form.repeat.repeat,
1276
  params : $scope.form.repeat[$scope.form.repeat.repeat],
1277
  extras : extras,
1283
  $scope.form.schedule.items = response.data;
1284
  $scope.form.schedule.page = 0;
1285
  $scope.form.schedule.another_time = [];
1286
+ booklyAngular.forEach($scope.form.schedule.items, function (item) {
1287
+ item.date = moment(item.date, 'YYYY-MM-DD');
1288
  if (item.another_time) {
1289
  var page = parseInt( ( item.index - 1 ) / 10 ) + 1;
1290
  if ($scope.form.schedule.another_time.indexOf(page) < 0) {
1356
  });
1357
 
1358
  var exclude = [];
1359
+ booklyAngular.forEach($scope.form.schedule.items, function (_item) {
1360
  if (item.slots != _item.slots && !_item.deleted) {
1361
  exclude.push(_item.slots);
1362
  }
1369
  staff_id : $scope.form.staff.id,
1370
  service_id : $scope.form.service.id,
1371
  location_id : $scope.form.location ? $scope.form.location.id : null,
1372
+ datetime : item.date.format('YYYY-MM-DD') + ' 00:00',
1373
+ until : item.date.format('YYYY-MM-DD'),
1374
  repeat : 'daily',
1375
  params : {every: 1},
1376
  with_options : 1,
1412
  });
1413
  };
1414
  $scope.schDatePickerOptions = jQuery.extend({}, BooklyL10nAppDialog.datePicker, {dateFormat: 'D, M dd, yy'});
1415
+ $scope.schOnChange = function (picker) {
1416
+ $scope.schOnDateChange(picker.opts.item);
1417
+ };
1418
  $scope.schViewSeries = function ( customer ) {
1419
  jQuery(document.body).trigger( 'recurring_appointments.series_dialog', [ customer.series_id, function (event) {
1420
  // Switch to the event owner tab.
1450
  */
1451
  module.directive('popover', function() {
1452
  return function(scope, element, attrs) {
1453
+ element.booklyPopover({
1454
  trigger : 'hover',
1455
+ container: jQuery(element).closest('li'),
1456
  content : function() { return this.getAttribute('popover'); },
1457
  html : true,
1458
  placement: 'top',
1459
+ template: '<div class="bookly-popover"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'
1460
  });
1461
  };
1462
  });
1490
  * @param function callback
1491
  */
1492
  var showAppointmentDialog = function (appointment_id, staff_id, start_date, callback) {
 
 
 
1493
  var $dialog = jQuery('#bookly-appointment-dialog');
1494
+ var $scope = booklyAngular.element($dialog[0]).scope();
1495
  $scope.$apply(function ($scope) {
1496
  $scope.loading = true;
1497
  $scope.form.titles = {
1512
  });
1513
 
1514
  // hide customer details dialog, if it remained opened.
1515
+ if (jQuery('#bookly-customer-details-dialog').hasClass('show')) {
1516
+ jQuery('#bookly-customer-details-dialog').booklyModal('hide');
1517
  }
1518
 
1519
  // hide new customer dialog, if it remained opened.
1520
+ if (jQuery('#bookly-customer-dialog').hasClass('show')) {
1521
+ jQuery('#bookly-customer-dialog').booklyModal('hide');
1522
  }
1523
 
1524
+ $dialog.booklyModal('show');
1525
  };
1526
 
1527
  jQuery(function($) {
1528
  $('#bookly-appointment-dialog')
1529
  .on('click', '[data-action=show-payment]', function () {
1530
+ jQuery('#bookly-payment-details-modal').booklyModal('show', this);
1531
  })
1532
  .on('click', '[data-action=show-collaborative]', function () {
1533
+ jQuery('#bookly-collaborative-services-dialog').booklyModal('show', this);
1534
  })
1535
  .on('click', '[data-action=show-compound]', function () {
1536
+ jQuery('#bookly-compound-services-dialog').booklyModal('show', this);
1537
  });
1538
  });
backend/components/dialogs/appointment/edit/templates/edit.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
 
3
  use Bookly\Backend\Components\Dialogs;
4
  use Bookly\Backend\Components\Dialogs\Appointment\Edit\Proxy;
5
  use Bookly\Backend\Components\Dialogs\Appointment\AttachPayment\Proxy as AttachPaymentProxy;
@@ -7,14 +8,14 @@ use Bookly\Lib;
7
  use Bookly\Lib\Config;
8
  use Bookly\Lib\Entities\CustomerAppointment;
9
  ?>
10
- <div ng-app="appointmentDialog" ng-controller="appointmentDialogCtrl">
11
- <div id=bookly-appointment-dialog class="modal fade" tabindex=-1 role="dialog">
12
- <div class="modal-dialog">
13
  <div class="modal-content">
14
- <form ng-submit=processForm()>
15
  <div class="modal-header">
16
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
17
- <div class="modal-title h2">{{ form.screen == 'queue' ? form.titles.queue : form.title }}</div>
18
  </div>
19
  <div ng-show=loading class="modal-body">
20
  <div class="bookly-loading"></div>
@@ -22,12 +23,12 @@ use Bookly\Lib\Entities\CustomerAppointment;
22
  <div ng-hide="loading || form.screen != 'main'" class="modal-body">
23
  <div class=form-group>
24
  <label for="bookly-provider"><?php esc_html_e( 'Provider', 'bookly' ) ?></label>
25
- <select id="bookly-provider" class="form-control" ng-model="form.staff" ng-options="s.full_name + (form.staff_any == s ? ' (' + dataSource.l10n.staff_any + ')' : '') group by s.category for s in dataSource.data.staff | filter:filterStaff" ng-change="onStaffChange()"></select>
26
  </div>
27
 
28
  <div class=form-group>
29
  <label for="bookly-service"><?php esc_html_e( 'Service', 'bookly' ) ?></label>
30
- <select id="bookly-service" class="form-control" ng-model="form.service"
31
  ng-options="s.title group by s.category for s in form.staff.services" ng-change="onServiceChange()">
32
  <option value=""><?php esc_html_e( '-- Select a service --', 'bookly' ) ?></option>
33
  </select>
@@ -41,38 +42,35 @@ use Bookly\Lib\Entities\CustomerAppointment;
41
  <?php if ( Config::locationsActive() ): ?>
42
  <div class="form-group">
43
  <label for="bookly-appointment-location"><?php esc_html_e( 'Location', 'bookly' ) ?></label>
44
- <select id="bookly-appointment-location" class="form-control" ng-model="form.location"
45
  ng-options="l.name for l in form.staff.locations" ng-change="onLocationChange()">
46
  <option value=""></option>
47
  </select>
48
  </div>
49
  <?php endif ?>
50
 
51
- <?php Proxy\Tasks::renderSkipDate() ?>
52
-
53
- <div ng-hide="form.skip_date">
54
- <div class=form-group>
55
- <div class="row">
56
  <div class="col-sm-4">
57
  <label for="bookly-date"><?php esc_html_e( 'Date', 'bookly' ) ?></label>
58
- <input id="bookly-date" class="form-control" type=text
59
- ng-model=form.date ui-date="datePickerOptions" autocomplete="off"
60
- ng-change=onDateChange()>
61
  </div>
62
  <div class="col-sm-8">
63
  <div ng-hide="form.service.duration >= 86400 && form.service.units_max == 1">
64
  <label for="bookly-period"><?php esc_html_e( 'Period', 'bookly' ) ?></label>
65
- <div class="bookly-flexbox">
66
- <div class="bookly-flex-cell">
67
- <select id="bookly-period" class="form-control" ng-model=form.start_time
68
  ng-options="t.title for t in dataSource.getDataForStartTime()"
69
  ng-change=onStartTimeChange()></select>
70
  </div>
71
- <div class="bookly-flex-cell" style="width: 4%">
72
- <div class="bookly-margin-horizontal-md"><?php esc_html_e( 'to', 'bookly' ) ?></div>
73
  </div>
74
- <div class="bookly-flex-cell" style="width: 48%">
75
- <select class="form-control" ng-model=form.end_time
76
  ng-options="t.title for t in form.end_time_data"
77
  ng-change=onEndTimeChange()></select>
78
  </div>
@@ -94,107 +92,86 @@ use Bookly\Lib\Entities\CustomerAppointment;
94
  <?php esc_html_e( 'Selected period doesn\'t match service schedule', 'bookly' ) ?>
95
  </p>
96
  <p class="text-success" my-slide-up=errors.staff_reaches_working_time_limit id=staff_reaches_working_time_limit_msg>
97
- <?php is_admin() ?
98
- esc_html_e( 'Booking exceeds the working hours limit for staff member', 'bookly' ) :
99
- esc_html_e( 'Booking exceeds your working hours limit', 'bookly' ) ?>
100
  </p>
101
- </div>
102
 
103
- <?php Proxy\RecurringAppointments::renderSubForm() ?>
 
104
  </div>
105
-
106
  <div class=form-group>
107
- <label for="bookly-select2"><?php esc_html_e( 'Customers', 'bookly' ) ?></label>
108
- <span ng-show="form.service && form.service.id" title="<?php esc_attr_e( 'Selected / maximum', 'bookly' ) ?>">
109
  ({{dataSource.getTotalNumberOfPersons()}}/{{form.service.capacity_max}})
110
- </span>
 
 
111
  <span ng-show="form.customers.length > 5" ng-click="form.expand_customers_list = !form.expand_customers_list" role="button">
112
- <i class="fa fa-fw" ng-class="{'fa-angle-down':!form.expand_customers_list, 'fa-angle-up':form.expand_customers_list}"></i>
113
  </span>
114
  <p class="text-success" ng-show=form.service my-slide-up="form.service.capacity_min > 1 && form.service.capacity_min > dataSource.getTotalNumberOfPersons()">
115
  <?php esc_html_e( 'Minimum capacity', 'bookly' ) ?>: {{form.service.capacity_min}}
116
  </p>
117
- <ul class="bookly-flexbox">
118
- <li ng-repeat="customer in form.customers" class="bookly-flex-row" ng-hide="$index > 4 && !form.expand_customers_list">
119
- <div class="bookly-flex-cell-sm">
120
- <a ng-click="editCustomerDetails(customer)" title="<?php esc_attr_e( 'Edit booking details', 'bookly' ) ?>" class="bookly-flex-cell bookly-padding-bottom-sm" href>{{customer.name}}</a>
121
  </div>
122
- <div class="bookly-flex-cell-sm text-right text-nowrap bookly-padding-bottom-sm">
123
  <?php Proxy\Shared::renderAppointmentDialogCustomersList() ?>
124
  <span class="dropdown">
125
- <button type="button" class="btn btn-sm btn-default bookly-margin-left-xs" data-toggle="dropdown" popover="<?php esc_attr_e( 'Status', 'bookly' ) ?>: {{statusToString(customer.status)}}">
126
- <span ng-class="{'fa fa-fw': true, 'fa-clock': customer.status == 'pending', 'fa-check': customer.status == 'approved', 'fa-times': customer.status == 'cancelled', 'fa-times-circle': customer.status == 'rejected', 'fa-list-ol': customer.status == 'waitlisted', 'fa-check-circle': customer.status == 'done', 'fa-lock': 0<?php foreach ( Lib\Proxy\CustomStatuses::prepareBusyStatuses( array() ) as $status ): ?> || customer.status == '<?php echo $status ?>'<?php endforeach ?>, 'fa-lock-open': 0<?php foreach ( Lib\Proxy\CustomStatuses::prepareFreeStatuses( array() ) as $status ): ?> || customer.status == '<?php echo $status ?>'<?php endforeach ?>}"></span>
127
- <span class="caret"></span>
128
  </button>
129
- <ul class="dropdown-menu">
130
- <li>
131
- <a href ng-click="customer.status = 'pending'">
132
- <span class="fa fa-fw fa-clock"></span>
133
- <?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_PENDING ) ) ?>
134
- </a>
135
- </li>
136
- <li>
137
- <a href ng-click="customer.status = 'approved'">
138
- <span class="fa fa-fw fa-check"></span>
139
- <?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_APPROVED ) ) ?>
140
- </a>
141
- </li>
142
- <li>
143
- <a href ng-click="customer.status = 'cancelled'">
144
- <span class="fa fa-fw fa-times"></span>
145
- <?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_CANCELLED ) ) ?>
146
- </a>
147
- </li>
148
- <li>
149
- <a href ng-click="customer.status = 'rejected'">
150
- <span class="fa fa-fw fa-times-circle"></span>
151
- <?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_REJECTED ) ) ?>
152
  </a>
153
- </li>
154
- <?php if ( Config::waitingListActive() ): ?>
155
- <li>
156
- <a href ng-click="customer.status = 'waitlisted'">
157
- <span class="fa fa-fw fa-list-ol"></span>
158
- <?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_WAITLISTED ) ) ?>
159
- </a>
160
- </li>
161
  <?php endif ?>
162
- <?php if ( Config::tasksActive() ): ?>
163
- <li>
164
- <a href ng-click="customer.status = 'done'">
165
- <span class="fa fa-fw fa-check-circle"></span>
166
- <?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_DONE ) ) ?>
167
- </a>
168
- </li>
169
  <?php endif ?>
170
- <?php foreach ( (array) Lib\Proxy\CustomStatuses::getAll() as $status ): ?>
171
- <li>
172
- <a href ng-click="customer.status = '<?php echo $status->getSlug() ?>'">
173
- <span class="fa fa-fw fa-lock<?php if ( ! $status->getBusy() ): ?>-open<?php endif ?>"></span>
174
- <?php echo esc_html( $status->getName() ) ?>
175
- </a>
176
- </li>
177
  <?php endforeach ?>
178
- </ul>
179
  </span>
180
- <button type="button" class="btn btn-sm btn-default bookly-margin-left-xs" data-action="show-payment" data-payment_id="{{customer.payment_id}}" ng-show="customer.payment_id || customer.payment_create" popover="<?php esc_attr_e( 'Payment', 'bookly' ) ?>: {{customer.payment_title}}" ng-disabled="customer.payment_create">
181
- <span ng-class="{'bookly-js-toggle-popover fa fa-fw': true, 'fa-clipboard-check': customer.payment_type == 'full', 'fa-hourglass': customer.payment_type == 'partial'}"></span>
182
  </button>
183
 
184
  <?php Proxy\Pro::renderAttachPaymentButton() ?>
185
 
186
- <span class="btn btn-sm btn-default disabled bookly-margin-left-xs" style="opacity:1;cursor:default;"><i class="fa fa-fw fa-user"></i>&times;{{customer.number_of_persons}}</span>
187
  <?php if ( Config::packagesActive() ) : ?>
188
- <button type="button" class="btn btn-sm btn-default bookly-margin-left-xs" ng-click="editPackageSchedule(customer)" ng-show="customer.package_id" popover="<?php esc_attr_e( 'Package schedule', 'bookly' ) ?>">
189
- <span class="fa fa-fw fa-calendar-alt"></span>
190
  </button>
191
  <?php endif ?>
192
  <?php if ( Config::recurringAppointmentsActive() ) : ?>
193
- <button type="button" class="btn btn-sm btn-default bookly-margin-left-xs" ng-click="schViewSeries(customer)" ng-show="customer.series_id" popover="<?php esc_attr_e( 'View series', 'bookly' ) ?>">
194
- <span class="fa fa-fw fa-link"></span>
195
  </button>
196
  <?php endif ?>
197
- <a ng-click="removeCustomer(customer)" class="fa fa-fw fa-trash-alt text-danger bookly-vertical-middle" href="#"
198
  popover="<?php esc_attr_e( 'Remove customer', 'bookly' ) ?>"></a>
199
  </div>
200
  </li>
@@ -205,15 +182,15 @@ use Bookly\Lib\Entities\CustomerAppointment;
205
  <div class="input-group">
206
  <select id="bookly-appointment-dialog-select2" multiple data-placeholder="<?php esc_attr_e( '-- Search customers --', 'bookly' ) ?>"
207
  class="form-control"
208
- >
209
  <option ng-repeat="customer in dataSource.data.customers" value="{{customer.id}}">{{customer.name}}</option>
210
  </select>
211
- <span class="input-group-btn">
212
- <a class="btn btn-success" ng-click="openNewCustomerDialog()">
213
- <i class="fa fa-fw fa-plus"></i>
214
  <?php esc_html_e( 'New customer', 'bookly' ) ?>
215
- </a>
216
- </span>
217
  </div>
218
  </div>
219
  </div>
@@ -231,46 +208,50 @@ use Bookly\Lib\Entities\CustomerAppointment;
231
  <div ng-hide="loading || form.screen != 'queue'" class="modal-body">
232
  <div class="form-group" ng-hide="!form.queue.all.length || !form.queue.changed_status.length">
233
  <label for="bookly-notification"><?php esc_html_e( 'Send notifications', 'bookly' ) ?></label>
234
- <p class="help-block"><?php esc_html_e( 'If you have added a new customer to this appointment or changed the appointment status for an existing customer, and for these records you want the corresponding email or SMS notifications to be sent to their recipients, select the "Send if new or status changed" option before clicking Save. You can also send notifications as if all customers were added as new by selecting "Send as for new".', 'bookly' ) ?></p>
235
- <div class="radio"><label><input type="radio" name="queue_type" value="changed_status" ng-model=form.queue_type><?php esc_html_e( 'Send if new or status changed', 'bookly' ) ?></label></div>
236
- <div class="radio"><label><input type="radio" name="queue_type" value="all" ng-model=form.queue_type><?php esc_html_e( 'Send as for new', 'bookly' ) ?></label></div>
237
  </div>
238
  <div ng-repeat="(key, value) in form.queue.all">
239
- <div class="checkbox bookly-margin-bottom-lg bookly-margin-top-remove" ng-hide="form.queue_type == 'changed_status'">
240
- <label>
241
- <input type=checkbox ng-model=value.checked ng-true-value="1" ng-false-value="0" ng-init="value.checked=1"/> <i class="fa fa-fw" ng-class="{'fa-sms':value.gateway == 'sms', 'fa-envelope':value.gateway != 'sms'}"></i> <b>{{value.data.name}}</b> ({{value.address}})<br/>
242
- {{ value.name }}
243
- </label>
 
244
  </div>
245
  </div>
246
  <div ng-repeat="(key, value) in form.queue.changed_status">
247
- <div class="checkbox bookly-margin-bottom-lg bookly-margin-top-remove" ng-hide="form.queue_type != 'changed_status'">
248
- <label>
249
- <input type=checkbox ng-model=value.checked ng-true-value="1" ng-false-value="0" ng-init="value.checked=1"/> <i class="fa fa-fw" ng-class="{'fa-sms':value.gateway == 'sms', 'fa-envelope':value.gateway != 'sms'}"></i> <b>{{value.data.name}}</b> ({{value.address}})<br/>
250
- {{ value.name }}
251
- </label>
 
252
  </div>
253
  </div>
254
  </div>
255
  <?php Proxy\RecurringAppointments::renderSchedule() ?>
256
- <div ng-hide="loading || form.screen != 'main'" class="modal-body bookly-padding-top-remove" style="margin-top: -15px;">
257
- <div class="checkbox bookly-margin-bottom-lg bookly-margin-top-remove">
258
- <label>
259
- <input type=checkbox ng-model=form.notification ng-true-value="1" ng-false-value="0" ng-init="form.notification=<?php echo get_user_meta( get_current_user_id(), 'bookly_appointment_form_send_notifications', true ) ?: 0 ?>"/><b><?php esc_html_e( 'Send notifications', 'bookly' ) ?></b>
260
- </label>
261
- </div>
 
262
  </div>
263
  <div class="modal-footer">
264
  <div ng-hide=loading>
265
  <?php Proxy\Shared::renderAppointmentDialogFooter() ?>
266
- <?php Buttons::renderSubmit( null, null, null,
267
  array(
268
  'ng-hide' => 'form.screen == \'queue\' || (form.repeat.enabled && !form.skip_date && form.screen == \'main\')',
269
  'ng-disabled' => '!form.skip_date && form.repeat.enabled && schIsScheduleEmpty() || (!form.date && !form.skip_date)',
270
  'formnovalidate' => '',
 
271
  ) ) ?>
272
- <?php Buttons::renderSubmit( null, 'bookly-js-queue-send', esc_html__( 'Send', 'bookly' ), array( 'ng-show' => 'form.screen == \'queue\'' ) ) ?>
273
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Cancel', 'bookly' ), array( 'ng-click' => 'closeDialog()', 'data-dismiss' => 'modal' ) ) ?>
274
  </div>
275
  </div>
276
  </form>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
+ use Bookly\Backend\Components\Controls\Inputs;
4
  use Bookly\Backend\Components\Dialogs;
5
  use Bookly\Backend\Components\Dialogs\Appointment\Edit\Proxy;
6
  use Bookly\Backend\Components\Dialogs\Appointment\AttachPayment\Proxy as AttachPaymentProxy;
8
  use Bookly\Lib\Config;
9
  use Bookly\Lib\Entities\CustomerAppointment;
10
  ?>
11
+ <div ng-bookly-app="appointmentDialog" ng-controller="appointmentDialogCtrl">
12
+ <div id=bookly-appointment-dialog class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
13
+ <div class="modal-dialog modal-lg">
14
  <div class="modal-content">
15
+ <form>
16
  <div class="modal-header">
17
+ <h5 class="modal-title">{{ form.screen == 'queue' ? form.titles.queue : form.title }}</h5>
18
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
19
  </div>
20
  <div ng-show=loading class="modal-body">
21
  <div class="bookly-loading"></div>
23
  <div ng-hide="loading || form.screen != 'main'" class="modal-body">
24
  <div class=form-group>
25
  <label for="bookly-provider"><?php esc_html_e( 'Provider', 'bookly' ) ?></label>
26
+ <select id="bookly-provider" class="form-control custom-select" ng-model="form.staff" ng-options="s.full_name + (form.staff_any == s ? ' (' + dataSource.l10n.staff_any + ')' : '') group by s.category for s in dataSource.data.staff | filter:filterStaff" ng-change="onStaffChange()"></select>
27
  </div>
28
 
29
  <div class=form-group>
30
  <label for="bookly-service"><?php esc_html_e( 'Service', 'bookly' ) ?></label>
31
+ <select id="bookly-service" class="form-control custom-select" ng-model="form.service"
32
  ng-options="s.title group by s.category for s in form.staff.services" ng-change="onServiceChange()">
33
  <option value=""><?php esc_html_e( '-- Select a service --', 'bookly' ) ?></option>
34
  </select>
42
  <?php if ( Config::locationsActive() ): ?>
43
  <div class="form-group">
44
  <label for="bookly-appointment-location"><?php esc_html_e( 'Location', 'bookly' ) ?></label>
45
+ <select id="bookly-appointment-location" class="form-control custom-select" ng-model="form.location"
46
  ng-options="l.name for l in form.staff.locations" ng-change="onLocationChange()">
47
  <option value=""></option>
48
  </select>
49
  </div>
50
  <?php endif ?>
51
 
52
+ <div class=form-group>
53
+ <?php Proxy\Tasks::renderSkipDate() ?>
54
+ <div ng-hide="form.skip_date">
55
+ <div class="form-row">
 
56
  <div class="col-sm-4">
57
  <label for="bookly-date"><?php esc_html_e( 'Date', 'bookly' ) ?></label>
58
+ <input date-range-picker id="bookly-date" class="form-control" type="text" ng-model="form.date" options="{parentEl:'#bookly-appointment-dialog',singleDatePicker:true,showDropdowns:true, locale:datePickerOptions}" autocomplete="off">
 
 
59
  </div>
60
  <div class="col-sm-8">
61
  <div ng-hide="form.service.duration >= 86400 && form.service.units_max == 1">
62
  <label for="bookly-period"><?php esc_html_e( 'Period', 'bookly' ) ?></label>
63
+ <div class="row">
64
+ <div class="col">
65
+ <select id="bookly-period" class="form-control custom-select" ng-model=form.start_time
66
  ng-options="t.title for t in dataSource.getDataForStartTime()"
67
  ng-change=onStartTimeChange()></select>
68
  </div>
69
+ <div class="mt-2">
70
+ <?php esc_html_e( 'to', 'bookly' ) ?>
71
  </div>
72
+ <div class="col">
73
+ <select class="form-control custom-select" ng-model=form.end_time
74
  ng-options="t.title for t in form.end_time_data"
75
  ng-change=onEndTimeChange()></select>
76
  </div>
92
  <?php esc_html_e( 'Selected period doesn\'t match service schedule', 'bookly' ) ?>
93
  </p>
94
  <p class="text-success" my-slide-up=errors.staff_reaches_working_time_limit id=staff_reaches_working_time_limit_msg>
95
+ <?php is_admin()
96
+ ? esc_html_e( 'Booking exceeds the working hours limit for staff member', 'bookly' )
97
+ : esc_html_e( 'Booking exceeds your working hours limit', 'bookly' ) ?>
98
  </p>
 
99
 
100
+ <?php Proxy\RecurringAppointments::renderSubForm() ?>
101
+ </div>
102
  </div>
 
103
  <div class=form-group>
104
+ <label for="bookly-select2"><?php esc_html_e( 'Customers', 'bookly' ) ?>
105
+ <span ng-show="form.service && form.service.id" title="<?php esc_attr_e( 'Selected / maximum', 'bookly' ) ?>">
106
  ({{dataSource.getTotalNumberOfPersons()}}/{{form.service.capacity_max}})
107
+ </span>
108
+ </label>
109
+
110
  <span ng-show="form.customers.length > 5" ng-click="form.expand_customers_list = !form.expand_customers_list" role="button">
111
+ <i class="far fa-fw" ng-class="{'fa-angle-down':!form.expand_customers_list, 'fa-angle-up':form.expand_customers_list}"></i>
112
  </span>
113
  <p class="text-success" ng-show=form.service my-slide-up="form.service.capacity_min > 1 && form.service.capacity_min > dataSource.getTotalNumberOfPersons()">
114
  <?php esc_html_e( 'Minimum capacity', 'bookly' ) ?>: {{form.service.capacity_min}}
115
  </p>
116
+ <ul class="list-unstyled pl-0 bookly-hide-empty mr-3" ng-class="{'my-0':form.customers.length == 0}">
117
+ <li class="row mb-1" ng-repeat="customer in form.customers" ng-hide="$index > 4 && !form.expand_customers_list">
118
+ <div class="col mt-1">
119
+ <a ng-click="editCustomerDetails(customer)" title="<?php esc_attr_e( 'Edit booking details', 'bookly' ) ?>" href>{{customer.name}}</a>
120
  </div>
121
+ <div class="ml-auto">
122
  <?php Proxy\Shared::renderAppointmentDialogCustomersList() ?>
123
  <span class="dropdown">
124
+ <button type="button" class="btn btn-sm btn-default dropdown-toggle" data-toggle="dropdown" popover="<?php esc_attr_e( 'Status', 'bookly' ) ?>: {{statusToString(customer.status)}}" >
125
+ <span ng-class="{'fa-fw fa-lg': true, 'far fa-clock': customer.status == 'pending', 'fas fa-check': customer.status == 'approved', 'fas fa-times': customer.status == 'cancelled', 'fas fa-ban': customer.status == 'rejected', 'fas fa-list-ol': customer.status == 'waitlisted', 'far fa-check-circle': customer.status == 'done', 'fas fa-lock': 0<?php foreach ( Lib\Proxy\CustomStatuses::prepareBusyStatuses( array() ) as $status ): ?> || customer.status == '<?php echo $status ?>'<?php endforeach ?>, 'fas fa-lock-open': 0<?php foreach ( Lib\Proxy\CustomStatuses::prepareFreeStatuses( array() ) as $status ): ?> || customer.status == '<?php echo $status ?>'<?php endforeach ?>}"></span>
 
126
  </button>
127
+ <div class="dropdown-menu">
128
+ <a href class="dropdown-item pl-3" ng-click="customer.status = 'pending'">
129
+ <span class="far fa-fw fa-clock mr-2"></span><?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_PENDING ) ) ?>
130
+ </a>
131
+ <a href class="dropdown-item pl-3" ng-click="customer.status = 'approved'">
132
+ <span class="fas fa-fw fa-check mr-2"></span><?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_APPROVED ) ) ?>
133
+ </a>
134
+ <a href class="dropdown-item pl-3" ng-click="customer.status = 'cancelled'">
135
+ <span class="fas fa-fw fa-times mr-2"></span><?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_CANCELLED ) ) ?>
136
+ </a>
137
+ <a href class="dropdown-item pl-3" ng-click="customer.status = 'rejected'">
138
+ <span class="fas fa-fw fa-ban mr-2"></span><?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_REJECTED ) ) ?>
139
+ </a>
140
+ <?php if ( Config::waitingListActive() ) : ?>
141
+ <a href class="dropdown-item pl-3" ng-click="customer.status = 'waitlisted'">
142
+ <span class="fas fa-fw fa-list-ol mr-2"></span><?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_WAITLISTED ) ) ?>
 
 
 
 
 
 
 
143
  </a>
 
 
 
 
 
 
 
 
144
  <?php endif ?>
145
+ <?php if ( Config::tasksActive() ) : ?>
146
+ <a href class="dropdown-item pl-3" ng-click="customer.status = 'done'">
147
+ <span class="far fa-fw fa-check-circle mr-2"></span><?php echo esc_html( CustomerAppointment::statusToString( CustomerAppointment::STATUS_DONE ) ) ?>
148
+ </a>
 
 
 
149
  <?php endif ?>
150
+ <?php foreach ( (array) Lib\Proxy\CustomStatuses::getAll() as $status ) : ?>
151
+ <a href class="dropdown-item pl-3" ng-click="customer.status = '<?php echo $status->getSlug() ?>'">
152
+ <span class="fas fa-fw fa-lock<?php if ( ! $status->getBusy() ): ?>-open<?php endif ?> mr-2"></span><?php echo esc_html( $status->getName() ) ?>
153
+ </a>
 
 
 
154
  <?php endforeach ?>
155
+ </div>
156
  </span>
157
+ <button type="button" class="btn btn-sm btn-default" data-action="show-payment" data-payment_id="{{customer.payment_id}}" ng-show="customer.payment_id || customer.payment_create" popover="<?php esc_attr_e( 'Payment', 'bookly' ) ?>: {{customer.payment_title}}" ng-disabled="customer.payment_create">
158
+ <span ng-class="{'bookly-js-toggle-popover fas fa-fw fa-lg': true, 'fa-file-invoice-dollar': customer.payment_type == 'full', 'fa-hourglass': customer.payment_type == 'partial'}"></span>
159
  </button>
160
 
161
  <?php Proxy\Pro::renderAttachPaymentButton() ?>
162
 
163
+ <span class="btn btn-sm btn-default disabled" style="opacity:1;cursor:default;"><i class="far fa-lg fa-fw fa-user"></i>&times;{{customer.number_of_persons}}</span>
164
  <?php if ( Config::packagesActive() ) : ?>
165
+ <button type="button" class="btn btn-sm btn-default" ng-click="editPackageSchedule(customer)" ng-show="customer.package_id" popover="<?php esc_attr_e( 'Package schedule', 'bookly' ) ?>">
166
+ <span class="far fa-lg fa-fw fa-calendar-alt"></span>
167
  </button>
168
  <?php endif ?>
169
  <?php if ( Config::recurringAppointmentsActive() ) : ?>
170
+ <button type="button" class="btn btn-sm btn-default" ng-click="schViewSeries(customer)" ng-show="customer.series_id" popover="<?php esc_attr_e( 'View series', 'bookly' ) ?>">
171
+ <span class="fas fa-fw fa-link"></span>
172
  </button>
173
  <?php endif ?>
174
+ <a ng-click="removeCustomer(customer)" class="far fa-fw fa-trash-alt text-danger" href="#"
175
  popover="<?php esc_attr_e( 'Remove customer', 'bookly' ) ?>"></a>
176
  </div>
177
  </li>
182
  <div class="input-group">
183
  <select id="bookly-appointment-dialog-select2" multiple data-placeholder="<?php esc_attr_e( '-- Search customers --', 'bookly' ) ?>"
184
  class="form-control"
185
+ >
186
  <option ng-repeat="customer in dataSource.data.customers" value="{{customer.id}}">{{customer.name}}</option>
187
  </select>
188
+ <div class="input-group-append">
189
+ <button class="btn btn-success" type="button" ng-click="openNewCustomerDialog()">
190
+ <i class="fas fa-fw fa-plus"></i>
191
  <?php esc_html_e( 'New customer', 'bookly' ) ?>
192
+ </button>
193
+ </div>
194
  </div>
195
  </div>
196
  </div>
208
  <div ng-hide="loading || form.screen != 'queue'" class="modal-body">
209
  <div class="form-group" ng-hide="!form.queue.all.length || !form.queue.changed_status.length">
210
  <label for="bookly-notification"><?php esc_html_e( 'Send notifications', 'bookly' ) ?></label>
211
+ <?php Inputs::renderRadio( __( 'Send if new or status changed', 'bookly' ), 'changed_status', null, array( 'name' => 'queue_type', 'ng-model' => 'form.queue_type' ) ) ?>
212
+ <?php Inputs::renderRadio( __( 'Send as for new', 'bookly' ), 'all', null, array( 'name' => 'queue_type', 'ng-model' => 'form.queue_type' ) ) ?>
213
+ <small class="help-block"><?php esc_html_e( 'If you have added a new customer to this appointment or changed the appointment status for an existing customer, and for these records you want the corresponding email or SMS notifications to be sent to their recipients, select the "Send if new or status changed" option before clicking Save. You can also send notifications as if all customers were added as new by selecting "Send as for new".', 'bookly' ) ?></small>
214
  </div>
215
  <div ng-repeat="(key, value) in form.queue.all">
216
+ <div ng-hide="form.queue_type == 'changed_status'">
217
+ <div class="custom-control custom-checkbox">
218
+ <input class="custom-control-input" id="bookly-ch-all-{{key}}" type="checkbox" ng-model=value.checked ng-true-value="1" ng-false-value="0" ng-init="value.checked=1">
219
+ <label class="custom-control-label" for="bookly-ch-all-{{key}}"><i class="fa-fw" ng-class="{'fas fa-sms':value.gateway == 'sms', 'far fa-envelope':value.gateway != 'sms'}"></i> <b>{{value.data.name}}</b> ({{value.address}})<br/>
220
+ {{ value.name }}</label>
221
+ </div>
222
  </div>
223
  </div>
224
  <div ng-repeat="(key, value) in form.queue.changed_status">
225
+ <div ng-hide="form.queue_type != 'changed_status'">
226
+ <div class="custom-control custom-checkbox">
227
+ <input class="custom-control-input" id="bookly-ch-sc-{{key}}" type="checkbox" ng-model=value.checked ng-true-value="1" ng-false-value="0" ng-init="value.checked=1"/>
228
+ <label class="custom-control-label" for="bookly-ch-sc-{{key}}"><i class="fa-fw" ng-class="{'fas fa-sms':value.gateway == 'sms', 'far fa-envelope':value.gateway != 'sms'}"></i> <b>{{value.data.name}}</b> ({{value.address}})<br/>
229
+ {{ value.name }}</label>
230
+ </div>
231
  </div>
232
  </div>
233
  </div>
234
  <?php Proxy\RecurringAppointments::renderSchedule() ?>
235
+ <div ng-hide="loading || form.screen != 'main'" class="modal-body" style="margin-top: -30px;">
236
+ <?php Inputs::renderCheckBox( __( 'Send notifications', 'bookly' ), null, null, array(
237
+ 'ng-model' => 'form.notification',
238
+ 'ng-true-value' => '1',
239
+ 'ng-false-value' => '0',
240
+ 'ng-init' => 'form.notification=' . ( get_user_meta( get_current_user_id(), 'bookly_appointment_form_send_notifications', true ) ?: 0 ) )
241
+ ) ?>
242
  </div>
243
  <div class="modal-footer">
244
  <div ng-hide=loading>
245
  <?php Proxy\Shared::renderAppointmentDialogFooter() ?>
246
+ <?php Buttons::render( null, 'btn-success', __( 'Save', 'bookly' ),
247
  array(
248
  'ng-hide' => 'form.screen == \'queue\' || (form.repeat.enabled && !form.skip_date && form.screen == \'main\')',
249
  'ng-disabled' => '!form.skip_date && form.repeat.enabled && schIsScheduleEmpty() || (!form.date && !form.skip_date)',
250
  'formnovalidate' => '',
251
+ 'ng-click' => 'processForm()',
252
  ) ) ?>
253
+ <?php Buttons::render( null, 'bookly-js-queue-send btn-success', __( 'Send', 'bookly' ), array( 'ng-show' => 'form.screen == \'queue\'', 'ng-click' => 'processForm()' ) ) ?>
254
+ <?php Buttons::renderCancel( null, array( 'ng-click' => 'closeDialog()' ) ) ?>
255
  </div>
256
  </div>
257
  </form>
backend/components/dialogs/common/templates/delete_cascade.php CHANGED
@@ -1,20 +1,20 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
- <div class="modal fade bookly-js-delete-cascade-confirm" tabindex="-1" role="dialog">
5
  <div class="modal-dialog modal-lg" role="document">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
9
- <div class="modal-title h4"><?php _e( 'Are you sure?', 'bookly' ) ?></div>
10
  </div>
11
  <div class="modal-body">
12
- <p><?php _e( 'You are going to delete item which is involved in upcoming appointments. All related appointments will be deleted. Please double check and edit appointments before this item deletion if needed.', 'bookly' ) ?></p>
13
  </div>
14
  <div class="modal-footer">
15
- <?php Buttons::renderCustom( null, 'btn-lg btn-danger bookly-js-delete', __( 'Delete', 'bookly' ) ) ?>
16
- <?php Buttons::renderCustom( null, 'btn-lg btn-success bookly-js-edit', __( 'Edit appointments', 'bookly' ) ) ?>
17
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', __( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
18
  </div>
19
  </div>
20
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
+ <div class="bookly-modal bookly-fade bookly-js-delete-cascade-confirm" tabindex="-1" role="dialog">
5
  <div class="modal-dialog modal-lg" role="document">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
+ <h5 class="modal-title"><?php esc_html_e( 'Are you sure?', 'bookly' ) ?></h5>
9
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
10
  </div>
11
  <div class="modal-body">
12
+ <p><?php esc_html_e( 'You are going to delete item which is involved in upcoming appointments. All related appointments will be deleted. Please double check and edit appointments before this item deletion if needed.', 'bookly' ) ?></p>
13
  </div>
14
  <div class="modal-footer">
15
+ <?php Buttons::render( null, 'btn-danger bookly-js-delete', __( 'Delete', 'bookly' ) ) ?>
16
+ <?php Buttons::render( null, 'btn-success bookly-js-edit', __( 'Edit appointments', 'bookly' ) ) ?>
17
+ <?php Buttons::renderCancel() ?>
18
  </div>
19
  </div>
20
  </div>
backend/components/dialogs/common/templates/unsaved_changes.php CHANGED
@@ -1,20 +1,20 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
- <div class="modal fade bookly-js-unsaved-changes" tabindex="-1" role="dialog">
5
  <div class="modal-dialog modal-lg" role="document">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
9
- <div class="modal-title h4"><?php _e( 'Are you sure?', 'bookly' ) ?></div>
10
  </div>
11
  <div class="modal-body">
12
- <p><?php _e( 'All unsaved changes will be lost.', 'bookly' ) ?></p>
13
  </div>
14
  <div class="modal-footer">
15
- <?php Buttons::renderCustom( null, 'btn-lg btn-success bookly-js-save-changes', __( 'Save', 'bookly' ) ) ?>
16
- <?php Buttons::renderCustom( null, 'btn-lg btn-danger bookly-js-ignore-changes', __( 'Don\'t save', 'bookly' ) ) ?>
17
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', __( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
18
  </div>
19
  </div>
20
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
+ <div class="bookly-modal bookly-fade bookly-js-unsaved-changes" tabindex="-1" role="dialog">
5
  <div class="modal-dialog modal-lg" role="document">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
+ <div class="modal-title h5"><?php esc_html_e( 'Are you sure?', 'bookly' ) ?></div>
9
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
10
  </div>
11
  <div class="modal-body">
12
+ <p><?php esc_html_e( 'All unsaved changes will be lost.', 'bookly' ) ?></p>
13
  </div>
14
  <div class="modal-footer">
15
+ <?php Buttons::renderSubmit( null, 'bookly-js-save-changes' ) ?>
16
+ <?php Buttons::render( null, 'btn-danger bookly-js-ignore-changes', __( 'Don\'t save', 'bookly' ) ) ?>
17
+ <?php Buttons::renderCancel() ?>
18
  </div>
19
  </div>
20
  </div>
backend/components/dialogs/customer/delete/resources/js/delete-customers.js CHANGED
@@ -1,13 +1,14 @@
1
  jQuery(function ($) {
 
2
 
3
- var
4
  $customersList = $('#bookly-customers-list'),
5
  $initDeletingButton = $('#bookly-delete'),
6
  $deleteDialog = $('#bookly-delete-dialog'),
7
  $deleteButton = $('.bookly-js-delete', $deleteDialog),
8
- $rememberCheckbox = $('.bookly-js-remember-choice-checkbox', $deleteDialog),
9
- $deleteEventsCheckbox = $('.bookly-js-delete-with-events-checkbox', $deleteDialog),
10
- $deleteWPUserCheckbox = $('.bookly-js-delete-with-wp-user-checkbox', $deleteDialog)
11
  ;
12
 
13
  /**
@@ -43,7 +44,7 @@ jQuery(function ($) {
43
  $deleteEventsCheckbox.prop('checked', response.data.with_events);
44
  $deleteWPUserCheckbox.prop('checked', response.data.with_wp_users);
45
  $rememberCheckbox.prop('checked', response.data.remember);
46
- $deleteDialog.modal('show');
47
  }
48
  });
49
  } else {
@@ -82,7 +83,7 @@ jQuery(function ($) {
82
  dataType: 'json',
83
  success : function (response) {
84
  ladda.stop();
85
- $deleteDialog.modal('hide');
86
  if (response.success) {
87
  $customersList.DataTable().ajax.reload(null, false);
88
  } else {
1
  jQuery(function ($) {
2
+ 'use strict';
3
 
4
+ let
5
  $customersList = $('#bookly-customers-list'),
6
  $initDeletingButton = $('#bookly-delete'),
7
  $deleteDialog = $('#bookly-delete-dialog'),
8
  $deleteButton = $('.bookly-js-delete', $deleteDialog),
9
+ $rememberCheckbox = $('#bookly-js-remember-choice-checkbox', $deleteDialog),
10
+ $deleteEventsCheckbox = $('#bookly-js-delete-with-events-checkbox', $deleteDialog),
11
+ $deleteWPUserCheckbox = $('#bookly-js-delete-with-wp-user-checkbox', $deleteDialog)
12
  ;
13
 
14
  /**
44
  $deleteEventsCheckbox.prop('checked', response.data.with_events);
45
  $deleteWPUserCheckbox.prop('checked', response.data.with_wp_users);
46
  $rememberCheckbox.prop('checked', response.data.remember);
47
+ $deleteDialog.booklyModal('show');
48
  }
49
  });
50
  } else {
83
  dataType: 'json',
84
  success : function (response) {
85
  ladda.stop();
86
+ $deleteDialog.booklyModal('hide');
87
  if (response.success) {
88
  $customersList.DataTable().ajax.reload(null, false);
89
  } else {
backend/components/dialogs/customer/delete/templates/dialog.php CHANGED
@@ -1,41 +1,29 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
 
 
3
  ?>
4
- <form id="bookly-delete-dialog" class="modal fade" tabindex=-1>
5
  <div class="modal-dialog">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
- <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
9
- <div class="modal-title h2"><?php esc_html_e( 'Delete customers', 'bookly' ) ?></div>
10
  </div>
11
  <div class="modal-body">
12
  <p class="bookly-js-delete-with-events"><?php esc_html_e( 'You are going to delete customers with existing bookings. Notifications will not be sent to them.', 'bookly' ) ?></p>
13
  <p class="bookly-js-delete-without-events"><?php esc_html_e( 'You are going to delete customers, are you sure?', 'bookly' ) ?></p>
14
- <div class="bookly-js-delete-with-events bookly-margin-bottom-sm collapse">
15
- <div class="checkbox">
16
- <label>
17
- <input class="bookly-js-delete-with-events-checkbox" type="checkbox"/><?php esc_html_e( 'Delete customers with existing bookings', 'bookly' ) ?>
18
- </label>
19
- </div>
20
  </div>
21
  <div>
22
- <div class="checkbox">
23
- <label>
24
- <input class="bookly-js-delete-with-wp-user-checkbox" type="checkbox"/><?php esc_html_e( 'Delete customers\' WordPress accounts if there are any', 'bookly' ) ?>
25
- </label>
26
- </div>
27
- </div>
28
- <div>
29
- <div class="checkbox">
30
- <label>
31
- <input class="bookly-js-remember-choice-checkbox" type="checkbox"/><?php esc_html_e( 'Remember my choice', 'bookly' ) ?>
32
- </label>
33
- </div>
34
  </div>
35
  </div>
36
  <div class="modal-footer">
37
- <?php Buttons::renderCustom( null, 'btn-danger ladda-button bookly-js-delete btn-lg', esc_html__( 'Delete', 'bookly' ) ) ?>
38
- <?php Buttons::renderCustom( null, 'btn-default btn-lg', esc_html__( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
39
  </div>
40
  </div>
41
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
+ use Bookly\Backend\Components\Controls\Inputs;
4
+
5
  ?>
6
+ <form id="bookly-delete-dialog" class="bookly-modal bookly-fade" tabindex=-1>
7
  <div class="modal-dialog">
8
  <div class="modal-content">
9
  <div class="modal-header">
10
+ <h5 class="modal-title"><?php esc_html_e( 'Delete customers', 'bookly' ) ?></h5>
11
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
12
  </div>
13
  <div class="modal-body">
14
  <p class="bookly-js-delete-with-events"><?php esc_html_e( 'You are going to delete customers with existing bookings. Notifications will not be sent to them.', 'bookly' ) ?></p>
15
  <p class="bookly-js-delete-without-events"><?php esc_html_e( 'You are going to delete customers, are you sure?', 'bookly' ) ?></p>
16
+ <div class="bookly-js-delete-with-events collapse">
17
+ <?php Inputs::renderCheckBox( __( 'Delete customers with existing bookings', 'bookly' ), null, null, array( 'id' => 'bookly-js-delete-with-events-checkbox' ) ) ?>
 
 
 
 
18
  </div>
19
  <div>
20
+ <?php Inputs::renderCheckBox( __( 'Delete customers\' WordPress accounts if there are any', 'bookly' ), null, null, array( 'id' => 'bookly-js-delete-with-wp-user-checkbox' ) ) ?>
21
+ <?php Inputs::renderCheckBox( __( 'Remember my choice', 'bookly' ), null, null, array( 'id' => 'bookly-js-remember-choice-checkbox' ) ) ?>
 
 
 
 
 
 
 
 
 
 
22
  </div>
23
  </div>
24
  <div class="modal-footer">
25
+ <?php Buttons::renderDelete( null, 'bookly-js-delete', null, array(), false ) ?>
26
+ <?php Buttons::renderCancel() ?>
27
  </div>
28
  </div>
29
  </div>
backend/components/dialogs/customer/edit/Dialog.php CHANGED
@@ -15,25 +15,26 @@ class Dialog extends Lib\Base\Component
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
- 'backend' => array( 'css/jquery-ui-theme/jquery-ui.min.css', 'css/select2.min.css', ),
19
  'frontend' => get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
20
  ? array()
21
  : array( 'css/intlTelInput.css' ),
22
  ) );
23
 
24
  self::enqueueScripts( array(
25
- 'backend' => array(
26
- 'js/angular.min.js' => array( 'jquery' ),
27
- 'js/select2.full.min.js' => array( 'jquery' ),
28
- 'js/angular-ui-date-0.0.8.js' => array( 'bookly-angular.min.js', 'jquery-ui-datepicker' ),
29
- ),
 
 
30
  'frontend' => get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
31
  ? array()
32
  : array( 'js/intlTelInput.min.js' => array( 'jquery' ) ),
33
- 'module' => array( 'js/ng-customer.js' => array( 'bookly-angular.min.js' ), )
34
  ) );
35
 
36
- wp_add_inline_script( 'bookly-select2.full.min.js', 'delete jQuery.fn.select2;', 'before' );
37
 
38
  wp_localize_script( 'bookly-ng-customer.js', 'BooklyL10nCustDialog', array(
39
  'csrf_token' => Lib\Utils\Common::getCsrfToken(),
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
 
18
  'frontend' => get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
19
  ? array()
20
  : array( 'css/intlTelInput.css' ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
24
+ 'backend' => array(
25
+ 'js/angular.min.js' => array( 'jquery' ),
26
+ 'js/moment.min.js' => array( 'jquery' ),
27
+ 'js/select2.min.js' => array( 'jquery' ),
28
+ 'js/daterangepicker.js' => array( 'jquery' ),
29
+ 'js/angular-daterangepicker.js' => array( 'bookly-angular.min.js', 'bookly-daterangepicker.js' ),
30
+ ),
31
  'frontend' => get_option( 'bookly_cst_phone_default_country' ) == 'disabled'
32
  ? array()
33
  : array( 'js/intlTelInput.min.js' => array( 'jquery' ) ),
34
+ 'module' => array( 'js/ng-customer.js' => array( 'bookly-angular.min.js' ), ),
35
  ) );
36
 
37
+ wp_add_inline_script( 'bookly-select2.min.js', 'delete jQuery.fn.select2;', 'before' );
38
 
39
  wp_localize_script( 'bookly-ng-customer.js', 'BooklyL10nCustDialog', array(
40
  'csrf_token' => Lib\Utils\Common::getCsrfToken(),
backend/components/dialogs/customer/edit/resources/js/ng-customer.js CHANGED
@@ -1,6 +1,6 @@
1
  ;(function() {
2
 
3
- angular.module('customerDialog', ['ui.date']).directive('customerDialog', function() {
4
  return {
5
  restrict : 'A',
6
  replace : true,
@@ -70,17 +70,12 @@
70
 
71
  // Do customer on modal hide.
72
  element
73
- .on('hidden.bs.modal', function () {
74
- // Fix scroll issues when another modal is shown.
75
- if (jQuery('.modal-backdrop').length) {
76
- jQuery('body').addClass('modal-open');
77
- }
78
- })
79
  .one('shown.bs.modal', () => {
80
  jQuery('#wp_user')
81
  .select2({
82
  width: '100%',
83
- theme: 'bootstrap',
 
84
  allowClear: true,
85
  placeholder: '',
86
  dropdownParent: jQuery('#bookly-customer-dialog'),
@@ -134,6 +129,9 @@
134
  scope.form.phone = BooklyL10nCustDialog.intlTelInput.enabled
135
  ? element.find('#phone').intlTelInput('getNumber')
136
  : element.find('#phone').val();
 
 
 
137
  jQuery.ajax({
138
  url : ajaxurl,
139
  type : 'POST',
@@ -168,7 +166,7 @@
168
  birthday : ''
169
  };
170
  // Close the dialog.
171
- element.modal('hide');
172
 
173
  // Add new customer to select2 filter
174
  let $customersFilter = jQuery('#bookly-filter-customer');
@@ -206,15 +204,7 @@
206
  /**
207
  * Datepicker options.
208
  */
209
- scope.datePickerOptions = jQuery.extend({
210
- beforeShow: function (input, inst) {
211
- jQuery(document).off('focusin.bs.modal');
212
- },
213
- onClose: function () {
214
- jQuery(document).on('focusin.bs.modal');
215
- },
216
- },
217
- BooklyL10nCustDialog.datePicker);
218
 
219
  /**
220
  * Toggle checkbox info field.
1
  ;(function() {
2
 
3
+ booklyAngular.module('customerDialog', ['daterangepicker']).directive('customerDialog', function() {
4
  return {
5
  restrict : 'A',
6
  replace : true,
70
 
71
  // Do customer on modal hide.
72
  element
 
 
 
 
 
 
73
  .one('shown.bs.modal', () => {
74
  jQuery('#wp_user')
75
  .select2({
76
  width: '100%',
77
+ theme: 'bootstrap4',
78
+ dropdownParent: '#bookly-tbs',
79
  allowClear: true,
80
  placeholder: '',
81
  dropdownParent: jQuery('#bookly-customer-dialog'),
129
  scope.form.phone = BooklyL10nCustDialog.intlTelInput.enabled
130
  ? element.find('#phone').intlTelInput('getNumber')
131
  : element.find('#phone').val();
132
+ scope.form.birthday = moment.isMoment(scope.form.birthday)
133
+ ? scope.form.birthday.format('YYYY-MM-DD')
134
+ : scope.form.birthday;
135
  jQuery.ajax({
136
  url : ajaxurl,
137
  type : 'POST',
166
  birthday : ''
167
  };
168
  // Close the dialog.
169
+ element.booklyModal('hide');
170
 
171
  // Add new customer to select2 filter
172
  let $customersFilter = jQuery('#bookly-filter-customer');
204
  /**
205
  * Datepicker options.
206
  */
207
+ scope.datePickerOptions = BooklyL10nCustDialog.datePicker;
 
 
 
 
 
 
 
 
208
 
209
  /**
210
  * Toggle checkbox info field.
backend/components/dialogs/customer/edit/templates/edit.php CHANGED
@@ -4,12 +4,12 @@ use Bookly\Backend\Components\Dialogs\Customer\Edit\Proxy;
4
  use Bookly\Lib\Config;
5
  ?>
6
  <script type="text/ng-template" id="bookly-customer-dialog.tpl">
7
- <div id="bookly-customer-dialog" class="modal fade" tabindex=-1 role="dialog">
8
  <div class="modal-dialog">
9
  <div class="modal-content">
10
  <div class="modal-header">
11
- <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
12
- <div class="modal-title h2"><?php esc_html_e( 'New Customer', 'bookly' ) ?></div>
13
  </div>
14
  <div ng-show=loading class="modal-body">
15
  <div class="bookly-loading"></div>
@@ -17,7 +17,7 @@ use Bookly\Lib\Config;
17
  <div class="modal-body" ng-hide="loading">
18
  <div class="form-group">
19
  <label for="wp_user"><?php esc_html_e( 'User', 'bookly' ) ?></label>
20
- <select ng-model="form.wp_user_id" class="form-control" id="wp_user" ng-change="changeWpUser()">
21
  <?php foreach ( get_users( array( 'fields' => array( 'ID', 'display_name', 'user_email' ), 'orderby' => 'display_name' ) ) as $wp_user ) : ?>
22
  <?php $user_data = get_userdata( $wp_user->ID ) ?>
23
  <option value="<?php echo $wp_user->ID ?>" data-email="<?php echo esc_html( $wp_user->user_email ) ?>" data-first-name="<?php echo esc_html( $user_data->first_name ) ?>" data-last-name="<?php echo esc_html( $user_data->last_name ) ?>" data-phone="<?php echo esc_html( get_user_meta( $wp_user->ID, 'billing_phone', true ) ) ?>">
@@ -73,8 +73,8 @@ use Bookly\Lib\Config;
73
  </div>
74
  <div class="modal-footer">
75
  <div ng-hide=loading>
76
- <?php Buttons::renderCustom( null, 'btn-success btn-lg', null, array( 'ng-click' => 'processForm()' ) ) ?>
77
- <?php Buttons::renderCustom( null, 'btn-default btn-lg', esc_html__( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
78
  </div>
79
  </div>
80
  </div>
4
  use Bookly\Lib\Config;
5
  ?>
6
  <script type="text/ng-template" id="bookly-customer-dialog.tpl">
7
+ <div id="bookly-customer-dialog" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
8
  <div class="modal-dialog">
9
  <div class="modal-content">
10
  <div class="modal-header">
11
+ <h5 class="modal-title"><?php esc_html_e( 'New Customer', 'bookly' ) ?></h5>
12
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-hidden="true" aria-label="Close">&times;</button>
13
  </div>
14
  <div ng-show=loading class="modal-body">
15
  <div class="bookly-loading"></div>
17
  <div class="modal-body" ng-hide="loading">
18
  <div class="form-group">
19
  <label for="wp_user"><?php esc_html_e( 'User', 'bookly' ) ?></label>
20
+ <select ng-model="form.wp_user_id" class="form-control custom-select" id="wp_user" ng-change="changeWpUser()">
21
  <?php foreach ( get_users( array( 'fields' => array( 'ID', 'display_name', 'user_email' ), 'orderby' => 'display_name' ) ) as $wp_user ) : ?>
22
  <?php $user_data = get_userdata( $wp_user->ID ) ?>
23
  <option value="<?php echo $wp_user->ID ?>" data-email="<?php echo esc_html( $wp_user->user_email ) ?>" data-first-name="<?php echo esc_html( $user_data->first_name ) ?>" data-last-name="<?php echo esc_html( $user_data->last_name ) ?>" data-phone="<?php echo esc_html( get_user_meta( $wp_user->ID, 'billing_phone', true ) ) ?>">
73
  </div>
74
  <div class="modal-footer">
75
  <div ng-hide=loading>
76
+ <?php Buttons::renderSubmit( null, null, null, array( 'ng-click' => 'processForm()' ) ) ?>
77
+ <?php Buttons::renderCancel() ?>
78
  </div>
79
  </div>
80
  </div>
backend/components/dialogs/notifications/Dialog.php CHANGED
@@ -17,7 +17,7 @@ class Dialog extends SmsDialog
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
@@ -25,7 +25,7 @@ class Dialog extends SmsDialog
25
  'js/spin.min.js' => array( 'jquery', ),
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
- 'backend' => array( 'js/select2.full.min.js' => array( 'jquery' ), ),
29
  'bookly' => array( 'backend/components/dialogs/sms/resources/js/notification-dialog.js' => array( 'jquery' ), ),
30
  ) );
31
 
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
25
  'js/spin.min.js' => array( 'jquery', ),
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
+ 'backend' => array( 'js/select2.min.js' => array( 'jquery' ), ),
29
  'bookly' => array( 'backend/components/dialogs/sms/resources/js/notification-dialog.js' => array( 'jquery' ), ),
30
  ) );
31
 
backend/components/dialogs/notifications/templates/_attach.php CHANGED
@@ -1,13 +1,11 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
2
  use Bookly\Backend\Modules\Notifications\Proxy;
3
  ?>
4
- <div class="bookly-js-attach-container">
5
- <div class="form-group bookly-js-attach bookly-js-ics">
6
  <input type="hidden" name="notification[attach_ics]" value="0">
7
- <div class="checkbox"><label for="notification_attach_ics">
8
- <input id="notification_attach_ics" name="notification[attach_ics]" type="checkbox" value="1"/> <?php esc_attr_e( 'Attach ICS file', 'bookly' ) ?>
9
- </label>
10
- </div>
11
  </div>
12
  <?php Proxy\Invoices::renderAttach() ?>
13
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ use Bookly\Backend\Components\Controls\Inputs;
3
  use Bookly\Backend\Modules\Notifications\Proxy;
4
  ?>
5
+ <div class="form-group bookly-js-attach-container">
6
+ <div class="bookly-js-attach bookly-js-ics">
7
  <input type="hidden" name="notification[attach_ics]" value="0">
8
+ <?php Inputs::renderCheckBox( __( 'Attach ICS file', 'bookly' ), 1, null, array( 'name' => 'notification[attach_ics]' ) ) ?>
 
 
 
9
  </div>
10
  <?php Proxy\Invoices::renderAttach() ?>
11
  </div>
backend/components/dialogs/notifications/templates/_codes.php CHANGED
@@ -4,7 +4,7 @@ $codes = new \Bookly\Backend\Modules\Notifications\Lib\Codes( 'email' )
4
  ?>
5
  <div class="form-group bookly-js-codes-container">
6
  <label><?php esc_attr_e( 'Codes', 'bookly' ) ?></label>
7
- <div class="bookly-max-height-md">
8
  <?php foreach ( Notification::getTypes() as $notification_type ) :
9
  if ( in_array( $notification_type, array(
10
  Notification::TYPE_NEW_BOOKING_RECURRING,
4
  ?>
5
  <div class="form-group bookly-js-codes-container">
6
  <label><?php esc_attr_e( 'Codes', 'bookly' ) ?></label>
7
+ <div>
8
  <?php foreach ( Notification::getTypes() as $notification_type ) :
9
  if ( in_array( $notification_type, array(
10
  Notification::TYPE_NEW_BOOKING_RECURRING,
backend/components/dialogs/notifications/templates/_editor.php CHANGED
@@ -8,6 +8,7 @@
8
  'media_buttons' => false,
9
  'editor_height' => 250,
10
  'default_editor' => 'tinymce',
 
11
  'tinymce' => array(
12
  'resize' => true,
13
  'wp_autoresize_on' => true,
8
  'media_buttons' => false,
9
  'editor_height' => 250,
10
  'default_editor' => 'tinymce',
11
+ 'editor_css' => '<style>.wp-editor-tools{margin-top:-27px;}.wp-editor-tools [type="button"]{box-sizing:content-box!important;}</style>',
12
  'tinymce' => array(
13
  'resize' => true,
14
  'wp_autoresize_on' => true,
backend/components/dialogs/notifications/templates/_subject.php CHANGED
@@ -1,9 +1,9 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
- <div class="row">
3
  <div class="col-md-12">
4
  <div class="form-group">
5
  <label for="notification_subject"><?php esc_attr_e( 'Subject', 'bookly' ) ?></label>
6
- <input type="text" class="form-control" id="notification_subject" name="notification[subject]" value=""/>
7
  <input type="hidden" name="notification[gateway]" value="email"/>
8
  </div>
9
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
+ <div class="row mt-3">
3
  <div class="col-md-12">
4
  <div class="form-group">
5
  <label for="notification_subject"><?php esc_attr_e( 'Subject', 'bookly' ) ?></label>
6
+ <input type="text" class="form-control" id="notification_subject" name="notification[subject]">
7
  <input type="hidden" name="notification[gateway]" value="email"/>
8
  </div>
9
  </div>
backend/components/dialogs/notifications/templates/_types.php CHANGED
@@ -6,8 +6,7 @@ use Bookly\Lib\Config;
6
  <div class="col-md-12">
7
  <div class="form-group">
8
  <label for="notification_type"><?php esc_attr_e( 'Type', 'bookly' ) ?></label>
9
- <p class="help-block"><?php esc_html_e( 'Select the type of event at which the notification is sent.', 'bookly' ) ?></p>
10
- <select class="form-control" name="notification[type]" id="notification_type">
11
  <optgroup label="<?php esc_attr_e( 'Instant notifications', 'bookly' ) ?>">
12
  <option value="<?php echo Notification::TYPE_NEW_BOOKING ?>"
13
  data-set="instantly"
@@ -94,7 +93,8 @@ use Bookly\Lib\Config;
94
  </optgroup>
95
  <?php endif ?>
96
  </select>
97
- <p class="help-block bookly-js-help-block bookly-margin-top-xs <?php echo Notification::TYPE_NEW_BOOKING_COMBINED ?>"><?php esc_html_e( 'This notification is sent once for a booking made by a customer and includes all cart items.', 'bookly' ) ?></p>
 
98
  </div>
99
  </div>
100
  </div>
6
  <div class="col-md-12">
7
  <div class="form-group">
8
  <label for="notification_type"><?php esc_attr_e( 'Type', 'bookly' ) ?></label>
9
+ <select class="form-control custom-select" name="notification[type]" id="notification_type">
 
10
  <optgroup label="<?php esc_attr_e( 'Instant notifications', 'bookly' ) ?>">
11
  <option value="<?php echo Notification::TYPE_NEW_BOOKING ?>"
12
  data-set="instantly"
93
  </optgroup>
94
  <?php endif ?>
95
  </select>
96
+ <small class="text-muted"><?php esc_html_e( 'Select the type of event at which the notification is sent.', 'bookly' ) ?></small>
97
+ <small class="text-muted bookly-js-help-block <?php echo Notification::TYPE_NEW_BOOKING_COMBINED ?>"><?php esc_html_e( 'This notification is sent once for a booking made by a customer and includes all cart items.', 'bookly' ) ?></small>
98
  </div>
99
  </div>
100
  </div>
backend/components/dialogs/payment/resources/js/ng-payment_details.js CHANGED
@@ -1,6 +1,6 @@
1
  ;(function() {
2
 
3
- angular.module('paymentDetailsDialog', []).directive('paymentDetailsDialog', function() {
4
  return {
5
  restrict: 'A',
6
  replace: true,
@@ -94,7 +94,7 @@
94
  }
95
  }
96
  });
97
- jQuery(element).modal('hide');
98
  });
99
  var $adjust_button = jQuery('#bookly-js-adjustment-button', $body),
100
  $adjust_field = jQuery('#bookly-js-adjustment-field', $body),
@@ -144,9 +144,6 @@
144
  })
145
  .on('hidden.bs.modal', function () {
146
  $body.html(spinner);
147
- if ((jQuery("#bookly-appointment-dialog").data('bs.modal') || {isShown: false}).isShown) {
148
- jQuery('body').addClass('modal-open');
149
- }
150
  });
151
  }
152
  }
1
  ;(function() {
2
 
3
+ booklyAngular.module('paymentDetailsDialog', []).directive('paymentDetailsDialog', function() {
4
  return {
5
  restrict: 'A',
6
  replace: true,
94
  }
95
  }
96
  });
97
+ jQuery(element).booklyModal('hide');
98
  });
99
  var $adjust_button = jQuery('#bookly-js-adjustment-button', $body),
100
  $adjust_field = jQuery('#bookly-js-adjustment-field', $body),
144
  })
145
  .on('hidden.bs.modal', function () {
146
  $body.html(spinner);
 
 
 
147
  });
148
  }
149
  }
backend/components/dialogs/payment/templates/details.php CHANGED
@@ -36,7 +36,7 @@ if ( ! $can_edit ) {
36
  </table>
37
  </div>
38
 
39
- <div class="table-responsive">
40
  <table class="table table-bordered">
41
  <thead>
42
  <tr>
@@ -58,7 +58,7 @@ if ( ! $can_edit ) {
58
  <td>
59
  <?php if ( $item['number_of_persons'] > 1 ) echo $item['number_of_persons'] . '&nbsp;&times;&nbsp;' ?><?php echo esc_html( $item['service_name'] ) ?><?php if ( isset( $item['units'], $item['duration'] ) && $item['units'] > 1 ) echo '&nbsp;(' . DateTime::secondsToInterval( $item['units'] * $item['duration'] ) . ')' ?>
60
  <?php if ( ! empty ( $item['extras'] ) ) : ?>
61
- <ul class="bookly-list list-dots">
62
  <?php foreach ( $item['extras'] as $extra ) : ?>
63
  <li><?php if ( $payment['extras_multiply_nop'] && $item['number_of_persons'] > 1 ) echo $item['number_of_persons'] . '&nbsp;&times;&nbsp;' ?><?php if ( $extra['quantity'] > 1 ) echo $extra['quantity'] . '&nbsp;&times;&nbsp;' ?><?php echo esc_html( $extra['title'] ) ?></li>
64
  <?php endforeach ?>
@@ -77,7 +77,7 @@ if ( ! $can_edit ) {
77
  <?php else : ?>
78
  <?php if ( $item['number_of_persons'] > 1 ) $service_price = $item['number_of_persons'] . '&nbsp;&times;&nbsp' . $service_price ?>
79
  <?php echo $service_price ?>
80
- <ul class="bookly-list">
81
  <?php foreach ( $item['extras'] as $extra ) : ?>
82
  <li>
83
  <?php printf( '%s%s%s',
@@ -94,7 +94,7 @@ if ( ! $can_edit ) {
94
  <td class="text-right"><?php echo $item['service_tax'] !== null
95
  ? sprintf( $payment['tax_in_price'] === 'included' ? '(%s)' : '%s', Price::format( $item['service_tax'] ) )
96
  : '-' ?>
97
- <ul class="bookly-list">
98
  <?php foreach ( $item['extras'] as $extra ) : ?>
99
  <?php if ( isset( $extra['tax'] ) ) : ?>
100
  <li>
@@ -222,11 +222,11 @@ if ( ! $can_edit ) {
222
  <div class="bookly-js-details-main-controls">
223
  <?php Proxy\Pro::renderManualAdjustmentButton() ?>
224
  <?php if ( $payment['total'] != $payment['paid'] ) : ?>
225
- <button type="button" class="btn btn-success ladda-button" id="bookly-complete-payment" data-spinner-size="40" data-style="zoom-in"><i><?php esc_html_e( 'Complete payment', 'bookly' ) ?></i></button>
226
  <?php endif ?>
227
  </div>
228
  <div class="bookly-js-details-bind-controls collapse">
229
- <?php Buttons::renderCustom( 'bookly-js-attach-payment', 'btn-success', esc_html__( 'Bind payment', 'bookly' ) ) ?>
230
  </div>
231
  </th>
232
  </tr>
36
  </table>
37
  </div>
38
 
39
+ <div class="table-responsive overflow-hidden">
40
  <table class="table table-bordered">
41
  <thead>
42
  <tr>
58
  <td>
59
  <?php if ( $item['number_of_persons'] > 1 ) echo $item['number_of_persons'] . '&nbsp;&times;&nbsp;' ?><?php echo esc_html( $item['service_name'] ) ?><?php if ( isset( $item['units'], $item['duration'] ) && $item['units'] > 1 ) echo '&nbsp;(' . DateTime::secondsToInterval( $item['units'] * $item['duration'] ) . ')' ?>
60
  <?php if ( ! empty ( $item['extras'] ) ) : ?>
61
+ <ul class="pl-3 m-0">
62
  <?php foreach ( $item['extras'] as $extra ) : ?>
63
  <li><?php if ( $payment['extras_multiply_nop'] && $item['number_of_persons'] > 1 ) echo $item['number_of_persons'] . '&nbsp;&times;&nbsp;' ?><?php if ( $extra['quantity'] > 1 ) echo $extra['quantity'] . '&nbsp;&times;&nbsp;' ?><?php echo esc_html( $extra['title'] ) ?></li>
64
  <?php endforeach ?>
77
  <?php else : ?>
78
  <?php if ( $item['number_of_persons'] > 1 ) $service_price = $item['number_of_persons'] . '&nbsp;&times;&nbsp' . $service_price ?>
79
  <?php echo $service_price ?>
80
+ <ul class="pl-3 m-0 list-unstyled">
81
  <?php foreach ( $item['extras'] as $extra ) : ?>
82
  <li>
83
  <?php printf( '%s%s%s',
94
  <td class="text-right"><?php echo $item['service_tax'] !== null
95
  ? sprintf( $payment['tax_in_price'] === 'included' ? '(%s)' : '%s', Price::format( $item['service_tax'] ) )
96
  : '-' ?>
97
+ <ul class="pl-3 m-0 list-unstyled">
98
  <?php foreach ( $item['extras'] as $extra ) : ?>
99
  <?php if ( isset( $extra['tax'] ) ) : ?>
100
  <li>
222
  <div class="bookly-js-details-main-controls">
223
  <?php Proxy\Pro::renderManualAdjustmentButton() ?>
224
  <?php if ( $payment['total'] != $payment['paid'] ) : ?>
225
+ <?php Buttons::render( 'bookly-complete-payment', 'btn btn-success', __( 'Complete payment', 'bookly' ) ) ?>
226
  <?php endif ?>
227
  </div>
228
  <div class="bookly-js-details-bind-controls collapse">
229
+ <?php Buttons::render( 'bookly-js-attach-payment', 'btn-success', __( 'Bind payment', 'bookly' ) ) ?>
230
  </div>
231
  </th>
232
  </tr>
backend/components/dialogs/payment/templates/dialog.php CHANGED
@@ -2,18 +2,18 @@
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
  <script type="text/ng-template" id="bookly-payment-details-dialog.tpl">
5
- <div class="modal fade" id="bookly-payment-details-modal" tabindex="-1" role="dialog">
6
- <div class="modal-dialog" role="document">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
- <button type="button" class="close" data-dismiss="modal" aria-label="<?php esc_attr_e( 'Close', 'bookly' ) ?>"><span aria-hidden="true">&times;</span></button>
10
- <div class="modal-title h2"><?php _e( 'Payment', 'bookly' ) ?></div>
11
  </div>
12
  <div class="modal-body">
13
  <div class="bookly-loading"></div>
14
  </div>
15
  <div class="modal-footer">
16
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', __( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
17
  </div>
18
  </div>
19
  </div>
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  ?>
4
  <script type="text/ng-template" id="bookly-payment-details-dialog.tpl">
5
+ <div class="bookly-modal bookly-fade" id="bookly-payment-details-modal" tabindex="-1" role="dialog">
6
+ <div class="modal-dialog modal-lg" role="document">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <h5 class="modal-title"><?php esc_html_e( 'Payment', 'bookly' ) ?></h5>
10
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
11
  </div>
12
  <div class="modal-body">
13
  <div class="bookly-loading"></div>
14
  </div>
15
  <div class="modal-footer">
16
+ <?php Buttons::renderCancel( __( 'Close', 'bookly' ) ) ?>
17
  </div>
18
  </div>
19
  </div>
backend/components/dialogs/queue/Dialog.php CHANGED
@@ -16,7 +16,7 @@ class Dialog extends BooklyLib\Base\Component
16
  {
17
  self::enqueueStyles( array(
18
  'frontend' => array( 'css/ladda.min.css', ),
19
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
16
  {
17
  self::enqueueStyles( array(
18
  'frontend' => array( 'css/ladda.min.css', ),
19
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
backend/components/dialogs/queue/resources/js/queue-dialog.js CHANGED
@@ -10,16 +10,14 @@ jQuery(function ($) {
10
  queue.forEach(function (notification, index) {
11
  $queue.append(
12
  $template.clone().show().html()
13
- .replace(/{{icon}}/g, notification.gateway == 'sms' ? 'fa-sms' : 'fa-envelope')
14
  .replace(/{{recipient}}/g, notification.data.name)
15
  .replace(/{{address}}/g, notification.address)
16
  .replace(/{{description}}/g, notification.name)
17
  .replace(/{{index}}/g, index)
18
  );
19
  });
20
- $dialog.off().on('shown.bs.modal', function () {
21
- $('body').addClass('modal-open');
22
- }).on('click', '.bookly-js-send', function (e) {
23
  e.preventDefault();
24
  var ladda = Ladda.create(this),
25
  send_queue = [];
@@ -40,7 +38,7 @@ jQuery(function ($) {
40
  ladda.stop();
41
  if (response.success) {
42
  // Close the dialog.
43
- $dialog.modal('hide');
44
  }
45
  if (callback) {
46
  // Call callback.
@@ -64,7 +62,7 @@ jQuery(function ($) {
64
  // Call callback.
65
  callback();
66
  }
67
- }).modal('show');
68
  }
69
  );
70
  });
10
  queue.forEach(function (notification, index) {
11
  $queue.append(
12
  $template.clone().show().html()
13
+ .replace(/{{icon}}/g, notification.gateway == 'sms' ? 'fas fa-sms' : 'far fa-envelope')
14
  .replace(/{{recipient}}/g, notification.data.name)
15
  .replace(/{{address}}/g, notification.address)
16
  .replace(/{{description}}/g, notification.name)
17
  .replace(/{{index}}/g, index)
18
  );
19
  });
20
+ $dialog.off().on('click', '.bookly-js-send', function (e) {
 
 
21
  e.preventDefault();
22
  var ladda = Ladda.create(this),
23
  send_queue = [];
38
  ladda.stop();
39
  if (response.success) {
40
  // Close the dialog.
41
+ $dialog.booklyModal('hide');
42
  }
43
  if (callback) {
44
  // Call callback.
62
  // Call callback.
63
  callback();
64
  }
65
+ }).booklyModal('show');
66
  }
67
  );
68
  });
backend/components/dialogs/queue/templates/dialog.php CHANGED
@@ -2,29 +2,29 @@
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
- <form id="bookly-queue-modal" class="modal fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
10
- <div class="modal-title h2"><?php esc_html_e( 'Send notifications', 'bookly' ) ?></div>
11
  </div>
12
  <div class="modal-body">
13
  <div id="bookly-queue"></div>
14
  </div>
15
  <div class="modal-footer">
16
  <?php Inputs::renderCsrf() ?>
17
- <?php Buttons::renderCustom( null, 'bookly-js-send btn-lg btn-success', esc_html__( 'Send', 'bookly' ) ) ?>
18
- <?php Buttons::renderCustom( null, 'bookly-js-cancel btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
19
  </div>
20
  </div>
21
  </div>
22
  </form>
23
  <div id="bookly-notification-template" class="collapse">
24
- <div class="bookly-js-notification-queue checkbox bookly-margin-bottom-lg bookly-margin-top-remove">
25
- <label>
26
- <input type="checkbox" data-index="{{index}}" checked/> <i class="fa fa-fw {{icon}}"></i> <b>{{recipient}}</b> ({{address}})<br/>
27
  {{description}}
28
- </label>
29
  </div>
30
  </div>
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
+ <form id="bookly-queue-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <h5 class="modal-title"><?php esc_html_e( 'Send notifications', 'bookly' ) ?></h5>
10
+ <button type="button" class="close" data-dismiss="bookly-modal"><span>×</span></button>
11
  </div>
12
  <div class="modal-body">
13
  <div id="bookly-queue"></div>
14
  </div>
15
  <div class="modal-footer">
16
  <?php Inputs::renderCsrf() ?>
17
+ <?php Buttons::render( null, 'bookly-js-send btn-success', __( 'Send', 'bookly' ) ) ?>
18
+ <?php Buttons::render( null, 'bookly-js-cancel btn-default', __( 'Close', 'bookly' ), array( 'data-dismiss' => 'bookly-modal' ) ) ?>
19
  </div>
20
  </div>
21
  </div>
22
  </form>
23
  <div id="bookly-notification-template" class="collapse">
24
+ <div class="bookly-js-notification-queue">
25
+ <div class="custom-control custom-checkbox">
26
+ <input class="custom-control-input" id="bookly-nq-{{index}}" type="checkbox" data-index="{{index}}" checked/><label class="custom-control-label" for="bookly-nq-{{index}}"><i class="fa-fw {{icon}} mr-1"></i><b>{{recipient}}</b> ({{address}})</label><br/>
27
  {{description}}
28
+ </div>
29
  </div>
30
  </div>
backend/components/dialogs/service/categories/Dialog.php CHANGED
@@ -17,7 +17,7 @@ class Dialog extends Lib\Base\Component
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
@@ -26,9 +26,10 @@ class Dialog extends Lib\Base\Component
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
  'backend' => array(
29
- 'js/select2.full.min.js' => array( 'jquery' ),
 
30
  ),
31
- 'module' => array( 'js/service-categories-dialog.js' => array( 'jquery', ) ),
32
  ) );
33
 
34
  wp_localize_script( 'bookly-service-categories-dialog.js', 'BooklyServiceCreateDialogL10n', array(
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
  'backend' => array(
29
+ 'js/sortable.min.js' => array( 'jquery' ),
30
+ 'js/select2.min.js' => array( 'jquery' ),
31
  ),
32
+ 'module' => array( 'js/service-categories-dialog.js' => array( 'jquery', 'bookly-sortable.min.js') ),
33
  ) );
34
 
35
  wp_localize_script( 'bookly-service-categories-dialog.js', 'BooklyServiceCreateDialogL10n', array(
backend/components/dialogs/service/categories/resources/js/service-categories-dialog.js CHANGED
@@ -44,7 +44,7 @@ jQuery(function ($) {
44
  if (response.success) {
45
  BooklyL10n.categories = response.data;
46
  $servicesList.DataTable().ajax.reload();
47
- $dialog.modal('hide');
48
  }
49
  ladda.stop();
50
  });
@@ -62,9 +62,7 @@ jQuery(function ($) {
62
  );
63
  });
64
  });
65
-
66
- $categories.sortable({
67
- axis : 'y',
68
  handle: '.bookly-js-draghandle',
69
  });
70
  });
44
  if (response.success) {
45
  BooklyL10n.categories = response.data;
46
  $servicesList.DataTable().ajax.reload();
47
+ $dialog.booklyModal('hide');
48
  }
49
  ladda.stop();
50
  });
62
  );
63
  });
64
  });
65
+ Sortable.create($categories[0], {
 
 
66
  handle: '.bookly-js-draghandle',
67
  });
68
  });
backend/components/dialogs/service/categories/templates/dialog.php CHANGED
@@ -1,37 +1,33 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
- use Bookly\Backend\Components\Controls;
4
- use Bookly\Lib;
5
  ?>
6
- <form id="bookly-service-categories-modal" class="modal fade" tabindex=-1 role="dialog">
7
  <div class="modal-dialog">
8
  <div class="modal-content">
9
  <div class="modal-header">
10
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
11
- <div class="modal-title h2"><?php esc_html_e( 'Categories', 'bookly' ) ?></div>
12
  </div>
13
  <div class="modal-body">
14
- <div class="form-inline bookly-margin-bottom-lg text-right">
15
- <div class="form-group">
16
- <?php Controls\Buttons::renderAdd( 'bookly-js-new-category', 'btn-success', esc_html__( 'Add category', 'bookly' ) ) ?>
17
- </div>
18
- </div>
19
- <ul id="bookly-services-categories"></ul>
20
  </div>
21
  <div class="modal-footer">
22
  <?php Buttons::renderSubmit() ?>
23
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
24
  </div>
25
  </div>
26
  </div>
27
  </form>
28
  <div class="collapse" id="bookly-new-category-template">
29
  <li class="form-group">
30
- <div class="row" style="line-height: 34px;">
31
  <input type="hidden" name="category_id" value="{{id}}"/>
32
- <div class="col-xs-1"><i class="fa fa-fw fa-lg fa-bars text-muted bookly-cursor-move bookly-js-draghandle" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i></div>
33
- <div class="col-xs-10"><input type="text" class="form-control" name="category_name" value="{{name}}"/></div>
34
- <div class="col-xs-1"><a href="#"><i class="fa fa-fw fa-trash fa-lg text-danger bookly-js-delete-category" title="<?php esc_attr_e( 'Delete', 'bookly' ) ?>"></i></a></div>
35
  </div>
36
  </li>
37
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
+ use Bookly\Backend\Components\Controls\Elements;
 
4
  ?>
5
+ <form id="bookly-service-categories-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <h5 class="modal-title"><?php esc_html_e( 'Categories', 'bookly' ) ?></h5>
10
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
11
  </div>
12
  <div class="modal-body">
13
+ <ul id="bookly-services-categories" class="list-unstyled"></ul>
14
+ <?php Buttons::renderAdd( 'bookly-js-new-category', null, __( 'Add category', 'bookly' ), array(), false ) ?>
15
+ <small class="d-block text-muted mt-3"><?php esc_html_e( 'Adjust the order of categories in your booking form', 'bookly' ) ?></small>
 
 
 
16
  </div>
17
  <div class="modal-footer">
18
  <?php Buttons::renderSubmit() ?>
19
+ <?php Buttons::renderCancel() ?>
20
  </div>
21
  </div>
22
  </div>
23
  </form>
24
  <div class="collapse" id="bookly-new-category-template">
25
  <li class="form-group">
26
+ <div class="row align-items-center">
27
  <input type="hidden" name="category_id" value="{{id}}"/>
28
+ <div class="col-auto pr-1"><?php Elements::renderReorder() ?></div>
29
+ <div class="col-auto px-1"><input type="text" class="form-control" name="category_name" value="{{name}}"/></div>
30
+ <div class="col-auto pl-1"><a href="#"><i class="far fa-fw fa-trash-alt text-danger bookly-js-delete-category" title="<?php esc_attr_e( 'Delete', 'bookly' ) ?>"></i></a></div>
31
  </div>
32
  </li>
33
  </div>
backend/components/dialogs/service/create/Dialog.php CHANGED
@@ -17,7 +17,7 @@ class Dialog extends Lib\Base\Component
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
@@ -26,12 +26,12 @@ class Dialog extends Lib\Base\Component
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
  'backend' => array(
29
- 'js/select2.full.min.js' => array( 'jquery' ),
30
  ),
31
  'module' => array( 'js/service-create-dialog.js' => array( 'jquery', ) ),
32
  ) );
33
 
34
- $type_icons = Proxy\Shared::prepareServiceIcons( array( Lib\Entities\Service::TYPE_SIMPLE => 'fa-calendar-day' ) );
35
 
36
  wp_localize_script( 'bookly-service-create-dialog.js', 'BooklyServiceCreateDialogL10n', array(
37
  'csrfToken' => Lib\Utils\Common::getCsrfToken(),
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
  'backend' => array(
29
+ 'js/select2.min.js' => array( 'jquery' ),
30
  ),
31
  'module' => array( 'js/service-create-dialog.js' => array( 'jquery', ) ),
32
  ) );
33
 
34
+ $type_icons = Proxy\Shared::prepareServiceIcons( array( Lib\Entities\Service::TYPE_SIMPLE => 'far fa-calendar-check' ) );
35
 
36
  wp_localize_script( 'bookly-service-create-dialog.js', 'BooklyServiceCreateDialogL10n', array(
37
  'csrfToken' => Lib\Utils\Common::getCsrfToken(),
backend/components/dialogs/service/create/resources/js/service-create-dialog.js CHANGED
@@ -9,18 +9,18 @@ jQuery(function ($) {
9
  ;
10
 
11
  function format(option) {
12
- return option.id && option.element.dataset.icon ? '<i class="fa fa-fw ' + option.element.dataset.icon + '"></i> ' + option.text : option.text;
13
  }
14
 
15
-
16
  $serviceType.select2({
17
  minimumResultsForSearch: -1,
18
- width : '100%',
19
- theme : 'bootstrap',
20
- allowClear : false,
21
- templateResult : format,
22
- templateSelection : format,
23
- escapeMarkup : function (m) {
 
24
  return m;
25
  }
26
  });
@@ -37,7 +37,7 @@ jQuery(function ($) {
37
  $servicesList.DataTable().ajax.reload();
38
  $serviceTitle.val('');
39
  $serviceType.val('simple').trigger('change');
40
- $modal.modal('hide');
41
 
42
  BooklyServiceOrderDialogL10n.services.push({id: response.data.id, title: response.data.title});
43
  } else {
9
  ;
10
 
11
  function format(option) {
12
+ return option.id && option.element.dataset.icon ? '<i class="far fa-fw ' + option.element.dataset.icon + '"></i> ' + option.text : option.text;
13
  }
14
 
 
15
  $serviceType.select2({
16
  minimumResultsForSearch: -1,
17
+ width: '100%',
18
+ theme: 'bootstrap4',
19
+ dropdownParent: '#bookly-tbs',
20
+ allowClear: false,
21
+ templateResult: format,
22
+ templateSelection: format,
23
+ escapeMarkup: function (m) {
24
  return m;
25
  }
26
  });
37
  $servicesList.DataTable().ajax.reload();
38
  $serviceTitle.val('');
39
  $serviceType.val('simple').trigger('change');
40
+ $modal.booklyModal('hide');
41
 
42
  BooklyServiceOrderDialogL10n.services.push({id: response.data.id, title: response.data.title});
43
  } else {
backend/components/dialogs/service/create/templates/dialog.php CHANGED
@@ -4,38 +4,34 @@ use Bookly\Backend\Components\Controls\Inputs;
4
  use Bookly\Backend\Modules\Services\Proxy;
5
  use Bookly\Lib;
6
  ?>
7
- <form id="bookly-create-service-modal" class="modal fade" tabindex=-1 role="dialog">
8
  <div class="modal-dialog">
9
  <div class="modal-content">
10
  <div class="modal-header">
11
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
12
- <div class="modal-title h2"><?php esc_html_e( 'Create service', 'bookly' ) ?></div>
13
  </div>
14
  <div class="modal-body">
15
- <div class="form-group bookly-margin-bottom-md">
16
- <div class="form-field form-required">
17
- <label for="bookly-new-service-title"><?php _e( 'Title', 'bookly' ) ?></label>
18
- <input class="form-control bookly-js-new-service-title" id="bookly-new-service-title" name="title" type="text">
19
- </div>
20
  </div>
21
  <?php if ( count( $service_types = Proxy\Shared::prepareServiceTypes( array( Lib\Entities\Service::TYPE_SIMPLE => ucfirst( Lib\Entities\Service::TYPE_SIMPLE ) ) ) ) > 1 ) : ?>
22
- <div class="form-group bookly-margin-bottom-md">
23
- <div class="form-field form-required">
24
- <label for="bookly-new-service-type"><?php _e( 'Type', 'bookly' ) ?></label>
25
- <select class="form-control bookly-js-new-service-type" id="bookly-new-service-type" name="type">
26
- <?php foreach ( $service_types as $type => $title ): ?>
27
- <option data-icon="<?php echo esc_attr( $type_icons[ $type ] ) ?>" value="<?php echo $type ?>"><?php echo $title ?></option>
28
- <?php endforeach ?>
29
- </select>
30
- </div>
31
  </div>
32
  <?php endif ?>
33
  </div>
34
  <div class="modal-footer">
35
  <input type="hidden" name="action" value="bookly_create_service"/>
36
  <?php Inputs::renderCsrf() ?>
37
- <?php Buttons::renderSubmit( null, 'bookly-js-save', esc_html__( 'Create service', 'bookly' ) ) ?>
38
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
39
  </div>
40
  </div>
41
  </div>
4
  use Bookly\Backend\Modules\Services\Proxy;
5
  use Bookly\Lib;
6
  ?>
7
+ <form id="bookly-create-service-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
8
  <div class="modal-dialog">
9
  <div class="modal-content">
10
  <div class="modal-header">
11
+ <h5 class="modal-title"><?php esc_html_e( 'Create service', 'bookly' ) ?></h5>
12
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>×</span></button>
13
  </div>
14
  <div class="modal-body">
15
+ <div class="form-group">
16
+ <label for="bookly-new-service-title"><?php esc_html_e( 'Title', 'bookly' ) ?></label>
17
+ <input class="form-control bookly-js-new-service-title" id="bookly-new-service-title" name="title" type="text" />
 
 
18
  </div>
19
  <?php if ( count( $service_types = Proxy\Shared::prepareServiceTypes( array( Lib\Entities\Service::TYPE_SIMPLE => ucfirst( Lib\Entities\Service::TYPE_SIMPLE ) ) ) ) > 1 ) : ?>
20
+ <div class="form-group">
21
+ <label for="bookly-new-service-type"><?php esc_html_e( 'Type', 'bookly' ) ?></label>
22
+ <select class="form-control bookly-js-new-service-type" id="bookly-new-service-type" name="type">
23
+ <?php foreach ( $service_types as $type => $title ): ?>
24
+ <option data-icon="<?php echo esc_attr( $type_icons[ $type ] ) ?>" value="<?php echo $type ?>"><?php echo $title ?></option>
25
+ <?php endforeach ?>
26
+ </select>
 
 
27
  </div>
28
  <?php endif ?>
29
  </div>
30
  <div class="modal-footer">
31
  <input type="hidden" name="action" value="bookly_create_service"/>
32
  <?php Inputs::renderCsrf() ?>
33
+ <?php Buttons::renderSubmit( null, 'bookly-js-save',__( 'Create service', 'bookly' ) ) ?>
34
+ <?php Buttons::renderCancel( __( 'Close', 'bookly' ) ) ?>
35
  </div>
36
  </div>
37
  </div>
backend/components/dialogs/service/edit/Dialog.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
2
  namespace Bookly\Backend\Components\Dialogs\Service\Edit;
3
 
 
4
  use Bookly\Lib;
5
  use Bookly\Backend\Modules\Services\Page;
6
 
@@ -17,7 +18,7 @@ class Dialog extends Lib\Base\Component
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
@@ -26,9 +27,10 @@ class Dialog extends Lib\Base\Component
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
  'backend' => array(
29
- 'js/select2.full.min.js' => array( 'jquery' ),
 
30
  ),
31
- 'module' => array( 'js/service-edit-dialog.js' => array( 'jquery', ) ),
32
  ) );
33
 
34
  $staff = array();
1
  <?php
2
  namespace Bookly\Backend\Components\Dialogs\Service\Edit;
3
 
4
+ use Bookly\Backend\Components\Controls\Elements;
5
  use Bookly\Lib;
6
  use Bookly\Backend\Modules\Services\Page;
7
 
18
  {
19
  self::enqueueStyles( array(
20
  'frontend' => array( 'css/ladda.min.css', ),
21
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
22
  ) );
23
 
24
  self::enqueueScripts( array(
27
  'js/ladda.min.js' => array( 'jquery', ),
28
  ),
29
  'backend' => array(
30
+ 'js/select2.min.js' => array( 'jquery' ),
31
+ 'js/sortable.min.js' => array( 'jquery' ),
32
  ),
33
+ 'module' => array( 'js/service-edit-dialog.js' => array( 'jquery', 'bookly-sortable.min.js' ) ),
34
  ) );
35
 
36
  $staff = array();
backend/components/dialogs/service/edit/resources/js/service-edit-dialog.js CHANGED
@@ -3,7 +3,7 @@ jQuery(function ($) {
3
  var $servicesList = $('#services-list'),
4
  $serviceDialog = $('#bookly-edit-service-modal'),
5
  $containers = $('.bookly-js-service-containers .tab-pane > div'),
6
- $serviceLoading = $('.bookly-js-service-containers > .bookly-loading', $serviceDialog),
7
  $serviceTabs = $('.bookly-js-service-tabs', $serviceDialog),
8
  $wrapContainer = $('.bookly-js-service-containers', $serviceDialog),
9
  $generalContainer = $('#bookly-services-general-container', $serviceDialog),
@@ -14,19 +14,24 @@ jQuery(function ($) {
14
  $scheduleContainer = $('#bookly-services-schedule-container', $serviceDialog),
15
  $additionalContainer = $('#bookly-service-additional-html', $serviceDialog),
16
  $saveButton = $('#bookly-save', $serviceDialog),
17
- updateStaffChoice = null,
18
  $updateStaffModal = $('#bookly-update-service-settings'),
19
  $serviceType = $('[name="type"]', $serviceDialog),
20
  $serviceId = $('[name="id"]', $serviceDialog),
21
- $serviceError = $('.bookly-js-service-error', $serviceDialog)
 
22
  ;
23
 
 
 
 
 
 
24
  $servicesList.on('click', '[data-action="edit"]', function () {
25
  let data = $servicesList.DataTable().row($(this).closest('td')).data();
26
  $containers.html('');
27
  $serviceTabs.hide();
28
  $serviceLoading.show();
29
- $serviceDialog.modal('show');
30
  $.ajax({
31
  url : ajaxurl,
32
  type : 'POST',
@@ -50,21 +55,20 @@ jQuery(function ($) {
50
  /**
51
  * Init general tab
52
  */
53
- var $panel = $generalContainer,
54
- $colorPicker = $panel.find('.bookly-js-color-picker'),
55
- $visibility = $panel.find('input[name="visibility"]'),
56
- $providers = $panel.find('.bookly-js-providers'),
57
- $staffPreference = $panel.find('[name=staff_preference]'),
58
- $prefStaffOrder = $panel.find('.bookly-js-preferred-staff-order'),
59
- $prefStaffList = $panel.find('.bookly-js-preferred-staff-list'),
60
- $prefPeriod = $panel.find('.bookly-js-preferred-period'),
61
  staff_data = {}
62
  ;
63
  // Color picker.
64
  initColorPicker($colorPicker);
65
  // Visibility.
66
  $visibility.off().on('change', function () {
67
- $panel.find('.bookly-js-groups-list').toggle($panel.find('input[name="visibility"]:checked').val() === 'group');
68
  });
69
  // Providers.
70
  $providers.booklyDropdown();
@@ -77,7 +81,7 @@ jQuery(function ($) {
77
  $staffPreference.on('change', function () {
78
  if (this.value === 'order' && $prefStaffList.html() === '') {
79
  var $staffIds = $staffPreference.data('default'),
80
- $draggable = $('<div class="bookly-flex-cell"><i class="bookly-js-handle bookly-margin-right-sm bookly-icon bookly-icon-draghandle bookly-cursor-move"></i><input type="hidden" name="positions[]" /></div>');
81
  $draggable.find('i').attr('title', BooklyL10n.reorder);
82
  $staffIds.forEach(function (staffId) {
83
  $prefStaffList.append($draggable.clone().find('input').val(staffId).end().append(staff_data[staffId]));
@@ -85,7 +89,7 @@ jQuery(function ($) {
85
  Object.keys(BooklyServiceEditDialogL10n.staff).forEach(function (staffId) {
86
  staffId = parseInt(staffId);
87
  if ($staffIds.indexOf(staffId) === -1) {
88
- $prefStaffList.append($draggable.clone().find('input').val(staffId).end().append(staff_data[staffId]));
89
  }
90
  });
91
  }
@@ -93,26 +97,27 @@ jQuery(function ($) {
93
  $prefPeriod.toggle(this.value === 'least_occupied_for_period' || this.value === 'most_occupied_for_period');
94
  }).trigger('change');
95
  // Preferred providers order.
96
- $prefStaffList.sortable({
97
- axis : 'y',
98
- handle: '.bookly-js-handle',
99
- update: function () {
100
- var positions = [];
101
- $prefStaffList.find('input').each(function () {
102
- positions.push(this.value);
103
- });
104
- $.ajax({
105
- type: 'POST',
106
- url : ajaxurl,
107
- data: {
108
- action : 'bookly_pro_update_service_staff_preference_orders',
109
- service_id: $panel.data('service-id'),
110
- positions : positions,
111
- csrf_token: BooklyServiceEditDialogL10n.csrfToken
112
- }
113
- });
114
- }
115
- });
 
116
 
117
  /**
118
  * Init advanced tab
@@ -133,9 +138,9 @@ jQuery(function ($) {
133
  /**
134
  * Init time tab
135
  */
136
- var $duration = $('.bookly-js-duration', $timeContainer),
137
- $unitsBlock = $('.bookly-js-units-block', $timeContainer),
138
- $unitDuration = $('.bookly-js-unit-duration', $timeContainer)
139
  ;
140
  // Duration (and unit duration).
141
  $duration.off().on('change', function () {
@@ -168,7 +173,7 @@ jQuery(function ($) {
168
  $serviceDialog.find('.bookly-js-service-' + response.data.type).css('display', '');
169
 
170
  // Switch to 'General' tab if active is not visible
171
- if ($('.bookly-js-service-tabs li.active').css('display') == 'none') {
172
  $('#bookly-services-general-tab').click();
173
  }
174
 
@@ -191,7 +196,7 @@ jQuery(function ($) {
191
  });
192
  }
193
  if (showModal) {
194
- $updateStaffModal.data('panel', $panel).modal('show');
195
  } else {
196
  submitServiceFrom($serviceDialog, updateStaffChoice);
197
  }
@@ -201,7 +206,7 @@ jQuery(function ($) {
201
  * Update staff services modal
202
  */
203
  $updateStaffModal.off().on('click', '.bookly-yes', function () {
204
- $updateStaffModal.modal('hide');
205
  if ($('#bookly-remember-my-choice').prop('checked')) {
206
  updateStaffChoice = true;
207
  }
@@ -211,8 +216,6 @@ jQuery(function ($) {
211
  updateStaffChoice = false;
212
  }
213
  submitServiceFrom($serviceDialog, 0);
214
- }).on('hidden.bs.modal', function () {
215
- $('body').addClass('modal-open');
216
  });
217
 
218
  /**
@@ -266,7 +269,7 @@ jQuery(function ($) {
266
  ExtrasL10n.list = response.data.new_extras_list
267
  }
268
  $servicesList.DataTable().ajax.reload();
269
- $serviceDialog.modal('hide');
270
  }
271
  }, 'json').always(function() {
272
  ladda.stop();
3
  var $servicesList = $('#services-list'),
4
  $serviceDialog = $('#bookly-edit-service-modal'),
5
  $containers = $('.bookly-js-service-containers .tab-pane > div'),
6
+ $serviceLoading = $('.bookly-js-service-containers > .bookly-js-loading', $serviceDialog),
7
  $serviceTabs = $('.bookly-js-service-tabs', $serviceDialog),
8
  $wrapContainer = $('.bookly-js-service-containers', $serviceDialog),
9
  $generalContainer = $('#bookly-services-general-container', $serviceDialog),
14
  $scheduleContainer = $('#bookly-services-schedule-container', $serviceDialog),
15
  $additionalContainer = $('#bookly-service-additional-html', $serviceDialog),
16
  $saveButton = $('#bookly-save', $serviceDialog),
 
17
  $updateStaffModal = $('#bookly-update-service-settings'),
18
  $serviceType = $('[name="type"]', $serviceDialog),
19
  $serviceId = $('[name="id"]', $serviceDialog),
20
+ $serviceError = $('.bookly-js-service-error', $serviceDialog),
21
+ updateStaffChoice = null
22
  ;
23
 
24
+ $serviceDialog.on('keydown', ':input:not(textarea)', function (event) {
25
+ if (event.key == "Enter") {
26
+ event.preventDefault();
27
+ }
28
+ });
29
  $servicesList.on('click', '[data-action="edit"]', function () {
30
  let data = $servicesList.DataTable().row($(this).closest('td')).data();
31
  $containers.html('');
32
  $serviceTabs.hide();
33
  $serviceLoading.show();
34
+ $serviceDialog.booklyModal('show');
35
  $.ajax({
36
  url : ajaxurl,
37
  type : 'POST',
55
  /**
56
  * Init general tab
57
  */
58
+ let $colorPicker = $('.bookly-js-color-picker',$generalContainer),
59
+ $visibility = $('input[name="visibility"]',$generalContainer),
60
+ $providers = $('.bookly-js-providers',$generalContainer),
61
+ $staffPreference = $('[name=staff_preference]',$generalContainer),
62
+ $prefStaffOrder = $('.bookly-js-preferred-staff-order',$generalContainer),
63
+ $prefStaffList = $('.bookly-js-preferred-staff-list',$generalContainer),
64
+ $prefPeriod = $('.bookly-js-preferred-period',$generalContainer),
 
65
  staff_data = {}
66
  ;
67
  // Color picker.
68
  initColorPicker($colorPicker);
69
  // Visibility.
70
  $visibility.off().on('change', function () {
71
+ $generalContainer.find('.bookly-js-groups-list').toggle($generalContainer.find('input[name="visibility"]:checked').val() === 'group');
72
  });
73
  // Providers.
74
  $providers.booklyDropdown();
81
  $staffPreference.on('change', function () {
82
  if (this.value === 'order' && $prefStaffList.html() === '') {
83
  var $staffIds = $staffPreference.data('default'),
84
+ $draggable = $('<div class="col-12">').append('<i class="fas fa-fw fa-bars text-muted bookly-cursor-move bookly-js-draghandle"/>').append('<input type="hidden" name="positions[]"/>');
85
  $draggable.find('i').attr('title', BooklyL10n.reorder);
86
  $staffIds.forEach(function (staffId) {
87
  $prefStaffList.append($draggable.clone().find('input').val(staffId).end().append(staff_data[staffId]));
89
  Object.keys(BooklyServiceEditDialogL10n.staff).forEach(function (staffId) {
90
  staffId = parseInt(staffId);
91
  if ($staffIds.indexOf(staffId) === -1) {
92
+ $prefStaffList.append($draggable.clone().find('input').val(staffId).end().append('&nbsp;' + staff_data[staffId]));
93
  }
94
  });
95
  }
97
  $prefPeriod.toggle(this.value === 'least_occupied_for_period' || this.value === 'most_occupied_for_period');
98
  }).trigger('change');
99
  // Preferred providers order.
100
+ if ($prefStaffList.length) {
101
+ Sortable.create($prefStaffList[0], {
102
+ handle: '.bookly-js-draghandle',
103
+ onEnd : function () {
104
+ var positions = [];
105
+ $prefStaffList.find('input').each(function () {
106
+ positions.push(this.value);
107
+ });
108
+ $.ajax({
109
+ type: 'POST',
110
+ url : ajaxurl,
111
+ data: {
112
+ action : 'bookly_pro_update_service_staff_preference_orders',
113
+ service_id: $generalContainer.data('service-id'),
114
+ positions : positions,
115
+ csrf_token: BooklyServiceEditDialogL10n.csrfToken
116
+ }
117
+ });
118
+ }
119
+ });
120
+ }
121
 
122
  /**
123
  * Init advanced tab
138
  /**
139
  * Init time tab
140
  */
141
+ var $duration = $('.bookly-js-duration', $timeContainer),
142
+ $unitsBlock = $('.bookly-js-units-block', $timeContainer),
143
+ $unitDuration = $('.bookly-js-unit-duration', $timeContainer)
144
  ;
145
  // Duration (and unit duration).
146
  $duration.off().on('change', function () {
173
  $serviceDialog.find('.bookly-js-service-' + response.data.type).css('display', '');
174
 
175
  // Switch to 'General' tab if active is not visible
176
+ if ($('.bookly-js-service-tabs a.active').closest('li').css('display') == 'none') {
177
  $('#bookly-services-general-tab').click();
178
  }
179
 
196
  });
197
  }
198
  if (showModal) {
199
+ $updateStaffModal.data('panel', $generalContainer).booklyModal('show');
200
  } else {
201
  submitServiceFrom($serviceDialog, updateStaffChoice);
202
  }
206
  * Update staff services modal
207
  */
208
  $updateStaffModal.off().on('click', '.bookly-yes', function () {
209
+ $updateStaffModal.booklyModal('hide');
210
  if ($('#bookly-remember-my-choice').prop('checked')) {
211
  updateStaffChoice = true;
212
  }
216
  updateStaffChoice = false;
217
  }
218
  submitServiceFrom($serviceDialog, 0);
 
 
219
  });
220
 
221
  /**
269
  ExtrasL10n.list = response.data.new_extras_list
270
  }
271
  $servicesList.DataTable().ajax.reload();
272
+ $serviceDialog.booklyModal('hide');
273
  }
274
  }, 'json').always(function() {
275
  ladda.stop();
backend/components/dialogs/service/edit/templates/dialog.php CHANGED
@@ -4,33 +4,33 @@ use Bookly\Backend\Components\Controls\Inputs;
4
  use Bookly\Backend\Modules\Services\Proxy;
5
  use Bookly\Lib;
6
  ?>
7
- <div id="bookly-edit-service-modal" class="modal fade" tabindex=-1 role="dialog">
8
  <div class="modal-dialog modal-lg">
9
  <div class="modal-content">
10
  <form>
11
  <div class="modal-header">
12
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
13
- <div class="modal-title h2"><?php esc_html_e( 'Edit service', 'bookly' ) ?></div>
14
  </div>
15
  <div class="modal-body">
16
- <ul class="nav nav-tabs nav-justified bookly-nav-justified bookly-js-service-tabs">
17
- <li class="active">
18
- <a id="bookly-services-general-tab" href="#bookly-services-general" data-toggle="tab">
19
- <i class="fa fa-cog fa-fw"></i>
20
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'General', 'bookly' ) ?></span>
21
  </a>
22
  </li>
23
- <li class="bookly-js-service bookly-js-service-simple bookly-js-service-collaborative">
24
- <a id="bookly-services-time-tab" href="#bookly-services-time" data-toggle="tab">
25
- <i class="fa fa-clock fa-fw"></i>
26
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'Time', 'bookly' ) ?></span>
27
  </a>
28
  </li>
29
  <?php if ( Lib\Config::proActive() ) : ?>
30
- <li class="bookly-js-service bookly-js-service-simple bookly-js-service-collaborative bookly-js-service-compound">
31
- <a id="bookly-services-advanced-tab" href="#bookly-services-advanced" data-toggle="tab">
32
- <i class="fa fa-cogs fa-fw"></i>
33
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'Advanced', 'bookly' ) ?></span>
34
  </a>
35
  </li>
36
  <?php endif ?>
@@ -40,8 +40,8 @@ use Bookly\Lib;
40
  <?php Proxy\ServiceSpecialDays::renderTab() ?>
41
  <?php endif ?>
42
  </ul>
43
- <div class="bookly-js-service-containers tab-content">
44
- <div style="display: none;" class="bookly-loading"></div>
45
 
46
  <div class="tab-pane active" id="bookly-services-general">
47
  <div id="bookly-services-general-container"></div>
@@ -64,14 +64,14 @@ use Bookly\Lib;
64
  </div>
65
  </div>
66
  <div class="modal-footer">
67
- <span class="bookly-js-service-error text-danger pull-left text-left"></span>
68
  <input type="hidden" name="action" value="bookly_update_service"/>
69
  <input type="hidden" name="id"/>
70
  <input type="hidden" name="type"/>
71
  <input type="hidden" name="update_staff" value="0"/>
72
  <?php Inputs::renderCsrf() ?>
73
  <?php Buttons::renderSubmit() ?>
74
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
75
  </div>
76
  </form>
77
  </div>
4
  use Bookly\Backend\Modules\Services\Proxy;
5
  use Bookly\Lib;
6
  ?>
7
+ <div id="bookly-edit-service-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
8
  <div class="modal-dialog modal-lg">
9
  <div class="modal-content">
10
  <form>
11
  <div class="modal-header">
12
+ <h5 class="modal-title"><?php esc_html_e( 'Edit service', 'bookly' ) ?></h5>
13
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
14
  </div>
15
  <div class="modal-body">
16
+ <ul class="nav nav-tabs mb-3 bookly-js-service-tabs">
17
+ <li class="nav-item">
18
+ <a id="bookly-services-general-tab" class="nav-link active" href="#bookly-services-general" data-toggle="bookly-tab">
19
+ <i class="fas fa-fw fa-cog mr-1"></i>
20
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'General', 'bookly' ) ?></span>
21
  </a>
22
  </li>
23
+ <li class="nav-item bookly-js-service bookly-js-service-simple bookly-js-service-collaborative">
24
+ <a id="bookly-services-time-tab" class="nav-link" href="#bookly-services-time" data-toggle="bookly-tab">
25
+ <i class="far fa-fw fa-clock mr-1"></i>
26
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'Time', 'bookly' ) ?></span>
27
  </a>
28
  </li>
29
  <?php if ( Lib\Config::proActive() ) : ?>
30
+ <li class="nav-item bookly-js-service bookly-js-service-simple bookly-js-service-collaborative bookly-js-service-compound">
31
+ <a id="bookly-services-advanced-tab" class="nav-link" href="#bookly-services-advanced" data-toggle="bookly-tab">
32
+ <i class="fas fa-fw fa-cogs mr-1"></i>
33
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'Advanced', 'bookly' ) ?></span>
34
  </a>
35
  </li>
36
  <?php endif ?>
40
  <?php Proxy\ServiceSpecialDays::renderTab() ?>
41
  <?php endif ?>
42
  </ul>
43
+ <div class="tab-content bookly-js-service-containers">
44
+ <div class="bookly-loading bookly-js-loading"></div>
45
 
46
  <div class="tab-pane active" id="bookly-services-general">
47
  <div id="bookly-services-general-container"></div>
64
  </div>
65
  </div>
66
  <div class="modal-footer">
67
+ <span class="bookly-js-service-error text-danger float-left text-left"></span>
68
  <input type="hidden" name="action" value="bookly_update_service"/>
69
  <input type="hidden" name="id"/>
70
  <input type="hidden" name="type"/>
71
  <input type="hidden" name="update_staff" value="0"/>
72
  <?php Inputs::renderCsrf() ?>
73
  <?php Buttons::renderSubmit() ?>
74
+ <?php Buttons::renderCancel() ?>
75
  </div>
76
  </form>
77
  </div>
backend/components/dialogs/service/order/resources/js/service-order-dialog.js CHANGED
@@ -27,7 +27,6 @@ jQuery(function ($) {
27
  var $dialog = $('#bookly-service-order-modal'),
28
  $list = $('#bookly-list', $dialog),
29
  $template = $('#bookly-service-template'),
30
- $table = $('#services-list'),
31
  $save = $('#bookly-save', $dialog)
32
  ;
33
 
@@ -48,7 +47,7 @@ jQuery(function ($) {
48
  function (response) {
49
  if (response.success) {
50
  BooklyServiceOrderDialogL10n.services = response.data;
51
- $dialog.modal('hide');
52
  }
53
  ladda.stop();
54
  });
@@ -65,8 +64,7 @@ jQuery(function ($) {
65
  });
66
  });
67
 
68
- $list.sortable({
69
- axis : 'y',
70
  handle: '.bookly-js-draghandle',
71
  });
72
  });
27
  var $dialog = $('#bookly-service-order-modal'),
28
  $list = $('#bookly-list', $dialog),
29
  $template = $('#bookly-service-template'),
 
30
  $save = $('#bookly-save', $dialog)
31
  ;
32
 
47
  function (response) {
48
  if (response.success) {
49
  BooklyServiceOrderDialogL10n.services = response.data;
50
+ $dialog.booklyModal('hide');
51
  }
52
  ladda.stop();
53
  });
64
  });
65
  });
66
 
67
+ Sortable.create($list[0], {
 
68
  handle: '.bookly-js-draghandle',
69
  });
70
  });
backend/components/dialogs/service/order/templates/dialog.php CHANGED
@@ -1,30 +1,31 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
 
3
  ?>
4
- <form id="bookly-service-order-modal" class="modal fade" tabindex=-1 role="dialog">
5
  <div class="modal-dialog">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
9
- <div class="modal-title h2"><?php esc_html_e( 'Services order', 'bookly' ) ?></div>
10
  </div>
11
  <div class="modal-body">
12
- <ul id="bookly-list"></ul>
13
- <p class="help-block bookly-js-without-icon"><?php esc_html_e( 'Adjust the order of services in your booking form', 'bookly' ) ?></p>
14
  </div>
15
  <div class="modal-footer">
16
  <?php Buttons::renderSubmit() ?>
17
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
18
  </div>
19
  </div>
20
  </div>
21
  </form>
22
  <div class="collapse" id="bookly-service-template">
23
- <li class="form-group">
24
- <div class="row"">
25
  <input type="hidden" name="id" value="{{id}}"/>
26
- <div class="col-xs-1"><i class="fa fa-fw fa-lg fa-bars text-muted bookly-cursor-move bookly-js-draghandle" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i></div>
27
- <div class="col-xs-11">{{title}}</div>
28
  </div>
29
  </li>
30
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
+ use Bookly\Backend\Components\Controls\Elements;
4
  ?>
5
+ <form id="bookly-service-order-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <h5 class="modal-title"><?php esc_html_e( 'Services order', 'bookly' ) ?></h5>
10
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
11
  </div>
12
  <div class="modal-body">
13
+ <ul id="bookly-list" class="list-unstyled"></ul>
14
+ <small class="text-muted form-text"><?php esc_html_e( 'Adjust the order of services in your booking form', 'bookly' ) ?></small>
15
  </div>
16
  <div class="modal-footer">
17
  <?php Buttons::renderSubmit() ?>
18
+ <?php Buttons::renderCancel() ?>
19
  </div>
20
  </div>
21
  </div>
22
  </form>
23
  <div class="collapse" id="bookly-service-template">
24
+ <li class="mb-1">
25
+ <div class="row align-items-center">
26
  <input type="hidden" name="id" value="{{id}}"/>
27
+ <div class="col-auto pr-1"><?php Elements::renderReorder() ?></div>
28
+ <div class="col-auto pl-1">{{title}}</div>
29
  </div>
30
  </li>
31
  </div>
backend/components/dialogs/sms/Dialog.php CHANGED
@@ -17,7 +17,7 @@ class Dialog extends BooklyLib\Base\Component
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
@@ -25,10 +25,11 @@ class Dialog extends BooklyLib\Base\Component
25
  'js/spin.min.js' => array( 'jquery', ),
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
- 'backend' => array(
29
- 'js/select2.full.min.js' => array( 'jquery' ),
30
- 'js/dropdown.js' => array( 'jquery' ),),
31
- 'module' => array( 'js/notification-dialog.js' => array( 'bookly-dropdown.js', 'bookly-select2.full.min.js' ), ),
 
32
  ) );
33
 
34
  wp_localize_script( 'bookly-notification-dialog.js', 'BooklyNotificationDialogL10n', array(
@@ -50,8 +51,8 @@ class Dialog extends BooklyLib\Base\Component
50
 
51
  public static function renderNewNotificationButton()
52
  {
53
- print '<div class="form-group">';
54
- Buttons::renderCustom( 'bookly-js-new-notification', 'btn-success', esc_html__( 'New notification...', 'bookly' ) );
55
  print '</div>';
56
  }
57
 
@@ -60,7 +61,7 @@ class Dialog extends BooklyLib\Base\Component
60
  */
61
  protected static function getDefaultNotification()
62
  {
63
- $default = array(
64
  'type' => BooklyLib\Entities\Notification::TYPE_NEW_BOOKING,
65
  'active' => 1,
66
  'attach_ics' => 0,
@@ -73,7 +74,5 @@ class Dialog extends BooklyLib\Base\Component
73
  'to_staff' => 0,
74
  'settings' => BooklyLib\DataHolders\Notification\Settings::getDefault(),
75
  );
76
-
77
- return $default;
78
  }
79
  }
17
  {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
21
  ) );
22
 
23
  self::enqueueScripts( array(
25
  'js/spin.min.js' => array( 'jquery', ),
26
  'js/ladda.min.js' => array( 'jquery', ),
27
  ),
28
+ 'backend' => array(
29
+ 'js/select2.min.js' => array( 'jquery' ),
30
+ 'js/dropdown.js' => array( 'jquery' ),
31
+ ),
32
+ 'module' => array( 'js/notification-dialog.js' => array( 'bookly-dropdown.js', 'bookly-select2.min.js' ), ),
33
  ) );
34
 
35
  wp_localize_script( 'bookly-notification-dialog.js', 'BooklyNotificationDialogL10n', array(
51
 
52
  public static function renderNewNotificationButton()
53
  {
54
+ print '<div class="col-12 col-sm-auto">';
55
+ Buttons::renderAdd( 'bookly-js-new-notification', 'btn-success', __( 'New notification', 'bookly' ) );
56
  print '</div>';
57
  }
58
 
61
  */
62
  protected static function getDefaultNotification()
63
  {
64
+ return array(
65
  'type' => BooklyLib\Entities\Notification::TYPE_NEW_BOOKING,
66
  'active' => 1,
67
  'attach_ics' => 0,
74
  'to_staff' => 0,
75
  'settings' => BooklyLib\DataHolders\Notification\Settings::getDefault(),
76
  );
 
 
77
  }
78
  }
backend/components/dialogs/sms/resources/js/notification-dialog.js CHANGED
@@ -18,7 +18,7 @@ jQuery(function ($) {
18
  $offsetBefore = $('.bookly-js-offset-before', containers.settings),
19
  $btnSaveNotification = $('.bookly-js-save', $modalNotification),
20
  $helpType = $('.bookly-js-help-block', containers.settings),
21
- $codes = $('table.bookly-codes', $modalNotification),
22
  $status = $("select[name='notification[settings][status]']", containers.settings),
23
  $defaultStatuses,
24
  useTinyMCE = !BooklyNotificationDialogL10n.sms && typeof(tinyMCE) !== 'undefined',
@@ -26,15 +26,14 @@ jQuery(function ($) {
26
  ;
27
 
28
  function setNotificationText(text) {
 
29
  if (useTinyMCE) {
30
  tinyMCE.activeEditor.setContent(text);
31
- } else {
32
- return $textarea.val(text);
33
  }
34
  }
35
 
36
  function format(option) {
37
- return option.id && option.element.dataset.icon ? '<i class="fa fa-fw ' + option.element.dataset.icon + '"></i> ' + option.text : option.text;
38
  }
39
 
40
  $modalNotification
@@ -123,7 +122,7 @@ jQuery(function ($) {
123
 
124
  // Hide/un hide recipient
125
  $.each(['customer', 'staff', 'admin'], function (index, value) {
126
- $("[name$='[to_" + value + "]']:checkbox", containers.recipient).closest('.checkbox').toggle(recipients.indexOf(value) != -1);
127
  });
128
 
129
  // Hide/un hide attach
@@ -136,12 +135,13 @@ jQuery(function ($) {
136
  })
137
  .select2({
138
  minimumResultsForSearch: -1,
139
- width : '100%',
140
- theme : 'bootstrap',
141
- allowClear : false,
142
- templateResult : format,
143
- templateSelection : format,
144
- escapeMarkup : function (m) {
 
145
  return m;
146
  }
147
  });
@@ -172,7 +172,7 @@ jQuery(function ($) {
172
  ladda.stop();
173
  if (response.success) {
174
  $notificationList.DataTable().ajax.reload();
175
- $modalNotification.modal('hide');
176
  }
177
  }
178
  });
@@ -188,7 +188,7 @@ jQuery(function ($) {
188
  function showNotificationDialog(id) {
189
  $('.bookly-js-loading:first-child', $modalNotification).addClass('bookly-loading').removeClass('collapse');
190
  $('.bookly-js-loading:last-child', $modalNotification).addClass('collapse');
191
- $modalNotification.modal('show');
192
  if (id === undefined) {
193
  setNotificationData(BooklyNotificationDialogL10n.defaultNotification);
194
  } else {
@@ -276,7 +276,5 @@ jQuery(function ($) {
276
  if ($(e.target).closest("#link-selector").length) {
277
  e.stopImmediatePropagation();
278
  }
279
- })
280
- // Restore class 'modal-open' because wplink on closing remove this class
281
- .on('wplink-close', () => $(document.body).addClass('modal-open'));
282
  });
18
  $offsetBefore = $('.bookly-js-offset-before', containers.settings),
19
  $btnSaveNotification = $('.bookly-js-save', $modalNotification),
20
  $helpType = $('.bookly-js-help-block', containers.settings),
21
+ $codes = $('table.bookly-js-codes', $modalNotification),
22
  $status = $("select[name='notification[settings][status]']", containers.settings),
23
  $defaultStatuses,
24
  useTinyMCE = !BooklyNotificationDialogL10n.sms && typeof(tinyMCE) !== 'undefined',
26
  ;
27
 
28
  function setNotificationText(text) {
29
+ $textarea.val(text);
30
  if (useTinyMCE) {
31
  tinyMCE.activeEditor.setContent(text);
 
 
32
  }
33
  }
34
 
35
  function format(option) {
36
+ return option.id && option.element.dataset.icon ? '<i class="fa-fw ' + option.element.dataset.icon + '"></i> ' + option.text : option.text;
37
  }
38
 
39
  $modalNotification
122
 
123
  // Hide/un hide recipient
124
  $.each(['customer', 'staff', 'admin'], function (index, value) {
125
+ $("[name$='[to_" + value + "]']:checkbox", containers.recipient).closest('.custom-control').toggle(recipients.indexOf(value) != -1);
126
  });
127
 
128
  // Hide/un hide attach
135
  })
136
  .select2({
137
  minimumResultsForSearch: -1,
138
+ width: '100%',
139
+ theme: 'bootstrap4',
140
+ dropdownParent: '#bookly-tbs',
141
+ allowClear: false,
142
+ templateResult: format,
143
+ templateSelection: format,
144
+ escapeMarkup: function (m) {
145
  return m;
146
  }
147
  });
172
  ladda.stop();
173
  if (response.success) {
174
  $notificationList.DataTable().ajax.reload();
175
+ $modalNotification.booklyModal('hide');
176
  }
177
  }
178
  });
188
  function showNotificationDialog(id) {
189
  $('.bookly-js-loading:first-child', $modalNotification).addClass('bookly-loading').removeClass('collapse');
190
  $('.bookly-js-loading:last-child', $modalNotification).addClass('collapse');
191
+ $modalNotification.booklyModal('show');
192
  if (id === undefined) {
193
  setNotificationData(BooklyNotificationDialogL10n.defaultNotification);
194
  } else {
276
  if ($(e.target).closest("#link-selector").length) {
277
  e.stopImmediatePropagation();
278
  }
279
+ });
 
 
280
  });
backend/components/dialogs/sms/templates/_codes.php CHANGED
@@ -2,7 +2,7 @@
2
  use Bookly\Lib\Entities\Notification;
3
  $codes = new \Bookly\Backend\Modules\Notifications\Lib\Codes( 'sms' )
4
  ?>
5
- <div class="form-group bookly-js-codes-container bookly-max-height-md">
6
  <label><?php esc_attr_e( 'Codes', 'bookly' ) ?></label>
7
  <?php foreach ( Notification::getTypes( 'sms' ) as $notification_type ) :
8
  if ( in_array( $notification_type, array(
2
  use Bookly\Lib\Entities\Notification;
3
  $codes = new \Bookly\Backend\Modules\Notifications\Lib\Codes( 'sms' )
4
  ?>
5
+ <div class="form-group bookly-js-codes-container overflow-auto" style="max-height: 300px">
6
  <label><?php esc_attr_e( 'Codes', 'bookly' ) ?></label>
7
  <?php foreach ( Notification::getTypes( 'sms' ) as $notification_type ) :
8
  if ( in_array( $notification_type, array(
backend/components/dialogs/sms/templates/_editor.php CHANGED
@@ -1,5 +1,5 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
- <div class="row">
3
  <div class="col-md-12">
4
  <div class="form-group"><label for="bookly-js-message"><?php esc_html_e( 'Body', 'bookly' ) ?></label>
5
  <textarea class="form-control" name="notification[message]" rows="8" id="bookly-js-message"></textarea>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
+ <div class="row mt-3">
3
  <div class="col-md-12">
4
  <div class="form-group"><label for="bookly-js-message"><?php esc_html_e( 'Body', 'bookly' ) ?></label>
5
  <textarea class="form-control" name="notification[message]" rows="8" id="bookly-js-message"></textarea>
backend/components/dialogs/sms/templates/_modal_body.php CHANGED
@@ -1,26 +1,23 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Container;
 
3
  ?>
4
  <div class="bookly-js-loading" style="height: 200px;"></div>
5
  <div class="bookly-js-loading">
6
  <?php Container::renderHeader( __( 'Notification settings', 'bookly' ), 'bookly-js-settings-container' ) ?>
7
  <input type="hidden" name="notification[id]" value="0">
8
- <div class="row">
9
  <div class="col-md-12">
10
  <div class="form-group">
11
  <label for="notification_name"><?php esc_attr_e( 'Name', 'bookly' ) ?></label>
12
- <p class="help-block"><?php esc_html_e( 'Enter notification name which will be displayed in the list.', 'bookly' ) ?></p>
13
  <input type="text" class="form-control" id="notification_name" name="notification[name]" value=""/>
 
14
  </div>
15
  </div>
16
  </div>
17
  <div class="row">
18
  <div class="col-md-12">
19
- <div class="form-group"><label><?php esc_html_e( 'State', 'bookly' ) ?></label>
20
- <p class="help-block"><?php esc_html_e( 'Choose whether notification is enabled and sending messages or it is disabled and no messages are sent until you activate the notification.', 'bookly' ) ?></p>
21
- <div class="radio"><label><input type="radio" name="notification[active]" value="1" checked="checked"> <?php esc_html_e( 'Enabled', 'bookly' ) ?></label></div>
22
- <div class="radio"><label><input type="radio" name="notification[active]" value="0"> <?php esc_html_e( 'Disabled', 'bookly' ) ?></label></div>
23
- </div>
24
  </div>
25
  </div>
26
 
@@ -31,13 +28,13 @@ use Bookly\Backend\Components\Controls\Container;
31
  <div class="col-md-12">
32
  <div class="form-group">
33
  <label><?php esc_attr_e( 'Recipients', 'bookly' ) ?></label>
34
- <p class="help-block"><?php esc_html_e( 'Choose who will receive this notification.', 'bookly' ) ?></p>
35
  <input type="hidden" name="notification[to_customer]" value="0">
36
- <div class="checkbox"><label><input type="checkbox" name="notification[to_customer]" value="1"> <?php esc_attr_e( 'Client', 'bookly' ) ?></label></div>
37
  <input type="hidden" name="notification[to_staff]" value="0">
38
- <div class="checkbox"><label><input type="checkbox" name="notification[to_staff]" value="1"> <?php esc_attr_e( 'Staff', 'bookly' ) ?></label></div>
39
  <input type="hidden" name="notification[to_admin]" value="0">
40
- <div class="checkbox"><label><input type="checkbox" name="notification[to_admin]" value="1"> <?php esc_attr_e( 'Administrators', 'bookly' ) ?></label></div>
 
41
  </div>
42
  </div>
43
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Container;
3
+ use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
  <div class="bookly-js-loading" style="height: 200px;"></div>
6
  <div class="bookly-js-loading">
7
  <?php Container::renderHeader( __( 'Notification settings', 'bookly' ), 'bookly-js-settings-container' ) ?>
8
  <input type="hidden" name="notification[id]" value="0">
9
+ <div class="row mt-3">
10
  <div class="col-md-12">
11
  <div class="form-group">
12
  <label for="notification_name"><?php esc_attr_e( 'Name', 'bookly' ) ?></label>
 
13
  <input type="text" class="form-control" id="notification_name" name="notification[name]" value=""/>
14
+ <small class="form-text text-muted"><?php esc_html_e( 'Enter notification name which will be displayed in the list.', 'bookly' ) ?></small>
15
  </div>
16
  </div>
17
  </div>
18
  <div class="row">
19
  <div class="col-md-12">
20
+ <?php Inputs::renderRadioGroup( __( 'State', 'bookly' ), __( 'Choose whether notification is enabled and sending messages or it is disabled and no messages are sent until you activate the notification.', 'bookly' ), array(), 1, array( 'name' => 'notification[active]' ) ) ?>
 
 
 
 
21
  </div>
22
  </div>
23
 
28
  <div class="col-md-12">
29
  <div class="form-group">
30
  <label><?php esc_attr_e( 'Recipients', 'bookly' ) ?></label>
 
31
  <input type="hidden" name="notification[to_customer]" value="0">
32
+ <?php Inputs::renderCheckBox( __( 'Client', 'bookly' ), 1, null, array( 'name' => 'notification[to_customer]' ) ) ?>
33
  <input type="hidden" name="notification[to_staff]" value="0">
34
+ <?php Inputs::renderCheckBox( __( 'Staff', 'bookly' ), 1, null, array( 'name' => 'notification[to_staff]' ) ) ?>
35
  <input type="hidden" name="notification[to_admin]" value="0">
36
+ <?php Inputs::renderCheckBox( __( 'Administrators', 'bookly' ), 1, null, array( 'name' => 'notification[to_admin]' ) ) ?>
37
+ <small class="form-text text-muted"><?php esc_html_e( 'Choose who will receive this notification.', 'bookly' ) ?></small>
38
  </div>
39
  </div>
40
  </div>
backend/components/dialogs/sms/templates/_settings.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Lib\Entities\CustomerAppointment;
 
3
  $statuses = \Bookly\Lib\Entities\CustomerAppointment::getStatuses();
4
  $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's.type <> "package"' );
5
  ?>
@@ -8,13 +9,13 @@ $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's
8
  <div class="col-md-12">
9
  <div class="form-group">
10
  <label for="notification_status"><?php esc_attr_e( 'Appointment status', 'bookly' ) ?></label>
11
- <p class="help-block"><?php esc_html_e( 'Select what status an appointment should have for the notification to be sent.', 'bookly' ) ?></p>
12
- <select class="form-control" name="notification[settings][status]" id="notification_status">
13
  <option value="any"><?php esc_attr_e( 'Any', 'bookly' ) ?></option>
14
  <?php foreach ( $statuses as $status ) : ?>
15
  <option value="<?php echo $status ?>"><?php echo CustomerAppointment::statusToString( $status ) ?></option>
16
  <?php endforeach ?>
17
  </select>
 
18
  </div>
19
  </div>
20
  </div>
@@ -22,36 +23,37 @@ $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's
22
  <div class="bookly-js-services-container">
23
  <div class="row">
24
  <div class="col-md-12">
25
- <div class="form-group"><label><?php esc_html_e( 'Services', 'bookly' ) ?></label>
26
- <p class="help-block"><?php esc_html_e( 'Choose whether notification should be sent for specific services only or not.', 'bookly' ) ?></p>
27
- <div class="radio"><label><input type="radio" name="notification[settings][services][any]" value="any" checked="checked"> <?php esc_html_e( 'Any', 'bookly' ) ?></label></div>
28
- <div class="form-inline">
29
- <div class="form-group">
30
- <label><input type="radio" name="notification[settings][services][any]" value="selected"></label>
31
- <div class="form-group">
32
- <ul class="bookly-js-services"
33
- data-icon-class="glyphicon glyphicon-tag"
34
- data-txt-select-all="<?php esc_attr_e( 'All services', 'bookly' ) ?>"
35
- data-txt-all-selected="<?php esc_attr_e( 'All services', 'bookly' ) ?>"
36
- data-txt-nothing-selected="<?php esc_attr_e( 'No service selected', 'bookly' ) ?>"
37
- >
38
- <?php foreach ( $service_dropdown_data as $category_id => $category ): ?>
39
- <li<?php if ( ! $category_id ) : ?> data-flatten-if-single<?php endif ?>><?php echo esc_html( $category['name'] ) ?>
40
- <ul>
41
- <?php foreach ( $category['items'] as $service ) : ?>
42
- <li data-input-name="notification[settings][services][ids][]"
43
- data-value="<?php echo $service['id'] ?>"
44
- >
45
- <?php echo esc_html( $service['title'] ) ?>
46
- </li>
47
- <?php endforeach ?>
48
- </ul>
49
- </li>
50
- <?php endforeach ?>
51
- </ul>
52
- </div>
53
  </div>
54
  </div>
 
55
  </div>
56
  </div>
57
  </div>
@@ -59,49 +61,92 @@ $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's
59
 
60
  <div class="row bookly-js-offset bookly-js-offset-exists">
61
  <div class="col-md-12">
62
- <div class="form-group bookly-margin-bottom-remove">
63
- <label><?php esc_attr_e( 'Send', 'bookly' ) ?></label>
64
- </div>
65
  </div>
66
  </div>
67
 
68
  <div class="bookly-js-offset bookly-js-offset-bidirectional">
69
- <div class="row bookly-js-offsets bookly-js-relative bookly-js-full">
70
- <div class="col-md-12 bookly-margin-bottom-md">
71
- <div class="form-inline">
72
- <div class="form-group">
73
- <label><input type="radio" name="notification[settings][option]" value="1" checked></label>
74
- <select class="form-control" name="notification[settings][offset_hours]">
75
- <?php foreach ( array_merge( range( 1, 24 ), range( 48, 336, 24 ), array( 504, 672 ) ) as $hour ) : ?>
76
- <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( $hour * HOUR_IN_SECONDS ) ?></option>
77
- <?php endforeach ?>
78
- <option value="43200">30 <?php esc_attr_e( 'days', 'bookly' ) ?></option>
79
- </select>
80
- <select class="form-control" name="notification[settings][perform]">
81
- <option value="before"><?php esc_attr_e( 'before', 'bookly' ) ?></option>
82
- <option value="after"><?php esc_attr_e( 'after', 'bookly' ) ?></option>
83
- </select>
 
 
 
 
 
 
 
84
  </div>
85
  </div>
86
  </div>
87
  </div>
88
 
89
- <div class="row bookly-js-offsets bookly-js-at-time bookly-js-full">
90
  <div class="col-md-12">
91
- <div class="form-inline bookly-margin-bottom-sm">
92
- <div class="form-group">
93
- <label><input type="radio" name="notification[settings][option]" value="2"></label>
94
- <select class="form-control" name="notification[settings][offset_bidirectional_hours]">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  <?php foreach ( array_merge( array( - 672, - 504 ), range( - 336, - 24, 24 ) ) as $hour ) : ?>
96
  <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( abs( $hour ) * HOUR_IN_SECONDS ) ?>&nbsp;<?php esc_attr_e( 'before', 'bookly' ) ?></option>
97
  <?php endforeach ?>
98
  <option value="0" selected><?php esc_attr_e( 'on the same day', 'bookly' ) ?></option>
99
- <?php foreach ( array_merge( range( 24, 336, 24 ), array( 504, 672 ) ) as $hour ) : ?>
100
- <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( $hour * HOUR_IN_SECONDS ) ?>&nbsp;<?php esc_attr_e( 'after', 'bookly' ) ?></option>
101
- <?php endforeach ?>
102
  </select>
 
 
103
  <?php esc_attr_e( 'at', 'bookly' ) ?>
104
- <select class="form-control" name="notification[settings][at_hour]">
 
 
105
  <?php foreach ( range( 0, 23 ) as $hour ) : ?>
106
  <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::buildTimeString( $hour * HOUR_IN_SECONDS, false ) ?></option>
107
  <?php endforeach ?>
@@ -110,26 +155,4 @@ $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's
110
  </div>
111
  </div>
112
  </div>
113
- </div>
114
-
115
- <div class="row bookly-js-offset bookly-js-offset-before">
116
- <div class="col-md-12">
117
- <div class="form-inline bookly-margin-bottom-sm">
118
- <div class="form-group">
119
- <label><input type="radio" name="notification[settings][option]" value="3"></label>
120
- <select class="form-control" name="notification[settings][offset_before_hours]" id="notification_send_2">
121
- <?php foreach ( array_merge( array( - 672, - 504 ), range( - 336, - 24, 24 ) ) as $hour ) : ?>
122
- <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( abs( $hour ) * HOUR_IN_SECONDS ) ?>&nbsp;<?php esc_attr_e( 'before', 'bookly' ) ?></option>
123
- <?php endforeach ?>
124
- <option value="0" selected><?php esc_attr_e( 'on the same day', 'bookly' ) ?></option>
125
- </select>
126
- <?php esc_attr_e( 'at', 'bookly' ) ?>
127
- <select class="form-control" name="notification[settings][before_at_hour]">
128
- <?php foreach ( range( 0, 23 ) as $hour ) : ?>
129
- <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::buildTimeString( $hour * HOUR_IN_SECONDS, false ) ?></option>
130
- <?php endforeach ?>
131
- </select>
132
- </div>
133
- </div>
134
- </div>
135
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Lib\Entities\CustomerAppointment;
3
+ use Bookly\Backend\Components\Controls\Inputs;
4
  $statuses = \Bookly\Lib\Entities\CustomerAppointment::getStatuses();
5
  $service_dropdown_data = \Bookly\Lib\Utils\Common::getServiceDataForDropDown( 's.type <> "package"' );
6
  ?>
9
  <div class="col-md-12">
10
  <div class="form-group">
11
  <label for="notification_status"><?php esc_attr_e( 'Appointment status', 'bookly' ) ?></label>
12
+ <select class="form-control custom-select" class="mt-2 ml-1" name="notification[settings][status]" id="notification_status">
 
13
  <option value="any"><?php esc_attr_e( 'Any', 'bookly' ) ?></option>
14
  <?php foreach ( $statuses as $status ) : ?>
15
  <option value="<?php echo $status ?>"><?php echo CustomerAppointment::statusToString( $status ) ?></option>
16
  <?php endforeach ?>
17
  </select>
18
+ <small class="form-text text-muted"><?php esc_html_e( 'Select what status an appointment should have for the notification to be sent.', 'bookly' ) ?></small>
19
  </div>
20
  </div>
21
  </div>
23
  <div class="bookly-js-services-container">
24
  <div class="row">
25
  <div class="col-md-12">
26
+ <div class="form-group">
27
+ <label><?php esc_html_e( 'Services', 'bookly' ) ?></label>
28
+ <?php Inputs::renderRadio( __( 'Any', 'bookly' ), 'any', true, array( 'name' => 'notification[settings][services][any]' ) ) ?>
29
+ <div class="d-flex">
30
+ <div class="align-self-center">
31
+ <?php Inputs::renderRadio( '', 'selected', null, array( 'name' => 'notification[settings][services][any]' ) ) ?>
32
+ </div>
33
+ <div class="col-auto pl-0">
34
+ <ul class="bookly-js-services"
35
+ data-icon-class="fas fa-tags"
36
+ data-txt-select-all="<?php esc_attr_e( 'All services', 'bookly' ) ?>"
37
+ data-txt-all-selected="<?php esc_attr_e( 'All services', 'bookly' ) ?>"
38
+ data-txt-nothing-selected="<?php esc_attr_e( 'No service selected', 'bookly' ) ?>"
39
+ >
40
+ <?php foreach ( $service_dropdown_data as $category_id => $category ): ?>
41
+ <li<?php if ( ! $category_id ) : ?> data-flatten-if-single<?php endif ?>><?php echo esc_html( $category['name'] ) ?>
42
+ <ul>
43
+ <?php foreach ( $category['items'] as $service ) : ?>
44
+ <li data-input-name="notification[settings][services][ids][]"
45
+ data-value="<?php echo $service['id'] ?>"
46
+ >
47
+ <?php echo esc_html( $service['title'] ) ?>
48
+ </li>
49
+ <?php endforeach ?>
50
+ </ul>
51
+ </li>
52
+ <?php endforeach ?>
53
+ </ul>
54
  </div>
55
  </div>
56
+ <small class="form-text text-muted"><?php esc_html_e( 'Choose whether notification should be sent for specific services only or not.', 'bookly' ) ?></small>
57
  </div>
58
  </div>
59
  </div>
61
 
62
  <div class="row bookly-js-offset bookly-js-offset-exists">
63
  <div class="col-md-12">
64
+ <label><?php esc_attr_e( 'Send', 'bookly' ) ?></label>
 
 
65
  </div>
66
  </div>
67
 
68
  <div class="bookly-js-offset bookly-js-offset-bidirectional">
69
+ <div class="row bookly-js-offsets bookly-js-relative bookly-js-full mb-2">
70
+ <div class="col-md-12">
71
+ <div class="form-group mb-0">
72
+ <div class="d-flex flex-row">
73
+ <div class="align-self-center">
74
+ <?php Inputs::renderRadio( '', '1', true, array( 'name' => 'notification[settings][option]' ) ) ?>
75
+ </div>
76
+ <div>
77
+ <select class="form-control custom-select" name="notification[settings][offset_hours]">
78
+ <?php foreach ( array_merge( range( 1, 24 ), range( 48, 336, 24 ), array( 504, 672 ) ) as $hour ) : ?>
79
+ <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( $hour * HOUR_IN_SECONDS ) ?></option>
80
+ <?php endforeach ?>
81
+ <option value="43200">30 <?php esc_attr_e( 'days', 'bookly' ) ?></option>
82
+ </select>
83
+ </div>
84
+
85
+ <div class="ml-2">
86
+ <select class="form-control custom-select" name="notification[settings][perform]">
87
+ <option value="before"><?php esc_attr_e( 'before', 'bookly' ) ?></option>
88
+ <option value="after"><?php esc_attr_e( 'after', 'bookly' ) ?></option>
89
+ </select>
90
+ </div>
91
  </div>
92
  </div>
93
  </div>
94
  </div>
95
 
96
+ <div class="row bookly-js-offsets bookly-js-at-time bookly-js-full mb-3">
97
  <div class="col-md-12">
98
+ <div class="form-group mb-0">
99
+ <div class="d-flex">
100
+ <div class="align-self-center">
101
+ <?php Inputs::renderRadio( '', '2', true, array( 'name' => 'notification[settings][option]' ) ) ?>
102
+ </div>
103
+ <div>
104
+ <select class="form-control custom-select" name="notification[settings][offset_bidirectional_hours]">
105
+ <?php foreach ( array_merge( array( - 672, - 504 ), range( - 336, - 24, 24 ) ) as $hour ) : ?>
106
+ <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( abs( $hour ) * HOUR_IN_SECONDS ) ?>&nbsp;<?php esc_attr_e( 'before', 'bookly' ) ?></option>
107
+ <?php endforeach ?>
108
+ <option value="0" selected><?php esc_attr_e( 'on the same day', 'bookly' ) ?></option>
109
+ <?php foreach ( array_merge( range( 24, 336, 24 ), array( 504, 672 ) ) as $hour ) : ?>
110
+ <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( $hour * HOUR_IN_SECONDS ) ?>&nbsp;<?php esc_attr_e( 'after', 'bookly' ) ?></option>
111
+ <?php endforeach ?>
112
+ </select>
113
+ </div>
114
+ <div class="align-self-center mx-2">
115
+ <?php esc_attr_e( 'at', 'bookly' ) ?>
116
+ </div>
117
+ <div>
118
+ <select class="form-control custom-select" name="notification[settings][at_hour]">
119
+ <?php foreach ( range( 0, 23 ) as $hour ) : ?>
120
+ <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::buildTimeString( $hour * HOUR_IN_SECONDS, false ) ?></option>
121
+ <?php endforeach ?>
122
+ </select>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="row bookly-js-offset bookly-js-offset-before mb-3">
131
+ <div class="col-md-12">
132
+ <div class="form-group">
133
+ <div class="d-flex flex-row">
134
+ <div class="align-self-center">
135
+ <?php Inputs::renderRadio( '', '3', true, array( 'name' => 'notification[settings][option]' ) ) ?>
136
+ </div>
137
+ <div>
138
+ <select class="form-control custom-select" name="notification[settings][offset_before_hours]" id="notification_send_2">
139
  <?php foreach ( array_merge( array( - 672, - 504 ), range( - 336, - 24, 24 ) ) as $hour ) : ?>
140
  <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::secondsToInterval( abs( $hour ) * HOUR_IN_SECONDS ) ?>&nbsp;<?php esc_attr_e( 'before', 'bookly' ) ?></option>
141
  <?php endforeach ?>
142
  <option value="0" selected><?php esc_attr_e( 'on the same day', 'bookly' ) ?></option>
 
 
 
143
  </select>
144
+ </div>
145
+ <div class="align-self-center mx-2">
146
  <?php esc_attr_e( 'at', 'bookly' ) ?>
147
+ </div>
148
+ <div>
149
+ <select class="form-control custom-select" name="notification[settings][before_at_hour]">
150
  <?php foreach ( range( 0, 23 ) as $hour ) : ?>
151
  <option value="<?php echo $hour ?>"><?php echo \Bookly\Lib\Utils\DateTime::buildTimeString( $hour * HOUR_IN_SECONDS, false ) ?></option>
152
  <?php endforeach ?>
155
  </div>
156
  </div>
157
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  </div>
backend/components/dialogs/sms/templates/_types.php CHANGED
@@ -6,8 +6,7 @@ use Bookly\Lib\Config;
6
  <div class="col-md-12">
7
  <div class="form-group">
8
  <label for="notification_type"><?php esc_attr_e( 'Type', 'bookly' ) ?></label>
9
- <p class="help-block"><?php esc_html_e( 'Select the type of event at which the notification is sent.', 'bookly' ) ?></p>
10
- <select class="form-control" name="notification[type]" id="notification_type">
11
  <optgroup label="<?php esc_attr_e( 'Instant notifications', 'bookly' ) ?>">
12
  <option value="<?php echo Notification::TYPE_NEW_BOOKING ?>"
13
  data-set="instantly"
@@ -94,7 +93,8 @@ use Bookly\Lib\Config;
94
  data-attach='[]'><?php echo esc_attr( Notification::getTitle( Notification::TYPE_STAFF_DAY_AGENDA ) ) ?></option>
95
  </optgroup>
96
  </select>
97
- <p class="help-block bookly-js-help-block bookly-margin-top-xs <?php echo Notification::TYPE_NEW_BOOKING_COMBINED ?>"><?php esc_html_e( 'This notification is sent once for a booking made by a customer and includes all cart items.', 'bookly' ) ?></p>
 
98
  </div>
99
  </div>
100
  </div>
6
  <div class="col-md-12">
7
  <div class="form-group">
8
  <label for="notification_type"><?php esc_attr_e( 'Type', 'bookly' ) ?></label>
9
+ <select class="form-control custom-select" name="notification[type]" id="notification_type">
 
10
  <optgroup label="<?php esc_attr_e( 'Instant notifications', 'bookly' ) ?>">
11
  <option value="<?php echo Notification::TYPE_NEW_BOOKING ?>"
12
  data-set="instantly"
93
  data-attach='[]'><?php echo esc_attr( Notification::getTitle( Notification::TYPE_STAFF_DAY_AGENDA ) ) ?></option>
94
  </optgroup>
95
  </select>
96
+ <small class="form-text text-muted"><?php esc_html_e( 'Select the type of event at which the notification is sent.', 'bookly' ) ?></small>
97
+ <small class="form-text text-muted bookly-js-help-block mt-2 <?php echo Notification::TYPE_NEW_BOOKING_COMBINED ?>"><?php esc_html_e( 'This notification is sent once for a booking made by a customer and includes all cart items.', 'bookly' ) ?></small>
98
  </div>
99
  </div>
100
  </div>
backend/components/dialogs/sms/templates/dialog.php CHANGED
@@ -2,20 +2,20 @@
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
- <form id="bookly-js-notification-modal" class="modal fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog modal-lg">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
10
- <div class="modal-title h2"></div>
11
  </div>
12
  <div class="modal-body">
13
  <?php static::renderTemplate( '_modal_body', compact( 'self' ) ) ?>
14
  </div>
15
  <div class="modal-footer">
16
  <?php Inputs::renderCsrf() ?>
17
- <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', esc_html__( 'Save notification', 'bookly' ) ) ?>
18
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
19
  </div>
20
  </div>
21
  </div>
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
+ <form id="bookly-js-notification-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog modal-lg">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <h5 class="modal-title"></h5>
10
+ <button type="button" class="close" data-dismiss="bookly-modal"><span>&times;</span></button>
11
  </div>
12
  <div class="modal-body">
13
  <?php static::renderTemplate( '_modal_body', compact( 'self' ) ) ?>
14
  </div>
15
  <div class="modal-footer">
16
  <?php Inputs::renderCsrf() ?>
17
+ <?php Buttons::render( null, 'bookly-js-save btn-success', __( 'Save notification', 'bookly' ) ) ?>
18
+ <?php Buttons::renderCancel() ?>
19
  </div>
20
  </div>
21
  </div>
backend/components/dialogs/staff/edit/Ajax.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
  namespace Bookly\Backend\Components\Dialogs\Staff\Edit;
3
 
4
- use Bookly\Backend\Modules\Staff\Forms\Widgets\TimeChoice;
 
5
  use Bookly\Backend\Modules\Staff\Proxy as StaffProxy;
6
  use Bookly\Lib;
7
 
@@ -218,53 +219,39 @@ class Ajax extends Lib\Base\Ajax
218
  $end_time = self::parameter( 'end_time' );
219
  $working_start = self::parameter( 'working_start' );
220
  $working_end = self::parameter( 'working_end' );
 
221
 
222
  if ( Lib\Utils\DateTime::timeToSeconds( $start_time ) >= Lib\Utils\DateTime::timeToSeconds( $end_time ) ) {
223
  wp_send_json_error( array( 'message' => __( 'The start time must be less than the end one', 'bookly' ), ) );
224
  }
225
 
226
- $res_schedule = new Lib\Entities\StaffScheduleItem();
227
- $res_schedule->load( self::parameter( 'staff_schedule_item_id' ) );
228
-
229
- $break_id = self::parameter( 'break_id', 0 );
230
 
231
  $in_working_time = $working_start <= $start_time && $start_time <= $working_end
232
  && $working_start <= $end_time && $end_time <= $working_end;
233
- if ( ! $in_working_time || ! $res_schedule->isBreakIntervalAvailable( $start_time, $end_time, $break_id ) ) {
234
  wp_send_json_error( array( 'message' => __( 'The requested interval is not available', 'bookly' ), ) );
235
  }
236
 
237
- $formatted_start = Lib\Utils\DateTime::formatTime( Lib\Utils\DateTime::timeToSeconds( $start_time ) );
238
- $formatted_end = Lib\Utils\DateTime::formatTime( Lib\Utils\DateTime::timeToSeconds( $end_time ) );
239
- $formatted_interval = $formatted_start . ' - ' . $formatted_end;
240
-
241
  if ( $break_id ) {
242
- $break = new Lib\Entities\ScheduleItemBreak();
243
- $break->load( $break_id );
244
- $break->setStartTime( $start_time )
245
- ->setEndTime( $end_time )
246
- ->save();
247
-
248
- wp_send_json_success( array( 'interval' => $formatted_interval, ) );
249
  } else {
250
- $res_schedule_break = new Lib\Entities\ScheduleItemBreak();
251
- $res_schedule_break->setFields( self::postParameters() );
252
- $res_schedule_break->save();
253
- if ( $res_schedule_break ) {
254
- $breakStart = new TimeChoice( array( 'use_empty' => false, 'type' => 'break_from' ) );
255
- $breakEnd = new TimeChoice( array( 'use_empty' => false, 'type' => 'to' ) );
256
- wp_send_json( array(
257
- 'success' => true,
258
- 'item_content' => self::renderTemplate( '_break', array(
259
- 'staff_schedule_item_break_id' => $res_schedule_break->getId(),
260
- 'formatted_interval' => $formatted_interval,
261
- 'break_start_choices' => $breakStart->render( '', $start_time, array( 'class' => 'break-start form-control' ) ),
262
- 'break_end_choices' => $breakEnd->render( '', $end_time, array( 'class' => 'break-end form-control' ) ),
263
- ), false ),
264
- ) );
265
- } else {
266
- wp_send_json_error( array( 'message' => __( 'Error adding the break interval', 'bookly' ), ) );
267
- }
268
  }
269
  }
270
 
@@ -351,8 +338,26 @@ class Ajax extends Lib\Base\Ajax
351
  {
352
  $staff = new Lib\Entities\Staff();
353
  $staff->load( $staff_id );
354
- $schedule_items = $staff->getScheduleItems( $location_id );
355
- return self::renderTemplate( 'schedule', compact( 'schedule_items', 'staff_id', 'location_id' ), false );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356
  }
357
 
358
  /**
@@ -379,7 +384,7 @@ class Ajax extends Lib\Base\Ajax
379
  && ( self::$staff->getId() == self::parameter( 'staff_id' ) );
380
  case 'staffScheduleHandleBreak':
381
  $res_schedule = new Lib\Entities\StaffScheduleItem();
382
- $res_schedule->load( self::parameter( 'staff_schedule_item_id' ) );
383
  return self::$staff->isLoaded()
384
  && ( self::$staff->getId() == $res_schedule->getStaffId() );
385
  break;
@@ -392,8 +397,8 @@ class Ajax extends Lib\Base\Ajax
392
  && ( self::$staff->getId() == $res_schedule->getStaffId() );
393
  break;
394
  case 'staffScheduleUpdate':
395
- if ( self::hasParameter( 'days' ) ) {
396
- foreach ( self::parameter( 'days' ) as $id => $day_index ) {
397
  $res_schedule = new Lib\Entities\StaffScheduleItem();
398
  $res_schedule->load( $id );
399
  $staff = new Lib\Entities\Staff();
1
  <?php
2
  namespace Bookly\Backend\Components\Dialogs\Staff\Edit;
3
 
4
+ use Bookly\Backend\Components\Schedule\BreakItem;
5
+ use Bookly\Backend\Components\Schedule\Component as ScheduleComponent;
6
  use Bookly\Backend\Modules\Staff\Proxy as StaffProxy;
7
  use Bookly\Lib;
8
 
219
  $end_time = self::parameter( 'end_time' );
220
  $working_start = self::parameter( 'working_start' );
221
  $working_end = self::parameter( 'working_end' );
222
+ $break_id = self::parameter( 'id', 0 );
223
 
224
  if ( Lib\Utils\DateTime::timeToSeconds( $start_time ) >= Lib\Utils\DateTime::timeToSeconds( $end_time ) ) {
225
  wp_send_json_error( array( 'message' => __( 'The start time must be less than the end one', 'bookly' ), ) );
226
  }
227
 
228
+ $schedule_item = new Lib\Entities\StaffScheduleItem();
229
+ $schedule_item->load( self::parameter( 'ss_id' ) );
 
 
230
 
231
  $in_working_time = $working_start <= $start_time && $start_time <= $working_end
232
  && $working_start <= $end_time && $end_time <= $working_end;
233
+ if ( ! $in_working_time || ! $schedule_item->isBreakIntervalAvailable( $start_time, $end_time, $break_id ) ) {
234
  wp_send_json_error( array( 'message' => __( 'The requested interval is not available', 'bookly' ), ) );
235
  }
236
 
237
+ $schedule_item_break = new Lib\Entities\ScheduleItemBreak();
 
 
 
238
  if ( $break_id ) {
239
+ $schedule_item_break->load( $break_id );
 
 
 
 
 
 
240
  } else {
241
+ $schedule_item_break->setStaffScheduleItemId( $schedule_item->getId() );
242
+ }
243
+ $schedule_item_break
244
+ ->setStartTime( $start_time )
245
+ ->setEndTime( $end_time )
246
+ ->save();
247
+ if ( $schedule_item_break ) {
248
+ $break = new BreakItem( $schedule_item_break->getId(), $schedule_item_break->getStartTime(), $schedule_item_break->getEndTime() );
249
+ wp_send_json_success( array(
250
+ 'html' => $break->render( false ),
251
+ 'interval' => $break->getFormatedInterval(),
252
+ ) );
253
+ } else {
254
+ wp_send_json_error( array( 'message' => __( 'Error adding the break interval', 'bookly' ), ) );
 
 
 
 
255
  }
256
  }
257
 
338
  {
339
  $staff = new Lib\Entities\Staff();
340
  $staff->load( $staff_id );
341
+
342
+ $schedule = new ScheduleComponent( 'start_time[{index}]', 'end_time[{index}]' );
343
+
344
+ $ss_ids = array();
345
+ foreach ( $staff->getScheduleItems( $location_id ) as $item ) {
346
+ $id = $item->getId();
347
+ $schedule->addHours( $id, $item->getDayIndex(), $item->getStartTime(), $item->getEndTime() );
348
+ $ss_ids[ $id ] = $item->getDayIndex();
349
+ }
350
+
351
+ foreach (
352
+ Lib\Entities\ScheduleItemBreak::query()
353
+ ->whereIn( 'staff_schedule_item_id', array_keys( $ss_ids) )
354
+ ->sortBy( 'start_time, end_time' )
355
+ ->fetchArray() as $break
356
+ ) {
357
+ $schedule->addBreak( $break['staff_schedule_item_id'], $break['id'], $break['start_time'], $break['end_time'] );
358
+ }
359
+
360
+ return self::renderTemplate( 'schedule', compact( 'schedule', 'staff_id', 'location_id', 'ss_ids' ), false );
361
  }
362
 
363
  /**
384
  && ( self::$staff->getId() == self::parameter( 'staff_id' ) );
385
  case 'staffScheduleHandleBreak':
386
  $res_schedule = new Lib\Entities\StaffScheduleItem();
387
+ $res_schedule->load( self::parameter( 'ss_id' ) );
388
  return self::$staff->isLoaded()
389
  && ( self::$staff->getId() == $res_schedule->getStaffId() );
390
  break;
397
  && ( self::$staff->getId() == $res_schedule->getStaffId() );
398
  break;
399
  case 'staffScheduleUpdate':
400
+ if ( self::hasParameter( 'ssi' ) ) {
401
+ foreach ( self::parameter( 'ssi' ) as $id => $day_index ) {
402
  $res_schedule = new Lib\Entities\StaffScheduleItem();
403
  $res_schedule->load( $id );
404
  $staff = new Lib\Entities\Staff();
backend/components/dialogs/staff/edit/Dialog.php CHANGED
@@ -28,7 +28,7 @@ class Dialog extends Lib\Base\Component
28
  ? array()
29
  : array( 'css/intlTelInput.css' )
30
  ),
31
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
32
  ) );
33
 
34
  self::enqueueScripts( array(
@@ -42,18 +42,19 @@ class Dialog extends Lib\Base\Component
42
  : array( 'js/intlTelInput.min.js' => array( 'jquery' ) )
43
  ),
44
  'backend' => array(
45
- 'js/jCal.js' => array( 'jquery' ),
46
- 'js/dropdown.js' => array( 'jquery' ),
47
- 'js/range_tools.js' => array( 'jquery' ),
48
  'js/moment.min.js',
49
- 'js/select2.full.min.js' => array( 'jquery' ),
 
50
  ),
51
  'module' => array(
52
- 'js/staff-details.js' => array( 'jquery' ),
53
- 'js/staff-services.js' => array( 'bookly-staff-details.js' ),
54
- 'js/staff-schedule.js' => array( 'bookly-staff-services.js' ),
55
- 'js/staff-days-off.js' => array( 'bookly-staff-schedule.js' ),
56
- 'js/staff-edit-dialog.js' => array( 'jquery-ui-sortable', 'jquery-ui-datepicker', 'bookly-range_tools.js', 'bookly-staff-days-off.js' )
57
  ),
58
  ) );
59
 
28
  ? array()
29
  : array( 'css/intlTelInput.css' )
30
  ),
31
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
32
  ) );
33
 
34
  self::enqueueScripts( array(
42
  : array( 'js/intlTelInput.min.js' => array( 'jquery' ) )
43
  ),
44
  'backend' => array(
45
+ 'js/jCal.js' => array( 'jquery' ),
46
+ 'js/dropdown.js' => array( 'jquery' ),
47
+ 'js/range-tools.js' => array( 'jquery' ),
48
  'js/moment.min.js',
49
+ 'js/daterangepicker.js' => array( 'jquery' ),
50
+ 'js/select2.min.js' => array( 'jquery' ),
51
  ),
52
  'module' => array(
53
+ 'js/staff-details.js' => array( 'bookly-range-tools.js' ),
54
+ 'js/staff-services.js' => array( 'bookly-staff-details.js' ),
55
+ 'js/staff-schedule.js' => array( 'bookly-staff-services.js' ),
56
+ 'js/staff-days-off.js' => array( 'bookly-staff-schedule.js' ),
57
+ 'js/staff-edit-dialog.js' => array( 'bookly-daterangepicker.js', 'bookly-staff-days-off.js' ),
58
  ),
59
  ) );
60
 
backend/components/dialogs/staff/edit/resources/js/staff-days-off.js CHANGED
@@ -1,4 +1,4 @@
1
- jQuery(function ($) {
2
 
3
  var DaysOff = function($container, options) {
4
  var obj = this;
@@ -59,4 +59,4 @@ jQuery(function ($) {
59
  };
60
 
61
  window.BooklyStaffDaysOff = DaysOff;
62
- });
1
+ (function ($) {
2
 
3
  var DaysOff = function($container, options) {
4
  var obj = this;
59
  };
60
 
61
  window.BooklyStaffDaysOff = DaysOff;
62
+ })(jQuery);
backend/components/dialogs/staff/edit/resources/js/staff-details.js CHANGED
@@ -1,4 +1,4 @@
1
- jQuery(function ($) {
2
 
3
  var Details = function ($container, options) {
4
  var obj = this;
@@ -68,7 +68,7 @@ jQuery(function ($) {
68
  var url = $(this).attr('href');
69
  if (has_changes) {
70
  e.preventDefault();
71
- $unsaved_changes.modal('show');
72
  $unsaved_changes.data('url', url);
73
  }
74
  })
@@ -76,7 +76,7 @@ jQuery(function ($) {
76
  var url = $(this).attr('href');
77
  if (has_changes) {
78
  e.preventDefault();
79
- $unsaved_changes.modal('show');
80
  $unsaved_changes.data('url', url);
81
  }
82
  })
@@ -87,7 +87,7 @@ jQuery(function ($) {
87
  has_changes = true;
88
  $('.bookly-js-outlook-calendars-list', $container).toggle(!this.checked);
89
  })
90
- .on('click', '.bookly-pretty-indicator', function (e) {
91
  e.preventDefault();
92
  e.stopPropagation();
93
  var frame = wp.media({
@@ -110,9 +110,6 @@ jQuery(function ($) {
110
  $(this).hide();
111
  has_changes = true;
112
  }
113
- })
114
- .on('close', function(){
115
- $('body').addClass('modal-open');
116
  });
117
 
118
  frame.open();
@@ -123,6 +120,7 @@ jQuery(function ($) {
123
  $thumb.attr('style', '');
124
  $container.find('[name=attachment_id]').val('').trigger('change');
125
  has_changes = true;
 
126
  })
127
  // Save staff member details.
128
  .on('click', '#bookly-details-save', function (e) {
@@ -169,11 +167,6 @@ jQuery(function ($) {
169
  window.location.href = $unsaved_changes.data('url');
170
  });
171
 
172
- $unsaved_changes
173
- .on('hidden.bs.modal', function () {
174
- jQuery('body').addClass('modal-open');
175
- });
176
-
177
  function save(callback) {
178
  var data = $form.serializeArray(),
179
  $staff_phone = $('#bookly-phone', $form),
@@ -223,4 +216,4 @@ jQuery(function ($) {
223
  };
224
 
225
  window.BooklyStaffDetails = Details;
226
- });
1
+ (function ($) {
2
 
3
  var Details = function ($container, options) {
4
  var obj = this;
68
  var url = $(this).attr('href');
69
  if (has_changes) {
70
  e.preventDefault();
71
+ $unsaved_changes.booklyModal('show');
72
  $unsaved_changes.data('url', url);
73
  }
74
  })
76
  var url = $(this).attr('href');
77
  if (has_changes) {
78
  e.preventDefault();
79
+ $unsaved_changes.booklyModal('show');
80
  $unsaved_changes.data('url', url);
81
  }
82
  })
87
  has_changes = true;
88
  $('.bookly-js-outlook-calendars-list', $container).toggle(!this.checked);
89
  })
90
+ .on('click', '.bookly-thumb label', function (e) {
91
  e.preventDefault();
92
  e.stopPropagation();
93
  var frame = wp.media({
110
  $(this).hide();
111
  has_changes = true;
112
  }
 
 
 
113
  });
114
 
115
  frame.open();
120
  $thumb.attr('style', '');
121
  $container.find('[name=attachment_id]').val('').trigger('change');
122
  has_changes = true;
123
+ $('.bookly-thumb-delete').hide();
124
  })
125
  // Save staff member details.
126
  .on('click', '#bookly-details-save', function (e) {
167
  window.location.href = $unsaved_changes.data('url');
168
  });
169
 
 
 
 
 
 
170
  function save(callback) {
171
  var data = $form.serializeArray(),
172
  $staff_phone = $('#bookly-phone', $form),
216
  };
217
 
218
  window.BooklyStaffDetails = Details;
219
+ })(jQuery);
backend/components/dialogs/staff/edit/resources/js/staff-edit-dialog.js CHANGED
@@ -15,6 +15,11 @@ jQuery(function ($) {
15
  staff_id,
16
  holidays
17
  ;
 
 
 
 
 
18
 
19
  $staffList
20
  .on('click', '[data-action="edit"]', function () {
@@ -23,7 +28,7 @@ jQuery(function ($) {
23
  editStaff(staff_id);
24
  });
25
 
26
- $('#bookly-create-staff-modal-activator')
27
  .on('click', function () {
28
  if (BooklyStaffEditDialogL10n.proRequired == '1' && $staffCount.html() > 0) {
29
  booklyAlert({error: [BooklyStaffEditDialogL10n.limitation]});
@@ -50,7 +55,7 @@ jQuery(function ($) {
50
  $validateErrors.html('');
51
  $saveBtn.prop('disabled', false);
52
  $modalBody.html('<div class="bookly-loading"></div>');
53
- $modal.modal();
54
  $.get(ajaxurl, {action: 'bookly_get_staff_data', id: staff_id, csrf_token: BooklyStaffEditDialogL10n.csrfToken}, function (response) {
55
  $modalBody.html(response.data.html.edit);
56
  booklyAlert(response.data.alert);
@@ -68,7 +73,7 @@ jQuery(function ($) {
68
  $holidays_container.append(response.data.html.holidays);
69
  $special_days_container.append(response.data.html.special_days);
70
 
71
- $('.panel-footer', $modalBody).hide();
72
 
73
  new BooklyStaffDetails($details_container, {
74
  get_details : {},
@@ -99,7 +104,7 @@ jQuery(function ($) {
99
  if (!response.success) {
100
  switch (response.data.action) {
101
  case 'show_modal':
102
- $deleteCascadeModal.modal('show');
103
  break;
104
  case 'confirm':
105
  if (confirm(BooklyStaffEditDialogL10n.areYouSure)) {
@@ -108,7 +113,7 @@ jQuery(function ($) {
108
  break;
109
  }
110
  } else {
111
- $modal.modal('hide');
112
  $staffList.DataTable().ajax.reload();
113
  }
114
  });
@@ -145,7 +150,7 @@ jQuery(function ($) {
145
  csrf_token: BooklyStaffEditDialogL10n.csrfToken
146
  },
147
  onLoad: function () {
148
- $('.panel-footer', $container).hide();
149
  $('#bookly-services-save', $container).addClass('bookly-js-save');
150
  $(document.body).trigger('staff.validation', ['staff-services', false, '']);
151
  },
@@ -182,7 +187,7 @@ jQuery(function ($) {
182
  csrf_token: BooklyStaffEditDialogL10n.csrfToken
183
  },
184
  onLoad: function () {
185
- $('.panel-footer', $container).hide();
186
  $('#bookly-schedule-save', $container).addClass('bookly-js-save');
187
  },
188
  l10n: BooklyL10n
@@ -205,7 +210,7 @@ jQuery(function ($) {
205
 
206
  $container.show();
207
  })
208
- .on('click', '> .bookly-nav-justified [data-toggle=tab]', function () {
209
  currentTab = $(this).attr('id');
210
  });
211
 
@@ -215,7 +220,7 @@ jQuery(function ($) {
215
  $modalBody.html('<div class="bookly-loading"></div>');
216
  ladda = Ladda.create(this);
217
  deleteStaff({force_delete: true}, ladda);
218
- $deleteCascadeModal.modal('hide');
219
  ladda.stop();
220
  })
221
  // Edit
@@ -235,7 +240,7 @@ jQuery(function ($) {
235
  ladda = Ladda.create(this);
236
  ladda.start();
237
 
238
- let $buttons = $('.panel-footer', $modalBody);
239
  waitResposes = 0;
240
  success = true;
241
  $buttons
@@ -258,9 +263,11 @@ jQuery(function ($) {
258
  waitResposes --;
259
  }
260
  if (waitResposes <= 0) {
261
- $staffList.DataTable().ajax.reload();
 
 
262
  ladda ? ladda.stop() : null;
263
- $modal.modal('hide');
264
  booklyAlert({success: [BooklyStaffEditDialogL10n.settingsSaved]})
265
  }
266
  })
15
  staff_id,
16
  holidays
17
  ;
18
+ $modal.on('keydown', ':input:not(textarea)', function (event) {
19
+ if (event.key == "Enter") {
20
+ event.preventDefault();
21
+ }
22
+ });
23
 
24
  $staffList
25
  .on('click', '[data-action="edit"]', function () {
28
  editStaff(staff_id);
29
  });
30
 
31
+ $('#bookly-js-new-staff')
32
  .on('click', function () {
33
  if (BooklyStaffEditDialogL10n.proRequired == '1' && $staffCount.html() > 0) {
34
  booklyAlert({error: [BooklyStaffEditDialogL10n.limitation]});
55
  $validateErrors.html('');
56
  $saveBtn.prop('disabled', false);
57
  $modalBody.html('<div class="bookly-loading"></div>');
58
+ $modal.booklyModal();
59
  $.get(ajaxurl, {action: 'bookly_get_staff_data', id: staff_id, csrf_token: BooklyStaffEditDialogL10n.csrfToken}, function (response) {
60
  $modalBody.html(response.data.html.edit);
61
  booklyAlert(response.data.alert);
73
  $holidays_container.append(response.data.html.holidays);
74
  $special_days_container.append(response.data.html.special_days);
75
 
76
+ $('.bookly-js-modal-footer', $modalBody).hide();
77
 
78
  new BooklyStaffDetails($details_container, {
79
  get_details : {},
104
  if (!response.success) {
105
  switch (response.data.action) {
106
  case 'show_modal':
107
+ $deleteCascadeModal.booklyModal('show');
108
  break;
109
  case 'confirm':
110
  if (confirm(BooklyStaffEditDialogL10n.areYouSure)) {
113
  break;
114
  }
115
  } else {
116
+ $modal.booklyModal('hide');
117
  $staffList.DataTable().ajax.reload();
118
  }
119
  });
150
  csrf_token: BooklyStaffEditDialogL10n.csrfToken
151
  },
152
  onLoad: function () {
153
+ $('.bookly-js-modal-footer', $container).hide();
154
  $('#bookly-services-save', $container).addClass('bookly-js-save');
155
  $(document.body).trigger('staff.validation', ['staff-services', false, '']);
156
  },
187
  csrf_token: BooklyStaffEditDialogL10n.csrfToken
188
  },
189
  onLoad: function () {
190
+ $('.bookly-js-modal-footer', $container).hide();
191
  $('#bookly-schedule-save', $container).addClass('bookly-js-save');
192
  },
193
  l10n: BooklyL10n
210
 
211
  $container.show();
212
  })
213
+ .on('click', '> .nav-tabs [data-toggle=tab]', function () {
214
  currentTab = $(this).attr('id');
215
  });
216
 
220
  $modalBody.html('<div class="bookly-loading"></div>');
221
  ladda = Ladda.create(this);
222
  deleteStaff({force_delete: true}, ladda);
223
+ $deleteCascadeModal.booklyModal('hide');
224
  ladda.stop();
225
  })
226
  // Edit
240
  ladda = Ladda.create(this);
241
  ladda.start();
242
 
243
+ let $buttons = $('.bookly-js-modal-footer', $modalBody);
244
  waitResposes = 0;
245
  success = true;
246
  $buttons
263
  waitResposes --;
264
  }
265
  if (waitResposes <= 0) {
266
+ $staffList.DataTable().ajax.reload(function () {
267
+ $staffList.DataTable().responsive.recalc();
268
+ });
269
  ladda ? ladda.stop() : null;
270
+ $modal.booklyModal('hide');
271
  booklyAlert({success: [BooklyStaffEditDialogL10n.settingsSaved]})
272
  }
273
  })
backend/components/dialogs/staff/edit/resources/js/staff-schedule.js CHANGED
@@ -1,7 +1,7 @@
1
- jQuery(function ($) {
2
  var Schedule = function ($container, options) {
3
- var obj = this;
4
- jQuery.extend(obj.options, options);
5
 
6
  // Loads schedule list
7
  if (!$container.children().length) {
@@ -19,69 +19,31 @@ jQuery(function ($) {
19
  $container.append(response.data.html);
20
  $container.removeData('init');
21
  obj.options.onLoad();
22
- init($container, obj);
23
  }
24
  });
25
  } else {
26
- init($container, obj);
27
  }
28
 
29
- function init($container, obj) {
30
- if ($container.data('init') != true) {
31
- $container.booklyHelp();
32
-
33
- // init 'add break' functionality
34
- $('.bookly-js-toggle-popover:not(.break-interval)', $container).popover({
35
- html: true,
36
- placement: 'bottom',
37
- template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
38
- trigger: 'manual',
39
- content: function () {
40
- return $($(this).data('popover-content')).html()
41
- }
42
- }).on('click', function () {
43
- $(this).popover('toggle');
44
-
45
- var $popover = $(this).next('.popover'),
46
- working_start = $popover.closest('.row').find('.working-schedule-start').val(),
47
- $break_start = $popover.find('.break-start'),
48
- $break_end = $popover.find('.break-end'),
49
- working_start_time = working_start.split(':'),
50
- working_start_hours = parseInt(working_start_time[0], 10),
51
- break_start_hours = working_start_hours + 1;
52
- if (break_start_hours < 10) {
53
- break_start_hours = '0' + break_start_hours;
54
- }
55
- var break_end_hours = working_start_hours + 2;
56
- if (break_end_hours < 10) {
57
- break_end_hours = '0' + break_end_hours;
58
- }
59
- var break_end_hours_str = break_end_hours + ':' + working_start_time[1] + ':' + working_start_time[2],
60
- break_start_hours_str = break_start_hours + ':' + working_start_time[1] + ':' + working_start_time[2];
61
-
62
- $break_start.val(break_start_hours_str);
63
- $break_end.val(break_end_hours_str);
64
-
65
- hideInaccessibleBreaks($break_start, $break_end);
66
-
67
- $popover.find('.bookly-popover-close').on('click', function () {
68
- $popover.prev('.bookly-js-toggle-popover').popover('toggle');
69
- });
70
- });
71
 
72
  $container.off()
73
  // Save Schedule
74
  .on('click', '#bookly-schedule-save', function (e) {
75
  e.preventDefault();
76
- var ladda = Ladda.create(this);
 
77
  ladda.start();
78
- var data = {};
79
- $('select.working-schedule-start, select.working-schedule-end, input:hidden', $container).each(function () {
80
  data[this.name] = this.value;
81
  });
82
  data['location_id'] = $('#staff_location_id', $container).val();
83
  data['custom_location_settings'] = $('#custom_location_settings', $container).val();
84
  data['staff_id'] = options.get_staff_schedule.staff_id;
 
85
  $.post(ajaxurl, $.param(data), function () {
86
  ladda.stop();
87
  obj.options.saving({success: [obj.options.l10n.saved]});
@@ -93,12 +55,12 @@ jQuery(function ($) {
93
  var ladda = Ladda.create(this);
94
  ladda.start();
95
 
96
- $('.working-schedule-start', $container).each(function () {
97
  $(this).val($(this).data('default_value'));
98
  $(this).trigger('change');
99
  });
100
 
101
- $('.working-schedule-end', $container).each(function () {
102
  $(this).val($(this).data('default_value'));
103
  });
104
 
@@ -109,146 +71,94 @@ jQuery(function ($) {
109
  data: {action: 'bookly_staff_cabinet_reset_breaks', breaks: $(this).data('default-breaks'), staff_cabinet: $(this).data('staff-cabinet') || 0, csrf_token: obj.options.l10n.csrfToken},
110
  dataType: 'json',
111
  success: function (response) {
112
- for (var k in response) {
113
- var $content = $(response[k]);
114
- $('[data-staff_schedule_item_id=' + k + '] .breaks', $container).html($content);
115
- $content.find('.bookly-intervals-wrapper .delete-break').on('click', function () {
116
- deleteBreak.call(this);
117
- });
118
- }
 
 
 
 
 
 
119
  },
120
  complete: function () {
121
  ladda.stop();
122
  }
123
  });
124
  })
125
-
126
- .on('click', '.break-interval', function () {
127
- var $button = $(this);
128
- $('.popover').prev('.bookly-js-toggle-popover').popover('toggle');
129
- var break_id = $button.closest('.bookly-intervals-wrapper').data('break_id');
130
- $(this).popover({
131
- html: true,
132
- placement: 'bottom',
133
- template: '<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
134
- content: function () {
135
- return $('.bookly-js-content-break-' + break_id).html();
136
- },
137
- trigger: 'manual'
138
- });
139
-
140
- $(this).popover('toggle');
141
-
142
- var $popover = $(this).next('.popover'),
143
- $break_start = $popover.find('.break-start'),
144
- $break_end = $popover.find('.break-end');
145
-
146
- if ($button.hasClass('break-interval')) {
147
- var interval = $button.html().trim().split(' - ');
148
- rangeTools.setVal($break_start, interval[0]);
149
- rangeTools.setVal($break_end, interval[1]);
150
- }
151
-
152
- hideInaccessibleBreaks($break_start, $break_end, true);
153
-
154
- $popover.find('.bookly-popover-close').on('click', function () {
155
- $popover.prev('.bookly-js-toggle-popover').popover('toggle');
156
- });
157
- })
158
-
159
- .on('click', '.bookly-js-save-break', function (e) {
160
- var $table = $(this).closest('.bookly-js-schedule-form'),
161
- $row = $table.parents('.staff-schedule-item-row').first(),
162
- data = {
163
- action: 'bookly_staff_schedule_handle_break',
164
- staff_schedule_item_id: $row.data('staff_schedule_item_id'),
165
- start_time: $table.find('.break-start > option:selected').val(),
166
- end_time: $table.find('.break-end > option:selected').val(),
167
- working_end: $row.find('.working-schedule-end > option:selected').val(),
168
- working_start: $row.find('.working-schedule-start > option:selected').val(),
169
- csrf_token: obj.options.l10n.csrfToken
170
- },
171
- $break_interval_wrapper = $table.parents('.bookly-intervals-wrapper').first(),
172
- ladda = Ladda.create(e.currentTarget);
173
- ladda.start();
174
-
175
- if ($break_interval_wrapper.data('break_id')) {
176
- data['break_id'] = $break_interval_wrapper.data('break_id');
177
- }
178
  $.ajax({
179
- url : ajaxurl,
180
- type: 'POST',
181
  data: data,
182
  dataType: 'json',
183
  success: function (response) {
184
  if (response.success) {
185
- if (response['item_content']) {
186
- var $new_break_interval_item = $(response['item_content']);
187
- $new_break_interval_item
188
- .hide()
189
- .appendTo($row.find('.breaks-list-content'))
190
- .fadeIn('slow');
191
- } else if (response.data.interval) {
192
- $break_interval_wrapper
193
- .find('.break-interval')
194
- .text(response.data.interval);
195
  }
196
- $('.popover').prev('.bookly-js-toggle-popover').popover('toggle');
197
  } else {
198
- obj.options.booklyAlert({error: [response.data.message]});
 
 
199
  }
200
- },
201
- complete: function () {
202
- ladda.stop();
203
  }
 
 
204
  });
205
-
206
- return false;
207
  })
208
-
209
- .on('click', '.bookly-intervals-wrapper .delete-break', function () {
210
  deleteBreak.call(this);
211
  })
212
 
213
- .on('change', '.break-start', function () {
214
- var $start = $(this);
215
- var $end = $start.parents('.bookly-flexbox').find('.break-end');
216
- hideInaccessibleBreaks($start, $end);
 
 
 
217
  })
218
 
219
- .on('change', '.working-schedule-start', function () {
220
- var $this = $(this),
221
- $end_select = $this.closest('.bookly-flexbox').find('.working-schedule-end'),
222
- start_time = $this.val();
223
-
224
- // Hide end time options to keep them within 24 hours after start time.
225
- var parts = start_time.split(':');
226
- parts[0] = parseInt(parts[0]) + 24;
227
- var end_time = parts.join(':');
228
- var frag = document.createDocumentFragment();
229
- var old_value = $end_select.val();
230
- var new_value = null;
231
- $('option', $end_select).each(function () {
232
- if (this.value <= start_time || this.value > end_time) {
233
- var span = document.createElement('span');
234
- span.style.display = 'none';
235
- span.appendChild(this.cloneNode(true));
236
- frag.appendChild(span);
237
- } else {
238
- frag.appendChild(this.cloneNode(true));
239
- if (new_value === null || old_value == this.value) {
240
- new_value = this.value;
241
- }
242
- }
243
- });
244
- $end_select.empty().append(frag).val(new_value);
245
-
246
- // when the working day is disabled (working start time is set to 'OFF')
247
- // hide all the elements inside the row
248
- if (!$this.val()) {
249
- $this.closest('.row').find('.bookly-hide-on-off').hide();
250
  } else {
251
- $this.closest('.row').find('.bookly-hide-on-off').show();
 
 
 
252
  }
253
  })
254
  // Change location
@@ -271,75 +181,75 @@ jQuery(function ($) {
271
  // Change default/custom settings for location
272
  .on('change', '#custom_location_settings', function () {
273
  if ($(this).val() == 1) {
274
- $('.panel', $container).show();
275
  } else {
276
- $('.panel', $container).hide();
277
  }
278
  })
279
  ;
280
 
281
  $('#custom_location_settings', $container).trigger('change');
282
- $('.working-schedule-start', $container).trigger('change');
283
- $('.break-start', $container).trigger('change');
284
  $container.data('init', true);
285
  }
286
  }
287
 
288
- function hideInaccessibleBreaks($start, $end, force_keep_values) {
289
- var $row = $start.closest('.row'),
290
- $working_start = $row.find('.working-schedule-start'),
291
- $working_end = $row.find('.working-schedule-end'),
292
- frag1 = document.createDocumentFragment(),
293
- frag2 = document.createDocumentFragment(),
294
- old_value = $start.val(),
295
- new_value = null;
296
-
297
- $('option', $start).each(function () {
298
- if ((this.value < $working_start.val() || this.value >= $working_end.val()) && (!force_keep_values || this.value != old_value)) {
299
- var span = document.createElement('span');
300
- span.style.display = 'none';
301
- span.appendChild(this.cloneNode(true));
302
- frag1.appendChild(span);
303
- } else {
304
- frag1.appendChild(this.cloneNode(true));
305
- if (new_value === null || old_value == this.value) {
306
- new_value = this.value;
307
- }
308
- }
309
- });
310
- $start.empty().append(frag1).val(new_value);
 
 
 
 
 
 
 
 
 
 
 
311
 
312
- // Hide end time options with value less than in the start time.
313
- old_value = $end.val();
314
- new_value = null;
315
- $('option', $end).each(function () {
316
- if ((this.value <= $start.val() || this.value > $working_end.val()) && (!force_keep_values || this.value != old_value)) {
317
- var span = document.createElement('span');
318
- span.style.display = 'none';
319
- span.appendChild(this.cloneNode(true));
320
- frag2.appendChild(span);
321
- } else {
322
- frag2.appendChild(this.cloneNode(true));
323
- if (new_value === null || old_value == this.value) {
324
- new_value = this.value;
325
  }
326
- }
327
- });
328
- $end.empty().append(frag2).val(new_value);
 
 
329
  }
330
 
331
  function deleteBreak() {
332
- var $break_interval_wrapper = $(this).closest('.bookly-intervals-wrapper');
333
  if (confirm(obj.options.l10n.areYouSure)) {
334
  var ladda = Ladda.create(this);
335
  ladda.start();
336
  $.ajax({
337
  url: ajaxurl,
338
  type: 'POST',
339
- data: {action: 'bookly_delete_staff_schedule_break', id: $break_interval_wrapper.data('break_id'), csrf_token: obj.options.l10n.csrfToken},
340
  success: function (response) {
341
  if (response.success) {
342
- $break_interval_wrapper.remove();
343
  }
344
  },
345
  complete: function () {
@@ -367,5 +277,4 @@ jQuery(function ($) {
367
  };
368
 
369
  window.BooklyStaffSchedule = Schedule;
370
- });
371
-
1
+ (function ($) {
2
  var Schedule = function ($container, options) {
3
+ let obj = this;
4
+ jQuery.extend(obj.options, options);
5
 
6
  // Loads schedule list
7
  if (!$container.children().length) {
19
  $container.append(response.data.html);
20
  $container.removeData('init');
21
  obj.options.onLoad();
22
+ initContainer($container, obj);
23
  }
24
  });
25
  } else {
26
+ initContainer($container, obj);
27
  }
28
 
29
+ function initContainer($panel, obj) {
30
+ if ($panel.data('init') != true) {
31
+ initBooklyPopover($container);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  $container.off()
34
  // Save Schedule
35
  .on('click', '#bookly-schedule-save', function (e) {
36
  e.preventDefault();
37
+ let ladda = Ladda.create(this),
38
+ data = {};
39
  ladda.start();
40
+ $('select.bookly-js-parent-range-start, select.bookly-js-parent-range-end, input:hidden', $container).each(function () {
 
41
  data[this.name] = this.value;
42
  });
43
  data['location_id'] = $('#staff_location_id', $container).val();
44
  data['custom_location_settings'] = $('#custom_location_settings', $container).val();
45
  data['staff_id'] = options.get_staff_schedule.staff_id;
46
+ data['action'] = 'bookly_staff_schedule_update';
47
  $.post(ajaxurl, $.param(data), function () {
48
  ladda.stop();
49
  obj.options.saving({success: [obj.options.l10n.saved]});
55
  var ladda = Ladda.create(this);
56
  ladda.start();
57
 
58
+ $('.bookly-js-parent-range-start', $container).each(function () {
59
  $(this).val($(this).data('default_value'));
60
  $(this).trigger('change');
61
  });
62
 
63
+ $('.bookly-js-parent-range-end', $container).each(function () {
64
  $(this).val($(this).data('default_value'));
65
  });
66
 
71
  data: {action: 'bookly_staff_cabinet_reset_breaks', breaks: $(this).data('default-breaks'), staff_cabinet: $(this).data('staff-cabinet') || 0, csrf_token: obj.options.l10n.csrfToken},
72
  dataType: 'json',
73
  success: function (response) {
74
+ $('[data-index]', $container).each(function () {
75
+ let $row = $(this),
76
+ index = $row.data('index'),
77
+ $list = $('.bookly-js-breaks-list', $row);
78
+ $list.html('');
79
+ if (response.data.breaks.hasOwnProperty(index)) {
80
+ response.data.breaks[index].forEach(elem => {
81
+ var $html = $.parseHTML(elem);
82
+ initBooklyPopover($html);
83
+ $list.append($html)
84
+ });
85
+ }
86
+ });
87
  },
88
  complete: function () {
89
  ladda.stop();
90
  }
91
  });
92
  })
93
+ .on('click', '.popover-body :submit', function (e) {
94
+ e.preventDefault();
95
+ // Listener for saving break.
96
+ let $button = $(this),
97
+ $body = $button.closest('.popover-body'),
98
+ ladda = rangeTools.ladda(this),
99
+ data = $.extend({
100
+ action : 'bookly_staff_schedule_handle_break',
101
+ csrf_token: obj.options.l10n.csrfToken,
102
+ start_time: $('.bookly-js-popover-range-start', $body).val(),
103
+ end_time : $('.bookly-js-popover-range-end', $body).val(),
104
+ }, $button.data('submit'));
105
+ let $parentRange = $('.bookly-js-range-row[data-key=' + data.ss_id + ']');
106
+
107
+ data.working_end = $('.bookly-js-parent-range-end > option:selected', $parentRange).val();
108
+ data.working_start = $('.bookly-js-parent-range-start > option:selected', $parentRange).val();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  $.ajax({
110
+ method: 'POST',
111
+ url: ajaxurl,
112
  data: data,
113
  dataType: 'json',
114
  success: function (response) {
115
  if (response.success) {
116
+ if (data.hasOwnProperty('id')) {
117
+ // Change text on button with new range value.
118
+ var $interval_button = $('button.bookly-js-break-interval', $('[data-entity-id=' + data.id + ']'));
119
+ $interval_button.html(response.data.interval);
120
+ } else {
121
+ var $html = $.parseHTML(response.data.html);
122
+ initBooklyPopover($html);
123
+ $('.bookly-js-range-row[data-key=' + data.ss_id + '] .bookly-js-breaks-list', $container)
124
+ .append($html);
 
125
  }
126
+ $button.parents('.bookly-popover').booklyPopover('hide');
127
  } else {
128
+ if (response.data && response.data.message) {
129
+ obj.options.booklyAlert({error: [response.data.message]});
130
+ }
131
  }
 
 
 
132
  }
133
+ }).always(function () {
134
+ ladda.stop()
135
  });
 
 
136
  })
137
+ .on('click', '.bookly-js-delete-break', function () {
 
138
  deleteBreak.call(this);
139
  })
140
 
141
+ .on('change', '.bookly-js-popover-range-start', function () {
142
+ let $start = $(this),
143
+ $body = $start.closest('.popover-body'),
144
+ $end = $('.bookly-js-popover-range-end', $body),
145
+ ss_id = $(':submit', $body).data('submit').ss_id,
146
+ $parent = $('.bookly-js-range-row[data-key=' + ss_id + ']');
147
+ rangeTools.hideInaccessibleBreaks($start, $end, $parent);
148
  })
149
 
150
+ .on('change', '.bookly-js-parent-range-start', function () {
151
+ var $parentRangeStart = $(this),
152
+ $rangeRow = $parentRangeStart.parents('.bookly-js-range-row');
153
+ if ($parentRangeStart.val() == '') {
154
+ $rangeRow
155
+ .find('.bookly-js-hide-on-off').hide().end()
156
+ .find('.bookly-js-invisible-on-off').addClass('invisible');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
  } else {
158
+ $rangeRow
159
+ .find('.bookly-js-hide-on-off').show().end()
160
+ .find('.bookly-js-invisible-on-off').removeClass('invisible');
161
+ rangeTools.hideInaccessibleEndTime($parentRangeStart, $('.bookly-js-parent-range-end', $rangeRow));
162
  }
163
  })
164
  // Change location
181
  // Change default/custom settings for location
182
  .on('change', '#custom_location_settings', function () {
183
  if ($(this).val() == 1) {
184
+ $('.bookly-js-range-row', $container).show();
185
  } else {
186
+ $('.bookly-js-range-row', $container).hide();
187
  }
188
  })
189
  ;
190
 
191
  $('#custom_location_settings', $container).trigger('change');
192
+ $('.bookly-js-parent-range-start', $container).trigger('change');
 
193
  $container.data('init', true);
194
  }
195
  }
196
 
197
+ function initBooklyPopover($panel) {
198
+ $('.bookly-js-toggle-popover', $panel)
199
+ .booklyPopover({
200
+ html : true,
201
+ placement: 'bottom',
202
+ container: $container,
203
+ template : '<div class="bookly-popover mw-100" role="tooltip"><div class="arrow"></div><div class="popover-body"></div></div>',
204
+ trigger : 'manual',
205
+ content : function () {
206
+ let $button = $(this),
207
+ $popover = $('.bookly-js-edit-break-body > div', $container).clone(),
208
+ $popoverStart = $('.bookly-js-popover-range-start', $popover),
209
+ $popoverEnd = $('.bookly-js-popover-range-end', $popover),
210
+ $saveButton = $(':submit', $popover),
211
+ force_keep_values = false;
212
+ if ($button.hasClass('bookly-js-break-interval')) {
213
+ let interval = $button.html().trim().split(' - ');
214
+ rangeTools.setVal($popoverStart, interval[0]);
215
+ rangeTools.setVal($popoverEnd, interval[1]);
216
+ force_keep_values = true;
217
+ $saveButton.data('submit', {
218
+ id: $button.closest('[data-entity-id]').data('entity-id'),
219
+ ss_id: $button.closest('.bookly-js-range-row').data('key'),
220
+ });
221
+ } else {
222
+ rangeTools.setPopoverRangeDefault($popoverStart, $popoverEnd, $button.closest('.bookly-js-range-row'));
223
+ $saveButton.data('submit', {
224
+ ss_id: $button.closest('.bookly-js-range-row').data('key'),
225
+ });
226
+ }
227
+ rangeTools.hideInaccessibleBreaks($popoverStart, $popoverEnd, $button.closest('.bookly-js-range-row'), force_keep_values);
228
+ $('.bookly-js-close', $popover).on('click', function () {
229
+ $button.booklyPopover('hide');
230
+ });
231
 
232
+ return $popover;
 
 
 
 
 
 
 
 
 
 
 
 
233
  }
234
+ })
235
+ .on('click', function () {
236
+ $('.bookly-js-toggle-popover').booklyPopover('hide');
237
+ $(this).booklyPopover('toggle');
238
+ });
239
  }
240
 
241
  function deleteBreak() {
242
+ var $btn_group = $(this).closest('[data-entity-id]');
243
  if (confirm(obj.options.l10n.areYouSure)) {
244
  var ladda = Ladda.create(this);
245
  ladda.start();
246
  $.ajax({
247
  url: ajaxurl,
248
  type: 'POST',
249
+ data: {action: 'bookly_delete_staff_schedule_break', id: $btn_group.data('entity-id'), csrf_token: obj.options.l10n.csrfToken},
250
  success: function (response) {
251
  if (response.success) {
252
+ $btn_group.remove();
253
  }
254
  },
255
  complete: function () {
277
  };
278
 
279
  window.BooklyStaffSchedule = Schedule;
280
+ })(jQuery);
 
backend/components/dialogs/staff/edit/resources/js/staff-services.js CHANGED
@@ -1,4 +1,4 @@
1
- jQuery(function ($) {
2
 
3
  var Services = function($container, options) {
4
  var obj = this;
@@ -30,29 +30,29 @@ jQuery(function ($) {
30
  function init($container, obj) {
31
  if ($container.data('init') != true) {
32
  let $services_form = $('form', $container);
33
- $services_form.booklyHelp();
34
  $(document.body).trigger('special_hours.tab_init', [$container, obj.options]);
35
  var autoTickCheckboxes = function () {
36
  // Handle 'select category' checkbox.
37
- $('.bookly-services-category .bookly-category-checkbox').each(function () {
38
  $(this).prop(
39
  'checked',
40
- $('.bookly-category-services .bookly-service-checkbox.bookly-category-' + $(this).data('category-id') + ':not(:checked)').length == 0
41
  );
42
  });
43
  // Handle 'select all services' checkbox.
44
  $('#bookly-check-all-entities').prop(
45
  'checked',
46
- $('.bookly-service-checkbox:not(:checked)').length == 0
47
  );
48
  };
49
  var checkCapacityError = function ($form_group) {
50
  if (parseInt($form_group.find('.bookly-js-capacity-min').val()) > parseInt($form_group.find('.bookly-js-capacity-max').val())) {
51
- $form_group.addClass('has-error');
52
  } else {
53
- $form_group.removeClass('has-error');
54
  }
55
- let has_errors = $('.bookly-js-capacity-form-group.has-error', $container).length != 0;
56
 
57
  if (has_errors) {
58
  $services_form.find('.bookly-js-services-error').html(obj.options.l10n.capacity_error);
@@ -66,17 +66,17 @@ jQuery(function ($) {
66
 
67
  $services_form
68
  // Select all services related to chosen category
69
- .on('click', '.bookly-category-checkbox', function () {
70
- $('.bookly-category-services .bookly-category-' + $(this).data('category-id')).prop('checked', $(this).is(':checked')).change();
71
  autoTickCheckboxes();
72
  })
73
  // Check and uncheck all services
74
  .on('click', '#bookly-check-all-entities', function () {
75
- $('.bookly-service-checkbox', $services_form).prop('checked', $(this).is(':checked')).change();
76
- $('.bookly-category-checkbox').prop('checked', $(this).is(':checked'));
77
  })
78
  // Select service
79
- .on('click', '.bookly-service-checkbox', function () {
80
  autoTickCheckboxes();
81
  })
82
  // Save services
@@ -106,7 +106,7 @@ jQuery(function ($) {
106
  $('.bookly-js-capacity-form-group', $services_form).each(function () {
107
  checkCapacityError($(this));
108
  });
109
- $('.bookly-service-checkbox', $services_form).trigger('change');
110
  }, 0);
111
  })
112
  // Change location
@@ -128,13 +128,13 @@ jQuery(function ($) {
128
  // Change default/custom settings for location
129
  .on('change', '#custom_location_settings', function () {
130
  if ($(this).val() == 1) {
131
- $('.panel', $services_form).show();
132
  } else {
133
- $('.panel', $services_form).hide();
134
  }
135
  });
136
 
137
- $('.bookly-service-checkbox').on('change', function () {
138
  var $this = $(this),
139
  $service = $this.closest('li'),
140
  $inputs = $service.find('input:not(:checkbox)');
@@ -143,12 +143,12 @@ jQuery(function ($) {
143
 
144
  // Handle package-service connections
145
  if ($(this).is(':checked') && $service.data('service-type') == 'package') {
146
- $('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-service-checkbox', $services_form).prop('checked', true).trigger('change');
147
  $('.bookly-js-capacity-min', $service).val($('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-capacity-min', $services_form).val());
148
  $('.bookly-js-capacity-max', $service).val($('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-capacity-max', $services_form).val());
149
  }
150
  if (!$(this).is(':checked') && $service.data('service-type') == 'simple') {
151
- $('li[data-service-type="package"][data-sub-service="' + $service.data('service-id') + '"] .bookly-service-checkbox', $services_form).prop('checked', false).trigger('change');
152
  }
153
  });
154
 
@@ -187,4 +187,4 @@ jQuery(function ($) {
187
  };
188
 
189
  window.BooklyStaffServices = Services;
190
- });
1
+ (function ($) {
2
 
3
  var Services = function($container, options) {
4
  var obj = this;
30
  function init($container, obj) {
31
  if ($container.data('init') != true) {
32
  let $services_form = $('form', $container);
33
+
34
  $(document.body).trigger('special_hours.tab_init', [$container, obj.options]);
35
  var autoTickCheckboxes = function () {
36
  // Handle 'select category' checkbox.
37
+ $('.bookly-js-category-checkbox').each(function () {
38
  $(this).prop(
39
  'checked',
40
+ $('.bookly-js-category-services .bookly-js-service-checkbox[data-category-id="' + $(this).data('category-id') + '"]:not(:checked)').length == 0
41
  );
42
  });
43
  // Handle 'select all services' checkbox.
44
  $('#bookly-check-all-entities').prop(
45
  'checked',
46
+ $('.bookly-js-service-checkbox:not(:checked)').length == 0
47
  );
48
  };
49
  var checkCapacityError = function ($form_group) {
50
  if (parseInt($form_group.find('.bookly-js-capacity-min').val()) > parseInt($form_group.find('.bookly-js-capacity-max').val())) {
51
+ $form_group.find('input').addClass('is-invalid');
52
  } else {
53
+ $form_group.find('input').removeClass('is-invalid');
54
  }
55
+ let has_errors = $('.bookly-js-capacity-form-group .is-invalid', $container).length != 0;
56
 
57
  if (has_errors) {
58
  $services_form.find('.bookly-js-services-error').html(obj.options.l10n.capacity_error);
66
 
67
  $services_form
68
  // Select all services related to chosen category
69
+ .on('click', '.bookly-js-category-checkbox', function () {
70
+ $('.bookly-js-category-services [data-category-id="' + $(this).data('category-id') + '"]').prop('checked', $(this).is(':checked')).change();
71
  autoTickCheckboxes();
72
  })
73
  // Check and uncheck all services
74
  .on('click', '#bookly-check-all-entities', function () {
75
+ $('.bookly-js-service-checkbox', $services_form).prop('checked', $(this).is(':checked')).change();
76
+ $('.bookly-js-category-checkbox').prop('checked', $(this).is(':checked'));
77
  })
78
  // Select service
79
+ .on('click', '.bookly-js-service-checkbox', function () {
80
  autoTickCheckboxes();
81
  })
82
  // Save services
106
  $('.bookly-js-capacity-form-group', $services_form).each(function () {
107
  checkCapacityError($(this));
108
  });
109
+ $('.bookly-js-service-checkbox', $services_form).trigger('change');
110
  }, 0);
111
  })
112
  // Change location
128
  // Change default/custom settings for location
129
  .on('change', '#custom_location_settings', function () {
130
  if ($(this).val() == 1) {
131
+ $('#bookly-staff-services', $services_form).show();
132
  } else {
133
+ $('#bookly-staff-services', $services_form).hide();
134
  }
135
  });
136
 
137
+ $('.bookly-js-service-checkbox').on('change', function () {
138
  var $this = $(this),
139
  $service = $this.closest('li'),
140
  $inputs = $service.find('input:not(:checkbox)');
143
 
144
  // Handle package-service connections
145
  if ($(this).is(':checked') && $service.data('service-type') == 'package') {
146
+ $('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-service-checkbox', $services_form).prop('checked', true).trigger('change');
147
  $('.bookly-js-capacity-min', $service).val($('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-capacity-min', $services_form).val());
148
  $('.bookly-js-capacity-max', $service).val($('li[data-service-type="simple"][data-service-id="' + $service.data('sub-service') + '"] .bookly-js-capacity-max', $services_form).val());
149
  }
150
  if (!$(this).is(':checked') && $service.data('service-type') == 'simple') {
151
+ $('li[data-service-type="package"][data-sub-service="' + $service.data('service-id') + '"] .bookly-js-service-checkbox', $services_form).prop('checked', false).trigger('change');
152
  }
153
  });
154
 
187
  };
188
 
189
  window.BooklyStaffServices = Services;
190
+ })(jQuery);
backend/components/dialogs/staff/edit/templates/_break.php DELETED
@@ -1,37 +0,0 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
- use Bookly\Backend\Components\Controls\Buttons;
3
- ?>
4
- <div class="bookly-intervals-wrapper bookly-hide-on-off" data-break_id="<?php echo $staff_schedule_item_break_id ?>">
5
- <div class="btn-group btn-group-sm bookly-margin-top-sm">
6
- <button type="button" class="btn btn-info bookly-js-toggle-popover break-interval"
7
- data-popover-content=".bookly-js-content-break-<?php echo $staff_schedule_item_break_id ?>">
8
- <?php echo $formatted_interval ?>
9
- </button>
10
- <button title="<?php _e( 'Delete break', 'bookly' ) ?>" type="button" class="btn btn-info delete-break ladda-button" data-style="zoom-in" data-spinner-size="20"><span class="ladda-label">&times;</span></button>
11
- </div>
12
-
13
- <div class="bookly-js-content-break-<?php echo $staff_schedule_item_break_id ?> hidden">
14
- <div class="bookly-js-schedule-form">
15
- <div class="bookly-flexbox" style="width: 280px;">
16
- <div class="bookly-flex-cell" style="width: 48%;">
17
- <?php echo $break_start_choices ?>
18
- </div>
19
- <div class="bookly-flex-cell" style="width: 4%;">
20
- <div class="bookly-margin-horizontal-lg">
21
- <?php _e( 'to', 'bookly' ) ?>
22
- </div>
23
- </div>
24
- <div class="bookly-flex-cell" style="width: 48%;">
25
- <?php echo $break_end_choices ?>
26
- </div>
27
- </div>
28
-
29
- <hr>
30
-
31
- <div class="clearfix text-right">
32
- <?php Buttons::renderSubmit( null, 'bookly-js-save-break' ) ?>
33
- <?php Buttons::renderCustom( null, 'bookly-popover-close btn-lg btn-default', __( 'Close', 'bookly' ) ) ?>
34
- </div>
35
- </div>
36
- </div>
37
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/components/dialogs/staff/edit/templates/_breaks.php DELETED
@@ -1,41 +0,0 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
- /** @var \Bookly\Lib\Entities\StaffScheduleItem $item */
3
- $breaks_list = $item->getBreaksList();
4
- ?>
5
- <div class="breaks-list">
6
- <?php if ( $breaks_list ) : ?>
7
- <div class="bookly-font-smaller bookly-margin-bottom-xs bookly-color-gray visible-xs visible-sm">
8
- <?php _e( 'Breaks', 'bookly' ) ?>
9
- </div>
10
- <?php endif ?>
11
-
12
- <div class="breaks-list-content">
13
- <?php foreach ( $breaks_list as $break_interval ) :
14
- if ( isset ( $default_breaks ) ) {
15
- $default_breaks['breaks'][] = array(
16
- 'start_time' => $break_interval['start_time'],
17
- 'end_time' => $break_interval['end_time'],
18
- 'staff_schedule_item_id' => $break_interval['staff_schedule_item_id'],
19
- );
20
- }
21
- $break_start_choices = $break_start->render(
22
- '',
23
- $break_interval['start_time'],
24
- array( 'class' => 'break-start form-control' )
25
- );
26
-
27
- $break_end_choices = $break_end->render(
28
- '',
29
- $break_interval['end_time'],
30
- array( 'class' => 'break-end form-control' )
31
- );
32
-
33
- $self::renderTemplate( '_break', array(
34
- 'break_start_choices' => $break_start_choices,
35
- 'break_end_choices' => $break_end_choices,
36
- 'formatted_interval' => \Bookly\Lib\Utils\DateTime::formatInterval( $break_interval['start_time'], $break_interval['end_time'] ),
37
- 'staff_schedule_item_break_id' => $break_interval['id'],
38
- ) );
39
- endforeach ?>
40
- </div>
41
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/components/dialogs/staff/edit/templates/details.php CHANGED
@@ -7,56 +7,52 @@ use Bookly\Lib\Config;
7
  /** @var Bookly\Lib\Entities\Staff $staff */
8
  ?>
9
  <form class="bookly-js-staff-details">
10
- <div class="bookly-flexbox bookly-margin-bottom-lg">
11
- <div class="bookly-flex-cell bookly-vertical-middle" style="width: 1%">
12
- <div id="bookly-js-staff-avatar" class="bookly-thumb bookly-thumb-lg bookly-margin-right-lg">
13
- <div class="bookly-flex-cell" style="width: 100%">
14
- <div class="form-group">
15
- <?php $img = wp_get_attachment_image_src( $staff->getAttachmentId(), 'thumbnail' ) ?>
16
 
17
- <div class="bookly-js-image bookly-thumb bookly-thumb-lg bookly-margin-right-lg"
18
- <?php echo $img ? 'style="background-image: url(' . $img[0] . '); background-size: cover;"' : '' ?>
19
- >
20
- <a class="dashicons dashicons-trash text-danger bookly-thumb-delete"
21
- href="javascript:void(0)"
22
- title="<?php esc_attr_e( 'Delete', 'bookly' ) ?>"
23
- <?php if ( ! $img ) : ?>style="display: none;"<?php endif ?>>
24
- </a>
25
- <div class="bookly-thumb-edit">
26
- <div class="bookly-pretty">
27
- <label class="bookly-pretty-indicator bookly-thumb-edit-btn">
28
- <?php esc_html_e( 'Image', 'bookly' ) ?>
29
- </label>
30
- </div>
31
  </div>
32
  </div>
33
  </div>
34
  </div>
35
  </div>
36
- </div>
37
- <div style="font-size: 27px;margin-left: -10px;"><?php Proxy\Ratings::renderStaffServiceRating( $staff->getId(), null, 'left' ) ?></div>
38
- <div class="form-group" style="margin-top: 20px; margin-bottom: 0px">
39
- <label for="bookly-full-name"><?php esc_html_e( 'Full name', 'bookly' ) ?></label>
40
- <input type="text" class="form-control" id="bookly-full-name" name="full_name" value="<?php echo esc_attr( $staff->getFullName() ) ?>"/>
 
41
  </div>
42
  </div>
43
 
44
  <?php if ( Common::isCurrentUserAdmin() ) : ?>
45
  <div class="form-group">
46
  <label for="bookly-wp-user"><?php esc_html_e( 'User', 'bookly' ) ?></label>
47
-
48
- <p class="help-block">
49
- <?php esc_html_e( 'If this staff member requires separate login to access personal calendar, a regular WP user needs to be created for this purpose.', 'bookly' ) ?>
50
- <?php esc_html_e( 'User with "Administrator" role will have access to calendars and settings of all staff members, user with another role will have access only to personal calendar and settings.', 'bookly' ) ?>
51
- <?php esc_html_e( 'If you leave this field blank, this staff member will not be able to access personal calendar using WP backend.', 'bookly' ) ?>
52
- </p>
53
-
54
- <select class="form-control" name="wp_user_id" id="bookly-wp-user">
55
  <option value=""><?php esc_html_e( 'Select from WP users', 'bookly' ) ?></option>
56
  <?php foreach ( $users_for_staff as $user ) : ?>
57
  <option value="<?php echo $user->ID ?>" data-email="<?php echo $user->user_email ?>" <?php selected( $user->ID, $staff->getWpUserId() ) ?>><?php echo $user->display_name ?></option>
58
  <?php endforeach ?>
59
  </select>
 
 
 
 
 
60
  </div>
61
  <?php endif ?>
62
 
@@ -81,20 +77,27 @@ use Bookly\Lib\Config;
81
 
82
  <div class="form-group">
83
  <label for="bookly-info"><?php esc_html_e( 'Info', 'bookly' ) ?></label>
84
- <p class="help-block">
85
- <?php printf( __( 'This text can be inserted into notifications with %s code.', 'bookly' ), '{staff_info}' ) ?>
86
- </p>
87
  <textarea id="bookly-info" name="info" rows="3" class="form-control"><?php echo esc_textarea( $staff->getInfo() ) ?></textarea>
 
88
  </div>
89
 
90
  <div class="form-group" id="bookly-visibility" data-default="<?php echo esc_attr( $staff->getVisibility() ) ?>">
91
  <label><?php esc_html_e( 'Visibility', 'bookly' ) ?></label>
92
- <p class="help-block"><?php esc_html_e( 'To make staff member invisible to your customers set the visibility to "Private".', 'bookly' ) ?></p>
93
- <div class="radio"><label><input type="radio" name="visibility" value="public" <?php checked( $staff->getVisibility(), 'public' ) ?>><?php esc_html_e( 'Public', 'bookly' ) ?></label></div>
94
- <div class="radio"><label><input type="radio" name="visibility" value="private" <?php checked( $staff->getVisibility(), 'private' ) ?>><?php esc_html_e( 'Private', 'bookly' ) ?></label></div>
 
 
 
 
 
95
  <?php if ( Config::proActive() || $staff->getVisibility() === 'archive' ) : ?>
96
- <div class="radio"><label><input type="radio" name="visibility" value="archive" <?php checked( $staff->getVisibility(), 'archive' ) ?>><?php esc_html_e( 'Archive', 'bookly' ) ?></label></div>
 
 
 
97
  <?php endif ?>
 
98
  </div>
99
 
100
  <?php Proxy\Pro::renderStaffDetails( $staff ) ?>
@@ -107,11 +110,11 @@ use Bookly\Lib\Config;
107
  <input type="hidden" name="attachment_id" value="<?php echo $staff->getAttachmentId() ?>">
108
  <?php Inputs::renderCsrf() ?>
109
 
110
- <div class="panel-footer">
111
  <?php if ( Common::isCurrentUserAdmin() ) : ?>
112
- <?php Buttons::renderDelete( 'bookly-staff-delete', 'btn-lg pull-left' ) ?>
113
- <?php Buttons::renderCustom( null, 'btn-lg btn-danger ladda-button bookly-js-staff-archive pull-left', esc_html__( 'Archive', 'bookly' ), !Config::proActive() || $staff->getVisibility() == 'archive' ? array( 'style' => 'display:none;' ) : array(), '<i class="fa fa-archive"></i> {caption}' ) ?>
114
  <?php endif ?>
115
- <?php Buttons::renderCustom( 'bookly-details-save', 'btn-lg btn-success bookly-js-save', esc_html__( 'Save', 'bookly' ) ) ?>
116
  </div>
117
  </form>
7
  /** @var Bookly\Lib\Entities\Staff $staff */
8
  ?>
9
  <form class="bookly-js-staff-details">
10
+ <div class="row">
11
+ <div class="col-md-auto">
12
+ <div id="bookly-js-staff-avatar">
13
+ <div class="form-group">
14
+ <?php $img = wp_get_attachment_image_src( $staff->getAttachmentId(), 'thumbnail' ) ?>
 
15
 
16
+ <div class="bookly-js-image bookly-thumb"
17
+ <?php echo $img ? 'style="background-image: url(' . $img[0] . '); background-size: cover;"' : '' ?>
18
+ >
19
+ <a class="far fa-fw fa-trash-alt text-danger bookly-thumb-delete bookly-js-delete"
20
+ href="javascript:void(0)"
21
+ title="<?php esc_attr_e( 'Delete', 'bookly' ) ?>"
22
+ <?php if ( ! $img ) : ?>style="display: none;"<?php endif ?>>
23
+ </a>
24
+ <div class="bookly-thumb-edit">
25
+ <label class="bookly-thumb-edit-btn">
26
+ <?php esc_html_e( 'Image', 'bookly' ) ?>
27
+ </label>
 
 
28
  </div>
29
  </div>
30
  </div>
31
  </div>
32
  </div>
33
+ <div class="col">
34
+ <div style="font-size: 27px;"><?php Proxy\Ratings::renderStaffServiceRating( $staff->getId(), null, 'left' ) ?></div>
35
+ <div class="form-group">
36
+ <label for="bookly-full-name"><?php esc_html_e( 'Full name', 'bookly' ) ?></label>
37
+ <input type="text" class="form-control" id="bookly-full-name" name="full_name" value="<?php echo esc_attr( $staff->getFullName() ) ?>"/>
38
+ </div>
39
  </div>
40
  </div>
41
 
42
  <?php if ( Common::isCurrentUserAdmin() ) : ?>
43
  <div class="form-group">
44
  <label for="bookly-wp-user"><?php esc_html_e( 'User', 'bookly' ) ?></label>
45
+ <select class="form-control custom-select" name="wp_user_id" id="bookly-wp-user">
 
 
 
 
 
 
 
46
  <option value=""><?php esc_html_e( 'Select from WP users', 'bookly' ) ?></option>
47
  <?php foreach ( $users_for_staff as $user ) : ?>
48
  <option value="<?php echo $user->ID ?>" data-email="<?php echo $user->user_email ?>" <?php selected( $user->ID, $staff->getWpUserId() ) ?>><?php echo $user->display_name ?></option>
49
  <?php endforeach ?>
50
  </select>
51
+ <small class="form-text text-muted">
52
+ <?php esc_html_e( 'If this staff member requires separate login to access personal calendar, a regular WP user needs to be created for this purpose.', 'bookly' ) ?>
53
+ <?php esc_html_e( 'User with "Administrator" role will have access to calendars and settings of all staff members, user with another role will have access only to personal calendar and settings.', 'bookly' ) ?>
54
+ <?php esc_html_e( 'If you leave this field blank, this staff member will not be able to access personal calendar using WP backend.', 'bookly' ) ?>
55
+ </small>
56
  </div>
57
  <?php endif ?>
58
 
77
 
78
  <div class="form-group">
79
  <label for="bookly-info"><?php esc_html_e( 'Info', 'bookly' ) ?></label>
 
 
 
80
  <textarea id="bookly-info" name="info" rows="3" class="form-control"><?php echo esc_textarea( $staff->getInfo() ) ?></textarea>
81
+ <small class="form-text text-muted"><?php printf( esc_html__( 'This text can be inserted into notifications with %s code.', 'bookly' ), '{staff_info}' ) ?></small>
82
  </div>
83
 
84
  <div class="form-group" id="bookly-visibility" data-default="<?php echo esc_attr( $staff->getVisibility() ) ?>">
85
  <label><?php esc_html_e( 'Visibility', 'bookly' ) ?></label>
86
+ <div class="custom-control custom-radio">
87
+ <input type="radio" name="visibility" id="bookly-visibility-public" value="public" <?php checked( $staff->getVisibility(), 'public' ) ?> class="custom-control-input" />
88
+ <label for="bookly-visibility-public" class="custom-control-label"><?php esc_html_e( 'Public', 'bookly' ) ?></label>
89
+ </div>
90
+ <div class="custom-control custom-radio">
91
+ <input type="radio" name="visibility" id="bookly-visibility-private" value="private" <?php checked( $staff->getVisibility(), 'private' ) ?> class="custom-control-input" />
92
+ <label for="bookly-visibility-private" class="custom-control-label"><?php esc_html_e( 'Private', 'bookly' ) ?></label>
93
+ </div>
94
  <?php if ( Config::proActive() || $staff->getVisibility() === 'archive' ) : ?>
95
+ <div class="custom-control custom-radio">
96
+ <input type="radio" name="visibility" id="bookly-visibility-archive" value="archive" <?php checked( $staff->getVisibility(), 'archive' ) ?> class="custom-control-input" />
97
+ <label for="bookly-visibility-archive" class="custom-control-label"><?php esc_html_e( 'Archive', 'bookly' ) ?></label>
98
+ </div>
99
  <?php endif ?>
100
+ <small class="form-text text-muted"><?php esc_html_e( 'To make staff member invisible to your customers set the visibility to "Private".', 'bookly' ) ?></small>
101
  </div>
102
 
103
  <?php Proxy\Pro::renderStaffDetails( $staff ) ?>
110
  <input type="hidden" name="attachment_id" value="<?php echo $staff->getAttachmentId() ?>">
111
  <?php Inputs::renderCsrf() ?>
112
 
113
+ <div class="bookly-js-modal-footer">
114
  <?php if ( Common::isCurrentUserAdmin() ) : ?>
115
+ <?php Buttons::renderDelete( 'bookly-staff-delete' ) ?>
116
+ <?php Buttons::render( null, 'btn-danger ladda-button bookly-js-staff-archive', __( 'Archive', 'bookly' ), !Config::proActive() || $staff->getVisibility() == 'archive' ? array( 'style' => 'display:none;' ) : array(), '<i class="fas fa-fw fa-archive mr-1"></i>{caption}' ) ?>
117
  <?php endif ?>
118
+ <?php Buttons::render( 'bookly-details-save', 'btn-success bookly-js-save', __( 'Save', 'bookly' ) ) ?>
119
  </div>
120
  </form>
backend/components/dialogs/staff/edit/templates/dialog.php CHANGED
@@ -5,26 +5,32 @@ use Bookly\Lib\Utils\Common;
5
 
6
  /** @var Bookly\Lib\Entities\Staff $staff */
7
  ?>
8
- <form id="bookly-staff-edit-modal" class="modal fade" tabindex=-1 role="dialog">
9
  <div class="modal-dialog modal-lg">
10
  <div class="modal-content">
11
  <div class="modal-header">
12
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
13
- <div class="modal-title h2"></div>
14
  </div>
15
  <div class="modal-body">
16
 
17
  </div>
18
  <div class="modal-footer">
19
- <?php if ( Common::isCurrentUserAdmin() ) : ?>
20
- <?php Buttons::renderDelete( 'bookly-staff-delete', 'btn-lg pull-left bookly-js-hide-on-loading' ) ?>
21
- <?php if ( Config::proActive() ) : ?>
22
- <?php Buttons::renderCustom( null, 'btn-lg btn-danger ladda-button bookly-js-staff-archive pull-left bookly-js-hide-on-loading', esc_html__( 'Archive', 'bookly' ) . '...', array(), '<i class="fa fa-archive"></i> {caption}' ) ?>
 
 
23
  <?php endif ?>
24
- <?php endif ?>
25
- <span class="bookly-js-errors text-danger" style="max-width: 353px;display: inline-grid;"></span>
26
- <?php Buttons::renderCustom( null, 'btn-lg btn-success bookly-js-save bookly-js-hide-on-loading', esc_html__( 'Save', 'bookly' ) ) ?>
27
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
 
 
 
 
28
  </div>
29
  </div>
30
  </div>
5
 
6
  /** @var Bookly\Lib\Entities\Staff $staff */
7
  ?>
8
+ <form id="bookly-staff-edit-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
9
  <div class="modal-dialog modal-lg">
10
  <div class="modal-content">
11
  <div class="modal-header">
12
+ <div class="modal-title h5"></div>
13
+ <button type="button" class="close" data-dismiss="bookly-modal"><span>×</span></button>
14
  </div>
15
  <div class="modal-body">
16
 
17
  </div>
18
  <div class="modal-footer">
19
+ <div class="mr-auto">
20
+ <?php if ( Common::isCurrentUserAdmin() ) : ?>
21
+ <?php Buttons::renderDelete( 'bookly-staff-delete', 'bookly-js-hide-on-loading' ) ?>
22
+ <?php if ( Config::proActive() ) : ?>
23
+ <?php Buttons::render( null, 'btn-danger ladda-button bookly-js-staff-archive bookly-js-hide-on-loading', __( 'Archive', 'bookly' ) . '…', array(), '<i class="fas fa-fw fa-archive mr-1"></i>{caption}' ) ?>
24
+ <?php endif ?>
25
  <?php endif ?>
26
+ </div>
27
+ <div class="flex-fill">
28
+ <span class="bookly-js-errors text-danger" style="max-width: 353px;display: inline-grid;"></span>
29
+ </div>
30
+ <div class="ml-auto">
31
+ <?php Buttons::renderSubmit( null, 'bookly-js-save bookly-js-hide-on-loading' ) ?>
32
+ <?php Buttons::renderCancel( __( 'Close', 'bookly' ) ) ?>
33
+ </div>
34
  </div>
35
  </div>
36
  </div>
backend/components/dialogs/staff/edit/templates/dialog_body.php CHANGED
@@ -3,51 +3,49 @@ use Bookly\Backend\Modules\Staff\Proxy;
3
  /** @var Bookly\Lib\Entities\Staff $staff */
4
  ?>
5
  <?php if ( $staff->getId() ) : ?>
6
- <ul class="nav nav-tabs nav-justified bookly-nav-justified">
7
- <li class="active">
8
- <a id="bookly-details-tab" href="#details" data-toggle="tab">
9
- <i class="fa fa-cog fa-fw"></i>
10
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'Details', 'bookly' ) ?></span>
11
  </a>
12
  </li>
13
- <li>
14
- <a id="bookly-services-tab" href="#services" data-toggle="tab">
15
  <i class="fas fa-th fa-fw"></i>
16
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'Services', 'bookly' ) ?></span>
17
  </a>
18
  </li>
19
- <li>
20
- <a id="bookly-schedule-tab" href="#schedule" data-toggle="tab">
21
- <i class="fas fa-clock fa-fw"></i>
22
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'Schedule', 'bookly' ) ?></span>
23
  </a>
24
  </li>
25
  <?php Proxy\Shared::renderStaffTab( $staff ) ?>
26
- <li>
27
- <a id="bookly-holidays-tab" href="#days_off" data-toggle="tab">
28
- <i class="fas fa-calendar fa-fw"></i>
29
- <span class="bookly-nav-tabs-title"><?php esc_html_e( 'Days Off', 'bookly' ) ?></span>
30
  </a>
31
  </li>
32
  </ul>
33
  <?php endif ?>
34
 
35
- <div class="tab-content">
36
- <div style="display: none;" class="bookly-loading"></div>
37
-
38
  <div class="tab-pane active" id="details">
39
  <div id="bookly-details-container"></div>
40
  </div>
41
  <div class="tab-pane" id="services">
42
- <div id="bookly-services-container" style="display: none"></div>
43
  </div>
44
  <div class="tab-pane" id="schedule">
45
- <div id="bookly-schedule-container" style="display: none"></div>
46
  </div>
47
  <div class="tab-pane" id="special_days">
48
- <div id="bookly-special-days-container" style="display: none"></div>
49
  </div>
50
  <div class="tab-pane" id="days_off">
51
- <div id="bookly-holidays-container" style="display: none"></div>
52
  </div>
53
  </div>
3
  /** @var Bookly\Lib\Entities\Staff $staff */
4
  ?>
5
  <?php if ( $staff->getId() ) : ?>
6
+ <ul class="nav nav-tabs nav-fill mb-3">
7
+ <li class="nav-item">
8
+ <a id="bookly-details-tab" href="#details" data-toggle="bookly-tab" class="nav-link active">
9
+ <i class="fas fa-cog fa-fw"></i>
10
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'Details', 'bookly' ) ?></span>
11
  </a>
12
  </li>
13
+ <li class="nav-item">
14
+ <a id="bookly-services-tab" href="#services" data-toggle="bookly-tab" class="nav-link">
15
  <i class="fas fa-th fa-fw"></i>
16
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'Services', 'bookly' ) ?></span>
17
  </a>
18
  </li>
19
+ <li class="nav-item">
20
+ <a id="bookly-schedule-tab" href="#schedule" data-toggle="bookly-tab" class="nav-link">
21
+ <i class="far fa-fw fa-calendar-alt"></i>
22
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'Schedule', 'bookly' ) ?></span>
23
  </a>
24
  </li>
25
  <?php Proxy\Shared::renderStaffTab( $staff ) ?>
26
+ <li class="nav-item">
27
+ <a id="bookly-holidays-tab" href="#days_off" data-toggle="bookly-tab" class="nav-link">
28
+ <i class="far fa-calendar fa-fw"></i>
29
+ <span class="d-none d-lg-inline"><?php esc_html_e( 'Days Off', 'bookly' ) ?></span>
30
  </a>
31
  </li>
32
  </ul>
33
  <?php endif ?>
34
 
35
+ <div class="tab-content bookly-js-staff-containers">
 
 
36
  <div class="tab-pane active" id="details">
37
  <div id="bookly-details-container"></div>
38
  </div>
39
  <div class="tab-pane" id="services">
40
+ <div id="bookly-services-container"></div>
41
  </div>
42
  <div class="tab-pane" id="schedule">
43
+ <div id="bookly-schedule-container"></div>
44
  </div>
45
  <div class="tab-pane" id="special_days">
46
+ <div id="bookly-special-days-container"></div>
47
  </div>
48
  <div class="tab-pane" id="days_off">
49
+ <div id="bookly-holidays-container"></div>
50
  </div>
51
  </div>
backend/components/dialogs/staff/edit/templates/holidays.php CHANGED
@@ -1,18 +1,13 @@
1
  <?php if (!defined('ABSPATH')) exit; // Exit if accessed directly ?>
2
- <div class="bookly-holidays-nav">
3
- <div class="input-group input-group-lg">
4
- <div class="input-group-btn">
5
- <button class="btn btn-default bookly-js-jCalBtn" data-trigger=".jCal .left" type="button">
6
- <i class="dashicons dashicons-arrow-left-alt2"></i>
7
- </button>
8
- </div>
9
- <input class="form-control text-center jcal_year" id="appendedPrependedInput"
10
- readonly type="text" value="">
11
- <div class="input-group-btn">
12
- <button class="btn btn-default bookly-js-jCalBtn" data-trigger=".jCal .right" type="button">
13
- <i class="dashicons dashicons-arrow-right-alt2"></i>
14
- </button>
15
- </div>
16
  </div>
17
  </div>
18
- <div class="bookly-js-holidays jCal-wrap bookly-margin-top-lg" style="height: 1080px;"></div>
1
  <?php if (!defined('ABSPATH')) exit; // Exit if accessed directly ?>
2
+ <div class="bookly-js-holidays-nav text-center">
3
+ <div class="btn-group btn-group-lg" role="group">
4
+ <button class="btn btn-default bookly-js-jCalBtn" data-trigger=".jCal .left" type="button">
5
+ <i class="fas fa-fw fa-angle-left"></i>
6
+ </button>
7
+ <button class="btn btn-default jcal_year" type="button" disabled="disabled"></button>
8
+ <button class="btn btn-default bookly-js-jCalBtn" data-trigger=".jCal .right" type="button">
9
+ <i class="fas fa-fw fa-angle-right"></i>
10
+ </button>
 
 
 
 
 
11
  </div>
12
  </div>
13
+ <div class="bookly-js-holidays jCal-wrap mt-4" style="height: 1080px;"></div>
backend/components/dialogs/staff/edit/templates/schedule.php CHANGED
@@ -1,118 +1,23 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
- use Bookly\Backend\Modules\Staff\Forms\Widgets\TimeChoice;
5
  use Bookly\Backend\Modules\Staff\Proxy;
6
- /** @var \Bookly\Lib\Entities\StaffScheduleItem[] $schedule_items */
7
- $working_start = new TimeChoice( array( 'empty_value' => __( 'OFF', 'bookly' ), 'type' => 'from' ) );
8
- $working_end = new TimeChoice( array( 'use_empty' => false, 'type' => 'to' ) );
9
- $default_breaks = array( 'staff_id' => $staff_id );
10
- $break_start = new TimeChoice( array( 'use_empty' => false, 'type' => 'break_from' ) );
11
- $break_end = clone $working_end;
12
  ?>
13
  <div>
14
  <form>
15
  <?php Proxy\Locations::renderLocationSwitcher( $staff_id, $location_id, 'custom_schedule' ) ?>
16
- <?php foreach ( $schedule_items as $item ) : ?>
17
- <div data-id="<?php echo $item->getDayIndex() ?>"
18
- data-staff_schedule_item_id="<?php echo $item->getId() ?>"
19
- class="staff-schedule-item-row panel panel-default bookly-panel-unborder">
20
-
21
- <div class="panel-heading bookly-padding-vertical-md">
22
- <div class="row">
23
- <div class="col-sm-7 col-lg-5">
24
- <span class="panel-title"><?php esc_html_e( \Bookly\Lib\Utils\DateTime::getWeekDayByNumber( $item->getDayIndex() - 1 ) /* take translation from WP catalog */ ) ?></span>
25
- </div>
26
- <div class="col-sm-5 col-lg-7 hidden-xs hidden-sm">
27
- <div class="bookly-font-smaller bookly-color-gray">
28
- <?php esc_html_e( 'Breaks', 'bookly' ) ?>
29
- </div>
30
- </div>
31
- </div>
32
- </div>
33
-
34
- <div class="panel-body padding-lr-none">
35
- <div class="row">
36
- <div class="col-sm-7 col-lg-5">
37
- <div class="bookly-flexbox form-group">
38
- <div class="bookly-flex-cell" style="width: 50%">
39
- <?php
40
- $day_is_not_available = null === $item->getStartTime();
41
- echo $working_start->render(
42
- "start_time[{$item->getDayIndex()}]",
43
- $item->getStartTime(),
44
- array( 'class' => 'working-schedule-start form-control' )
45
- );
46
- ?>
47
- </div>
48
- <div class="bookly-flex-cell text-center" style="width: 1%">
49
- <div class="bookly-margin-horizontal-lg bookly-hide-on-off">
50
- <?php esc_html_e( 'to', 'bookly' ) ?>
51
- </div>
52
- </div>
53
- <div class="bookly-flex-cell" style="width: 50%">
54
- <?php
55
- echo $working_end->render(
56
- "end_time[{$item->getDayIndex()}]",
57
- $item->getEndTime(),
58
- array( 'class' => 'working-schedule-end form-control bookly-hide-on-off' )
59
- );
60
- ?>
61
- </div>
62
- </div>
63
-
64
- <input type="hidden" name="days[<?php echo $item->getId() ?>]" value="<?php echo $item->getDayIndex() ?>">
65
- </div>
66
-
67
- <div class="col-sm-5 col-lg-7">
68
- <div class="bookly-intervals-wrapper bookly-hide-on-off">
69
- <button type="button"
70
- class="bookly-js-toggle-popover btn btn-link bookly-btn-unborder bookly-margin-vertical-screenxs-sm"
71
- data-popover-content=".bookly-js-content-break-<?php echo $item->getId() ?>">
72
- <?php esc_html_e( 'add break', 'bookly' ) ?>
73
- </button>
74
-
75
- <div class="bookly-js-content-break-<?php echo $item->getId() ?> hidden">
76
- <div class="error" style="display: none"></div>
77
-
78
- <div class="bookly-js-schedule-form">
79
- <div class="bookly-flexbox" style="width: 260px">
80
- <div class="bookly-flex-cell" style="width: 48%;">
81
- <?php echo $break_start->render( '', $item->getStartTime(), array( 'class' => 'break-start form-control' ) ) ?>
82
- </div>
83
- <div class="bookly-flex-cell" style="width: 4%;">
84
- <div class="bookly-margin-horizontal-lg">
85
- <?php esc_html_e( 'to', 'bookly' ) ?>
86
- </div>
87
- </div>
88
- <div class="bookly-flex-cell" style="width: 48%;">
89
- <?php echo $break_end->render( '', $item->getEndTime(), array( 'class' => 'break-end form-control' ) ) ?>
90
- </div>
91
- </div>
92
- <hr>
93
- <div class="text-right">
94
- <?php Buttons::renderCustom( null, 'bookly-js-save-break btn-lg btn-success', __( 'Save', 'bookly' ) ) ?>
95
- <?php Buttons::renderCustom( null, 'bookly-popover-close btn-lg btn-default', __( 'Close', 'bookly' ) ) ?>
96
- </div>
97
- </div>
98
- </div>
99
- </div>
100
-
101
- <div class="breaks bookly-hide-on-off">
102
- <?php include '_breaks.php' ?>
103
- </div>
104
- </div>
105
- </div>
106
- </div>
107
- </div>
108
  <?php endforeach ?>
109
-
110
- <input type="hidden" name="action" value="bookly_staff_schedule_update">
111
  <?php Inputs::renderCsrf() ?>
112
 
113
- <div class="panel-footer">
114
- <?php Buttons::renderCustom( 'bookly-schedule-save', 'btn-lg btn-success', esc_attr__( 'Save', 'bookly' ) ) ?>
115
- <?php Buttons::renderReset( 'bookly-schedule-reset', null, null, array( 'data-default-breaks' => json_encode( $default_breaks ), 'data-spinner-color' => 'rgb(62, 66, 74)' ) ) ?>
116
  </div>
117
  </form>
118
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
 
4
  use Bookly\Backend\Modules\Staff\Proxy;
5
+ /**
6
+ * @var Bookly\Backend\Components\Schedule\Component $schedule
7
+ * @var array $ss_ids
8
+ */
 
 
9
  ?>
10
  <div>
11
  <form>
12
  <?php Proxy\Locations::renderLocationSwitcher( $staff_id, $location_id, 'custom_schedule' ) ?>
13
+ <?php $schedule->render() ?>
14
+ <?php foreach ( $ss_ids as $id => $index ) : ?>
15
+ <input type="hidden" name="ssi[<?php echo $id ?>]" value="<?php echo $index ?>" />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  <?php endforeach ?>
 
 
17
  <?php Inputs::renderCsrf() ?>
18
 
19
+ <div class="bookly-js-modal-footer">
20
+ <?php Buttons::renderSubmit( 'bookly-schedule-save' ) ?>
 
21
  </div>
22
  </form>
23
  </div>
backend/components/dialogs/staff/edit/templates/services.php CHANGED
@@ -4,73 +4,66 @@ use Bookly\Backend\Components\Controls\Inputs;
4
  use Bookly\Backend\Components\Dialogs;
5
  use Bookly\Backend\Modules\Staff\Proxy;
6
  use Bookly\Lib\Utils\Common;
 
7
  /** @var Dialogs\Staff\Edit\Forms\StaffServices $form */
8
  ?>
9
  <div>
10
  <?php if ( $form->getCategories() || $form->getUncategorizedServices() ) : ?>
11
  <form>
12
  <?php Proxy\Locations::renderLocationSwitcher( $staff_id, $location_id, 'custom_services' ) ?>
13
- <?php if ( $form->getUncategorizedServices() ) : ?>
14
- <div class="panel panel-default bookly-panel-unborder">
15
- <div class="panel-heading">
16
  <div class="row">
17
- <div class="col-lg-6">
18
- <div class="checkbox bookly-margin-remove">
19
- <label>
20
- <input id="bookly-check-all-entities" type="checkbox">
21
- <b><?php esc_html_e( 'All services', 'bookly' ) ?></b>
22
- </label>
23
  </div>
24
  </div>
25
- <div class="col-lg-6">
26
- <div class="bookly-flexbox">
27
- <div class="bookly-flex-row">
28
- <div class="bookly-flex-cell hidden-xs hidden-sm hidden-md text-right">
29
- <div class="bookly-font-smaller bookly-color-gray">
30
- <?php esc_html_e( 'Price', 'bookly' ) ?>
31
- </div>
32
- </div>
33
- <?php Proxy\Shared::renderStaffServiceLabels() ?>
34
  </div>
 
35
  </div>
36
  </div>
37
  </div>
38
  </div>
39
-
40
- <ul class="bookly-category-services list-group bookly-padding-top-md">
41
  <?php foreach ( $form->getUncategorizedServices() as $service ) : ?>
42
  <?php $sub_service = current( $service->getSubServices() ) ?>
43
- <li class="list-group-item" data-service-id="<?php echo $service->getId() ?>" data-service-type="<?php echo $service->getType() ?>" data-sub-service="<?php echo empty( $sub_service ) ? null : $sub_service->getId(); ?>">
 
44
  <div class="row">
45
- <div class="col-lg-6">
46
- <div class="checkbox">
47
- <label>
48
- <input class="bookly-service-checkbox" <?php checked( array_key_exists( $service->getId(), $services_data ) ) ?>
49
- type="checkbox" value="<?php echo $service->getId() ?>"
50
- name="service[<?php echo $service->getId() ?>]"
51
- >
52
- <span class="bookly-toggle-label"><?php echo esc_html( $service->getTitle() ) ?></span>
 
 
 
 
 
53
  </label>
54
- <?php Proxy\Ratings::renderStaffServiceRating( $staff_id, $service->getId(), 'right' ) ?>
55
  </div>
56
  </div>
57
- <div class="col-lg-6">
58
- <div class="row">
59
- <div class="bookly-flexbox">
60
- <div class="bookly-flex-row">
61
- <div class="bookly-flex-cell">
62
- <div class="bookly-font-smaller bookly-margin-bottom-xs bookly-color-gray visible-xs visible-sm visible-md">
63
- <?php esc_html_e( 'Price', 'bookly' ) ?>
64
- </div>
65
- <input class="form-control text-right" type="text" <?php disabled( ! array_key_exists( $service->getId(), $services_data ) ) ?>
66
- name="price[<?php echo $service->getId() ?>]"
67
- value="<?php echo array_key_exists( $service->getId(), $services_data ) ? $services_data[ $service->getId() ]['price'] : $service->getPrice() ?>"
68
- />
69
- </div>
70
-
71
- <?php Proxy\Shared::renderStaffService( $staff_id, $service, $services_data, array() ) ?>
72
- </div>
73
  </div>
 
 
74
  </div>
75
  </div>
76
  </div>
@@ -78,60 +71,54 @@ use Bookly\Lib\Utils\Common;
78
  </li>
79
  <?php endforeach ?>
80
  </ul>
81
- </div>
82
- <?php endif ?>
83
 
84
- <?php foreach ( $form->getCategories() as $category ) : ?>
85
- <div class="panel panel-default bookly-panel-unborder">
86
- <div class="panel-heading bookly-services-category">
87
  <div class="row">
88
- <div class="col-lg-6">
89
- <div class="checkbox bookly-margin-remove">
90
- <label>
91
- <input type="checkbox" class="bookly-category-checkbox bookly-category-<?php echo $category->getId() ?>"
92
- data-category-id="<?php echo $category->getId() ?>">
93
- <b><?php echo esc_html( $category->getName() ) ?></b>
94
- </label>
95
  </div>
96
  </div>
97
- <div class="col-lg-6">
98
- <div class="bookly-flexbox">
99
- <div class="bookly-flex-row">
100
- <div class="bookly-flex-cell hidden-xs hidden-sm hidden-md text-right">
101
- <div class="bookly-font-smaller bookly-color-gray"><?php esc_html_e( 'Price', 'bookly' ) ?></div>
102
- </div>
103
- <?php Proxy\Shared::renderStaffServiceLabels() ?>
104
  </div>
 
105
  </div>
106
  </div>
107
  </div>
108
  </div>
109
-
110
- <ul class="bookly-category-services list-group bookly-padding-top-md">
111
  <?php foreach ( $category->getServices() as $service ) : ?>
112
  <?php $sub_service = current( $service->getSubServices() ) ?>
113
- <li class="list-group-item" data-service-id="<?php echo $service->getId() ?>" data-service-type="<?php echo $service->getType() ?>" data-sub-service="<?php echo empty( $sub_service ) ? null : $sub_service->getId(); ?>">
 
114
  <div class="row">
115
- <div class="col-lg-6">
116
- <div class="checkbox">
117
- <label>
118
- <input class="bookly-service-checkbox bookly-category-<?php echo $category->getId() ?>"
119
- data-category-id="<?php echo $category->getId() ?>" <?php checked( array_key_exists( $service->getId(), $services_data ) ) ?>
120
- type="checkbox" value="<?php echo $service->getId() ?>"
121
- name="service[<?php echo $service->getId() ?>]"
122
- />
123
- <span class="bookly-toggle-label"><?php echo esc_html( $service->getTitle() ) ?></span>
 
 
 
 
 
124
  </label>
125
- <?php Proxy\Ratings::renderStaffServiceRating( $staff_id, $service->getId(), 'right' ) ?>
126
  </div>
127
  </div>
128
- <div class="col-lg-6">
129
- <div class="bookly-flexbox">
130
- <div class="bookly-flex-row">
131
- <div class="bookly-flex-cell">
132
- <div class="bookly-font-smaller bookly-margin-bottom-xs bookly-color-gray visible-xs visible-sm visible-md">
133
- <?php esc_html_e( 'Price', 'bookly' ) ?>
134
- </div>
135
  <input class="form-control text-right" type="text" <?php disabled( ! array_key_exists( $service->getId(), $services_data ) ) ?>
136
  name="price[<?php echo $service->getId() ?>]"
137
  value="<?php echo array_key_exists( $service->getId(), $services_data ) ? $services_data[ $service->getId() ]['price'] : $service->getPrice() ?>"
@@ -139,7 +126,6 @@ use Bookly\Lib\Utils\Common;
139
  </div>
140
 
141
  <?php Proxy\Shared::renderStaffService( $staff_id, $service, $services_data, array() ) ?>
142
- </div>
143
  </div>
144
  </div>
145
  </div>
@@ -147,24 +133,24 @@ use Bookly\Lib\Utils\Common;
147
  </li>
148
  <?php endforeach ?>
149
  </ul>
150
- </div>
151
- <?php endforeach ?>
152
 
153
- <input type="hidden" name="action" value="bookly_staff_services_update">
154
- <input type="hidden" name="staff_id" value="<?php echo $staff_id ?>">
155
- <?php Inputs::renderCsrf() ?>
156
 
157
- <div class="panel-footer">
158
- <span class="bookly-js-services-error text-danger"></span>
159
- <?php Buttons::renderCustom( 'bookly-services-save', 'btn-lg btn-success' ) ?>
160
- <?php Buttons::renderReset( 'bookly-services-reset' ) ?>
 
161
  </div>
162
  </form>
163
  <?php else : ?>
164
  <h5 class="text-center"><?php esc_html_e( 'No services found. Please add services.', 'bookly' ) ?></h5>
165
- <p class="bookly-margin-top-xlg text-center">
166
  <a class="btn btn-xlg btn-success-outline"
167
- href="<?php echo Common::escAdminUrl( Bookly\Backend\Modules\Services\Page::pageSlug() ) ?>" >
168
  <?php esc_html_e( 'Add Service', 'bookly' ) ?>
169
  </a>
170
  </p>
4
  use Bookly\Backend\Components\Dialogs;
5
  use Bookly\Backend\Modules\Staff\Proxy;
6
  use Bookly\Lib\Utils\Common;
7
+
8
  /** @var Dialogs\Staff\Edit\Forms\StaffServices $form */
9
  ?>
10
  <div>
11
  <?php if ( $form->getCategories() || $form->getUncategorizedServices() ) : ?>
12
  <form>
13
  <?php Proxy\Locations::renderLocationSwitcher( $staff_id, $location_id, 'custom_services' ) ?>
14
+ <div id="bookly-staff-services">
15
+ <?php if ( $form->getUncategorizedServices() ) : ?>
16
+ <div class="card bg-light p-3">
17
  <div class="row">
18
+ <div class="col-lg-5">
19
+ <div class="custom-control custom-checkbox">
20
+ <input class="custom-control-input" id="bookly-check-all-entities" type="checkbox"/>
21
+ <label class="custom-control-label" for="bookly-check-all-entities"><?php esc_html_e( 'All services', 'bookly' ) ?></label>
 
 
22
  </div>
23
  </div>
24
+ <div class="col-lg-7">
25
+ <div class="form-row text-muted d-none d-lg-flex">
26
+ <div class="col-lg-3 text-center">
27
+ <?php esc_html_e( 'Price', 'bookly' ) ?>
 
 
 
 
 
28
  </div>
29
+ <?php Proxy\Shared::renderStaffServiceLabels() ?>
30
  </div>
31
  </div>
32
  </div>
33
  </div>
34
+ <ul class="bookly-js-category-services list-group pt-2 list-unstyled">
 
35
  <?php foreach ( $form->getUncategorizedServices() as $service ) : ?>
36
  <?php $sub_service = current( $service->getSubServices() ) ?>
37
+ <li class="p-2 mx-2" data-service-id="<?php echo $service->getId() ?>" data-service-type="<?php echo $service->getType() ?>"
38
+ data-sub-service="<?php echo empty( $sub_service ) ? null : $sub_service->getId() ?>">
39
  <div class="row">
40
+ <div class="col-lg-5">
41
+ <div class="custom-control custom-checkbox mt-2">
42
+ <input
43
+ class="custom-control-input bookly-js-service-checkbox"
44
+ id="bookly-check-service-<?php echo $service->getId() ?>"
45
+ type="checkbox"
46
+ <?php checked( array_key_exists( $service->getId(), $services_data ) ) ?>
47
+ value="<?php echo $service->getId() ?>"
48
+ name="service[<?php echo $service->getId() ?>]"
49
+ />
50
+ <label class="custom-control-label w-100 bookly-toggle-label" for="bookly-check-service-<?php echo $service->getId() ?>">
51
+ <?php echo esc_html( $service->getTitle() ) ?>
52
+ <?php Proxy\Ratings::renderStaffServiceRating( $staff_id, $service->getId(), 'right' ) ?>
53
  </label>
 
54
  </div>
55
  </div>
56
+ <div class="col-lg-7">
57
+ <div class="form-row">
58
+ <div class="col-3">
59
+ <div class="d-lg-none"><?php esc_html_e( 'Price', 'bookly' ) ?></div>
60
+ <input class="form-control text-right" type="text" <?php disabled( ! array_key_exists( $service->getId(), $services_data ) ) ?>
61
+ name="price[<?php echo $service->getId() ?>]"
62
+ value="<?php echo array_key_exists( $service->getId(), $services_data ) ? $services_data[ $service->getId() ]['price'] : $service->getPrice() ?>"
63
+ />
 
 
 
 
 
 
 
 
64
  </div>
65
+
66
+ <?php Proxy\Shared::renderStaffService( $staff_id, $service, $services_data, array() ) ?>
67
  </div>
68
  </div>
69
  </div>
71
  </li>
72
  <?php endforeach ?>
73
  </ul>
74
+ <?php endif ?>
 
75
 
76
+ <?php foreach ( $form->getCategories() as $category ) : ?>
77
+ <div class="card bg-light p-3">
 
78
  <div class="row">
79
+ <div class="col-lg-5">
80
+ <div class="custom-control custom-checkbox">
81
+ <input class="custom-control-input bookly-js-category-checkbox" id="bookly-category-<?php echo $category->getId() ?>" type="checkbox" data-category-id="<?php echo $category->getId() ?>"/>
82
+ <label class="custom-control-label" for="bookly-category-<?php echo $category->getId() ?>"><?php echo esc_html( $category->getName() ) ?></label>
 
 
 
83
  </div>
84
  </div>
85
+ <div class="col-lg-7">
86
+ <div class="form-row text-muted d-none d-lg-flex">
87
+ <div class="col-lg-3 text-center">
88
+ <?php esc_html_e( 'Price', 'bookly' ) ?>
 
 
 
89
  </div>
90
+ <?php Proxy\Shared::renderStaffServiceLabels() ?>
91
  </div>
92
  </div>
93
  </div>
94
  </div>
95
+ <ul class="bookly-js-category-services list-group pt-2 list-unstyled">
 
96
  <?php foreach ( $category->getServices() as $service ) : ?>
97
  <?php $sub_service = current( $service->getSubServices() ) ?>
98
+ <li class="p-2 mx-2" data-service-id="<?php echo $service->getId() ?>" data-service-type="<?php echo $service->getType() ?>"
99
+ data-sub-service="<?php echo empty( $sub_service ) ? null : $sub_service->getId() ?>">
100
  <div class="row">
101
+ <div class="col-lg-5">
102
+ <div class="custom-control custom-checkbox mt-2">
103
+ <input
104
+ class="custom-control-input bookly-js-service-checkbox"
105
+ data-category-id="<?php echo $category->getId() ?>"
106
+ id="bookly-check-service-<?php echo $service->getId() ?>"
107
+ type="checkbox"
108
+ <?php checked( array_key_exists( $service->getId(), $services_data ) ) ?>
109
+ value="<?php echo $service->getId() ?>"
110
+ name="service[<?php echo $service->getId() ?>]"
111
+ />
112
+ <label class="custom-control-label w-100 bookly-toggle-label" for="bookly-check-service-<?php echo $service->getId() ?>">
113
+ <?php echo esc_html( $service->getTitle() ) ?>
114
+ <?php Proxy\Ratings::renderStaffServiceRating( $staff_id, $service->getId(), 'right' ) ?>
115
  </label>
 
116
  </div>
117
  </div>
118
+ <div class="col-lg-7">
119
+ <div class="form-row">
120
+ <div class="col-3">
121
+ <div class="d-lg-none"><?php esc_html_e( 'Price', 'bookly' ) ?></div>
 
 
 
122
  <input class="form-control text-right" type="text" <?php disabled( ! array_key_exists( $service->getId(), $services_data ) ) ?>
123
  name="price[<?php echo $service->getId() ?>]"
124
  value="<?php echo array_key_exists( $service->getId(), $services_data ) ? $services_data[ $service->getId() ]['price'] : $service->getPrice() ?>"
126
  </div>
127
 
128
  <?php Proxy\Shared::renderStaffService( $staff_id, $service, $services_data, array() ) ?>
 
129
  </div>
130
  </div>
131
  </div>
133
  </li>
134
  <?php endforeach ?>
135
  </ul>
136
+ <?php endforeach ?>
 
137
 
138
+ <input type="hidden" name="action" value="bookly_staff_services_update">
139
+ <input type="hidden" name="staff_id" value="<?php echo $staff_id ?>">
140
+ <?php Inputs::renderCsrf() ?>
141
 
142
+ <div class="bookly-js-modal-footer">
143
+ <span class="bookly-js-services-error text-danger"></span>
144
+ <?php Buttons::renderSubmit( 'bookly-services-save' ) ?>
145
+ <?php Buttons::renderReset( 'bookly-services-reset' ) ?>
146
+ </div>
147
  </div>
148
  </form>
149
  <?php else : ?>
150
  <h5 class="text-center"><?php esc_html_e( 'No services found. Please add services.', 'bookly' ) ?></h5>
151
+ <p class="text-center">
152
  <a class="btn btn-xlg btn-success-outline"
153
+ href="<?php echo Common::escAdminUrl( Bookly\Backend\Modules\Services\Page::pageSlug() ) ?>">
154
  <?php esc_html_e( 'Add Service', 'bookly' ) ?>
155
  </a>
156
  </p>
backend/components/dialogs/staff/order/Dialog.php CHANGED
@@ -18,15 +18,16 @@ class Dialog extends Lib\Base\Component
18
 
19
  self::enqueueStyles( array(
20
  'frontend' => array( 'css/ladda.min.css', ),
21
- 'backend' => array( 'css/fontawesome-all.min.css', 'css/select2.min.css' ),
22
  ) );
23
 
24
  self::enqueueScripts( array(
 
25
  'frontend' => array(
26
  'js/spin.min.js' => array( 'jquery', ),
27
  'js/ladda.min.js' => array( 'jquery', ),
28
  ),
29
- 'module' => array( 'js/staff-order-dialog.js' => array( 'jquery', ) ),
30
  ) );
31
 
32
  $query = Lib\Entities\Staff::query( 's' )
18
 
19
  self::enqueueStyles( array(
20
  'frontend' => array( 'css/ladda.min.css', ),
21
+ 'backend' => array( 'css/fontawesome-all.min.css', ),
22
  ) );
23
 
24
  self::enqueueScripts( array(
25
+ 'backend' => array( 'js/sortable.min.js' ),
26
  'frontend' => array(
27
  'js/spin.min.js' => array( 'jquery', ),
28
  'js/ladda.min.js' => array( 'jquery', ),
29
  ),
30
+ 'module' => array( 'js/staff-order-dialog.js' => array( 'jquery', 'bookly-sortable.min.js' ) ),
31
  ) );
32
 
33
  $query = Lib\Entities\Staff::query( 's' )
backend/components/dialogs/staff/order/resources/js/staff-order-dialog.js CHANGED
@@ -17,14 +17,12 @@ jQuery(function ($) {
17
  })
18
  .on('staff.deleted', {},
19
  function (event, staff) {
20
- BooklyStaffOrderDialogL10n.staff.forEach((s, index) => {
21
- if (staff.includes(String(s.id))) {
22
- delete BooklyStaffOrderDialogL10n.staff[index];
23
- }
24
- });
25
- // Remove undefined values
26
- BooklyStaffOrderDialogL10n.staff.filter(function (el) {
27
- return el != undefined;
28
  });
29
  });
30
 
@@ -55,7 +53,7 @@ jQuery(function ($) {
55
  },
56
  function (response) {
57
  if (response.success) {
58
- $dialog.modal('hide');
59
  BooklyStaffOrderDialogL10n.staff = list;
60
  }
61
  ladda.stop();
@@ -73,8 +71,7 @@ jQuery(function ($) {
73
  });
74
  });
75
 
76
- $list.sortable({
77
- axis : 'y',
78
  handle: '.bookly-js-draghandle',
79
  });
80
  });
17
  })
18
  .on('staff.deleted', {},
19
  function (event, staff) {
20
+ staff.forEach(id => {
21
+ BooklyStaffOrderDialogL10n.staff.forEach((s, index) => {
22
+ if (s.id === parseInt(id)) {
23
+ BooklyStaffOrderDialogL10n.staff.splice(index, 1);
24
+ }
25
+ });
 
 
26
  });
27
  });
28
 
53
  },
54
  function (response) {
55
  if (response.success) {
56
+ $dialog.booklyModal('hide');
57
  BooklyStaffOrderDialogL10n.staff = list;
58
  }
59
  ladda.stop();
71
  });
72
  });
73
 
74
+ Sortable.create($list[0], {
 
75
  handle: '.bookly-js-draghandle',
76
  });
77
  });
backend/components/dialogs/staff/order/templates/dialog.php CHANGED
@@ -1,30 +1,31 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
 
3
  ?>
4
- <form id="bookly-staff-order-modal" class="modal fade" tabindex=-1 role="dialog">
5
  <div class="modal-dialog">
6
  <div class="modal-content">
7
  <div class="modal-header">
8
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
9
- <div class="modal-title h2"><?php esc_html_e( 'Staff members order', 'bookly' ) ?></div>
10
  </div>
11
  <div class="modal-body">
12
- <ul id="bookly-list"></ul>
13
- <p class="help-block bookly-js-without-icon"><?php esc_html_e( 'Adjust the order of staff members in your booking form', 'bookly' ) ?></p>
14
  </div>
15
  <div class="modal-footer">
16
  <?php Buttons::renderSubmit() ?>
17
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
18
  </div>
19
  </div>
20
  </div>
21
  </form>
22
  <div class="collapse" id="bookly-staff-template">
23
  <li class="form-group">
24
- <div class="row"">
25
  <input type="hidden" name="id" value="{{id}}"/>
26
- <div class="col-xs-1"><i class="fa fa-fw fa-lg fa-bars text-muted bookly-cursor-move bookly-js-draghandle" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i></div>
27
- <div class="col-xs-11 bookly-js-full_name">{{full_name}}</div>
28
  </div>
29
  </li>
30
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
+ use Bookly\Backend\Components\Controls\Elements;
4
  ?>
5
+ <form id="bookly-staff-order-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <div class="modal-title h5"><?php esc_html_e( 'Staff members order', 'bookly' ) ?></div>
10
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
11
  </div>
12
  <div class="modal-body">
13
+ <ul id="bookly-list" class="list-unstyled"></ul>
14
+ <small class="text-muted form-text"><?php esc_html_e( 'Adjust the order of staff members in your booking form', 'bookly' ) ?></small>
15
  </div>
16
  <div class="modal-footer">
17
  <?php Buttons::renderSubmit() ?>
18
+ <?php Buttons::renderCancel() ?>
19
  </div>
20
  </div>
21
  </div>
22
  </form>
23
  <div class="collapse" id="bookly-staff-template">
24
  <li class="form-group">
25
+ <div class="row align-items-center">
26
  <input type="hidden" name="id" value="{{id}}"/>
27
+ <div class="col-auto pr-1"><?php Elements::renderReorder() ?></div>
28
+ <div class="col-auto pl-1 bookly-js-full_name">{{full_name}}</div>
29
  </div>
30
  </li>
31
  </div>
backend/components/dialogs/table_settings/Dialog.php CHANGED
@@ -20,11 +20,14 @@ class Dialog extends Lib\Base\Component
20
  ) );
21
 
22
  self::enqueueScripts( array(
 
 
 
23
  'frontend' => array(
24
- 'js/spin.min.js' => array( 'jquery', ),
25
- 'js/ladda.min.js' => array( 'jquery', ),
26
  ),
27
- 'module' => array( 'js/table-settings-dialog.js' => array( 'jquery-ui-sortable' ), ),
28
  ) );
29
 
30
  wp_localize_script( 'bookly-table-settings-dialog.js', 'BooklyTableSettingsDialogL10n', array(
@@ -39,9 +42,10 @@ class Dialog extends Lib\Base\Component
39
  *
40
  * @param string $table_name
41
  * @param string $setting_name
 
42
  */
43
- public static function renderButton( $table_name, $setting_name = 'BooklyL10n' )
44
  {
45
- self::renderTemplate( 'button', compact( 'table_name', 'setting_name' ) );
46
  }
47
  }
20
  ) );
21
 
22
  self::enqueueScripts( array(
23
+ 'backend' => array(
24
+ 'js/sortable.min.js' => array( 'jquery' ),
25
+ ),
26
  'frontend' => array(
27
+ 'js/spin.min.js' => array( 'jquery' ),
28
+ 'js/ladda.min.js' => array( 'jquery' ),
29
  ),
30
+ 'module' => array( 'js/table-settings-dialog.js' => array( 'jquery', 'bookly-sortable.min.js' ) ),
31
  ) );
32
 
33
  wp_localize_script( 'bookly-table-settings-dialog.js', 'BooklyTableSettingsDialogL10n', array(
42
  *
43
  * @param string $table_name
44
  * @param string $setting_name
45
+ * @param string $location
46
  */
47
+ public static function renderButton( $table_name, $setting_name = 'BooklyL10n', $location = '' )
48
  {
49
+ self::renderTemplate( 'button', compact( 'table_name', 'setting_name', 'location' ) );
50
  }
51
  }
backend/components/dialogs/table_settings/resources/js/table-settings-dialog.js CHANGED
@@ -2,7 +2,7 @@ jQuery(function ($) {
2
  'use strict';
3
  var $modal = $('#bookly-table-settings-modal'),
4
  $save_button = $('.bookly-js-table-settings-save', $modal),
5
- $columns = $modal.find('.bookly-js-table-columns'),
6
  $template = $('#bookly-table-settings-template');
7
 
8
  // Save settings.
@@ -23,21 +23,25 @@ jQuery(function ($) {
23
  csrf_token: BooklyTableSettingsDialogL10n.csrfToken
24
  },
25
  function (response) {
26
- location.reload();
 
 
 
 
27
  });
28
  });
29
 
30
- $columns.sortable({
31
- axis : 'y',
32
- handle: '.bookly-js-draghandle',
33
  });
34
 
35
  // Open table settings modal.
36
  $('.bookly-js-table-settings').off().on('click', function () {
37
- var table_settings = window[$(this).data('setting-name')].datatables[$(this).data('table-name')].settings,
38
- table_titles = window[$(this).data('setting-name')].datatables[$(this).data('table-name')].titles;
 
39
 
40
- $modal.find('[name="bookly-table-name"]').val($(this).data('table-name'));
41
 
42
  // Generate columns.
43
  $columns.html('');
@@ -47,9 +51,10 @@ jQuery(function ($) {
47
  .replace(/{{name}}/g, name)
48
  .replace(/{{title}}/g, table_titles[name])
49
  .replace(/{{checked}}/g, show ? 'checked' : '')
 
 
50
  );
51
  });
52
-
53
- $('#bookly-table-settings-modal').modal('show');
54
  });
55
  });
2
  'use strict';
3
  var $modal = $('#bookly-table-settings-modal'),
4
  $save_button = $('.bookly-js-table-settings-save', $modal),
5
+ $columns = $('.bookly-js-table-columns', $modal),
6
  $template = $('#bookly-table-settings-template');
7
 
8
  // Save settings.
23
  csrf_token: BooklyTableSettingsDialogL10n.csrfToken
24
  },
25
  function (response) {
26
+ if ($modal.data('location').length !== '') {
27
+ location = $modal.data('location');
28
+ } else {
29
+ location.reload();
30
+ }
31
  });
32
  });
33
 
34
+ Sortable.create($columns[0], {
35
+ handle : '.bookly-js-draghandle'
 
36
  });
37
 
38
  // Open table settings modal.
39
  $('.bookly-js-table-settings').off().on('click', function () {
40
+ let table_settings = window[$(this).data('setting-name')].datatables[$(this).data('table-name')].settings,
41
+ table_titles = window[$(this).data('setting-name')].datatables[$(this).data('table-name')].titles,
42
+ table_name = $(this).data('table-name');
43
 
44
+ $('[name="bookly-table-name"]', $modal).val(table_name);
45
 
46
  // Generate columns.
47
  $columns.html('');
51
  .replace(/{{name}}/g, name)
52
  .replace(/{{title}}/g, table_titles[name])
53
  .replace(/{{checked}}/g, show ? 'checked' : '')
54
+ .replace(/{{id}}/g, 'bookly-ts-' + table_name + '-' + name)
55
+
56
  );
57
  });
58
+ $('#bookly-table-settings-modal').data('location', $(this).data('location')).booklyModal('show');
 
59
  });
60
  });
backend/components/dialogs/table_settings/templates/button.php CHANGED
@@ -1,4 +1,4 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
- <div class="form-group text-right">
3
- <button type="button" class="btn btn-default bookly-btn-block-xs bookly-js-table-settings" data-table-name="<?php echo $table_name ?>" data-setting-name="<?php echo $setting_name ?>"><i class="fa fa-fw fa-cog"></i></button>
4
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
+ <div class="col-12 col-sm-auto">
3
+ <button type="button" class="btn btn-default w-100 mb-3 bookly-js-table-settings" data-location="<?php echo $location ?>" data-table-name="<?php echo $table_name ?>" data-setting-name="<?php echo $setting_name ?>"><i class="far fa-fw fa-eye"></i></button>
4
  </div>
backend/components/dialogs/table_settings/templates/dialog.php CHANGED
@@ -1,44 +1,41 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
- /** @var string $table */
4
  ?>
5
- <form id="bookly-table-settings-modal" class="bookly-js-table-settings-modal modal fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
10
- <div class="modal-title h2"><?php esc_html_e( 'Table settings', 'bookly' ) ?></div>
11
  </div>
12
  <div class="modal-body">
13
- <div class="panel panel-default bookly-panel-unborder">
14
- <div class="panel-heading bookly-padding-horizontal-remove">
15
- <div class="row">
16
- <div class="col-xs-1"></div>
17
- <div class="col-xs-9">
18
- <div class="bookly-font-smaller bookly-color-gray"><?php esc_html_e( 'Column', 'bookly' ) ?></div>
19
- </div>
20
- <div class="col-xs-2">
21
- <div class="bookly-font-smaller bookly-color-gray"><?php esc_html_e( 'Show', 'bookly' ) ?></div>
22
- </div>
23
- </div>
24
- </div>
25
- <ul class="bookly-margin-top-md bookly-js-table-columns"></ul>
26
  </div>
 
27
  </div>
28
  <div class="modal-footer">
29
  <input type="hidden" name="bookly-table-name" value="">
30
- <?php Buttons::renderCustom( null, 'bookly-js-table-settings-save btn-lg btn-success', esc_html__( 'Save', 'bookly' ) ) ?>
31
- <?php Buttons::renderCustom( null, 'bookly-js-cancel btn-lg btn-default', esc_html__( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
32
  </div>
33
  </div>
34
  </div>
35
  </form>
36
  <div id="bookly-table-settings-template" class="hidden">
37
- <li class="bookly-margin-bottom-md">
38
  <div class="row">
39
- <div class="col-xs-1"><i class="fa fa-fw fa-lg fa-bars text-muted bookly-cursor-move bookly-js-draghandle" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i></div>
40
- <div class="col-xs-9">{{title}}</div>
41
- <div class="col-xs-2"><input name="{{name}}" type="checkbox" {{checked}}/></div>
 
 
 
 
 
42
  </div>
43
  </li>
44
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Controls\Buttons;
3
+ use Bookly\Backend\Components\Controls\Elements;
4
  ?>
5
+ <form id="bookly-table-settings-modal" class="bookly-js-table-settings-modal bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <div class="modal-header">
9
+ <h5 class="modal-title"><?php esc_html_e( 'Table settings', 'bookly' ) ?></h5>
10
+ <button type="button" class="close" data-dismiss="bookly-modal"><span>&times;</span></button>
11
  </div>
12
  <div class="modal-body">
13
+ <div class="row font-weight-bold mb-2">
14
+ <div class="col-auto pr-1"><i class="fas fa-fw fa-bars invisible"></i></div>
15
+ <div class="col px-1"><?php esc_html_e( 'Column', 'bookly' ) ?></div>
16
+ <div class="col-2 pl-1"><?php esc_html_e( 'Show', 'bookly' ) ?></div>
 
 
 
 
 
 
 
 
 
17
  </div>
18
+ <ul class="list-unstyled bookly-js-table-columns"></ul>
19
  </div>
20
  <div class="modal-footer">
21
  <input type="hidden" name="bookly-table-name" value="">
22
+ <?php Buttons::renderSubmit( null, 'bookly-js-table-settings-save' ) ?>
23
+ <?php Buttons::renderCancel( __( 'Close', 'bookly' ) ) ?>
24
  </div>
25
  </div>
26
  </div>
27
  </form>
28
  <div id="bookly-table-settings-template" class="hidden">
29
+ <li class="mb-1">
30
  <div class="row">
31
+ <div class="col-1 pr-1"><?php Elements::renderReorder() ?></i></div>
32
+ <div class="col-9 pl-1">{{title}}</div>
33
+ <div class="col-2">
34
+ <div class="custom-control custom-checkbox">
35
+ <input id="{{id}}" name="{{name}}" type="checkbox" {{checked}} class="custom-control-input" />
36
+ <label for="{{id}}" class="custom-control-label"></label>
37
+ </div>
38
+ </div>
39
  </div>
40
  </li>
41
  </div>
backend/components/notices/CollectStats.php CHANGED
@@ -17,9 +17,19 @@ class CollectStats extends Lib\Base\Component
17
  if ( self::needShowCollectStatNotice() ) {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
 
20
  ) );
21
  self::enqueueScripts( array(
22
- 'module' => array( 'js/collect-stats.js' => array( 'jquery' ), ),
 
 
 
 
 
 
 
 
 
23
  ) );
24
 
25
  self::renderTemplate( 'collect_stats', array( 'enabled' => get_option( 'bookly_gen_collect_stats' ) == '1' ) );
17
  if ( self::needShowCollectStatNotice() ) {
18
  self::enqueueStyles( array(
19
  'frontend' => array( 'css/ladda.min.css', ),
20
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
21
  ) );
22
  self::enqueueScripts( array(
23
+ 'backend' => array( 'bootstrap/js/bootstrap.min.js' => array( 'jquery' ), ),
24
+ 'frontend' => array(
25
+ 'js/spin.min.js' => array( 'jquery' ),
26
+ 'js/ladda.min.js' => array( 'jquery' ),
27
+ ),
28
+ 'module' => array( 'js/collect-stats.js' => array( 'jquery' ), ),
29
+ ) );
30
+
31
+ wp_localize_script( 'bookly-collect-stats.js', 'BooklyCollectStatsL10n', array(
32
+ 'csrfToken' => Lib\Utils\Common::getCsrfToken(),
33
  ) );
34
 
35
  self::renderTemplate( 'collect_stats', array( 'enabled' => get_option( 'bookly_gen_collect_stats' ) == '1' ) );
backend/components/notices/LiteRebranding.php CHANGED
@@ -17,8 +17,17 @@ class LiteRebranding extends Lib\Base\Component
17
  if ( Lib\Utils\Common::isCurrentUserAdmin() &&
18
  get_user_meta( get_current_user_id(), 'bookly_show_lite_rebranding_notice', true ) ) {
19
 
 
 
 
 
20
  self::enqueueScripts( array(
21
- 'module' => array( 'js/lite-rebranding.js' => array( 'jquery' ), ),
 
 
 
 
 
22
  ) );
23
 
24
  self::renderTemplate( 'lite_rebranding' );
17
  if ( Lib\Utils\Common::isCurrentUserAdmin() &&
18
  get_user_meta( get_current_user_id(), 'bookly_show_lite_rebranding_notice', true ) ) {
19
 
20
+ self::enqueueStyles( array(
21
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
22
+ ) );
23
+
24
  self::enqueueScripts( array(
25
+ 'backend' => array( 'bootstrap/js/bootstrap.min.js' => array( 'jquery' ), ),
26
+ 'module' => array( 'js/lite-rebranding.js' => array( 'jquery' ), ),
27
+ ) );
28
+
29
+ wp_localize_script( 'bookly-lite-rebranding.js', 'BooklyLiteL10n', array(
30
+ 'csrfToken' => Lib\Utils\Common::getCsrfToken(),
31
  ) );
32
 
33
  self::renderTemplate( 'lite_rebranding' );
backend/components/notices/Nps.php CHANGED
@@ -23,23 +23,30 @@ class Nps extends Lib\Base\Component
23
  if ( time() - Lib\Plugin::getInstallationTime() >= 30 * DAY_IN_SECONDS ) {
24
  self::enqueueStyles( array(
25
  'frontend' => array( 'css/ladda.min.css', ),
26
- 'module' => array( 'css/bootstrap-stars.css', ),
 
 
 
27
  ) );
28
 
29
  self::enqueueScripts( array(
30
- 'backend' => array(
31
  'js/alert.js' => array( 'jquery' ),
 
32
  ),
33
  'frontend' => array(
34
  'js/spin.min.js' => array( 'jquery' ),
35
  'js/ladda.min.js' => array( 'jquery' ),
36
  ),
37
- 'module' => array(
38
- 'js/jquery.barrating.min.js' => array( 'jquery' ),
39
- 'js/nps.js' => array( 'bookly-jquery.barrating.min.js', 'bookly-alert.js', 'bookly-ladda.min.js', ),
40
  ),
41
  ) );
42
 
 
 
 
 
43
  self::renderTemplate( 'nps', array( 'current_user' => wp_get_current_user() ) );
44
  }
45
  }
23
  if ( time() - Lib\Plugin::getInstallationTime() >= 30 * DAY_IN_SECONDS ) {
24
  self::enqueueStyles( array(
25
  'frontend' => array( 'css/ladda.min.css', ),
26
+ 'backend' => array(
27
+ 'css/fontawesome-all.min.css',
28
+ 'bootstrap/css/bootstrap.min.css',
29
+ ),
30
  ) );
31
 
32
  self::enqueueScripts( array(
33
+ 'backend' => array(
34
  'js/alert.js' => array( 'jquery' ),
35
+ 'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
36
  ),
37
  'frontend' => array(
38
  'js/spin.min.js' => array( 'jquery' ),
39
  'js/ladda.min.js' => array( 'jquery' ),
40
  ),
41
+ 'module' => array(
42
+ 'js/nps.js' => array( 'bookly-alert.js', 'bookly-ladda.min.js', ),
 
43
  ),
44
  ) );
45
 
46
+ wp_localize_script( 'bookly-nps.js', 'BooklyNpsL10n', array(
47
+ 'csrfToken' => Lib\Utils\Common::getCsrfToken(),
48
+ ) );
49
+
50
  self::renderTemplate( 'nps', array( 'current_user' => wp_get_current_user() ) );
51
  }
52
  }
backend/components/notices/PoweredBy.php CHANGED
@@ -20,8 +20,10 @@ class PoweredBy extends Lib\Base\Component
20
  ) {
21
  self::enqueueStyles( array(
22
  'frontend' => array( 'css/ladda.min.css', ),
 
23
  ) );
24
  self::enqueueScripts( array(
 
25
  'frontend' => array(
26
  'js/spin.min.js' => array( 'jquery' ),
27
  'js/ladda.min.js' => array( 'jquery' ),
@@ -29,6 +31,10 @@ class PoweredBy extends Lib\Base\Component
29
  'module' => array( 'js/powered-by.js' => array( 'bookly-ladda.min.js', ), ),
30
  ) );
31
 
 
 
 
 
32
  self::renderTemplate( 'powered_by' );
33
  }
34
  }
20
  ) {
21
  self::enqueueStyles( array(
22
  'frontend' => array( 'css/ladda.min.css', ),
23
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
24
  ) );
25
  self::enqueueScripts( array(
26
+ 'backend' => array( 'bootstrap/js/bootstrap.min.js' => array( 'jquery' ), ),
27
  'frontend' => array(
28
  'js/spin.min.js' => array( 'jquery' ),
29
  'js/ladda.min.js' => array( 'jquery' ),
31
  'module' => array( 'js/powered-by.js' => array( 'bookly-ladda.min.js', ), ),
32
  ) );
33
 
34
+ wp_localize_script( 'bookly-powered-by.js', 'BooklyPoweredByL10n', array(
35
+ 'csrfToken' => Lib\Utils\Common::getCsrfToken(),
36
+ ) );
37
+
38
  self::renderTemplate( 'powered_by' );
39
  }
40
  }
backend/components/notices/Subscribe.php CHANGED
@@ -21,9 +21,16 @@ class Subscribe extends Lib\Base\Component
21
  if ( time() - Lib\Plugin::getInstallationTime() >= DAY_IN_SECONDS ) {
22
  self::enqueueStyles( array(
23
  'frontend' => array( 'css/ladda.min.css', ),
 
 
 
 
24
  ) );
25
  self::enqueueScripts( array(
26
- 'backend' => array( 'js/alert.js' => array( 'jquery' ), ),
 
 
 
27
  'frontend' => array(
28
  'js/spin.min.js' => array( 'jquery' ),
29
  'js/ladda.min.js' => array( 'jquery' ),
@@ -31,6 +38,10 @@ class Subscribe extends Lib\Base\Component
31
  'module' => array( 'js/subscribe.js' => array( 'bookly-alert.js', 'bookly-ladda.min.js', ), ),
32
  ) );
33
 
 
 
 
 
34
  self::renderTemplate( 'subscribe' );
35
  }
36
  }
21
  if ( time() - Lib\Plugin::getInstallationTime() >= DAY_IN_SECONDS ) {
22
  self::enqueueStyles( array(
23
  'frontend' => array( 'css/ladda.min.css', ),
24
+ 'backend' => array(
25
+ 'css/fontawesome-all.min.css',
26
+ 'bootstrap/css/bootstrap.min.css',
27
+ ),
28
  ) );
29
  self::enqueueScripts( array(
30
+ 'backend' => array(
31
+ 'js/alert.js' => array( 'jquery' ),
32
+ 'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
33
+ ),
34
  'frontend' => array(
35
  'js/spin.min.js' => array( 'jquery' ),
36
  'js/ladda.min.js' => array( 'jquery' ),
38
  'module' => array( 'js/subscribe.js' => array( 'bookly-alert.js', 'bookly-ladda.min.js', ), ),
39
  ) );
40
 
41
+ wp_localize_script( 'bookly-subscribe.js', 'BooklySubscribeL10n', array(
42
+ 'csrfToken' => Lib\Utils\Common::getCsrfToken(),
43
+ ) );
44
+
45
  self::renderTemplate( 'subscribe' );
46
  }
47
  }
backend/components/notices/resources/css/bootstrap-stars.css DELETED
@@ -1,38 +0,0 @@
1
- .br-theme-bootstrap-stars .br-widget {
2
- height: 28px;
3
- white-space: nowrap;
4
- }
5
- .br-theme-bootstrap-stars .br-widget a {
6
- font: normal normal normal 30px/1 'Glyphicons Halflings';
7
- text-rendering: auto;
8
- -webkit-font-smoothing: antialiased;
9
- text-decoration: none;
10
- margin-right: 2px;
11
- }
12
- .br-theme-bootstrap-stars .br-widget a:after {
13
- content: '\e006';
14
- color: #d2d2d2;
15
- }
16
- .br-theme-bootstrap-stars .br-widget a.br-active:after {
17
- color: #EDB867;
18
- }
19
- .br-theme-bootstrap-stars .br-widget a.br-selected:after {
20
- color: #EDB867;
21
- }
22
- .br-theme-bootstrap-stars .br-widget .br-current-rating {
23
- display: none;
24
- }
25
- .br-theme-bootstrap-stars .br-readonly a {
26
- cursor: default;
27
- }
28
- @media print {
29
- .br-theme-bootstrap-stars .br-widget a:after {
30
- content: '\e007';
31
- color: black;
32
- }
33
- .br-theme-bootstrap-stars .br-widget a.br-active:after,
34
- .br-theme-bootstrap-stars .br-widget a.br-selected:after {
35
- content: '\e006';
36
- color: black;
37
- }
38
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/components/notices/resources/js/collect-stats.js CHANGED
@@ -1,9 +1,13 @@
1
  jQuery(function ($) {
2
- var $notice = $('#bookly-collect-stats-notice');
3
  $notice.on('close.bs.alert', function () {
4
- $.post(ajaxurl, {action: $notice.data('action'), csrf_token : BooklySupportL10n.csrfToken});
5
  });
6
  $notice.find('#bookly-enable-collecting-stats-btn').on('click', function () {
7
- $.post(ajaxurl, {action: 'bookly_enable_collecting_stats', csrf_token : BooklySupportL10n.csrfToken});
 
 
 
 
8
  });
9
  });
1
  jQuery(function ($) {
2
+ let $notice = $('#bookly-collect-stats-notice');
3
  $notice.on('close.bs.alert', function () {
4
+ $.post(ajaxurl, {action: $notice.data('action'), csrf_token : BooklyCollectStatsL10n.csrfToken});
5
  });
6
  $notice.find('#bookly-enable-collecting-stats-btn').on('click', function () {
7
+ let ladda = Ladda.create(this);
8
+ ladda.start();
9
+ $.post(ajaxurl, {action: 'bookly_enable_collecting_stats', csrf_token: BooklyCollectStatsL10n.csrfToken}, function (response) {
10
+ $notice.alert('close');
11
+ });
12
  });
13
  });
backend/components/notices/resources/js/jquery.barrating.min.js DELETED
@@ -1 +0,0 @@
1
- !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&module.exports?module.exports=t(require("jquery")):t(jQuery)}(function(t){var e=function(){function e(){var e=this,n=function(){var n=["br-wrapper"];""!==e.options.theme&&n.push("br-theme-"+e.options.theme),e.$elem.wrap(t("<div />",{"class":n.join(" ")}))},i=function(){e.$elem.unwrap()},a=function(n){return t.isNumeric(n)&&(n=Math.floor(n)),t('option[value="'+n+'"]',e.$elem)},r=function(){var n=e.options.initialRating;return n?a(n):t("option:selected",e.$elem)},o=function(){var n=e.$elem.find('option[value="'+e.options.emptyValue+'"]');return!n.length&&e.options.allowEmpty?(n=t("<option />",{value:e.options.emptyValue}),n.prependTo(e.$elem)):n},l=function(t){var n=e.$elem.data("barrating");return"undefined"!=typeof t?n[t]:n},s=function(t,n){null!==n&&"object"==typeof n?e.$elem.data("barrating",n):e.$elem.data("barrating")[t]=n},u=function(){var t=r(),n=o(),i=t.val(),a=t.data("html")?t.data("html"):t.text(),l=null!==e.options.allowEmpty?e.options.allowEmpty:!!n.length,u=n.length?n.val():null,d=n.length?n.text():null;s(null,{userOptions:e.options,ratingValue:i,ratingText:a,originalRatingValue:i,originalRatingText:a,allowEmpty:l,emptyRatingValue:u,emptyRatingText:d,readOnly:e.options.readonly,ratingMade:!1})},d=function(){e.$elem.removeData("barrating")},c=function(){return l("ratingText")},f=function(){return l("ratingValue")},g=function(){var n=t("<div />",{"class":"br-widget"});return e.$elem.find("option").each(function(){var i,a,r,o;i=t(this).val(),i!==l("emptyRatingValue")&&(a=t(this).text(),r=t(this).data("html"),r&&(a=r),o=t("<a />",{href:"#","data-rating-value":i,"data-rating-text":a,html:e.options.showValues?a:""}),n.append(o))}),e.options.showSelectedRating&&n.append(t("<div />",{text:"","class":"br-current-rating"})),e.options.reverse&&n.addClass("br-reverse"),e.options.readonly&&n.addClass("br-readonly"),n},p=function(){return l("userOptions").reverse?"nextAll":"prevAll"},h=function(t){a(t).prop("selected",!0),l("userOptions").triggerChange&&e.$elem.change()},m=function(){t("option",e.$elem).prop("selected",function(){return this.defaultSelected}),l("userOptions").triggerChange&&e.$elem.change()},v=function(t){t=t?t:c(),t==l("emptyRatingText")&&(t=""),e.options.showSelectedRating&&e.$elem.parent().find(".br-current-rating").text(t)},y=function(t){return Math.round(Math.floor(10*t)/10%1*100)},b=function(){e.$widget.find("a").removeClass(function(t,e){return(e.match(/(^|\s)br-\S+/g)||[]).join(" ")})},w=function(){var n,i,a=e.$widget.find('a[data-rating-value="'+f()+'"]'),r=l("userOptions").initialRating,o=t.isNumeric(f())?f():0,s=y(r);if(b(),a.addClass("br-selected br-current")[p()]().addClass("br-selected"),!l("ratingMade")&&t.isNumeric(r)){if(o>=r||!s)return;n=e.$widget.find("a"),i=a.length?a[l("userOptions").reverse?"prev":"next"]():n[l("userOptions").reverse?"last":"first"](),i.addClass("br-fractional"),i.addClass("br-fractional-"+s)}},$=function(t){return l("allowEmpty")&&l("userOptions").deselectable?f()==t.attr("data-rating-value"):!1},x=function(n){n.on("click.barrating",function(n){var i,a,r=t(this),o=l("userOptions");return n.preventDefault(),i=r.attr("data-rating-value"),a=r.attr("data-rating-text"),$(r)&&(i=l("emptyRatingValue"),a=l("emptyRatingText")),s("ratingValue",i),s("ratingText",a),s("ratingMade",!0),h(i),v(a),w(),o.onSelect.call(e,f(),c(),n),!1})},R=function(e){e.on("mouseenter.barrating",function(){var e=t(this);b(),e.addClass("br-active")[p()]().addClass("br-active"),v(e.attr("data-rating-text"))})},C=function(t){e.$widget.on("mouseleave.barrating blur.barrating",function(){v(),w()})},O=function(e){e.on("touchstart.barrating",function(e){e.preventDefault(),e.stopPropagation(),t(this).click()})},V=function(t){t.on("click.barrating",function(t){t.preventDefault()})},S=function(t){x(t),e.options.hoverState&&(R(t),C(t))},T=function(t){t.off(".barrating")},j=function(t){var n=e.$widget.find("a");O&&O(n),t?(T(n),V(n)):S(n)};this.show=function(){l()||(n(),u(),e.$widget=g(),e.$widget.insertAfter(e.$elem),w(),v(),j(e.options.readonly),e.$elem.hide())},this.readonly=function(t){"boolean"==typeof t&&l("readOnly")!=t&&(j(t),s("readOnly",t),e.$widget.toggleClass("br-readonly"))},this.set=function(t){var n=l("userOptions");0!==e.$elem.find('option[value="'+t+'"]').length&&(s("ratingValue",t),s("ratingText",e.$elem.find('option[value="'+t+'"]').text()),s("ratingMade",!0),h(f()),v(c()),w(),n.silent||n.onSelect.call(this,f(),c()))},this.clear=function(){var t=l("userOptions");s("ratingValue",l("originalRatingValue")),s("ratingText",l("originalRatingText")),s("ratingMade",!1),m(),v(c()),w(),t.onClear.call(this,f(),c())},this.destroy=function(){var t=f(),n=c(),a=l("userOptions");T(e.$widget.find("a")),e.$widget.remove(),d(),i(),e.$elem.show(),a.onDestroy.call(this,t,n)}}return e.prototype.init=function(e,n){return this.$elem=t(n),this.options=t.extend({},t.fn.barrating.defaults,e),this.options},e}();t.fn.barrating=function(n,i){return this.each(function(){var a=new e;if(t(this).is("select")||t.error("Sorry, this plugin only works with select fields."),a.hasOwnProperty(n)){if(a.init(i,this),"show"===n)return a.show(i);if(a.$elem.data("barrating"))return a.$widget=t(this).next(".br-widget"),a[n](i)}else{if("object"==typeof n||!n)return i=n,a.init(i,this),a.show();t.error("Method "+n+" does not exist on jQuery.barrating")}})},t.fn.barrating.defaults={theme:"",initialRating:null,allowEmpty:null,emptyValue:"",showValues:!1,showSelectedRating:!0,deselectable:!0,reverse:!1,readonly:!1,fastClicks:!0,hoverState:!0,silent:!1,triggerChange:!0,onSelect:function(t,e,n){},onClear:function(t,e){},onDestroy:function(t,e){}},t.fn.barrating.BarRating=e});
 
backend/components/notices/resources/js/lite-rebranding.js CHANGED
@@ -1,6 +1,6 @@
1
  jQuery(function ($) {
2
- var $notice = $('#bookly-lite-rebranding-notice');
3
  $notice.on('close.bs.alert', function () {
4
- $.post(ajaxurl, {action: $notice.data('action'), csrf_token : BooklySupportL10n.csrfToken});
5
  });
6
  });
1
  jQuery(function ($) {
2
+ let $notice = $('#bookly-lite-rebranding-notice');
3
  $notice.on('close.bs.alert', function () {
4
+ $.post(ajaxurl, {action: $notice.data('action'), csrf_token : BooklyLiteL10n.csrfToken});
5
  });
6
  });
backend/components/notices/resources/js/nps.js CHANGED
@@ -1,41 +1,46 @@
1
  jQuery(function ($) {
2
- var $alert = $('#bookly-nps-notice'),
3
  $quiz = $('#bookly-nps-quiz'),
4
  $stars = $('#bookly-nps-stars'),
5
  $msg = $('#bookly-nps-msg'),
6
  $email = $('#bookly-nps-email'),
7
  $form = $('#bookly-nps-form'),
8
- $thanks = $('#bookly-nps-thanks')
9
- ;
10
 
11
  // Init stars.
12
- $stars.barrating({
13
- theme: 'bootstrap-stars',
14
- allowEmpty: false,
15
- onSelect: function (value, text, event) {
16
- if (value <= 7) {
17
- $form.show();
18
  } else {
19
- $.post(ajaxurl, {action: 'bookly_nps_send', csrf_token : BooklySupportL10n.csrfToken, rate: value});
20
- $quiz.hide();
21
- $form.hide();
22
- $thanks.show();
23
  }
 
 
 
 
 
 
 
 
 
24
  }
25
  });
26
 
27
  $('#bookly-nps-btn').on('click', function () {
28
- $alert.find('.form-group').removeClass('has-error');
29
  if ($msg.val() == '') {
30
- $msg.closest('.form-group').addClass('has-error');
31
  } else {
32
- var ladda = Ladda.create(this);
33
  ladda.start();
34
  $.post(
35
  ajaxurl,
36
  {
37
  action : 'bookly_nps_send',
38
- csrf_token : BooklySupportL10n.csrfToken,
39
  rate : $stars.val(),
40
  msg : $msg.val(),
41
  email : $email.val()
@@ -52,7 +57,7 @@ jQuery(function ($) {
52
  });
53
 
54
  $alert.on('close.bs.alert', function () {
55
- $.post(ajaxurl, {action: 'bookly_dismiss_nps_notice', csrf_token : BooklySupportL10n.csrfToken}, function () {
56
  // Indicator for Selenium that request has completed.
57
  $('.bookly-js-nps-notice').remove();
58
  });
1
  jQuery(function ($) {
2
+ let $alert = $('#bookly-nps-notice'),
3
  $quiz = $('#bookly-nps-quiz'),
4
  $stars = $('#bookly-nps-stars'),
5
  $msg = $('#bookly-nps-msg'),
6
  $email = $('#bookly-nps-email'),
7
  $form = $('#bookly-nps-form'),
8
+ $thanks = $('#bookly-nps-thanks'),
9
+ rating = 0;
10
 
11
  // Init stars.
12
+ $quiz.on('mouseenter', '.bookly-js-star', function () {
13
+ rating = $(this).index();
14
+ $('#bookly-nps-quiz i.bookly-js-star').each(function () {
15
+ if ($(this).index() <= rating) {
16
+ $(this).removeClass('text-muted far').addClass('text-warning fas');
 
17
  } else {
18
+ $(this).removeClass('text-warning fas').addClass('text-muted far');
 
 
 
19
  }
20
+ });
21
+ }).on('click', '.bookly-js-star', function () {
22
+ if (rating <= 7) {
23
+ $form.show();
24
+ } else {
25
+ $.post(ajaxurl, {action: 'bookly_nps_send', csrf_token: BooklyNpsL10n.csrfToken, rate: rating});
26
+ $quiz.hide();
27
+ $form.hide();
28
+ $thanks.show();
29
  }
30
  });
31
 
32
  $('#bookly-nps-btn').on('click', function () {
33
+ $alert.find('.form-group .form-control').removeClass('is-invalid');
34
  if ($msg.val() == '') {
35
+ $msg.addClass('is-invalid');
36
  } else {
37
+ let ladda = Ladda.create(this);
38
  ladda.start();
39
  $.post(
40
  ajaxurl,
41
  {
42
  action : 'bookly_nps_send',
43
+ csrf_token : BooklyNpsL10n.csrfToken,
44
  rate : $stars.val(),
45
  msg : $msg.val(),
46
  email : $email.val()
57
  });
58
 
59
  $alert.on('close.bs.alert', function () {
60
+ $.post(ajaxurl, {action: 'bookly_dismiss_nps_notice', csrf_token : BooklyNpsL10n.csrfToken}, function () {
61
  // Indicator for Selenium that request has completed.
62
  $('.bookly-js-nps-notice').remove();
63
  });
backend/components/notices/resources/js/powered-by.js CHANGED
@@ -1,11 +1,11 @@
1
  jQuery(function ($) {
2
- var $notice = $('#bookly-js-powered-by');
3
  $notice.on('close.bs.alert', function () {
4
- $.post(ajaxurl, {action: $notice.data('action'), csrf_token: BooklySupportL10n.csrfToken});
5
- }).on('click', '#bookly-js-show-powered-by', function () {
6
- var ladda = Ladda.create(this);
7
  ladda.start();
8
- $.post(ajaxurl, {action: 'bookly_enable_show_powered_by', csrf_token: BooklySupportL10n.csrfToken}, function (response) {
9
  $notice.alert('close');
10
  });
11
  });
1
  jQuery(function ($) {
2
+ let $notice = $('#bookly-powered-by');
3
  $notice.on('close.bs.alert', function () {
4
+ $.post(ajaxurl, {action: $notice.data('action'), csrf_token: BooklyPoweredByL10n.csrfToken});
5
+ }).on('click', '#bookly-show-powered-by', function () {
6
+ let ladda = Ladda.create(this);
7
  ladda.start();
8
+ $.post(ajaxurl, {action: 'bookly_enable_show_powered_by', csrf_token: BooklyPoweredByL10n.csrfToken}, function (response) {
9
  $notice.alert('close');
10
  });
11
  });
backend/components/notices/resources/js/subscribe.js CHANGED
@@ -1,10 +1,10 @@
1
  jQuery(function ($) {
2
- var $alert = $('#bookly-subscribe-notice');
3
  $('#bookly-subscribe-btn').on('click', function () {
4
  $alert.find('.input-group').removeClass('has-error');
5
- var ladda = Ladda.create(this);
6
  ladda.start();
7
- $.post(ajaxurl, {action: 'bookly_subscribe', csrf_token : BooklySupportL10n.csrfToken, email: $('#bookly-subscribe-email').val()}, function (response) {
8
  ladda.stop();
9
  if (response.success) {
10
  $alert.alert('close');
@@ -16,7 +16,7 @@ jQuery(function ($) {
16
  });
17
  });
18
  $alert.on('close.bs.alert', function () {
19
- $.post(ajaxurl, {action: 'bookly_dismiss_subscribe_notice', csrf_token : BooklySupportL10n.csrfToken}, function () {
20
  // Indicator for Selenium that request has completed.
21
  $alert.remove();
22
  });
1
  jQuery(function ($) {
2
+ let $alert = $('#bookly-subscribe-notice');
3
  $('#bookly-subscribe-btn').on('click', function () {
4
  $alert.find('.input-group').removeClass('has-error');
5
+ let ladda = Ladda.create(this);
6
  ladda.start();
7
+ $.post(ajaxurl, {action: 'bookly_subscribe', csrf_token : BooklySubscribeL10n.csrfToken, email: $('#bookly-subscribe-email').val()}, function (response) {
8
  ladda.stop();
9
  if (response.success) {
10
  $alert.alert('close');
16
  });
17
  });
18
  $alert.on('close.bs.alert', function () {
19
+ $.post(ajaxurl, {action: 'bookly_dismiss_subscribe_notice', csrf_token : BooklySubscribeL10n.csrfToken}, function () {
20
  // Indicator for Selenium that request has completed.
21
  $alert.remove();
22
  });
backend/components/notices/templates/collect_stats.php CHANGED
@@ -1,20 +1,22 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
 
 
2
  <div id="bookly-tbs" class="wrap">
3
- <div id="bookly-collect-stats-notice" class="alert alert-info bookly-tbs-body bookly-flexbox" data-action="bookly_dismiss_collect<?php if ( $enabled ): ?>ing<?php endif ?>_stats_notice">
4
- <div class="bookly-flex-row">
5
- <div class="bookly-flex-cell" style="width:39px"><i class="alert-icon"></i></div>
6
- <div class="bookly-flex-cell">
7
- <button type="button" class="close" data-dismiss="alert">&times;</button>
8
  <?php if ( $enabled ): ?>
9
  <?php esc_html_e( 'To help us improve Bookly, the plugin anonymously collects usage information. You can opt out of sharing the information in Settings > General.', 'bookly' ) ?>
10
- <div class="bookly-margin-top-md">
11
- <button type="button" class="btn btn-primary" data-dismiss="alert"><?php esc_html_e( 'Close', 'bookly' ) ?></button>
12
  </div>
13
  <?php else: ?>
14
  <?php esc_html_e( 'Let the plugin anonymously collect usage information to help Bookly team improve the product.', 'bookly' ) ?>
15
- <div class="bookly-margin-top-md">
16
- <button type="button" class="btn btn-default" data-dismiss="alert"><?php esc_html_e( 'Disagree', 'bookly' ) ?></button>
17
- <button type="button" class="btn btn-success" id="bookly-enable-collecting-stats-btn" data-dismiss="alert"><?php esc_html_e( 'Agree', 'bookly' ) ?></button>
18
  </div>
19
  <?php endif ?>
20
  </div>
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ use Bookly\Backend\Components\Controls\Buttons;
3
+ ?>
4
  <div id="bookly-tbs" class="wrap">
5
+ <div id="bookly-collect-stats-notice" class="alert alert-info" data-action="bookly_dismiss_collect<?php if ( $enabled ): ?>ing<?php endif ?>_stats_notice">
6
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
7
+ <div class="form-row">
8
+ <div class="mr-3"><i class="fas fa-info-circle fa-2x"></i></div>
9
+ <div class="col">
10
  <?php if ( $enabled ): ?>
11
  <?php esc_html_e( 'To help us improve Bookly, the plugin anonymously collects usage information. You can opt out of sharing the information in Settings > General.', 'bookly' ) ?>
12
+ <div class="mt-2">
13
+ <button type="button" class="btn btn-default" data-dismiss="alert"><?php esc_html_e( 'Close', 'bookly' ) ?></button>
14
  </div>
15
  <?php else: ?>
16
  <?php esc_html_e( 'Let the plugin anonymously collect usage information to help Bookly team improve the product.', 'bookly' ) ?>
17
+ <div class="mt-2">
18
+ <?php Buttons::render( null, 'btn-default', __( 'Disagree', 'bookly' ), array( 'data-dismiss' => 'alert' ) ) ?>
19
+ <?php Buttons::render( 'bookly-enable-collecting-stats-btn', 'btn-success', __( 'Agree', 'bookly' ) ) ?>
20
  </div>
21
  <?php endif ?>
22
  </div>
backend/components/notices/templates/limitation.php CHANGED
@@ -1,3 +1,3 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
- <b class="h4"><?php _e( 'This function is not available in the Bookly.', 'bookly' ) ?></b>
3
  <br><br><?php _e( 'To get access to all Bookly features, lifetime free updates and 24/7 support, please upgrade to the Pro version of Bookly.<br>For more information visit', 'bookly' ) ?> <a href="http://booking-wp-plugin.com" target="_blank" class="alert-link">http://www.booking-wp-plugin.com</a>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
+ <b class="h4"><?php esc_html_e( 'This function is not available in the Bookly.', 'bookly' ) ?></b>
3
  <br><br><?php _e( 'To get access to all Bookly features, lifetime free updates and 24/7 support, please upgrade to the Pro version of Bookly.<br>For more information visit', 'bookly' ) ?> <a href="http://booking-wp-plugin.com" target="_blank" class="alert-link">http://www.booking-wp-plugin.com</a>
backend/components/notices/templates/lite_rebranding.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
  <div id="bookly-tbs" class="wrap">
3
- <div id="bookly-lite-rebranding-notice" class="alert alert-info bookly-tbs-body bookly-flexbox" data-action="bookly_dismiss_lite_rebranding_notice">
4
- <div class="bookly-flex-row">
5
- <div class="bookly-flex-cell" style="width:39px"><i class="alert-icon"></i></div>
6
- <div class="bookly-flex-cell">
7
- <button type="button" class="close" data-dismiss="alert">&times;</button>
8
  <?php printf( __( '<b>Bookly Lite rebrands into Bookly with more features available.</b><br/><br/>We have changed the architecture of Bookly Lite and Bookly to optimize the development of both plugin versions and add more features to the new free Bookly. To learn more about the major Bookly update, check our <a href="%s" target="_blank">blog post</a>.', 'bookly' ), 'https://www.booking-wp-plugin.com/bookly-major-update/?utm_source=bookly_admin&utm_medium=pro_not_active&utm_campaign=notification' ) ?>
9
  </div>
10
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
  <div id="bookly-tbs" class="wrap">
3
+ <div id="bookly-lite-rebranding-notice" class="alert alert-info" data-action="bookly_dismiss_lite_rebranding_notice">
4
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
5
+ <div class="form-row">
6
+ <div class="mr-3"><i class="fas fa-info-circle fa-2x"></i></div>
7
+ <div class="col">
8
  <?php printf( __( '<b>Bookly Lite rebrands into Bookly with more features available.</b><br/><br/>We have changed the architecture of Bookly Lite and Bookly to optimize the development of both plugin versions and add more features to the new free Bookly. To learn more about the major Bookly update, check our <a href="%s" target="_blank">blog post</a>.', 'bookly' ), 'https://www.booking-wp-plugin.com/bookly-major-update/?utm_source=bookly_admin&utm_medium=pro_not_active&utm_campaign=notification' ) ?>
9
  </div>
10
  </div>
backend/components/notices/templates/nps.php CHANGED
@@ -4,35 +4,32 @@ use Bookly\Backend\Components\Support\Lib\Urls;
4
  use Bookly\Lib\Utils\Common;
5
  ?>
6
  <div id="bookly-tbs" class="wrap bookly-js-nps-notice">
7
- <div id="bookly-nps-notice" class="alert alert-info bookly-tbs-body bookly-flexbox">
8
- <div class="bookly-flex-row">
9
- <div class="bookly-flex-cell" style="width:39px"><i class="alert-icon"></i></div>
10
- <div class="bookly-flex-cell">
11
- <button type="button" class="close" data-dismiss="alert">&times;</button>
12
- <div id="bookly-nps-quiz">
13
  <label><?php esc_html_e( 'How likely is it that you would recommend Bookly to a friend or colleague?', 'bookly' ) ?></label>
14
- <select id="bookly-nps-stars" class="hidden">
15
- <option value=""></option>
16
- <?php for ( $i = 1; $i <= 10; ++ $i ): ?>
17
- <option value="<?php echo $i ?>"><?php echo $i ?></option>
18
- <?php endfor ?>
19
- </select>
20
  </div>
21
- <div id="bookly-nps-form" class="bookly-margin-top-lg" style="max-width:400px;display:none;">
22
  <div class="form-group">
23
  <label for="bookly-nps-msg" class="control-label"><?php esc_html_e( 'What do you think should be improved?', 'bookly' ) ?></label>
24
  <textarea id="bookly-nps-msg" class="form-control"></textarea>
25
  </div>
26
  <div class="form-group">
27
  <label for="bookly-nps-email" class="control-label"><?php esc_html_e( 'Please enter your email (optional)', 'bookly' ) ?></label>
28
- <input type="text" id="bookly-nps-email" class="form-control" value="<?php echo esc_attr( $current_user->user_email ) ?>" />
29
  </div>
30
- <?php Buttons::renderCustom( 'bookly-nps-btn', 'btn-success', __( 'Send', 'bookly' ) ) ?>
31
  </div>
32
- <div id="bookly-nps-thanks" style="display:none;">
33
  <?php printf(
34
- __( 'Please leave your feedback <a href="%s" target="_blank">here</a>.', 'bookly' ),
35
- Common::prepareUrlReferrers( Urls::REVIEWS_PAGE, 'nps' )
36
  ) ?>
37
  </div>
38
  </div>
4
  use Bookly\Lib\Utils\Common;
5
  ?>
6
  <div id="bookly-tbs" class="wrap bookly-js-nps-notice">
7
+ <div id="bookly-nps-notice" class="alert alert-info">
8
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
9
+ <div class="form-row">
10
+ <div class="mr-3"><i class="fas fa-info-circle fa-2x"></i></div>
11
+ <div class="col">
12
+ <div id="bookly-nps-quiz" class="my-2">
13
  <label><?php esc_html_e( 'How likely is it that you would recommend Bookly to a friend or colleague?', 'bookly' ) ?></label>
14
+ <div>
15
+ <?php for ( $i = 1; $i <= 10; ++ $i ): ?><i class="bookly-js-star far fa-star fa-lg text-muted"></i><?php endfor ?>
16
+ </div>
 
 
 
17
  </div>
18
+ <div id="bookly-nps-form" class="mt-4 collapse" style="max-width:400px;">
19
  <div class="form-group">
20
  <label for="bookly-nps-msg" class="control-label"><?php esc_html_e( 'What do you think should be improved?', 'bookly' ) ?></label>
21
  <textarea id="bookly-nps-msg" class="form-control"></textarea>
22
  </div>
23
  <div class="form-group">
24
  <label for="bookly-nps-email" class="control-label"><?php esc_html_e( 'Please enter your email (optional)', 'bookly' ) ?></label>
25
+ <input type="text" id="bookly-nps-email" class="form-control" value="<?php echo esc_attr( $current_user->user_email ) ?>"/>
26
  </div>
27
+ <?php Buttons::render( 'bookly-nps-btn', 'btn-success', __( 'Send', 'bookly' ) ) ?>
28
  </div>
29
+ <div id="bookly-nps-thanks" class="collapse mt-1">
30
  <?php printf(
31
+ __( 'Please leave your feedback <a href="%s" target="_blank">here</a>.', 'bookly' ),
32
+ Common::prepareUrlReferrers( Urls::REVIEWS_PAGE, 'nps' )
33
  ) ?>
34
  </div>
35
  </div>
backend/components/notices/templates/powered_by.php CHANGED
@@ -1,14 +1,16 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
 
 
2
  <div id="bookly-tbs" class="wrap">
3
- <div id="bookly-js-powered-by" class="alert alert-info bookly-tbs-body bookly-flexbox" data-action="bookly_dismiss_powered_by_notice">
4
- <div class="bookly-flex-row">
5
- <div class="bookly-flex-cell" style="width:39px"><i class="alert-icon"></i></div>
6
- <div class="bookly-flex-cell">
7
- <button type="button" class="close" data-dismiss="alert">&times;</button>
8
  <?php esc_html_e( 'Allow the plugin to set a Powered by Bookly notice on the booking widget to spread information about the plugin. This will allow the team to improve the product and enhance its functionality.', 'bookly' ) ?>
9
- <div class="bookly-margin-top-md">
10
- <button type="button" class="btn btn-default" data-dismiss="alert"><?php esc_html_e( 'Disagree', 'bookly' ) ?></button>
11
- <button type="button" class="btn btn-success" id="bookly-js-show-powered-by"><?php esc_html_e( 'Agree', 'bookly' ) ?></button>
12
  </div>
13
  </div>
14
  </div>
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ use Bookly\Backend\Components\Controls\Buttons;
3
+ ?>
4
  <div id="bookly-tbs" class="wrap">
5
+ <div id="bookly-powered-by" class="alert alert-info" data-action="bookly_dismiss_powered_by_notice">
6
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
7
+ <div class="form-row">
8
+ <div class="mr-3"><i class="fas fa-info-circle fa-2x"></i></div>
9
+ <div class="col">
10
  <?php esc_html_e( 'Allow the plugin to set a Powered by Bookly notice on the booking widget to spread information about the plugin. This will allow the team to improve the product and enhance its functionality.', 'bookly' ) ?>
11
+ <div class="mt-2">
12
+ <?php Buttons::render( null, 'btn-default', __( 'Disagree', 'bookly' ), array( 'data-dismiss' => 'alert' ) ) ?>
13
+ <?php Buttons::render( 'bookly-show-powered-by', 'btn-success', __( 'Agree', 'bookly' ) ) ?>
14
  </div>
15
  </div>
16
  </div>
backend/components/notices/templates/subscribe.php CHANGED
@@ -1,19 +1,21 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
- <div id="bookly-tbs" class="wrap bookly-js-subscribe-notice">
3
- <div id="bookly-subscribe-notice" class="alert alert-info bookly-tbs-body bookly-flexbox">
4
- <div class="bookly-flex-row">
5
- <div class="bookly-flex-cell" style="width:39px"><i class="alert-icon"></i></div>
6
- <div class="bookly-flex-cell">
7
- <button type="button" class="close" data-dismiss="alert">&times;</button>
8
- <label for="bookly-subscribe-email"><?php _e( 'Subscribe to monthly emails about Bookly improvements and new releases.', 'bookly' ) ?></label>
9
- <div class="input-group input-group-sm" style="max-width: 400px">
10
- <span class="input-group-addon"><i class="glyphicon glyphicon-envelope"></i></span>
11
- <input type="text" id="bookly-subscribe-email" class="form-control" />
12
- <span class="input-group-btn">
13
- <button type="button" id="bookly-subscribe-btn" class="btn btn-info ladda-button" data-spinner-size="30" data-style="zoom-in">
14
- <span class="ladda-label"><?php _e( 'Send', 'bookly' ) ?></span>
15
- </button>
16
- </span>
 
 
17
  </div>
18
  </div>
19
  </div>
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ use Bookly\Backend\Components\Controls\Buttons;
3
+ ?>
4
+ <div id="bookly-tbs" class="wrap">
5
+ <div id="bookly-subscribe-notice" class="alert alert-info">
6
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
7
+ <div class="form-row">
8
+ <div class="mr-3"><i class="fas fa-info-circle fa-2x"></i></div>
9
+ <div class="col">
10
+ <label for="bookly-subscribe-email"><?php esc_html_e( 'Subscribe to monthly emails about Bookly improvements and new releases.', 'bookly' ) ?></label>
11
+ <div class="input-group" style="max-width: 400px;">
12
+ <div class="input-group-prepend">
13
+ <div class="input-group-text"><i class="fas fa-fw fa-envelope"></i></div>
14
+ </div>
15
+ <input type="text" id="bookly-subscribe-email" class="form-control"/>
16
+ <div class="input-group-append">
17
+ <?php Buttons::render( 'bookly-subscribe-btn', 'btn-info', __( 'Send', 'bookly' ) ) ?>
18
+ </div>
19
  </div>
20
  </div>
21
  </div>
backend/components/schedule/BreakItem.php ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Bookly\Backend\Components\Schedule;
3
+
4
+ use Bookly\Lib;
5
+
6
+ /**
7
+ * Class BreakItem
8
+ * @package Bookly\Backend\Components\Schedule
9
+ */
10
+ class BreakItem extends Lib\Base\Component
11
+ {
12
+ /** @var int */
13
+ protected $id;
14
+ /** @var string */
15
+ protected $start;
16
+ /** @var string */
17
+ protected $end;
18
+
19
+ /**
20
+ * Constructor.
21
+ *
22
+ * @param int $id
23
+ * @param string $start
24
+ * @param string $end
25
+ */
26
+ public function __construct( $id, $start, $end )
27
+ {
28
+ $this->id = $id;
29
+ $this->start = $start;
30
+ $this->end = $end;
31
+ }
32
+
33
+ /**
34
+ * Render break item.
35
+ *
36
+ * @param bool $echo
37
+ * @return string|void
38
+ */
39
+ public function render( $echo = true )
40
+ {
41
+ return self::renderTemplate( 'break', array(
42
+ 'id' => $this->id,
43
+ 'interval' => $this->getFormatedInterval(),
44
+ ), $echo );
45
+ }
46
+
47
+ /**
48
+ * Gets start
49
+ *
50
+ * @return string
51
+ */
52
+ public function getStart()
53
+ {
54
+ return $this->start;
55
+ }
56
+
57
+ /**
58
+ * Gets end
59
+ *
60
+ * @return string
61
+ */
62
+ public function getEnd()
63
+ {
64
+ return $this->end;
65
+ }
66
+
67
+ /**
68
+ * Format interval.
69
+ *
70
+ * @return string
71
+ */
72
+ public function getFormatedInterval()
73
+ {
74
+ return Lib\Utils\DateTime::formatInterval( $this->start, $this->end );
75
+ }
76
+ }
backend/components/schedule/Component.php ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Bookly\Backend\Components\Schedule;
3
+
4
+ use Bookly\Lib;
5
+
6
+ /**
7
+ * Class Component
8
+ * @package Bookly\Backend\Components\Schedule
9
+ */
10
+ class Component extends Lib\Base\Component implements \Iterator
11
+ {
12
+ /** @var array */
13
+ protected $days = array();
14
+ /** @var Range[] */
15
+ protected $hours = array();
16
+ /** @var array|null */
17
+ protected $breaks;
18
+
19
+ /** @var BreakItem[] */
20
+ public $day_breaks = array();
21
+
22
+ /** @var Select */
23
+ public $start_select;
24
+
25
+ /** @var Select */
26
+ public $end_select;
27
+ /** @var string */
28
+ protected $end_default = '18:00:00';
29
+
30
+ /** @var array */
31
+ protected $keys;
32
+
33
+ /**
34
+ * Constructor.
35
+ *
36
+ * @param string $start_name
37
+ * @param string $end_name
38
+ * @param bool $with_breaks
39
+ */
40
+ public function __construct( $start_name, $end_name, $with_breaks = true )
41
+ {
42
+ $this->start_select = new Select( array(
43
+ 'use_empty' => true,
44
+ 'empty_value' => __( 'OFF', 'bookly' ),
45
+ 'type' => 'from',
46
+ 'class' => 'bookly-js-parent-range-start',
47
+ 'name' => $start_name
48
+ ) );
49
+ $this->end_select = new Select( array(
50
+ 'use_empty' => false,
51
+ 'type' => 'to',
52
+ 'class' => 'bookly-js-parent-range-end',
53
+ 'name' => $end_name
54
+ ) );
55
+
56
+ if ( $with_breaks ) {
57
+ $this->breaks = array();
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Add working hours.
63
+ *
64
+ * @param string $key record key
65
+ * @param string $day_index
66
+ * @param string $start
67
+ * @param string $end
68
+ * @return $this
69
+ */
70
+ public function addHours( $key, $day_index, $start, $end )
71
+ {
72
+ $this->hours[ $key ] = new Range( $start, $end );
73
+ $this->keys[ $day_index ] = $key;
74
+
75
+ return $this;
76
+ }
77
+
78
+ /**
79
+ * Whether schedule may have breaks or not.
80
+ *
81
+ * @return bool
82
+ */
83
+ public function withBreaks()
84
+ {
85
+ return is_array( $this->breaks );
86
+ }
87
+
88
+ /**
89
+ * Add break.
90
+ *
91
+ * @param string $index
92
+ * @param string $entity_id
93
+ * @param string $start
94
+ * @param string $end
95
+ * @return $this
96
+ */
97
+ public function addBreak( $index, $entity_id, $start, $end )
98
+ {
99
+ $this->breaks[ $index ][] = new BreakItem( $entity_id, $start, $end );
100
+
101
+ return $this;
102
+ }
103
+
104
+ /**
105
+ * Get breaks as array.
106
+ *
107
+ * @return array
108
+ */
109
+ public function getBreaksArray()
110
+ {
111
+ $flat = array();
112
+ foreach ( $this->breaks as $index => $day_breaks ) {
113
+ /** @var BreakItem $break */
114
+ foreach ( $day_breaks as $break ) {
115
+ $flat[] = array(
116
+ 'index' => $index,
117
+ 'start' => $break->getStart(),
118
+ 'end' => $break->getEnd(),
119
+ );
120
+ }
121
+ }
122
+
123
+ return $flat;
124
+ }
125
+
126
+ /**
127
+ * Render schedule.
128
+ *
129
+ * @param bool $echo
130
+ * @return string|void
131
+ */
132
+ public function render( $echo = true )
133
+ {
134
+ /** @global \WP_Locale $wp_locale */
135
+ global $wp_locale;
136
+
137
+ $start_of_week = (int) get_option( 'start_of_week' );
138
+ for ( $i = 1; $i <= 7; $i ++ ) {
139
+ $day_index = ( $start_of_week + $i ) < 8 ? $start_of_week + $i : $start_of_week + $i - 7;
140
+ $id = $this->keys[ $day_index ];
141
+ $this->days[ $id ] = $wp_locale->weekday[ $day_index == 7 ? 6 : ( $day_index - 1 ) ];
142
+ }
143
+
144
+ return self::renderTemplate( 'schedule', array( 'schedule' => $this ), $echo );
145
+ }
146
+
147
+ /**
148
+ * Return day index
149
+ *
150
+ * @return int
151
+ */
152
+ public function index()
153
+ {
154
+ return array_search( $this->key(), $this->keys );
155
+ }
156
+
157
+ /**
158
+ * Render edit break dialog.
159
+ *
160
+ * @param bool $echo
161
+ * @return string|void
162
+ */
163
+ public static function renderBreakDialog( $echo = true )
164
+ {
165
+ return self::renderTemplate( 'break_dialog', array(
166
+ 'start_select' => new Select( array(
167
+ 'use_empty' => false,
168
+ 'type' => 'break_from',
169
+ 'class' => 'bookly-js-popover-range-start',
170
+ ) ),
171
+ 'end_select' => new Select( array(
172
+ 'use_empty' => false,
173
+ 'type' => 'to',
174
+ 'class' => 'bookly-js-popover-range-end',
175
+ ) ),
176
+ ), $echo );
177
+ }
178
+
179
+ /**
180
+ * @inheritDoc
181
+ */
182
+ public function current()
183
+ {
184
+ return current( $this->days );
185
+ }
186
+
187
+ /**
188
+ * @inheritDoc
189
+ */
190
+ public function next()
191
+ {
192
+ if ( next( $this->days ) !== false ) {
193
+ $this->setState();
194
+ }
195
+ }
196
+
197
+ /**
198
+ * @inheritDoc
199
+ */
200
+ public function key()
201
+ {
202
+ return key( $this->days );
203
+ }
204
+
205
+ /**
206
+ * @inheritDoc
207
+ */
208
+ public function valid()
209
+ {
210
+ return (bool) key( $this->days );
211
+ }
212
+
213
+ /**
214
+ * @inheritDoc
215
+ */
216
+ public function rewind()
217
+ {
218
+ if ( reset( $this->days ) !== false ) {
219
+ $this->setState();
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Set state for current iteration.
225
+ */
226
+ protected function setState()
227
+ {
228
+ $index = $this->key();
229
+ $hours = $this->hours[ $index ];
230
+
231
+ $this
232
+ ->start_select
233
+ ->setIndex( $index )
234
+ ->setValue( $hours->getStart() );
235
+ $this
236
+ ->end_select
237
+ ->setIndex( $index )
238
+ ->setValue( $hours->getEnd() ?: $this->end_default );
239
+
240
+ $this->day_breaks = isset ( $this->breaks[ $index ] ) ? $this->breaks[ $index ] : array();
241
+ }
242
+ }
backend/components/schedule/Range.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Bookly\Backend\Components\Schedule;
3
+
4
+ use Bookly\Lib;
5
+
6
+ /**
7
+ * Class Range
8
+ * @package Bookly\Backend\Components\Schedule
9
+ */
10
+ class Range extends Lib\Base\Component
11
+ {
12
+ /** @var string */
13
+ protected $start;
14
+ /** @var string */
15
+ protected $end;
16
+
17
+ /**
18
+ * Constructor.
19
+ *
20
+ * @param string $start
21
+ * @param string $end
22
+ */
23
+ public function __construct( $start, $end )
24
+ {
25
+ $this->start = $start;
26
+ $this->end = $end;
27
+ }
28
+
29
+ /**
30
+ * Gets start
31
+ *
32
+ * @return string
33
+ */
34
+ public function getStart()
35
+ {
36
+ return $this->start;
37
+ }
38
+
39
+ /**
40
+ * Gets end
41
+ *
42
+ * @return string
43
+ */
44
+ public function getEnd()
45
+ {
46
+ return $this->end;
47
+ }
48
+ }
backend/components/schedule/Select.php ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace Bookly\Backend\Components\Schedule;
3
+
4
+ use Bookly\Lib;
5
+
6
+ /**
7
+ * Class Select
8
+ * @package Bookly\Backend\Components\Schedule
9
+ */
10
+ class Select
11
+ {
12
+ /** @var array */
13
+ protected $values = array();
14
+
15
+ /** @var string */
16
+ protected $name;
17
+ /** @var string */
18
+ protected $class = 'form-control custom-select';
19
+ /** @var string */
20
+ protected $index;
21
+ /** @var string */
22
+ protected $value;
23
+
24
+ /**
25
+ * Constructor.
26
+ *
27
+ * @param array $options
28
+ */
29
+ public function __construct( array $options = array() )
30
+ {
31
+ // Handle widget options.
32
+ $options = array_merge( array(
33
+ 'use_empty' => true,
34
+ 'empty_value' => null,
35
+ 'type' => 'from',
36
+ ), $options );
37
+
38
+ if ( array_key_exists( 'name', $options ) ) {
39
+ $this->name = $options['name'];
40
+ }
41
+ if ( array_key_exists( 'class', $options ) ) {
42
+ $this->class .= ' ' . $options['class'];
43
+ }
44
+
45
+ // Insert empty value if required.
46
+ if ( $options['use_empty'] ) {
47
+ $this->values[ null ] = $options['empty_value'];
48
+ }
49
+
50
+ $ts_length = Lib\Config::getTimeSlotLength();
51
+ $time_start = 0;
52
+ $time_end = DAY_IN_SECONDS;
53
+
54
+ if ( $options['type'] == 'from' ) {
55
+ $time_end -= $ts_length; // Exclude last slot.
56
+ } else if ( $options['type'] == 'break_from' ) {
57
+ $time_end *= 2; // Create slots for 2 days.
58
+ $time_end -= $ts_length; // Exclude last slot.
59
+ } else if ( $options['type'] == 'to' ) {
60
+ $time_end *= 2; // Create slots for 2 days.
61
+ }
62
+
63
+ // Run the loop.
64
+ while ( $time_start <= $time_end ) {
65
+ $this->values[ Lib\Utils\DateTime::buildTimeString( $time_start ) ] = Lib\Utils\DateTime::formatTime( $time_start );
66
+ $time_start += $ts_length;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * @param $index
72
+ * @return $this
73
+ */
74
+ public function setIndex( $index )
75
+ {
76
+ $this->index = $index;
77
+
78
+ return $this;
79
+ }
80
+
81
+ /**
82
+ * @param string $value
83
+ * @return $this
84
+ */
85
+ public function setValue( $value = null )
86
+ {
87
+ $this->value = $value;
88
+
89
+ return $this;
90
+ }
91
+
92
+ /**
93
+ * Render select.
94
+ *
95
+ * @param bool $echo
96
+ * @return string|void
97
+ */
98
+ public function render( $echo = true )
99
+ {
100
+ $attributes_str = 'class="' . $this->class . '"';
101
+ if ( $this->name ) {
102
+ $attributes_str .= ' name="' . str_replace( '{index}', $this->index, $this->name ) . '"';
103
+ }
104
+ $options = '';
105
+ $value_added = false;
106
+ foreach ( $this->values as $option_value => $option_text ) {
107
+ if ( $value_added === false ) {
108
+ if ( $this->value == $option_value ) {
109
+ $value_added = true;
110
+ } elseif ( $this->value < $option_value ) {
111
+ // Make sure that value presents in the list,
112
+ // even if corresponding option did not exist in $this->values.
113
+ $options .= sprintf(
114
+ '<option value="%s" selected="selected">%s</option>',
115
+ $this->value,
116
+ Lib\Utils\DateTime::formatTime( Lib\Utils\DateTime::timeToSeconds( $this->value ) )
117
+ );
118
+ $value_added = true;
119
+ }
120
+ }
121
+ $options .= sprintf(
122
+ '<option value="%s"%s>%s</option>',
123
+ $option_value,
124
+ selected( $this->value, $option_value, false ),
125
+ $option_text
126
+ );
127
+ }
128
+
129
+ $html = sprintf( '<select %s data-default_value="%s">%s</select>',
130
+ $attributes_str,
131
+ $this->value,
132
+ $options
133
+ );
134
+
135
+ if ( $echo ) {
136
+ echo $html;
137
+ } else {
138
+ return $html;
139
+ }
140
+ }
141
+ }
backend/components/schedule/templates/break.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ /**
3
+ * @var int $id
4
+ * @var string $interval
5
+ */
6
+ ?>
7
+ <div class="btn-group btn-group-sm mb-1" data-entity-id="<?php echo $id ?>">
8
+ <button type="button" class="btn btn-info bookly-js-toggle-popover bookly-js-break-interval">
9
+ <?php echo $interval ?>
10
+ </button>
11
+ <button type="button" title="<?php esc_attr_e( 'Delete break', 'bookly' ) ?>" class="btn btn-info bookly-js-delete-break mr-1" data-style="zoom-in" data-spinner-size="20"><span class="ladda-label">&times;</span></button>
12
+ </div>
backend/components/schedule/templates/break_dialog.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ use Bookly\Backend\Components\Controls\Buttons;
3
+ /**
4
+ * @var Bookly\Backend\Components\Schedule\Select $start_select
5
+ * @var Bookly\Backend\Components\Schedule\Select $end_select
6
+ */
7
+ ?>
8
+ <div class="d-none bookly-js-edit-break-body">
9
+ <div>
10
+ <div class="form-row align-items-center">
11
+ <div class="col">
12
+ <?php $start_select->render() ?>
13
+ </div>
14
+ <div class="col-auto">
15
+ <?php esc_html_e( 'to', 'bookly' ) ?>
16
+ </div>
17
+ <div class="col">
18
+ <?php $end_select->render() ?>
19
+ </div>
20
+ </div>
21
+ <hr>
22
+ <div class="text-right">
23
+ <?php Buttons::renderSubmit() ?>
24
+ <?php Buttons::renderDefault( null, 'bookly-js-close', __( 'Close', 'bookly' ) ) ?>
25
+ </div>
26
+ </div>
27
+ </div>
backend/components/schedule/templates/schedule.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ /**
3
+ * @var Bookly\Backend\Components\Schedule\Component $schedule
4
+ */
5
+ ?>
6
+ <div class="form-group">
7
+ <?php foreach ( $schedule as $title ) : ?>
8
+ <div class="form-row form-group bookly-js-range-row" data-key="<?php echo $schedule->key() ?>" data-index="<?php echo $schedule->index() ?>">
9
+ <div class="col-12 col-lg-6">
10
+ <div class="form-row align-items-center">
11
+ <div class="col-3">
12
+ <?php echo esc_html( $title ) ?>
13
+ </div>
14
+ <div class="col">
15
+ <?php $schedule->start_select->render() ?>
16
+ </div>
17
+ <div class="col-auto bookly-js-invisible-on-off">
18
+ <?php esc_html_e( 'to', 'bookly' ) ?>
19
+ </div>
20
+ <div class="col bookly-js-invisible-on-off">
21
+ <?php $schedule->end_select->render() ?>
22
+ </div>
23
+ </div>
24
+ </div>
25
+ <?php if ( $schedule->withBreaks() ) : ?>
26
+ <div class="col-12 col-lg bookly-js-breaks-wrapper bookly-js-hide-on-off">
27
+ <button type="button" class="bookly-js-toggle-popover btn btn-link pl-0">
28
+ <?php esc_html_e( 'add break', 'bookly' ) ?>
29
+ </button>
30
+ <div class="bookly-js-breaks-list">
31
+ <?php foreach ( $schedule->day_breaks as $break ) $break->render() ?>
32
+ </div>
33
+ </div>
34
+ <?php endif ?>
35
+ </div>
36
+ <?php endforeach ?>
37
+ <?php if ( $schedule->withBreaks() ): $schedule::renderBreakDialog(); endif ?>
38
+ </div>
backend/components/settings/Inputs.php CHANGED
@@ -87,11 +87,12 @@ class Inputs
87
  */
88
  public static function buildControl( $option_name, $label, $help, $control_html )
89
  {
 
90
  return strtr(
91
- '<div class="form-group">{label}{help}{control}</div>',
92
  array(
93
  '{label}' => $label != '' ? sprintf( '<label for="%s">%s</label>', $option_name, $label ) : '',
94
- '{help}' => $help != '' ? sprintf( '<p class="help-block">%s</p>', $help ) : '',
95
  '{control}' => $control_html,
96
  )
97
  );
87
  */
88
  public static function buildControl( $option_name, $label, $help, $control_html )
89
  {
90
+
91
  return strtr(
92
+ '<div class="form-group">{label}{control}{help}</div>',
93
  array(
94
  '{label}' => $label != '' ? sprintf( '<label for="%s">%s</label>', $option_name, $label ) : '',
95
+ '{help}' => $help != '' ? sprintf( '<small class="form-text text-muted">%s</small>', $help ) : '',
96
  '{control}' => $control_html,
97
  )
98
  );
backend/components/settings/Menu.php CHANGED
@@ -15,9 +15,9 @@ class Menu
15
  */
16
  public static function renderItem( $title, $tab )
17
  {
18
- printf( '<li class="bookly-nav-item" data-target="#bookly_settings_%s" data-toggle="tab">%s</li>',
19
  $tab,
20
- $title
21
  );
22
  }
23
  }
15
  */
16
  public static function renderItem( $title, $tab )
17
  {
18
+ printf( '<a class="nav-link mb-2" href="#bookly_settings_%s" data-toggle="bookly-pill">%s</a>',
19
  $tab,
20
+ esc_html( $title )
21
  );
22
  }
23
  }
backend/components/settings/Selects.php CHANGED
@@ -1,5 +1,6 @@
1
  <?php
2
  namespace Bookly\Backend\Components\Settings;
 
3
 
4
  /**
5
  * Class Selects
@@ -19,18 +20,28 @@ class Selects
19
  {
20
  $values = (array) get_option( $option_name );
21
  $control = '';
22
- foreach ( $options as $attr ) {
23
  $control .= strtr(
24
- '<div class="checkbox"><label><input type="checkbox" name="{name}[]" value="{value}"{checked} />{caption}</label></div>',
 
 
 
 
 
 
 
 
 
25
  array(
 
26
  '{name}' => $option_name,
27
- '{value}' => esc_attr( $attr[0] ),
28
- '{checked}' => checked( in_array( $attr[0], $values ), true, false ),
29
- '{caption}' => esc_html( $attr[1] ),
30
  )
31
  );
32
  }
33
- $control = "<div class=\"bookly-flags\" id=\"$option_name\">$control</div>";
34
 
35
  echo Inputs::buildControl( $option_name, $label, $help, $control );
36
  }
@@ -45,36 +56,17 @@ class Selects
45
  */
46
  public static function renderRadios( $option_name, $label = null, $help = null, array $radios = array() )
47
  {
48
- $template = '<div class="radio"><label><input type="radio" name="{name}" id="{name}" value="{value}"{attr}> {label}</label></div>';
49
  if ( empty ( $radios ) ) {
50
  $radios = array(
51
- // value title disabled
52
- array( 1, __( 'Enabled', 'bookly' ), 0 ),
53
- array( 0, __( 'Disabled', 'bookly' ), 0 ),
54
- );
55
- }
56
- $html = '';
57
- foreach ( $radios as $attr ) {
58
- $html .= strtr(
59
- $template,
60
- array(
61
- '{name}' => $option_name,
62
- '{value}' => esc_attr( $attr[ 0 ] ),
63
- '{attr}' => empty ( $attr[ 2 ] )
64
- ? checked( get_option( $option_name ), $attr[0], false )
65
- : disabled( true, true, false ),
66
- '{label}' => esc_html( $attr[1] ),
67
- )
68
  );
69
  }
70
 
71
- echo strtr(
72
- '<div class="form-group">{label}{help}{control}</div>',
73
- array(
74
- '{label}' => $label != '' ? sprintf( '<label>%s</label>', $label ) : '',
75
- '{help}' => $help != '' ? sprintf( '<p class="help-block">%s</p>', $help ) : '',
76
- '{control}' => $html,
77
- )
78
  );
79
  }
80
 
@@ -111,7 +103,7 @@ class Selects
111
  }
112
 
113
  $control = strtr(
114
- '<select id="{name}" class="form-control" name="{name}">{options}</select>',
115
  array(
116
  '{name}' => $option_name,
117
  '{options}' => $options_str,
1
  <?php
2
  namespace Bookly\Backend\Components\Settings;
3
+ use Bookly\Backend\Components\Controls;
4
 
5
  /**
6
  * Class Selects
20
  {
21
  $values = (array) get_option( $option_name );
22
  $control = '';
23
+ foreach ( $options as $i => $option ) {
24
  $control .= strtr(
25
+ '<div class="custom-control custom-checkbox">
26
+ <input type="checkbox" class="custom-control-input"
27
+ id="{id}"
28
+ name="{name}[]"
29
+ value="{value}"{checked}
30
+ />
31
+ <label class="custom-control-label" for="{id}">
32
+ {caption}
33
+ </label>
34
+ </div>',
35
  array(
36
+ '{id}' => "{$option_name}_{$i}",
37
  '{name}' => $option_name,
38
+ '{value}' => esc_attr( $option[0] ),
39
+ '{checked}' => checked( in_array( $option[0], $values ), true, false ),
40
+ '{caption}' => esc_html( $option[1] ),
41
  )
42
  );
43
  }
44
+ $control = "<div id=\"$option_name\">$control</div>";
45
 
46
  echo Inputs::buildControl( $option_name, $label, $help, $control );
47
  }
56
  */
57
  public static function renderRadios( $option_name, $label = null, $help = null, array $radios = array() )
58
  {
 
59
  if ( empty ( $radios ) ) {
60
  $radios = array(
61
+ //value => data
62
+ 0 => array( 'title' => __( 'Disabled', 'bookly' ) ),
63
+ 1 => array( 'title' => __( 'Enabled', 'bookly' ) ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  );
65
  }
66
 
67
+ Controls\Inputs::renderRadioGroup( $label, $help,
68
+ $radios,
69
+ get_option( $option_name ), array( 'name' => $option_name )
 
 
 
 
70
  );
71
  }
72
 
103
  }
104
 
105
  $control = strtr(
106
+ '<select id="{name}" class="form-control custom-select" name="{name}">{options}</select>',
107
  array(
108
  '{name}' => $option_name,
109
  '{options}' => $options_str,
backend/components/settings/templates/image.php CHANGED
@@ -1,20 +1,16 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
- <div id="bookly-js-<?php echo esc_attr( $option_name ) ?>" class="bookly-thumb bookly-thumb-<?php echo $class ?> bookly-margin-right-lg">
3
  <input type="hidden" name="<?php echo $option_name ?>" data-default="<?php echo esc_attr( $option_value ) ?>" value="<?php echo esc_attr( $option_value ) ?>">
4
- <div class="bookly-flex-cell">
5
- <div class="form-group">
6
- <div class="bookly-js-image bookly-thumb bookly-thumb-<?php echo esc_attr( $class ) ?> bookly-margin-right-lg" style="<?php echo esc_attr( $img_style ) ?>" data-style="<?php echo esc_attr( $img_style ) ?>">
7
- <a class="dashicons dashicons-trash text-danger bookly-thumb-delete" href="javascript:void(0)" style="<?php echo esc_attr( $delete_style ) ?>" title="<?php esc_attr_e( 'Delete', 'bookly' ) ?>"></a>
8
- <div class="bookly-thumb-edit">
9
- <div class="bookly-pretty"><label class="bookly-pretty-indicator bookly-thumb-edit-btn"><?php esc_html_e( 'Image', 'bookly' ) ?></label></div>
10
- </div>
11
- </div>
12
  </div>
13
  </div>
14
  </div>
15
  <script type="text/javascript">
16
  jQuery(function ($) {
17
- $('#bookly-js-<?php echo $option_name ?> .bookly-pretty-indicator').on('click', function(){
18
  var frame = wp.media({
19
  library: {type: 'image'},
20
  multiple: false
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
2
+ <div id="bookly-js-<?php echo esc_attr( $option_name ) ?>">
3
  <input type="hidden" name="<?php echo $option_name ?>" data-default="<?php echo esc_attr( $option_value ) ?>" value="<?php echo esc_attr( $option_value ) ?>">
4
+ <div class="bookly-js-image bookly-thumb <?php echo esc_attr( $class ) ?>" style="<?php echo esc_attr( $img_style ) ?>" data-style="<?php echo esc_attr( $img_style ) ?>">
5
+ <a class="far fa-fw fa-trash-alt text-danger bookly-thumb-delete" href="javascript:void(0)" style="<?php echo esc_attr( $delete_style ) ?>" title="<?php esc_attr_e( 'Delete', 'bookly' ) ?>"></a>
6
+ <div class="bookly-thumb-edit">
7
+ <label class="bookly-thumb-edit-btn"><?php esc_html_e( 'Image', 'bookly' ) ?></label>
 
 
 
 
8
  </div>
9
  </div>
10
  </div>
11
  <script type="text/javascript">
12
  jQuery(function ($) {
13
+ $('#bookly-js-<?php echo $option_name ?> label').on('click', function(){
14
  var frame = wp.media({
15
  library: {type: 'image'},
16
  multiple: false
backend/components/settings/templates/price_correction.php CHANGED
@@ -1,22 +1,28 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Settings;
3
  use Bookly\Lib\Entities\Payment;
 
 
 
4
  ?>
5
- <label for="bookly_<?php echo $gateway ?>_discount"><?php _e( 'Price correction', 'bookly' ) ?></label>
6
- <?php if ( ! in_array( $gateway, array( Payment::TYPE_MOLLIE, Payment::TYPE_PAYSON, Payment::TYPE_STRIPE, Payment::TYPE_PAYUBIZ ) ) ) : ?>
7
- <?php if ( \Bookly\Lib\Config::taxesActive() ) :
8
- Settings\Proxy\Taxes::renderHelpMessage();
9
- else: ?>
10
- <p class="help-block"><?php esc_html_e( 'This setting affects the cost of the booking according to the payment gateway used. Specify a percentage or fixed amount. Use minus ("-") sign for decrease/discount.', 'bookly' ) ?></p>
11
- <?php endif ?>
12
- <?php else: ?>
13
- <p class="help-block"><?php esc_html_e( 'This setting affects the cost of the booking according to the payment gateway used. Specify a percentage or fixed amount. Use minus ("-") sign for decrease/discount.', 'bookly' ) ?></p>
14
- <?php endif ?>
15
- <div class="row">
16
- <div class="col-md-6">
17
- <?php Settings\Inputs::renderNumber( 'bookly_' . $gateway . '_increase', __( 'Increase/Discount (%)', 'bookly' ), '', -100, 'any', 100 ) ?>
18
- </div>
19
- <div class="col-md-6">
20
- <?php Settings\Inputs::renderNumber( 'bookly_' . $gateway . '_addition', __( 'Addition/Deduction', 'bookly' ), '', null, 'any' ) ?>
21
  </div>
 
 
 
 
 
 
 
 
 
22
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
  use Bookly\Backend\Components\Settings;
3
  use Bookly\Lib\Entities\Payment;
4
+
5
+ $option_increase = 'bookly_' . $gateway . '_increase';
6
+ $option_addition = 'bookly_' . $gateway . '_addition';
7
  ?>
8
+ <div class="form-group">
9
+ <div class="form-row">
10
+ <div class="col-6">
11
+ <label for="<?php echo $option_increase ?>"><?php esc_html_e( 'Price correction', 'bookly' ) ?> <span class="text-muted"><?php esc_html_e( 'Increase/Discount (%)', 'bookly' ) ?></span></label>
12
+ <input type="number" id="<?php echo $option_increase ?>" class="form-control" name="<?php echo $option_increase ?>" value="<?php echo esc_attr( get_option( $option_increase ) ) ?>" min="-100" max="100" step="any" />
13
+ </div>
14
+ <div class="col-6">
15
+ <label for="<?php echo $option_addition ?>"><span class="text-muted"><?php esc_html_e( 'Addition/Deduction', 'bookly' ) ?></span></label>
16
+ <input type="number" id="<?php echo $option_addition ?>" class="form-control" name="<?php echo $option_addition ?>" value="<?php echo esc_attr( get_option( $option_addition ) ) ?>" step="any" />
17
+ </div>
 
 
 
 
 
 
18
  </div>
19
+ <?php if ( ! in_array( $gateway, array( Payment::TYPE_MOLLIE, Payment::TYPE_PAYSON, Payment::TYPE_STRIPE, Payment::TYPE_PAYUBIZ ) ) ) : ?>
20
+ <?php if ( \Bookly\Lib\Config::taxesActive() ) :
21
+ Settings\Proxy\Taxes::renderHelpMessage();
22
+ else: ?>
23
+ <small class="form-text text-muted"><?php esc_html_e( 'This setting affects the cost of the booking according to the payment gateway used. Specify a percentage or fixed amount. Use minus ("-") sign for decrease/discount.', 'bookly' ) ?></small>
24
+ <?php endif ?>
25
+ <?php else: ?>
26
+ <small class="form-text text-muted"><?php esc_html_e( 'This setting affects the cost of the booking according to the payment gateway used. Specify a percentage or fixed amount. Use minus ("-") sign for decrease/discount.', 'bookly' ) ?></small>
27
+ <?php endif ?>
28
  </div>
backend/components/support/resources/js/support.js CHANGED
@@ -1,61 +1,81 @@
1
  jQuery(function ($) {
2
  let $modal = $('#bookly-contact-us-modal'),
3
- $btnContactUs = $('#bookly-contact-us-modal-activator'),
4
- $btnFeedback = $('#bookly-feedback-btn')
 
 
 
 
 
 
 
5
  ;
6
 
7
- if ($btnContactUs.data('trigger')) {
8
  $btnContactUs
9
- .popover().popover('show')
10
- .next('.popover')
11
- .find('.arrow').removeClass().addClass('popover-arrow').end()
12
- .find('.popover-content button').on('click', function () {
13
- $btnContactUs.popover('hide');
14
- $.ajax({
15
- url : ajaxurl,
16
- type : 'POST',
17
- data : { action : 'bookly_dismiss_contact_us_notice', csrf_token : BooklySupportL10n.csrfToken },
18
- success : function(response) {
19
- $btnContactUs.attr('data-processed', true);
20
- }
21
- });
22
- }).end()
23
- .end()
24
  .on('click', function () {
25
- $btnContactUs.popover('hide');
26
  $.ajax({
27
  url : ajaxurl,
28
  type : 'POST',
29
  data : { action : 'bookly_contact_us_btn_clicked', csrf_token : BooklySupportL10n.csrfToken }
30
  });
31
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  }
33
 
34
- if ($btnFeedback.data('trigger')) {
35
  $btnFeedback
36
- .popover().popover('show')
37
- .next('.popover')
38
- .css({right:'10px',left:'auto'})
39
- .find('.arrow').removeClass().addClass('popover-arrow').css({right:($btnFeedback.outerWidth()/2)+'px',left:'auto'}).end()
40
- .find('.popover-content').css({overflow:'hidden'})
41
- .find('button').on('click', function () {
42
- $btnFeedback.popover('hide');
43
- $.ajax({
44
- url : ajaxurl,
45
- type : 'POST',
46
- data : { action : 'bookly_dismiss_feedback_notice', csrf_token : BooklySupportL10n.csrfToken }
47
- });
48
- }).end()
49
- .end()
50
- .end()
51
  .on('click', function () {
52
- $btnFeedback.popover('hide');
53
  $.ajax({
54
  url : ajaxurl,
55
  type : 'POST',
56
  data : { action : 'bookly_dismiss_feedback_notice', csrf_token : BooklySupportL10n.csrfToken }
57
  });
58
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
60
 
61
  $('#bookly-support-send').on('click', function () {
@@ -86,7 +106,7 @@ jQuery(function ($) {
86
  success : function (response) {
87
  if (response.success) {
88
  $msg.val('');
89
- $modal.modal('hide');
90
  booklyAlert({success : [response.data.message]});
91
  } else {
92
  booklyAlert({error : [response.data.message]});
@@ -134,21 +154,12 @@ jQuery(function ($) {
134
  });
135
  });
136
 
137
- $('[data-action=feature-request]')
138
- .on('click', function () {
139
- if ($(this).data('target')) {
140
- window.open($(this).data('target'), '_blank');
141
- } else {
142
- $('#bookly-feature-requests-modal').modal('show');
143
- }
144
- });
145
-
146
  $('.bookly-js-proceed-to-demo')
147
  .on('click', function () {
148
  var $modal = $('#bookly-demo-site-info-modal'),
149
  target = $(this).data('target');
150
 
151
- if ($('#bookly-js-dont-show-again', $modal).prop('checked')) {
152
  $.ajax({
153
  url: ajaxurl,
154
  type: 'POST',
@@ -164,23 +175,14 @@ jQuery(function ($) {
164
  }
165
  });
166
  }
167
- $modal.modal('hide');
168
  window.open(target, '_blank');
169
  });
170
 
171
- $('[data-action=show-demo]')
172
- .on('click', function () {
173
- if ($(this).data('target')) {
174
- window.open($(this).data('target'), '_blank');
175
- } else {
176
- $('#bookly-demo-site-info-modal').modal('show');
177
- }
178
- });
179
-
180
  $('.bookly-js-proceed-requests')
181
  .on('click', function () {
182
  var $modal = $('#bookly-feature-requests-modal');
183
- if ($('#bookly-js-dont-show-again', $modal).prop('checked')) {
184
  $.ajax({
185
  url: ajaxurl,
186
  type: 'POST',
@@ -196,7 +198,7 @@ jQuery(function ($) {
196
  }
197
  });
198
  }
199
- $modal.modal('hide');
200
  window.open(BooklySupportL10n.featuresRequestUrl, '_blank');
201
  });
202
  });
1
  jQuery(function ($) {
2
  let $modal = $('#bookly-contact-us-modal'),
3
+ $btnContactUs = $('#bookly-contact-us-btn'),
4
+ $btnFeedback = $('#bookly-feedback-btn'),
5
+ popoverConfig = {
6
+ html: true,
7
+ sanitize: false,
8
+ trigger: 'manual',
9
+ container: '#bookly-tbs',
10
+ template: '<div class="bookly-popover" role="tooltip"><div class="arrow"></div><div class="popover-body"></div></div>'
11
+ }
12
  ;
13
 
14
+ if ($btnContactUs.data('content')) {
15
  $btnContactUs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  .on('click', function () {
17
+ $btnContactUs.booklyPopover('hide');
18
  $.ajax({
19
  url : ajaxurl,
20
  type : 'POST',
21
  data : { action : 'bookly_contact_us_btn_clicked', csrf_token : BooklySupportL10n.csrfToken }
22
  });
23
+ })
24
+ .booklyPopover($.extend({
25
+ placement: function (tip) {
26
+ $(tip)
27
+ .css({maxWidth:'none'})
28
+ .find('.popover-body button').on('click', function () {
29
+ $btnContactUs.booklyPopover('hide');
30
+ $.ajax({
31
+ url: ajaxurl,
32
+ type: 'POST',
33
+ data: {
34
+ action: 'bookly_dismiss_contact_us_notice',
35
+ csrf_token: BooklySupportL10n.csrfToken
36
+ },
37
+ success: function (response) {
38
+ $btnContactUs.attr('data-processed', true);
39
+ }
40
+ });
41
+ });
42
+
43
+ return 'bottom';
44
+ }
45
+ }, popoverConfig))
46
+ .booklyPopover('show')
47
+ ;
48
  }
49
 
50
+ if ($btnFeedback.data('content')) {
51
  $btnFeedback
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  .on('click', function () {
53
+ $btnFeedback.booklyPopover('hide');
54
  $.ajax({
55
  url : ajaxurl,
56
  type : 'POST',
57
  data : { action : 'bookly_dismiss_feedback_notice', csrf_token : BooklySupportL10n.csrfToken }
58
  });
59
+ })
60
+ .booklyPopover($.extend({
61
+ placement: function (tip) {
62
+ $(tip)
63
+ .css({maxWidth:'none'})
64
+ .find('.popover-body').css({overflow:'hidden'})
65
+ .find('button').on('click', function () {
66
+ $btnFeedback.booklyPopover('hide');
67
+ $.ajax({
68
+ url : ajaxurl,
69
+ type : 'POST',
70
+ data : { action : 'bookly_dismiss_feedback_notice', csrf_token : BooklySupportL10n.csrfToken }
71
+ });
72
+ });
73
+
74
+ return 'bottom';
75
+ }
76
+ }, popoverConfig))
77
+ .booklyPopover('show')
78
+ ;
79
  }
80
 
81
  $('#bookly-support-send').on('click', function () {
106
  success : function (response) {
107
  if (response.success) {
108
  $msg.val('');
109
+ $modal.booklyModal('hide');
110
  booklyAlert({success : [response.data.message]});
111
  } else {
112
  booklyAlert({error : [response.data.message]});
154
  });
155
  });
156
 
 
 
 
 
 
 
 
 
 
157
  $('.bookly-js-proceed-to-demo')
158
  .on('click', function () {
159
  var $modal = $('#bookly-demo-site-info-modal'),
160
  target = $(this).data('target');
161
 
162
+ if ($('#bookly-js-dont-show-again-demo', $modal).prop('checked')) {
163
  $.ajax({
164
  url: ajaxurl,
165
  type: 'POST',
175
  }
176
  });
177
  }
178
+ $modal.booklyModal('hide');
179
  window.open(target, '_blank');
180
  });
181
 
 
 
 
 
 
 
 
 
 
182
  $('.bookly-js-proceed-requests')
183
  .on('click', function () {
184
  var $modal = $('#bookly-feature-requests-modal');
185
+ if ($('#bookly-js-dont-show-again-feature', $modal).prop('checked')) {
186
  $.ajax({
187
  url: ajaxurl,
188
  type: 'POST',
198
  }
199
  });
200
  }
201
+ $modal.booklyModal('hide');
202
  window.open(BooklySupportL10n.featuresRequestUrl, '_blank');
203
  });
204
  });
backend/components/support/templates/buttons.php CHANGED
@@ -3,122 +3,178 @@ use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  use Bookly\Backend\Components\Support\Lib\Urls;
5
  use Bookly\Lib\Utils;
 
 
 
 
 
 
 
 
6
  ?>
7
- <style type="text/css">
8
- #bookly-tbs .page-header > .popover {
9
- z-index: 1039;
10
- }
11
- </style>
12
- <span class="bookly-support-panel">
13
- <?php
14
- /**
15
- * Messages
16
- */
17
- ?>
18
- <?php if ( Utils\Common::isCurrentUserAdmin() ) : ?>
19
- <span class="dropdown">
20
- <button type="button" class="btn btn-default-outline dropdown-toggle ladda-button" data-toggle="dropdown" id="bookly-bell" aria-haspopup="true" aria-expanded="true" data-spinner-size="40" data-style="zoom-in" data-spinner-color="#DDDDDD"><span class="ladda-label"><i class="fas fa-bell"></i></span></button>
21
  <?php if ( $messages_new ) : ?>
22
- <span class="badge bookly-js-new-messages-count"><?php echo $messages_new ?></span>
23
  <?php endif ?>
24
- <ul class="dropdown-menu dropdown-menu-right" aria-labelledby="bookly-bell">
25
- <?php foreach ( $messages as $message ) : ?>
26
- <li><a href="<?php echo $messages_link ?>"><?php echo Utils\DateTime::formatDate( $message['created'] ) . ': ';
27
- if ( $message['seen'] ) :
28
- echo esc_html( $message['subject'] );
29
- else:
30
- echo '<b>' . esc_html( $message['subject'] ) . '</b>';
31
- endif ?>
32
- </a></li>
33
- <?php endforeach ?>
34
- <li role="separator" class="divider"></li>
35
- <li><a href="<?php echo $messages_link ?>"><?php esc_html_e( 'Show all notifications', 'bookly' ) ?></a></li>
36
- <?php if ( $messages_new ) : ?>
37
- <li><a href="#" id="bookly-js-mark-read-all-messages"><?php esc_html_e( 'Mark all notifications as read', 'bookly' ) ?></a></li>
38
- <?php endif ?>
39
- </ul>
40
- </span>
41
- <?php endif ?>
 
42
 
43
- <?php
44
- /**
45
- * View demo
46
- */
47
- ?>
48
- <?php if ( isset( $demo_links[ $page_slug ] ) ) :
49
- $target = Utils\Common::prepareUrlReferrers( $demo_links[ $page_slug ], 'demo' ); ?>
50
- <?php if ( get_user_meta( get_current_user_id(), 'bookly_dismiss_demo_site_description', true ) ) : ?>
51
- <a href="<?php echo $target ?>" target="_blank" class="btn btn-default-outline" title="<?php esc_attr_e( 'View this page at Bookly Pro Demo', 'bookly' ) ?>">
52
- <i class="fas fa-certificate"></i> <span class="visible-lg-inline"><?php esc_html_e( 'View this page at Bookly Pro Demo', 'bookly' ) ?></span>
53
- </a>
54
- <?php else : ?>
55
- <div id="bookly-demo-site-info-modal" class="modal fade text-left" tabindex=-1>
 
 
 
 
 
 
 
 
 
56
  <div class="modal-dialog">
57
  <div class="modal-content">
58
  <div class="modal-header">
59
- <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
60
- <h4 class="modal-title"><?php esc_html_e( 'Visit demo', 'bookly' ) ?></h4>
61
  </div>
62
  <div class="modal-body">
63
  <p>
64
  <?php esc_html_e( 'The demo is a version of Bookly Pro with all installed add-ons so that you can try all the features and capabilities of the system and then choose the most suitable configuration according to your business needs.', 'bookly' ) ?>
65
  </p>
66
- <div class="form-inline">
67
- <input type="checkbox" id="bookly-js-dont-show-again" /> <label class="bookly-checkbox-text" for="bookly-js-dont-show-again"><?php esc_html_e( 'don\'t show this notification again', 'bookly' ) ?></label>
 
 
68
  </div>
69
  </div>
70
  <div class="modal-footer">
71
- <?php Buttons::renderCustom( null, 'bookly-js-proceed-to-demo btn-success btn-lg', esc_html__( 'Proceed to demo', 'bookly' ), array( 'data-target' => $target ) ) ?>
72
- <?php Buttons::renderCustom( null, 'btn-default btn-lg', esc_html__( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
73
  </div>
74
  </div>
75
  </div>
76
  </div>
77
- <button data-action="show-demo" class="btn btn-default-outline" title="<?php esc_attr_e( 'View this page at Bookly Pro Demo', 'bookly' ) ?>">
78
- <i class="fas fa-certificate"></i> <span class="visible-lg-inline"><?php esc_html_e( 'View this page at Bookly Pro Demo', 'bookly' ) ?></span>
79
- </button>
80
- <?php endif ?>
81
  <?php endif ?>
 
82
 
83
- <?php
84
- /**
85
- * Documentation
86
- */
87
- ?>
88
- <a href="<?php echo esc_url( 'https://api.booking-wp-plugin.com/go/' . $page_slug ) ?>" id="bookly-help-btn" target="_blank" class="btn btn-default-outline" title="<?php esc_attr_e( 'Documentation', 'bookly' ) ?>">
89
- <i class="fas fa-question-circle"></i> <span class="visible-lg-inline"><?php esc_html_e( 'Documentation', 'bookly' ) ?></span>
 
90
  </a>
 
91
 
92
- <?php
93
- /**
94
- * Contact us
95
- */
96
- ?>
97
- <a href="#bookly-contact-us-modal" id="bookly-contact-us-modal-activator" class="btn btn-default-outline" title="<?php esc_attr_e( 'Contact us', 'bookly' ) ?>" data-toggle="modal"
 
98
  <?php if ( $show_contact_us_notice ) : ?>
99
  data-processed="false"
100
- data-trigger="manual" data-placement="bottom" data-html="1"
101
- data-content="<?php echo esc_attr( '<button type="button" class="close pull-right bookly-margin-left-sm"><span>&times;</span></button>' . esc_html__( 'Need help? Contact us here.', 'bookly' ) ) ?>"
102
  <?php endif ?>
103
  >
104
- <i class="fas fa-envelope"></i> <span class="visible-lg-inline"><?php esc_html_e( 'Contact us', 'bookly' ) ?></span>
105
  </a>
106
- <?php
107
- /**
108
- * Feature requests
109
- */
110
- ?>
111
- <?php if ( get_user_meta( get_current_user_id(), 'bookly_dismiss_feature_requests_description', true ) ) : ?>
112
- <a href="<?php echo Utils\Common::prepareUrlReferrers( Urls::FEATURES_REQUEST_PAGE, 'notification_bar' ) ?>" target="_blank" class="btn btn-default-outline" title="<?php esc_attr_e( 'Feature requests', 'bookly' ) ?>">
113
- <i class="fas fa-lightbulb"></i> <span class="visible-lg-inline"><?php esc_html_e( 'Feature requests', 'bookly' ) ?></span>
114
- </a>
115
- <?php else : ?>
116
- <div id="bookly-feature-requests-modal" class="modal fade text-left" tabindex=-1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  <div class="modal-dialog">
118
  <div class="modal-content">
119
  <div class="modal-header">
120
- <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
121
- <h4 class="modal-title"><?php esc_html_e( 'Feature requests', 'bookly' ) ?></h4>
122
  </div>
123
  <div class="modal-body">
124
  <p>
@@ -129,66 +185,39 @@ use Bookly\Lib\Utils;
129
  </p>
130
  <p>
131
  <?php esc_html_e( 'It\'s much easier for us to address a suggestion if we clearly understand the context of the issue, the problem, and why it matters to you. When commenting or posting, please consider these questions so we can get a better idea of the problem you\'re facing:', 'bookly' ) ?>
132
- <div>&#9679; <?php esc_html_e( 'What is the issue you\'re struggling with?', 'bookly' ) ?></div>
133
- <div>&#9679; <?php esc_html_e( 'Where in your workflow do you encounter this issue?', 'bookly' ) ?></div>
134
- <div>&#9679; <?php esc_html_e( 'Is this something that impacts just you, your whole team, or your customers?', 'bookly' ) ?></div>
135
  </p>
136
- <div class="form-inline">
137
- <input type="checkbox" id="bookly-js-dont-show-again" /> <label class="bookly-checkbox-text" for="bookly-js-dont-show-again"><?php esc_html_e( 'don\'t show this notification again', 'bookly' ) ?></label>
 
 
 
 
 
 
 
138
  </div>
139
  </div>
140
  <div class="modal-footer">
141
- <?php Buttons::renderCustom( null, 'bookly-js-proceed-requests btn-success btn-lg', esc_html__( 'Proceed to Feature requests', 'bookly' ) ) ?>
142
- <?php Buttons::renderCustom( null, 'btn-default btn-lg', esc_html__( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
143
  </div>
144
  </div>
145
  </div>
146
  </div>
147
- <button data-action="feature-request" class="btn btn-default-outline" title="<?php esc_attr_e( 'Feature requests', 'bookly' ) ?>">
148
- <i class="fas fa-lightbulb"></i> <span class="visible-lg-inline"><?php esc_html_e( 'Feature requests', 'bookly' ) ?></span>
149
- </button>
150
  <?php endif ?>
 
151
 
152
- <?php
153
- /**
154
- * Feedback
155
- */
156
- ?>
157
- <a href="<?php echo Utils\Common::prepareUrlReferrers( Urls::REVIEWS_PAGE, 'feedback' ) ?>" id="bookly-feedback-btn" target="_blank" class="btn btn-default-outline" title="<?php esc_attr_e( 'Feedback', 'bookly' ) ?>"
 
158
  <?php if ( $show_feedback_notice ) : ?>
159
- data-trigger="manual" data-placement="bottom" data-html="1"
160
- data-content="<?php echo esc_attr( '<button type="button" class="close pull-right bookly-margin-left-sm"><span>&times;</span></button><div class="pull-left">' . esc_html__( 'We care about your experience of using Bookly!<br/>Leave a review and tell others what you think.', 'bookly' ) . '</div>' ) ?>"
161
  <?php endif ?>
162
  >
163
- <i class="fas fa-comment-dots"></i> <span class="visible-lg-inline"><?php esc_html_e( 'Feedback', 'bookly' ) ?></span>
164
  </a>
165
- <div id="bookly-contact-us-modal" class="modal fade text-left" tabindex=-1>
166
- <div class="modal-dialog">
167
- <div class="modal-content">
168
- <div class="modal-header">
169
- <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
170
- <h4 class="modal-title"><?php esc_html_e( 'Leave us a message', 'bookly' ) ?></h4>
171
- </div>
172
- <div class="modal-body">
173
- <div class="form-group">
174
- <label for="bookly-support-name" class="control-label"><?php esc_html_e( 'Your name', 'bookly' ) ?></label>
175
- <input type="text" id="bookly-support-name" class="form-control" value="<?php echo esc_attr( $current_user->user_firstname . ' ' . $current_user->user_lastname ) ?>" />
176
- </div>
177
- <div class="form-group">
178
- <label for="bookly-support-email" class="control-label"><?php esc_html_e( 'Email address', 'bookly' ) ?> <span class="bookly-color-brand-danger">*</span></label>
179
- <input type="text" id="bookly-support-email" class="form-control" value="<?php echo esc_attr( $current_user->user_email ) ?>" />
180
- </div>
181
- <div class="form-group">
182
- <label for="bookly-support-msg" class="control-label"><?php esc_html_e( 'How can we help you?', 'bookly' ) ?> <span class="bookly-color-brand-danger">*</span></label>
183
- <textarea id="bookly-support-msg" class="form-control" rows="10"></textarea>
184
- </div>
185
- </div>
186
- <div class="modal-footer">
187
- <?php Inputs::renderCsrf() ?>
188
- <?php Buttons::renderCustom( 'bookly-support-send', 'btn-success btn-lg', esc_html__( 'Send', 'bookly' ) ) ?>
189
- <?php Buttons::renderCustom( null, 'btn-default btn-lg', esc_html__( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
190
- </div>
191
- </div>
192
- </div>
193
- </div>
194
- </span>
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  use Bookly\Backend\Components\Support\Lib\Urls;
5
  use Bookly\Lib\Utils;
6
+ /**
7
+ * @var int $messages_new
8
+ * @var array $messages
9
+ * @var string $messages_link
10
+ * @var array $demo_links
11
+ * @var bool $show_contact_us_notice
12
+ * @var bool $show_feedback_notice
13
+ */
14
  ?>
15
+
16
+ <?php
17
+ /**
18
+ * Messages
19
+ */
20
+ ?>
21
+ <?php if ( Utils\Common::isCurrentUserAdmin() ) : ?>
22
+ <div class="col-auto">
23
+ <button type="button" id="bookly-bell" class="btn btn-default dropdown-toggle ladda-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-spinner-size="30" data-style="zoom-in" data-spinner-color="#343a40">
24
+ <i class="far fa-bell"></i>
 
 
 
 
25
  <?php if ( $messages_new ) : ?>
26
+ <span class="badge badge-danger bookly-js-new-messages-count"><?php echo $messages_new ?></span>
27
  <?php endif ?>
28
+ </button>
29
+ <div class="dropdown-menu dropdown-menu-right" aria-labelledby="bookly-bell">
30
+ <?php foreach ( $messages as $message ) : ?>
31
+ <a class="dropdown-item" href="<?php echo $messages_link ?>"><?php echo Utils\DateTime::formatDate( $message['created'] ) . ': ';
32
+ if ( $message['seen'] ) :
33
+ echo esc_html( $message['subject'] );
34
+ else:
35
+ echo '<b>' . esc_html( $message['subject'] ) . '</b>';
36
+ endif ?>
37
+ </a>
38
+ <?php endforeach ?>
39
+ <div class="dropdown-divider"></div>
40
+ <a class="dropdown-item" href="<?php echo $messages_link ?>"><?php esc_html_e( 'Show all notifications', 'bookly' ) ?></a>
41
+ <?php if ( $messages_new ) : ?>
42
+ <a class="dropdown-item" href="#" id="bookly-js-mark-read-all-messages"><?php esc_html_e( 'Mark all notifications as read', 'bookly' ) ?></a>
43
+ <?php endif ?>
44
+ </div>
45
+ </div>
46
+ <?php endif ?>
47
 
48
+ <?php
49
+ /**
50
+ * View demo
51
+ */
52
+ ?>
53
+ <?php
54
+ if ( isset ( $demo_links[ $page_slug ] ) ) :
55
+ $target = Utils\Common::prepareUrlReferrers( $demo_links[ $page_slug ], 'demo' );
56
+ $dismiss = get_user_meta( get_current_user_id(), 'bookly_dismiss_demo_site_description', true );
57
+ ?>
58
+ <div class="col-auto">
59
+ <a class="btn btn-default" title="<?php esc_attr_e( 'View this page at Bookly Pro Demo', 'bookly' ) ?>"
60
+ <?php if ( $dismiss ) : ?>
61
+ href="<?php echo $target ?>"
62
+ <?php else : ?>
63
+ href="#bookly-demo-site-info-modal" data-toggle="bookly-modal"
64
+ <?php endif ?>
65
+ >
66
+ <i class="fas fa-fw fa-certificate"></i><span class="d-none d-lg-inline ml-2"><?php esc_html_e( 'View this page at Bookly Pro Demo', 'bookly' ) ?></span>
67
+ </a>
68
+ <?php if ( ! $dismiss ) : ?>
69
+ <div id="bookly-demo-site-info-modal" class="bookly-modal bookly-fade text-left" tabindex=-1>
70
  <div class="modal-dialog">
71
  <div class="modal-content">
72
  <div class="modal-header">
73
+ <h5 class="modal-title"><?php esc_html_e( 'Visit demo', 'bookly' ) ?></h5>
74
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
75
  </div>
76
  <div class="modal-body">
77
  <p>
78
  <?php esc_html_e( 'The demo is a version of Bookly Pro with all installed add-ons so that you can try all the features and capabilities of the system and then choose the most suitable configuration according to your business needs.', 'bookly' ) ?>
79
  </p>
80
+
81
+ <div class="custom-control custom-checkbox">
82
+ <input class="custom-control-input form-check-input" id="bookly-js-dont-show-again-demo" type="checkbox"/>
83
+ <label class="custom-control-label" for="bookly-js-dont-show-again-demo"><?php esc_html_e( 'don\'t show this notification again', 'bookly' ) ?></label>
84
  </div>
85
  </div>
86
  <div class="modal-footer">
87
+ <?php Buttons::renderSubmit( null, 'bookly-js-proceed-to-demo', __( 'Proceed to demo', 'bookly' ), array( 'data-target' => $target ) ) ?>
88
+ <?php Buttons::renderCancel() ?>
89
  </div>
90
  </div>
91
  </div>
92
  </div>
93
+ </div>
 
 
 
94
  <?php endif ?>
95
+ <?php endif ?>
96
 
97
+ <?php
98
+ /**
99
+ * Documentation
100
+ */
101
+ ?>
102
+ <div class="col-auto">
103
+ <a href="<?php echo esc_url( 'https://api.booking-wp-plugin.com/go/' . $page_slug ) ?>" id="bookly-help-btn" target="_blank" class="btn btn-default" title="<?php esc_attr_e( 'Documentation', 'bookly' ) ?>">
104
+ <i class="far fa-question-circle"></i><span class="d-none d-lg-inline ml-2"><?php esc_html_e( 'Documentation', 'bookly' ) ?></span>
105
  </a>
106
+ </div>
107
 
108
+ <?php
109
+ /**
110
+ * Contact us
111
+ */
112
+ ?>
113
+ <div class="col-auto">
114
+ <a href="#bookly-contact-us-modal" id="bookly-contact-us-btn" class="btn btn-default" title="<?php esc_attr_e( 'Contact us', 'bookly' ) ?>" data-toggle="bookly-modal"
115
  <?php if ( $show_contact_us_notice ) : ?>
116
  data-processed="false"
117
+ data-content="<?php echo esc_attr( '<button type="button" class="close ml-2"><span>&times;</span></button>' . __( 'Need help? Contact us here.', 'bookly' ) ) ?>"
 
118
  <?php endif ?>
119
  >
120
+ <i class="far fa-envelope"></i><span class="d-none d-lg-inline ml-2"><?php esc_html_e( 'Contact us', 'bookly' ) ?></span>
121
  </a>
122
+ <div id="bookly-contact-us-modal" class="bookly-modal bookly-fade text-left" tabindex=-1>
123
+ <div class="modal-dialog">
124
+ <div class="modal-content">
125
+ <div class="modal-header">
126
+ <h5 class="modal-title"><?php esc_html_e( 'Leave us a message', 'bookly' ) ?></h5>
127
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
128
+ </div>
129
+ <div class="modal-body">
130
+ <div class="form-group">
131
+ <label for="bookly-support-name"><?php esc_html_e( 'Your name', 'bookly' ) ?></label>
132
+ <input type="text" id="bookly-support-name" class="form-control" value="<?php echo esc_attr( $current_user->user_firstname . ' ' . $current_user->user_lastname ) ?>" />
133
+ </div>
134
+ <div class="form-group">
135
+ <label for="bookly-support-email"><?php esc_html_e( 'Email address', 'bookly' ) ?> <span class="text-danger">*</span></label>
136
+ <input type="text" id="bookly-support-email" class="form-control" value="<?php echo esc_attr( $current_user->user_email ) ?>" />
137
+ </div>
138
+ <div class="form-group">
139
+ <label for="bookly-support-msg"><?php esc_html_e( 'How can we help you?', 'bookly' ) ?> <span class="text-danger">*</span></label>
140
+ <textarea id="bookly-support-msg" class="form-control" rows="10"></textarea>
141
+ </div>
142
+ </div>
143
+ <div class="modal-footer">
144
+ <?php Inputs::renderCsrf() ?>
145
+ <?php Buttons::renderSubmit( 'bookly-support-send', null, __( 'Send', 'bookly' ) ) ?>
146
+ <?php Buttons::renderCancel() ?>
147
+ </div>
148
+ </div>
149
+ </div>
150
+ </div>
151
+ </div>
152
+
153
+ <?php
154
+ /**
155
+ * Feature requests
156
+ */
157
+ ?>
158
+ <?php
159
+ $dismiss = get_user_meta( get_current_user_id(), 'bookly_dismiss_feature_requests_description', true );
160
+ ?>
161
+ <div class="col-auto">
162
+ <a class="btn btn-default" title="<?php esc_attr_e( 'Feature requests', 'bookly' ) ?>"
163
+ <?php if ( $dismiss ) : ?>
164
+ href="<?php echo Utils\Common::prepareUrlReferrers( Urls::FEATURES_REQUEST_PAGE, 'notification_bar' ) ?>" target="_blank"
165
+ <?php else : ?>
166
+ href="#bookly-feature-requests-modal" data-toggle="bookly-modal"
167
+ <?php endif ?>
168
+ >
169
+ <i class="far fa-lightbulb"></i><span class="d-none d-lg-inline ml-2"><?php esc_html_e( 'Feature requests', 'bookly' ) ?></span>
170
+ </a>
171
+ <?php if ( ! $dismiss ) : ?>
172
+ <div id="bookly-feature-requests-modal" class="bookly-modal bookly-fade text-left" tabindex=-1>
173
  <div class="modal-dialog">
174
  <div class="modal-content">
175
  <div class="modal-header">
176
+ <h5 class="modal-title"><?php esc_html_e( 'Feature requests', 'bookly' ) ?></h5>
177
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
178
  </div>
179
  <div class="modal-body">
180
  <p>
185
  </p>
186
  <p>
187
  <?php esc_html_e( 'It\'s much easier for us to address a suggestion if we clearly understand the context of the issue, the problem, and why it matters to you. When commenting or posting, please consider these questions so we can get a better idea of the problem you\'re facing:', 'bookly' ) ?>
 
 
 
188
  </p>
189
+ <ul>
190
+ <li><?php esc_html_e( 'What is the issue you\'re struggling with?', 'bookly' ) ?></li>
191
+ <li><?php esc_html_e( 'Where in your workflow do you encounter this issue?', 'bookly' ) ?></li>
192
+ <li><?php esc_html_e( 'Is this something that impacts just you, your whole team, or your customers?', 'bookly' ) ?></li>
193
+ </ul>
194
+
195
+ <div class="custom-control custom-checkbox">
196
+ <input class="custom-control-input form-check-input" id="bookly-js-dont-show-again-feature" type=checkbox />
197
+ <label class="custom-control-label" for="bookly-js-dont-show-again-feature"><?php esc_html_e( 'don\'t show this notification again', 'bookly' ) ?></label>
198
  </div>
199
  </div>
200
  <div class="modal-footer">
201
+ <?php Buttons::renderSubmit( null, 'bookly-js-proceed-requests', __( 'Proceed to Feature requests', 'bookly' ) ) ?>
202
+ <?php Buttons::renderCancel() ?>
203
  </div>
204
  </div>
205
  </div>
206
  </div>
 
 
 
207
  <?php endif ?>
208
+ </div>
209
 
210
+ <?php
211
+ /**
212
+ * Feedback
213
+ */
214
+ ?>
215
+ <div class="col-auto">
216
+ <a href="<?php echo Utils\Common::prepareUrlReferrers( Urls::REVIEWS_PAGE, 'feedback' ) ?>" id="bookly-feedback-btn" target="_blank" class="btn btn-default" title="<?php esc_attr_e( 'Feedback', 'bookly' ) ?>"
217
  <?php if ( $show_feedback_notice ) : ?>
218
+ data-content="<?php echo esc_attr( '<button type="button" class="close ml-2"><span>&times;</span></button>' . __( 'We care about your experience of using Bookly!<br/>Leave a review and tell others what you think.', 'bookly' ) ) ?>"
 
219
  <?php endif ?>
220
  >
221
+ <i class="far fa-comment-dots"></i><span class="d-none d-lg-inline ml-2"><?php esc_html_e( 'Feedback', 'bookly' ) ?></span>
222
  </a>
223
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/components/tiny_mce/templates/bookly_form.php CHANGED
@@ -8,7 +8,7 @@ use Bookly\Backend\Components\TinyMce\Proxy;
8
  <label for="bookly-select-category"><?php esc_html_e( 'Default value for category select', 'bookly' ) ?></label>
9
  </td>
10
  <td>
11
- <select id="bookly-select-category" class="form-control">
12
  <option value=""><?php esc_html_e( 'Select category', 'bookly' ) ?></option>
13
  </select>
14
  <div class="checkbox">
@@ -24,7 +24,7 @@ use Bookly\Backend\Components\TinyMce\Proxy;
24
  <label for="bookly-select-service"><?php esc_html_e( 'Default value for service select', 'bookly' ) ?></label>
25
  </td>
26
  <td>
27
- <select id="bookly-select-service" class="form-control">
28
  <option value=""><?php esc_html_e( 'Select service', 'bookly' ) ?></option>
29
  </select>
30
  <div class="checkbox">
@@ -41,7 +41,7 @@ use Bookly\Backend\Components\TinyMce\Proxy;
41
  <label for="bookly-select-employee"><?php esc_html_e( 'Default value for employee select', 'bookly' ) ?></label>
42
  </td>
43
  <td>
44
- <select class="form-control" id="bookly-select-employee">
45
  <option value=""><?php esc_html_e( 'Any', 'bookly' ) ?></option>
46
  </select>
47
  <div class="checkbox">
8
  <label for="bookly-select-category"><?php esc_html_e( 'Default value for category select', 'bookly' ) ?></label>
9
  </td>
10
  <td>
11
+ <select id="bookly-select-category" class="form-control custom-select">
12
  <option value=""><?php esc_html_e( 'Select category', 'bookly' ) ?></option>
13
  </select>
14
  <div class="checkbox">
24
  <label for="bookly-select-service"><?php esc_html_e( 'Default value for service select', 'bookly' ) ?></label>
25
  </td>
26
  <td>
27
+ <select id="bookly-select-service" class="form-control custom-select">
28
  <option value=""><?php esc_html_e( 'Select service', 'bookly' ) ?></option>
29
  </select>
30
  <div class="checkbox">
41
  <label for="bookly-select-employee"><?php esc_html_e( 'Default value for employee select', 'bookly' ) ?></label>
42
  </td>
43
  <td>
44
+ <select class="form-control custom-select" id="bookly-select-employee">
45
  <option value=""><?php esc_html_e( 'Any', 'bookly' ) ?></option>
46
  </select>
47
  <div class="checkbox">
backend/modules/appearance/Ajax.php CHANGED
@@ -33,9 +33,6 @@ class Ajax extends Lib\Base\Ajax
33
  'bookly_l10n_button_apply',
34
  'bookly_l10n_button_back',
35
  'bookly_l10n_label_category',
36
- 'bookly_l10n_label_ccard_code',
37
- 'bookly_l10n_label_ccard_expire',
38
- 'bookly_l10n_label_ccard_number',
39
  'bookly_l10n_label_email',
40
  'bookly_l10n_label_email_confirm',
41
  'bookly_l10n_label_employee',
@@ -46,7 +43,6 @@ class Ajax extends Lib\Base\Ajax
46
  'bookly_l10n_label_last_name',
47
  'bookly_l10n_label_notes',
48
  'bookly_l10n_label_number_of_persons',
49
- 'bookly_l10n_label_pay_ccard',
50
  'bookly_l10n_label_pay_locally',
51
  'bookly_l10n_label_phone',
52
  'bookly_l10n_label_select_date',
33
  'bookly_l10n_button_apply',
34
  'bookly_l10n_button_back',
35
  'bookly_l10n_label_category',
 
 
 
36
  'bookly_l10n_label_email',
37
  'bookly_l10n_label_email_confirm',
38
  'bookly_l10n_label_employee',
43
  'bookly_l10n_label_last_name',
44
  'bookly_l10n_label_notes',
45
  'bookly_l10n_label_number_of_persons',
 
46
  'bookly_l10n_label_pay_locally',
47
  'bookly_l10n_label_phone',
48
  'bookly_l10n_label_select_date',
backend/modules/appearance/Page.php CHANGED
@@ -31,9 +31,9 @@ class Page extends Lib\Base\Component
31
  ? array( 'css/bookly-rtl.css', 'css/bookly-main.css', )
32
  : array( 'css/bookly-main.css', )
33
  ),
34
- 'backend' => array( 'bootstrap/css/bootstrap-theme.min.css', ),
35
  'wp' => array( 'wp-color-picker', ),
36
- 'module' => array( 'css/bootstrap-editable.css', )
37
  ) );
38
 
39
  self::enqueueScripts( array(
@@ -54,9 +54,8 @@ class Page extends Lib\Base\Component
54
  ),
55
  'wp' => array( 'wp-color-picker' ),
56
  'module' => array(
57
- 'js/bootstrap-editable.min.js' => array( 'bookly-bootstrap.min.js' ),
58
- 'js/bootstrap-editable.bookly.js' => array( 'bookly-bootstrap-editable.min.js' ),
59
- 'js/appearance.js' => array( 'bookly-bootstrap-editable.bookly.js' )
60
  )
61
  ) );
62
 
@@ -72,6 +71,7 @@ class Page extends Lib\Base\Component
72
  'date_format' => Lib\Utils\DateTime::convertFormat( 'date', Lib\Utils\DateTime::FORMAT_PICKADATE ),
73
  'firstDay' => (int) get_option( 'start_of_week' ),
74
  'saved' => __( 'Settings saved.', 'bookly' ),
 
75
  'intlTelInput' => array(
76
  'enabled' => get_option( 'bookly_cst_phone_default_country' ) != 'disabled',
77
  'utils' => is_rtl() ? '' : plugins_url( 'intlTelInput.utils.js', Lib\Plugin::getDirectory() . '/frontend/resources/js/intlTelInput.utils.js' ),
31
  ? array( 'css/bookly-rtl.css', 'css/bookly-main.css', )
32
  : array( 'css/bookly-main.css', )
33
  ),
34
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
35
  'wp' => array( 'wp-color-picker', ),
36
+ 'module' => array( 'css/appearance.css', )
37
  ) );
38
 
39
  self::enqueueScripts( array(
54
  ),
55
  'wp' => array( 'wp-color-picker' ),
56
  'module' => array(
57
+ 'js/editable.js' => array( 'bookly-bootstrap.min.js' ),
58
+ 'js/appearance.js' => array( 'bookly-editable.js' )
 
59
  )
60
  ) );
61
 
71
  'date_format' => Lib\Utils\DateTime::convertFormat( 'date', Lib\Utils\DateTime::FORMAT_PICKADATE ),
72
  'firstDay' => (int) get_option( 'start_of_week' ),
73
  'saved' => __( 'Settings saved.', 'bookly' ),
74
+ 'empty' => __( 'Empty', 'bookly' ),
75
  'intlTelInput' => array(
76
  'enabled' => get_option( 'bookly_cst_phone_default_country' ) != 'disabled',
77
  'utils' => is_rtl() ? '' : plugins_url( 'intlTelInput.utils.js', Lib\Plugin::getDirectory() . '/frontend/resources/js/intlTelInput.utils.js' ),
backend/modules/appearance/proxy/Pro.php CHANGED
@@ -10,6 +10,7 @@ use Bookly\Lib;
10
  * @method static void renderBookingStatesSelector() Render single/multiple/100% off booking selector on Payment step.
11
  * @method static void renderBookingStatesText() Render multiple or 100% off booking text option on Payment step.
12
  * @method static void renderFacebookButton() Render facebook login button on Time step.
 
13
  * @method static void renderPayPalPaymentOption() Render Cart step.
14
  * @method static void renderShowAddress() render 'Show Address Fields' on Details Step.
15
  * @method static void renderShowBirthday() render 'Show Birthday Fields' on Details Step.
10
  * @method static void renderBookingStatesSelector() Render single/multiple/100% off booking selector on Payment step.
11
  * @method static void renderBookingStatesText() Render multiple or 100% off booking text option on Payment step.
12
  * @method static void renderFacebookButton() Render facebook login button on Time step.
13
+ * @method static void renderPaymentGatewaySelector( string $l10n_option, string $title, bool $with_card ) Render radio button for payment gateway
14
  * @method static void renderPayPalPaymentOption() Render Cart step.
15
  * @method static void renderShowAddress() render 'Show Address Fields' on Details Step.
16
  * @method static void renderShowBirthday() render 'Show Birthday Fields' on Details Step.
backend/modules/appearance/proxy/Shared.php CHANGED
@@ -11,7 +11,6 @@ use Bookly\Lib;
11
  * @method static void renderPaymentGatewaySelector() Render gateway selector.
12
  * @method static int renderServiceStepSettings() Render checkbox settings.
13
  * @method static int renderTimeStepSettings() Render checkbox settings.
14
- * @method static bool showCreditCard() In case there are payment systems that request credit card information in the Details step, it will return true.
15
  */
16
  abstract class Shared extends Lib\Base\Proxy
17
  {
11
  * @method static void renderPaymentGatewaySelector() Render gateway selector.
12
  * @method static int renderServiceStepSettings() Render checkbox settings.
13
  * @method static int renderTimeStepSettings() Render checkbox settings.
 
14
  */
15
  abstract class Shared extends Lib\Base\Proxy
16
  {
backend/modules/appearance/resources/css/appearance.css ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .bookly-columnizer .bookly-hour.bookly-slot-in-waiting-list span.bookly-time-additional {
2
+ color: #f4662f!important;
3
+ }
4
+ #bookly-step-settings > div > .col-md-3:nth-child(4n+1) {
5
+ clear: both;
6
+ }
7
+ #bookly-tbs .bookly-cart .bookly-extras-cart-title {
8
+ padding-left: 25px;
9
+ }
10
+ #bookly-tbs .bookly-animate {
11
+ -webkit-transition: background-color 500ms ease-in;
12
+ -ms-transition: background-color 500ms ease-in;
13
+ transition: background-color 500ms ease-in;
14
+ }
15
+ #bookly-tbs .bookly-form label input[type="radio"] {
16
+ display: inline-block!important;
17
+ width: 16px!important;
18
+ height: 16px!important;
19
+ margin-left: 1px!important;
20
+ }
21
+
22
+ #bookly-tbs .bookly-form button {
23
+ border-radius: 4px;
24
+ }
25
+
26
+ #bookly-tbs .bookly-form ul {
27
+ padding: 0;
28
+ }
29
+
30
+ #bookly-tbs .bookly-form select {
31
+ max-width: none;
32
+ min-height: unset;
33
+ background: none;
34
+ -webkit-appearance: revert;
35
+ }
36
+
37
+ @media (max-width: 767px) {
38
+ #bookly-tbs .bookly-form .bookly-progress-tracker {
39
+ display: none !important;
40
+ }
41
+ }
42
+
43
+ #bookly-tbs .bookly-editable {
44
+ cursor: pointer;
45
+ border-bottom: dashed 1px #0088cc;
46
+ }
47
+
48
+ #bookly-tbs #bookly-appearance .bookly-popover,
49
+ #bookly-tbs #bookly_settings_invoices .bookly-popover {
50
+ min-width: 280px;
51
+ max-width: unset;
52
+ white-space: nowrap;
53
+ }
54
+
55
+ #bookly-tbs .bookly-editable-clear {
56
+ margin-left: -40px;
57
+ z-index: 100;
58
+ }
59
+
60
+ #bookly-tbs .bookly-editable-clear:not(:hover) {
61
+ color: grey;
62
+ }
63
+
64
+ #bookly-tbs .bookly-editable-clear:focus {
65
+ box-shadow: none;
66
+ }
backend/modules/appearance/resources/css/bootstrap-editable.css DELETED
@@ -1,663 +0,0 @@
1
- /*! X-editable - v1.5.1
2
- * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
3
- * http://github.com/vitalets/x-editable
4
- * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
5
- .editableform {
6
- margin-bottom: 0; /* overwrites bootstrap margin */
7
- }
8
-
9
- .editableform .control-group {
10
- margin-bottom: 0; /* overwrites bootstrap margin */
11
- white-space: nowrap; /* prevent wrapping buttons on new line */
12
- line-height: 20px; /* overwriting bootstrap line-height. See #133 */
13
- }
14
-
15
- /*
16
- BS3 width:1005 for inputs breaks editable form in popup
17
- See: https://github.com/vitalets/x-editable/issues/393
18
- */
19
- .editableform .form-control {
20
- width: auto;
21
- }
22
-
23
- .editable-buttons {
24
- display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
25
- vertical-align: top;
26
- margin-left: 7px;
27
- /* inline-block emulation for IE7*/
28
- zoom: 1;
29
- *display: inline;
30
- }
31
-
32
- .editable-buttons.editable-buttons-bottom {
33
- display: block;
34
- margin-top: 7px;
35
- margin-left: 0;
36
- }
37
-
38
- .editable-input {
39
- vertical-align: top;
40
- display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */
41
- width: auto; /* bootstrap-responsive has width: 100% that breakes layout */
42
- white-space: normal; /* reset white-space decalred in parent*/
43
- /* display-inline emulation for IE7*/
44
- zoom: 1;
45
- *display: inline;
46
- }
47
-
48
- .editable-buttons .editable-cancel {
49
- margin-left: 7px;
50
- }
51
-
52
- /*for jquery-ui buttons need set height to look more pretty*/
53
- .editable-buttons button.ui-button-icon-only {
54
- height: 24px;
55
- width: 30px;
56
- }
57
-
58
- .editableform-loading {
59
- background: url('../../../../resources/images/loading.gif') center center no-repeat;
60
- height: 25px;
61
- width: auto;
62
- min-width: 25px;
63
- }
64
-
65
- .editable-inline .editableform-loading {
66
- background-position: left 5px;
67
- }
68
-
69
- .editable-error-block {
70
- max-width: 300px;
71
- margin: 5px 0 0 0;
72
- width: auto;
73
- white-space: normal;
74
- }
75
-
76
- /*add padding for jquery ui*/
77
- .editable-error-block.ui-state-error {
78
- padding: 3px;
79
- }
80
-
81
- .editable-error {
82
- color: red;
83
- }
84
-
85
- /* ---- For specific types ---- */
86
-
87
- .editableform .editable-date {
88
- padding: 0;
89
- margin: 0;
90
- float: left;
91
- }
92
-
93
- /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */
94
- .editable-inline .add-on .icon-th {
95
- margin-top: 3px;
96
- margin-left: 1px;
97
- }
98
-
99
-
100
- /* checklist vertical alignment */
101
- .editable-checklist label input[type="checkbox"],
102
- .editable-checklist label span {
103
- vertical-align: middle;
104
- margin: 0;
105
- }
106
-
107
- .editable-checklist label {
108
- white-space: nowrap;
109
- }
110
-
111
- /* set exact width of textarea to fit buttons toolbar */
112
- .editable-wysihtml5 {
113
- width: 566px;
114
- height: 250px;
115
- }
116
-
117
- /* clear button shown as link in date inputs */
118
- .editable-clear {
119
- clear: both;
120
- font-size: 0.9em;
121
- text-decoration: none;
122
- text-align: right;
123
- }
124
-
125
- /* IOS-style clear button for text inputs */
126
- .editable-clear-x {
127
- background: url('../../../../resources/images/clear.png') center center no-repeat;
128
- display: block;
129
- width: 13px;
130
- height: 13px;
131
- position: absolute;
132
- opacity: 0.6;
133
- z-index: 100;
134
-
135
- top: 50%;
136
- right: 6px;
137
- margin-top: -6px;
138
-
139
- }
140
-
141
- .editable-clear-x:hover {
142
- opacity: 1;
143
- }
144
-
145
- .editable-pre-wrapped {
146
- white-space: pre-wrap;
147
- }
148
- .editable-container.editable-popup {
149
- max-width: none !important; /* without this rule poshytip/tooltip does not stretch */
150
- }
151
-
152
- .editable-container.popover {
153
- width: auto; /* without this rule popover does not stretch */
154
- }
155
-
156
- .editable-container.editable-inline {
157
- display: inline-block;
158
- vertical-align: middle;
159
- width: auto;
160
- /* inline-block emulation for IE7*/
161
- zoom: 1;
162
- *display: inline;
163
- }
164
-
165
- .editable-container.ui-widget {
166
- font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */
167
- z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */
168
- }
169
- .editable-click,
170
- a.editable-click,
171
- a.editable-click:hover {
172
- text-decoration: none;
173
- border-bottom: dashed 1px #0088cc;
174
- }
175
-
176
- .editable-click.editable-disabled,
177
- a.editable-click.editable-disabled,
178
- a.editable-click.editable-disabled:hover {
179
- color: #585858;
180
- cursor: default;
181
- border-bottom: none;
182
- }
183
-
184
- .editable-empty, .editable-empty:hover, .editable-empty:focus{
185
- font-style: italic;
186
- color: #DD1144;
187
- /* border-bottom: none; */
188
- text-decoration: none;
189
- }
190
-
191
- .editable-unsaved {
192
- font-weight: bold;
193
- }
194
-
195
- .editable-unsaved:after {
196
- /* content: '*'*/
197
- }
198
-
199
- .editable-bg-transition {
200
- -webkit-transition: background-color 1400ms ease-out;
201
- -moz-transition: background-color 1400ms ease-out;
202
- -o-transition: background-color 1400ms ease-out;
203
- -ms-transition: background-color 1400ms ease-out;
204
- transition: background-color 1400ms ease-out;
205
- }
206
-
207
- /*see https://github.com/vitalets/x-editable/issues/139 */
208
- .form-horizontal .editable
209
- {
210
- padding-top: 5px;
211
- display:inline-block;
212
- }
213
-
214
-
215
- /*!
216
- * Datepicker for Bootstrap
217
- *
218
- * Copyright 2012 Stefan Petre
219
- * Improvements by Andrew Rowls
220
- * Licensed under the Apache License v2.0
221
- * http://www.apache.org/licenses/LICENSE-2.0
222
- *
223
- */
224
- .datepicker {
225
- padding: 4px;
226
- -webkit-border-radius: 4px;
227
- -moz-border-radius: 4px;
228
- border-radius: 4px;
229
- direction: ltr;
230
- /*.dow {
231
- border-top: 1px solid #ddd !important;
232
- }*/
233
-
234
- }
235
- .datepicker-inline {
236
- width: 220px;
237
- }
238
- .datepicker.datepicker-rtl {
239
- direction: rtl;
240
- }
241
- .datepicker.datepicker-rtl table tr td span {
242
- float: right;
243
- }
244
- .datepicker-dropdown {
245
- top: 0;
246
- left: 0;
247
- }
248
- .datepicker-dropdown:before {
249
- content: '';
250
- display: inline-block;
251
- border-left: 7px solid transparent;
252
- border-right: 7px solid transparent;
253
- border-bottom: 7px solid #ccc;
254
- border-bottom-color: rgba(0, 0, 0, 0.2);
255
- position: absolute;
256
- top: -7px;
257
- left: 6px;
258
- }
259
- .datepicker-dropdown:after {
260
- content: '';
261
- display: inline-block;
262
- border-left: 6px solid transparent;
263
- border-right: 6px solid transparent;
264
- border-bottom: 6px solid #ffffff;
265
- position: absolute;
266
- top: -6px;
267
- left: 7px;
268
- }
269
- .datepicker > div {
270
- display: none;
271
- }
272
- .datepicker.days div.datepicker-days {
273
- display: block;
274
- }
275
- .datepicker.months div.datepicker-months {
276
- display: block;
277
- }
278
- .datepicker.years div.datepicker-years {
279
- display: block;
280
- }
281
- .datepicker table {
282
- margin: 0;
283
- }
284
- .datepicker td,
285
- .datepicker th {
286
- text-align: center;
287
- width: 20px;
288
- height: 20px;
289
- -webkit-border-radius: 4px;
290
- -moz-border-radius: 4px;
291
- border-radius: 4px;
292
- border: none;
293
- }
294
- .table-striped .datepicker table tr td,
295
- .table-striped .datepicker table tr th {
296
- background-color: transparent;
297
- }
298
- .datepicker table tr td.day:hover {
299
- background: #eeeeee;
300
- cursor: pointer;
301
- }
302
- .datepicker table tr td.old,
303
- .datepicker table tr td.new {
304
- color: #999999;
305
- }
306
- .datepicker table tr td.disabled,
307
- .datepicker table tr td.disabled:hover {
308
- background: none;
309
- color: #999999;
310
- cursor: default;
311
- }
312
- .datepicker table tr td.today,
313
- .datepicker table tr td.today:hover,
314
- .datepicker table tr td.today.disabled,
315
- .datepicker table tr td.today.disabled:hover {
316
- background-color: #fde19a;
317
- background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a);
318
- background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a);
319
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a));
320
- background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a);
321
- background-image: -o-linear-gradient(top, #fdd49a, #fdf59a);
322
- background-image: linear-gradient(top, #fdd49a, #fdf59a);
323
- background-repeat: repeat-x;
324
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0);
325
- border-color: #fdf59a #fdf59a #fbed50;
326
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
327
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
328
- color: #000;
329
- }
330
- .datepicker table tr td.today:hover,
331
- .datepicker table tr td.today:hover:hover,
332
- .datepicker table tr td.today.disabled:hover,
333
- .datepicker table tr td.today.disabled:hover:hover,
334
- .datepicker table tr td.today:active,
335
- .datepicker table tr td.today:hover:active,
336
- .datepicker table tr td.today.disabled:active,
337
- .datepicker table tr td.today.disabled:hover:active,
338
- .datepicker table tr td.today.active,
339
- .datepicker table tr td.today:hover.active,
340
- .datepicker table tr td.today.disabled.active,
341
- .datepicker table tr td.today.disabled:hover.active,
342
- .datepicker table tr td.today.disabled,
343
- .datepicker table tr td.today:hover.disabled,
344
- .datepicker table tr td.today.disabled.disabled,
345
- .datepicker table tr td.today.disabled:hover.disabled,
346
- .datepicker table tr td.today[disabled],
347
- .datepicker table tr td.today:hover[disabled],
348
- .datepicker table tr td.today.disabled[disabled],
349
- .datepicker table tr td.today.disabled:hover[disabled] {
350
- background-color: #fdf59a;
351
- }
352
- .datepicker table tr td.today:active,
353
- .datepicker table tr td.today:hover:active,
354
- .datepicker table tr td.today.disabled:active,
355
- .datepicker table tr td.today.disabled:hover:active,
356
- .datepicker table tr td.today.active,
357
- .datepicker table tr td.today:hover.active,
358
- .datepicker table tr td.today.disabled.active,
359
- .datepicker table tr td.today.disabled:hover.active {
360
- background-color: #fbf069 \9;
361
- }
362
- .datepicker table tr td.today:hover:hover {
363
- color: #000;
364
- }
365
- .datepicker table tr td.today.active:hover {
366
- color: #fff;
367
- }
368
- .datepicker table tr td.range,
369
- .datepicker table tr td.range:hover,
370
- .datepicker table tr td.range.disabled,
371
- .datepicker table tr td.range.disabled:hover {
372
- background: #eeeeee;
373
- -webkit-border-radius: 0;
374
- -moz-border-radius: 0;
375
- border-radius: 0;
376
- }
377
- .datepicker table tr td.range.today,
378
- .datepicker table tr td.range.today:hover,
379
- .datepicker table tr td.range.today.disabled,
380
- .datepicker table tr td.range.today.disabled:hover {
381
- background-color: #f3d17a;
382
- background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a);
383
- background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a);
384
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a));
385
- background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a);
386
- background-image: -o-linear-gradient(top, #f3c17a, #f3e97a);
387
- background-image: linear-gradient(top, #f3c17a, #f3e97a);
388
- background-repeat: repeat-x;
389
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0);
390
- border-color: #f3e97a #f3e97a #edde34;
391
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
392
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
393
- -webkit-border-radius: 0;
394
- -moz-border-radius: 0;
395
- border-radius: 0;
396
- }
397
- .datepicker table tr td.range.today:hover,
398
- .datepicker table tr td.range.today:hover:hover,
399
- .datepicker table tr td.range.today.disabled:hover,
400
- .datepicker table tr td.range.today.disabled:hover:hover,
401
- .datepicker table tr td.range.today:active,
402
- .datepicker table tr td.range.today:hover:active,
403
- .datepicker table tr td.range.today.disabled:active,
404
- .datepicker table tr td.range.today.disabled:hover:active,
405
- .datepicker table tr td.range.today.active,
406
- .datepicker table tr td.range.today:hover.active,
407
- .datepicker table tr td.range.today.disabled.active,
408
- .datepicker table tr td.range.today.disabled:hover.active,
409
- .datepicker table tr td.range.today.disabled,
410
- .datepicker table tr td.range.today:hover.disabled,
411
- .datepicker table tr td.range.today.disabled.disabled,
412
- .datepicker table tr td.range.today.disabled:hover.disabled,
413
- .datepicker table tr td.range.today[disabled],
414
- .datepicker table tr td.range.today:hover[disabled],
415
- .datepicker table tr td.range.today.disabled[disabled],
416
- .datepicker table tr td.range.today.disabled:hover[disabled] {
417
- background-color: #f3e97a;
418
- }
419
- .datepicker table tr td.range.today:active,
420
- .datepicker table tr td.range.today:hover:active,
421
- .datepicker table tr td.range.today.disabled:active,
422
- .datepicker table tr td.range.today.disabled:hover:active,
423
- .datepicker table tr td.range.today.active,
424
- .datepicker table tr td.range.today:hover.active,
425
- .datepicker table tr td.range.today.disabled.active,
426
- .datepicker table tr td.range.today.disabled:hover.active {
427
- background-color: #efe24b \9;
428
- }
429
- .datepicker table tr td.selected,
430
- .datepicker table tr td.selected:hover,
431
- .datepicker table tr td.selected.disabled,
432
- .datepicker table tr td.selected.disabled:hover {
433
- background-color: #9e9e9e;
434
- background-image: -moz-linear-gradient(top, #b3b3b3, #808080);
435
- background-image: -ms-linear-gradient(top, #b3b3b3, #808080);
436
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080));
437
- background-image: -webkit-linear-gradient(top, #b3b3b3, #808080);
438
- background-image: -o-linear-gradient(top, #b3b3b3, #808080);
439
- background-image: linear-gradient(top, #b3b3b3, #808080);
440
- background-repeat: repeat-x;
441
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0);
442
- border-color: #808080 #808080 #595959;
443
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
444
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
445
- color: #fff;
446
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
447
- }
448
- .datepicker table tr td.selected:hover,
449
- .datepicker table tr td.selected:hover:hover,
450
- .datepicker table tr td.selected.disabled:hover,
451
- .datepicker table tr td.selected.disabled:hover:hover,
452
- .datepicker table tr td.selected:active,
453
- .datepicker table tr td.selected:hover:active,
454
- .datepicker table tr td.selected.disabled:active,
455
- .datepicker table tr td.selected.disabled:hover:active,
456
- .datepicker table tr td.selected.active,
457
- .datepicker table tr td.selected:hover.active,
458
- .datepicker table tr td.selected.disabled.active,
459
- .datepicker table tr td.selected.disabled:hover.active,
460
- .datepicker table tr td.selected.disabled,
461
- .datepicker table tr td.selected:hover.disabled,
462
- .datepicker table tr td.selected.disabled.disabled,
463
- .datepicker table tr td.selected.disabled:hover.disabled,
464
- .datepicker table tr td.selected[disabled],
465
- .datepicker table tr td.selected:hover[disabled],
466
- .datepicker table tr td.selected.disabled[disabled],
467
- .datepicker table tr td.selected.disabled:hover[disabled] {
468
- background-color: #808080;
469
- }
470
- .datepicker table tr td.selected:active,
471
- .datepicker table tr td.selected:hover:active,
472
- .datepicker table tr td.selected.disabled:active,
473
- .datepicker table tr td.selected.disabled:hover:active,
474
- .datepicker table tr td.selected.active,
475
- .datepicker table tr td.selected:hover.active,
476
- .datepicker table tr td.selected.disabled.active,
477
- .datepicker table tr td.selected.disabled:hover.active {
478
- background-color: #666666 \9;
479
- }
480
- .datepicker table tr td.active,
481
- .datepicker table tr td.active:hover,
482
- .datepicker table tr td.active.disabled,
483
- .datepicker table tr td.active.disabled:hover {
484
- background-color: #006dcc;
485
- background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
486
- background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
487
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
488
- background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
489
- background-image: -o-linear-gradient(top, #0088cc, #0044cc);
490
- background-image: linear-gradient(top, #0088cc, #0044cc);
491
- background-repeat: repeat-x;
492
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
493
- border-color: #0044cc #0044cc #002a80;
494
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
495
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
496
- color: #fff;
497
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
498
- }
499
- .datepicker table tr td.active:hover,
500
- .datepicker table tr td.active:hover:hover,
501
- .datepicker table tr td.active.disabled:hover,
502
- .datepicker table tr td.active.disabled:hover:hover,
503
- .datepicker table tr td.active:active,
504
- .datepicker table tr td.active:hover:active,
505
- .datepicker table tr td.active.disabled:active,
506
- .datepicker table tr td.active.disabled:hover:active,
507
- .datepicker table tr td.active.active,
508
- .datepicker table tr td.active:hover.active,
509
- .datepicker table tr td.active.disabled.active,
510
- .datepicker table tr td.active.disabled:hover.active,
511
- .datepicker table tr td.active.disabled,
512
- .datepicker table tr td.active:hover.disabled,
513
- .datepicker table tr td.active.disabled.disabled,
514
- .datepicker table tr td.active.disabled:hover.disabled,
515
- .datepicker table tr td.active[disabled],
516
- .datepicker table tr td.active:hover[disabled],
517
- .datepicker table tr td.active.disabled[disabled],
518
- .datepicker table tr td.active.disabled:hover[disabled] {
519
- background-color: #0044cc;
520
- }
521
- .datepicker table tr td.active:active,
522
- .datepicker table tr td.active:hover:active,
523
- .datepicker table tr td.active.disabled:active,
524
- .datepicker table tr td.active.disabled:hover:active,
525
- .datepicker table tr td.active.active,
526
- .datepicker table tr td.active:hover.active,
527
- .datepicker table tr td.active.disabled.active,
528
- .datepicker table tr td.active.disabled:hover.active {
529
- background-color: #003399 \9;
530
- }
531
- .datepicker table tr td span {
532
- display: block;
533
- width: 23%;
534
- height: 54px;
535
- line-height: 54px;
536
- float: left;
537
- margin: 1%;
538
- cursor: pointer;
539
- -webkit-border-radius: 4px;
540
- -moz-border-radius: 4px;
541
- border-radius: 4px;
542
- }
543
- .datepicker table tr td span:hover {
544
- background: #eeeeee;
545
- }
546
- .datepicker table tr td span.disabled,
547
- .datepicker table tr td span.disabled:hover {
548
- background: none;
549
- color: #999999;
550
- cursor: default;
551
- }
552
- .datepicker table tr td span.active,
553
- .datepicker table tr td span.active:hover,
554
- .datepicker table tr td span.active.disabled,
555
- .datepicker table tr td span.active.disabled:hover {
556
- background-color: #006dcc;
557
- background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
558
- background-image: -ms-linear-gradient(top, #0088cc, #0044cc);
559
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
560
- background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
561
- background-image: -o-linear-gradient(top, #0088cc, #0044cc);
562
- background-image: linear-gradient(top, #0088cc, #0044cc);
563
- background-repeat: repeat-x;
564
- filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);
565
- border-color: #0044cc #0044cc #002a80;
566
- border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
567
- filter: progid:DXImageTransform.Microsoft.gradient(enabled=false);
568
- color: #fff;
569
- text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
570
- }
571
- .datepicker table tr td span.active:hover,
572
- .datepicker table tr td span.active:hover:hover,
573
- .datepicker table tr td span.active.disabled:hover,
574
- .datepicker table tr td span.active.disabled:hover:hover,
575
- .datepicker table tr td span.active:active,
576
- .datepicker table tr td span.active:hover:active,
577
- .datepicker table tr td span.active.disabled:active,
578
- .datepicker table tr td span.active.disabled:hover:active,
579
- .datepicker table tr td span.active.active,
580
- .datepicker table tr td span.active:hover.active,
581
- .datepicker table tr td span.active.disabled.active,
582
- .datepicker table tr td span.active.disabled:hover.active,
583
- .datepicker table tr td span.active.disabled,
584
- .datepicker table tr td span.active:hover.disabled,
585
- .datepicker table tr td span.active.disabled.disabled,
586
- .datepicker table tr td span.active.disabled:hover.disabled,
587
- .datepicker table tr td span.active[disabled],
588
- .datepicker table tr td span.active:hover[disabled],
589
- .datepicker table tr td span.active.disabled[disabled],
590
- .datepicker table tr td span.active.disabled:hover[disabled] {
591
- background-color: #0044cc;
592
- }
593
- .datepicker table tr td span.active:active,
594
- .datepicker table tr td span.active:hover:active,
595
- .datepicker table tr td span.active.disabled:active,
596
- .datepicker table tr td span.active.disabled:hover:active,
597
- .datepicker table tr td span.active.active,
598
- .datepicker table tr td span.active:hover.active,
599
- .datepicker table tr td span.active.disabled.active,
600
- .datepicker table tr td span.active.disabled:hover.active {
601
- background-color: #003399 \9;
602
- }
603
- .datepicker table tr td span.old,
604
- .datepicker table tr td span.new {
605
- color: #999999;
606
- }
607
- .datepicker th.datepicker-switch {
608
- width: 145px;
609
- }
610
- .datepicker thead tr:first-child th,
611
- .datepicker tfoot tr th {
612
- cursor: pointer;
613
- }
614
- .datepicker thead tr:first-child th:hover,
615
- .datepicker tfoot tr th:hover {
616
- background: #eeeeee;
617
- }
618
- .datepicker .cw {
619
- font-size: 10px;
620
- width: 12px;
621
- padding: 0 2px 0 5px;
622
- vertical-align: middle;
623
- }
624
- .datepicker thead tr:first-child th.cw {
625
- cursor: default;
626
- background-color: transparent;
627
- }
628
- .input-append.date .add-on i,
629
- .input-prepend.date .add-on i {
630
- display: block;
631
- cursor: pointer;
632
- width: 16px;
633
- height: 16px;
634
- }
635
- .input-daterange input {
636
- text-align: center;
637
- }
638
- .input-daterange input:first-child {
639
- -webkit-border-radius: 3px 0 0 3px;
640
- -moz-border-radius: 3px 0 0 3px;
641
- border-radius: 3px 0 0 3px;
642
- }
643
- .input-daterange input:last-child {
644
- -webkit-border-radius: 0 3px 3px 0;
645
- -moz-border-radius: 0 3px 3px 0;
646
- border-radius: 0 3px 3px 0;
647
- }
648
- .input-daterange .add-on {
649
- display: inline-block;
650
- width: auto;
651
- min-width: 16px;
652
- height: 18px;
653
- padding: 4px 5px;
654
- font-weight: normal;
655
- line-height: 18px;
656
- text-align: center;
657
- text-shadow: 0 1px 0 #ffffff;
658
- vertical-align: middle;
659
- background-color: #eeeeee;
660
- border: 1px solid #ccc;
661
- margin-left: -5px;
662
- margin-right: -5px;
663
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/modules/appearance/resources/js/appearance.js CHANGED
@@ -139,7 +139,7 @@ jQuery(function($) {
139
  });
140
 
141
  // Init editable elements.
142
- $editableElements.editable();
143
 
144
  // Show progress tracker.
145
  $show_progress_tracker.on('change', function() {
@@ -160,18 +160,18 @@ jQuery(function($) {
160
  }).trigger('change');
161
 
162
  // Show steps.
163
- $('.bookly-js-show-step').on('change', function () {
164
  var target = $(this).data('target'),
165
- $button = $('li.bookly-nav-item[data-target="#' + target + '"]'),
166
  $step = $('div[data-step="' + target + '"]');
167
  if ($(this).prop('checked')) {
168
- $button.show();
169
  $step.show();
170
  } else {
171
  if ($button.hasClass('active')) {
172
- $('li.bookly-nav-item[data-target="#bookly-step-1"]').trigger('click');
173
  }
174
- $button.hide();
175
  $step.hide();
176
  }
177
  // Hide/show cart buttons
@@ -188,9 +188,9 @@ jQuery(function($) {
188
  }).trigger('change');
189
 
190
  // Show step specific settings.
191
- $('li.bookly-nav-item').on('shown.bs.tab', function (e) {
192
  $step_settings.children().hide();
193
- switch (e.target.getAttribute('data-target')) {
194
  case '#bookly-step-1': $step_settings.find('.bookly-js-service-settings').show(); break;
195
  case '#bookly-step-2': $step_settings.find('.bookly-js-extras-settings').show(); break;
196
  case '#bookly-step-3': $step_settings.find('.bookly-js-time-settings').show(); break;
@@ -488,7 +488,6 @@ jQuery(function($) {
488
  }
489
  });
490
 
491
-
492
  /**
493
  * Step Repeat.
494
  */
@@ -529,9 +528,9 @@ jQuery(function($) {
529
 
530
  // Show Facebook login button.
531
  $show_facebook_login_button.change(function () {
532
- if ($(this).data('appid') == '') {
533
  if (this.checked) {
534
- $('#bookly-facebook-warning').modal('show');
535
  this.checked = false;
536
  }
537
  } else {
@@ -541,7 +540,7 @@ jQuery(function($) {
541
 
542
  // Show first and last name.
543
  $first_last_name.on('change', function () {
544
- $first_last_name.popover('toggle');
545
  if (this.checked) {
546
  $('.bookly-js-details-full-name').addClass('collapse');
547
  $('.bookly-js-details-first-last-name').removeClass('collapse');
@@ -608,10 +607,10 @@ jQuery(function($) {
608
  $show_address_fields.change(function () {
609
  $('#bookly-js-address').toggle(this.checked);
610
  if (this.checked) {
611
- $show_google_maps.closest('[data-toggle="popover"]').popover('destroy');
612
  $show_google_maps.prop('disabled', false);
613
  } else {
614
- $show_google_maps.closest('[data-toggle="popover"]').popover();
615
  $show_google_maps.prop('checked', false).prop('disabled', true).trigger('change');
616
  }
617
  }).trigger('change');
@@ -624,10 +623,10 @@ jQuery(function($) {
624
  $show_custom_fields.change(function () {
625
  $('.bookly-js-custom-fields').toggle(this.checked);
626
  if (this.checked) {
627
- $show_files.closest('[data-toggle="popover"]').popover('destroy');
628
  $show_files.prop('disabled', false);
629
  } else {
630
- $show_files.closest('[data-toggle="popover"]').popover();
631
  $show_files.prop('checked', false).prop('disabled', true).trigger('change');
632
  }
633
  }).trigger('change');
@@ -654,7 +653,10 @@ jQuery(function($) {
654
 
655
  // Show credit card form.
656
  $('.bookly-payment-nav :radio').on('change', function () {
657
- $('form.bookly-card-form').toggle(this.id == 'bookly-card-payment');
 
 
 
658
  });
659
 
660
  $show_coupons.on('change', function () {
@@ -672,16 +674,18 @@ jQuery(function($) {
672
  $('.bookly-js-done-processing').toggle(this.value == 'booking-processing');
673
  });
674
 
675
-
676
  /**
677
  * Misc.
678
  */
679
- $('.bookly-js-simple-popover').popover();
 
 
 
680
 
681
  // Custom CSS.
682
  $('#bookly-custom-css-save').on('click', function (e) {
683
- var $custom_css = $('#bookly-custom-css'),
684
- $modal = $('#bookly-custom-css-dialog');
685
 
686
  saved_css = $custom_css.val();
687
 
@@ -699,7 +703,7 @@ jQuery(function($) {
699
  dataType : 'json',
700
  success : function (response) {
701
  if (response.success) {
702
- $modal.modal('hide');
703
  booklyAlert({success : [response.data.message]});
704
  }
705
  },
@@ -709,11 +713,11 @@ jQuery(function($) {
709
  });
710
  });
711
 
712
- $('#bookly-custom-css-cancel').on('click', function (e) {
713
  var $custom_css = $('#bookly-custom-css'),
714
  $modal = $('#bookly-custom-css-dialog');
715
 
716
- $modal.modal('hide');
717
 
718
  $custom_css.val(saved_css);
719
  });
@@ -788,7 +792,7 @@ jQuery(function($) {
788
  };
789
  // Add data from editable elements.
790
  $editableElements.each(function () {
791
- $.extend(data.options, $(this).editable('getValue', true));
792
  });
793
 
794
  // Update data and show spinner while updating.
@@ -807,7 +811,7 @@ jQuery(function($) {
807
 
808
  // Reset editable texts.
809
  $editableElements.each(function () {
810
- $(this).editable('setValue', $.extend({}, $(this).data('values')));
811
  });
812
 
813
  $checkboxes.each(function () {
@@ -820,7 +824,7 @@ jQuery(function($) {
820
  $(this).val($(this).data('default')).trigger('change');
821
  }
822
  });
823
- $first_last_name.popover('hide');
824
  });
825
 
826
  function bookly_highlight($element) {
139
  });
140
 
141
  // Init editable elements.
142
+ $editableElements.booklyEditable({empty: BooklyL10n.empty});
143
 
144
  // Show progress tracker.
145
  $show_progress_tracker.on('change', function() {
160
  }).trigger('change');
161
 
162
  // Show steps.
163
+ $('[data-type="bookly-show-step-checkbox"]').on('change', function () {
164
  var target = $(this).data('target'),
165
+ $button = $('.bookly-js-appearance-steps li a[href="#' + target + '"]'),
166
  $step = $('div[data-step="' + target + '"]');
167
  if ($(this).prop('checked')) {
168
+ $button.parent().show();
169
  $step.show();
170
  } else {
171
  if ($button.hasClass('active')) {
172
+ $('.bookly-js-appearance-steps li a[href="#bookly-step-1"]').trigger('click');
173
  }
174
+ $button.parent().hide();
175
  $step.hide();
176
  }
177
  // Hide/show cart buttons
188
  }).trigger('change');
189
 
190
  // Show step specific settings.
191
+ $('.bookly-js-appearance-steps li.nav-item').on('shown.bs.tab', function (e) {
192
  $step_settings.children().hide();
193
+ switch ($(e.target).attr('href')) {
194
  case '#bookly-step-1': $step_settings.find('.bookly-js-service-settings').show(); break;
195
  case '#bookly-step-2': $step_settings.find('.bookly-js-extras-settings').show(); break;
196
  case '#bookly-step-3': $step_settings.find('.bookly-js-time-settings').show(); break;
488
  }
489
  });
490
 
 
491
  /**
492
  * Step Repeat.
493
  */
528
 
529
  // Show Facebook login button.
530
  $show_facebook_login_button.change(function () {
531
+ if ($(this).data('appid') == undefined || $(this).data('appid') == '') {
532
  if (this.checked) {
533
+ $('#bookly-facebook-warning').booklyModal('show');
534
  this.checked = false;
535
  }
536
  } else {
540
 
541
  // Show first and last name.
542
  $first_last_name.on('change', function () {
543
+ $first_last_name.closest('[data-toggle="bookly-popover"]').booklyPopover('toggle');
544
  if (this.checked) {
545
  $('.bookly-js-details-full-name').addClass('collapse');
546
  $('.bookly-js-details-first-last-name').removeClass('collapse');
607
  $show_address_fields.change(function () {
608
  $('#bookly-js-address').toggle(this.checked);
609
  if (this.checked) {
610
+ $show_google_maps.closest('[data-toggle="bookly-popover"]').booklyPopover('disable');
611
  $show_google_maps.prop('disabled', false);
612
  } else {
613
+ $show_google_maps.closest('[data-toggle="bookly-popover"]').booklyPopover('enable');
614
  $show_google_maps.prop('checked', false).prop('disabled', true).trigger('change');
615
  }
616
  }).trigger('change');
623
  $show_custom_fields.change(function () {
624
  $('.bookly-js-custom-fields').toggle(this.checked);
625
  if (this.checked) {
626
+ $show_files.closest('[data-toggle="bookly-popover"]').booklyPopover('disable');
627
  $show_files.prop('disabled', false);
628
  } else {
629
+ $show_files.closest('[data-toggle="bookly-popover"]').booklyPopover('enable');
630
  $show_files.prop('checked', false).prop('disabled', true).trigger('change');
631
  }
632
  }).trigger('change');
653
 
654
  // Show credit card form.
655
  $('.bookly-payment-nav :radio').on('change', function () {
656
+ $('form.bookly-card-form').hide();
657
+ if (this.id == 'bookly-card-payment') {
658
+ $('form.bookly-card-form', $(this).closest('.bookly-box')).show();
659
+ }
660
  });
661
 
662
  $show_coupons.on('change', function () {
674
  $('.bookly-js-done-processing').toggle(this.value == 'booking-processing');
675
  });
676
 
 
677
  /**
678
  * Misc.
679
  */
680
+
681
+ $('.bookly-js-simple-popover').booklyPopover({
682
+ container: $('#bookly-appearance'),
683
+ });
684
 
685
  // Custom CSS.
686
  $('#bookly-custom-css-save').on('click', function (e) {
687
+ let $custom_css = $('#bookly-custom-css'),
688
+ $modal = $('#bookly-custom-css-dialog');
689
 
690
  saved_css = $custom_css.val();
691
 
703
  dataType : 'json',
704
  success : function (response) {
705
  if (response.success) {
706
+ $modal.booklyModal('hide');
707
  booklyAlert({success : [response.data.message]});
708
  }
709
  },
713
  });
714
  });
715
 
716
+ $('#bookly-custom-css-dialog button[data-dismiss="bookly-modal"]').on('click', function (e) {
717
  var $custom_css = $('#bookly-custom-css'),
718
  $modal = $('#bookly-custom-css-dialog');
719
 
720
+ $modal.booklyModal('hide');
721
 
722
  $custom_css.val(saved_css);
723
  });
792
  };
793
  // Add data from editable elements.
794
  $editableElements.each(function () {
795
+ $.extend(data.options, $(this).booklyEditable('getValue'));
796
  });
797
 
798
  // Update data and show spinner while updating.
811
 
812
  // Reset editable texts.
813
  $editableElements.each(function () {
814
+ $(this).booklyEditable('setValue', $.extend({}, $(this).data('values')));
815
  });
816
 
817
  $checkboxes.each(function () {
824
  $(this).val($(this).data('default')).trigger('change');
825
  }
826
  });
827
+ $first_last_name.booklyPopover('hide');
828
  });
829
 
830
  function bookly_highlight($element) {
backend/modules/appearance/resources/js/bootstrap-editable.bookly.js DELETED
@@ -1,125 +0,0 @@
1
- jQuery(function($) {
2
- var Bookly = function (options) {
3
- this.init('bookly', options, Bookly.defaults);
4
- };
5
-
6
- // Inherit from Abstract input.
7
- $.fn.editableutils.inherit(Bookly, $.fn.editabletypes.abstractinput);
8
-
9
- $.extend(Bookly.prototype, {
10
- html2value: function(html) {
11
- return $.extend({}, $(this.options.scope).data('values'));
12
- },
13
- value2html: function (values, element) {
14
- $.each(values, function (option_name, option_value) {
15
- // Find all elements which display option value.
16
- $('.bookly-js-option[data-option="' + option_name + '"]').each(function () {
17
- var $this = $(this);
18
- if (!$this.hasClass('editable') || $this.is(element)) {
19
- // Update text.
20
- $this.text(option_value);
21
- }
22
- });
23
- });
24
- },
25
- activate: function () {
26
- this.$tpl.find(':input:first').focus();
27
- },
28
- value2input: function (values) {
29
- var _this = this;
30
- this.$tpl.empty();
31
- $.each(values, function (option_name, option_value) {
32
- var $row = $('<div/>')
33
- .css({position: 'relative', 'margin-top': '6px'})
34
- .appendTo(_this.$tpl);
35
- switch (_this.options.fieldType) {
36
- case 'input':
37
- // Create input with "x" button.
38
- var $clear = $('<span class="editable-clear-x"></span>');
39
- var $input = $('<input/>', {
40
- type : 'text',
41
- class: 'form-control',
42
- name : option_name,
43
- value: option_value
44
- });
45
- $input.keyup(function(e) {
46
- // arrows, enter, tab, etc
47
- if (~$.inArray(e.keyCode, [40,38,9,13,27])) {
48
- return;
49
- }
50
- clearTimeout(this.t);
51
- this.t = setTimeout(function() {
52
- var len = $input.val().length,
53
- visible = $clear.is(':visible');
54
- if (len && !visible) {
55
- $clear.show();
56
- }
57
- if (!len && visible) {
58
- $clear.hide();
59
- }
60
- }, 100);
61
- });
62
- $clear.click(function () {
63
- $clear.hide();
64
- $input.val('').focus();
65
- });
66
- $row.append($input).append($clear);
67
- break;
68
- case 'number':
69
- // Create input[type="number"]
70
- $('<input/>', {
71
- type : 'number',
72
- class: 'form-control',
73
- name : option_name,
74
- min : $(_this.options.scope).data('min'),
75
- step : $(_this.options.scope).data('step')
76
- }).val(option_value).appendTo($row);
77
- break;
78
- default :
79
- // Create textarea.
80
- $('<textarea/>', {
81
- class: 'form-control',
82
- name : option_name,
83
- rows : 7
84
- }).val(option_value).appendTo($row);
85
- break;
86
- }
87
- });
88
- // Set codes.
89
- this.$tpl.closest('form').find('.bookly-js-codes').html($(this.options.scope).data('codes'));
90
- },
91
- input2value: function () {
92
- var _this = this;
93
- var values = {};
94
- this.$tpl.find(':input').each(function () {
95
- values[this.name] = this.value;
96
- // Find all elements which display option value.
97
- var option_name = this.name;
98
- var option_value = this.value;
99
- $('.bookly-js-option.' + option_name).each(function () {
100
- var $this = $(this);
101
- if ($this.hasClass('editable') && !$this.is(_this.$tpl)) {
102
- // Update editable value.
103
- var val = $this.editable('getValue', true);
104
- val[option_name] = option_value;
105
- $this.editable('setValue', val);
106
- }
107
- });
108
- });
109
-
110
- return values;
111
- }
112
- });
113
-
114
- Bookly.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
115
- tpl: '<div/>',
116
- fieldType: 'input'
117
- });
118
-
119
- $.fn.editabletypes.bookly = Bookly;
120
-
121
- // Set template for popovers and editable form.
122
- $.fn.popover.Constructor.DEFAULTS.template = '<div class="popover"><div class="popover-arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>';
123
- $.fn.editableform.template = '<form class="form-inline editableform"><div class="control-group"><div><div class="editable-input"></div><div class="editable-buttons"></div></div><div class="bookly-js-codes"></div><div class="editable-error-block"></div></div></form>';
124
- $.fn.editableform.buttons = '<div class="btn-group btn-group-sm"><button type="submit" class="btn btn-success editable-submit"><span class="glyphicon glyphicon-ok"></span></button><button type="button" class="btn btn-default editable-cancel"><span class="glyphicon glyphicon-remove"></span></button></div>';
125
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/modules/appearance/resources/js/bootstrap-editable.min.js DELETED
@@ -1,7 +0,0 @@
1
- /*! X-editable - v1.5.1
2
- * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery
3
- * http://github.com/vitalets/x-editable
4
- * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */
5
- !function(a){"use strict";var b=function(b,c){this.options=a.extend({},a.fn.editableform.defaults,c),this.$div=a(b),this.options.scope||(this.options.scope=this)};b.prototype={constructor:b,initInput:function(){this.input=this.options.input,this.value=this.input.str2value(this.options.value),this.input.prerender()},initTemplate:function(){this.$form=a(a.fn.editableform.template)},initButtons:function(){var b=this.$form.find(".editable-buttons");b.append(a.fn.editableform.buttons),"bottom"===this.options.showbuttons&&b.addClass("editable-buttons-bottom")},render:function(){this.$loading=a(a.fn.editableform.loading),this.$div.empty().append(this.$loading),this.initTemplate(),this.options.showbuttons?this.initButtons():this.$form.find(".editable-buttons").remove(),this.showLoading(),this.isSaving=!1,this.$div.triggerHandler("rendering"),this.initInput(),this.$form.find("div.editable-input").append(this.input.$tpl),this.$div.append(this.$form),a.when(this.input.render()).then(a.proxy(function(){if(this.options.showbuttons||this.input.autosubmit(),this.$form.find(".editable-cancel").click(a.proxy(this.cancel,this)),this.input.error)this.error(this.input.error),this.$form.find(".editable-submit").attr("disabled",!0),this.input.$input.attr("disabled",!0),this.$form.submit(function(a){a.preventDefault()});else{this.error(!1),this.input.$input.removeAttr("disabled"),this.$form.find(".editable-submit").removeAttr("disabled");var b=null===this.value||void 0===this.value||""===this.value?this.options.defaultValue:this.value;this.input.value2input(b),this.$form.submit(a.proxy(this.submit,this))}this.$div.triggerHandler("rendered"),this.showForm(),this.input.postrender&&this.input.postrender()},this))},cancel:function(){this.$div.triggerHandler("cancel")},showLoading:function(){var a,b;this.$form?(a=this.$form.outerWidth(),b=this.$form.outerHeight(),a&&this.$loading.width(a),b&&this.$loading.height(b),this.$form.hide()):(a=this.$loading.parent().width(),a&&this.$loading.width(a)),this.$loading.show()},showForm:function(a){this.$loading.hide(),this.$form.show(),a!==!1&&this.input.activate(),this.$div.triggerHandler("show")},error:function(b){var c,d=this.$form.find(".control-group"),e=this.$form.find(".editable-error-block");if(b===!1)d.removeClass(a.fn.editableform.errorGroupClass),e.removeClass(a.fn.editableform.errorBlockClass).empty().hide();else{if(b){c=(""+b).split("\n");for(var f=0;f<c.length;f++)c[f]=a("<div>").text(c[f]).html();b=c.join("<br>")}d.addClass(a.fn.editableform.errorGroupClass),e.addClass(a.fn.editableform.errorBlockClass).html(b).show()}},submit:function(b){b.stopPropagation(),b.preventDefault();var c=this.input.input2value(),d=this.validate(c);if("object"===a.type(d)&&void 0!==d.newValue){if(c=d.newValue,this.input.value2input(c),"string"==typeof d.msg)return this.error(d.msg),this.showForm(),void 0}else if(d)return this.error(d),this.showForm(),void 0;if(!this.options.savenochange&&this.input.value2str(c)==this.input.value2str(this.value))return this.$div.triggerHandler("nochange"),void 0;var e=this.input.value2submit(c);this.isSaving=!0,a.when(this.save(e)).done(a.proxy(function(a){this.isSaving=!1;var b="function"==typeof this.options.success?this.options.success.call(this.options.scope,a,c):null;return b===!1?(this.error(!1),this.showForm(!1),void 0):"string"==typeof b?(this.error(b),this.showForm(),void 0):(b&&"object"==typeof b&&b.hasOwnProperty("newValue")&&(c=b.newValue),this.error(!1),this.value=c,this.$div.triggerHandler("save",{newValue:c,submitValue:e,response:a}),void 0)},this)).fail(a.proxy(function(a){this.isSaving=!1;var b;b="function"==typeof this.options.error?this.options.error.call(this.options.scope,a,c):"string"==typeof a?a:a.responseText||a.statusText||"Unknown error!",this.error(b),this.showForm()},this))},save:function(b){this.options.pk=a.fn.editableutils.tryParseJson(this.options.pk,!0);var c,d="function"==typeof this.options.pk?this.options.pk.call(this.options.scope):this.options.pk,e=!!("function"==typeof this.options.url||this.options.url&&("always"===this.options.send||"auto"===this.options.send&&null!==d&&void 0!==d));return e?(this.showLoading(),c={name:this.options.name||"",value:b,pk:d},"function"==typeof this.options.params?c=this.options.params.call(this.options.scope,c):(this.options.params=a.fn.editableutils.tryParseJson(this.options.params,!0),a.extend(c,this.options.params)),"function"==typeof this.options.url?this.options.url.call(this.options.scope,c):a.ajax(a.extend({url:this.options.url,data:c,type:"POST"},this.options.ajaxOptions))):void 0},validate:function(a){return void 0===a&&(a=this.value),"function"==typeof this.options.validate?this.options.validate.call(this.options.scope,a):void 0},option:function(a,b){a in this.options&&(this.options[a]=b),"value"===a&&this.setValue(b)},setValue:function(a,b){this.value=b?this.input.str2value(a):a,this.$form&&this.$form.is(":visible")&&this.input.value2input(this.value)}},a.fn.editableform=function(c){var d=arguments;return this.each(function(){var e=a(this),f=e.data("editableform"),g="object"==typeof c&&c;f||e.data("editableform",f=new b(this,g)),"string"==typeof c&&f[c].apply(f,Array.prototype.slice.call(d,1))})},a.fn.editableform.Constructor=b,a.fn.editableform.defaults={type:"text",url:null,params:null,name:null,pk:null,value:null,defaultValue:null,send:"auto",validate:null,success:null,error:null,ajaxOptions:null,showbuttons:!0,scope:null,savenochange:!1},a.fn.editableform.template='<form class="form-inline editableform"><div class="control-group"><div><div class="editable-input"></div><div class="editable-buttons"></div></div><div class="editable-error-block"></div></div></form>',a.fn.editableform.loading='<div class="editableform-loading"></div>',a.fn.editableform.buttons='<button type="submit" class="editable-submit">ok</button><button type="button" class="editable-cancel">cancel</button>',a.fn.editableform.errorGroupClass=null,a.fn.editableform.errorBlockClass="editable-error",a.fn.editableform.engine="jquery"}(window.jQuery),function(a){"use strict";a.fn.editableutils={inherit:function(a,b){var c=function(){};c.prototype=b.prototype,a.prototype=new c,a.prototype.constructor=a,a.superclass=b.prototype},setCursorPosition:function(a,b){if(a.setSelectionRange)a.setSelectionRange(b,b);else if(a.createTextRange){var c=a.createTextRange();c.collapse(!0),c.moveEnd("character",b),c.moveStart("character",b),c.select()}},tryParseJson:function(a,b){if("string"==typeof a&&a.length&&a.match(/^[\{\[].*[\}\]]$/))if(b)try{a=new Function("return "+a)()}catch(c){}finally{return a}else a=new Function("return "+a)();return a},sliceObj:function(b,c,d){var e,f,g={};if(!a.isArray(c)||!c.length)return g;for(var h=0;h<c.length;h++)e=c[h],b.hasOwnProperty(e)&&(g[e]=b[e]),d!==!0&&(f=e.toLowerCase(),b.hasOwnProperty(f)&&(g[e]=b[f]));return g},getConfigData:function(b){var c={};return a.each(b.data(),function(a,b){("object"!=typeof b||b&&"object"==typeof b&&(b.constructor===Object||b.constructor===Array))&&(c[a]=b)}),c},objectKeys:function(a){if(Object.keys)return Object.keys(a);if(a!==Object(a))throw new TypeError("Object.keys called on a non-object");var b,c=[];for(b in a)Object.prototype.hasOwnProperty.call(a,b)&&c.push(b);return c},escape:function(b){return a("<div>").text(b).html()},itemsByValue:function(b,c,d){if(!c||null===b)return[];if("function"!=typeof d){var e=d||"value";d=function(a){return a[e]}}var f=a.isArray(b),g=[],h=this;return a.each(c,function(c,e){if(e.children)g=g.concat(h.itemsByValue(b,e.children,d));else if(f)a.grep(b,function(a){return a==(e&&"object"==typeof e?d(e):e)}).length&&g.push(e);else{var i=e&&"object"==typeof e?d(e):e;b==i&&g.push(e)}}),g},createInput:function(b){var c,d,e,f=b.type;return"date"===f&&("inline"===b.mode?a.fn.editabletypes.datefield?f="datefield":a.fn.editabletypes.dateuifield&&(f="dateuifield"):a.fn.editabletypes.date?f="date":a.fn.editabletypes.dateui&&(f="dateui"),"date"!==f||a.fn.editabletypes.date||(f="combodate")),"datetime"===f&&"inline"===b.mode&&(f="datetimefield"),"wysihtml5"!==f||a.fn.editabletypes[f]||(f="textarea"),"function"==typeof a.fn.editabletypes[f]?(c=a.fn.editabletypes[f],d=this.sliceObj(b,this.objectKeys(c.defaults)),e=new c(d)):(a.error("Unknown type: "+f),!1)},supportsTransitions:function(){var a=document.body||document.documentElement,b=a.style,c="transition",d=["Moz","Webkit","Khtml","O","ms"];if("string"==typeof b[c])return!0;c=c.charAt(0).toUpperCase()+c.substr(1);for(var e=0;e<d.length;e++)if("string"==typeof b[d[e]+c])return!0;return!1}}}(window.jQuery),function(a){"use strict";var b=function(a,b){this.init(a,b)},c=function(a,b){this.init(a,b)};b.prototype={containerName:null,containerDataName:null,innerCss:null,containerClass:"editable-container editable-popup",defaults:{},init:function(c,d){this.$element=a(c),this.options=a.extend({},a.fn.editableContainer.defaults,d),this.splitOptions(),this.formOptions.scope=this.$element[0],this.initContainer(),this.delayedHide=!1,this.$element.on("destroyed",a.proxy(function(){this.destroy()},this)),a(document).data("editable-handlers-attached")||(a(document).on("keyup.editable",function(b){27===b.which&&a(".editable-open").editableContainer("hide")}),a(document).on("click.editable",function(c){var d,e=a(c.target),f=[".editable-container",".ui-datepicker-header",".datepicker",".modal-backdrop",".bootstrap-wysihtml5-insert-image-modal",".bootstrap-wysihtml5-insert-link-modal"];if(a.contains(document.documentElement,c.target)&&!e.is(document)){for(d=0;d<f.length;d++)if(e.is(f[d])||e.parents(f[d]).length)return;b.prototype.closeOthers(c.target)}}),a(document).data("editable-handlers-attached",!0))},splitOptions:function(){if(this.containerOptions={},this.formOptions={},!a.fn[this.containerName])throw new Error(this.containerName+" not found. Have you included corresponding js file?");for(var b in this.options)b in this.defaults?this.containerOptions[b]=this.options[b]:this.formOptions[b]=this.options[b]},tip:function(){return this.container()?this.container().$tip:null},container:function(){var a;return this.containerDataName&&(a=this.$element.data(this.containerDataName))?a:a=this.$element.data(this.containerName)},call:function(){this.$element[this.containerName].apply(this.$element,arguments)},initContainer:function(){this.call(this.containerOptions)},renderForm:function(){this.$form.editableform(this.formOptions).on({save:a.proxy(this.save,this),nochange:a.proxy(function(){this.hide("nochange")},this),cancel:a.proxy(function(){this.hide("cancel")},this),show:a.proxy(function(){this.delayedHide?(this.hide(this.delayedHide.reason),this.delayedHide=!1):this.setPosition()},this),rendering:a.proxy(this.setPosition,this),resize:a.proxy(this.setPosition,this),rendered:a.proxy(function(){this.$element.triggerHandler("shown",a(this.options.scope).data("editable"))},this)}).editableform("render")},show:function(b){this.$element.addClass("editable-open"),b!==!1&&this.closeOthers(this.$element[0]),this.innerShow(),this.tip().addClass(this.containerClass),this.$form,this.$form=a("<div>"),this.tip().is(this.innerCss)?this.tip().append(this.$form):this.tip().find(this.innerCss).append(this.$form),this.renderForm()},hide:function(a){if(this.tip()&&this.tip().is(":visible")&&this.$element.hasClass("editable-open")){if(this.$form.data("editableform").isSaving)return this.delayedHide={reason:a},void 0;this.delayedHide=!1,this.$element.removeClass("editable-open"),this.innerHide(),this.$element.triggerHandler("hidden",a||"manual")}},innerShow:function(){},innerHide:function(){},toggle:function(a){this.container()&&this.tip()&&this.tip().is(":visible")?this.hide():this.show(a)},setPosition:function(){},save:function(a,b){this.$element.triggerHandler("save",b),this.hide("save")},option:function(a,b){this.options[a]=b,a in this.containerOptions?(this.containerOptions[a]=b,this.setContainerOption(a,b)):(this.formOptions[a]=b,this.$form&&this.$form.editableform("option",a,b))},setContainerOption:function(a,b){this.call("option",a,b)},destroy:function(){this.hide(),this.innerDestroy(),this.$element.off("destroyed"),this.$element.removeData("editableContainer")},innerDestroy:function(){},closeOthers:function(b){a(".editable-open").each(function(c,d){if(d!==b&&!a(d).find(b).length){var e=a(d),f=e.data("editableContainer");f&&("cancel"===f.options.onblur?e.data("editableContainer").hide("onblur"):"submit"===f.options.onblur&&e.data("editableContainer").tip().find("form").submit())}})},activate:function(){this.tip&&this.tip().is(":visible")&&this.$form&&this.$form.data("editableform").input.activate()}},a.fn.editableContainer=function(d){var e=arguments;return this.each(function(){var f=a(this),g="editableContainer",h=f.data(g),i="object"==typeof d&&d,j="inline"===i.mode?c:b;h||f.data(g,h=new j(this,i)),"string"==typeof d&&h[d].apply(h,Array.prototype.slice.call(e,1))})},a.fn.editableContainer.Popup=b,a.fn.editableContainer.Inline=c,a.fn.editableContainer.defaults={value:null,placement:"top",autohide:!0,onblur:"cancel",anim:!1,mode:"popup"},jQuery.event.special.destroyed={remove:function(a){a.handler&&a.handler()}}}(window.jQuery),function(a){"use strict";a.extend(a.fn.editableContainer.Inline.prototype,a.fn.editableContainer.Popup.prototype,{containerName:"editableform",innerCss:".editable-inline",containerClass:"editable-container editable-inline",initContainer:function(){this.$tip=a("<span></span>"),this.options.anim||(this.options.anim=0)},splitOptions:function(){this.containerOptions={},this.formOptions=this.options},tip:function(){return this.$tip},innerShow:function(){this.$element.hide(),this.tip().insertAfter(this.$element).show()},innerHide:function(){this.$tip.hide(this.options.anim,a.proxy(function(){this.$element.show(),this.innerDestroy()},this))},innerDestroy:function(){this.tip()&&this.tip().empty().remove()}})}(window.jQuery),function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.editable.defaults,c,a.fn.editableutils.getConfigData(this.$element)),this.options.selector?this.initLive():this.init(),this.options.highlight&&!a.fn.editableutils.supportsTransitions()&&(this.options.highlight=!1)};b.prototype={constructor:b,init:function(){var b,c=!1;if(this.options.name=this.options.name||this.$element.attr("id"),this.options.scope=this.$element[0],this.input=a.fn.editableutils.createInput(this.options),this.input){switch(void 0===this.options.value||null===this.options.value?(this.value=this.input.html2value(a.trim(this.$element.html())),c=!0):(this.options.value=a.fn.editableutils.tryParseJson(this.options.value,!0),this.value="string"==typeof this.options.value?this.input.str2value(this.options.value):this.options.value),this.$element.addClass("editable"),"textarea"===this.input.type&&this.$element.addClass("editable-pre-wrapped"),"manual"!==this.options.toggle?(this.$element.addClass("editable-click"),this.$element.on(this.options.toggle+".editable",a.proxy(function(a){if(this.options.disabled||a.preventDefault(),"mouseenter"===this.options.toggle)this.show();else{var b="click"!==this.options.toggle;this.toggle(b)}},this))):this.$element.attr("tabindex",-1),"function"==typeof this.options.display&&(this.options.autotext="always"),this.options.autotext){case"always":b=!0;break;case"auto":b=!a.trim(this.$element.text()).length&&null!==this.value&&void 0!==this.value&&!c;break;default:b=!1}a.when(b?this.render():!0).then(a.proxy(function(){this.options.disabled?this.disable():this.enable(),this.$element.triggerHandler("init",this)},this))}},initLive:function(){var b=this.options.selector;this.options.selector=!1,this.options.autotext="never",this.$element.on(this.options.toggle+".editable",b,a.proxy(function(b){var c=a(b.target);c.data("editable")||(c.hasClass(this.options.emptyclass)&&c.empty(),c.editable(this.options).trigger(b))},this))},render:function(a){return this.options.display!==!1?this.input.value2htmlFinal?this.input.value2html(this.value,this.$element[0],this.options.display,a):"function"==typeof this.options.display?this.options.display.call(this.$element[0],this.value,a):this.input.value2html(this.value,this.$element[0]):void 0},enable:function(){this.options.disabled=!1,this.$element.removeClass("editable-disabled"),this.handleEmpty(this.isEmpty),"manual"!==this.options.toggle&&"-1"===this.$element.attr("tabindex")&&this.$element.removeAttr("tabindex")},disable:function(){this.options.disabled=!0,this.hide(),this.$element.addClass("editable-disabled"),this.handleEmpty(this.isEmpty),this.$element.attr("tabindex",-1)},toggleDisabled:function(){this.options.disabled?this.enable():this.disable()},option:function(b,c){return b&&"object"==typeof b?(a.each(b,a.proxy(function(b,c){this.option(a.trim(b),c)},this)),void 0):(this.options[b]=c,"disabled"===b?c?this.disable():this.enable():("value"===b&&this.setValue(c),this.container&&this.container.option(b,c),this.input.option&&this.input.option(b,c),void 0))},handleEmpty:function(b){this.options.display!==!1&&(this.isEmpty=void 0!==b?b:"function"==typeof this.input.isEmpty?this.input.isEmpty(this.$element):""===a.trim(this.$element.html()),this.options.disabled?this.isEmpty&&(this.$element.empty(),this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass)):this.isEmpty?(this.$element.html(this.options.emptytext),this.options.emptyclass&&this.$element.addClass(this.options.emptyclass)):this.options.emptyclass&&this.$element.removeClass(this.options.emptyclass))},show:function(b){if(!this.options.disabled){if(this.container){if(this.container.tip().is(":visible"))return}else{var c=a.extend({},this.options,{value:this.value,input:this.input});this.$element.editableContainer(c),this.$element.on("save.internal",a.proxy(this.save,this)),this.container=this.$element.data("editableContainer")}this.container.show(b)}},hide:function(){this.container&&this.container.hide()},toggle:function(a){this.container&&this.container.tip().is(":visible")?this.hide():this.show(a)},save:function(a,b){if(this.options.unsavedclass){var c=!1;c=c||"function"==typeof this.options.url,c=c||this.options.display===!1,c=c||void 0!==b.response,c=c||this.options.savenochange&&this.input.value2str(this.value)!==this.input.value2str(b.newValue),c?this.$element.removeClass(this.options.unsavedclass):this.$element.addClass(this.options.unsavedclass)}if(this.options.highlight){var d=this.$element,e=d.css("background-color");d.css("background-color",this.options.highlight),setTimeout(function(){"transparent"===e&&(e=""),d.css("background-color",e),d.addClass("editable-bg-transition"),setTimeout(function(){d.removeClass("editable-bg-transition")},1700)},10)}this.setValue(b.newValue,!1,b.response)},validate:function(){return"function"==typeof this.options.validate?this.options.validate.call(this,this.value):void 0},setValue:function(b,c,d){this.value=c?this.input.str2value(b):b,this.container&&this.container.option("value",this.value),a.when(this.render(d)).then(a.proxy(function(){this.handleEmpty()},this))},activate:function(){this.container&&this.container.activate()},destroy:function(){this.disable(),this.container&&this.container.destroy(),this.input.destroy(),"manual"!==this.options.toggle&&(this.$element.removeClass("editable-click"),this.$element.off(this.options.toggle+".editable")),this.$element.off("save.internal"),this.$element.removeClass("editable editable-open editable-disabled"),this.$element.removeData("editable")}},a.fn.editable=function(c){var d={},e=arguments,f="editable";switch(c){case"validate":return this.each(function(){var b,c=a(this),e=c.data(f);e&&(b=e.validate())&&(d[e.options.name]=b)}),d;case"getValue":return 2===arguments.length&&arguments[1]===!0?d=this.eq(0).data(f).value:this.each(function(){var b=a(this),c=b.data(f);c&&void 0!==c.value&&null!==c.value&&(d[c.options.name]=c.input.value2submit(c.value))}),d;case"submit":var g=arguments[1]||{},h=this,i=this.editable("validate");if(a.isEmptyObject(i)){var j={};if(1===h.length){var k=h.data("editable"),l={name:k.options.name||"",value:k.input.value2submit(k.value),pk:"function"==typeof k.options.pk?k.options.pk.call(k.options.scope):k.options.pk};"function"==typeof k.options.params?l=k.options.params.call(k.options.scope,l):(k.options.params=a.fn.editableutils.tryParseJson(k.options.params,!0),a.extend(l,k.options.params)),j={url:k.options.url,data:l,type:"POST"},g.success=g.success||k.options.success,g.error=g.error||k.options.error}else{var m=this.editable("getValue");j={url:g.url,data:m,type:"POST"}}j.success="function"==typeof g.success?function(a){g.success.call(h,a,g)}:a.noop,j.error="function"==typeof g.error?function(){g.error.apply(h,arguments)}:a.noop,g.ajaxOptions&&a.extend(j,g.ajaxOptions),g.data&&a.extend(j.data,g.data),a.ajax(j)}else"function"==typeof g.error&&g.error.call(h,i);return this}return this.each(function(){var d=a(this),g=d.data(f),h="object"==typeof c&&c;return h&&h.selector?(g=new b(this,h),void 0):(g||d.data(f,g=new b(this,h)),"string"==typeof c&&g[c].apply(g,Array.prototype.slice.call(e,1)),void 0)})},a.fn.editable.defaults={type:"text",disabled:!1,toggle:"click",emptytext:"Empty",autotext:"auto",value:null,display:null,emptyclass:"editable-empty",unsavedclass:"editable-unsaved",selector:null,highlight:"#FFFF80"}}(window.jQuery),function(a){"use strict";a.fn.editabletypes={};var b=function(){};b.prototype={init:function(b,c,d){this.type=b,this.options=a.extend({},d,c)},prerender:function(){this.$tpl=a(this.options.tpl),this.$input=this.$tpl,this.$clear=null,this.error=null},render:function(){},value2html:function(b,c){a(c)[this.options.escape?"text":"html"](a.trim(b))},html2value:function(b){return a("<div>").html(b).text()},value2str:function(a){return a},str2value:function(a){return a},value2submit:function(a){return a},value2input:function(a){this.$input.val(a)},input2value:function(){return this.$input.val()},activate:function(){this.$input.is(":visible")&&this.$input.focus()},clear:function(){this.$input.val(null)},escape:function(b){return a("<div>").text(b).html()},autosubmit:function(){},destroy:function(){},setClass:function(){this.options.inputclass&&this.$input.addClass(this.options.inputclass)},setAttr:function(a){void 0!==this.options[a]&&null!==this.options[a]&&this.$input.attr(a,this.options[a])},option:function(a,b){this.options[a]=b}},b.defaults={tpl:"",inputclass:null,escape:!0,scope:null,showbuttons:!0},a.extend(a.fn.editabletypes,{abstractinput:b})}(window.jQuery),function(a){"use strict";var b=function(){};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){var b=a.Deferred();return this.error=null,this.onSourceReady(function(){this.renderList(),b.resolve()},function(){this.error=this.options.sourceError,b.resolve()}),b.promise()},html2value:function(){return null},value2html:function(b,c,d,e){var f=a.Deferred(),g=function(){"function"==typeof d?d.call(c,b,this.sourceData,e):this.value2htmlFinal(b,c),f.resolve()};return null===b?g.call(this):this.onSourceReady(g,function(){f.resolve()}),f.promise()},onSourceReady:function(b,c){var d;if(a.isFunction(this.options.source)?(d=this.options.source.call(this.options.scope),this.sourceData=null):d=this.options.source,this.options.sourceCache&&a.isArray(this.sourceData))return b.call(this),void 0;try{d=a.fn.editableutils.tryParseJson(d,!1)}catch(e){return c.call(this),void 0}if("string"==typeof d){if(this.options.sourceCache){var f,g=d;if(a(document).data(g)||a(document).data(g,{}),f=a(document).data(g),f.loading===!1&&f.sourceData)return this.sourceData=f.sourceData,this.doPrepend(),b.call(this),void 0;if(f.loading===!0)return f.callbacks.push(a.proxy(function(){this.sourceData=f.sourceData,this.doPrepend(),b.call(this)},this)),f.err_callbacks.push(a.proxy(c,this)),void 0;f.loading=!0,f.callbacks=[],f.err_callbacks=[]}var h=a.extend({url:d,type:"get",cache:!1,dataType:"json",success:a.proxy(function(d){f&&(f.loading=!1),this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(f&&(f.sourceData=this.sourceData,a.each(f.callbacks,function(){this.call()})),this.doPrepend(),b.call(this)):(c.call(this),f&&a.each(f.err_callbacks,function(){this.call()}))},this),error:a.proxy(function(){c.call(this),f&&(f.loading=!1,a.each(f.err_callbacks,function(){this.call()}))},this)},this.options.sourceOptions);a.ajax(h)}else this.sourceData=this.makeArray(d),a.isArray(this.sourceData)?(this.doPrepend(),b.call(this)):c.call(this)},doPrepend:function(){null!==this.options.prepend&&void 0!==this.options.prepend&&(a.isArray(this.prependData)||(a.isFunction(this.options.prepend)&&(this.options.prepend=this.options.prepend.call(this.options.scope)),this.options.prepend=a.fn.editableutils.tryParseJson(this.options.prepend,!0),"string"==typeof this.options.prepend&&(this.options.prepend={"":this.options.prepend}),this.prependData=this.makeArray(this.options.prepend)),a.isArray(this.prependData)&&a.isArray(this.sourceData)&&(this.sourceData=this.prependData.concat(this.sourceData)))},renderList:function(){},value2htmlFinal:function(){},makeArray:function(b){var c,d,e,f,g=[];if(!b||"string"==typeof b)return null;if(a.isArray(b)){f=function(a,b){return d={value:a,text:b},c++>=2?!1:void 0};for(var h=0;h<b.length;h++)e=b[h],"object"==typeof e?(c=0,a.each(e,f),1===c?g.push(d):c>1&&(e.children&&(e.children=this.makeArray(e.children)),g.push(e))):g.push({value:e,text:e})}else a.each(b,function(a,b){g.push({value:a,text:b})});return g},option:function(a,b){this.options[a]=b,"source"===a&&(this.sourceData=null),"prepend"===a&&(this.prependData=null)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{source:null,prepend:!1,sourceError:"Error when loading list",sourceCache:!0,sourceOptions:null}),a.fn.editabletypes.list=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("text",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.renderClear(),this.setClass(),this.setAttr("placeholder")},activate:function(){this.$input.is(":visible")&&(this.$input.focus(),a.fn.editableutils.setCursorPosition(this.$input.get(0),this.$input.val().length),this.toggleClear&&this.toggleClear())},renderClear:function(){this.options.clear&&(this.$clear=a('<span class="editable-clear-x"></span>'),this.$input.after(this.$clear).css("padding-right",24).keyup(a.proxy(function(b){if(!~a.inArray(b.keyCode,[40,38,9,13,27])){clearTimeout(this.t);var c=this;this.t=setTimeout(function(){c.toggleClear(b)},100)}},this)).parent().css("position","relative"),this.$clear.click(a.proxy(this.clear,this)))},postrender:function(){},toggleClear:function(){if(this.$clear){var a=this.$input.val().length,b=this.$clear.is(":visible");a&&!b&&this.$clear.show(),!a&&b&&this.$clear.hide()}},clear:function(){this.$clear.hide(),this.$input.val("").focus()}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'<input type="text">',placeholder:null,clear:!0}),a.fn.editabletypes.text=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("textarea",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.setClass(),this.setAttr("placeholder"),this.setAttr("rows"),this.$input.keydown(function(b){b.ctrlKey&&13===b.which&&a(this).closest("form").submit()})},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:"<textarea></textarea>",inputclass:"input-large",placeholder:null,rows:7}),a.fn.editabletypes.textarea=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("select",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.list),a.extend(b.prototype,{renderList:function(){this.$input.empty();var b=function(c,d){var e;if(a.isArray(d))for(var f=0;f<d.length;f++)e={},d[f].children?(e.label=d[f].text,c.append(b(a("<optgroup>",e),d[f].children))):(e.value=d[f].value,d[f].disabled&&(e.disabled=!0),c.append(a("<option>",e).text(d[f].text)));return c};b(this.$input,this.sourceData),this.setClass(),this.$input.on("keydown.editable",function(b){13===b.which&&a(this).closest("form").submit()})},value2htmlFinal:function(b,c){var d="",e=a.fn.editableutils.itemsByValue(b,this.sourceData);e.length&&(d=e[0].text),a.fn.editabletypes.abstractinput.prototype.value2html.call(this,d,c)},autosubmit:function(){this.$input.off("keydown.editable").on("change.editable",function(){a(this).closest("form").submit()})}}),b.defaults=a.extend({},a.fn.editabletypes.list.defaults,{tpl:"<select></select>"}),a.fn.editabletypes.select=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("checklist",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.list),a.extend(b.prototype,{renderList:function(){var b;if(this.$tpl.empty(),a.isArray(this.sourceData)){for(var c=0;c<this.sourceData.length;c++)b=a("<label>").append(a("<input>",{type:"checkbox",value:this.sourceData[c].value})).append(a("<span>").text(" "+this.sourceData[c].text)),a("<div>").append(b).appendTo(this.$tpl);this.$input=this.$tpl.find('input[type="checkbox"]'),this.setClass()}},value2str:function(b){return a.isArray(b)?b.sort().join(a.trim(this.options.separator)):""},str2value:function(b){var c,d=null;return"string"==typeof b&&b.length?(c=new RegExp("\\s*"+a.trim(this.options.separator)+"\\s*"),d=b.split(c)):d=a.isArray(b)?b:[b],d},value2input:function(b){this.$input.prop("checked",!1),a.isArray(b)&&b.length&&this.$input.each(function(c,d){var e=a(d);a.each(b,function(a,b){e.val()==b&&e.prop("checked",!0)})})},input2value:function(){var b=[];return this.$input.filter(":checked").each(function(c,d){b.push(a(d).val())}),b},value2htmlFinal:function(b,c){var d=[],e=a.fn.editableutils.itemsByValue(b,this.sourceData),f=this.options.escape;e.length?(a.each(e,function(b,c){var e=f?a.fn.editableutils.escape(c.text):c.text;d.push(e)}),a(c).html(d.join("<br>"))):a(c).empty()},activate:function(){this.$input.first().focus()},autosubmit:function(){this.$input.on("keydown",function(b){13===b.which&&a(this).closest("form").submit()})}}),b.defaults=a.extend({},a.fn.editabletypes.list.defaults,{tpl:'<div class="editable-checklist"></div>',inputclass:null,separator:","}),a.fn.editabletypes.checklist=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("password",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.text),a.extend(b.prototype,{value2html:function(b,c){b?a(c).text("[hidden]"):a(c).empty()},html2value:function(){return null}}),b.defaults=a.extend({},a.fn.editabletypes.text.defaults,{tpl:'<input type="password">'}),a.fn.editabletypes.password=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("email",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.text),b.defaults=a.extend({},a.fn.editabletypes.text.defaults,{tpl:'<input type="email">'}),a.fn.editabletypes.email=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("url",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.text),b.defaults=a.extend({},a.fn.editabletypes.text.defaults,{tpl:'<input type="url">'}),a.fn.editabletypes.url=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("tel",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.text),b.defaults=a.extend({},a.fn.editabletypes.text.defaults,{tpl:'<input type="tel">'}),a.fn.editabletypes.tel=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("number",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.text),a.extend(b.prototype,{render:function(){b.superclass.render.call(this),this.setAttr("min"),this.setAttr("max"),this.setAttr("step")},postrender:function(){this.$clear&&this.$clear.css({right:24})}}),b.defaults=a.extend({},a.fn.editabletypes.text.defaults,{tpl:'<input type="number">',inputclass:"input-mini",min:null,max:null,step:null}),a.fn.editabletypes.number=b}(window.jQuery),function(a){"use strict";
6
- var b=function(a){this.init("range",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.number),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.filter("input"),this.setClass(),this.setAttr("min"),this.setAttr("max"),this.setAttr("step"),this.$input.on("input",function(){a(this).siblings("output").text(a(this).val())})},activate:function(){this.$input.focus()}}),b.defaults=a.extend({},a.fn.editabletypes.number.defaults,{tpl:'<input type="range"><output style="width: 30px; display: inline-block"></output>',inputclass:"input-medium"}),a.fn.editabletypes.range=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("time",a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.setClass()}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'<input type="time">'}),a.fn.editabletypes.time=b}(window.jQuery),function(a){"use strict";var b=function(c){if(this.init("select2",c,b.defaults),c.select2=c.select2||{},this.sourceData=null,c.placeholder&&(c.select2.placeholder=c.placeholder),!c.select2.tags&&c.source){var d=c.source;a.isFunction(c.source)&&(d=c.source.call(c.scope)),"string"==typeof d?(c.select2.ajax=c.select2.ajax||{},c.select2.ajax.data||(c.select2.ajax.data=function(a){return{query:a}}),c.select2.ajax.results||(c.select2.ajax.results=function(a){return{results:a}}),c.select2.ajax.url=d):(this.sourceData=this.convertSource(d),c.select2.data=this.sourceData)}if(this.options.select2=a.extend({},b.defaults.select2,c.select2),this.isMultiple=this.options.select2.tags||this.options.select2.multiple,this.isRemote="ajax"in this.options.select2,this.idFunc=this.options.select2.id,"function"!=typeof this.idFunc){var e=this.idFunc||"id";this.idFunc=function(a){return a[e]}}this.formatSelection=this.options.select2.formatSelection,"function"!=typeof this.formatSelection&&(this.formatSelection=function(a){return a.text})};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.setClass(),this.isRemote&&this.$input.on("select2-loaded",a.proxy(function(a){this.sourceData=a.items.results},this)),this.isMultiple&&this.$input.on("change",function(){a(this).closest("form").parent().triggerHandler("resize")})},value2html:function(c,d){var e,f="",g=this;this.options.select2.tags?e=c:this.sourceData&&(e=a.fn.editableutils.itemsByValue(c,this.sourceData,this.idFunc)),a.isArray(e)?(f=[],a.each(e,function(a,b){f.push(b&&"object"==typeof b?g.formatSelection(b):b)})):e&&(f=g.formatSelection(e)),f=a.isArray(f)?f.join(this.options.viewseparator):f,b.superclass.value2html.call(this,f,d)},html2value:function(a){return this.options.select2.tags?this.str2value(a,this.options.viewseparator):null},value2input:function(b){if(a.isArray(b)&&(b=b.join(this.getSeparator())),this.$input.data("select2")?this.$input.val(b).trigger("change",!0):(this.$input.val(b),this.$input.select2(this.options.select2)),this.isRemote&&!this.isMultiple&&!this.options.select2.initSelection){var c=this.options.select2.id,d=this.options.select2.formatSelection;if(!c&&!d){var e=a(this.options.scope);if(!e.data("editable").isEmpty){var f={id:b,text:e.text()};this.$input.select2("data",f)}}}},input2value:function(){return this.$input.select2("val")},str2value:function(b,c){if("string"!=typeof b||!this.isMultiple)return b;c=c||this.getSeparator();var d,e,f;if(null===b||b.length<1)return null;for(d=b.split(c),e=0,f=d.length;f>e;e+=1)d[e]=a.trim(d[e]);return d},autosubmit:function(){this.$input.on("change",function(b,c){c||a(this).closest("form").submit()})},getSeparator:function(){return this.options.select2.separator||a.fn.select2.defaults.separator},convertSource:function(b){if(a.isArray(b)&&b.length&&void 0!==b[0].value)for(var c=0;c<b.length;c++)void 0!==b[c].value&&(b[c].id=b[c].value,delete b[c].value);return b},destroy:function(){this.$input.data("select2")&&this.$input.select2("destroy")}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'<input type="hidden">',select2:null,placeholder:null,source:null,viewseparator:", "}),a.fn.editabletypes.select2=b}(window.jQuery),function(a){var b=function(b,c){return this.$element=a(b),this.$element.is("input")?(this.options=a.extend({},a.fn.combodate.defaults,c,this.$element.data()),this.init(),void 0):(a.error("Combodate should be applied to INPUT element"),void 0)};b.prototype={constructor:b,init:function(){this.map={day:["D","date"],month:["M","month"],year:["Y","year"],hour:["[Hh]","hours"],minute:["m","minutes"],second:["s","seconds"],ampm:["[Aa]",""]},this.$widget=a('<span class="combodate"></span>').html(this.getTemplate()),this.initCombos(),this.$widget.on("change","select",a.proxy(function(b){this.$element.val(this.getValue()).change(),this.options.smartDays&&(a(b.target).is(".month")||a(b.target).is(".year"))&&this.fillCombo("day")},this)),this.$widget.find("select").css("width","auto"),this.$element.hide().after(this.$widget),this.setValue(this.$element.val()||this.options.value)},getTemplate:function(){var b=this.options.template;return a.each(this.map,function(a,c){c=c[0];var d=new RegExp(c+"+"),e=c.length>1?c.substring(1,2):c;b=b.replace(d,"{"+e+"}")}),b=b.replace(/ /g,"&nbsp;"),a.each(this.map,function(a,c){c=c[0];var d=c.length>1?c.substring(1,2):c;b=b.replace("{"+d+"}",'<select class="'+a+'"></select>')}),b},initCombos:function(){for(var a in this.map){var b=this.$widget.find("."+a);this["$"+a]=b.length?b:null,this.fillCombo(a)}},fillCombo:function(a){var b=this["$"+a];if(b){var c="fill"+a.charAt(0).toUpperCase()+a.slice(1),d=this[c](),e=b.val();b.empty();for(var f=0;f<d.length;f++)b.append('<option value="'+d[f][0]+'">'+d[f][1]+"</option>");b.val(e)}},fillCommon:function(a){var b,c=[];if("name"===this.options.firstItem){b=moment.relativeTime||moment.langData()._relativeTime;var d="function"==typeof b[a]?b[a](1,!0,a,!1):b[a];d=d.split(" ").reverse()[0],c.push(["",d])}else"empty"===this.options.firstItem&&c.push(["",""]);return c},fillDay:function(){var a,b,c=this.fillCommon("d"),d=-1!==this.options.template.indexOf("DD"),e=31;if(this.options.smartDays&&this.$month&&this.$year){var f=parseInt(this.$month.val(),10),g=parseInt(this.$year.val(),10);isNaN(f)||isNaN(g)||(e=moment([g,f]).daysInMonth())}for(b=1;e>=b;b++)a=d?this.leadZero(b):b,c.push([b,a]);return c},fillMonth:function(){var a,b,c=this.fillCommon("M"),d=-1!==this.options.template.indexOf("MMMM"),e=-1!==this.options.template.indexOf("MMM"),f=-1!==this.options.template.indexOf("MM");for(b=0;11>=b;b++)a=d?moment().date(1).month(b).format("MMMM"):e?moment().date(1).month(b).format("MMM"):f?this.leadZero(b+1):b+1,c.push([b,a]);return c},fillYear:function(){var a,b,c=[],d=-1!==this.options.template.indexOf("YYYY");for(b=this.options.maxYear;b>=this.options.minYear;b--)a=d?b:(b+"").substring(2),c[this.options.yearDescending?"push":"unshift"]([b,a]);return c=this.fillCommon("y").concat(c)},fillHour:function(){var a,b,c=this.fillCommon("h"),d=-1!==this.options.template.indexOf("h"),e=(-1!==this.options.template.indexOf("H"),-1!==this.options.template.toLowerCase().indexOf("hh")),f=d?1:0,g=d?12:23;for(b=f;g>=b;b++)a=e?this.leadZero(b):b,c.push([b,a]);return c},fillMinute:function(){var a,b,c=this.fillCommon("m"),d=-1!==this.options.template.indexOf("mm");for(b=0;59>=b;b+=this.options.minuteStep)a=d?this.leadZero(b):b,c.push([b,a]);return c},fillSecond:function(){var a,b,c=this.fillCommon("s"),d=-1!==this.options.template.indexOf("ss");for(b=0;59>=b;b+=this.options.secondStep)a=d?this.leadZero(b):b,c.push([b,a]);return c},fillAmpm:function(){var a=-1!==this.options.template.indexOf("a"),b=(-1!==this.options.template.indexOf("A"),[["am",a?"am":"AM"],["pm",a?"pm":"PM"]]);return b},getValue:function(b){var c,d={},e=this,f=!1;return a.each(this.map,function(a){if("ampm"!==a){var b="day"===a?1:0;return d[a]=e["$"+a]?parseInt(e["$"+a].val(),10):b,isNaN(d[a])?(f=!0,!1):void 0}}),f?"":(this.$ampm&&(d.hour=12===d.hour?"am"===this.$ampm.val()?0:12:"am"===this.$ampm.val()?d.hour:d.hour+12),c=moment([d.year,d.month,d.day,d.hour,d.minute,d.second]),this.highlight(c),b=void 0===b?this.options.format:b,null===b?c.isValid()?c:null:c.isValid()?c.format(b):"")},setValue:function(b){function c(b,c){var d={};return b.children("option").each(function(b,e){var f,g=a(e).attr("value");""!==g&&(f=Math.abs(g-c),("undefined"==typeof d.distance||f<d.distance)&&(d={value:g,distance:f}))}),d.value}if(b){var d="string"==typeof b?moment(b,this.options.format):moment(b),e=this,f={};d.isValid()&&(a.each(this.map,function(a,b){"ampm"!==a&&(f[a]=d[b[1]]())}),this.$ampm&&(f.hour>=12?(f.ampm="pm",f.hour>12&&(f.hour-=12)):(f.ampm="am",0===f.hour&&(f.hour=12))),a.each(f,function(a,b){e["$"+a]&&("minute"===a&&e.options.minuteStep>1&&e.options.roundTime&&(b=c(e["$"+a],b)),"second"===a&&e.options.secondStep>1&&e.options.roundTime&&(b=c(e["$"+a],b)),e["$"+a].val(b))}),this.options.smartDays&&this.fillCombo("day"),this.$element.val(d.format(this.options.format)).change())}},highlight:function(a){a.isValid()?this.options.errorClass?this.$widget.removeClass(this.options.errorClass):this.$widget.find("select").css("border-color",this.borderColor):this.options.errorClass?this.$widget.addClass(this.options.errorClass):(this.borderColor||(this.borderColor=this.$widget.find("select").css("border-color")),this.$widget.find("select").css("border-color","red"))},leadZero:function(a){return 9>=a?"0"+a:a},destroy:function(){this.$widget.remove(),this.$element.removeData("combodate").show()}},a.fn.combodate=function(c){var d,e=Array.apply(null,arguments);return e.shift(),"getValue"===c&&this.length&&(d=this.eq(0).data("combodate"))?d.getValue.apply(d,e):this.each(function(){var d=a(this),f=d.data("combodate"),g="object"==typeof c&&c;f||d.data("combodate",f=new b(this,g)),"string"==typeof c&&"function"==typeof f[c]&&f[c].apply(f,e)})},a.fn.combodate.defaults={format:"DD-MM-YYYY HH:mm",template:"D / MMM / YYYY H : mm",value:null,minYear:1970,maxYear:2015,yearDescending:!0,minuteStep:5,secondStep:1,firstItem:"empty",errorClass:null,roundTime:!0,smartDays:!1}}(window.jQuery),function(a){"use strict";var b=function(c){this.init("combodate",c,b.defaults),this.options.viewformat||(this.options.viewformat=this.options.format),c.combodate=a.fn.editableutils.tryParseJson(c.combodate,!0),this.options.combodate=a.extend({},b.defaults.combodate,c.combodate,{format:this.options.format,template:this.options.template})};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{render:function(){this.$input.combodate(this.options.combodate),"bs3"===a.fn.editableform.engine&&this.$input.siblings().find("select").addClass("form-control"),this.options.inputclass&&this.$input.siblings().find("select").addClass(this.options.inputclass)},value2html:function(a,c){var d=a?a.format(this.options.viewformat):"";b.superclass.value2html.call(this,d,c)},html2value:function(a){return a?moment(a,this.options.viewformat):null},value2str:function(a){return a?a.format(this.options.format):""},str2value:function(a){return a?moment(a,this.options.format):null},value2submit:function(a){return this.value2str(a)},value2input:function(a){this.$input.combodate("setValue",a)},input2value:function(){return this.$input.combodate("getValue",null)},activate:function(){this.$input.siblings(".combodate").find("select").eq(0).focus()},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'<input type="text">',inputclass:null,format:"YYYY-MM-DD",viewformat:null,template:"D / MMM / YYYY",combodate:null}),a.fn.editabletypes.combodate=b}(window.jQuery),function(a){"use strict";var b=a.fn.editableform.Constructor.prototype.initInput;a.extend(a.fn.editableform.Constructor.prototype,{initTemplate:function(){this.$form=a(a.fn.editableform.template),this.$form.find(".control-group").addClass("form-group"),this.$form.find(".editable-error-block").addClass("help-block")},initInput:function(){b.apply(this);var c=null===this.input.options.inputclass||this.input.options.inputclass===!1,d="input-sm",e="text,select,textarea,password,email,url,tel,number,range,time,typeaheadjs".split(",");~a.inArray(this.input.type,e)&&(this.input.$input.addClass("form-control"),c&&(this.input.options.inputclass=d,this.input.$input.addClass(d)));for(var f=this.$form.find(".editable-buttons"),g=c?[d]:this.input.options.inputclass.split(" "),h=0;h<g.length;h++)"input-lg"===g[h].toLowerCase()&&f.find("button").removeClass("btn-sm").addClass("btn-lg")}}),a.fn.editableform.buttons='<button type="submit" class="btn btn-primary btn-sm editable-submit"><i class="glyphicon glyphicon-ok"></i></button><button type="button" class="btn btn-default btn-sm editable-cancel"><i class="glyphicon glyphicon-remove"></i></button>',a.fn.editableform.errorGroupClass="has-error",a.fn.editableform.errorBlockClass=null,a.fn.editableform.engine="bs3"}(window.jQuery),function(a){"use strict";a.extend(a.fn.editableContainer.Popup.prototype,{containerName:"popover",containerDataName:"bs.popover",innerCss:".popover-content",defaults:a.fn.popover.Constructor.DEFAULTS,initContainer:function(){a.extend(this.containerOptions,{trigger:"manual",selector:!1,content:" ",template:this.defaults.template});var b;this.$element.data("template")&&(b=this.$element.data("template"),this.$element.removeData("template")),this.call(this.containerOptions),b&&this.$element.data("template",b)},innerShow:function(){this.call("show")},innerHide:function(){this.call("hide")},innerDestroy:function(){this.call("destroy")},setContainerOption:function(a,b){this.container().options[a]=b},setPosition:function(){!function(){var a=this.tip(),b="function"==typeof this.options.placement?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,c=/\s?auto?\s?/i,d=c.test(b);d&&(b=b.replace(c,"")||"top");var e=this.getPosition(),f=a[0].offsetWidth,g=a[0].offsetHeight;if(d){var h=this.$element.parent(),i=b,j=document.documentElement.scrollTop||document.body.scrollTop,k="body"==this.options.container?window.innerWidth:h.outerWidth(),l="body"==this.options.container?window.innerHeight:h.outerHeight(),m="body"==this.options.container?0:h.offset().left;b="bottom"==b&&e.top+e.height+g-j>l?"top":"top"==b&&e.top-j-g<0?"bottom":"right"==b&&e.right+f>k?"left":"left"==b&&e.left-f<m?"right":b,a.removeClass(i).addClass(b)}var n=this.getCalculatedOffset(b,e,f,g);this.applyPlacement(n,b)}.call(this.container())}})}(window.jQuery),function(a){function b(){return new Date(Date.UTC.apply(Date,arguments))}function c(b,c){var d,e=a(b).data(),f={},g=new RegExp("^"+c.toLowerCase()+"([A-Z])"),c=new RegExp("^"+c.toLowerCase());for(var h in e)c.test(h)&&(d=h.replace(g,function(a,b){return b.toLowerCase()}),f[d]=e[h]);return f}function d(b){var c={};if(k[b]||(b=b.split("-")[0],k[b])){var d=k[b];return a.each(j,function(a,b){b in d&&(c[b]=d[b])}),c}}var e=function(b,c){this._process_options(c),this.element=a(b),this.isInline=!1,this.isInput=this.element.is("input"),this.component=this.element.is(".date")?this.element.find(".add-on, .btn"):!1,this.hasInput=this.component&&this.element.find("input").length,this.component&&0===this.component.length&&(this.component=!1),this.picker=a(l.template),this._buildEvents(),this._attachEvents(),this.isInline?this.picker.addClass("datepicker-inline").appendTo(this.element):this.picker.addClass("datepicker-dropdown dropdown-menu"),this.o.rtl&&(this.picker.addClass("datepicker-rtl"),this.picker.find(".prev i, .next i").toggleClass("icon-arrow-left icon-arrow-right")),this.viewMode=this.o.startView,this.o.calendarWeeks&&this.picker.find("tfoot th.today").attr("colspan",function(a,b){return parseInt(b)+1}),this._allow_update=!1,this.setStartDate(this.o.startDate),this.setEndDate(this.o.endDate),this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled),this.fillDow(),this.fillMonths(),this._allow_update=!0,this.update(),this.showMode(),this.isInline&&this.show()};e.prototype={constructor:e,_process_options:function(b){this._o=a.extend({},this._o,b);var c=this.o=a.extend({},this._o),d=c.language;switch(k[d]||(d=d.split("-")[0],k[d]||(d=i.language)),c.language=d,c.startView){case 2:case"decade":c.startView=2;break;case 1:case"year":c.startView=1;break;default:c.startView=0}switch(c.minViewMode){case 1:case"months":c.minViewMode=1;break;case 2:case"years":c.minViewMode=2;break;default:c.minViewMode=0}c.startView=Math.max(c.startView,c.minViewMode),c.weekStart%=7,c.weekEnd=(c.weekStart+6)%7;var e=l.parseFormat(c.format);c.startDate!==-1/0&&(c.startDate=l.parseDate(c.startDate,e,c.language)),1/0!==c.endDate&&(c.endDate=l.parseDate(c.endDate,e,c.language)),c.daysOfWeekDisabled=c.daysOfWeekDisabled||[],a.isArray(c.daysOfWeekDisabled)||(c.daysOfWeekDisabled=c.daysOfWeekDisabled.split(/[,\s]*/)),c.daysOfWeekDisabled=a.map(c.daysOfWeekDisabled,function(a){return parseInt(a,10)})},_events:[],_secondaryEvents:[],_applyEvents:function(a){for(var b,c,d=0;d<a.length;d++)b=a[d][0],c=a[d][1],b.on(c)},_unapplyEvents:function(a){for(var b,c,d=0;d<a.length;d++)b=a[d][0],c=a[d][1],b.off(c)},_buildEvents:function(){this.isInput?this._events=[[this.element,{focus:a.proxy(this.show,this),keyup:a.proxy(this.update,this),keydown:a.proxy(this.keydown,this)}]]:this.component&&this.hasInput?this._events=[[this.element.find("input"),{focus:a.proxy(this.show,this),keyup:a.proxy(this.update,this),keydown:a.proxy(this.keydown,this)}],[this.component,{click:a.proxy(this.show,this)}]]:this.element.is("div")?this.isInline=!0:this._events=[[this.element,{click:a.proxy(this.show,this)}]],this._secondaryEvents=[[this.picker,{click:a.proxy(this.click,this)}],[a(window),{resize:a.proxy(this.place,this)}],[a(document),{mousedown:a.proxy(function(a){this.element.is(a.target)||this.element.find(a.target).size()||this.picker.is(a.target)||this.picker.find(a.target).size()||this.hide()},this)}]]},_attachEvents:function(){this._detachEvents(),this._applyEvents(this._events)},_detachEvents:function(){this._unapplyEvents(this._events)},_attachSecondaryEvents:function(){this._detachSecondaryEvents(),this._applyEvents(this._secondaryEvents)},_detachSecondaryEvents:function(){this._unapplyEvents(this._secondaryEvents)},_trigger:function(b,c){var d=c||this.date,e=new Date(d.getTime()+6e4*d.getTimezoneOffset());this.element.trigger({type:b,date:e,format:a.proxy(function(a){var b=a||this.o.format;return l.formatDate(d,b,this.o.language)},this)})},show:function(a){this.isInline||this.picker.appendTo("body"),this.picker.show(),this.height=this.component?this.component.outerHeight():this.element.outerHeight(),this.place(),this._attachSecondaryEvents(),a&&a.preventDefault(),this._trigger("show")},hide:function(){this.isInline||this.picker.is(":visible")&&(this.picker.hide().detach(),this._detachSecondaryEvents(),this.viewMode=this.o.startView,this.showMode(),this.o.forceParse&&(this.isInput&&this.element.val()||this.hasInput&&this.element.find("input").val())&&this.setValue(),this._trigger("hide"))},remove:function(){this.hide(),this._detachEvents(),this._detachSecondaryEvents(),this.picker.remove(),delete this.element.data().datepicker,this.isInput||delete this.element.data().date},getDate:function(){var a=this.getUTCDate();return new Date(a.getTime()+6e4*a.getTimezoneOffset())},getUTCDate:function(){return this.date},setDate:function(a){this.setUTCDate(new Date(a.getTime()-6e4*a.getTimezoneOffset()))},setUTCDate:function(a){this.date=a,this.setValue()},setValue:function(){var a=this.getFormattedDate();this.isInput?this.element.val(a):this.component&&this.element.find("input").val(a)},getFormattedDate:function(a){return void 0===a&&(a=this.o.format),l.formatDate(this.date,a,this.o.language)},setStartDate:function(a){this._process_options({startDate:a}),this.update(),this.updateNavArrows()},setEndDate:function(a){this._process_options({endDate:a}),this.update(),this.updateNavArrows()},setDaysOfWeekDisabled:function(a){this._process_options({daysOfWeekDisabled:a}),this.update(),this.updateNavArrows()},place:function(){if(!this.isInline){var b=parseInt(this.element.parents().filter(function(){return"auto"!=a(this).css("z-index")}).first().css("z-index"))+10,c=this.component?this.component.parent().offset():this.element.offset(),d=this.component?this.component.outerHeight(!0):this.element.outerHeight(!0);this.picker.css({top:c.top+d,left:c.left,zIndex:b})}},_allow_update:!0,update:function(){if(this._allow_update){var a,b=!1;arguments&&arguments.length&&("string"==typeof arguments[0]||arguments[0]instanceof Date)?(a=arguments[0],b=!0):(a=this.isInput?this.element.val():this.element.data("date")||this.element.find("input").val(),delete this.element.data().date),this.date=l.parseDate(a,this.o.format,this.o.language),b&&this.setValue(),this.viewDate=this.date<this.o.startDate?new Date(this.o.startDate):this.date>this.o.endDate?new Date(this.o.endDate):new Date(this.date),this.fill()}},fillDow:function(){var a=this.o.weekStart,b="<tr>";if(this.o.calendarWeeks){var c='<th class="cw">&nbsp;</th>';b+=c,this.picker.find(".datepicker-days thead tr:first-child").prepend(c)}for(;a<this.o.weekStart+7;)b+='<th class="dow">'+k[this.o.language].daysMin[a++%7]+"</th>";b+="</tr>",this.picker.find(".datepicker-days thead").append(b)},fillMonths:function(){for(var a="",b=0;12>b;)a+='<span class="month">'+k[this.o.language].monthsShort[b++]+"</span>";this.picker.find(".datepicker-months td").html(a)},setRange:function(b){b&&b.length?this.range=a.map(b,function(a){return a.valueOf()}):delete this.range,this.fill()},getClassNames:function(b){var c=[],d=this.viewDate.getUTCFullYear(),e=this.viewDate.getUTCMonth(),f=this.date.valueOf(),g=new Date;return b.getUTCFullYear()<d||b.getUTCFullYear()==d&&b.getUTCMonth()<e?c.push("old"):(b.getUTCFullYear()>d||b.getUTCFullYear()==d&&b.getUTCMonth()>e)&&c.push("new"),this.o.todayHighlight&&b.getUTCFullYear()==g.getFullYear()&&b.getUTCMonth()==g.getMonth()&&b.getUTCDate()==g.getDate()&&c.push("today"),f&&b.valueOf()==f&&c.push("active"),(b.valueOf()<this.o.startDate||b.valueOf()>this.o.endDate||-1!==a.inArray(b.getUTCDay(),this.o.daysOfWeekDisabled))&&c.push("disabled"),this.range&&(b>this.range[0]&&b<this.range[this.range.length-1]&&c.push("range"),-1!=a.inArray(b.valueOf(),this.range)&&c.push("selected")),c},fill:function(){var c,d=new Date(this.viewDate),e=d.getUTCFullYear(),f=d.getUTCMonth(),g=this.o.startDate!==-1/0?this.o.startDate.getUTCFullYear():-1/0,h=this.o.startDate!==-1/0?this.o.startDate.getUTCMonth():-1/0,i=1/0!==this.o.endDate?this.o.endDate.getUTCFullYear():1/0,j=1/0!==this.o.endDate?this.o.endDate.getUTCMonth():1/0;this.date&&this.date.valueOf(),this.picker.find(".datepicker-days thead th.datepicker-switch").text(k[this.o.language].months[f]+" "+e),this.picker.find("tfoot th.today").text(k[this.o.language].today).toggle(this.o.todayBtn!==!1),this.picker.find("tfoot th.clear").text(k[this.o.language].clear).toggle(this.o.clearBtn!==!1),this.updateNavArrows(),this.fillMonths();var m=b(e,f-1,28,0,0,0,0),n=l.getDaysInMonth(m.getUTCFullYear(),m.getUTCMonth());m.setUTCDate(n),m.setUTCDate(n-(m.getUTCDay()-this.o.weekStart+7)%7);var o=new Date(m);o.setUTCDate(o.getUTCDate()+42),o=o.valueOf();for(var p,q=[];m.valueOf()<o;){if(m.getUTCDay()==this.o.weekStart&&(q.push("<tr>"),this.o.calendarWeeks)){var r=new Date(+m+864e5*((this.o.weekStart-m.getUTCDay()-7)%7)),s=new Date(+r+864e5*((11-r.getUTCDay())%7)),t=new Date(+(t=b(s.getUTCFullYear(),0,1))+864e5*((11-t.getUTCDay())%7)),u=(s-t)/864e5/7+1;q.push('<td class="cw">'+u+"</td>")}p=this.getClassNames(m),p.push("day");var v=this.o.beforeShowDay(m);void 0===v?v={}:"boolean"==typeof v?v={enabled:v}:"string"==typeof v&&(v={classes:v}),v.enabled===!1&&p.push("disabled"),v.classes&&(p=p.concat(v.classes.split(/\s+/))),v.tooltip&&(c=v.tooltip),p=a.unique(p),q.push('<td class="'+p.join(" ")+'"'+(c?' title="'+c+'"':"")+">"+m.getUTCDate()+"</td>"),m.getUTCDay()==this.o.weekEnd&&q.push("</tr>"),m.setUTCDate(m.getUTCDate()+1)}this.picker.find(".datepicker-days tbody").empty().append(q.join(""));var w=this.date&&this.date.getUTCFullYear(),x=this.picker.find(".datepicker-months").find("th:eq(1)").text(e).end().find("span").removeClass("active");w&&w==e&&x.eq(this.date.getUTCMonth()).addClass("active"),(g>e||e>i)&&x.addClass("disabled"),e==g&&x.slice(0,h).addClass("disabled"),e==i&&x.slice(j+1).addClass("disabled"),q="",e=10*parseInt(e/10,10);var y=this.picker.find(".datepicker-years").find("th:eq(1)").text(e+"-"+(e+9)).end().find("td");e-=1;for(var z=-1;11>z;z++)q+='<span class="year'+(-1==z?" old":10==z?" new":"")+(w==e?" active":"")+(g>e||e>i?" disabled":"")+'">'+e+"</span>",e+=1;y.html(q)},updateNavArrows:function(){if(this._allow_update){var a=new Date(this.viewDate),b=a.getUTCFullYear(),c=a.getUTCMonth();switch(this.viewMode){case 0:this.o.startDate!==-1/0&&b<=this.o.startDate.getUTCFullYear()&&c<=this.o.startDate.getUTCMonth()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.o.endDate&&b>=this.o.endDate.getUTCFullYear()&&c>=this.o.endDate.getUTCMonth()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"});break;case 1:case 2:this.o.startDate!==-1/0&&b<=this.o.startDate.getUTCFullYear()?this.picker.find(".prev").css({visibility:"hidden"}):this.picker.find(".prev").css({visibility:"visible"}),1/0!==this.o.endDate&&b>=this.o.endDate.getUTCFullYear()?this.picker.find(".next").css({visibility:"hidden"}):this.picker.find(".next").css({visibility:"visible"})}}},click:function(c){c.preventDefault();var d=a(c.target).closest("span, td, th");if(1==d.length)switch(d[0].nodeName.toLowerCase()){case"th":switch(d[0].className){case"datepicker-switch":this.showMode(1);break;case"prev":case"next":var e=l.modes[this.viewMode].navStep*("prev"==d[0].className?-1:1);switch(this.viewMode){case 0:this.viewDate=this.moveMonth(this.viewDate,e);break;case 1:case 2:this.viewDate=this.moveYear(this.viewDate,e)}this.fill();break;case"today":var f=new Date;f=b(f.getFullYear(),f.getMonth(),f.getDate(),0,0,0),this.showMode(-2);var g="linked"==this.o.todayBtn?null:"view";this._setDate(f,g);break;case"clear":var h;this.isInput?h=this.element:this.component&&(h=this.element.find("input")),h&&h.val("").change(),this._trigger("changeDate"),this.update(),this.o.autoclose&&this.hide()}break;case"span":if(!d.is(".disabled")){if(this.viewDate.setUTCDate(1),d.is(".month")){var i=1,j=d.parent().find("span").index(d),k=this.viewDate.getUTCFullYear();this.viewDate.setUTCMonth(j),this._trigger("changeMonth",this.viewDate),1===this.o.minViewMode&&this._setDate(b(k,j,i,0,0,0,0))}else{var k=parseInt(d.text(),10)||0,i=1,j=0;this.viewDate.setUTCFullYear(k),this._trigger("changeYear",this.viewDate),2===this.o.minViewMode&&this._setDate(b(k,j,i,0,0,0,0))}this.showMode(-1),this.fill()}break;case"td":if(d.is(".day")&&!d.is(".disabled")){var i=parseInt(d.text(),10)||1,k=this.viewDate.getUTCFullYear(),j=this.viewDate.getUTCMonth();d.is(".old")?0===j?(j=11,k-=1):j-=1:d.is(".new")&&(11==j?(j=0,k+=1):j+=1),this._setDate(b(k,j,i,0,0,0,0))}}},_setDate:function(a,b){b&&"date"!=b||(this.date=new Date(a)),b&&"view"!=b||(this.viewDate=new Date(a)),this.fill(),this.setValue(),this._trigger("changeDate");var c;this.isInput?c=this.element:this.component&&(c=this.element.find("input")),c&&(c.change(),!this.o.autoclose||b&&"date"!=b||this.hide())},moveMonth:function(a,b){if(!b)return a;var c,d,e=new Date(a.valueOf()),f=e.getUTCDate(),g=e.getUTCMonth(),h=Math.abs(b);if(b=b>0?1:-1,1==h)d=-1==b?function(){return e.getUTCMonth()==g}:function(){return e.getUTCMonth()!=c},c=g+b,e.setUTCMonth(c),(0>c||c>11)&&(c=(c+12)%12);else{for(var i=0;h>i;i++)e=this.moveMonth(e,b);c=e.getUTCMonth(),e.setUTCDate(f),d=function(){return c!=e.getUTCMonth()}}for(;d();)e.setUTCDate(--f),e.setUTCMonth(c);return e},moveYear:function(a,b){return this.moveMonth(a,12*b)},dateWithinRange:function(a){return a>=this.o.startDate&&a<=this.o.endDate},keydown:function(a){if(this.picker.is(":not(:visible)"))return 27==a.keyCode&&this.show(),void 0;var b,c,d,e=!1;switch(a.keyCode){case 27:this.hide(),a.preventDefault();break;case 37:case 39:if(!this.o.keyboardNavigation)break;b=37==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date),c.setUTCDate(this.date.getUTCDate()+b),d=new Date(this.viewDate),d.setUTCDate(this.viewDate.getUTCDate()+b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 38:case 40:if(!this.o.keyboardNavigation)break;b=38==a.keyCode?-1:1,a.ctrlKey?(c=this.moveYear(this.date,b),d=this.moveYear(this.viewDate,b)):a.shiftKey?(c=this.moveMonth(this.date,b),d=this.moveMonth(this.viewDate,b)):(c=new Date(this.date),c.setUTCDate(this.date.getUTCDate()+7*b),d=new Date(this.viewDate),d.setUTCDate(this.viewDate.getUTCDate()+7*b)),this.dateWithinRange(c)&&(this.date=c,this.viewDate=d,this.setValue(),this.update(),a.preventDefault(),e=!0);break;case 13:this.hide(),a.preventDefault();break;case 9:this.hide()}if(e){this._trigger("changeDate");var f;this.isInput?f=this.element:this.component&&(f=this.element.find("input")),f&&f.change()}},showMode:function(a){a&&(this.viewMode=Math.max(this.o.minViewMode,Math.min(2,this.viewMode+a))),this.picker.find(">div").hide().filter(".datepicker-"+l.modes[this.viewMode].clsName).css("display","block"),this.updateNavArrows()}};var f=function(b,c){this.element=a(b),this.inputs=a.map(c.inputs,function(a){return a.jquery?a[0]:a}),delete c.inputs,a(this.inputs).datepicker(c).bind("changeDate",a.proxy(this.dateUpdated,this)),this.pickers=a.map(this.inputs,function(b){return a(b).data("datepicker")}),this.updateDates()};f.prototype={updateDates:function(){this.dates=a.map(this.pickers,function(a){return a.date}),this.updateRanges()},updateRanges:function(){var b=a.map(this.dates,function(a){return a.valueOf()});a.each(this.pickers,function(a,c){c.setRange(b)})},dateUpdated:function(b){var c=a(b.target).data("datepicker"),d=c.getUTCDate(),e=a.inArray(b.target,this.inputs),f=this.inputs.length;if(-1!=e){if(d<this.dates[e])for(;e>=0&&d<this.dates[e];)this.pickers[e--].setUTCDate(d);else if(d>this.dates[e])for(;f>e&&d>this.dates[e];)this.pickers[e++].setUTCDate(d);this.updateDates()}},remove:function(){a.map(this.pickers,function(a){a.remove()}),delete this.element.data().datepicker}};var g=a.fn.datepicker,h=a.fn.datepicker=function(b){var g=Array.apply(null,arguments);g.shift();var h;return this.each(function(){var j=a(this),k=j.data("datepicker"),l="object"==typeof b&&b;if(!k){var m=c(this,"date"),n=a.extend({},i,m,l),o=d(n.language),p=a.extend({},i,o,m,l);if(j.is(".input-daterange")||p.inputs){var q={inputs:p.inputs||j.find("input").toArray()};j.data("datepicker",k=new f(this,a.extend(p,q)))}else j.data("datepicker",k=new e(this,p))}return"string"==typeof b&&"function"==typeof k[b]&&(h=k[b].apply(k,g),void 0!==h)?!1:void 0}),void 0!==h?h:this},i=a.fn.datepicker.defaults={autoclose:!1,beforeShowDay:a.noop,calendarWeeks:!1,clearBtn:!1,daysOfWeekDisabled:[],endDate:1/0,forceParse:!0,format:"mm/dd/yyyy",keyboardNavigation:!0,language:"en",minViewMode:0,rtl:!1,startDate:-1/0,startView:0,todayBtn:!1,todayHighlight:!1,weekStart:0},j=a.fn.datepicker.locale_opts=["format","rtl","weekStart"];a.fn.datepicker.Constructor=e;var k=a.fn.datepicker.dates={en:{days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],daysShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"],daysMin:["Su","Mo","Tu","We","Th","Fr","Sa","Su"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],monthsShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],today:"Today",clear:"Clear"}},l={modes:[{clsName:"days",navFnc:"Month",navStep:1},{clsName:"months",navFnc:"FullYear",navStep:1},{clsName:"years",navFnc:"FullYear",navStep:10}],isLeapYear:function(a){return 0===a%4&&0!==a%100||0===a%400
7
- },getDaysInMonth:function(a,b){return[31,l.isLeapYear(a)?29:28,31,30,31,30,31,31,30,31,30,31][b]},validParts:/dd?|DD?|mm?|MM?|yy(?:yy)?/g,nonpunctuation:/[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,parseFormat:function(a){var b=a.replace(this.validParts,"\0").split("\0"),c=a.match(this.validParts);if(!b||!b.length||!c||0===c.length)throw new Error("Invalid date format.");return{separators:b,parts:c}},parseDate:function(c,d,f){if(c instanceof Date)return c;if("string"==typeof d&&(d=l.parseFormat(d)),/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(c)){var g,h,i=/([\-+]\d+)([dmwy])/,j=c.match(/([\-+]\d+)([dmwy])/g);c=new Date;for(var m=0;m<j.length;m++)switch(g=i.exec(j[m]),h=parseInt(g[1]),g[2]){case"d":c.setUTCDate(c.getUTCDate()+h);break;case"m":c=e.prototype.moveMonth.call(e.prototype,c,h);break;case"w":c.setUTCDate(c.getUTCDate()+7*h);break;case"y":c=e.prototype.moveYear.call(e.prototype,c,h)}return b(c.getUTCFullYear(),c.getUTCMonth(),c.getUTCDate(),0,0,0)}var n,o,g,j=c&&c.match(this.nonpunctuation)||[],c=new Date,p={},q=["yyyy","yy","M","MM","m","mm","d","dd"],r={yyyy:function(a,b){return a.setUTCFullYear(b)},yy:function(a,b){return a.setUTCFullYear(2e3+b)},m:function(a,b){for(b-=1;0>b;)b+=12;for(b%=12,a.setUTCMonth(b);a.getUTCMonth()!=b;)a.setUTCDate(a.getUTCDate()-1);return a},d:function(a,b){return a.setUTCDate(b)}};r.M=r.MM=r.mm=r.m,r.dd=r.d,c=b(c.getFullYear(),c.getMonth(),c.getDate(),0,0,0);var s=d.parts.slice();if(j.length!=s.length&&(s=a(s).filter(function(b,c){return-1!==a.inArray(c,q)}).toArray()),j.length==s.length){for(var m=0,t=s.length;t>m;m++){if(n=parseInt(j[m],10),g=s[m],isNaN(n))switch(g){case"MM":o=a(k[f].months).filter(function(){var a=this.slice(0,j[m].length),b=j[m].slice(0,a.length);return a==b}),n=a.inArray(o[0],k[f].months)+1;break;case"M":o=a(k[f].monthsShort).filter(function(){var a=this.slice(0,j[m].length),b=j[m].slice(0,a.length);return a==b}),n=a.inArray(o[0],k[f].monthsShort)+1}p[g]=n}for(var u,m=0;m<q.length;m++)u=q[m],u in p&&!isNaN(p[u])&&r[u](c,p[u])}return c},formatDate:function(b,c,d){"string"==typeof c&&(c=l.parseFormat(c));var e={d:b.getUTCDate(),D:k[d].daysShort[b.getUTCDay()],DD:k[d].days[b.getUTCDay()],m:b.getUTCMonth()+1,M:k[d].monthsShort[b.getUTCMonth()],MM:k[d].months[b.getUTCMonth()],yy:b.getUTCFullYear().toString().substring(2),yyyy:b.getUTCFullYear()};e.dd=(e.d<10?"0":"")+e.d,e.mm=(e.m<10?"0":"")+e.m;for(var b=[],f=a.extend([],c.separators),g=0,h=c.parts.length;h>=g;g++)f.length&&b.push(f.shift()),b.push(e[c.parts[g]]);return b.join("")},headTemplate:'<thead><tr><th class="prev"><i class="icon-arrow-left"/></th><th colspan="5" class="datepicker-switch"></th><th class="next"><i class="icon-arrow-right"/></th></tr></thead>',contTemplate:'<tbody><tr><td colspan="7"></td></tr></tbody>',footTemplate:'<tfoot><tr><th colspan="7" class="today"></th></tr><tr><th colspan="7" class="clear"></th></tr></tfoot>'};l.template='<div class="datepicker"><div class="datepicker-days"><table class=" table-condensed">'+l.headTemplate+"<tbody></tbody>"+l.footTemplate+"</table>"+"</div>"+'<div class="datepicker-months">'+'<table class="table-condensed">'+l.headTemplate+l.contTemplate+l.footTemplate+"</table>"+"</div>"+'<div class="datepicker-years">'+'<table class="table-condensed">'+l.headTemplate+l.contTemplate+l.footTemplate+"</table>"+"</div>"+"</div>",a.fn.datepicker.DPGlobal=l,a.fn.datepicker.noConflict=function(){return a.fn.datepicker=g,this},a(document).on("focus.datepicker.data-api click.datepicker.data-api",'[data-provide="datepicker"]',function(b){var c=a(this);c.data("datepicker")||(b.preventDefault(),h.call(c,"show"))}),a(function(){h.call(a('[data-provide="datepicker-inline"]'))})}(window.jQuery),function(a){"use strict";a.fn.bdatepicker=a.fn.datepicker.noConflict(),a.fn.datepicker||(a.fn.datepicker=a.fn.bdatepicker);var b=function(a){this.init("date",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{initPicker:function(b,c){this.options.viewformat||(this.options.viewformat=this.options.format),b.datepicker=a.fn.editableutils.tryParseJson(b.datepicker,!0),this.options.datepicker=a.extend({},c.datepicker,b.datepicker,{format:this.options.viewformat}),this.options.datepicker.language=this.options.datepicker.language||"en",this.dpg=a.fn.bdatepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat)},render:function(){this.$input.bdatepicker(this.options.datepicker),this.options.clear&&(this.$clear=a('<a href="#"></a>').html(this.options.clear).click(a.proxy(function(a){a.preventDefault(),a.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(a('<div class="editable-clear">').append(this.$clear)))},value2html:function(a,c){var d=a?this.dpg.formatDate(a,this.parsedViewFormat,this.options.datepicker.language):"";b.superclass.value2html.call(this,d,c)},html2value:function(a){return this.parseDate(a,this.parsedViewFormat)},value2str:function(a){return a?this.dpg.formatDate(a,this.parsedFormat,this.options.datepicker.language):""},str2value:function(a){return this.parseDate(a,this.parsedFormat)},value2submit:function(a){return this.value2str(a)},value2input:function(a){this.$input.bdatepicker("update",a)},input2value:function(){return this.$input.data("datepicker").date},activate:function(){},clear:function(){this.$input.data("datepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".day",function(b){if(!a(b.currentTarget).is(".old")&&!a(b.currentTarget).is(".new")){var c=a(this).closest("form");setTimeout(function(){c.submit()},200)}})},parseDate:function(a,b){var c,d=null;return a&&(d=this.dpg.parseDate(a,b,this.options.datepicker.language),"string"==typeof a&&(c=this.dpg.formatDate(d,b,this.options.datepicker.language),a!==c&&(d=null))),d}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'<div class="editable-date well"></div>',inputclass:null,format:"yyyy-mm-dd",viewformat:null,datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!1},clear:"&times; clear"}),a.fn.editabletypes.date=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datefield",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.date),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.bdatepicker(this.options.datepicker),this.$input.off("focus keydown"),this.$input.keyup(a.proxy(function(){this.$tpl.removeData("date"),this.$tpl.bdatepicker("update")},this))},value2input:function(a){this.$input.val(a?this.dpg.formatDate(a,this.parsedViewFormat,this.options.datepicker.language):""),this.$tpl.bdatepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.date.defaults,{tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',inputclass:"input-small",datepicker:{weekStart:0,startView:0,minViewMode:0,autoclose:!0}}),a.fn.editabletypes.datefield=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datetime",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.abstractinput),a.extend(b.prototype,{initPicker:function(b,c){this.options.viewformat||(this.options.viewformat=this.options.format),b.datetimepicker=a.fn.editableutils.tryParseJson(b.datetimepicker,!0),this.options.datetimepicker=a.extend({},c.datetimepicker,b.datetimepicker,{format:this.options.viewformat}),this.options.datetimepicker.language=this.options.datetimepicker.language||"en",this.dpg=a.fn.datetimepicker.DPGlobal,this.parsedFormat=this.dpg.parseFormat(this.options.format,this.options.formatType),this.parsedViewFormat=this.dpg.parseFormat(this.options.viewformat,this.options.formatType)},render:function(){this.$input.datetimepicker(this.options.datetimepicker),this.$input.on("changeMode",function(){var b=a(this).closest("form").parent();setTimeout(function(){b.triggerHandler("resize")},0)}),this.options.clear&&(this.$clear=a('<a href="#"></a>').html(this.options.clear).click(a.proxy(function(a){a.preventDefault(),a.stopPropagation(),this.clear()},this)),this.$tpl.parent().append(a('<div class="editable-clear">').append(this.$clear)))},value2html:function(a,c){var d=a?this.dpg.formatDate(this.toUTC(a),this.parsedViewFormat,this.options.datetimepicker.language,this.options.formatType):"";return c?(b.superclass.value2html.call(this,d,c),void 0):d},html2value:function(a){var b=this.parseDate(a,this.parsedViewFormat);return b?this.fromUTC(b):null},value2str:function(a){return a?this.dpg.formatDate(this.toUTC(a),this.parsedFormat,this.options.datetimepicker.language,this.options.formatType):""},str2value:function(a){var b=this.parseDate(a,this.parsedFormat);return b?this.fromUTC(b):null},value2submit:function(a){return this.value2str(a)},value2input:function(a){a&&this.$input.data("datetimepicker").setDate(a)},input2value:function(){var a=this.$input.data("datetimepicker");return a.date?a.getDate():null},activate:function(){},clear:function(){this.$input.data("datetimepicker").date=null,this.$input.find(".active").removeClass("active"),this.options.showbuttons||this.$input.closest("form").submit()},autosubmit:function(){this.$input.on("mouseup",".minute",function(){var b=a(this).closest("form");setTimeout(function(){b.submit()},200)})},toUTC:function(a){return a?new Date(a.valueOf()-6e4*a.getTimezoneOffset()):a},fromUTC:function(a){return a?new Date(a.valueOf()+6e4*a.getTimezoneOffset()):a},parseDate:function(a,b){var c,d=null;return a&&(d=this.dpg.parseDate(a,b,this.options.datetimepicker.language,this.options.formatType),"string"==typeof a&&(c=this.dpg.formatDate(d,b,this.options.datetimepicker.language,this.options.formatType),a!==c&&(d=null))),d}}),b.defaults=a.extend({},a.fn.editabletypes.abstractinput.defaults,{tpl:'<div class="editable-date well"></div>',inputclass:null,format:"yyyy-mm-dd hh:ii",formatType:"standard",viewformat:null,datetimepicker:{todayHighlight:!1,autoclose:!1},clear:"&times; clear"}),a.fn.editabletypes.datetime=b}(window.jQuery),function(a){"use strict";var b=function(a){this.init("datetimefield",a,b.defaults),this.initPicker(a,b.defaults)};a.fn.editableutils.inherit(b,a.fn.editabletypes.datetime),a.extend(b.prototype,{render:function(){this.$input=this.$tpl.find("input"),this.setClass(),this.setAttr("placeholder"),this.$tpl.datetimepicker(this.options.datetimepicker),this.$input.off("focus keydown"),this.$input.keyup(a.proxy(function(){this.$tpl.removeData("date"),this.$tpl.datetimepicker("update")},this))},value2input:function(a){this.$input.val(this.value2html(a)),this.$tpl.datetimepicker("update")},input2value:function(){return this.html2value(this.$input.val())},activate:function(){a.fn.editabletypes.text.prototype.activate.call(this)},autosubmit:function(){}}),b.defaults=a.extend({},a.fn.editabletypes.datetime.defaults,{tpl:'<div class="input-append date"><input type="text"/><span class="add-on"><i class="icon-th"></i></span></div>',inputclass:"input-medium",datetimepicker:{todayHighlight:!1,autoclose:!0}}),a.fn.editabletypes.datetimefield=b}(window.jQuery);
 
 
 
 
 
 
 
backend/modules/appearance/resources/js/editable.js ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * jQuery booklyEditable.
3
+ */
4
+ (function ($) {
5
+ let methods = {
6
+ init : function (options) {
7
+ let opts = $.extend({}, $.fn.booklyEditable.defaults, options);
8
+
9
+ return this.each(function () {
10
+ if ($(this).data('booklyEditable')) {
11
+ return;
12
+ }
13
+ let obj = {
14
+ $container: $(this),
15
+ opts : opts,
16
+ values : {},
17
+ option : '',
18
+ type : '',
19
+ content : function () {
20
+ let $content = $('<div class="mt-2">');
21
+ switch (obj.type) {
22
+ case 'textarea':
23
+ $.each(obj.values, function (index, value) {
24
+ $content.append('<div class="form-group mb-2"><textarea class="form-control bookly-js-editable-control" name="' + index + '" rows="5">' + value + '</textarea></div>');
25
+ });
26
+ break;
27
+ default:
28
+ $.each(obj.values, function (index, value) {
29
+ $content.append('<div class="form-group mb-2"><input type="text" class="form-control bookly-js-editable-control" name="' + index + '" value="' + value + '"/></div>');
30
+ });
31
+ break;
32
+ }
33
+ $content.append('<hr/>');
34
+ $content.append('<div class="text-right"><div class="btn-group btn-group-sm" role="group"><button type="button" class="btn btn-success bookly-js-editable-save"><i class="fas fa-fw fa-check"></i></button><button type="button" class="btn btn-default" data-dismiss="bookly-popover"><i class="fas fa-fw fa-times"></i></button></div></div>');
35
+ let codes = obj.$container.data('codes');
36
+ if (codes !== undefined) {
37
+ $content.append(codes);
38
+ }
39
+ // Click on "Close" button.
40
+ $content.find('button[data-dismiss="bookly-popover"]').click(function () {
41
+ close();
42
+ });
43
+ // Click on "Save" button.
44
+ $content.find('button.bookly-js-editable-save').click(function () {
45
+ save();
46
+ });
47
+ // Process keypress.
48
+ $content.find('.bookly-js-editable-control').on('keyup', function (e) {
49
+ if (e.keyCode === 27) {
50
+ close();
51
+ }
52
+ });
53
+
54
+ function close() {
55
+ obj.$container.booklyPopover('hide');
56
+ }
57
+
58
+ function save() {
59
+ $content.find('.bookly-js-editable-control').each(function () {
60
+ obj.values[this.name] = this.value;
61
+ });
62
+ // Update values for all editable fields with same data-option
63
+ $('[data-option="' + obj.option + '"]').each(function () {
64
+ $(this).booklyEditable('setValue', obj.values);
65
+ });
66
+ obj.$container.booklyPopover('hide');
67
+ }
68
+
69
+ return $content;
70
+ },
71
+ title : function () {
72
+ let title = obj.$container.data('title');
73
+ return title === undefined ? '' : title;
74
+ }
75
+ }
76
+ $.each(methods.parseJson(obj.$container.data('values')), function (index, value) {
77
+ obj.values[index] = value;
78
+ });
79
+ obj.type = obj.$container.data('fieldtype') || 'input';
80
+ obj.option = obj.$container.data('option');
81
+ obj.$container.booklyPopover({
82
+ html : true,
83
+ placement : obj.$container.data('placement') !== undefined ? obj.$container.data('placement') : opts.placement,
84
+ fallbackPlacement: obj.$container.data('fallbackPlacement') !== undefined ? obj.$container.data('fallbackPlacement') : opts.fallbackPlacement,
85
+ container : opts.container,
86
+ template : '<div class="bookly-popover" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',
87
+ trigger : 'manual',
88
+ title : obj.title,
89
+ content : obj.content
90
+ });
91
+
92
+ // Click on editable field.
93
+ obj.$container.on('click', function (e) {
94
+ e.preventDefault();
95
+ if (!obj.$container.attr('aria-describedby')) {
96
+ $('.bookly-popover').each(function () {
97
+ $('[aria-describedby="' + $(this).attr('id') + '"]').booklyPopover('hide');
98
+ });
99
+
100
+ obj.$container.booklyPopover('show');
101
+ obj.$container.off('shown.bs.popover').on('shown.bs.popover', function () {
102
+ if (obj.$container.attr('aria-describedby') !== undefined) {
103
+ $(obj.$container.data('bs.popover').tip).find('.bookly-js-editable-control:first').focus();
104
+ }
105
+ });
106
+ } else {
107
+ obj.$container.booklyPopover('hide');
108
+ }
109
+ });
110
+
111
+ // Set text for empty field.
112
+ if (obj.$container.text() === '') {
113
+ obj.$container.text(opts.empty);
114
+ }
115
+
116
+ obj.$container.data('booklyEditable', obj);
117
+ });
118
+ },
119
+ setValue : function (values) {
120
+ var obj = this.data('booklyEditable');
121
+ if (!obj) {
122
+ return;
123
+ }
124
+
125
+ obj.values = values;
126
+
127
+ // Update field text.
128
+ obj.$container.text(obj.values[obj.option] === '' ? obj.opts.empty : obj.values[obj.option]);
129
+ },
130
+ getValue : function () {
131
+ var obj = this.data('booklyEditable');
132
+ if (!obj) {
133
+ return;
134
+ }
135
+
136
+ return obj.values;
137
+ },
138
+ parseJson: function (s) {
139
+ if (typeof s === 'string' && s.length && s.match(/^[\{\[].*[\}\]]$/)) {
140
+ s = (new Function('return ' + s))();
141
+ }
142
+ return s;
143
+ },
144
+ };
145
+
146
+ // Process click outside popover to hide it.
147
+ $(document).on('click', function (e) {
148
+ if (!$(e.target).hasClass('bookly-js-editable')) {
149
+ let $activators = $('.bookly-js-editable[aria-describedby]');
150
+ if ($activators.length > 0 && $(e.target).parents('.bookly-popover').length === 0) {
151
+ $activators.booklyPopover('hide');
152
+ }
153
+ }
154
+ });
155
+
156
+ $.fn.booklyEditable = function (method) {
157
+ if (methods[method]) {
158
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
159
+ } else if (typeof method === 'object' || !method) {
160
+ return methods.init.apply(this, arguments);
161
+ } else {
162
+ $.error('No method ' + method + ' for jQuery.booklyEditable');
163
+ }
164
+ };
165
+
166
+ $.fn.booklyEditable.defaults = {
167
+ placement : 'auto',
168
+ fallbackPlacement: ['bottom'],
169
+ container : '#bookly-appearance',
170
+ empty : 'Empty',
171
+ };
172
+ })(jQuery);
backend/modules/appearance/templates/_1_service.php CHANGED
@@ -6,6 +6,11 @@ use Bookly\Backend\Components\Appearance\Editable;
6
  /** @var WP_Locale $wp_locale */
7
  global $wp_locale;
8
  ?>
 
 
 
 
 
9
  <div class="bookly-form">
10
  <?php include '_progress_tracker.php' ?>
11
 
6
  /** @var WP_Locale $wp_locale */
7
  global $wp_locale;
8
  ?>
9
+ <style>
10
+ .picker__holder * {
11
+ box-sizing: unset !important;
12
+ }
13
+ </style>
14
  <div class="bookly-form">
15
  <?php include '_progress_tracker.php' ?>
16
 
backend/modules/appearance/templates/_7_payment.php CHANGED
@@ -11,30 +11,18 @@ use Bookly\Backend\Modules\Appearance\Proxy;
11
 
12
  <div class="bookly-payment-nav">
13
  <div class="bookly-box bookly-js-payment-single-app">
14
- <?php Editable::renderText( 'bookly_l10n_info_payment_step_single_app', Codes::getHtml( 7 ), 'right' ) ?>
15
  </div>
16
  <?php Proxy\Pro::renderBookingStatesText() ?>
17
  <div class="bookly-js-payment-gateways">
18
  <div class="bookly-box bookly-list ">
19
  <label>
20
  <input type="radio" name="payment" checked="checked"/>
21
- <?php Editable::renderString( array( 'bookly_l10n_label_pay_locally', ) ) ?>
22
  </label>
23
  </div>
24
 
25
  <?php Proxy\Pro::renderPayPalPaymentOption() ?>
26
-
27
- <div class="bookly-box bookly-list"<?php if ( Proxy\Shared::showCreditCard() == false ): ?> style="display: none"<?php endif ?>>
28
- <label>
29
- <input type="radio" name="payment" id="bookly-card-payment"/>
30
- <?php Editable::renderString( array( 'bookly_l10n_label_pay_ccard', ) ) ?>
31
- <img src="<?php echo plugins_url( 'frontend/resources/images/cards.png', \Bookly\Lib\Plugin::getMainFile() ) ?>" alt="cards"/>
32
- </label>
33
- <form class="bookly-card-form bookly-clear-bottom" style="margin-top:15px;display: none;">
34
- <?php include '_card_payment.php' ?>
35
- </form>
36
- </div>
37
-
38
  <?php Proxy\Shared::renderPaymentGatewaySelector() ?>
39
  </div>
40
  </div>
11
 
12
  <div class="bookly-payment-nav">
13
  <div class="bookly-box bookly-js-payment-single-app">
14
+ <?php Editable::renderText( 'bookly_l10n_info_payment_step_single_app', Codes::getHtml( 7 ) ) ?>
15
  </div>
16
  <?php Proxy\Pro::renderBookingStatesText() ?>
17
  <div class="bookly-js-payment-gateways">
18
  <div class="bookly-box bookly-list ">
19
  <label>
20
  <input type="radio" name="payment" checked="checked"/>
21
+ <?php Editable::renderString( array( 'bookly_l10n_label_pay_locally', ), __( 'Local', 'bookly' ) ) ?>
22
  </label>
23
  </div>
24
 
25
  <?php Proxy\Pro::renderPayPalPaymentOption() ?>
 
 
 
 
 
 
 
 
 
 
 
 
26
  <?php Proxy\Shared::renderPaymentGatewaySelector() ?>
27
  </div>
28
  </div>
backend/modules/appearance/templates/_card_payment.php DELETED
@@ -1,40 +0,0 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
- use Bookly\Backend\Components\Appearance\Editable;
3
- ?>
4
- <div class="bookly-box bookly-table">
5
- <div class="bookly-form-group" style="width:200px!important">
6
- <label>
7
- <?php Editable::renderString( array( 'bookly_l10n_label_ccard_number', ) ) ?>
8
- </label>
9
- <div>
10
- <input type="text" />
11
- </div>
12
- </div>
13
- <div class="bookly-form-group">
14
- <label>
15
- <?php Editable::renderString( array( 'bookly_l10n_label_ccard_expire', ) ) ?>
16
- </label>
17
- <div>
18
- <select class="bookly-card-exp">
19
- <?php for ( $i = 1; $i <= 12; ++ $i ) : ?>
20
- <option value="<?php echo $i ?>"><?php printf( '%02d', $i ) ?></option>
21
- <?php endfor ?>
22
- </select>
23
- <select class="bookly-card-exp">
24
- <?php for ( $i = date( 'Y' ); $i <= date( 'Y' ) + 10; ++ $i ) : ?>
25
- <option value="<?php echo $i ?>"><?php echo $i ?></option>
26
- <?php endfor ?>
27
- </select>
28
- </div>
29
- </div>
30
- </div>
31
- <div class="bookly-box bookly-clear-bottom">
32
- <div class="bookly-form-group">
33
- <label>
34
- <?php Editable::renderString( array( 'bookly_l10n_label_ccard_code', ) ) ?>
35
- </label>
36
- <div>
37
- <input class="bookly-card-cvc" type="text" />
38
- </div>
39
- </div>
40
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
backend/modules/appearance/templates/_custom_css.php CHANGED
@@ -4,30 +4,31 @@ use Bookly\Backend\Components\Controls\Buttons;
4
  ?>
5
 
6
  <div class="form-group">
7
- <?php Buttons::renderModalActivator( 'bookly-custom-css-dialog', null, esc_html__( 'Edit custom CSS', 'bookly' ) ) ?>
8
  </div>
9
 
10
- <div id="bookly-custom-css-dialog" class="modal fade" tabindex=-1 role="dialog">
11
  <div class="modal-dialog">
12
  <div class="modal-content">
13
  <div class="modal-header">
14
- <?php _e( 'Edit custom CSS', 'bookly' ) ?>
 
15
  </div>
16
  <div class="modal-body">
17
  <div class="form-group">
18
- <label for="bookly-custom-css" class="control-label"><?php _e( 'Set up your custom CSS styles', 'bookly' ) ?></label>
19
  <textarea id="bookly-custom-css" class="form-control" rows="10"><?php echo $custom_css ?></textarea>
20
  </div>
21
  </div>
22
  <div class="modal-footer">
23
  <div id="bookly-custom-css-error"></div>
24
- <?php Buttons::renderCustom( 'bookly-custom-css-save', 'btn-success btn-lg', __( 'Save', 'bookly' ) ) ?>
25
- <?php Buttons::renderCustom( 'bookly-custom-css-cancel', 'btn-default btn-lg', __( 'Cancel', 'bookly' ) ) ?>
26
  </div>
27
  </div>
28
  </div>
29
  </div>
30
 
31
  <script type="text/javascript">
32
- var saved_css = <?php echo json_encode( $custom_css ); ?>;
33
  </script>
4
  ?>
5
 
6
  <div class="form-group">
7
+ <?php Buttons::renderDefault( null, null, __( 'Edit custom CSS', 'bookly' ), array( 'data-toggle' => 'bookly-modal', 'data-target' => '#bookly-custom-css-dialog' ), true ) ?>
8
  </div>
9
 
10
+ <div id="bookly-custom-css-dialog" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
11
  <div class="modal-dialog">
12
  <div class="modal-content">
13
  <div class="modal-header">
14
+ <h5 class="modal-title"><?php esc_html_e( 'Edit custom CSS', 'bookly' ) ?></h5>
15
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
16
  </div>
17
  <div class="modal-body">
18
  <div class="form-group">
19
+ <label for="bookly-custom-css" class="control-label"><?php esc_html_e( 'Set up your custom CSS styles', 'bookly' ) ?></label>
20
  <textarea id="bookly-custom-css" class="form-control" rows="10"><?php echo $custom_css ?></textarea>
21
  </div>
22
  </div>
23
  <div class="modal-footer">
24
  <div id="bookly-custom-css-error"></div>
25
+ <?php Buttons::renderSubmit( 'bookly-custom-css-save' ) ?>
26
+ <?php Buttons::renderCancel() ?>
27
  </div>
28
  </div>
29
  </div>
30
  </div>
31
 
32
  <script type="text/javascript">
33
+ var saved_css = <?php echo json_encode( $custom_css ) ?>;
34
  </script>
backend/modules/appearance/templates/index.php CHANGED
@@ -2,24 +2,9 @@
2
  use Bookly\Lib;
3
  use Bookly\Backend\Components\Support;
4
  use Bookly\Backend\Components\Controls\Buttons;
 
5
  use Bookly\Backend\Modules\Appearance\Proxy;
6
  ?>
7
- <style type="text/css">
8
- .bookly-columnizer .bookly-hour.bookly-slot-in-waiting-list span.bookly-time-additional {
9
- color: #f4662f!important;
10
- }
11
- #bookly-step-settings > div > .col-md-3:nth-child(4n+1) {
12
- clear: both;
13
- }
14
- #bookly-tbs .bookly-cart .bookly-extras-cart-title {
15
- padding-left: 25px;
16
- }
17
- #bookly-tbs .bookly-animate {
18
- -webkit-transition: background-color 500ms ease-in;
19
- -ms-transition: background-color 500ms ease-in;
20
- transition: background-color 500ms ease-in;
21
- }
22
- </style>
23
  <?php if ( trim( $custom_css ) ) : ?>
24
  <style type="text/css">
25
  <?php echo $custom_css ?>
@@ -27,170 +12,116 @@ use Bookly\Backend\Modules\Appearance\Proxy;
27
  <?php endif ?>
28
 
29
  <div id="bookly-tbs" class="wrap">
30
- <div class="bookly-tbs-body">
31
- <div class="page-header text-right clearfix">
32
- <div class="bookly-page-title">
33
- <?php esc_html_e( 'Appearance', 'bookly' ) ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  </div>
35
- <?php Support\Buttons::render( $self::pageSlug() ) ?>
36
  </div>
37
- <div class="panel panel-default bookly-main">
38
- <div class="panel-body">
39
- <div id="bookly-appearance">
40
- <div class="row">
41
- <div class="col-sm-3 col-lg-2 bookly-color-picker-wrapper">
42
- <input type="text" name="color" class="bookly-js-color-picker"
43
- value="<?php form_option( 'bookly_app_color' ) ?>"
44
- data-selected="<?php form_option( 'bookly_app_color' ) ?>" />
45
- </div>
46
- <div class="col-sm-3 col-lg-2">
47
- <div class="checkbox">
48
- <label>
49
- <input type="checkbox" id=bookly-show-progress-tracker <?php checked( get_option( 'bookly_app_show_progress_tracker' ) ) ?>>
50
- <?php esc_html_e( 'Show form progress tracker', 'bookly' ) ?>
51
- </label>
52
- </div>
53
- </div>
54
- <div class="col-sm-3 col-lg-2">
55
- <div class="checkbox">
56
- <label>
57
- <input type="checkbox" id="bookly-align-buttons-left" <?php checked( get_option( 'bookly_app_align_buttons_left' ) ) ?>>
58
- <?php esc_html_e( 'Align buttons to the left', 'bookly' ) ?>
59
- </label>
60
- </div>
61
- </div>
62
- <?php Proxy\ServiceExtras::renderShowStep() ?>
63
- <?php Proxy\RecurringAppointments::renderShowStep() ?>
64
- <?php Proxy\Cart::renderShowStep() ?>
65
- </div>
66
-
67
- <ul class="bookly-nav bookly-nav-tabs bookly-margin-top-lg bookly-js-appearance-steps" role="tablist">
68
- <?php $i = 1 ?>
69
- <?php foreach ( $steps as $data ) : ?>
70
- <li class="bookly-nav-item <?php if ( $data['step'] == 1 ) : ?>active<?php endif ?>" data-target="#bookly-step-<?php echo $data['step'] ?>" data-toggle="tab" <?php if ( ! $data['show'] ) : ?>style="display: none;"<?php endif ?>>
71
- <span class="bookly-js-step-number"><?php echo $data['show'] ? $i++ : $i ?></span>. <?php echo esc_html( $data['title'] ) ?>
72
- </li>
73
- <?php endforeach ?>
74
- </ul>
75
 
76
- <?php if ( ! get_user_meta( get_current_user_id(), Lib\Plugin::getPrefix() . 'dismiss_appearance_notice', true ) ): ?>
77
- <div class="alert alert-info alert-dismissible fade in bookly-margin-top-lg bookly-margin-bottom-remove" id="bookly-js-hint-alert" role="alert">
78
- <button type="button" class="close" data-dismiss="alert">&times;</button>
79
- <p>
80
- <?php esc_html_e( 'Click on the underlined text to edit.', 'bookly' ) ?>
81
- </p>
82
- <p><?php esc_html_e( 'How to publish this form on your web site?', 'bookly' ) ?>
83
- <br>
84
- <?php esc_html_e( 'Open the page where you want to add the booking form in page edit mode and click on the "Add Bookly booking form" button. Choose which fields you\'d like to keep or remove from the booking form. Click Insert, and the booking form will be added to the page.', 'bookly' ) ?>
85
- <a href="<?php echo Bookly\Lib\Utils\Common::prepareUrlReferrers( 'https://support.booking-wp-plugin.com/hc/en-us/articles/212800185-Publish-Booking-Form', 'appearance' ) ?>" target="_blank"><?php esc_html_e( 'Read more', 'bookly' ) ?></a>
86
- </p>
87
- </div>
88
- <?php endif ?>
89
 
90
- <div class="row" id="bookly-step-settings">
91
- <div class="bookly-js-service-settings bookly-margin-top-lg">
92
- <?php Proxy\Locations::renderShowLocation() ?>
93
- <?php Proxy\CustomDuration::renderShowCustomDuration() ?>
94
- <?php Proxy\GroupBooking::renderShowNOP() ?>
95
- <?php Proxy\MultiplyAppointments::renderShowQuantity() ?>
96
- <div class="col-md-3">
97
- <div class="checkbox">
98
- <label>
99
- <input type="checkbox" id=bookly-required-employee <?php checked( get_option( 'bookly_app_required_employee' ) ) ?>>
100
- <?php esc_html_e( 'Make selecting employee required', 'bookly' ) ?>
101
- </label>
102
- </div>
103
  </div>
104
- <div class="col-md-3">
105
- <div class="checkbox">
106
- <label>
107
- <input type="checkbox" id=bookly-staff-name-with-price <?php checked( get_option( 'bookly_app_staff_name_with_price' ) ) ?>>
108
- <?php esc_html_e( 'Show service price next to employee name', 'bookly' ) ?>
109
- </label>
110
- </div>
111
  </div>
112
- <div class="col-md-3">
113
- <div class="checkbox">
114
- <label>
115
- <input type="checkbox" id=bookly-service-name-with-duration <?php checked( get_option( 'bookly_app_service_name_with_duration' ) ) ?>>
116
- <?php esc_html_e( 'Show service duration next to service name', 'bookly' ) ?>
117
- </label>
118
- </div>
119
  </div>
120
  <?php Proxy\Shared::renderServiceStepSettings() ?>
121
  </div>
122
- <div class="bookly-js-time-settings bookly-margin-top-lg" style="display:none">
123
- <div class="col-md-3">
124
- <div class="checkbox">
125
- <label>
126
- <input type="checkbox" id="bookly-show-calendar" <?php checked( get_option( 'bookly_app_show_calendar' ) ) ?>>
127
- <?php esc_html_e( 'Show calendar', 'bookly' ) ?>
128
- </label>
129
- </div>
130
  </div>
131
- <div class="col-md-3">
132
- <div class="checkbox">
133
- <label>
134
- <input type="checkbox" id="bookly-show-blocked-timeslots" <?php checked( get_option( 'bookly_app_show_blocked_timeslots' ) ) ?>>
135
- <?php esc_html_e( 'Show blocked timeslots', 'bookly' ) ?>
136
- </label>
137
- </div>
138
  </div>
139
- <div class="col-md-3">
140
- <div class="checkbox">
141
- <label>
142
- <input type="checkbox" id="bookly-show-day-one-column" <?php checked( get_option( 'bookly_app_show_day_one_column' ) ) ?>>
143
- <?php esc_html_e( 'Show each day in one column', 'bookly' ) ?>
144
- </label>
145
- </div>
146
  </div>
147
  <?php Proxy\Pro::renderTimeZoneSwitcherCheckbox() ?>
148
  <?php Proxy\Shared::renderTimeStepSettings() ?>
149
  </div>
 
150
 
151
- <?php Proxy\Cart::renderCartStepSettings() ?>
152
- <?php Proxy\ServiceExtras::renderStepSettings() ?>
153
-
154
- <div class="bookly-js-details-settings bookly-margin-top-lg container-fluid" style="display:none">
155
 
 
 
156
  <div class="col-md-3">
157
- <select id="bookly-cst-required-details" class="form-control" data-default="<?php echo ! array_diff( array( 'phone', 'email' ), get_option( 'bookly_cst_required_details', array() ) ) ? 'both' : current( get_option( 'bookly_cst_required_details', array() ) ) ?>">
158
- <option value="phone"<?php selected( in_array( 'phone', get_option( 'bookly_cst_required_details', array() ) ) && ! in_array( 'email', get_option( 'bookly_cst_required_details', array() ) ) ) ?><?php disabled( get_option( 'bookly_cst_create_account' ) ) ?>><?php esc_html_e( 'Phone field required', 'bookly' ) ?></option>
159
- <option value="email"<?php selected( in_array( 'email', get_option( 'bookly_cst_required_details', array() ) ) && ! in_array( 'phone', get_option( 'bookly_cst_required_details', array() ) ) ) ?>><?php esc_html_e( 'Email field required', 'bookly' ) ?></option>
160
- <option value="both"<?php selected( ! array_diff( array( 'phone', 'email' ), get_option( 'bookly_cst_required_details', array() ) ) ) ?>><?php esc_html_e( 'Both email and phone fields required', 'bookly' ) ?></option>
161
- </select>
162
- </div>
163
- <div class="col-md-3">
164
- <div class="checkbox">
165
- <label>
166
- <input type="checkbox" id="bookly-show-login-button" <?php checked( get_option( 'bookly_app_show_login_button' ) ) ?>>
167
- <?php esc_html_e( 'Show Login button', 'bookly' ) ?>
168
- </label>
169
  </div>
170
  </div>
171
- <div class="col-md-3">
172
- <div class="checkbox">
173
- <label>
174
- <input type="checkbox" id="bookly-cst-first-last-name" <?php checked( get_option( 'bookly_cst_first_last_name' ) ) ?> data-toggle="popover" data-trigger="focus" data-placement="auto bottom" data-content="<?php esc_attr_e( 'Do not forget to update your email and SMS codes for customer names', 'bookly' ) ?>">
175
- <?php esc_html_e( 'Use first and last name instead of full name', 'bookly' ) ?>
176
- </label>
177
- </div>
178
  </div>
179
- <div class="col-md-3">
180
- <div class="checkbox">
181
- <label>
182
- <input type="checkbox" id="bookly-cst-show-email-confirm" <?php checked( get_option( 'bookly_app_show_email_confirm' ) ) ?>>
183
- <?php esc_html_e( 'Email confirmation field', 'bookly' ) ?>
184
- </label>
185
  </div>
186
  </div>
187
- <div class="col-md-3">
188
- <div class="checkbox">
189
- <label>
190
- <input type="checkbox" id="bookly-show-notes" <?php checked( get_option( 'bookly_app_show_notes' ) ) ?>>
191
- <?php esc_html_e( 'Show notes field', 'bookly' ) ?>
192
- </label>
193
- </div>
194
  </div>
195
  <?php Proxy\Pro::renderShowBirthday() ?>
196
  <?php Proxy\Pro::renderShowAddress() ?>
@@ -200,67 +131,67 @@ use Bookly\Backend\Modules\Appearance\Proxy;
200
  <?php Proxy\CustomerInformation::renderShowCustomerInformation() ?>
201
  <?php Proxy\Pro::renderShowFacebookButton() ?>
202
  </div>
203
- <div class="bookly-js-payment-settings bookly-margin-top-lg" style="display:none">
 
 
204
  <?php Proxy\Coupons::renderShowCoupons() ?>
205
- <?php Proxy\Pro::renderBookingStatesSelector() ?>
206
  </div>
 
 
207
 
208
- <div class="bookly-js-done-settings bookly-margin-top-lg" style="display:none">
209
- <div class="col-md-12">
210
- <div class="alert alert-info bookly-margin-top-lg bookly-margin-bottom-remove bookly-flexbox">
211
- <div class="bookly-flex-row">
212
- <div class="bookly-flex-cell" style="width:39px"><i class="alert-icon"></i></div>
213
- <div class="bookly-flex-cell">
214
- <div>
215
- <?php esc_html_e( 'The booking form on this step may have different set or states of its elements. It depends on various conditions such as installed/activated add-ons, settings configuration or choices made on previous steps. Select option and click on the underlined text to edit.', 'bookly' ) ?>
216
- </div>
217
- <div class="bookly-margin-top-lg">
218
- <select id="bookly-done-step-view" class="form-control">
219
- <option value="booking-success"><?php esc_html_e( 'Form view in case of successful booking', 'bookly' ) ?></option>
220
- <option value="booking-limit-error"><?php esc_html_e( 'Form view in case the number of bookings exceeds the limit', 'bookly' ) ?></option>
221
- <option value="booking-processing"><?php esc_html_e( 'Form view in case of payment has been accepted for processing', 'bookly' ) ?></option>
222
- </select>
223
- </div>
224
- </div>
225
  </div>
226
  </div>
227
  </div>
228
  </div>
229
  </div>
 
230
 
231
- <div class="panel panel-default bookly-margin-top-lg">
232
- <div class="panel-body">
233
- <div class="tab-content">
234
- <?php foreach ( $steps as $step => $step_name ) : ?>
235
- <div id="bookly-step-<?php echo $step ?>" class="tab-pane <?php if ( $step == 1 ) : ?>active<?php endif ?>" data-target="<?php echo $step ?>">
236
- <?php // Render unique data per step
237
- switch ( $step ) :
238
- case 1: include '_1_service.php'; break;
239
- case 2: Proxy\ServiceExtras::renderStep( $self::renderTemplate( '_progress_tracker', compact( 'step' ), false ) );
240
- break;
241
- case 3: include '_3_time.php'; break;
242
- case 4: Proxy\RecurringAppointments::renderStep( $self::renderTemplate( '_progress_tracker', compact( 'step' ), false ) );
243
- break;
244
- case 5: Proxy\Cart::renderStep( $self::renderTemplate( '_progress_tracker', compact( 'step' ), false ) );
245
- break;
246
- case 6: include '_6_details.php'; break;
247
- case 7: include '_7_payment.php'; break;
248
- case 8: include '_8_complete.php'; break;
249
- endswitch ?>
250
- </div>
251
- <?php endforeach ?>
252
- </div>
253
  </div>
254
  </div>
255
- <div>
256
- <?php $self::renderTemplate( '_custom_css', array( 'custom_css' => $custom_css ) ) ?>
257
- </div>
258
  </div>
259
  </div>
260
- <div class="panel-footer">
261
- <?php Buttons::renderSubmit( 'ajax-send-appearance' ) ?>
262
- <?php Buttons::renderReset() ?>
263
- </div>
264
  </div>
265
  </div>
266
  </div>
2
  use Bookly\Lib;
3
  use Bookly\Backend\Components\Support;
4
  use Bookly\Backend\Components\Controls\Buttons;
5
+ use Bookly\Backend\Components\Controls\Inputs;
6
  use Bookly\Backend\Modules\Appearance\Proxy;
7
  ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  <?php if ( trim( $custom_css ) ) : ?>
9
  <style type="text/css">
10
  <?php echo $custom_css ?>
12
  <?php endif ?>
13
 
14
  <div id="bookly-tbs" class="wrap">
15
+ <div class="form-row align-items-center mb-3">
16
+ <h4 class="col m-0"><?php esc_html_e( 'Appearance', 'bookly' ) ?></h4>
17
+ <?php Support\Buttons::render( $self::pageSlug() ) ?>
18
+ </div>
19
+ <div class="card mb-2">
20
+ <div class="card-body">
21
+ <div class="row align-items-center">
22
+ <div class="col-lg-3 col-xl-2 bookly-color-picker-wrapper mb-2 mb-lg-0">
23
+ <div class="bookly-color-picker">
24
+ <input name="color" value="<?php form_option( 'bookly_app_color' ) ?>" class="bookly-js-color-picker" data-selected="<?php form_option( 'bookly_app_color' ) ?>" type="text" />
25
+ </div>
26
+ </div>
27
+ <div class="col-lg-3 col-xl-2">
28
+ <?php Inputs::renderCheckBox( __( 'Show form progress tracker', 'bookly' ), null, get_option( 'bookly_app_show_progress_tracker' ), array( 'id' => 'bookly-show-progress-tracker' ) ) ?>
29
+ </div>
30
+ <div class="col-lg-3 col-xl-2">
31
+ <?php Inputs::renderCheckBox( __( 'Align buttons to the left', 'bookly' ), null, get_option( 'bookly_app_align_buttons_left' ), array( 'id' => 'bookly-align-buttons-left' ) ) ?>
32
+ </div>
33
+ <?php Proxy\ServiceExtras::renderShowStep() ?>
34
+ <?php Proxy\RecurringAppointments::renderShowStep() ?>
35
+ <?php Proxy\Cart::renderShowStep() ?>
36
  </div>
 
37
  </div>
38
+ </div>
39
+ <div class="card">
40
+ <div class="card-header">
41
+ <ul class="nav nav-tabs card-header-tabs bookly-js-appearance-steps flex-column flex-lg-row bookly-nav-tabs-md" role="tablist">
42
+ <?php $i = 1 ?>
43
+ <?php foreach ( $steps as $data ) : ?>
44
+ <li class="nav-item text-center" <?php if ( ! $data['show'] ) : ?>style="display: none;"<?php endif ?>>
45
+ <a class="nav-link<?php if ( $data['step'] == 1 ) : ?> active<?php endif ?>" href="#bookly-step-<?php echo $data['step'] ?>" data-toggle="bookly-tab"><span class="bookly-js-step-number"><?php echo $data['show'] ? $i++ : $i ?></span>. <?php echo esc_html( $data['title'] ) ?></a>
46
+ </li>
47
+ <?php endforeach ?>
48
+ </ul>
49
+ </div>
50
+ <div class="card-body">
51
+ <div id="bookly-appearance">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
 
53
+ <?php if ( ! get_user_meta( get_current_user_id(), Lib\Plugin::getPrefix() . 'dismiss_appearance_notice', true ) ): ?>
54
+ <div class="alert alert-info alert-dismissible my-2" id="bookly-js-hint-alert" role="alert">
55
+ <button type="button" class="close" data-dismiss="alert">&times;</button>
56
+ <p>
57
+ <?php esc_html_e( 'Click on the underlined text to edit.', 'bookly' ) ?>
58
+ </p>
59
+ <p class="mb-0"><?php esc_html_e( 'How to publish this form on your web site?', 'bookly' ) ?>
60
+ <br/>
61
+ <?php esc_html_e( 'Open the page where you want to add the booking form in page edit mode and click on the "Add Bookly booking form" button. Choose which fields you\'d like to keep or remove from the booking form. Click Insert, and the booking form will be added to the page.', 'bookly' ) ?>
62
+ <a href="<?php echo Bookly\Lib\Utils\Common::prepareUrlReferrers( 'https://support.booking-wp-plugin.com/hc/en-us/articles/212800185-Publish-Booking-Form', 'appearance' ) ?>" target="_blank"><?php esc_html_e( 'Read more', 'bookly' ) ?></a>
63
+ </p>
64
+ </div>
65
+ <?php endif ?>
66
 
67
+ <div id="bookly-step-settings">
68
+ <div class="bookly-js-service-settings">
69
+ <div class="row">
70
+ <div class="col-md-3 my-2">
71
+ <?php Inputs::renderCheckBox( __( 'Make selecting employee required', 'bookly' ), null, get_option( 'bookly_app_required_employee' ), array( 'id' => 'bookly-required-employee' ) ) ?>
 
 
 
 
 
 
 
 
72
  </div>
73
+ <div class="col-md-3 my-2">
74
+ <?php Inputs::renderCheckBox( __( 'Show service price next to employee name', 'bookly' ), null, get_option( 'bookly_app_staff_name_with_price' ), array( 'id' => 'bookly-staff-name-with-price' ) ) ?>
 
 
 
 
 
75
  </div>
76
+ <div class="col-md-3 my-2">
77
+ <?php Inputs::renderCheckBox( __( 'Show service duration next to service name', 'bookly' ), null, get_option( 'bookly_app_service_name_with_duration' ), array( 'id' => 'bookly-service-name-with-duration' ) ) ?>
 
 
 
 
 
78
  </div>
79
  <?php Proxy\Shared::renderServiceStepSettings() ?>
80
  </div>
81
+ </div>
82
+ <div class="bookly-js-time-settings collapse">
83
+ <div class="row">
84
+ <div class="col-md-3 my-2">
85
+ <?php Inputs::renderCheckBox( __( 'Show calendar', 'bookly' ), null, get_option( 'bookly_app_show_calendar' ), array( 'id' => 'bookly-show-calendar' ) ) ?>
 
 
 
86
  </div>
87
+ <div class="col-md-3 my-2">
88
+ <?php Inputs::renderCheckBox( __( 'Show blocked timeslots', 'bookly' ), null, get_option( 'bookly_app_show_blocked_timeslots' ), array( 'id' => 'bookly-show-blocked-timeslots' ) ) ?>
 
 
 
 
 
89
  </div>
90
+ <div class="col-md-3 my-2">
91
+ <?php Inputs::renderCheckBox( __( 'Show each day in one column', 'bookly' ), null, get_option( 'bookly_app_show_day_one_column' ), array( 'id' => 'bookly-show-day-one-column' ) ) ?>
 
 
 
 
 
92
  </div>
93
  <?php Proxy\Pro::renderTimeZoneSwitcherCheckbox() ?>
94
  <?php Proxy\Shared::renderTimeStepSettings() ?>
95
  </div>
96
+ </div>
97
 
98
+ <?php Proxy\Cart::renderCartStepSettings() ?>
99
+ <?php Proxy\ServiceExtras::renderStepSettings() ?>
 
 
100
 
101
+ <div class="bookly-js-details-settings collapse">
102
+ <div class="row">
103
  <div class="col-md-3">
104
+ <div class="form-group mb-0">
105
+ <select id="bookly-cst-required-details" class="form-control custom-select" data-default="<?php echo ! array_diff( array( 'phone', 'email' ), get_option( 'bookly_cst_required_details', array() ) ) ? 'both' : current( get_option( 'bookly_cst_required_details', array() ) ) ?>">
106
+ <option value="phone"<?php selected( in_array( 'phone', get_option( 'bookly_cst_required_details', array() ) ) && ! in_array( 'email', get_option( 'bookly_cst_required_details', array() ) ) ) ?><?php disabled( get_option( 'bookly_cst_create_account' ) ) ?>><?php esc_html_e( 'Phone field required', 'bookly' ) ?></option>
107
+ <option value="email"<?php selected( in_array( 'email', get_option( 'bookly_cst_required_details', array() ) ) && ! in_array( 'phone', get_option( 'bookly_cst_required_details', array() ) ) ) ?>><?php esc_html_e( 'Email field required', 'bookly' ) ?></option>
108
+ <option value="both"<?php selected( ! array_diff( array( 'phone', 'email' ), get_option( 'bookly_cst_required_details', array() ) ) ) ?>><?php esc_html_e( 'Both email and phone fields required', 'bookly' ) ?></option>
109
+ </select>
 
 
 
 
 
 
110
  </div>
111
  </div>
112
+ <div class="col-md-3 my-2">
113
+ <?php Inputs::renderCheckBox( __( 'Show Login button', 'bookly' ), null, get_option( 'bookly_app_show_login_button' ), array( 'id' => 'bookly-show-login-button' ) ) ?>
 
 
 
 
 
114
  </div>
115
+ <div class="col-md-3 my-2">
116
+ <div id="bookly-cst-first-last-name-popover" data-container="#bookly-cst-first-last-name-popover" data-toggle="bookly-popover" data-trigger="focus" data-placement="bottom" data-content="<?php esc_attr_e( 'Do not forget to update your email and SMS codes for customer names', 'bookly' ) ?>">
117
+ <?php Inputs::renderCheckBox( __( 'Use first and last name instead of full name', 'bookly' ), null, get_option( 'bookly_cst_first_last_name' ), array( 'id' => 'bookly-cst-first-last-name' ) ) ?>
 
 
 
118
  </div>
119
  </div>
120
+ <div class="col-md-3 my-2">
121
+ <?php Inputs::renderCheckBox( __( 'Email confirmation field', 'bookly' ), null, get_option( 'bookly_app_show_email_confirm' ), array( 'id' => 'bookly-cst-show-email-confirm' ) ) ?>
122
+ </div>
123
+ <div class="col-md-3 my-2">
124
+ <?php Inputs::renderCheckBox( __( 'Show notes field', 'bookly' ), null, get_option( 'bookly_app_show_notes' ), array( 'id' => 'bookly-show-notes' ) ) ?>
 
 
125
  </div>
126
  <?php Proxy\Pro::renderShowBirthday() ?>
127
  <?php Proxy\Pro::renderShowAddress() ?>
131
  <?php Proxy\CustomerInformation::renderShowCustomerInformation() ?>
132
  <?php Proxy\Pro::renderShowFacebookButton() ?>
133
  </div>
134
+ </div>
135
+ <div class="bookly-js-payment-settings collapse">
136
+ <div class="row">
137
  <?php Proxy\Coupons::renderShowCoupons() ?>
 
138
  </div>
139
+ <?php Proxy\Pro::renderBookingStatesSelector() ?>
140
+ </div>
141
 
142
+ <div class="bookly-js-done-settings collapse">
143
+ <div class="alert alert-info">
144
+ <div class="d-flex">
145
+ <div class="mr-3"><i class="fas fa-info-circle fa-2x"></i></div>
146
+ <div class="flex-fill">
147
+ <div>
148
+ <?php esc_html_e( 'The booking form on this step may have different set or states of its elements. It depends on various conditions such as installed/activated add-ons, settings configuration or choices made on previous steps. Select option and click on the underlined text to edit.', 'bookly' ) ?>
149
+ </div>
150
+ <div class="mt-2">
151
+ <select id="bookly-done-step-view" class="form-control custom-select">
152
+ <option value="booking-success"><?php esc_html_e( 'Form view in case of successful booking', 'bookly' ) ?></option>
153
+ <option value="booking-limit-error"><?php esc_html_e( 'Form view in case the number of bookings exceeds the limit', 'bookly' ) ?></option>
154
+ <option value="booking-processing"><?php esc_html_e( 'Form view in case of payment has been accepted for processing', 'bookly' ) ?></option>
155
+ </select>
 
 
 
156
  </div>
157
  </div>
158
  </div>
159
  </div>
160
  </div>
161
+ </div>
162
 
163
+ <div class="card my-2">
164
+ <div class="card-body">
165
+ <div class="tab-content">
166
+ <?php foreach ( $steps as $step => $step_name ) : ?>
167
+ <div id="bookly-step-<?php echo $step ?>" class="tab-pane <?php if ( $step == 1 ) : ?>active<?php endif ?>" data-target="<?php echo $step ?>">
168
+ <?php // Render unique data per step
169
+ switch ( $step ) :
170
+ case 1: include '_1_service.php'; break;
171
+ case 2: Proxy\ServiceExtras::renderStep( $self::renderTemplate( '_progress_tracker', compact( 'step' ), false ) );
172
+ break;
173
+ case 3: include '_3_time.php'; break;
174
+ case 4: Proxy\RecurringAppointments::renderStep( $self::renderTemplate( '_progress_tracker', compact( 'step' ), false ) );
175
+ break;
176
+ case 5: Proxy\Cart::renderStep( $self::renderTemplate( '_progress_tracker', compact( 'step' ), false ) );
177
+ break;
178
+ case 6: include '_6_details.php'; break;
179
+ case 7: include '_7_payment.php'; break;
180
+ case 8: include '_8_complete.php'; break;
181
+ endswitch ?>
182
+ </div>
183
+ <?php endforeach ?>
 
184
  </div>
185
  </div>
186
+ </div>
187
+ <div>
188
+ <?php $self::renderTemplate( '_custom_css', array( 'custom_css' => $custom_css ) ) ?>
189
  </div>
190
  </div>
191
+ </div>
192
+ <div class="card-footer bg-transparent text-right">
193
+ <?php Buttons::renderSubmit( 'ajax-send-appearance' ) ?>
194
+ <?php Buttons::renderReset() ?>
195
  </div>
196
  </div>
197
  </div>
backend/modules/appointments/Ajax.php CHANGED
@@ -248,7 +248,7 @@ class Ajax extends Lib\Base\Ajax
248
  $extras = (array) Lib\Proxy\ServiceExtras::getInfo( json_decode( $row['extras'], true ), false );
249
  if ( $row['extras_multiply_nop'] && $row['number_of_persons'] > 1 ) {
250
  foreach ( $extras as $index => $extra ) {
251
- $extras[ $index ]['title'] = '<i class="fa fa-user"></i>&nbsp;' . $row['number_of_persons'] . '&nbsp;&times;&nbsp;' . $extra['title'];
252
  }
253
  }
254
  } else {
@@ -289,11 +289,6 @@ class Ajax extends Lib\Base\Ajax
289
  $custom_fields = array_map( function () { return ''; }, $custom_fields );
290
  }
291
 
292
- return array(
293
- 'data' => $data,
294
- 'total' => $total,
295
- 'filtered' => $filtered,
296
- );
297
-
298
  }
299
  }
248
  $extras = (array) Lib\Proxy\ServiceExtras::getInfo( json_decode( $row['extras'], true ), false );
249
  if ( $row['extras_multiply_nop'] && $row['number_of_persons'] > 1 ) {
250
  foreach ( $extras as $index => $extra ) {
251
+ $extras[ $index ]['title'] = '<i class="far fa-user"></i>&nbsp;' . $row['number_of_persons'] . '&nbsp;&times;&nbsp;' . $extra['title'];
252
  }
253
  }
254
  } else {
289
  $custom_fields = array_map( function () { return ''; }, $custom_fields );
290
  }
291
 
292
+ return compact( 'data', 'total', 'filtered' );
 
 
 
 
 
293
  }
294
  }
backend/modules/appointments/Page.php CHANGED
@@ -16,11 +16,7 @@ class Page extends Lib\Base\Component
16
  {
17
  self::enqueueStyles( array(
18
  'frontend' => array( 'css/ladda.min.css', ),
19
- 'backend' => array(
20
- 'css/select2.min.css',
21
- 'bootstrap/css/bootstrap-theme.min.css',
22
- 'css/daterangepicker.css',
23
- ),
24
  ) );
25
 
26
  self::enqueueScripts( array(
@@ -29,7 +25,7 @@ class Page extends Lib\Base\Component
29
  'js/datatables.min.js' => array( 'jquery' ),
30
  'js/moment.min.js',
31
  'js/daterangepicker.js' => array( 'jquery' ),
32
- 'js/select2.full.min.js' => array( 'jquery' ),
33
  ),
34
  'frontend' => array(
35
  'js/spin.min.js' => array( 'jquery' ),
16
  {
17
  self::enqueueStyles( array(
18
  'frontend' => array( 'css/ladda.min.css', ),
19
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
 
 
 
 
20
  ) );
21
 
22
  self::enqueueScripts( array(
25
  'js/datatables.min.js' => array( 'jquery' ),
26
  'js/moment.min.js',
27
  'js/daterangepicker.js' => array( 'jquery' ),
28
+ 'js/select2.min.js' => array( 'jquery' ),
29
  ),
30
  'frontend' => array(
31
  'js/spin.min.js' => array( 'jquery' ),
backend/modules/appointments/resources/js/appointments.js CHANGED
@@ -1,5 +1,5 @@
1
  jQuery(function($) {
2
-
3
  let
4
  $appointmentsList = $('#bookly-appointments-list'),
5
  $checkAllButton = $('#bookly-check-all'),
@@ -10,9 +10,9 @@ jQuery(function($) {
10
  $customerFilter = $('#bookly-filter-customer'),
11
  $serviceFilter = $('#bookly-filter-service'),
12
  $statusFilter = $('#bookly-filter-status'),
13
- $addButton = $('#bookly-add'),
14
  $printDialog = $('#bookly-print-dialog'),
15
- $printButton = $('#bookly-print'),
16
  $exportDialog = $('#bookly-export-dialog'),
17
  $exportForm = $('form', $exportDialog),
18
  $deleteButton = $('#bookly-delete'),
@@ -57,7 +57,7 @@ jQuery(function($) {
57
  $appointmentDateFilter
58
  .data('date', pickers.appointmentDate.startDate.format(pickers.dateFormat) + ' - ' + pickers.appointmentDate.endDate.format(pickers.dateFormat))
59
  .find('span')
60
- .html(pickers.appointmentDate.startDate.format(BooklyL10n.dateRange.dateFormat) + ' - ' + pickers.appointmentDate.endDate.format(BooklyL10n.dateRange.dateFormat));
61
  }
62
  } else if (params[0] == 'tasks') {
63
  $appointmentDateFilter
@@ -69,7 +69,7 @@ jQuery(function($) {
69
  $creationDateFilter
70
  .data('date', pickers.creationDate.startDate.format(pickers.dateFormat) + ' - ' + pickers.creationDate.endDate.format(pickers.dateFormat))
71
  .find('span')
72
- .html(pickers.creationDate.startDate.format(BooklyL10n.dateRange.dateFormat) + ' - ' + pickers.creationDate.endDate.format(BooklyL10n.dateRange.dateFormat));
73
  } else {
74
  $('#bookly-filter-' + params[0]).val(params[1]);
75
  }
@@ -140,7 +140,7 @@ jQuery(function($) {
140
  data: 'payment',
141
  render: function ( data, type, row, meta ) {
142
  if (row.payment_id) {
143
- return '<a role="button" data-action="show-payment" data-payment_id="' + row.payment_id + '">' + data + '</a>';
144
  }
145
  return '';
146
  }
@@ -154,7 +154,7 @@ jQuery(function($) {
154
  data: 'attachment',
155
  render: function (data, type, row, meta) {
156
  if (data == '1') {
157
- return '<button type="button" class="btn btn-link" data-action="show-attachments" title="' + BooklyL10n.attachments + '"><span class="dashicons dashicons-paperclip"></span></button>';
158
  }
159
  return '';
160
  }
@@ -167,7 +167,7 @@ jQuery(function($) {
167
  if (row.rating_comment == null) {
168
  return row.rating;
169
  } else {
170
- return '<a href="#" data-toggle="popover" data-trigger="focus" data-placement="bottom" data-content="' + $.fn.dataTable.render.text().display(row.rating_comment) + '">' + $.fn.dataTable.render.text().display(row.rating) + '</a>';
171
  }
172
  },
173
  });
@@ -192,16 +192,20 @@ jQuery(function($) {
192
  });
193
  columns.push({
194
  responsivePriority: 1,
195
- orderable : false,
196
- render : function (data, type, row, meta) {
197
- return '<button type="button" class="btn btn-default" data-action="edit"><i class="glyphicon glyphicon-edit"></i> ' + BooklyL10n.edit + '</a>';
 
198
  }
199
  });
200
  columns.push({
201
  responsivePriority: 1,
202
  orderable : false,
203
  render : function (data, type, row, meta) {
204
- return '<input type="checkbox" value="' + row.ca_id + '" data-appointment="' + row.id + '" />';
 
 
 
205
  }
206
  });
207
 
@@ -225,9 +229,9 @@ jQuery(function($) {
225
  pagingType : 'numbers',
226
  serverSide : true,
227
  drawCallback: function( settings ) {
228
- $('[data-toggle="popover"]').on('click', function (e) {
229
  e.preventDefault();
230
- }).popover();
231
  dt.responsive.recalc();
232
  },
233
  ajax: {
@@ -248,19 +252,26 @@ jQuery(function($) {
248
  }
249
  },
250
  columns: columns,
251
- dom: "<'row'<'col-sm-6'l><'col-sm-6'f>>" +
252
- "<'row'<'col-sm-12'tr>>" +
253
- "<'row pull-left'<'col-sm-12 bookly-margin-top-lg'p>>",
254
  language: {
255
  zeroRecords: BooklyL10n.zeroRecords,
256
  processing: BooklyL10n.processing
257
  }
258
  });
259
 
 
 
 
 
 
 
 
 
 
260
  /**
261
  * Add appointment.
262
  */
263
- $addButton.on('click', function () {
264
  showAppointmentDialog(
265
  null,
266
  null,
@@ -275,7 +286,7 @@ jQuery(function($) {
275
  * Export.
276
  */
277
  $exportForm.on('submit', function () {
278
- $exportDialog.find('[name="filter"]').val(JSON.stringify({
279
  id : $idFilter.val(),
280
  date : $appointmentDateFilter.data('date'),
281
  created_date: $creationDateFilter.data('date'),
@@ -284,7 +295,7 @@ jQuery(function($) {
284
  service : $serviceFilter.val(),
285
  status : $statusFilter.val()
286
  }));
287
- $exportDialog.modal('hide');
288
 
289
  return true;
290
  });
@@ -294,7 +305,7 @@ jQuery(function($) {
294
  */
295
  $printButton.on('click', function () {
296
  var columns = [];
297
- $printDialog.find('input:checked').each(function () {
298
  columns.push(this.value);
299
  });
300
  var config = {
@@ -325,7 +336,7 @@ jQuery(function($) {
325
  })
326
  // Show payment details
327
  .on('click', '[data-action=show-payment]', function () {
328
- $('#bookly-payment-details-modal').modal('show', this);
329
  })
330
  // Edit appointment.
331
  .on('click', '[data-action=edit]', function (e) {
@@ -339,7 +350,7 @@ jQuery(function($) {
339
  dt.ajax.reload();
340
  }
341
  )
342
- });;
343
 
344
  /**
345
  * Delete appointments.
@@ -367,7 +378,7 @@ jQuery(function($) {
367
  dataType : 'json',
368
  success : function(response) {
369
  ladda.stop();
370
- $('#bookly-delete-dialog').modal('hide');
371
  if (response.success) {
372
  dt.draw(false);
373
  if (response.data && response.data.queue && response.data.queue.length) {
@@ -383,15 +394,8 @@ jQuery(function($) {
383
  /**
384
  * Init date range pickers.
385
  */
386
- moment.locale('en', {
387
- months : BooklyL10n.datePicker.monthNames,
388
- monthsShort : BooklyL10n.datePicker.monthNamesShort,
389
- weekdays : BooklyL10n.datePicker.dayNames,
390
- weekdaysShort: BooklyL10n.datePicker.dayNamesShort,
391
- weekdaysMin : BooklyL10n.datePicker.dayNamesMin
392
- });
393
 
394
- var
395
  pickerRanges1 = {},
396
  pickerRanges2 = {}
397
  ;
@@ -414,18 +418,10 @@ jQuery(function($) {
414
  startDate: pickers.appointmentDate.startDate,
415
  endDate : pickers.appointmentDate.endDate,
416
  ranges : pickerRanges1,
 
 
417
  autoUpdateInput: false,
418
- locale: {
419
- applyLabel : BooklyL10n.dateRange.apply,
420
- cancelLabel: BooklyL10n.dateRange.cancel,
421
- fromLabel : BooklyL10n.dateRange.from,
422
- toLabel : BooklyL10n.dateRange.to,
423
- customRangeLabel: BooklyL10n.dateRange.customRange,
424
- daysOfWeek : BooklyL10n.datePicker.dayNamesShort,
425
- monthNames : BooklyL10n.datePicker.monthNames,
426
- firstDay : parseInt(BooklyL10n.dateRange.firstDay),
427
- format : BooklyL10n.dateRange.dateFormat
428
- }
429
  },
430
  function(start, end, label) {
431
  switch (label) {
@@ -445,7 +441,7 @@ jQuery(function($) {
445
  $appointmentDateFilter
446
  .data('date', start.format(pickers.dateFormat) + ' - ' + end.format(pickers.dateFormat))
447
  .find('span')
448
- .html(start.format(BooklyL10n.dateRange.dateFormat) + ' - ' + end.format(BooklyL10n.dateRange.dateFormat));
449
  }
450
  }
451
  );
@@ -456,18 +452,10 @@ jQuery(function($) {
456
  startDate: pickers.creationDate.startDate,
457
  endDate : pickers.creationDate.endDate,
458
  ranges: pickerRanges2,
 
 
459
  autoUpdateInput: false,
460
- locale: {
461
- applyLabel : BooklyL10n.dateRange.apply,
462
- cancelLabel: BooklyL10n.dateRange.cancel,
463
- fromLabel : BooklyL10n.dateRange.from,
464
- toLabel : BooklyL10n.dateRange.to,
465
- customRangeLabel: BooklyL10n.dateRange.customRange,
466
- daysOfWeek : BooklyL10n.datePicker.dayNamesShort,
467
- monthNames : BooklyL10n.datePicker.monthNames,
468
- firstDay : parseInt(BooklyL10n.dateRange.firstDay),
469
- format : BooklyL10n.dateRange.dateFormat
470
- }
471
  },
472
  function(start, end, label) {
473
  switch (label) {
@@ -487,7 +475,7 @@ jQuery(function($) {
487
  $creationDateFilter
488
  .data('date', start.format(pickers.dateFormat) + ' - ' + end.format(pickers.dateFormat))
489
  .find('span')
490
- .html(start.format(BooklyL10n.dateRange.dateFormat) + ' - ' + end.format(BooklyL10n.dateRange.dateFormat));
491
  }
492
  }
493
  );
@@ -498,10 +486,11 @@ jQuery(function($) {
498
  $('.bookly-js-select')
499
  .select2({
500
  width: '100%',
501
- theme: 'bootstrap',
 
502
  allowClear: true,
503
  placeholder: '',
504
- language : {
505
  noResults: function() { return BooklyL10n.no_result_found; }
506
  },
507
  matcher: function (params, data) {
@@ -526,11 +515,12 @@ jQuery(function($) {
526
  $('.bookly-js-select-ajax')
527
  .select2({
528
  width: '100%',
529
- theme: 'bootstrap',
 
530
  allowClear: true,
531
  placeholder: '',
532
  language : {
533
- noResults: function() { return BooklyL10n.no_result_found; },
534
  searching: function () { return BooklyL10n.searching; }
535
  },
536
  ajax: {
@@ -556,5 +546,4 @@ jQuery(function($) {
556
  $customerFilter.on('change', function () { dt.ajax.reload(); });
557
  $serviceFilter.on('change', function () { dt.ajax.reload(); });
558
  $statusFilter.on('change', function () { dt.ajax.reload(); });
559
-
560
  });
1
  jQuery(function($) {
2
+ 'use strict';
3
  let
4
  $appointmentsList = $('#bookly-appointments-list'),
5
  $checkAllButton = $('#bookly-check-all'),
10
  $customerFilter = $('#bookly-filter-customer'),
11
  $serviceFilter = $('#bookly-filter-service'),
12
  $statusFilter = $('#bookly-filter-status'),
13
+ $newAppointmentBtn = $('#bookly-new-appointment'),
14
  $printDialog = $('#bookly-print-dialog'),
15
+ $printButton = $(':submit',$printDialog),
16
  $exportDialog = $('#bookly-export-dialog'),
17
  $exportForm = $('form', $exportDialog),
18
  $deleteButton = $('#bookly-delete'),
57
  $appointmentDateFilter
58
  .data('date', pickers.appointmentDate.startDate.format(pickers.dateFormat) + ' - ' + pickers.appointmentDate.endDate.format(pickers.dateFormat))
59
  .find('span')
60
+ .html(pickers.appointmentDate.startDate.format(BooklyL10n.dateRange.format) + ' - ' + pickers.appointmentDate.endDate.format(BooklyL10n.dateRange.format));
61
  }
62
  } else if (params[0] == 'tasks') {
63
  $appointmentDateFilter
69
  $creationDateFilter
70
  .data('date', pickers.creationDate.startDate.format(pickers.dateFormat) + ' - ' + pickers.creationDate.endDate.format(pickers.dateFormat))
71
  .find('span')
72
+ .html(pickers.creationDate.startDate.format(BooklyL10n.dateRange.format) + ' - ' + pickers.creationDate.endDate.format(BooklyL10n.dateRange.format));
73
  } else {
74
  $('#bookly-filter-' + params[0]).val(params[1]);
75
  }
140
  data: 'payment',
141
  render: function ( data, type, row, meta ) {
142
  if (row.payment_id) {
143
+ return '<a type="button" data-action="show-payment" class="text-primary" data-payment_id="' + row.payment_id + '">' + data + '</a>';
144
  }
145
  return '';
146
  }
154
  data: 'attachment',
155
  render: function (data, type, row, meta) {
156
  if (data == '1') {
157
+ return '<button type="button" class="btn btn-link" data-action="show-attachments" title="' + BooklyL10n.attachments + '"><i class="fas fa-fw fa-paperclip"></i></button>';
158
  }
159
  return '';
160
  }
167
  if (row.rating_comment == null) {
168
  return row.rating;
169
  } else {
170
+ return '<a href="#" data-toggle="bookly-popover" data-trigger="hover" data-placement="bottom" data-content="' + $.fn.dataTable.render.text().display(row.rating_comment) + '" data-container="#bookly-appointments-list">' + $.fn.dataTable.render.text().display(row.rating) + '</a>';
171
  }
172
  },
173
  });
192
  });
193
  columns.push({
194
  responsivePriority: 1,
195
+ orderable : false,
196
+ width : 120,
197
+ render : function (data, type, row, meta) {
198
+ return '<button type="button" class="btn btn-default" data-action="edit"><i class="far fa-fw fa-edit mr-1"></i>' + BooklyL10n.edit + '…</a>';
199
  }
200
  });
201
  columns.push({
202
  responsivePriority: 1,
203
  orderable : false,
204
  render : function (data, type, row, meta) {
205
+ return '<div class="custom-control custom-checkbox">' +
206
+ '<input value="' + row.ca_id + '" data-appointment="' + row.id + '" id="bookly-dt-' + row.ca_id + '" type="checkbox" class="custom-control-input">' +
207
+ '<label for="bookly-dt-' + row.ca_id + '" class="custom-control-label"></label>' +
208
+ '</div>';
209
  }
210
  });
211
 
229
  pagingType : 'numbers',
230
  serverSide : true,
231
  drawCallback: function( settings ) {
232
+ $('[data-toggle="bookly-popover"]', $appointmentsList).on('click', function (e) {
233
  e.preventDefault();
234
+ }).booklyPopover();
235
  dt.responsive.recalc();
236
  },
237
  ajax: {
252
  }
253
  },
254
  columns: columns,
255
+ dom : "<'row'<'col-sm-12'tr>><'row float-left mt-3'<'col-sm-12'p>>",
 
 
256
  language: {
257
  zeroRecords: BooklyL10n.zeroRecords,
258
  processing: BooklyL10n.processing
259
  }
260
  });
261
 
262
+ // Show ratings in expanded rows.
263
+ dt.on( 'responsive-display', function (e, datatable, row, showHide, update) {
264
+ if (showHide) {
265
+ $('[data-toggle="bookly-popover"]', row.child()).on('click', function (e) {
266
+ e.preventDefault();
267
+ }).booklyPopover();
268
+ }
269
+ });
270
+
271
  /**
272
  * Add appointment.
273
  */
274
+ $newAppointmentBtn.on('click', function () {
275
  showAppointmentDialog(
276
  null,
277
  null,
286
  * Export.
287
  */
288
  $exportForm.on('submit', function () {
289
+ $('[name="filter"]', $exportDialog).val(JSON.stringify({
290
  id : $idFilter.val(),
291
  date : $appointmentDateFilter.data('date'),
292
  created_date: $creationDateFilter.data('date'),
295
  service : $serviceFilter.val(),
296
  status : $statusFilter.val()
297
  }));
298
+ $exportDialog.booklyModal('hide');
299
 
300
  return true;
301
  });
305
  */
306
  $printButton.on('click', function () {
307
  var columns = [];
308
+ $('input:checked', $printDialog).each(function () {
309
  columns.push(this.value);
310
  });
311
  var config = {
336
  })
337
  // Show payment details
338
  .on('click', '[data-action=show-payment]', function () {
339
+ $('#bookly-payment-details-modal').booklyModal('show', this);
340
  })
341
  // Edit appointment.
342
  .on('click', '[data-action=edit]', function (e) {
350
  dt.ajax.reload();
351
  }
352
  )
353
+ });
354
 
355
  /**
356
  * Delete appointments.
378
  dataType : 'json',
379
  success : function(response) {
380
  ladda.stop();
381
+ $('#bookly-delete-dialog').booklyModal('hide');
382
  if (response.success) {
383
  dt.draw(false);
384
  if (response.data && response.data.queue && response.data.queue.length) {
394
  /**
395
  * Init date range pickers.
396
  */
 
 
 
 
 
 
 
397
 
398
+ let
399
  pickerRanges1 = {},
400
  pickerRanges2 = {}
401
  ;
418
  startDate: pickers.appointmentDate.startDate,
419
  endDate : pickers.appointmentDate.endDate,
420
  ranges : pickerRanges1,
421
+ showDropdowns : true,
422
+ linkedCalendars: false,
423
  autoUpdateInput: false,
424
+ locale: $.extend({},BooklyL10n.dateRange, BooklyL10n.datePicker)
 
 
 
 
 
 
 
 
 
 
425
  },
426
  function(start, end, label) {
427
  switch (label) {
441
  $appointmentDateFilter
442
  .data('date', start.format(pickers.dateFormat) + ' - ' + end.format(pickers.dateFormat))
443
  .find('span')
444
+ .html(start.format(BooklyL10n.dateRange.format) + ' - ' + end.format(BooklyL10n.dateRange.format));
445
  }
446
  }
447
  );
452
  startDate: pickers.creationDate.startDate,
453
  endDate : pickers.creationDate.endDate,
454
  ranges: pickerRanges2,
455
+ showDropdowns : true,
456
+ linkedCalendars: false,
457
  autoUpdateInput: false,
458
+ locale: $.extend(BooklyL10n.dateRange, BooklyL10n.datePicker)
 
 
 
 
 
 
 
 
 
 
459
  },
460
  function(start, end, label) {
461
  switch (label) {
475
  $creationDateFilter
476
  .data('date', start.format(pickers.dateFormat) + ' - ' + end.format(pickers.dateFormat))
477
  .find('span')
478
+ .html(start.format(BooklyL10n.dateRange.format) + ' - ' + end.format(BooklyL10n.dateRange.format));
479
  }
480
  }
481
  );
486
  $('.bookly-js-select')
487
  .select2({
488
  width: '100%',
489
+ theme: 'bootstrap4',
490
+ dropdownParent: '#bookly-tbs',
491
  allowClear: true,
492
  placeholder: '',
493
+ language: {
494
  noResults: function() { return BooklyL10n.no_result_found; }
495
  },
496
  matcher: function (params, data) {
515
  $('.bookly-js-select-ajax')
516
  .select2({
517
  width: '100%',
518
+ theme: 'bootstrap4',
519
+ dropdownParent: '#bookly-tbs',
520
  allowClear: true,
521
  placeholder: '',
522
  language : {
523
+ noResults: function () { return BooklyL10n.no_result_found; },
524
  searching: function () { return BooklyL10n.searching; }
525
  },
526
  ajax: {
546
  $customerFilter.on('change', function () { dt.ajax.reload(); });
547
  $serviceFilter.on('change', function () { dt.ajax.reload(); });
548
  $statusFilter.on('change', function () { dt.ajax.reload(); });
 
549
  });
backend/modules/appointments/templates/index.php CHANGED
@@ -9,121 +9,109 @@ use Bookly\Lib\Utils\DateTime;
9
  /** @var array $datatables */
10
  ?>
11
  <div id="bookly-tbs" class="wrap">
12
- <div class="bookly-tbs-body">
13
- <div class="page-header text-right clearfix">
14
- <div class="bookly-page-title">
15
- <?php _e( 'Appointments', 'bookly' ) ?>
 
 
 
 
 
 
 
 
 
16
  </div>
17
- <?php Support\Buttons::render( $self::pageSlug() ) ?>
18
- </div>
19
- <div class="panel panel-default bookly-main">
20
- <div class="panel-body">
21
- <div class="row">
22
- <div class="col-xs-12">
23
- <div class="form-inline bookly-margin-bottom-lg text-right">
24
- <?php Proxy\Pro::renderExportButton() ?>
25
- <?php Proxy\Pro::renderPrintButton() ?>
26
- <div class="form-group">
27
- <button type="button" class="btn btn-success bookly-btn-block-xs" id="bookly-add"><i class="glyphicon glyphicon-plus"></i> <?php esc_html_e( 'New appointment', 'bookly' ) ?>...</button>
28
- </div>
29
- <?php Dialogs\TableSettings\Dialog::renderButton( 'appointments' ) ?>
30
- </div>
31
  </div>
32
  </div>
33
- <div class="row">
34
- <div class="col-md-3 col-lg-1">
35
- <div class="form-group">
36
- <input class="form-control" type="text" id="bookly-filter-id" placeholder="<?php esc_attr_e( 'No.', 'bookly' ) ?>"/>
37
- </div>
38
- </div>
39
- <div class="col-md-3 col-lg-2">
40
- <div class="bookly-margin-bottom-lg bookly-relative">
41
- <button type="button" class="btn btn-block btn-default" id="bookly-filter-date" data-date="<?php echo date( 'Y-m-d', strtotime( 'first day of' ) ) ?> - <?php echo date( 'Y-m-d', strtotime( 'last day of' ) ) ?>">
42
- <i class="dashicons dashicons-calendar-alt"></i>
43
- <span>
44
- <?php echo DateTime::formatDate( 'first day of this month' ) ?> - <?php echo DateTime::formatDate( 'last day of this month' ) ?>
45
- </span>
46
- </button>
47
- </div>
48
- </div>
49
- <div class="col-md-3 col-lg-2">
50
- <div class="bookly-margin-bottom-lg bookly-relative">
51
- <button type="button" class="btn btn-block btn-default" id="bookly-filter-creation-date" data-date="any">
52
- <i class="dashicons dashicons-calendar-alt"></i>
53
- <span>
54
- <?php esc_html_e( 'Created at any time', 'bookly' ) ?>
55
- </span>
56
- </button>
57
- </div>
58
- </div>
59
- <div class="col-md-3 col-lg-2">
60
- <div class="form-group">
61
- <select class="form-control bookly-js-select" id="bookly-filter-staff" data-placeholder="<?php echo esc_attr( Common::getTranslatedOption( 'bookly_l10n_label_employee' ) ) ?>">
62
- <?php foreach ( $staff_members as $staff ) : ?>
63
- <option value="<?php echo $staff['id'] ?>"><?php echo esc_html( $staff['full_name'] ) ?></option>
64
- <?php endforeach ?>
65
- </select>
66
- </div>
67
  </div>
68
- <div class="clearfix visible-md-block"></div>
69
- <div class="col-md-3 col-lg-2">
70
- <div class="form-group">
71
- <select class="form-control <?php echo $customers === false ? 'bookly-js-select-ajax' : 'bookly-js-select' ?>" id="bookly-filter-customer" data-placeholder="<?php esc_attr_e( 'Customer', 'bookly' ) ?>" <?php echo $customers === false ? 'data-ajax--action' : 'data-action' ?>="bookly_get_customers_list">
72
- <?php if ( $customers !== false ) : ?>
73
- <?php foreach ( $customers as $customer_id => $customer ) : ?>
74
- <option value="<?php echo $customer_id ?>" data-search='<?php echo json_encode( array_values( $customer ) ) ?>'><?php echo esc_html( $customer['full_name'] ) ?></option>
75
- <?php endforeach ?>
76
- <?php endif ?>
77
- </select>
78
- </div>
79
  </div>
80
- <div class="col-md-3 col-lg-2">
81
- <div class="form-group">
82
- <select class="form-control bookly-js-select" id="bookly-filter-service" data-placeholder="<?php echo esc_attr( Common::getTranslatedOption( 'bookly_l10n_label_service' ) ) ?>">
83
- <option value="0"><?php esc_html_e( 'Custom', 'bookly' ) ?></option>
84
- <?php foreach ( $services as $service ) : ?>
85
- <option value="<?php echo $service['id'] ?>"><?php echo esc_html( $service['title'] ) ?></option>
86
- <?php endforeach ?>
87
- </select>
88
- </div>
89
  </div>
90
- <div class="col-md-3 col-lg-1">
91
- <div class="form-group">
92
- <select class="form-control bookly-js-select" id="bookly-filter-status" data-placeholder="<?php esc_attr_e( 'Status', 'bookly' ) ?>">
93
- <?php foreach ( CustomerAppointment::getStatuses() as $status ): ?>
94
- <option value="<?php echo $status ?>"><?php echo esc_html( CustomerAppointment::statusToString( $status ) ) ?></option>
95
- <?php endforeach ?>
96
- </select>
97
- </div>
98
  </div>
99
  </div>
100
- <table id="bookly-appointments-list" class="table table-striped" width="100%">
101
- <thead>
102
- <tr>
103
- <?php foreach ( $datatables['appointments']['settings']['columns'] as $column => $show ) : ?>
104
- <?php if ( $show ) : ?>
105
- <th><?php echo $datatables['appointments']['titles'][ $column ] ?></th>
106
- <?php endif ?>
107
- <?php endforeach ?>
108
- <th></th>
109
- <th width="16"><input type="checkbox" id="bookly-check-all"/></th>
110
- </tr>
111
- </thead>
112
- </table>
 
113
 
114
- <div class="text-right bookly-margin-top-lg">
115
- <?php Controls\Buttons::renderModalActivator( 'bookly-delete-dialog', 'btn-danger', esc_html__( 'Delete', 'bookly' ) ) ?>
116
- </div>
117
  </div>
118
  </div>
 
119
 
120
- <?php Proxy\Pro::renderExportDialog( $datatables['appointments'] ) ?>
121
- <?php Proxy\Pro::renderPrintDialog( $datatables['appointments'] ) ?>
122
 
123
- <?php Dialogs\Appointment\Delete\Dialog::render() ?>
124
- <?php Dialogs\TableSettings\Dialog::render() ?>
125
- <?php Dialogs\Appointment\Edit\Dialog::render() ?>
126
- <?php Dialogs\Queue\Dialog::render() ?>
127
- <?php Proxy\Shared::renderAddOnsComponents() ?>
128
- </div>
129
  </div>
9
  /** @var array $datatables */
10
  ?>
11
  <div id="bookly-tbs" class="wrap">
12
+ <div class="form-row align-items-center mb-3">
13
+ <h4 class="col m-0"><?php esc_html_e( 'Appointments', 'bookly' ) ?></h4>
14
+ <?php Support\Buttons::render( $self::pageSlug() ) ?>
15
+ </div>
16
+ <div class="card">
17
+ <div class="card-body">
18
+ <div class="form-row justify-content-end">
19
+ <?php Proxy\Pro::renderExportButton() ?>
20
+ <?php Proxy\Pro::renderPrintButton() ?>
21
+ <div class="col-12 col-sm-auto">
22
+ <?php Controls\Buttons::render( 'bookly-new-appointment', 'btn-success w-100 mb-3', __( 'New appointment', 'bookly' ), array(), '<i class="fas fa-fw fa-plus"></i> {caption}…' ) ?>
23
+ </div>
24
+ <?php Dialogs\TableSettings\Dialog::renderButton( 'appointments' ) ?>
25
  </div>
26
+ <div class="form-row">
27
+ <div class="col-md-1">
28
+ <div class="form-group">
29
+ <input class="form-control" type="text" id="bookly-filter-id" placeholder="<?php esc_attr_e( 'No.', 'bookly' ) ?>"/>
 
 
 
 
 
 
 
 
 
 
30
  </div>
31
  </div>
32
+ <div class="col-md-2">
33
+ <button type="button" class="btn btn-default w-100 mb-3 text-truncate text-left" id="bookly-filter-date" data-date="<?php echo date( 'Y-m-d', strtotime( 'first day of' ) ) ?> - <?php echo date( 'Y-m-d', strtotime( 'last day of' ) ) ?>">
34
+ <i class="far fa-calendar-alt mr-1"></i>
35
+ <span>
36
+ <?php echo DateTime::formatDate( 'first day of this month' ) ?> - <?php echo DateTime::formatDate( 'last day of this month' ) ?>
37
+ </span>
38
+ </button>
39
+ </div>
40
+ <div class="col-md-2">
41
+ <button type="button" class="btn btn-default w-100 mb-3 text-truncate text-left" id="bookly-filter-creation-date" data-date="any">
42
+ <i class="far fa-calendar-alt mr-1"></i>
43
+ <span>
44
+ <?php esc_html_e( 'Created at any time', 'bookly' ) ?>
45
+ </span>
46
+ </button>
47
+ </div>
48
+ <div class="col-md-2">
49
+ <div class="form-group">
50
+ <select class="form-control bookly-js-select" id="bookly-filter-staff" data-placeholder="<?php echo esc_attr( Common::getTranslatedOption( 'bookly_l10n_label_employee' ) ) ?>">
51
+ <?php foreach ( $staff_members as $staff ) : ?>
52
+ <option value="<?php echo $staff['id'] ?>"><?php echo esc_html( $staff['full_name'] ) ?></option>
53
+ <?php endforeach ?>
54
+ </select>
 
 
 
 
 
 
 
 
 
 
 
55
  </div>
56
+ </div>
57
+ <div class="col-md-2">
58
+ <div class="form-group">
59
+ <select class="form-control <?php echo $customers === false ? 'bookly-js-select-ajax' : 'bookly-js-select' ?>" id="bookly-filter-customer"
60
+ data-placeholder="<?php esc_attr_e( 'Customer', 'bookly' ) ?>" <?php echo $customers === false ? 'data-ajax--action' : 'data-action' ?>="bookly_get_customers_list">
61
+ <?php if ( $customers !== false ) : ?>
62
+ <?php foreach ( $customers as $customer_id => $customer ) : ?>
63
+ <option value="<?php echo $customer_id ?>" data-search='<?php echo json_encode( array_values( $customer ) ) ?>'><?php echo esc_html( $customer['full_name'] ) ?></option>
64
+ <?php endforeach ?>
65
+ <?php endif ?>
66
+ </select>
67
  </div>
68
+ </div>
69
+ <div class="col-md-2">
70
+ <div class="form-group">
71
+ <select class="form-control bookly-js-select" id="bookly-filter-service" data-placeholder="<?php echo esc_attr( Common::getTranslatedOption( 'bookly_l10n_label_service' ) ) ?>">
72
+ <option value="0"><?php esc_html_e( 'Custom', 'bookly' ) ?></option>
73
+ <?php foreach ( $services as $service ) : ?>
74
+ <option value="<?php echo $service['id'] ?>"><?php echo esc_html( $service['title'] ) ?></option>
75
+ <?php endforeach ?>
76
+ </select>
77
  </div>
78
+ </div>
79
+ <div class="col-md-1">
80
+ <div class="form-group">
81
+ <select class="form-control bookly-js-select" id="bookly-filter-status" data-placeholder="<?php esc_attr_e( 'Status', 'bookly' ) ?>">
82
+ <?php foreach ( CustomerAppointment::getStatuses() as $status ): ?>
83
+ <option value="<?php echo $status ?>"><?php echo esc_html( CustomerAppointment::statusToString( $status ) ) ?></option>
84
+ <?php endforeach ?>
85
+ </select>
86
  </div>
87
  </div>
88
+ </div>
89
+ <table id="bookly-appointments-list" class="table table-striped w-100">
90
+ <thead>
91
+ <tr>
92
+ <?php foreach ( $datatables['appointments']['settings']['columns'] as $column => $show ) : ?>
93
+ <?php if ( $show ) : ?>
94
+ <th><?php echo $datatables['appointments']['titles'][ $column ] ?></th>
95
+ <?php endif ?>
96
+ <?php endforeach ?>
97
+ <th></th>
98
+ <th width="16"><?php Controls\Inputs::renderCheckBox( null, null, null, array( 'id' => 'bookly-check-all' ) ) ?></th>
99
+ </tr>
100
+ </thead>
101
+ </table>
102
 
103
+ <div class="text-right mt-3">
104
+ <?php Controls\Buttons::renderDelete( null, null, null, array( 'data-toggle' => 'bookly-modal', 'data-target' => '#bookly-delete-dialog' ) ) ?>
 
105
  </div>
106
  </div>
107
+ </div>
108
 
109
+ <?php Proxy\Pro::renderExportDialog( $datatables['appointments'] ) ?>
110
+ <?php Proxy\Pro::renderPrintDialog( $datatables['appointments'] ) ?>
111
 
112
+ <?php Dialogs\Appointment\Delete\Dialog::render() ?>
113
+ <?php Dialogs\TableSettings\Dialog::render() ?>
114
+ <?php Dialogs\Appointment\Edit\Dialog::render() ?>
115
+ <?php Dialogs\Queue\Dialog::render() ?>
116
+ <?php Proxy\Shared::renderAddOnsComponents() ?>
 
117
  </div>
backend/modules/calendar/Page.php CHANGED
@@ -16,7 +16,7 @@ class Page extends Lib\Base\Ajax
16
  {
17
  self::enqueueStyles( array(
18
  'module' => array( 'css/fullcalendar.min.css', ),
19
- 'backend' => array( 'bootstrap/css/bootstrap-theme.min.css' ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
16
  {
17
  self::enqueueStyles( array(
18
  'module' => array( 'css/fullcalendar.min.css', ),
19
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css' ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
backend/modules/calendar/resources/js/calendar-common.js CHANGED
@@ -1,4 +1,4 @@
1
- jQuery(function ($) {
2
 
3
  var Calendar = function($container, options) {
4
  var obj = this;
@@ -23,7 +23,7 @@ jQuery(function ($) {
23
  dayNames: obj.options.l10n.datePicker.dayNames,
24
  dayNamesShort: obj.options.l10n.datePicker.dayNamesShort,
25
  allDaySlot: false,
26
- eventBackgroundColor: 'silver',
27
  // Agenda Options.
28
  displayEventEnd: true,
29
  // Event Dragging & Resizing.
@@ -51,11 +51,16 @@ jQuery(function ($) {
51
  }
52
  }],
53
  eventAfterRender: function (calEvent, $calEventList, calendar) {
 
 
 
 
 
54
  if (calEvent.rendering !== 'background') {
55
  $calEventList.each(function () {
56
  var $calEvent = $(this),
57
  origHeight = $calEvent.outerHeight(),
58
- z_index = $calEvent.zIndex();
59
  // Mouse handlers.
60
  $calEvent
61
  .on('mouseenter', function () {
@@ -122,7 +127,7 @@ jQuery(function ($) {
122
  }
123
  if (obj.options.l10n.recurring_appointments.active == '1' && calEvent.series_id) {
124
  $time.prepend(
125
- $('<a class="bookly-fc-icon dashicons dashicons-admin-links"></a>')
126
  .attr('title', obj.options.l10n.recurring_appointments.title)
127
  .on('click', function (e) {
128
  e.stopPropagation();
@@ -135,13 +140,13 @@ jQuery(function ($) {
135
  }
136
  if (obj.options.l10n.waiting_list.active == '1' && calEvent.waitlisted > 0) {
137
  $time.prepend(
138
- $('<span class="bookly-fc-icon dashicons dashicons-list-view"></span>')
139
  .attr('title', obj.options.l10n.waiting_list.title)
140
  );
141
  }
142
  if (obj.options.l10n.packages.active == '1' && calEvent.package_id > 0) {
143
  $time.prepend(
144
- $('<span class="bookly-fc-icon dashicons dashicons-calendar" style="padding:0 2px;"></span>')
145
  .attr('title', obj.options.l10n.packages.title)
146
  .on('click', function (e) {
147
  e.stopPropagation();
@@ -154,7 +159,7 @@ jQuery(function ($) {
154
  );
155
  }
156
  $time.prepend(
157
- $('<a class="bookly-fc-icon dashicons dashicons-trash"></a>')
158
  .attr('title', obj.options.l10n.delete)
159
  .on('click', function (e) {
160
  e.stopPropagation();
@@ -162,7 +167,7 @@ jQuery(function ($) {
162
  if (obj.options.l10n.recurring_appointments.active == '1' && calEvent.series_id) {
163
  $(document.body).trigger('recurring_appointments.delete_dialog', [$container, calEvent]);
164
  } else {
165
- obj.$deleteDialog.data('calEvent', calEvent).modal('show');
166
  }
167
  })
168
  );
@@ -205,86 +210,64 @@ jQuery(function ($) {
205
  },
206
  loading: function (isLoading) {
207
  if (isLoading) {
208
- $('.fc-loading-inner').show();
209
  }
210
  },
211
  eventAfterAllRender: function () {
212
- $('.fc-loading-inner').hide();
213
  }
214
  };
215
 
216
  // Init fullcalendar
217
  $container.fullCalendar($.extend({}, settings, obj.options.fullcalendar));
218
 
219
- var $fcDatePicker = $('<input type=hidden />');
220
-
221
- $('.fc-toolbar .fc-center h2', $container).before($fcDatePicker).on('click', function () {
222
- $fcDatePicker.datepicker('setDate', $container.fullCalendar('getDate').toDate()).datepicker('show');
223
- });
224
-
225
  // Init date picker for fast navigation in FullCalendar.
226
- $fcDatePicker.datepicker({
227
- dayNamesMin: settings.dayNamesShort,
228
- monthNames: settings.monthNames,
229
- monthNamesShort: settings.monthNamesShort,
230
- firstDay: settings.firstDay,
231
- beforeShow: function (input, inst) {
232
- inst.dpDiv.queue(function () {
233
- inst.dpDiv.css({marginTop: '35px', 'font-size': '13.5px'});
234
- inst.dpDiv.dequeue();
235
- });
236
- },
237
- onSelect: function (dateText, inst) {
238
- var d = new Date(inst.selectedYear, inst.selectedMonth, inst.selectedDay);
239
- $container.fullCalendar('gotoDate', d);
240
- if ($container.fullCalendar('getView').type != 'agendaDay' &&
241
- $container.fullCalendar('getView').type != 'multiStaffDay') {
242
- $container.find('.fc-day').removeClass('bookly-fc-day-active');
243
- $container.find('.fc-day[data-date="' + moment(d).format('YYYY-MM-DD') + '"]').addClass('bookly-fc-day-active');
244
- }
245
- },
246
- onClose: function (dateText, inst) {
247
- inst.dpDiv.queue(function () {
248
- inst.dpDiv.css({marginTop: '0'});
249
- inst.dpDiv.dequeue();
250
- });
251
  }
252
  });
253
 
254
  /**
255
  * On delete appointment click.
256
  */
257
- if (obj.$deleteDialog.data('events') == undefined
258
- || obj.$deleteDialog.data('events').click == undefined)
259
- {
260
- obj.$deleteDialog.on('click', '#bookly-delete', function (e) {
261
- var calEvent = obj.$deleteDialog.data('calEvent'),
262
- ladda = Ladda.create(this);
263
- ladda.start();
264
- $.ajax({
265
- type : 'POST',
266
- url : ajaxurl,
267
- data : {
268
- 'action': 'bookly_delete_appointment',
269
- 'csrf_token': obj.options.l10n.csrf_token,
270
- 'appointment_id': calEvent.id,
271
- 'notify': $('#bookly-delete-notify').prop('checked') ? 1 : 0,
272
- 'reason': $('#bookly-delete-reason').val()
273
- },
274
- dataType : 'json',
275
- xhrFields : {withCredentials: true},
276
- crossDomain: 'withCredentials' in new XMLHttpRequest(),
277
- success : function (response) {
278
- ladda.stop();
279
- $container.fullCalendar('removeEvents', calEvent.id);
280
- obj.$deleteDialog.modal('hide');
281
- if (response.data && response.data.queue && response.data.queue.length) {
282
- $(document.body).trigger('bookly.queue_dialog', [response.data.queue]);
283
- }
284
  }
285
- });
286
  });
287
- }
288
  };
289
 
290
  var locationChanged = false;
@@ -292,7 +275,6 @@ jQuery(function ($) {
292
  locationChanged = true;
293
  });
294
 
295
- Calendar.prototype.$deleteDialog = $('#bookly-delete-dialog');
296
  Calendar.prototype.options = {
297
  fullcalendar: {},
298
  getCurrentStaffId: function () { return -1; },
@@ -303,4 +285,4 @@ jQuery(function ($) {
303
  };
304
 
305
  window.BooklyCalendar = Calendar;
306
- });
1
+ (function ($) {
2
 
3
  var Calendar = function($container, options) {
4
  var obj = this;
23
  dayNames: obj.options.l10n.datePicker.dayNames,
24
  dayNamesShort: obj.options.l10n.datePicker.dayNamesShort,
25
  allDaySlot: false,
26
+ eventBackgroundColor: '#d7d7d7',
27
  // Agenda Options.
28
  displayEventEnd: true,
29
  // Event Dragging & Resizing.
51
  }
52
  }],
53
  eventAfterRender: function (calEvent, $calEventList, calendar) {
54
+ let getZIndex = function (e) {
55
+ var z = document.defaultView.getComputedStyle(e).getPropertyValue('z-index');
56
+ if (isNaN(z)) return getZIndex(e.parentNode);
57
+ else return z;
58
+ };
59
  if (calEvent.rendering !== 'background') {
60
  $calEventList.each(function () {
61
  var $calEvent = $(this),
62
  origHeight = $calEvent.outerHeight(),
63
+ z_index = getZIndex($calEvent[0]);
64
  // Mouse handlers.
65
  $calEvent
66
  .on('mouseenter', function () {
127
  }
128
  if (obj.options.l10n.recurring_appointments.active == '1' && calEvent.series_id) {
129
  $time.prepend(
130
+ $('<a class="bookly-fc-icon fas fa-fw fa-link"></a>')
131
  .attr('title', obj.options.l10n.recurring_appointments.title)
132
  .on('click', function (e) {
133
  e.stopPropagation();
140
  }
141
  if (obj.options.l10n.waiting_list.active == '1' && calEvent.waitlisted > 0) {
142
  $time.prepend(
143
+ $('<span class="bookly-fc-icon far fa-fw fa-list-alt"></span>')
144
  .attr('title', obj.options.l10n.waiting_list.title)
145
  );
146
  }
147
  if (obj.options.l10n.packages.active == '1' && calEvent.package_id > 0) {
148
  $time.prepend(
149
+ $('<span class="bookly-fc-icon far fa-fw fa-calendar-alt" style="padding:0 2px;"></span>')
150
  .attr('title', obj.options.l10n.packages.title)
151
  .on('click', function (e) {
152
  e.stopPropagation();
159
  );
160
  }
161
  $time.prepend(
162
+ $('<a class="bookly-fc-icon far fa-fw fa-trash-alt"></a>')
163
  .attr('title', obj.options.l10n.delete)
164
  .on('click', function (e) {
165
  e.stopPropagation();
167
  if (obj.options.l10n.recurring_appointments.active == '1' && calEvent.series_id) {
168
  $(document.body).trigger('recurring_appointments.delete_dialog', [$container, calEvent]);
169
  } else {
170
+ $('#bookly-delete-dialog').data('calEvent', calEvent).booklyModal('show');
171
  }
172
  })
173
  );
210
  },
211
  loading: function (isLoading) {
212
  if (isLoading) {
213
+ $('.bookly-fc-loading').show();
214
  }
215
  },
216
  eventAfterAllRender: function () {
217
+ $('.bookly-fc-loading').hide();
218
  }
219
  };
220
 
221
  // Init fullcalendar
222
  $container.fullCalendar($.extend({}, settings, obj.options.fullcalendar));
223
 
 
 
 
 
 
 
224
  // Init date picker for fast navigation in FullCalendar.
225
+ $('.fc-toolbar .fc-center h2').daterangepicker({
226
+ parentEl : '.bookly-js-calendar',
227
+ singleDatePicker: true,
228
+ showDropdowns : true,
229
+ autoUpdateInput : false,
230
+ locale : obj.options.l10n.datePicker
231
+ }).on('apply.daterangepicker', function (ev, picker) {
232
+ $container.fullCalendar('gotoDate', picker.startDate.toDate());
233
+ if ($container.fullCalendar('getView').type != 'agendaDay' &&
234
+ $container.fullCalendar('getView').type != 'multiStaffDay') {
235
+ $container.find('.fc-day').removeClass('bookly-fc-day-active');
236
+ $container.find('.fc-day[data-date="' + picker.startDate.format('YYYY-MM-DD') + '"]').addClass('bookly-fc-day-active');
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  }
238
  });
239
 
240
  /**
241
  * On delete appointment click.
242
  */
243
+ $('#bookly-delete-dialog').off().on('click', '#bookly-delete', function (e) {
244
+ var $modal = $(this).closest('.bookly-modal'),
245
+ calEvent = $modal.data('calEvent'),
246
+ ladda = Ladda.create(this);
247
+ ladda.start();
248
+ $.ajax({
249
+ type : 'POST',
250
+ url : ajaxurl,
251
+ data : {
252
+ 'action' : 'bookly_delete_appointment',
253
+ 'csrf_token' : obj.options.l10n.csrf_token,
254
+ 'appointment_id': calEvent.id,
255
+ 'notify' : $('#bookly-delete-notify', $modal).prop('checked') ? 1 : 0,
256
+ 'reason' : $('#bookly-delete-reason', $modal).val()
257
+ },
258
+ dataType : 'json',
259
+ xhrFields : {withCredentials: true},
260
+ crossDomain: 'withCredentials' in new XMLHttpRequest(),
261
+ success : function (response) {
262
+ ladda.stop();
263
+ $container.fullCalendar('removeEvents', calEvent.id);
264
+ $modal.booklyModal('hide');
265
+ if (response.data && response.data.queue && response.data.queue.length) {
266
+ $(document.body).trigger('bookly.queue_dialog', [response.data.queue]);
 
 
 
267
  }
268
+ }
269
  });
270
+ });
271
  };
272
 
273
  var locationChanged = false;
275
  locationChanged = true;
276
  });
277
 
 
278
  Calendar.prototype.options = {
279
  fullcalendar: {},
280
  getCurrentStaffId: function () { return -1; },
285
  };
286
 
287
  window.BooklyCalendar = Calendar;
288
+ })(jQuery);
backend/modules/calendar/resources/js/calendar.js CHANGED
@@ -1,7 +1,7 @@
1
  jQuery(function ($) {
2
 
3
- var $fullCalendar = $('#bookly-fc-wrapper .bookly-js-calendar-element'),
4
- $tabs = $('.bookly-js-calendar-tab'),
5
  $staffFilter = $('#bookly-js-staff-filter'),
6
  $locationsFilter = $('#bookly-js-locations-filter'),
7
  firstHour = new Date().getHours(),
@@ -25,7 +25,7 @@ jQuery(function ($) {
25
  e.preventDefault();
26
  $tabs.removeClass('active');
27
  $(this).addClass('active');
28
- var staff_id = $(this).data('staff_id');
29
  setCookie('bookly_cal_tab_id', staff_id);
30
  if (staff_id == 0) {
31
  $('.fc-agendaDay-button').hide();
@@ -35,7 +35,7 @@ jQuery(function ($) {
35
  } else {
36
  $('.fc-multiStaffDay-button').hide();
37
  $('.fc-agendaDay-button').show();
38
- var view = $fullCalendar.fullCalendar('getView');
39
  if (view.type == 'multiStaffDay') {
40
  $fullCalendar.fullCalendar('changeView', 'agendaDay');
41
  }
@@ -43,8 +43,8 @@ jQuery(function ($) {
43
  }
44
  });
45
  $tabs.filter('[data-staff_id=' + tabId + ']').addClass('active');
46
- if ($tabs.filter('li.active').length === 0) {
47
- $tabs.eq(0).addClass('active').show();
48
  }
49
 
50
  /**
@@ -52,7 +52,7 @@ jQuery(function ($) {
52
  */
53
  $staffFilter.booklyDropdown({
54
  onChange: function (values, selected, all) {
55
- var ids = [];
56
  staffMembers.length = 0;
57
  this.booklyDropdown('getSelectedExt').forEach(function (item) {
58
  ids.push(item.value);
@@ -60,16 +60,16 @@ jQuery(function ($) {
60
  });
61
  setCookie('bookly_cal_st_ids', ids);
62
  if (all) {
63
- $tabs.filter('[data-staff_id!=0]').toggle(selected);
64
  } else {
65
  values.forEach(function (value) {
66
- $tabs.filter('[data-staff_id=' + value + ']').toggle(selected);
67
  });
68
  }
69
  if ($tabs.filter(':visible.active').length === 0) {
70
  $tabs.filter(':visible:first').triggerHandler('click');
71
  } else if ($tabs.filter('.active').data('staff_id') === 0) {
72
- var view = $fullCalendar.fullCalendar('getView');
73
  if (view.type === 'multiStaffDay') {
74
  view.displayView($fullCalendar.fullCalendar('getDate'));
75
  }
@@ -87,7 +87,7 @@ jQuery(function ($) {
87
  // Populate staffMembers.
88
  $staffFilter.booklyDropdown('getSelectedExt').forEach(function (item) {
89
  staffMembers.push({id: item.value, name: item.name});
90
- $tabs.filter('[data-staff_id=' + item.value + ']').show();
91
  });
92
 
93
  /**
@@ -159,7 +159,7 @@ jQuery(function ($) {
159
  });
160
 
161
  function heightFC() {
162
- var height = $(window).height() - $('#bookly-fc-wrapper').offset().top - 20;
163
 
164
  return height > 620 ? height : 620;
165
  }
1
  jQuery(function ($) {
2
 
3
+ let $fullCalendar = $('.bookly-js-calendar'),
4
+ $tabs = $('ul.bookly-js-calendar-tabs > li > a'),
5
  $staffFilter = $('#bookly-js-staff-filter'),
6
  $locationsFilter = $('#bookly-js-locations-filter'),
7
  firstHour = new Date().getHours(),
25
  e.preventDefault();
26
  $tabs.removeClass('active');
27
  $(this).addClass('active');
28
+ let staff_id = $(this).data('staff_id');
29
  setCookie('bookly_cal_tab_id', staff_id);
30
  if (staff_id == 0) {
31
  $('.fc-agendaDay-button').hide();
35
  } else {
36
  $('.fc-multiStaffDay-button').hide();
37
  $('.fc-agendaDay-button').show();
38
+ let view = $fullCalendar.fullCalendar('getView');
39
  if (view.type == 'multiStaffDay') {
40
  $fullCalendar.fullCalendar('changeView', 'agendaDay');
41
  }
43
  }
44
  });
45
  $tabs.filter('[data-staff_id=' + tabId + ']').addClass('active');
46
+ if ($tabs.filter('.active').length === 0) {
47
+ $tabs.eq(0).addClass('active').parent().show();
48
  }
49
 
50
  /**
52
  */
53
  $staffFilter.booklyDropdown({
54
  onChange: function (values, selected, all) {
55
+ let ids = [];
56
  staffMembers.length = 0;
57
  this.booklyDropdown('getSelectedExt').forEach(function (item) {
58
  ids.push(item.value);
60
  });
61
  setCookie('bookly_cal_st_ids', ids);
62
  if (all) {
63
+ $tabs.filter('[data-staff_id!=0]').parent().toggle(selected);
64
  } else {
65
  values.forEach(function (value) {
66
+ $tabs.filter('[data-staff_id=' + value + ']').parent().toggle(selected);
67
  });
68
  }
69
  if ($tabs.filter(':visible.active').length === 0) {
70
  $tabs.filter(':visible:first').triggerHandler('click');
71
  } else if ($tabs.filter('.active').data('staff_id') === 0) {
72
+ let view = $fullCalendar.fullCalendar('getView');
73
  if (view.type === 'multiStaffDay') {
74
  view.displayView($fullCalendar.fullCalendar('getDate'));
75
  }
87
  // Populate staffMembers.
88
  $staffFilter.booklyDropdown('getSelectedExt').forEach(function (item) {
89
  staffMembers.push({id: item.value, name: item.name});
90
+ $tabs.filter('[data-staff_id=' + item.value + ']').parent().show();
91
  });
92
 
93
  /**
159
  });
160
 
161
  function heightFC() {
162
+ let height = $(window).height() - $fullCalendar.offset().top - 20;
163
 
164
  return height > 620 ? height : 620;
165
  }
backend/modules/calendar/resources/js/fullcalendar.min.js CHANGED
@@ -1,9 +1,9 @@
1
  /*!
2
- * FullCalendar v2.4.0
3
  * Docs & License: http://fullcalendar.io/
4
  * (c) 2015 Adam Shaw
5
  */
6
- !function(a){"function"==typeof define&&define.amd?define(["jquery","moment"],a):"object"==typeof exports?module.exports=a(require("jquery"),require("moment")):a(jQuery,moment)}(function(a,b){function c(a){return Q(a,Oa)}function d(b){var c,d={views:b.views||{}};return a.each(b,function(b,e){"views"!=b&&(a.isPlainObject(e)&&!/(time|duration|interval)$/i.test(b)&&-1==a.inArray(b,Oa)?(c=null,a.each(e,function(a,e){/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(a)?(d.views[a]||(d.views[a]={}),d.views[a][b]=e):(c||(c={}),c[a]=e)}),c&&(d[b]=c)):d[b]=e)}),d}function e(a,b){b.left&&a.css({"border-left-width":1,"margin-left":b.left-1}),b.right&&a.css({"border-right-width":1,"margin-right":b.right-1})}function f(a){a.css({"margin-left":"","margin-right":"","border-left-width":"","border-right-width":""})}function g(){a("body").addClass("fc-not-allowed")}function h(){a("body").removeClass("fc-not-allowed")}function i(b,c,d){var e=Math.floor(c/b.length),f=Math.floor(c-e*(b.length-1)),g=[],h=[],i=[],k=0;j(b),b.each(function(c,d){var j=c===b.length-1?f:e,l=a(d).outerHeight(!0);j>l?(g.push(d),h.push(l),i.push(a(d).height())):k+=l}),d&&(c-=k,e=Math.floor(c/g.length),f=Math.floor(c-e*(g.length-1))),a(g).each(function(b,c){var d=b===g.length-1?f:e,j=h[b],k=i[b],l=d-(j-k);d>j&&a(c).height(l)})}function j(a){a.height("")}function k(b){var c=0;return b.find("> *").each(function(b,d){var e=a(d).outerWidth();e>c&&(c=e)}),c++,b.width(c),c}function l(a,b){return a.height(b).addClass("fc-scroller"),a[0].scrollHeight-1>a[0].clientHeight?!0:(m(a),!1)}function m(a){a.height("").removeClass("fc-scroller")}function n(b){var c=b.css("position"),d=b.parents().filter(function(){var b=a(this);return/(auto|scroll)/.test(b.css("overflow")+b.css("overflow-y")+b.css("overflow-x"))}).eq(0);return"fixed"!==c&&d.length?d:a(b[0].ownerDocument||document)}function o(a){var b=a.offset();return{left:b.left,right:b.left+a.outerWidth(),top:b.top,bottom:b.top+a.outerHeight()}}function p(a){var b=a.offset(),c=r(a),d=b.left+u(a,"border-left-width")+c.left,e=b.top+u(a,"border-top-width")+c.top;return{left:d,right:d+a[0].clientWidth,top:e,bottom:e+a[0].clientHeight}}function q(a){var b=a.offset(),c=b.left+u(a,"border-left-width")+u(a,"padding-left"),d=b.top+u(a,"border-top-width")+u(a,"padding-top");return{left:c,right:c+a.width(),top:d,bottom:d+a.height()}}function r(a){var b=a.innerWidth()-a[0].clientWidth,c={left:0,right:0,top:0,bottom:a.innerHeight()-a[0].clientHeight};return s()&&"rtl"==a.css("direction")?c.left=b:c.right=b,c}function s(){return null===Pa&&(Pa=t()),Pa}function t(){var b=a("<div><div/></div>").css({position:"absolute",top:-1e3,left:0,border:0,padding:0,overflow:"scroll",direction:"rtl"}).appendTo("body"),c=b.children(),d=c.offset().left>b.offset().left;return b.remove(),d}function u(a,b){return parseFloat(a.css(b))||0}function v(a){return 1==a.which&&!a.ctrlKey}function w(a,b){var c={left:Math.max(a.left,b.left),right:Math.min(a.right,b.right),top:Math.max(a.top,b.top),bottom:Math.min(a.bottom,b.bottom)};return c.left<c.right&&c.top<c.bottom?c:!1}function x(a,b){return{left:Math.min(Math.max(a.left,b.left),b.right),top:Math.min(Math.max(a.top,b.top),b.bottom)}}function y(a){return{left:(a.left+a.right)/2,top:(a.top+a.bottom)/2}}function z(a,b){return{left:a.left-b.left,top:a.top-b.top}}function A(b){var c,d,e=[],f=[];for("string"==typeof b?f=b.split(/\s*,\s*/):"function"==typeof b?f=[b]:a.isArray(b)&&(f=b),c=0;c<f.length;c++)d=f[c],"string"==typeof d?e.push("-"==d.charAt(0)?{field:d.substring(1),order:-1}:{field:d,order:1}):"function"==typeof d&&e.push({func:d});return e}function B(a,b,c){var d,e;for(d=0;d<c.length;d++)if(e=C(a,b,c[d]))return e;return 0}function C(a,b,c){return c.func?c.func(a,b):D(a[c.field],b[c.field])*(c.order||1)}function D(b,c){return b||c?null==c?-1:null==b?1:"string"===a.type(b)||"string"===a.type(c)?String(b).localeCompare(String(c)):b-c:0}function E(a,b){var c,d,e,f,g=a.start,h=a.end,i=b.start,j=b.end;return h>i&&j>g?(g>=i?(c=g.clone(),e=!0):(c=i.clone(),e=!1),j>=h?(d=h.clone(),f=!0):(d=j.clone(),f=!1),{start:c,end:d,isStart:e,isEnd:f}):void 0}function F(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days"),ms:a.time()-c.time()})}function G(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days")})}function H(a,c,d){return b.duration(Math.round(a.diff(c,d,!0)),d)}function I(a,b){var c,d,e;for(c=0;c<Ra.length&&(d=Ra[c],e=J(d,a,b),!(e>=1&&ba(e)));c++);return d}function J(a,c,d){return null!=d?d.diff(c,a,!0):b.isDuration(c)?c.as(a):c.end.diff(c.start,a,!0)}function K(a,b,c){var d;return N(c)?(b-a)/c:(d=c.asMonths(),Math.abs(d)>=1&&ba(d)?b.diff(a,"months",!0)/d:b.diff(a,"days",!0)/c.asDays())}function L(a,b){var c,d;return N(a)||N(b)?a/b:(c=a.asMonths(),d=b.asMonths(),Math.abs(c)>=1&&ba(c)&&Math.abs(d)>=1&&ba(d)?c/d:a.asDays()/b.asDays())}function M(a,c){var d;return N(a)?b.duration(a*c):(d=a.asMonths(),Math.abs(d)>=1&&ba(d)?b.duration({months:d*c}):b.duration({days:a.asDays()*c}))}function N(a){return Boolean(a.hours()||a.minutes()||a.seconds()||a.milliseconds())}function O(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function P(a){return/^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(a)}function Q(a,b){var c,d,e,f,g,h,i={};if(b)for(c=0;c<b.length;c++){for(d=b[c],e=[],f=a.length-1;f>=0;f--)if(g=a[f][d],"object"==typeof g)e.unshift(g);else if(void 0!==g){i[d]=g;break}e.length&&(i[d]=Q(e))}for(c=a.length-1;c>=0;c--){h=a[c];for(d in h)d in i||(i[d]=h[d])}return i}function R(a){var b=function(){};return b.prototype=a,new b}function S(a,b){for(var c in a)U(a,c)&&(b[c]=a[c])}function T(a,b){var c,d,e=["constructor","toString","valueOf"];for(c=0;c<e.length;c++)d=e[c],a[d]!==Object.prototype[d]&&(b[d]=a[d])}function U(a,b){return Va.call(a,b)}function V(b){return/undefined|null|boolean|number|string/.test(a.type(b))}function W(b,c,d){if(a.isFunction(b)&&(b=[b]),b){var e,f;for(e=0;e<b.length;e++)f=b[e].apply(c,d)||f;return f}}function X(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a]}function Y(a){return(a+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#039;").replace(/"/g,"&quot;").replace(/\n/g,"<br />")}function Z(a){return a.replace(/&.*?;/g,"")}function $(b){var c=[];return a.each(b,function(a,b){null!=b&&c.push(a+":"+b)}),c.join(";")}function _(a){return a.charAt(0).toUpperCase()+a.slice(1)}function aa(a,b){return a-b}function ba(a){return a%1===0}function ca(a,b){var c=a[b];return function(){return c.apply(a,arguments)}}function da(a,b){var c,d,e,f,g=function(){var h=+new Date-f;b>h&&h>0?c=setTimeout(g,b-h):(c=null,a.apply(e,d),c||(e=d=null))};return function(){e=this,d=arguments,f=+new Date,c||(c=setTimeout(g,b))}}function ea(c,d,e){var f,g,h,i,j=c[0],k=1==c.length&&"string"==typeof j;return b.isMoment(j)?(i=b.apply(null,c),ga(j,i)):O(j)||void 0===j?i=b.apply(null,c):(f=!1,g=!1,k?Wa.test(j)?(j+="-01",c=[j],f=!0,g=!0):(h=Xa.exec(j))&&(f=!h[5],g=!0):a.isArray(j)&&(g=!0),i=d||f?b.utc.apply(b,c):b.apply(null,c),f?(i._ambigTime=!0,i._ambigZone=!0):e&&(g?i._ambigZone=!0:k&&(i.utcOffset?i.utcOffset(j):i.zone(j)))),i._fullCalendar=!0,i}function fa(a,c){var d,e,f=!1,g=!1,h=a.length,i=[];for(d=0;h>d;d++)e=a[d],b.isMoment(e)||(e=Ma.moment.parseZone(e)),f=f||e._ambigTime,g=g||e._ambigZone,i.push(e);for(d=0;h>d;d++)e=i[d],c||!f||e._ambigTime?g&&!e._ambigZone&&(i[d]=e.clone().stripZone()):i[d]=e.clone().stripTime();return i}function ga(a,b){a._ambigTime?b._ambigTime=!0:b._ambigTime&&(b._ambigTime=!1),a._ambigZone?b._ambigZone=!0:b._ambigZone&&(b._ambigZone=!1)}function ha(a,b){a.year(b[0]||0).month(b[1]||0).date(b[2]||0).hours(b[3]||0).minutes(b[4]||0).seconds(b[5]||0).milliseconds(b[6]||0)}function ia(a,b){return Za.format.call(a,b)}function ja(a,b){return ka(a,pa(b))}function ka(a,b){var c,d="";for(c=0;c<b.length;c++)d+=la(a,b[c]);return d}function la(a,b){var c,d;return"string"==typeof b?b:(c=b.token)?$a[c]?$a[c](a):ia(a,c):b.maybe&&(d=ka(a,b.maybe),d.match(/[1-9]/))?d:""}function ma(a,b,c,d,e){var f;return a=Ma.moment.parseZone(a),b=Ma.moment.parseZone(b),f=(a.localeData||a.lang).call(a),c=f.longDateFormat(c)||c,d=d||" - ",na(a,b,pa(c),d,e)}function na(a,b,c,d,e){var f,g,h,i,j="",k="",l="",m="",n="";for(g=0;g<c.length&&(f=oa(a,b,c[g]),f!==!1);g++)j+=f;for(h=c.length-1;h>g&&(f=oa(a,b,c[h]),f!==!1);h--)k=f+k;for(i=g;h>=i;i++)l+=la(a,c[i]),m+=la(b,c[i]);return(l||m)&&(n=e?m+d+l:l+d+m),j+n+k}function oa(a,b,c){var d,e;return"string"==typeof c?c:(d=c.token)&&(e=_a[d.charAt(0)],e&&a.isSame(b,e))?ia(a,d):!1}function pa(a){return a in ab?ab[a]:ab[a]=qa(a)}function qa(a){for(var b,c=[],d=/\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;b=d.exec(a);)b[1]?c.push(b[1]):b[2]?c.push({maybe:qa(b[2])}):b[3]?c.push({token:b[3]}):b[5]&&c.push(b[5]);return c}function ra(){}function sa(a,b){return a||b?a&&b?a.grid===b.grid&&a.row===b.row&&a.col===b.col:!1:!0}function ta(a){var b=va(a);return"background"===b||"inverse-background"===b}function ua(a){return"inverse-background"===va(a)}function va(a){return X((a.source||{}).rendering,a.rendering)}function wa(a){var b,c,d={};for(b=0;b<a.length;b++)c=a[b],(d[c._id]||(d[c._id]=[])).push(c);return d}function xa(a,b){return a.eventStartMS-b.eventStartMS}function ya(c){var d,e,f,g,h=Ma.dataAttrPrefix;return h&&(h+="-"),d=c.data(h+"event")||null,d&&(d="object"==typeof d?a.extend({},d):{},e=d.start,null==e&&(e=d.time),f=d.duration,g=d.stick,delete d.start,delete d.time,delete d.duration,delete d.stick),null==e&&(e=c.data(h+"start")),null==e&&(e=c.data(h+"time")),null==f&&(f=c.data(h+"duration")),null==g&&(g=c.data(h+"stick")),e=null!=e?b.duration(e):null,f=null!=f?b.duration(f):null,g=Boolean(g),{eventProps:d,startTime:e,duration:f,stick:g}}function za(a,b){var c,d;for(c=0;c<b.length;c++)if(d=b[c],d.leftCol<=a.rightCol&&d.rightCol>=a.leftCol)return!0;return!1}function Aa(a,b){return a.leftCol-b.leftCol}function Ba(a){var b,c,d,e=[];for(b=0;b<a.length;b++){for(c=a[b],d=0;d<e.length&&Ea(c,e[d]).length;d++);c.level=d,(e[d]||(e[d]=[])).push(c)}return e}function Ca(a){var b,c,d,e,f;for(b=0;b<a.length;b++)for(c=a[b],d=0;d<c.length;d++)for(e=c[d],e.forwardSegs=[],f=b+1;f<a.length;f++)Ea(e,a[f],e.forwardSegs)}function Da(a){var b,c,d=a.forwardSegs,e=0;if(void 0===a.forwardPressure){for(b=0;b<d.length;b++)c=d[b],Da(c),e=Math.max(e,1+c.forwardPressure);a.forwardPressure=e}}function Ea(a,b,c){c=c||[];for(var d=0;d<b.length;d++)Fa(a,b[d])&&c.push(b[d]);return c}function Fa(a,b){return a.bottom>b.top&&a.top<b.bottom}function Ga(c,d){function e(){U?h()&&(k(),i()):f()}function f(){V=O.theme?"ui":"fc",c.addClass("fc"),O.isRTL?c.addClass("fc-rtl"):c.addClass("fc-ltr"),O.theme?c.addClass("ui-widget"):c.addClass("fc-unthemed"),U=a("<div class='fc-view-container'/>").prependTo(c),S=N.header=new Ja(N,O),T=S.render(),T&&c.prepend(T),i(O.defaultView),O.handleWindowResize&&(Y=da(m,O.windowResizeDelay),a(window).resize(Y))}function g(){W&&W.removeElement(),S.removeElement(),U.remove(),c.removeClass("fc fc-ltr fc-rtl fc-unthemed ui-widget"),Y&&a(window).unbind("resize",Y)}function h(){return c.is(":visible")}function i(b){ca++,W&&b&&W.type!==b&&(S.deactivateButton(W.type),H(),W.removeElement(),W=N.view=null),!W&&b&&(W=N.view=ba[b]||(ba[b]=N.instantiateView(b)),W.setElement(a("<div class='fc-view fc-"+b+"-view' />").appendTo(U)),S.activateButton(b)),W&&(Z=W.massageCurrentDate(Z),W.displaying&&Z.isWithin(W.intervalStart,W.intervalEnd)||h()&&(H(),W.display(Z),I(),u(),v(),q())),I(),ca--}function j(a){return h()?(a&&l(),ca++,W.updateSize(!0),ca--,!0):void 0}function k(){h()&&l()}function l(){X="number"==typeof O.contentHeight?O.contentHeight:"number"==typeof O.height?O.height-(T?T.outerHeight(!0):0):Math.round(U.width()/Math.max(O.aspectRatio,.5))}function m(a){!ca&&a.target===window&&W.start&&j(!0)&&W.trigger("windowResize",aa)}function n(){p(),r()}function o(){h()&&(H(),W.displayEvents(ea),I())}function p(){H(),W.clearEvents(),I()}function q(){!O.lazyFetching||$(W.start,W.end)?r():o()}function r(){_(W.start,W.end)}function s(a){ea=a,o()}function t(){o()}function u(){S.updateTitle(W.title)}function v(){var a=N.getNow();a.isWithin(W.intervalStart,W.intervalEnd)?S.disableButton("today"):S.enableButton("today")}function w(a,b){W.select(N.buildSelectRange.apply(N,arguments))}function x(){W&&W.unselect()}function y(){Z=W.computePrevDate(Z),i()}function z(){Z=W.computeNextDate(Z),i()}function A(){Z.add(-1,"years"),i()}function B(){Z.add(1,"years"),i()}function C(){Z=N.getNow(),i()}function D(a){Z=N.moment(a),i()}function E(a){Z.add(b.duration(a)),i()}function F(a,b){var c;b=b||"day",c=N.getViewSpec(b)||N.getUnitViewSpec(b),Z=a,i(c?c.type:null)}function G(){return Z.clone()}function H(){U.css({width:"100%",height:U.height(),overflow:"hidden"})}function I(){U.css({width:"",height:"",overflow:""})}function J(){return N}function K(){return W}function L(a,b){return void 0===b?O[a]:void(("height"==a||"contentHeight"==a||"aspectRatio"==a)&&(O[a]=b,j(!0)))}function M(a,b){var c=Array.prototype.slice.call(arguments,2);return b=b||aa,this.triggerWith(a,b,c),O[a]?O[a].apply(b,c):void 0}var N=this;N.initOptions(d||{});var O=this.options;N.render=e,N.destroy=g,N.refetchEvents=n,N.reportEvents=s,N.reportEventChange=t,N.rerenderEvents=o,N.changeView=i,N.select=w,N.unselect=x,N.prev=y,N.next=z,N.prevYear=A,N.nextYear=B,N.today=C,N.gotoDate=D,N.incrementDate=E,N.zoomTo=F,N.getDate=G,N.getCalendar=J,N.getView=K,N.option=L,N.trigger=M;var P=R(Ia(O.lang));if(O.monthNames&&(P._months=O.monthNames),O.monthNamesShort&&(P._monthsShort=O.monthNamesShort),O.dayNames&&(P._weekdays=O.dayNames),O.dayNamesShort&&(P._weekdaysShort=O.dayNamesShort),null!=O.firstDay){var Q=R(P._week);Q.dow=O.firstDay,P._week=Q}P._fullCalendar_weekCalc=function(a){return"function"==typeof a?a:"local"===a?a:"iso"===a||"ISO"===a?"ISO":void 0}(O.weekNumberCalculation),N.defaultAllDayEventDuration=b.duration(O.defaultAllDayEventDuration),N.defaultTimedEventDuration=b.duration(O.defaultTimedEventDuration),N.moment=function(){var a;return"local"===O.timezone?(a=Ma.moment.apply(null,arguments),a.hasTime()&&a.local()):a="UTC"===O.timezone?Ma.moment.utc.apply(null,arguments):Ma.moment.parseZone.apply(null,arguments),"_locale"in a?a._locale=P:a._lang=P,a},N.getIsAmbigTimezone=function(){return"local"!==O.timezone&&"UTC"!==O.timezone},N.rezoneDate=function(a){return N.moment(a.toArray())},N.getNow=function(){var a=O.now;return"function"==typeof a&&(a=a()),N.moment(a)},N.getEventEnd=function(a){return a.end?a.end.clone():N.getDefaultEventEnd(a.allDay,a.start)},N.getDefaultEventEnd=function(a,b){var c=b.clone();return a?c.stripTime().add(N.defaultAllDayEventDuration):c.add(N.defaultTimedEventDuration),N.getIsAmbigTimezone()&&c.stripZone(),c},N.humanizeDuration=function(a){return(a.locale||a.lang).call(a,O.lang).humanize()},Ka.call(N,O);var S,T,U,V,W,X,Y,Z,$=N.isFetchNeeded,_=N.fetchEvents,aa=c[0],ba={},ca=0,ea=[];Z=null!=O.defaultDate?N.moment(O.defaultDate):N.getNow(),N.getSuggestedViewHeight=function(){return void 0===X&&k(),X},N.isHeightAuto=function(){return"auto"===O.contentHeight||"auto"===O.height},N.initialize()}function Ha(b){a.each(rb,function(a,c){null==b[a]&&(b[a]=c(b))})}function Ia(a){var c=b.localeData||b.langData;return c.call(b,a)||c.call(b,"en")}function Ja(b,c){function d(){var b=c.header;return n=c.theme?"ui":"fc",b?o=a("<div class='fc-toolbar'/>").append(f("left")).append(f("right")).append(f("center")).append('<div class="fc-clear"/>'):void 0}function e(){o.remove(),o=a()}function f(d){var e=a('<div class="fc-'+d+'"/>'),f=c.header[d];return f&&a.each(f.split(" "),function(d){var f,g=a(),h=!0;a.each(this.split(","),function(d,e){var f,i,j,k,l,m,o,q,r,s;"title"==e?(g=g.add(a("<h2>&nbsp;</h2>")),h=!1):((f=(b.options.customButtons||{})[e])?(j=function(a){f.click&&f.click.call(s[0],a)},k="",l=f.text):(i=b.getViewSpec(e))?(j=function(){b.changeView(e)},p.push(e),k=i.buttonTextOverride,l=i.buttonTextDefault):b[e]&&(j=function(){b[e]()},k=(b.overrides.buttonText||{})[e],l=c.buttonText[e]),j&&(m=f?f.themeIcon:c.themeButtonIcons[e],o=f?f.icon:c.buttonIcons[e],q=k?Y(k):m&&c.theme?"<span class='ui-icon ui-icon-"+m+"'></span>":o&&!c.theme?"<span class='fc-icon fc-icon-"+o+"'></span>":Y(l),r=["fc-"+e+"-button",n+"-button",n+"-state-default"],s=a('<button type="button" class="'+r.join(" ")+'">'+q+"</button>").click(function(a){s.hasClass(n+"-state-disabled")||(j(a),(s.hasClass(n+"-state-active")||s.hasClass(n+"-state-disabled"))&&s.removeClass(n+"-state-hover"))}).mousedown(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-down")}).mouseup(function(){s.removeClass(n+"-state-down")}).hover(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-hover")},function(){s.removeClass(n+"-state-hover").removeClass(n+"-state-down")}),g=g.add(s)))}),h&&g.first().addClass(n+"-corner-left").end().last().addClass(n+"-corner-right").end(),g.length>1?(f=a("<div/>"),h&&f.addClass("fc-button-group"),f.append(g),e.append(f)):e.append(g)}),e}function g(a){o.find("h2").text(a)}function h(a){o.find(".fc-"+a+"-button").addClass(n+"-state-active")}function i(a){o.find(".fc-"+a+"-button").removeClass(n+"-state-active")}function j(a){o.find(".fc-"+a+"-button").attr("disabled","disabled").addClass(n+"-state-disabled")}function k(a){o.find(".fc-"+a+"-button").removeAttr("disabled").removeClass(n+"-state-disabled")}function l(){return p}var m=this;m.render=d,m.removeElement=e,m.updateTitle=g,m.activateButton=h,m.deactivateButton=i,m.disableButton=j,m.enableButton=k,m.getViewsWithButtons=l;var n,o=a(),p=[]}function Ka(c){function d(a,b){return!M||a.clone().stripZone()<M.clone().stripZone()||b.clone().stripZone()>N.clone().stripZone()}function e(a,b){M=a,N=b,U=[];var c=++S,d=R.length;T=d;for(var e=0;d>e;e++)f(R[e],c)}function f(b,c){g(b,function(d){var e,f,g,h=a.isArray(b.events);if(c==S){if(d)for(e=0;e<d.length;e++)f=d[e],g=h?f:s(f,b),g&&U.push.apply(U,x(g));T--,T||O(U)}})}function g(b,d){var e,f,h=Ma.sourceFetchers;for(e=0;e<h.length;e++){if(f=h[e].call(L,b,M.clone(),N.clone(),c.timezone,d),f===!0)return;if("object"==typeof f)return void g(f,d)}var i=b.events;if(i)a.isFunction(i)?(L.pushLoading(),i.call(L,M.clone(),N.clone(),c.timezone,function(a){d(a),L.popLoading()})):a.isArray(i)?d(i):d();else{var j=b.url;if(j){var k,l=b.success,m=b.error,n=b.complete;k=a.isFunction(b.data)?b.data():b.data;var o=a.extend({},k||{}),p=X(b.startParam,c.startParam),q=X(b.endParam,c.endParam),r=X(b.timezoneParam,c.timezoneParam);p&&(o[p]=M.format()),q&&(o[q]=N.format()),c.timezone&&"local"!=c.timezone&&(o[r]=c.timezone),L.pushLoading(),a.ajax(a.extend({},sb,b,{data:o,success:function(b){b=b||[];var c=W(l,this,arguments);a.isArray(c)&&(b=c),d(b)},error:function(){W(m,this,arguments),d()},complete:function(){W(n,this,arguments),L.popLoading()}}))}else d()}}function h(a){var b=i(a);b&&(R.push(b),T++,f(b,S))}function i(b){var c,d,e=Ma.sourceNormalizers;if(a.isFunction(b)||a.isArray(b)?c={events:b}:"string"==typeof b?c={url:b}:"object"==typeof b&&(c=a.extend({},b)),c){for(c.className?"string"==typeof c.className&&(c.className=c.className.split(/\s+/)):c.className=[],a.isArray(c.events)&&(c.origArray=c.events,c.events=a.map(c.events,function(a){return s(a,c)})),d=0;d<e.length;d++)e[d].call(L,c);return c}}function j(b){R=a.grep(R,function(a){return!k(a,b)}),U=a.grep(U,function(a){return!k(a.source,b)}),O(U)}function k(a,b){return a&&b&&l(a)==l(b)}function l(a){return("object"==typeof a?a.origArray||a.googleCalendarId||a.url||a.events:null)||a}function m(a){a.start=L.moment(a.start),a.end?a.end=L.moment(a.end):a.end=null,y(a,n(a)),O(U)}function n(b){var c={};return a.each(b,function(a,b){o(a)&&void 0!==b&&V(b)&&(c[a]=b)}),c}function o(a){return!/^_|^(id|allDay|start|end)$/.test(a)}function p(a,b){var c,d,e,f=s(a);if(f){for(c=x(f),d=0;d<c.length;d++)e=c[d],e.source||(b&&(Q.events.push(e),e.source=Q),U.push(e));return O(U),c}return[]}function q(b){var c,d;for(null==b?b=function(){return!0}:a.isFunction(b)||(c=b+"",b=function(a){return a._id==c}),U=a.grep(U,b,!0),d=0;d<R.length;d++)a.isArray(R[d].events)&&(R[d].events=a.grep(R[d].events,b,!0));O(U)}function r(b){return a.isFunction(b)?a.grep(U,b):null!=b?(b+="",a.grep(U,function(a){return a._id==b})):U}function s(d,e){var f,g,h,i={};if(c.eventDataTransform&&(d=c.eventDataTransform(d)),e&&e.eventDataTransform&&(d=e.eventDataTransform(d)),a.extend(i,d),e&&(i.source=e),i._id=d._id||(void 0===d.id?"_fc"+tb++:d.id+""),d.className?"string"==typeof d.className?i.className=d.className.split(/\s+/):i.className=d.className:i.className=[],f=d.start||d.date,g=d.end,P(f)&&(f=b.duration(f)),P(g)&&(g=b.duration(g)),d.dow||b.isDuration(f)||b.isDuration(g))i.start=f?b.duration(f):null,i.end=g?b.duration(g):null,i._recurring=!0;else{if(f&&(f=L.moment(f),!f.isValid()))return!1;g&&(g=L.moment(g),g.isValid()||(g=null)),h=d.allDay,void 0===h&&(h=X(e?e.allDayDefault:void 0,c.allDayDefault)),t(f,g,h,i)}return i}function t(a,b,c,d){d.start=a,d.end=b,d.allDay=c,u(d),La(d)}function u(a){v(a),a.end&&!a.end.isAfter(a.start)&&(a.end=null),a.end||(c.forceEventDuration?a.end=L.getDefaultEventEnd(a.allDay,a.start):a.end=null)}function v(a){null==a.allDay&&(a.allDay=!(a.start.hasTime()||a.end&&a.end.hasTime())),a.allDay?(a.start.stripTime(),a.end&&a.end.stripTime()):(a.start.hasTime()||(a.start=L.rezoneDate(a.start)),a.end&&!a.end.hasTime()&&(a.end=L.rezoneDate(a.end)))}function w(b){var c;return b.end||(c=b.allDay,null==c&&(c=!b.start.hasTime()),b=a.extend({},b),b.end=L.getDefaultEventEnd(c,b.start)),b}function x(b,c,d){var e,f,g,h,i,j,k,l,m,n=[];if(c=c||M,d=d||N,b)if(b._recurring){if(f=b.dow)for(e={},g=0;g<f.length;g++)e[f[g]]=!0;for(h=c.clone().stripTime();h.isBefore(d);)(!e||e[h.day()])&&(i=b.start,j=b.end,k=h.clone(),l=null,i&&(k=k.time(i)),j&&(l=h.clone().time(j)),m=a.extend({},b),t(k,l,!i&&!j,m),n.push(m)),h.add(1,"days")}else n.push(b);return n}function y(b,c,d){function e(a,b){return d?H(a,b,d):c.allDay?G(a,b):F(a,b)}var f,g,h,i,j,k,l={};return c=c||{},c.start||(c.start=b.start.clone()),void 0===c.end&&(c.end=b.end?b.end.clone():null),null==c.allDay&&(c.allDay=b.allDay),u(c),f={start:b._start.clone(),end:b._end?b._end.clone():L.getDefaultEventEnd(b._allDay,b._start),allDay:c.allDay},u(f),g=null!==b._end&&null===c.end,h=e(c.start,f.start),c.end?(i=e(c.end,f.end),j=i.subtract(h)):j=null,a.each(c,function(a,b){o(a)&&void 0!==b&&(l[a]=b)}),k=z(r(b._id),g,c.allDay,h,j,l),{dateDelta:h,durationDelta:j,undo:k}}function z(b,c,d,e,f,g){var h=L.getIsAmbigTimezone(),i=[];return e&&!e.valueOf()&&(e=null),f&&!f.valueOf()&&(f=null),a.each(b,function(b,j){var k,l;k={start:j.start.clone(),end:j.end?j.end.clone():null,allDay:j.allDay},a.each(g,function(a){k[a]=j[a]}),l={start:j._start,end:j._end,allDay:d},u(l),c?l.end=null:f&&!l.end&&(l.end=L.getDefaultEventEnd(l.allDay,l.start)),e&&(l.start.add(e),l.end&&l.end.add(e)),f&&l.end.add(f),h&&!l.allDay&&(e||f)&&(l.start.stripZone(),l.end&&l.end.stripZone()),a.extend(j,g,l),La(j),i.push(function(){a.extend(j,k),La(j)})}),function(){for(var a=0;a<i.length;a++)i[a]()}}function A(b){var d,e=c.businessHours,f={className:"fc-nonbusiness",start:"09:00",end:"17:00",dow:[1,2,3,4,5],rendering:"inverse-background"},g=L.getView();return e&&(d=a.extend({},f,"object"==typeof e?e:{})),d?(b&&(d.start=null,d.end=null),x(s(d),g.start,g.end)):[]}function B(a,b){var d=b.source||{},e=X(b.constraint,d.constraint,c.eventConstraint),f=X(b.overlap,d.overlap,c.eventOverlap);return a=w(a),E(a,e,f,b)}function C(a){return E(a,c.selectConstraint,c.selectOverlap)}function D(b,c){var d,e;return c&&(d=a.extend({},c,b),e=x(s(d))[0]),e?B(b,e):(b=w(b),C(b))}function E(b,c,d,e){var f,g,h,i,j,k;if(b=a.extend({},b),b.start=b.start.clone().stripZone(),b.end=b.end.clone().stripZone(),null!=c){for(f=I(c),g=!1,i=0;i<f.length;i++)if(J(f[i],b)){g=!0;break}if(!g)return!1}for(h=L.getPeerEvents(e,b),i=0;i<h.length;i++)if(j=h[i],K(j,b)){if(d===!1)return!1;if("function"==typeof d&&!d(j,e))return!1;if(e){if(k=X(j.overlap,(j.source||{}).overlap),k===!1)return!1;if("function"==typeof k&&!k(e,j))return!1}}return!0}function I(a){return"businessHours"===a?A():"object"==typeof a?x(s(a)):r(a)}function J(a,b){var c=a.start.clone().stripZone(),d=L.getEventEnd(a).stripZone();return b.start>=c&&b.end<=d}function K(a,b){var c=a.start.clone().stripZone(),d=L.getEventEnd(a).stripZone();return b.start<d&&b.end>c}var L=this;L.isFetchNeeded=d,L.fetchEvents=e,L.addEventSource=h,L.removeEventSource=j,L.updateEvent=m,L.renderEvent=p,L.removeEvents=q,L.clientEvents=r,L.mutateEvent=y,L.normalizeEventRange=u,L.normalizeEventRangeTimes=v,L.ensureVisibleEventRange=w;var M,N,O=L.reportEvents,Q={events:[]},R=[Q],S=0,T=0,U=[];a.each((c.events?[c.events]:[]).concat(c.eventSources||[]),function(a,b){var c=i(b);c&&R.push(c)}),L.getBusinessHoursEvents=A,L.isEventRangeAllowed=B,L.isSelectionRangeAllowed=C,L.isExternalDropRangeAllowed=D,L.getEventCache=function(){return U}}function La(a){a._allDay=a.allDay,a._start=a.start.clone(),a._end=a.end?a.end.clone():null}var Ma=a.fullCalendar={version:"2.4.0"},Na=Ma.views={};a.fn.fullCalendar=function(b){var c=Array.prototype.slice.call(arguments,1),d=this;return this.each(function(e,f){var g,h=a(f),i=h.data("fullCalendar");"string"==typeof b?i&&a.isFunction(i[b])&&(g=i[b].apply(i,c),e||(d=g),"destroy"===b&&h.removeData("fullCalendar")):i||(i=new nb(h,b),h.data("fullCalendar",i),i.render())}),d};var Oa=["header","buttonText","buttonIcons","themeButtonIcons"];Ma.intersectionToSeg=E,Ma.applyAll=W,Ma.debounce=da,Ma.isInt=ba,Ma.htmlEscape=Y,Ma.cssToStr=$,Ma.proxy=ca,Ma.capitaliseFirstLetter=_,Ma.getClientRect=p,Ma.getContentRect=q,Ma.getScrollbarWidths=r;var Pa=null;Ma.intersectRects=w,Ma.parseFieldSpecs=A,Ma.compareByFieldSpecs=B,Ma.compareByFieldSpec=C,Ma.flexibleCompare=D,Ma.computeIntervalUnit=I,Ma.divideRangeByDuration=K,Ma.divideDurationByDuration=L,Ma.multiplyDuration=M,Ma.durationHasTime=N;var Qa=["sun","mon","tue","wed","thu","fri","sat"],Ra=["year","month","week","day","hour","minute","second","millisecond"];Ma.log=function(){var a=window.console;return a&&a.log?a.log.apply(a,arguments):void 0},Ma.warn=function(){var a=window.console;return a&&a.warn?a.warn.apply(a,arguments):Ma.log.apply(Ma,arguments)};var Sa,Ta,Ua,Va={}.hasOwnProperty,Wa=/^\s*\d{4}-\d\d$/,Xa=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/,Ya=b.fn,Za=a.extend({},Ya);Ma.moment=function(){return ea(arguments)},Ma.moment.utc=function(){var a=ea(arguments,!0);return a.hasTime()&&a.utc(),a},Ma.moment.parseZone=function(){return ea(arguments,!0,!0)},Ya.clone=function(){var a=Za.clone.apply(this,arguments);return ga(this,a),this._fullCalendar&&(a._fullCalendar=!0),a},Ya.week=Ya.weeks=function(a){var b=(this._locale||this._lang)._fullCalendar_weekCalc;return null==a&&"function"==typeof b?b(this):"ISO"===b?Za.isoWeek.apply(this,arguments):Za.week.apply(this,arguments)},Ya.time=function(a){if(!this._fullCalendar)return Za.time.apply(this,arguments);if(null==a)return b.duration({hours:this.hours(),minutes:this.minutes(),seconds:this.seconds(),milliseconds:this.milliseconds()});this._ambigTime=!1,b.isDuration(a)||b.isMoment(a)||(a=b.duration(a));var c=0;return b.isDuration(a)&&(c=24*Math.floor(a.asDays())),this.hours(c+a.hours()).minutes(a.minutes()).seconds(a.seconds()).milliseconds(a.milliseconds())},Ya.stripTime=function(){var a;return this._ambigTime||(a=this.toArray(),this.utc(),Ta(this,a.slice(0,3)),this._ambigTime=!0,this._ambigZone=!0),this},Ya.hasTime=function(){return!this._ambigTime},Ya.stripZone=function(){var a,b;return this._ambigZone||(a=this.toArray(),b=this._ambigTime,this.utc(),Ta(this,a),this._ambigTime=b||!1,this._ambigZone=!0),this},Ya.hasZone=function(){return!this._ambigZone},Ya.local=function(){var a=this.toArray(),b=this._ambigZone;return Za.local.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,b&&Ua(this,a),this},Ya.utc=function(){return Za.utc.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,this},a.each(["zone","utcOffset"],function(a,b){Za[b]&&(Ya[b]=function(a){return null!=a&&(this._ambigTime=!1,this._ambigZone=!1),Za[b].apply(this,arguments)})}),Ya.format=function(){return this._fullCalendar&&arguments[0]?ja(this,arguments[0]):this._ambigTime?ia(this,"YYYY-MM-DD"):this._ambigZone?ia(this,"YYYY-MM-DD[T]HH:mm:ss"):Za.format.apply(this,arguments)},Ya.toISOString=function(){return this._ambigTime?ia(this,"YYYY-MM-DD"):this._ambigZone?ia(this,"YYYY-MM-DD[T]HH:mm:ss"):Za.toISOString.apply(this,arguments)},Ya.isWithin=function(a,b){var c=fa([this,a,b]);return c[0]>=c[1]&&c[0]<c[2]},Ya.isSame=function(a,b){var c;return this._fullCalendar?b?(c=fa([this,a],!0),Za.isSame.call(c[0],c[1],b)):(a=Ma.moment.parseZone(a),Za.isSame.call(this,a)&&Boolean(this._ambigTime)===Boolean(a._ambigTime)&&Boolean(this._ambigZone)===Boolean(a._ambigZone)):Za.isSame.apply(this,arguments)},a.each(["isBefore","isAfter"],function(a,b){Ya[b]=function(a,c){var d;return this._fullCalendar?(d=fa([this,a]),Za[b].call(d[0],d[1],c)):Za[b].apply(this,arguments)}}),Sa="_d"in b()&&"updateOffset"in b,Ta=Sa?function(a,c){a._d.setTime(Date.UTC.apply(Date,c)),b.updateOffset(a,!1)}:ha,Ua=Sa?function(a,c){a._d.setTime(+new Date(c[0]||0,c[1]||0,c[2]||0,c[3]||0,c[4]||0,c[5]||0,c[6]||0)),b.updateOffset(a,!1)}:ha;var $a={t:function(a){return ia(a,"a").charAt(0)},T:function(a){return ia(a,"A").charAt(0)}};Ma.formatRange=ma;var _a={Y:"year",M:"month",D:"day",d:"day",A:"second",a:"second",T:"second",t:"second",H:"second",h:"second",m:"second",s:"second"},ab={};Ma.Class=ra,ra.extend=function(a){var b,c=this;return a=a||{},U(a,"constructor")&&(b=a.constructor),"function"!=typeof b&&(b=a.constructor=function(){c.apply(this,arguments)}),b.prototype=R(c.prototype),S(a,b.prototype),T(a,b.prototype),S(c,b),b},ra.mixin=function(a){S(a.prototype||a,this.prototype)};var bb=Ma.Emitter=ra.extend({callbackHash:null,on:function(a,b){return this.getCallbacks(a).add(b),this},off:function(a,b){return this.getCallbacks(a).remove(b),this},trigger:function(a){var b=Array.prototype.slice.call(arguments,1);return this.triggerWith(a,this,b),this},triggerWith:function(a,b,c){var d=this.getCallbacks(a);return d.fireWith(b,c),this},getCallbacks:function(b){var c;return this.callbackHash||(this.callbackHash={}),c=this.callbackHash[b],c||(c=this.callbackHash[b]=a.Callbacks()),c}}),cb=ra.extend({isHidden:!0,options:null,el:null,documentMousedownProxy:null,margin:10,constructor:function(a){this.options=a||{}},show:function(){this.isHidden&&(this.el||this.render(),this.el.show(),this.position(),this.isHidden=!1,this.trigger("show"))},hide:function(){this.isHidden||(this.el.hide(),this.isHidden=!0,this.trigger("hide"))},render:function(){var b=this,c=this.options;this.el=a('<div class="fc-popover"/>').addClass(c.className||"").css({top:0,left:0}).append(c.content).appendTo(c.parentEl),this.el.on("click",".fc-close",function(){b.hide()}),c.autoHide&&a(document).on("mousedown",this.documentMousedownProxy=ca(this,"documentMousedown"))},documentMousedown:function(b){this.el&&!a(b.target).closest(this.el).length&&this.hide()},removeElement:function(){this.hide(),this.el&&(this.el.remove(),this.el=null),a(document).off("mousedown",this.documentMousedownProxy)},position:function(){var b,c,d,e,f,g=this.options,h=this.el.offsetParent().offset(),i=this.el.outerWidth(),j=this.el.outerHeight(),k=a(window),l=n(this.el);e=g.top||0,f=void 0!==g.left?g.left:void 0!==g.right?g.right-i:0,l.is(window)||l.is(document)?(l=k,b=0,c=0):(d=l.offset(),b=d.top,c=d.left),b+=k.scrollTop(),c+=k.scrollLeft(),g.viewportConstrain!==!1&&(e=Math.min(e,b+l.outerHeight()-j-this.margin),e=Math.max(e,b+this.margin),f=Math.min(f,c+l.outerWidth()-i-this.margin),f=Math.max(f,c+this.margin)),this.el.css({top:e-h.top,left:f-h.left})},trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1));
7
  }}),db=ra.extend({grid:null,rowCoords:null,colCoords:null,containerEl:null,bounds:null,constructor:function(a){this.grid=a},build:function(){this.grid.build(),this.rowCoords=this.grid.computeRowCoords(),this.colCoords=this.grid.computeColCoords(),this.computeBounds()},clear:function(){this.grid.clear(),this.rowCoords=null,this.colCoords=null},getCell:function(b,c){var d,e,f,g=this.rowCoords,h=g.length,i=this.colCoords,j=i.length,k=null,l=null;if(this.inBounds(b,c)){for(d=0;h>d;d++)if(e=g[d],c>=e.top&&c<e.bottom){k=d;break}for(d=0;j>d;d++)if(e=i[d],b>=e.left&&b<e.right){l=d;break}if(null!==k&&null!==l)return f=this.grid.getCell(k,l),f.grid=this.grid,a.extend(f,g[k],i[l]),f}return null},computeBounds:function(){this.bounds=this.containerEl?p(this.containerEl):null},inBounds:function(a,b){var c=this.bounds;return c?a>=c.left&&a<c.right&&b>=c.top&&b<c.bottom:!0}}),eb=ra.extend({coordMaps:null,constructor:function(a){this.coordMaps=a},build:function(){var a,b=this.coordMaps;for(a=0;a<b.length;a++)b[a].build()},getCell:function(a,b){var c,d=this.coordMaps,e=null;for(c=0;c<d.length&&!e;c++)e=d[c].getCell(a,b);return e},clear:function(){var a,b=this.coordMaps;for(a=0;a<b.length;a++)b[a].clear()}}),fb=Ma.DragListener=ra.extend({options:null,isListening:!1,isDragging:!1,originX:null,originY:null,mousemoveProxy:null,mouseupProxy:null,subjectEl:null,subjectHref:null,scrollEl:null,scrollBounds:null,scrollTopVel:null,scrollLeftVel:null,scrollIntervalId:null,scrollHandlerProxy:null,scrollSensitivity:30,scrollSpeed:200,scrollIntervalMs:50,constructor:function(a){a=a||{},this.options=a,this.subjectEl=a.subjectEl},mousedown:function(a){v(a)&&(a.preventDefault(),this.startListening(a),this.options.distance||this.startDrag(a))},startListening:function(b){var c;this.isListening||(b&&this.options.scroll&&(c=n(a(b.target)),c.is(window)||c.is(document)||(this.scrollEl=c,this.scrollHandlerProxy=da(ca(this,"scrollHandler"),100),this.scrollEl.on("scroll",this.scrollHandlerProxy))),a(document).on("mousemove",this.mousemoveProxy=ca(this,"mousemove")).on("mouseup",this.mouseupProxy=ca(this,"mouseup")).on("selectstart",this.preventDefault),b?(this.originX=b.pageX,this.originY=b.pageY):(this.originX=0,this.originY=0),this.isListening=!0,this.listenStart(b))},listenStart:function(a){this.trigger("listenStart",a)},mousemove:function(a){var b,c,d=a.pageX-this.originX,e=a.pageY-this.originY;this.isDragging||(b=this.options.distance||1,c=d*d+e*e,c>=b*b&&this.startDrag(a)),this.isDragging&&this.drag(d,e,a)},startDrag:function(a){this.isListening||this.startListening(),this.isDragging||(this.isDragging=!0,this.dragStart(a))},dragStart:function(a){var b=this.subjectEl;this.trigger("dragStart",a),(this.subjectHref=b?b.attr("href"):null)&&b.removeAttr("href")},drag:function(a,b,c){this.trigger("drag",a,b,c),this.updateScroll(c)},mouseup:function(a){this.stopListening(a)},stopDrag:function(a){this.isDragging&&(this.stopScrolling(),this.dragStop(a),this.isDragging=!1)},dragStop:function(a){var b=this;this.trigger("dragStop",a),setTimeout(function(){b.subjectHref&&b.subjectEl.attr("href",b.subjectHref)},0)},stopListening:function(b){this.stopDrag(b),this.isListening&&(this.scrollEl&&(this.scrollEl.off("scroll",this.scrollHandlerProxy),this.scrollHandlerProxy=null),a(document).off("mousemove",this.mousemoveProxy).off("mouseup",this.mouseupProxy).off("selectstart",this.preventDefault),this.mousemoveProxy=null,this.mouseupProxy=null,this.isListening=!1,this.listenStop(b))},listenStop:function(a){this.trigger("listenStop",a)},trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1))},preventDefault:function(a){a.preventDefault()},computeScrollBounds:function(){var a=this.scrollEl;this.scrollBounds=a?o(a):null},updateScroll:function(a){var b,c,d,e,f=this.scrollSensitivity,g=this.scrollBounds,h=0,i=0;g&&(b=(f-(a.pageY-g.top))/f,c=(f-(g.bottom-a.pageY))/f,d=(f-(a.pageX-g.left))/f,e=(f-(g.right-a.pageX))/f,b>=0&&1>=b?h=b*this.scrollSpeed*-1:c>=0&&1>=c&&(h=c*this.scrollSpeed),d>=0&&1>=d?i=d*this.scrollSpeed*-1:e>=0&&1>=e&&(i=e*this.scrollSpeed)),this.setScrollVel(h,i)},setScrollVel:function(a,b){this.scrollTopVel=a,this.scrollLeftVel=b,this.constrainScrollVel(),!this.scrollTopVel&&!this.scrollLeftVel||this.scrollIntervalId||(this.scrollIntervalId=setInterval(ca(this,"scrollIntervalFunc"),this.scrollIntervalMs))},constrainScrollVel:function(){var a=this.scrollEl;this.scrollTopVel<0?a.scrollTop()<=0&&(this.scrollTopVel=0):this.scrollTopVel>0&&a.scrollTop()+a[0].clientHeight>=a[0].scrollHeight&&(this.scrollTopVel=0),this.scrollLeftVel<0?a.scrollLeft()<=0&&(this.scrollLeftVel=0):this.scrollLeftVel>0&&a.scrollLeft()+a[0].clientWidth>=a[0].scrollWidth&&(this.scrollLeftVel=0)},scrollIntervalFunc:function(){var a=this.scrollEl,b=this.scrollIntervalMs/1e3;this.scrollTopVel&&a.scrollTop(a.scrollTop()+this.scrollTopVel*b),this.scrollLeftVel&&a.scrollLeft(a.scrollLeft()+this.scrollLeftVel*b),this.constrainScrollVel(),this.scrollTopVel||this.scrollLeftVel||this.stopScrolling()},stopScrolling:function(){this.scrollIntervalId&&(clearInterval(this.scrollIntervalId),this.scrollIntervalId=null,this.scrollStop())},scrollHandler:function(){this.scrollIntervalId||this.scrollStop()},scrollStop:function(){}}),gb=fb.extend({coordMap:null,origCell:null,cell:null,coordAdjust:null,constructor:function(a,b){fb.prototype.constructor.call(this,b),this.coordMap=a},listenStart:function(a){var b,c,d,e=this.subjectEl;fb.prototype.listenStart.apply(this,arguments),this.computeCoords(),a?(c={left:a.pageX,top:a.pageY},d=c,e&&(b=o(e),d=x(d,b)),this.origCell=this.getCell(d.left,d.top),e&&this.options.subjectCenter&&(this.origCell&&(b=w(this.origCell,b)||b),d=y(b)),this.coordAdjust=z(d,c)):(this.origCell=null,this.coordAdjust=null)},computeCoords:function(){this.coordMap.build(),this.computeScrollBounds()},dragStart:function(a){var b;fb.prototype.dragStart.apply(this,arguments),b=this.getCell(a.pageX,a.pageY),b&&this.cellOver(b)},drag:function(a,b,c){var d;fb.prototype.drag.apply(this,arguments),d=this.getCell(c.pageX,c.pageY),sa(d,this.cell)||(this.cell&&this.cellOut(),d&&this.cellOver(d))},dragStop:function(){this.cellDone(),fb.prototype.dragStop.apply(this,arguments)},cellOver:function(a){this.cell=a,this.trigger("cellOver",a,sa(a,this.origCell),this.origCell)},cellOut:function(){this.cell&&(this.trigger("cellOut",this.cell),this.cellDone(),this.cell=null)},cellDone:function(){this.cell&&this.trigger("cellDone",this.cell)},listenStop:function(){fb.prototype.listenStop.apply(this,arguments),this.origCell=this.cell=null,this.coordMap.clear()},scrollStop:function(){fb.prototype.scrollStop.apply(this,arguments),this.computeCoords()},getCell:function(a,b){return this.coordAdjust&&(a+=this.coordAdjust.left,b+=this.coordAdjust.top),this.coordMap.getCell(a,b)}}),hb=ra.extend({options:null,sourceEl:null,el:null,parentEl:null,top0:null,left0:null,mouseY0:null,mouseX0:null,topDelta:null,leftDelta:null,mousemoveProxy:null,isFollowing:!1,isHidden:!1,isAnimating:!1,constructor:function(b,c){this.options=c=c||{},this.sourceEl=b,this.parentEl=c.parentEl?a(c.parentEl):b.parent()},start:function(b){this.isFollowing||(this.isFollowing=!0,this.mouseY0=b.pageY,this.mouseX0=b.pageX,this.topDelta=0,this.leftDelta=0,this.isHidden||this.updatePosition(),a(document).on("mousemove",this.mousemoveProxy=ca(this,"mousemove")))},stop:function(b,c){function d(){this.isAnimating=!1,e.removeElement(),this.top0=this.left0=null,c&&c()}var e=this,f=this.options.revertDuration;this.isFollowing&&!this.isAnimating&&(this.isFollowing=!1,a(document).off("mousemove",this.mousemoveProxy),b&&f&&!this.isHidden?(this.isAnimating=!0,this.el.animate({top:this.top0,left:this.left0},{duration:f,complete:d})):d())},getEl:function(){var a=this.el;return a||(this.sourceEl.width(),a=this.el=this.sourceEl.clone().css({position:"absolute",visibility:"",display:this.isHidden?"none":"",margin:0,right:"auto",bottom:"auto",width:this.sourceEl.width(),height:this.sourceEl.height(),opacity:this.options.opacity||"",zIndex:this.options.zIndex}).appendTo(this.parentEl)),a},removeElement:function(){this.el&&(this.el.remove(),this.el=null)},updatePosition:function(){var a,b;this.getEl(),null===this.top0&&(this.sourceEl.width(),a=this.sourceEl.offset(),b=this.el.offsetParent().offset(),this.top0=a.top-b.top,this.left0=a.left-b.left),this.el.css({top:this.top0+this.topDelta,left:this.left0+this.leftDelta})},mousemove:function(a){this.topDelta=a.pageY-this.mouseY0,this.leftDelta=a.pageX-this.mouseX0,this.isHidden||this.updatePosition()},hide:function(){this.isHidden||(this.isHidden=!0,this.el&&this.el.hide())},show:function(){this.isHidden&&(this.isHidden=!1,this.updatePosition(),this.getEl().show())}}),ib=ra.extend({view:null,isRTL:null,cellHtml:"<td/>",constructor:function(a){this.view=a,this.isRTL=a.opt("isRTL")},rowHtml:function(a,b){var c,d,e=this.getHtmlRenderer("cell",a),f="";for(b=b||0,c=0;c<this.colCnt;c++)d=this.getCell(b,c),f+=e(d);return f=this.bookendCells(f,a,b),"<tr>"+f+"</tr>"},bookendCells:function(a,b,c){var d=this.getHtmlRenderer("intro",b)(c||0),e=this.getHtmlRenderer("outro",b)(c||0),f=this.isRTL?e:d,g=this.isRTL?d:e;return"string"==typeof a?f+a+g:a.prepend(f).append(g)},getHtmlRenderer:function(a,b){var c,d,e,f,g=this.view;return c=a+"Html",b&&(d=b+_(a)+"Html"),d&&(f=g[d])?e=g:d&&(f=this[d])?e=this:(f=g[c])?e=g:(f=this[c])&&(e=this),"function"==typeof f?function(){return f.apply(e,arguments)||""}:function(){return f||""}}}),jb=Ma.Grid=ib.extend({start:null,end:null,rowCnt:0,colCnt:0,el:null,coordMap:null,elsByFill:null,externalDragStartProxy:null,colHeadFormat:null,eventTimeFormat:null,displayEventTime:null,displayEventEnd:null,cellDuration:null,largeUnit:null,constructor:function(){ib.apply(this,arguments),this.coordMap=new db(this),this.elsByFill={},this.externalDragStartProxy=ca(this,"externalDragStart")},computeColHeadFormat:function(){},computeEventTimeFormat:function(){return this.view.opt("smallTimeFormat")},computeDisplayEventTime:function(){return!0},computeDisplayEventEnd:function(){return!0},setRange:function(a){this.start=a.start.clone(),this.end=a.end.clone(),this.rangeUpdated(),this.processRangeOptions()},rangeUpdated:function(){},processRangeOptions:function(){var a,b,c=this.view;this.colHeadFormat=c.opt("columnFormat")||this.computeColHeadFormat(),this.eventTimeFormat=c.opt("eventTimeFormat")||c.opt("timeFormat")||this.computeEventTimeFormat(),a=c.opt("displayEventTime"),null==a&&(a=this.computeDisplayEventTime()),b=c.opt("displayEventEnd"),null==b&&(b=this.computeDisplayEventEnd()),this.displayEventTime=a,this.displayEventEnd=b},build:function(){},clear:function(){},rangeToSegs:function(a){},diffDates:function(a,b){return this.largeUnit?H(a,b,this.largeUnit):F(a,b)},getCell:function(b,c){var d;return null==c&&("number"==typeof b?(c=b%this.colCnt,b=Math.floor(b/this.colCnt)):(c=b.col,b=b.row)),d={row:b,col:c},a.extend(d,this.getRowData(b),this.getColData(c)),a.extend(d,this.computeCellRange(d)),d},computeCellRange:function(a){var b=this.computeCellDate(a);return{start:b,end:b.clone().add(this.cellDuration)}},computeCellDate:function(a){},getRowData:function(a){return{}},getColData:function(a){return{}},getRowEl:function(a){},getColEl:function(a){},getCellDayEl:function(a){return this.getColEl(a.col)||this.getRowEl(a.row)},computeRowCoords:function(){var a,b,c,d=[];for(a=0;a<this.rowCnt;a++)b=this.getRowEl(a),c=b.offset().top,d.push({top:c,bottom:c+b.outerHeight()});return d},computeColCoords:function(){var a,b,c,d=[];for(a=0;a<this.colCnt;a++)b=this.getColEl(a),c=b.offset().left,d.push({left:c,right:c+b.outerWidth()});return d},setElement:function(b){var c=this;this.el=b,b.on("mousedown",function(b){a(b.target).is(".fc-event-container *, .fc-more")||a(b.target).closest(".fc-popover").length||c.dayMousedown(b)}),this.bindSegHandlers(),this.bindGlobalHandlers()},removeElement:function(){this.unbindGlobalHandlers(),this.el.remove()},renderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},bindGlobalHandlers:function(){a(document).on("dragstart sortstart",this.externalDragStartProxy)},unbindGlobalHandlers:function(){a(document).off("dragstart sortstart",this.externalDragStartProxy)},dayMousedown:function(a){var b,c,d=this,e=this.view,f=e.opt("selectable"),i=new gb(this.coordMap,{scroll:e.opt("dragScroll"),dragStart:function(){e.unselect()},cellOver:function(a,e,h){h&&(b=e?a:null,f&&(c=d.computeSelection(h,a),c?d.renderSelection(c):g()))},cellOut:function(a){b=null,c=null,d.unrenderSelection(),h()},listenStop:function(a){b&&e.triggerDayClick(b,d.getCellDayEl(b),a),c&&e.reportSelection(c,a),h()}});i.mousedown(a)},renderRangeHelper:function(a,b){var c=this.fabricateHelperEvent(a,b);this.renderHelper(c,b)},fabricateHelperEvent:function(a,b){var c=b?R(b.event):{};return c.start=a.start.clone(),c.end=a.end?a.end.clone():null,c.allDay=null,this.view.calendar.normalizeEventRange(c),c.className=(c.className||[]).concat("fc-helper"),b||(c.editable=!1),c},renderHelper:function(a,b){},unrenderHelper:function(){},renderSelection:function(a){this.renderHighlight(this.selectionRangeToSegs(a))},unrenderSelection:function(){this.unrenderHighlight()},computeSelection:function(a,b){var c,d=[a.start,a.end,b.start,b.end];return d.sort(aa),c={start:d[0].clone(),end:d[3].clone()},this.view.calendar.isSelectionRangeAllowed(c)?c:null},selectionRangeToSegs:function(a){return this.rangeToSegs(a)},renderHighlight:function(a){this.renderFill("highlight",a)},unrenderHighlight:function(){this.unrenderFill("highlight")},highlightSegClasses:function(){return["fc-highlight"]},renderFill:function(a,b){},unrenderFill:function(a){var b=this.elsByFill[a];b&&(b.remove(),delete this.elsByFill[a])},renderFillSegEls:function(b,c){var d,e=this,f=this[b+"SegEl"],g="",h=[];if(c.length){for(d=0;d<c.length;d++)g+=this.fillSegHtml(b,c[d]);a(g).each(function(b,d){var g=c[b],i=a(d);f&&(i=f.call(e,g,i)),i&&(i=a(i),i.is(e.fillSegTag)&&(g.el=i,h.push(g)))})}return h},fillSegTag:"div",fillSegHtml:function(a,b){var c=this[a+"SegClasses"],d=this[a+"SegCss"],e=c?c.call(this,b):[],f=$(d?d.call(this,b):{});return"<"+this.fillSegTag+(e.length?' class="'+e.join(" ")+'"':"")+(f?' style="'+f+'"':"")+" />"},headHtml:function(){return'<div class="fc-row '+this.view.widgetHeaderClass+'"><table><thead>'+this.rowHtml("head")+"</thead></table></div>"},headCellHtml:function(a){var b=this.view,c=a.start;return'<th class="fc-day-header '+b.widgetHeaderClass+" fc-"+Qa[c.day()]+'">'+Y(c.format(this.colHeadFormat))+"</th>"},bgCellHtml:function(a){var b=this.view,c=a.start,d=this.getDayClasses(c);return d.unshift("fc-day",b.widgetContentClass),'<td class="'+d.join(" ")+'" data-date="'+c.format("YYYY-MM-DD")+'"></td>'},getDayClasses:function(a){var b=this.view,c=b.calendar.getNow().stripTime(),d=["fc-"+Qa[a.day()]];return 1==b.intervalDuration.as("months")&&a.month()!=b.intervalStart.month()&&d.push("fc-other-month"),a.isSame(c,"day")?d.push("fc-today",b.highlightStateClass):c>a?d.push("fc-past"):d.push("fc-future"),d}});jb.mixin({mousedOverSeg:null,isDraggingSeg:!1,isResizingSeg:!1,isDraggingExternal:!1,segs:null,renderEvents:function(a){var b,c,d=this.eventsToSegs(a),e=[],f=[];for(b=0;b<d.length;b++)c=d[b],ta(c.event)?e.push(c):f.push(c);e=this.renderBgSegs(e)||e,f=this.renderFgSegs(f)||f,this.segs=e.concat(f)},unrenderEvents:function(){this.triggerSegMouseout(),this.unrenderFgSegs(),this.unrenderBgSegs(),this.segs=null},getEventSegs:function(){return this.segs||[]},renderFgSegs:function(a){},unrenderFgSegs:function(){},renderFgSegEls:function(b,c){var d,e=this.view,f="",g=[];if(b.length){for(d=0;d<b.length;d++)f+=this.fgSegHtml(b[d],c);a(f).each(function(c,d){var f=b[c],h=e.resolveEventEl(f.event,a(d));h&&(h.data("fc-seg",f),f.el=h,g.push(f))})}return g},fgSegHtml:function(a,b){},renderBgSegs:function(a){return this.renderFill("bgEvent",a)},unrenderBgSegs:function(){this.unrenderFill("bgEvent")},bgEventSegEl:function(a,b){return this.view.resolveEventEl(a.event,b)},bgEventSegClasses:function(a){var b=a.event,c=b.source||{};return["fc-bgevent"].concat(b.className,c.className||[])},bgEventSegCss:function(a){var b=this.view,c=a.event,d=c.source||{};return{"background-color":c.backgroundColor||c.color||d.backgroundColor||d.color||b.opt("eventBackgroundColor")||b.opt("eventColor")}},businessHoursSegClasses:function(a){return["fc-nonbusiness","fc-bgevent"]},bindSegHandlers:function(){var b=this,c=this.view;a.each({mouseenter:function(a,c){b.triggerSegMouseover(a,c)},mouseleave:function(a,c){b.triggerSegMouseout(a,c)},click:function(a,b){return c.trigger("eventClick",this,a.event,b)},mousedown:function(d,e){a(e.target).is(".fc-resizer")&&c.isEventResizable(d.event)?b.segResizeMousedown(d,e,a(e.target).is(".fc-start-resizer")):c.isEventDraggable(d.event)&&b.segDragMousedown(d,e)}},function(c,d){b.el.on(c,".fc-event-container > *",function(c){var e=a(this).data("fc-seg");return!e||b.isDraggingSeg||b.isResizingSeg?void 0:d.call(this,e,c)})})},triggerSegMouseover:function(a,b){this.mousedOverSeg||(this.mousedOverSeg=a,this.view.trigger("eventMouseover",a.el[0],a.event,b))},triggerSegMouseout:function(a,b){b=b||{},this.mousedOverSeg&&(a=a||this.mousedOverSeg,this.mousedOverSeg=null,this.view.trigger("eventMouseout",a.el[0],a.event,b))},segDragMousedown:function(a,b){var c,d=this,e=this.view,f=e.calendar,i=a.el,j=a.event,k=new hb(a.el,{parentEl:e.el,opacity:e.opt("dragOpacity"),revertDuration:e.opt("dragRevertDuration"),zIndex:2}),l=new gb(e.coordMap,{distance:5,scroll:e.opt("dragScroll"),subjectEl:i,subjectCenter:!0,listenStart:function(a){k.hide(),k.start(a)},dragStart:function(b){d.triggerSegMouseout(a,b),d.segDragStart(a,b),e.hideEvent(j)},cellOver:function(b,h,i){a.cell&&(i=a.cell),c=d.computeEventDrop(i,b,j),c&&!f.isEventRangeAllowed(c,j)&&(g(),c=null),c&&e.renderDrag(c,a)?k.hide():k.show(),h&&(c=null)},cellOut:function(){e.unrenderDrag(),k.show(),c=null},cellDone:function(){h()},dragStop:function(b){k.stop(!c,function(){e.unrenderDrag(),e.showEvent(j),d.segDragStop(a,b),c&&e.reportEventDrop(j,c,this.largeUnit,i,b)})},listenStop:function(){k.stop()}});l.mousedown(b)},segDragStart:function(a,b){this.isDraggingSeg=!0,this.view.trigger("eventDragStart",a.el[0],a.event,b,{})},segDragStop:function(a,b){this.isDraggingSeg=!1,this.view.trigger("eventDragStop",a.el[0],a.event,b,{})},computeEventDrop:function(a,b,c){var d,e,f=this.view.calendar,g=a.start,h=b.start;return g.hasTime()===h.hasTime()?(d=this.diffDates(h,g),c.allDay&&N(d)?(e={start:c.start.clone(),end:f.getEventEnd(c),allDay:!1},f.normalizeEventRangeTimes(e)):e={start:c.start.clone(),end:c.end?c.end.clone():null,allDay:c.allDay},e.start.add(d),e.end&&e.end.add(d)):e={start:h.clone(),end:null,allDay:!h.hasTime()},e},applyDragOpacity:function(a){var b=this.view.opt("dragOpacity");null!=b&&a.each(function(a,c){c.style.opacity=b})},externalDragStart:function(b,c){var d,e,f=this.view;f.opt("droppable")&&(d=a((c?c.item:null)||b.target),e=f.opt("dropAccept"),(a.isFunction(e)?e.call(d[0],d):d.is(e))&&(this.isDraggingExternal||this.listenToExternalDrag(d,b,c)))},listenToExternalDrag:function(a,b,c){var d,e,f=this,i=ya(a);d=new gb(this.coordMap,{listenStart:function(){f.isDraggingExternal=!0},cellOver:function(a){e=f.computeExternalDrop(a,i),e?f.renderDrag(e):g()},cellOut:function(){e=null,f.unrenderDrag(),h()},dragStop:function(){f.unrenderDrag(),h(),e&&f.view.reportExternalDrop(i,e,a,b,c)},listenStop:function(){f.isDraggingExternal=!1}}),d.startDrag(b)},computeExternalDrop:function(a,b){var c={start:a.start.clone(),end:null};return b.startTime&&!c.start.hasTime()&&c.start.time(b.startTime),b.duration&&(c.end=c.start.clone().add(b.duration)),this.view.calendar.isExternalDropRangeAllowed(c,b.eventProps)?c:null},renderDrag:function(a,b){},unrenderDrag:function(){},segResizeMousedown:function(a,b,c){var d,e,f=this,i=this.view,j=i.calendar,k=a.el,l=a.event,m=j.getEventEnd(l);d=new gb(this.coordMap,{distance:5,scroll:i.opt("dragScroll"),subjectEl:k,dragStart:function(b){f.triggerSegMouseout(a,b),f.segResizeStart(a,b)},cellOver:function(b,d,h){e=c?f.computeEventStartResize(h,b,l):f.computeEventEndResize(h,b,l),e&&(j.isEventRangeAllowed(e,l)?e.start.isSame(l.start)&&e.end.isSame(m)&&(e=null):(g(),e=null)),e&&(i.hideEvent(l),f.renderEventResize(e,a))},cellOut:function(){e=null},cellDone:function(){f.unrenderEventResize(),i.showEvent(l),h()},dragStop:function(b){f.segResizeStop(a,b),e&&i.reportEventResize(l,e,this.largeUnit,k,b)}}),d.mousedown(b)},segResizeStart:function(a,b){this.isResizingSeg=!0,this.view.trigger("eventResizeStart",a.el[0],a.event,b,{})},segResizeStop:function(a,b){this.isResizingSeg=!1,this.view.trigger("eventResizeStop",a.el[0],a.event,b,{})},computeEventStartResize:function(a,b,c){return this.computeEventResize("start",a,b,c)},computeEventEndResize:function(a,b,c){return this.computeEventResize("end",a,b,c)},computeEventResize:function(a,b,c,d){var e,f,g=this.view.calendar,h=this.diffDates(c[a],b[a]);return e={start:d.start.clone(),end:g.getEventEnd(d),allDay:d.allDay},e.allDay&&N(h)&&(e.allDay=!1,g.normalizeEventRangeTimes(e)),e[a].add(h),e.start.isBefore(e.end)||(f=d.allDay?g.defaultAllDayEventDuration:g.defaultTimedEventDuration,this.cellDuration&&this.cellDuration<f&&(f=this.cellDuration),"start"==a?e.start=e.end.clone().subtract(f):e.end=e.start.clone().add(f)),e},renderEventResize:function(a,b){},unrenderEventResize:function(){},getEventTimeText:function(a,b,c){return null==b&&(b=this.eventTimeFormat),null==c&&(c=this.displayEventEnd),this.displayEventTime&&a.start.hasTime()?c&&a.end?this.view.formatRange(a,b):a.start.format(b):""},getSegClasses:function(a,b,c){var d=a.event,e=["fc-event",a.isStart?"fc-start":"fc-not-start",a.isEnd?"fc-end":"fc-not-end"].concat(d.className,d.source?d.source.className:[]);return b&&e.push("fc-draggable"),c&&e.push("fc-resizable"),e},getEventSkinCss:function(a){var b=this.view,c=a.source||{},d=a.color,e=c.color,f=b.opt("eventColor");return{"background-color":a.backgroundColor||d||c.backgroundColor||e||b.opt("eventBackgroundColor")||f,"border-color":a.borderColor||d||c.borderColor||e||b.opt("eventBorderColor")||f,color:a.textColor||c.textColor||b.opt("eventTextColor")}},eventsToSegs:function(a,b){var c,d=this.eventsToRanges(a),e=[];for(c=0;c<d.length;c++)e.push.apply(e,this.eventRangeToSegs(d[c],b));return e},eventsToRanges:function(b){var c=this,d=wa(b),e=[];return a.each(d,function(a,b){b.length&&e.push.apply(e,ua(b[0])?c.eventsToInverseRanges(b):c.eventsToNormalRanges(b))}),e},eventsToNormalRanges:function(a){var b,c,d,e,f=this.view.calendar,g=[];for(b=0;b<a.length;b++)c=a[b],d=c.start.clone().stripZone(),e=f.getEventEnd(c).stripZone(),g.push({event:c,start:d,end:e,eventStartMS:+d,eventDurationMS:e-d});return g},eventsToInverseRanges:function(a){var b,c,d=this.view,e=d.start.clone().stripZone(),f=d.end.clone().stripZone(),g=this.eventsToNormalRanges(a),h=[],i=a[0],j=e;for(g.sort(xa),b=0;b<g.length;b++)c=g[b],c.start>j&&h.push({event:i,start:j,end:c.start}),j=c.end;return f>j&&h.push({event:i,start:j,end:f}),h},eventRangeToSegs:function(a,b){var c,d,e;for(a=this.view.calendar.ensureVisibleEventRange(a),c=b?b(a):this.rangeToSegs(a),d=0;d<c.length;d++)e=c[d],e.event=a.event,e.eventStartMS=a.eventStartMS,e.eventDurationMS=a.eventDurationMS;return c},sortSegs:function(a){a.sort(ca(this,"compareSegs"))},compareSegs:function(a,b){return a.eventStartMS-b.eventStartMS||b.eventDurationMS-a.eventDurationMS||b.event.allDay-a.event.allDay||B(a.event,b.event,this.view.eventOrderSpecs)}}),Ma.dataAttrPrefix="";var kb=jb.extend({numbersVisible:!1,bottomCoordPadding:0,breakOnWeeks:null,cellDates:null,dayToCellOffsets:null,rowEls:null,dayEls:null,helperEls:null,constructor:function(){jb.apply(this,arguments),this.cellDuration=b.duration(1,"day")},renderDates:function(a){var b,c,d,e=this.view,f=this.rowCnt,g=this.colCnt,h=f*g,i="";for(b=0;f>b;b++)i+=this.dayRowHtml(b,a);for(this.el.html(i),this.rowEls=this.el.find(".fc-row"),this.dayEls=this.el.find(".fc-day"),c=0;h>c;c++)d=this.getCell(c),e.trigger("dayRender",null,d.start,this.dayEls.eq(c))},unrenderDates:function(){this.removeSegPopover()},renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents(!0),b=this.eventsToSegs(a);this.renderFill("businessHours",b,"bgevent")},dayRowHtml:function(a,b){var c=this.view,d=["fc-row","fc-week",c.widgetContentClass];return b&&d.push("fc-rigid"),'<div class="'+d.join(" ")+'"><div class="fc-bg"><table>'+this.rowHtml("day",a)+'</table></div><div class="fc-content-skeleton"><table>'+(this.numbersVisible?"<thead>"+this.rowHtml("number",a)+"</thead>":"")+"</table></div></div>"},dayCellHtml:function(a){return this.bgCellHtml(a)},computeColHeadFormat:function(){return this.rowCnt>1?"ddd":this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},computeEventTimeFormat:function(){return this.view.opt("extraSmallTimeFormat")},computeDisplayEventEnd:function(){return 1==this.colCnt},rangeUpdated:function(){var a,b,c,d;if(this.updateCellDates(),a=this.cellDates,this.breakOnWeeks){for(b=a[0].day(),d=1;d<a.length&&a[d].day()!=b;d++);c=Math.ceil(a.length/d)}else c=1,d=a.length;this.rowCnt=c,this.colCnt=d},updateCellDates:function(){for(var a=this.view,b=this.start.clone(),c=[],d=-1,e=[];b.isBefore(this.end);)a.isHiddenDay(b)?e.push(d+.5):(d++,e.push(d),c.push(b.clone())),b.add(1,"days");this.cellDates=c,this.dayToCellOffsets=e},computeCellDate:function(a){var b=this.colCnt,c=a.row*b+(this.isRTL?b-a.col-1:a.col);return this.cellDates[c].clone()},getRowEl:function(a){return this.rowEls.eq(a)},getColEl:function(a){return this.dayEls.eq(a)},getCellDayEl:function(a){return this.dayEls.eq(a.row*this.colCnt+a.col)},computeRowCoords:function(){var a=jb.prototype.computeRowCoords.call(this);return a[a.length-1].bottom+=this.bottomCoordPadding,a},rangeToSegs:function(a){var b,c,d,e,f,g,h,i,j,k,l=this.isRTL,m=this.rowCnt,n=this.colCnt,o=[];for(a=this.view.computeDayRange(a),b=this.dateToCellOffset(a.start),c=this.dateToCellOffset(a.end.subtract(1,"days")),d=0;m>d;d++)e=d*n,f=e+n-1,i=Math.max(e,b),j=Math.min(f,c),i=Math.ceil(i),j=Math.floor(j),j>=i&&(g=i===b,h=j===c,i-=e,j-=e,k={row:d,isStart:g,isEnd:h},l?(k.leftCol=n-j-1,k.rightCol=n-i-1):(k.leftCol=i,k.rightCol=j),o.push(k));return o},dateToCellOffset:function(a){var b=this.dayToCellOffsets,c=a.diff(this.start,"days");return 0>c?b[0]-1:c>=b.length?b[b.length-1]+1:b[c]},renderDrag:function(a,b){return this.renderHighlight(this.eventRangeToSegs(a)),b&&!b.el.closest(this.el).length?(this.renderRangeHelper(a,b),this.applyDragOpacity(this.helperEls),!0):void 0},unrenderDrag:function(){this.unrenderHighlight(),this.unrenderHelper()},renderEventResize:function(a,b){this.renderHighlight(this.eventRangeToSegs(a)),this.renderRangeHelper(a,b)},unrenderEventResize:function(){this.unrenderHighlight(),this.unrenderHelper()},renderHelper:function(b,c){var d,e=[],f=this.eventsToSegs([b]);f=this.renderFgSegEls(f),d=this.renderSegRows(f),this.rowEls.each(function(b,f){var g,h=a(f),i=a('<div class="fc-helper-skeleton"><table/></div>');g=c&&c.row===b?c.el.position().top:h.find(".fc-content-skeleton tbody").position().top,i.css("top",g).find("table").append(d[b].tbodyEl),h.append(i),e.push(i[0])}),this.helperEls=a(e)},unrenderHelper:function(){this.helperEls&&(this.helperEls.remove(),this.helperEls=null)},fillSegTag:"td",renderFill:function(b,c,d){var e,f,g,h=[];for(c=this.renderFillSegEls(b,c),e=0;e<c.length;e++)f=c[e],g=this.renderFillRow(b,f,d),this.rowEls.eq(f.row).append(g),h.push(g[0]);return this.elsByFill[b]=a(h),c},renderFillRow:function(b,c,d){var e,f,g=this.colCnt,h=c.leftCol,i=c.rightCol+1;return d=d||b.toLowerCase(),e=a('<div class="fc-'+d+'-skeleton"><table><tr/></table></div>'),f=e.find("tr"),h>0&&f.append('<td colspan="'+h+'"/>'),f.append(c.el.attr("colspan",i-h)),g>i&&f.append('<td colspan="'+(g-i)+'"/>'),this.bookendCells(f,b),e}});kb.mixin({rowStructs:null,unrenderEvents:function(){this.removeSegPopover(),jb.prototype.unrenderEvents.apply(this,arguments)},getEventSegs:function(){return jb.prototype.getEventSegs.call(this).concat(this.popoverSegs||[])},renderBgSegs:function(b){var c=a.grep(b,function(a){return a.event.allDay});return jb.prototype.renderBgSegs.call(this,c)},renderFgSegs:function(b){var c;return b=this.renderFgSegEls(b),c=this.rowStructs=this.renderSegRows(b),this.rowEls.each(function(b,d){a(d).find(".fc-content-skeleton > table").append(c[b].tbodyEl)}),b},unrenderFgSegs:function(){for(var a,b=this.rowStructs||[];a=b.pop();)a.tbodyEl.remove();this.rowStructs=null},renderSegRows:function(a){var b,c,d=[];for(b=this.groupSegRows(a),c=0;c<b.length;c++)d.push(this.renderSegRow(c,b[c]));return d},fgSegHtml:function(a,b){var c,d,e=this.view,f=a.event,g=e.isEventDraggable(f),h=!b&&f.allDay&&a.isStart&&e.isEventResizableFromStart(f),i=!b&&f.allDay&&a.isEnd&&e.isEventResizableFromEnd(f),j=this.getSegClasses(a,g,h||i),k=$(this.getEventSkinCss(f)),l="";return j.unshift("fc-day-grid-event","fc-h-event"),a.isStart&&(c=this.getEventTimeText(f),c&&(l='<span class="fc-time">'+Y(c)+"</span>")),d='<span class="fc-title">'+(Y(f.title||"")||"&nbsp;")+"</span>",'<a class="'+j.join(" ")+'"'+(f.url?' href="'+Y(f.url)+'"':"")+(k?' style="'+k+'"':"")+'><div class="fc-content">'+(this.isRTL?d+" "+l:l+" "+d)+"</div>"+(h?'<div class="fc-resizer fc-start-resizer" />':"")+(i?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},renderSegRow:function(b,c){function d(b){for(;b>g;)k=(r[e-1]||[])[g],k?k.attr("rowspan",parseInt(k.attr("rowspan")||1,10)+1):(k=a("<td/>"),h.append(k)),q[e][g]=k,r[e][g]=k,g++}var e,f,g,h,i,j,k,l=this.colCnt,m=this.buildSegLevels(c),n=Math.max(1,m.length),o=a("<tbody/>"),p=[],q=[],r=[];for(e=0;n>e;e++){if(f=m[e],g=0,h=a("<tr/>"),p.push([]),q.push([]),r.push([]),f)for(i=0;i<f.length;i++){for(j=f[i],d(j.leftCol),k=a('<td class="fc-event-container"/>').append(j.el),j.leftCol!=j.rightCol?k.attr("colspan",j.rightCol-j.leftCol+1):r[e][g]=k;g<=j.rightCol;)q[e][g]=k,p[e][g]=j,g++;h.append(k)}d(l),this.bookendCells(h,"eventSkeleton"),o.append(h)}return{row:b,tbodyEl:o,cellMatrix:q,segMatrix:p,segLevels:m,segs:c}},buildSegLevels:function(a){var b,c,d,e=[];for(this.sortSegs(a),b=0;b<a.length;b++){for(c=a[b],d=0;d<e.length&&za(c,e[d]);d++);c.level=d,(e[d]||(e[d]=[])).push(c)}for(d=0;d<e.length;d++)e[d].sort(Aa);return e},groupSegRows:function(a){var b,c=[];for(b=0;b<this.rowCnt;b++)c.push([]);for(b=0;b<a.length;b++)c[a[b].row].push(a[b]);return c}}),kb.mixin({segPopover:null,popoverSegs:null,removeSegPopover:function(){this.segPopover&&this.segPopover.hide()},limitRows:function(a){var b,c,d=this.rowStructs||[];for(b=0;b<d.length;b++)this.unlimitRow(b),c=a?"number"==typeof a?a:this.computeRowLevelLimit(b):!1,c!==!1&&this.limitRow(b,c)},computeRowLevelLimit:function(b){function c(b,c){f=Math.max(f,a(c).outerHeight())}var d,e,f,g=this.rowEls.eq(b),h=g.height(),i=this.rowStructs[b].tbodyEl.children();for(d=0;d<i.length;d++)if(e=i.eq(d).removeClass("fc-limited"),f=0,e.find("> td > :first-child").each(c),e.position().top+f>h)return d;return!1},limitRow:function(b,c){function d(d){for(;d>x;)e=u.getCell(b,x),k=u.getCellSegs(e,c),k.length&&(n=g[c-1][x],t=u.renderMoreLink(e,k),s=a("<div/>").append(t),n.append(s),w.push(s[0])),x++}var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=this,v=this.rowStructs[b],w=[],x=0;if(c&&c<v.segLevels.length){for(f=v.segLevels[c-1],g=v.cellMatrix,h=v.tbodyEl.children().slice(c).addClass("fc-limited").get(),i=0;i<f.length;i++){for(j=f[i],d(j.leftCol),m=[],l=0;x<=j.rightCol;)e=this.getCell(b,x),k=this.getCellSegs(e,c),m.push(k),l+=k.length,x++;if(l){for(n=g[c-1][j.leftCol],o=n.attr("rowspan")||1,p=[],q=0;q<m.length;q++)r=a('<td class="fc-more-cell"/>').attr("rowspan",o),k=m[q],e=this.getCell(b,j.leftCol+q),t=this.renderMoreLink(e,[j].concat(k)),s=a("<div/>").append(t),r.append(s),p.push(r[0]),w.push(r[0]);n.addClass("fc-limited").after(a(p)),h.push(n[0])}}d(this.colCnt),v.moreEls=a(w),v.limitedEls=a(h)}},
8
- unlimitRow:function(a){var b=this.rowStructs[a];b.moreEls&&(b.moreEls.remove(),b.moreEls=null),b.limitedEls&&(b.limitedEls.removeClass("fc-limited"),b.limitedEls=null)},renderMoreLink:function(b,c){var d=this,e=this.view;return a('<a class="fc-more"/>').text(this.getMoreLinkText(c.length)).on("click",function(f){var g=e.opt("eventLimitClick"),h=b.start,i=a(this),j=d.getCellDayEl(b),k=d.getCellSegs(b),l=d.resliceDaySegs(k,h),m=d.resliceDaySegs(c,h);"function"==typeof g&&(g=e.trigger("eventLimitClick",null,{date:h,dayEl:j,moreEl:i,segs:l,hiddenSegs:m},f)),"popover"===g?d.showSegPopover(b,i,l):"string"==typeof g&&e.calendar.zoomTo(h,g)})},showSegPopover:function(a,b,c){var d,e,f=this,g=this.view,h=b.parent();d=1==this.rowCnt?g.el:this.rowEls.eq(a.row),e={className:"fc-more-popover",content:this.renderSegPopoverContent(a,c),parentEl:this.el,top:d.offset().top,autoHide:!0,viewportConstrain:g.opt("popoverViewportConstrain"),hide:function(){f.segPopover.removeElement(),f.segPopover=null,f.popoverSegs=null}},this.isRTL?e.right=h.offset().left+h.outerWidth()+1:e.left=h.offset().left-1,this.segPopover=new cb(e),this.segPopover.show()},renderSegPopoverContent:function(b,c){var d,e=this.view,f=e.opt("theme"),g=b.start.format(e.opt("dayPopoverFormat")),h=a('<div class="fc-header '+e.widgetHeaderClass+'"><span class="fc-close '+(f?"ui-icon ui-icon-closethick":"fc-icon fc-icon-x")+'"></span><span class="fc-title">'+Y(g)+'</span><div class="fc-clear"/></div><div class="fc-body '+e.widgetContentClass+'"><div class="fc-event-container"></div></div>'),i=h.find(".fc-event-container");for(c=this.renderFgSegEls(c,!0),this.popoverSegs=c,d=0;d<c.length;d++)c[d].cell=b,i.append(c[d].el);return h},resliceDaySegs:function(b,c){var d=a.map(b,function(a){return a.event}),e=c.clone().stripTime(),f=e.clone().add(1,"days"),g={start:e,end:f};return b=this.eventsToSegs(d,function(a){var b=E(a,g);return b?[b]:[]}),this.sortSegs(b),b},getMoreLinkText:function(a){var b=this.view.opt("eventLimitText");return"function"==typeof b?b(a):"+"+a+" "+b},getCellSegs:function(a,b){for(var c,d=this.rowStructs[a.row].segMatrix,e=b||0,f=[];e<d.length;)c=d[e][a.col],c&&f.push(c),e++;return f}});var lb=jb.extend({slotDuration:null,snapDuration:null,minTime:null,maxTime:null,colDates:null,labelFormat:null,labelInterval:null,dayEls:null,slatEls:null,slatTops:null,helperEl:null,businessHourSegs:null,constructor:function(){jb.apply(this,arguments),this.processOptions()},renderDates:function(){this.el.html(this.renderHtml()),this.dayEls=this.el.find(".fc-day"),this.slatEls=this.el.find(".fc-slats tr")},renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents();this.businessHourSegs=this.renderFill("businessHours",this.eventsToSegs(a),"bgevent")},renderHtml:function(){return'<div class="fc-bg"><table>'+this.rowHtml("slotBg")+'</table></div><div class="fc-slats"><table>'+this.slatRowHtml()+"</table></div>"},slotBgCellHtml:function(a){return this.bgCellHtml(a)},slatRowHtml:function(){for(var a,c,d,e=this.view,f=this.isRTL,g="",h=b.duration(+this.minTime);h<this.maxTime;)a=this.start.clone().time(h),c=ba(L(h,this.labelInterval)),d='<td class="fc-axis fc-time '+e.widgetContentClass+'" '+e.axisStyleAttr()+">"+(c?"<span>"+Y(a.format(this.labelFormat))+"</span>":"")+"</td>",g+="<tr "+(c?"":'class="fc-minor"')+">"+(f?"":d)+'<td class="'+e.widgetContentClass+'"/>'+(f?d:"")+"</tr>",h.add(this.slotDuration);return g},processOptions:function(){var c,d=this.view,e=d.opt("slotDuration"),f=d.opt("snapDuration");e=b.duration(e),f=f?b.duration(f):e,this.slotDuration=e,this.snapDuration=f,this.cellDuration=f,this.minTime=b.duration(d.opt("minTime")),this.maxTime=b.duration(d.opt("maxTime")),c=d.opt("slotLabelFormat"),a.isArray(c)&&(c=c[c.length-1]),this.labelFormat=c||d.opt("axisFormat")||d.opt("smallTimeFormat"),c=d.opt("slotLabelInterval"),this.labelInterval=c?b.duration(c):this.computeLabelInterval(e)},computeLabelInterval:function(a){var c,d,e;for(c=yb.length-1;c>=0;c--)if(d=b.duration(yb[c]),e=L(d,a),ba(e)&&e>1)return d;return b.duration(a)},computeColHeadFormat:function(){return this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},computeEventTimeFormat:function(){return this.view.opt("noMeridiemTimeFormat")},computeDisplayEventEnd:function(){return!0},rangeUpdated:function(){var a,b=this.view,c=[];for(a=this.start.clone();a.isBefore(this.end);)c.push(a.clone()),a.add(1,"day"),a=b.skipHiddenDays(a);this.isRTL&&c.reverse(),this.colDates=c,this.colCnt=c.length,this.rowCnt=Math.ceil((this.maxTime-this.minTime)/this.snapDuration)},computeCellDate:function(a){var b=this.colDates[a.col],c=this.computeSnapTime(a.row);return b=this.view.calendar.rezoneDate(b),b.time(c),b},getColEl:function(a){return this.dayEls.eq(a)},computeSnapTime:function(a){return b.duration(this.minTime+this.snapDuration*a)},rangeToSegs:function(a){var b,c,d,e,f=this.colCnt,g=[];for(a={start:a.start.clone().stripZone(),end:a.end.clone().stripZone()},c=0;f>c;c++)d=this.colDates[c],e={start:d.clone().time(this.minTime),end:d.clone().time(this.maxTime)},b=E(a,e),b&&(b.col=c,g.push(b));return g},updateSize:function(a){this.computeSlatTops(),a&&this.updateSegVerticals()},computeRowCoords:function(){var a,b,c=this.el.offset().top,d=[];for(a=0;a<this.rowCnt;a++)b={top:c+this.computeTimeTop(this.computeSnapTime(a))},a>0&&(d[a-1].bottom=b.top),d.push(b);return b.bottom=b.top+this.computeTimeTop(this.computeSnapTime(a)),d},computeDateTop:function(a,c){return this.computeTimeTop(b.duration(a.clone().stripZone()-c.clone().stripTime()))},computeTimeTop:function(a){var b,c,d,e,f=(a-this.minTime)/this.slotDuration;return f=Math.max(0,f),f=Math.min(this.slatEls.length,f),b=Math.floor(f),c=f-b,d=this.slatTops[b],c?(e=this.slatTops[b+1],d+(e-d)*c):d},computeSlatTops:function(){var b,c=[];this.slatEls.each(function(d,e){b=a(e).position().top,c.push(b)}),c.push(b+this.slatEls.last().outerHeight()),this.slatTops=c},renderDrag:function(a,b){return b?(this.renderRangeHelper(a,b),this.applyDragOpacity(this.helperEl),!0):void this.renderHighlight(this.eventRangeToSegs(a))},unrenderDrag:function(){this.unrenderHelper(),this.unrenderHighlight()},renderEventResize:function(a,b){this.renderRangeHelper(a,b)},unrenderEventResize:function(){this.unrenderHelper()},renderHelper:function(b,c){var d,e,f,g,h=this.eventsToSegs([b]);for(h=this.renderFgSegEls(h),d=this.renderSegTable(h),e=0;e<h.length;e++)f=h[e],c&&c.col===f.col&&(g=c.el,f.el.css({left:g.css("left"),right:g.css("right"),"margin-left":g.css("margin-left"),"margin-right":g.css("margin-right")}));this.helperEl=a('<div class="fc-helper-skeleton"/>').append(d).appendTo(this.el)},unrenderHelper:function(){this.helperEl&&(this.helperEl.remove(),this.helperEl=null)},renderSelection:function(a){this.view.opt("selectHelper")?this.renderRangeHelper(a):this.renderHighlight(this.selectionRangeToSegs(a))},unrenderSelection:function(){this.unrenderHelper(),this.unrenderHighlight()},renderFill:function(b,c,d){var e,f,g,h,i,j,k,l,m,n;if(c.length){for(c=this.renderFillSegEls(b,c),e=this.groupSegCols(c),d=d||b.toLowerCase(),f=a('<div class="fc-'+d+'-skeleton"><table><tr/></table></div>'),g=f.find("tr"),h=0;h<e.length;h++)if(i=e[h],j=a("<td/>").appendTo(g),i.length)for(k=a('<div class="fc-'+d+'-container"/>').appendTo(j),l=this.colDates[h],m=0;m<i.length;m++)n=i[m],k.append(n.el.css({top:this.computeDateTop(n.start,l),bottom:-this.computeDateTop(n.end,l)}));this.bookendCells(g,b),this.el.append(f),this.elsByFill[b]=f}return c}});lb.mixin({eventSkeletonEl:null,renderFgSegs:function(b){return b=this.renderFgSegEls(b),this.el.append(this.eventSkeletonEl=a('<div class="fc-content-skeleton"/>').append(this.renderSegTable(b))),b},unrenderFgSegs:function(a){this.eventSkeletonEl&&(this.eventSkeletonEl.remove(),this.eventSkeletonEl=null)},renderSegTable:function(b){var c,d,e,f,g,h,i=a("<table><tr/></table>"),j=i.find("tr");for(c=this.groupSegCols(b),this.computeSegVerticals(b),f=0;f<c.length;f++){for(g=c[f],this.placeSlotSegs(g),h=a('<div class="fc-event-container"/>'),d=0;d<g.length;d++)e=g[d],e.el.css(this.generateSegPositionCss(e)),e.bottom-e.top<30&&e.el.addClass("fc-short"),h.append(e.el);j.append(a("<td/>").append(h))}return this.bookendCells(j,"eventSkeleton"),i},placeSlotSegs:function(a){var b,c,d;if(this.sortSegs(a),b=Ba(a),Ca(b),c=b[0]){for(d=0;d<c.length;d++)Da(c[d]);for(d=0;d<c.length;d++)this.computeSlotSegCoords(c[d],0,0)}},computeSlotSegCoords:function(a,b,c){var d,e=a.forwardSegs;if(void 0===a.forwardCoord)for(e.length?(this.sortForwardSlotSegs(e),this.computeSlotSegCoords(e[0],b+1,c),a.forwardCoord=e[0].backwardCoord):a.forwardCoord=1,a.backwardCoord=a.forwardCoord-(a.forwardCoord-c)/(b+1),d=0;d<e.length;d++)this.computeSlotSegCoords(e[d],0,a.forwardCoord)},updateSegVerticals:function(){var a,b=(this.segs||[]).concat(this.businessHourSegs||[]);for(this.computeSegVerticals(b),a=0;a<b.length;a++)b[a].el.css(this.generateSegVerticalCss(b[a]))},computeSegVerticals:function(a){var b,c;for(b=0;b<a.length;b++)c=a[b],c.top=this.computeDateTop(c.start,c.start),c.bottom=this.computeDateTop(c.end,c.start)},fgSegHtml:function(a,b){var c,d,e,f=this.view,g=a.event,h=f.isEventDraggable(g),i=!b&&a.isStart&&f.isEventResizableFromStart(g),j=!b&&a.isEnd&&f.isEventResizableFromEnd(g),k=this.getSegClasses(a,h,i||j),l=$(this.getEventSkinCss(g));return k.unshift("fc-time-grid-event","fc-v-event"),f.isMultiDayEvent(g)?(a.isStart||a.isEnd)&&(c=this.getEventTimeText(a),d=this.getEventTimeText(a,"LT"),e=this.getEventTimeText(a,null,!1)):(c=this.getEventTimeText(g),d=this.getEventTimeText(g,"LT"),e=this.getEventTimeText(g,null,!1)),'<a class="'+k.join(" ")+'"'+(g.url?' href="'+Y(g.url)+'"':"")+(l?' style="'+l+'"':"")+'><div class="fc-content">'+(c?'<div class="fc-time" data-start="'+Y(e)+'" data-full="'+Y(d)+'"><span>'+Y(c)+"</span></div>":"")+(g.title?'<div class="fc-title">'+Y(g.title)+"</div>":"")+'</div><div class="fc-bg"/>'+(j?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},generateSegPositionCss:function(a){var b,c,d=this.view.opt("slotEventOverlap"),e=a.backwardCoord,f=a.forwardCoord,g=this.generateSegVerticalCss(a);return d&&(f=Math.min(1,e+2*(f-e))),this.isRTL?(b=1-f,c=e):(b=e,c=1-f),g.zIndex=a.level+1,g.left=100*b+"%",g.right=100*c+"%",d&&a.forwardPressure&&(g[this.isRTL?"marginLeft":"marginRight"]=20),g},generateSegVerticalCss:function(a){return{top:a.top,bottom:-a.bottom}},groupSegCols:function(a){var b,c=[];for(b=0;b<this.colCnt;b++)c.push([]);for(b=0;b<a.length;b++)c[a[b].col].push(a[b]);return c},sortForwardSlotSegs:function(a){a.sort(ca(this,"compareForwardSlotSegs"))},compareForwardSlotSegs:function(a,b){return b.forwardPressure-a.forwardPressure||(a.backwardCoord||0)-(b.backwardCoord||0)||this.compareSegs(a,b)}});var mb=Ma.View=ra.extend({type:null,name:null,title:null,calendar:null,options:null,coordMap:null,el:null,displaying:null,isSkeletonRendered:!1,isEventsRendered:!1,start:null,end:null,intervalStart:null,intervalEnd:null,intervalDuration:null,intervalUnit:null,isRTL:!1,isSelected:!1,eventOrderSpecs:null,scrollerEl:null,scrollTop:null,widgetHeaderClass:null,widgetContentClass:null,highlightStateClass:null,nextDayThreshold:null,isHiddenDayHash:null,documentMousedownProxy:null,constructor:function(a,c,d,e){this.calendar=a,this.type=this.name=c,this.options=d,this.intervalDuration=e||b.duration(1,"day"),this.nextDayThreshold=b.duration(this.opt("nextDayThreshold")),this.initThemingProps(),this.initHiddenDays(),this.isRTL=this.opt("isRTL"),this.eventOrderSpecs=A(this.opt("eventOrder")),this.documentMousedownProxy=ca(this,"documentMousedown"),this.initialize()},initialize:function(){},opt:function(a){return this.options[a]},trigger:function(a,b){var c=this.calendar;return c.trigger.apply(c,[a,b||this].concat(Array.prototype.slice.call(arguments,2),[this]))},setDate:function(a){this.setRange(this.computeRange(a))},setRange:function(b){a.extend(this,b),this.updateTitle()},computeRange:function(a){var b,c,d=I(this.intervalDuration),e=a.clone().startOf(d),f=e.clone().add(this.intervalDuration);return/year|month|week|day/.test(d)?(e.stripTime(),f.stripTime()):(e.hasTime()||(e=this.calendar.rezoneDate(e)),f.hasTime()||(f=this.calendar.rezoneDate(f))),b=e.clone(),b=this.skipHiddenDays(b),c=f.clone(),c=this.skipHiddenDays(c,-1,!0),{intervalUnit:d,intervalStart:e,intervalEnd:f,start:b,end:c}},computePrevDate:function(a){return this.massageCurrentDate(a.clone().startOf(this.intervalUnit).subtract(this.intervalDuration),-1)},computeNextDate:function(a){return this.massageCurrentDate(a.clone().startOf(this.intervalUnit).add(this.intervalDuration))},massageCurrentDate:function(a,b){return this.intervalDuration.as("days")<=1&&this.isHiddenDay(a)&&(a=this.skipHiddenDays(a,b),a.startOf("day")),a},updateTitle:function(){this.title=this.computeTitle()},computeTitle:function(){return this.formatRange({start:this.intervalStart,end:this.intervalEnd},this.opt("titleFormat")||this.computeTitleFormat(),this.opt("titleRangeSeparator"))},computeTitleFormat:function(){return"year"==this.intervalUnit?"YYYY":"month"==this.intervalUnit?this.opt("monthYearFormat"):this.intervalDuration.as("days")>1?"ll":"LL"},formatRange:function(a,b,c){var d=a.end;return d.hasTime()||(d=d.clone().subtract(1)),ma(a.start,d,b,c,this.opt("isRTL"))},setElement:function(a){this.el=a,this.bindGlobalHandlers()},removeElement:function(){this.clear(),this.isSkeletonRendered&&(this.unrenderSkeleton(),this.isSkeletonRendered=!1),this.unbindGlobalHandlers(),this.el.remove()},display:function(b){var c=this,d=null;return this.displaying&&(d=this.queryScroll()),this.clear().then(function(){return c.displaying=a.when(c.displayView(b)).then(function(){c.forceScroll(c.computeInitialScroll(d)),c.triggerRender()})})},clear:function(){var b=this,c=this.displaying;return c?c.then(function(){return b.displaying=null,b.clearEvents(),b.clearView()}):a.when()},displayView:function(a){this.isSkeletonRendered||(this.renderSkeleton(),this.isSkeletonRendered=!0),this.setDate(a),this.render&&this.render(),this.renderDates(),this.updateSize(),this.renderBusinessHours()},clearView:function(){this.unselect(),this.triggerUnrender(),this.unrenderBusinessHours(),this.unrenderDates(),this.destroy&&this.destroy()},renderSkeleton:function(){},unrenderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},renderBusinessHours:function(){},unrenderBusinessHours:function(){},triggerRender:function(){this.trigger("viewRender",this,this,this.el)},triggerUnrender:function(){this.trigger("viewDestroy",this,this,this.el)},bindGlobalHandlers:function(){a(document).on("mousedown",this.documentMousedownProxy)},unbindGlobalHandlers:function(){a(document).off("mousedown",this.documentMousedownProxy)},initThemingProps:function(){var a=this.opt("theme")?"ui":"fc";this.widgetHeaderClass=a+"-widget-header",this.widgetContentClass=a+"-widget-content",this.highlightStateClass=a+"-state-highlight"},updateSize:function(a){var b;a&&(b=this.queryScroll()),this.updateHeight(a),this.updateWidth(a),a&&this.setScroll(b)},updateWidth:function(a){},updateHeight:function(a){var b=this.calendar;this.setHeight(b.getSuggestedViewHeight(),b.isHeightAuto())},setHeight:function(a,b){},computeScrollerHeight:function(a){var b,c,d=this.scrollerEl;return b=this.el.add(d),b.css({position:"relative",left:-1}),c=this.el.outerHeight()-d.height(),b.css({position:"",left:""}),a-c},computeInitialScroll:function(a){return 0},queryScroll:function(){return this.scrollerEl?this.scrollerEl.scrollTop():void 0},setScroll:function(a){return this.scrollerEl?this.scrollerEl.scrollTop(a):void 0},forceScroll:function(a){var b=this;this.setScroll(a),setTimeout(function(){b.setScroll(a)},0)},displayEvents:function(a){var b=this.queryScroll();this.clearEvents(),this.renderEvents(a),this.isEventsRendered=!0,this.setScroll(b),this.triggerEventRender()},clearEvents:function(){this.isEventsRendered&&(this.triggerEventUnrender(),this.destroyEvents&&this.destroyEvents(),this.unrenderEvents(),this.isEventsRendered=!1)},renderEvents:function(a){},unrenderEvents:function(){},triggerEventRender:function(){this.renderedEventSegEach(function(a){this.trigger("eventAfterRender",a.event,a.event,a.el)}),this.trigger("eventAfterAllRender")},triggerEventUnrender:function(){this.renderedEventSegEach(function(a){this.trigger("eventDestroy",a.event,a.event,a.el)})},resolveEventEl:function(b,c){var d=this.trigger("eventRender",b,b,c);return d===!1?c=null:d&&d!==!0&&(c=a(d)),c},showEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","")},a)},hideEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","hidden")},a)},renderedEventSegEach:function(a,b){var c,d=this.getEventSegs();for(c=0;c<d.length;c++)b&&d[c].event._id!==b._id||d[c].el&&a.call(this,d[c])},getEventSegs:function(){return[]},isEventDraggable:function(a){var b=a.source||{};return X(a.startEditable,b.startEditable,this.opt("eventStartEditable"),a.editable,b.editable,this.opt("editable"))},reportEventDrop:function(a,b,c,d,e){var f=this.calendar,g=f.mutateEvent(a,b,c),h=function(){g.undo(),f.reportEventChange()};this.triggerEventDrop(a,g.dateDelta,h,d,e),f.reportEventChange()},triggerEventDrop:function(a,b,c,d,e){this.trigger("eventDrop",d[0],a,b,c,e,{})},reportExternalDrop:function(b,c,d,e,f){var g,h,i=b.eventProps;i&&(g=a.extend({},i,c),h=this.calendar.renderEvent(g,b.stick)[0]),this.triggerExternalDrop(h,c,d,e,f)},triggerExternalDrop:function(a,b,c,d,e){this.trigger("drop",c[0],b.start,d,e),a&&this.trigger("eventReceive",null,a)},renderDrag:function(a,b){},unrenderDrag:function(){},isEventResizableFromStart:function(a){return this.opt("eventResizableFromStart")&&this.isEventResizable(a)},isEventResizableFromEnd:function(a){return this.isEventResizable(a)},isEventResizable:function(a){var b=a.source||{};return X(a.durationEditable,b.durationEditable,this.opt("eventDurationEditable"),a.editable,b.editable,this.opt("editable"))},reportEventResize:function(a,b,c,d,e){var f=this.calendar,g=f.mutateEvent(a,b,c),h=function(){g.undo(),f.reportEventChange()};this.triggerEventResize(a,g.durationDelta,h,d,e),f.reportEventChange()},triggerEventResize:function(a,b,c,d,e){this.trigger("eventResize",d[0],a,b,c,e,{})},select:function(a,b){this.unselect(b),this.renderSelection(a),this.reportSelection(a,b)},renderSelection:function(a){},reportSelection:function(a,b){this.isSelected=!0,this.triggerSelect(a,b)},triggerSelect:function(a,b){this.trigger("select",null,a.start,a.end,b)},unselect:function(a){this.isSelected&&(this.isSelected=!1,this.destroySelection&&this.destroySelection(),this.unrenderSelection(),this.trigger("unselect",null,a))},unrenderSelection:function(){},documentMousedown:function(b){var c;this.isSelected&&this.opt("unselectAuto")&&v(b)&&(c=this.opt("unselectCancel"),c&&a(b.target).closest(c).length||this.unselect(b))},triggerDayClick:function(a,b,c){this.trigger("dayClick",b,a.start,c)},initHiddenDays:function(){var b,c=this.opt("hiddenDays")||[],d=[],e=0;for(this.opt("weekends")===!1&&c.push(0,6),b=0;7>b;b++)(d[b]=-1!==a.inArray(b,c))||e++;if(!e)throw"invalid hiddenDays";this.isHiddenDayHash=d},isHiddenDay:function(a){return b.isMoment(a)&&(a=a.day()),this.isHiddenDayHash[a]},skipHiddenDays:function(a,b,c){var d=a.clone();for(b=b||1;this.isHiddenDayHash[(d.day()+(c?b:0)+7)%7];)d.add(b,"days");return d},computeDayRange:function(a){var b,c=a.start.clone().stripTime(),d=a.end,e=null;return d&&(e=d.clone().stripTime(),b=+d.time(),b&&b>=this.nextDayThreshold&&e.add(1,"days")),(!d||c>=e)&&(e=c.clone().add(1,"days")),{start:c,end:e}},isMultiDayEvent:function(a){var b=this.computeDayRange(a);return b.end.diff(b.start,"days")>1}}),nb=Ma.Calendar=ra.extend({dirDefaults:null,langDefaults:null,overrides:null,options:null,viewSpecCache:null,view:null,header:null,loadingLevel:0,constructor:Ga,initialize:function(){},initOptions:function(a){var b,e,f,g;a=d(a),b=a.lang,e=ob[b],e||(b=nb.defaults.lang,e=ob[b]||{}),f=X(a.isRTL,e.isRTL,nb.defaults.isRTL),g=f?nb.rtlDefaults:{},this.dirDefaults=g,this.langDefaults=e,this.overrides=a,this.options=c([nb.defaults,g,e,a]),Ha(this.options),this.viewSpecCache={}},getViewSpec:function(a){var b=this.viewSpecCache;return b[a]||(b[a]=this.buildViewSpec(a))},getUnitViewSpec:function(b){var c,d,e;if(-1!=a.inArray(b,Ra))for(c=this.header.getViewsWithButtons(),a.each(Ma.views,function(a){c.push(a)}),d=0;d<c.length;d++)if(e=this.getViewSpec(c[d]),e&&e.singleUnit==b)return e},buildViewSpec:function(a){for(var d,e,f,g,h=this.overrides.views||{},i=[],j=[],k=[],l=a;l;)d=Na[l],e=h[l],l=null,"function"==typeof d&&(d={"class":d}),d&&(i.unshift(d),j.unshift(d.defaults||{}),f=f||d.duration,l=l||d.type),e&&(k.unshift(e),f=f||e.duration,l=l||e.type);return d=Q(i),d.type=a,d["class"]?(f&&(f=b.duration(f),f.valueOf()&&(d.duration=f,g=I(f),1===f.as(g)&&(d.singleUnit=g,k.unshift(h[g]||{})))),d.defaults=c(j),d.overrides=c(k),this.buildViewSpecOptions(d),this.buildViewSpecButtonText(d,a),d):!1},buildViewSpecOptions:function(a){a.options=c([nb.defaults,a.defaults,this.dirDefaults,this.langDefaults,this.overrides,a.overrides]),Ha(a.options)},buildViewSpecButtonText:function(a,b){function c(c){var d=c.buttonText||{};return d[b]||(a.singleUnit?d[a.singleUnit]:null)}a.buttonTextOverride=c(this.overrides)||a.overrides.buttonText,a.buttonTextDefault=c(this.langDefaults)||c(this.dirDefaults)||a.defaults.buttonText||c(nb.defaults)||(a.duration?this.humanizeDuration(a.duration):null)||b},instantiateView:function(a){var b=this.getViewSpec(a);return new b["class"](this,a,b.options,b.duration)},isValidViewType:function(a){return Boolean(this.getViewSpec(a))},pushLoading:function(){this.loadingLevel++||this.trigger("loading",null,!0,this.view)},popLoading:function(){--this.loadingLevel||this.trigger("loading",null,!1,this.view)},buildSelectRange:function(a,b){return a=this.moment(a),b=b?this.moment(b):a.hasTime()?a.clone().add(this.defaultTimedEventDuration):a.clone().add(this.defaultAllDayEventDuration),{start:a,end:b}}});nb.mixin(bb),nb.defaults={titleRangeSeparator:" — ",monthYearFormat:"MMMM YYYY",defaultTimedEventDuration:"02:00:00",defaultAllDayEventDuration:{days:1},forceEventDuration:!1,nextDayThreshold:"09:00:00",defaultView:"month",aspectRatio:1.35,header:{left:"title",center:"",right:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberTitle:"W",weekNumberCalculation:"local",scrollTime:"06:00:00",lazyFetching:!0,startParam:"start",endParam:"end",timezoneParam:"timezone",timezone:!1,isRTL:!1,buttonText:{prev:"prev",next:"next",prevYear:"prev year",nextYear:"next year",year:"year",today:"today",month:"month",week:"week",day:"day"},buttonIcons:{prev:"left-single-arrow",next:"right-single-arrow",prevYear:"left-double-arrow",nextYear:"right-double-arrow"},theme:!1,themeButtonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e",prevYear:"seek-prev",nextYear:"seek-next"},dragOpacity:.75,dragRevertDuration:500,dragScroll:!0,unselectAuto:!0,dropAccept:"*",eventOrder:"title",eventLimit:!1,eventLimitText:"more",eventLimitClick:"popover",dayPopoverFormat:"LL",handleWindowResize:!0,windowResizeDelay:200},nb.englishDefaults={dayPopoverFormat:"dddd, MMMM D"},nb.rtlDefaults={header:{left:"next,prev today",center:"",right:"title"},buttonIcons:{prev:"right-single-arrow",next:"left-single-arrow",prevYear:"right-double-arrow",nextYear:"left-double-arrow"},themeButtonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w",nextYear:"seek-prev",prevYear:"seek-next"}};var ob=Ma.langs={};Ma.datepickerLang=function(b,c,d){var e=ob[b]||(ob[b]={});e.isRTL=d.isRTL,e.weekNumberTitle=d.weekHeader,a.each(pb,function(a,b){e[a]=b(d)}),a.datepicker&&(a.datepicker.regional[c]=a.datepicker.regional[b]=d,a.datepicker.regional.en=a.datepicker.regional[""],a.datepicker.setDefaults(d))},Ma.lang=function(b,d){var e,f;e=ob[b]||(ob[b]={}),d&&(e=ob[b]=c([e,d])),f=Ia(b),a.each(qb,function(a,b){null==e[a]&&(e[a]=b(f,e))}),nb.defaults.lang=b};var pb={buttonText:function(a){return{prev:Z(a.prevText),next:Z(a.nextText),today:Z(a.currentText)}},monthYearFormat:function(a){return a.showMonthAfterYear?"YYYY["+a.yearSuffix+"] MMMM":"MMMM YYYY["+a.yearSuffix+"]"}},qb={dayOfMonthFormat:function(a,b){var c=a.longDateFormat("l");return c=c.replace(/^Y+[^\w\s]*|[^\w\s]*Y+$/g,""),b.isRTL?c+=" ddd":c="ddd "+c,c},mediumTimeFormat:function(a){return a.longDateFormat("LT").replace(/\s*a$/i,"a")},smallTimeFormat:function(a){return a.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"a")},extraSmallTimeFormat:function(a){return a.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"t")},hourFormat:function(a){return a.longDateFormat("LT").replace(":mm","").replace(/(\Wmm)$/,"").replace(/\s*a$/i,"a")},noMeridiemTimeFormat:function(a){return a.longDateFormat("LT").replace(/\s*a$/i,"")}},rb={smallDayDateFormat:function(a){return a.isRTL?"D dd":"dd D"},weekFormat:function(a){return a.isRTL?"w[ "+a.weekNumberTitle+"]":"["+a.weekNumberTitle+" ]w"},smallWeekFormat:function(a){return a.isRTL?"w["+a.weekNumberTitle+"]":"["+a.weekNumberTitle+"]w"}};Ma.lang("en",nb.englishDefaults),Ma.sourceNormalizers=[],Ma.sourceFetchers=[];var sb={dataType:"json",cache:!1},tb=1;nb.prototype.getPeerEvents=function(a,b){var c,d,e=this.getEventCache(),f=[];for(c=0;c<e.length;c++)d=e[c],a&&a._id===d._id||f.push(d);return f};var ub=mb.extend({dayGrid:null,dayNumbersVisible:!1,weekNumbersVisible:!1,weekNumberWidth:null,headRowEl:null,initialize:function(){this.dayGrid=new kb(this),this.coordMap=this.dayGrid.coordMap},setRange:function(a){mb.prototype.setRange.call(this,a),this.dayGrid.breakOnWeeks=/year|month|week/.test(this.intervalUnit),this.dayGrid.setRange(a)},computeRange:function(a){var b=mb.prototype.computeRange.call(this,a);return/year|month/.test(b.intervalUnit)&&(b.start.startOf("week"),b.start=this.skipHiddenDays(b.start),b.end.weekday()&&(b.end.add(1,"week").startOf("week"),b.end=this.skipHiddenDays(b.end,-1,!0))),b},renderDates:function(){this.dayNumbersVisible=this.dayGrid.rowCnt>1,this.weekNumbersVisible=this.opt("weekNumbers"),this.dayGrid.numbersVisible=this.dayNumbersVisible||this.weekNumbersVisible,this.el.addClass("fc-basic-view").html(this.renderHtml()),this.headRowEl=this.el.find("thead .fc-row"),this.scrollerEl=this.el.find(".fc-day-grid-container"),this.dayGrid.coordMap.containerEl=this.scrollerEl,this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(this.hasRigidRows())},unrenderDates:function(){this.dayGrid.unrenderDates(),this.dayGrid.removeElement()},renderBusinessHours:function(){this.dayGrid.renderBusinessHours()},renderHtml:function(){return'<table><thead class="fc-head"><tr><td class="'+this.widgetHeaderClass+'">'+this.dayGrid.headHtml()+'</td></tr></thead><tbody class="fc-body"><tr><td class="'+this.widgetContentClass+'"><div class="fc-day-grid-container"><div class="fc-day-grid"/></div></td></tr></tbody></table>'},headIntroHtml:function(){return this.weekNumbersVisible?'<th class="fc-week-number '+this.widgetHeaderClass+'" '+this.weekNumberStyleAttr()+"><span>"+Y(this.opt("weekNumberTitle"))+"</span></th>":void 0},numberIntroHtml:function(a){return this.weekNumbersVisible?'<td class="fc-week-number" '+this.weekNumberStyleAttr()+"><span>"+this.dayGrid.getCell(a,0).start.format("w")+"</span></td>":void 0},dayIntroHtml:function(){return this.weekNumbersVisible?'<td class="fc-week-number '+this.widgetContentClass+'" '+this.weekNumberStyleAttr()+"></td>":void 0},introHtml:function(){return this.weekNumbersVisible?'<td class="fc-week-number" '+this.weekNumberStyleAttr()+"></td>":void 0},numberCellHtml:function(a){var b,c=a.start;return this.dayNumbersVisible?(b=this.dayGrid.getDayClasses(c),b.unshift("fc-day-number"),'<td class="'+b.join(" ")+'" data-date="'+c.format()+'">'+c.date()+"</td>"):"<td/>"},weekNumberStyleAttr:function(){return null!==this.weekNumberWidth?'style="width:'+this.weekNumberWidth+'px"':""},hasRigidRows:function(){var a=this.opt("eventLimit");return a&&"number"!=typeof a},updateWidth:function(){this.weekNumbersVisible&&(this.weekNumberWidth=k(this.el.find(".fc-week-number")))},setHeight:function(a,b){var c,d=this.opt("eventLimit");m(this.scrollerEl),f(this.headRowEl),this.dayGrid.removeSegPopover(),d&&"number"==typeof d&&this.dayGrid.limitRows(d),c=this.computeScrollerHeight(a),this.setGridHeight(c,b),d&&"number"!=typeof d&&this.dayGrid.limitRows(d),!b&&l(this.scrollerEl,c)&&(e(this.headRowEl,r(this.scrollerEl)),c=this.computeScrollerHeight(a),this.scrollerEl.height(c))},setGridHeight:function(a,b){b?j(this.dayGrid.rowEls):i(this.dayGrid.rowEls,a,!0)},renderEvents:function(a){this.dayGrid.renderEvents(a),this.updateHeight()},getEventSegs:function(){return this.dayGrid.getEventSegs()},unrenderEvents:function(){this.dayGrid.unrenderEvents()},renderDrag:function(a,b){return this.dayGrid.renderDrag(a,b)},unrenderDrag:function(){this.dayGrid.unrenderDrag()},renderSelection:function(a){this.dayGrid.renderSelection(a)},unrenderSelection:function(){this.dayGrid.unrenderSelection()}}),vb=ub.extend({computeRange:function(a){var b,c=ub.prototype.computeRange.call(this,a);return this.isFixedWeeks()&&(b=Math.ceil(c.end.diff(c.start,"weeks",!0)),c.end.add(6-b,"weeks")),c},setGridHeight:function(a,b){b=b||"variable"===this.opt("weekMode"),b&&(a*=this.rowCnt/6),i(this.dayGrid.rowEls,a,!b)},isFixedWeeks:function(){var a=this.opt("weekMode");return a?"fixed"===a:this.opt("fixedWeekCount")}});Na.basic={"class":ub},Na.basicDay={type:"basic",duration:{days:1}},Na.basicWeek={type:"basic",duration:{weeks:1}},Na.month={"class":vb,duration:{months:1},defaults:{fixedWeekCount:!0}};var wb=mb.extend({timeGrid:null,dayGrid:null,axisWidth:null,noScrollRowEls:null,bottomRuleEl:null,bottomRuleHeight:null,initialize:function(){this.timeGrid=new lb(this),this.opt("allDaySlot")?(this.dayGrid=new kb(this),this.coordMap=new eb([this.dayGrid.coordMap,this.timeGrid.coordMap])):this.coordMap=this.timeGrid.coordMap},setRange:function(a){mb.prototype.setRange.call(this,a),this.timeGrid.setRange(a),this.dayGrid&&this.dayGrid.setRange(a)},renderDates:function(){this.el.addClass("fc-agenda-view").html(this.renderHtml()),this.scrollerEl=this.el.find(".fc-time-grid-container"),this.timeGrid.coordMap.containerEl=this.scrollerEl,this.timeGrid.setElement(this.el.find(".fc-time-grid")),this.timeGrid.renderDates(),this.bottomRuleEl=a('<hr class="fc-divider '+this.widgetHeaderClass+'"/>').appendTo(this.timeGrid.el),this.dayGrid&&(this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(),this.dayGrid.bottomCoordPadding=this.dayGrid.el.next("hr").outerHeight()),this.noScrollRowEls=this.el.find(".fc-row:not(.fc-scroller *)")},unrenderDates:function(){this.timeGrid.unrenderDates(),this.timeGrid.removeElement(),this.dayGrid&&(this.dayGrid.unrenderDates(),this.dayGrid.removeElement())},renderBusinessHours:function(){this.timeGrid.renderBusinessHours(),this.dayGrid&&this.dayGrid.renderBusinessHours()},renderHtml:function(){return'<table><thead class="fc-head"><tr><td class="'+this.widgetHeaderClass+'">'+this.timeGrid.headHtml()+'</td></tr></thead><tbody class="fc-body"><tr><td class="'+this.widgetContentClass+'">'+(this.dayGrid?'<div class="fc-day-grid"/><hr class="fc-divider '+this.widgetHeaderClass+'"/>':"")+'<div class="fc-time-grid-container"><div class="fc-time-grid"/></div></td></tr></tbody></table>'},headIntroHtml:function(){var a,b;return this.opt("weekNumbers")?(a=this.timeGrid.getCell(0).start,b=a.format(this.opt("smallWeekFormat")),'<th class="fc-axis fc-week-number '+this.widgetHeaderClass+'" '+this.axisStyleAttr()+"><span>"+Y(b)+"</span></th>"):'<th class="fc-axis '+this.widgetHeaderClass+'" '+this.axisStyleAttr()+"></th>"},dayIntroHtml:function(){return'<td class="fc-axis '+this.widgetContentClass+'" '+this.axisStyleAttr()+"><span>"+(this.opt("allDayHtml")||Y(this.opt("allDayText")))+"</span></td>"},slotBgIntroHtml:function(){return'<td class="fc-axis '+this.widgetContentClass+'" '+this.axisStyleAttr()+"></td>";
9
  },introHtml:function(){return'<td class="fc-axis" '+this.axisStyleAttr()+"></td>"},axisStyleAttr:function(){return null!==this.axisWidth?'style="width:'+this.axisWidth+'px"':""},updateSize:function(a){this.timeGrid.updateSize(a),mb.prototype.updateSize.call(this,a)},updateWidth:function(){this.axisWidth=k(this.el.find(".fc-axis"))},setHeight:function(a,b){var c,d;null===this.bottomRuleHeight&&(this.bottomRuleHeight=this.bottomRuleEl.outerHeight()),this.bottomRuleEl.hide(),this.scrollerEl.css("overflow",""),m(this.scrollerEl),f(this.noScrollRowEls),this.dayGrid&&(this.dayGrid.removeSegPopover(),c=this.opt("eventLimit"),c&&"number"!=typeof c&&(c=xb),c&&this.dayGrid.limitRows(c)),b||(d=this.computeScrollerHeight(a),l(this.scrollerEl,d)?(e(this.noScrollRowEls,r(this.scrollerEl)),d=this.computeScrollerHeight(a),this.scrollerEl.height(d)):(this.scrollerEl.height(d).css("overflow","hidden"),this.bottomRuleEl.show()))},computeInitialScroll:function(){var a=b.duration(this.opt("scrollTime")),c=this.timeGrid.computeTimeTop(a);return c=Math.ceil(c),c&&c++,c},renderEvents:function(a){var b,c,d=[],e=[],f=[];for(c=0;c<a.length;c++)a[c].allDay?d.push(a[c]):e.push(a[c]);b=this.timeGrid.renderEvents(e),this.dayGrid&&(f=this.dayGrid.renderEvents(d)),this.updateHeight()},getEventSegs:function(){return this.timeGrid.getEventSegs().concat(this.dayGrid?this.dayGrid.getEventSegs():[])},unrenderEvents:function(){this.timeGrid.unrenderEvents(),this.dayGrid&&this.dayGrid.unrenderEvents()},renderDrag:function(a,b){return a.start.hasTime()?this.timeGrid.renderDrag(a,b):this.dayGrid?this.dayGrid.renderDrag(a,b):void 0},unrenderDrag:function(){this.timeGrid.unrenderDrag(),this.dayGrid&&this.dayGrid.unrenderDrag()},renderSelection:function(a){a.start.hasTime()||a.end.hasTime()?this.timeGrid.renderSelection(a):this.dayGrid&&this.dayGrid.renderSelection(a)},unrenderSelection:function(){this.timeGrid.unrenderSelection(),this.dayGrid&&this.dayGrid.unrenderSelection()}}),xb=5,yb=[{hours:1},{minutes:30},{minutes:15},{seconds:30},{seconds:15}];return Na.agenda={"class":wb,defaults:{allDaySlot:!0,allDayText:"all-day",slotDuration:"00:30:00",minTime:"00:00:00",maxTime:"24:00:00",slotEventOverlap:!0}},Na.agendaDay={type:"agenda",duration:{days:1}},Na.agendaWeek={type:"agenda",duration:{weeks:1}},Ma});
1
  /*!
2
+ * FullCalendar v2.4.0 (patched in BP-2145)
3
  * Docs & License: http://fullcalendar.io/
4
  * (c) 2015 Adam Shaw
5
  */
6
+ !function(a){"function"==typeof define&&define.amd?define(["jquery","moment"],a):"object"==typeof exports?module.exports=a(require("jquery"),require("moment")):a(jQuery,moment)}(function(a,b){function c(a){return Q(a,Oa)}function d(b){var c,d={views:b.views||{}};return a.each(b,function(b,e){"views"!=b&&(a.isPlainObject(e)&&!/(time|duration|interval)$/i.test(b)&&-1==a.inArray(b,Oa)?(c=null,a.each(e,function(a,e){/^(month|week|day|default|basic(Week|Day)?|agenda(Week|Day)?)$/.test(a)?(d.views[a]||(d.views[a]={}),d.views[a][b]=e):(c||(c={}),c[a]=e)}),c&&(d[b]=c)):d[b]=e)}),d}function e(a,b){b.left&&a.css({"border-left-width":1,"margin-left":b.left-1}),b.right&&a.css({"border-right-width":1,"margin-right":b.right-1})}function f(a){a.css({"margin-left":"","margin-right":"","border-left-width":"","border-right-width":""})}function g(){a("body").addClass("fc-not-allowed")}function h(){a("body").removeClass("fc-not-allowed")}function i(b,c,d){var e=Math.floor(c/b.length),f=Math.floor(c-e*(b.length-1)),g=[],h=[],i=[],k=0;j(b),b.each(function(c,d){var j=c===b.length-1?f:e,l=a(d).outerHeight(!0);j>l?(g.push(d),h.push(l),i.push(a(d).height())):k+=l}),d&&(c-=k,e=Math.floor(c/g.length),f=Math.floor(c-e*(g.length-1))),a(g).each(function(b,c){var d=b===g.length-1?f:e,j=h[b],k=i[b],l=d-(j-k);d>j&&a(c).height(l)})}function j(a){a.height("")}function k(b){var c=0;return b.find("> *").each(function(b,d){var e=a(d).outerWidth();e>c&&(c=e)}),c++,b.width(c),c}function l(a,b){return a.height(b).addClass("fc-scroller"),a[0].scrollHeight-1>a[0].clientHeight?!0:(m(a),!1)}function m(a){a.height("").removeClass("fc-scroller")}function n(b){var c=b.css("position"),d=b.parents().filter(function(){var b=a(this);return/(auto|scroll)/.test(b.css("overflow")+b.css("overflow-y")+b.css("overflow-x"))}).eq(0);return"fixed"!==c&&d.length?d:a(b[0].ownerDocument||document)}function o(a){var b=a.offset();return{left:b.left,right:b.left+a.outerWidth(),top:b.top,bottom:b.top+a.outerHeight()}}function p(a){var b=a.offset(),c=r(a),d=b.left+u(a,"border-left-width")+c.left,e=b.top+u(a,"border-top-width")+c.top;return{left:d,right:d+a[0].clientWidth,top:e,bottom:e+a[0].clientHeight}}function q(a){var b=a.offset(),c=b.left+u(a,"border-left-width")+u(a,"padding-left"),d=b.top+u(a,"border-top-width")+u(a,"padding-top");return{left:c,right:c+a.width(),top:d,bottom:d+a.height()}}function r(a){var b=a.innerWidth()-a[0].clientWidth,c={left:0,right:0,top:0,bottom:a.innerHeight()-a[0].clientHeight};return s()&&"rtl"==a.css("direction")?c.left=b:c.right=b,c}function s(){return null===Pa&&(Pa=t()),Pa}function t(){var b=a("<div><div/></div>").css({position:"absolute",top:-1e3,left:0,border:0,padding:0,overflow:"scroll",direction:"rtl"}).appendTo("body"),c=b.children(),d=c.offset().left>b.offset().left;return b.remove(),d}function u(a,b){return parseFloat(a.css(b))||0}function v(a){return 1==a.which&&!a.ctrlKey}function w(a,b){var c={left:Math.max(a.left,b.left),right:Math.min(a.right,b.right),top:Math.max(a.top,b.top),bottom:Math.min(a.bottom,b.bottom)};return c.left<c.right&&c.top<c.bottom?c:!1}function x(a,b){return{left:Math.min(Math.max(a.left,b.left),b.right),top:Math.min(Math.max(a.top,b.top),b.bottom)}}function y(a){return{left:(a.left+a.right)/2,top:(a.top+a.bottom)/2}}function z(a,b){return{left:a.left-b.left,top:a.top-b.top}}function A(b){var c,d,e=[],f=[];for("string"==typeof b?f=b.split(/\s*,\s*/):"function"==typeof b?f=[b]:a.isArray(b)&&(f=b),c=0;c<f.length;c++)d=f[c],"string"==typeof d?e.push("-"==d.charAt(0)?{field:d.substring(1),order:-1}:{field:d,order:1}):"function"==typeof d&&e.push({func:d});return e}function B(a,b,c){var d,e;for(d=0;d<c.length;d++)if(e=C(a,b,c[d]))return e;return 0}function C(a,b,c){return c.func?c.func(a,b):D(a[c.field],b[c.field])*(c.order||1)}function D(b,c){return b||c?null==c?-1:null==b?1:"string"===a.type(b)||"string"===a.type(c)?String(b).localeCompare(String(c)):b-c:0}function E(a,b){var c,d,e,f,g=a.start,h=a.end,i=b.start,j=b.end;return h>i&&j>g?(g>=i?(c=g.clone(),e=!0):(c=i.clone(),e=!1),j>=h?(d=h.clone(),f=!0):(d=j.clone(),f=!1),{start:c,end:d,isStart:e,isEnd:f}):void 0}function F(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days"),ms:a.time()-c.time()})}function G(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days")})}function H(a,c,d){return b.duration(Math.round(a.diff(c,d,!0)),d)}function I(a,b){var c,d,e;for(c=0;c<Ra.length&&(d=Ra[c],e=J(d,a,b),!(e>=1&&ba(e)));c++);return d}function J(a,c,d){return null!=d?d.diff(c,a,!0):b.isDuration(c)?c.as(a):c.end.diff(c.start,a,!0)}function K(a,b,c){var d;return N(c)?(b-a)/c:(d=c.asMonths(),Math.abs(d)>=1&&ba(d)?b.diff(a,"months",!0)/d:b.diff(a,"days",!0)/c.asDays())}function L(a,b){var c,d;return N(a)||N(b)?a/b:(c=a.asMonths(),d=b.asMonths(),Math.abs(c)>=1&&ba(c)&&Math.abs(d)>=1&&ba(d)?c/d:a.asDays()/b.asDays())}function M(a,c){var d;return N(a)?b.duration(a*c):(d=a.asMonths(),Math.abs(d)>=1&&ba(d)?b.duration({months:d*c}):b.duration({days:a.asDays()*c}))}function N(a){return Boolean(a.hours()||a.minutes()||a.seconds()||a.milliseconds())}function O(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function P(a){return/^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(a)}function Q(a,b){var c,d,e,f,g,h,i={};if(b)for(c=0;c<b.length;c++){for(d=b[c],e=[],f=a.length-1;f>=0;f--)if(g=a[f][d],"object"==typeof g)e.unshift(g);else if(void 0!==g){i[d]=g;break}e.length&&(i[d]=Q(e))}for(c=a.length-1;c>=0;c--){h=a[c];for(d in h)d in i||(i[d]=h[d])}return i}function R(a){var b=function(){};return b.prototype=a,new b}function S(a,b){for(var c in a)U(a,c)&&(b[c]=a[c])}function T(a,b){var c,d,e=["constructor","toString","valueOf"];for(c=0;c<e.length;c++)d=e[c],a[d]!==Object.prototype[d]&&(b[d]=a[d])}function U(a,b){return Va.call(a,b)}function V(b){return/undefined|null|boolean|number|string/.test(a.type(b))}function W(b,c,d){if(a.isFunction(b)&&(b=[b]),b){var e,f;for(e=0;e<b.length;e++)f=b[e].apply(c,d)||f;return f}}function X(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a]}function Y(a){return(a+"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/'/g,"&#039;").replace(/"/g,"&quot;").replace(/\n/g,"<br />")}function Z(a){return a.replace(/&.*?;/g,"")}function $(b){var c=[];return a.each(b,function(a,b){null!=b&&c.push(a+":"+b)}),c.join(";")}function _(a){return a.charAt(0).toUpperCase()+a.slice(1)}function aa(a,b){return a-b}function ba(a){return a%1===0}function ca(a,b){var c=a[b];return function(){return c.apply(a,arguments)}}function da(a,b){var c,d,e,f,g=function(){var h=+new Date-f;b>h&&h>0?c=setTimeout(g,b-h):(c=null,a.apply(e,d),c||(e=d=null))};return function(){e=this,d=arguments,f=+new Date,c||(c=setTimeout(g,b))}}function zz(b,c){if(!b||!b.then||b.state()==='resolved'){return a.when(c())}else if(c){return b.then(c)}}function ea(c,d,e){var f,g,h,i,j=c[0],k=1==c.length&&"string"==typeof j;return b.isMoment(j)?(i=b.apply(null,c),ga(j,i)):O(j)||void 0===j?i=b.apply(null,c):(f=!1,g=!1,k?Wa.test(j)?(j+="-01",c=[j],f=!0,g=!0):(h=Xa.exec(j))&&(f=!h[5],g=!0):a.isArray(j)&&(g=!0),i=d||f?b.utc.apply(b,c):b.apply(null,c),f?(i._ambigTime=!0,i._ambigZone=!0):e&&(g?i._ambigZone=!0:k&&(i.utcOffset?i.utcOffset(j):i.zone(j)))),i._fullCalendar=!0,i}function fa(a,c){var d,e,f=!1,g=!1,h=a.length,i=[];for(d=0;h>d;d++)e=a[d],b.isMoment(e)||(e=Ma.moment.parseZone(e)),f=f||e._ambigTime,g=g||e._ambigZone,i.push(e);for(d=0;h>d;d++)e=i[d],c||!f||e._ambigTime?g&&!e._ambigZone&&(i[d]=e.clone().stripZone()):i[d]=e.clone().stripTime();return i}function ga(a,b){a._ambigTime?b._ambigTime=!0:b._ambigTime&&(b._ambigTime=!1),a._ambigZone?b._ambigZone=!0:b._ambigZone&&(b._ambigZone=!1)}function ha(a,b){a.year(b[0]||0).month(b[1]||0).date(b[2]||0).hours(b[3]||0).minutes(b[4]||0).seconds(b[5]||0).milliseconds(b[6]||0)}function ia(a,b){return Za.format.call(a,b)}function ja(a,b){return ka(a,pa(b))}function ka(a,b){var c,d="";for(c=0;c<b.length;c++)d+=la(a,b[c]);return d}function la(a,b){var c,d;return"string"==typeof b?b:(c=b.token)?$a[c]?$a[c](a):ia(a,c):b.maybe&&(d=ka(a,b.maybe),d.match(/[1-9]/))?d:""}function ma(a,b,c,d,e){var f;return a=Ma.moment.parseZone(a),b=Ma.moment.parseZone(b),f=(a.localeData||a.lang).call(a),c=f.longDateFormat(c)||c,d=d||" - ",na(a,b,pa(c),d,e)}function na(a,b,c,d,e){var f,g,h,i,j="",k="",l="",m="",n="";for(g=0;g<c.length&&(f=oa(a,b,c[g]),f!==!1);g++)j+=f;for(h=c.length-1;h>g&&(f=oa(a,b,c[h]),f!==!1);h--)k=f+k;for(i=g;h>=i;i++)l+=la(a,c[i]),m+=la(b,c[i]);return(l||m)&&(n=e?m+d+l:l+d+m),j+n+k}function oa(a,b,c){var d,e;return"string"==typeof c?c:(d=c.token)&&(e=_a[d.charAt(0)],e&&a.isSame(b,e))?ia(a,d):!1}function pa(a){return a in ab?ab[a]:ab[a]=qa(a)}function qa(a){for(var b,c=[],d=/\[([^\]]*)\]|\(([^\)]*)\)|(LTS|LT|(\w)\4*o?)|([^\w\[\(]+)/g;b=d.exec(a);)b[1]?c.push(b[1]):b[2]?c.push({maybe:qa(b[2])}):b[3]?c.push({token:b[3]}):b[5]&&c.push(b[5]);return c}function ra(){}function sa(a,b){return a||b?a&&b?a.grid===b.grid&&a.row===b.row&&a.col===b.col:!1:!0}function ta(a){var b=va(a);return"background"===b||"inverse-background"===b}function ua(a){return"inverse-background"===va(a)}function va(a){return X((a.source||{}).rendering,a.rendering)}function wa(a){var b,c,d={};for(b=0;b<a.length;b++)c=a[b],(d[c._id]||(d[c._id]=[])).push(c);return d}function xa(a,b){return a.eventStartMS-b.eventStartMS}function ya(c){var d,e,f,g,h=Ma.dataAttrPrefix;return h&&(h+="-"),d=c.data(h+"event")||null,d&&(d="object"==typeof d?a.extend({},d):{},e=d.start,null==e&&(e=d.time),f=d.duration,g=d.stick,delete d.start,delete d.time,delete d.duration,delete d.stick),null==e&&(e=c.data(h+"start")),null==e&&(e=c.data(h+"time")),null==f&&(f=c.data(h+"duration")),null==g&&(g=c.data(h+"stick")),e=null!=e?b.duration(e):null,f=null!=f?b.duration(f):null,g=Boolean(g),{eventProps:d,startTime:e,duration:f,stick:g}}function za(a,b){var c,d;for(c=0;c<b.length;c++)if(d=b[c],d.leftCol<=a.rightCol&&d.rightCol>=a.leftCol)return!0;return!1}function Aa(a,b){return a.leftCol-b.leftCol}function Ba(a){var b,c,d,e=[];for(b=0;b<a.length;b++){for(c=a[b],d=0;d<e.length&&Ea(c,e[d]).length;d++);c.level=d,(e[d]||(e[d]=[])).push(c)}return e}function Ca(a){var b,c,d,e,f;for(b=0;b<a.length;b++)for(c=a[b],d=0;d<c.length;d++)for(e=c[d],e.forwardSegs=[],f=b+1;f<a.length;f++)Ea(e,a[f],e.forwardSegs)}function Da(a){var b,c,d=a.forwardSegs,e=0;if(void 0===a.forwardPressure){for(b=0;b<d.length;b++)c=d[b],Da(c),e=Math.max(e,1+c.forwardPressure);a.forwardPressure=e}}function Ea(a,b,c){c=c||[];for(var d=0;d<b.length;d++)Fa(a,b[d])&&c.push(b[d]);return c}function Fa(a,b){return a.bottom>b.top&&a.top<b.bottom}function Ga(c,d){function e(){U?h()&&(k(),i()):f()}function f(){V=O.theme?"ui":"fc",c.addClass("fc"),O.isRTL?c.addClass("fc-rtl"):c.addClass("fc-ltr"),O.theme?c.addClass("ui-widget"):c.addClass("fc-unthemed"),U=a("<div class='fc-view-container'/>").prependTo(c),S=N.header=new Ja(N,O),T=S.render(),T&&c.prepend(T),i(O.defaultView),O.handleWindowResize&&(Y=da(m,O.windowResizeDelay),a(window).resize(Y))}function g(){W&&W.removeElement(),S.removeElement(),U.remove(),c.removeClass("fc fc-ltr fc-rtl fc-unthemed ui-widget"),Y&&a(window).unbind("resize",Y)}function h(){return c.is(":visible")}function i(b){ca++,W&&b&&W.type!==b&&(S.deactivateButton(W.type),H(),W.removeElement(),W=N.view=null),!W&&b&&(W=N.view=ba[b]||(ba[b]=N.instantiateView(b)),W.setElement(a("<div class='fc-view fc-"+b+"-view' />").appendTo(U)),S.activateButton(b)),W&&(Z=W.massageCurrentDate(Z),W.displaying&&Z.isWithin(W.intervalStart,W.intervalEnd)||h()&&(H(),W.display(Z),I(),u(),v(),q())),I(),ca--}function j(a){return h()?(a&&l(),ca++,W.updateSize(!0),ca--,!0):void 0}function k(){h()&&l()}function l(){X="number"==typeof O.contentHeight?O.contentHeight:"number"==typeof O.height?O.height-(T?T.outerHeight(!0):0):Math.round(U.width()/Math.max(O.aspectRatio,.5))}function m(a){!ca&&a.target===window&&W.start&&j(!0)&&W.trigger("windowResize",aa)}function n(){p(),r()}function o(){h()&&(H(),W.displayEvents(ea),I())}function p(){H(),W.clearEvents(),I()}function q(){!O.lazyFetching||$(W.start,W.end)?r():o()}function r(){_(W.start,W.end)}function s(a){ea=a,o()}function t(){o()}function u(){S.updateTitle(W.title)}function v(){var a=N.getNow();a.isWithin(W.intervalStart,W.intervalEnd)?S.disableButton("today"):S.enableButton("today")}function w(a,b){W.select(N.buildSelectRange.apply(N,arguments))}function x(){W&&W.unselect()}function y(){Z=W.computePrevDate(Z),i()}function z(){Z=W.computeNextDate(Z),i()}function A(){Z.add(-1,"years"),i()}function B(){Z.add(1,"years"),i()}function C(){Z=N.getNow(),i()}function D(a){Z=N.moment(a),i()}function E(a){Z.add(b.duration(a)),i()}function F(a,b){var c;b=b||"day",c=N.getViewSpec(b)||N.getUnitViewSpec(b),Z=a,i(c?c.type:null)}function G(){return Z.clone()}function H(){U.css({width:"100%",height:U.height(),overflow:"hidden"})}function I(){U.css({width:"",height:"",overflow:""})}function J(){return N}function K(){return W}function L(a,b){return void 0===b?O[a]:void(("height"==a||"contentHeight"==a||"aspectRatio"==a)&&(O[a]=b,j(!0)))}function M(a,b){var c=Array.prototype.slice.call(arguments,2);return b=b||aa,this.triggerWith(a,b,c),O[a]?O[a].apply(b,c):void 0}var N=this;N.initOptions(d||{});var O=this.options;N.render=e,N.destroy=g,N.refetchEvents=n,N.reportEvents=s,N.reportEventChange=t,N.rerenderEvents=o,N.changeView=i,N.select=w,N.unselect=x,N.prev=y,N.next=z,N.prevYear=A,N.nextYear=B,N.today=C,N.gotoDate=D,N.incrementDate=E,N.zoomTo=F,N.getDate=G,N.getCalendar=J,N.getView=K,N.option=L,N.trigger=M;var P=R(Ia(O.lang));if(O.monthNames&&(P._months=O.monthNames),O.monthNamesShort&&(P._monthsShort=O.monthNamesShort),O.dayNames&&(P._weekdays=O.dayNames),O.dayNamesShort&&(P._weekdaysShort=O.dayNamesShort),null!=O.firstDay){var Q=R(P._week);Q.dow=O.firstDay,P._week=Q}P._fullCalendar_weekCalc=function(a){return"function"==typeof a?a:"local"===a?a:"iso"===a||"ISO"===a?"ISO":void 0}(O.weekNumberCalculation),N.defaultAllDayEventDuration=b.duration(O.defaultAllDayEventDuration),N.defaultTimedEventDuration=b.duration(O.defaultTimedEventDuration),N.moment=function(){var a;return"local"===O.timezone?(a=Ma.moment.apply(null,arguments),a.hasTime()&&a.local()):a="UTC"===O.timezone?Ma.moment.utc.apply(null,arguments):Ma.moment.parseZone.apply(null,arguments),"_locale"in a?a._locale=P:a._lang=P,a},N.getIsAmbigTimezone=function(){return"local"!==O.timezone&&"UTC"!==O.timezone},N.rezoneDate=function(a){return N.moment(a.toArray())},N.getNow=function(){var a=O.now;return"function"==typeof a&&(a=a()),N.moment(a)},N.getEventEnd=function(a){return a.end?a.end.clone():N.getDefaultEventEnd(a.allDay,a.start)},N.getDefaultEventEnd=function(a,b){var c=b.clone();return a?c.stripTime().add(N.defaultAllDayEventDuration):c.add(N.defaultTimedEventDuration),N.getIsAmbigTimezone()&&c.stripZone(),c},N.humanizeDuration=function(a){return(a.locale||a.lang).call(a,O.lang).humanize()},Ka.call(N,O);var S,T,U,V,W,X,Y,Z,$=N.isFetchNeeded,_=N.fetchEvents,aa=c[0],ba={},ca=0,ea=[];Z=null!=O.defaultDate?N.moment(O.defaultDate):N.getNow(),N.getSuggestedViewHeight=function(){return void 0===X&&k(),X},N.isHeightAuto=function(){return"auto"===O.contentHeight||"auto"===O.height},N.initialize()}function Ha(b){a.each(rb,function(a,c){null==b[a]&&(b[a]=c(b))})}function Ia(a){var c=b.localeData||b.langData;return c.call(b,a)||c.call(b,"en")}function Ja(b,c){function d(){var b=c.header;return n=c.theme?"ui":"fc",b?o=a("<div class='fc-toolbar'/>").append(f("left")).append(f("right")).append(f("center")).append('<div class="fc-clear"/>'):void 0}function e(){o.remove(),o=a()}function f(d){var e=a('<div class="fc-'+d+'"/>'),f=c.header[d];return f&&a.each(f.split(" "),function(d){var f,g=a(),h=!0;a.each(this.split(","),function(d,e){var f,i,j,k,l,m,o,q,r,s;"title"==e?(g=g.add(a("<h2>&nbsp;</h2>")),h=!1):((f=(b.options.customButtons||{})[e])?(j=function(a){f.click&&f.click.call(s[0],a)},k="",l=f.text):(i=b.getViewSpec(e))?(j=function(){b.changeView(e)},p.push(e),k=i.buttonTextOverride,l=i.buttonTextDefault):b[e]&&(j=function(){b[e]()},k=(b.overrides.buttonText||{})[e],l=c.buttonText[e]),j&&(m=f?f.themeIcon:c.themeButtonIcons[e],o=f?f.icon:c.buttonIcons[e],q=k?Y(k):m&&c.theme?"<span class='ui-icon ui-icon-"+m+"'></span>":o&&!c.theme?"<span class='fc-icon fc-icon-"+o+"'></span>":Y(l),r=["fc-"+e+"-button",n+"-button",n+"-state-default"],s=a('<button type="button" class="'+r.join(" ")+'">'+q+"</button>").click(function(a){s.hasClass(n+"-state-disabled")||(j(a),(s.hasClass(n+"-state-active")||s.hasClass(n+"-state-disabled"))&&s.removeClass(n+"-state-hover"))}).mousedown(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-down")}).mouseup(function(){s.removeClass(n+"-state-down")}).hover(function(){s.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-hover")},function(){s.removeClass(n+"-state-hover").removeClass(n+"-state-down")}),g=g.add(s)))}),h&&g.first().addClass(n+"-corner-left").end().last().addClass(n+"-corner-right").end(),g.length>1?(f=a("<div/>"),h&&f.addClass("fc-button-group"),f.append(g),e.append(f)):e.append(g)}),e}function g(a){o.find("h2").text(a)}function h(a){o.find(".fc-"+a+"-button").addClass(n+"-state-active")}function i(a){o.find(".fc-"+a+"-button").removeClass(n+"-state-active")}function j(a){o.find(".fc-"+a+"-button").attr("disabled","disabled").addClass(n+"-state-disabled")}function k(a){o.find(".fc-"+a+"-button").removeAttr("disabled").removeClass(n+"-state-disabled")}function l(){return p}var m=this;m.render=d,m.removeElement=e,m.updateTitle=g,m.activateButton=h,m.deactivateButton=i,m.disableButton=j,m.enableButton=k,m.getViewsWithButtons=l;var n,o=a(),p=[]}function Ka(c){function d(a,b){return!M||a.clone().stripZone()<M.clone().stripZone()||b.clone().stripZone()>N.clone().stripZone()}function e(a,b){M=a,N=b,U=[];var c=++S,d=R.length;T=d;for(var e=0;d>e;e++)f(R[e],c)}function f(b,c){g(b,function(d){var e,f,g,h=a.isArray(b.events);if(c==S){if(d)for(e=0;e<d.length;e++)f=d[e],g=h?f:s(f,b),g&&U.push.apply(U,x(g));T--,T||O(U)}})}function g(b,d){var e,f,h=Ma.sourceFetchers;for(e=0;e<h.length;e++){if(f=h[e].call(L,b,M.clone(),N.clone(),c.timezone,d),f===!0)return;if("object"==typeof f)return void g(f,d)}var i=b.events;if(i)a.isFunction(i)?(L.pushLoading(),i.call(L,M.clone(),N.clone(),c.timezone,function(a){d(a),L.popLoading()})):a.isArray(i)?d(i):d();else{var j=b.url;if(j){var k,l=b.success,m=b.error,n=b.complete;k=a.isFunction(b.data)?b.data():b.data;var o=a.extend({},k||{}),p=X(b.startParam,c.startParam),q=X(b.endParam,c.endParam),r=X(b.timezoneParam,c.timezoneParam);p&&(o[p]=M.format()),q&&(o[q]=N.format()),c.timezone&&"local"!=c.timezone&&(o[r]=c.timezone),L.pushLoading(),a.ajax(a.extend({},sb,b,{data:o,success:function(b){b=b||[];var c=W(l,this,arguments);a.isArray(c)&&(b=c),d(b)},error:function(){W(m,this,arguments),d()},complete:function(){W(n,this,arguments),L.popLoading()}}))}else d()}}function h(a){var b=i(a);b&&(R.push(b),T++,f(b,S))}function i(b){var c,d,e=Ma.sourceNormalizers;if(a.isFunction(b)||a.isArray(b)?c={events:b}:"string"==typeof b?c={url:b}:"object"==typeof b&&(c=a.extend({},b)),c){for(c.className?"string"==typeof c.className&&(c.className=c.className.split(/\s+/)):c.className=[],a.isArray(c.events)&&(c.origArray=c.events,c.events=a.map(c.events,function(a){return s(a,c)})),d=0;d<e.length;d++)e[d].call(L,c);return c}}function j(b){R=a.grep(R,function(a){return!k(a,b)}),U=a.grep(U,function(a){return!k(a.source,b)}),O(U)}function k(a,b){return a&&b&&l(a)==l(b)}function l(a){return("object"==typeof a?a.origArray||a.googleCalendarId||a.url||a.events:null)||a}function m(a){a.start=L.moment(a.start),a.end?a.end=L.moment(a.end):a.end=null,y(a,n(a)),O(U)}function n(b){var c={};return a.each(b,function(a,b){o(a)&&void 0!==b&&V(b)&&(c[a]=b)}),c}function o(a){return!/^_|^(id|allDay|start|end)$/.test(a)}function p(a,b){var c,d,e,f=s(a);if(f){for(c=x(f),d=0;d<c.length;d++)e=c[d],e.source||(b&&(Q.events.push(e),e.source=Q),U.push(e));return O(U),c}return[]}function q(b){var c,d;for(null==b?b=function(){return!0}:a.isFunction(b)||(c=b+"",b=function(a){return a._id==c}),U=a.grep(U,b,!0),d=0;d<R.length;d++)a.isArray(R[d].events)&&(R[d].events=a.grep(R[d].events,b,!0));O(U)}function r(b){return a.isFunction(b)?a.grep(U,b):null!=b?(b+="",a.grep(U,function(a){return a._id==b})):U}function s(d,e){var f,g,h,i={};if(c.eventDataTransform&&(d=c.eventDataTransform(d)),e&&e.eventDataTransform&&(d=e.eventDataTransform(d)),a.extend(i,d),e&&(i.source=e),i._id=d._id||(void 0===d.id?"_fc"+tb++:d.id+""),d.className?"string"==typeof d.className?i.className=d.className.split(/\s+/):i.className=d.className:i.className=[],f=d.start||d.date,g=d.end,P(f)&&(f=b.duration(f)),P(g)&&(g=b.duration(g)),d.dow||b.isDuration(f)||b.isDuration(g))i.start=f?b.duration(f):null,i.end=g?b.duration(g):null,i._recurring=!0;else{if(f&&(f=L.moment(f),!f.isValid()))return!1;g&&(g=L.moment(g),g.isValid()||(g=null)),h=d.allDay,void 0===h&&(h=X(e?e.allDayDefault:void 0,c.allDayDefault)),t(f,g,h,i)}return i}function t(a,b,c,d){d.start=a,d.end=b,d.allDay=c,u(d),La(d)}function u(a){v(a),a.end&&!a.end.isAfter(a.start)&&(a.end=null),a.end||(c.forceEventDuration?a.end=L.getDefaultEventEnd(a.allDay,a.start):a.end=null)}function v(a){null==a.allDay&&(a.allDay=!(a.start.hasTime()||a.end&&a.end.hasTime())),a.allDay?(a.start.stripTime(),a.end&&a.end.stripTime()):(a.start.hasTime()||(a.start=L.rezoneDate(a.start)),a.end&&!a.end.hasTime()&&(a.end=L.rezoneDate(a.end)))}function w(b){var c;return b.end||(c=b.allDay,null==c&&(c=!b.start.hasTime()),b=a.extend({},b),b.end=L.getDefaultEventEnd(c,b.start)),b}function x(b,c,d){var e,f,g,h,i,j,k,l,m,n=[];if(c=c||M,d=d||N,b)if(b._recurring){if(f=b.dow)for(e={},g=0;g<f.length;g++)e[f[g]]=!0;for(h=c.clone().stripTime();h.isBefore(d);)(!e||e[h.day()])&&(i=b.start,j=b.end,k=h.clone(),l=null,i&&(k=k.time(i)),j&&(l=h.clone().time(j)),m=a.extend({},b),t(k,l,!i&&!j,m),n.push(m)),h.add(1,"days")}else n.push(b);return n}function y(b,c,d){function e(a,b){return d?H(a,b,d):c.allDay?G(a,b):F(a,b)}var f,g,h,i,j,k,l={};return c=c||{},c.start||(c.start=b.start.clone()),void 0===c.end&&(c.end=b.end?b.end.clone():null),null==c.allDay&&(c.allDay=b.allDay),u(c),f={start:b._start.clone(),end:b._end?b._end.clone():L.getDefaultEventEnd(b._allDay,b._start),allDay:c.allDay},u(f),g=null!==b._end&&null===c.end,h=e(c.start,f.start),c.end?(i=e(c.end,f.end),j=i.subtract(h)):j=null,a.each(c,function(a,b){o(a)&&void 0!==b&&(l[a]=b)}),k=z(r(b._id),g,c.allDay,h,j,l),{dateDelta:h,durationDelta:j,undo:k}}function z(b,c,d,e,f,g){var h=L.getIsAmbigTimezone(),i=[];return e&&!e.valueOf()&&(e=null),f&&!f.valueOf()&&(f=null),a.each(b,function(b,j){var k,l;k={start:j.start.clone(),end:j.end?j.end.clone():null,allDay:j.allDay},a.each(g,function(a){k[a]=j[a]}),l={start:j._start,end:j._end,allDay:d},u(l),c?l.end=null:f&&!l.end&&(l.end=L.getDefaultEventEnd(l.allDay,l.start)),e&&(l.start.add(e),l.end&&l.end.add(e)),f&&l.end.add(f),h&&!l.allDay&&(e||f)&&(l.start.stripZone(),l.end&&l.end.stripZone()),a.extend(j,g,l),La(j),i.push(function(){a.extend(j,k),La(j)})}),function(){for(var a=0;a<i.length;a++)i[a]()}}function A(b){var d,e=c.businessHours,f={className:"fc-nonbusiness",start:"09:00",end:"17:00",dow:[1,2,3,4,5],rendering:"inverse-background"},g=L.getView();return e&&(d=a.extend({},f,"object"==typeof e?e:{})),d?(b&&(d.start=null,d.end=null),x(s(d),g.start,g.end)):[]}function B(a,b){var d=b.source||{},e=X(b.constraint,d.constraint,c.eventConstraint),f=X(b.overlap,d.overlap,c.eventOverlap);return a=w(a),E(a,e,f,b)}function C(a){return E(a,c.selectConstraint,c.selectOverlap)}function D(b,c){var d,e;return c&&(d=a.extend({},c,b),e=x(s(d))[0]),e?B(b,e):(b=w(b),C(b))}function E(b,c,d,e){var f,g,h,i,j,k;if(b=a.extend({},b),b.start=b.start.clone().stripZone(),b.end=b.end.clone().stripZone(),null!=c){for(f=I(c),g=!1,i=0;i<f.length;i++)if(J(f[i],b)){g=!0;break}if(!g)return!1}for(h=L.getPeerEvents(e,b),i=0;i<h.length;i++)if(j=h[i],K(j,b)){if(d===!1)return!1;if("function"==typeof d&&!d(j,e))return!1;if(e){if(k=X(j.overlap,(j.source||{}).overlap),k===!1)return!1;if("function"==typeof k&&!k(e,j))return!1}}return!0}function I(a){return"businessHours"===a?A():"object"==typeof a?x(s(a)):r(a)}function J(a,b){var c=a.start.clone().stripZone(),d=L.getEventEnd(a).stripZone();return b.start>=c&&b.end<=d}function K(a,b){var c=a.start.clone().stripZone(),d=L.getEventEnd(a).stripZone();return b.start<d&&b.end>c}var L=this;L.isFetchNeeded=d,L.fetchEvents=e,L.addEventSource=h,L.removeEventSource=j,L.updateEvent=m,L.renderEvent=p,L.removeEvents=q,L.clientEvents=r,L.mutateEvent=y,L.normalizeEventRange=u,L.normalizeEventRangeTimes=v,L.ensureVisibleEventRange=w;var M,N,O=L.reportEvents,Q={events:[]},R=[Q],S=0,T=0,U=[];a.each((c.events?[c.events]:[]).concat(c.eventSources||[]),function(a,b){var c=i(b);c&&R.push(c)}),L.getBusinessHoursEvents=A,L.isEventRangeAllowed=B,L.isSelectionRangeAllowed=C,L.isExternalDropRangeAllowed=D,L.getEventCache=function(){return U}}function La(a){a._allDay=a.allDay,a._start=a.start.clone(),a._end=a.end?a.end.clone():null}var Ma=a.fullCalendar={version:"2.4.0"},Na=Ma.views={};a.fn.fullCalendar=function(b){var c=Array.prototype.slice.call(arguments,1),d=this;return this.each(function(e,f){var g,h=a(f),i=h.data("fullCalendar");"string"==typeof b?i&&a.isFunction(i[b])&&(g=i[b].apply(i,c),e||(d=g),"destroy"===b&&h.removeData("fullCalendar")):i||(i=new nb(h,b),h.data("fullCalendar",i),i.render())}),d};var Oa=["header","buttonText","buttonIcons","themeButtonIcons"];Ma.intersectionToSeg=E,Ma.applyAll=W,Ma.debounce=da,Ma.isInt=ba,Ma.htmlEscape=Y,Ma.cssToStr=$,Ma.proxy=ca,Ma.capitaliseFirstLetter=_,Ma.getClientRect=p,Ma.getContentRect=q,Ma.getScrollbarWidths=r;var Pa=null;Ma.intersectRects=w,Ma.parseFieldSpecs=A,Ma.compareByFieldSpecs=B,Ma.compareByFieldSpec=C,Ma.flexibleCompare=D,Ma.computeIntervalUnit=I,Ma.divideRangeByDuration=K,Ma.divideDurationByDuration=L,Ma.multiplyDuration=M,Ma.durationHasTime=N;var Qa=["sun","mon","tue","wed","thu","fri","sat"],Ra=["year","month","week","day","hour","minute","second","millisecond"];Ma.log=function(){var a=window.console;return a&&a.log?a.log.apply(a,arguments):void 0},Ma.warn=function(){var a=window.console;return a&&a.warn?a.warn.apply(a,arguments):Ma.log.apply(Ma,arguments)};var Sa,Ta,Ua,Va={}.hasOwnProperty,Wa=/^\s*\d{4}-\d\d$/,Xa=/^\s*\d{4}-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?)?$/,Ya=b.fn,Za=a.extend({},Ya);Ma.moment=function(){return ea(arguments)},Ma.moment.utc=function(){var a=ea(arguments,!0);return a.hasTime()&&a.utc(),a},Ma.moment.parseZone=function(){return ea(arguments,!0,!0)},Ya.clone=function(){var a=Za.clone.apply(this,arguments);return ga(this,a),this._fullCalendar&&(a._fullCalendar=!0),a},Ya.week=Ya.weeks=function(a){var b=(this._locale||this._lang)._fullCalendar_weekCalc;return null==a&&"function"==typeof b?b(this):"ISO"===b?Za.isoWeek.apply(this,arguments):Za.week.apply(this,arguments)},Ya.time=function(a){if(!this._fullCalendar)return Za.time.apply(this,arguments);if(null==a)return b.duration({hours:this.hours(),minutes:this.minutes(),seconds:this.seconds(),milliseconds:this.milliseconds()});this._ambigTime=!1,b.isDuration(a)||b.isMoment(a)||(a=b.duration(a));var c=0;return b.isDuration(a)&&(c=24*Math.floor(a.asDays())),this.hours(c+a.hours()).minutes(a.minutes()).seconds(a.seconds()).milliseconds(a.milliseconds())},Ya.stripTime=function(){var a;return this._ambigTime||(a=this.toArray(),this.utc(),Ta(this,a.slice(0,3)),this._ambigTime=!0,this._ambigZone=!0),this},Ya.hasTime=function(){return!this._ambigTime},Ya.stripZone=function(){var a,b;return this._ambigZone||(a=this.toArray(),b=this._ambigTime,this.utc(),Ta(this,a),this._ambigTime=b||!1,this._ambigZone=!0),this},Ya.hasZone=function(){return!this._ambigZone},Ya.local=function(){var a=this.toArray(),b=this._ambigZone;return Za.local.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,b&&Ua(this,a),this},Ya.utc=function(){return Za.utc.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,this},a.each(["zone","utcOffset"],function(a,b){Za[b]&&(Ya[b]=function(a){return null!=a&&(this._ambigTime=!1,this._ambigZone=!1),Za[b].apply(this,arguments)})}),Ya.format=function(){return this._fullCalendar&&arguments[0]?ja(this,arguments[0]):this._ambigTime?ia(this,"YYYY-MM-DD"):this._ambigZone?ia(this,"YYYY-MM-DD[T]HH:mm:ss"):Za.format.apply(this,arguments)},Ya.toISOString=function(){return this._ambigTime?ia(this,"YYYY-MM-DD"):this._ambigZone?ia(this,"YYYY-MM-DD[T]HH:mm:ss"):Za.toISOString.apply(this,arguments)},Ya.isWithin=function(a,b){var c=fa([this,a,b]);return c[0]>=c[1]&&c[0]<c[2]},Ya.isSame=function(a,b){var c;return this._fullCalendar?b?(c=fa([this,a],!0),Za.isSame.call(c[0],c[1],b)):(a=Ma.moment.parseZone(a),Za.isSame.call(this,a)&&Boolean(this._ambigTime)===Boolean(a._ambigTime)&&Boolean(this._ambigZone)===Boolean(a._ambigZone)):Za.isSame.apply(this,arguments)},a.each(["isBefore","isAfter"],function(a,b){Ya[b]=function(a,c){var d;return this._fullCalendar?(d=fa([this,a]),Za[b].call(d[0],d[1],c)):Za[b].apply(this,arguments)}}),Sa="_d"in b()&&"updateOffset"in b,Ta=Sa?function(a,c){a._d.setTime(Date.UTC.apply(Date,c)),b.updateOffset(a,!1)}:ha,Ua=Sa?function(a,c){a._d.setTime(+new Date(c[0]||0,c[1]||0,c[2]||0,c[3]||0,c[4]||0,c[5]||0,c[6]||0)),b.updateOffset(a,!1)}:ha;var $a={t:function(a){return ia(a,"a").charAt(0)},T:function(a){return ia(a,"A").charAt(0)}};Ma.formatRange=ma;var _a={Y:"year",M:"month",D:"day",d:"day",A:"second",a:"second",T:"second",t:"second",H:"second",h:"second",m:"second",s:"second"},ab={};Ma.Class=ra,ra.extend=function(a){var b,c=this;return a=a||{},U(a,"constructor")&&(b=a.constructor),"function"!=typeof b&&(b=a.constructor=function(){c.apply(this,arguments)}),b.prototype=R(c.prototype),S(a,b.prototype),T(a,b.prototype),S(c,b),b},ra.mixin=function(a){S(a.prototype||a,this.prototype)};var bb=Ma.Emitter=ra.extend({callbackHash:null,on:function(a,b){return this.getCallbacks(a).add(b),this},off:function(a,b){return this.getCallbacks(a).remove(b),this},trigger:function(a){var b=Array.prototype.slice.call(arguments,1);return this.triggerWith(a,this,b),this},triggerWith:function(a,b,c){var d=this.getCallbacks(a);return d.fireWith(b,c),this},getCallbacks:function(b){var c;return this.callbackHash||(this.callbackHash={}),c=this.callbackHash[b],c||(c=this.callbackHash[b]=a.Callbacks()),c}}),cb=ra.extend({isHidden:!0,options:null,el:null,documentMousedownProxy:null,margin:10,constructor:function(a){this.options=a||{}},show:function(){this.isHidden&&(this.el||this.render(),this.el.show(),this.position(),this.isHidden=!1,this.trigger("show"))},hide:function(){this.isHidden||(this.el.hide(),this.isHidden=!0,this.trigger("hide"))},render:function(){var b=this,c=this.options;this.el=a('<div class="fc-popover"/>').addClass(c.className||"").css({top:0,left:0}).append(c.content).appendTo(c.parentEl),this.el.on("click",".fc-close",function(){b.hide()}),c.autoHide&&a(document).on("mousedown",this.documentMousedownProxy=ca(this,"documentMousedown"))},documentMousedown:function(b){this.el&&!a(b.target).closest(this.el).length&&this.hide()},removeElement:function(){this.hide(),this.el&&(this.el.remove(),this.el=null),a(document).off("mousedown",this.documentMousedownProxy)},position:function(){var b,c,d,e,f,g=this.options,h=this.el.offsetParent().offset(),i=this.el.outerWidth(),j=this.el.outerHeight(),k=a(window),l=n(this.el);e=g.top||0,f=void 0!==g.left?g.left:void 0!==g.right?g.right-i:0,l.is(window)||l.is(document)?(l=k,b=0,c=0):(d=l.offset(),b=d.top,c=d.left),b+=k.scrollTop(),c+=k.scrollLeft(),g.viewportConstrain!==!1&&(e=Math.min(e,b+l.outerHeight()-j-this.margin),e=Math.max(e,b+this.margin),f=Math.min(f,c+l.outerWidth()-i-this.margin),f=Math.max(f,c+this.margin)),this.el.css({top:e-h.top,left:f-h.left})},trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1));
7
  }}),db=ra.extend({grid:null,rowCoords:null,colCoords:null,containerEl:null,bounds:null,constructor:function(a){this.grid=a},build:function(){this.grid.build(),this.rowCoords=this.grid.computeRowCoords(),this.colCoords=this.grid.computeColCoords(),this.computeBounds()},clear:function(){this.grid.clear(),this.rowCoords=null,this.colCoords=null},getCell:function(b,c){var d,e,f,g=this.rowCoords,h=g.length,i=this.colCoords,j=i.length,k=null,l=null;if(this.inBounds(b,c)){for(d=0;h>d;d++)if(e=g[d],c>=e.top&&c<e.bottom){k=d;break}for(d=0;j>d;d++)if(e=i[d],b>=e.left&&b<e.right){l=d;break}if(null!==k&&null!==l)return f=this.grid.getCell(k,l),f.grid=this.grid,a.extend(f,g[k],i[l]),f}return null},computeBounds:function(){this.bounds=this.containerEl?p(this.containerEl):null},inBounds:function(a,b){var c=this.bounds;return c?a>=c.left&&a<c.right&&b>=c.top&&b<c.bottom:!0}}),eb=ra.extend({coordMaps:null,constructor:function(a){this.coordMaps=a},build:function(){var a,b=this.coordMaps;for(a=0;a<b.length;a++)b[a].build()},getCell:function(a,b){var c,d=this.coordMaps,e=null;for(c=0;c<d.length&&!e;c++)e=d[c].getCell(a,b);return e},clear:function(){var a,b=this.coordMaps;for(a=0;a<b.length;a++)b[a].clear()}}),fb=Ma.DragListener=ra.extend({options:null,isListening:!1,isDragging:!1,originX:null,originY:null,mousemoveProxy:null,mouseupProxy:null,subjectEl:null,subjectHref:null,scrollEl:null,scrollBounds:null,scrollTopVel:null,scrollLeftVel:null,scrollIntervalId:null,scrollHandlerProxy:null,scrollSensitivity:30,scrollSpeed:200,scrollIntervalMs:50,constructor:function(a){a=a||{},this.options=a,this.subjectEl=a.subjectEl},mousedown:function(a){v(a)&&(a.preventDefault(),this.startListening(a),this.options.distance||this.startDrag(a))},startListening:function(b){var c;this.isListening||(b&&this.options.scroll&&(c=n(a(b.target)),c.is(window)||c.is(document)||(this.scrollEl=c,this.scrollHandlerProxy=da(ca(this,"scrollHandler"),100),this.scrollEl.on("scroll",this.scrollHandlerProxy))),a(document).on("mousemove",this.mousemoveProxy=ca(this,"mousemove")).on("mouseup",this.mouseupProxy=ca(this,"mouseup")).on("selectstart",this.preventDefault),b?(this.originX=b.pageX,this.originY=b.pageY):(this.originX=0,this.originY=0),this.isListening=!0,this.listenStart(b))},listenStart:function(a){this.trigger("listenStart",a)},mousemove:function(a){var b,c,d=a.pageX-this.originX,e=a.pageY-this.originY;this.isDragging||(b=this.options.distance||1,c=d*d+e*e,c>=b*b&&this.startDrag(a)),this.isDragging&&this.drag(d,e,a)},startDrag:function(a){this.isListening||this.startListening(),this.isDragging||(this.isDragging=!0,this.dragStart(a))},dragStart:function(a){var b=this.subjectEl;this.trigger("dragStart",a),(this.subjectHref=b?b.attr("href"):null)&&b.removeAttr("href")},drag:function(a,b,c){this.trigger("drag",a,b,c),this.updateScroll(c)},mouseup:function(a){this.stopListening(a)},stopDrag:function(a){this.isDragging&&(this.stopScrolling(),this.dragStop(a),this.isDragging=!1)},dragStop:function(a){var b=this;this.trigger("dragStop",a),setTimeout(function(){b.subjectHref&&b.subjectEl.attr("href",b.subjectHref)},0)},stopListening:function(b){this.stopDrag(b),this.isListening&&(this.scrollEl&&(this.scrollEl.off("scroll",this.scrollHandlerProxy),this.scrollHandlerProxy=null),a(document).off("mousemove",this.mousemoveProxy).off("mouseup",this.mouseupProxy).off("selectstart",this.preventDefault),this.mousemoveProxy=null,this.mouseupProxy=null,this.isListening=!1,this.listenStop(b))},listenStop:function(a){this.trigger("listenStop",a)},trigger:function(a){this.options[a]&&this.options[a].apply(this,Array.prototype.slice.call(arguments,1))},preventDefault:function(a){a.preventDefault()},computeScrollBounds:function(){var a=this.scrollEl;this.scrollBounds=a?o(a):null},updateScroll:function(a){var b,c,d,e,f=this.scrollSensitivity,g=this.scrollBounds,h=0,i=0;g&&(b=(f-(a.pageY-g.top))/f,c=(f-(g.bottom-a.pageY))/f,d=(f-(a.pageX-g.left))/f,e=(f-(g.right-a.pageX))/f,b>=0&&1>=b?h=b*this.scrollSpeed*-1:c>=0&&1>=c&&(h=c*this.scrollSpeed),d>=0&&1>=d?i=d*this.scrollSpeed*-1:e>=0&&1>=e&&(i=e*this.scrollSpeed)),this.setScrollVel(h,i)},setScrollVel:function(a,b){this.scrollTopVel=a,this.scrollLeftVel=b,this.constrainScrollVel(),!this.scrollTopVel&&!this.scrollLeftVel||this.scrollIntervalId||(this.scrollIntervalId=setInterval(ca(this,"scrollIntervalFunc"),this.scrollIntervalMs))},constrainScrollVel:function(){var a=this.scrollEl;this.scrollTopVel<0?a.scrollTop()<=0&&(this.scrollTopVel=0):this.scrollTopVel>0&&a.scrollTop()+a[0].clientHeight>=a[0].scrollHeight&&(this.scrollTopVel=0),this.scrollLeftVel<0?a.scrollLeft()<=0&&(this.scrollLeftVel=0):this.scrollLeftVel>0&&a.scrollLeft()+a[0].clientWidth>=a[0].scrollWidth&&(this.scrollLeftVel=0)},scrollIntervalFunc:function(){var a=this.scrollEl,b=this.scrollIntervalMs/1e3;this.scrollTopVel&&a.scrollTop(a.scrollTop()+this.scrollTopVel*b),this.scrollLeftVel&&a.scrollLeft(a.scrollLeft()+this.scrollLeftVel*b),this.constrainScrollVel(),this.scrollTopVel||this.scrollLeftVel||this.stopScrolling()},stopScrolling:function(){this.scrollIntervalId&&(clearInterval(this.scrollIntervalId),this.scrollIntervalId=null,this.scrollStop())},scrollHandler:function(){this.scrollIntervalId||this.scrollStop()},scrollStop:function(){}}),gb=fb.extend({coordMap:null,origCell:null,cell:null,coordAdjust:null,constructor:function(a,b){fb.prototype.constructor.call(this,b),this.coordMap=a},listenStart:function(a){var b,c,d,e=this.subjectEl;fb.prototype.listenStart.apply(this,arguments),this.computeCoords(),a?(c={left:a.pageX,top:a.pageY},d=c,e&&(b=o(e),d=x(d,b)),this.origCell=this.getCell(d.left,d.top),e&&this.options.subjectCenter&&(this.origCell&&(b=w(this.origCell,b)||b),d=y(b)),this.coordAdjust=z(d,c)):(this.origCell=null,this.coordAdjust=null)},computeCoords:function(){this.coordMap.build(),this.computeScrollBounds()},dragStart:function(a){var b;fb.prototype.dragStart.apply(this,arguments),b=this.getCell(a.pageX,a.pageY),b&&this.cellOver(b)},drag:function(a,b,c){var d;fb.prototype.drag.apply(this,arguments),d=this.getCell(c.pageX,c.pageY),sa(d,this.cell)||(this.cell&&this.cellOut(),d&&this.cellOver(d))},dragStop:function(){this.cellDone(),fb.prototype.dragStop.apply(this,arguments)},cellOver:function(a){this.cell=a,this.trigger("cellOver",a,sa(a,this.origCell),this.origCell)},cellOut:function(){this.cell&&(this.trigger("cellOut",this.cell),this.cellDone(),this.cell=null)},cellDone:function(){this.cell&&this.trigger("cellDone",this.cell)},listenStop:function(){fb.prototype.listenStop.apply(this,arguments),this.origCell=this.cell=null,this.coordMap.clear()},scrollStop:function(){fb.prototype.scrollStop.apply(this,arguments),this.computeCoords()},getCell:function(a,b){return this.coordAdjust&&(a+=this.coordAdjust.left,b+=this.coordAdjust.top),this.coordMap.getCell(a,b)}}),hb=ra.extend({options:null,sourceEl:null,el:null,parentEl:null,top0:null,left0:null,mouseY0:null,mouseX0:null,topDelta:null,leftDelta:null,mousemoveProxy:null,isFollowing:!1,isHidden:!1,isAnimating:!1,constructor:function(b,c){this.options=c=c||{},this.sourceEl=b,this.parentEl=c.parentEl?a(c.parentEl):b.parent()},start:function(b){this.isFollowing||(this.isFollowing=!0,this.mouseY0=b.pageY,this.mouseX0=b.pageX,this.topDelta=0,this.leftDelta=0,this.isHidden||this.updatePosition(),a(document).on("mousemove",this.mousemoveProxy=ca(this,"mousemove")))},stop:function(b,c){function d(){this.isAnimating=!1,e.removeElement(),this.top0=this.left0=null,c&&c()}var e=this,f=this.options.revertDuration;this.isFollowing&&!this.isAnimating&&(this.isFollowing=!1,a(document).off("mousemove",this.mousemoveProxy),b&&f&&!this.isHidden?(this.isAnimating=!0,this.el.animate({top:this.top0,left:this.left0},{duration:f,complete:d})):d())},getEl:function(){var a=this.el;return a||(this.sourceEl.width(),a=this.el=this.sourceEl.clone().css({position:"absolute",visibility:"",display:this.isHidden?"none":"",margin:0,right:"auto",bottom:"auto",width:this.sourceEl.width(),height:this.sourceEl.height(),opacity:this.options.opacity||"",zIndex:this.options.zIndex}).appendTo(this.parentEl)),a},removeElement:function(){this.el&&(this.el.remove(),this.el=null)},updatePosition:function(){var a,b;this.getEl(),null===this.top0&&(this.sourceEl.width(),a=this.sourceEl.offset(),b=this.el.offsetParent().offset(),this.top0=a.top-b.top,this.left0=a.left-b.left),this.el.css({top:this.top0+this.topDelta,left:this.left0+this.leftDelta})},mousemove:function(a){this.topDelta=a.pageY-this.mouseY0,this.leftDelta=a.pageX-this.mouseX0,this.isHidden||this.updatePosition()},hide:function(){this.isHidden||(this.isHidden=!0,this.el&&this.el.hide())},show:function(){this.isHidden&&(this.isHidden=!1,this.updatePosition(),this.getEl().show())}}),ib=ra.extend({view:null,isRTL:null,cellHtml:"<td/>",constructor:function(a){this.view=a,this.isRTL=a.opt("isRTL")},rowHtml:function(a,b){var c,d,e=this.getHtmlRenderer("cell",a),f="";for(b=b||0,c=0;c<this.colCnt;c++)d=this.getCell(b,c),f+=e(d);return f=this.bookendCells(f,a,b),"<tr>"+f+"</tr>"},bookendCells:function(a,b,c){var d=this.getHtmlRenderer("intro",b)(c||0),e=this.getHtmlRenderer("outro",b)(c||0),f=this.isRTL?e:d,g=this.isRTL?d:e;return"string"==typeof a?f+a+g:a.prepend(f).append(g)},getHtmlRenderer:function(a,b){var c,d,e,f,g=this.view;return c=a+"Html",b&&(d=b+_(a)+"Html"),d&&(f=g[d])?e=g:d&&(f=this[d])?e=this:(f=g[c])?e=g:(f=this[c])&&(e=this),"function"==typeof f?function(){return f.apply(e,arguments)||""}:function(){return f||""}}}),jb=Ma.Grid=ib.extend({start:null,end:null,rowCnt:0,colCnt:0,el:null,coordMap:null,elsByFill:null,externalDragStartProxy:null,colHeadFormat:null,eventTimeFormat:null,displayEventTime:null,displayEventEnd:null,cellDuration:null,largeUnit:null,constructor:function(){ib.apply(this,arguments),this.coordMap=new db(this),this.elsByFill={},this.externalDragStartProxy=ca(this,"externalDragStart")},computeColHeadFormat:function(){},computeEventTimeFormat:function(){return this.view.opt("smallTimeFormat")},computeDisplayEventTime:function(){return!0},computeDisplayEventEnd:function(){return!0},setRange:function(a){this.start=a.start.clone(),this.end=a.end.clone(),this.rangeUpdated(),this.processRangeOptions()},rangeUpdated:function(){},processRangeOptions:function(){var a,b,c=this.view;this.colHeadFormat=c.opt("columnFormat")||this.computeColHeadFormat(),this.eventTimeFormat=c.opt("eventTimeFormat")||c.opt("timeFormat")||this.computeEventTimeFormat(),a=c.opt("displayEventTime"),null==a&&(a=this.computeDisplayEventTime()),b=c.opt("displayEventEnd"),null==b&&(b=this.computeDisplayEventEnd()),this.displayEventTime=a,this.displayEventEnd=b},build:function(){},clear:function(){},rangeToSegs:function(a){},diffDates:function(a,b){return this.largeUnit?H(a,b,this.largeUnit):F(a,b)},getCell:function(b,c){var d;return null==c&&("number"==typeof b?(c=b%this.colCnt,b=Math.floor(b/this.colCnt)):(c=b.col,b=b.row)),d={row:b,col:c},a.extend(d,this.getRowData(b),this.getColData(c)),a.extend(d,this.computeCellRange(d)),d},computeCellRange:function(a){var b=this.computeCellDate(a);return{start:b,end:b.clone().add(this.cellDuration)}},computeCellDate:function(a){},getRowData:function(a){return{}},getColData:function(a){return{}},getRowEl:function(a){},getColEl:function(a){},getCellDayEl:function(a){return this.getColEl(a.col)||this.getRowEl(a.row)},computeRowCoords:function(){var a,b,c,d=[];for(a=0;a<this.rowCnt;a++)b=this.getRowEl(a),c=b.offset().top,d.push({top:c,bottom:c+b.outerHeight()});return d},computeColCoords:function(){var a,b,c,d=[];for(a=0;a<this.colCnt;a++)b=this.getColEl(a),c=b.offset().left,d.push({left:c,right:c+b.outerWidth()});return d},setElement:function(b){var c=this;this.el=b,b.on("mousedown",function(b){a(b.target).is(".fc-event-container *, .fc-more")||a(b.target).closest(".fc-popover").length||c.dayMousedown(b)}),this.bindSegHandlers(),this.bindGlobalHandlers()},removeElement:function(){this.unbindGlobalHandlers(),this.el.remove()},renderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},bindGlobalHandlers:function(){a(document).on("dragstart sortstart",this.externalDragStartProxy)},unbindGlobalHandlers:function(){a(document).off("dragstart sortstart",this.externalDragStartProxy)},dayMousedown:function(a){var b,c,d=this,e=this.view,f=e.opt("selectable"),i=new gb(this.coordMap,{scroll:e.opt("dragScroll"),dragStart:function(){e.unselect()},cellOver:function(a,e,h){h&&(b=e?a:null,f&&(c=d.computeSelection(h,a),c?d.renderSelection(c):g()))},cellOut:function(a){b=null,c=null,d.unrenderSelection(),h()},listenStop:function(a){b&&e.triggerDayClick(b,d.getCellDayEl(b),a),c&&e.reportSelection(c,a),h()}});i.mousedown(a)},renderRangeHelper:function(a,b){var c=this.fabricateHelperEvent(a,b);this.renderHelper(c,b)},fabricateHelperEvent:function(a,b){var c=b?R(b.event):{};return c.start=a.start.clone(),c.end=a.end?a.end.clone():null,c.allDay=null,this.view.calendar.normalizeEventRange(c),c.className=(c.className||[]).concat("fc-helper"),b||(c.editable=!1),c},renderHelper:function(a,b){},unrenderHelper:function(){},renderSelection:function(a){this.renderHighlight(this.selectionRangeToSegs(a))},unrenderSelection:function(){this.unrenderHighlight()},computeSelection:function(a,b){var c,d=[a.start,a.end,b.start,b.end];return d.sort(aa),c={start:d[0].clone(),end:d[3].clone()},this.view.calendar.isSelectionRangeAllowed(c)?c:null},selectionRangeToSegs:function(a){return this.rangeToSegs(a)},renderHighlight:function(a){this.renderFill("highlight",a)},unrenderHighlight:function(){this.unrenderFill("highlight")},highlightSegClasses:function(){return["fc-highlight"]},renderFill:function(a,b){},unrenderFill:function(a){var b=this.elsByFill[a];b&&(b.remove(),delete this.elsByFill[a])},renderFillSegEls:function(b,c){var d,e=this,f=this[b+"SegEl"],g="",h=[];if(c.length){for(d=0;d<c.length;d++)g+=this.fillSegHtml(b,c[d]);a(g).each(function(b,d){var g=c[b],i=a(d);f&&(i=f.call(e,g,i)),i&&(i=a(i),i.is(e.fillSegTag)&&(g.el=i,h.push(g)))})}return h},fillSegTag:"div",fillSegHtml:function(a,b){var c=this[a+"SegClasses"],d=this[a+"SegCss"],e=c?c.call(this,b):[],f=$(d?d.call(this,b):{});return"<"+this.fillSegTag+(e.length?' class="'+e.join(" ")+'"':"")+(f?' style="'+f+'"':"")+" />"},headHtml:function(){return'<div class="fc-row '+this.view.widgetHeaderClass+'"><table><thead>'+this.rowHtml("head")+"</thead></table></div>"},headCellHtml:function(a){var b=this.view,c=a.start;return'<th class="fc-day-header '+b.widgetHeaderClass+" fc-"+Qa[c.day()]+'">'+Y(c.format(this.colHeadFormat))+"</th>"},bgCellHtml:function(a){var b=this.view,c=a.start,d=this.getDayClasses(c);return d.unshift("fc-day",b.widgetContentClass),'<td class="'+d.join(" ")+'" data-date="'+c.format("YYYY-MM-DD")+'"></td>'},getDayClasses:function(a){var b=this.view,c=b.calendar.getNow().stripTime(),d=["fc-"+Qa[a.day()]];return 1==b.intervalDuration.as("months")&&a.month()!=b.intervalStart.month()&&d.push("fc-other-month"),a.isSame(c,"day")?d.push("fc-today",b.highlightStateClass):c>a?d.push("fc-past"):d.push("fc-future"),d}});jb.mixin({mousedOverSeg:null,isDraggingSeg:!1,isResizingSeg:!1,isDraggingExternal:!1,segs:null,renderEvents:function(a){var b,c,d=this.eventsToSegs(a),e=[],f=[];for(b=0;b<d.length;b++)c=d[b],ta(c.event)?e.push(c):f.push(c);e=this.renderBgSegs(e)||e,f=this.renderFgSegs(f)||f,this.segs=e.concat(f)},unrenderEvents:function(){this.triggerSegMouseout(),this.unrenderFgSegs(),this.unrenderBgSegs(),this.segs=null},getEventSegs:function(){return this.segs||[]},renderFgSegs:function(a){},unrenderFgSegs:function(){},renderFgSegEls:function(b,c){var d,e=this.view,f="",g=[];if(b.length){for(d=0;d<b.length;d++)f+=this.fgSegHtml(b[d],c);a(f).each(function(c,d){var f=b[c],h=e.resolveEventEl(f.event,a(d));h&&(h.data("fc-seg",f),f.el=h,g.push(f))})}return g},fgSegHtml:function(a,b){},renderBgSegs:function(a){return this.renderFill("bgEvent",a)},unrenderBgSegs:function(){this.unrenderFill("bgEvent")},bgEventSegEl:function(a,b){return this.view.resolveEventEl(a.event,b)},bgEventSegClasses:function(a){var b=a.event,c=b.source||{};return["fc-bgevent"].concat(b.className,c.className||[])},bgEventSegCss:function(a){var b=this.view,c=a.event,d=c.source||{};return{"background-color":c.backgroundColor||c.color||d.backgroundColor||d.color||b.opt("eventBackgroundColor")||b.opt("eventColor")}},businessHoursSegClasses:function(a){return["fc-nonbusiness","fc-bgevent"]},bindSegHandlers:function(){var b=this,c=this.view;a.each({mouseenter:function(a,c){b.triggerSegMouseover(a,c)},mouseleave:function(a,c){b.triggerSegMouseout(a,c)},click:function(a,b){return c.trigger("eventClick",this,a.event,b)},mousedown:function(d,e){a(e.target).is(".fc-resizer")&&c.isEventResizable(d.event)?b.segResizeMousedown(d,e,a(e.target).is(".fc-start-resizer")):c.isEventDraggable(d.event)&&b.segDragMousedown(d,e)}},function(c,d){b.el.on(c,".fc-event-container > *",function(c){var e=a(this).data("fc-seg");return!e||b.isDraggingSeg||b.isResizingSeg?void 0:d.call(this,e,c)})})},triggerSegMouseover:function(a,b){this.mousedOverSeg||(this.mousedOverSeg=a,this.view.trigger("eventMouseover",a.el[0],a.event,b))},triggerSegMouseout:function(a,b){b=b||{},this.mousedOverSeg&&(a=a||this.mousedOverSeg,this.mousedOverSeg=null,this.view.trigger("eventMouseout",a.el[0],a.event,b))},segDragMousedown:function(a,b){var c,d=this,e=this.view,f=e.calendar,i=a.el,j=a.event,k=new hb(a.el,{parentEl:e.el,opacity:e.opt("dragOpacity"),revertDuration:e.opt("dragRevertDuration"),zIndex:2}),l=new gb(e.coordMap,{distance:5,scroll:e.opt("dragScroll"),subjectEl:i,subjectCenter:!0,listenStart:function(a){k.hide(),k.start(a)},dragStart:function(b){d.triggerSegMouseout(a,b),d.segDragStart(a,b),e.hideEvent(j)},cellOver:function(b,h,i){a.cell&&(i=a.cell),c=d.computeEventDrop(i,b,j),c&&!f.isEventRangeAllowed(c,j)&&(g(),c=null),c&&e.renderDrag(c,a)?k.hide():k.show(),h&&(c=null)},cellOut:function(){e.unrenderDrag(),k.show(),c=null},cellDone:function(){h()},dragStop:function(b){k.stop(!c,function(){e.unrenderDrag(),e.showEvent(j),d.segDragStop(a,b),c&&e.reportEventDrop(j,c,this.largeUnit,i,b)})},listenStop:function(){k.stop()}});l.mousedown(b)},segDragStart:function(a,b){this.isDraggingSeg=!0,this.view.trigger("eventDragStart",a.el[0],a.event,b,{})},segDragStop:function(a,b){this.isDraggingSeg=!1,this.view.trigger("eventDragStop",a.el[0],a.event,b,{})},computeEventDrop:function(a,b,c){var d,e,f=this.view.calendar,g=a.start,h=b.start;return g.hasTime()===h.hasTime()?(d=this.diffDates(h,g),c.allDay&&N(d)?(e={start:c.start.clone(),end:f.getEventEnd(c),allDay:!1},f.normalizeEventRangeTimes(e)):e={start:c.start.clone(),end:c.end?c.end.clone():null,allDay:c.allDay},e.start.add(d),e.end&&e.end.add(d)):e={start:h.clone(),end:null,allDay:!h.hasTime()},e},applyDragOpacity:function(a){var b=this.view.opt("dragOpacity");null!=b&&a.each(function(a,c){c.style.opacity=b})},externalDragStart:function(b,c){var d,e,f=this.view;f.opt("droppable")&&(d=a((c?c.item:null)||b.target),e=f.opt("dropAccept"),(a.isFunction(e)?e.call(d[0],d):d.is(e))&&(this.isDraggingExternal||this.listenToExternalDrag(d,b,c)))},listenToExternalDrag:function(a,b,c){var d,e,f=this,i=ya(a);d=new gb(this.coordMap,{listenStart:function(){f.isDraggingExternal=!0},cellOver:function(a){e=f.computeExternalDrop(a,i),e?f.renderDrag(e):g()},cellOut:function(){e=null,f.unrenderDrag(),h()},dragStop:function(){f.unrenderDrag(),h(),e&&f.view.reportExternalDrop(i,e,a,b,c)},listenStop:function(){f.isDraggingExternal=!1}}),d.startDrag(b)},computeExternalDrop:function(a,b){var c={start:a.start.clone(),end:null};return b.startTime&&!c.start.hasTime()&&c.start.time(b.startTime),b.duration&&(c.end=c.start.clone().add(b.duration)),this.view.calendar.isExternalDropRangeAllowed(c,b.eventProps)?c:null},renderDrag:function(a,b){},unrenderDrag:function(){},segResizeMousedown:function(a,b,c){var d,e,f=this,i=this.view,j=i.calendar,k=a.el,l=a.event,m=j.getEventEnd(l);d=new gb(this.coordMap,{distance:5,scroll:i.opt("dragScroll"),subjectEl:k,dragStart:function(b){f.triggerSegMouseout(a,b),f.segResizeStart(a,b)},cellOver:function(b,d,h){e=c?f.computeEventStartResize(h,b,l):f.computeEventEndResize(h,b,l),e&&(j.isEventRangeAllowed(e,l)?e.start.isSame(l.start)&&e.end.isSame(m)&&(e=null):(g(),e=null)),e&&(i.hideEvent(l),f.renderEventResize(e,a))},cellOut:function(){e=null},cellDone:function(){f.unrenderEventResize(),i.showEvent(l),h()},dragStop:function(b){f.segResizeStop(a,b),e&&i.reportEventResize(l,e,this.largeUnit,k,b)}}),d.mousedown(b)},segResizeStart:function(a,b){this.isResizingSeg=!0,this.view.trigger("eventResizeStart",a.el[0],a.event,b,{})},segResizeStop:function(a,b){this.isResizingSeg=!1,this.view.trigger("eventResizeStop",a.el[0],a.event,b,{})},computeEventStartResize:function(a,b,c){return this.computeEventResize("start",a,b,c)},computeEventEndResize:function(a,b,c){return this.computeEventResize("end",a,b,c)},computeEventResize:function(a,b,c,d){var e,f,g=this.view.calendar,h=this.diffDates(c[a],b[a]);return e={start:d.start.clone(),end:g.getEventEnd(d),allDay:d.allDay},e.allDay&&N(h)&&(e.allDay=!1,g.normalizeEventRangeTimes(e)),e[a].add(h),e.start.isBefore(e.end)||(f=d.allDay?g.defaultAllDayEventDuration:g.defaultTimedEventDuration,this.cellDuration&&this.cellDuration<f&&(f=this.cellDuration),"start"==a?e.start=e.end.clone().subtract(f):e.end=e.start.clone().add(f)),e},renderEventResize:function(a,b){},unrenderEventResize:function(){},getEventTimeText:function(a,b,c){return null==b&&(b=this.eventTimeFormat),null==c&&(c=this.displayEventEnd),this.displayEventTime&&a.start.hasTime()?c&&a.end?this.view.formatRange(a,b):a.start.format(b):""},getSegClasses:function(a,b,c){var d=a.event,e=["fc-event",a.isStart?"fc-start":"fc-not-start",a.isEnd?"fc-end":"fc-not-end"].concat(d.className,d.source?d.source.className:[]);return b&&e.push("fc-draggable"),c&&e.push("fc-resizable"),e},getEventSkinCss:function(a){var b=this.view,c=a.source||{},d=a.color,e=c.color,f=b.opt("eventColor");return{"background-color":a.backgroundColor||d||c.backgroundColor||e||b.opt("eventBackgroundColor")||f,"border-color":a.borderColor||d||c.borderColor||e||b.opt("eventBorderColor")||f,color:a.textColor||c.textColor||b.opt("eventTextColor")}},eventsToSegs:function(a,b){var c,d=this.eventsToRanges(a),e=[];for(c=0;c<d.length;c++)e.push.apply(e,this.eventRangeToSegs(d[c],b));return e},eventsToRanges:function(b){var c=this,d=wa(b),e=[];return a.each(d,function(a,b){b.length&&e.push.apply(e,ua(b[0])?c.eventsToInverseRanges(b):c.eventsToNormalRanges(b))}),e},eventsToNormalRanges:function(a){var b,c,d,e,f=this.view.calendar,g=[];for(b=0;b<a.length;b++)c=a[b],d=c.start.clone().stripZone(),e=f.getEventEnd(c).stripZone(),g.push({event:c,start:d,end:e,eventStartMS:+d,eventDurationMS:e-d});return g},eventsToInverseRanges:function(a){var b,c,d=this.view,e=d.start.clone().stripZone(),f=d.end.clone().stripZone(),g=this.eventsToNormalRanges(a),h=[],i=a[0],j=e;for(g.sort(xa),b=0;b<g.length;b++)c=g[b],c.start>j&&h.push({event:i,start:j,end:c.start}),j=c.end;return f>j&&h.push({event:i,start:j,end:f}),h},eventRangeToSegs:function(a,b){var c,d,e;for(a=this.view.calendar.ensureVisibleEventRange(a),c=b?b(a):this.rangeToSegs(a),d=0;d<c.length;d++)e=c[d],e.event=a.event,e.eventStartMS=a.eventStartMS,e.eventDurationMS=a.eventDurationMS;return c},sortSegs:function(a){a.sort(ca(this,"compareSegs"))},compareSegs:function(a,b){return a.eventStartMS-b.eventStartMS||b.eventDurationMS-a.eventDurationMS||b.event.allDay-a.event.allDay||B(a.event,b.event,this.view.eventOrderSpecs)}}),Ma.dataAttrPrefix="";var kb=jb.extend({numbersVisible:!1,bottomCoordPadding:0,breakOnWeeks:null,cellDates:null,dayToCellOffsets:null,rowEls:null,dayEls:null,helperEls:null,constructor:function(){jb.apply(this,arguments),this.cellDuration=b.duration(1,"day")},renderDates:function(a){var b,c,d,e=this.view,f=this.rowCnt,g=this.colCnt,h=f*g,i="";for(b=0;f>b;b++)i+=this.dayRowHtml(b,a);for(this.el.html(i),this.rowEls=this.el.find(".fc-row"),this.dayEls=this.el.find(".fc-day"),c=0;h>c;c++)d=this.getCell(c),e.trigger("dayRender",null,d.start,this.dayEls.eq(c))},unrenderDates:function(){this.removeSegPopover()},renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents(!0),b=this.eventsToSegs(a);this.renderFill("businessHours",b,"bgevent")},dayRowHtml:function(a,b){var c=this.view,d=["fc-row","fc-week",c.widgetContentClass];return b&&d.push("fc-rigid"),'<div class="'+d.join(" ")+'"><div class="fc-bg"><table>'+this.rowHtml("day",a)+'</table></div><div class="fc-content-skeleton"><table>'+(this.numbersVisible?"<thead>"+this.rowHtml("number",a)+"</thead>":"")+"</table></div></div>"},dayCellHtml:function(a){return this.bgCellHtml(a)},computeColHeadFormat:function(){return this.rowCnt>1?"ddd":this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},computeEventTimeFormat:function(){return this.view.opt("extraSmallTimeFormat")},computeDisplayEventEnd:function(){return 1==this.colCnt},rangeUpdated:function(){var a,b,c,d;if(this.updateCellDates(),a=this.cellDates,this.breakOnWeeks){for(b=a[0].day(),d=1;d<a.length&&a[d].day()!=b;d++);c=Math.ceil(a.length/d)}else c=1,d=a.length;this.rowCnt=c,this.colCnt=d},updateCellDates:function(){for(var a=this.view,b=this.start.clone(),c=[],d=-1,e=[];b.isBefore(this.end);)a.isHiddenDay(b)?e.push(d+.5):(d++,e.push(d),c.push(b.clone())),b.add(1,"days");this.cellDates=c,this.dayToCellOffsets=e},computeCellDate:function(a){var b=this.colCnt,c=a.row*b+(this.isRTL?b-a.col-1:a.col);return this.cellDates[c].clone()},getRowEl:function(a){return this.rowEls.eq(a)},getColEl:function(a){return this.dayEls.eq(a)},getCellDayEl:function(a){return this.dayEls.eq(a.row*this.colCnt+a.col)},computeRowCoords:function(){var a=jb.prototype.computeRowCoords.call(this);return a[a.length-1].bottom+=this.bottomCoordPadding,a},rangeToSegs:function(a){var b,c,d,e,f,g,h,i,j,k,l=this.isRTL,m=this.rowCnt,n=this.colCnt,o=[];for(a=this.view.computeDayRange(a),b=this.dateToCellOffset(a.start),c=this.dateToCellOffset(a.end.subtract(1,"days")),d=0;m>d;d++)e=d*n,f=e+n-1,i=Math.max(e,b),j=Math.min(f,c),i=Math.ceil(i),j=Math.floor(j),j>=i&&(g=i===b,h=j===c,i-=e,j-=e,k={row:d,isStart:g,isEnd:h},l?(k.leftCol=n-j-1,k.rightCol=n-i-1):(k.leftCol=i,k.rightCol=j),o.push(k));return o},dateToCellOffset:function(a){var b=this.dayToCellOffsets,c=a.diff(this.start,"days");return 0>c?b[0]-1:c>=b.length?b[b.length-1]+1:b[c]},renderDrag:function(a,b){return this.renderHighlight(this.eventRangeToSegs(a)),b&&!b.el.closest(this.el).length?(this.renderRangeHelper(a,b),this.applyDragOpacity(this.helperEls),!0):void 0},unrenderDrag:function(){this.unrenderHighlight(),this.unrenderHelper()},renderEventResize:function(a,b){this.renderHighlight(this.eventRangeToSegs(a)),this.renderRangeHelper(a,b)},unrenderEventResize:function(){this.unrenderHighlight(),this.unrenderHelper()},renderHelper:function(b,c){var d,e=[],f=this.eventsToSegs([b]);f=this.renderFgSegEls(f),d=this.renderSegRows(f),this.rowEls.each(function(b,f){var g,h=a(f),i=a('<div class="fc-helper-skeleton"><table/></div>');g=c&&c.row===b?c.el.position().top:h.find(".fc-content-skeleton tbody").position().top,i.css("top",g).find("table").append(d[b].tbodyEl),h.append(i),e.push(i[0])}),this.helperEls=a(e)},unrenderHelper:function(){this.helperEls&&(this.helperEls.remove(),this.helperEls=null)},fillSegTag:"td",renderFill:function(b,c,d){var e,f,g,h=[];for(c=this.renderFillSegEls(b,c),e=0;e<c.length;e++)f=c[e],g=this.renderFillRow(b,f,d),this.rowEls.eq(f.row).append(g),h.push(g[0]);return this.elsByFill[b]=a(h),c},renderFillRow:function(b,c,d){var e,f,g=this.colCnt,h=c.leftCol,i=c.rightCol+1;return d=d||b.toLowerCase(),e=a('<div class="fc-'+d+'-skeleton"><table><tr/></table></div>'),f=e.find("tr"),h>0&&f.append('<td colspan="'+h+'"/>'),f.append(c.el.attr("colspan",i-h)),g>i&&f.append('<td colspan="'+(g-i)+'"/>'),this.bookendCells(f,b),e}});kb.mixin({rowStructs:null,unrenderEvents:function(){this.removeSegPopover(),jb.prototype.unrenderEvents.apply(this,arguments)},getEventSegs:function(){return jb.prototype.getEventSegs.call(this).concat(this.popoverSegs||[])},renderBgSegs:function(b){var c=a.grep(b,function(a){return a.event.allDay});return jb.prototype.renderBgSegs.call(this,c)},renderFgSegs:function(b){var c;return b=this.renderFgSegEls(b),c=this.rowStructs=this.renderSegRows(b),this.rowEls.each(function(b,d){a(d).find(".fc-content-skeleton > table").append(c[b].tbodyEl)}),b},unrenderFgSegs:function(){for(var a,b=this.rowStructs||[];a=b.pop();)a.tbodyEl.remove();this.rowStructs=null},renderSegRows:function(a){var b,c,d=[];for(b=this.groupSegRows(a),c=0;c<b.length;c++)d.push(this.renderSegRow(c,b[c]));return d},fgSegHtml:function(a,b){var c,d,e=this.view,f=a.event,g=e.isEventDraggable(f),h=!b&&f.allDay&&a.isStart&&e.isEventResizableFromStart(f),i=!b&&f.allDay&&a.isEnd&&e.isEventResizableFromEnd(f),j=this.getSegClasses(a,g,h||i),k=$(this.getEventSkinCss(f)),l="";return j.unshift("fc-day-grid-event","fc-h-event"),a.isStart&&(c=this.getEventTimeText(f),c&&(l='<span class="fc-time">'+Y(c)+"</span>")),d='<span class="fc-title">'+(Y(f.title||"")||"&nbsp;")+"</span>",'<a class="'+j.join(" ")+'"'+(f.url?' href="'+Y(f.url)+'"':"")+(k?' style="'+k+'"':"")+'><div class="fc-content">'+(this.isRTL?d+" "+l:l+" "+d)+"</div>"+(h?'<div class="fc-resizer fc-start-resizer" />':"")+(i?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},renderSegRow:function(b,c){function d(b){for(;b>g;)k=(r[e-1]||[])[g],k?k.attr("rowspan",parseInt(k.attr("rowspan")||1,10)+1):(k=a("<td/>"),h.append(k)),q[e][g]=k,r[e][g]=k,g++}var e,f,g,h,i,j,k,l=this.colCnt,m=this.buildSegLevels(c),n=Math.max(1,m.length),o=a("<tbody/>"),p=[],q=[],r=[];for(e=0;n>e;e++){if(f=m[e],g=0,h=a("<tr/>"),p.push([]),q.push([]),r.push([]),f)for(i=0;i<f.length;i++){for(j=f[i],d(j.leftCol),k=a('<td class="fc-event-container"/>').append(j.el),j.leftCol!=j.rightCol?k.attr("colspan",j.rightCol-j.leftCol+1):r[e][g]=k;g<=j.rightCol;)q[e][g]=k,p[e][g]=j,g++;h.append(k)}d(l),this.bookendCells(h,"eventSkeleton"),o.append(h)}return{row:b,tbodyEl:o,cellMatrix:q,segMatrix:p,segLevels:m,segs:c}},buildSegLevels:function(a){var b,c,d,e=[];for(this.sortSegs(a),b=0;b<a.length;b++){for(c=a[b],d=0;d<e.length&&za(c,e[d]);d++);c.level=d,(e[d]||(e[d]=[])).push(c)}for(d=0;d<e.length;d++)e[d].sort(Aa);return e},groupSegRows:function(a){var b,c=[];for(b=0;b<this.rowCnt;b++)c.push([]);for(b=0;b<a.length;b++)c[a[b].row].push(a[b]);return c}}),kb.mixin({segPopover:null,popoverSegs:null,removeSegPopover:function(){this.segPopover&&this.segPopover.hide()},limitRows:function(a){var b,c,d=this.rowStructs||[];for(b=0;b<d.length;b++)this.unlimitRow(b),c=a?"number"==typeof a?a:this.computeRowLevelLimit(b):!1,c!==!1&&this.limitRow(b,c)},computeRowLevelLimit:function(b){function c(b,c){f=Math.max(f,a(c).outerHeight())}var d,e,f,g=this.rowEls.eq(b),h=g.height(),i=this.rowStructs[b].tbodyEl.children();for(d=0;d<i.length;d++)if(e=i.eq(d).removeClass("fc-limited"),f=0,e.find("> td > :first-child").each(c),e.position().top+f>h)return d;return!1},limitRow:function(b,c){function d(d){for(;d>x;)e=u.getCell(b,x),k=u.getCellSegs(e,c),k.length&&(n=g[c-1][x],t=u.renderMoreLink(e,k),s=a("<div/>").append(t),n.append(s),w.push(s[0])),x++}var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u=this,v=this.rowStructs[b],w=[],x=0;if(c&&c<v.segLevels.length){for(f=v.segLevels[c-1],g=v.cellMatrix,h=v.tbodyEl.children().slice(c).addClass("fc-limited").get(),i=0;i<f.length;i++){for(j=f[i],d(j.leftCol),m=[],l=0;x<=j.rightCol;)e=this.getCell(b,x),k=this.getCellSegs(e,c),m.push(k),l+=k.length,x++;if(l){for(n=g[c-1][j.leftCol],o=n.attr("rowspan")||1,p=[],q=0;q<m.length;q++)r=a('<td class="fc-more-cell"/>').attr("rowspan",o),k=m[q],e=this.getCell(b,j.leftCol+q),t=this.renderMoreLink(e,[j].concat(k)),s=a("<div/>").append(t),r.append(s),p.push(r[0]),w.push(r[0]);n.addClass("fc-limited").after(a(p)),h.push(n[0])}}d(this.colCnt),v.moreEls=a(w),v.limitedEls=a(h)}},
8
+ unlimitRow:function(a){var b=this.rowStructs[a];b.moreEls&&(b.moreEls.remove(),b.moreEls=null),b.limitedEls&&(b.limitedEls.removeClass("fc-limited"),b.limitedEls=null)},renderMoreLink:function(b,c){var d=this,e=this.view;return a('<a class="fc-more"/>').text(this.getMoreLinkText(c.length)).on("click",function(f){var g=e.opt("eventLimitClick"),h=b.start,i=a(this),j=d.getCellDayEl(b),k=d.getCellSegs(b),l=d.resliceDaySegs(k,h),m=d.resliceDaySegs(c,h);"function"==typeof g&&(g=e.trigger("eventLimitClick",null,{date:h,dayEl:j,moreEl:i,segs:l,hiddenSegs:m},f)),"popover"===g?d.showSegPopover(b,i,l):"string"==typeof g&&e.calendar.zoomTo(h,g)})},showSegPopover:function(a,b,c){var d,e,f=this,g=this.view,h=b.parent();d=1==this.rowCnt?g.el:this.rowEls.eq(a.row),e={className:"fc-more-popover",content:this.renderSegPopoverContent(a,c),parentEl:this.el,top:d.offset().top,autoHide:!0,viewportConstrain:g.opt("popoverViewportConstrain"),hide:function(){f.segPopover.removeElement(),f.segPopover=null,f.popoverSegs=null}},this.isRTL?e.right=h.offset().left+h.outerWidth()+1:e.left=h.offset().left-1,this.segPopover=new cb(e),this.segPopover.show()},renderSegPopoverContent:function(b,c){var d,e=this.view,f=e.opt("theme"),g=b.start.format(e.opt("dayPopoverFormat")),h=a('<div class="fc-header '+e.widgetHeaderClass+'"><span class="fc-close '+(f?"ui-icon ui-icon-closethick":"fc-icon fc-icon-x")+'"></span><span class="fc-title">'+Y(g)+'</span><div class="fc-clear"/></div><div class="fc-body '+e.widgetContentClass+'"><div class="fc-event-container"></div></div>'),i=h.find(".fc-event-container");for(c=this.renderFgSegEls(c,!0),this.popoverSegs=c,d=0;d<c.length;d++)c[d].cell=b,i.append(c[d].el);return h},resliceDaySegs:function(b,c){var d=a.map(b,function(a){return a.event}),e=c.clone().stripTime(),f=e.clone().add(1,"days"),g={start:e,end:f};return b=this.eventsToSegs(d,function(a){var b=E(a,g);return b?[b]:[]}),this.sortSegs(b),b},getMoreLinkText:function(a){var b=this.view.opt("eventLimitText");return"function"==typeof b?b(a):"+"+a+" "+b},getCellSegs:function(a,b){for(var c,d=this.rowStructs[a.row].segMatrix,e=b||0,f=[];e<d.length;)c=d[e][a.col],c&&f.push(c),e++;return f}});var lb=jb.extend({slotDuration:null,snapDuration:null,minTime:null,maxTime:null,colDates:null,labelFormat:null,labelInterval:null,dayEls:null,slatEls:null,slatTops:null,helperEl:null,businessHourSegs:null,constructor:function(){jb.apply(this,arguments),this.processOptions()},renderDates:function(){this.el.html(this.renderHtml()),this.dayEls=this.el.find(".fc-day"),this.slatEls=this.el.find(".fc-slats tr")},renderBusinessHours:function(){var a=this.view.calendar.getBusinessHoursEvents();this.businessHourSegs=this.renderFill("businessHours",this.eventsToSegs(a),"bgevent")},renderHtml:function(){return'<div class="fc-bg"><table>'+this.rowHtml("slotBg")+'</table></div><div class="fc-slats"><table>'+this.slatRowHtml()+"</table></div>"},slotBgCellHtml:function(a){return this.bgCellHtml(a)},slatRowHtml:function(){for(var a,c,d,e=this.view,f=this.isRTL,g="",h=b.duration(+this.minTime);h<this.maxTime;)a=this.start.clone().time(h),c=ba(L(h,this.labelInterval)),d='<td class="fc-axis fc-time '+e.widgetContentClass+'" '+e.axisStyleAttr()+">"+(c?"<span>"+Y(a.format(this.labelFormat))+"</span>":"")+"</td>",g+="<tr "+(c?"":'class="fc-minor"')+">"+(f?"":d)+'<td class="'+e.widgetContentClass+'"/>'+(f?d:"")+"</tr>",h.add(this.slotDuration);return g},processOptions:function(){var c,d=this.view,e=d.opt("slotDuration"),f=d.opt("snapDuration");e=b.duration(e),f=f?b.duration(f):e,this.slotDuration=e,this.snapDuration=f,this.cellDuration=f,this.minTime=b.duration(d.opt("minTime")),this.maxTime=b.duration(d.opt("maxTime")),c=d.opt("slotLabelFormat"),a.isArray(c)&&(c=c[c.length-1]),this.labelFormat=c||d.opt("axisFormat")||d.opt("smallTimeFormat"),c=d.opt("slotLabelInterval"),this.labelInterval=c?b.duration(c):this.computeLabelInterval(e)},computeLabelInterval:function(a){var c,d,e;for(c=yb.length-1;c>=0;c--)if(d=b.duration(yb[c]),e=L(d,a),ba(e)&&e>1)return d;return b.duration(a)},computeColHeadFormat:function(){return this.colCnt>1?this.view.opt("dayOfMonthFormat"):"dddd"},computeEventTimeFormat:function(){return this.view.opt("noMeridiemTimeFormat")},computeDisplayEventEnd:function(){return!0},rangeUpdated:function(){var a,b=this.view,c=[];for(a=this.start.clone();a.isBefore(this.end);)c.push(a.clone()),a.add(1,"day"),a=b.skipHiddenDays(a);this.isRTL&&c.reverse(),this.colDates=c,this.colCnt=c.length,this.rowCnt=Math.ceil((this.maxTime-this.minTime)/this.snapDuration)},computeCellDate:function(a){var b=this.colDates[a.col],c=this.computeSnapTime(a.row);return b=this.view.calendar.rezoneDate(b),b.time(c),b},getColEl:function(a){return this.dayEls.eq(a)},computeSnapTime:function(a){return b.duration(this.minTime+this.snapDuration*a)},rangeToSegs:function(a){var b,c,d,e,f=this.colCnt,g=[];for(a={start:a.start.clone().stripZone(),end:a.end.clone().stripZone()},c=0;f>c;c++)d=this.colDates[c],e={start:d.clone().time(this.minTime),end:d.clone().time(this.maxTime)},b=E(a,e),b&&(b.col=c,g.push(b));return g},updateSize:function(a){this.computeSlatTops(),a&&this.updateSegVerticals()},computeRowCoords:function(){var a,b,c=this.el.offset().top,d=[];for(a=0;a<this.rowCnt;a++)b={top:c+this.computeTimeTop(this.computeSnapTime(a))},a>0&&(d[a-1].bottom=b.top),d.push(b);return b.bottom=b.top+this.computeTimeTop(this.computeSnapTime(a)),d},computeDateTop:function(a,c){return this.computeTimeTop(b.duration(a.clone().stripZone()-c.clone().stripTime()))},computeTimeTop:function(a){var b,c,d,e,f=(a-this.minTime)/this.slotDuration;return f=Math.max(0,f),f=Math.min(this.slatEls.length,f),b=Math.floor(f),c=f-b,d=this.slatTops[b],c?(e=this.slatTops[b+1],d+(e-d)*c):d},computeSlatTops:function(){var b,c=[];this.slatEls.each(function(d,e){b=a(e).position().top,c.push(b)}),c.push(b+this.slatEls.last().outerHeight()),this.slatTops=c},renderDrag:function(a,b){return b?(this.renderRangeHelper(a,b),this.applyDragOpacity(this.helperEl),!0):void this.renderHighlight(this.eventRangeToSegs(a))},unrenderDrag:function(){this.unrenderHelper(),this.unrenderHighlight()},renderEventResize:function(a,b){this.renderRangeHelper(a,b)},unrenderEventResize:function(){this.unrenderHelper()},renderHelper:function(b,c){var d,e,f,g,h=this.eventsToSegs([b]);for(h=this.renderFgSegEls(h),d=this.renderSegTable(h),e=0;e<h.length;e++)f=h[e],c&&c.col===f.col&&(g=c.el,f.el.css({left:g.css("left"),right:g.css("right"),"margin-left":g.css("margin-left"),"margin-right":g.css("margin-right")}));this.helperEl=a('<div class="fc-helper-skeleton"/>').append(d).appendTo(this.el)},unrenderHelper:function(){this.helperEl&&(this.helperEl.remove(),this.helperEl=null)},renderSelection:function(a){this.view.opt("selectHelper")?this.renderRangeHelper(a):this.renderHighlight(this.selectionRangeToSegs(a))},unrenderSelection:function(){this.unrenderHelper(),this.unrenderHighlight()},renderFill:function(b,c,d){var e,f,g,h,i,j,k,l,m,n;if(c.length){for(c=this.renderFillSegEls(b,c),e=this.groupSegCols(c),d=d||b.toLowerCase(),f=a('<div class="fc-'+d+'-skeleton"><table><tr/></table></div>'),g=f.find("tr"),h=0;h<e.length;h++)if(i=e[h],j=a("<td/>").appendTo(g),i.length)for(k=a('<div class="fc-'+d+'-container"/>').appendTo(j),l=this.colDates[h],m=0;m<i.length;m++)n=i[m],k.append(n.el.css({top:this.computeDateTop(n.start,l),bottom:-this.computeDateTop(n.end,l)}));this.bookendCells(g,b),this.el.append(f),this.elsByFill[b]=f}return c}});lb.mixin({eventSkeletonEl:null,renderFgSegs:function(b){return b=this.renderFgSegEls(b),this.el.append(this.eventSkeletonEl=a('<div class="fc-content-skeleton"/>').append(this.renderSegTable(b))),b},unrenderFgSegs:function(a){this.eventSkeletonEl&&(this.eventSkeletonEl.remove(),this.eventSkeletonEl=null)},renderSegTable:function(b){var c,d,e,f,g,h,i=a("<table><tr/></table>"),j=i.find("tr");for(c=this.groupSegCols(b),this.computeSegVerticals(b),f=0;f<c.length;f++){for(g=c[f],this.placeSlotSegs(g),h=a('<div class="fc-event-container"/>'),d=0;d<g.length;d++)e=g[d],e.el.css(this.generateSegPositionCss(e)),e.bottom-e.top<30&&e.el.addClass("fc-short"),h.append(e.el);j.append(a("<td/>").append(h))}return this.bookendCells(j,"eventSkeleton"),i},placeSlotSegs:function(a){var b,c,d;if(this.sortSegs(a),b=Ba(a),Ca(b),c=b[0]){for(d=0;d<c.length;d++)Da(c[d]);for(d=0;d<c.length;d++)this.computeSlotSegCoords(c[d],0,0)}},computeSlotSegCoords:function(a,b,c){var d,e=a.forwardSegs;if(void 0===a.forwardCoord)for(e.length?(this.sortForwardSlotSegs(e),this.computeSlotSegCoords(e[0],b+1,c),a.forwardCoord=e[0].backwardCoord):a.forwardCoord=1,a.backwardCoord=a.forwardCoord-(a.forwardCoord-c)/(b+1),d=0;d<e.length;d++)this.computeSlotSegCoords(e[d],0,a.forwardCoord)},updateSegVerticals:function(){var a,b=(this.segs||[]).concat(this.businessHourSegs||[]);for(this.computeSegVerticals(b),a=0;a<b.length;a++)b[a].el.css(this.generateSegVerticalCss(b[a]))},computeSegVerticals:function(a){var b,c;for(b=0;b<a.length;b++)c=a[b],c.top=this.computeDateTop(c.start,c.start),c.bottom=this.computeDateTop(c.end,c.start)},fgSegHtml:function(a,b){var c,d,e,f=this.view,g=a.event,h=f.isEventDraggable(g),i=!b&&a.isStart&&f.isEventResizableFromStart(g),j=!b&&a.isEnd&&f.isEventResizableFromEnd(g),k=this.getSegClasses(a,h,i||j),l=$(this.getEventSkinCss(g));return k.unshift("fc-time-grid-event","fc-v-event"),f.isMultiDayEvent(g)?(a.isStart||a.isEnd)&&(c=this.getEventTimeText(a),d=this.getEventTimeText(a,"LT"),e=this.getEventTimeText(a,null,!1)):(c=this.getEventTimeText(g),d=this.getEventTimeText(g,"LT"),e=this.getEventTimeText(g,null,!1)),'<a class="'+k.join(" ")+'"'+(g.url?' href="'+Y(g.url)+'"':"")+(l?' style="'+l+'"':"")+'><div class="fc-content">'+(c?'<div class="fc-time" data-start="'+Y(e)+'" data-full="'+Y(d)+'"><span>'+Y(c)+"</span></div>":"")+(g.title?'<div class="fc-title">'+Y(g.title)+"</div>":"")+'</div><div class="fc-bg"/>'+(j?'<div class="fc-resizer fc-end-resizer" />':"")+"</a>"},generateSegPositionCss:function(a){var b,c,d=this.view.opt("slotEventOverlap"),e=a.backwardCoord,f=a.forwardCoord,g=this.generateSegVerticalCss(a);return d&&(f=Math.min(1,e+2*(f-e))),this.isRTL?(b=1-f,c=e):(b=e,c=1-f),g.zIndex=a.level+1,g.left=100*b+"%",g.right=100*c+"%",d&&a.forwardPressure&&(g[this.isRTL?"marginLeft":"marginRight"]=20),g},generateSegVerticalCss:function(a){return{top:a.top,bottom:-a.bottom}},groupSegCols:function(a){var b,c=[];for(b=0;b<this.colCnt;b++)c.push([]);for(b=0;b<a.length;b++)c[a[b].col].push(a[b]);return c},sortForwardSlotSegs:function(a){a.sort(ca(this,"compareForwardSlotSegs"))},compareForwardSlotSegs:function(a,b){return b.forwardPressure-a.forwardPressure||(a.backwardCoord||0)-(b.backwardCoord||0)||this.compareSegs(a,b)}});var mb=Ma.View=ra.extend({type:null,name:null,title:null,calendar:null,options:null,coordMap:null,el:null,displaying:null,isSkeletonRendered:!1,isEventsRendered:!1,start:null,end:null,intervalStart:null,intervalEnd:null,intervalDuration:null,intervalUnit:null,isRTL:!1,isSelected:!1,eventOrderSpecs:null,scrollerEl:null,scrollTop:null,widgetHeaderClass:null,widgetContentClass:null,highlightStateClass:null,nextDayThreshold:null,isHiddenDayHash:null,documentMousedownProxy:null,constructor:function(a,c,d,e){this.calendar=a,this.type=this.name=c,this.options=d,this.intervalDuration=e||b.duration(1,"day"),this.nextDayThreshold=b.duration(this.opt("nextDayThreshold")),this.initThemingProps(),this.initHiddenDays(),this.isRTL=this.opt("isRTL"),this.eventOrderSpecs=A(this.opt("eventOrder")),this.documentMousedownProxy=ca(this,"documentMousedown"),this.initialize()},initialize:function(){},opt:function(a){return this.options[a]},trigger:function(a,b){var c=this.calendar;return c.trigger.apply(c,[a,b||this].concat(Array.prototype.slice.call(arguments,2),[this]))},setDate:function(a){this.setRange(this.computeRange(a))},setRange:function(b){a.extend(this,b),this.updateTitle()},computeRange:function(a){var b,c,d=I(this.intervalDuration),e=a.clone().startOf(d),f=e.clone().add(this.intervalDuration);return/year|month|week|day/.test(d)?(e.stripTime(),f.stripTime()):(e.hasTime()||(e=this.calendar.rezoneDate(e)),f.hasTime()||(f=this.calendar.rezoneDate(f))),b=e.clone(),b=this.skipHiddenDays(b),c=f.clone(),c=this.skipHiddenDays(c,-1,!0),{intervalUnit:d,intervalStart:e,intervalEnd:f,start:b,end:c}},computePrevDate:function(a){return this.massageCurrentDate(a.clone().startOf(this.intervalUnit).subtract(this.intervalDuration),-1)},computeNextDate:function(a){return this.massageCurrentDate(a.clone().startOf(this.intervalUnit).add(this.intervalDuration))},massageCurrentDate:function(a,b){return this.intervalDuration.as("days")<=1&&this.isHiddenDay(a)&&(a=this.skipHiddenDays(a,b),a.startOf("day")),a},updateTitle:function(){this.title=this.computeTitle()},computeTitle:function(){return this.formatRange({start:this.intervalStart,end:this.intervalEnd},this.opt("titleFormat")||this.computeTitleFormat(),this.opt("titleRangeSeparator"))},computeTitleFormat:function(){return"year"==this.intervalUnit?"YYYY":"month"==this.intervalUnit?this.opt("monthYearFormat"):this.intervalDuration.as("days")>1?"ll":"LL"},formatRange:function(a,b,c){var d=a.end;return d.hasTime()||(d=d.clone().subtract(1)),ma(a.start,d,b,c,this.opt("isRTL"))},setElement:function(a){this.el=a,this.bindGlobalHandlers()},removeElement:function(){this.clear(),this.isSkeletonRendered&&(this.unrenderSkeleton(),this.isSkeletonRendered=!1),this.unbindGlobalHandlers(),this.el.remove()},display:function(b){var c=this,d=null;return this.displaying&&(d=this.queryScroll()),zz(this.clear(),function(){return c.displaying=zz(c.displayView(b),function(){c.forceScroll(c.computeInitialScroll(d)),c.triggerRender()})})},clear:function(){var b=this,c=this.displaying;return c?c.then(function(){return b.displaying=null,b.clearEvents(),b.clearView()}):a.when()},displayView:function(a){this.isSkeletonRendered||(this.renderSkeleton(),this.isSkeletonRendered=!0),this.setDate(a),this.render&&this.render(),this.renderDates(),this.updateSize(),this.renderBusinessHours()},clearView:function(){this.unselect(),this.triggerUnrender(),this.unrenderBusinessHours(),this.unrenderDates(),this.destroy&&this.destroy()},renderSkeleton:function(){},unrenderSkeleton:function(){},renderDates:function(){},unrenderDates:function(){},renderBusinessHours:function(){},unrenderBusinessHours:function(){},triggerRender:function(){this.trigger("viewRender",this,this,this.el)},triggerUnrender:function(){this.trigger("viewDestroy",this,this,this.el)},bindGlobalHandlers:function(){a(document).on("mousedown",this.documentMousedownProxy)},unbindGlobalHandlers:function(){a(document).off("mousedown",this.documentMousedownProxy)},initThemingProps:function(){var a=this.opt("theme")?"ui":"fc";this.widgetHeaderClass=a+"-widget-header",this.widgetContentClass=a+"-widget-content",this.highlightStateClass=a+"-state-highlight"},updateSize:function(a){var b;a&&(b=this.queryScroll()),this.updateHeight(a),this.updateWidth(a),a&&this.setScroll(b)},updateWidth:function(a){},updateHeight:function(a){var b=this.calendar;this.setHeight(b.getSuggestedViewHeight(),b.isHeightAuto())},setHeight:function(a,b){},computeScrollerHeight:function(a){var b,c,d=this.scrollerEl;return b=this.el.add(d),b.css({position:"relative",left:-1}),c=this.el.outerHeight()-d.height(),b.css({position:"",left:""}),a-c},computeInitialScroll:function(a){return 0},queryScroll:function(){return this.scrollerEl?this.scrollerEl.scrollTop():void 0},setScroll:function(a){return this.scrollerEl?this.scrollerEl.scrollTop(a):void 0},forceScroll:function(a){var b=this;this.setScroll(a),setTimeout(function(){b.setScroll(a)},0)},displayEvents:function(a){var b=this.queryScroll();this.clearEvents(),this.renderEvents(a),this.isEventsRendered=!0,this.setScroll(b),this.triggerEventRender()},clearEvents:function(){this.isEventsRendered&&(this.triggerEventUnrender(),this.destroyEvents&&this.destroyEvents(),this.unrenderEvents(),this.isEventsRendered=!1)},renderEvents:function(a){},unrenderEvents:function(){},triggerEventRender:function(){this.renderedEventSegEach(function(a){this.trigger("eventAfterRender",a.event,a.event,a.el)}),this.trigger("eventAfterAllRender")},triggerEventUnrender:function(){this.renderedEventSegEach(function(a){this.trigger("eventDestroy",a.event,a.event,a.el)})},resolveEventEl:function(b,c){var d=this.trigger("eventRender",b,b,c);return d===!1?c=null:d&&d!==!0&&(c=a(d)),c},showEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","")},a)},hideEvent:function(a){this.renderedEventSegEach(function(a){a.el.css("visibility","hidden")},a)},renderedEventSegEach:function(a,b){var c,d=this.getEventSegs();for(c=0;c<d.length;c++)b&&d[c].event._id!==b._id||d[c].el&&a.call(this,d[c])},getEventSegs:function(){return[]},isEventDraggable:function(a){var b=a.source||{};return X(a.startEditable,b.startEditable,this.opt("eventStartEditable"),a.editable,b.editable,this.opt("editable"))},reportEventDrop:function(a,b,c,d,e){var f=this.calendar,g=f.mutateEvent(a,b,c),h=function(){g.undo(),f.reportEventChange()};this.triggerEventDrop(a,g.dateDelta,h,d,e),f.reportEventChange()},triggerEventDrop:function(a,b,c,d,e){this.trigger("eventDrop",d[0],a,b,c,e,{})},reportExternalDrop:function(b,c,d,e,f){var g,h,i=b.eventProps;i&&(g=a.extend({},i,c),h=this.calendar.renderEvent(g,b.stick)[0]),this.triggerExternalDrop(h,c,d,e,f)},triggerExternalDrop:function(a,b,c,d,e){this.trigger("drop",c[0],b.start,d,e),a&&this.trigger("eventReceive",null,a)},renderDrag:function(a,b){},unrenderDrag:function(){},isEventResizableFromStart:function(a){return this.opt("eventResizableFromStart")&&this.isEventResizable(a)},isEventResizableFromEnd:function(a){return this.isEventResizable(a)},isEventResizable:function(a){var b=a.source||{};return X(a.durationEditable,b.durationEditable,this.opt("eventDurationEditable"),a.editable,b.editable,this.opt("editable"))},reportEventResize:function(a,b,c,d,e){var f=this.calendar,g=f.mutateEvent(a,b,c),h=function(){g.undo(),f.reportEventChange()};this.triggerEventResize(a,g.durationDelta,h,d,e),f.reportEventChange()},triggerEventResize:function(a,b,c,d,e){this.trigger("eventResize",d[0],a,b,c,e,{})},select:function(a,b){this.unselect(b),this.renderSelection(a),this.reportSelection(a,b)},renderSelection:function(a){},reportSelection:function(a,b){this.isSelected=!0,this.triggerSelect(a,b)},triggerSelect:function(a,b){this.trigger("select",null,a.start,a.end,b)},unselect:function(a){this.isSelected&&(this.isSelected=!1,this.destroySelection&&this.destroySelection(),this.unrenderSelection(),this.trigger("unselect",null,a))},unrenderSelection:function(){},documentMousedown:function(b){var c;this.isSelected&&this.opt("unselectAuto")&&v(b)&&(c=this.opt("unselectCancel"),c&&a(b.target).closest(c).length||this.unselect(b))},triggerDayClick:function(a,b,c){this.trigger("dayClick",b,a.start,c)},initHiddenDays:function(){var b,c=this.opt("hiddenDays")||[],d=[],e=0;for(this.opt("weekends")===!1&&c.push(0,6),b=0;7>b;b++)(d[b]=-1!==a.inArray(b,c))||e++;if(!e)throw"invalid hiddenDays";this.isHiddenDayHash=d},isHiddenDay:function(a){return b.isMoment(a)&&(a=a.day()),this.isHiddenDayHash[a]},skipHiddenDays:function(a,b,c){var d=a.clone();for(b=b||1;this.isHiddenDayHash[(d.day()+(c?b:0)+7)%7];)d.add(b,"days");return d},computeDayRange:function(a){var b,c=a.start.clone().stripTime(),d=a.end,e=null;return d&&(e=d.clone().stripTime(),b=+d.time(),b&&b>=this.nextDayThreshold&&e.add(1,"days")),(!d||c>=e)&&(e=c.clone().add(1,"days")),{start:c,end:e}},isMultiDayEvent:function(a){var b=this.computeDayRange(a);return b.end.diff(b.start,"days")>1}}),nb=Ma.Calendar=ra.extend({dirDefaults:null,langDefaults:null,overrides:null,options:null,viewSpecCache:null,view:null,header:null,loadingLevel:0,constructor:Ga,initialize:function(){},initOptions:function(a){var b,e,f,g;a=d(a),b=a.lang,e=ob[b],e||(b=nb.defaults.lang,e=ob[b]||{}),f=X(a.isRTL,e.isRTL,nb.defaults.isRTL),g=f?nb.rtlDefaults:{},this.dirDefaults=g,this.langDefaults=e,this.overrides=a,this.options=c([nb.defaults,g,e,a]),Ha(this.options),this.viewSpecCache={}},getViewSpec:function(a){var b=this.viewSpecCache;return b[a]||(b[a]=this.buildViewSpec(a))},getUnitViewSpec:function(b){var c,d,e;if(-1!=a.inArray(b,Ra))for(c=this.header.getViewsWithButtons(),a.each(Ma.views,function(a){c.push(a)}),d=0;d<c.length;d++)if(e=this.getViewSpec(c[d]),e&&e.singleUnit==b)return e},buildViewSpec:function(a){for(var d,e,f,g,h=this.overrides.views||{},i=[],j=[],k=[],l=a;l;)d=Na[l],e=h[l],l=null,"function"==typeof d&&(d={"class":d}),d&&(i.unshift(d),j.unshift(d.defaults||{}),f=f||d.duration,l=l||d.type),e&&(k.unshift(e),f=f||e.duration,l=l||e.type);return d=Q(i),d.type=a,d["class"]?(f&&(f=b.duration(f),f.valueOf()&&(d.duration=f,g=I(f),1===f.as(g)&&(d.singleUnit=g,k.unshift(h[g]||{})))),d.defaults=c(j),d.overrides=c(k),this.buildViewSpecOptions(d),this.buildViewSpecButtonText(d,a),d):!1},buildViewSpecOptions:function(a){a.options=c([nb.defaults,a.defaults,this.dirDefaults,this.langDefaults,this.overrides,a.overrides]),Ha(a.options)},buildViewSpecButtonText:function(a,b){function c(c){var d=c.buttonText||{};return d[b]||(a.singleUnit?d[a.singleUnit]:null)}a.buttonTextOverride=c(this.overrides)||a.overrides.buttonText,a.buttonTextDefault=c(this.langDefaults)||c(this.dirDefaults)||a.defaults.buttonText||c(nb.defaults)||(a.duration?this.humanizeDuration(a.duration):null)||b},instantiateView:function(a){var b=this.getViewSpec(a);return new b["class"](this,a,b.options,b.duration)},isValidViewType:function(a){return Boolean(this.getViewSpec(a))},pushLoading:function(){this.loadingLevel++||this.trigger("loading",null,!0,this.view)},popLoading:function(){--this.loadingLevel||this.trigger("loading",null,!1,this.view)},buildSelectRange:function(a,b){return a=this.moment(a),b=b?this.moment(b):a.hasTime()?a.clone().add(this.defaultTimedEventDuration):a.clone().add(this.defaultAllDayEventDuration),{start:a,end:b}}});nb.mixin(bb),nb.defaults={titleRangeSeparator:" — ",monthYearFormat:"MMMM YYYY",defaultTimedEventDuration:"02:00:00",defaultAllDayEventDuration:{days:1},forceEventDuration:!1,nextDayThreshold:"09:00:00",defaultView:"month",aspectRatio:1.35,header:{left:"title",center:"",right:"today prev,next"},weekends:!0,weekNumbers:!1,weekNumberTitle:"W",weekNumberCalculation:"local",scrollTime:"06:00:00",lazyFetching:!0,startParam:"start",endParam:"end",timezoneParam:"timezone",timezone:!1,isRTL:!1,buttonText:{prev:"prev",next:"next",prevYear:"prev year",nextYear:"next year",year:"year",today:"today",month:"month",week:"week",day:"day"},buttonIcons:{prev:"left-single-arrow",next:"right-single-arrow",prevYear:"left-double-arrow",nextYear:"right-double-arrow"},theme:!1,themeButtonIcons:{prev:"circle-triangle-w",next:"circle-triangle-e",prevYear:"seek-prev",nextYear:"seek-next"},dragOpacity:.75,dragRevertDuration:500,dragScroll:!0,unselectAuto:!0,dropAccept:"*",eventOrder:"title",eventLimit:!1,eventLimitText:"more",eventLimitClick:"popover",dayPopoverFormat:"LL",handleWindowResize:!0,windowResizeDelay:200},nb.englishDefaults={dayPopoverFormat:"dddd, MMMM D"},nb.rtlDefaults={header:{left:"next,prev today",center:"",right:"title"},buttonIcons:{prev:"right-single-arrow",next:"left-single-arrow",prevYear:"right-double-arrow",nextYear:"left-double-arrow"},themeButtonIcons:{prev:"circle-triangle-e",next:"circle-triangle-w",nextYear:"seek-prev",prevYear:"seek-next"}};var ob=Ma.langs={};Ma.datepickerLang=function(b,c,d){var e=ob[b]||(ob[b]={});e.isRTL=d.isRTL,e.weekNumberTitle=d.weekHeader,a.each(pb,function(a,b){e[a]=b(d)}),a.datepicker&&(a.datepicker.regional[c]=a.datepicker.regional[b]=d,a.datepicker.regional.en=a.datepicker.regional[""],a.datepicker.setDefaults(d))},Ma.lang=function(b,d){var e,f;e=ob[b]||(ob[b]={}),d&&(e=ob[b]=c([e,d])),f=Ia(b),a.each(qb,function(a,b){null==e[a]&&(e[a]=b(f,e))}),nb.defaults.lang=b};var pb={buttonText:function(a){return{prev:Z(a.prevText),next:Z(a.nextText),today:Z(a.currentText)}},monthYearFormat:function(a){return a.showMonthAfterYear?"YYYY["+a.yearSuffix+"] MMMM":"MMMM YYYY["+a.yearSuffix+"]"}},qb={dayOfMonthFormat:function(a,b){var c=a.longDateFormat("l");return c=c.replace(/^Y+[^\w\s]*|[^\w\s]*Y+$/g,""),b.isRTL?c+=" ddd":c="ddd "+c,c},mediumTimeFormat:function(a){return a.longDateFormat("LT").replace(/\s*a$/i,"a")},smallTimeFormat:function(a){return a.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"a")},extraSmallTimeFormat:function(a){return a.longDateFormat("LT").replace(":mm","(:mm)").replace(/(\Wmm)$/,"($1)").replace(/\s*a$/i,"t")},hourFormat:function(a){return a.longDateFormat("LT").replace(":mm","").replace(/(\Wmm)$/,"").replace(/\s*a$/i,"a")},noMeridiemTimeFormat:function(a){return a.longDateFormat("LT").replace(/\s*a$/i,"")}},rb={smallDayDateFormat:function(a){return a.isRTL?"D dd":"dd D"},weekFormat:function(a){return a.isRTL?"w[ "+a.weekNumberTitle+"]":"["+a.weekNumberTitle+" ]w"},smallWeekFormat:function(a){return a.isRTL?"w["+a.weekNumberTitle+"]":"["+a.weekNumberTitle+"]w"}};Ma.lang("en",nb.englishDefaults),Ma.sourceNormalizers=[],Ma.sourceFetchers=[];var sb={dataType:"json",cache:!1},tb=1;nb.prototype.getPeerEvents=function(a,b){var c,d,e=this.getEventCache(),f=[];for(c=0;c<e.length;c++)d=e[c],a&&a._id===d._id||f.push(d);return f};var ub=mb.extend({dayGrid:null,dayNumbersVisible:!1,weekNumbersVisible:!1,weekNumberWidth:null,headRowEl:null,initialize:function(){this.dayGrid=new kb(this),this.coordMap=this.dayGrid.coordMap},setRange:function(a){mb.prototype.setRange.call(this,a),this.dayGrid.breakOnWeeks=/year|month|week/.test(this.intervalUnit),this.dayGrid.setRange(a)},computeRange:function(a){var b=mb.prototype.computeRange.call(this,a);return/year|month/.test(b.intervalUnit)&&(b.start.startOf("week"),b.start=this.skipHiddenDays(b.start),b.end.weekday()&&(b.end.add(1,"week").startOf("week"),b.end=this.skipHiddenDays(b.end,-1,!0))),b},renderDates:function(){this.dayNumbersVisible=this.dayGrid.rowCnt>1,this.weekNumbersVisible=this.opt("weekNumbers"),this.dayGrid.numbersVisible=this.dayNumbersVisible||this.weekNumbersVisible,this.el.addClass("fc-basic-view").html(this.renderHtml()),this.headRowEl=this.el.find("thead .fc-row"),this.scrollerEl=this.el.find(".fc-day-grid-container"),this.dayGrid.coordMap.containerEl=this.scrollerEl,this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(this.hasRigidRows())},unrenderDates:function(){this.dayGrid.unrenderDates(),this.dayGrid.removeElement()},renderBusinessHours:function(){this.dayGrid.renderBusinessHours()},renderHtml:function(){return'<table><thead class="fc-head"><tr><td class="'+this.widgetHeaderClass+'">'+this.dayGrid.headHtml()+'</td></tr></thead><tbody class="fc-body"><tr><td class="'+this.widgetContentClass+'"><div class="fc-day-grid-container"><div class="fc-day-grid"/></div></td></tr></tbody></table>'},headIntroHtml:function(){return this.weekNumbersVisible?'<th class="fc-week-number '+this.widgetHeaderClass+'" '+this.weekNumberStyleAttr()+"><span>"+Y(this.opt("weekNumberTitle"))+"</span></th>":void 0},numberIntroHtml:function(a){return this.weekNumbersVisible?'<td class="fc-week-number" '+this.weekNumberStyleAttr()+"><span>"+this.dayGrid.getCell(a,0).start.format("w")+"</span></td>":void 0},dayIntroHtml:function(){return this.weekNumbersVisible?'<td class="fc-week-number '+this.widgetContentClass+'" '+this.weekNumberStyleAttr()+"></td>":void 0},introHtml:function(){return this.weekNumbersVisible?'<td class="fc-week-number" '+this.weekNumberStyleAttr()+"></td>":void 0},numberCellHtml:function(a){var b,c=a.start;return this.dayNumbersVisible?(b=this.dayGrid.getDayClasses(c),b.unshift("fc-day-number"),'<td class="'+b.join(" ")+'" data-date="'+c.format()+'">'+c.date()+"</td>"):"<td/>"},weekNumberStyleAttr:function(){return null!==this.weekNumberWidth?'style="width:'+this.weekNumberWidth+'px"':""},hasRigidRows:function(){var a=this.opt("eventLimit");return a&&"number"!=typeof a},updateWidth:function(){this.weekNumbersVisible&&(this.weekNumberWidth=k(this.el.find(".fc-week-number")))},setHeight:function(a,b){var c,d=this.opt("eventLimit");m(this.scrollerEl),f(this.headRowEl),this.dayGrid.removeSegPopover(),d&&"number"==typeof d&&this.dayGrid.limitRows(d),c=this.computeScrollerHeight(a),this.setGridHeight(c,b),d&&"number"!=typeof d&&this.dayGrid.limitRows(d),!b&&l(this.scrollerEl,c)&&(e(this.headRowEl,r(this.scrollerEl)),c=this.computeScrollerHeight(a),this.scrollerEl.height(c))},setGridHeight:function(a,b){b?j(this.dayGrid.rowEls):i(this.dayGrid.rowEls,a,!0)},renderEvents:function(a){this.dayGrid.renderEvents(a),this.updateHeight()},getEventSegs:function(){return this.dayGrid.getEventSegs()},unrenderEvents:function(){this.dayGrid.unrenderEvents()},renderDrag:function(a,b){return this.dayGrid.renderDrag(a,b)},unrenderDrag:function(){this.dayGrid.unrenderDrag()},renderSelection:function(a){this.dayGrid.renderSelection(a)},unrenderSelection:function(){this.dayGrid.unrenderSelection()}}),vb=ub.extend({computeRange:function(a){var b,c=ub.prototype.computeRange.call(this,a);return this.isFixedWeeks()&&(b=Math.ceil(c.end.diff(c.start,"weeks",!0)),c.end.add(6-b,"weeks")),c},setGridHeight:function(a,b){b=b||"variable"===this.opt("weekMode"),b&&(a*=this.rowCnt/6),i(this.dayGrid.rowEls,a,!b)},isFixedWeeks:function(){var a=this.opt("weekMode");return a?"fixed"===a:this.opt("fixedWeekCount")}});Na.basic={"class":ub},Na.basicDay={type:"basic",duration:{days:1}},Na.basicWeek={type:"basic",duration:{weeks:1}},Na.month={"class":vb,duration:{months:1},defaults:{fixedWeekCount:!0}};var wb=mb.extend({timeGrid:null,dayGrid:null,axisWidth:null,noScrollRowEls:null,bottomRuleEl:null,bottomRuleHeight:null,initialize:function(){this.timeGrid=new lb(this),this.opt("allDaySlot")?(this.dayGrid=new kb(this),this.coordMap=new eb([this.dayGrid.coordMap,this.timeGrid.coordMap])):this.coordMap=this.timeGrid.coordMap},setRange:function(a){mb.prototype.setRange.call(this,a),this.timeGrid.setRange(a),this.dayGrid&&this.dayGrid.setRange(a)},renderDates:function(){this.el.addClass("fc-agenda-view").html(this.renderHtml()),this.scrollerEl=this.el.find(".fc-time-grid-container"),this.timeGrid.coordMap.containerEl=this.scrollerEl,this.timeGrid.setElement(this.el.find(".fc-time-grid")),this.timeGrid.renderDates(),this.bottomRuleEl=a('<hr class="fc-divider '+this.widgetHeaderClass+'"/>').appendTo(this.timeGrid.el),this.dayGrid&&(this.dayGrid.setElement(this.el.find(".fc-day-grid")),this.dayGrid.renderDates(),this.dayGrid.bottomCoordPadding=this.dayGrid.el.next("hr").outerHeight()),this.noScrollRowEls=this.el.find(".fc-row:not(.fc-scroller *)")},unrenderDates:function(){this.timeGrid.unrenderDates(),this.timeGrid.removeElement(),this.dayGrid&&(this.dayGrid.unrenderDates(),this.dayGrid.removeElement())},renderBusinessHours:function(){this.timeGrid.renderBusinessHours(),this.dayGrid&&this.dayGrid.renderBusinessHours()},renderHtml:function(){return'<table><thead class="fc-head"><tr><td class="'+this.widgetHeaderClass+'">'+this.timeGrid.headHtml()+'</td></tr></thead><tbody class="fc-body"><tr><td class="'+this.widgetContentClass+'">'+(this.dayGrid?'<div class="fc-day-grid"/><hr class="fc-divider '+this.widgetHeaderClass+'"/>':"")+'<div class="fc-time-grid-container"><div class="fc-time-grid"/></div></td></tr></tbody></table>'},headIntroHtml:function(){var a,b;return this.opt("weekNumbers")?(a=this.timeGrid.getCell(0).start,b=a.format(this.opt("smallWeekFormat")),'<th class="fc-axis fc-week-number '+this.widgetHeaderClass+'" '+this.axisStyleAttr()+"><span>"+Y(b)+"</span></th>"):'<th class="fc-axis '+this.widgetHeaderClass+'" '+this.axisStyleAttr()+"></th>"},dayIntroHtml:function(){return'<td class="fc-axis '+this.widgetContentClass+'" '+this.axisStyleAttr()+"><span>"+(this.opt("allDayHtml")||Y(this.opt("allDayText")))+"</span></td>"},slotBgIntroHtml:function(){return'<td class="fc-axis '+this.widgetContentClass+'" '+this.axisStyleAttr()+"></td>";
9
  },introHtml:function(){return'<td class="fc-axis" '+this.axisStyleAttr()+"></td>"},axisStyleAttr:function(){return null!==this.axisWidth?'style="width:'+this.axisWidth+'px"':""},updateSize:function(a){this.timeGrid.updateSize(a),mb.prototype.updateSize.call(this,a)},updateWidth:function(){this.axisWidth=k(this.el.find(".fc-axis"))},setHeight:function(a,b){var c,d;null===this.bottomRuleHeight&&(this.bottomRuleHeight=this.bottomRuleEl.outerHeight()),this.bottomRuleEl.hide(),this.scrollerEl.css("overflow",""),m(this.scrollerEl),f(this.noScrollRowEls),this.dayGrid&&(this.dayGrid.removeSegPopover(),c=this.opt("eventLimit"),c&&"number"!=typeof c&&(c=xb),c&&this.dayGrid.limitRows(c)),b||(d=this.computeScrollerHeight(a),l(this.scrollerEl,d)?(e(this.noScrollRowEls,r(this.scrollerEl)),d=this.computeScrollerHeight(a),this.scrollerEl.height(d)):(this.scrollerEl.height(d).css("overflow","hidden"),this.bottomRuleEl.show()))},computeInitialScroll:function(){var a=b.duration(this.opt("scrollTime")),c=this.timeGrid.computeTimeTop(a);return c=Math.ceil(c),c&&c++,c},renderEvents:function(a){var b,c,d=[],e=[],f=[];for(c=0;c<a.length;c++)a[c].allDay?d.push(a[c]):e.push(a[c]);b=this.timeGrid.renderEvents(e),this.dayGrid&&(f=this.dayGrid.renderEvents(d)),this.updateHeight()},getEventSegs:function(){return this.timeGrid.getEventSegs().concat(this.dayGrid?this.dayGrid.getEventSegs():[])},unrenderEvents:function(){this.timeGrid.unrenderEvents(),this.dayGrid&&this.dayGrid.unrenderEvents()},renderDrag:function(a,b){return a.start.hasTime()?this.timeGrid.renderDrag(a,b):this.dayGrid?this.dayGrid.renderDrag(a,b):void 0},unrenderDrag:function(){this.timeGrid.unrenderDrag(),this.dayGrid&&this.dayGrid.unrenderDrag()},renderSelection:function(a){a.start.hasTime()||a.end.hasTime()?this.timeGrid.renderSelection(a):this.dayGrid&&this.dayGrid.renderSelection(a)},unrenderSelection:function(){this.timeGrid.unrenderSelection(),this.dayGrid&&this.dayGrid.unrenderSelection()}}),xb=5,yb=[{hours:1},{minutes:30},{minutes:15},{seconds:30},{seconds:15}];return Na.agenda={"class":wb,defaults:{allDaySlot:!0,allDayText:"all-day",slotDuration:"00:30:00",minTime:"00:00:00",maxTime:"24:00:00",slotEventOverlap:!0}},Na.agendaDay={type:"agenda",duration:{days:1}},Na.agendaWeek={type:"agenda",duration:{weeks:1}},Ma});
backend/modules/calendar/templates/calendar.php CHANGED
@@ -3,101 +3,103 @@ use Bookly\Lib\Utils\Common;
3
  use Bookly\Backend\Components;
4
  use Bookly\Backend\Modules as Backend;
5
  use Bookly\Backend\Modules\Calendar\Proxy;
6
- /** @var Bookly\Lib\Entities\Staff[] $staff_members */
 
 
 
7
  ?>
8
  <style>
9
  .fc-slats tr { height: <?php echo max( 21, (int) ( 0.43 * get_option( 'bookly_gen_time_slot_length' ) ) ) ?>px; }
10
  .fc-time-grid-event.fc-short .fc-time::after { content: '' !important; }
11
  </style>
12
  <div id="bookly-tbs" class="wrap">
13
- <div class="bookly-tbs-body">
14
- <div class="page-header text-right clearfix">
15
- <div class="bookly-page-title">
16
- <?php _e( 'Calendar', 'bookly' ) ?>
17
- </div>
18
- <?php if ( Common::isCurrentUserSupervisor() ) : ?>
19
- <?php Components\Support\Buttons::render( $self::pageSlug() ) ?>
20
- <?php endif ?>
21
- </div>
22
- <div class="panel panel-default bookly-main bookly-fc-inner">
23
- <div class="panel-body">
24
  <?php if ( $staff_members ) : ?>
25
- <ul class="bookly-nav bookly-nav-tabs">
26
- <?php if ( Common::isCurrentUserSupervisor() ) : ?>
27
- <li class="bookly-nav-item bookly-js-calendar-tab" data-staff_id="0">
28
- <?php _e( 'All', 'bookly' ) ?>
29
- </li>
30
- <?php endif ?>
31
- <?php foreach ( $staff_members as $staff ) : ?>
32
- <li class="bookly-nav-item bookly-js-calendar-tab" data-staff_id="<?php echo $staff->getId() ?>" style="display: none">
33
- <?php echo esc_html( $staff->getFullName() ) ?>
34
- </li>
35
- <?php endforeach ?>
36
- <?php if ( Common::isCurrentUserSupervisor() ) : ?>
37
- <ul id="bookly-js-staff-filter"
38
- data-container-class="pull-right bookly-margin-top-xs"
39
- data-txt-select-all="<?php esc_attr_e( 'All staff', 'bookly' ) ?>"
40
- data-txt-all-selected="<?php esc_attr_e( 'All staff', 'bookly' ) ?>"
41
- data-txt-nothing-selected="<?php esc_attr_e( 'No staff selected', 'bookly' ) ?>"
42
- >
43
- <?php foreach ( $staff_dropdown_data as $category_id => $category ): ?>
44
- <li<?php if ( ! $category_id ) : ?> data-flatten-if-single<?php endif ?>><?php echo esc_html( $category['name'] ) ?>
45
- <ul>
46
- <?php foreach ( $category['items'] as $staff ) : ?>
47
- <li data-value="<?php echo $staff['id'] ?>">
48
- <?php echo esc_html( $staff['full_name'] ) ?>
49
- </li>
50
- <?php endforeach ?>
51
- </ul>
52
- </li>
53
- <?php endforeach ?>
54
- </ul>
55
- <?php endif ?>
56
- <?php Proxy\Locations::renderCalendarLocationFilter() ?>
57
- <?php Proxy\AdvancedGoogleCalendar::renderSyncButton( $staff_members ) ?>
58
  <?php Proxy\OutlookCalendar::renderSyncButton( $staff_members ) ?>
59
- </ul>
60
- <?php endif ?>
61
- <div class="bookly-margin-top-xlg">
62
- <?php if ( $staff_members ) : ?>
63
- <div class="fc-loading-inner" style="display: none">
64
- <div class="fc-loading"></div>
65
- </div>
66
- <div id="bookly-fc-wrapper" class="bookly-calendar">
67
- <div class="bookly-js-calendar-element"></div>
68
- </div>
69
- <?php Components\Dialogs\Appointment\Edit\Dialog::render() ?>
70
- <?php Proxy\Shared::renderAddOnsComponents() ?>
71
- <?php elseif( Bookly\Lib\Config::proActive() ) : ?>
72
- <?php Components\Notices\Proxy\Pro::renderWelcome() ?>
73
- <?php else : ?>
74
- <div class="well">
75
- <div class="h1"><?php esc_html_e( 'Welcome to Bookly and thank you for your choice!', 'bookly' ) ?></div>
76
- <h3><?php esc_html_e( 'Bookly will simplify the booking process for your customers. This plugin creates another touchpoint to convert your visitors into customers. With Bookly your clients can see your availability, pick the services you provide, book them online and much more.', 'bookly' ) ?></h3>
77
- <p><?php esc_html_e( 'To start using Bookly, you need to set up the services you provide and specify the staff members who will provide those services.', 'bookly' ) ?></p>
78
- <ol>
79
- <li><?php esc_html_e( 'Add a staff member (you can add only one service provider with a free version of Bookly).', 'bookly' ) ?></li>
80
- <li><?php esc_html_e( 'Add services you provide (up to five with a free version of Bookly) and assign them to a staff member.', 'bookly' ) ?></li>
81
- <li><?php esc_html_e( 'Go to Posts/Pages and click on the “Add Bookly booking form” button in the page editor to publish the booking form on your website.', 'bookly' ) ?></li>
82
- </ol>
83
- <p><?php printf( __( 'Bookly can boost your sales and scale together with your business. Get more features and remove the limits by upgrading to the paid version with the <a href="%s" target="_blank">Bookly Pro add-on</a>, which allows you to use a vast number of additional features and settings for booking services, install other add-ons for Bookly, and includes six months of customer support.', 'bookly' ), Common::prepareUrlReferrers( 'https://codecanyon.net/item/bookly/7226091?ref=ladela', 'welcome' ) ) ?></p>
84
- <hr>
85
- <a class="btn btn-success" href="<?php echo Common::escAdminUrl( Backend\Staff\Ajax::pageSlug() ) ?>">
86
- <?php esc_html_e( 'Add Staff Members', 'bookly' ) ?>
87
- </a>
88
- <a class="btn btn-success" href="<?php echo Common::escAdminUrl( Backend\Services\Ajax::pageSlug() ) ?>">
89
- <?php esc_html_e( 'Add Services', 'bookly' ) ?>
90
- </a>
91
- <a class="btn btn-success" href="<?php echo Common::prepareUrlReferrers( 'https://codecanyon.net/item/bookly/7226091?ref=ladela', 'welcome' ) ?>" target="_blank">
92
- <?php esc_html_e( 'Try Bookly Pro add-on', 'bookly' ) ?>
93
- </a>
94
  </div>
95
  <?php endif ?>
96
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  </div>
98
  </div>
99
-
100
- <?php Components\Dialogs\Appointment\Delete\Dialog::render() ?>
101
- <?php Components\Dialogs\Queue\Dialog::render() ?>
102
  </div>
 
 
 
103
  </div>
3
  use Bookly\Backend\Components;
4
  use Bookly\Backend\Modules as Backend;
5
  use Bookly\Backend\Modules\Calendar\Proxy;
6
+ /**
7
+ * @var Bookly\Lib\Entities\Staff[] $staff_members
8
+ * @var array $staff_dropdown_data
9
+ */
10
  ?>
11
  <style>
12
  .fc-slats tr { height: <?php echo max( 21, (int) ( 0.43 * get_option( 'bookly_gen_time_slot_length' ) ) ) ?>px; }
13
  .fc-time-grid-event.fc-short .fc-time::after { content: '' !important; }
14
  </style>
15
  <div id="bookly-tbs" class="wrap">
16
+ <div class="form-row align-items-center mb-3">
17
+ <h4 class="col m-0"><?php esc_html_e( 'Calendar', 'bookly' ) ?></h4>
18
+ <?php if ( Common::isCurrentUserSupervisor() ) : ?>
19
+ <?php Components\Support\Buttons::render( $self::pageSlug() ) ?>
20
+ <?php endif ?>
21
+ </div>
22
+ <div class="card">
23
+ <div class="card-body">
24
+ <div class="form-row justify-content-center justify-content-md-end">
 
 
25
  <?php if ( $staff_members ) : ?>
26
+ <ul class="col-auto nav nav-pills bookly-js-calendar-tabs">
27
+ <?php if ( Common::isCurrentUserSupervisor() ) : ?>
28
+ <li class="nav-item mr-2 mb-2">
29
+ <a class="nav-link" href="#" data-staff_id="0"><?php esc_html_e( 'All', 'bookly' ) ?></a>
30
+ </li>
31
+ <?php endif ?>
32
+ <?php foreach ( $staff_members as $staff ) : ?>
33
+ <li class="nav-item mr-2 mb-2" style="display: none">
34
+ <a class="nav-link" href="#" data-staff_id="<?php echo $staff->getId() ?>"><?php echo esc_html( $staff->getFullName() ) ?></a>
35
+ </li>
36
+ <?php endforeach ?>
37
+ </ul>
38
+ <div class="col-auto col-md"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  <?php Proxy\OutlookCalendar::renderSyncButton( $staff_members ) ?>
40
+ <?php Proxy\AdvancedGoogleCalendar::renderSyncButton( $staff_members ) ?>
41
+ <?php Proxy\Locations::renderCalendarLocationFilter() ?>
42
+ <?php if ( Common::isCurrentUserSupervisor() ) : ?>
43
+ <div class="col-auto mb-2">
44
+ <ul id="bookly-js-staff-filter"
45
+ data-align="right"
46
+ data-txt-select-all="<?php esc_attr_e( 'All staff', 'bookly' ) ?>"
47
+ data-txt-all-selected="<?php esc_attr_e( 'All staff', 'bookly' ) ?>"
48
+ data-txt-nothing-selected="<?php esc_attr_e( 'No staff selected', 'bookly' ) ?>"
49
+ >
50
+ <?php foreach ( $staff_dropdown_data as $category_id => $category ): ?>
51
+ <li<?php if ( ! $category_id ) : ?> data-flatten-if-single<?php endif ?>><?php echo esc_html( $category['name'] ) ?>
52
+ <ul>
53
+ <?php foreach ( $category['items'] as $staff ) : ?>
54
+ <li data-value="<?php echo $staff['id'] ?>">
55
+ <?php echo esc_html( $staff['full_name'] ) ?>
56
+ </li>
57
+ <?php endforeach ?>
58
+ </ul>
59
+ </li>
60
+ <?php endforeach ?>
61
+ </ul>
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  </div>
63
  <?php endif ?>
64
+ <?php endif ?>
65
+ </div>
66
+ <div class="mt-3 position-relative">
67
+ <?php if ( $staff_members ) : ?>
68
+ <div class="bookly-fc-loading" style="display: none">
69
+ <div class="bookly-fc-loading-icon"></div>
70
+ </div>
71
+ <div class="bookly-js-calendar"></div>
72
+ <?php Components\Dialogs\Appointment\Edit\Dialog::render() ?>
73
+ <?php Proxy\Shared::renderAddOnsComponents() ?>
74
+ <?php elseif( Bookly\Lib\Config::proActive() ) : ?>
75
+ <?php Components\Notices\Proxy\Pro::renderWelcome() ?>
76
+ <?php else : ?>
77
+ <div class="m-3">
78
+ <div class="h1"><?php esc_html_e( 'Welcome to Bookly and thank you for your choice!', 'bookly' ) ?></div>
79
+ <h4><?php esc_html_e( 'Bookly will simplify the booking process for your customers. This plugin creates another touchpoint to convert your visitors into customers. With Bookly your clients can see your availability, pick the services you provide, book them online and much more.', 'bookly' ) ?></h4>
80
+ <p><?php esc_html_e( 'To start using Bookly, you need to set up the services you provide and specify the staff members who will provide those services.', 'bookly' ) ?></p>
81
+ <ol>
82
+ <li><?php esc_html_e( 'Add a staff member (you can add only one service provider with a free version of Bookly).', 'bookly' ) ?></li>
83
+ <li><?php esc_html_e( 'Add services you provide (up to five with a free version of Bookly) and assign them to a staff member.', 'bookly' ) ?></li>
84
+ <li><?php esc_html_e( 'Go to Posts/Pages and click on the “Add Bookly booking form” button in the page editor to publish the booking form on your website.', 'bookly' ) ?></li>
85
+ </ol>
86
+ <p><?php printf( __( 'Bookly can boost your sales and scale together with your business. Get more features and remove the limits by upgrading to the paid version with the <a href="%s" target="_blank">Bookly Pro add-on</a>, which allows you to use a vast number of additional features and settings for booking services, install other add-ons for Bookly, and includes six months of customer support.', 'bookly' ), Common::prepareUrlReferrers( 'https://codecanyon.net/item/bookly/7226091?ref=ladela', 'welcome' ) ) ?></p>
87
+ <hr>
88
+ <a class="btn btn-success" href="<?php echo Common::escAdminUrl( Backend\Staff\Ajax::pageSlug() ) ?>">
89
+ <?php esc_html_e( 'Add Staff Members', 'bookly' ) ?>
90
+ </a>
91
+ <a class="btn btn-success" href="<?php echo Common::escAdminUrl( Backend\Services\Ajax::pageSlug() ) ?>">
92
+ <?php esc_html_e( 'Add Services', 'bookly' ) ?>
93
+ </a>
94
+ <a class="btn btn-success" href="<?php echo Common::prepareUrlReferrers( 'https://codecanyon.net/item/bookly/7226091?ref=ladela', 'welcome' ) ?>" target="_blank">
95
+ <?php esc_html_e( 'Try Bookly Pro add-on', 'bookly' ) ?>
96
+ </a>
97
+ </div>
98
+ <?php endif ?>
99
  </div>
100
  </div>
 
 
 
101
  </div>
102
+
103
+ <?php Components\Dialogs\Appointment\Delete\Dialog::render() ?>
104
+ <?php Components\Dialogs\Queue\Dialog::render() ?>
105
  </div>
backend/modules/customers/Page.php CHANGED
@@ -19,7 +19,7 @@ class Page extends Lib\Base\Component
19
  }
20
 
21
  self::enqueueStyles( array(
22
- 'backend' => array( 'bootstrap/css/bootstrap-theme.min.css', ),
23
  'frontend' => array( 'css/ladda.min.css', ),
24
  ) );
25
 
19
  }
20
 
21
  self::enqueueStyles( array(
22
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
23
  'frontend' => array( 'css/ladda.min.css', ),
24
  ) );
25
 
backend/modules/customers/proxy/CustomerGroups.php CHANGED
@@ -10,7 +10,6 @@ use Bookly\Lib;
10
  * @method static array prepareCustomerListData( array $data, array $row ) Prepare 'Customer Groups' data in customers table.
11
  * @method static Lib\Query prepareCustomerQuery( Lib\Query $query ) Prepare 'Customer Groups' query in customers table.
12
  * @method static string prepareCustomerSelect( string $select ) Prepare 'Customer Groups' select in customers table.
13
- * @method static array prepareExportTitles( array $titles ) Prepare 'Customer Groups' titles in customers export.
14
  */
15
  abstract class CustomerGroups extends Lib\Base\Proxy
16
  {
10
  * @method static array prepareCustomerListData( array $data, array $row ) Prepare 'Customer Groups' data in customers table.
11
  * @method static Lib\Query prepareCustomerQuery( Lib\Query $query ) Prepare 'Customer Groups' query in customers table.
12
  * @method static string prepareCustomerSelect( string $select ) Prepare 'Customer Groups' select in customers table.
 
13
  */
14
  abstract class CustomerGroups extends Lib\Base\Proxy
15
  {
backend/modules/customers/resources/js/customers.js CHANGED
@@ -8,9 +8,9 @@ jQuery(function($) {
8
  $checkAllButton = $('#bookly-check-all'),
9
  $customerDialog = $('#bookly-customer-dialog'),
10
  $selectForMergeButton = $('#bookly-select-for-merge'),
11
- $mergeWithButton = $('#bookly-merge-dialog-activator'),
12
  $mergeDialog = $('#bookly-merge-dialog'),
13
- $mergeButton = $('#bookly-merge'),
14
  columns = [],
15
  order = [],
16
  row
@@ -42,8 +42,10 @@ jQuery(function($) {
42
  break;
43
  default:
44
  if (column.startsWith('info_fields_')) {
 
 
45
  columns.push({
46
- data: column.replace(/_([^_]*)$/, '.$1.value'),
47
  render: $.fn.dataTable.render.text(),
48
  orderable: false
49
  });
@@ -89,24 +91,26 @@ jQuery(function($) {
89
  columns: columns.concat([
90
  {
91
  responsivePriority: 1,
92
- orderable : false,
93
- searchable : false,
94
- render : function (data, type, row, meta) {
95
- return '<button type="button" class="btn btn-default" data-action="edit"><i class="glyphicon glyphicon-edit"></i> ' + BooklyL10n.edit + '</button>';
 
96
  }
97
  },
98
  {
99
  responsivePriority: 1,
100
- orderable : false,
101
- searchable : false,
102
- render : function (data, type, row, meta) {
103
- return '<input type="checkbox" value="' + row.id + '" />';
 
 
 
104
  }
105
  }
106
  ]),
107
- dom: "<'row'<'col-sm-6'l><'col-sm-6'f>>" +
108
- "<'row'<'col-sm-12'tr>>" +
109
- "<'row pull-left'<'col-sm-12 bookly-margin-top-lg'p>>",
110
  language: {
111
  zeroRecords: BooklyL10n.zeroRecords,
112
  processing: BooklyL10n.processing
@@ -129,7 +133,7 @@ jQuery(function($) {
129
  // Edit customer.
130
  .on('click', '[data-action=edit]', function () {
131
  row = dt.row($(this).closest('td'));
132
- $customerDialog.modal('show');
133
  });
134
 
135
  /**
@@ -170,8 +174,9 @@ jQuery(function($) {
170
  $title.text(BooklyL10n.new_customer);
171
  $button.text(BooklyL10n.create_customer);
172
  }
 
173
 
174
- var $scope = angular.element(this).scope();
175
  $scope.$apply(function ($scope) {
176
  $scope.customer = customer;
177
  setTimeout(function () {
@@ -206,7 +211,7 @@ jQuery(function($) {
206
  orderable : false,
207
  searchable : false,
208
  render : function (data, type, row, meta) {
209
- return '<button type="button" class="btn btn-default"><i class="glyphicon glyphicon-remove"></i></button>';
210
  }
211
  }
212
  ]),
@@ -238,8 +243,9 @@ jQuery(function($) {
238
  /**
239
  * Merge customers.
240
  */
241
- $mergeButton.on('click', function () {
242
- var ladda = Ladda.create(this),
 
243
  ids = [];
244
  ladda.start();
245
  mdt.rows().every(function () {
@@ -257,7 +263,7 @@ jQuery(function($) {
257
  dataType : 'json',
258
  success : function(response) {
259
  ladda.stop();
260
- $mergeDialog.modal('hide');
261
  if (response.success) {
262
  dt.ajax.reload(null, false);
263
  mdt.clear();
@@ -289,7 +295,7 @@ jQuery(function($) {
289
  });
290
 
291
  (function() {
292
- var module = angular.module('customer', ['customerDialog']);
293
  module.controller('customerCtrl', function($scope) {
294
  $scope.customer = {
295
  id : '',
@@ -311,7 +317,9 @@ jQuery(function($) {
311
  birthday : ''
312
  };
313
  $scope.saveCustomer = function(customer) {
314
- jQuery('#bookly-customers-list').DataTable().ajax.reload(null, false);
 
 
315
  };
316
  });
317
  })();
8
  $checkAllButton = $('#bookly-check-all'),
9
  $customerDialog = $('#bookly-customer-dialog'),
10
  $selectForMergeButton = $('#bookly-select-for-merge'),
11
+ $mergeWithButton = $('[data-target=#bookly-merge-dialog]'),
12
  $mergeDialog = $('#bookly-merge-dialog'),
13
+ $mergeButton = $('#bookly-merge',$mergeDialog),
14
  columns = [],
15
  order = [],
16
  row
42
  break;
43
  default:
44
  if (column.startsWith('info_fields_')) {
45
+ const id = parseInt(column.split('_').pop());
46
+ const field = BooklyL10n.infoFields.find( i => i.id === id);
47
  columns.push({
48
+ data: 'info_fields.' + id + '.value' + (field.type === 'checkboxes' ? '[, ]' : ''),
49
  render: $.fn.dataTable.render.text(),
50
  orderable: false
51
  });
91
  columns: columns.concat([
92
  {
93
  responsivePriority: 1,
94
+ orderable : false,
95
+ searchable : false,
96
+ width : 120,
97
+ render : function (data, type, row, meta) {
98
+ return '<button type="button" class="btn btn-default" data-action="edit"><i class="far fa-fw fa-edit mr-1"></i>' + BooklyL10n.edit + '…</button>';
99
  }
100
  },
101
  {
102
  responsivePriority: 1,
103
+ orderable : false,
104
+ searchable : false,
105
+ render : function (data, type, row, meta) {
106
+ return '<div class="custom-control custom-checkbox">' +
107
+ '<input value="' + row.id + '" id="bookly-dt-' + row.id + '" type="checkbox" class="custom-control-input">' +
108
+ '<label for="bookly-dt-' + row.id + '" class="custom-control-label"></label>' +
109
+ '</div>';
110
  }
111
  }
112
  ]),
113
+ dom : "<'row'<'col-sm-12'tr>><'row float-left mt-3'<'col-sm-12'p>>",
 
 
114
  language: {
115
  zeroRecords: BooklyL10n.zeroRecords,
116
  processing: BooklyL10n.processing
133
  // Edit customer.
134
  .on('click', '[data-action=edit]', function () {
135
  row = dt.row($(this).closest('td'));
136
+ $customerDialog.booklyModal('show');
137
  });
138
 
139
  /**
174
  $title.text(BooklyL10n.new_customer);
175
  $button.text(BooklyL10n.create_customer);
176
  }
177
+ customer.birthday = customer.birthday === null ? customer.birthday : moment(customer.birthday);
178
 
179
+ var $scope = booklyAngular.element(this).scope();
180
  $scope.$apply(function ($scope) {
181
  $scope.customer = customer;
182
  setTimeout(function () {
211
  orderable : false,
212
  searchable : false,
213
  render : function (data, type, row, meta) {
214
+ return '<button type="button" class="btn btn-default"><i class="fas fa-fw fa-times"></i></button>';
215
  }
216
  }
217
  ]),
243
  /**
244
  * Merge customers.
245
  */
246
+ $mergeButton.on('click', function (e) {
247
+ e.preventDefault();
248
+ let ladda = Ladda.create(this),
249
  ids = [];
250
  ladda.start();
251
  mdt.rows().every(function () {
263
  dataType : 'json',
264
  success : function(response) {
265
  ladda.stop();
266
+ $mergeDialog.booklyModal('hide');
267
  if (response.success) {
268
  dt.ajax.reload(null, false);
269
  mdt.clear();
295
  });
296
 
297
  (function() {
298
+ var module = booklyAngular.module('customer', ['customerDialog']);
299
  module.controller('customerCtrl', function($scope) {
300
  $scope.customer = {
301
  id : '',
317
  birthday : ''
318
  };
319
  $scope.saveCustomer = function(customer) {
320
+ jQuery('#bookly-customers-list').DataTable().ajax.reload(function () {
321
+ jQuery('#bookly-customers-list').DataTable().responsive.recalc();
322
+ }, false);
323
  };
324
  });
325
  })();
backend/modules/customers/templates/index.php CHANGED
@@ -1,98 +1,97 @@
1
- <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
 
 
2
  use Bookly\Backend\Components\Controls\Buttons;
 
3
  use Bookly\Backend\Components\Dialogs;
4
  use Bookly\Backend\Components\Support;
5
  use Bookly\Backend\Modules\Customers\Proxy;
6
  /** @var array $datatables */
7
  ?>
8
  <div id="bookly-tbs" class="wrap">
9
- <div class="bookly-tbs-body">
10
- <div class="page-header text-right clearfix">
11
- <div class="bookly-page-title">
12
- <?php esc_html_e( 'Customers', 'bookly' ) ?>
13
- </div>
14
- <?php Support\Buttons::render( $self::pageSlug() ) ?>
15
- </div>
16
- <div class="panel panel-default bookly-main">
17
- <div class="panel-body">
18
- <div class="row">
19
- <div class="col-md-4">
20
- <div class="form-group">
21
- <input class="form-control" type="text" id="bookly-filter" placeholder="<?php esc_attr_e( 'Quick search customer', 'bookly' ) ?>" />
22
- </div>
23
  </div>
24
- <div class="col-md-8 form-inline bookly-margin-bottom-lg text-right">
25
- <?php
26
- Proxy\Pro::renderExportButton();
27
- Proxy\Pro::renderImportButton();
28
- ?>
29
- <div class="form-group">
30
- <?php Buttons::renderModalActivator( 'bookly-customer-dialog', 'btn-success bookly-btn-block-xs', esc_html__( 'New customer', 'bookly' ), array(), '<i class="glyphicon glyphicon-plus"></i> {caption}' ) ?>
31
- </div>
32
- <?php Dialogs\TableSettings\Dialog::renderButton( 'customers' ) ?>
33
  </div>
 
34
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
- <table id="bookly-customers-list" class="table table-striped" width="100%">
37
- <thead>
38
- <tr>
39
- <?php foreach ( $datatables['customers']['settings']['columns'] as $column => $show ) : ?>
40
- <?php if ( $show ) : ?>
41
- <th><?php echo $datatables['customers']['titles'][ $column ] ?></th>
42
- <?php endif ?>
43
- <?php endforeach ?>
44
- <th></th>
45
- <th width="16"><input type="checkbox" id="bookly-check-all"/></th>
46
- </tr>
47
- </thead>
48
- </table>
49
-
50
- <div class="text-right form-inline bookly-margin-top-lg">
51
- <div class="form-group">
52
- <?php Buttons::renderModalActivator( 'bookly-merge-dialog', null, esc_html__( 'Merge with', 'bookly' ), array( 'disabled' => 'disabled', 'style' => 'display:none' ), '<i class="glyphicon glyphicon-road"></i> {caption}' ) ?>
53
- </div>
54
- <div class="form-group">
55
- <button type="button" id="bookly-select-for-merge" class="btn btn-default"><i class="glyphicon glyphicon-plus"></i> <?php esc_html_e( 'Select for merge', 'bookly' ) ?></button>
56
- </div>
57
- <div class="form-group">
58
- <?php Dialogs\Customer\Delete\Dialog::renderDeleteButton() ?>
59
  </div>
60
- </div>
61
 
62
- <div id="bookly-merge-list" class="bookly-margin-top-xlg" style="display:none">
63
- <h4><?php esc_html_e( 'Merge list', 'bookly' ) ?></h4>
 
64
  </div>
65
  </div>
66
  </div>
67
 
68
- <?php
69
- Proxy\Pro::renderImportDialog();
70
- Proxy\Pro::renderExportDialog( $datatables['customers']['settings'], $datatables['customers']['titles'] );
71
- Dialogs\Customer\Delete\Dialog::render();
72
- ?>
73
 
74
- <div id="bookly-merge-dialog" class="modal fade" tabindex=-1 role="dialog">
75
  <div class="modal-dialog">
76
  <div class="modal-content">
77
  <div class="modal-header">
78
- <button type="button" class="close" data-dismiss="modal"><span>&times;</span></button>
79
- <div class="modal-title h2"><?php _e( 'Merge customers', 'bookly' ) ?></div>
80
  </div>
81
  <div class="modal-body">
82
  <?php esc_html_e( 'You are about to merge customers from the merge list with the selected one. This will result in losing the merged customers and moving all their appointments to the selected customer. Are you sure you want to continue?', 'bookly' ) ?>
83
  </div>
84
  <div class="modal-footer">
85
- <?php Buttons::renderCustom( 'bookly-merge', 'btn-danger btn-lg', esc_html__( 'Merge', 'bookly' ), array(), '<span class="ladda-label"><i class="glyphicon glyphicon-road"></i> {caption}</span>' ) ?>
86
- <?php Buttons::renderCustom( null, 'btn-default btn-lg', __( 'Cancel', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
87
  </div>
88
  </div>
89
  </div>
90
  </div>
91
 
92
- <div ng-app="customer" ng-controller="customerCtrl">
93
  <div customer-dialog=saveCustomer(customer) customer="customer"></div>
94
  <?php Dialogs\Customer\Edit\Dialog::render() ?>
95
  </div>
96
  <?php Dialogs\TableSettings\Dialog::render() ?>
97
  </div>
 
98
  </div>
1
+ <?php if ( ! defined( 'ABSPATH' ) ) {
2
+ exit;
3
+ } // Exit if accessed directly
4
  use Bookly\Backend\Components\Controls\Buttons;
5
+ use Bookly\Backend\Components\Controls\Inputs;
6
  use Bookly\Backend\Components\Dialogs;
7
  use Bookly\Backend\Components\Support;
8
  use Bookly\Backend\Modules\Customers\Proxy;
9
  /** @var array $datatables */
10
  ?>
11
  <div id="bookly-tbs" class="wrap">
12
+ <div class="form-row align-items-center mb-3">
13
+ <h4 class="col m-0"><?php esc_html_e( 'Customers', 'bookly' ) ?></h4>
14
+ <?php Support\Buttons::render( $self::pageSlug() ) ?>
15
+ </div>
16
+ <div class="card">
17
+ <div class="card-body">
18
+ <div class="row">
19
+ <div class="col-md-4">
20
+ <div class="form-group">
21
+ <input class="form-control" type="text" id="bookly-filter" placeholder="<?php esc_attr_e( 'Quick search services', 'bookly' ) ?>"/>
 
 
 
 
22
  </div>
23
+ </div>
24
+ <div class="col-md-8 form-row justify-content-end pr-0">
25
+ <?php Proxy\Pro::renderExportButton() ?>
26
+ <?php Proxy\Pro::renderImportButton() ?>
27
+ <div class="col-auto">
28
+ <button type="button" class="btn btn-success" data-toggle="bookly-modal" data-target="#bookly-customer-dialog"><i class="fas fa-fw fa-plus"></i> <?php esc_html_e( 'New customer', 'bookly' ) ?>…</button>
 
 
 
29
  </div>
30
+ <?php Dialogs\TableSettings\Dialog::renderButton( 'customers' ) ?>
31
  </div>
32
+ </div>
33
+ <div class="row">
34
+ <div class="col">
35
+ <table id="bookly-customers-list" class="table table-striped w-100">
36
+ <thead>
37
+ <tr>
38
+ <?php foreach ( $datatables['customers']['settings']['columns'] as $column => $show ) : ?>
39
+ <?php if ( $show ) : ?>
40
+ <th><?php echo $datatables['customers']['titles'][ $column ] ?></th>
41
+ <?php endif ?>
42
+ <?php endforeach ?>
43
+ <th></th>
44
+ <th width="16"><?php Inputs::renderCheckBox( null, null, null, array( 'id' => 'bookly-check-all' ) ) ?></th>
45
+ </tr>
46
+ </thead>
47
+ </table>
48
 
49
+ <div class="form-row justify-content-end mt-3">
50
+ <div class="col-auto">
51
+ <button type="button" id="bookly-merge-with" class="btn btn-default" data-toggle="bookly-modal" data-target="#bookly-merge-dialog" disabled="disabled" style="display:none"><i class="fas fa-fw fa-road mr-1"></i><?php esc_html_e( 'Merge with', 'bookly' ) ?>…</button>
52
+ </div>
53
+ <div class="col-auto">
54
+ <button type="button" id="bookly-select-for-merge" class="btn btn-default"><i class="fas fa-fw fa-plus mr-1"></i><?php esc_html_e( 'Select for merge', 'bookly' ) ?>…</button>
55
+ </div>
56
+ <div class="col-auto pr-0">
57
+ <?php Dialogs\Customer\Delete\Dialog::renderDeleteButton() ?>
58
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  </div>
 
60
 
61
+ <div id="bookly-merge-list" class="mt-3" style="display:none">
62
+ <h4><?php esc_html_e( 'Merge list', 'bookly' ) ?></h4>
63
+ </div>
64
  </div>
65
  </div>
66
  </div>
67
 
68
+ <?php Proxy\Pro::renderImportDialog() ?>
69
+ <?php Proxy\Pro::renderExportDialog( $datatables['customers']['settings'], $datatables['customers']['titles'] ) ?>
70
+ <?php Dialogs\Customer\Delete\Dialog::render() ?>
 
 
71
 
72
+ <div id="bookly-merge-dialog" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
73
  <div class="modal-dialog">
74
  <div class="modal-content">
75
  <div class="modal-header">
76
+ <h5 class="modal-title"><?php esc_html_e( 'Merge customers', 'bookly' ) ?></h5>
77
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span>&times;</span></button>
78
  </div>
79
  <div class="modal-body">
80
  <?php esc_html_e( 'You are about to merge customers from the merge list with the selected one. This will result in losing the merged customers and moving all their appointments to the selected customer. Are you sure you want to continue?', 'bookly' ) ?>
81
  </div>
82
  <div class="modal-footer">
83
+ <?php Buttons::render( 'bookly-merge', 'btn-danger', __( 'Merge', 'bookly' ), array(), '<span class="ladda-label"><i class="fas fa-fw fa-road mr-1"></i>{caption}</span>' ) ?>
84
+ <?php Buttons::renderCancel() ?>
85
  </div>
86
  </div>
87
  </div>
88
  </div>
89
 
90
+ <div ng-bookly-app="customer" ng-controller="customerCtrl">
91
  <div customer-dialog=saveCustomer(customer) customer="customer"></div>
92
  <?php Dialogs\Customer\Edit\Dialog::render() ?>
93
  </div>
94
  <?php Dialogs\TableSettings\Dialog::render() ?>
95
  </div>
96
+
97
  </div>
backend/modules/dashboard/Page.php CHANGED
@@ -15,21 +15,19 @@ class Page extends Lib\Base\Component
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
- 'backend' => array(
19
- 'bootstrap/css/bootstrap-theme.min.css',
20
- 'css/daterangepicker.css',
21
- ),
22
  ) );
23
 
24
  self::enqueueScripts( array(
25
  'backend' => array(
26
  'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
27
- 'js/alert.js' => array( 'jquery' ),
28
  'js/moment.min.js',
29
- 'js/daterangepicker.js' => array( 'jquery' ),
 
30
  ),
31
- 'module' => array(
32
- 'js/dashboard.js' => array( 'jquery', 'bookly-appointments-dashboard.js' ),
33
  ),
34
  ) );
35
  wp_localize_script( 'bookly-dashboard.js', 'BooklyL10n', array(
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
 
 
 
19
  ) );
20
 
21
  self::enqueueScripts( array(
22
  'backend' => array(
23
  'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
24
+ 'js/alert.js' => array( 'jquery' ),
25
  'js/moment.min.js',
26
+ 'js/daterangepicker.js' => array( 'jquery' ),
27
+ 'js/dropdown.js' => array( 'jquery' ),
28
  ),
29
+ 'module' => array(
30
+ 'js/dashboard.js' => array( 'bookly-dropdown.js', 'bookly-appointments-dashboard.js' ),
31
  ),
32
  ) );
33
  wp_localize_script( 'bookly-dashboard.js', 'BooklyL10n', array(
backend/modules/dashboard/resources/js/dashboard.js CHANGED
@@ -5,13 +5,6 @@ jQuery(function ($) {
5
  /**
6
  * Init date range pickers.
7
  */
8
- moment.locale('en', {
9
- months : BooklyL10n.datePicker.monthNames,
10
- monthsShort : BooklyL10n.datePicker.monthNamesShort,
11
- weekdays : BooklyL10n.datePicker.dayNames,
12
- weekdaysShort: BooklyL10n.datePicker.dayNamesShort,
13
- weekdaysMin : BooklyL10n.datePicker.dayNamesMin
14
- });
15
 
16
  pickerRanges[BooklyL10n.dateRange.last_7] = [moment().subtract(7, 'days'), moment()];
17
  pickerRanges[BooklyL10n.dateRange.last_30] = [moment().subtract(30, 'days'), moment()];
@@ -23,18 +16,10 @@ jQuery(function ($) {
23
  startDate: moment().subtract(7, 'days'),
24
  endDate : moment(),
25
  ranges : pickerRanges,
 
 
26
  autoUpdateInput: false,
27
- locale: {
28
- applyLabel : BooklyL10n.dateRange.apply,
29
- cancelLabel: BooklyL10n.dateRange.cancel,
30
- fromLabel : BooklyL10n.dateRange.from,
31
- toLabel : BooklyL10n.dateRange.to,
32
- customRangeLabel: BooklyL10n.dateRange.customRange,
33
- daysOfWeek : BooklyL10n.datePicker.dayNamesShort,
34
- monthNames : BooklyL10n.datePicker.monthNames,
35
- firstDay : parseInt(BooklyL10n.dateRange.firstDay),
36
- format : BooklyL10n.dateRange.dateFormat
37
- }
38
  },
39
  function(start, end, label) {
40
  switch (label) {
@@ -43,7 +28,7 @@ jQuery(function ($) {
43
  $dateFilter
44
  .data('date', start.format(format) + ' - ' + end.format(format))
45
  .find('span')
46
- .html(start.format(BooklyL10n.dateRange.dateFormat) + ' - ' + end.format(BooklyL10n.dateRange.dateFormat));
47
  }
48
  } );
49
 
5
  /**
6
  * Init date range pickers.
7
  */
 
 
 
 
 
 
 
8
 
9
  pickerRanges[BooklyL10n.dateRange.last_7] = [moment().subtract(7, 'days'), moment()];
10
  pickerRanges[BooklyL10n.dateRange.last_30] = [moment().subtract(30, 'days'), moment()];
16
  startDate: moment().subtract(7, 'days'),
17
  endDate : moment(),
18
  ranges : pickerRanges,
19
+ showDropdowns : true,
20
+ linkedCalendars: false,
21
  autoUpdateInput: false,
22
+ locale: $.extend({},BooklyL10n.dateRange, BooklyL10n.datePicker)
 
 
 
 
 
 
 
 
 
 
23
  },
24
  function(start, end, label) {
25
  switch (label) {
28
  $dateFilter
29
  .data('date', start.format(format) + ' - ' + end.format(format))
30
  .find('span')
31
+ .html(start.format(BooklyL10n.dateRange.format) + ' - ' + end.format(BooklyL10n.dateRange.format));
32
  }
33
  } );
34
 
backend/modules/dashboard/templates/index.php CHANGED
@@ -6,37 +6,31 @@ use Bookly\Lib\Utils\Common;
6
  use Bookly\Lib\Utils\DateTime;
7
  ?>
8
  <div id="bookly-tbs" class="wrap">
9
- <div class="bookly-tbs-body">
10
- <div class="page-header text-right">
11
- <div class="bookly-page-title">
12
- <?php esc_html_e( 'Dashboard', 'bookly' ) ?>
13
- </div>
14
- <?php if ( Common::isCurrentUserSupervisor() ) : ?>
15
- <?php Components\Support\Buttons::render( $self::pageSlug() ) ?>
16
- <?php endif ?>
 
 
 
 
 
 
17
  </div>
18
- <div class="row">
19
- <div class="col-md-3 col-sm-6">
20
- <div class="bookly-margin-bottom-lg bookly-relative">
21
- <button type="button" class="btn btn-block btn-default" id="bookly-filter-date" data-date="<?php echo date( 'Y-m-d', strtotime( '-7 days' ) ) ?> - <?php echo date( 'Y-m-d' ) ?>">
22
- <i class="dashicons dashicons-calendar-alt"></i>
23
- <span>
24
- <?php echo DateTime::formatDate( '-7 days' ) ?> - <?php echo DateTime::formatDate( 'today' ) ?>
25
- </span>
26
- </button>
27
- </div>
28
- </div>
29
- <div class="col-md-9 col-sm-6">
30
- <div class="h5">
31
- <?php esc_html_e( 'See the number of appointments and total revenue for the selected period', 'bookly' ) ?>
32
- </div>
33
- </div>
34
  </div>
35
- <div class="panel panel-default bookly-main">
36
- <div class="panel-body">
37
- <?php Dashboard\Appointments\Widget::renderChart() ?>
38
- <?php Proxy\Pro::renderAnalytics() ?>
39
- </div>
40
  </div>
41
  </div>
42
- </div>
6
  use Bookly\Lib\Utils\DateTime;
7
  ?>
8
  <div id="bookly-tbs" class="wrap">
9
+ <div class="form-row align-items-center">
10
+ <h4 class="col m-0"><?php esc_html_e( 'Dashboard', 'bookly' ) ?></h4>
11
+ <?php if ( Common::isCurrentUserSupervisor() ) : ?>
12
+ <?php Components\Support\Buttons::render( $self::pageSlug() ) ?>
13
+ <?php endif ?>
14
+ </div>
15
+ <div class="row my-3">
16
+ <div class="col-md-3 col-sm-6">
17
+ <button type="button" class="btn btn-block btn-default text-left text-truncate" id="bookly-filter-date" data-date="<?php printf( '%s - %s', date( 'Y-m-d', strtotime( '-7 days' ) ), date( 'Y-m-d' ) ) ?>">
18
+ <i class="far fa-calendar-alt mr-1"></i>
19
+ <span>
20
+ <?php echo DateTime::formatDate( '-7 days' ) ?> - <?php echo DateTime::formatDate( 'today' ) ?>
21
+ </span>
22
+ </button>
23
  </div>
24
+ <div class="col-md-9 col-sm-6">
25
+ <h6 class="mt-2 text-muted">
26
+ <?php esc_html_e( 'See the number of appointments and total revenue for the selected period', 'bookly' ) ?>
27
+ </h6>
 
 
 
 
 
 
 
 
 
 
 
 
28
  </div>
29
+ </div>
30
+ <div class="card">
31
+ <div class="card-body">
32
+ <?php Dashboard\Appointments\Widget::renderChart() ?>
33
+ <?php Proxy\Pro::renderAnalytics() ?>
34
  </div>
35
  </div>
36
+ </div>
backend/modules/debug/Ajax.php CHANGED
@@ -179,324 +179,324 @@ class Ajax extends Lib\Base\Ajax
179
  FROM INFORMATION_SCHEMA.COLUMNS
180
  WHERE TABLE_SCHEMA = SCHEMA()
181
  AND TABLE_NAME LIKE 'wp_bookly_%'
182
- ORDER BY TABLE_NAME, COLUMN_NAME
183
  */
184
 
185
  $fields = array(
186
- 'bookly_appointments.created' => "datetime not null",
187
- 'bookly_appointments.created_from' => "enum('bookly','google','outlook') not null default 'bookly'",
 
 
 
188
  'bookly_appointments.custom_service_name' => "varchar(255) null default null",
189
  'bookly_appointments.custom_service_price' => "decimal(10,2) null default null",
 
190
  'bookly_appointments.end_date' => "datetime null default null",
191
- 'bookly_appointments.extras_duration' => "int(11) not null default '0'",
192
- 'bookly_appointments.google_event_etag' => "varchar(255) null default null",
193
- 'bookly_appointments.google_event_id' => "varchar(255) null default null",
194
- 'bookly_appointments.id' => "int(10) unsigned not null auto_increment primary key",
195
  'bookly_appointments.internal_note' => "text null default null",
196
- 'bookly_appointments.location_id' => "int(10) unsigned null default null",
197
- 'bookly_appointments.outlook_event_change_key' => "varchar(255) null default null",
198
  'bookly_appointments.outlook_event_id' => "varchar(255) null default null",
 
199
  'bookly_appointments.outlook_event_series_id' => "varchar(255) null default null",
200
- 'bookly_appointments.service_id' => "int(10) unsigned null default null",
201
- 'bookly_appointments.staff_any' => "tinyint(1) not null default '0'",
202
- 'bookly_appointments.staff_id' => "int(10) unsigned not null",
203
- 'bookly_appointments.start_date' => "datetime null default null",
204
- 'bookly_categories.id' => "int(10) unsigned not null auto_increment primary key",
205
  'bookly_categories.name' => "varchar(255) not null",
206
- 'bookly_categories.position' => "int(11) not null default '9999'",
 
 
 
 
 
 
 
 
 
 
207
  'bookly_coupons.code' => "varchar(255) not null default ''",
208
- 'bookly_coupons.date_limit_end' => "date null default null",
209
- 'bookly_coupons.date_limit_start' => "date null default null",
210
- 'bookly_coupons.deduction' => "decimal(10,2) not null default '0.00'",
211
  'bookly_coupons.discount' => "decimal(3,0) not null default '0'",
212
- 'bookly_coupons.id' => "int(10) unsigned not null auto_increment primary key",
213
- 'bookly_coupons.max_appointments' => "int(10) unsigned null default null",
214
- 'bookly_coupons.min_appointments' => "int(10) unsigned not null default '1'",
215
  'bookly_coupons.once_per_customer' => "tinyint(1) not null default '0'",
216
- 'bookly_coupons.usage_limit' => "int(10) unsigned not null default '1'",
217
- 'bookly_coupons.used' => "int(10) unsigned not null default '0'",
218
- 'bookly_coupon_customers.coupon_id' => "int(10) unsigned not null",
219
- 'bookly_coupon_customers.customer_id' => "int(10) unsigned not null",
220
- 'bookly_coupon_customers.id' => "int(10) unsigned not null auto_increment primary key",
221
- 'bookly_coupon_services.coupon_id' => "int(10) unsigned not null",
222
- 'bookly_coupon_services.id' => "int(10) unsigned not null auto_increment primary key",
223
- 'bookly_coupon_services.service_id' => "int(10) unsigned not null",
224
- 'bookly_coupon_staff.coupon_id' => "int(10) unsigned not null",
225
- 'bookly_coupon_staff.id' => "int(10) unsigned not null auto_increment primary key",
226
- 'bookly_coupon_staff.staff_id' => "int(10) unsigned not null",
227
- 'bookly_customers.additional_address' => "varchar(255) null default null",
228
- 'bookly_customers.birthday' => "date null default null",
229
- 'bookly_customers.city' => "varchar(255) null default null",
230
- 'bookly_customers.country' => "varchar(255) null default null",
231
- 'bookly_customers.created' => "datetime not null",
232
- 'bookly_customers.email' => "varchar(255) not null default ''",
233
- 'bookly_customers.facebook_id' => "bigint(20) unsigned null default null",
234
- 'bookly_customers.first_name' => "varchar(255) not null default ''",
235
- 'bookly_customers.full_name' => "varchar(255) not null default ''",
236
- 'bookly_customers.group_id' => "int(10) unsigned null default null",
237
- 'bookly_customers.id' => "int(10) unsigned not null auto_increment primary key",
238
- 'bookly_customers.info_fields' => "text null default null",
239
- 'bookly_customers.last_name' => "varchar(255) not null default ''",
240
- 'bookly_customers.notes' => "text not null",
241
- 'bookly_customers.phone' => "varchar(255) not null default ''",
242
- 'bookly_customers.postcode' => "varchar(255) null default null",
243
- 'bookly_customers.state' => "varchar(255) null default null",
244
- 'bookly_customers.street' => "varchar(255) null default null",
245
- 'bookly_customers.street_number' => "varchar(255) null default null",
246
- 'bookly_customers.wp_user_id' => "bigint(20) unsigned null default null",
247
- 'bookly_customer_appointments.appointment_id' => "int(10) unsigned not null",
248
- 'bookly_customer_appointments.collaborative_service_id' => "int(10) unsigned null default null",
249
- 'bookly_customer_appointments.collaborative_token' => "varchar(255) null default null",
250
- 'bookly_customer_appointments.compound_service_id' => "int(10) unsigned null default null",
251
- 'bookly_customer_appointments.compound_token' => "varchar(255) null default null",
252
- 'bookly_customer_appointments.created' => "datetime not null",
253
- 'bookly_customer_appointments.created_from' => "enum('frontend','backend') not null default 'frontend'",
254
- 'bookly_customer_appointments.customer_id' => "int(10) unsigned not null",
255
- 'bookly_customer_appointments.custom_fields' => "text null default null",
256
  'bookly_customer_appointments.extras' => "text null default null",
257
- 'bookly_customer_appointments.extras_consider_duration' => "tinyint(1) not null default '1'",
258
  'bookly_customer_appointments.extras_multiply_nop' => "tinyint(1) not null default '1'",
259
- 'bookly_customer_appointments.id' => "int(10) unsigned not null auto_increment primary key",
260
- 'bookly_customer_appointments.locale' => "varchar(8) null default null",
261
- 'bookly_customer_appointments.notes' => "text null default null",
262
- 'bookly_customer_appointments.number_of_persons' => "int(10) unsigned not null default '1'",
263
- 'bookly_customer_appointments.package_id' => "int(10) unsigned null default null",
264
- 'bookly_customer_appointments.payment_id' => "int(10) unsigned null default null",
265
- 'bookly_customer_appointments.rating' => "int(11) null default null",
266
- 'bookly_customer_appointments.rating_comment' => "text null default null",
267
- 'bookly_customer_appointments.series_id' => "int(10) unsigned null default null",
268
  'bookly_customer_appointments.status' => "varchar(255) not null default 'approved'",
269
  'bookly_customer_appointments.status_changed_at' => "datetime null default null",
270
- 'bookly_customer_appointments.time_zone' => "varchar(255) null default null",
271
- 'bookly_customer_appointments.time_zone_offset' => "int(11) null default null",
272
  'bookly_customer_appointments.token' => "varchar(255) null default null",
273
- 'bookly_customer_appointments.units' => "int(10) unsigned not null default '1'",
274
- 'bookly_customer_appointment_files.customer_appointment_id' => "int(10) unsigned not null",
275
- 'bookly_customer_appointment_files.file_id' => "int(10) unsigned not null",
276
- 'bookly_customer_appointment_files.id' => "int(10) unsigned not null auto_increment primary key",
277
- 'bookly_customer_groups.appointment_status' => "varchar(255) not null default ''",
 
 
 
 
 
 
 
 
278
  'bookly_customer_groups.description' => "text not null",
 
279
  'bookly_customer_groups.discount' => "varchar(100) not null default '0'",
280
- 'bookly_customer_groups.id' => "int(10) unsigned not null auto_increment primary key",
281
- 'bookly_customer_groups.name' => "varchar(255) not null",
282
- 'bookly_customer_groups_services.group_id' => "int(10) unsigned not null",
283
- 'bookly_customer_groups_services.id' => "int(10) unsigned not null auto_increment primary key",
284
- 'bookly_customer_groups_services.service_id' => "int(10) unsigned not null",
285
- 'bookly_custom_statuses.busy' => "tinyint(1) not null default '1'",
286
- 'bookly_custom_statuses.id' => "int(10) unsigned not null auto_increment primary key",
287
- 'bookly_custom_statuses.name' => "varchar(255) null default null",
288
- 'bookly_custom_statuses.position' => "int(11) not null default '9999'",
289
- 'bookly_custom_statuses.slug' => "varchar(255) not null",
290
- 'bookly_files.custom_field_id' => "int(11) null default null",
291
- 'bookly_files.id' => "int(10) unsigned not null auto_increment primary key",
 
 
 
 
 
 
 
 
 
 
 
 
292
  'bookly_files.name' => "text not null",
293
- 'bookly_files.path' => "text not null",
294
  'bookly_files.slug' => "varchar(32) not null",
 
 
 
 
 
295
  'bookly_holidays.date' => "date not null",
296
- 'bookly_holidays.id' => "int(10) unsigned not null auto_increment primary key",
297
- 'bookly_holidays.parent_id' => "int(10) unsigned null default null",
298
  'bookly_holidays.repeat_event' => "tinyint(1) not null default '0'",
299
- 'bookly_holidays.staff_id' => "int(10) unsigned null default null",
300
- 'bookly_locations.id' => "int(10) unsigned not null auto_increment primary key",
301
- 'bookly_locations.info' => "text null default null",
302
  'bookly_locations.name' => "varchar(255) null default ''",
303
- 'bookly_locations.position' => "int(11) not null default '9999'",
 
 
 
 
 
304
  'bookly_messages.body' => "text null default null",
305
- 'bookly_messages.created' => "datetime not null",
306
- 'bookly_messages.id' => "int(10) unsigned not null auto_increment primary key",
307
- 'bookly_messages.message_id' => "int(10) unsigned not null",
308
  'bookly_messages.seen' => "tinyint(1) not null default '0'",
309
- 'bookly_messages.subject' => "text null default null",
310
- 'bookly_messages.type' => "varchar(255) not null",
311
- 'bookly_notifications.active' => "tinyint(1) not null default '0'",
312
- 'bookly_notifications.attach_ics' => "tinyint(1) not null default '0'",
313
- 'bookly_notifications.attach_invoice' => "tinyint(1) not null default '0'",
314
  'bookly_notifications.gateway' => "enum('email','sms') not null default 'email'",
315
- 'bookly_notifications.id' => "int(10) unsigned not null auto_increment primary key",
316
- 'bookly_notifications.message' => "text null default null",
317
  'bookly_notifications.name' => "varchar(255) not null default ''",
318
- 'bookly_notifications.settings' => "text null default null",
319
  'bookly_notifications.subject' => "varchar(255) not null default ''",
320
- 'bookly_notifications.to_admin' => "tinyint(1) not null default '0'",
321
- 'bookly_notifications.to_customer' => "tinyint(1) not null default '0'",
322
  'bookly_notifications.to_staff' => "tinyint(1) not null default '0'",
323
- 'bookly_notifications.type' => "varchar(255) not null default ''",
324
- 'bookly_packages.created' => "datetime not null",
325
- 'bookly_packages.customer_id' => "int(10) unsigned not null",
326
- 'bookly_packages.id' => "int(10) unsigned not null auto_increment primary key",
 
 
 
 
 
 
327
  'bookly_packages.internal_note' => "text null default null",
328
- 'bookly_packages.location_id' => "int(10) unsigned null default null",
329
- 'bookly_packages.service_id' => "int(10) unsigned not null",
330
- 'bookly_packages.staff_id' => "int(10) unsigned null default null",
331
- 'bookly_payments.coupon_id' => "int(10) unsigned null default null",
332
- 'bookly_payments.created' => "datetime not null",
333
- 'bookly_payments.details' => "text null default null",
334
- 'bookly_payments.gateway_price_correction' => "decimal(10,2) null default '0.00'",
335
- 'bookly_payments.id' => "int(10) unsigned not null auto_increment primary key",
336
  'bookly_payments.paid' => "decimal(10,2) not null default '0.00'",
337
  'bookly_payments.paid_type' => "enum('in_full','deposit') not null default 'in_full'",
 
338
  'bookly_payments.status' => "enum('pending','completed','rejected') not null default 'completed'",
339
- 'bookly_payments.tax' => "decimal(10,2) not null default '0.00'",
340
- 'bookly_payments.total' => "decimal(10,2) not null default '0.00'",
341
- 'bookly_payments.type' => "enum('local','coupon','paypal','authorize_net','stripe','2checkout','payu_biz','payu_latam','payson','mollie','woocommerce') not null default 'local'",
342
- 'bookly_schedule_item_breaks.end_time' => "time null default null",
343
- 'bookly_schedule_item_breaks.id' => "int(10) unsigned not null auto_increment primary key",
344
- 'bookly_schedule_item_breaks.staff_schedule_item_id' => "int(10) unsigned not null",
345
  'bookly_schedule_item_breaks.start_time' => "time null default null",
 
 
 
 
346
  'bookly_sent_notifications.created' => "datetime not null",
347
- 'bookly_sent_notifications.id' => "int(10) unsigned not null auto_increment primary key",
348
- 'bookly_sent_notifications.notification_id' => "int(10) unsigned not null",
349
- 'bookly_sent_notifications.ref_id' => "int(10) unsigned not null",
350
- 'bookly_series.id' => "int(10) unsigned not null auto_increment primary key",
351
  'bookly_series.repeat' => "varchar(255) null default null",
352
  'bookly_series.token' => "varchar(255) not null",
353
- 'bookly_services.appointments_limit' => "int(11) null default null",
354
- 'bookly_services.capacity_max' => "int(11) not null default '1'",
355
- 'bookly_services.capacity_min' => "int(11) not null default '1'",
356
- 'bookly_services.category_id' => "int(10) unsigned null default null",
357
- 'bookly_services.collaborative_equal_duration' => "tinyint(1) not null default '0'",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
358
  'bookly_services.color' => "varchar(255) not null default '#FFFFFF'",
359
  'bookly_services.deposit' => "varchar(100) not null default '100%'",
360
- 'bookly_services.duration' => "int(11) not null default '900'",
361
- 'bookly_services.end_time_info' => "varchar(255) null default ''",
362
- 'bookly_services.id' => "int(10) unsigned not null auto_increment primary key",
363
- 'bookly_services.info' => "text null default null",
364
- 'bookly_services.limit_period' => "enum('off','day','week','month','year','upcoming','calendar_day','calendar_week','calendar_month','calendar_year') not null default 'off'",
365
  'bookly_services.one_booking_per_slot' => "tinyint(1) not null default '0'",
366
- 'bookly_services.package_life_time' => "int(11) null default null",
367
- 'bookly_services.package_size' => "int(11) null default null",
 
 
 
 
 
 
 
368
  'bookly_services.package_unassigned' => "tinyint(1) not null default '0'",
369
- 'bookly_services.padding_left' => "int(11) not null default '0'",
370
- 'bookly_services.padding_right' => "int(11) not null default '0'",
371
- 'bookly_services.position' => "int(11) not null default '9999'",
372
- 'bookly_services.price' => "decimal(10,2) not null default '0.00'",
373
- 'bookly_services.recurrence_enabled' => "tinyint(1) not null default '1'",
374
- 'bookly_services.recurrence_frequencies' => "set('daily','weekly','biweekly','monthly') not null default 'daily,weekly,biweekly,monthly'",
375
- 'bookly_services.slot_length' => "varchar(255) not null default 'default'",
376
  'bookly_services.staff_preference' => "enum('order','least_occupied','most_occupied','least_occupied_for_period','most_occupied_for_period','least_expensive','most_expensive') not null default 'most_expensive'",
377
  'bookly_services.staff_preference_settings' => "text null default null",
378
- 'bookly_services.start_time_info' => "varchar(255) null default ''",
 
379
  'bookly_services.time_requirements' => "enum('required','optional','off') not null default 'required'",
380
- 'bookly_services.title' => "varchar(255) null default ''",
381
- 'bookly_services.type' => "enum('simple','collaborative','compound','package') not null default 'simple'",
382
- 'bookly_services.units_max' => "int(10) unsigned not null default '1'",
383
- 'bookly_services.units_min' => "int(10) unsigned not null default '1'",
384
  'bookly_services.visibility' => "enum('public','private','group') not null default 'public'",
385
- 'bookly_service_extras.attachment_id' => "int(10) unsigned null default null",
386
- 'bookly_service_extras.duration' => "int(11) not null default '0'",
387
- 'bookly_service_extras.id' => "int(10) unsigned not null auto_increment primary key",
388
- 'bookly_service_extras.max_quantity' => "int(11) not null default '1'",
389
- 'bookly_service_extras.position' => "int(11) not null default '9999'",
390
- 'bookly_service_extras.price' => "decimal(10,2) not null default '0.00'",
391
- 'bookly_service_extras.service_id' => "int(10) unsigned not null",
392
- 'bookly_service_extras.title' => "varchar(255) null default ''",
393
- 'bookly_service_schedule_breaks.end_time' => "time null default null",
394
- 'bookly_service_schedule_breaks.id' => "int(10) unsigned not null auto_increment primary key",
395
- 'bookly_service_schedule_breaks.service_schedule_day_id' => "int(10) unsigned not null",
396
- 'bookly_service_schedule_breaks.start_time' => "time null default null",
397
- 'bookly_service_schedule_days.day_index' => "smallint(6) null default null",
398
- 'bookly_service_schedule_days.end_time' => "time null default null",
399
- 'bookly_service_schedule_days.id' => "int(10) unsigned not null auto_increment primary key",
400
- 'bookly_service_schedule_days.service_id' => "int(10) unsigned not null",
401
- 'bookly_service_schedule_days.start_time' => "time null default null",
402
- 'bookly_service_special_days.date' => "date null default null",
403
- 'bookly_service_special_days.end_time' => "time null default null",
404
- 'bookly_service_special_days.id' => "int(10) unsigned not null auto_increment primary key",
405
- 'bookly_service_special_days.service_id' => "int(10) unsigned not null",
406
- 'bookly_service_special_days.start_time' => "time null default null",
407
- 'bookly_service_special_days_breaks.end_time' => "time null default null",
408
- 'bookly_service_special_days_breaks.id' => "int(10) unsigned not null auto_increment primary key",
409
- 'bookly_service_special_days_breaks.service_special_day_id' => "int(10) unsigned not null",
410
- 'bookly_service_special_days_breaks.start_time' => "time null default null",
411
- 'bookly_service_taxes.id' => "int(10) unsigned not null auto_increment primary key",
412
- 'bookly_service_taxes.service_id' => "int(10) unsigned not null",
413
- 'bookly_service_taxes.tax_id' => "int(10) unsigned not null",
414
- 'bookly_shop.created' => "datetime not null",
415
  'bookly_shop.demo_url' => "varchar(255) null default null",
 
 
416
  'bookly_shop.description' => "text not null",
417
- 'bookly_shop.highlighted' => "tinyint(1) not null default '0'",
418
  'bookly_shop.icon' => "varchar(255) not null",
419
- 'bookly_shop.id' => "int(10) unsigned not null auto_increment primary key",
420
- 'bookly_shop.plugin_id' => "int(10) unsigned not null",
421
  'bookly_shop.price' => "decimal(10,2) not null",
422
- 'bookly_shop.priority' => "int(10) unsigned null default '0'",
423
- 'bookly_shop.published' => "datetime not null",
424
  'bookly_shop.rating' => "decimal(10,2) not null",
425
- 'bookly_shop.reviews' => "int(10) unsigned not null",
426
- 'bookly_shop.sales' => "int(10) unsigned not null",
427
  'bookly_shop.seen' => "tinyint(1) not null default '0'",
428
- 'bookly_shop.slug' => "varchar(255) not null",
429
- 'bookly_shop.title' => "varchar(255) not null",
430
- 'bookly_shop.type' => "enum('plugin','bundle') not null default 'plugin'",
431
- 'bookly_shop.url' => "varchar(255) not null",
432
- 'bookly_special_days_breaks.end_time' => "time null default null",
433
- 'bookly_special_days_breaks.id' => "int(10) unsigned not null auto_increment primary key",
434
- 'bookly_special_days_breaks.staff_special_day_id' => "int(10) unsigned not null",
435
  'bookly_special_days_breaks.start_time' => "time null default null",
436
- 'bookly_staff.attachment_id' => "int(10) unsigned null default null",
437
- 'bookly_staff.category_id' => "int(10) unsigned null default null",
438
- 'bookly_staff.email' => "varchar(255) null default null",
 
 
439
  'bookly_staff.full_name' => "varchar(255) null default null",
440
- 'bookly_staff.google_data' => "text null default null",
441
- 'bookly_staff.id' => "int(10) unsigned not null auto_increment primary key",
442
- 'bookly_staff.info' => "text null default null",
443
- 'bookly_staff.outlook_data' => "text null default null",
444
  'bookly_staff.phone' => "varchar(255) null default null",
445
- 'bookly_staff.position' => "int(11) not null default '9999'",
 
446
  'bookly_staff.visibility' => "enum('public','private','archive') not null default 'public'",
447
- 'bookly_staff.working_time_limit' => "int(10) unsigned null default null",
448
- 'bookly_staff.wp_user_id' => "bigint(20) unsigned null default null",
449
- 'bookly_staff_categories.id' => "int(10) unsigned not null auto_increment primary key",
 
450
  'bookly_staff_categories.name' => "varchar(255) not null",
451
- 'bookly_staff_categories.position' => "int(11) not null default '9999'",
452
- 'bookly_staff_locations.custom_schedule' => "tinyint(1) not null default '0'",
 
 
453
  'bookly_staff_locations.custom_services' => "tinyint(1) not null default '0'",
454
- 'bookly_staff_locations.id' => "int(10) unsigned not null auto_increment primary key",
455
- 'bookly_staff_locations.location_id' => "int(10) unsigned not null",
456
- 'bookly_staff_locations.staff_id' => "int(10) unsigned not null",
457
- 'bookly_staff_preference_orders.id' => "int(10) unsigned not null auto_increment primary key",
458
- 'bookly_staff_preference_orders.position' => "int(11) not null default '9999'",
459
- 'bookly_staff_preference_orders.service_id' => "int(10) unsigned not null",
460
- 'bookly_staff_preference_orders.staff_id' => "int(10) unsigned not null",
461
- 'bookly_staff_schedule_items.day_index' => "int(10) unsigned not null",
462
- 'bookly_staff_schedule_items.end_time' => "time null default null",
463
- 'bookly_staff_schedule_items.id' => "int(10) unsigned not null auto_increment primary key",
464
- 'bookly_staff_schedule_items.location_id' => "int(10) unsigned null default null",
465
- 'bookly_staff_schedule_items.staff_id' => "int(10) unsigned not null",
466
  'bookly_staff_schedule_items.start_time' => "time null default null",
467
- 'bookly_staff_services.capacity_max' => "int(11) not null default '1'",
468
- 'bookly_staff_services.capacity_min' => "int(11) not null default '1'",
469
- 'bookly_staff_services.deposit' => "varchar(100) not null default '100%'",
470
- 'bookly_staff_services.id' => "int(10) unsigned not null auto_increment primary key",
471
- 'bookly_staff_services.location_id' => "int(10) unsigned null default null",
472
  'bookly_staff_services.price' => "decimal(10,2) not null default '0.00'",
473
- 'bookly_staff_services.service_id' => "int(10) unsigned not null",
474
- 'bookly_staff_services.staff_id' => "int(10) unsigned not null",
 
 
 
475
  'bookly_staff_special_days.date' => "date null default null",
476
- 'bookly_staff_special_days.end_time' => "time null default null",
477
- 'bookly_staff_special_days.id' => "int(10) unsigned not null auto_increment primary key",
478
- 'bookly_staff_special_days.staff_id' => "int(10) unsigned not null",
479
  'bookly_staff_special_days.start_time' => "time null default null",
 
 
 
 
 
 
480
  'bookly_staff_special_hours.end_time' => "time null default null",
481
- 'bookly_staff_special_hours.id' => "int(10) unsigned not null auto_increment primary key",
482
- 'bookly_staff_special_hours.location_id' => "int(10) unsigned null default null",
483
  'bookly_staff_special_hours.price' => "decimal(10,2) not null default '0.00'",
484
- 'bookly_staff_special_hours.service_id' => "int(10) unsigned not null",
485
- 'bookly_staff_special_hours.staff_id' => "int(10) unsigned not null",
486
- 'bookly_staff_special_hours.start_time' => "time null default null",
487
- 'bookly_stats.created' => "datetime not null",
488
- 'bookly_stats.id' => "int(10) unsigned not null auto_increment primary key",
489
  'bookly_stats.name' => "varchar(255) not null",
490
  'bookly_stats.value' => "text null default null",
491
- 'bookly_sub_services.duration' => "int(11) null default null",
492
- 'bookly_sub_services.id' => "int(10) unsigned not null auto_increment primary key",
493
- 'bookly_sub_services.position' => "int(11) not null default '9999'",
494
- 'bookly_sub_services.service_id' => "int(10) unsigned not null",
495
- 'bookly_sub_services.sub_service_id' => "int(10) unsigned null default null",
496
  'bookly_sub_services.type' => "enum('service','spare_time') not null default 'service'",
497
- 'bookly_taxes.id' => "int(10) unsigned not null auto_increment primary key",
498
- 'bookly_taxes.rate' => "decimal(10,3) not null default '0.000'",
 
 
 
499
  'bookly_taxes.title' => "varchar(255) null default ''",
 
500
  );
501
 
502
  $prefix_len = strlen( $wpdb->prefix );
179
  FROM INFORMATION_SCHEMA.COLUMNS
180
  WHERE TABLE_SCHEMA = SCHEMA()
181
  AND TABLE_NAME LIKE 'wp_bookly_%'
182
+ ORDER BY TABLE_NAME, ORDINAL_POSITION
183
  */
184
 
185
  $fields = array(
186
+ 'bookly_appointments.id' => "int unsigned not null auto_increment primary key",
187
+ 'bookly_appointments.location_id' => "int unsigned null default null",
188
+ 'bookly_appointments.staff_id' => "int unsigned not null",
189
+ 'bookly_appointments.staff_any' => "tinyint(1) not null default '0'",
190
+ 'bookly_appointments.service_id' => "int unsigned null default null",
191
  'bookly_appointments.custom_service_name' => "varchar(255) null default null",
192
  'bookly_appointments.custom_service_price' => "decimal(10,2) null default null",
193
+ 'bookly_appointments.start_date' => "datetime null default null",
194
  'bookly_appointments.end_date' => "datetime null default null",
195
+ 'bookly_appointments.extras_duration' => "int not null default '0'",
 
 
 
196
  'bookly_appointments.internal_note' => "text null default null",
197
+ 'bookly_appointments.google_event_id' => "varchar(255) null default null",
198
+ 'bookly_appointments.google_event_etag' => "varchar(255) null default null",
199
  'bookly_appointments.outlook_event_id' => "varchar(255) null default null",
200
+ 'bookly_appointments.outlook_event_change_key' => "varchar(255) null default null",
201
  'bookly_appointments.outlook_event_series_id' => "varchar(255) null default null",
202
+ 'bookly_appointments.created_from' => "enum('bookly','google','outlook') not null default 'bookly'",
203
+ 'bookly_appointments.created' => "datetime not null",
204
+ 'bookly_categories.id' => "int unsigned not null auto_increment primary key",
 
 
205
  'bookly_categories.name' => "varchar(255) not null",
206
+ 'bookly_categories.position' => "int not null default '9999'",
207
+ 'bookly_coupon_customers.id' => "int unsigned not null auto_increment primary key",
208
+ 'bookly_coupon_customers.coupon_id' => "int unsigned not null",
209
+ 'bookly_coupon_customers.customer_id' => "int unsigned not null",
210
+ 'bookly_coupon_services.id' => "int unsigned not null auto_increment primary key",
211
+ 'bookly_coupon_services.coupon_id' => "int unsigned not null",
212
+ 'bookly_coupon_services.service_id' => "int unsigned not null",
213
+ 'bookly_coupon_staff.id' => "int unsigned not null auto_increment primary key",
214
+ 'bookly_coupon_staff.coupon_id' => "int unsigned not null",
215
+ 'bookly_coupon_staff.staff_id' => "int unsigned not null",
216
+ 'bookly_coupons.id' => "int unsigned not null auto_increment primary key",
217
  'bookly_coupons.code' => "varchar(255) not null default ''",
 
 
 
218
  'bookly_coupons.discount' => "decimal(3,0) not null default '0'",
219
+ 'bookly_coupons.deduction' => "decimal(10,2) not null default '0.00'",
220
+ 'bookly_coupons.usage_limit' => "int unsigned not null default '1'",
221
+ 'bookly_coupons.used' => "int unsigned not null default '0'",
222
  'bookly_coupons.once_per_customer' => "tinyint(1) not null default '0'",
223
+ 'bookly_coupons.date_limit_start' => "date null default null",
224
+ 'bookly_coupons.date_limit_end' => "date null default null",
225
+ 'bookly_coupons.min_appointments' => "int unsigned not null default '1'",
226
+ 'bookly_coupons.max_appointments' => "int unsigned null default null",
227
+ 'bookly_custom_statuses.id' => "int unsigned not null auto_increment primary key",
228
+ 'bookly_custom_statuses.slug' => "varchar(255) not null",
229
+ 'bookly_custom_statuses.name' => "varchar(255) null default null",
230
+ 'bookly_custom_statuses.busy' => "tinyint(1) not null default '1'",
231
+ 'bookly_custom_statuses.position' => "int not null default '9999'",
232
+ 'bookly_customer_appointment_files.id' => "int unsigned not null auto_increment primary key",
233
+ 'bookly_customer_appointment_files.customer_appointment_id' => "int unsigned not null",
234
+ 'bookly_customer_appointment_files.file_id' => "int unsigned not null",
235
+ 'bookly_customer_appointments.id' => "int unsigned not null auto_increment primary key",
236
+ 'bookly_customer_appointments.series_id' => "int unsigned null default null",
237
+ 'bookly_customer_appointments.package_id' => "int unsigned null default null",
238
+ 'bookly_customer_appointments.customer_id' => "int unsigned not null",
239
+ 'bookly_customer_appointments.appointment_id' => "int unsigned not null",
240
+ 'bookly_customer_appointments.payment_id' => "int unsigned null default null",
241
+ 'bookly_customer_appointments.number_of_persons' => "int unsigned not null default '1'",
242
+ 'bookly_customer_appointments.units' => "int unsigned not null default '1'",
243
+ 'bookly_customer_appointments.notes' => "text null default null",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  'bookly_customer_appointments.extras' => "text null default null",
 
245
  'bookly_customer_appointments.extras_multiply_nop' => "tinyint(1) not null default '1'",
246
+ 'bookly_customer_appointments.extras_consider_duration' => "tinyint(1) not null default '1'",
247
+ 'bookly_customer_appointments.custom_fields' => "text null default null",
 
 
 
 
 
 
 
248
  'bookly_customer_appointments.status' => "varchar(255) not null default 'approved'",
249
  'bookly_customer_appointments.status_changed_at' => "datetime null default null",
 
 
250
  'bookly_customer_appointments.token' => "varchar(255) null default null",
251
+ 'bookly_customer_appointments.time_zone' => "varchar(255) null default null",
252
+ 'bookly_customer_appointments.time_zone_offset' => "int null default null",
253
+ 'bookly_customer_appointments.rating' => "int null default null",
254
+ 'bookly_customer_appointments.rating_comment' => "text null default null",
255
+ 'bookly_customer_appointments.locale' => "varchar(8) null default null",
256
+ 'bookly_customer_appointments.collaborative_service_id' => "int unsigned null default null",
257
+ 'bookly_customer_appointments.collaborative_token' => "varchar(255) null default null",
258
+ 'bookly_customer_appointments.compound_service_id' => "int unsigned null default null",
259
+ 'bookly_customer_appointments.compound_token' => "varchar(255) null default null",
260
+ 'bookly_customer_appointments.created_from' => "enum('frontend','backend') not null default 'frontend'",
261
+ 'bookly_customer_appointments.created' => "datetime not null",
262
+ 'bookly_customer_groups.id' => "int unsigned not null auto_increment primary key",
263
+ 'bookly_customer_groups.name' => "varchar(255) not null",
264
  'bookly_customer_groups.description' => "text not null",
265
+ 'bookly_customer_groups.appointment_status' => "varchar(255) not null default ''",
266
  'bookly_customer_groups.discount' => "varchar(100) not null default '0'",
267
+ 'bookly_customer_groups_services.id' => "int unsigned not null auto_increment primary key",
268
+ 'bookly_customer_groups_services.group_id' => "int unsigned not null",
269
+ 'bookly_customer_groups_services.service_id' => "int unsigned not null",
270
+ 'bookly_customers.id' => "int unsigned not null auto_increment primary key",
271
+ 'bookly_customers.wp_user_id' => "bigint unsigned null default null",
272
+ 'bookly_customers.facebook_id' => "bigint unsigned null default null",
273
+ 'bookly_customers.group_id' => "int unsigned null default null",
274
+ 'bookly_customers.full_name' => "varchar(255) not null default ''",
275
+ 'bookly_customers.first_name' => "varchar(255) not null default ''",
276
+ 'bookly_customers.last_name' => "varchar(255) not null default ''",
277
+ 'bookly_customers.phone' => "varchar(255) not null default ''",
278
+ 'bookly_customers.email' => "varchar(255) not null default ''",
279
+ 'bookly_customers.birthday' => "date null default null",
280
+ 'bookly_customers.country' => "varchar(255) null default null",
281
+ 'bookly_customers.state' => "varchar(255) null default null",
282
+ 'bookly_customers.postcode' => "varchar(255) null default null",
283
+ 'bookly_customers.city' => "varchar(255) null default null",
284
+ 'bookly_customers.street' => "varchar(255) null default null",
285
+ 'bookly_customers.street_number' => "varchar(255) null default null",
286
+ 'bookly_customers.additional_address' => "varchar(255) null default null",
287
+ 'bookly_customers.notes' => "text not null",
288
+ 'bookly_customers.info_fields' => "text null default null",
289
+ 'bookly_customers.created' => "datetime not null",
290
+ 'bookly_files.id' => "int unsigned not null auto_increment primary key",
291
  'bookly_files.name' => "text not null",
 
292
  'bookly_files.slug' => "varchar(32) not null",
293
+ 'bookly_files.path' => "text not null",
294
+ 'bookly_files.custom_field_id' => "int null default null",
295
+ 'bookly_holidays.id' => "int unsigned not null auto_increment primary key",
296
+ 'bookly_holidays.staff_id' => "int unsigned null default null",
297
+ 'bookly_holidays.parent_id' => "int unsigned null default null",
298
  'bookly_holidays.date' => "date not null",
 
 
299
  'bookly_holidays.repeat_event' => "tinyint(1) not null default '0'",
300
+ 'bookly_locations.id' => "int unsigned not null auto_increment primary key",
 
 
301
  'bookly_locations.name' => "varchar(255) null default ''",
302
+ 'bookly_locations.info' => "text null default null",
303
+ 'bookly_locations.position' => "int not null default '9999'",
304
+ 'bookly_messages.id' => "int unsigned not null auto_increment primary key",
305
+ 'bookly_messages.message_id' => "int unsigned not null",
306
+ 'bookly_messages.type' => "varchar(255) not null",
307
+ 'bookly_messages.subject' => "text null default null",
308
  'bookly_messages.body' => "text null default null",
 
 
 
309
  'bookly_messages.seen' => "tinyint(1) not null default '0'",
310
+ 'bookly_messages.created' => "datetime not null",
311
+ 'bookly_notifications.id' => "int unsigned not null auto_increment primary key",
 
 
 
312
  'bookly_notifications.gateway' => "enum('email','sms') not null default 'email'",
313
+ 'bookly_notifications.type' => "varchar(255) not null default ''",
314
+ 'bookly_notifications.active' => "tinyint(1) not null default '0'",
315
  'bookly_notifications.name' => "varchar(255) not null default ''",
 
316
  'bookly_notifications.subject' => "varchar(255) not null default ''",
317
+ 'bookly_notifications.message' => "text null default null",
 
318
  'bookly_notifications.to_staff' => "tinyint(1) not null default '0'",
319
+ 'bookly_notifications.to_customer' => "tinyint(1) not null default '0'",
320
+ 'bookly_notifications.to_admin' => "tinyint(1) not null default '0'",
321
+ 'bookly_notifications.attach_ics' => "tinyint(1) not null default '0'",
322
+ 'bookly_notifications.attach_invoice' => "tinyint(1) not null default '0'",
323
+ 'bookly_notifications.settings' => "text null default null",
324
+ 'bookly_packages.id' => "int unsigned not null auto_increment primary key",
325
+ 'bookly_packages.location_id' => "int unsigned null default null",
326
+ 'bookly_packages.staff_id' => "int unsigned null default null",
327
+ 'bookly_packages.service_id' => "int unsigned not null",
328
+ 'bookly_packages.customer_id' => "int unsigned not null",
329
  'bookly_packages.internal_note' => "text null default null",
330
+ 'bookly_packages.created' => "datetime not null",
331
+ 'bookly_payments.id' => "int unsigned not null auto_increment primary key",
332
+ 'bookly_payments.coupon_id' => "int unsigned null default null",
333
+ 'bookly_payments.type' => "enum('local','free','paypal','authorize_net','stripe','2checkout','payu_biz','payu_latam','payson','mollie','woocommerce') not null default 'local'",
334
+ 'bookly_payments.total' => "decimal(10,2) not null default '0.00'",
335
+ 'bookly_payments.tax' => "decimal(10,2) not null default '0.00'",
 
 
336
  'bookly_payments.paid' => "decimal(10,2) not null default '0.00'",
337
  'bookly_payments.paid_type' => "enum('in_full','deposit') not null default 'in_full'",
338
+ 'bookly_payments.gateway_price_correction' => "decimal(10,2) null default '0.00'",
339
  'bookly_payments.status' => "enum('pending','completed','rejected') not null default 'completed'",
340
+ 'bookly_payments.details' => "text null default null",
341
+ 'bookly_payments.created' => "datetime not null",
342
+ 'bookly_schedule_item_breaks.id' => "int unsigned not null auto_increment primary key",
343
+ 'bookly_schedule_item_breaks.staff_schedule_item_id' => "int unsigned not null",
 
 
344
  'bookly_schedule_item_breaks.start_time' => "time null default null",
345
+ 'bookly_schedule_item_breaks.end_time' => "time null default null",
346
+ 'bookly_sent_notifications.id' => "int unsigned not null auto_increment primary key",
347
+ 'bookly_sent_notifications.ref_id' => "int unsigned not null",
348
+ 'bookly_sent_notifications.notification_id' => "int unsigned not null",
349
  'bookly_sent_notifications.created' => "datetime not null",
350
+ 'bookly_series.id' => "int unsigned not null auto_increment primary key",
 
 
 
351
  'bookly_series.repeat' => "varchar(255) null default null",
352
  'bookly_series.token' => "varchar(255) not null",
353
+ 'bookly_service_extras.id' => "int unsigned not null auto_increment primary key",
354
+ 'bookly_service_extras.service_id' => "int unsigned not null",
355
+ 'bookly_service_extras.attachment_id' => "int unsigned null default null",
356
+ 'bookly_service_extras.title' => "varchar(255) null default ''",
357
+ 'bookly_service_extras.duration' => "int not null default '0'",
358
+ 'bookly_service_extras.price' => "decimal(10,2) not null default '0.00'",
359
+ 'bookly_service_extras.max_quantity' => "int not null default '1'",
360
+ 'bookly_service_extras.position' => "int not null default '9999'",
361
+ 'bookly_service_schedule_breaks.id' => "int unsigned not null auto_increment primary key",
362
+ 'bookly_service_schedule_breaks.service_schedule_day_id' => "int unsigned not null",
363
+ 'bookly_service_schedule_breaks.start_time' => "time null default null",
364
+ 'bookly_service_schedule_breaks.end_time' => "time null default null",
365
+ 'bookly_service_schedule_days.id' => "int unsigned not null auto_increment primary key",
366
+ 'bookly_service_schedule_days.service_id' => "int unsigned not null",
367
+ 'bookly_service_schedule_days.day_index' => "smallint null default null",
368
+ 'bookly_service_schedule_days.start_time' => "time null default null",
369
+ 'bookly_service_schedule_days.end_time' => "time null default null",
370
+ 'bookly_service_special_days.id' => "int unsigned not null auto_increment primary key",
371
+ 'bookly_service_special_days.service_id' => "int unsigned not null",
372
+ 'bookly_service_special_days.date' => "date null default null",
373
+ 'bookly_service_special_days.start_time' => "time null default null",
374
+ 'bookly_service_special_days.end_time' => "time null default null",
375
+ 'bookly_service_special_days_breaks.id' => "int unsigned not null auto_increment primary key",
376
+ 'bookly_service_special_days_breaks.service_special_day_id' => "int unsigned not null",
377
+ 'bookly_service_special_days_breaks.start_time' => "time null default null",
378
+ 'bookly_service_special_days_breaks.end_time' => "time null default null",
379
+ 'bookly_service_taxes.id' => "int unsigned not null auto_increment primary key",
380
+ 'bookly_service_taxes.service_id' => "int unsigned not null",
381
+ 'bookly_service_taxes.tax_id' => "int unsigned not null",
382
+ 'bookly_services.id' => "int unsigned not null auto_increment primary key",
383
+ 'bookly_services.category_id' => "int unsigned null default null",
384
+ 'bookly_services.type' => "enum('simple','collaborative','compound','package') not null default 'simple'",
385
+ 'bookly_services.title' => "varchar(255) null default ''",
386
+ 'bookly_services.duration' => "int not null default '900'",
387
+ 'bookly_services.slot_length' => "varchar(255) not null default 'default'",
388
+ 'bookly_services.price' => "decimal(10,2) not null default '0.00'",
389
  'bookly_services.color' => "varchar(255) not null default '#FFFFFF'",
390
  'bookly_services.deposit' => "varchar(100) not null default '100%'",
391
+ 'bookly_services.capacity_min' => "int not null default '1'",
392
+ 'bookly_services.capacity_max' => "int not null default '1'",
 
 
 
393
  'bookly_services.one_booking_per_slot' => "tinyint(1) not null default '0'",
394
+ 'bookly_services.padding_left' => "int not null default '0'",
395
+ 'bookly_services.padding_right' => "int not null default '0'",
396
+ 'bookly_services.info' => "text null default null",
397
+ 'bookly_services.start_time_info' => "varchar(255) null default ''",
398
+ 'bookly_services.end_time_info' => "varchar(255) null default ''",
399
+ 'bookly_services.units_min' => "int unsigned not null default '1'",
400
+ 'bookly_services.units_max' => "int unsigned not null default '1'",
401
+ 'bookly_services.package_life_time' => "int null default null",
402
+ 'bookly_services.package_size' => "int null default null",
403
  'bookly_services.package_unassigned' => "tinyint(1) not null default '0'",
404
+ 'bookly_services.appointments_limit' => "int null default null",
405
+ 'bookly_services.limit_period' => "enum('off','day','week','month','year','upcoming','calendar_day','calendar_week','calendar_month','calendar_year') not null default 'off'",
 
 
 
 
 
406
  'bookly_services.staff_preference' => "enum('order','least_occupied','most_occupied','least_occupied_for_period','most_occupied_for_period','least_expensive','most_expensive') not null default 'most_expensive'",
407
  'bookly_services.staff_preference_settings' => "text null default null",
408
+ 'bookly_services.recurrence_enabled' => "tinyint(1) not null default '1'",
409
+ 'bookly_services.recurrence_frequencies' => "set('daily','weekly','biweekly','monthly') not null default 'daily,weekly,biweekly,monthly'",
410
  'bookly_services.time_requirements' => "enum('required','optional','off') not null default 'required'",
411
+ 'bookly_services.collaborative_equal_duration' => "tinyint(1) not null default '0'",
 
 
 
412
  'bookly_services.visibility' => "enum('public','private','group') not null default 'public'",
413
+ 'bookly_services.position' => "int not null default '9999'",
414
+ 'bookly_shop.id' => "int unsigned not null auto_increment primary key",
415
+ 'bookly_shop.plugin_id' => "int unsigned not null",
416
+ 'bookly_shop.type' => "enum('plugin','bundle') not null default 'plugin'",
417
+ 'bookly_shop.highlighted' => "tinyint(1) not null default '0'",
418
+ 'bookly_shop.priority' => "int unsigned null default '0'",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
419
  'bookly_shop.demo_url' => "varchar(255) null default null",
420
+ 'bookly_shop.title' => "varchar(255) not null",
421
+ 'bookly_shop.slug' => "varchar(255) not null",
422
  'bookly_shop.description' => "text not null",
423
+ 'bookly_shop.url' => "varchar(255) not null",
424
  'bookly_shop.icon' => "varchar(255) not null",
 
 
425
  'bookly_shop.price' => "decimal(10,2) not null",
426
+ 'bookly_shop.sales' => "int unsigned not null",
 
427
  'bookly_shop.rating' => "decimal(10,2) not null",
428
+ 'bookly_shop.reviews' => "int unsigned not null",
429
+ 'bookly_shop.published' => "datetime not null",
430
  'bookly_shop.seen' => "tinyint(1) not null default '0'",
431
+ 'bookly_shop.created' => "datetime not null",
432
+ 'bookly_special_days_breaks.id' => "int unsigned not null auto_increment primary key",
433
+ 'bookly_special_days_breaks.staff_special_day_id' => "int unsigned not null",
 
 
 
 
434
  'bookly_special_days_breaks.start_time' => "time null default null",
435
+ 'bookly_special_days_breaks.end_time' => "time null default null",
436
+ 'bookly_staff.id' => "int unsigned not null auto_increment primary key",
437
+ 'bookly_staff.category_id' => "int unsigned null default null",
438
+ 'bookly_staff.wp_user_id' => "bigint unsigned null default null",
439
+ 'bookly_staff.attachment_id' => "int unsigned null default null",
440
  'bookly_staff.full_name' => "varchar(255) null default null",
441
+ 'bookly_staff.email' => "varchar(255) null default null",
 
 
 
442
  'bookly_staff.phone' => "varchar(255) null default null",
443
+ 'bookly_staff.info' => "text null default null",
444
+ 'bookly_staff.working_time_limit' => "int unsigned null default null",
445
  'bookly_staff.visibility' => "enum('public','private','archive') not null default 'public'",
446
+ 'bookly_staff.position' => "int not null default '9999'",
447
+ 'bookly_staff.google_data' => "text null default null",
448
+ 'bookly_staff.outlook_data' => "text null default null",
449
+ 'bookly_staff_categories.id' => "int unsigned not null auto_increment primary key",
450
  'bookly_staff_categories.name' => "varchar(255) not null",
451
+ 'bookly_staff_categories.position' => "int not null default '9999'",
452
+ 'bookly_staff_locations.id' => "int unsigned not null auto_increment primary key",
453
+ 'bookly_staff_locations.staff_id' => "int unsigned not null",
454
+ 'bookly_staff_locations.location_id' => "int unsigned not null",
455
  'bookly_staff_locations.custom_services' => "tinyint(1) not null default '0'",
456
+ 'bookly_staff_locations.custom_schedule' => "tinyint(1) not null default '0'",
457
+ 'bookly_staff_preference_orders.id' => "int unsigned not null auto_increment primary key",
458
+ 'bookly_staff_preference_orders.service_id' => "int unsigned not null",
459
+ 'bookly_staff_preference_orders.staff_id' => "int unsigned not null",
460
+ 'bookly_staff_preference_orders.position' => "int not null default '9999'",
461
+ 'bookly_staff_schedule_items.id' => "int unsigned not null auto_increment primary key",
462
+ 'bookly_staff_schedule_items.staff_id' => "int unsigned not null",
463
+ 'bookly_staff_schedule_items.location_id' => "int unsigned null default null",
464
+ 'bookly_staff_schedule_items.day_index' => "int unsigned not null",
 
 
 
465
  'bookly_staff_schedule_items.start_time' => "time null default null",
466
+ 'bookly_staff_schedule_items.end_time' => "time null default null",
467
+ 'bookly_staff_services.id' => "int unsigned not null auto_increment primary key",
468
+ 'bookly_staff_services.staff_id' => "int unsigned not null",
469
+ 'bookly_staff_services.service_id' => "int unsigned not null",
470
+ 'bookly_staff_services.location_id' => "int unsigned null default null",
471
  'bookly_staff_services.price' => "decimal(10,2) not null default '0.00'",
472
+ 'bookly_staff_services.deposit' => "varchar(100) not null default '100%'",
473
+ 'bookly_staff_services.capacity_min' => "int not null default '1'",
474
+ 'bookly_staff_services.capacity_max' => "int not null default '1'",
475
+ 'bookly_staff_special_days.id' => "int unsigned not null auto_increment primary key",
476
+ 'bookly_staff_special_days.staff_id' => "int unsigned not null",
477
  'bookly_staff_special_days.date' => "date null default null",
 
 
 
478
  'bookly_staff_special_days.start_time' => "time null default null",
479
+ 'bookly_staff_special_days.end_time' => "time null default null",
480
+ 'bookly_staff_special_hours.id' => "int unsigned not null auto_increment primary key",
481
+ 'bookly_staff_special_hours.staff_id' => "int unsigned not null",
482
+ 'bookly_staff_special_hours.service_id' => "int unsigned not null",
483
+ 'bookly_staff_special_hours.location_id' => "int unsigned null default null",
484
+ 'bookly_staff_special_hours.start_time' => "time null default null",
485
  'bookly_staff_special_hours.end_time' => "time null default null",
 
 
486
  'bookly_staff_special_hours.price' => "decimal(10,2) not null default '0.00'",
487
+ 'bookly_stats.id' => "int unsigned not null auto_increment primary key",
 
 
 
 
488
  'bookly_stats.name' => "varchar(255) not null",
489
  'bookly_stats.value' => "text null default null",
490
+ 'bookly_stats.created' => "datetime not null",
491
+ 'bookly_sub_services.id' => "int unsigned not null auto_increment primary key",
 
 
 
492
  'bookly_sub_services.type' => "enum('service','spare_time') not null default 'service'",
493
+ 'bookly_sub_services.service_id' => "int unsigned not null",
494
+ 'bookly_sub_services.sub_service_id' => "int unsigned null default null",
495
+ 'bookly_sub_services.duration' => "int null default null",
496
+ 'bookly_sub_services.position' => "int not null default '9999'",
497
+ 'bookly_taxes.id' => "int unsigned not null auto_increment primary key",
498
  'bookly_taxes.title' => "varchar(255) null default ''",
499
+ 'bookly_taxes.rate' => "decimal(10,3) not null default '0.000'",
500
  );
501
 
502
  $prefix_len = strlen( $wpdb->prefix );
backend/modules/debug/Page.php CHANGED
@@ -26,7 +26,7 @@ class Page extends Lib\Base\Component
26
 
27
  self::enqueueStyles( array(
28
  'frontend' => array( 'css/ladda.min.css', ),
29
- 'backend' => array( 'bootstrap/css/bootstrap-theme.min.css', ),
30
  'module' => array( 'css/style.css' ),
31
  ) );
32
 
@@ -44,6 +44,7 @@ class Page extends Lib\Base\Component
44
 
45
  $debug = array();
46
  $schema = new Schema();
 
47
  /** @var Lib\Base\Plugin $plugin */
48
  foreach ( apply_filters( 'bookly_plugins', array() ) as $plugin ) {
49
  foreach ( $plugin::getEntityClasses() as $entity_class ) {
@@ -72,10 +73,12 @@ class Page extends Lib\Base\Component
72
  if ( $expect && $diff ) {
73
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_INFO;
74
  $debug[ $table_name ]['info'][ $field ] = array_keys( $diff );
 
75
  }
76
  } else {
77
  $debug[ $table_name ]['fields'][ $field ] = 0;
78
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_WARNING;
 
79
  }
80
  }
81
 
@@ -88,6 +91,7 @@ class Page extends Lib\Base\Component
88
  } else {
89
  $debug[ $table_name ]['constraints'][ $key ]['status'] = 0;
90
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_WARNING;
 
91
  }
92
  }
93
  $debug[ $table_name ]['constraints_3d'] = array();
@@ -101,6 +105,7 @@ class Page extends Lib\Base\Component
101
  }
102
  } else {
103
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_ERROR;
 
104
  }
105
  }
106
  }
@@ -135,6 +140,6 @@ class Page extends Lib\Base\Component
135
  }
136
  }
137
  }
138
- self::renderTemplate( 'index', compact( 'debug', 'import_status', 'tools' ) );
139
  }
140
  }
26
 
27
  self::enqueueStyles( array(
28
  'frontend' => array( 'css/ladda.min.css', ),
29
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', 'css/fontawesome-all.min.css' ),
30
  'module' => array( 'css/style.css' ),
31
  ) );
32
 
44
 
45
  $debug = array();
46
  $schema = new Schema();
47
+ $trouble = false;
48
  /** @var Lib\Base\Plugin $plugin */
49
  foreach ( apply_filters( 'bookly_plugins', array() ) as $plugin ) {
50
  foreach ( $plugin::getEntityClasses() as $entity_class ) {
73
  if ( $expect && $diff ) {
74
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_INFO;
75
  $debug[ $table_name ]['info'][ $field ] = array_keys( $diff );
76
+ $trouble = true;
77
  }
78
  } else {
79
  $debug[ $table_name ]['fields'][ $field ] = 0;
80
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_WARNING;
81
+ $trouble = true;
82
  }
83
  }
84
 
91
  } else {
92
  $debug[ $table_name ]['constraints'][ $key ]['status'] = 0;
93
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_WARNING;
94
+ $trouble = true;
95
  }
96
  }
97
  $debug[ $table_name ]['constraints_3d'] = array();
105
  }
106
  } else {
107
  $debug[ $table_name ]['status'] = self::TABLE_STATUS_ERROR;
108
+ $trouble = true;
109
  }
110
  }
111
  }
140
  }
141
  }
142
  }
143
+ self::renderTemplate( 'index', compact( 'debug', 'import_status', 'tools', 'trouble' ) );
144
  }
145
  }
backend/modules/debug/lib/QueryBuilder.php CHANGED
@@ -139,20 +139,20 @@ class QueryBuilder
139
  FROM INFORMATION_SCHEMA.COLUMNS
140
  WHERE TABLE_SCHEMA = SCHEMA()
141
  AND TABLE_NAME LIKE 'wp_bookly_%'
142
- ORDER BY TABLE_NAME, COLUMN_NAME
143
  */
144
 
145
  $data = array(
146
- 'bookly_appointments.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
147
- 'bookly_appointments.location_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
148
- 'bookly_appointments.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
149
  'bookly_appointments.staff_any' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
150
- 'bookly_appointments.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
151
  'bookly_appointments.custom_service_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
152
  'bookly_appointments.custom_service_price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
153
  'bookly_appointments.start_date' => array( 'type' => "datetime", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
154
  'bookly_appointments.end_date' => array( 'type' => "datetime", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
155
- 'bookly_appointments.extras_duration' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
156
  'bookly_appointments.internal_note' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
157
  'bookly_appointments.google_event_id' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
158
  'bookly_appointments.google_event_etag' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
@@ -161,57 +161,45 @@ class QueryBuilder
161
  'bookly_appointments.outlook_event_series_id' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
162
  'bookly_appointments.created_from' => array( 'type' => "enum('bookly','google','outlook')", 'is_nullabe' => 0, 'extra' => "", 'default' => "bookly", 'key' => "" ),
163
  'bookly_appointments.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
164
- 'bookly_categories.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
165
  'bookly_categories.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
166
- 'bookly_categories.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
167
- 'bookly_coupons.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
 
 
 
 
 
 
 
 
 
168
  'bookly_coupons.code' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
169
  'bookly_coupons.discount' => array( 'type' => "decimal(3,0)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
170
  'bookly_coupons.deduction' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
171
- 'bookly_coupons.usage_limit' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
172
- 'bookly_coupons.used' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
173
  'bookly_coupons.once_per_customer' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
174
  'bookly_coupons.date_limit_start' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
175
  'bookly_coupons.date_limit_end' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
176
- 'bookly_coupons.min_appointments' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
177
- 'bookly_coupons.max_appointments' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
178
- 'bookly_coupon_customers.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
179
- 'bookly_coupon_customers.coupon_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
180
- 'bookly_coupon_customers.customer_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
181
- 'bookly_coupon_services.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
182
- 'bookly_coupon_services.coupon_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
183
- 'bookly_coupon_services.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
184
- 'bookly_coupon_staff.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
185
- 'bookly_coupon_staff.coupon_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
186
- 'bookly_coupon_staff.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
187
- 'bookly_customers.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
188
- 'bookly_customers.wp_user_id' => array( 'type' => "bigint(20) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
189
- 'bookly_customers.facebook_id' => array( 'type' => "bigint(20) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
190
- 'bookly_customers.group_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
191
- 'bookly_customers.full_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
192
- 'bookly_customers.first_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
193
- 'bookly_customers.last_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
194
- 'bookly_customers.phone' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
195
- 'bookly_customers.email' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
196
- 'bookly_customers.birthday' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
197
- 'bookly_customers.country' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
198
- 'bookly_customers.state' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
199
- 'bookly_customers.postcode' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
200
- 'bookly_customers.city' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
201
- 'bookly_customers.street' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
202
- 'bookly_customers.street_number' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
203
- 'bookly_customers.additional_address' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
204
- 'bookly_customers.notes' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
205
- 'bookly_customers.info_fields' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
206
- 'bookly_customers.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
207
- 'bookly_customer_appointments.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
208
- 'bookly_customer_appointments.series_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
209
- 'bookly_customer_appointments.package_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
210
- 'bookly_customer_appointments.customer_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
211
- 'bookly_customer_appointments.appointment_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
212
- 'bookly_customer_appointments.payment_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
213
- 'bookly_customer_appointments.number_of_persons' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
214
- 'bookly_customer_appointments.units' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
215
  'bookly_customer_appointments.notes' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
216
  'bookly_customer_appointments.extras' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
217
  'bookly_customer_appointments.extras_multiply_nop' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
@@ -221,54 +209,66 @@ class QueryBuilder
221
  'bookly_customer_appointments.status_changed_at' => array( 'type' => "datetime", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
222
  'bookly_customer_appointments.token' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
223
  'bookly_customer_appointments.time_zone' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
224
- 'bookly_customer_appointments.time_zone_offset' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
225
- 'bookly_customer_appointments.rating' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
226
  'bookly_customer_appointments.rating_comment' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
227
  'bookly_customer_appointments.locale' => array( 'type' => "varchar(8)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
228
- 'bookly_customer_appointments.collaborative_service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
229
  'bookly_customer_appointments.collaborative_token' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
230
- 'bookly_customer_appointments.compound_service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
231
  'bookly_customer_appointments.compound_token' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
232
  'bookly_customer_appointments.created_from' => array( 'type' => "enum('frontend','backend')", 'is_nullabe' => 0, 'extra' => "", 'default' => "frontend", 'key' => "" ),
233
  'bookly_customer_appointments.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
234
- 'bookly_customer_appointment_files.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
235
- 'bookly_customer_appointment_files.customer_appointment_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
236
- 'bookly_customer_appointment_files.file_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
237
- 'bookly_customer_groups.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
238
  'bookly_customer_groups.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
239
  'bookly_customer_groups.description' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
240
  'bookly_customer_groups.appointment_status' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
241
  'bookly_customer_groups.discount' => array( 'type' => "varchar(100)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
242
- 'bookly_customer_groups_services.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
243
- 'bookly_customer_groups_services.group_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
244
- 'bookly_customer_groups_services.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
245
- 'bookly_custom_statuses.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
246
- 'bookly_custom_statuses.slug' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "UNI" ),
247
- 'bookly_custom_statuses.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
248
- 'bookly_custom_statuses.busy' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
249
- 'bookly_custom_statuses.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
250
- 'bookly_files.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  'bookly_files.name' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
252
  'bookly_files.slug' => array( 'type' => "varchar(32)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
253
  'bookly_files.path' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
254
- 'bookly_files.custom_field_id' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
255
- 'bookly_holidays.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
256
- 'bookly_holidays.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
257
- 'bookly_holidays.parent_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
258
  'bookly_holidays.date' => array( 'type' => "date", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
259
  'bookly_holidays.repeat_event' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
260
- 'bookly_locations.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
261
  'bookly_locations.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
262
  'bookly_locations.info' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
263
- 'bookly_locations.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
264
- 'bookly_messages.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
265
- 'bookly_messages.message_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
266
  'bookly_messages.type' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
267
  'bookly_messages.subject' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
268
  'bookly_messages.body' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
269
  'bookly_messages.seen' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
270
  'bookly_messages.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
271
- 'bookly_notifications.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
272
  'bookly_notifications.gateway' => array( 'type' => "enum('email','sms')", 'is_nullabe' => 0, 'extra' => "", 'default' => "email", 'key' => "" ),
273
  'bookly_notifications.type' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
274
  'bookly_notifications.active' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
@@ -281,16 +281,16 @@ class QueryBuilder
281
  'bookly_notifications.attach_ics' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
282
  'bookly_notifications.attach_invoice' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
283
  'bookly_notifications.settings' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
284
- 'bookly_packages.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
285
- 'bookly_packages.location_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
286
- 'bookly_packages.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
287
- 'bookly_packages.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
288
- 'bookly_packages.customer_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
289
  'bookly_packages.internal_note' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
290
  'bookly_packages.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
291
- 'bookly_payments.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
292
- 'bookly_payments.coupon_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
293
- 'bookly_payments.type' => array( 'type' => "enum('local','free','paypal','authorize_net','stripe','2checkout','payu_biz','payu_latam','payson','mollie','woocommerce')", 'is_nullabe' => 0, 'extra' => "", 'default' => "local", 'key' => "" ),
294
  'bookly_payments.total' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
295
  'bookly_payments.tax' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
296
  'bookly_payments.paid' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
@@ -299,83 +299,83 @@ class QueryBuilder
299
  'bookly_payments.status' => array( 'type' => "enum('pending','completed','rejected')", 'is_nullabe' => 0, 'extra' => "", 'default' => "completed", 'key' => "" ),
300
  'bookly_payments.details' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
301
  'bookly_payments.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
302
- 'bookly_schedule_item_breaks.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
303
- 'bookly_schedule_item_breaks.staff_schedule_item_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
304
  'bookly_schedule_item_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
305
  'bookly_schedule_item_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
306
- 'bookly_sent_notifications.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
307
- 'bookly_sent_notifications.ref_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
308
- 'bookly_sent_notifications.notification_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
309
  'bookly_sent_notifications.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
310
- 'bookly_series.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
311
  'bookly_series.repeat' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
312
  'bookly_series.token' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
313
- 'bookly_services.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
314
- 'bookly_services.category_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
315
  'bookly_services.type' => array( 'type' => "enum('simple','collaborative','compound','package')", 'is_nullabe' => 0, 'extra' => "", 'default' => "simple", 'key' => "" ),
316
  'bookly_services.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
317
- 'bookly_services.duration' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "900", 'key' => "" ),
318
  'bookly_services.slot_length' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "default", 'key' => "" ),
319
  'bookly_services.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
320
  'bookly_services.color' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "#FFFFFF", 'key' => "" ),
321
  'bookly_services.deposit' => array( 'type' => "varchar(100)", 'is_nullabe' => 0, 'extra' => "", 'default' => "100%", 'key' => "" ),
322
- 'bookly_services.capacity_min' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
323
- 'bookly_services.capacity_max' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
324
  'bookly_services.one_booking_per_slot' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
325
- 'bookly_services.padding_left' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
326
- 'bookly_services.padding_right' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
327
  'bookly_services.info' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
328
  'bookly_services.start_time_info' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
329
  'bookly_services.end_time_info' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
330
- 'bookly_services.units_min' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
331
- 'bookly_services.units_max' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
332
- 'bookly_services.package_life_time' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
333
- 'bookly_services.package_size' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
334
  'bookly_services.package_unassigned' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
335
- 'bookly_services.appointments_limit' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
336
- 'bookly_services.limit_period' => array( 'type' => "enum('off','day','week','month','year','upcoming','calendar_day','calendar_week','calendar_month','calendar_year')", 'is_nullabe' => 0, 'extra' => "", 'default' => "off", 'key' => "" ),
337
- 'bookly_services.staff_preference' => array( 'type' => "enum('order','least_occupied','most_occupied','least_occupied_for_period','most_occupied_for_period','least_expensive','most_expensive')", 'is_nullabe' => 0, 'extra' => "", 'default' => "most_expensive", 'key' => "" ),
338
  'bookly_services.staff_preference_settings' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
339
  'bookly_services.recurrence_enabled' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
340
  'bookly_services.recurrence_frequencies' => array( 'type' => "set('daily','weekly','biweekly','monthly')", 'is_nullabe' => 0, 'extra' => "", 'default' => "daily,weekly,biweekly,monthly", 'key' => "" ),
341
  'bookly_services.time_requirements' => array( 'type' => "enum('required','optional','off')", 'is_nullabe' => 0, 'extra' => "", 'default' => "required", 'key' => "" ),
342
  'bookly_services.collaborative_equal_duration' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
343
  'bookly_services.visibility' => array( 'type' => "enum('public','private','group')", 'is_nullabe' => 0, 'extra' => "", 'default' => "public", 'key' => "" ),
344
- 'bookly_services.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
345
- 'bookly_service_extras.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
346
- 'bookly_service_extras.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
347
- 'bookly_service_extras.attachment_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
348
- 'bookly_service_extras.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
349
- 'bookly_service_extras.duration' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
350
- 'bookly_service_extras.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
351
- 'bookly_service_extras.max_quantity' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
352
- 'bookly_service_extras.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
353
- 'bookly_service_schedule_breaks.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
354
- 'bookly_service_schedule_breaks.service_schedule_day_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
355
- 'bookly_service_schedule_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
356
- 'bookly_service_schedule_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
357
- 'bookly_service_schedule_days.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
358
- 'bookly_service_schedule_days.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
359
- 'bookly_service_schedule_days.day_index' => array( 'type' => "smallint(6)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
360
- 'bookly_service_schedule_days.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
361
- 'bookly_service_schedule_days.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
362
- 'bookly_service_special_days.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
363
- 'bookly_service_special_days.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
364
- 'bookly_service_special_days.date' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
365
- 'bookly_service_special_days.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
366
- 'bookly_service_special_days.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
367
- 'bookly_service_special_days_breaks.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
368
- 'bookly_service_special_days_breaks.service_special_day_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
369
- 'bookly_service_special_days_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
370
- 'bookly_service_special_days_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
371
- 'bookly_service_taxes.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
372
- 'bookly_service_taxes.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
373
- 'bookly_service_taxes.tax_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
374
- 'bookly_shop.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
375
- 'bookly_shop.plugin_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
376
  'bookly_shop.type' => array( 'type' => "enum('plugin','bundle')", 'is_nullabe' => 0, 'extra' => "", 'default' => "plugin", 'key' => "" ),
377
  'bookly_shop.highlighted' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
378
- 'bookly_shop.priority' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => "0", 'key' => "" ),
379
  'bookly_shop.demo_url' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
380
  'bookly_shop.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
381
  'bookly_shop.slug' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
@@ -383,78 +383,78 @@ class QueryBuilder
383
  'bookly_shop.url' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
384
  'bookly_shop.icon' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
385
  'bookly_shop.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
386
- 'bookly_shop.sales' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
387
  'bookly_shop.rating' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
388
- 'bookly_shop.reviews' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
389
  'bookly_shop.published' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
390
  'bookly_shop.seen' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
391
  'bookly_shop.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
392
- 'bookly_special_days_breaks.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
393
- 'bookly_special_days_breaks.staff_special_day_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
394
  'bookly_special_days_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
395
  'bookly_special_days_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
396
- 'bookly_staff.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
397
- 'bookly_staff.category_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
398
- 'bookly_staff.wp_user_id' => array( 'type' => "bigint(20) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
399
- 'bookly_staff.attachment_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
400
  'bookly_staff.full_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
401
  'bookly_staff.email' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
402
  'bookly_staff.phone' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
403
  'bookly_staff.info' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
404
- 'bookly_staff.working_time_limit' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
405
  'bookly_staff.visibility' => array( 'type' => "enum('public','private','archive')", 'is_nullabe' => 0, 'extra' => "", 'default' => "public", 'key' => "" ),
406
- 'bookly_staff.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
407
  'bookly_staff.google_data' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
408
  'bookly_staff.outlook_data' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
409
- 'bookly_staff_categories.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
410
  'bookly_staff_categories.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
411
- 'bookly_staff_categories.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
412
- 'bookly_staff_locations.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
413
- 'bookly_staff_locations.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
414
- 'bookly_staff_locations.location_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
415
  'bookly_staff_locations.custom_services' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
416
  'bookly_staff_locations.custom_schedule' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
417
- 'bookly_staff_preference_orders.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
418
- 'bookly_staff_preference_orders.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
419
- 'bookly_staff_preference_orders.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
420
- 'bookly_staff_preference_orders.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
421
- 'bookly_staff_schedule_items.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
422
- 'bookly_staff_schedule_items.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
423
- 'bookly_staff_schedule_items.location_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
424
- 'bookly_staff_schedule_items.day_index' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
425
  'bookly_staff_schedule_items.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
426
  'bookly_staff_schedule_items.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
427
- 'bookly_staff_services.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
428
- 'bookly_staff_services.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
429
- 'bookly_staff_services.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
430
- 'bookly_staff_services.location_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
431
  'bookly_staff_services.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
432
  'bookly_staff_services.deposit' => array( 'type' => "varchar(100)", 'is_nullabe' => 0, 'extra' => "", 'default' => "100%", 'key' => "" ),
433
- 'bookly_staff_services.capacity_min' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
434
- 'bookly_staff_services.capacity_max' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
435
- 'bookly_staff_special_days.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
436
- 'bookly_staff_special_days.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
437
  'bookly_staff_special_days.date' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
438
  'bookly_staff_special_days.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
439
  'bookly_staff_special_days.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
440
- 'bookly_staff_special_hours.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
441
- 'bookly_staff_special_hours.staff_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
442
- 'bookly_staff_special_hours.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
443
- 'bookly_staff_special_hours.location_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
444
  'bookly_staff_special_hours.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
445
  'bookly_staff_special_hours.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
446
  'bookly_staff_special_hours.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
447
- 'bookly_stats.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
448
  'bookly_stats.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
449
  'bookly_stats.value' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
450
  'bookly_stats.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
451
- 'bookly_sub_services.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
452
  'bookly_sub_services.type' => array( 'type' => "enum('service','spare_time')", 'is_nullabe' => 0, 'extra' => "", 'default' => "service", 'key' => "" ),
453
- 'bookly_sub_services.service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
454
- 'bookly_sub_services.sub_service_id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
455
- 'bookly_sub_services.duration' => array( 'type' => "int(11)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
456
- 'bookly_sub_services.position' => array( 'type' => "int(11)", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
457
- 'bookly_taxes.id' => array( 'type' => "int(10) unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
458
  'bookly_taxes.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
459
  'bookly_taxes.rate' => array( 'type' => "decimal(10,3)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.000", 'key' => "" ),
460
  );
139
  FROM INFORMATION_SCHEMA.COLUMNS
140
  WHERE TABLE_SCHEMA = SCHEMA()
141
  AND TABLE_NAME LIKE 'wp_bookly_%'
142
+ ORDER BY TABLE_NAME, ORDINAL_POSITION
143
  */
144
 
145
  $data = array(
146
+ 'bookly_appointments.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
147
+ 'bookly_appointments.location_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
148
+ 'bookly_appointments.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
149
  'bookly_appointments.staff_any' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
150
+ 'bookly_appointments.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
151
  'bookly_appointments.custom_service_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
152
  'bookly_appointments.custom_service_price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
153
  'bookly_appointments.start_date' => array( 'type' => "datetime", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
154
  'bookly_appointments.end_date' => array( 'type' => "datetime", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
155
+ 'bookly_appointments.extras_duration' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
156
  'bookly_appointments.internal_note' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
157
  'bookly_appointments.google_event_id' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
158
  'bookly_appointments.google_event_etag' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
161
  'bookly_appointments.outlook_event_series_id' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
162
  'bookly_appointments.created_from' => array( 'type' => "enum('bookly','google','outlook')", 'is_nullabe' => 0, 'extra' => "", 'default' => "bookly", 'key' => "" ),
163
  'bookly_appointments.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
164
+ 'bookly_categories.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
165
  'bookly_categories.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
166
+ 'bookly_categories.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
167
+ 'bookly_coupon_customers.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
168
+ 'bookly_coupon_customers.coupon_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
169
+ 'bookly_coupon_customers.customer_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
170
+ 'bookly_coupon_services.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
171
+ 'bookly_coupon_services.coupon_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
172
+ 'bookly_coupon_services.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
173
+ 'bookly_coupon_staff.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
174
+ 'bookly_coupon_staff.coupon_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
175
+ 'bookly_coupon_staff.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
176
+ 'bookly_coupons.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
177
  'bookly_coupons.code' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
178
  'bookly_coupons.discount' => array( 'type' => "decimal(3,0)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
179
  'bookly_coupons.deduction' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
180
+ 'bookly_coupons.usage_limit' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
181
+ 'bookly_coupons.used' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
182
  'bookly_coupons.once_per_customer' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
183
  'bookly_coupons.date_limit_start' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
184
  'bookly_coupons.date_limit_end' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
185
+ 'bookly_coupons.min_appointments' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
186
+ 'bookly_coupons.max_appointments' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
187
+ 'bookly_custom_statuses.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
188
+ 'bookly_custom_statuses.slug' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "UNI" ),
189
+ 'bookly_custom_statuses.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
190
+ 'bookly_custom_statuses.busy' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
191
+ 'bookly_custom_statuses.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
192
+ 'bookly_customer_appointment_files.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
193
+ 'bookly_customer_appointment_files.customer_appointment_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
194
+ 'bookly_customer_appointment_files.file_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
195
+ 'bookly_customer_appointments.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
196
+ 'bookly_customer_appointments.series_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
197
+ 'bookly_customer_appointments.package_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
198
+ 'bookly_customer_appointments.customer_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
199
+ 'bookly_customer_appointments.appointment_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
200
+ 'bookly_customer_appointments.payment_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
201
+ 'bookly_customer_appointments.number_of_persons' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
202
+ 'bookly_customer_appointments.units' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  'bookly_customer_appointments.notes' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
204
  'bookly_customer_appointments.extras' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
205
  'bookly_customer_appointments.extras_multiply_nop' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
209
  'bookly_customer_appointments.status_changed_at' => array( 'type' => "datetime", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
210
  'bookly_customer_appointments.token' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
211
  'bookly_customer_appointments.time_zone' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
212
+ 'bookly_customer_appointments.time_zone_offset' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
213
+ 'bookly_customer_appointments.rating' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
214
  'bookly_customer_appointments.rating_comment' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
215
  'bookly_customer_appointments.locale' => array( 'type' => "varchar(8)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
216
+ 'bookly_customer_appointments.collaborative_service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
217
  'bookly_customer_appointments.collaborative_token' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
218
+ 'bookly_customer_appointments.compound_service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
219
  'bookly_customer_appointments.compound_token' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
220
  'bookly_customer_appointments.created_from' => array( 'type' => "enum('frontend','backend')", 'is_nullabe' => 0, 'extra' => "", 'default' => "frontend", 'key' => "" ),
221
  'bookly_customer_appointments.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
222
+ 'bookly_customer_groups.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
 
 
 
223
  'bookly_customer_groups.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
224
  'bookly_customer_groups.description' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
225
  'bookly_customer_groups.appointment_status' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
226
  'bookly_customer_groups.discount' => array( 'type' => "varchar(100)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
227
+ 'bookly_customer_groups_services.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
228
+ 'bookly_customer_groups_services.group_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
229
+ 'bookly_customer_groups_services.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
230
+ 'bookly_customers.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
231
+ 'bookly_customers.wp_user_id' => array( 'type' => "bigint unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
232
+ 'bookly_customers.facebook_id' => array( 'type' => "bigint unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
233
+ 'bookly_customers.group_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
234
+ 'bookly_customers.full_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
235
+ 'bookly_customers.first_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
236
+ 'bookly_customers.last_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
237
+ 'bookly_customers.phone' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
238
+ 'bookly_customers.email' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
239
+ 'bookly_customers.birthday' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
240
+ 'bookly_customers.country' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
241
+ 'bookly_customers.state' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
242
+ 'bookly_customers.postcode' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
243
+ 'bookly_customers.city' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
244
+ 'bookly_customers.street' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
245
+ 'bookly_customers.street_number' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
246
+ 'bookly_customers.additional_address' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
247
+ 'bookly_customers.notes' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
248
+ 'bookly_customers.info_fields' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
249
+ 'bookly_customers.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
250
+ 'bookly_files.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
251
  'bookly_files.name' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
252
  'bookly_files.slug' => array( 'type' => "varchar(32)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
253
  'bookly_files.path' => array( 'type' => "text", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
254
+ 'bookly_files.custom_field_id' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
255
+ 'bookly_holidays.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
256
+ 'bookly_holidays.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
257
+ 'bookly_holidays.parent_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
258
  'bookly_holidays.date' => array( 'type' => "date", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
259
  'bookly_holidays.repeat_event' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
260
+ 'bookly_locations.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
261
  'bookly_locations.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
262
  'bookly_locations.info' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
263
+ 'bookly_locations.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
264
+ 'bookly_messages.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
265
+ 'bookly_messages.message_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
266
  'bookly_messages.type' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
267
  'bookly_messages.subject' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
268
  'bookly_messages.body' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
269
  'bookly_messages.seen' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
270
  'bookly_messages.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
271
+ 'bookly_notifications.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
272
  'bookly_notifications.gateway' => array( 'type' => "enum('email','sms')", 'is_nullabe' => 0, 'extra' => "", 'default' => "email", 'key' => "" ),
273
  'bookly_notifications.type' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "", 'key' => "" ),
274
  'bookly_notifications.active' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
281
  'bookly_notifications.attach_ics' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
282
  'bookly_notifications.attach_invoice' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
283
  'bookly_notifications.settings' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
284
+ 'bookly_packages.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
285
+ 'bookly_packages.location_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
286
+ 'bookly_packages.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
287
+ 'bookly_packages.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
288
+ 'bookly_packages.customer_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
289
  'bookly_packages.internal_note' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
290
  'bookly_packages.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
291
+ 'bookly_payments.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
292
+ 'bookly_payments.coupon_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
293
+ 'bookly_payments.type' => array( 'type' => "enum('local','free','paypal','authorize_net','stripe','2checkout','payu_biz','payu_latam','payson','mollie','woocommerce')", 'is_nullabe' => 0, 'extra' => "", 'default' => "local", 'key' => "", ),
294
  'bookly_payments.total' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
295
  'bookly_payments.tax' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
296
  'bookly_payments.paid' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
299
  'bookly_payments.status' => array( 'type' => "enum('pending','completed','rejected')", 'is_nullabe' => 0, 'extra' => "", 'default' => "completed", 'key' => "" ),
300
  'bookly_payments.details' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
301
  'bookly_payments.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
302
+ 'bookly_schedule_item_breaks.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
303
+ 'bookly_schedule_item_breaks.staff_schedule_item_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
304
  'bookly_schedule_item_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
305
  'bookly_schedule_item_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
306
+ 'bookly_sent_notifications.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
307
+ 'bookly_sent_notifications.ref_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
308
+ 'bookly_sent_notifications.notification_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
309
  'bookly_sent_notifications.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
310
+ 'bookly_series.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
311
  'bookly_series.repeat' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
312
  'bookly_series.token' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
313
+ 'bookly_service_extras.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
314
+ 'bookly_service_extras.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
315
+ 'bookly_service_extras.attachment_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
316
+ 'bookly_service_extras.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
317
+ 'bookly_service_extras.duration' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
318
+ 'bookly_service_extras.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
319
+ 'bookly_service_extras.max_quantity' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
320
+ 'bookly_service_extras.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
321
+ 'bookly_service_schedule_breaks.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
322
+ 'bookly_service_schedule_breaks.service_schedule_day_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
323
+ 'bookly_service_schedule_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
324
+ 'bookly_service_schedule_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
325
+ 'bookly_service_schedule_days.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
326
+ 'bookly_service_schedule_days.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
327
+ 'bookly_service_schedule_days.day_index' => array( 'type' => "smallint", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
328
+ 'bookly_service_schedule_days.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
329
+ 'bookly_service_schedule_days.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
330
+ 'bookly_service_special_days.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
331
+ 'bookly_service_special_days.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
332
+ 'bookly_service_special_days.date' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
333
+ 'bookly_service_special_days.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
334
+ 'bookly_service_special_days.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
335
+ 'bookly_service_special_days_breaks.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
336
+ 'bookly_service_special_days_breaks.service_special_day_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
337
+ 'bookly_service_special_days_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
338
+ 'bookly_service_special_days_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
339
+ 'bookly_service_taxes.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
340
+ 'bookly_service_taxes.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
341
+ 'bookly_service_taxes.tax_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
342
+ 'bookly_services.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
343
+ 'bookly_services.category_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
344
  'bookly_services.type' => array( 'type' => "enum('simple','collaborative','compound','package')", 'is_nullabe' => 0, 'extra' => "", 'default' => "simple", 'key' => "" ),
345
  'bookly_services.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
346
+ 'bookly_services.duration' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "900", 'key' => "" ),
347
  'bookly_services.slot_length' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "default", 'key' => "" ),
348
  'bookly_services.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
349
  'bookly_services.color' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => "#FFFFFF", 'key' => "" ),
350
  'bookly_services.deposit' => array( 'type' => "varchar(100)", 'is_nullabe' => 0, 'extra' => "", 'default' => "100%", 'key' => "" ),
351
+ 'bookly_services.capacity_min' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
352
+ 'bookly_services.capacity_max' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
353
  'bookly_services.one_booking_per_slot' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
354
+ 'bookly_services.padding_left' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
355
+ 'bookly_services.padding_right' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
356
  'bookly_services.info' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
357
  'bookly_services.start_time_info' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
358
  'bookly_services.end_time_info' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
359
+ 'bookly_services.units_min' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
360
+ 'bookly_services.units_max' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
361
+ 'bookly_services.package_life_time' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
362
+ 'bookly_services.package_size' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
363
  'bookly_services.package_unassigned' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
364
+ 'bookly_services.appointments_limit' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
365
+ 'bookly_services.limit_period' => array( 'type' => "enum('off','day','week','month','year','upcoming','calendar_day','calendar_week','calendar_month','calendar_year')", 'is_nullabe' => 0, 'extra' => "", 'default' => "off", 'key' => "", ),
366
+ 'bookly_services.staff_preference' => array( 'type' => "enum('order','least_occupied','most_occupied','least_occupied_for_period','most_occupied_for_period','least_expensive','most_expensive')", 'is_nullabe' => 0, 'extra' => "", 'default' => "most_expensive", 'key' => "", ),
367
  'bookly_services.staff_preference_settings' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
368
  'bookly_services.recurrence_enabled' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
369
  'bookly_services.recurrence_frequencies' => array( 'type' => "set('daily','weekly','biweekly','monthly')", 'is_nullabe' => 0, 'extra' => "", 'default' => "daily,weekly,biweekly,monthly", 'key' => "" ),
370
  'bookly_services.time_requirements' => array( 'type' => "enum('required','optional','off')", 'is_nullabe' => 0, 'extra' => "", 'default' => "required", 'key' => "" ),
371
  'bookly_services.collaborative_equal_duration' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
372
  'bookly_services.visibility' => array( 'type' => "enum('public','private','group')", 'is_nullabe' => 0, 'extra' => "", 'default' => "public", 'key' => "" ),
373
+ 'bookly_services.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
374
+ 'bookly_shop.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
375
+ 'bookly_shop.plugin_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  'bookly_shop.type' => array( 'type' => "enum('plugin','bundle')", 'is_nullabe' => 0, 'extra' => "", 'default' => "plugin", 'key' => "" ),
377
  'bookly_shop.highlighted' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
378
+ 'bookly_shop.priority' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => "0", 'key' => "" ),
379
  'bookly_shop.demo_url' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
380
  'bookly_shop.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
381
  'bookly_shop.slug' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
383
  'bookly_shop.url' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
384
  'bookly_shop.icon' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
385
  'bookly_shop.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
386
+ 'bookly_shop.sales' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
387
  'bookly_shop.rating' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
388
+ 'bookly_shop.reviews' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
389
  'bookly_shop.published' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
390
  'bookly_shop.seen' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
391
  'bookly_shop.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
392
+ 'bookly_special_days_breaks.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
393
+ 'bookly_special_days_breaks.staff_special_day_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
394
  'bookly_special_days_breaks.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
395
  'bookly_special_days_breaks.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
396
+ 'bookly_staff.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
397
+ 'bookly_staff.category_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
398
+ 'bookly_staff.wp_user_id' => array( 'type' => "bigint unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
399
+ 'bookly_staff.attachment_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
400
  'bookly_staff.full_name' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
401
  'bookly_staff.email' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
402
  'bookly_staff.phone' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
403
  'bookly_staff.info' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
404
+ 'bookly_staff.working_time_limit' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
405
  'bookly_staff.visibility' => array( 'type' => "enum('public','private','archive')", 'is_nullabe' => 0, 'extra' => "", 'default' => "public", 'key' => "" ),
406
+ 'bookly_staff.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
407
  'bookly_staff.google_data' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
408
  'bookly_staff.outlook_data' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
409
+ 'bookly_staff_categories.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
410
  'bookly_staff_categories.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
411
+ 'bookly_staff_categories.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
412
+ 'bookly_staff_locations.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
413
+ 'bookly_staff_locations.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
414
+ 'bookly_staff_locations.location_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
415
  'bookly_staff_locations.custom_services' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
416
  'bookly_staff_locations.custom_schedule' => array( 'type' => "tinyint(1)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0", 'key' => "" ),
417
+ 'bookly_staff_preference_orders.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
418
+ 'bookly_staff_preference_orders.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
419
+ 'bookly_staff_preference_orders.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
420
+ 'bookly_staff_preference_orders.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
421
+ 'bookly_staff_schedule_items.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
422
+ 'bookly_staff_schedule_items.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
423
+ 'bookly_staff_schedule_items.location_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
424
+ 'bookly_staff_schedule_items.day_index' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
425
  'bookly_staff_schedule_items.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
426
  'bookly_staff_schedule_items.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
427
+ 'bookly_staff_services.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
428
+ 'bookly_staff_services.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
429
+ 'bookly_staff_services.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
430
+ 'bookly_staff_services.location_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
431
  'bookly_staff_services.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
432
  'bookly_staff_services.deposit' => array( 'type' => "varchar(100)", 'is_nullabe' => 0, 'extra' => "", 'default' => "100%", 'key' => "" ),
433
+ 'bookly_staff_services.capacity_min' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
434
+ 'bookly_staff_services.capacity_max' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "1", 'key' => "" ),
435
+ 'bookly_staff_special_days.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
436
+ 'bookly_staff_special_days.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
437
  'bookly_staff_special_days.date' => array( 'type' => "date", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
438
  'bookly_staff_special_days.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
439
  'bookly_staff_special_days.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
440
+ 'bookly_staff_special_hours.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
441
+ 'bookly_staff_special_hours.staff_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
442
+ 'bookly_staff_special_hours.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
443
+ 'bookly_staff_special_hours.location_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
444
  'bookly_staff_special_hours.start_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
445
  'bookly_staff_special_hours.end_time' => array( 'type' => "time", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
446
  'bookly_staff_special_hours.price' => array( 'type' => "decimal(10,2)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.00", 'key' => "" ),
447
+ 'bookly_stats.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
448
  'bookly_stats.name' => array( 'type' => "varchar(255)", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
449
  'bookly_stats.value' => array( 'type' => "text", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
450
  'bookly_stats.created' => array( 'type' => "datetime", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "" ),
451
+ 'bookly_sub_services.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
452
  'bookly_sub_services.type' => array( 'type' => "enum('service','spare_time')", 'is_nullabe' => 0, 'extra' => "", 'default' => "service", 'key' => "" ),
453
+ 'bookly_sub_services.service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "", 'default' => null, 'key' => "MUL" ),
454
+ 'bookly_sub_services.sub_service_id' => array( 'type' => "int unsigned", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "MUL" ),
455
+ 'bookly_sub_services.duration' => array( 'type' => "int", 'is_nullabe' => 1, 'extra' => "", 'default' => null, 'key' => "" ),
456
+ 'bookly_sub_services.position' => array( 'type' => "int", 'is_nullabe' => 0, 'extra' => "", 'default' => "9999", 'key' => "" ),
457
+ 'bookly_taxes.id' => array( 'type' => "int unsigned", 'is_nullabe' => 0, 'extra' => "auto_increment", 'default' => null, 'key' => "PRI" ),
458
  'bookly_taxes.title' => array( 'type' => "varchar(255)", 'is_nullabe' => 1, 'extra' => "", 'default' => "", 'key' => "" ),
459
  'bookly_taxes.rate' => array( 'type' => "decimal(10,3)", 'is_nullabe' => 0, 'extra' => "", 'default' => "0.000", 'key' => "" ),
460
  );
backend/modules/debug/lib/Schema.php CHANGED
@@ -74,15 +74,21 @@ class Schema
74
  global $wpdb;
75
 
76
  $tableStructure = array();
77
- $results = $wpdb->get_results( 'DESCRIBE `' . $table . '`;', ARRAY_A );
 
 
 
 
 
 
78
  if ( $results ) {
79
  foreach ( $results as $row ) {
80
- $tableStructure[ $row['Field'] ] = array(
81
- 'type' => $row['Type'],
82
- 'is_nullabe' => $row['Null'] === 'YES' ? 1 : 0,
83
- 'extra' => $row['Extra'],
84
- 'default' => $row['Default'],
85
- 'key' => $row['Key']
86
  );
87
  }
88
  }
74
  global $wpdb;
75
 
76
  $tableStructure = array();
77
+ $results = $wpdb->get_results( $wpdb->prepare( 'SELECT COLUMN_NAME,
78
+ CASE
79
+ WHEN DATA_TYPE IN( \'smallint\', \'int\', \'bigint\' ) THEN CONCAT( DATA_TYPE, IF(COLUMN_TYPE LIKE \'%unsigned\', \' unsigned\', \'\'))
80
+ ELSE COLUMN_TYPE
81
+ END AS DATA_TYPE,
82
+ IS_NULLABLE, COLUMN_KEY, COLUMN_DEFAULT, EXTRA
83
+ FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = %s', $table ), ARRAY_A );
84
  if ( $results ) {
85
  foreach ( $results as $row ) {
86
+ $tableStructure[ $row['COLUMN_NAME'] ] = array(
87
+ 'type' => $row['DATA_TYPE'],
88
+ 'is_nullabe' => $row['IS_NULLABLE'] === 'YES' ? 1 : 0,
89
+ 'extra' => $row['EXTRA'],
90
+ 'default' => $row['COLUMN_DEFAULT'],
91
+ 'key' => $row['COLUMN_KEY']
92
  );
93
  }
94
  }
backend/modules/debug/lib/tools/Plugins.php CHANGED
@@ -47,7 +47,7 @@ class Plugins extends Base
47
  }
48
  }
49
 
50
- $menu .= sprintf( '<li><a href="#" data-tool="%s" data-plugin="%s" data-action="%s">%s (%s)</li>', $this->tool, $slug, $action, $data['name'], $action );
51
  }
52
 
53
  return $menu;
47
  }
48
  }
49
 
50
+ $menu .= sprintf( '<a href="#" data-tool="%s" data-plugin="%s" data-action="%s" class="dropdown-item">%s (%s)</a>', $this->tool, $slug, $action, $data['name'], $action );
51
  }
52
 
53
  return $menu;
backend/modules/debug/resources/css/style.css CHANGED
@@ -1,19 +1,3 @@
1
- .panel {
2
- margin-right: 20px;
3
- margin-top: 20px;
4
- }
5
-
6
- .panel-body .list-group{
7
- margin-bottom: 0;
8
- }
9
-
10
- .list-group-item{
11
- padding: 5px 10px;
12
- }
13
- .btn-file {
14
- position: relative;
15
- overflow: hidden;
16
- }
17
  .btn-file input[type=file] {
18
  position: absolute;
19
  top: 0;
@@ -28,7 +12,4 @@
28
  background: white;
29
  cursor: inherit;
30
  display: block;
31
- }
32
- .bookly-data-button {
33
- display: inline-block;
34
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  .btn-file input[type=file] {
2
  position: absolute;
3
  top: 0;
12
  background: white;
13
  cursor: inherit;
14
  display: block;
 
 
 
15
  }
backend/modules/debug/resources/js/debug.js CHANGED
@@ -53,7 +53,7 @@ jQuery(function($) {
53
  e.preventDefault();
54
  $status = $(this).closest('td');
55
  let $tr = $(this).closest('tr'),
56
- table = $tr.closest('.panel-collapse').attr('id'),
57
  column = $tr.find('td:eq(0)').html(),
58
  ref_table = $tr.find('td:eq(1)').html(),
59
  ref_column = $tr.find('td:eq(2)').html()
@@ -61,7 +61,7 @@ jQuery(function($) {
61
  $('.bookly-js-loading:first-child', $addConstraintModal).addClass('bookly-loading').removeClass('collapse');
62
  $('.bookly-js-loading:last-child', $addConstraintModal).addClass('collapse');
63
  $('.bookly-js-fix-consistency', $addConstraintModal).hide();
64
- $addConstraintModal.modal();
65
  $.ajax({
66
  url: ajaxurl,
67
  type: 'POST',
@@ -97,10 +97,10 @@ jQuery(function($) {
97
  $buttonAction = $(this);
98
  $status = $(this).closest('td');
99
  let $tr = $(this).closest('tr'),
100
- table = $tr.closest('.panel-collapse').attr('id'),
101
  constrain = $tr.find('td:eq(2)').html()
102
  ;
103
- $dropConstraintModal.modal();
104
  $('#bookly-js-table', $dropConstraintModal).html(table);
105
  $('#bookly-js-constraint', $dropConstraintModal).html(constrain);
106
  });
@@ -126,7 +126,7 @@ jQuery(function($) {
126
  success : function (response) {
127
  if (response.success) {
128
  booklyAlert({success: [response.data.message]});
129
- $addConstraintModal.modal('hide');
130
  $status.html('OK');
131
  } else {
132
  booklyAlert({error : [response.data.message]});
@@ -209,13 +209,13 @@ jQuery(function($) {
209
  e.preventDefault();
210
  $status = $(this).closest('td');
211
  let $tr = $(this).closest('tr'),
212
- table = $tr.closest('.panel-collapse').attr('id'),
213
- column = $tr.find('td:eq(0)').html()
214
  ;
215
  $('.bookly-js-loading:first-child', $columnModal).addClass('bookly-loading').removeClass('collapse');
216
  $('.bookly-js-loading:last-child', $columnModal).addClass('collapse');
217
  $('.bookly-js-fix-consistency', $columnModal).hide();
218
- $columnModal.modal();
219
  $.ajax({
220
  url: ajaxurl,
221
  type: 'POST',
@@ -255,8 +255,9 @@ jQuery(function($) {
255
  success : function (response) {
256
  if (response.success) {
257
  booklyAlert({success: [response.data.message]});
258
- $columnModal.modal('hide');
259
  $status.html('OK');
 
260
  } else {
261
  booklyAlert({error : [response.data.message]});
262
  }
@@ -273,10 +274,10 @@ jQuery(function($) {
273
  .on('click', function (e) {
274
  e.preventDefault();
275
  $buttonAction = $(this);
276
- let table = $buttonAction.closest('.panel').find('.panel-collapse').attr('id');
277
  $('.bookly-js-loading:first-child', $tableModal).addClass('bookly-loading').removeClass('collapse');
278
  $('.bookly-js-loading:last-child', $tableModal).addClass('collapse');
279
- $tableModal.modal();
280
  $.ajax({
281
  url: ajaxurl,
282
  type: 'POST',
@@ -320,7 +321,7 @@ jQuery(function($) {
320
  success : function (response) {
321
  if (response.success) {
322
  booklyAlert({success: [response.data.message]});
323
- $tableModal.modal('hide');
324
  $buttonAction.closest('.panel').find('.panel-body').html('Refresh the current page');
325
  $buttonAction.remove();
326
  } else {
@@ -353,7 +354,7 @@ jQuery(function($) {
353
  success : function (response) {
354
  if (response.success) {
355
  booklyAlert({success: [response.data.message]});
356
- $dropConstraintModal.modal('hide');
357
  $buttonAction.closest('tr').remove();
358
  } else {
359
  booklyAlert({error : [response.data.message]});
53
  e.preventDefault();
54
  $status = $(this).closest('td');
55
  let $tr = $(this).closest('tr'),
56
+ table = $tr.closest('.card').find('.bookly-js-table').attr('id'),
57
  column = $tr.find('td:eq(0)').html(),
58
  ref_table = $tr.find('td:eq(1)').html(),
59
  ref_column = $tr.find('td:eq(2)').html()
61
  $('.bookly-js-loading:first-child', $addConstraintModal).addClass('bookly-loading').removeClass('collapse');
62
  $('.bookly-js-loading:last-child', $addConstraintModal).addClass('collapse');
63
  $('.bookly-js-fix-consistency', $addConstraintModal).hide();
64
+ $addConstraintModal.booklyModal();
65
  $.ajax({
66
  url: ajaxurl,
67
  type: 'POST',
97
  $buttonAction = $(this);
98
  $status = $(this).closest('td');
99
  let $tr = $(this).closest('tr'),
100
+ table = $tr.closest('.card').find('.bookly-js-table').attr('id'),
101
  constrain = $tr.find('td:eq(2)').html()
102
  ;
103
+ $dropConstraintModal.booklyModal();
104
  $('#bookly-js-table', $dropConstraintModal).html(table);
105
  $('#bookly-js-constraint', $dropConstraintModal).html(constrain);
106
  });
126
  success : function (response) {
127
  if (response.success) {
128
  booklyAlert({success: [response.data.message]});
129
+ $addConstraintModal.booklyModal('hide');
130
  $status.html('OK');
131
  } else {
132
  booklyAlert({error : [response.data.message]});
209
  e.preventDefault();
210
  $status = $(this).closest('td');
211
  let $tr = $(this).closest('tr'),
212
+ table = $tr.closest('.card').find('.bookly-js-table').attr('id'),
213
+ column = $tr.find('td:eq(0)').html().trim()
214
  ;
215
  $('.bookly-js-loading:first-child', $columnModal).addClass('bookly-loading').removeClass('collapse');
216
  $('.bookly-js-loading:last-child', $columnModal).addClass('collapse');
217
  $('.bookly-js-fix-consistency', $columnModal).hide();
218
+ $columnModal.booklyModal();
219
  $.ajax({
220
  url: ajaxurl,
221
  type: 'POST',
255
  success : function (response) {
256
  if (response.success) {
257
  booklyAlert({success: [response.data.message]});
258
+ $columnModal.booklyModal('hide');
259
  $status.html('OK');
260
+ $status.closest('tr').removeClass('bg-danger');
261
  } else {
262
  booklyAlert({error : [response.data.message]});
263
  }
274
  .on('click', function (e) {
275
  e.preventDefault();
276
  $buttonAction = $(this);
277
+ let table = $buttonAction.parent().attr('id');
278
  $('.bookly-js-loading:first-child', $tableModal).addClass('bookly-loading').removeClass('collapse');
279
  $('.bookly-js-loading:last-child', $tableModal).addClass('collapse');
280
+ $tableModal.booklyModal();
281
  $.ajax({
282
  url: ajaxurl,
283
  type: 'POST',
321
  success : function (response) {
322
  if (response.success) {
323
  booklyAlert({success: [response.data.message]});
324
+ $tableModal.booklyModal('hide');
325
  $buttonAction.closest('.panel').find('.panel-body').html('Refresh the current page');
326
  $buttonAction.remove();
327
  } else {
354
  success : function (response) {
355
  if (response.success) {
356
  booklyAlert({success: [response.data.message]});
357
+ $dropConstraintModal.booklyModal('hide');
358
  $buttonAction.closest('tr').remove();
359
  } else {
360
  booklyAlert({error : [response.data.message]});
backend/modules/debug/templates/index.php CHANGED
@@ -3,163 +3,155 @@ use Bookly\Backend\Components\Controls\Inputs;
3
  use Bookly\Backend\Components\Controls\Buttons;
4
  ?>
5
  <div id="bookly-tbs" class="wrap">
6
- <div class="bookly-tbs-body">
7
- <div class="page-header text-right clearfix">
8
- <div class="bookly-page-title">
9
- Data management
10
- </div>
11
- </div>
12
- <?php if ( $import_status ) : ?>
13
- <div class="alert alert-success">
14
- Data successfully imported
15
- </div>
16
- <?php endif ?>
17
 
18
- <div class="panel-group" id="data-management">
19
- <div class="bookly-data-button">
20
- <form action="<?php echo admin_url( 'admin-ajax.php?action=bookly_export_data' ) ?>" method="POST">
21
- <?php Inputs::renderCsrf() ?>
22
- <button id="bookly-export" type="submit" class="btn btn-lg btn-success">
23
- <span class="ladda-label">Export data</span>
24
- </button>
25
- </form>
26
- </div>
27
- <div class="bookly-data-button">
28
- <form id="bookly_import" action="<?php echo admin_url( 'admin-ajax.php?action=bookly_import_data' ) ?>" method="POST" enctype="multipart/form-data">
29
- <?php Inputs::renderCsrf() ?>
30
- <div id="bookly-import" class="btn btn-lg btn-primary btn-file">
31
- <span class="ladda-label">Import data</span>
32
- <input type="file" id="bookly_import_file" name="import">
33
- </div>
34
- </form>
35
- </div>
36
- <div class="bookly-data-button pull-right" >
37
- <div class="dropdown pull-left bookly-margin-right-xs">
38
- <button class="btn btn-lg btn-default dropdown-toggle" type="button" data-spinner-size="40" data-style="zoom-in" data-spinner-color="rgb(62, 66, 74)" id="tools-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
39
- <span class="ladda-label">Tools</span>
40
- <span class="caret"></span>
41
- </button>
42
- <ul class="dropdown-menu bookly-js-tools" aria-labelledby="dropdownMenu1">
43
- <?php echo $tools ?>
44
- </ul>
45
  </div>
46
- <?php Bookly\Backend\Components\Controls\Buttons::renderCustom( 'bookly-all-test', 'btn-default btn-lg', 'Tests', array( 'data-spinner-color' => 'rgb(62, 66, 74)' ) ) ?>
47
- <?php Bookly\Backend\Components\Controls\Buttons::renderCustom( 'bookly-fix-all-silent', 'btn-success btn-lg', 'Fix database schema ...' ) ?>
48
- </div>
49
  </div>
50
- <div class="page-header text-right clearfix">
51
- <div class="bookly-page-title">
52
- Database Integrity
 
 
 
 
 
 
 
53
  </div>
54
  </div>
55
- <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
 
 
 
 
 
 
 
 
 
56
  <?php foreach ( $debug as $tableName => $table ) : ?>
57
- <div class="panel <?php echo $table['status'] == 1 ? 'panel-success' : 'panel-danger' ?> bookly-margin-right-remove">
58
- <div class="panel-heading" role="tab" id="heading_<?php echo $tableName ?>">
59
- <h4 class="panel-title">
60
- <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#<?php echo $tableName ?>" aria-expanded="true" aria-controls="<?php echo $tableName ?>">
61
- <?php echo $tableName ?>
62
- </a>
63
- <?php if ( ! $table['status'] ) : ?>
64
- <button class="btn btn-success btn-xs pull-right" type="button" data-action="fix-create-table">create</button>
65
- <?php endif ?>
66
- </h4>
67
- </div>
68
- <div id="<?php echo $tableName ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="<?php echo $tableName ?>">
69
- <div class="panel-body">
70
- <?php if ( $table['status'] ) : ?>
71
- <h4>Columns</h4>
72
- <table class="table table-condensed">
73
- <thead>
74
- <tr>
75
- <th>Column name</th>
76
- <th width="50">Status</th>
77
- </tr>
78
- </thead>
79
- <tbody>
80
- <?php foreach ( $table['fields'] as $field => $status ) : ?>
81
- <tr class="<?php echo $status ? 'default' : 'danger' ?>">
82
- <td><?php echo $field ?>
83
- <?php if ( isset( $table['info'][ $field ] ) ) : ?>
84
- <div class="pull-right">
85
  <?php foreach ( $table['info'][ $field ] as $key ) : ?>
86
- <span class="label label-warning" style="margin: 0 5px;"><?php echo $key ?></span>
87
  <?php endforeach ?>
88
- </div>
89
- <?php endif ?>
90
- </td>
91
- <td><?php echo $status ? 'OK' : '<button class="btn btn-success btn-xs" type="button" data-action="fix-column">FIX…</button>' ?></td>
92
- </tr>
93
- <?php endforeach ?>
94
- </tbody>
95
- </table>
96
- <?php if ( $table['constraints'] ) : ?>
97
- <h4>Constraints</h4>
98
- <table class="table table-condensed">
99
- <thead>
100
- <tr>
101
- <th>Column name</th>
102
- <th>Referenced table name</th>
103
- <th>Referenced column name</th>
104
- <th width="50">Status</th>
105
- </tr>
106
- </thead>
107
- <tbody>
108
- <?php foreach ( $table['constraints'] as $key => $constraint ) : ?>
109
- <tr class="<?php echo $constraint['status'] ? 'default' : 'danger' ?>">
110
- <td><?php echo $constraint['column_name'] ?></td>
111
- <td><?php echo $constraint['referenced_table_name'] ?></td>
112
- <td><?php echo $constraint['referenced_column_name'] ?></td>
113
- <td><?php echo $constraint['status'] ? 'OK' : '<button class="btn btn-success btn-xs" type="button" data-action="fix-constraint">FIX…</button>' ?></td>
114
- </tr>
115
- <?php endforeach ?>
116
- </tbody>
117
- </table>
118
- <?php endif ?>
119
- <?php if ( $table['constraints_3d'] ) : ?>
120
- <h4>Third-party constraints</h4>
121
- <table class="table table-condensed">
122
- <thead>
123
- <tr>
124
- <th>Column name</th>
125
- <th>Reference</th>
126
- <th>Name</th>
127
- <th width="50">Status</th>
128
- </tr>
129
- </thead>
130
- <tbody>
131
- <?php foreach ( $table['constraints_3d'] as $key => $constraint ) : ?>
132
- <tr class="<?php echo $constraint['status'] ? 'default' : 'danger' ?>">
133
- <td><?php echo $constraint['column_name'] ?></td>
134
- <td><?php echo $constraint['referenced_table_name'] . '.' . $constraint['referenced_column_name'] ?>
135
- <?php if ( ! $constraint['reference_exists'] ) : ?><div class="pull-right"><span class="label label-warning" style="margin: 0 5px;">not exist</span><?php endif ?></div></td>
136
- <td><?php echo $constraint['constraint_name'] ?></td>
137
- <td><?php if ( $constraint['status'] ) : ?>
138
- OK
139
- <?php else : ?>
140
- <button class="btn btn-xs <?php echo $constraint['reference_exists']?'btn-danger':'btn-success' ?>" type="button" data-action="drop-constraint">DROP…</button>
141
- <?php endif ?>
142
- </td>
143
- </tr>
144
- <?php endforeach ?>
145
- </tbody>
146
- </table>
147
- <?php endif ?>
148
- <?php else : ?>
149
- Table does not exist
150
- <?php endif ?>
151
- </div>
152
- </div>
153
  </div>
154
- <?php endforeach ?>
155
- </div>
156
  </div>
157
- <div id="bookly-js-add-constraint" class="modal fade" tabindex="-1" role="dialog">
 
158
  <div class="modal-dialog" role="document">
159
  <div class="modal-content">
160
  <div class="modal-header">
161
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
162
- <h4 class="modal-title">Add constraint</h4>
163
  </div>
164
  <div class="modal-body">
165
  <div class="bookly-js-loading" style="height: 120px;"></div>
@@ -188,66 +180,66 @@ ADD CONSTRAINT
188
  <div class="modal-footer">
189
  <div class="pull-left">
190
  <div class="btn-group bookly-js-fix-consistency">
191
- <button type="button" class="btn btn-lg btn-danger bookly-js-auto ladda-button" data-spinner-size="40" data-style="zoom-in" data-action="fix-consistency"><span class="ladda-label">Consistency…</span></button>
192
- <button type="button" class="btn btn-lg btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
193
  <span class="caret"></span>
194
  <span class="sr-only">Toggle Dropdown</span>
195
  </button>
196
- <ul class="dropdown-menu">
197
- <li><a class="bookly-js-update" href="#" data-action="fix-consistency">UPDATE `<span class="bookly-js-table"></span>` SET `<span class="bookly-js-ref_column"></span>` = NULL WHERE `<span class="bookly-js-ref_column"></span>` NOT IN (…)</a></li>
198
- <li><a class="bookly-js-delete" href="#" data-action="fix-consistency">DELETE FROM `<span class="bookly-js-table"></span>` WHERE `<span class="bookly-js-ref_column"></span>` NOT IN (…)</a></li>
199
- </ul>
200
  </div>
201
  </div>
202
- <?php Buttons::renderCustom( null, 'bookly-js-delete btn-lg btn-danger pull-left', 'Delete rows…', array( 'style' => 'display:none' ) ) ?>
203
- <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', 'Add constraint' ) ?>
204
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', 'Close', array( 'data-dismiss' => 'modal' ) ) ?>
205
  </div>
206
  </div>
207
  </div>
208
  </div>
209
- <div id="bookly-js-add-field" class="modal fade" tabindex="-1" role="dialog">
210
- <div class="modal-dialog" role="document">
211
  <div class="modal-content">
212
  <div class="modal-header">
213
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
214
- <h4 class="modal-title">Add column</h4>
215
  </div>
216
  <div class="modal-body">
217
  <div class="bookly-js-loading" style="height: 120px;"></div>
218
  <div class="bookly-js-loading"><pre></pre></div>
219
  </div>
220
  <div class="modal-footer">
221
- <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', 'Add column' ) ?>
222
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', 'Close', array( 'data-dismiss' => 'modal' ) ) ?>
223
  </div>
224
  </div>
225
  </div>
226
  </div>
227
- <div id="bookly-js-create-table" class="modal fade" tabindex="-1" role="dialog">
228
- <div class="modal-dialog" role="document">
229
  <div class="modal-content">
230
  <div class="modal-header">
231
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
232
- <h4 class="modal-title">Create table</h4>
233
  </div>
234
  <div class="modal-body">
235
  <div class="bookly-js-loading" style="height: 120px;"></div>
236
  <div class="bookly-js-loading"><pre></pre></div>
237
  </div>
238
  <div class="modal-footer">
239
- <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', 'Create table' ) ?>
240
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', 'Close', array( 'data-dismiss' => 'modal' ) ) ?>
241
  </div>
242
  </div>
243
  </div>
244
  </div>
245
- <div id="bookly-js-drop-constraint" class="modal fade" tabindex="-1" role="dialog">
246
  <div class="modal-dialog" role="document">
247
  <div class="modal-content">
248
  <div class="modal-header">
249
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
250
- <h4 class="modal-title">Drop foreign key</h4>
251
  </div>
252
  <div class="modal-body">
253
  <div class="bookly-js-loading"><pre>
@@ -255,8 +247,8 @@ ADD CONSTRAINT
255
  DROP FOREIGN KEY `<span id="bookly-js-constraint"></span>`</pre></div>
256
  </div>
257
  <div class="modal-footer">
258
- <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', 'Drop' ) ?>
259
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', 'Close', array( 'data-dismiss' => 'modal' ) ) ?>
260
  </div>
261
  </div>
262
  </div>
3
  use Bookly\Backend\Components\Controls\Buttons;
4
  ?>
5
  <div id="bookly-tbs" class="wrap">
6
+ <div class="form-row align-items-center mb-3">
7
+ <h4 class="col m-0">Data management</h4>
8
+ </div>
 
 
 
 
 
 
 
 
9
 
10
+ <div class="form-row">
11
+ <div class="col-12 col-sm-auto mb-3">
12
+ <form action="<?php echo admin_url( 'admin-ajax.php?action=bookly_export_data' ) ?>" method="POST">
13
+ <?php Inputs::renderCsrf() ?>
14
+ <button id="bookly-export" type="submit" class="btn btn-success">
15
+ <span class="ladda-label">Export data</span>
16
+ </button>
17
+ </form>
18
+ </div>
19
+ <div class="col-12 col-sm-auto mb-3">
20
+ <form id="bookly_import" action="<?php echo admin_url( 'admin-ajax.php?action=bookly_import_data' ) ?>" method="POST" enctype="multipart/form-data">
21
+ <?php Inputs::renderCsrf() ?>
22
+ <div id="bookly-import" class="btn btn-primary btn-file">
23
+ <span class="ladda-label">Import data</span>
24
+ <input type="file" id="bookly_import_file" name="import" class="w-100">
 
 
 
 
 
 
 
 
 
 
 
 
25
  </div>
26
+ </form>
 
 
27
  </div>
28
+ <div class="col-12 col-sm-auto ml-auto mb-3">
29
+ <div class="dropdown">
30
+ <button class="btn btn-default dropdown-toggle" type="button" data-spinner-size="40" data-style="zoom-in" data-spinner-color="rgb(62, 66, 74)" id="tools-dropdown" data-toggle="dropdown" aria-haspopup="true"
31
+ aria-expanded="true">
32
+ <span class="ladda-label">Tools</span>
33
+ <span class="caret"></span>
34
+ </button>
35
+ <div class="dropdown-menu bookly-js-tools" aria-labelledby="dropdownMenu1">
36
+ <?php echo $tools ?>
37
+ </div>
38
  </div>
39
  </div>
40
+ <div class="col-12 col-sm-auto mb-3">
41
+ <?php Bookly\Backend\Components\Controls\Buttons::render( 'bookly-all-test', 'btn-default', 'Tests', array( 'data-spinner-color' => 'rgb(62, 66, 74)' ) ) ?>
42
+ </div>
43
+ <div class="col-12 col-sm-auto mb-3">
44
+ <?php Bookly\Backend\Components\Controls\Buttons::render( 'bookly-fix-all-silent', $trouble ? 'btn-success' : 'btn-default', 'Fix database schema…' ) ?>
45
+ </div>
46
+ </div>
47
+
48
+ <div class="card">
49
+ <div class="card-body" id="accordion" role="tablist" aria-multiselectable="true">
50
  <?php foreach ( $debug as $tableName => $table ) : ?>
51
+ <div class="card bookly-collapse my-1">
52
+ <div class="card-header py-1 d-flex align-items-center bookly-js-table <?php echo $table['status'] == 1 ? '' : 'bg-danger' ?>" role="tab" id="<?php echo $tableName ?>">
53
+ <a role="button" class="collapsed" role="button" data-toggle="collapse" href="#table-<?php echo $tableName ?>" aria-expanded="true" aria-controls="<?php echo $tableName ?>">
54
+ <?php echo $tableName ?>
55
+ </a>
56
+ <?php if ( ! $table['status'] ) : ?>
57
+ <button class="btn btn-success btn-sm py-0 ml-auto" type="button" data-action="fix-create-table">create</button>
58
+ <?php endif ?>
59
+ </div>
60
+ <div class="card-body collapse" id="table-<?php echo $tableName ?>">
61
+ <?php if ( $table['status'] ) : ?>
62
+ <h5>Columns</h5>
63
+ <table class="table table-condensed table-striped table-sm">
64
+ <thead>
65
+ <tr>
66
+ <th>Column name</th>
67
+ <th width="50">Status</th>
68
+ </tr>
69
+ </thead>
70
+ <tbody>
71
+ <?php foreach ( $table['fields'] as $field => $status ) : ?>
72
+ <tr class="<?php echo $status ? 'bg-default' : 'bg-danger' ?>">
73
+ <td><?php echo $field ?>
74
+ <?php if ( isset( $table['info'][ $field ] ) ) : ?>
75
+ <div class="float-right">
 
 
 
76
  <?php foreach ( $table['info'][ $field ] as $key ) : ?>
77
+ <span class="badge badge-warning" style="margin: 0 5px;"><?php echo $key ?></span>
78
  <?php endforeach ?>
79
+ </div>
80
+ <?php endif ?>
81
+ </td>
82
+ <td><?php echo $status ? 'OK' : '<button class="btn btn-success btn-sm py-0" type="button" data-action="fix-column">FIX…</button>' ?></td>
83
+ </tr>
84
+ <?php endforeach ?>
85
+ </tbody>
86
+ </table>
87
+ <?php if ( $table['constraints'] ) : ?>
88
+ <h5>Constraints</h5>
89
+ <table class="table table-condensed table-striped table-sm">
90
+ <thead>
91
+ <tr>
92
+ <th>Column name</th>
93
+ <th>Referenced table name</th>
94
+ <th>Referenced column name</th>
95
+ <th width="50">Status</th>
96
+ </tr>
97
+ </thead>
98
+ <tbody>
99
+ <?php foreach ( $table['constraints'] as $key => $constraint ) : ?>
100
+ <tr class="<?php echo $constraint['status'] ? 'bg-default' : 'bg-danger' ?>">
101
+ <td><?php echo $constraint['column_name'] ?></td>
102
+ <td><?php echo $constraint['referenced_table_name'] ?></td>
103
+ <td><?php echo $constraint['referenced_column_name'] ?></td>
104
+ <td><?php echo $constraint['status'] ? 'OK' : '<button class="btn btn-success btn-sm py-0" type="button" data-action="fix-constraint">FIX…</button>' ?></td>
105
+ </tr>
106
+ <?php endforeach ?>
107
+ </tbody>
108
+ </table>
109
+ <?php endif ?>
110
+ <?php if ( $table['constraints_3d'] ) : ?>
111
+ <h5>Third-party constraints</h5>
112
+ <table class="table table-condensed table-sm">
113
+ <thead>
114
+ <tr>
115
+ <th>Column name</th>
116
+ <th>Reference</th>
117
+ <th>Name</th>
118
+ <th width="50">Status</th>
119
+ </tr>
120
+ </thead>
121
+ <tbody>
122
+ <?php foreach ( $table['constraints_3d'] as $key => $constraint ) : ?>
123
+ <tr class="<?php echo $constraint['status'] ? 'default' : 'danger' ?>">
124
+ <td><?php echo $constraint['column_name'] ?></td>
125
+ <td><?php echo $constraint['referenced_table_name'] . '.' . $constraint['referenced_column_name'] ?>
126
+ <?php if ( ! $constraint['reference_exists'] ) : ?>
127
+ <div class="float-right"><span class="badge badge-warning" style="margin: 0 5px;">not exist</span><?php endif ?></div>
128
+ </td>
129
+ <td><?php echo $constraint['constraint_name'] ?></td>
130
+ <td><?php if ( $constraint['status'] ) : ?>
131
+ OK
132
+ <?php else : ?>
133
+ <button class="btn btn-sm py-0 <?php echo $constraint['reference_exists'] ? 'btn-danger' : 'btn-success' ?>" type="button" data-action="drop-constraint">DROP…</button>
134
+ <?php endif ?>
135
+ </td>
136
+ </tr>
137
+ <?php endforeach ?>
138
+ </tbody>
139
+ </table>
140
+ <?php endif ?>
141
+ <?php else : ?>
142
+ Table does not exist
143
+ <?php endif ?>
144
  </div>
145
+ </div>
146
+ <?php endforeach ?>
147
  </div>
148
+ </div>
149
+ <div id="bookly-js-add-constraint" class="bookly-modal bookly-fade" tabindex="-1" role="dialog">
150
  <div class="modal-dialog" role="document">
151
  <div class="modal-content">
152
  <div class="modal-header">
153
+ <h5 class="modal-title">Add constraint</h5>
154
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
155
  </div>
156
  <div class="modal-body">
157
  <div class="bookly-js-loading" style="height: 120px;"></div>
180
  <div class="modal-footer">
181
  <div class="pull-left">
182
  <div class="btn-group bookly-js-fix-consistency">
183
+ <button type="button" class="btn btn-danger bookly-js-auto ladda-button" data-spinner-size="40" data-style="zoom-in" data-action="fix-consistency"><span class="ladda-label">Consistency…</span></button>
184
+ <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
185
  <span class="caret"></span>
186
  <span class="sr-only">Toggle Dropdown</span>
187
  </button>
188
+ <div class="dropdown-menu">
189
+ <a class="bookly-js-update dropdown-item" href="#" data-action="fix-consistency">UPDATE `<span class="bookly-js-table"></span>` SET `<span class="bookly-js-ref_column"></span>` = NULL WHERE `<span class="bookly-js-ref_column"></span>` NOT IN (…)</a>
190
+ <a class="bookly-js-delete dropdown-item" href="#" data-action="fix-consistency">DELETE FROM `<span class="bookly-js-table"></span>` WHERE `<span class="bookly-js-ref_column"></span>` NOT IN (…)</a>
191
+ </div>
192
  </div>
193
  </div>
194
+ <?php Buttons::render( null, 'bookly-js-delete btn-danger pull-left', 'Delete rows…', array( 'style' => 'display:none' ) ) ?>
195
+ <?php Buttons::render( null, 'bookly-js-save btn-success', 'Add constraint' ) ?>
196
+ <?php Buttons::renderCancel( 'Close' ) ?>
197
  </div>
198
  </div>
199
  </div>
200
  </div>
201
+ <div id="bookly-js-add-field" class="bookly-modal bookly-fade" tabindex="-1" role="dialog">
202
+ <div class="modal-dialog modal-lg" role="document">
203
  <div class="modal-content">
204
  <div class="modal-header">
205
+ <h5 class="modal-title">Add column</h5>
206
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
207
  </div>
208
  <div class="modal-body">
209
  <div class="bookly-js-loading" style="height: 120px;"></div>
210
  <div class="bookly-js-loading"><pre></pre></div>
211
  </div>
212
  <div class="modal-footer">
213
+ <?php Buttons::render( null, 'bookly-js-save btn-success', 'Add column' ) ?>
214
+ <?php Buttons::renderCancel( 'Close' ) ?>
215
  </div>
216
  </div>
217
  </div>
218
  </div>
219
+ <div id="bookly-js-create-table" class="bookly-modal bookly-fade" tabindex="-1" role="dialog">
220
+ <div class="modal-dialog modal-lg" role="document">
221
  <div class="modal-content">
222
  <div class="modal-header">
223
+ <h5 class="modal-title">Create table</h5>
224
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
225
  </div>
226
  <div class="modal-body">
227
  <div class="bookly-js-loading" style="height: 120px;"></div>
228
  <div class="bookly-js-loading"><pre></pre></div>
229
  </div>
230
  <div class="modal-footer">
231
+ <?php Buttons::render( null, 'bookly-js-save btn-success', 'Create table' ) ?>
232
+ <?php Buttons::renderCancel( 'Close' ) ?>
233
  </div>
234
  </div>
235
  </div>
236
  </div>
237
+ <div id="bookly-js-drop-constraint" class="bookly-modal bookly-fade" tabindex="-1" role="dialog">
238
  <div class="modal-dialog" role="document">
239
  <div class="modal-content">
240
  <div class="modal-header">
241
+ <h5 class="modal-title">Drop foreign key</h5>
242
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
243
  </div>
244
  <div class="modal-body">
245
  <div class="bookly-js-loading"><pre>
247
  DROP FOREIGN KEY `<span id="bookly-js-constraint"></span>`</pre></div>
248
  </div>
249
  <div class="modal-footer">
250
+ <?php Buttons::render( null, 'bookly-js-save btn-success', 'Drop' ) ?>
251
+ <?php Buttons::renderCancel( 'Close' ) ?>
252
  </div>
253
  </div>
254
  </div>
backend/modules/messages/Page.php CHANGED
@@ -15,7 +15,7 @@ class Page extends Lib\Base\Component
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
- 'backend' => array( 'bootstrap/css/bootstrap-theme.min.css', ),
19
  ) );
20
 
21
  self::enqueueScripts( array(
15
  public static function render()
16
  {
17
  self::enqueueStyles( array(
18
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
19
  ) );
20
 
21
  self::enqueueScripts( array(
backend/modules/messages/resources/js/message.js CHANGED
@@ -6,7 +6,9 @@ jQuery(function($) {
6
  * Init DataTables.
7
  */
8
  var dt = $message_list.DataTable({
9
- paging: true,
 
 
10
  ordering: false,
11
  info: false,
12
  searching: false,
@@ -55,16 +57,10 @@ jQuery(function($) {
55
  },
56
  { data: 'body' }
57
  ],
 
58
  language: {
59
  zeroRecords: BooklyL10n.datatable.zeroRecords,
60
  processing: BooklyL10n.datatable.processing,
61
- sLengthMenu: '_MENU_ ' + BooklyL10n.datatable.per_page,
62
- paginate: {
63
- first: BooklyL10n.datatable.paginate.first,
64
- previous: BooklyL10n.datatable.paginate.previous,
65
- next: BooklyL10n.datatable.paginate.next,
66
- last: BooklyL10n.datatable.paginate.last
67
- }
68
  }
69
  });
70
 
6
  * Init DataTables.
7
  */
8
  var dt = $message_list.DataTable({
9
+ pageLength : 25,
10
+ pagingType : 'numbers',
11
+ lengthChange: false,
12
  ordering: false,
13
  info: false,
14
  searching: false,
57
  },
58
  { data: 'body' }
59
  ],
60
+ dom : "<'row'<'col-sm-12'tr>><'row float-left mt-3'<'col-sm-12'p>>",
61
  language: {
62
  zeroRecords: BooklyL10n.datatable.zeroRecords,
63
  processing: BooklyL10n.datatable.processing,
 
 
 
 
 
 
 
64
  }
65
  });
66
 
backend/modules/messages/templates/index.php CHANGED
@@ -1,26 +1,22 @@
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
- use Bookly\Backend\Components;
3
  ?>
4
  <div id="bookly-tbs" class="wrap">
5
- <div class="bookly-tbs-body">
6
- <div class="page-header text-right clearfix">
7
- <div class="bookly-page-title">
8
- <?php _e( 'Messages', 'bookly' ) ?>
9
- </div>
10
- <?php Components\Support\Buttons::render( $self::pageSlug() ) ?>
11
- </div>
12
- <div class="panel panel-default bookly-main">
13
- <div class="panel-body">
14
- <table id="bookly-messages-list" class="table table-striped" width="100%">
15
- <thead>
16
- <tr>
17
- <th><?php _e( 'Date', 'bookly' ) ?></th>
18
- <th><?php _e( 'Subject', 'bookly' ) ?></th>
19
- <th><?php _e( 'Message', 'bookly' ) ?></th>
20
- </tr>
21
- </thead>
22
- </table>
23
- </div>
24
  </div>
25
  </div>
26
  </div>
1
  <?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
2
+ use Bookly\Backend\Components\Support;
3
  ?>
4
  <div id="bookly-tbs" class="wrap">
5
+ <div class="form-row align-items-center mb-3">
6
+ <h4 class="col m-0"><?php esc_html_e( 'Messages', 'bookly' ) ?></h4>
7
+ <?php Support\Buttons::render( $self::pageSlug() ) ?>
8
+ </div>
9
+ <div class="card">
10
+ <div class="card-body">
11
+ <table id="bookly-messages-list" class="table table-striped w-100">
12
+ <thead>
13
+ <tr>
14
+ <th><?php esc_html_e( 'Date', 'bookly' ) ?></th>
15
+ <th><?php esc_html_e( 'Subject', 'bookly' ) ?></th>
16
+ <th><?php esc_html_e( 'Message', 'bookly' ) ?></th>
17
+ </tr>
18
+ </thead>
19
+ </table>
 
 
 
 
20
  </div>
21
  </div>
22
  </div>
backend/modules/notifications/Page.php CHANGED
@@ -16,7 +16,7 @@ class Page extends Lib\Base\Component
16
  {
17
  self::enqueueStyles( array(
18
  'frontend' => array( 'css/ladda.min.css' ),
19
- 'backend' => array( 'bootstrap/css/bootstrap-theme.min.css', ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
16
  {
17
  self::enqueueStyles( array(
18
  'frontend' => array( 'css/ladda.min.css' ),
19
+ 'backend' => array( 'bootstrap/css/bootstrap.min.css', ),
20
  ) );
21
 
22
  self::enqueueScripts( array(
backend/modules/notifications/lib/Codes.php CHANGED
@@ -127,14 +127,14 @@ class Codes
127
  $tbody = '';
128
  foreach ( $codes as $code => $description ) {
129
  $tbody .= sprintf(
130
- '<tr><td><input value="{%s}" readonly="readonly" onclick="this.select()" /> - %s</td></tr>',
131
  $code,
132
  esc_html( $description )
133
  );
134
  }
135
 
136
  printf(
137
- '<table class="bookly-codes bookly-js-codes-%s"><tbody>%s</tbody></table>',
138
  $notification_type,
139
  $tbody
140
  );
@@ -237,14 +237,14 @@ class Codes
237
  $tbody = '';
238
  foreach ( $codes as $code => $description ) {
239
  $tbody .= sprintf(
240
- '<tr><td><input value="{%s}" readonly="readonly" onclick="this.select()" /> - %s</td></tr>',
241
  $code,
242
  esc_html( $description )
243
  );
244
  }
245
 
246
  $result = sprintf(
247
- '<table class="bookly-codes"><tbody>%s</tbody></table>',
248
  $tbody
249
  );
250
 
127
  $tbody = '';
128
  foreach ( $codes as $code => $description ) {
129
  $tbody .= sprintf(
130
+ '<tr><td class="p-0"><input value="{%s}" class="border-0" readonly="readonly" onclick="this.select()" /> &ndash; %s</td></tr>',
131
  $code,
132
  esc_html( $description )
133
  );
134
  }
135
 
136
  printf(
137
+ '<table class="bookly-js-codes bookly-js-codes-%s"><tbody>%s</tbody></table>',
138
  $notification_type,
139
  $tbody
140
  );
237
  $tbody = '';
238
  foreach ( $codes as $code => $description ) {
239
  $tbody .= sprintf(
240
+ '<tr><td class="p-0"><input value="{%s}" readonly="readonly" class="border-0" onclick="this.select()" /> - %s</td></tr>',
241
  $code,
242
  esc_html( $description )
243
  );
244
  }
245
 
246
  $result = sprintf(
247
+ '<table class="overflow-auto" style="max-height: 300px"><tbody>%s</tbody></table>',
248
  $tbody
249
  );
250
 
backend/modules/notifications/templates/_common_settings.php CHANGED
@@ -25,7 +25,7 @@ $bookly_email_sender = get_option( 'bookly_email_sender' ) == '' ?
25
  <div class="row">
26
  <div class="col-md-12">
27
  <?php Selects::renderRadios( 'bookly_email_send_as', __( 'Send emails as', 'bookly' ), __( 'HTML allows formatting, colors, fonts, positioning, etc. With Text you must use Text mode of rich-text editors below. On some servers only text emails are sent successfully.', 'bookly' ),
28
- array( array( 'html', __( 'HTML', 'bookly' ) ), array( 'text', __( 'Text', 'bookly' ) ) )
29
  ) ?>
30
  </div>
31
  </div>
25
  <div class="row">
26
  <div class="col-md-12">
27
  <?php Selects::renderRadios( 'bookly_email_send_as', __( 'Send emails as', 'bookly' ), __( 'HTML allows formatting, colors, fonts, positioning, etc. With Text you must use Text mode of rich-text editors below. On some servers only text emails are sent successfully.', 'bookly' ),
28
+ array( 'html' => array( 'title' => __( 'HTML', 'bookly' ) ), 'text' => array( 'title' => __( 'Text', 'bookly' ) ) )
29
  ) ?>
30
  </div>
31
  </div>
backend/modules/notifications/templates/_general_settings_modal.php CHANGED
@@ -8,12 +8,12 @@ foreach ( range( 1, 23 ) as $hours ) {
8
  $bookly_ntf_processing_interval_values[] = array( $hours, Utils\DateTime::secondsToInterval( $hours * HOUR_IN_SECONDS ) );
9
  }
10
  ?>
11
- <form id="bookly-js-general-settings-modal" class="modal fade" tabindex=-1 role="dialog">
12
  <div class="modal-dialog">
13
  <div class="modal-content">
14
  <div class="modal-header">
15
- <button type="button" class="close" data-dismiss="modal"><span>×</span></button>
16
- <div class="modal-title h2"><?php esc_html_e( 'General settings', 'bookly' ) ?></div>
17
  </div>
18
  <div class="modal-body">
19
  <?php self::renderTemplate( '_common_settings', array( 'tail' => '_gen' ) ) ?>
@@ -25,8 +25,8 @@ foreach ( range( 1, 23 ) as $hours ) {
25
  </div>
26
  <div class="modal-footer">
27
  <?php Inputs::renderCsrf() ?>
28
- <?php Buttons::renderCustom( null, 'bookly-js-save btn-lg btn-success', __( 'Save settings', 'bookly' ) ) ?>
29
- <?php Buttons::renderCustom( null, 'btn-lg btn-default', __( 'Close', 'bookly' ), array( 'data-dismiss' => 'modal' ) ) ?>
30
  </div>
31
  </div>
32
  </div>
8
  $bookly_ntf_processing_interval_values[] = array( $hours, Utils\DateTime::secondsToInterval( $hours * HOUR_IN_SECONDS ) );
9
  }
10
  ?>
11
+ <form id="bookly-js-general-settings-modal" class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
12
  <div class="modal-dialog">
13
  <div class="modal-content">
14
  <div class="modal-header">
15
+ <h5 class="modal-title"><?php esc_html_e( 'General settings', 'bookly' ) ?></h5>
16
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
17
  </div>
18
  <div class="modal-body">
19
  <?php self::renderTemplate( '_common_settings', array( 'tail' => '_gen' ) ) ?>
25
  </div>
26
  <div class="modal-footer">
27
  <?php Inputs::renderCsrf() ?>
28
+ <?php Buttons::renderSubmit( null, 'bookly-js-save', __( 'Save settings', 'bookly' ) ) ?>
29
+ <?php Buttons::renderCancel( __( 'Close', 'bookly' ) ) ?>
30
  </div>
31
  </div>
32
  </div>
backend/modules/notifications/templates/_test_email_modal.php CHANGED
@@ -2,13 +2,13 @@
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
- <div id=bookly-test-email-notifications-modal class="modal fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <form>
9
  <div class="modal-header">
10
- <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
11
- <div class="modal-title h2"><?php esc_html_e( 'Test email notifications', 'bookly' ) ?></div>
12
  </div>
13
  <div class="modal-body">
14
  <div class="row">
@@ -20,35 +20,29 @@ use Bookly\Backend\Components\Controls\Inputs;
20
  </div>
21
  </div>
22
  <?php self::renderTemplate( '_common_settings', array( 'tail' => '_test' ) ) ?>
23
- <div>
24
- <div class="btn-group bookly-margin-bottom-lg">
25
- <button class="btn btn-default btn-block dropdown-toggle bookly-flexbox" data-toggle="dropdown">
26
- <div class="bookly-flex-cell text-left" style="width: 100%">
27
- <?php esc_html_e( 'Notification templates', 'bookly' ) ?>
28
- (<span class="bookly-js-count">0</span>)
29
- </div>
30
- <div class="bookly-flex-cell">
31
- <div class="bookly-margin-left-md"><span class="caret"></span></div>
32
- </div>
33
- </button>
34
- <ul class="dropdown-menu" style="width: 570px">
35
- <li class="bookly-padding-horizontal-md">
36
- <div class="checkbox">
37
- <label>
38
- <input type="checkbox" id="bookly-check-all-entities"/>
39
- <?php esc_html_e( 'All templates', 'bookly' ) ?>
40
- </label>
41
  </div>
42
- </li>
43
- <li role="separator" class="divider"></li>
44
- <li id="bookly-js-test-notifications-list"></li>
45
- </ul>
46
  </div>
47
  </div>
48
  </div>
49
  <div class="modal-footer">
50
  <?php Inputs::renderCsrf() ?>
51
- <?php Buttons::renderCustom( null, 'btn-lg btn-success', esc_attr__( 'Send', 'bookly' ), array( 'disabled' => 'disabled' ) ) ?>
52
  </div>
53
  </form>
54
  </div>
2
  use Bookly\Backend\Components\Controls\Buttons;
3
  use Bookly\Backend\Components\Controls\Inputs;
4
  ?>
5
+ <div id=bookly-test-email-notifications-modal class="bookly-modal bookly-fade" tabindex=-1 role="dialog">
6
  <div class="modal-dialog">
7
  <div class="modal-content">
8
  <form>
9
  <div class="modal-header">
10
+ <h5 class="modal-title"><?php esc_html_e( 'Test email notifications', 'bookly' ) ?></h5>
11
+ <button type="button" class="close" data-dismiss="bookly-modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
12
  </div>
13
  <div class="modal-body">
14
  <div class="row">
20
  </div>
21
  </div>
22
  <?php self::renderTemplate( '_common_settings', array( 'tail' => '_test' ) ) ?>
23
+ <div class="row">
24
+ <div class="col-md-12">
25
+ <div class="form-group">
26
+ <div class="dropdown">
27
+ <button class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-display="static">
28
+ <?php esc_html_e( 'Notification templates', 'bookly' ) ?>
29
+ (<span class="bookly-js-count">0</span>)
30
+ </button>
31
+ <div class="dropdown-menu">
32
+ <div class="dropdown-item my-0 pl-3">
33
+ <?php Inputs::renderCheckBox( __( 'All templates', 'bookly' ), null, null, array( 'id' => 'bookly-check-all-entities' ) ) ?>
34
+ </div>
35
+ <div class="dropdown-divider"></div>
36
+ <div id="bookly-js-test-notifications-list"></div>
 
 
 
 
37
  </div>
38
+ </div>
39
+ </div>
 
 
40
  </div>
41
  </div>
42
  </div>
43
  <div class="modal-footer">
44
  <?php Inputs::renderCsrf() ?>
45
+ <?php Buttons::render( null, 'btn-success', __( 'Send', 'bookly' ), array( 'disabled' => 'disabled' ) ) ?>
46
  </div>
47
  </form>
48
  </div>
backend/modules/notifications/templates/index.php CHANGED
@@ -5,40 +5,38 @@ use Bookly\Backend\Components\Dialogs;
5
  use Bookly\Backend\Components\Support;
6
  use Bookly\Lib\Utils\Common;
7
  use Bookly\Lib\Config;
 
8
  /** @var array $datatables */
9
  ?>
10
  <div id="bookly-tbs" class="wrap">
11
- <div class="bookly-tbs-body">
12
- <div class="page-header text-right clearfix">
13
- <div class="bookly-page-title">
14
- <?php esc_html_e( 'Email notifications', 'bookly' ) ?>
15
- </div>
16
- <?php Support\Buttons::render( $self::pageSlug() ) ?>
17
- </div>
18
- <form method="post" action="<?php echo Common::escAdminUrl( $self::pageSlug() ) ?>">
19
- <div class="panel panel-default bookly-main">
20
- <div class="panel-body">
21
- <div class="row">
22
- <div class="col-md-4">
23
- <div class="form-group">
24
- <input class="form-control" type="text" id="bookly-filter" placeholder="<?php esc_attr_e( 'Quick search notifications', 'bookly' ) ?>" />
25
- </div>
26
- </div>
27
- <div class="col-md-8 form-inline bookly-margin-bottom-lg text-right">
28
- <div class="form-group">
29
- <?php Buttons::renderCustom( 'bookly-js-settings', 'btn-default', esc_html__( 'General settings...', 'bookly' ) ) ?>
30
- </div>
31
- <?php Dialogs\Notifications\Dialog::renderNewNotificationButton() ?>
32
- <?php Dialogs\TableSettings\Dialog::renderButton( 'email_notifications', 'BooklyL10n' ) ?>
33
- </div>
34
  </div>
35
-
36
- <table id="bookly-js-notification-list" class="table table-striped" style="width: 100%">
 
 
 
 
 
 
 
 
 
 
37
  <thead>
38
  <tr>
39
  <?php foreach ( $datatables['email_notifications']['settings']['columns'] as $column => $show ) : ?>
40
  <?php if ( $show ) : ?>
41
- <?php if ( $column == 'type' ) : ?>
42
  <th width="1"></th>
43
  <?php else : ?>
44
  <th><?php echo $datatables['email_notifications']['titles'][ $column ] ?></th>
@@ -46,42 +44,40 @@ use Bookly\Lib\Config;
46
  <?php endif ?>
47
  <?php endforeach ?>
48
  <th width="75"></th>
49
- <th width="16"><input type="checkbox" class="bookly-js-check-all"/></th>
50
  </tr>
51
  </thead>
52
  </table>
53
-
54
- <div class="form-inline bookly-margin-bottom-lg text-right">
55
- <?php Inputs::renderCsrf() ?>
56
- <?php Buttons::renderDelete( 'bookly-js-delete-notifications' ) ?>
57
-
58
- <div class="pull-left">
59
- <button type="button" class="btn btn-default" id="bookly-js-test-email-notifications">
60
- <?php esc_html_e( 'Test email notifications...', 'bookly' ) ?>
61
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
62
  </div>
63
  </div>
64
- <?php if ( Config::proActive() ) : ?>
65
- <div class="alert alert-info">
66
- <div class="row">
67
- <div class="col-md-12">
68
- <?php if ( is_multisite() ) : ?>
69
- <p><?php printf( __( 'To send scheduled notifications please refer to <a href="%1$s">Bookly Multisite</a> add-on <a href="%2$s">message</a>.', 'bookly' ), Common::prepareUrlReferrers( 'http://codecanyon.net/item/bookly-multisite-addon/13903524?ref=ladela', 'cron_setup' ), network_admin_url( 'admin.php?page=bookly-multisite-network' ) ) ?></p>
70
- <?php else : ?>
71
- <p><?php esc_html_e( 'To send scheduled notifications please execute the following command hourly with your cron:', 'bookly' ) ?></p>
72
- <code class="bookly-text-wrap">wget -q -O - <?php echo site_url( 'wp-cron.php' ) ?></code>
73
- <?php endif ?>
74
- </div>
75
- </div>
76
- </div>
77
- <?php endif ?>
78
  </div>
79
- </div>
80
- </form>
81
-
82
- <?php $self::renderTemplate( '_test_email_modal' ) ?>
83
- <?php $self::renderTemplate( '_general_settings_modal' ) ?>
84
- <?php Dialogs\Notifications\Dialog::render() ?>
85
- <?php Dialogs\TableSettings\Dialog::render() ?>
86
  </div>
 
 
 
 
 
87
  </div>
5
  use Bookly\Backend\Components\Support;
6
  use Bookly\Lib\Utils\Common;
7
  use Bookly\Lib\Config;
8
+
9
  /** @var array $datatables */
10
  ?>
11
  <div id="bookly-tbs" class="wrap">
12
+ <div class="form-row align-items-center mb-3">
13
+ <h4 class="col m-0"><?php esc_html_e( 'Email notifications', 'bookly' ) ?></h4>
14
+ <?php Support\Buttons::render( $self::pageSlug() ) ?>
15
+ </div>
16
+ <div class="card">
17
+ <div class="card-body">
18
+ <div class="row">
19
+ <div class="col-md-4">
20
+ <div class="form-group">
21
+ <input class="form-control" type="text" id="bookly-filter" placeholder="<?php esc_attr_e( 'Quick search notifications', 'bookly' ) ?>"/>
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  </div>
23
+ </div>
24
+ <div class="col-md-8 form-row justify-content-end pr-0">
25
+ <div class="col-auto">
26
+ <?php Buttons::renderDefault( 'bookly-js-settings', null, __( 'General settings', 'bookly' ), array(), true ) ?>
27
+ </div>
28
+ <?php Dialogs\Notifications\Dialog::renderNewNotificationButton() ?>
29
+ <?php Dialogs\TableSettings\Dialog::renderButton( 'email_notifications', 'BooklyL10n' ) ?>
30
+ </div>
31
+ </div>
32
+ <div class="row">
33
+ <div class="col">
34
+ <table id="bookly-js-notification-list" class="table table-striped w-100">
35
  <thead>
36
  <tr>
37
  <?php foreach ( $datatables['email_notifications']['settings']['columns'] as $column => $show ) : ?>
38
  <?php if ( $show ) : ?>
39
+ <?php if ( $column == 'type' ) : ?>
40
  <th width="1"></th>
41
  <?php else : ?>
42
  <th><?php echo $datatables['email_notifications']['titles'][ $column ] ?></th>
44
  <?php endif ?>
45
  <?php endforeach ?>
46
  <th width="75"></th>
47
+ <th width="16"><?php Inputs::renderCheckBox( null, null, null, array( 'id' => 'bookly-check-all' ) ) ?></th>
48
  </tr>
49
  </thead>
50
  </table>
51
+ </div>
52
+ </div>
53
+ <div class="form-row mb-3">
54
+ <div class="col-auto">
55
+ <?php Inputs::renderCsrf() ?>
56
+ <?php Buttons::renderDefault( 'bookly-js-test-email-notifications', null, __( 'Test email notifications', 'bookly' ), array(), true ) ?>
57
+ </div>
58
+ <div class="ml-auto mr-1">
59
+ <?php Buttons::renderDelete( 'bookly-js-delete-notifications' ) ?>
60
+ </div>
61
+ </div>
62
+ <?php if ( Config::proActive() ) : ?>
63
+ <div class="alert alert-info">
64
+ <div class="row">
65
+ <div class="col-md-12">
66
+ <?php if ( is_multisite() ) : ?>
67
+ <p><?php printf( __( 'To send scheduled notifications please refer to <a href="%1$s">Bookly Multisite</a> add-on <a href="%2$s">message</a>.', 'bookly' ), Common::prepareUrlReferrers( 'http://codecanyon.net/item/bookly-multisite-addon/13903524?ref=ladela', 'cron_setup' ), network_admin_url( 'admin.php?page=bookly-multisite-network' ) ) ?></p>
68
+ <?php else : ?>
69
+ <p><?php esc_html_e( 'To send scheduled notifications please execute the following command hourly with your cron:', 'bookly' ) ?></p>
70
+ <code>wget -q -O - <?php echo site_url( 'wp-cron.php' ) ?></code>
71
+ <?php endif ?>
72
  </div>
73
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
  </div>
75
+ <?php endif ?>
76
+ </div>
 
 
 
 
 
77
  </div>
78
+
79
+ <?php $self::renderTemplate( '_test_email_modal' ) ?>
80
+ <?php $self::renderTemplate( '_general_settings_modal' ) ?>
81
+ <?php Dialogs\Notifications\Dialog::render() ?>
82
+ <?php Dialogs\TableSettings\Dialog::render() ?>
83
  </div>
backend/modules/payments/Page.php CHANGED
@@ -16,11 +16,7 @@ class Page extends Lib\Base\Component
16
  {
17
  self::enq
16
  {
17
  self::enq