Version Description
- Fixed disabling SMS and email notifications
Download this release
Release Info
Developer | Ladela |
Plugin | WordPress Online Booking and Scheduling Plugin – Bookly |
Version | 7.6.1 |
Comparing to | |
See all releases |
Code changes from version 2.0.1 to 7.6.1
- autoload.php +19 -0
- backend/AB_Backend.php +65 -183
- backend/modules/appearance/AB_AppearanceController.php +108 -37
- backend/modules/appearance/resources/css/appearance.css +25 -8
- backend/modules/appearance/resources/js/appearance.js +192 -85
- backend/modules/appearance/templates/_1_service.php +75 -133
- backend/modules/appearance/templates/_2_time.php +185 -101
- backend/modules/appearance/templates/_3_details.php +36 -42
- backend/modules/appearance/templates/_4_payment.php +38 -19
- backend/modules/appearance/templates/_5_done.php +3 -10
- backend/modules/appearance/templates/_card_payment.php +34 -0
- backend/modules/appearance/templates/_codes.php +16 -0
- backend/modules/appearance/templates/_progress_tracker.php +8 -7
- backend/modules/appearance/templates/index.php +84 -79
- backend/modules/appointments/AB_AppointmentsController.php +276 -0
- backend/modules/appointments/resources/js/ng-app.js +208 -0
- backend/modules/appointments/templates/index.php +79 -0
- backend/modules/calendar/AB_CalendarController.php +363 -549
- backend/modules/calendar/forms/AB_AppointmentForm.php +6 -7
- backend/modules/calendar/forms/AB_CustomerAppointmentForm.php +17 -0
- backend/modules/calendar/resources/css/calendar.css +68 -28
- backend/modules/calendar/resources/css/chosen.css +0 -437
- backend/modules/calendar/resources/css/fullcalendar.min.css +5 -0
- backend/modules/calendar/resources/css/jquery-ui-1.10.1.css +0 -1174
- backend/modules/calendar/resources/css/jquery.weekcalendar.css +0 -287
- backend/modules/calendar/resources/images/calendar1.png +0 -0
- backend/modules/calendar/resources/images/chosen-sprite.png +0 -0
- backend/modules/calendar/resources/images/information.png +0 -0
- backend/modules/calendar/resources/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- backend/modules/calendar/resources/images/user-white.png +0 -0
- backend/modules/calendar/resources/images/user.png +0 -0
- backend/modules/calendar/resources/js/calendar.js +350 -492
- backend/modules/calendar/resources/js/calendar_daypicker.js +0 -126
- backend/modules/calendar/resources/js/calendar_weekpicker.js +0 -168
- backend/modules/calendar/resources/js/chosen.jquery.js +0 -1229
- backend/modules/calendar/resources/js/fc-multistaff-view.js +160 -0
- backend/modules/calendar/resources/js/fullcalendar.min.js +8 -0
- backend/modules/calendar/resources/js/jquery.weekcalendar.js +0 -2951
- backend/modules/calendar/resources/js/ng-app.js +0 -379
- backend/modules/calendar/templates/_appointment_form.php +108 -0
- backend/modules/calendar/templates/_custom_fields_form.php +77 -0
- backend/modules/calendar/templates/appointment_form.php +0 -93
- backend/modules/calendar/templates/calendar.php +56 -121
- backend/modules/coupons/AB_CouponsController.php +43 -0
- backend/modules/coupons/resources/css/coupons.css +20 -0
- backend/modules/coupons/resources/js/coupons.js +5 -0
- backend/modules/coupons/templates/_list.php +4 -0
- backend/modules/coupons/templates/index.php +35 -0
- backend/modules/custom_fields/AB_CustomFieldsController.php +63 -0
- backend/modules/custom_fields/resources/css/custom_fields.css +86 -0
- backend/modules/custom_fields/resources/js/custom_fields.js +166 -0
- backend/modules/custom_fields/templates/index.php +134 -0
- backend/modules/customer/AB_CustomerController.php +161 -113
- backend/modules/customer/forms/AB_CustomerForm.php +9 -9
- backend/modules/customer/resources/css/customers.css +10 -0
- backend/modules/customer/resources/js/ng-app.js +344 -214
- backend/modules/customer/templates/_import.php +37 -0
- backend/modules/customer/templates/index.php +124 -94
- backend/modules/customer/templates/ng-new_customer_dialog.php +107 -46
- backend/modules/export/AB_ExportController.php +0 -123
- backend/modules/export/templates/index.php +0 -47
- backend/modules/notifications/AB_NotificationsController.php +56 -48
- backend/modules/notifications/forms/AB_NotificationsForm.php +166 -0
- backend/modules/notifications/resources/css/notifications.css +29 -0
- backend/modules/notifications/resources/js/notification.js +30 -0
- backend/modules/notifications/templates/_codes.php +24 -0
- backend/modules/notifications/templates/_codes_client_new_wp_user.php +12 -0
- backend/modules/notifications/templates/_codes_staff_agenda.php +4 -0
- backend/modules/notifications/templates/_tags_client_info.php +0 -48
- backend/modules/notifications/templates/_tags_evening_after.php +0 -40
- backend/modules/notifications/templates/_tags_evening_next_day.php +0 -40
- backend/modules/notifications/templates/_tags_event_next_day.php +0 -8
- backend/modules/notifications/templates/_tags_provider_info.php +0 -60
- backend/modules/notifications/templates/index.php +130 -115
- backend/modules/payment/AB_PaymentController.php +72 -47
- backend/modules/payment/templates/_alert.php +2 -2
- backend/modules/payment/templates/index.php +131 -63
- backend/modules/service/AB_ServiceController.php +188 -80
- backend/modules/service/forms/AB_CategoryForm.php +5 -5
- backend/modules/service/forms/AB_ServiceForm.php +18 -17
- backend/modules/service/resources/css/service.css +104 -13
- backend/modules/service/resources/js/service.js +311 -256
- backend/modules/service/templates/_list.php +177 -0
- backend/modules/service/templates/index.php +100 -55
- backend/modules/service/templates/list.php +0 -31
- backend/modules/service/templates/list_item.php +0 -96
- backend/modules/settings/AB_SettingsController.php +177 -133
- backend/modules/settings/forms/AB_BusinessHoursForm.php +28 -21
- backend/modules/settings/forms/AB_CompanyForm.php +26 -20
- backend/modules/settings/forms/AB_PaymentsForm.php +0 -19
- backend/modules/settings/resources/js/settings.js +66 -16
- backend/modules/settings/templates/_companyForm.php +24 -22
- backend/modules/settings/templates/_customers.php +48 -0
- backend/modules/settings/templates/_generalForm.php +87 -68
- backend/modules/settings/templates/_googleCalendarForm.php +110 -0
- backend/modules/settings/templates/_holidaysForm.php +10 -10
- backend/modules/settings/templates/_hoursForm.php +20 -20
- backend/modules/settings/templates/_paymentsForm.php +44 -48
- backend/modules/settings/templates/_purchaseCodeForm.php +0 -26
- backend/modules/settings/templates/_woocommerce.php +77 -0
- backend/modules/settings/templates/admin_notice.php +4 -3
- backend/modules/settings/templates/index.php +68 -30
- backend/modules/sms/AB_SmsController.php +46 -0
- backend/modules/sms/resources/css/flags.css +230 -0
- backend/modules/sms/resources/css/flags.png +0 -0
- backend/modules/sms/resources/css/sms.css +53 -0
- backend/modules/sms/resources/js/sms.js +6 -0
- backend/modules/sms/templates/_price.php +21 -0
- backend/modules/sms/templates/index.php +110 -0
- backend/modules/staff/AB_StaffController.php +335 -179
- backend/modules/staff/forms/AB_StaffMemberEditForm.php +40 -21
- backend/modules/staff/forms/AB_StaffMemberForm.php +30 -18
- backend/modules/staff/forms/AB_StaffMemberNewForm.php +3 -4
- backend/modules/staff/forms/AB_StaffScheduleForm.php +12 -18
- backend/modules/staff/forms/AB_StaffScheduleItemBreakForm.php +7 -8
- backend/modules/staff/forms/AB_StaffServicesForm.php +33 -44
- backend/modules/staff/forms/widget/AB_TimeChoiceWidget.php +43 -37
- backend/modules/staff/resources/css/staff.css +47 -18
- backend/modules/staff/resources/js/staff.js +59 -33
autoload.php
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @param $className
|
5 |
+
*/
|
6 |
+
function bookly_autoload( $className ) {
|
7 |
+
|
8 |
+
$paths = array(
|
9 |
+
'/lib/'
|
10 |
+
);
|
11 |
+
|
12 |
+
foreach ( $paths as $path ) {
|
13 |
+
if ( file_exists( AB_PATH . $path . $className . '.php' ) ) {
|
14 |
+
require_once( AB_PATH . $path . $className . '.php' );
|
15 |
+
}
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
spl_autoload_register( 'bookly_autoload' );
|
backend/AB_Backend.php
CHANGED
@@ -1,56 +1,39 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include 'modules/appearance/AB_AppearanceController.php';
|
6 |
-
include 'modules/staff/AB_StaffController.php';
|
7 |
-
include 'modules/service/AB_ServiceController.php';
|
8 |
-
include 'modules/calendar/AB_CalendarController.php';
|
9 |
-
include 'modules/payment/AB_PaymentController.php';
|
10 |
-
include 'modules/notifications/AB_NotificationsController.php';
|
11 |
-
include 'modules/settings/AB_SettingsController.php';
|
12 |
-
include 'modules/customer/AB_CustomerController.php';
|
13 |
-
include 'modules/tinymce/AB_TinyMCE_Plugin.php';
|
14 |
-
include 'modules/export/AB_ExportController.php';
|
15 |
|
16 |
class AB_Backend {
|
17 |
|
18 |
public function __construct() {
|
19 |
add_action( 'admin_menu', array( $this, 'addAdminMenu' ) );
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
$this->
|
24 |
-
|
25 |
-
$this->serviceController = new AB_ServiceController();
|
26 |
-
// Calendar
|
27 |
-
$this->calendarController = new AB_CalendarController();
|
28 |
-
// Payments
|
29 |
-
$this->paymentController = new AB_PaymentController();
|
30 |
-
// Notifications
|
31 |
$this->notificationsController = new AB_NotificationsController();
|
32 |
-
|
33 |
-
$this->
|
34 |
-
|
35 |
-
$this->
|
36 |
-
|
37 |
-
$this->
|
38 |
-
|
39 |
-
$this->
|
|
|
|
|
|
|
40 |
|
41 |
-
add_action( 'wp_loaded',
|
42 |
-
add_action( 'admin_init',
|
43 |
-
add_action( 'admin_notices', array( $this->settingsController, 'showAdminNotice' ) );
|
44 |
}
|
45 |
|
46 |
public function addTinyMCEPlugin() {
|
47 |
-
|
48 |
-
|
49 |
new AB_TinyMCE_Plugin();
|
50 |
}
|
51 |
|
52 |
public function init() {
|
53 |
-
if ( !session_id() ) {
|
54 |
@session_start();
|
55 |
}
|
56 |
|
@@ -61,169 +44,68 @@ class AB_Backend {
|
|
61 |
break;
|
62 |
}
|
63 |
}
|
64 |
-
|
65 |
-
// for Appearance\Services\Settings all CSS and JS must be located directly in <HEAD>
|
66 |
-
if ( isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'ab-system-appearance' ) { // Appearance
|
67 |
-
// include StyleSheets
|
68 |
-
//wp_enqueue_style( 'ab-reset', plugins_url( 'css/ab-reset.css', dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
69 |
-
wp_enqueue_style( 'ab-style', plugins_url( 'resources/css/ab_style.css', __FILE__ ) );
|
70 |
-
wp_enqueue_style( 'ab-bootstrap', plugins_url( 'resources/bootstrap/css/bootstrap.min.css', __FILE__ ) );
|
71 |
-
wp_enqueue_style( 'ab-bootstrap-editable', plugins_url( 'resources/bootstrap/css/bootstrap-editable.css', __FILE__ ) );
|
72 |
-
wp_enqueue_style( 'ab-ladda-themeless', plugins_url( 'css/ladda-themeless.min.css',
|
73 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
74 |
-
wp_enqueue_style( 'ab-ladda-min', plugins_url( 'css/ladda.min.css',
|
75 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
76 |
-
wp_enqueue_style( 'ab-frontend-style', plugins_url( 'css/ab_frontend_style.css',
|
77 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
78 |
-
wp_enqueue_style( 'ab-columnizer', plugins_url( 'css/ab-columnizer.css',
|
79 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
80 |
-
wp_enqueue_style( 'ab-pickadate', plugins_url( 'css/pickadate.classic.css',
|
81 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
82 |
-
wp_enqueue_style( 'ab-columnizer', plugins_url( 'resources/css/ab-columnizer.css',
|
83 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ) );
|
84 |
-
wp_enqueue_style( 'wp-color-picker' );
|
85 |
-
wp_enqueue_style( 'ab-appearance', plugins_url( 'modules/appearance/resources/css/appearance.css', __FILE__ ) );
|
86 |
-
// include JavaScript
|
87 |
-
wp_enqueue_script( 'ab-bootstrap', plugins_url( 'resources/bootstrap/js/bootstrap.min.js',
|
88 |
-
__FILE__ ), array( 'jquery' ) );
|
89 |
-
wp_enqueue_script( 'ab-bootstrap-editable', plugins_url( 'resources/bootstrap/js/bootstrap-editable.min.js',
|
90 |
-
__FILE__ ), array( 'jquery' ) );
|
91 |
-
wp_enqueue_script( 'ab-appearance',
|
92 |
-
plugins_url( 'modules/appearance/resources/js/appearance.js', __FILE__ ),
|
93 |
-
array( 'jquery' )
|
94 |
-
);
|
95 |
-
wp_enqueue_script( 'ab-pickadate', plugins_url( 'js/pickadate.legacy.min.js',
|
96 |
-
dirname(__FILE__). '../../frontend/resources/AB_Frontend.php' ), array( 'jquery' ) );
|
97 |
-
wp_localize_script( 'ab-pickadate', 'BooklyL10n', array(
|
98 |
-
'today' => __( 'Today', 'ab' ),
|
99 |
-
'month' => array(
|
100 |
-
'January' => __( 'January', 'ab' ),
|
101 |
-
'February' => __( 'February', 'ab' ),
|
102 |
-
'March' => __( 'March', 'ab' ),
|
103 |
-
'April' => __( 'April', 'ab' ),
|
104 |
-
'May' => __( 'May', 'ab' ),
|
105 |
-
'June' => __( 'June', 'ab' ),
|
106 |
-
'July' => __( 'July', 'ab' ),
|
107 |
-
'August' => __( 'August', 'ab' ),
|
108 |
-
'September' => __( 'September', 'ab' ),
|
109 |
-
'October' => __( 'October', 'ab' ),
|
110 |
-
'November' => __( 'November', 'ab' ),
|
111 |
-
'December' => __( 'December', 'ab' )
|
112 |
-
),
|
113 |
-
'day' => array(
|
114 |
-
'Sun' => __( 'Sun', 'ab' ),
|
115 |
-
'Mon' => __( 'Mon', 'ab' ),
|
116 |
-
'Tue' => __( 'Tue', 'ab' ),
|
117 |
-
'Wed' => __( 'Wed', 'ab' ),
|
118 |
-
'Thu' => __( 'Thu', 'ab' ),
|
119 |
-
'Fri' => __( 'Fri', 'ab' ),
|
120 |
-
'Sat' => __( 'Sat', 'ab' )
|
121 |
-
)
|
122 |
-
) );
|
123 |
-
wp_enqueue_script( 'wp-color-picker' );
|
124 |
-
} elseif ( isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'ab-system-services' ) { // Services
|
125 |
-
// include StyleSheets
|
126 |
-
wp_enqueue_style( 'wp-color-picker' );
|
127 |
-
wp_enqueue_style( 'ab-style', plugins_url( 'resources/css/ab_style.css', __FILE__ ) );
|
128 |
-
wp_enqueue_style( 'ab-service', plugins_url( 'modules/service/resources/css/service.css', __FILE__ ) );
|
129 |
-
wp_enqueue_style( 'ab-bootstrap', plugins_url( 'resources/bootstrap/css/bootstrap.min.css', __FILE__ ) );
|
130 |
-
// include JavaScript
|
131 |
-
wp_enqueue_script( 'wp-color-picker' );
|
132 |
-
wp_enqueue_script( 'ab-popup', plugins_url( 'resources/js/ab_popup.js', __FILE__ ), array( 'jquery' ) );
|
133 |
-
wp_enqueue_script( 'ab-bootstrap', plugins_url( 'resources/bootstrap/js/bootstrap.min.js', __FILE__ ), array( 'jquery' ) );
|
134 |
-
wp_enqueue_script( 'ab-service', plugins_url( 'modules/service/resources/js/service.js', __FILE__ ), array( 'jquery' ) );
|
135 |
-
wp_localize_script( 'ab-service', 'BooklyL10n', array(
|
136 |
-
'are_you_sure' => __( 'Are you sure?', 'ab' ),
|
137 |
-
'please_select_at_least_one_service' => __( 'Please select at least one service.', 'ab'),
|
138 |
-
) );
|
139 |
-
} elseif ( isset( $_GET[ 'page' ] ) && $_GET[ 'page' ] == 'ab-system-settings' ) { // Settings
|
140 |
-
// include StyleSheets
|
141 |
-
wp_enqueue_style( 'ab-style', plugins_url( 'resources/css/ab_style.css', __FILE__ ) );
|
142 |
-
wp_enqueue_style( 'ab-bootstrap', plugins_url( 'resources/bootstrap/css/bootstrap.min.css', __FILE__ ) );
|
143 |
-
wp_enqueue_style( 'ab-jCal', plugins_url( 'resources/css/jCal.css', __FILE__ ) );
|
144 |
-
// include JavaScript
|
145 |
-
wp_enqueue_script( 'ab-bootstrap', plugins_url( 'resources/bootstrap/js/bootstrap.min.js', __FILE__ ), array( 'jquery' ) );
|
146 |
-
wp_enqueue_script( 'ab-settings', plugins_url( 'modules/settings/resources/js/settings.js', __FILE__ ), array( 'jquery' ) );
|
147 |
-
wp_enqueue_script( 'ab-jCal', plugins_url( 'resources/js/jCal.js', __FILE__ ), array( 'jquery' ) );
|
148 |
-
wp_localize_script( 'ab-jCal', 'BooklyL10n', array(
|
149 |
-
'we_are_not_working' => __( 'We are not working on this day', 'ab' ),
|
150 |
-
'repeat' => __( 'Repeat every year', 'ab' ),
|
151 |
-
'month' => array(
|
152 |
-
'January' => __( 'January', 'ab' ),
|
153 |
-
'February' => __( 'February', 'ab' ),
|
154 |
-
'March' => __( 'March', 'ab' ),
|
155 |
-
'April' => __( 'April', 'ab' ),
|
156 |
-
'May' => __( 'May', 'ab' ),
|
157 |
-
'June' => __( 'June', 'ab' ),
|
158 |
-
'July' => __( 'July', 'ab' ),
|
159 |
-
'August' => __( 'August', 'ab' ),
|
160 |
-
'September' => __( 'September', 'ab' ),
|
161 |
-
'October' => __( 'October', 'ab' ),
|
162 |
-
'November' => __( 'November', 'ab' ),
|
163 |
-
'December' => __( 'December', 'ab' )
|
164 |
-
),
|
165 |
-
'day' => array(
|
166 |
-
'Mon' => __( 'Mon', 'ab' ),
|
167 |
-
'Tue' => __( 'Tue', 'ab' ),
|
168 |
-
'Wed' => __( 'Wed', 'ab' ),
|
169 |
-
'Thu' => __( 'Thu', 'ab' ),
|
170 |
-
'Fri' => __( 'Fri', 'ab' ),
|
171 |
-
'Sat' => __( 'Sat', 'ab' ),
|
172 |
-
'Sun' => __( 'Sun', 'ab' )
|
173 |
-
)
|
174 |
-
) );
|
175 |
-
}
|
176 |
}
|
177 |
|
178 |
public function addAdminMenu() {
|
179 |
-
/** @var wpdb $wpdb */
|
180 |
-
global $wpdb;
|
181 |
/** @var WP_User $current_user */
|
182 |
global $current_user;
|
183 |
|
184 |
-
//
|
185 |
-
$calendar = __( 'Calendar',
|
186 |
-
$
|
187 |
-
$
|
188 |
-
$
|
189 |
-
$
|
190 |
-
$
|
191 |
-
$
|
192 |
-
$
|
193 |
-
$
|
|
|
|
|
|
|
194 |
|
195 |
-
if (
|
196 |
-
|| $wpdb->get_var( $wpdb->prepare(
|
197 |
-
'SELECT COUNT(id) AS numb FROM ab_staff WHERE wp_user_id = %d', $current_user->ID
|
198 |
-
) ) ) {
|
199 |
if ( function_exists( 'add_options_page' ) ) {
|
200 |
-
|
201 |
-
add_menu_page( 'Bookly', 'Bookly', 'read', 'ab-system',
|
202 |
-
array( $this->staffController, 'renderStaffMembers'),
|
203 |
plugins_url('resources/images/menu.png', __FILE__), $dynamic_position );
|
204 |
-
add_submenu_page( 'ab-system', $calendar, $calendar, 'read', 'ab-
|
205 |
-
array( $this->calendarController, '
|
206 |
-
add_submenu_page( 'ab-system', $
|
207 |
-
array( $this->
|
208 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
209 |
array( $this->serviceController, 'index' ) );
|
210 |
-
add_submenu_page( 'ab-system', $customers, $customers, 'manage_options',
|
211 |
array( $this->customerController, 'index' ) );
|
212 |
-
add_submenu_page( 'ab-system', $notifications, $notifications, 'manage_options', 'ab-
|
213 |
array( $this->notificationsController, 'index' ) );
|
214 |
-
add_submenu_page( 'ab-system', $
|
|
|
|
|
215 |
array( $this->paymentController, 'index' ) );
|
216 |
-
add_submenu_page( 'ab-system', $appearance, $appearance, 'manage_options', 'ab-
|
217 |
array( $this->apearanceController, 'index' ) );
|
218 |
-
add_submenu_page( 'ab-system', $
|
|
|
|
|
|
|
|
|
219 |
array( $this->settingsController, 'index' ) );
|
220 |
-
add_submenu_page( 'ab-system', $export, $export, 'manage_options', 'ab-system-export',
|
221 |
-
array( $this->exportController, 'index' ) );
|
222 |
|
223 |
global $submenu;
|
|
|
224 |
unset( $submenu[ 'ab-system' ][ 0 ] );
|
225 |
}
|
226 |
}
|
227 |
}
|
228 |
|
229 |
-
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
class AB_Backend {
|
4 |
|
5 |
public function __construct() {
|
6 |
add_action( 'admin_menu', array( $this, 'addAdminMenu' ) );
|
7 |
+
|
8 |
+
// Backend controllers.
|
9 |
+
$this->apearanceController = new AB_AppearanceController();
|
10 |
+
$this->calendarController = new AB_CalendarController();
|
11 |
+
$this->customerController = new AB_CustomerController();
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
$this->notificationsController = new AB_NotificationsController();
|
13 |
+
$this->paymentController = new AB_PaymentController();
|
14 |
+
$this->serviceController = new AB_ServiceController();
|
15 |
+
$this->smsController = new AB_SmsController();
|
16 |
+
$this->settingsController = new AB_SettingsController();
|
17 |
+
$this->staffController = new AB_StaffController();
|
18 |
+
$this->couponsController = new AB_CouponsController();
|
19 |
+
$this->customFieldsController = new AB_CustomFieldsController();
|
20 |
+
$this->appointmentsController = new AB_AppointmentsController();
|
21 |
+
|
22 |
+
// Frontend controllers that work via admin-ajax.php.
|
23 |
+
$this->bookingController = new AB_BookingController();
|
24 |
|
25 |
+
add_action( 'wp_loaded', array( $this, 'init' ) );
|
26 |
+
add_action( 'admin_init', array( $this, 'addTinyMCEPlugin' ) );
|
|
|
27 |
}
|
28 |
|
29 |
public function addTinyMCEPlugin() {
|
30 |
+
/** @var WP_User $current_user */
|
31 |
+
global $current_user;
|
32 |
new AB_TinyMCE_Plugin();
|
33 |
}
|
34 |
|
35 |
public function init() {
|
36 |
+
if ( ! session_id() ) {
|
37 |
@session_start();
|
38 |
}
|
39 |
|
44 |
break;
|
45 |
}
|
46 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
}
|
48 |
|
49 |
public function addAdminMenu() {
|
|
|
|
|
50 |
/** @var WP_User $current_user */
|
51 |
global $current_user;
|
52 |
|
53 |
+
// Translated submenu pages.
|
54 |
+
$calendar = __( 'Calendar', 'bookly' );
|
55 |
+
$appointments = __( 'Appointments', 'bookly' );
|
56 |
+
$staff_members = __( 'Staff Members', 'bookly' );
|
57 |
+
$services = __( 'Services', 'bookly' );
|
58 |
+
$sms = __( 'SMS Notifications', 'bookly' );
|
59 |
+
$notifications = __( 'Email Notifications', 'bookly' );
|
60 |
+
$customers = __( 'Customers', 'bookly' );
|
61 |
+
$payments = __( 'Payments', 'bookly' );
|
62 |
+
$appearance = __( 'Appearance', 'bookly' );
|
63 |
+
$settings = __( 'Settings', 'bookly' );
|
64 |
+
$coupons = __( 'Coupons', 'bookly' );
|
65 |
+
$custom_fields = __( 'Custom Fields', 'bookly' );
|
66 |
|
67 |
+
if ( $current_user->has_cap( 'administrator' ) || AB_Staff::query()->where( 'wp_user_id', $current_user->ID )->count() ) {
|
|
|
|
|
|
|
68 |
if ( function_exists( 'add_options_page' ) ) {
|
69 |
+
$dynamic_position = '80.0000001' . mt_rand( 1, 1000 ); // position always is under `Settings`
|
70 |
+
add_menu_page( 'Bookly', 'Bookly', 'read', 'ab-system', '',
|
|
|
71 |
plugins_url('resources/images/menu.png', __FILE__), $dynamic_position );
|
72 |
+
add_submenu_page( 'ab-system', $calendar, $calendar, 'read', 'ab-calendar',
|
73 |
+
array( $this->calendarController, 'index' ) );
|
74 |
+
add_submenu_page( 'ab-system', $appointments, $appointments, 'manage_options', 'ab-appointments',
|
75 |
+
array( $this->appointmentsController, 'index' ) );
|
76 |
+
if ( $current_user->has_cap( 'administrator' ) ) {
|
77 |
+
add_submenu_page( 'ab-system', $staff_members, $staff_members, 'manage_options', AB_StaffController::page_slug,
|
78 |
+
array( $this->staffController, 'index' ) );
|
79 |
+
} else {
|
80 |
+
if ( 1 == get_option( 'ab_settings_allow_staff_members_edit_profile' ) ) {
|
81 |
+
add_submenu_page( 'ab-system', __( 'Profile', 'bookly' ), __( 'Profile', 'bookly' ), 'read', AB_StaffController::page_slug,
|
82 |
+
array( $this->staffController, 'index' ) );
|
83 |
+
}
|
84 |
+
}
|
85 |
+
add_submenu_page( 'ab-system', $services, $services, 'manage_options', AB_ServiceController::page_slug,
|
86 |
array( $this->serviceController, 'index' ) );
|
87 |
+
add_submenu_page( 'ab-system', $customers, $customers, 'manage_options', AB_CustomerController::page_slug,
|
88 |
array( $this->customerController, 'index' ) );
|
89 |
+
add_submenu_page( 'ab-system', $notifications, $notifications, 'manage_options', 'ab-notifications',
|
90 |
array( $this->notificationsController, 'index' ) );
|
91 |
+
add_submenu_page( 'ab-system', $sms, $sms, 'manage_options', AB_SmsController::page_slug,
|
92 |
+
array( $this->smsController, 'index' ) );
|
93 |
+
add_submenu_page( 'ab-system', $payments, $payments, 'manage_options', 'ab-payments',
|
94 |
array( $this->paymentController, 'index' ) );
|
95 |
+
add_submenu_page( 'ab-system', $appearance, $appearance, 'manage_options', 'ab-appearance',
|
96 |
array( $this->apearanceController, 'index' ) );
|
97 |
+
add_submenu_page( 'ab-system', $custom_fields, $custom_fields, 'manage_options', 'ab-custom-fields',
|
98 |
+
array( $this->customFieldsController, 'index' ) );
|
99 |
+
add_submenu_page( 'ab-system', $coupons, $coupons, 'manage_options', 'ab-coupons',
|
100 |
+
array( $this->couponsController, 'index' ) );
|
101 |
+
add_submenu_page( 'ab-system', $settings, $settings, 'manage_options', AB_SettingsController::page_slug,
|
102 |
array( $this->settingsController, 'index' ) );
|
|
|
|
|
103 |
|
104 |
global $submenu;
|
105 |
+
do_action( 'bookly_addons_menu', 'ab-system' );
|
106 |
unset( $submenu[ 'ab-system' ][ 0 ] );
|
107 |
}
|
108 |
}
|
109 |
}
|
110 |
|
111 |
+
}
|
backend/modules/appearance/AB_AppearanceController.php
CHANGED
@@ -1,6 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
5 |
/**
|
6 |
* Class AB_AppearanceController
|
@@ -10,8 +8,66 @@ class AB_AppearanceController extends AB_Controller {
|
|
10 |
/**
|
11 |
* Default Action
|
12 |
*/
|
13 |
-
public function index()
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
$this->steps = array(
|
16 |
1 => get_option( 'ab_appearance_text_step_service' ),
|
17 |
2 => get_option( 'ab_appearance_text_step_time' ),
|
@@ -20,62 +76,77 @@ class AB_AppearanceController extends AB_Controller {
|
|
20 |
5 => get_option( 'ab_appearance_text_step_done' )
|
21 |
);
|
22 |
|
23 |
-
//
|
24 |
$this->render( 'index' );
|
25 |
} // index
|
26 |
|
27 |
/**
|
28 |
* Update options
|
29 |
*/
|
30 |
-
public function executeUpdateAppearanceOptions()
|
31 |
-
|
|
|
32 |
$get_option = $this->getParameter( 'options' );
|
33 |
$options = array(
|
34 |
// Info text.
|
35 |
-
'ab_appearance_text_info_first_step'
|
36 |
-
'ab_appearance_text_info_second_step'
|
37 |
-
'ab_appearance_text_info_third_step'
|
38 |
-
'
|
39 |
-
'
|
|
|
|
|
40 |
// Color.
|
41 |
-
'ab_appearance_color'
|
42 |
// Step, label and option texts.
|
43 |
-
'ab_appearance_text_step_service'
|
44 |
-
'ab_appearance_text_step_time'
|
45 |
-
'ab_appearance_text_step_details'
|
46 |
-
'ab_appearance_text_step_payment'
|
47 |
-
'ab_appearance_text_step_done'
|
48 |
-
'ab_appearance_text_label_category'
|
49 |
-
'ab_appearance_text_label_service'
|
50 |
-
'
|
51 |
-
'
|
52 |
-
'
|
53 |
-
'
|
54 |
-
'
|
55 |
-
'
|
56 |
-
'
|
57 |
-
'
|
58 |
-
'ab_appearance_text_option_service'
|
59 |
-
'ab_appearance_text_option_category'
|
60 |
-
'ab_appearance_text_option_employee'
|
|
|
|
|
61 |
// Checkboxes.
|
62 |
-
'ab_appearance_show_progress_tracker'
|
|
|
|
|
|
|
63 |
);
|
64 |
|
65 |
// Save options.
|
66 |
foreach ( $options as $option_name => $option_value ) {
|
67 |
update_option( $option_name, $option_value );
|
|
|
|
|
|
|
|
|
68 |
}
|
69 |
}
|
70 |
exit;
|
71 |
-
}
|
72 |
|
73 |
/**
|
74 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
75 |
* so current 'execute*' methods look nicer.
|
|
|
|
|
76 |
*/
|
77 |
-
protected function registerWpActions( $prefix = '' )
|
|
|
78 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
79 |
-
}
|
80 |
|
81 |
-
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_AppearanceController
|
8 |
/**
|
9 |
* Default Action
|
10 |
*/
|
11 |
+
public function index()
|
12 |
+
{
|
13 |
+
/** @var WP_Locale $wp_locale */
|
14 |
+
global $wp_locale;
|
15 |
+
|
16 |
+
$this->enqueueStyles( array(
|
17 |
+
'frontend' => array(
|
18 |
+
'css/intlTelInput.css',
|
19 |
+
'css/ladda.min.css',
|
20 |
+
'css/bookly-main.css',
|
21 |
+
'css/ab-columnizer.css',
|
22 |
+
'css/picker.classic.css',
|
23 |
+
'css/picker.classic.date.css',
|
24 |
+
'css/ab-picker.css',
|
25 |
+
),
|
26 |
+
'backend' => array(
|
27 |
+
'css/bookly.main-backend.css',
|
28 |
+
'bootstrap/css/bootstrap.min.css',
|
29 |
+
'css/bootstrap-editable.css',
|
30 |
+
),
|
31 |
+
'wp' => array(
|
32 |
+
'wp-color-picker',
|
33 |
+
),
|
34 |
+
'module' => array(
|
35 |
+
'css/appearance.css',
|
36 |
+
)
|
37 |
+
) );
|
38 |
+
|
39 |
+
$this->enqueueScripts( array(
|
40 |
+
'backend' => array(
|
41 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
42 |
+
'js/bootstrap-editable.min.js' => array( 'jquery' ),
|
43 |
+
),
|
44 |
+
'frontend' => array(
|
45 |
+
'js/picker.js' => array( 'jquery' ),
|
46 |
+
'js/picker.date.js' => array( 'jquery' ),
|
47 |
+
'js/spin.min.js' => array( 'jquery' ),
|
48 |
+
'js/ladda.min.js' => array( 'jquery' ),
|
49 |
+
'js/intlTelInput.min.js' => array( 'ab-picker.date.js' )
|
50 |
+
),
|
51 |
+
'wp' => array(
|
52 |
+
'wp-color-picker',
|
53 |
+
),
|
54 |
+
'module' => array(
|
55 |
+
'js/appearance.js' => array( 'jquery' ),
|
56 |
+
)
|
57 |
+
) );
|
58 |
+
|
59 |
+
wp_localize_script( 'ab-picker.date.js', 'BooklyL10n', array(
|
60 |
+
'today' => __( 'Today', 'bookly' ),
|
61 |
+
'months' => array_values( $wp_locale->month ),
|
62 |
+
'days' => array_values( $wp_locale->weekday_abbrev ),
|
63 |
+
'nextMonth' => __( 'Next month', 'bookly' ),
|
64 |
+
'prevMonth' => __( 'Previous month', 'bookly' ),
|
65 |
+
'date_format' => AB_DateTimeUtils::convertFormat( 'date', AB_DateTimeUtils::FORMAT_PICKADATE ),
|
66 |
+
'start_of_week' => (int) get_option( 'start_of_week' ),
|
67 |
+
'intlTelInput_utils' => plugins_url( 'intlTelInput.utils.js', AB_PATH . '/frontend/resources/js/intlTelInput.utils.js' ),
|
68 |
+
) );
|
69 |
+
|
70 |
+
// Initialize steps (tabs).
|
71 |
$this->steps = array(
|
72 |
1 => get_option( 'ab_appearance_text_step_service' ),
|
73 |
2 => get_option( 'ab_appearance_text_step_time' ),
|
76 |
5 => get_option( 'ab_appearance_text_step_done' )
|
77 |
);
|
78 |
|
79 |
+
// Render general layout.
|
80 |
$this->render( 'index' );
|
81 |
} // index
|
82 |
|
83 |
/**
|
84 |
* Update options
|
85 |
*/
|
86 |
+
public function executeUpdateAppearanceOptions()
|
87 |
+
{
|
88 |
+
if ( $this->hasParameter( 'options' ) ) {
|
89 |
$get_option = $this->getParameter( 'options' );
|
90 |
$options = array(
|
91 |
// Info text.
|
92 |
+
'ab_appearance_text_info_first_step' => $get_option['text_info_first_step'],
|
93 |
+
'ab_appearance_text_info_second_step' => $get_option['text_info_second_step'],
|
94 |
+
'ab_appearance_text_info_third_step' => $get_option['text_info_third_step'],
|
95 |
+
'ab_appearance_text_info_third_step_guest' => $get_option['text_info_third_step_guest'],
|
96 |
+
'ab_appearance_text_info_fourth_step' => $get_option['text_info_fourth_step'],
|
97 |
+
'ab_appearance_text_info_fifth_step' => $get_option['text_info_fifth_step'],
|
98 |
+
'ab_appearance_text_info_coupon' => $get_option['text_info_coupon'],
|
99 |
// Color.
|
100 |
+
'ab_appearance_color' => $get_option['color'],
|
101 |
// Step, label and option texts.
|
102 |
+
'ab_appearance_text_step_service' => $get_option['text_step_service'],
|
103 |
+
'ab_appearance_text_step_time' => $get_option['text_step_time'],
|
104 |
+
'ab_appearance_text_step_details' => $get_option['text_step_details'],
|
105 |
+
'ab_appearance_text_step_payment' => $get_option['text_step_payment'],
|
106 |
+
'ab_appearance_text_step_done' => $get_option['text_step_done'],
|
107 |
+
'ab_appearance_text_label_category' => $get_option['text_label_category'],
|
108 |
+
'ab_appearance_text_label_service' => $get_option['text_label_service'],
|
109 |
+
'ab_appearance_text_label_number_of_persons' => $get_option['text_label_number_of_persons'],
|
110 |
+
'ab_appearance_text_label_employee' => $get_option['text_label_employee'],
|
111 |
+
'ab_appearance_text_label_select_date' => $get_option['text_label_select_date'],
|
112 |
+
'ab_appearance_text_label_start_from' => $get_option['text_label_start_from'],
|
113 |
+
'ab_appearance_text_label_finish_by' => $get_option['text_label_finish_by'],
|
114 |
+
'ab_appearance_text_label_name' => $get_option['text_label_name'],
|
115 |
+
'ab_appearance_text_label_phone' => $get_option['text_label_phone'],
|
116 |
+
'ab_appearance_text_label_email' => $get_option['text_label_email'],
|
117 |
+
'ab_appearance_text_option_service' => $get_option['text_option_service'],
|
118 |
+
'ab_appearance_text_option_category' => $get_option['text_option_category'],
|
119 |
+
'ab_appearance_text_option_employee' => $get_option['text_option_employee'],
|
120 |
+
'ab_appearance_text_label_coupon' => $get_option['text_label_coupon'],
|
121 |
+
'ab_appearance_text_label_pay_locally' => $get_option['text_label_pay_locally'],
|
122 |
// Checkboxes.
|
123 |
+
'ab_appearance_show_progress_tracker' => $get_option['progress_tracker'],
|
124 |
+
'ab_appearance_show_blocked_timeslots' => $get_option['blocked_timeslots'],
|
125 |
+
'ab_appearance_show_day_one_column' => $get_option['day_one_column'],
|
126 |
+
'ab_appearance_show_calendar' => $get_option['show_calendar'],
|
127 |
);
|
128 |
|
129 |
// Save options.
|
130 |
foreach ( $options as $option_name => $option_value ) {
|
131 |
update_option( $option_name, $option_value );
|
132 |
+
// Register string for translate in WPML.
|
133 |
+
if ( strpos( $option_name, 'ab_appearance_text_' ) === 0 ) {
|
134 |
+
do_action( 'wpml_register_single_string', 'bookly', $option_name, $option_value );
|
135 |
+
}
|
136 |
}
|
137 |
}
|
138 |
exit;
|
139 |
+
}
|
140 |
|
141 |
/**
|
142 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
143 |
* so current 'execute*' methods look nicer.
|
144 |
+
*
|
145 |
+
* @param string $prefix
|
146 |
*/
|
147 |
+
protected function registerWpActions( $prefix = '' )
|
148 |
+
{
|
149 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
150 |
+
}
|
151 |
|
152 |
+
}
|
backend/modules/appearance/resources/css/appearance.css
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
/* Backend-Appearance */
|
2 |
-
|
3 |
div.controls {
|
4 |
float: right;
|
5 |
margin-right: 15px;
|
@@ -11,15 +11,32 @@ span.spinner {
|
|
11 |
margin-right: 20px;
|
12 |
}
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
|
|
|
|
|
|
|
17 |
}
|
18 |
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
}
|
22 |
|
23 |
-
|
24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
}
|
1 |
/* Backend-Appearance */
|
2 |
+
#ab-appearance { max-width: 960px; }
|
3 |
div.controls {
|
4 |
float: right;
|
5 |
margin-right: 15px;
|
11 |
margin-right: 20px;
|
12 |
}
|
13 |
|
14 |
+
.editable-click {
|
15 |
+
cursor: pointer;
|
16 |
+
}
|
17 |
+
|
18 |
+
.ab-first-step .select-list {
|
19 |
+
background: transparent;
|
20 |
}
|
21 |
|
22 |
+
input.appearance-color-picker{
|
23 |
+
height: 24px !important;
|
24 |
+
background:#f3f3f3;
|
25 |
+
background-image:-webkit-gradient(linear,left top,left bottom,from(#fefefe),to(#f4f4f4));
|
26 |
+
background-image:-webkit-linear-gradient(top,#fefefe,#f4f4f4);
|
27 |
+
background-image:-moz-linear-gradient(top,#fefefe,#f4f4f4);
|
28 |
+
background-image:-o-linear-gradient(top,#fefefe,#f4f4f4);
|
29 |
+
background-image:linear-gradient(to bottom,#fefefe,#f4f4f4);
|
30 |
}
|
31 |
|
32 |
+
.editable-container.popover { z-index: 10001; }
|
33 |
+
.editable-container.editable-popup .arrow { margin-left: 0 !important; }
|
34 |
+
.editable-input > textarea { width: 475px!important; }
|
35 |
+
|
36 |
+
.editableform-loading { background: url('../../../../resources/images/loading.gif') center center no-repeat !important; }
|
37 |
+
.editable-clear-x { background: url('../../../../resources/images/clear.png') center center no-repeat !important; }
|
38 |
+
|
39 |
+
/* media query */
|
40 |
+
@media screen and (max-width: 782px) {
|
41 |
+
.ab-columnizer-wrap { height: 662px!important; }
|
42 |
}
|
backend/modules/appearance/resources/js/appearance.js
CHANGED
@@ -1,12 +1,16 @@
|
|
1 |
jQuery(function($) {
|
2 |
-
var // Progress Tracker
|
3 |
$progress_tracker_option = $('input#ab-progress-tracker-checkbox'),
|
4 |
-
//
|
|
|
|
|
|
|
|
|
5 |
$tabs = $('div.tabbable').find('.nav-tabs'),
|
6 |
$tab_content = $('div.tab-content'),
|
7 |
// Buttons.
|
8 |
-
$
|
9 |
-
$reset_button = $('
|
10 |
// Texts.
|
11 |
$text_step_service = $('#ab-text-step-service'),
|
12 |
$text_step_time = $('#ab-text-step-time'),
|
@@ -18,6 +22,7 @@ jQuery(function($) {
|
|
18 |
$text_option_service = $('#ab-text-option-service'),
|
19 |
$text_option_employee = $('#ab-text-option-employee'),
|
20 |
$text_label_service = $('#ab-text-label-service'),
|
|
|
21 |
$text_label_employee = $('#ab-text-label-employee'),
|
22 |
$text_label_select_date = $('#ab-text-label-select_date'),
|
23 |
$text_label_start_from = $('#ab-text-label-start_from'),
|
@@ -25,22 +30,40 @@ jQuery(function($) {
|
|
25 |
$text_label_name = $('#ab-text-label-name'),
|
26 |
$text_label_phone = $('#ab-text-label-phone'),
|
27 |
$text_label_email = $('#ab-text-label-email'),
|
28 |
-
$
|
29 |
$text_info_service = $('#ab-text-info-first'),
|
30 |
$text_info_time = $('#ab-text-info-second'),
|
31 |
$text_info_details = $('#ab-text-info-third'),
|
|
|
32 |
$text_info_payment = $('#ab-text-info-fourth'),
|
33 |
$text_info_done = $('#ab-text-info-fifth'),
|
|
|
34 |
$color_picker = $('.wp-color-picker'),
|
35 |
-
$ab_editable = $('.ab_editable')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
// menu fix for WP 3.8.1
|
38 |
$('#toplevel_page_ab-system > ul').css('margin-left', '0px');
|
39 |
|
40 |
-
// Tabs
|
41 |
$tabs.find('.ab-step-tabs').on('click', function() {
|
42 |
var $step_id = $(this).data('step-id');
|
43 |
-
//
|
44 |
$tab_content.children('div[data-step-id!="' + $step_id + '"]').removeClass('active').hide();
|
45 |
$tab_content.children('div[data-step-id="' + $step_id + '"]').addClass('active').show();
|
46 |
}).filter('li:first').trigger('click');
|
@@ -53,21 +76,19 @@ jQuery(function($) {
|
|
53 |
$('.ab-mobile-step_1 label').css('color', $color_picker.wpColorPicker('color'));
|
54 |
$('.ab-next-step, .ab-mobile-next-step').css('background', $color_picker.wpColorPicker('color'));
|
55 |
$('.ab-week-days label').css('background-color', $color_picker.wpColorPicker('color'));
|
56 |
-
$('.
|
57 |
-
$('.
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
$('.
|
64 |
-
$('.pickadate__button--clear').attr('style', 'color: ' + color_important);
|
65 |
-
$('.pickadate__button--today').attr('style', 'color: ' + color_important);
|
66 |
$('.ab-columnizer .ab-available-day').css({
|
67 |
'background': $color_picker.wpColorPicker('color'),
|
68 |
'border-color': $color_picker.wpColorPicker('color')
|
69 |
});
|
70 |
-
$('.ab-
|
71 |
$('.ab-columnizer .ab-available-hour').off().hover(
|
72 |
function() { // mouse-on
|
73 |
$(this).css({
|
@@ -85,7 +106,7 @@ jQuery(function($) {
|
|
85 |
function() { // mouse-out
|
86 |
$(this).css({
|
87 |
'color': '#333333',
|
88 |
-
'border': '1px solid
|
89 |
});
|
90 |
$(this).find('.ab-hour-icon').css({
|
91 |
'border-color': '#333333',
|
@@ -96,66 +117,112 @@ jQuery(function($) {
|
|
96 |
});
|
97 |
}
|
98 |
);
|
99 |
-
$('div.ab-
|
100 |
$('.ab-to-second-step, .ab-to-fourth-step, .ab-to-third-step, .ab-final-step')
|
101 |
.css('background', $color_picker.wpColorPicker('color'));
|
102 |
};
|
103 |
$color_picker.wpColorPicker({
|
104 |
change : function() {
|
105 |
applyColor();
|
|
|
|
|
|
|
|
|
106 |
}
|
107 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
|
109 |
-
$
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
}
|
|
|
|
|
115 |
});
|
|
|
|
|
116 |
|
117 |
// Update options.
|
118 |
-
$
|
|
|
119 |
var data = {
|
120 |
action: 'ab_update_appearance_options',
|
121 |
options: {
|
122 |
// Color.
|
123 |
-
'color'
|
124 |
// Info text.
|
125 |
-
'text_info_first_step'
|
126 |
-
'text_info_second_step'
|
127 |
-
'text_info_third_step'
|
128 |
-
'
|
129 |
-
'
|
|
|
|
|
130 |
// Step and label texts.
|
131 |
-
'text_step_service'
|
132 |
-
'text_step_time'
|
133 |
-
'text_step_details'
|
134 |
-
'text_step_payment'
|
135 |
-
'text_step_done'
|
136 |
-
'text_label_category'
|
137 |
-
'text_label_service'
|
138 |
-
'
|
139 |
-
'
|
140 |
-
'
|
141 |
-
'
|
142 |
-
'
|
143 |
-
'
|
144 |
-
'
|
145 |
-
'
|
146 |
-
'
|
147 |
-
'
|
148 |
-
'
|
|
|
|
|
149 |
// Checkboxes.
|
150 |
-
'progress_tracker'
|
|
|
|
|
|
|
151 |
} // options
|
152 |
}; // data
|
153 |
|
154 |
// update data and show spinner while updating
|
155 |
-
|
|
|
156 |
$.post(ajaxurl, data, function (response) {
|
157 |
-
|
158 |
-
$('.
|
159 |
});
|
160 |
});
|
161 |
|
@@ -199,6 +266,50 @@ jQuery(function($) {
|
|
199 |
$(this).is(':checked') ? $('div.ab-progress-tracker').show() : $('div.ab-progress-tracker').hide();
|
200 |
}).trigger('change');
|
201 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
202 |
// Clickable week-days.
|
203 |
$('.ab-week-day').on('change', function () {
|
204 |
var self = $(this);
|
@@ -209,32 +320,11 @@ jQuery(function($) {
|
|
209 |
}
|
210 |
});
|
211 |
|
212 |
-
/**
|
213 |
-
* Helper functions.
|
214 |
-
*/
|
215 |
-
function nl2br(str, is_xhtml) {
|
216 |
-
var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
|
217 |
-
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
|
218 |
-
}
|
219 |
-
function escapeHtml(string) {
|
220 |
-
var entityMap = {
|
221 |
-
"&": "&",
|
222 |
-
"<": "<",
|
223 |
-
">": ">",
|
224 |
-
'"': '"',
|
225 |
-
"'": ''',
|
226 |
-
"/": '/'
|
227 |
-
};
|
228 |
-
return String(string).replace(/[&<>"'\/]/g, function (s) {
|
229 |
-
return entityMap[s];
|
230 |
-
});
|
231 |
-
}
|
232 |
-
|
233 |
var multiple = function (options) {
|
234 |
this.init('multiple', options, multiple.defaults);
|
235 |
};
|
236 |
|
237 |
-
//
|
238 |
$.fn.editableutils.inherit(multiple, $.fn.editabletypes.abstractinput);
|
239 |
|
240 |
$.extend(multiple.prototype, {
|
@@ -274,8 +364,8 @@ jQuery(function($) {
|
|
274 |
});
|
275 |
|
276 |
multiple.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
277 |
-
tpl: '<div class="editable-multiple"><label><input type="text" name="label" class="input-medium"></label></div>'+
|
278 |
-
'<div style="margin-top:5px;" class="editable-multiple"><label><input type="text" name="option" class="input-medium"><input type="hidden" name="id_option"></label></div>',
|
279 |
|
280 |
inputclass: ''
|
281 |
});
|
@@ -286,26 +376,26 @@ jQuery(function($) {
|
|
286 |
value: {
|
287 |
label: $text_label_category.text(),
|
288 |
option: $text_option_category.text(),
|
289 |
-
id_option: $text_label_category.data('
|
290 |
}
|
291 |
});
|
292 |
$text_label_service.editable({
|
293 |
value: {
|
294 |
label: $text_label_service.text(),
|
295 |
option: $text_option_service.text(),
|
296 |
-
id_option: $text_label_service.data('
|
297 |
}
|
298 |
});
|
299 |
$text_label_employee.editable({
|
300 |
value: {
|
301 |
label: $text_label_employee.text(),
|
302 |
option: $text_option_employee.text(),
|
303 |
-
id_option: $text_label_employee.data('
|
304 |
}
|
305 |
});
|
306 |
|
307 |
-
$('#ab-text-info-
|
308 |
-
$ab_editable.editable(
|
309 |
|
310 |
$.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 style="margin-top: 10px;" class="editable-notes"></div><div class="editable-error-block"></div></div> </form>';
|
311 |
|
@@ -317,4 +407,21 @@ jQuery(function($) {
|
|
317 |
$("span[data-link-class='" + $(e.target).data('link-class') + "']").editable('setValue', params.newValue);
|
318 |
$("span." + $(e.target).data('link-class')).text(params.newValue);
|
319 |
});
|
320 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
jQuery(function($) {
|
2 |
+
var // Progress Tracker.
|
3 |
$progress_tracker_option = $('input#ab-progress-tracker-checkbox'),
|
4 |
+
// Time slots setting.
|
5 |
+
$blocked_timeslots_option = $('input#ab-blocked-timeslots-checkbox'),
|
6 |
+
$day_one_column_option = $('input#ab-day-one-column-checkbox'),
|
7 |
+
$show_calendar_option = $('input#ab-show-calendar-checkbox'),
|
8 |
+
// Tabs.
|
9 |
$tabs = $('div.tabbable').find('.nav-tabs'),
|
10 |
$tab_content = $('div.tab-content'),
|
11 |
// Buttons.
|
12 |
+
$save_button = $('#ajax-send-appearance'),
|
13 |
+
$reset_button = $('button[type=reset]'),
|
14 |
// Texts.
|
15 |
$text_step_service = $('#ab-text-step-service'),
|
16 |
$text_step_time = $('#ab-text-step-time'),
|
22 |
$text_option_service = $('#ab-text-option-service'),
|
23 |
$text_option_employee = $('#ab-text-option-employee'),
|
24 |
$text_label_service = $('#ab-text-label-service'),
|
25 |
+
$text_label_number_of_persons = $('#ab-text-label-number-of-persons'),
|
26 |
$text_label_employee = $('#ab-text-label-employee'),
|
27 |
$text_label_select_date = $('#ab-text-label-select_date'),
|
28 |
$text_label_start_from = $('#ab-text-label-start_from'),
|
30 |
$text_label_name = $('#ab-text-label-name'),
|
31 |
$text_label_phone = $('#ab-text-label-phone'),
|
32 |
$text_label_email = $('#ab-text-label-email'),
|
33 |
+
$text_label_coupon = $('#ab-text-label-coupon'),
|
34 |
$text_info_service = $('#ab-text-info-first'),
|
35 |
$text_info_time = $('#ab-text-info-second'),
|
36 |
$text_info_details = $('#ab-text-info-third'),
|
37 |
+
$text_info_details_guest = $('#ab-text-info-third-guest'),
|
38 |
$text_info_payment = $('#ab-text-info-fourth'),
|
39 |
$text_info_done = $('#ab-text-info-fifth'),
|
40 |
+
$text_info_coupon = $('#ab-text-info-coupon'),
|
41 |
$color_picker = $('.wp-color-picker'),
|
42 |
+
$ab_editable = $('.ab_editable'),
|
43 |
+
$text_label_pay_locally = $('#ab-text-label-pay-locally'),
|
44 |
+
// Calendars.
|
45 |
+
$second_step_calendar = $('.ab-selected-date'),
|
46 |
+
$second_step_calendar_wrap = $('.ab-slot-calendar')
|
47 |
+
;
|
48 |
+
|
49 |
+
$('.ab-user-phone').intlTelInput({
|
50 |
+
defaultCountry: 'auto',
|
51 |
+
geoIpLookup: function(callback) {
|
52 |
+
$.get(ajaxurl, {action: 'ab_ip_info'}, function() {}, 'json').always(function(resp) {
|
53 |
+
var countryCode = (resp && resp.country) ? resp.country : '';
|
54 |
+
callback(countryCode);
|
55 |
+
});
|
56 |
+
},
|
57 |
+
utilsScript: BooklyL10n.intlTelInput_utils
|
58 |
+
});
|
59 |
|
60 |
// menu fix for WP 3.8.1
|
61 |
$('#toplevel_page_ab-system > ul').css('margin-left', '0px');
|
62 |
|
63 |
+
// Tabs.
|
64 |
$tabs.find('.ab-step-tabs').on('click', function() {
|
65 |
var $step_id = $(this).data('step-id');
|
66 |
+
// Hide all other tab content and show only current.
|
67 |
$tab_content.children('div[data-step-id!="' + $step_id + '"]').removeClass('active').hide();
|
68 |
$tab_content.children('div[data-step-id="' + $step_id + '"]').addClass('active').show();
|
69 |
}).filter('li:first').trigger('click');
|
76 |
$('.ab-mobile-step_1 label').css('color', $color_picker.wpColorPicker('color'));
|
77 |
$('.ab-next-step, .ab-mobile-next-step').css('background', $color_picker.wpColorPicker('color'));
|
78 |
$('.ab-week-days label').css('background-color', $color_picker.wpColorPicker('color'));
|
79 |
+
$('.picker__frame').attr('style', 'background: ' + color_important);
|
80 |
+
$('.picker__header').attr('style', 'border-bottom: ' + '1px solid ' + color_important);
|
81 |
+
$('.picker__day').mouseenter(function(){
|
82 |
+
$(this).attr('style', 'color: ' + color_important);
|
83 |
+
}).mouseleave(function(){ $(this).attr('style', $(this).hasClass('picker__day--selected') ? 'color: ' + color_important : '') });
|
84 |
+
$('.picker__day--selected').attr('style', 'color: ' + color_important);
|
85 |
+
$('.picker__button--clear').attr('style', 'color: ' + color_important);
|
86 |
+
$('.picker__button--today').attr('style', 'color: ' + color_important);
|
|
|
|
|
87 |
$('.ab-columnizer .ab-available-day').css({
|
88 |
'background': $color_picker.wpColorPicker('color'),
|
89 |
'border-color': $color_picker.wpColorPicker('color')
|
90 |
});
|
91 |
+
$('.ab-nav-tabs .ladda-button, .ab-nav-steps .ladda-button, .ab-btn.ladda-button').css('background-color', $color_picker.wpColorPicker('color'));
|
92 |
$('.ab-columnizer .ab-available-hour').off().hover(
|
93 |
function() { // mouse-on
|
94 |
$(this).css({
|
106 |
function() { // mouse-out
|
107 |
$(this).css({
|
108 |
'color': '#333333',
|
109 |
+
'border': '1px solid #cccccc'
|
110 |
});
|
111 |
$(this).find('.ab-hour-icon').css({
|
112 |
'border-color': '#333333',
|
117 |
});
|
118 |
}
|
119 |
);
|
120 |
+
$('div.ab-formGroup > label.ab-formLabel').css('color', $color_picker.wpColorPicker('color'));
|
121 |
$('.ab-to-second-step, .ab-to-fourth-step, .ab-to-third-step, .ab-final-step')
|
122 |
.css('background', $color_picker.wpColorPicker('color'));
|
123 |
};
|
124 |
$color_picker.wpColorPicker({
|
125 |
change : function() {
|
126 |
applyColor();
|
127 |
+
var style_arrow = '' +
|
128 |
+
'.picker__nav--next:before { border-left: 6px solid ' + $color_picker.wpColorPicker('color') + '!important; } ' +
|
129 |
+
'.picker__nav--prev:before { border-right: 6px solid ' + $color_picker.wpColorPicker('color') + '!important; }';
|
130 |
+
$('#ab_update_arrow').html(style_arrow);
|
131 |
}
|
132 |
});
|
133 |
+
// Init calendars.
|
134 |
+
$('.ab-date-from').pickadate({
|
135 |
+
formatSubmit : 'yyyy-mm-dd',
|
136 |
+
format : BooklyL10n.date_format,
|
137 |
+
min : true,
|
138 |
+
clear : false,
|
139 |
+
close : false,
|
140 |
+
today : BooklyL10n.today,
|
141 |
+
weekdaysShort : BooklyL10n.days,
|
142 |
+
monthsFull : BooklyL10n.months,
|
143 |
+
labelMonthNext : BooklyL10n.nextMonth,
|
144 |
+
labelMonthPrev : BooklyL10n.prevMonth,
|
145 |
+
onRender : applyColor,
|
146 |
+
firstDay : BooklyL10n.start_of_week == 1
|
147 |
+
});
|
148 |
|
149 |
+
$second_step_calendar.pickadate({
|
150 |
+
formatSubmit : 'yyyy-mm-dd',
|
151 |
+
format : BooklyL10n.date_format,
|
152 |
+
min : true,
|
153 |
+
weekdaysShort : BooklyL10n.days,
|
154 |
+
monthsFull : BooklyL10n.months,
|
155 |
+
labelMonthNext : BooklyL10n.nextMonth,
|
156 |
+
labelMonthPrev : BooklyL10n.prevMonth,
|
157 |
+
close : false,
|
158 |
+
clear : false,
|
159 |
+
today : false,
|
160 |
+
closeOnSelect : false,
|
161 |
+
onRender : applyColor,
|
162 |
+
firstDay : BooklyL10n.start_of_week == 1,
|
163 |
+
klass : {
|
164 |
+
picker: 'picker picker--opened picker--focused'
|
165 |
+
},
|
166 |
+
onClose : function() {
|
167 |
+
this.open(false);
|
168 |
}
|
169 |
+
|
170 |
+
|
171 |
});
|
172 |
+
$second_step_calendar_wrap.find('.picker__holder').css({ top : '0px', left : '0px' });
|
173 |
+
$second_step_calendar_wrap.toggle($show_calendar_option.prop('checked'));
|
174 |
|
175 |
// Update options.
|
176 |
+
$save_button.on('click', function(e) {
|
177 |
+
e.preventDefault();
|
178 |
var data = {
|
179 |
action: 'ab_update_appearance_options',
|
180 |
options: {
|
181 |
// Color.
|
182 |
+
'color' : $color_picker.wpColorPicker('color'),
|
183 |
// Info text.
|
184 |
+
'text_info_first_step' : $.trim($text_info_service.text() == 'Empty' ? '' : $text_info_service.text()),
|
185 |
+
'text_info_second_step' : $.trim($text_info_time.text() == 'Empty' ? '' : $text_info_time.text()),
|
186 |
+
'text_info_third_step' : $.trim($text_info_details.text() == 'Empty' ? '' : $text_info_details.text()),
|
187 |
+
'text_info_third_step_guest' : $.trim($text_info_details_guest.text() == 'Empty' ? '' : $text_info_details_guest.text()),
|
188 |
+
'text_info_fourth_step' : $.trim($text_info_payment.text() == 'Empty' ? '' : $text_info_payment.text()),
|
189 |
+
'text_info_fifth_step' : $.trim($text_info_done.text() == 'Empty' ? '' : $text_info_done.text()),
|
190 |
+
'text_info_coupon' : $.trim($text_info_coupon.text() == 'Empty' ? '' : $text_info_coupon.text()),
|
191 |
// Step and label texts.
|
192 |
+
'text_step_service' : $.trim($text_step_service.text() == 'Empty' ? '' : $text_step_service.text()),
|
193 |
+
'text_step_time' : $.trim($text_step_time.text() == 'Empty' ? '' : $text_step_time.text()),
|
194 |
+
'text_step_details' : $.trim($text_step_details.text() == 'Empty' ? '' : $text_step_details.text()),
|
195 |
+
'text_step_payment' : $.trim($text_step_payment.text() == 'Empty' ? '' : $text_step_payment.text()),
|
196 |
+
'text_step_done' : $.trim($text_step_done.text() == 'Empty' ? '' : $text_step_done.text()),
|
197 |
+
'text_label_category' : $.trim($text_label_category.text() == 'Empty' ? '' : $text_label_category.text()),
|
198 |
+
'text_label_service' : $.trim($text_label_service.text() == 'Empty' ? '' : $text_label_service.text()),
|
199 |
+
'text_label_number_of_persons' : $.trim($text_label_number_of_persons.text() == 'Empty' ? '' : $text_label_number_of_persons.text()),
|
200 |
+
'text_label_employee' : $.trim($text_label_employee.text() == 'Empty' ? '' : $text_label_employee.text()),
|
201 |
+
'text_label_select_date' : $.trim($text_label_select_date.text() == 'Empty' ? '' : $text_label_select_date.text()),
|
202 |
+
'text_label_start_from' : $.trim($text_label_start_from.text() == 'Empty' ? '' : $text_label_start_from.text()),
|
203 |
+
'text_label_finish_by' : $.trim($text_label_finish_by.text() == 'Empty' ? '' : $text_label_finish_by.text()),
|
204 |
+
'text_label_name' : $.trim($text_label_name.text() == 'Empty' ? '' : $text_label_name.text()),
|
205 |
+
'text_label_phone' : $.trim($text_label_phone.text() == 'Empty' ? '' : $text_label_phone.text()),
|
206 |
+
'text_label_email' : $.trim($text_label_email.text() == 'Empty' ? '' : $text_label_email.text()),
|
207 |
+
'text_label_coupon' : $.trim($text_label_coupon.text() == 'Empty' ? '' : $text_label_coupon.text()),
|
208 |
+
'text_option_category' : $.trim($text_option_category.text() == 'Empty' ? '' : $text_option_category.text()),
|
209 |
+
'text_option_service' : $.trim($text_option_service.text() == 'Empty' ? '' : $text_option_service.text()),
|
210 |
+
'text_option_employee' : $.trim($text_option_employee.text() == 'Empty' ? '' : $text_option_employee.text()),
|
211 |
+
'text_label_pay_locally' : $.trim($text_label_pay_locally.text() == 'Empty' ? '' : $text_label_pay_locally.text()),
|
212 |
// Checkboxes.
|
213 |
+
'progress_tracker' : Number($progress_tracker_option.prop('checked')),
|
214 |
+
'blocked_timeslots' : Number($blocked_timeslots_option.prop('checked')),
|
215 |
+
'day_one_column' : Number($day_one_column_option.prop('checked')),
|
216 |
+
'show_calendar' : Number($show_calendar_option.prop('checked'))
|
217 |
} // options
|
218 |
}; // data
|
219 |
|
220 |
// update data and show spinner while updating
|
221 |
+
var ladda = Ladda.create(this);
|
222 |
+
ladda.start();
|
223 |
$.post(ajaxurl, data, function (response) {
|
224 |
+
ladda.stop();
|
225 |
+
$('.notice-success').show();
|
226 |
});
|
227 |
});
|
228 |
|
266 |
$(this).is(':checked') ? $('div.ab-progress-tracker').show() : $('div.ab-progress-tracker').hide();
|
267 |
}).trigger('change');
|
268 |
|
269 |
+
var clickTwoStep = function() {
|
270 |
+
$tabs.children('li').removeClass('active');
|
271 |
+
$tabs.children('li[data-step-id="2"]').trigger('click').addClass('active');
|
272 |
+
};
|
273 |
+
|
274 |
+
var day_one_column = $('.ab-day-one-column'),
|
275 |
+
day_columns = $('.ab-day-columns');
|
276 |
+
|
277 |
+
// Change show calendar
|
278 |
+
$show_calendar_option.change(function() {
|
279 |
+
if (this.checked) {
|
280 |
+
$second_step_calendar_wrap.show();
|
281 |
+
day_columns.find('.col5,.col6,.col7').hide();
|
282 |
+
day_one_column.find('.col5,.col6,.col7').hide();
|
283 |
+
} else {
|
284 |
+
$second_step_calendar_wrap.hide();
|
285 |
+
day_one_column.find('.col5,.col6,.col7').css('display','inline-block');
|
286 |
+
day_columns.find('.col5,.col6,.col7').css('display','inline-block');
|
287 |
+
}
|
288 |
+
clickTwoStep();
|
289 |
+
});
|
290 |
+
|
291 |
+
// Change blocked time slots.
|
292 |
+
$blocked_timeslots_option.change(function(){
|
293 |
+
if (this.checked) {
|
294 |
+
$('.ab-available-hour.no-booked').removeClass('no-booked').addClass('booked');
|
295 |
+
} else {
|
296 |
+
$('.ab-available-hour.booked').removeClass('booked').addClass('no-booked');
|
297 |
+
}
|
298 |
+
clickTwoStep();
|
299 |
+
});
|
300 |
+
|
301 |
+
// Change day one column.
|
302 |
+
$day_one_column_option.change(function() {
|
303 |
+
if (this.checked) {
|
304 |
+
day_one_column.show();
|
305 |
+
day_columns.hide();
|
306 |
+
} else {
|
307 |
+
day_one_column.hide();
|
308 |
+
day_columns.show();
|
309 |
+
}
|
310 |
+
clickTwoStep();
|
311 |
+
});
|
312 |
+
|
313 |
// Clickable week-days.
|
314 |
$('.ab-week-day').on('change', function () {
|
315 |
var self = $(this);
|
320 |
}
|
321 |
});
|
322 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
var multiple = function (options) {
|
324 |
this.init('multiple', options, multiple.defaults);
|
325 |
};
|
326 |
|
327 |
+
// Inherit from Abstract input.
|
328 |
$.fn.editableutils.inherit(multiple, $.fn.editabletypes.abstractinput);
|
329 |
|
330 |
$.extend(multiple.prototype, {
|
364 |
});
|
365 |
|
366 |
multiple.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
|
367 |
+
tpl: '<div class="editable-multiple"><label><input type="text" name="label" class="input-medium form-control"></label></div>'+
|
368 |
+
'<div style="margin-top:5px;" class="editable-multiple"><label><input type="text" name="option" class="input-medium form-control"><input type="hidden" name="id_option"></label></div>',
|
369 |
|
370 |
inputclass: ''
|
371 |
});
|
376 |
value: {
|
377 |
label: $text_label_category.text(),
|
378 |
option: $text_option_category.text(),
|
379 |
+
id_option: $text_label_category.data('option-id')
|
380 |
}
|
381 |
});
|
382 |
$text_label_service.editable({
|
383 |
value: {
|
384 |
label: $text_label_service.text(),
|
385 |
option: $text_option_service.text(),
|
386 |
+
id_option: $text_label_service.data('option-id')
|
387 |
}
|
388 |
});
|
389 |
$text_label_employee.editable({
|
390 |
value: {
|
391 |
label: $text_label_employee.text(),
|
392 |
option: $text_option_employee.text(),
|
393 |
+
id_option: $text_label_employee.data('option-id')
|
394 |
}
|
395 |
});
|
396 |
|
397 |
+
$text_info_service.add('#ab-text-info-second').add('#ab-text-info-third').add('#ab-text-info-fourth').add('#ab-text-info-fifth').add('#ab-text-info-coupon').editable({placement: 'right'});
|
398 |
+
$ab_editable.editable();
|
399 |
|
400 |
$.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 style="margin-top: 10px;" class="editable-notes"></div><div class="editable-error-block"></div></div> </form>';
|
401 |
|
407 |
$("span[data-link-class='" + $(e.target).data('link-class') + "']").editable('setValue', params.newValue);
|
408 |
$("span." + $(e.target).data('link-class')).text(params.newValue);
|
409 |
});
|
410 |
+
|
411 |
+
if(jQuery('.ab-authorizenet-payment').is(':checked')) {
|
412 |
+
jQuery('form.ab-authorizenet').show();
|
413 |
+
}
|
414 |
+
|
415 |
+
if(jQuery('.ab-stripe-payment').is(':checked')) {
|
416 |
+
jQuery('form.ab-stripe').show();
|
417 |
+
}
|
418 |
+
|
419 |
+
jQuery('input[type=radio]').change( function() {
|
420 |
+
jQuery('form.ab-authorizenet').add('form.ab-stripe').hide();
|
421 |
+
if(jQuery('.ab-authorizenet-payment').is(':checked')) {
|
422 |
+
jQuery('form.ab-authorizenet').show();
|
423 |
+
} else if(jQuery('.ab-stripe-payment').is(':checked')) {
|
424 |
+
jQuery('form.ab-stripe').show();
|
425 |
+
}
|
426 |
+
});
|
427 |
+
}); // jQuery
|
backend/modules/appearance/templates/_1_service.php
CHANGED
@@ -1,21 +1,23 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
-
|
3 |
-
|
|
|
|
|
4 |
|
5 |
<!-- Progress Tracker-->
|
6 |
<?php $step = 1; include '_progress_tracker.php'; ?>
|
7 |
|
8 |
-
<div class="ab-
|
9 |
-
<div
|
10 |
-
<span data-inputclass="input-xxlarge" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_first_step' ) )
|
11 |
</div>
|
12 |
<div class=ab-service-form>
|
13 |
-
<div class="ab-mobile-step_1 ab-row-fluid">
|
14 |
-
<div class="ab-
|
15 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_category' )
|
16 |
-
<div class="ab-
|
17 |
-
<select class="
|
18 |
-
<option value="" class="editable" id="ab-text-option-category" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_option_category' ) )
|
19 |
<option value="1">Cosmetic Dentistry</option>
|
20 |
<option value="2">Invisalign</option>
|
21 |
<option value="3">Orthodontics</option>
|
@@ -23,11 +25,11 @@
|
|
23 |
</select>
|
24 |
</div>
|
25 |
</div>
|
26 |
-
<div class="ab-
|
27 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_service' )
|
28 |
-
<div class="ab-
|
29 |
-
<select class="
|
30 |
-
<option value="" class="editable" id="ab-text-option-service" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_option_service' ) ); ?>"><?php echo
|
31 |
<option value="1">Crown and Bridge</option>
|
32 |
<option value="2">Teeth Whitening</option>
|
33 |
<option value="3">Veneers</option>
|
@@ -39,11 +41,11 @@
|
|
39 |
</select>
|
40 |
</div>
|
41 |
</div>
|
42 |
-
<div class="ab-
|
43 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_employee' )
|
44 |
-
<div class="ab-
|
45 |
-
<select class="
|
46 |
-
<option value="" class="editable" id="ab-text-option-employee" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_option_employee' ) )
|
47 |
<option value="1">Nick Knight</option>
|
48 |
<option value="2">Jane Howard</option>
|
49 |
<option value="3">Ashley Stamp</option>
|
@@ -57,139 +59,79 @@
|
|
57 |
</select>
|
58 |
</div>
|
59 |
</div>
|
60 |
-
<
|
61 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
</button>
|
63 |
</div>
|
64 |
<div class="ab-mobile-step_2">
|
65 |
<div class="ab-row-fluid">
|
66 |
-
<div class="ab-
|
67 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_select_date' )
|
68 |
-
<div class="ab-input-wrap">
|
69 |
-
<span class="ab-
|
70 |
-
<input style="
|
71 |
</span>
|
72 |
</div>
|
73 |
</div>
|
74 |
-
<div class="ab-
|
75 |
<ul class="ab-week-days">
|
76 |
-
|
77 |
-
<
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
<div class="ab-bold"><?php _e( 'Mon', 'ab' ) ?></div>
|
85 |
-
<!-- #11055: all days are checked by default -->
|
86 |
-
<label class="active">
|
87 |
-
<input class="ab-week-day ab-week-day-2" value="2" checked="checked" type="checkbox">
|
88 |
-
</label>
|
89 |
-
</li>
|
90 |
-
<li>
|
91 |
-
<div class="ab-bold"><?php _e( 'Tue', 'ab' ) ?></div>
|
92 |
-
<!-- #11055: all days are checked by default -->
|
93 |
-
<label class="active">
|
94 |
-
<input class="ab-week-day ab-week-day-3" value="3" checked="checked" type="checkbox">
|
95 |
-
</label>
|
96 |
-
</li>
|
97 |
-
<li>
|
98 |
-
<div class="ab-bold"><?php _e( 'Wed', 'ab' ) ?></div>
|
99 |
-
<!-- #11055: all days are checked by default -->
|
100 |
-
<label class="active">
|
101 |
-
<input class="ab-week-day ab-week-day-4" value="4" checked="checked" type="checkbox">
|
102 |
-
</label>
|
103 |
-
</li>
|
104 |
-
<li>
|
105 |
-
<div class="ab-bold"><?php _e( 'Thu', 'ab' ) ?></div>
|
106 |
-
<!-- #11055: all days are checked by default -->
|
107 |
-
<label class="active">
|
108 |
-
<input class="ab-week-day ab-week-day-5" value="5" checked="checked" type="checkbox">
|
109 |
-
</label>
|
110 |
-
</li>
|
111 |
-
<li>
|
112 |
-
<div class="ab-bold"><?php _e( 'Fri', 'ab' ) ?></div>
|
113 |
-
<!-- #11055: all days are checked by default -->
|
114 |
-
<label class="active">
|
115 |
-
<input class="ab-week-day ab-week-day-6" value="6" checked="checked" type="checkbox">
|
116 |
-
</label>
|
117 |
-
</li>
|
118 |
-
<li>
|
119 |
-
<div class="ab-bold"><?php _e( 'Sat', 'ab' ) ?></div>
|
120 |
-
<!-- #11055: all days are checked by default -->
|
121 |
-
<label class="active">
|
122 |
-
<input class="ab-week-day ab-week-day-7" value="7" checked="checked" type="checkbox">
|
123 |
-
</label>
|
124 |
-
</li>
|
125 |
</ul>
|
126 |
</div>
|
127 |
-
<div class="ab-
|
128 |
-
<div class="ab-
|
129 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_start_from' )
|
130 |
-
<div
|
131 |
-
<select class="select-list ab-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
<option value="03:00">3:00 am</option>
|
136 |
-
<option value="04:00">4:00 am</option>
|
137 |
-
<option value="05:00">5:00 am</option>
|
138 |
-
<option value="06:00">6:00 am</option>
|
139 |
-
<option value="07:00">7:00 am</option>
|
140 |
-
<option value="08:00" selected="selected">8:00 am</option>
|
141 |
-
<option value="09:00">9:00 am</option>
|
142 |
-
<option value="10:00">10:00 am</option>
|
143 |
-
<option value="11:00">11:00 am</option>
|
144 |
-
<option value="12:00">12:00 pm</option>
|
145 |
-
<option value="13:00">1:00 pm</option>
|
146 |
-
<option value="14:00">2:00 pm</option>
|
147 |
-
<option value="15:00">3:00 pm</option>
|
148 |
-
<option value="16:00">4:00 pm</option>
|
149 |
-
<option value="17:00">5:00 pm</option>
|
150 |
-
<option value="18:00">6:00 pm</option>
|
151 |
-
<option value="19:00">7:00 pm</option>
|
152 |
-
<option value="20:00">8:00 pm</option>
|
153 |
-
<option value="21:00">9:00 pm</option>
|
154 |
-
<option value="22:00">10:00 pm</option>
|
155 |
-
<option value="23:00">11:00 pm</option>
|
156 |
</select>
|
157 |
</div>
|
158 |
</div>
|
159 |
-
<div class="ab-
|
160 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_finish_by' )
|
161 |
-
<div
|
162 |
-
<select class="select-list ab-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
<option value="12:00">12:00 pm</option>
|
167 |
-
<option value="13:00">1:00 pm</option>
|
168 |
-
<option value="14:00">2:00 pm</option>
|
169 |
-
<option value="15:00">3:00 pm</option>
|
170 |
-
<option value="16:00">4:00 pm</option>
|
171 |
-
<option value="17:00">5:00 pm</option>
|
172 |
-
<option value="18:00">6:00 pm</option>
|
173 |
-
<option value="19:00">7:00 pm</option>
|
174 |
-
<option value="20:00">8:00 pm</option>
|
175 |
-
<option value="21:00">9:00 pm</option>
|
176 |
-
<option value="22:00">10:00 pm</option>
|
177 |
-
<option value="23:00">11:00 pm</option>
|
178 |
-
<option value="23:59">12:00 am</option>
|
179 |
</select>
|
180 |
</div>
|
181 |
</div>
|
182 |
</div>
|
183 |
</div>
|
184 |
<div class="ab-row-fluid ab-nav-steps last-row ab-clear">
|
185 |
-
<button class="ab-right ab-mobile-prev-step
|
186 |
-
<span><?php _e( 'Back', '
|
187 |
</button>
|
188 |
-
<button class="ab-right ab-next-step ladda-button
|
189 |
-
<span><?php _e( 'Next', '
|
190 |
</button>
|
191 |
</div>
|
192 |
</div>
|
193 |
</div>
|
194 |
</div>
|
195 |
-
</div>
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
/** @var WP_Locale $wp_locale */
|
3 |
+
global $wp_locale;
|
4 |
+
?>
|
5 |
+
<div class="ab-booking-form">
|
6 |
|
7 |
<!-- Progress Tracker-->
|
8 |
<?php $step = 1; include '_progress_tracker.php'; ?>
|
9 |
|
10 |
+
<div class="ab-first-step">
|
11 |
+
<div class="ab-row-fluid">
|
12 |
+
<span data-inputclass="input-xxlarge" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_first_step' ) ) ?>" class="ab-bold ab_editable" id="ab-text-info-first" data-rows="7" data-type="textarea"><?php echo esc_html( get_option( 'ab_appearance_text_info_first_step' ) ) ?></span>
|
13 |
</div>
|
14 |
<div class=ab-service-form>
|
15 |
+
<div class="ab-mobile-step_1 ab-four-cols ab-row-fluid">
|
16 |
+
<div class="ab-formGroup ab-left">
|
17 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_category' ) ) ?>" class="ab-formLabel text_category_label" id="ab-text-label-category" data-type="multiple" data-option-id="ab-text-option-category"><?php echo esc_html( get_option( 'ab_appearance_text_label_category' ) ) ?></label>
|
18 |
+
<div class="ab-formField">
|
19 |
+
<select class="ab-formElement ab-select-mobile ab-select-category" style="width: 100%">
|
20 |
+
<option value="" class="editable" id="ab-text-option-category" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_option_category' ) ) ?>"><?php echo esc_html( get_option( 'ab_appearance_text_option_category' ) ) ?></option>
|
21 |
<option value="1">Cosmetic Dentistry</option>
|
22 |
<option value="2">Invisalign</option>
|
23 |
<option value="3">Orthodontics</option>
|
25 |
</select>
|
26 |
</div>
|
27 |
</div>
|
28 |
+
<div class="ab-formGroup ab-left">
|
29 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_service' ) ) ?>" class="ab-formLabel text_service_label" id="ab-text-label-service" data-type="multiple" data-option-id="ab-text-option-service"><?php echo esc_html( get_option( 'ab_appearance_text_label_service' ) ) ?></label>
|
30 |
+
<div class="ab-formField">
|
31 |
+
<select class="ab-formElement ab-select-mobile ab-select-service" style="width: 100%">
|
32 |
+
<option value="" class="editable" id="ab-text-option-service" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_option_service' ) ); ?>"><?php echo esc_html( get_option( 'ab_appearance_text_option_service' ) ) ?></option>
|
33 |
<option value="1">Crown and Bridge</option>
|
34 |
<option value="2">Teeth Whitening</option>
|
35 |
<option value="3">Veneers</option>
|
41 |
</select>
|
42 |
</div>
|
43 |
</div>
|
44 |
+
<div class="ab-formGroup ab-left">
|
45 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_employee' ) ) ?>" class="ab-formLabel text_employee_label" id="ab-text-label-employee" data-type="multiple" data-option-id="ab-text-option-employee"><?php echo esc_html( get_option( 'ab_appearance_text_label_employee' ) ) ?></label>
|
46 |
+
<div class="ab-formField">
|
47 |
+
<select class="ab-formElement ab-select-mobile ab-select-employee" style="width: 100%">
|
48 |
+
<option value="" class="editable" id="ab-text-option-employee" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_option_employee' ) ) ?>"><?php echo esc_html( get_option( 'ab_appearance_text_option_employee' ) ) ?></option>
|
49 |
<option value="1">Nick Knight</option>
|
50 |
<option value="2">Jane Howard</option>
|
51 |
<option value="3">Ashley Stamp</option>
|
59 |
</select>
|
60 |
</div>
|
61 |
</div>
|
62 |
+
<div class="ab-formGroup ab-left">
|
63 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_number_of_persons' ) ) ?>" class="ab-formLabel ab_editable" data-type="text" id="ab-text-label-number-of-persons"><?php echo esc_html( get_option( 'ab_appearance_text_label_number_of_persons' ) ) ?></label>
|
64 |
+
<div class="ab-formField">
|
65 |
+
<select class="ab-formElement ab-select-mobile ab-select-number-of-persons">
|
66 |
+
<option value="1">1</option>
|
67 |
+
<option value="2">2</option>
|
68 |
+
<option value="3">3</option>
|
69 |
+
</select>
|
70 |
+
</div>
|
71 |
+
</div>
|
72 |
+
|
73 |
+
<button class="ab-right ab-mobile-next-step ab-btn ab-none ladda-button" onclick="return false">
|
74 |
+
<span><?php _e( 'Next', 'bookly' ) ?></span>
|
75 |
</button>
|
76 |
</div>
|
77 |
<div class="ab-mobile-step_2">
|
78 |
<div class="ab-row-fluid">
|
79 |
+
<div class="ab-available-date ab-formGroup ab-lastGroup ab-left">
|
80 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_select_date' ) ) ?>" class="ab_editable ab-nowrap" id="ab-text-label-select_date" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_select_date' ) ) ?></label>
|
81 |
+
<div class="ab-input-wrap ab-formField">
|
82 |
+
<span class="ab-date-wrap">
|
83 |
+
<input style="background: white" class="ab-date-from ab-formElement picker__input--active" type="text" data-value="<?php echo date( 'Y-m-d' ) ?>" />
|
84 |
</span>
|
85 |
</div>
|
86 |
</div>
|
87 |
+
<div class="ab-available-days ab-left">
|
88 |
<ul class="ab-week-days">
|
89 |
+
<?php foreach ( $wp_locale->weekday_abbrev as $weekday_abbrev ): ?>
|
90 |
+
<li>
|
91 |
+
<div class="ab-bold"><?php echo $weekday_abbrev ?></div>
|
92 |
+
<label class="active">
|
93 |
+
<input class="ab-week-day" value="1" checked="checked" type="checkbox">
|
94 |
+
</label>
|
95 |
+
</li>
|
96 |
+
<?php endforeach ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
</ul>
|
98 |
</div>
|
99 |
+
<div class="ab-time-range ab-left">
|
100 |
+
<div class="ab-time-from ab-left">
|
101 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_start_from' ) ) ?>" class="ab_editable" id="ab-text-label-start_from" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_start_from' ) ) ?></label>
|
102 |
+
<div>
|
103 |
+
<select class="select-list ab-select-time-from">
|
104 |
+
<?php for ( $i = 28800; $i <= 64800; $i += 3600 ): ?>
|
105 |
+
<option><?php echo AB_DateTimeUtils::formatTime( $i ) ?></option>
|
106 |
+
<?php endfor ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
</select>
|
108 |
</div>
|
109 |
</div>
|
110 |
+
<div class="ab-time-to ab-left">
|
111 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_finish_by' ) ) ?>" class="ab_editable" id="ab-text-label-finish_by" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_finish_by' ) ) ?></label>
|
112 |
+
<div>
|
113 |
+
<select class="select-list ab-select-time-to">
|
114 |
+
<?php for ( $i = 28800; $i <= 64800; $i += 3600 ): ?>
|
115 |
+
<option<?php selected( $i == 64800 ) ?>><?php echo AB_DateTimeUtils::formatTime( $i ) ?></option>
|
116 |
+
<?php endfor ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
</select>
|
118 |
</div>
|
119 |
</div>
|
120 |
</div>
|
121 |
</div>
|
122 |
<div class="ab-row-fluid ab-nav-steps last-row ab-clear">
|
123 |
+
<button class="ab-right ab-mobile-prev-step ab-btn ab-none ladda-button">
|
124 |
+
<span><?php _e( 'Back', 'bookly' ) ?></span>
|
125 |
</button>
|
126 |
+
<button class="ab-right ab-next-step ab-btn ladda-button">
|
127 |
+
<span><?php _e( 'Next', 'bookly' ) ?></span>
|
128 |
</button>
|
129 |
</div>
|
130 |
</div>
|
131 |
</div>
|
132 |
</div>
|
133 |
+
</div>
|
134 |
+
<style id="ab_update_arrow">
|
135 |
+
.picker__nav--next:before { border-left: 6px solid <?php echo get_option( 'ab_appearance_color' ) ?>!important; }
|
136 |
+
.picker__nav--prev:before { border-right: 6px solid <?php echo get_option( 'ab_appearance_color' ) ?>!important; }
|
137 |
+
</style>
|
backend/modules/appearance/templates/_2_time.php
CHANGED
@@ -1,108 +1,192 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
<?php $step = 2; include '_progress_tracker.php'; ?>
|
6 |
|
7 |
-
<div
|
8 |
-
|
9 |
-
</div>
|
10 |
-
<!-- timeslots -->
|
11 |
-
<div class="ab-columnizer-wrap" style="height: 400px;">
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
<
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
<
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
<
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
<
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
<
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
</div>
|
86 |
-
|
87 |
-
|
88 |
-
<
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
<
|
94 |
-
|
95 |
-
|
96 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
</div>
|
98 |
</div>
|
99 |
</div>
|
100 |
-
|
101 |
-
<
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
|
|
|
|
|
|
108 |
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div id="ab-booking-form" class="ab-booking-form">
|
3 |
+
<!-- Progress Tracker-->
|
4 |
+
<?php $step = 2; include '_progress_tracker.php'; ?>
|
|
|
5 |
|
6 |
+
<div class="ab-row-fluid">
|
7 |
+
<span data-inputclass="input-xxlarge" data-notes="<?php echo esc_attr( $this->render( '_codes', array( 'step' => 2 ), false ) ) ?>" data-placement="bottom" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_second_step' ) ) ?>" class="ab-text-info-second-preview ab-row-fluid ab_editable" id="ab-text-info-second" data-type="textarea"><?php echo esc_html( get_option( 'ab_appearance_text_info_second_step' ) ) ?></span>
|
8 |
+
</div>
|
9 |
+
<!-- timeslots -->
|
10 |
+
<div class="ab-columnizer-wrap" style="height: 400px;">
|
11 |
+
<div class="ab-columnizer">
|
12 |
+
<div class="ab-time-screen ab-day-columns" style="display: <?php echo get_option( 'ab_appearance_show_day_one_column' ) == 1 ? ' none' : 'block' ?>">
|
13 |
+
<div style="margin-right: 40px;" class="ab-input-wrap ab-slot-calendar">
|
14 |
+
<span class="ab-date-wrap">
|
15 |
+
<input style="display: none" class="ab-selected-date ab-formElement" type="text" data-value="<?php echo date( 'Y-m-d' ) ?>" />
|
16 |
+
</span>
|
17 |
+
</div>
|
18 |
+
<div class="ab-column col1">
|
19 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d' ) ?></button>
|
20 |
+
<?php for ( $i = 50400; $i <= 57600; $i += 900 ): ?>
|
21 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
22 |
+
<span class="ladda-label">
|
23 |
+
<i class="ab-hour-icon"><span></span></i>
|
24 |
+
<?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
25 |
+
</span>
|
26 |
+
</button>
|
27 |
+
<?php endfor ?>
|
28 |
+
</div>
|
29 |
+
<div class="ab-column col2">
|
30 |
+
<?php for ( $i = 58500; $i <= 63900; $i += 900 ): ?>
|
31 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
32 |
+
<span class="ladda-label">
|
33 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
34 |
+
</span>
|
35 |
+
</button>
|
36 |
+
<?php endfor ?>
|
37 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+1 day' ) ) ?></button>
|
38 |
+
<button class="ab-available-hour ladda-button ab-last-child">
|
39 |
+
<span class="ladda-label">
|
40 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( 28800 ) ?>
|
41 |
+
</span>
|
42 |
+
</button>
|
43 |
+
<button class="ab-available-hour ladda-button ab-last-child">
|
44 |
+
<span class="ladda-label">
|
45 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( 29700 ) ?>
|
46 |
+
</span>
|
47 |
+
</button>
|
48 |
+
</div>
|
49 |
+
<div class="ab-column col3">
|
50 |
+
<?php for ( $i = 30600; $i <= 38700; $i += 900 ): ?>
|
51 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
52 |
+
<span class="ladda-label">
|
53 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
54 |
+
</span>
|
55 |
+
</button>
|
56 |
+
<?php endfor ?>
|
57 |
+
</div>
|
58 |
+
<div class="ab-column col4">
|
59 |
+
<?php for ( $i = 39600; $i <= 47700; $i += 900 ): ?>
|
60 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
61 |
+
<span class="ladda-label">
|
62 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
63 |
+
</span>
|
64 |
+
</button>
|
65 |
+
<?php endfor ?>
|
66 |
+
</div>
|
67 |
+
<div class="ab-column col5" style="display:<?php echo get_option( 'ab_appearance_show_calendar' ) == 1 ? ' none' : ' inline-block' ?>">
|
68 |
+
<?php for ( $i = 48600; $i <= 56700; $i += 900 ): ?>
|
69 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
70 |
+
<span class="ladda-label">
|
71 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
72 |
+
</span>
|
73 |
+
</button>
|
74 |
+
<?php endfor ?>
|
75 |
+
</div>
|
76 |
+
<div class="ab-column col6" style="display: <?php echo get_option( 'ab_appearance_show_calendar' ) == 1 ? ' none' : 'inline-block' ?>">
|
77 |
+
<?php for ( $i = 57600; $i <= 63900; $i += 900 ): ?>
|
78 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
79 |
+
<span class="ladda-label">
|
80 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
81 |
+
</span>
|
82 |
+
</button>
|
83 |
+
<?php endfor ?>
|
84 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+2 days' ) ) ?></button>
|
85 |
+
<button class="ab-available-hour ladda-button ab-last-child">
|
86 |
+
<span class="ladda-label">
|
87 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( 28800 ) ?>
|
88 |
+
</span>
|
89 |
+
</button>
|
90 |
+
</div>
|
91 |
+
<div class="ab-column col7" style="display:<?php echo get_option( 'ab_appearance_show_calendar' ) == 1 ? ' none' : ' inline-block' ?>">
|
92 |
+
<?php for ( $i = 29700; $i <= 37800; $i += 900 ): ?>
|
93 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
94 |
+
<span class="ladda-label">
|
95 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
96 |
+
</span>
|
97 |
+
</button>
|
98 |
+
<?php endfor ?>
|
99 |
+
</div>
|
100 |
</div>
|
101 |
+
|
102 |
+
<div class="ab-time-screen ab-day-one-column" style="display: <?php echo get_option( 'ab_appearance_show_day_one_column' ) == 1 ? ' block' : 'none' ?>">
|
103 |
+
<div style="margin-right: 40px;" class="ab-input-wrap ab-slot-calendar">
|
104 |
+
<span class="ab-date-wrap">
|
105 |
+
<input style="display: none" class="ab-selected-date ab-formElement" type="text" data-value="<?php echo date( 'Y-m-d' ) ?>" />
|
106 |
+
</span>
|
107 |
+
</div>
|
108 |
+
<div class="ab-column col1">
|
109 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d' ) ?></button>
|
110 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
111 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
112 |
+
<span class="ladda-label">
|
113 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
114 |
+
</span>
|
115 |
+
</button>
|
116 |
+
<?php endfor ?>
|
117 |
+
</div>
|
118 |
+
<div class="ab-column col2">
|
119 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+1 day' ) ) ?></button>
|
120 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
121 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
122 |
+
<span class="ladda-label">
|
123 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
124 |
+
</span>
|
125 |
+
</button>
|
126 |
+
<?php endfor ?>
|
127 |
+
</div>
|
128 |
+
<div class="ab-column col3">
|
129 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+2 days' ) ) ?></button>
|
130 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
131 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
132 |
+
<span class="ladda-label">
|
133 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
134 |
+
</span>
|
135 |
+
</button>
|
136 |
+
<?php endfor ?>
|
137 |
+
</div>
|
138 |
+
<div class="ab-column col4">
|
139 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+3 days' ) ) ?></button>
|
140 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
141 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
142 |
+
<span class="ladda-label">
|
143 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
144 |
+
</span>
|
145 |
+
</button>
|
146 |
+
<?php endfor ?>
|
147 |
+
</div>
|
148 |
+
<div class="ab-column col5" style="display: <?php echo get_option( 'ab_appearance_show_calendar' ) == 1 ? ' none' : 'inline-block' ?>">
|
149 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+4 days' ) ) ?></button>
|
150 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
151 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
152 |
+
<span class="ladda-label">
|
153 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
154 |
+
</span>
|
155 |
+
</button>
|
156 |
+
<?php endfor ?>
|
157 |
+
</div>
|
158 |
+
<div class="ab-column col6" style="display: <?php echo get_option( 'ab_appearance_show_calendar' ) == 1 ? ' none' : 'inline-block' ?>">
|
159 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+5 days' ) ) ?></button>
|
160 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
161 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
162 |
+
<span class="ladda-label">
|
163 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
164 |
+
</span>
|
165 |
+
</button>
|
166 |
+
<?php endfor ?>
|
167 |
+
</div>
|
168 |
+
<div class="ab-column col7" style="display: <?php echo get_option( 'ab_appearance_show_calendar' ) == 1 ? ' none' : 'inline-block' ?>">
|
169 |
+
<button class="ab-available-day ab-first-child"><?php echo date_i18n( 'D, M d', strtotime( '+6 days' ) ) ?></button>
|
170 |
+
<?php for ( $i = 28800; $i <= 36000; $i += 900 ): ?>
|
171 |
+
<button class="ab-available-hour ladda-button<?php if ( mt_rand( 0, 1 ) ) echo get_option( 'ab_appearance_show_blocked_timeslots' ) == 1 ? ' booked' : ' no-booked' ?>">
|
172 |
+
<span class="ladda-label">
|
173 |
+
<i class="ab-hour-icon"><span></span></i><?php echo AB_DateTimeUtils::formatTime( $i ) ?>
|
174 |
+
</span>
|
175 |
+
</button>
|
176 |
+
<?php endfor ?>
|
177 |
+
</div>
|
178 |
</div>
|
179 |
</div>
|
180 |
</div>
|
181 |
+
<div class="ab-row-fluid ab-nav-steps last-row ab-clear">
|
182 |
+
<button class="ab-time-next ab-btn ab-right ladda-button">
|
183 |
+
<span class="ab_label">></span>
|
184 |
+
</button>
|
185 |
+
<button class="ab-time-prev ab-btn ab-right ladda-button">
|
186 |
+
<span class="ab_label"><</span>
|
187 |
+
</button>
|
188 |
+
<button class="ab-left ab-to-first-step ab-btn ladda-button">
|
189 |
+
<span><?php _e( 'Back', 'bookly' ) ?></span>
|
190 |
+
</button>
|
191 |
+
</div>
|
192 |
</div>
|
backend/modules/appearance/templates/_3_details.php
CHANGED
@@ -1,48 +1,42 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
<?php $step = 3; include '_progress_tracker.php'; ?>
|
6 |
|
7 |
-
|
8 |
-
|
9 |
-
</div>
|
10 |
-
<form class="ab-your-details-form ab-row-fluid">
|
11 |
-
<div class="ab-details-list ab-left">
|
12 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_name' ); ?>" data-link-class="text_name_label" class="ab-formLabel text_name_label ab_editable" id="ab-text-label-name" data-type="text" data-pk="1"><?php echo esc_html(get_option( 'ab_appearance_text_label_name' )) ?></label>
|
13 |
-
<div class="ab-details-wrap">
|
14 |
-
<input class="ab-full-name" type="text" value="" maxlength="60">
|
15 |
-
</div>
|
16 |
-
<div class="ab-full-name-error ab-bold"></div>
|
17 |
</div>
|
18 |
-
<div class="ab-
|
19 |
-
|
20 |
-
<div class="ab-details-wrap">
|
21 |
-
<input class="ab-user-phone" maxlength="30" type="text" value="">
|
22 |
-
</div>
|
23 |
-
<div class="ab-user-phone-error ab-bold"></div>
|
24 |
</div>
|
25 |
-
<
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
</div>
|
32 |
-
<div class="ab-clear"></div>
|
33 |
-
<div class="ab-details-list ab-textarea">
|
34 |
-
<label data-default="<?php echo get_option( 'ab_appearance_text_label_notes' ); ?>" data-link-class="text_notes_label" class="ab-formLabel text_notes_label ab_editable" id="ab-text-label-notes" data-type="text" data-pk="1"><?php echo esc_html(get_option( 'ab_appearance_text_label_notes' )) ?></label>
|
35 |
-
<div style="margin: 5px 2px 0 0">
|
36 |
-
<textarea rows="6" class="ab-user-notes"></textarea>
|
37 |
-
</div>
|
38 |
-
</div>
|
39 |
-
</form>
|
40 |
-
<div class="ab-row-fluid last-row ab-nav-steps ab-clear">
|
41 |
-
<button class="ab-left ab-to-second-step ladda-button orange zoom-in" style="margin-right: 10px;">
|
42 |
-
<span><?php _e( 'Back', 'ab' ) ?></span>
|
43 |
-
</button>
|
44 |
-
<button class="ab-right ab-to-fourth-step ladda-button orange zoom-in">
|
45 |
-
<span><?php _e( 'Next', 'ab' ) ?></span>
|
46 |
-
</button>
|
47 |
-
</div>
|
48 |
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="ab-booking-form">
|
3 |
+
<!-- Progress Tracker-->
|
4 |
+
<?php $step = 3; include '_progress_tracker.php'; ?>
|
|
|
5 |
|
6 |
+
<div class="ab-row-fluid">
|
7 |
+
<span data-inputclass="input-xxlarge" data-notes="<?php echo esc_attr( $this->render( '_codes', array( 'step' => 3, 'login' => false ), false ) ) ?>" data-placement="bottom" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_third_step' ) ) ?>" class="ab-text-info-third-preview ab-row-fluid ab_editable" id="ab-text-info-third" data-type="textarea"><?php echo esc_html( get_option( 'ab_appearance_text_info_third_step' ) ) ?></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
</div>
|
9 |
+
<div class="ab-row-fluid">
|
10 |
+
<span data-inputclass="input-xxlarge" data-title="<?php _e( 'Visible to non-logged in customers only', 'bookly' ) ?>" data-notes="<?php echo esc_attr( $this->render( '_codes', array( 'step' => 3, 'login' => true ), false ) ) ?>" data-placement="bottom" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_third_step_guest' ) ) ?>" class="ab-text-info-third-preview ab-row-fluid ab_editable" id="ab-text-info-third-guest" data-type="textarea"><?php echo esc_html( get_option( 'ab_appearance_text_info_third_step_guest' ) ) ?></span>
|
|
|
|
|
|
|
|
|
11 |
</div>
|
12 |
+
<form class="ab-third-step">
|
13 |
+
<div class="ab-row-fluid ab-col-phone" style="height: 55px; overflow: visible;">
|
14 |
+
<div class="ab-formGroup ab-left">
|
15 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_name' ) ) ?>" class="ab-formLabel text_name_label ab_editable" id="ab-text-label-name" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_name' ) ) ?></label>
|
16 |
+
<div class="ab-formField">
|
17 |
+
<input class="ab-formElement" type="text" value="" maxlength="60" />
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
<div class="ab-formGroup ab-left">
|
21 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_phone' ) ) ?>" class="ab-formLabel text_phone_label ab_editable" id="ab-text-label-phone" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_phone' ) ) ?></label>
|
22 |
+
<div class="ab-formField">
|
23 |
+
<input class="ab-formElement ab-user-phone" maxlength="30" type="tel" value="" />
|
24 |
+
</div>
|
25 |
+
</div>
|
26 |
+
<div class="ab-formGroup ab-left">
|
27 |
+
<label data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_email' ) ) ?>" class="ab-formLabel text_email_label ab_editable" id="ab-text-label-email" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_email' ) ) ?></label>
|
28 |
+
<div class="ab-formField" style="margin-right: 0">
|
29 |
+
<input class="ab-formElement" maxlength="40" type="text" value="" />
|
30 |
+
</div>
|
31 |
+
</div>
|
32 |
+
</div>
|
33 |
+
</form>
|
34 |
+
<div class="ab-row-fluid last-row ab-nav-steps ab-clear">
|
35 |
+
<button class="ab-left ab-to-second-step ab-btn ladda-button">
|
36 |
+
<span><?php _e( 'Back', 'bookly' ) ?></span>
|
37 |
+
</button>
|
38 |
+
<button class="ab-right ab-to-fourth-step ab-btn ladda-button">
|
39 |
+
<span><?php _e( 'Next', 'bookly' ) ?></span>
|
40 |
+
</button>
|
41 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
</div>
|
backend/modules/appearance/templates/_4_payment.php
CHANGED
@@ -1,41 +1,60 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
|
3 |
-
<div class="ab-booking-form" style="overflow: hidden">
|
4 |
<!-- Progress Tracker-->
|
5 |
<?php $step = 4; include '_progress_tracker.php'; ?>
|
6 |
-
<div style="margin-bottom: 15px!important;" class="ab-row-fluid">
|
7 |
-
<span data-inputclass="input-xxlarge" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_fourth_step' ) ) ?>" data-link-class="ab-text-info-fourth" class="ab-text-info-fourth-preview ab-row-fluid ab_editable" id="ab-text-info-fourth" data-type="textarea" data-pk="1"><?php echo esc_html( get_option( 'ab_appearance_text_info_fourth_step' ) ) ?></span>
|
8 |
-
</div>
|
9 |
<!-- payment -->
|
10 |
<div class="ab-payment">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
<!-- label -->
|
12 |
<div class="ab-row-fluid">
|
13 |
<label>
|
14 |
<input type="radio" name="payment" class="ab-local-payment" checked="checked" value="local"/>
|
15 |
-
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
</label>
|
17 |
</div>
|
18 |
<div class="ab-row-fluid">
|
19 |
<label>
|
20 |
-
<input type="radio" name="payment" class="ab-
|
21 |
-
<?php _e( 'I will pay now with
|
|
|
22 |
</label>
|
|
|
|
|
|
|
23 |
</div>
|
|
|
24 |
<!-- buttons -->
|
25 |
<div class="ab-local-pay-button ab-row-fluid ab-nav-steps last-row">
|
26 |
-
<button class="ab-left ab-to-third-step ladda-button
|
27 |
-
<span><?php _e( 'Back', '
|
28 |
</button>
|
29 |
-
<button class="ab-right ab-final-step ladda-button
|
30 |
-
<span><?php _e( 'Next', '
|
31 |
</button>
|
32 |
</div>
|
33 |
</div>
|
34 |
-
</div>
|
35 |
-
|
36 |
-
<!-- fourth step options -->
|
37 |
-
<div class="ab-fourth-step-options">
|
38 |
-
<!-- booking-info -->
|
39 |
-
<div class="ab-booking-details">
|
40 |
-
</div>
|
41 |
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="ab-booking-form">
|
|
|
3 |
<!-- Progress Tracker-->
|
4 |
<?php $step = 4; include '_progress_tracker.php'; ?>
|
|
|
|
|
|
|
5 |
<!-- payment -->
|
6 |
<div class="ab-payment">
|
7 |
+
<!-- Coupons -->
|
8 |
+
<div class="ab-row-fluid">
|
9 |
+
<span data-inputclass="input-xxlarge" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_coupon' ) ) ?>" data-notes="<?php echo esc_attr( $this->render( '_codes', array( 'step' => 4 ), false ) ) ?>" class="ab-text-info-coupon-preview ab-row-fluid ab_editable" id="ab-text-info-coupon" data-type="textarea"><?php echo esc_html( get_option( 'ab_appearance_text_info_coupon' ) ) ?></span>
|
10 |
+
</div>
|
11 |
+
|
12 |
+
<div style="margin-bottom: 15px">
|
13 |
+
<span data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_coupon' ) ) ?>" class="ab_editable editable editable-click inline-block" id="ab-text-label-coupon" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_label_coupon' ) ) ?></span>
|
14 |
+
<div class="ab-inline-block">
|
15 |
+
<input class="ab-user-coupon ab-inline-block" maxlength="40" type="text" value="" />
|
16 |
+
<button class="ab-btn ladda-button orange ab-inline-block"><?php _e( 'Apply', 'bookly' ) ?></button>
|
17 |
+
</div>
|
18 |
+
</div>
|
19 |
+
<div class="ab-clear"></div>
|
20 |
+
|
21 |
+
<div class="ab-row-fluid">
|
22 |
+
<span data-inputclass="input-xxlarge" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_fourth_step' ) ) ?>" data-notes="<?php echo esc_attr( $this->render( '_codes', array( 'step' => 4 ), false ) ) ?>" class="ab-text-info-fourth-preview ab-row-fluid ab_editable" id="ab-text-info-fourth" data-type="textarea"><?php echo esc_html( get_option( 'ab_appearance_text_info_fourth_step' ) ) ?></span>
|
23 |
+
</div>
|
24 |
+
|
25 |
<!-- label -->
|
26 |
<div class="ab-row-fluid">
|
27 |
<label>
|
28 |
<input type="radio" name="payment" class="ab-local-payment" checked="checked" value="local"/>
|
29 |
+
<span id="ab-text-label-pay-locally" class="ab_editable" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_label_pay_locally' ) ) ?>"><?php echo esc_html( get_option( 'ab_appearance_text_label_pay_locally' ) ) ?></span>
|
30 |
+
</label>
|
31 |
+
</div>
|
32 |
+
<div class="ab-row-fluid">
|
33 |
+
<label>
|
34 |
+
<input type="radio" name="payment" class="ab-paypal-payment" value="paypal" />
|
35 |
+
<?php _e( 'I will pay now with PayPal', 'bookly' ) ?>
|
36 |
+
<img src="<?php echo plugins_url( 'frontend/resources/images/paypal.png', AB_PATH . '/main.php' ) ?>" style="margin-left: 10px;" alt="paypal" />
|
37 |
</label>
|
38 |
</div>
|
39 |
<div class="ab-row-fluid">
|
40 |
<label>
|
41 |
+
<input type="radio" name="payment" class="ab-stripe-payment" value="stripe"/>
|
42 |
+
<?php _e( 'I will pay now with Credit Card', 'bookly' ) ?>
|
43 |
+
<img style="margin-left: 10px;" src="<?php echo plugins_url( 'frontend/resources/images/cards.png', AB_PATH . '/main.php' ) ?>" alt="cards" />
|
44 |
</label>
|
45 |
+
<form class="ab-stripe ab-clearBottom" style="margin-top:15px;display: none;">
|
46 |
+
<?php include "_card_payment.php" ?>
|
47 |
+
</form>
|
48 |
</div>
|
49 |
+
|
50 |
<!-- buttons -->
|
51 |
<div class="ab-local-pay-button ab-row-fluid ab-nav-steps last-row">
|
52 |
+
<button class="ab-left ab-to-third-step ab-btn ladda-button">
|
53 |
+
<span><?php _e( 'Back', 'bookly' ) ?></span>
|
54 |
</button>
|
55 |
+
<button class="ab-right ab-final-step ab-btn ladda-button">
|
56 |
+
<span><?php _e( 'Next', 'bookly' ) ?></span>
|
57 |
</button>
|
58 |
</div>
|
59 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
</div>
|
backend/modules/appearance/templates/_5_done.php
CHANGED
@@ -1,15 +1,8 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
|
3 |
-
<div class="ab-booking-form" style="overflow: hidden">
|
4 |
<!-- Progress Tracker-->
|
5 |
<?php $step = 5; include '_progress_tracker.php'; ?>
|
6 |
-
<div
|
7 |
-
<span data-inputclass="input-xxlarge" data-link-class="ab-text-info-fifth" class="ab-text-info-fifth-preview ab_editable" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_fifth_step' ) ) ?>" id="ab-text-info-fifth" data-type="textarea"
|
8 |
-
</div>
|
9 |
-
</div>
|
10 |
-
|
11 |
-
<!-- fifth step options -->
|
12 |
-
<div class="ab-fifth-step-options">
|
13 |
-
<div class="ab-booking-details">
|
14 |
</div>
|
15 |
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="ab-booking-form">
|
|
|
3 |
<!-- Progress Tracker-->
|
4 |
<?php $step = 5; include '_progress_tracker.php'; ?>
|
5 |
+
<div class="ab-row-fluid">
|
6 |
+
<span data-inputclass="input-xxlarge" data-link-class="ab-text-info-fifth" class="ab-text-info-fifth-preview ab_editable" data-notes="<?php echo esc_attr( $this->render( '_codes', array( 'step' => 5 ), false ) ) ?>" data-placement="bottom" data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_info_fifth_step' ) ) ?>" id="ab-text-info-fifth" data-type="textarea"><?php echo nl2br( esc_html( get_option( 'ab_appearance_text_info_fifth_step' ) ) ) ?></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
</div>
|
8 |
</div>
|
backend/modules/appearance/templates/_card_payment.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="ab-row-fluid">
|
3 |
+
<div class="ab-formGroup ab-left">
|
4 |
+
<label class="ab-formLabel"><?php _e( 'Credit Card Number', 'bookly' ) ?></label>
|
5 |
+
<div class="ab-formField">
|
6 |
+
<input class="ab-formElement ab-full-name" type="text" name="ab_card_number">
|
7 |
+
</div>
|
8 |
+
</div>
|
9 |
+
<div class="ab-formGroup ab-left" style="width: auto;">
|
10 |
+
<label class="ab-formLabel"><?php _e( 'Expiration Date', 'bookly' ) ?></label>
|
11 |
+
<div class="ab-formField">
|
12 |
+
<select class="ab-formElement ab-full-name" style="width: 40px;float: left;" name="ab_card_month">
|
13 |
+
<?php for ( $i = 1; $i <= 12; ++ $i ): ?>
|
14 |
+
<option value="<?php echo $i ?>"><?php printf( '%02d', $i ) ?></option>
|
15 |
+
<?php endfor ?>
|
16 |
+
</select>
|
17 |
+
<select class="ab-formElement ab-full-name" style="width: 55px;float: left; margin-left: 10px;" name="ab_card_year">
|
18 |
+
<?php for ( $i = date( 'Y' ); $i <= date( 'Y' ) + 10; ++ $i ): ?>
|
19 |
+
<option value="<?php echo $i ?>"><?php echo $i ?></option>
|
20 |
+
<?php endfor ?>
|
21 |
+
</select>
|
22 |
+
</div>
|
23 |
+
</div>
|
24 |
+
</div>
|
25 |
+
<div class="ab-row-fluid">
|
26 |
+
<div class="ab-formGroup ab-left">
|
27 |
+
<label class="ab-formLabel"><?php _e( 'Card Security Code', 'bookly' ) ?></label>
|
28 |
+
<div class="ab-formField">
|
29 |
+
<input class="ab-formElement ab-full-name" style="width: 50px;float: left;" type="text" name="ab_card_code" />
|
30 |
+
</div>
|
31 |
+
</div>
|
32 |
+
<div class="ab-clear"></div>
|
33 |
+
<div class="ab-error ab-bold ab-card-error"></div>
|
34 |
+
</div>
|
backend/modules/appearance/templates/_codes.php
ADDED
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<b>[[CATEGORY_NAME]]</b> - <?php _e( 'name of category', 'bookly' ) ?><br />
|
3 |
+
<?php if ( $step == 3 && $login ) : ?>
|
4 |
+
<b>[[LOGIN_FORM]]</b> - <?php _e( 'login form', 'bookly' ) ?><br />
|
5 |
+
<?php endif ?>
|
6 |
+
<b>[[NUMBER_OF_PERSONS]]</b> - <?php _e( 'number of persons', 'bookly' ) ?><br />
|
7 |
+
<?php if ( $step > 2 ) : ?>
|
8 |
+
<b>[[SERVICE_DATE]]</b> - <?php _e( 'date of service', 'bookly' ) ?><br />
|
9 |
+
<?php endif ?>
|
10 |
+
<b>[[SERVICE_NAME]]</b> - <?php _e( 'name of service', 'bookly' ) ?><br />
|
11 |
+
<b>[[SERVICE_PRICE]]</b> - <?php _e( 'price of service', 'bookly' ) ?><br />
|
12 |
+
<?php if ( $step > 2 ) : ?>
|
13 |
+
<b>[[SERVICE_TIME]]</b> - <?php _e( 'time of service', 'bookly' ) ?><br />
|
14 |
+
<?php endif ?>
|
15 |
+
<b>[[STAFF_NAME]]</b> - <?php _e( 'name of staff', 'bookly' ) ?><br />
|
16 |
+
<b>[[TOTAL_PRICE]]</b> - <?php _e( 'total price of booking', 'bookly' ) ?>
|
backend/modules/appearance/templates/_progress_tracker.php
CHANGED
@@ -1,23 +1,24 @@
|
|
|
|
1 |
<div class="ab-progress-tracker">
|
2 |
<ul class="ab-progress-bar nav-3">
|
3 |
-
<li class="ab-step-tabs first active">
|
4 |
-
<a href="javascript:void(0)">1. <span data-default="<?php echo get_option( 'ab_appearance_text_step_service' )
|
5 |
<div class="step"></div>
|
6 |
</li>
|
7 |
<li class="ab-step-tabs<?php if ($step >= 2): ?> active<?php endif ?>">
|
8 |
-
<a href="javascript:void(0)">2. <span data-default="<?php echo get_option( 'ab_appearance_text_step_time' )
|
9 |
<div class="step"></div>
|
10 |
</li>
|
11 |
<li class="ab-step-tabs<?php if ($step >= 3): ?> active<?php endif ?>">
|
12 |
-
<a href="javascript:void(0)">3. <span data-default="<?php echo get_option( 'ab_appearance_text_step_details' )
|
13 |
<div class="step"></div>
|
14 |
</li>
|
15 |
<li class="ab-step-tabs<?php if ($step >= 4): ?> active<?php endif ?>">
|
16 |
-
<a href="javascript:void(0)">4. <span data-default="<?php echo get_option( 'ab_appearance_text_step_payment' )
|
17 |
<div class="step"></div>
|
18 |
</li>
|
19 |
-
<li class="ab-step-tabs last<?php if ($step >= 5): ?> active<?php endif ?>">
|
20 |
-
<a href="javascript:void(0)">5. <span data-default="<?php echo get_option( 'ab_appearance_text_step_done' )
|
21 |
<div class="step"></div>
|
22 |
</li>
|
23 |
</ul>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
<div class="ab-progress-tracker">
|
3 |
<ul class="ab-progress-bar nav-3">
|
4 |
+
<li class="ab-step-tabs ab-first active">
|
5 |
+
<a href="javascript:void(0)">1. <span data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_step_service' ) ) ?>" data-link-class="text_step_1" class="text_service ab_editable" id="ab-text-step-service" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_step_service' ) ) ?></span></a>
|
6 |
<div class="step"></div>
|
7 |
</li>
|
8 |
<li class="ab-step-tabs<?php if ($step >= 2): ?> active<?php endif ?>">
|
9 |
+
<a href="javascript:void(0)">2. <span data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_step_time' ) ) ?>" data-link-class="text_step_2" class="text_time text_step_2 ab_editable" id="ab-text-step-time" data-type="text"><?php echo esc_html(get_option( 'ab_appearance_text_step_time' )) ?></span></a>
|
10 |
<div class="step"></div>
|
11 |
</li>
|
12 |
<li class="ab-step-tabs<?php if ($step >= 3): ?> active<?php endif ?>">
|
13 |
+
<a href="javascript:void(0)">3. <span data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_step_details' ) ) ?>" data-link-class="text_step_3" class="text_details text_step_3 ab_editable" id="ab-text-step-details" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_step_details' ) ) ?></span></a>
|
14 |
<div class="step"></div>
|
15 |
</li>
|
16 |
<li class="ab-step-tabs<?php if ($step >= 4): ?> active<?php endif ?>">
|
17 |
+
<a href="javascript:void(0)">4. <span data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_step_payment' ) ) ?>" data-link-class="text_step_4" class="text_payment ab_editable" id="ab-text-step-payment" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_step_payment' ) ) ?></span></a>
|
18 |
<div class="step"></div>
|
19 |
</li>
|
20 |
+
<li class="ab-step-tabs ab-last<?php if ($step >= 5): ?> active<?php endif ?>">
|
21 |
+
<a href="javascript:void(0)">5. <span data-default="<?php echo esc_attr( get_option( 'ab_appearance_text_step_done' ) ) ?>" data-link-class="text_step_5" class="text_done ab_editable" id="ab-text-step-done" data-type="text"><?php echo esc_html( get_option( 'ab_appearance_text_step_done' ) ) ?></span></a>
|
22 |
<div class="step"></div>
|
23 |
</li>
|
24 |
</ul>
|
backend/modules/appearance/templates/index.php
CHANGED
@@ -1,85 +1,90 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
|
3 |
-
<div class="
|
4 |
-
|
5 |
-
<button type="button" class="close" onclick="jQuery('.alert').hide()">×</button>
|
6 |
-
<?php _e( 'Settings saved.', 'ab' ); ?>
|
7 |
</div>
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
<div
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
include '_2_time.php';
|
49 |
-
break;
|
50 |
-
// Details
|
51 |
-
case 3:
|
52 |
-
include '_3_details.php';
|
53 |
-
break;
|
54 |
-
// Payment
|
55 |
-
case 4:
|
56 |
-
include '_4_payment.php';
|
57 |
-
break;
|
58 |
-
// Done
|
59 |
-
case 5:
|
60 |
-
include '_5_done.php';
|
61 |
-
break;
|
62 |
-
}
|
63 |
-
?>
|
64 |
</div>
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
<
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
</div>
|
84 |
</div>
|
|
|
|
|
|
|
|
|
85 |
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="panel panel-default">
|
3 |
+
<div class="panel-heading">
|
4 |
+
<h3 class="panel-title"><?php _e( 'Appearance', 'bookly' ) ?></h3>
|
|
|
|
|
5 |
</div>
|
6 |
+
<div class="panel-body">
|
7 |
+
<?php AB_Utils::notice( __( 'Settings saved.', 'bookly' ), 'notice-success', false ) ?>
|
8 |
+
<input type=text class="wp-color-picker appearance-color-picker" name=color
|
9 |
+
value="<?php echo esc_attr( get_option( 'ab_appearance_color' ) ) ?>"
|
10 |
+
data-selected="<?php echo esc_attr( get_option( 'ab_appearance_color' ) ) ?>" />
|
11 |
+
<div id="ab-appearance">
|
12 |
+
<form method=post id=common_settings>
|
13 |
+
<div class="row">
|
14 |
+
<div class="col-md-3">
|
15 |
+
<div id=main_form class="checkbox">
|
16 |
+
<label>
|
17 |
+
<input id=ab-progress-tracker-checkbox name=ab-progress-tracker-checkbox <?php checked( get_option( 'ab_appearance_show_progress_tracker' ) ) ?> type=checkbox />
|
18 |
+
<b><?php _e( 'Show form progress tracker', 'bookly' ) ?></b>
|
19 |
+
</label>
|
20 |
+
</div>
|
21 |
+
</div>
|
22 |
+
<div class="col-md-3">
|
23 |
+
<div class="checkbox">
|
24 |
+
<label>
|
25 |
+
<input id="ab-show-calendar-checkbox" name="ab-show-calendar-checkbox" <?php checked ( get_option( 'ab_appearance_show_calendar' ) ) ?> type="checkbox" />
|
26 |
+
<b><?php _e( 'Show calendar', 'bookly' ) ?></b>
|
27 |
+
</label>
|
28 |
+
</div>
|
29 |
+
</div>
|
30 |
+
<div class="col-md-3">
|
31 |
+
<div class="checkbox">
|
32 |
+
<label>
|
33 |
+
<input id="ab-blocked-timeslots-checkbox" name="ab-blocked-timeslots-checkbox" <?php checked( get_option( 'ab_appearance_show_blocked_timeslots' ) ) ?> type="checkbox" />
|
34 |
+
<b><?php _e( 'Show blocked timeslots', 'bookly' ) ?></b>
|
35 |
+
</label>
|
36 |
+
</div>
|
37 |
+
</div>
|
38 |
+
<div class="col-md-3">
|
39 |
+
<div class="checkbox">
|
40 |
+
<label>
|
41 |
+
<input id="ab-day-one-column-checkbox" name="ab-day-one-column-checkbox" <?php checked( get_option( 'ab_appearance_show_day_one_column' ) ) ?> type="checkbox" />
|
42 |
+
<b><?php _e( 'Show each day in one column', 'bookly' ) ?></b>
|
43 |
+
</label>
|
44 |
+
</div>
|
45 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
</div>
|
47 |
+
</form>
|
48 |
+
<!-- Tabs -->
|
49 |
+
<div class=tabbable style="margin-top: 20px;">
|
50 |
+
<ul class="nav nav-tabs ab-nav-tabs">
|
51 |
+
<?php foreach ( $steps as $step_id => $step_name ): ?>
|
52 |
+
<li class="ab-step-tab-<?php echo $step_id ?> ab-step-tabs<?php if ( $step_id == 1 ): ?> active<?php endif ?>" data-step-id="<?php echo $step_id ?>">
|
53 |
+
<a href="#" data-toggle=tab><?php echo $step_id ?>. <span class="text_step_<?php echo $step_id ?>" ><?php echo esc_html( $step_name ) ?></span></a>
|
54 |
+
</li>
|
55 |
+
<?php endforeach ?>
|
56 |
+
</ul>
|
57 |
+
<!-- Tabs-Content -->
|
58 |
+
<div class=tab-content>
|
59 |
+
<?php foreach ( $steps as $step_id => $step_name ) : ?>
|
60 |
+
<div class="tab-pane-<?php echo $step_id ?><?php if ( $step_id == 1 ): ?> active<?php endif ?>" data-step-id="<?php echo $step_id ?>"<?php if ( $step_id != 1 ): ?> style="display: none"<?php endif ?>>
|
61 |
+
<?php
|
62 |
+
// Render unique data per step
|
63 |
+
switch ( $step_id ) {
|
64 |
+
case 1: // Service
|
65 |
+
include '_1_service.php'; break;
|
66 |
+
case 2: // Time
|
67 |
+
include '_2_time.php'; break;
|
68 |
+
case 3: // Details
|
69 |
+
include '_3_details.php'; break;
|
70 |
+
case 4: // Payment
|
71 |
+
include '_4_payment.php'; break;
|
72 |
+
case 5: // Done
|
73 |
+
include '_5_done.php'; break;
|
74 |
+
}
|
75 |
+
?>
|
76 |
+
</div>
|
77 |
+
<?php endforeach ?>
|
78 |
+
</div>
|
79 |
+
<div class="text-right">
|
80 |
+
<?php _e( 'Click on the underlined text to edit.', 'bookly' ) ?>
|
81 |
+
</div>
|
82 |
+
<div class="clear"></div>
|
83 |
+
</div>
|
84 |
</div>
|
85 |
</div>
|
86 |
+
<div class="panel-footer">
|
87 |
+
<?php AB_Utils::submitButton( 'ajax-send-appearance' ) ?>
|
88 |
+
<?php AB_Utils::resetButton() ?>
|
89 |
+
</div>
|
90 |
</div>
|
backend/modules/appointments/AB_AppointmentsController.php
ADDED
@@ -0,0 +1,276 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class AB_AppointmentsController
|
5 |
+
*/
|
6 |
+
class AB_AppointmentsController extends AB_Controller {
|
7 |
+
|
8 |
+
public function index()
|
9 |
+
{
|
10 |
+
/** @var WP_Locale $wp_locale */
|
11 |
+
global $wp_locale;
|
12 |
+
|
13 |
+
$this->enqueueStyles( array(
|
14 |
+
'frontend' => array(
|
15 |
+
'css/intlTelInput.css',
|
16 |
+
),
|
17 |
+
'backend' => array(
|
18 |
+
'css/jquery-ui-theme/jquery-ui.min.css',
|
19 |
+
'css/bookly.main-backend.css',
|
20 |
+
'bootstrap/css/bootstrap.min.css',
|
21 |
+
'css/daterangepicker.css',
|
22 |
+
'css/chosen.min.css'
|
23 |
+
)
|
24 |
+
) );
|
25 |
+
|
26 |
+
$this->enqueueScripts( array(
|
27 |
+
'backend' => array(
|
28 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
29 |
+
'js/angular.min.js',
|
30 |
+
'js/angular-sanitize.min.js' => array( 'ab-angular.min.js' ),
|
31 |
+
'js/angular-ui-utils-0.2.1.min.js' => array( 'ab-angular.min.js' ),
|
32 |
+
'js/ng-new_customer_dialog.js' => array( 'ab-intlTelInput.min.js', 'ab-angular.min.js' ),
|
33 |
+
'js/angular-ui-date-0.0.8.js' => array( 'ab-angular.min.js' ),
|
34 |
+
'js/moment.min.js',
|
35 |
+
'js/daterangepicker.js' => array( 'jquery' ),
|
36 |
+
'js/chosen.jquery.min.js' => array( 'jquery' ),
|
37 |
+
'js/ng-edit_appointment_dialog.js' => array( 'ab-angular-ui-date-0.0.8.js', 'jquery-ui-datepicker' ),
|
38 |
+
),
|
39 |
+
'frontend' => array(
|
40 |
+
'js/intlTelInput.min.js',
|
41 |
+
),
|
42 |
+
'module' => array(
|
43 |
+
'js/ng-app.js' => array( 'jquery', 'ab-angular.min.js', 'ab-angular-ui-utils-0.2.1.min.js' ),
|
44 |
+
),
|
45 |
+
) );
|
46 |
+
|
47 |
+
wp_localize_script( 'ab-ng-app.js', 'BooklyL10n', array(
|
48 |
+
'today' => __( 'Today', 'bookly' ),
|
49 |
+
'yesterday' => __( 'Yesterday', 'bookly' ),
|
50 |
+
'last_7' => __( 'Last 7 Days', 'bookly' ),
|
51 |
+
'last_30' => __( 'Last 30 Days', 'bookly' ),
|
52 |
+
'this_month' => __( 'This Month', 'bookly' ),
|
53 |
+
'next_month' => __( 'Next Month', 'bookly' ),
|
54 |
+
'custom_range' => __( 'Custom Range', 'bookly' ),
|
55 |
+
'apply' => __( 'Apply', 'bookly' ),
|
56 |
+
'cancel' => __( 'Cancel', 'bookly' ),
|
57 |
+
'to' => __( 'To', 'bookly' ),
|
58 |
+
'from' => __( 'From', 'bookly' ),
|
59 |
+
'editAppointment' => __( 'Edit appointment', 'bookly' ),
|
60 |
+
'newAppointment' => __( 'New appointment', 'bookly' ),
|
61 |
+
'longMonths' => array_values( $wp_locale->month ),
|
62 |
+
'shortMonths' => array_values( $wp_locale->month_abbrev ),
|
63 |
+
'shortDays' => array_values( $wp_locale->weekday_abbrev ),
|
64 |
+
'dpDateFormat' => AB_DateTimeUtils::convertFormat( 'date', AB_DateTimeUtils::FORMAT_JQUERY_DATEPICKER ),
|
65 |
+
'mjsDateFormat' => AB_DateTimeUtils::convertFormat( 'date', AB_DateTimeUtils::FORMAT_MOMENT_JS ),
|
66 |
+
'startOfWeek' => (int) get_option( 'start_of_week' ),
|
67 |
+
'country' => get_option( 'ab_settings_phone_default_country' ),
|
68 |
+
'intlTelInput_utils' => plugins_url( 'intlTelInput.utils.js', AB_PATH . '/frontend/resources/js/intlTelInput.utils.js' ),
|
69 |
+
'please_select_at_least_one_row' => __( 'Please select at least one appointment.', 'bookly' ),
|
70 |
+
));
|
71 |
+
|
72 |
+
$this->render( 'index' );
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Get list of appointments.
|
77 |
+
*/
|
78 |
+
public function executeGetAppointments()
|
79 |
+
{
|
80 |
+
$response = array(
|
81 |
+
'appointments' => array(),
|
82 |
+
'total' => 0,
|
83 |
+
'pages' => 0,
|
84 |
+
'active_page' => 0
|
85 |
+
);
|
86 |
+
|
87 |
+
$page = intval( $this->getParameter( 'page' ) );
|
88 |
+
$sort = in_array( $this->getParameter( 'sort' ), array( 'staff_name', 'service_title', 'start_date', 'price' ) )
|
89 |
+
? $this->getParameter( 'sort' ) : 'start_date';
|
90 |
+
$order = in_array( $this->getParameter( 'order' ), array( 'asc', 'desc' ) ) ? $this->getParameter( 'order' ) : 'asc';
|
91 |
+
|
92 |
+
$start_date = new DateTime( $this->getParameter( 'date_start' ) );
|
93 |
+
$start_date = $start_date->format( 'Y-m-d H:i:s' );
|
94 |
+
$end_date = new DateTime( $this->getParameter( 'date_end' ) );
|
95 |
+
$end_date = $end_date->modify( '+1 day' )->format( 'Y-m-d H:i:s' );
|
96 |
+
|
97 |
+
$items_per_page = 20;
|
98 |
+
$total = AB_Appointment::query()->whereBetween( 'start_date', $start_date, $end_date )->count();
|
99 |
+
$pages = ceil( $total / $items_per_page );
|
100 |
+
if ( $page < 1 || $page > $pages ) {
|
101 |
+
$page = 1;
|
102 |
+
}
|
103 |
+
|
104 |
+
if ( $total ) {
|
105 |
+
$query = AB_CustomerAppointment::query( 'ca' )
|
106 |
+
->select( 'ca.id,
|
107 |
+
ca.number_of_persons,
|
108 |
+
ca.coupon_discount,
|
109 |
+
ca.coupon_deduction,
|
110 |
+
ca.appointment_id,
|
111 |
+
a.start_date,
|
112 |
+
a.end_date,
|
113 |
+
a.staff_id,
|
114 |
+
st.full_name AS staff_name,
|
115 |
+
s.title AS service_title,
|
116 |
+
s.duration AS service_duration,
|
117 |
+
c.name AS customer_name,
|
118 |
+
ss.price' )
|
119 |
+
->leftJoin( 'AB_Appointment', 'a', 'a.id = ca.appointment_id' )
|
120 |
+
->leftJoin( 'AB_Service', 's', 's.id = a.service_id' )
|
121 |
+
->leftJoin( 'AB_Customer', 'c', 'c.id = ca.customer_id' )
|
122 |
+
->leftJoin( 'AB_Staff', 'st', 'st.id = a.staff_id' )
|
123 |
+
->leftJoin( 'AB_StaffService', 'ss', 'ss.staff_id = st.id AND ss.service_id = s.id')
|
124 |
+
->whereBetween( 'a.start_date', $start_date, $end_date )
|
125 |
+
->sortBy( $sort )
|
126 |
+
->order( $order );
|
127 |
+
|
128 |
+
// LIMIT.
|
129 |
+
$start = ( $page - 1 ) * $items_per_page;
|
130 |
+
$query->offset( $start )->limit( $items_per_page );
|
131 |
+
|
132 |
+
$rows = $query->fetchArray();
|
133 |
+
foreach ( $rows as &$row ) {
|
134 |
+
$row['price'] *= $row['number_of_persons'];
|
135 |
+
$row['price'] = AB_Utils::formatPrice( $row['price'] );
|
136 |
+
$row['start_date_f'] = AB_DateTimeUtils::formatDateTime( $row['start_date'] );
|
137 |
+
$row['service_duration'] = AB_DateTimeUtils::secondsToInterval( $row['service_duration'] );
|
138 |
+
}
|
139 |
+
|
140 |
+
// Populate response.
|
141 |
+
$response['appointments'] = $rows;
|
142 |
+
$response['total'] = $total;
|
143 |
+
$response['pages'] = $pages;
|
144 |
+
$response['active_page'] = $page;
|
145 |
+
}
|
146 |
+
|
147 |
+
wp_send_json_success( $response );
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Delete customer appointment.
|
152 |
+
*/
|
153 |
+
public function executeDeleteCustomerAppointment()
|
154 |
+
{
|
155 |
+
if ( $this->hasParameter( 'ids' ) ) {
|
156 |
+
foreach ( $this->getParameter( 'ids' ) as $id ) {
|
157 |
+
$customer_appointment = new AB_CustomerAppointment();
|
158 |
+
$customer_appointment->load( $id );
|
159 |
+
|
160 |
+
$appointment = new AB_Appointment();
|
161 |
+
$appointment->load( $customer_appointment->get( 'appointment_id' ) );
|
162 |
+
|
163 |
+
$customer_appointment->delete();
|
164 |
+
|
165 |
+
// Delete appointment, if there aren't customers.
|
166 |
+
$count = AB_CustomerAppointment::query()->where( 'appointment_id', $customer_appointment->get( 'appointment_id' ) )->count();
|
167 |
+
|
168 |
+
if ( ! $count ) {
|
169 |
+
$appointment->delete();
|
170 |
+
} else {
|
171 |
+
$appointment->handleGoogleCalendar();
|
172 |
+
}
|
173 |
+
}
|
174 |
+
}
|
175 |
+
wp_send_json_success();
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Export Appointment to CSV
|
180 |
+
*/
|
181 |
+
public function executeExportToCSV()
|
182 |
+
{
|
183 |
+
$start_date = new DateTime( $this->getParameter( 'date_start' ) );
|
184 |
+
$start_date = $start_date->format( 'Y-m-d H:i:s' );
|
185 |
+
$end_date = new DateTime( $this->getParameter( 'date_end' ) );
|
186 |
+
$end_date = $end_date->modify( '+1 day' )->format( 'Y-m-d H:i:s' );
|
187 |
+
$delimiter = $this->getParameter( 'delimiter', ',' );
|
188 |
+
|
189 |
+
header( 'Content-Type: text/csv; charset=utf-8' );
|
190 |
+
header( 'Content-Disposition: attachment; filename=Appointments.csv' );
|
191 |
+
|
192 |
+
$header = array(
|
193 |
+
__( 'Booking Time', 'bookly' ),
|
194 |
+
__( 'Staff Member', 'bookly' ),
|
195 |
+
__( 'Service', 'bookly' ),
|
196 |
+
__( 'Duration', 'bookly' ),
|
197 |
+
__( 'Price', 'bookly' ),
|
198 |
+
__( 'Customer', 'bookly' ),
|
199 |
+
__( 'Phone', 'bookly' ),
|
200 |
+
__( 'Email', 'bookly' ),
|
201 |
+
);
|
202 |
+
|
203 |
+
$custom_fields = array();
|
204 |
+
$fields_data = json_decode( get_option( 'ab_custom_fields' ) );
|
205 |
+
foreach ( $fields_data as $field_data ) {
|
206 |
+
$custom_fields[$field_data->id] = '';
|
207 |
+
$header[] = $field_data->label;
|
208 |
+
}
|
209 |
+
|
210 |
+
$output = fopen( 'php://output', 'w' );
|
211 |
+
fwrite( $output, pack( 'CCC', 0xef, 0xbb, 0xbf ) );
|
212 |
+
fputcsv( $output, $header, $delimiter );
|
213 |
+
$rows = AB_CustomerAppointment::query()
|
214 |
+
->select( 'r.id,
|
215 |
+
r.number_of_persons,
|
216 |
+
r.coupon_discount,
|
217 |
+
r.coupon_deduction,
|
218 |
+
st.full_name AS staff_name,
|
219 |
+
s.title AS service_title,
|
220 |
+
s.duration AS service_duration,
|
221 |
+
c.name AS customer_name,
|
222 |
+
c.phone AS customer_phone,
|
223 |
+
c.email AS customer_email,
|
224 |
+
ss.price,
|
225 |
+
a.start_date' )
|
226 |
+
->leftJoin( 'AB_Appointment', 'a', 'a.id = r.appointment_id' )
|
227 |
+
->leftJoin( 'AB_Service', 's', 's.id = a.service_id' )
|
228 |
+
->leftJoin( 'AB_Staff', 'st', 'st.id = a.staff_id' )
|
229 |
+
->leftJoin( 'AB_Customer', 'c', 'c.id = r.customer_id' )
|
230 |
+
->leftJoin( 'AB_StaffService', 'ss', 'ss.staff_id = st.id AND ss.service_id = s.id' )
|
231 |
+
->whereBetween( 'a.start_date', $start_date, $end_date )
|
232 |
+
->sortBy( 'a.start_date' )
|
233 |
+
->order( AB_Query::ORDER_DESCENDING )
|
234 |
+
->fetchArray();
|
235 |
+
|
236 |
+
foreach( $rows as $row ) {
|
237 |
+
$row['price'] *= $row['number_of_persons'];
|
238 |
+
|
239 |
+
$row_data = array(
|
240 |
+
$row['start_date'],
|
241 |
+
$row['staff_name'],
|
242 |
+
$row['service_title'],
|
243 |
+
AB_DateTimeUtils::secondsToInterval( $row['service_duration'] ),
|
244 |
+
AB_Utils::formatPrice( $row['price'] ),
|
245 |
+
$row['customer_name'],
|
246 |
+
$row['customer_phone'],
|
247 |
+
$row['customer_email'],
|
248 |
+
);
|
249 |
+
|
250 |
+
$customer_appointment = new AB_CustomerAppointment();
|
251 |
+
$customer_appointment->load( $row['id'] );
|
252 |
+
foreach ( $customer_appointment->getCustomFields() as $custom_field ) {
|
253 |
+
$custom_fields[$custom_field['id']] = $custom_field['value'];
|
254 |
+
}
|
255 |
+
|
256 |
+
fputcsv( $output, array_merge( $row_data, $custom_fields ), $delimiter );
|
257 |
+
|
258 |
+
$custom_fields = array_map( function () { return ''; }, $custom_fields );
|
259 |
+
}
|
260 |
+
fclose( $output );
|
261 |
+
|
262 |
+
exit();
|
263 |
+
}
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Override parent method to add 'wp_ajax_ab_' prefix
|
267 |
+
* so current 'execute*' methods look nicer.
|
268 |
+
*
|
269 |
+
* @param string $prefix
|
270 |
+
*/
|
271 |
+
protected function registerWpActions( $prefix = '' )
|
272 |
+
{
|
273 |
+
parent::registerWpActions( 'wp_ajax_ab_' );
|
274 |
+
}
|
275 |
+
|
276 |
+
}
|
backend/modules/appointments/resources/js/ng-app.js
ADDED
@@ -0,0 +1,208 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
;(function() {
|
2 |
+
|
3 |
+
var module = angular.module('appointments', ['ui.utils', 'ui.date', 'ngSanitize']);
|
4 |
+
|
5 |
+
module.factory('dataSource', function($q, $rootScope) {
|
6 |
+
var ds = {
|
7 |
+
appointments : [],
|
8 |
+
total : 0,
|
9 |
+
pages : [],
|
10 |
+
loadData : function(params) {
|
11 |
+
var deferred = $q.defer();
|
12 |
+
jQuery.ajax({
|
13 |
+
url : ajaxurl,
|
14 |
+
type : 'POST',
|
15 |
+
data : jQuery.extend({ action : 'ab_get_appointments' }, params),
|
16 |
+
dataType : 'json',
|
17 |
+
success : function(response) {
|
18 |
+
if (response.success) {
|
19 |
+
ds.appointments = response.data.appointments;
|
20 |
+
ds.total = response.data.total;
|
21 |
+
ds.pages = [];
|
22 |
+
for (var i = 0; i < response.data.pages; ++ i) {
|
23 |
+
ds.pages.push({
|
24 |
+
number : i + 1,
|
25 |
+
active : response.data.active_page == i + 1
|
26 |
+
});
|
27 |
+
}
|
28 |
+
}
|
29 |
+
$rootScope.$apply(deferred.resolve);
|
30 |
+
},
|
31 |
+
error : function() {
|
32 |
+
ds.appointments = [];
|
33 |
+
ds.total = 0;
|
34 |
+
$rootScope.$apply(deferred.resolve);
|
35 |
+
}
|
36 |
+
});
|
37 |
+
|
38 |
+
return deferred.promise;
|
39 |
+
}
|
40 |
+
};
|
41 |
+
|
42 |
+
return ds;
|
43 |
+
});
|
44 |
+
|
45 |
+
module.controller('appointmentsCtrl', function($scope, dataSource) {
|
46 |
+
// Set up initial data.
|
47 |
+
var params = {
|
48 |
+
page : 1,
|
49 |
+
sort : 'start_date',
|
50 |
+
order : 'desc',
|
51 |
+
date_start : '',
|
52 |
+
date_end : ''
|
53 |
+
};
|
54 |
+
$scope.loading = true;
|
55 |
+
$scope.css_class = {
|
56 |
+
staff_name : '',
|
57 |
+
customer_name : '',
|
58 |
+
service_title : '',
|
59 |
+
start_date : 'desc',
|
60 |
+
service_duration: '',
|
61 |
+
price : ''
|
62 |
+
};
|
63 |
+
|
64 |
+
var format = 'YYYY-MM-DD';
|
65 |
+
$scope.date_start = moment().startOf('month').format(format);
|
66 |
+
$scope.date_end = moment().endOf('month').format(format);
|
67 |
+
|
68 |
+
// Set up data source (data will be loaded in reload function).
|
69 |
+
$scope.dataSource = dataSource;
|
70 |
+
|
71 |
+
$scope.reload = function( opt ) {
|
72 |
+
$scope.loading = true;
|
73 |
+
if (opt !== undefined) {
|
74 |
+
if (opt.sort !== undefined) {
|
75 |
+
if (params.sort === opt.sort) {
|
76 |
+
// Toggle order when sorting by the same field.
|
77 |
+
params.order = params.order === 'asc' ? 'desc' : 'asc';
|
78 |
+
} else {
|
79 |
+
params.order = 'asc';
|
80 |
+
}
|
81 |
+
$scope.css_class = {
|
82 |
+
staff_name : '',
|
83 |
+
customer_name : '',
|
84 |
+
service_title : '',
|
85 |
+
start_date : '',
|
86 |
+
service_duration: '',
|
87 |
+
price : ''
|
88 |
+
};
|
89 |
+
$scope.css_class[opt.sort] = params.order;
|
90 |
+
}
|
91 |
+
jQuery.extend(params, opt);
|
92 |
+
}
|
93 |
+
params.date_start = $scope.date_start;
|
94 |
+
params.date_end = $scope.date_end;
|
95 |
+
dataSource.loadData(params).then(function() {
|
96 |
+
$scope.loading = false;
|
97 |
+
});
|
98 |
+
};
|
99 |
+
|
100 |
+
$scope.reload();
|
101 |
+
|
102 |
+
/**
|
103 |
+
* New appointment.
|
104 |
+
*
|
105 |
+
* @param appointment
|
106 |
+
*/
|
107 |
+
$scope.newAppointment = function() {
|
108 |
+
showAppointmentDialog(
|
109 |
+
null,
|
110 |
+
null,
|
111 |
+
moment(),
|
112 |
+
null,
|
113 |
+
function(event) {
|
114 |
+
$scope.$apply(function($scope) {
|
115 |
+
$scope.reload();
|
116 |
+
});
|
117 |
+
}
|
118 |
+
)
|
119 |
+
};
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Edit appointment.
|
123 |
+
*
|
124 |
+
* @param appointment
|
125 |
+
*/
|
126 |
+
$scope.editAppointment = function(appointment) {
|
127 |
+
showAppointmentDialog(
|
128 |
+
appointment.appointment_id,
|
129 |
+
appointment.staff_id,
|
130 |
+
moment(appointment.start_date),
|
131 |
+
moment(appointment.end_date),
|
132 |
+
function(event) {
|
133 |
+
$scope.$apply(function($scope) {
|
134 |
+
$scope.reload();
|
135 |
+
});
|
136 |
+
}
|
137 |
+
)
|
138 |
+
};
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Delete customer appointments.
|
142 |
+
*/
|
143 |
+
$scope.deleteAppointments = function() {
|
144 |
+
var ids = [];
|
145 |
+
jQuery('table input[type=checkbox]:checked').each(function() {
|
146 |
+
ids.push(jQuery(this).data('appointment_id'));
|
147 |
+
});
|
148 |
+
if( ids.length ) {
|
149 |
+
$scope.loading = true;
|
150 |
+
jQuery.ajax({
|
151 |
+
url: ajaxurl,
|
152 |
+
type: 'POST',
|
153 |
+
data: {
|
154 |
+
action: 'ab_delete_customer_appointment',
|
155 |
+
ids: ids
|
156 |
+
},
|
157 |
+
dataType: 'json',
|
158 |
+
success: function (response) {
|
159 |
+
$scope.$apply(function ($scope) {
|
160 |
+
$scope.reload();
|
161 |
+
});
|
162 |
+
}
|
163 |
+
});
|
164 |
+
} else{
|
165 |
+
alert(BooklyL10n.please_select_at_least_one_row);
|
166 |
+
}
|
167 |
+
};
|
168 |
+
|
169 |
+
// Init date range picker.
|
170 |
+
var picker_ranges = {};
|
171 |
+
picker_ranges[BooklyL10n.today] = [moment(), moment()];
|
172 |
+
picker_ranges[BooklyL10n.yesterday] = [moment().subtract(1, 'days'), moment().subtract(1, 'days')];
|
173 |
+
picker_ranges[BooklyL10n.last_7] = [moment().subtract(7, 'days'), moment()];
|
174 |
+
picker_ranges[BooklyL10n.last_30] = [moment().subtract(30, 'days'), moment()];
|
175 |
+
picker_ranges[BooklyL10n.this_month] = [moment().startOf('month'), moment().endOf('month')];
|
176 |
+
picker_ranges[BooklyL10n.next_month] = [moment().add(1, 'month').startOf('month'), moment().add(1, 'month').endOf('month')];
|
177 |
+
|
178 |
+
jQuery('#reportrange').daterangepicker(
|
179 |
+
{
|
180 |
+
startDate: moment().startOf('month'),
|
181 |
+
endDate: moment().endOf('month'),
|
182 |
+
ranges: picker_ranges,
|
183 |
+
locale: {
|
184 |
+
applyLabel : BooklyL10n.apply,
|
185 |
+
cancelLabel: BooklyL10n.cancel,
|
186 |
+
fromLabel : BooklyL10n.from,
|
187 |
+
toLabel : BooklyL10n.to,
|
188 |
+
customRangeLabel: BooklyL10n.custom_range,
|
189 |
+
daysOfWeek : BooklyL10n.shortDays,
|
190 |
+
monthNames : BooklyL10n.longMonths,
|
191 |
+
firstDay : parseInt(BooklyL10n.startOfWeek),
|
192 |
+
format : BooklyL10n.mjsDateFormat
|
193 |
+
}
|
194 |
+
},
|
195 |
+
function(start, end) {
|
196 |
+
jQuery('#reportrange span').html(start.format(BooklyL10n.mjsDateFormat) + ' - ' + end.format(BooklyL10n.mjsDateFormat));
|
197 |
+
$scope.$apply(function($scope){
|
198 |
+
$scope.date_start = start.format(format);
|
199 |
+
$scope.date_end = end.format(format);
|
200 |
+
$scope.reload();
|
201 |
+
});
|
202 |
+
}
|
203 |
+
);
|
204 |
+
});
|
205 |
+
|
206 |
+
// Bootstrap 'appointmentForm' application.
|
207 |
+
angular.bootstrap(document.getElementById('ab-appointment-form'), ['appointmentForm']);
|
208 |
+
})();
|
backend/modules/appointments/templates/index.php
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="panel panel-default">
|
3 |
+
<div class="panel-heading">
|
4 |
+
<h3 class="panel-title"><?php _e( 'Appointments', 'bookly' ) ?></h3>
|
5 |
+
</div>
|
6 |
+
<div class="panel-body">
|
7 |
+
<div ng-app="appointments" ng-controller="appointmentsCtrl" class="form-horizontal ng-cloak">
|
8 |
+
|
9 |
+
<form class="form-inline" action="<?php echo admin_url( 'admin-ajax.php' ) ?>?action=ab_export_to_csv" method="post" style="margin-bottom: 20px">
|
10 |
+
<div id=reportrange class="pull-left ab-reportrange">
|
11 |
+
<i class="glyphicon glyphicon-calendar"></i>
|
12 |
+
<span data-date="<?php echo date( 'F j, Y', strtotime( 'first day of' ) ) ?> - <?php echo date( 'F j, Y', strtotime( 'last day of' ) ) ?>"><?php echo date_i18n( get_option( 'date_format' ), strtotime( 'first day of' ) ) ?> - <?php echo date_i18n( get_option( 'date_format' ), strtotime( 'last day of' ) ) ?></span> <b style="margin-top: 8px;" class=caret></b>
|
13 |
+
</div>
|
14 |
+
<input type="hidden" name="date_start" ng-value="date_start" />
|
15 |
+
<input type="hidden" name="date_end" ng-value="date_end" />
|
16 |
+
<span class="help-inline"><?php _e( 'Delimiter', 'bookly' ) ?></span>
|
17 |
+
<select name="delimiter" style="width: 125px;height: 30px" class="form-control">
|
18 |
+
<option value=","><?php _e( 'Comma (,)', 'bookly' ) ?></option>
|
19 |
+
<option value=";"><?php _e( 'Semicolon (;)', 'bookly' ) ?></option>
|
20 |
+
</select>
|
21 |
+
<button type="submit" class="btn btn-info"><?php _e( 'Export to CSV', 'bookly' ) ?></button>
|
22 |
+
<button type="button" class="btn btn-info pull-right" ng-click="newAppointment()"><?php _e( 'New appointment', 'bookly' ) ?></button>
|
23 |
+
</form>
|
24 |
+
|
25 |
+
<div class="table-responsive">
|
26 |
+
<table id="ab_appointments_list" class="table table-striped" cellspacing=0 cellpadding=0 border=0 style="clear: both;">
|
27 |
+
<thead>
|
28 |
+
<tr>
|
29 |
+
<th style="width: 14%;" ng-class="css_class.start_date"><a href="" ng-click="reload({sort:'start_date'})"><?php _e( 'Booking Time', 'bookly' ) ?></a></th>
|
30 |
+
<th style="width: 14%;" ng-class="css_class.staff_name"><a href="" ng-click="reload({sort:'staff_name'})"><?php _e( 'Staff Member', 'bookly' ) ?></a></th>
|
31 |
+
<th style="width: 14%;" ng-class="css_class.customer_name"><a href="" ng-click="reload({sort:'customer_name'})"><?php _e( 'Customer Name', 'bookly' ) ?></a></th>
|
32 |
+
<th style="width: 14%;" ng-class="css_class.service_title"><a href="" ng-click="reload({sort:'service_title'})"><?php _e( 'Service', 'bookly' ) ?></a></th>
|
33 |
+
<th style="width: 14%;" ng-class="css_class.service_duration"><a href="" ng-click="reload({sort:'service_duration'})"><?php _e( 'Duration', 'bookly' ) ?></a></th>
|
34 |
+
<th style="width: 14%;" colspan="3" ng-class="css_class.price"><a href="" ng-click="reload({sort:'price'})"><?php _e( 'Price', 'bookly' ) ?></a></th>
|
35 |
+
</tr>
|
36 |
+
</thead>
|
37 |
+
<tbody>
|
38 |
+
<tr ng-repeat="appointment in dataSource.appointments">
|
39 |
+
<td>{{appointment.start_date_f}}</td>
|
40 |
+
<td>{{appointment.staff_name}}</td>
|
41 |
+
<td>{{appointment.customer_name}}</td>
|
42 |
+
<td>{{appointment.service_title}}</td>
|
43 |
+
<td>{{appointment.service_duration}}</td>
|
44 |
+
<td>{{appointment.price}}</td>
|
45 |
+
<td>
|
46 |
+
<button class="btn btn-info pull-right" ng-click="editAppointment(appointment)">
|
47 |
+
<?php _e( 'Edit', 'bookly' ) ?>
|
48 |
+
</button>
|
49 |
+
</td>
|
50 |
+
<td><input type="checkbox" data-appointment_id="{{appointment.id}}"></td>
|
51 |
+
</tr>
|
52 |
+
</tbody>
|
53 |
+
</table>
|
54 |
+
<div ng-hide="dataSource.appointments.length || loading" class="alert alert-info"><?php _e( 'No appointments for selected period.', 'bookly' ) ?></div>
|
55 |
+
</div>
|
56 |
+
|
57 |
+
<div class="btn-toolbar">
|
58 |
+
<div class="col-xs-8">
|
59 |
+
<div class="btn-group" ng-hide="dataSource.pages.length == 1">
|
60 |
+
<button ng-click="reload({page:page.number})" class="btn btn-default" ng-repeat="page in dataSource.pages" ng-switch on="page.active">
|
61 |
+
<span ng-switch-when="true">{{page.number}}</span>
|
62 |
+
<a href="" ng-switch-default>{{page.number}}</a>
|
63 |
+
</button>
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
<div class="col-xs-4">
|
67 |
+
<a class="btn btn-info pull-right" ng-click="deleteAppointments()"><?php _e( 'Delete', 'bookly' ) ?></a>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
|
71 |
+
<div ng-show="loading" class="loading-indicator">
|
72 |
+
<span class="ab-loader"></span>
|
73 |
+
</div>
|
74 |
+
</div>
|
75 |
+
<div id="ab-appointment-form">
|
76 |
+
<?php include AB_PATH . '/backend/modules/calendar/templates/_appointment_form.php' ?>
|
77 |
+
</div>
|
78 |
+
</div>
|
79 |
+
</div>
|
backend/modules/calendar/AB_CalendarController.php
CHANGED
@@ -1,516 +1,428 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
$path_to_entities = dirname(__FILE__) . '/../../../lib/entities/';
|
6 |
-
|
7 |
-
include 'forms/AB_AppointmentForm.php';
|
8 |
-
include $path_to_entities . 'AB_ScheduleItem.php';
|
9 |
|
10 |
/**
|
11 |
* Class AB_CalendarController
|
12 |
-
*
|
13 |
-
* @property $collection
|
14 |
-
* @property $staff_services
|
15 |
-
* @property $startDate
|
16 |
-
* @property $period_start
|
17 |
-
* @property $period_end
|
18 |
-
* @property $customers
|
19 |
-
* @property $staff_id
|
20 |
-
* @property $service_id
|
21 |
-
* @property $customer_id
|
22 |
-
* @property $staff_collection
|
23 |
-
* @property $date_interval_not_available
|
24 |
-
* @property $date_interval_warning
|
25 |
-
* @property $notes
|
26 |
*/
|
27 |
-
class AB_CalendarController extends AB_Controller
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
'ab-weekcalendar',
|
43 |
-
plugins_url( 'resources/js/jquery.weekcalendar.js', __FILE__ ),
|
44 |
-
array(
|
45 |
-
'jquery',
|
46 |
-
'jquery-ui-widget',
|
47 |
-
'jquery-ui-dialog',
|
48 |
-
'jquery-ui-button',
|
49 |
-
'jquery-ui-draggable',
|
50 |
-
'jquery-ui-droppable',
|
51 |
-
'jquery-ui-resizable',
|
52 |
-
'jquery-ui-datepicker'
|
53 |
-
)
|
54 |
-
);
|
55 |
-
wp_enqueue_script( 'ab-calendar_daypicker', plugins_url( 'resources/js/calendar_daypicker.js', __FILE__ ), array( 'jquery' ) );
|
56 |
-
wp_enqueue_script( 'ab-calendar_weekpicker', plugins_url( 'resources/js/calendar_weekpicker.js', __FILE__ ), array( 'jquery' ) );
|
57 |
-
wp_enqueue_script( 'ab-calendar', plugins_url( 'resources/js/calendar.js', __FILE__ ), array( 'jquery', 'ab-calendar_daypicker', 'ab-calendar_weekpicker' ) );
|
58 |
-
wp_enqueue_script( 'ab-angularjs', plugins_url( 'resources/js/angular-1.0.6.min.js', dirname( dirname( __FILE__ ) ) ) );
|
59 |
-
wp_enqueue_script( 'ab-angularui', plugins_url( 'resources/js/angular-ui-0.4.0.min.js', dirname( dirname( __FILE__ ) ) ) );
|
60 |
-
wp_enqueue_script( 'ab-ng-app', plugins_url( 'resources/js/ng-app.js', __FILE__ ), array( 'jquery' ) );
|
61 |
-
wp_enqueue_script( 'ab-ng-new_customer_dialog', plugins_url( 'resources/js/ng-new_customer_dialog.js', dirname( dirname(__FILE__) ) ), array( 'jquery', 'ab-angularjs' ) );
|
62 |
-
wp_localize_script( 'ab-ng-app', 'BooklyL10n', array(
|
63 |
-
'new_appointment' => __( 'New appointment', 'ab' ),
|
64 |
-
'edit_appointment' => __( 'Edit appointment', 'ab' ),
|
65 |
-
'are_you_sure' => __( 'Are you sure?', 'ab' ),
|
66 |
-
'phone' => __( 'Phone', 'ab' ),
|
67 |
-
'email' => __( 'Email', 'ab' ),
|
68 |
-
'timeslotsPerHour' => 60 / get_option('ab_settings_time_slot_length'),
|
69 |
-
'shortMonths' => array(
|
70 |
-
__( 'Jan', 'ab' ),
|
71 |
-
__( 'Feb', 'ab' ),
|
72 |
-
__( 'Mar', 'ab' ),
|
73 |
-
__( 'Apr', 'ab' ),
|
74 |
-
__( 'May', 'ab' ),
|
75 |
-
__( 'Jun', 'ab' ),
|
76 |
-
__( 'Jul', 'ab' ),
|
77 |
-
__( 'Aug', 'ab' ),
|
78 |
-
__( 'Sep', 'ab' ),
|
79 |
-
__( 'Oct', 'ab' ),
|
80 |
-
__( 'Nov', 'ab' ),
|
81 |
-
__( 'Dec', 'ab' ),
|
82 |
),
|
83 |
-
'
|
84 |
-
|
85 |
-
|
86 |
-
__( 'March', 'ab' ),
|
87 |
-
__( 'April', 'ab' ),
|
88 |
-
__( 'May', 'ab' ),
|
89 |
-
__( 'June', 'ab' ),
|
90 |
-
__( 'July', 'ab' ),
|
91 |
-
__( 'August', 'ab' ),
|
92 |
-
__( 'September', 'ab' ),
|
93 |
-
__( 'October', 'ab' ),
|
94 |
-
__( 'November', 'ab' ),
|
95 |
-
__( 'December', 'ab' )
|
96 |
),
|
97 |
-
'
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
__( 'Thu', 'ab' ),
|
103 |
-
__( 'Fri', 'ab' ),
|
104 |
-
__( 'Sat', 'ab' )
|
105 |
),
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
114 |
),
|
115 |
-
'
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
127 |
|
128 |
$this->render( 'calendar' );
|
129 |
}
|
|
|
130 |
/**
|
131 |
-
* Get data for
|
132 |
*
|
133 |
* @return json
|
134 |
*/
|
135 |
-
public function
|
136 |
-
|
137 |
-
$
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
$
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
si.id - 1 AS "day_index",
|
155 |
-
si.name AS "day_name"
|
156 |
-
FROM `ab_staff_schedule_item` ssi
|
157 |
-
LEFT JOIN `ab_schedule_item` si ON ssi.schedule_item_id = si.id
|
158 |
-
WHERE ssi.staff_id = %d',
|
159 |
-
$staff_id
|
160 |
-
) );
|
161 |
-
|
162 |
-
$holidays = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM ab_holiday WHERE staff_id = %d OR staff_id IS NULL', $staff_id ) );
|
163 |
-
|
164 |
-
if ( ! empty( $schedule ) ) {
|
165 |
-
$wp_week_start_day = get_option( 'start_of_week', 1 );
|
166 |
-
$schedule_start_day = $schedule[0]->id - 1;
|
167 |
-
|
168 |
-
// if wp week start day is higher than our
|
169 |
-
// cut the list into 2 parts (before and after wp wp week start day)
|
170 |
-
// move the second part of the list above the first one
|
171 |
-
if ( $wp_week_start_day > $schedule_start_day ) {
|
172 |
-
$schedule_start = array_slice( $schedule, 0, $wp_week_start_day );
|
173 |
-
$schedule_end = array_slice( $schedule, $wp_week_start_day );
|
174 |
-
$schedule = $schedule_end;
|
175 |
-
|
176 |
-
foreach ( $schedule_start as $schedule_item ) {
|
177 |
-
$schedule[] = $schedule_item;
|
178 |
-
}
|
179 |
-
}
|
180 |
-
|
181 |
-
$active_schedule_items_ids = array();
|
182 |
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
}
|
191 |
-
$
|
192 |
-
$
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
}
|
204 |
-
}
|
205 |
}
|
206 |
|
207 |
-
|
208 |
-
$result['freebusys'][] = $this->getFreeBusy( $startDate, $endDate, true );
|
209 |
-
$active_schedule_items_ids[] = $item->id;
|
210 |
}
|
211 |
-
}
|
212 |
|
213 |
-
|
214 |
-
|
215 |
-
|
|
|
|
|
|
|
|
|
|
|
216 |
|
217 |
-
|
218 |
-
'SELECT
|
219 |
-
sib.*,
|
220 |
-
si.id - 1 AS "day_index",
|
221 |
-
si.name AS "day_name"
|
222 |
-
FROM `ab_schedule_item_break` sib
|
223 |
-
LEFT JOIN `ab_staff_schedule_item` ssi ON sib.staff_schedule_item_id = ssi.id
|
224 |
-
LEFT JOIN `ab_schedule_item` si ON ssi.schedule_item_id = si.id
|
225 |
-
WHERE sib.staff_schedule_item_id IN (' . implode( ', ', $active_schedule_items_ids ) . ')'
|
226 |
-
);
|
227 |
|
228 |
-
|
229 |
-
$date = date( 'Y-m-d', strtotime( $break_item->day_name . ' this week', strtotime( $start_date ) ) );
|
230 |
-
$startDate = new DateTime( $date . ' ' . $break_item->start_time );
|
231 |
-
$endDate = new DateTime( $date . ' ' . $break_item->end_time );
|
232 |
-
|
233 |
-
// get breaks
|
234 |
-
$result['freebusys'][] = $this->getFreeBusy( $startDate, $endDate, false );
|
235 |
-
}
|
236 |
-
}
|
237 |
-
}
|
238 |
-
echo json_encode( $result );
|
239 |
-
exit;
|
240 |
-
}
|
241 |
-
|
242 |
-
/**
|
243 |
-
* Get data for WeekCalendar in `day` mode.
|
244 |
-
*
|
245 |
-
* @return json
|
246 |
-
*/
|
247 |
-
public function executeDayStaffAppointments() {
|
248 |
-
$result = array( 'events' => array(), 'freebusys' => array() );
|
249 |
-
$staff_ids = $this->getParameter( 'staff_id' );
|
250 |
-
if (is_array($staff_ids)) {
|
251 |
-
$wpdb = $this->getWpdb();
|
252 |
-
|
253 |
-
$start_date = $this->_post['start_date'];
|
254 |
-
|
255 |
-
$appointments = $wpdb->get_results( sprintf(
|
256 |
-
'SELECT
|
257 |
-
a.id,
|
258 |
-
a.start_date,
|
259 |
-
a.end_date,
|
260 |
-
a.notes,
|
261 |
-
a.customer_id AS "customer_id",
|
262 |
-
s.title,
|
263 |
-
s.color,
|
264 |
-
staff.id AS "staff_id",
|
265 |
-
staff.full_name AS "staff_fullname"
|
266 |
-
FROM ab_appointment a
|
267 |
-
LEFT JOIN ab_service s ON a.service_id = s.id
|
268 |
-
LEFT JOIN ab_staff staff ON a.staff_id = staff.id
|
269 |
-
WHERE DATE(a.start_date) = DATE("%s") AND staff_id IN (%s)
|
270 |
-
GROUP BY a.id',
|
271 |
-
mysql_real_escape_string($start_date),
|
272 |
-
implode(',', array_merge(array(0), array_map('intval', $staff_ids)))
|
273 |
-
) );
|
274 |
-
|
275 |
-
foreach ( $appointments as $appointment ) {
|
276 |
-
$result['events'][] = $this->getAppointment( $appointment, $appointment->staff_id, $day_view = true );
|
277 |
}
|
278 |
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
WHERE si.name = DATE_FORMAT(DATE("' . $start_date . '"), "%W")
|
287 |
-
AND ssi.start_time IS NOT NULL'
|
288 |
-
);
|
289 |
-
|
290 |
-
$active_schedule_items_ids = array();
|
291 |
-
|
292 |
-
foreach ( $schedule as $item ) {
|
293 |
-
$startDate = new DateTime(date( 'Y-m-d', strtotime( $start_date ) ) . ' ' . $item->start_time);
|
294 |
-
$endDate = new DateTime(date( 'Y-m-d', strtotime( $start_date ) ) . ' ' . $item->end_time);
|
295 |
-
|
296 |
-
$holidays = $wpdb->get_results($wpdb->prepare(
|
297 |
-
'SELECT * FROM ab_holiday WHERE staff_id = %d and ((`repeat_event` = 0 and DATE_FORMAT( `holiday` , "%%Y-%%m-%%d" ) = %s) or (`repeat_event` = 1 and DATE_FORMAT( `holiday` , "%%Y-%%m" ) = %s))',
|
298 |
-
array($item->staff_id, $startDate->format('Y-m-d'), $startDate->format('m-d')))
|
299 |
-
);
|
300 |
-
if (!$holidays){
|
301 |
-
$result['freebusys'][] = $this->getFreeBusy( $startDate, $endDate, true, $item->staff_id );
|
302 |
-
$active_schedule_items_ids[] = $item->id;
|
303 |
-
}
|
304 |
-
}
|
305 |
-
|
306 |
-
if ( empty($active_schedule_items_ids) ) {
|
307 |
-
$active_schedule_items_ids = array( 0 );
|
308 |
-
}
|
309 |
-
|
310 |
-
$schedule_breaks = $wpdb->get_results(
|
311 |
-
'SELECT
|
312 |
-
sib.*,
|
313 |
-
s.id AS "staff_id"
|
314 |
-
FROM `ab_schedule_item_break` sib
|
315 |
-
LEFT JOIN `ab_staff_schedule_item` ssi ON sib.staff_schedule_item_id = ssi.id
|
316 |
-
LEFT JOIN `ab_schedule_item` si ON ssi.schedule_item_id = si.id
|
317 |
-
LEFT JOIN `ab_staff` s ON ssi.staff_id = s.id
|
318 |
-
WHERE sib.staff_schedule_item_id IN (' . implode( ', ', $active_schedule_items_ids ) . ')'
|
319 |
-
);
|
320 |
-
|
321 |
-
foreach ( $schedule_breaks as $break_item ) {
|
322 |
-
$startDate = new DateTime(date( 'Y-m-d', strtotime( $start_date ) ) . ' ' . $break_item->start_time);
|
323 |
-
$endDate = new DateTime(date( 'Y-m-d', strtotime( $start_date ) ) . ' ' . $break_item->end_time);
|
324 |
-
|
325 |
-
$result['freebusys'][] = $this->getFreeBusy( $startDate, $endDate, false, $break_item->staff_id );
|
326 |
}
|
327 |
}
|
328 |
-
|
329 |
-
|
330 |
}
|
331 |
|
332 |
/**
|
333 |
* Get data needed for appointment form initialisation.
|
334 |
*/
|
335 |
-
public function executeGetDataForAppointmentForm()
|
336 |
-
|
337 |
-
$
|
338 |
-
$result = array(
|
339 |
'staff' => array(),
|
340 |
'customers' => array(),
|
341 |
-
'
|
|
|
342 |
'time_interval' => get_option( 'ab_settings_time_slot_length' ) * 60
|
343 |
);
|
344 |
|
345 |
// Staff list.
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
)
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
$result[ 'staff' ][] = array(
|
368 |
-
'id' => $st[ 'id' ],
|
369 |
-
'full_name' => $st[ 'full_name' ],
|
370 |
'services' => $services
|
371 |
);
|
372 |
}
|
373 |
|
374 |
// Customers list.
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
$customer = new AB_Customer();
|
380 |
-
foreach ($customers as $customer_data) {
|
381 |
-
$customer->setData( $customer_data );
|
382 |
-
|
383 |
-
$name = $customer->get('name');
|
384 |
-
if ($customer->get('email') && $customer->get('phone')){
|
385 |
-
$name .= ' (' . $customer->get('email') . ', ' . $customer->get('phone') . ')';
|
386 |
-
}elseif($customer->get('email')){
|
387 |
-
$name .= ' (' . $customer->get('email') . ')';
|
388 |
-
}elseif($customer->get('phone')){
|
389 |
-
$name .= ' (' . $customer->get('phone') . ')';
|
390 |
}
|
391 |
|
392 |
$result[ 'customers' ][] = array(
|
393 |
-
'id'
|
394 |
-
'name'
|
|
|
|
|
395 |
);
|
396 |
}
|
397 |
|
398 |
// Time list.
|
399 |
-
$
|
400 |
-
$
|
401 |
-
$
|
402 |
-
$time_end = new AB_DateTime( AB_StaffScheduleItem::WORKING_END_TIME, new DateTimeZone( 'UTC' ) );
|
403 |
|
404 |
// Run the loop.
|
405 |
-
while ( $time_start
|
406 |
-
$
|
407 |
-
'value' => $time_start
|
408 |
-
'title' =>
|
409 |
);
|
410 |
-
|
|
|
|
|
|
|
|
|
411 |
}
|
412 |
|
413 |
-
|
414 |
-
exit (0);
|
415 |
}
|
416 |
|
417 |
/**
|
418 |
-
* Get appointment data when editing
|
419 |
*/
|
420 |
-
public function executeGetDataForAppointment()
|
421 |
-
|
|
|
422 |
|
423 |
$appointment = new AB_Appointment();
|
424 |
-
if ( $appointment->load( $this->
|
425 |
-
$response[
|
426 |
-
|
427 |
-
$
|
428 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
429 |
}
|
430 |
-
|
431 |
-
echo json_encode( $response );
|
432 |
-
exit ( 0 );
|
433 |
}
|
434 |
|
435 |
/**
|
436 |
* Save appointment form (for both create and edit).
|
437 |
*/
|
438 |
-
public function executeSaveAppointmentForm()
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
|
443 |
-
$
|
444 |
-
$
|
445 |
-
$
|
446 |
-
$
|
447 |
-
$
|
448 |
-
|
449 |
-
$
|
|
|
|
|
|
|
|
|
450 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
451 |
if ( !$this->dateIntervalIsAvailableForAppointment( $start_date, $end_date, $staff_id, $appointment_id ) ) {
|
452 |
-
$response[
|
453 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
454 |
$appointment = new AB_Appointment();
|
455 |
if ( $appointment_id ) {
|
456 |
-
//
|
457 |
$appointment->load( $appointment_id );
|
458 |
}
|
459 |
-
$appointment->set( 'start_date',
|
460 |
-
$appointment->set( 'end_date',
|
461 |
-
$appointment->set( 'staff_id',
|
462 |
-
$appointment->set( 'service_id',
|
463 |
-
$appointment->set( 'customer_id', $customer_id );
|
464 |
-
$appointment->set( 'notes', $notes );
|
465 |
|
466 |
if ( $appointment->save() !== false ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
467 |
$startDate = new DateTime( $appointment->get( 'start_date' ) );
|
468 |
$endDate = new DateTime( $appointment->get( 'end_date' ) );
|
469 |
-
$
|
470 |
-
$
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
|
480 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
481 |
}
|
482 |
-
}
|
483 |
|
484 |
-
|
485 |
-
$desc[] = '<div class="
|
486 |
}
|
487 |
|
488 |
-
$
|
489 |
-
|
490 |
-
'start' => $startDate->format( 'm/d/Y H:i' ),
|
491 |
-
'end' => $endDate->format( 'm/d/Y H:i' ),
|
492 |
-
'desc' => implode('', $desc),
|
493 |
-
'title' => $service->get( 'title' ) ? $service->get( 'title' ) : __( 'Untitled', 'ab' ),
|
494 |
-
'color' => $service->get( 'color' ),
|
495 |
-
'userId' => (int)$appointment->get( 'staff_id' ),
|
496 |
-
);
|
497 |
|
498 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
499 |
} else {
|
500 |
-
$response[ 'errors' ] = array( '
|
501 |
}
|
502 |
}
|
503 |
|
504 |
-
|
505 |
-
exit ( 0 );
|
506 |
}
|
507 |
|
508 |
-
public function executeCheckAppointmentDateSelection()
|
509 |
-
|
510 |
-
$
|
511 |
-
$
|
512 |
-
$
|
513 |
-
$
|
|
|
514 |
$timestamp_diff = strtotime( $end_date ) - strtotime( $start_date );
|
515 |
|
516 |
$result = array(
|
@@ -528,147 +440,49 @@ class AB_CalendarController extends AB_Controller {
|
|
528 |
|
529 |
$duration = $service->get( 'duration' );
|
530 |
|
531 |
-
//
|
532 |
-
$result['date_interval_warning'] = ($timestamp_diff != $duration);
|
533 |
}
|
534 |
|
535 |
-
|
536 |
-
exit;
|
537 |
}
|
538 |
|
539 |
-
public function executeDeleteAppointment()
|
|
|
540 |
$appointment = new AB_Appointment();
|
541 |
-
$appointment->load( $this->
|
542 |
$appointment->delete();
|
543 |
exit;
|
544 |
}
|
545 |
|
546 |
-
private function dateIntervalIsAvailableForAppointment( $start_date, $end_date, $staff_id, $appointment_id ) {
|
547 |
-
return ! is_object( $this->getWpdb()->get_row( $this->getWpdb()->prepare(
|
548 |
-
'SELECT * FROM `ab_appointment`
|
549 |
-
WHERE (
|
550 |
-
start_date > %s AND start_date < %s
|
551 |
-
OR (end_date > %s AND end_date < %s)
|
552 |
-
OR (start_date < %s AND end_date > %s)
|
553 |
-
OR (start_date = %s OR end_date = %s)
|
554 |
-
)
|
555 |
-
AND staff_id = %d
|
556 |
-
AND id <> %d',
|
557 |
-
$start_date,
|
558 |
-
$end_date,
|
559 |
-
$start_date,
|
560 |
-
$end_date,
|
561 |
-
$start_date,
|
562 |
-
$end_date,
|
563 |
-
$start_date,
|
564 |
-
$end_date,
|
565 |
-
$staff_id,
|
566 |
-
$appointment_id
|
567 |
-
) ) );
|
568 |
-
}
|
569 |
-
|
570 |
/**
|
571 |
-
* @param $
|
572 |
-
*
|
573 |
-
* @
|
574 |
-
|
575 |
-
|
576 |
-
$customer = new AB_Customer();
|
577 |
-
$customer_data = $this->getWpdb()->get_row( $this->getWpdb()->prepare(
|
578 |
-
'SELECT * FROM `ab_customer` WHERE id = %d', $id
|
579 |
-
) );
|
580 |
-
// populate customer with data
|
581 |
-
if ( $customer_data ) {
|
582 |
-
$customer->setData( $customer_data );
|
583 |
-
}
|
584 |
-
|
585 |
-
return $customer;
|
586 |
-
}
|
587 |
-
|
588 |
-
/**
|
589 |
-
* Get appointment data
|
590 |
-
*
|
591 |
-
* @param stdClass $appointment
|
592 |
-
* @param null $user_id
|
593 |
-
* @param bool $day_view
|
594 |
-
*
|
595 |
-
* @return array
|
596 |
*/
|
597 |
-
private function
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
}
|
608 |
-
}
|
609 |
-
|
610 |
-
if ($appointment->notes) {
|
611 |
-
$desc[] = '<div class="wc-notes">' . nl2br( esc_html( $appointment->notes ) ) . '</div>';
|
612 |
-
}
|
613 |
-
|
614 |
-
$appointment_data = array(
|
615 |
-
'id' => $appointment->id,
|
616 |
-
'start' => $startDate->format( 'm/d/Y H:i' ),
|
617 |
-
'end' => $endDate->format( 'm/d/Y H:i' ),
|
618 |
-
'title' => $appointment->title ? esc_html( $appointment->title ) : __( 'Untitled', 'ab' ),
|
619 |
-
'desc' => implode('', $desc),
|
620 |
-
'color' => $appointment->color,
|
621 |
-
);
|
622 |
-
// if needed to be rendered for a specific user
|
623 |
-
// pass the the user id
|
624 |
-
if ( null !== $user_id ) {
|
625 |
-
$appointment_data['userId'] = $user_id;
|
626 |
-
}
|
627 |
-
return $appointment_data;
|
628 |
}
|
629 |
|
630 |
/**
|
631 |
-
* Get free busy data
|
632 |
-
*
|
633 |
-
* @param DateTime $startDate
|
634 |
-
* @param DateTime $endDate
|
635 |
-
* @param $free
|
636 |
-
* @param null $user_id
|
637 |
-
*
|
638 |
-
* @return array
|
639 |
-
*/
|
640 |
-
private function getFreeBusy( DateTime $startDate, DateTime $endDate, $free, $user_id = null ) {
|
641 |
-
$freebusy_data = array(
|
642 |
-
'start' => $startDate->format( 'm/d/Y H:i' ),
|
643 |
-
'end' => $endDate->format( 'm/d/Y H:i' ),
|
644 |
-
'free' => $free
|
645 |
-
);
|
646 |
-
// if needed to be rendered for a specific user
|
647 |
-
// pass the the user id
|
648 |
-
if ( null !== $user_id ) {
|
649 |
-
$freebusy_data['userId'] = $user_id;
|
650 |
-
}
|
651 |
-
return $freebusy_data;
|
652 |
-
}
|
653 |
-
|
654 |
-
private function dateFormatTojQueryUIDatePickerFormat() {
|
655 |
-
$chars = array(
|
656 |
-
// Day
|
657 |
-
'd' => 'dd', 'j' => 'd', 'l' => 'DD', 'D' => 'D',
|
658 |
-
// Month
|
659 |
-
'm' => 'mm', 'n' => 'm', 'F' => 'MM', 'M' => 'M',
|
660 |
-
// Year
|
661 |
-
'Y' => 'yy', 'y' => 'y',
|
662 |
-
);
|
663 |
-
|
664 |
-
return strtr((string)get_option('date_format'), $chars);
|
665 |
-
}
|
666 |
-
|
667 |
-
/**
|
668 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
669 |
* so current 'execute*' methods look nicer.
|
|
|
|
|
670 |
*/
|
671 |
-
protected function registerWpActions( $prefix = '' )
|
|
|
672 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
673 |
}
|
|
|
674 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_CalendarController
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
*/
|
6 |
+
class AB_CalendarController extends AB_Controller {
|
7 |
+
|
8 |
+
protected function getPermissions()
|
9 |
+
{
|
10 |
+
return array( '_this' => 'user' );
|
11 |
+
}
|
12 |
+
|
13 |
+
public function index()
|
14 |
+
{
|
15 |
+
/** @var WP_Locale $wp_locale */
|
16 |
+
global $wp_locale;
|
17 |
+
|
18 |
+
$this->enqueueStyles( array(
|
19 |
+
'frontend' => array(
|
20 |
+
'css/intlTelInput.css',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
),
|
22 |
+
'module' => array(
|
23 |
+
'css/calendar.css',
|
24 |
+
'css/fullcalendar.min.css',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
),
|
26 |
+
'backend' => array(
|
27 |
+
'css/chosen.min.css',
|
28 |
+
'css/jquery-ui-theme/jquery-ui.min.css',
|
29 |
+
'css/bookly.main-backend.css',
|
30 |
+
'bootstrap/css/bootstrap.min.css',
|
|
|
|
|
|
|
31 |
),
|
32 |
+
) );
|
33 |
+
|
34 |
+
$this->enqueueScripts( array(
|
35 |
+
'backend' => array(
|
36 |
+
'js/angular.min.js' => array( 'jquery' ),
|
37 |
+
'js/angular-ui-date-0.0.8.js' => array( 'ab-angular.min.js' ),
|
38 |
+
'js/ng-new_customer_dialog.js' => array( 'ab-angular.min.js' ),
|
39 |
+
'js/moment.min.js' => array( 'jquery' ),
|
40 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
41 |
+
'js/chosen.jquery.min.js' => array( 'jquery' ),
|
42 |
+
'js/ng-edit_appointment_dialog.js' => array( 'ab-angular-ui-date-0.0.8.js', 'jquery-ui-datepicker' ),
|
43 |
),
|
44 |
+
'module' => array(
|
45 |
+
'js/fullcalendar.min.js' => array( 'ab-moment.min.js' ),
|
46 |
+
'js/fc-multistaff-view.js' => array( 'ab-fullcalendar.min.js' ),
|
47 |
+
'js/calendar.js' => array( 'ab-fc-multistaff-view.js', 'ab-intlTelInput.min.js' ),
|
48 |
+
),
|
49 |
+
'frontend' => array(
|
50 |
+
'js/intlTelInput.min.js' => array( 'jquery' ),
|
51 |
+
)
|
52 |
+
) );
|
53 |
+
|
54 |
+
$slot_length_minutes = get_option( 'ab_settings_time_slot_length', '15' );
|
55 |
+
$slot = new DateInterval( 'PT' . $slot_length_minutes . 'M' );
|
56 |
+
|
57 |
+
$this->staff_members = AB_Utils::isCurrentUserAdmin()
|
58 |
+
? AB_Staff::query()->sortBy( 'position' )->find()
|
59 |
+
: AB_Staff::query()->where( 'wp_user_id', get_current_user_id() )->find();
|
60 |
+
|
61 |
+
|
62 |
+
wp_localize_script( 'ab-calendar.js', 'BooklyL10n', array(
|
63 |
+
'slotDuration' => $slot->format( '%H:%I:%S' ),
|
64 |
+
'shortMonths' => array_values( $wp_locale->month_abbrev ),
|
65 |
+
'longMonths' => array_values( $wp_locale->month ),
|
66 |
+
'shortDays' => array_values( $wp_locale->weekday_abbrev ),
|
67 |
+
'longDays' => array_values( $wp_locale->weekday ),
|
68 |
+
'AM' => $wp_locale->meridiem[ 'AM' ],
|
69 |
+
'PM' => $wp_locale->meridiem[ 'PM' ],
|
70 |
+
'dpDateFormat' => AB_DateTimeUtils::convertFormat( 'date', AB_DateTimeUtils::FORMAT_JQUERY_DATEPICKER ),
|
71 |
+
'mjsDateFormat' => AB_DateTimeUtils::convertFormat( 'date', AB_DateTimeUtils::FORMAT_MOMENT_JS ),
|
72 |
+
'mjsTimeFormat' => AB_DateTimeUtils::convertFormat( 'time', AB_DateTimeUtils::FORMAT_MOMENT_JS ),
|
73 |
+
'today' => __( 'Today', 'bookly' ),
|
74 |
+
'week' => __( 'Week', 'bookly' ),
|
75 |
+
'day' => __( 'Day', 'bookly' ),
|
76 |
+
'month' => __( 'Month', 'bookly' ),
|
77 |
+
'allDay' => __( 'All Day', 'bookly' ),
|
78 |
+
'noStaffSelected' => __( 'No staff selected', 'bookly' ),
|
79 |
+
'newAppointment' => __( 'New appointment', 'bookly' ),
|
80 |
+
'editAppointment' => __( 'Edit appointment', 'bookly' ),
|
81 |
+
'are_you_sure' => __( 'Are you sure?', 'bookly' ),
|
82 |
+
'startOfWeek' => (int) get_option( 'start_of_week' ),
|
83 |
+
'country' => get_option( 'ab_settings_phone_default_country' ),
|
84 |
+
'intlTelInput_utils' => plugins_url( 'intlTelInput.utils.js', AB_PATH . '/frontend/resources/js/intlTelInput.utils.js' ),
|
85 |
+
) );
|
86 |
|
87 |
$this->render( 'calendar' );
|
88 |
}
|
89 |
+
|
90 |
/**
|
91 |
+
* Get data for FullCalendar.
|
92 |
*
|
93 |
* @return json
|
94 |
*/
|
95 |
+
public function executeGetStaffAppointments()
|
96 |
+
{
|
97 |
+
$result = array();
|
98 |
+
$staff_members = array();
|
99 |
+
$one_day = new DateInterval( 'P1D' );
|
100 |
+
$start_date = new DateTime( $this->getParameter( 'start' ) );
|
101 |
+
$end_date = new DateTime( $this->getParameter( 'end' ) );
|
102 |
+
// FullCalendar sends end date as 1 day further.
|
103 |
+
$end_date->sub( $one_day );
|
104 |
+
|
105 |
+
if ( AB_Utils::isCurrentUserAdmin() ) {
|
106 |
+
$staff_members = AB_Staff::query()
|
107 |
+
->where( 'id', 1 )
|
108 |
+
->find();
|
109 |
+
} else {
|
110 |
+
$staff_members[] = AB_Staff::query()
|
111 |
+
->where( 'wp_user_id', get_current_user_id() )
|
112 |
+
->findOne();
|
113 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
|
115 |
+
foreach ( $staff_members as $staff ) {
|
116 |
+
/** @var AB_Staff $staff */
|
117 |
+
$result = array_merge( $result, $staff->getAppointmentsForFC( $start_date, $end_date ) );
|
118 |
+
|
119 |
+
// Schedule.
|
120 |
+
$items = $staff->getScheduleItems();
|
121 |
+
$day = clone $start_date;
|
122 |
+
// Find previous day end time.
|
123 |
+
$last_end = clone $day;
|
124 |
+
$last_end->sub( $one_day );
|
125 |
+
$w = $day->format( 'w' );
|
126 |
+
$end_time = $items[ $w > 0 ? $w : 7 ]->get( 'end_time' );
|
127 |
+
if ( $end_time !== null ) {
|
128 |
+
$end_time = explode( ':', $end_time );
|
129 |
+
$last_end->setTime( $end_time[0], $end_time[1] );
|
130 |
+
} else {
|
131 |
+
$last_end->setTime( 24, 0 );
|
132 |
+
}
|
133 |
+
// Do the loop.
|
134 |
+
while ( $day <= $end_date ) {
|
135 |
+
do {
|
136 |
+
/** @var AB_StaffScheduleItem $item */
|
137 |
+
$item = $items[ $day->format( 'w' ) + 1 ];
|
138 |
+
if ( $item->get( 'start_time' ) && ! $staff->isOnHoliday( $day ) ) {
|
139 |
+
$start = $last_end->format( 'Y-m-d H:i:s' );
|
140 |
+
$end = $day->format( 'Y-m-d '.$item->get( 'start_time' ) );
|
141 |
+
if ( $start < $end ) {
|
142 |
+
$result[] = array(
|
143 |
+
'start' => $start,
|
144 |
+
'end' => $end,
|
145 |
+
'rendering' => 'background',
|
146 |
+
'staffId' => $staff->get( 'id' ),
|
147 |
+
);
|
148 |
}
|
149 |
+
$last_end = clone $day;
|
150 |
+
$end_time = explode( ':', $item->get( 'end_time' ) );
|
151 |
+
$last_end->setTime( $end_time[0], $end_time[1] );
|
152 |
+
|
153 |
+
// Breaks.
|
154 |
+
foreach ( $item->getBreaksList() as $break ) {
|
155 |
+
$result[] = array(
|
156 |
+
'start' => $day->format( 'Y-m-d '.$break['start_time'] ),
|
157 |
+
'end' => $day->format( 'Y-m-d '.$break['end_time'] ),
|
158 |
+
'rendering' => 'background',
|
159 |
+
'staffId' => $staff->get( 'id' ),
|
160 |
+
);
|
|
|
|
|
161 |
}
|
162 |
|
163 |
+
break;
|
|
|
|
|
164 |
}
|
|
|
165 |
|
166 |
+
$result[] = array(
|
167 |
+
'start' => $last_end->format( 'Y-m-d H:i:s' ),
|
168 |
+
'end' => $day->format( 'Y-m-d 24:00:00' ),
|
169 |
+
'rendering' => 'background',
|
170 |
+
'staffId' => $staff->get( 'id' ),
|
171 |
+
);
|
172 |
+
$last_end = clone $day;
|
173 |
+
$last_end->setTime( 24, 0 );
|
174 |
|
175 |
+
} while ( 0 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
176 |
|
177 |
+
$day->add( $one_day );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
178 |
}
|
179 |
|
180 |
+
if ( $last_end->format( 'H' ) != 24 ) {
|
181 |
+
$result[] = array(
|
182 |
+
'start' => $last_end->format( 'Y-m-d H:i:s' ),
|
183 |
+
'end' => $last_end->format( 'Y-m-d 24:00:00' ),
|
184 |
+
'rendering' => 'background',
|
185 |
+
'staffId' => $staff->get( 'id' ),
|
186 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
}
|
188 |
}
|
189 |
+
|
190 |
+
wp_send_json( $result );
|
191 |
}
|
192 |
|
193 |
/**
|
194 |
* Get data needed for appointment form initialisation.
|
195 |
*/
|
196 |
+
public function executeGetDataForAppointmentForm()
|
197 |
+
{
|
198 |
+
$result = array(
|
|
|
199 |
'staff' => array(),
|
200 |
'customers' => array(),
|
201 |
+
'start_time' => array(),
|
202 |
+
'end_time' => array(),
|
203 |
'time_interval' => get_option( 'ab_settings_time_slot_length' ) * 60
|
204 |
);
|
205 |
|
206 |
// Staff list.
|
207 |
+
$staff_members = AB_Staff::query()->where( 'id', 1 )->sortBy( 'position' )->find();
|
208 |
+
|
209 |
+
|
210 |
+
/** @var AB_Staff $staff_member */
|
211 |
+
foreach ( $staff_members as $staff_member ) {
|
212 |
+
$services = array();
|
213 |
+
foreach ( $staff_member->getStaffServices() as $staff_service ) {
|
214 |
+
$services[] = array(
|
215 |
+
'id' => $staff_service->service->get( 'id' ),
|
216 |
+
'title' => sprintf(
|
217 |
+
'%s (%s)',
|
218 |
+
$staff_service->service->get( 'title' ),
|
219 |
+
AB_DateTimeUtils::secondsToInterval( $staff_service->service->get( 'duration' ) )
|
220 |
+
),
|
221 |
+
'duration' => $staff_service->service->get( 'duration' ),
|
222 |
+
'capacity' => $staff_service->get( 'capacity' )
|
223 |
+
);
|
224 |
+
}
|
225 |
+
$result['staff'][] = array(
|
226 |
+
'id' => 1,
|
227 |
+
'full_name' => $staff_member->get( 'full_name' ),
|
|
|
|
|
|
|
228 |
'services' => $services
|
229 |
);
|
230 |
}
|
231 |
|
232 |
// Customers list.
|
233 |
+
foreach ( AB_Customer::query()->sortBy( 'name' )->find() as $customer ) {
|
234 |
+
$name = $customer->get( 'name' );
|
235 |
+
if ( $customer->get( 'email' ) != '' || $customer->get( 'phone' ) != '' ) {
|
236 |
+
$name .= ' (' . trim( $customer->get( 'email' ) . ', ' . $customer->get( 'phone' ) , ', ') . ')';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
}
|
238 |
|
239 |
$result[ 'customers' ][] = array(
|
240 |
+
'id' => $customer->get( 'id' ),
|
241 |
+
'name' => $name,
|
242 |
+
'custom_fields' => array(),
|
243 |
+
'number_of_persons' => 1,
|
244 |
);
|
245 |
}
|
246 |
|
247 |
// Time list.
|
248 |
+
$ts_length = AB_Config::getTimeSlotLength();
|
249 |
+
$time_start = 0;
|
250 |
+
$time_end = DAY_IN_SECONDS * 2;
|
|
|
251 |
|
252 |
// Run the loop.
|
253 |
+
while ( $time_start <= $time_end ) {
|
254 |
+
$slot = array(
|
255 |
+
'value' => AB_DateTimeUtils::buildTimeString( $time_start, false ),
|
256 |
+
'title' => AB_DateTimeUtils::formatTime( $time_start )
|
257 |
);
|
258 |
+
if ( $time_start < DAY_IN_SECONDS ) {
|
259 |
+
$result['start_time'][] = $slot;
|
260 |
+
}
|
261 |
+
$result['end_time'][] = $slot;
|
262 |
+
$time_start += $ts_length;
|
263 |
}
|
264 |
|
265 |
+
wp_send_json( $result );
|
|
|
266 |
}
|
267 |
|
268 |
/**
|
269 |
+
* Get appointment data when editing an appointment.
|
270 |
*/
|
271 |
+
public function executeGetDataForAppointment()
|
272 |
+
{
|
273 |
+
$response = array( 'success' => false, 'data' => array( 'customers' => array() ) );
|
274 |
|
275 |
$appointment = new AB_Appointment();
|
276 |
+
if ( $appointment->load( $this->getParameter( 'id' ) ) ) {
|
277 |
+
$response['success'] = true;
|
278 |
+
|
279 |
+
$info = AB_Appointment::query( 'a' )
|
280 |
+
->select( 'ss.capacity AS max_capacity, SUM( ca.number_of_persons ) AS total_number_of_persons, a.staff_id, a.service_id, a.start_date, a.end_date' )
|
281 |
+
->leftJoin( 'AB_CustomerAppointment', 'ca', 'ca.appointment_id = a.id' )
|
282 |
+
->leftJoin( 'AB_StaffService', 'ss', 'ss.staff_id = a.staff_id AND ss.service_id = a.service_id' )
|
283 |
+
->where( 'a.id', $appointment->get( 'id' ) )
|
284 |
+
->fetchRow();
|
285 |
+
|
286 |
+
$response['data']['total_number_of_persons'] = $info['total_number_of_persons'];
|
287 |
+
$response['data']['max_capacity'] = $info['max_capacity'];
|
288 |
+
$response['data']['start_date'] = $info['start_date'];
|
289 |
+
$response['data']['end_date'] = $info['end_date'];
|
290 |
+
$response['data']['staff_id'] = $info['staff_id'];
|
291 |
+
$response['data']['service_id'] = $info['service_id'];
|
292 |
+
|
293 |
+
$customer_appointments = AB_CustomerAppointment::query()->where( 'appointment_id', $appointment->get( 'id' ) )->fetchArray();
|
294 |
+
|
295 |
+
foreach ( $customer_appointments as $customer_appointment ) {
|
296 |
+
$response[ 'data' ][ 'customers' ][] = array(
|
297 |
+
'id' => $customer_appointment['customer_id'],
|
298 |
+
'custom_fields' => $customer_appointment['custom_fields'] ? json_decode( $customer_appointment['custom_fields'], true ) : array(),
|
299 |
+
'number_of_persons' => $customer_appointment['number_of_persons']
|
300 |
+
);
|
301 |
+
}
|
302 |
}
|
303 |
+
wp_send_json( $response );
|
|
|
|
|
304 |
}
|
305 |
|
306 |
/**
|
307 |
* Save appointment form (for both create and edit).
|
308 |
*/
|
309 |
+
public function executeSaveAppointmentForm()
|
310 |
+
{
|
311 |
+
$response = array( 'success' => false );
|
312 |
+
|
313 |
+
$start_date = date( 'Y-m-d H:i:s', strtotime( $this->getParameter( 'start_date' ) ) );
|
314 |
+
$end_date = date( 'Y-m-d H:i:s', strtotime( $this->getParameter( 'end_date' ) ) );
|
315 |
+
$staff_id = $this->getParameter( 'staff_id' );
|
316 |
+
$service_id = $this->getParameter( 'service_id' );
|
317 |
+
$appointment_id = $this->getParameter( 'id', 0 );
|
318 |
+
$customers = json_decode( $this->getParameter( 'customers', '[]' ), true );
|
319 |
+
|
320 |
+
$staff_service = new AB_StaffService();
|
321 |
+
$staff_service->loadBy( array(
|
322 |
+
'staff_id' => $staff_id,
|
323 |
+
'service_id' => $service_id
|
324 |
+
) );
|
325 |
|
326 |
+
// Check for errors.
|
327 |
+
if ( ! $service_id ) {
|
328 |
+
$response['errors']['service_required'] = true;
|
329 |
+
}
|
330 |
+
if ( empty ( $customers ) ) {
|
331 |
+
$response['errors']['customers_required'] = true;
|
332 |
+
}
|
333 |
if ( !$this->dateIntervalIsAvailableForAppointment( $start_date, $end_date, $staff_id, $appointment_id ) ) {
|
334 |
+
$response['errors']['date_interval_not_available'] = true;
|
335 |
+
}
|
336 |
+
$number_of_persons = 0;
|
337 |
+
foreach ( $customers as $customer ) {
|
338 |
+
$number_of_persons += $customer['number_of_persons'];
|
339 |
+
}
|
340 |
+
if ( $number_of_persons > $staff_service->get( 'capacity' ) ) {
|
341 |
+
$response['errors']['overflow_capacity'] = __( 'The number of customers should be not more than ', 'bookly' ) . $staff_service->get( 'capacity' );
|
342 |
+
}
|
343 |
+
if ( ! $this->getParameter( 'start_date' ) ) {
|
344 |
+
$response['errors']['time_interval'] = __( 'Start time must not be empty', 'bookly' );
|
345 |
+
} elseif ( ! $this->getParameter( 'end_date' ) ) {
|
346 |
+
$response['errors']['time_interval'] = __( 'End time must not be empty', 'bookly' );
|
347 |
+
} elseif ( $start_date == $end_date ) {
|
348 |
+
$response['errors']['time_interval'] = __( 'End time must not be equal to start time', 'bookly' );
|
349 |
+
}
|
350 |
+
|
351 |
+
// If no errors then try to save the appointment.
|
352 |
+
if ( !isset ( $response[ 'errors' ] ) ) {
|
353 |
$appointment = new AB_Appointment();
|
354 |
if ( $appointment_id ) {
|
355 |
+
// Edit.
|
356 |
$appointment->load( $appointment_id );
|
357 |
}
|
358 |
+
$appointment->set( 'start_date', $start_date );
|
359 |
+
$appointment->set( 'end_date', $end_date );
|
360 |
+
$appointment->set( 'staff_id', $staff_id );
|
361 |
+
$appointment->set( 'service_id', $service_id );
|
|
|
|
|
362 |
|
363 |
if ( $appointment->save() !== false ) {
|
364 |
+
// Save customers.
|
365 |
+
$appointment->setCustomers( $customers );
|
366 |
+
|
367 |
+
// Google Calendar.
|
368 |
+
$appointment->handleGoogleCalendar();
|
369 |
+
|
370 |
$startDate = new DateTime( $appointment->get( 'start_date' ) );
|
371 |
$endDate = new DateTime( $appointment->get( 'end_date' ) );
|
372 |
+
$desc = array();
|
373 |
+
if ( $staff_service->get( 'capacity' ) == 1 ) {
|
374 |
+
$customer_appointments = $appointment->getCustomerAppointments();
|
375 |
+
if ( !empty ( $customer_appointments ) ) {
|
376 |
+
$ca = $customer_appointments[ 0 ]->customer;
|
377 |
+
foreach ( array( 'name', 'phone', 'email' ) as $data_entry ) {
|
378 |
+
$entry_value = $ca->get( $data_entry );
|
379 |
+
if ( $entry_value ) {
|
380 |
+
$desc[] = '<div class="fc-employee">' . esc_html( $entry_value ) . '</div>';
|
381 |
+
}
|
382 |
+
}
|
383 |
+
|
384 |
+
foreach ( $customer_appointments[0]->getCustomFields() as $custom_field ) {
|
385 |
+
$desc[] = '<div class="fc-notes">' . wp_strip_all_tags( $custom_field['label'] ) . ': ' . esc_html( $custom_field['value'] ) . '</div>';
|
386 |
+
}
|
387 |
+
}
|
388 |
+
} else {
|
389 |
+
$signed_up = 0;
|
390 |
+
foreach ( $appointment->getCustomerAppointments() as $ca ) {
|
391 |
+
$signed_up += $ca->get( 'number_of_persons' );
|
392 |
}
|
|
|
393 |
|
394 |
+
$desc[] = '<div class="fc-notes">' . __( 'Signed up', 'bookly' ) . ' ' . $signed_up . '</div>';
|
395 |
+
$desc[] = '<div class="fc-notes">' . __( 'Capacity', 'bookly' ) . ' ' . $staff_service->get( 'capacity' ) . '</div>';
|
396 |
}
|
397 |
|
398 |
+
$service = new AB_Service();
|
399 |
+
$service->load( $service_id );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
400 |
|
401 |
+
$response['success'] = true;
|
402 |
+
$response['data'] = array(
|
403 |
+
'id' => (int)$appointment->get( 'id' ),
|
404 |
+
'start' => $startDate->format( 'Y-m-d H:i:s' ),
|
405 |
+
'end' => $endDate->format( 'Y-m-d H:i:s' ),
|
406 |
+
'desc' => implode( '', $desc ),
|
407 |
+
'title' => $service->get( 'title' ) ? $service->get( 'title' ) : __( 'Untitled', 'bookly' ),
|
408 |
+
'color' => $service->get( 'color' ),
|
409 |
+
'staffId' => $appointment->get( 'staff_id' ),
|
410 |
+
);
|
411 |
} else {
|
412 |
+
$response[ 'errors' ] = array( 'db' => __( 'Could not save appointment in database.', 'bookly' ) );
|
413 |
}
|
414 |
}
|
415 |
|
416 |
+
wp_send_json( $response );
|
|
|
417 |
}
|
418 |
|
419 |
+
public function executeCheckAppointmentDateSelection()
|
420 |
+
{
|
421 |
+
$start_date = $this->getParameter( 'start_date' );
|
422 |
+
$end_date = $this->getParameter( 'end_date' );
|
423 |
+
$staff_id = $this->getParameter( 'staff_id' );
|
424 |
+
$service_id = $this->getParameter( 'service_id' );
|
425 |
+
$appointment_id = $this->getParameter( 'appointment_id' );
|
426 |
$timestamp_diff = strtotime( $end_date ) - strtotime( $start_date );
|
427 |
|
428 |
$result = array(
|
440 |
|
441 |
$duration = $service->get( 'duration' );
|
442 |
|
443 |
+
// Service duration interval is not equal to.
|
444 |
+
$result['date_interval_warning'] = ( $timestamp_diff != $duration );
|
445 |
}
|
446 |
|
447 |
+
wp_send_json( $result );
|
|
|
448 |
}
|
449 |
|
450 |
+
public function executeDeleteAppointment()
|
451 |
+
{
|
452 |
$appointment = new AB_Appointment();
|
453 |
+
$appointment->load( $this->getParameter( 'appointment_id' ) );
|
454 |
$appointment->delete();
|
455 |
exit;
|
456 |
}
|
457 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
458 |
/**
|
459 |
+
* @param $start_date
|
460 |
+
* @param $end_date
|
461 |
+
* @param $staff_id
|
462 |
+
* @param $appointment_id
|
463 |
+
* @return bool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
464 |
*/
|
465 |
+
private function dateIntervalIsAvailableForAppointment( $start_date, $end_date, $staff_id, $appointment_id )
|
466 |
+
{
|
467 |
+
return AB_Appointment::query()
|
468 |
+
->whereNot( 'id', $appointment_id )
|
469 |
+
->where( 'staff_id', $staff_id )
|
470 |
+
->whereRaw(
|
471 |
+
'(start_date > %s AND start_date < %s OR (end_date > %s AND end_date < %s) OR (start_date < %s AND end_date > %s) OR (start_date = %s OR end_date = %s) )',
|
472 |
+
array( $start_date, $end_date, $start_date, $end_date, $start_date, $end_date, $start_date, $end_date )
|
473 |
+
)
|
474 |
+
->count() == 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
475 |
}
|
476 |
|
477 |
/**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
478 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
479 |
* so current 'execute*' methods look nicer.
|
480 |
+
*
|
481 |
+
* @param string $prefix
|
482 |
*/
|
483 |
+
protected function registerWpActions( $prefix = '' )
|
484 |
+
{
|
485 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
486 |
}
|
487 |
+
|
488 |
}
|
backend/modules/calendar/forms/AB_AppointmentForm.php
CHANGED
@@ -1,8 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_Appointment.php';
|
6 |
|
7 |
/**
|
8 |
* Class AB_AppointmentForm
|
@@ -12,12 +8,15 @@ class AB_AppointmentForm extends AB_Form {
|
|
12 |
/**
|
13 |
* Constructor.
|
14 |
*/
|
15 |
-
public function __construct()
|
|
|
16 |
parent::$entity_class = 'AB_Appointment';
|
17 |
parent::__construct();
|
18 |
}
|
19 |
|
20 |
-
public function configure()
|
|
|
21 |
//$this->setFields( array() );
|
22 |
}
|
|
|
23 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_AppointmentForm
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_Appointment';
|
14 |
parent::__construct();
|
15 |
}
|
16 |
|
17 |
+
public function configure()
|
18 |
+
{
|
19 |
//$this->setFields( array() );
|
20 |
}
|
21 |
+
|
22 |
}
|
backend/modules/calendar/forms/AB_CustomerAppointmentForm.php
ADDED
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class AB_AppointmentForm
|
5 |
+
*/
|
6 |
+
class AB_CustomerAppointmentForm extends AB_Form {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Constructor.
|
10 |
+
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
+
parent::$entity_class = 'AB_CustomerAppointment';
|
14 |
+
parent::__construct();
|
15 |
+
}
|
16 |
+
|
17 |
+
}
|
backend/modules/calendar/resources/css/calendar.css
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
|
2 |
/* calendar nav */
|
3 |
.ab-calendar-day, .ab-calendar-week, .ab-calendar-today, .btn-list, .btn-dropdown {
|
4 |
display: inline-block;
|
@@ -33,9 +32,7 @@
|
|
33 |
.ab-calendar-week { border-bottom-left-radius: 0px; border-top-left-radius: 0px; margin-left: -3px; margin-top: 0; border-left: 0; }
|
34 |
.ab-calendar-today { margin: 0 5px; border-radius: 3px; }
|
35 |
.ab-nav-calendar { height: 30px; }
|
36 |
-
.ab-nav-calendar .ab-button-active {
|
37 |
-
background: #1f6a8c;
|
38 |
-
}
|
39 |
.ab-nav-calendar .ab-popup-wrapper { margin-left: 10px; }
|
40 |
.ab-popup-table td { white-space: nowrap; padding: 5px; border: 0!important; }
|
41 |
.ab-popup-table td > p { margin: 0; }
|
@@ -68,15 +65,14 @@
|
|
68 |
.ab-icon-button.ab-services {
|
69 |
background: url("../images/box-small.png") 2px 2px no-repeat;
|
70 |
}
|
71 |
-
.
|
72 |
-
background: url("../images/user-white.png") 0 2px no-repeat;
|
73 |
-
}
|
74 |
|
75 |
/** week picker */
|
76 |
-
.ab-week-picker-wrapper { width:
|
77 |
-
.ab-week-picker-wrapper .
|
|
|
78 |
.ab-week-picker-data { border-radius: 3px; background: url("../images/calendar.png") 2px 4px no-repeat; padding: 4px 7px 4px 25px; height: 16px; border: 1px solid black; }
|
79 |
-
#appendedPrependedInput {
|
80 |
|
81 |
/** appointment dialog */
|
82 |
.ab-appointment-popup .ui-widget-header {
|
@@ -89,7 +85,6 @@
|
|
89 |
line-height: 26px!important;
|
90 |
padding: 9px 15px!important;
|
91 |
}
|
92 |
-
.ab-appointment-popup .ui-widget-header .ui-state-hover { background: none!important; border: none!important; }
|
93 |
|
94 |
.ab-appointment-popup .loading-indicator img { display: block; margin: 20px auto; }
|
95 |
.ab-appointment-popup .dialog-button-wrapper { }
|
@@ -103,9 +98,17 @@
|
|
103 |
|
104 |
/** calendars */
|
105 |
#day_calendar_wrapper { margin-top: 55px; }
|
106 |
-
|
107 |
-
|
108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
|
110 |
/** wp elements */
|
111 |
#update-nag, .update-nag, #wpfooter { display: none; }
|
@@ -144,32 +147,69 @@
|
|
144 |
-moz-border-top-right-radius: 10px;
|
145 |
-o-border-top-right-radius: 10px;
|
146 |
}
|
147 |
-
|
|
|
148 |
background-color: #DDDDDD;
|
149 |
line-height: 16px!important;
|
|
|
150 |
}
|
151 |
-
.
|
152 |
background-color : #DDDDDD;
|
153 |
border-left-color : #DDDDDD;
|
154 |
border-right-color : #DDDDDD;
|
155 |
border-top-color : #DDDDDD;
|
156 |
border-bottom-color : #ABABAB;
|
|
|
157 |
}
|
158 |
|
159 |
-
.
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
}
|
|
|
|
|
166 |
|
167 |
-
|
168 |
-
|
|
|
169 |
}
|
170 |
|
171 |
-
.right-margin { margin-right: 10px; }
|
172 |
-
.pagination { margin: 0!important; }
|
173 |
|
174 |
-
.nav-tabs > .active > a { background: #1f6a8c!important; color: white!important; border-left: 0!important; }
|
175 |
-
.ab-date-calendar { padding-left: 25px!important; background: url("../images/calendar.png") 5px 8px no-repeat; }
|
|
|
1 |
/* calendar nav */
|
2 |
.ab-calendar-day, .ab-calendar-week, .ab-calendar-today, .btn-list, .btn-dropdown {
|
3 |
display: inline-block;
|
32 |
.ab-calendar-week { border-bottom-left-radius: 0px; border-top-left-radius: 0px; margin-left: -3px; margin-top: 0; border-left: 0; }
|
33 |
.ab-calendar-today { margin: 0 5px; border-radius: 3px; }
|
34 |
.ab-nav-calendar { height: 30px; }
|
35 |
+
.ab-nav-calendar .ab-button-active { background: #1f6a8c; }
|
|
|
|
|
36 |
.ab-nav-calendar .ab-popup-wrapper { margin-left: 10px; }
|
37 |
.ab-popup-table td { white-space: nowrap; padding: 5px; border: 0!important; }
|
38 |
.ab-popup-table td > p { margin: 0; }
|
65 |
.ab-icon-button.ab-services {
|
66 |
background: url("../images/box-small.png") 2px 2px no-repeat;
|
67 |
}
|
68 |
+
td.fc-axis.fc-time.fc-widget-content { vertical-align: top; }
|
|
|
|
|
69 |
|
70 |
/** week picker */
|
71 |
+
.ab-week-picker-wrapper { width: 350px; position: relative; margin-top: 2px; }
|
72 |
+
.ab-week-picker-wrapper i.glyphicon-calendar { position: absolute; left: 46px; top: 8px; z-index: 9; }
|
73 |
+
.ab-week-picker-wrapper .ab-week-picker { clear: both; left: -1px; position: absolute; top: 30px; z-index: 9; display: none; }
|
74 |
.ab-week-picker-data { border-radius: 3px; background: url("../images/calendar.png") 2px 4px no-repeat; padding: 4px 7px 4px 25px; height: 16px; border: 1px solid black; }
|
75 |
+
#appendedPrependedInput { background-color: #FFFFFF; cursor: default; }
|
76 |
|
77 |
/** appointment dialog */
|
78 |
.ab-appointment-popup .ui-widget-header {
|
85 |
line-height: 26px!important;
|
86 |
padding: 9px 15px!important;
|
87 |
}
|
|
|
88 |
|
89 |
.ab-appointment-popup .loading-indicator img { display: block; margin: 20px auto; }
|
90 |
.ab-appointment-popup .dialog-button-wrapper { }
|
98 |
|
99 |
/** calendars */
|
100 |
#day_calendar_wrapper { margin-top: 55px; }
|
101 |
+
.ab-calendar-inner .table-responsive { position: relative; }
|
102 |
+
.ab-calendar-inner .ab-loading-inner {
|
103 |
+
position: absolute;
|
104 |
+
left: 0;
|
105 |
+
top: 50px;
|
106 |
+
right: 0;
|
107 |
+
bottom: 0;
|
108 |
+
background-color: rgba(255, 255, 255, 0.7);
|
109 |
+
z-index: 9;
|
110 |
+
}
|
111 |
+
.ab-calendar-inner .ab-loading-inner .ab-loader { position: absolute; left: 50%; top: 50%; width: auto; }
|
112 |
|
113 |
/** wp elements */
|
114 |
#update-nag, .update-nag, #wpfooter { display: none; }
|
147 |
-moz-border-top-right-radius: 10px;
|
148 |
-o-border-top-right-radius: 10px;
|
149 |
}
|
150 |
+
|
151 |
+
.fc-cal-event {
|
152 |
background-color: #DDDDDD;
|
153 |
line-height: 16px!important;
|
154 |
+
opacity: 1;
|
155 |
}
|
156 |
+
.fc-cal-event .fc-time {
|
157 |
background-color : #DDDDDD;
|
158 |
border-left-color : #DDDDDD;
|
159 |
border-right-color : #DDDDDD;
|
160 |
border-top-color : #DDDDDD;
|
161 |
border-bottom-color : #ABABAB;
|
162 |
+
padding : 3.5px 0;
|
163 |
}
|
164 |
|
165 |
+
.pagination { margin: 0!important; }
|
166 |
+
|
167 |
+
.nav-tabs > .active > a { background: #1f6a8c!important; color: white!important; border-left: 0!important; }
|
168 |
+
.ab-date-calendar { padding-left: 25px!important; background: url("../images/calendar.png") 5px 8px no-repeat; }
|
169 |
+
|
170 |
+
/* Custom fields */
|
171 |
+
.dialog-content .ab-formGroup { margin-bottom: 15px; }
|
172 |
+
.ab-customer-list { margin: 6px 0 0 0; }
|
173 |
+
.ab-create-customer > a,
|
174 |
+
.ab-customer-list li a { cursor: pointer; border-bottom: 1px dashed #21759B; }
|
175 |
+
.ab-customer-list li a + .icon-remove { cursor: pointer; }
|
176 |
+
.ab-create-customer > a:hover,
|
177 |
+
.ab-customer-list li a:hover { text-decoration: none; color: #21759b; border-color: #21759b; }
|
178 |
+
|
179 |
+
/* Appointment dialog */
|
180 |
+
/*#ab_appointment_dialog { overflow: visible; }*/
|
181 |
+
#ab_appointment_dialog .chzn-container { font-family: Verdana,Arial,sans-serif; font-size: 14px; }
|
182 |
+
#ab_custom_fields_dialog * { font-family: "Helvetica Neue",Helvetica,Arial,sans-serif!important; }
|
183 |
+
|
184 |
+
.fc-content .icon-rt { float: right; position: absolute; top: 4px; right: 4px; cursor: pointer; }
|
185 |
+
.fc-view-container { box-shadow: 0 0 3px silver; }
|
186 |
+
.fc-widget-header table th { padding: 10px; }
|
187 |
+
.ab-head-calendar { margin-bottom: 0!important; }
|
188 |
+
.fc button { padding: 6px 12px!important; height: auto!important; }
|
189 |
+
.fc-time-grid-event.fc-short .fc-time:before { font-size: 12px; }
|
190 |
+
.fc-ltr .fc-time-grid .fc-event-container { margin: 0!important; }
|
191 |
+
.fc-time-grid-event .fc-time,
|
192 |
+
.fc-time-grid-event.fc-short .fc-title { font-size: 12px!important; padding: 0 5px!important; padding-top: 3px!important; }
|
193 |
+
.fc-time-grid-event.fc-short .fc-title { padding-top: 5px!important; display: block!important; }
|
194 |
+
.fc-day-grid-event,
|
195 |
+
.fc-time-grid-event { cursor: pointer; }
|
196 |
+
.fc-time-grid-event .fc-title { padding: 0 5px!important; padding-top: 5px!important; }
|
197 |
+
#full_calendar_wrapper .table-responsive { overflow: visible; }
|
198 |
+
.fc-toolbar h2 { position: relative; padding-right: 25px; }
|
199 |
+
.fc-toolbar h2:before {
|
200 |
+
content: "\e252";
|
201 |
+
font-family: 'Glyphicons Halflings';
|
202 |
+
position: absolute;
|
203 |
+
right: 0;
|
204 |
+
font-size: 19px;
|
205 |
+
top: 7px;
|
206 |
}
|
207 |
+
.fc-toolbar h2:hover,
|
208 |
+
.fc-toolbar h2:hover:before { color: #337ab7; cursor: pointer; }
|
209 |
|
210 |
+
/* media query */
|
211 |
+
@media screen and (max-width: 782px) {
|
212 |
+
#full_calendar_wrapper .table-responsive { overflow-y: hidden; }
|
213 |
}
|
214 |
|
|
|
|
|
215 |
|
|
|
|
backend/modules/calendar/resources/css/chosen.css
DELETED
@@ -1,437 +0,0 @@
|
|
1 |
-
/*!
|
2 |
-
Chosen, a Select Box Enhancer for jQuery and Prototype
|
3 |
-
by Patrick Filler for Harvest, http://getharvest.com
|
4 |
-
|
5 |
-
Version 1.2.0
|
6 |
-
Full source at https://github.com/harvesthq/chosen
|
7 |
-
Copyright (c) 2011-2014 Harvest http://getharvest.com
|
8 |
-
|
9 |
-
MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
|
10 |
-
This file is generated by `grunt build`, do not edit it by hand.
|
11 |
-
*/
|
12 |
-
|
13 |
-
/* @group Base */
|
14 |
-
.chosen-container {
|
15 |
-
position: relative;
|
16 |
-
display: inline-block;
|
17 |
-
vertical-align: middle;
|
18 |
-
font-size: 13px;
|
19 |
-
zoom: 1;
|
20 |
-
*display: inline;
|
21 |
-
-webkit-user-select: none;
|
22 |
-
-moz-user-select: none;
|
23 |
-
user-select: none;
|
24 |
-
}
|
25 |
-
.chosen-container * {
|
26 |
-
-webkit-box-sizing: border-box;
|
27 |
-
-moz-box-sizing: border-box;
|
28 |
-
box-sizing: border-box;
|
29 |
-
}
|
30 |
-
.chosen-container .chosen-drop {
|
31 |
-
position: absolute;
|
32 |
-
top: 100%;
|
33 |
-
left: -9999px;
|
34 |
-
z-index: 1010;
|
35 |
-
width: 100%;
|
36 |
-
border: 1px solid #aaa;
|
37 |
-
border-top: 0;
|
38 |
-
background: #fff;
|
39 |
-
box-shadow: 0 4px 5px rgba(0, 0, 0, 0.15);
|
40 |
-
}
|
41 |
-
.chosen-container.chosen-with-drop .chosen-drop {
|
42 |
-
left: 0;
|
43 |
-
}
|
44 |
-
.chosen-container a {
|
45 |
-
cursor: pointer;
|
46 |
-
}
|
47 |
-
|
48 |
-
/* @end */
|
49 |
-
/* @group Single Chosen */
|
50 |
-
.chosen-container-single .chosen-single {
|
51 |
-
position: relative;
|
52 |
-
display: block;
|
53 |
-
overflow: hidden;
|
54 |
-
padding: 0 0 0 8px;
|
55 |
-
height: 25px;
|
56 |
-
border: 1px solid #aaa;
|
57 |
-
border-radius: 5px;
|
58 |
-
background-color: #fff;
|
59 |
-
background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4));
|
60 |
-
background: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
|
61 |
-
background: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
|
62 |
-
background: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
|
63 |
-
background: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%);
|
64 |
-
background-clip: padding-box;
|
65 |
-
box-shadow: 0 0 3px white inset, 0 1px 1px rgba(0, 0, 0, 0.1);
|
66 |
-
color: #444;
|
67 |
-
text-decoration: none;
|
68 |
-
white-space: nowrap;
|
69 |
-
line-height: 24px;
|
70 |
-
}
|
71 |
-
.chosen-container-single .chosen-default {
|
72 |
-
color: #999;
|
73 |
-
}
|
74 |
-
.chosen-container-single .chosen-single span {
|
75 |
-
display: block;
|
76 |
-
overflow: hidden;
|
77 |
-
margin-right: 26px;
|
78 |
-
text-overflow: ellipsis;
|
79 |
-
white-space: nowrap;
|
80 |
-
}
|
81 |
-
.chosen-container-single .chosen-single-with-deselect span {
|
82 |
-
margin-right: 38px;
|
83 |
-
}
|
84 |
-
.chosen-container-single .chosen-single abbr {
|
85 |
-
position: absolute;
|
86 |
-
top: 6px;
|
87 |
-
right: 26px;
|
88 |
-
display: block;
|
89 |
-
width: 12px;
|
90 |
-
height: 12px;
|
91 |
-
background: url('chosen-sprite.png') -42px 1px no-repeat;
|
92 |
-
font-size: 1px;
|
93 |
-
}
|
94 |
-
.chosen-container-single .chosen-single abbr:hover {
|
95 |
-
background-position: -42px -10px;
|
96 |
-
}
|
97 |
-
.chosen-container-single.chosen-disabled .chosen-single abbr:hover {
|
98 |
-
background-position: -42px -10px;
|
99 |
-
}
|
100 |
-
.chosen-container-single .chosen-single div {
|
101 |
-
position: absolute;
|
102 |
-
top: 0;
|
103 |
-
right: 0;
|
104 |
-
display: block;
|
105 |
-
width: 18px;
|
106 |
-
height: 100%;
|
107 |
-
}
|
108 |
-
.chosen-container-single .chosen-single div b {
|
109 |
-
display: block;
|
110 |
-
width: 100%;
|
111 |
-
height: 100%;
|
112 |
-
background: url('chosen-sprite.png') no-repeat 0px 2px;
|
113 |
-
}
|
114 |
-
.chosen-container-single .chosen-search {
|
115 |
-
position: relative;
|
116 |
-
z-index: 1010;
|
117 |
-
margin: 0;
|
118 |
-
padding: 3px 4px;
|
119 |
-
white-space: nowrap;
|
120 |
-
}
|
121 |
-
.chosen-container-single .chosen-search input[type="text"] {
|
122 |
-
margin: 1px 0;
|
123 |
-
padding: 4px 20px 4px 5px;
|
124 |
-
width: 100%;
|
125 |
-
height: auto;
|
126 |
-
outline: 0;
|
127 |
-
border: 1px solid #aaa;
|
128 |
-
background: white url('chosen-sprite.png') no-repeat 100% -20px;
|
129 |
-
background: url('chosen-sprite.png') no-repeat 100% -20px;
|
130 |
-
font-size: 1em;
|
131 |
-
font-family: sans-serif;
|
132 |
-
line-height: normal;
|
133 |
-
border-radius: 0;
|
134 |
-
}
|
135 |
-
.chosen-container-single .chosen-drop {
|
136 |
-
margin-top: -1px;
|
137 |
-
border-radius: 0 0 4px 4px;
|
138 |
-
background-clip: padding-box;
|
139 |
-
}
|
140 |
-
.chosen-container-single.chosen-container-single-nosearch .chosen-search {
|
141 |
-
position: absolute;
|
142 |
-
left: -9999px;
|
143 |
-
}
|
144 |
-
|
145 |
-
/* @end */
|
146 |
-
/* @group Results */
|
147 |
-
.chosen-container .chosen-results {
|
148 |
-
color: #444;
|
149 |
-
position: relative;
|
150 |
-
overflow-x: hidden;
|
151 |
-
overflow-y: auto;
|
152 |
-
margin: 0 4px 4px 0;
|
153 |
-
padding: 0 0 0 4px;
|
154 |
-
max-height: 240px;
|
155 |
-
-webkit-overflow-scrolling: touch;
|
156 |
-
}
|
157 |
-
.chosen-container .chosen-results li {
|
158 |
-
display: none;
|
159 |
-
margin: 0;
|
160 |
-
padding: 5px 6px;
|
161 |
-
list-style: none;
|
162 |
-
line-height: 15px;
|
163 |
-
word-wrap: break-word;
|
164 |
-
-webkit-touch-callout: none;
|
165 |
-
}
|
166 |
-
.chosen-container .chosen-results li.active-result {
|
167 |
-
display: list-item;
|
168 |
-
cursor: pointer;
|
169 |
-
}
|
170 |
-
.chosen-container .chosen-results li.disabled-result {
|
171 |
-
display: list-item;
|
172 |
-
color: #ccc;
|
173 |
-
cursor: default;
|
174 |
-
}
|
175 |
-
.chosen-container .chosen-results li.highlighted {
|
176 |
-
background-color: #3875d7;
|
177 |
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc));
|
178 |
-
background-image: -webkit-linear-gradient(#3875d7 20%, #2a62bc 90%);
|
179 |
-
background-image: -moz-linear-gradient(#3875d7 20%, #2a62bc 90%);
|
180 |
-
background-image: -o-linear-gradient(#3875d7 20%, #2a62bc 90%);
|
181 |
-
background-image: linear-gradient(#3875d7 20%, #2a62bc 90%);
|
182 |
-
color: #fff;
|
183 |
-
}
|
184 |
-
.chosen-container .chosen-results li.no-results {
|
185 |
-
color: #777;
|
186 |
-
display: list-item;
|
187 |
-
background: #f4f4f4;
|
188 |
-
}
|
189 |
-
.chosen-container .chosen-results li.group-result {
|
190 |
-
display: list-item;
|
191 |
-
font-weight: bold;
|
192 |
-
cursor: default;
|
193 |
-
}
|
194 |
-
.chosen-container .chosen-results li.group-option {
|
195 |
-
padding-left: 15px;
|
196 |
-
}
|
197 |
-
.chosen-container .chosen-results li em {
|
198 |
-
font-style: normal;
|
199 |
-
text-decoration: underline;
|
200 |
-
}
|
201 |
-
|
202 |
-
/* @end */
|
203 |
-
/* @group Multi Chosen */
|
204 |
-
.chosen-container-multi .chosen-choices {
|
205 |
-
position: relative;
|
206 |
-
overflow: hidden;
|
207 |
-
margin: 0;
|
208 |
-
padding: 0 5px;
|
209 |
-
width: 100%;
|
210 |
-
height: auto !important;
|
211 |
-
height: 1%;
|
212 |
-
border: 1px solid #aaa;
|
213 |
-
background-color: #fff;
|
214 |
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff));
|
215 |
-
background-image: -webkit-linear-gradient(#eeeeee 1%, #ffffff 15%);
|
216 |
-
background-image: -moz-linear-gradient(#eeeeee 1%, #ffffff 15%);
|
217 |
-
background-image: -o-linear-gradient(#eeeeee 1%, #ffffff 15%);
|
218 |
-
background-image: linear-gradient(#eeeeee 1%, #ffffff 15%);
|
219 |
-
cursor: text;
|
220 |
-
}
|
221 |
-
.chosen-container-multi .chosen-choices li {
|
222 |
-
float: left;
|
223 |
-
list-style: none;
|
224 |
-
}
|
225 |
-
.chosen-container-multi .chosen-choices li.search-field {
|
226 |
-
margin: 0;
|
227 |
-
padding: 0;
|
228 |
-
white-space: nowrap;
|
229 |
-
}
|
230 |
-
.chosen-container-multi .chosen-choices li.search-field input[type="text"] {
|
231 |
-
margin: 1px 0;
|
232 |
-
padding: 0;
|
233 |
-
height: 25px;
|
234 |
-
outline: 0;
|
235 |
-
border: 0 !important;
|
236 |
-
background: transparent !important;
|
237 |
-
box-shadow: none;
|
238 |
-
color: #999;
|
239 |
-
font-size: 100%;
|
240 |
-
font-family: sans-serif;
|
241 |
-
line-height: normal;
|
242 |
-
border-radius: 0;
|
243 |
-
}
|
244 |
-
.chosen-container-multi .chosen-choices li.search-choice {
|
245 |
-
position: relative;
|
246 |
-
margin: 3px 5px 3px 0;
|
247 |
-
padding: 3px 20px 3px 5px;
|
248 |
-
border: 1px solid #aaa;
|
249 |
-
max-width: 100%;
|
250 |
-
border-radius: 3px;
|
251 |
-
background-color: #eeeeee;
|
252 |
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
|
253 |
-
background-image: -webkit-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
254 |
-
background-image: -moz-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
255 |
-
background-image: -o-linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
256 |
-
background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
257 |
-
background-size: 100% 19px;
|
258 |
-
background-repeat: repeat-x;
|
259 |
-
background-clip: padding-box;
|
260 |
-
box-shadow: 0 0 2px white inset, 0 1px 0 rgba(0, 0, 0, 0.05);
|
261 |
-
color: #333;
|
262 |
-
line-height: 13px;
|
263 |
-
cursor: default;
|
264 |
-
}
|
265 |
-
.chosen-container-multi .chosen-choices li.search-choice span {
|
266 |
-
word-wrap: break-word;
|
267 |
-
}
|
268 |
-
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close {
|
269 |
-
position: absolute;
|
270 |
-
top: 4px;
|
271 |
-
right: 3px;
|
272 |
-
display: block;
|
273 |
-
width: 12px;
|
274 |
-
height: 12px;
|
275 |
-
background: url('chosen-sprite.png') -42px 1px no-repeat;
|
276 |
-
font-size: 1px;
|
277 |
-
}
|
278 |
-
.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:hover {
|
279 |
-
background-position: -42px -10px;
|
280 |
-
}
|
281 |
-
.chosen-container-multi .chosen-choices li.search-choice-disabled {
|
282 |
-
padding-right: 5px;
|
283 |
-
border: 1px solid #ccc;
|
284 |
-
background-color: #e4e4e4;
|
285 |
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee));
|
286 |
-
background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
287 |
-
background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
288 |
-
background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
289 |
-
background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%);
|
290 |
-
color: #666;
|
291 |
-
}
|
292 |
-
.chosen-container-multi .chosen-choices li.search-choice-focus {
|
293 |
-
background: #d4d4d4;
|
294 |
-
}
|
295 |
-
.chosen-container-multi .chosen-choices li.search-choice-focus .search-choice-close {
|
296 |
-
background-position: -42px -10px;
|
297 |
-
}
|
298 |
-
.chosen-container-multi .chosen-results {
|
299 |
-
margin: 0;
|
300 |
-
padding: 0;
|
301 |
-
}
|
302 |
-
.chosen-container-multi .chosen-drop .result-selected {
|
303 |
-
display: list-item;
|
304 |
-
color: #ccc;
|
305 |
-
cursor: default;
|
306 |
-
}
|
307 |
-
|
308 |
-
/* @end */
|
309 |
-
/* @group Active */
|
310 |
-
.chosen-container-active .chosen-single {
|
311 |
-
border: 1px solid #5897fb;
|
312 |
-
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
313 |
-
}
|
314 |
-
.chosen-container-active.chosen-with-drop .chosen-single {
|
315 |
-
border: 1px solid #aaa;
|
316 |
-
-moz-border-radius-bottomright: 0;
|
317 |
-
border-bottom-right-radius: 0;
|
318 |
-
-moz-border-radius-bottomleft: 0;
|
319 |
-
border-bottom-left-radius: 0;
|
320 |
-
background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff));
|
321 |
-
background-image: -webkit-linear-gradient(#eeeeee 20%, #ffffff 80%);
|
322 |
-
background-image: -moz-linear-gradient(#eeeeee 20%, #ffffff 80%);
|
323 |
-
background-image: -o-linear-gradient(#eeeeee 20%, #ffffff 80%);
|
324 |
-
background-image: linear-gradient(#eeeeee 20%, #ffffff 80%);
|
325 |
-
box-shadow: 0 1px 0 #fff inset;
|
326 |
-
}
|
327 |
-
.chosen-container-active.chosen-with-drop .chosen-single div {
|
328 |
-
border-left: none;
|
329 |
-
background: transparent;
|
330 |
-
}
|
331 |
-
.chosen-container-active.chosen-with-drop .chosen-single div b {
|
332 |
-
background-position: -18px 2px;
|
333 |
-
}
|
334 |
-
.chosen-container-active .chosen-choices {
|
335 |
-
border: 1px solid #5897fb;
|
336 |
-
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
337 |
-
}
|
338 |
-
.chosen-container-active .chosen-choices li.search-field input[type="text"] {
|
339 |
-
color: #222 !important;
|
340 |
-
}
|
341 |
-
|
342 |
-
/* @end */
|
343 |
-
/* @group Disabled Support */
|
344 |
-
.chosen-disabled {
|
345 |
-
opacity: 0.5 !important;
|
346 |
-
cursor: default;
|
347 |
-
}
|
348 |
-
.chosen-disabled .chosen-single {
|
349 |
-
cursor: default;
|
350 |
-
}
|
351 |
-
.chosen-disabled .chosen-choices .search-choice .search-choice-close {
|
352 |
-
cursor: default;
|
353 |
-
}
|
354 |
-
|
355 |
-
/* @end */
|
356 |
-
/* @group Right to Left */
|
357 |
-
.chosen-rtl {
|
358 |
-
text-align: right;
|
359 |
-
}
|
360 |
-
.chosen-rtl .chosen-single {
|
361 |
-
overflow: visible;
|
362 |
-
padding: 0 8px 0 0;
|
363 |
-
}
|
364 |
-
.chosen-rtl .chosen-single span {
|
365 |
-
margin-right: 0;
|
366 |
-
margin-left: 26px;
|
367 |
-
direction: rtl;
|
368 |
-
}
|
369 |
-
.chosen-rtl .chosen-single-with-deselect span {
|
370 |
-
margin-left: 38px;
|
371 |
-
}
|
372 |
-
.chosen-rtl .chosen-single div {
|
373 |
-
right: auto;
|
374 |
-
left: 3px;
|
375 |
-
}
|
376 |
-
.chosen-rtl .chosen-single abbr {
|
377 |
-
right: auto;
|
378 |
-
left: 26px;
|
379 |
-
}
|
380 |
-
.chosen-rtl .chosen-choices li {
|
381 |
-
float: right;
|
382 |
-
}
|
383 |
-
.chosen-rtl .chosen-choices li.search-field input[type="text"] {
|
384 |
-
direction: rtl;
|
385 |
-
}
|
386 |
-
.chosen-rtl .chosen-choices li.search-choice {
|
387 |
-
margin: 3px 5px 3px 0;
|
388 |
-
padding: 3px 5px 3px 19px;
|
389 |
-
}
|
390 |
-
.chosen-rtl .chosen-choices li.search-choice .search-choice-close {
|
391 |
-
right: auto;
|
392 |
-
left: 4px;
|
393 |
-
}
|
394 |
-
.chosen-rtl.chosen-container-single-nosearch .chosen-search,
|
395 |
-
.chosen-rtl .chosen-drop {
|
396 |
-
left: 9999px;
|
397 |
-
}
|
398 |
-
.chosen-rtl.chosen-container-single .chosen-results {
|
399 |
-
margin: 0 0 4px 4px;
|
400 |
-
padding: 0 4px 0 0;
|
401 |
-
}
|
402 |
-
.chosen-rtl .chosen-results li.group-option {
|
403 |
-
padding-right: 15px;
|
404 |
-
padding-left: 0;
|
405 |
-
}
|
406 |
-
.chosen-rtl.chosen-container-active.chosen-with-drop .chosen-single div {
|
407 |
-
border-right: none;
|
408 |
-
}
|
409 |
-
.chosen-rtl .chosen-search input[type="text"] {
|
410 |
-
padding: 4px 5px 4px 20px;
|
411 |
-
background: white url('chosen-sprite.png') no-repeat -30px -20px;
|
412 |
-
background: url('chosen-sprite.png') no-repeat -30px -20px;
|
413 |
-
direction: rtl;
|
414 |
-
}
|
415 |
-
.chosen-rtl.chosen-container-single .chosen-single div b {
|
416 |
-
background-position: 6px 2px;
|
417 |
-
}
|
418 |
-
.chosen-rtl.chosen-container-single.chosen-with-drop .chosen-single div b {
|
419 |
-
background-position: -12px 2px;
|
420 |
-
}
|
421 |
-
|
422 |
-
/* @end */
|
423 |
-
/* @group Retina compatibility */
|
424 |
-
@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-resolution: 144dpi) {
|
425 |
-
.chosen-rtl .chosen-search input[type="text"],
|
426 |
-
.chosen-container-single .chosen-single abbr,
|
427 |
-
.chosen-container-single .chosen-single div b,
|
428 |
-
.chosen-container-single .chosen-search input[type="text"],
|
429 |
-
.chosen-container-multi .chosen-choices .search-choice .search-choice-close,
|
430 |
-
.chosen-container .chosen-results-scroll-down span,
|
431 |
-
.chosen-container .chosen-results-scroll-up span {
|
432 |
-
background-image: url('chosen-sprite@2x.png') !important;
|
433 |
-
background-size: 52px 37px !important;
|
434 |
-
background-repeat: no-repeat !important;
|
435 |
-
}
|
436 |
-
}
|
437 |
-
/* @end */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/css/fullcalendar.min.css
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* FullCalendar v2.3.2 Stylesheet
|
3 |
+
* Docs & License: http://fullcalendar.io/
|
4 |
+
* (c) 2015 Adam Shaw
|
5 |
+
*/.fc{direction:ltr;text-align:left}.fc-rtl{text-align:right}body .fc{font-size:1em}.fc-unthemed .fc-divider,.fc-unthemed .fc-popover,.fc-unthemed .fc-row,.fc-unthemed tbody,.fc-unthemed td,.fc-unthemed th,.fc-unthemed thead{border-color:#ddd}.fc-unthemed .fc-popover{background-color:#fff}.fc-unthemed .fc-divider,.fc-unthemed .fc-popover .fc-header{background:#eee}.fc-unthemed .fc-popover .fc-header .fc-close{color:#666}.fc-unthemed .fc-today{background:#fcf8e3}.fc-highlight{background:#bce8f1;opacity:.3;filter:alpha(opacity=30)}.fc-bgevent{background:#8fdf82;opacity:.3;filter:alpha(opacity=30)}.fc-nonbusiness{background:#d7d7d7}.fc-icon{display:inline-block;width:1em;height:1em;line-height:1em;font-size:1em;text-align:center;overflow:hidden;font-family:"Courier New",Courier,monospace;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fc-icon:after{position:relative;margin:0 -1em}.fc-icon-left-single-arrow:after{content:"\02039";font-weight:700;font-size:200%;top:-7%;left:3%}.fc-icon-right-single-arrow:after{content:"\0203A";font-weight:700;font-size:200%;top:-7%;left:-3%}.fc-icon-left-double-arrow:after{content:"\000AB";font-size:160%;top:-7%}.fc-icon-right-double-arrow:after{content:"\000BB";font-size:160%;top:-7%}.fc-icon-left-triangle:after{content:"\25C4";font-size:125%;top:3%;left:-2%}.fc-icon-right-triangle:after{content:"\25BA";font-size:125%;top:3%;left:2%}.fc-icon-down-triangle:after{content:"\25BC";font-size:125%;top:2%}.fc-icon-x:after{content:"\000D7";font-size:200%;top:6%}.fc button{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;height:2.1em;padding:0 .6em;font-size:1em;white-space:nowrap;cursor:pointer}.fc button::-moz-focus-inner{margin:0;padding:0}.fc-state-default{border:1px solid}.fc-state-default.fc-corner-left{border-top-left-radius:4px;border-bottom-left-radius:4px}.fc-state-default.fc-corner-right{border-top-right-radius:4px;border-bottom-right-radius:4px}.fc button .fc-icon{position:relative;top:-.05em;margin:0 .2em;vertical-align:middle}.fc-state-default{background-color:#f5f5f5;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,.1) rgba(0,0,0,.1) rgba(0,0,0,.25);color:#333;text-shadow:0 1px 1px rgba(255,255,255,.75);box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05)}.fc-state-active,.fc-state-disabled,.fc-state-down,.fc-state-hover{color:#333;background-color:#e6e6e6}.fc-state-hover{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.fc-state-active,.fc-state-down{background-color:#ccc;background-image:none;box-shadow:inset 0 2px 4px rgba(0,0,0,.15),0 1px 2px rgba(0,0,0,.05)}.fc-state-disabled{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);box-shadow:none}.fc-button-group{display:inline-block}.fc .fc-button-group>*{float:left;margin:0 0 0 -1px}.fc .fc-button-group>:first-child{margin-left:0}.fc-popover{position:absolute;box-shadow:0 2px 6px rgba(0,0,0,.15)}.fc-popover .fc-header{padding:2px 4px}.fc-popover .fc-header .fc-title{margin:0 2px}.fc-popover .fc-header .fc-close{cursor:pointer}.fc-ltr .fc-popover .fc-header .fc-title,.fc-rtl .fc-popover .fc-header .fc-close{float:left}.fc-ltr .fc-popover .fc-header .fc-close,.fc-rtl .fc-popover .fc-header .fc-title{float:right}.fc-unthemed .fc-popover{border-width:1px;border-style:solid}.fc-unthemed .fc-popover .fc-header .fc-close{font-size:.9em;margin-top:2px}.fc-popover>.ui-widget-header+.ui-widget-content{border-top:0}.fc-divider{border-style:solid;border-width:1px}hr.fc-divider{height:0;margin:0;padding:0 0 2px;border-width:1px 0}.fc-clear{clear:both}.fc-bg,.fc-bgevent-skeleton,.fc-helper-skeleton,.fc-highlight-skeleton{position:absolute;top:0;left:0;right:0}.fc-bg{bottom:0}.fc-bg table{height:100%}.fc table{width:100%;table-layout:fixed;border-collapse:collapse;border-spacing:0;font-size:1em}.fc th{text-align:center}.fc td,.fc th{border-style:solid;border-width:1px;padding:0;vertical-align:top}.fc td.fc-today{border-style:double}.fc .fc-row{border-style:solid;border-width:0}.fc-row table{border-left:0 hidden transparent;border-right:0 hidden transparent;border-bottom:0 hidden transparent}.fc-row:first-child table{border-top:0 hidden transparent}.fc-row{position:relative}.fc-row .fc-bg{z-index:1}.fc-row .fc-bgevent-skeleton,.fc-row .fc-highlight-skeleton{bottom:0}.fc-row .fc-bgevent-skeleton table,.fc-row .fc-highlight-skeleton table{height:100%}.fc-row .fc-bgevent-skeleton td,.fc-row .fc-highlight-skeleton td{border-color:transparent}.fc-row .fc-bgevent-skeleton{z-index:2}.fc-row .fc-highlight-skeleton{z-index:3}.fc-row .fc-content-skeleton{position:relative;z-index:4;padding-bottom:2px}.fc-row .fc-helper-skeleton{z-index:5}.fc-row .fc-content-skeleton td,.fc-row .fc-helper-skeleton td{background:0 0;border-color:transparent;border-bottom:0}.fc-row .fc-content-skeleton tbody td,.fc-row .fc-helper-skeleton tbody td{border-top:0}.fc-scroller{overflow-y:scroll;overflow-x:hidden}.fc-scroller>*{position:relative;width:100%;overflow:hidden}.fc-event{position:relative;display:block;font-size:.85em;line-height:1.3;border-radius:3px;border:1px solid #3a87ad;background-color:#3a87ad;font-weight:400}.fc-event,.fc-event:hover,.ui-widget .fc-event{color:#fff;text-decoration:none}.fc-event.fc-draggable,.fc-event[href]{cursor:pointer}.fc-not-allowed,.fc-not-allowed .fc-event{cursor:not-allowed}.fc-event .fc-bg{z-index:1;background:#fff;opacity:.25;filter:alpha(opacity=25)}.fc-event .fc-content{position:relative;z-index:2}.fc-event .fc-resizer{position:absolute;z-index:3}.fc-ltr .fc-h-event.fc-not-start,.fc-rtl .fc-h-event.fc-not-end{margin-left:0;border-left-width:0;padding-left:1px;border-top-left-radius:0;border-bottom-left-radius:0}.fc-ltr .fc-h-event.fc-not-end,.fc-rtl .fc-h-event.fc-not-start{margin-right:0;border-right-width:0;padding-right:1px;border-top-right-radius:0;border-bottom-right-radius:0}.fc-h-event .fc-resizer{top:-1px;bottom:-1px;left:-1px;right:-1px;width:5px}.fc-ltr .fc-h-event .fc-start-resizer,.fc-ltr .fc-h-event .fc-start-resizer:after,.fc-ltr .fc-h-event .fc-start-resizer:before,.fc-rtl .fc-h-event .fc-end-resizer,.fc-rtl .fc-h-event .fc-end-resizer:after,.fc-rtl .fc-h-event .fc-end-resizer:before{right:auto;cursor:w-resize}.fc-ltr .fc-h-event .fc-end-resizer,.fc-ltr .fc-h-event .fc-end-resizer:after,.fc-ltr .fc-h-event .fc-end-resizer:before,.fc-rtl .fc-h-event .fc-start-resizer,.fc-rtl .fc-h-event .fc-start-resizer:after,.fc-rtl .fc-h-event .fc-start-resizer:before{left:auto;cursor:e-resize}.fc-day-grid-event{margin:1px 2px 0;padding:0 1px}.fc-day-grid-event .fc-content{white-space:nowrap;overflow:hidden}.fc-day-grid-event .fc-time{font-weight:700}.fc-day-grid-event .fc-resizer{left:-3px;right:-3px;width:7px}a.fc-more{margin:1px 3px;font-size:.85em;cursor:pointer;text-decoration:none}a.fc-more:hover{text-decoration:underline}.fc-limited{display:none}.fc-day-grid .fc-row{z-index:1}.fc-more-popover{z-index:2;width:220px}.fc-more-popover .fc-event-container{padding:10px}.fc-toolbar{text-align:center;margin-bottom:1em}.fc-toolbar .fc-left{float:left}.fc-toolbar .fc-right{float:right}.fc-toolbar .fc-center{display:inline-block}.fc .fc-toolbar>*>*{float:left;margin-left:.75em}.fc .fc-toolbar>*>:first-child{margin-left:0}.fc-toolbar h2{margin:0}.fc-toolbar button{position:relative}.fc-toolbar .fc-state-hover,.fc-toolbar .ui-state-hover{z-index:2}.fc-toolbar .fc-state-down{z-index:3}.fc-toolbar .fc-state-active,.fc-toolbar .ui-state-active{z-index:4}.fc-toolbar button:focus{z-index:5}.fc-view-container *,.fc-view-container :after,.fc-view-container :before{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.fc-view,.fc-view>table{position:relative;z-index:1}.fc-basicDay-view .fc-content-skeleton,.fc-basicWeek-view .fc-content-skeleton{padding-top:1px;padding-bottom:1em}.fc-basic-view .fc-body .fc-row{min-height:4em}.fc-row.fc-rigid{overflow:hidden}.fc-row.fc-rigid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-basic-view .fc-day-number,.fc-basic-view .fc-week-number{padding:0 2px}.fc-basic-view td.fc-day-number,.fc-basic-view td.fc-week-number span{padding-top:2px;padding-bottom:2px}.fc-basic-view .fc-week-number{text-align:center}.fc-basic-view .fc-week-number span{display:inline-block;min-width:1.25em}.fc-ltr .fc-basic-view .fc-day-number{text-align:right}.fc-rtl .fc-basic-view .fc-day-number{text-align:left}.fc-day-number.fc-other-month{opacity:.3;filter:alpha(opacity=30)}.fc-agenda-view .fc-day-grid{position:relative;z-index:2}.fc-agenda-view .fc-day-grid .fc-row{min-height:3em}.fc-agenda-view .fc-day-grid .fc-row .fc-content-skeleton{padding-top:1px;padding-bottom:1em}.fc .fc-axis{vertical-align:middle;padding:0 4px;white-space:nowrap}.fc-ltr .fc-axis{text-align:right}.fc-rtl .fc-axis{text-align:left}.ui-widget td.fc-axis{font-weight:400}.fc-time-grid,.fc-time-grid-container{position:relative;z-index:1}.fc-time-grid{min-height:100%}.fc-time-grid table{border:0 hidden transparent}.fc-time-grid>.fc-bg{z-index:1}.fc-time-grid .fc-slats,.fc-time-grid>hr{position:relative;z-index:2}.fc-time-grid .fc-bgevent-skeleton,.fc-time-grid .fc-content-skeleton{position:absolute;top:0;left:0;right:0}.fc-time-grid .fc-bgevent-skeleton{z-index:3}.fc-time-grid .fc-highlight-skeleton{z-index:4}.fc-time-grid .fc-content-skeleton{z-index:5}.fc-time-grid .fc-helper-skeleton{z-index:6}.fc-time-grid .fc-slats td{height:1.5em;border-bottom:0}.fc-time-grid .fc-slats .fc-minor td{border-top-style:dotted}.fc-time-grid .fc-slats .ui-widget-content{background:0 0}.fc-time-grid .fc-highlight-container{position:relative}.fc-time-grid .fc-highlight{position:absolute;left:0;right:0}.fc-time-grid .fc-bgevent-container,.fc-time-grid .fc-event-container{position:relative}.fc-ltr .fc-time-grid .fc-event-container{margin:0 2.5% 0 2px}.fc-rtl .fc-time-grid .fc-event-container{margin:0 2px 0 2.5%}.fc-time-grid .fc-bgevent,.fc-time-grid .fc-event{position:absolute;z-index:1}.fc-time-grid .fc-bgevent{left:0;right:0}.fc-v-event.fc-not-start{border-top-width:0;padding-top:1px;border-top-left-radius:0;border-top-right-radius:0}.fc-v-event.fc-not-end{border-bottom-width:0;padding-bottom:1px;border-bottom-left-radius:0;border-bottom-right-radius:0}.fc-time-grid-event{overflow:hidden}.fc-time-grid-event .fc-time,.fc-time-grid-event .fc-title{padding:0 1px}.fc-time-grid-event .fc-time{font-size:.85em;white-space:nowrap}.fc-time-grid-event.fc-short .fc-content{white-space:nowrap}.fc-time-grid-event.fc-short .fc-time,.fc-time-grid-event.fc-short .fc-title{display:inline-block;vertical-align:top}.fc-time-grid-event.fc-short .fc-time span{display:none}.fc-time-grid-event.fc-short .fc-time:before{content:attr(data-start)}.fc-time-grid-event.fc-short .fc-time:after{content:"\000A0-\000A0"}.fc-time-grid-event.fc-short .fc-title{font-size:.85em;padding:0}.fc-time-grid-event .fc-resizer{left:0;right:0;bottom:0;height:8px;overflow:hidden;line-height:8px;font-size:11px;font-family:monospace;text-align:center;cursor:s-resize}.fc-time-grid-event .fc-resizer:after{content:"="}
|
backend/modules/calendar/resources/css/jquery-ui-1.10.1.css
DELETED
@@ -1,1174 +0,0 @@
|
|
1 |
-
/*! jQuery UI - v1.10.1 - 2013-02-15
|
2 |
-
* http://jqueryui.com
|
3 |
-
* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css
|
4 |
-
* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */
|
5 |
-
|
6 |
-
/* Layout helpers
|
7 |
-
----------------------------------*/
|
8 |
-
.ui-helper-hidden {
|
9 |
-
display: none;
|
10 |
-
}
|
11 |
-
.ui-helper-hidden-accessible {
|
12 |
-
border: 0;
|
13 |
-
clip: rect(0 0 0 0);
|
14 |
-
height: 1px;
|
15 |
-
margin: -1px;
|
16 |
-
overflow: hidden;
|
17 |
-
padding: 0;
|
18 |
-
position: absolute;
|
19 |
-
width: 1px;
|
20 |
-
}
|
21 |
-
.ui-helper-reset {
|
22 |
-
margin: 0;
|
23 |
-
padding: 0;
|
24 |
-
border: 0;
|
25 |
-
outline: 0;
|
26 |
-
line-height: 1.3;
|
27 |
-
text-decoration: none;
|
28 |
-
font-size: 100%;
|
29 |
-
list-style: none;
|
30 |
-
}
|
31 |
-
.ui-helper-clearfix:before,
|
32 |
-
.ui-helper-clearfix:after {
|
33 |
-
content: "";
|
34 |
-
display: table;
|
35 |
-
border-collapse: collapse;
|
36 |
-
}
|
37 |
-
.ui-helper-clearfix:after {
|
38 |
-
clear: both;
|
39 |
-
}
|
40 |
-
.ui-helper-clearfix {
|
41 |
-
min-height: 0; /* support: IE7 */
|
42 |
-
}
|
43 |
-
.ui-helper-zfix {
|
44 |
-
width: 100%;
|
45 |
-
height: 100%;
|
46 |
-
top: 0;
|
47 |
-
left: 0;
|
48 |
-
position: absolute;
|
49 |
-
opacity: 0;
|
50 |
-
filter:Alpha(Opacity=0);
|
51 |
-
}
|
52 |
-
|
53 |
-
.ui-front {
|
54 |
-
z-index: 100;
|
55 |
-
}
|
56 |
-
|
57 |
-
|
58 |
-
/* Interaction Cues
|
59 |
-
----------------------------------*/
|
60 |
-
.ui-state-disabled {
|
61 |
-
cursor: default !important;
|
62 |
-
}
|
63 |
-
|
64 |
-
|
65 |
-
/* Icons
|
66 |
-
----------------------------------*/
|
67 |
-
|
68 |
-
/* states and images */
|
69 |
-
.ui-icon {
|
70 |
-
display: block;
|
71 |
-
text-indent: -99999px;
|
72 |
-
overflow: hidden;
|
73 |
-
background-repeat: no-repeat;
|
74 |
-
}
|
75 |
-
|
76 |
-
|
77 |
-
/* Misc visuals
|
78 |
-
----------------------------------*/
|
79 |
-
|
80 |
-
/* Overlays */
|
81 |
-
.ui-widget-overlay {
|
82 |
-
position: fixed;
|
83 |
-
top: 0;
|
84 |
-
left: 0;
|
85 |
-
width: 100%;
|
86 |
-
height: 100%;
|
87 |
-
}
|
88 |
-
.ui-accordion .ui-accordion-header {
|
89 |
-
display: block;
|
90 |
-
cursor: pointer;
|
91 |
-
position: relative;
|
92 |
-
margin-top: 2px;
|
93 |
-
padding: .5em .5em .5em .7em;
|
94 |
-
min-height: 0; /* support: IE7 */
|
95 |
-
}
|
96 |
-
.ui-accordion .ui-accordion-icons {
|
97 |
-
padding-left: 2.2em;
|
98 |
-
}
|
99 |
-
.ui-accordion .ui-accordion-noicons {
|
100 |
-
padding-left: .7em;
|
101 |
-
}
|
102 |
-
.ui-accordion .ui-accordion-icons .ui-accordion-icons {
|
103 |
-
padding-left: 2.2em;
|
104 |
-
}
|
105 |
-
.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
|
106 |
-
position: absolute;
|
107 |
-
left: .5em;
|
108 |
-
top: 50%;
|
109 |
-
margin-top: -8px;
|
110 |
-
}
|
111 |
-
.ui-accordion .ui-accordion-content {
|
112 |
-
padding: 1em 2.2em;
|
113 |
-
border-top: 0;
|
114 |
-
overflow: auto;
|
115 |
-
}
|
116 |
-
.ui-autocomplete {
|
117 |
-
position: absolute;
|
118 |
-
top: 0;
|
119 |
-
left: 0;
|
120 |
-
cursor: default;
|
121 |
-
}
|
122 |
-
.ui-button {
|
123 |
-
display: inline-block;
|
124 |
-
position: relative;
|
125 |
-
padding: 0;
|
126 |
-
line-height: normal;
|
127 |
-
margin-right: .1em;
|
128 |
-
cursor: pointer;
|
129 |
-
vertical-align: middle;
|
130 |
-
text-align: center;
|
131 |
-
overflow: visible; /* removes extra width in IE */
|
132 |
-
}
|
133 |
-
.ui-button,
|
134 |
-
.ui-button:link,
|
135 |
-
.ui-button:visited,
|
136 |
-
.ui-button:hover,
|
137 |
-
.ui-button:active {
|
138 |
-
text-decoration: none;
|
139 |
-
}
|
140 |
-
/* to make room for the icon, a width needs to be set here */
|
141 |
-
.ui-button-icon-only {
|
142 |
-
width: 2.2em;
|
143 |
-
}
|
144 |
-
/* button elements seem to need a little more width */
|
145 |
-
button.ui-button-icon-only {
|
146 |
-
width: 2.4em;
|
147 |
-
}
|
148 |
-
.ui-button-icons-only {
|
149 |
-
width: 3.4em;
|
150 |
-
}
|
151 |
-
button.ui-button-icons-only {
|
152 |
-
width: 3.7em;
|
153 |
-
}
|
154 |
-
|
155 |
-
/* button text element */
|
156 |
-
.ui-button .ui-button-text {
|
157 |
-
display: block;
|
158 |
-
line-height: normal;
|
159 |
-
}
|
160 |
-
.ui-button-text-only .ui-button-text {
|
161 |
-
padding: .4em 1em;
|
162 |
-
}
|
163 |
-
.ui-button-icon-only .ui-button-text,
|
164 |
-
.ui-button-icons-only .ui-button-text {
|
165 |
-
padding: .4em;
|
166 |
-
text-indent: -9999999px;
|
167 |
-
}
|
168 |
-
.ui-button-text-icon-primary .ui-button-text,
|
169 |
-
.ui-button-text-icons .ui-button-text {
|
170 |
-
padding: .4em 1em .4em 2.1em;
|
171 |
-
}
|
172 |
-
.ui-button-text-icon-secondary .ui-button-text,
|
173 |
-
.ui-button-text-icons .ui-button-text {
|
174 |
-
padding: .4em 2.1em .4em 1em;
|
175 |
-
}
|
176 |
-
.ui-button-text-icons .ui-button-text {
|
177 |
-
padding-left: 2.1em;
|
178 |
-
padding-right: 2.1em;
|
179 |
-
}
|
180 |
-
/* no icon support for input elements, provide padding by default */
|
181 |
-
input.ui-button {
|
182 |
-
padding: .4em 1em;
|
183 |
-
}
|
184 |
-
|
185 |
-
/* button icon element(s) */
|
186 |
-
.ui-button-icon-only .ui-icon,
|
187 |
-
.ui-button-text-icon-primary .ui-icon,
|
188 |
-
.ui-button-text-icon-secondary .ui-icon,
|
189 |
-
.ui-button-text-icons .ui-icon,
|
190 |
-
.ui-button-icons-only .ui-icon {
|
191 |
-
position: absolute;
|
192 |
-
top: 50%;
|
193 |
-
margin-top: -8px;
|
194 |
-
}
|
195 |
-
.ui-button-icon-only .ui-icon {
|
196 |
-
left: 50%;
|
197 |
-
margin-left: -8px;
|
198 |
-
}
|
199 |
-
.ui-button-text-icon-primary .ui-button-icon-primary,
|
200 |
-
.ui-button-text-icons .ui-button-icon-primary,
|
201 |
-
.ui-button-icons-only .ui-button-icon-primary {
|
202 |
-
left: .5em;
|
203 |
-
}
|
204 |
-
.ui-button-text-icon-secondary .ui-button-icon-secondary,
|
205 |
-
.ui-button-text-icons .ui-button-icon-secondary,
|
206 |
-
.ui-button-icons-only .ui-button-icon-secondary {
|
207 |
-
right: .5em;
|
208 |
-
}
|
209 |
-
|
210 |
-
/* button sets */
|
211 |
-
.ui-buttonset {
|
212 |
-
margin-right: 7px;
|
213 |
-
}
|
214 |
-
.ui-buttonset .ui-button {
|
215 |
-
margin-left: 0;
|
216 |
-
margin-right: -.3em;
|
217 |
-
}
|
218 |
-
|
219 |
-
/* workarounds */
|
220 |
-
/* reset extra padding in Firefox, see h5bp.com/l */
|
221 |
-
input.ui-button::-moz-focus-inner,
|
222 |
-
button.ui-button::-moz-focus-inner {
|
223 |
-
border: 0;
|
224 |
-
padding: 0;
|
225 |
-
}
|
226 |
-
.ui-datepicker {
|
227 |
-
width: 17em;
|
228 |
-
padding: .2em .2em 0;
|
229 |
-
display: none;
|
230 |
-
}
|
231 |
-
.ui-datepicker .ui-datepicker-header {
|
232 |
-
position: relative;
|
233 |
-
padding: .2em 0;
|
234 |
-
}
|
235 |
-
.ui-datepicker .ui-datepicker-prev,
|
236 |
-
.ui-datepicker .ui-datepicker-next {
|
237 |
-
position: absolute;
|
238 |
-
top: 2px;
|
239 |
-
width: 1.8em;
|
240 |
-
height: 1.8em;
|
241 |
-
}
|
242 |
-
.ui-datepicker .ui-datepicker-prev-hover,
|
243 |
-
.ui-datepicker .ui-datepicker-next-hover {
|
244 |
-
top: 1px;
|
245 |
-
}
|
246 |
-
.ui-datepicker .ui-datepicker-prev {
|
247 |
-
left: 2px;
|
248 |
-
}
|
249 |
-
.ui-datepicker .ui-datepicker-next {
|
250 |
-
right: 2px;
|
251 |
-
}
|
252 |
-
.ui-datepicker .ui-datepicker-prev-hover {
|
253 |
-
left: 1px;
|
254 |
-
}
|
255 |
-
.ui-datepicker .ui-datepicker-next-hover {
|
256 |
-
right: 1px;
|
257 |
-
}
|
258 |
-
.ui-datepicker .ui-datepicker-prev span,
|
259 |
-
.ui-datepicker .ui-datepicker-next span {
|
260 |
-
display: block;
|
261 |
-
position: absolute;
|
262 |
-
left: 50%;
|
263 |
-
margin-left: -8px;
|
264 |
-
top: 50%;
|
265 |
-
margin-top: -8px;
|
266 |
-
}
|
267 |
-
.ui-datepicker .ui-datepicker-title {
|
268 |
-
margin: 0 2.3em;
|
269 |
-
line-height: 1.8em;
|
270 |
-
text-align: center;
|
271 |
-
}
|
272 |
-
.ui-datepicker .ui-datepicker-title select {
|
273 |
-
font-size: 1em;
|
274 |
-
margin: 1px 0;
|
275 |
-
}
|
276 |
-
.ui-datepicker select.ui-datepicker-month-year {
|
277 |
-
width: 100%;
|
278 |
-
}
|
279 |
-
.ui-datepicker select.ui-datepicker-month,
|
280 |
-
.ui-datepicker select.ui-datepicker-year {
|
281 |
-
width: 49%;
|
282 |
-
}
|
283 |
-
.ui-datepicker table {
|
284 |
-
width: 100%;
|
285 |
-
font-size: .9em;
|
286 |
-
border-collapse: collapse;
|
287 |
-
margin: 0 0 .4em;
|
288 |
-
}
|
289 |
-
.ui-datepicker th {
|
290 |
-
padding: .7em .3em;
|
291 |
-
text-align: center;
|
292 |
-
font-weight: bold;
|
293 |
-
border: 0;
|
294 |
-
}
|
295 |
-
.ui-datepicker td {
|
296 |
-
border: 0;
|
297 |
-
padding: 1px;
|
298 |
-
}
|
299 |
-
.ui-datepicker td span,
|
300 |
-
.ui-datepicker td a {
|
301 |
-
display: block;
|
302 |
-
padding: .2em;
|
303 |
-
text-align: right;
|
304 |
-
text-decoration: none;
|
305 |
-
}
|
306 |
-
.ui-datepicker .ui-datepicker-buttonpane {
|
307 |
-
background-image: none;
|
308 |
-
margin: .7em 0 0 0;
|
309 |
-
padding: 0 .2em;
|
310 |
-
border-left: 0;
|
311 |
-
border-right: 0;
|
312 |
-
border-bottom: 0;
|
313 |
-
}
|
314 |
-
.ui-datepicker .ui-datepicker-buttonpane button {
|
315 |
-
float: right;
|
316 |
-
margin: .5em .2em .4em;
|
317 |
-
cursor: pointer;
|
318 |
-
padding: .2em .6em .3em .6em;
|
319 |
-
width: auto;
|
320 |
-
overflow: visible;
|
321 |
-
}
|
322 |
-
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
|
323 |
-
float: left;
|
324 |
-
}
|
325 |
-
|
326 |
-
/* with multiple calendars */
|
327 |
-
.ui-datepicker.ui-datepicker-multi {
|
328 |
-
width: auto;
|
329 |
-
}
|
330 |
-
.ui-datepicker-multi .ui-datepicker-group {
|
331 |
-
float: left;
|
332 |
-
}
|
333 |
-
.ui-datepicker-multi .ui-datepicker-group table {
|
334 |
-
width: 95%;
|
335 |
-
margin: 0 auto .4em;
|
336 |
-
}
|
337 |
-
.ui-datepicker-multi-2 .ui-datepicker-group {
|
338 |
-
width: 50%;
|
339 |
-
}
|
340 |
-
.ui-datepicker-multi-3 .ui-datepicker-group {
|
341 |
-
width: 33.3%;
|
342 |
-
}
|
343 |
-
.ui-datepicker-multi-4 .ui-datepicker-group {
|
344 |
-
width: 25%;
|
345 |
-
}
|
346 |
-
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
|
347 |
-
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
|
348 |
-
border-left-width: 0;
|
349 |
-
}
|
350 |
-
.ui-datepicker-multi .ui-datepicker-buttonpane {
|
351 |
-
clear: left;
|
352 |
-
}
|
353 |
-
.ui-datepicker-row-break {
|
354 |
-
clear: both;
|
355 |
-
width: 100%;
|
356 |
-
font-size: 0;
|
357 |
-
}
|
358 |
-
|
359 |
-
/* RTL support */
|
360 |
-
.ui-datepicker-rtl {
|
361 |
-
direction: rtl;
|
362 |
-
}
|
363 |
-
.ui-datepicker-rtl .ui-datepicker-prev {
|
364 |
-
right: 2px;
|
365 |
-
left: auto;
|
366 |
-
}
|
367 |
-
.ui-datepicker-rtl .ui-datepicker-next {
|
368 |
-
left: 2px;
|
369 |
-
right: auto;
|
370 |
-
}
|
371 |
-
.ui-datepicker-rtl .ui-datepicker-prev:hover {
|
372 |
-
right: 1px;
|
373 |
-
left: auto;
|
374 |
-
}
|
375 |
-
.ui-datepicker-rtl .ui-datepicker-next:hover {
|
376 |
-
left: 1px;
|
377 |
-
right: auto;
|
378 |
-
}
|
379 |
-
.ui-datepicker-rtl .ui-datepicker-buttonpane {
|
380 |
-
clear: right;
|
381 |
-
}
|
382 |
-
.ui-datepicker-rtl .ui-datepicker-buttonpane button {
|
383 |
-
float: left;
|
384 |
-
}
|
385 |
-
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
|
386 |
-
.ui-datepicker-rtl .ui-datepicker-group {
|
387 |
-
float: right;
|
388 |
-
}
|
389 |
-
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
|
390 |
-
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
|
391 |
-
border-right-width: 0;
|
392 |
-
border-left-width: 1px;
|
393 |
-
}
|
394 |
-
.ui-dialog {
|
395 |
-
position: absolute;
|
396 |
-
top: 0;
|
397 |
-
left: 0;
|
398 |
-
padding: .2em;
|
399 |
-
outline: 0;
|
400 |
-
}
|
401 |
-
.ui-dialog .ui-dialog-titlebar {
|
402 |
-
padding: .4em 1em;
|
403 |
-
position: relative;
|
404 |
-
}
|
405 |
-
.ui-dialog .ui-dialog-title {
|
406 |
-
float: left;
|
407 |
-
margin: .1em 0;
|
408 |
-
white-space: nowrap;
|
409 |
-
width: 90%;
|
410 |
-
overflow: hidden;
|
411 |
-
text-overflow: ellipsis;
|
412 |
-
}
|
413 |
-
.ui-dialog .ui-dialog-titlebar-close {
|
414 |
-
position: absolute;
|
415 |
-
right: .3em;
|
416 |
-
top: 50%;
|
417 |
-
width: 21px;
|
418 |
-
margin: -10px 0 0 0;
|
419 |
-
padding: 1px;
|
420 |
-
height: 20px;
|
421 |
-
}
|
422 |
-
.ui-dialog .ui-dialog-content {
|
423 |
-
position: relative;
|
424 |
-
border: 0;
|
425 |
-
padding: .5em 1em;
|
426 |
-
background: none;
|
427 |
-
overflow: auto;
|
428 |
-
}
|
429 |
-
.ui-dialog .ui-dialog-buttonpane {
|
430 |
-
text-align: left;
|
431 |
-
border-width: 1px 0 0 0;
|
432 |
-
background-image: none;
|
433 |
-
margin-top: .5em;
|
434 |
-
padding: .3em 1em .5em .4em;
|
435 |
-
}
|
436 |
-
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
437 |
-
float: right;
|
438 |
-
}
|
439 |
-
.ui-dialog .ui-dialog-buttonpane button {
|
440 |
-
margin: .5em .4em .5em 0;
|
441 |
-
cursor: pointer;
|
442 |
-
}
|
443 |
-
.ui-dialog .ui-resizable-se {
|
444 |
-
width: 12px;
|
445 |
-
height: 12px;
|
446 |
-
right: -5px;
|
447 |
-
bottom: -5px;
|
448 |
-
background-position: 16px 16px;
|
449 |
-
}
|
450 |
-
.ui-draggable .ui-dialog-titlebar {
|
451 |
-
cursor: move;
|
452 |
-
}
|
453 |
-
.ui-menu {
|
454 |
-
list-style: none;
|
455 |
-
padding: 2px;
|
456 |
-
margin: 0;
|
457 |
-
display: block;
|
458 |
-
outline: none;
|
459 |
-
}
|
460 |
-
.ui-menu .ui-menu {
|
461 |
-
margin-top: -3px;
|
462 |
-
position: absolute;
|
463 |
-
}
|
464 |
-
.ui-menu .ui-menu-item {
|
465 |
-
margin: 0;
|
466 |
-
padding: 0;
|
467 |
-
width: 100%;
|
468 |
-
}
|
469 |
-
.ui-menu .ui-menu-divider {
|
470 |
-
margin: 5px -2px 5px -2px;
|
471 |
-
height: 0;
|
472 |
-
font-size: 0;
|
473 |
-
line-height: 0;
|
474 |
-
border-width: 1px 0 0 0;
|
475 |
-
}
|
476 |
-
.ui-menu .ui-menu-item a {
|
477 |
-
text-decoration: none;
|
478 |
-
display: block;
|
479 |
-
padding: 2px .4em;
|
480 |
-
line-height: 1.5;
|
481 |
-
min-height: 0; /* support: IE7 */
|
482 |
-
font-weight: normal;
|
483 |
-
}
|
484 |
-
.ui-menu .ui-menu-item a.ui-state-focus,
|
485 |
-
.ui-menu .ui-menu-item a.ui-state-active {
|
486 |
-
font-weight: normal;
|
487 |
-
margin: -1px;
|
488 |
-
}
|
489 |
-
|
490 |
-
.ui-menu .ui-state-disabled {
|
491 |
-
font-weight: normal;
|
492 |
-
margin: .4em 0 .2em;
|
493 |
-
line-height: 1.5;
|
494 |
-
}
|
495 |
-
.ui-menu .ui-state-disabled a {
|
496 |
-
cursor: default;
|
497 |
-
}
|
498 |
-
|
499 |
-
/* icon support */
|
500 |
-
.ui-menu-icons {
|
501 |
-
position: relative;
|
502 |
-
}
|
503 |
-
.ui-menu-icons .ui-menu-item a {
|
504 |
-
position: relative;
|
505 |
-
padding-left: 2em;
|
506 |
-
}
|
507 |
-
|
508 |
-
/* left-aligned */
|
509 |
-
.ui-menu .ui-icon {
|
510 |
-
position: absolute;
|
511 |
-
top: .2em;
|
512 |
-
left: .2em;
|
513 |
-
}
|
514 |
-
|
515 |
-
/* right-aligned */
|
516 |
-
.ui-menu .ui-menu-icon {
|
517 |
-
position: static;
|
518 |
-
float: right;
|
519 |
-
}
|
520 |
-
.ui-progressbar {
|
521 |
-
height: 2em;
|
522 |
-
text-align: left;
|
523 |
-
overflow: hidden;
|
524 |
-
}
|
525 |
-
.ui-progressbar .ui-progressbar-value {
|
526 |
-
margin: -1px;
|
527 |
-
height: 100%;
|
528 |
-
}
|
529 |
-
.ui-progressbar .ui-progressbar-overlay {
|
530 |
-
background: url("images/animated-overlay.gif");
|
531 |
-
height: 100%;
|
532 |
-
filter: alpha(opacity=25);
|
533 |
-
opacity: 0.25;
|
534 |
-
}
|
535 |
-
.ui-progressbar-indeterminate .ui-progressbar-value {
|
536 |
-
background-image: none;
|
537 |
-
}
|
538 |
-
.ui-resizable {
|
539 |
-
position: relative;
|
540 |
-
}
|
541 |
-
.ui-resizable-handle {
|
542 |
-
position: absolute;
|
543 |
-
font-size: 0.1px;
|
544 |
-
display: block;
|
545 |
-
}
|
546 |
-
.ui-resizable-disabled .ui-resizable-handle,
|
547 |
-
.ui-resizable-autohide .ui-resizable-handle {
|
548 |
-
display: none;
|
549 |
-
}
|
550 |
-
.ui-resizable-n {
|
551 |
-
cursor: n-resize;
|
552 |
-
height: 7px;
|
553 |
-
width: 100%;
|
554 |
-
top: -5px;
|
555 |
-
left: 0;
|
556 |
-
}
|
557 |
-
.ui-resizable-s {
|
558 |
-
cursor: s-resize;
|
559 |
-
height: 7px;
|
560 |
-
width: 100%;
|
561 |
-
bottom: -5px;
|
562 |
-
left: 0;
|
563 |
-
}
|
564 |
-
.ui-resizable-e {
|
565 |
-
cursor: e-resize;
|
566 |
-
width: 7px;
|
567 |
-
right: -5px;
|
568 |
-
top: 0;
|
569 |
-
height: 100%;
|
570 |
-
}
|
571 |
-
.ui-resizable-w {
|
572 |
-
cursor: w-resize;
|
573 |
-
width: 7px;
|
574 |
-
left: -5px;
|
575 |
-
top: 0;
|
576 |
-
height: 100%;
|
577 |
-
}
|
578 |
-
.ui-resizable-se {
|
579 |
-
cursor: se-resize;
|
580 |
-
width: 12px;
|
581 |
-
height: 12px;
|
582 |
-
right: 1px;
|
583 |
-
bottom: 1px;
|
584 |
-
}
|
585 |
-
.ui-resizable-sw {
|
586 |
-
cursor: sw-resize;
|
587 |
-
width: 9px;
|
588 |
-
height: 9px;
|
589 |
-
left: -5px;
|
590 |
-
bottom: -5px;
|
591 |
-
}
|
592 |
-
.ui-resizable-nw {
|
593 |
-
cursor: nw-resize;
|
594 |
-
width: 9px;
|
595 |
-
height: 9px;
|
596 |
-
left: -5px;
|
597 |
-
top: -5px;
|
598 |
-
}
|
599 |
-
.ui-resizable-ne {
|
600 |
-
cursor: ne-resize;
|
601 |
-
width: 9px;
|
602 |
-
height: 9px;
|
603 |
-
right: -5px;
|
604 |
-
top: -5px;
|
605 |
-
}
|
606 |
-
.ui-selectable-helper {
|
607 |
-
position: absolute;
|
608 |
-
z-index: 100;
|
609 |
-
border: 1px dotted black;
|
610 |
-
}
|
611 |
-
.ui-slider {
|
612 |
-
position: relative;
|
613 |
-
text-align: left;
|
614 |
-
}
|
615 |
-
.ui-slider .ui-slider-handle {
|
616 |
-
position: absolute;
|
617 |
-
z-index: 2;
|
618 |
-
width: 1.2em;
|
619 |
-
height: 1.2em;
|
620 |
-
cursor: default;
|
621 |
-
}
|
622 |
-
.ui-slider .ui-slider-range {
|
623 |
-
position: absolute;
|
624 |
-
z-index: 1;
|
625 |
-
font-size: .7em;
|
626 |
-
display: block;
|
627 |
-
border: 0;
|
628 |
-
background-position: 0 0;
|
629 |
-
}
|
630 |
-
|
631 |
-
/* For IE8 - See #6727 */
|
632 |
-
.ui-slider.ui-state-disabled .ui-slider-handle,
|
633 |
-
.ui-slider.ui-state-disabled .ui-slider-range {
|
634 |
-
filter: inherit;
|
635 |
-
}
|
636 |
-
|
637 |
-
.ui-slider-horizontal {
|
638 |
-
height: .8em;
|
639 |
-
}
|
640 |
-
.ui-slider-horizontal .ui-slider-handle {
|
641 |
-
top: -.3em;
|
642 |
-
margin-left: -.6em;
|
643 |
-
}
|
644 |
-
.ui-slider-horizontal .ui-slider-range {
|
645 |
-
top: 0;
|
646 |
-
height: 100%;
|
647 |
-
}
|
648 |
-
.ui-slider-horizontal .ui-slider-range-min {
|
649 |
-
left: 0;
|
650 |
-
}
|
651 |
-
.ui-slider-horizontal .ui-slider-range-max {
|
652 |
-
right: 0;
|
653 |
-
}
|
654 |
-
|
655 |
-
.ui-slider-vertical {
|
656 |
-
width: .8em;
|
657 |
-
height: 100px;
|
658 |
-
}
|
659 |
-
.ui-slider-vertical .ui-slider-handle {
|
660 |
-
left: -.3em;
|
661 |
-
margin-left: 0;
|
662 |
-
margin-bottom: -.6em;
|
663 |
-
}
|
664 |
-
.ui-slider-vertical .ui-slider-range {
|
665 |
-
left: 0;
|
666 |
-
width: 100%;
|
667 |
-
}
|
668 |
-
.ui-slider-vertical .ui-slider-range-min {
|
669 |
-
bottom: 0;
|
670 |
-
}
|
671 |
-
.ui-slider-vertical .ui-slider-range-max {
|
672 |
-
top: 0;
|
673 |
-
}
|
674 |
-
.ui-spinner {
|
675 |
-
position: relative;
|
676 |
-
display: inline-block;
|
677 |
-
overflow: hidden;
|
678 |
-
padding: 0;
|
679 |
-
vertical-align: middle;
|
680 |
-
}
|
681 |
-
.ui-spinner-input {
|
682 |
-
border: none;
|
683 |
-
background: none;
|
684 |
-
color: inherit;
|
685 |
-
padding: 0;
|
686 |
-
margin: .2em 0;
|
687 |
-
vertical-align: middle;
|
688 |
-
margin-left: .4em;
|
689 |
-
margin-right: 22px;
|
690 |
-
}
|
691 |
-
.ui-spinner-button {
|
692 |
-
width: 16px;
|
693 |
-
height: 50%;
|
694 |
-
font-size: .5em;
|
695 |
-
padding: 0;
|
696 |
-
margin: 0;
|
697 |
-
text-align: center;
|
698 |
-
position: absolute;
|
699 |
-
cursor: default;
|
700 |
-
display: block;
|
701 |
-
overflow: hidden;
|
702 |
-
right: 0;
|
703 |
-
}
|
704 |
-
/* more specificity required here to overide default borders */
|
705 |
-
.ui-spinner a.ui-spinner-button {
|
706 |
-
border-top: none;
|
707 |
-
border-bottom: none;
|
708 |
-
border-right: none;
|
709 |
-
}
|
710 |
-
/* vertical centre icon */
|
711 |
-
.ui-spinner .ui-icon {
|
712 |
-
position: absolute;
|
713 |
-
margin-top: -8px;
|
714 |
-
top: 50%;
|
715 |
-
left: 0;
|
716 |
-
}
|
717 |
-
.ui-spinner-up {
|
718 |
-
top: 0;
|
719 |
-
}
|
720 |
-
.ui-spinner-down {
|
721 |
-
bottom: 0;
|
722 |
-
}
|
723 |
-
|
724 |
-
/* TR overrides */
|
725 |
-
.ui-spinner .ui-icon-triangle-1-s {
|
726 |
-
/* need to fix icons sprite */
|
727 |
-
background-position: -65px -16px;
|
728 |
-
}
|
729 |
-
.ui-tabs {
|
730 |
-
position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
731 |
-
padding: .2em;
|
732 |
-
}
|
733 |
-
.ui-tabs .ui-tabs-nav {
|
734 |
-
margin: 0;
|
735 |
-
padding: .2em .2em 0;
|
736 |
-
}
|
737 |
-
.ui-tabs .ui-tabs-nav li {
|
738 |
-
list-style: none;
|
739 |
-
float: left;
|
740 |
-
position: relative;
|
741 |
-
top: 0;
|
742 |
-
margin: 1px .2em 0 0;
|
743 |
-
border-bottom: 0;
|
744 |
-
padding: 0;
|
745 |
-
white-space: nowrap;
|
746 |
-
}
|
747 |
-
.ui-tabs .ui-tabs-nav li a {
|
748 |
-
float: left;
|
749 |
-
padding: .5em 1em;
|
750 |
-
text-decoration: none;
|
751 |
-
}
|
752 |
-
.ui-tabs .ui-tabs-nav li.ui-tabs-active {
|
753 |
-
margin-bottom: -1px;
|
754 |
-
padding-bottom: 1px;
|
755 |
-
}
|
756 |
-
.ui-tabs .ui-tabs-nav li.ui-tabs-active a,
|
757 |
-
.ui-tabs .ui-tabs-nav li.ui-state-disabled a,
|
758 |
-
.ui-tabs .ui-tabs-nav li.ui-tabs-loading a {
|
759 |
-
cursor: text;
|
760 |
-
}
|
761 |
-
.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
|
762 |
-
.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a {
|
763 |
-
cursor: pointer;
|
764 |
-
}
|
765 |
-
.ui-tabs .ui-tabs-panel {
|
766 |
-
display: block;
|
767 |
-
border-width: 0;
|
768 |
-
padding: 1em 1.4em;
|
769 |
-
background: none;
|
770 |
-
}
|
771 |
-
.ui-tooltip {
|
772 |
-
padding: 8px;
|
773 |
-
position: absolute;
|
774 |
-
z-index: 9999;
|
775 |
-
max-width: 300px;
|
776 |
-
-webkit-box-shadow: 0 0 5px #aaa;
|
777 |
-
box-shadow: 0 0 5px #aaa;
|
778 |
-
}
|
779 |
-
body .ui-tooltip {
|
780 |
-
border-width: 2px;
|
781 |
-
}
|
782 |
-
|
783 |
-
/* Component containers
|
784 |
-
----------------------------------*/
|
785 |
-
.ui-widget {
|
786 |
-
font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
|
787 |
-
font-size: 1.1em/*{fsDefault}*/;
|
788 |
-
}
|
789 |
-
.ui-widget .ui-widget {
|
790 |
-
font-size: 1em;
|
791 |
-
}
|
792 |
-
.ui-widget input,
|
793 |
-
.ui-widget select,
|
794 |
-
.ui-widget textarea,
|
795 |
-
.ui-widget button {
|
796 |
-
font-family: Verdana,Arial,sans-serif/*{ffDefault}*/;
|
797 |
-
font-size: 1em;
|
798 |
-
}
|
799 |
-
.ui-widget-content {
|
800 |
-
border: 1px solid #aaaaaa/*{borderColorContent}*/;
|
801 |
-
background: #ffffff/*{bgColorContent}*/ url(images/ui-bg_flat_75_ffffff_40x100.png)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/;
|
802 |
-
color: #222222/*{fcContent}*/;
|
803 |
-
}
|
804 |
-
.ui-widget-content a {
|
805 |
-
color: #222222/*{fcContent}*/;
|
806 |
-
}
|
807 |
-
.ui-widget-header {
|
808 |
-
border: 1px solid #aaaaaa/*{borderColorHeader}*/;
|
809 |
-
background: #cccccc/*{bgColorHeader}*/ url(images/ui-bg_highlight-soft_75_cccccc_1x100.png)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/;
|
810 |
-
color: #222222/*{fcHeader}*/;
|
811 |
-
font-weight: bold;
|
812 |
-
}
|
813 |
-
.ui-widget-header a {
|
814 |
-
color: #222222/*{fcHeader}*/;
|
815 |
-
}
|
816 |
-
|
817 |
-
/* Interaction states
|
818 |
-
----------------------------------*/
|
819 |
-
.ui-state-default,
|
820 |
-
.ui-widget-content .ui-state-default,
|
821 |
-
.ui-widget-header .ui-state-default {
|
822 |
-
border: 1px solid #d3d3d3/*{borderColorDefault}*/;
|
823 |
-
background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/;
|
824 |
-
font-weight: normal/*{fwDefault}*/;
|
825 |
-
color: #555555/*{fcDefault}*/;
|
826 |
-
}
|
827 |
-
.ui-state-default a,
|
828 |
-
.ui-state-default a:link,
|
829 |
-
.ui-state-default a:visited {
|
830 |
-
color: #555555/*{fcDefault}*/;
|
831 |
-
text-decoration: none;
|
832 |
-
}
|
833 |
-
.ui-state-hover,
|
834 |
-
.ui-widget-content .ui-state-hover,
|
835 |
-
.ui-widget-header .ui-state-hover,
|
836 |
-
.ui-state-focus,
|
837 |
-
.ui-widget-content .ui-state-focus,
|
838 |
-
.ui-widget-header .ui-state-focus {
|
839 |
-
border: 1px solid #999999/*{borderColorHover}*/;
|
840 |
-
background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/;
|
841 |
-
font-weight: normal/*{fwDefault}*/;
|
842 |
-
color: #212121/*{fcHover}*/;
|
843 |
-
}
|
844 |
-
.ui-state-hover a,
|
845 |
-
.ui-state-hover a:hover,
|
846 |
-
.ui-state-hover a:link,
|
847 |
-
.ui-state-hover a:visited {
|
848 |
-
color: #212121/*{fcHover}*/;
|
849 |
-
text-decoration: none;
|
850 |
-
}
|
851 |
-
.ui-state-active,
|
852 |
-
.ui-widget-content .ui-state-active,
|
853 |
-
.ui-widget-header .ui-state-active {
|
854 |
-
border: 1px solid #aaaaaa/*{borderColorActive}*/;
|
855 |
-
background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/;
|
856 |
-
font-weight: normal/*{fwDefault}*/;
|
857 |
-
color: #212121/*{fcActive}*/;
|
858 |
-
}
|
859 |
-
.ui-state-active a,
|
860 |
-
.ui-state-active a:link,
|
861 |
-
.ui-state-active a:visited {
|
862 |
-
color: #212121/*{fcActive}*/;
|
863 |
-
text-decoration: none;
|
864 |
-
}
|
865 |
-
|
866 |
-
/* Interaction Cues
|
867 |
-
----------------------------------*/
|
868 |
-
.ui-state-highlight,
|
869 |
-
.ui-widget-content .ui-state-highlight,
|
870 |
-
.ui-widget-header .ui-state-highlight {
|
871 |
-
border: 1px solid #fcefa1/*{borderColorHighlight}*/;
|
872 |
-
background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/;
|
873 |
-
color: #363636/*{fcHighlight}*/;
|
874 |
-
}
|
875 |
-
.ui-state-highlight a,
|
876 |
-
.ui-widget-content .ui-state-highlight a,
|
877 |
-
.ui-widget-header .ui-state-highlight a {
|
878 |
-
color: #363636/*{fcHighlight}*/;
|
879 |
-
}
|
880 |
-
.ui-state-error,
|
881 |
-
.ui-widget-content .ui-state-error,
|
882 |
-
.ui-widget-header .ui-state-error {
|
883 |
-
border: 1px solid #cd0a0a/*{borderColorError}*/;
|
884 |
-
background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/;
|
885 |
-
color: #cd0a0a/*{fcError}*/;
|
886 |
-
}
|
887 |
-
.ui-state-error a,
|
888 |
-
.ui-widget-content .ui-state-error a,
|
889 |
-
.ui-widget-header .ui-state-error a {
|
890 |
-
color: #cd0a0a/*{fcError}*/;
|
891 |
-
}
|
892 |
-
.ui-state-error-text,
|
893 |
-
.ui-widget-content .ui-state-error-text,
|
894 |
-
.ui-widget-header .ui-state-error-text {
|
895 |
-
color: #cd0a0a/*{fcError}*/;
|
896 |
-
}
|
897 |
-
.ui-priority-primary,
|
898 |
-
.ui-widget-content .ui-priority-primary,
|
899 |
-
.ui-widget-header .ui-priority-primary {
|
900 |
-
font-weight: bold;
|
901 |
-
}
|
902 |
-
.ui-priority-secondary,
|
903 |
-
.ui-widget-content .ui-priority-secondary,
|
904 |
-
.ui-widget-header .ui-priority-secondary {
|
905 |
-
opacity: .7;
|
906 |
-
filter:Alpha(Opacity=70);
|
907 |
-
font-weight: normal;
|
908 |
-
}
|
909 |
-
.ui-state-disabled,
|
910 |
-
.ui-widget-content .ui-state-disabled,
|
911 |
-
.ui-widget-header .ui-state-disabled {
|
912 |
-
opacity: .35;
|
913 |
-
filter:Alpha(Opacity=35);
|
914 |
-
background-image: none;
|
915 |
-
}
|
916 |
-
.ui-state-disabled .ui-icon {
|
917 |
-
filter:Alpha(Opacity=35); /* For IE8 - See #6059 */
|
918 |
-
}
|
919 |
-
|
920 |
-
/* Icons
|
921 |
-
----------------------------------*/
|
922 |
-
|
923 |
-
/* states and images */
|
924 |
-
.ui-icon {
|
925 |
-
width: 16px;
|
926 |
-
height: 16px;
|
927 |
-
background-position: 16px 16px;
|
928 |
-
}
|
929 |
-
.ui-icon,
|
930 |
-
.ui-widget-content .ui-icon {
|
931 |
-
background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/;
|
932 |
-
}
|
933 |
-
.ui-widget-header .ui-icon {
|
934 |
-
background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/;
|
935 |
-
}
|
936 |
-
.ui-state-default .ui-icon {
|
937 |
-
background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/;
|
938 |
-
}
|
939 |
-
.ui-state-hover .ui-icon,
|
940 |
-
.ui-state-focus .ui-icon {
|
941 |
-
background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/;
|
942 |
-
}
|
943 |
-
.ui-state-active .ui-icon {
|
944 |
-
background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/;
|
945 |
-
}
|
946 |
-
.ui-state-highlight .ui-icon {
|
947 |
-
background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/;
|
948 |
-
}
|
949 |
-
.ui-state-error .ui-icon,
|
950 |
-
.ui-state-error-text .ui-icon {
|
951 |
-
background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/;
|
952 |
-
}
|
953 |
-
|
954 |
-
/* positioning */
|
955 |
-
.ui-icon-carat-1-n { background-position: 0 0; }
|
956 |
-
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
957 |
-
.ui-icon-carat-1-e { background-position: -32px 0; }
|
958 |
-
.ui-icon-carat-1-se { background-position: -48px 0; }
|
959 |
-
.ui-icon-carat-1-s { background-position: -64px 0; }
|
960 |
-
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
961 |
-
.ui-icon-carat-1-w { background-position: -96px 0; }
|
962 |
-
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
963 |
-
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
964 |
-
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
965 |
-
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
966 |
-
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
967 |
-
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
968 |
-
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
969 |
-
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
970 |
-
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
971 |
-
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
972 |
-
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
973 |
-
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
974 |
-
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
975 |
-
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
976 |
-
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
977 |
-
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
978 |
-
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
979 |
-
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
980 |
-
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
981 |
-
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
982 |
-
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
983 |
-
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
984 |
-
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
985 |
-
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
986 |
-
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
987 |
-
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
988 |
-
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
989 |
-
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
990 |
-
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
991 |
-
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
992 |
-
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
993 |
-
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
994 |
-
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
995 |
-
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
996 |
-
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
997 |
-
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
998 |
-
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
999 |
-
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
1000 |
-
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
1001 |
-
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
1002 |
-
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
1003 |
-
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
1004 |
-
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
1005 |
-
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
1006 |
-
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
1007 |
-
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
1008 |
-
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
1009 |
-
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
1010 |
-
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
1011 |
-
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
1012 |
-
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
1013 |
-
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
1014 |
-
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
1015 |
-
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
1016 |
-
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
1017 |
-
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
1018 |
-
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
1019 |
-
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
1020 |
-
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
1021 |
-
.ui-icon-extlink { background-position: -32px -80px; }
|
1022 |
-
.ui-icon-newwin { background-position: -48px -80px; }
|
1023 |
-
.ui-icon-refresh { background-position: -64px -80px; }
|
1024 |
-
.ui-icon-shuffle { background-position: -80px -80px; }
|
1025 |
-
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
1026 |
-
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
1027 |
-
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
1028 |
-
.ui-icon-folder-open { background-position: -16px -96px; }
|
1029 |
-
.ui-icon-document { background-position: -32px -96px; }
|
1030 |
-
.ui-icon-document-b { background-position: -48px -96px; }
|
1031 |
-
.ui-icon-note { background-position: -64px -96px; }
|
1032 |
-
.ui-icon-mail-closed { background-position: -80px -96px; }
|
1033 |
-
.ui-icon-mail-open { background-position: -96px -96px; }
|
1034 |
-
.ui-icon-suitcase { background-position: -112px -96px; }
|
1035 |
-
.ui-icon-comment { background-position: -128px -96px; }
|
1036 |
-
.ui-icon-person { background-position: -144px -96px; }
|
1037 |
-
.ui-icon-print { background-position: -160px -96px; }
|
1038 |
-
.ui-icon-trash { background-position: -176px -96px; }
|
1039 |
-
.ui-icon-locked { background-position: -192px -96px; }
|
1040 |
-
.ui-icon-unlocked { background-position: -208px -96px; }
|
1041 |
-
.ui-icon-bookmark { background-position: -224px -96px; }
|
1042 |
-
.ui-icon-tag { background-position: -240px -96px; }
|
1043 |
-
.ui-icon-home { background-position: 0 -112px; }
|
1044 |
-
.ui-icon-flag { background-position: -16px -112px; }
|
1045 |
-
.ui-icon-calendar { background-position: -32px -112px; }
|
1046 |
-
.ui-icon-cart { background-position: -48px -112px; }
|
1047 |
-
.ui-icon-pencil { background-position: -64px -112px; }
|
1048 |
-
.ui-icon-clock { background-position: -80px -112px; }
|
1049 |
-
.ui-icon-disk { background-position: -96px -112px; }
|
1050 |
-
.ui-icon-calculator { background-position: -112px -112px; }
|
1051 |
-
.ui-icon-zoomin { background-position: -128px -112px; }
|
1052 |
-
.ui-icon-zoomout { background-position: -144px -112px; }
|
1053 |
-
.ui-icon-search { background-position: -160px -112px; }
|
1054 |
-
.ui-icon-wrench { background-position: -176px -112px; }
|
1055 |
-
.ui-icon-gear { background-position: -192px -112px; }
|
1056 |
-
.ui-icon-heart { background-position: -208px -112px; }
|
1057 |
-
.ui-icon-star { background-position: -224px -112px; }
|
1058 |
-
.ui-icon-link { background-position: -240px -112px; }
|
1059 |
-
.ui-icon-cancel { background-position: 0 -128px; }
|
1060 |
-
.ui-icon-plus { background-position: -16px -128px; }
|
1061 |
-
.ui-icon-plusthick { background-position: -32px -128px; }
|
1062 |
-
.ui-icon-minus { background-position: -48px -128px; }
|
1063 |
-
.ui-icon-minusthick { background-position: -64px -128px; }
|
1064 |
-
.ui-icon-close { background-position: -80px -128px; }
|
1065 |
-
.ui-icon-closethick { background-position: -96px -128px; }
|
1066 |
-
.ui-icon-key { background-position: -112px -128px; }
|
1067 |
-
.ui-icon-lightbulb { background-position: -128px -128px; }
|
1068 |
-
.ui-icon-scissors { background-position: -144px -128px; }
|
1069 |
-
.ui-icon-clipboard { background-position: -160px -128px; }
|
1070 |
-
.ui-icon-copy { background-position: -176px -128px; }
|
1071 |
-
.ui-icon-contact { background-position: -192px -128px; }
|
1072 |
-
.ui-icon-image { background-position: -208px -128px; }
|
1073 |
-
.ui-icon-video { background-position: -224px -128px; }
|
1074 |
-
.ui-icon-script { background-position: -240px -128px; }
|
1075 |
-
.ui-icon-alert { background-position: 0 -144px; }
|
1076 |
-
.ui-icon-info { background-position: -16px -144px; }
|
1077 |
-
.ui-icon-notice { background-position: -32px -144px; }
|
1078 |
-
.ui-icon-help { background-position: -48px -144px; }
|
1079 |
-
.ui-icon-check { background-position: -64px -144px; }
|
1080 |
-
.ui-icon-bullet { background-position: -80px -144px; }
|
1081 |
-
.ui-icon-radio-on { background-position: -96px -144px; }
|
1082 |
-
.ui-icon-radio-off { background-position: -112px -144px; }
|
1083 |
-
.ui-icon-pin-w { background-position: -128px -144px; }
|
1084 |
-
.ui-icon-pin-s { background-position: -144px -144px; }
|
1085 |
-
.ui-icon-play { background-position: 0 -160px; }
|
1086 |
-
.ui-icon-pause { background-position: -16px -160px; }
|
1087 |
-
.ui-icon-seek-next { background-position: -32px -160px; }
|
1088 |
-
.ui-icon-seek-prev { background-position: -48px -160px; }
|
1089 |
-
.ui-icon-seek-end { background-position: -64px -160px; }
|
1090 |
-
.ui-icon-seek-start { background-position: -80px -160px; }
|
1091 |
-
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
1092 |
-
.ui-icon-seek-first { background-position: -80px -160px; }
|
1093 |
-
.ui-icon-stop { background-position: -96px -160px; }
|
1094 |
-
.ui-icon-eject { background-position: -112px -160px; }
|
1095 |
-
.ui-icon-volume-off { background-position: -128px -160px; }
|
1096 |
-
.ui-icon-volume-on { background-position: -144px -160px; }
|
1097 |
-
.ui-icon-power { background-position: 0 -176px; }
|
1098 |
-
.ui-icon-signal-diag { background-position: -16px -176px; }
|
1099 |
-
.ui-icon-signal { background-position: -32px -176px; }
|
1100 |
-
.ui-icon-battery-0 { background-position: -48px -176px; }
|
1101 |
-
.ui-icon-battery-1 { background-position: -64px -176px; }
|
1102 |
-
.ui-icon-battery-2 { background-position: -80px -176px; }
|
1103 |
-
.ui-icon-battery-3 { background-position: -96px -176px; }
|
1104 |
-
.ui-icon-circle-plus { background-position: 0 -192px; }
|
1105 |
-
.ui-icon-circle-minus { background-position: -16px -192px; }
|
1106 |
-
.ui-icon-circle-close { background-position: -32px -192px; }
|
1107 |
-
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
1108 |
-
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
1109 |
-
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
1110 |
-
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
1111 |
-
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
1112 |
-
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
1113 |
-
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
1114 |
-
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
1115 |
-
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
1116 |
-
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
1117 |
-
.ui-icon-circle-check { background-position: -208px -192px; }
|
1118 |
-
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
1119 |
-
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
1120 |
-
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
1121 |
-
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
1122 |
-
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
1123 |
-
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
1124 |
-
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
1125 |
-
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
1126 |
-
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
1127 |
-
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
1128 |
-
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
1129 |
-
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
1130 |
-
|
1131 |
-
|
1132 |
-
/* Misc visuals
|
1133 |
-
----------------------------------*/
|
1134 |
-
|
1135 |
-
/* Corner radius */
|
1136 |
-
.ui-corner-all,
|
1137 |
-
.ui-corner-top,
|
1138 |
-
.ui-corner-left,
|
1139 |
-
.ui-corner-tl {
|
1140 |
-
border-top-left-radius: 4px/*{cornerRadius}*/;
|
1141 |
-
}
|
1142 |
-
.ui-corner-all,
|
1143 |
-
.ui-corner-top,
|
1144 |
-
.ui-corner-right,
|
1145 |
-
.ui-corner-tr {
|
1146 |
-
border-top-right-radius: 4px/*{cornerRadius}*/;
|
1147 |
-
}
|
1148 |
-
.ui-corner-all,
|
1149 |
-
.ui-corner-bottom,
|
1150 |
-
.ui-corner-left,
|
1151 |
-
.ui-corner-bl {
|
1152 |
-
border-bottom-left-radius: 4px/*{cornerRadius}*/;
|
1153 |
-
}
|
1154 |
-
.ui-corner-all,
|
1155 |
-
.ui-corner-bottom,
|
1156 |
-
.ui-corner-right,
|
1157 |
-
.ui-corner-br {
|
1158 |
-
border-bottom-right-radius: 4px/*{cornerRadius}*/;
|
1159 |
-
}
|
1160 |
-
|
1161 |
-
/* Overlays */
|
1162 |
-
.ui-widget-overlay {
|
1163 |
-
background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/;
|
1164 |
-
opacity: .3/*{opacityOverlay}*/;
|
1165 |
-
filter: Alpha(Opacity=30)/*{opacityFilterOverlay}*/;
|
1166 |
-
}
|
1167 |
-
.ui-widget-shadow {
|
1168 |
-
margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/;
|
1169 |
-
padding: 8px/*{thicknessShadow}*/;
|
1170 |
-
background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/;
|
1171 |
-
opacity: .3/*{opacityShadow}*/;
|
1172 |
-
filter: Alpha(Opacity=30)/*{opacityFilterShadow}*/;
|
1173 |
-
border-radius: 8px/*{cornerRadiusShadow}*/;
|
1174 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/css/jquery.weekcalendar.css
DELETED
@@ -1,287 +0,0 @@
|
|
1 |
-
.wc-container {
|
2 |
-
font-size: 14px;
|
3 |
-
font-family: arial, helvetica;
|
4 |
-
}
|
5 |
-
|
6 |
-
.wc-toolbar {
|
7 |
-
padding: 1em;
|
8 |
-
font-size:0.8em;
|
9 |
-
}
|
10 |
-
|
11 |
-
.wc-toolbar .wc-nav {
|
12 |
-
float:left;
|
13 |
-
}
|
14 |
-
|
15 |
-
.wc-toolbar .wc-display {
|
16 |
-
float: right;
|
17 |
-
}
|
18 |
-
|
19 |
-
.wc-toolbar button {
|
20 |
-
margin-top: 0;
|
21 |
-
margin-bottom: 0;
|
22 |
-
}
|
23 |
-
|
24 |
-
.wc-toolbar .wc-title {
|
25 |
-
text-align: center;
|
26 |
-
padding:0;
|
27 |
-
margin:0;
|
28 |
-
}
|
29 |
-
|
30 |
-
.wc-container table {
|
31 |
-
border-collapse: collapse;
|
32 |
-
border-spacing: 0;
|
33 |
-
}
|
34 |
-
.wc-container table td {
|
35 |
-
margin: 0;
|
36 |
-
padding: 0;
|
37 |
-
}
|
38 |
-
|
39 |
-
.wc-header {
|
40 |
-
background: #eee;
|
41 |
-
border-width:1px 0;
|
42 |
-
border-style:solid;
|
43 |
-
}
|
44 |
-
.wc-header table{
|
45 |
-
width: 100%;
|
46 |
-
table-layout:fixed;
|
47 |
-
}
|
48 |
-
|
49 |
-
.wc-grid-timeslot-header,
|
50 |
-
.wc-header .wc-time-column-header {
|
51 |
-
width: 45px;
|
52 |
-
}
|
53 |
-
|
54 |
-
.wc-header .wc-scrollbar-shim {
|
55 |
-
/* this width replace js */
|
56 |
-
}
|
57 |
-
|
58 |
-
.wc-header .wc-day-column-header {
|
59 |
-
text-align: center;
|
60 |
-
padding: 0.4em;
|
61 |
-
}
|
62 |
-
|
63 |
-
.wc-header .wc-user-header{
|
64 |
-
text-align: center;
|
65 |
-
padding: 0.4em 0;
|
66 |
-
overflow:hidden;
|
67 |
-
}
|
68 |
-
.wc-grid-timeslot-header {
|
69 |
-
background: #eee;
|
70 |
-
}
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
.wc-scrollable-grid {
|
75 |
-
overflow: auto;
|
76 |
-
overflow-x: hidden !important;
|
77 |
-
overflow-y: auto !important;
|
78 |
-
position: relative;
|
79 |
-
background-color: #fff;
|
80 |
-
width: 100%;
|
81 |
-
}
|
82 |
-
|
83 |
-
|
84 |
-
table.wc-time-slots {
|
85 |
-
width: 100%;
|
86 |
-
table-layout: fixed;
|
87 |
-
cursor: default;
|
88 |
-
overflow:hidden;
|
89 |
-
}
|
90 |
-
|
91 |
-
.wc-day-column {
|
92 |
-
width: 13.5%;
|
93 |
-
overflow: visible;
|
94 |
-
vertical-align: top;
|
95 |
-
}
|
96 |
-
.wc-day-column-header{border-width: 0 0 0 3px; border-style: solid;border-color:#aaaaaa;}
|
97 |
-
.wc-scrollable-grid .wc-day-column-last,
|
98 |
-
.wc-scrollable-grid .wc-day-column-middle{border-width: 0 0 0 1px; border-style: dashed;}
|
99 |
-
.wc-scrollable-grid .wc-day-column-first{border-width: 0 0 0 3px; border-style: double;}
|
100 |
-
|
101 |
-
.wc-day-column-inner {
|
102 |
-
width: 100%;
|
103 |
-
position:relative;
|
104 |
-
}
|
105 |
-
|
106 |
-
.wc-no-height-wrapper{
|
107 |
-
position:relative;
|
108 |
-
overflow: visible;
|
109 |
-
height: 0px;
|
110 |
-
}
|
111 |
-
|
112 |
-
.wc-time-slot-wrapper {
|
113 |
-
/* top: 3px;*/
|
114 |
-
}
|
115 |
-
.wc-oddeven-wrapper .wc-full-height-column{
|
116 |
-
/* top: 2px; */
|
117 |
-
/* Modern Browsers */ opacity: 0.4;
|
118 |
-
/* IE 8 */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
|
119 |
-
/* IE 5-7 */ filter: alpha(opacity=40);
|
120 |
-
/* Netscape */ -moz-opacity: 0.4;
|
121 |
-
/* Safari 1 */ -khtml-opacity: 0.4;
|
122 |
-
}
|
123 |
-
.wc-freebusy-wrapper .wc-freebusy{
|
124 |
-
/* top: 1px;*/
|
125 |
-
/* Modern Browsers */ opacity: 0.4;
|
126 |
-
/* IE 8 */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
|
127 |
-
/* IE 5-7 */ filter: alpha(opacity=40);
|
128 |
-
/* Netscape */ -moz-opacity: 0.4;
|
129 |
-
/* Safari 1 */ -khtml-opacity: 0.4;
|
130 |
-
}
|
131 |
-
|
132 |
-
.wc-time-slots {
|
133 |
-
position: absolute;
|
134 |
-
width: 100%;
|
135 |
-
}
|
136 |
-
|
137 |
-
.wc-column-odd,
|
138 |
-
.wc-column-even.ui-state-hover{background-image:none;border:none;}
|
139 |
-
|
140 |
-
.wc-header .wc-today.ui-state-active{background-image:none;}
|
141 |
-
.wc-header .wc-today.wc-day-column-header{border-width:0 3px; border-style: solid;}
|
142 |
-
.wc-header .wc-user-header{border-width:0;}
|
143 |
-
|
144 |
-
.wc-time-slots .wc-day-column.ui-state-default{background:transparent;}
|
145 |
-
.wc-time-slots .wc-today.ui-state-active{background-image:none;}
|
146 |
-
.wc-header .wc-today.ui-state-active.wc-day-column-middle{border-width:0;}
|
147 |
-
.wc-header .wc-today.ui-state-active.wc-day-column-first{border-left-width:3px;}
|
148 |
-
.wc-header .wc-today.ui-state-active.wc-day-column-last{border-right-width:3px;}
|
149 |
-
|
150 |
-
.wc-full-height-column{
|
151 |
-
display:block;
|
152 |
-
/* width:100%;*/
|
153 |
-
}
|
154 |
-
|
155 |
-
|
156 |
-
.wc-time-header-cell {
|
157 |
-
padding: 5px;
|
158 |
-
height: 80px; /* reference height */
|
159 |
-
}
|
160 |
-
|
161 |
-
|
162 |
-
.wc-time-slot {
|
163 |
-
border-bottom: 1px dotted #ddd;
|
164 |
-
}
|
165 |
-
|
166 |
-
.wc-hour-header {
|
167 |
-
text-align: right;
|
168 |
-
}
|
169 |
-
.wc-hour-header.ui-state-active,
|
170 |
-
.wc-hour-header.ui-state-default{
|
171 |
-
border-width:0 0 1px 0;
|
172 |
-
}
|
173 |
-
|
174 |
-
.wc-hour-end, .wc-hour-header {
|
175 |
-
border-bottom: 1px solid #ccc;
|
176 |
-
color: #555;
|
177 |
-
|
178 |
-
}
|
179 |
-
|
180 |
-
.wc-business-hours {
|
181 |
-
background-color: #E6EEF1;
|
182 |
-
border-bottom: 1px solid #ccc;
|
183 |
-
color: #333;
|
184 |
-
font-size: 1.4em;
|
185 |
-
|
186 |
-
}
|
187 |
-
|
188 |
-
.wc-business-hours .wc-am-pm {
|
189 |
-
font-size: 0.6em;
|
190 |
-
}
|
191 |
-
|
192 |
-
.wc-day-header-cell {
|
193 |
-
text-align: center;
|
194 |
-
vertical-align: middle;
|
195 |
-
padding: 5px;
|
196 |
-
}
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
.wc-time-slot-header .wc-header-cell {
|
201 |
-
text-align: right;
|
202 |
-
padding-right: 10px;
|
203 |
-
}
|
204 |
-
|
205 |
-
.wc-cal-event {
|
206 |
-
background-color: #68a1e5;
|
207 |
-
/* Modern Browsers */ opacity: 0.8;
|
208 |
-
/* IE 8 */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
|
209 |
-
/* IE 5-7 */ filter: alpha(opacity=80);
|
210 |
-
/* Netscape */ -moz-opacity: 0.8;
|
211 |
-
/* Safari 1 */ -khtml-opacity: 0.8;
|
212 |
-
position: absolute;
|
213 |
-
text-align: center;
|
214 |
-
overflow: hidden;
|
215 |
-
cursor: pointer;
|
216 |
-
color: #fff;
|
217 |
-
width: 100%;
|
218 |
-
display: none;
|
219 |
-
}
|
220 |
-
|
221 |
-
|
222 |
-
.wc-cal-event-delete {
|
223 |
-
float: right;
|
224 |
-
cursor: pointer;
|
225 |
-
width: 16px;
|
226 |
-
height: 16px;
|
227 |
-
}
|
228 |
-
|
229 |
-
.wc-cal-event.ui-resizable-resizing {
|
230 |
-
cursor: s-resize;
|
231 |
-
}
|
232 |
-
|
233 |
-
.wc-cal-event .wc-time {
|
234 |
-
background-color: #2b72d0;
|
235 |
-
border: 1px solid #1b62c0;
|
236 |
-
color: #fff;
|
237 |
-
padding: 0;
|
238 |
-
font-weight: bold;
|
239 |
-
}
|
240 |
-
|
241 |
-
.wc-container .ui-draggable .wc-time {
|
242 |
-
cursor: move;
|
243 |
-
}
|
244 |
-
|
245 |
-
.wc-cal-event .wc-title {
|
246 |
-
position: relative;
|
247 |
-
}
|
248 |
-
|
249 |
-
.wc-container .ui-resizable-s {
|
250 |
-
height: 10px;
|
251 |
-
line-height: 10px;
|
252 |
-
bottom: -2px;
|
253 |
-
font-size: .75em;
|
254 |
-
}
|
255 |
-
|
256 |
-
|
257 |
-
.wc-container .ui-draggable-dragging {
|
258 |
-
z-index: 1000;
|
259 |
-
}
|
260 |
-
|
261 |
-
.free-busy-free{}
|
262 |
-
.free-busy-busy{
|
263 |
-
background:url("../images/ui-bg_flat_0_aaaaaa_40x100.png") repeat scroll 50% 50% #666666;
|
264 |
-
}
|
265 |
-
|
266 |
-
/** hourLine */
|
267 |
-
|
268 |
-
.wc-hourline {
|
269 |
-
height: 0pt;
|
270 |
-
border-top: 2px solid #FF7F6E;
|
271 |
-
overflow: hidden;
|
272 |
-
position: absolute;
|
273 |
-
width: inherit;
|
274 |
-
}
|
275 |
-
|
276 |
-
/* IE6 hacks */
|
277 |
-
* html .wc-no-height-wrapper{position:absolute;}
|
278 |
-
* html .wc-time-slot-wrapper{top:3px;}
|
279 |
-
* html .wc-grid-row-oddeven{top:2px;}
|
280 |
-
* html .wc-grid-row-freebusy{top:1px;}
|
281 |
-
|
282 |
-
/* IE7 hacks */
|
283 |
-
*:first-child+html .wc-no-height-wrapper{position:relative;}
|
284 |
-
*:first-child+html .wc-time-slot-wrapper{top:3px;}
|
285 |
-
*:first-child+html .wc-grid-row-oddeven{top:2px;}
|
286 |
-
*:first-child+html .wc-grid-row-freebusy{top:1px;}
|
287 |
-
*:first-child+html .wc-time-slots .wc-today{/* due to rendering issues, no background */background:none;}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/images/calendar1.png
DELETED
Binary file
|
backend/modules/calendar/resources/images/chosen-sprite.png
DELETED
Binary file
|
backend/modules/calendar/resources/images/information.png
DELETED
Binary file
|
backend/modules/calendar/resources/images/ui-bg_flat_0_aaaaaa_40x100.png
DELETED
Binary file
|
backend/modules/calendar/resources/images/user-white.png
DELETED
Binary file
|
backend/modules/calendar/resources/images/user.png
DELETED
Binary file
|
backend/modules/calendar/resources/js/calendar.js
CHANGED
@@ -1,525 +1,383 @@
|
|
1 |
jQuery(function ($) {
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
},
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
},
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
eventRender : function(calEvent, $event) {
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
borderRightColor : calEvent.color,
|
50 |
-
borderTopColor : calEvent.color,
|
51 |
-
borderBottomColor : '#ABABAB'
|
52 |
-
});
|
53 |
-
},
|
54 |
-
eventAfterRender : function(calEvent, $calEventList) {
|
55 |
-
$calEventList.each(function () {
|
56 |
-
var $calEvent = $(this);
|
57 |
-
var titleHeight = $calEvent.find('.wc-title').height();
|
58 |
-
var origHeight = $calEvent.height();
|
59 |
-
|
60 |
-
if ( origHeight < titleHeight ) {
|
61 |
-
var $info = $('<div class="wc-information"/>');
|
62 |
-
var $delete = $('.wc-cal-event-delete', $calEvent);
|
63 |
-
|
64 |
-
$delete.hide();
|
65 |
-
$('.wc-time', $calEvent).prepend($info);
|
66 |
-
|
67 |
-
// mouse handlers
|
68 |
-
$info.on('mouseenter', function () {
|
69 |
-
$calEvent.css({height: (titleHeight + 30), 'z-index': 1});
|
70 |
-
$info.hide();
|
71 |
-
$delete.show();
|
72 |
-
});
|
73 |
-
$calEvent.on('mouseleave', function () {
|
74 |
-
$calEvent.css({height: origHeight, 'z-index': 'auto'});
|
75 |
-
$delete.hide();
|
76 |
-
$info.show();
|
77 |
-
});
|
78 |
}
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
daysToShow: 7,
|
91 |
-
eventNew: function(calEvent, element, dayFreeBusyManager, calendar, mouseupEvent) {
|
92 |
-
element.hide().remove();
|
93 |
-
showAppointmentDialog(
|
94 |
-
null,
|
95 |
-
$week_calendar_wrapper.find('.ab-calendar-tab.active').data('staff-id'),
|
96 |
-
calEvent.start,
|
97 |
-
null,
|
98 |
-
calendar,
|
99 |
-
'week'
|
100 |
-
);
|
101 |
-
},
|
102 |
-
eventClick: function(calEvent, element, dayFreeBusyManager, calendar, clickEvent) {
|
103 |
-
showAppointmentDialog(
|
104 |
-
calEvent.id,
|
105 |
-
$week_calendar_wrapper.find('.ab-calendar-tab.active').data('staff-id'),
|
106 |
-
calEvent.start,
|
107 |
-
calEvent.end,
|
108 |
-
calendar,
|
109 |
-
'week'
|
110 |
-
);
|
111 |
-
},
|
112 |
-
data: function(start, end, callback) {
|
113 |
-
$.post(
|
114 |
-
ajaxurl,
|
115 |
-
{
|
116 |
-
action : 'ab_week_staff_appointments',
|
117 |
-
start_date : getFormattedDateForCalendar(start),
|
118 |
-
end_date : getFormattedDateForCalendar(end),
|
119 |
-
staff_id : $week_calendar_wrapper.find('.ab-calendar-tab.active').data('staff-id')
|
120 |
-
},
|
121 |
-
function (response) {
|
122 |
-
var appointments = $.map(response.events, function(value) {
|
123 |
-
return {
|
124 |
-
id : parseInt(value.id, 10),
|
125 |
-
start : new Date(value.start),
|
126 |
-
end : new Date(value.end),
|
127 |
-
title : value.title,
|
128 |
-
desc : value.desc,
|
129 |
-
color : value.color
|
130 |
-
};
|
131 |
-
});
|
132 |
-
var free_busys = $.map(response.freebusys, function(value) {
|
133 |
-
return {
|
134 |
-
start : new Date(value.start),
|
135 |
-
end : new Date(value.end),
|
136 |
-
free : value.free
|
137 |
-
};
|
138 |
-
});
|
139 |
-
|
140 |
-
callback({ events: appointments, freebusys: free_busys });
|
141 |
-
},
|
142 |
-
'json'
|
143 |
-
);
|
144 |
-
},
|
145 |
-
height: function() {
|
146 |
-
var $window_height = $(window).height(),
|
147 |
-
$wp_admin_bar_height = $('#wpadminbar').height(),
|
148 |
-
$ab_calendar_header_height = $('#ab_calendar_header').height(),
|
149 |
-
$ab_calendar_tabs_height = $('#week_calendar_wrapper .tabbable').outerHeight(true),
|
150 |
-
$height_to_reduce = $wp_admin_bar_height + $ab_calendar_header_height + $ab_calendar_tabs_height,
|
151 |
-
$wrap = $('#wpbody-content .wrap');
|
152 |
-
|
153 |
-
if ($wrap.css('margin-top')) {
|
154 |
-
$height_to_reduce += parseInt($wrap.css('margin-top').replace('px', ''), 10);
|
155 |
-
}
|
156 |
-
|
157 |
-
if ($wrap.css('margin-bottom')) {
|
158 |
-
$height_to_reduce += parseInt($wrap.css('margin-bottom').replace('px', ''), 10);
|
159 |
-
}
|
160 |
-
|
161 |
-
return $window_height - $height_to_reduce;
|
162 |
-
}
|
163 |
-
},
|
164 |
-
$day_calendar_options = {
|
165 |
-
data: function(start, end, callback) {
|
166 |
-
var selected_staff_ids = [];
|
167 |
-
$('.ab-staff-option:checked').each(function() {
|
168 |
-
selected_staff_ids.push(this.value);
|
169 |
-
});
|
170 |
-
var data = {
|
171 |
-
action : 'ab_day_staff_appointments',
|
172 |
-
start_date : getFormattedDateForCalendar(start),
|
173 |
-
staff_id : selected_staff_ids
|
174 |
-
};
|
175 |
-
$.post(
|
176 |
-
ajaxurl, data, function (response) {
|
177 |
-
var appointments = $.map(response.events, function(value) {
|
178 |
-
return {
|
179 |
-
id : parseInt(value.id, 10),
|
180 |
-
start : new Date(value.start),
|
181 |
-
end : new Date(value.end),
|
182 |
-
title : value.title,
|
183 |
-
color : value.color,
|
184 |
-
desc : value.desc,
|
185 |
-
userId : parseInt(value.userId, 10)
|
186 |
-
};
|
187 |
-
});
|
188 |
-
var free_busys = $.map(response.freebusys, function(value) {
|
189 |
-
return {
|
190 |
-
start : new Date(value.start),
|
191 |
-
end : new Date(value.end),
|
192 |
-
free : value.free,
|
193 |
-
userId : parseInt(value.userId, 10)
|
194 |
-
};
|
195 |
-
});
|
196 |
-
|
197 |
-
callback({ events: appointments, freebusys: free_busys });
|
198 |
-
},
|
199 |
-
'json'
|
200 |
-
);
|
201 |
},
|
202 |
-
|
203 |
-
|
204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
},
|
206 |
-
|
207 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
},
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
226 |
},
|
227 |
-
|
228 |
-
|
229 |
-
showAppointmentDialog(
|
230 |
-
null,
|
231 |
-
calEvent.userId,
|
232 |
-
calEvent.start,
|
233 |
-
null,
|
234 |
-
calendar,
|
235 |
-
'day'
|
236 |
-
);
|
237 |
},
|
238 |
-
|
239 |
-
|
240 |
-
calEvent.id,
|
241 |
-
calEvent.userId,
|
242 |
-
calEvent.start,
|
243 |
-
calEvent.end,
|
244 |
-
calendar,
|
245 |
-
'day'
|
246 |
-
);
|
247 |
}
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
week_picker.attachCalendar($week_calendar);
|
254 |
-
|
255 |
-
// week calendar
|
256 |
-
$week_calendar.weekCalendar($.extend({}, $calendar_common_options, $week_calendar_options));
|
257 |
-
|
258 |
-
// click on tabs
|
259 |
-
$tabs.find('.ab-calendar-tab').on('click', function(e) {
|
260 |
-
e.stopPropagation();
|
261 |
-
$('.ab-calendar-tab').removeClass('active');
|
262 |
-
$(this).addClass('active');
|
263 |
-
// prevents console error of initialization
|
264 |
-
$week_calendar.weekCalendar(); $week_calendar.weekCalendar('refresh');
|
265 |
-
});
|
266 |
-
|
267 |
-
// today
|
268 |
-
$('.ab-nav-calendar .ab-calendar-today').on('click', function(){
|
269 |
-
var $active_view_button = $('.ab-nav-calendar .ab-calendar-switch-view.ab-button-active');
|
270 |
-
if ($active_view_button.hasClass('ab-calendar-day')) {
|
271 |
-
day_picker.setDate(new Date());
|
272 |
} else {
|
273 |
-
|
274 |
}
|
275 |
-
});
|
276 |
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
return first_day_of_week <= now_date && now_date <= last_day_of_week;
|
308 |
-
},
|
309 |
-
|
310 |
-
/**
|
311 |
-
* result is an object of dates for start (monday)
|
312 |
-
* and end (sunday) of week based on supplied date object
|
313 |
-
*
|
314 |
-
* @return object
|
315 |
-
*/
|
316 |
-
startAndEndOfWeek = function(date) {
|
317 |
-
var result = {
|
318 |
-
first_day_of_week : null,
|
319 |
-
last_day_of_week : null
|
320 |
-
};
|
321 |
-
|
322 |
-
// If no date object supplied, use current date
|
323 |
-
// Copy date so don't modify supplied date
|
324 |
-
var now = date ? new Date(date) : new Date();
|
325 |
-
|
326 |
-
// set time to some convenient value
|
327 |
-
now.setHours(0, 0, 0, 0);
|
328 |
-
|
329 |
-
// Get the previous Monday
|
330 |
-
var monday = new Date(now);
|
331 |
-
monday.setDate(monday.getDate() - monday.getDay() + 1);
|
332 |
-
|
333 |
-
// Get next Sunday
|
334 |
-
var sunday = new Date(now);
|
335 |
-
sunday.setDate(sunday.getDate() - sunday.getDay() + 7);
|
336 |
-
|
337 |
-
// set result's days
|
338 |
-
result.first_day_of_week = monday;
|
339 |
-
result.last_day_of_week = sunday;
|
340 |
-
|
341 |
-
return result;
|
342 |
-
};
|
343 |
-
|
344 |
-
// Set visible users.
|
345 |
-
var users = [];
|
346 |
-
$('.ab-staff-option:checked').each(function() {
|
347 |
-
users.push({staff_id: parseInt(this.value), full_name: $(this).next().text()});
|
348 |
-
});
|
349 |
-
$day_calendar = $('<div class="ab-calendar-element" />').appendTo($day_calendar_container);
|
350 |
-
$day_calendar.weekCalendar($.extend({date: date_from_week_picker}, $calendar_common_options, $day_calendar_options, {users: users}));
|
351 |
-
$day_calendar_wrapper.show();
|
352 |
-
|
353 |
-
day_picker.attachCalendar($day_calendar);
|
354 |
-
|
355 |
-
// if week is current - set current date, otherwise set date from week-picker
|
356 |
-
is_current_week() ?
|
357 |
-
day_picker.setDate(new Date(), true) :
|
358 |
-
day_picker.setDate(date_from_week_picker, true);
|
359 |
-
|
360 |
-
day_picker.show();
|
361 |
-
|
362 |
-
// styles-fixing
|
363 |
-
$('td.wc-scrollbar-shim').hide();
|
364 |
-
// Switch to week view
|
365 |
-
} else {
|
366 |
-
$day_calendar_wrapper.hide();
|
367 |
-
$day_calendar.remove();
|
368 |
-
day_picker.hide();
|
369 |
-
|
370 |
-
var $week_calendar_container = $week_calendar_wrapper.find('.ab-calendar-element-container'),
|
371 |
-
date_from_day_picker = day_picker.getDate();
|
372 |
-
|
373 |
-
// Show tabs based on selected staff members.
|
374 |
-
var active_set = false;
|
375 |
-
$staff_option.each(function() {
|
376 |
-
if (this.checked) {
|
377 |
-
$('.ab-staff-tab-' + this.value).show().toggleClass('active', active_set === false);
|
378 |
-
active_set = true;
|
379 |
-
} else {
|
380 |
-
$('.ab-staff-tab-' + this.value).hide().removeClass('active');
|
381 |
}
|
382 |
-
|
383 |
-
|
384 |
-
$week_calendar = $('<div class="ab-calendar-element" />').appendTo($week_calendar_container);
|
385 |
-
if (active_set) {
|
386 |
-
$week_calendar_wrapper.show();
|
387 |
-
}
|
388 |
-
$week_calendar.weekCalendar($.extend({date: date_from_day_picker}, $calendar_common_options, $week_calendar_options));
|
389 |
-
scrollShim = document.querySelector('.wc-scrollbar-shim');
|
390 |
-
if ( scrollShim !== null ) scrollShim.style.width = scrollWidth + 'px';
|
391 |
-
|
392 |
-
// Set date from day calendar
|
393 |
-
week_picker.setDate(date_from_day_picker, false);
|
394 |
-
week_picker.attachCalendar($week_calendar);
|
395 |
-
week_picker.show();
|
396 |
-
} // end of Week View
|
397 |
-
});
|
398 |
-
|
399 |
-
// Staff filter
|
400 |
-
$('.ab-staff-filter-button').on('click', function (e) {
|
401 |
-
e.stopPropagation();
|
402 |
-
var menu = $(this).parent().find('.dropdown-menu');
|
403 |
-
if (menu.hasClass('open')) {
|
404 |
-
menu.removeClass('open').hide();
|
405 |
-
} else {
|
406 |
-
menu.addClass('open').show();
|
407 |
-
}
|
408 |
-
});
|
409 |
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
|
414 |
-
|
415 |
-
$
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
if (is_day) { // Day
|
436 |
-
// checkboxes
|
437 |
-
if (staff_option_checked) {
|
438 |
-
$day_calendar_wrapper.show();
|
439 |
-
// Refresh visible users in calendar.
|
440 |
-
var users = [];
|
441 |
-
$('.ab-staff-option:checked').each(function() {
|
442 |
-
users.push({staff_id: parseInt(this.value), full_name: $(this).next().text()});
|
443 |
-
});
|
444 |
-
$day_calendar.weekCalendar('option', 'users', users);
|
445 |
-
$day_calendar.weekCalendar('refresh');
|
446 |
-
// css-fix
|
447 |
-
$('td.wc-scrollbar-shim').hide();
|
448 |
-
} else { // No staff selected
|
449 |
-
$day_calendar_wrapper.hide();
|
450 |
-
}
|
451 |
-
} else { // Week
|
452 |
-
if (this.checked) {
|
453 |
-
$tab.show().click();
|
454 |
-
$staff_option.each(function(k, v) {
|
455 |
-
if ($(v).is(':not(:checked)') && !unchecked_options[$(v).val()]) {
|
456 |
-
unchecked_options.push($(v).val());
|
457 |
-
}
|
458 |
-
});
|
459 |
-
$active_tab.parent().find('li').each(function(k, v) {
|
460 |
-
unchecked_options.forEach(function(option) {
|
461 |
-
if ($(v).data('staff-id') == option) {
|
462 |
-
$('ul.nav-tabs').find('li').filter('[data-staff-id="' + option + '"]').hide();
|
463 |
}
|
464 |
-
|
465 |
-
}
|
466 |
-
|
467 |
-
$tab.hide();
|
468 |
-
$active_tab.is(':visible') ? $active_tab.click() : $staff_tabs.filter(':visible').filter(':first').click();
|
469 |
-
}
|
470 |
-
staff_option_checked ? $week_calendar_wrapper.show() : $week_calendar_wrapper.hide();
|
471 |
-
}
|
472 |
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
$staff_filter_button.text('No staff selected');
|
477 |
-
} else if (selected_staff_numb == 1) {
|
478 |
-
$staff_filter_button.text($("label[for='" + $staff_option.filter(':checked').attr('id') + "']").text());
|
479 |
-
} else {
|
480 |
-
$staff_filter_button.text(selected_staff_numb + ' staff members');
|
481 |
-
}
|
482 |
-
});
|
483 |
|
484 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
485 |
|
486 |
-
|
487 |
-
|
488 |
-
*
|
489 |
-
* @param date
|
490 |
-
* @return {String}
|
491 |
-
*/
|
492 |
-
function getFormattedDateForCalendar(date) {
|
493 |
-
var $hours = date.getHours(), $minutes = date.getMinutes();
|
494 |
|
495 |
-
|
496 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
497 |
}
|
498 |
|
499 |
-
|
500 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
501 |
}
|
502 |
|
503 |
-
|
504 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
505 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
* not null for preventing console errors when no one staff exists
|
511 |
-
*/
|
512 |
-
var scroll = document.querySelector('.wc-scrollable-grid'),
|
513 |
-
scrollShim = document.querySelector('.wc-scrollbar-shim'),
|
514 |
-
scrollWidth = scroll !== null ? scroll.offsetWidth - scroll.clientWidth : 0;
|
515 |
|
516 |
-
|
517 |
|
518 |
-
|
519 |
-
|
520 |
-
$('.wc-time-column-header:first-child').css('width','43px');
|
521 |
|
522 |
-
$('#email_notification').on('click', function() {
|
523 |
-
$('#email_notification_text').show();
|
524 |
-
});
|
525 |
});
|
1 |
jQuery(function ($) {
|
2 |
+
|
3 |
+
var $fullCalendar = $('#full_calendar_wrapper .ab-calendar-element'),
|
4 |
+
$tabs = $('li.ab-calendar-tab'),
|
5 |
+
$staff = $('input.ab-staff-filter'),
|
6 |
+
$showAll = $('input#ab-filter-all-staff'),
|
7 |
+
firstHour = new Date().getHours(),
|
8 |
+
$staffButton = $('#ab-staff-button'),
|
9 |
+
staffMembers = [],
|
10 |
+
staffIds = getCookie('bookly_cal_st_ids'),
|
11 |
+
tabId = getCookie('bookly_cal_tab_id'),
|
12 |
+
lastView = getCookie('bookly_cal_view'),
|
13 |
+
views = 'month,agendaWeek,agendaDay,multiStaffDay';
|
14 |
+
|
15 |
+
if (views.indexOf(lastView) == -1) {
|
16 |
+
lastView = 'agendaWeek';
|
17 |
+
}
|
18 |
+
// Init tabs and staff member filters.
|
19 |
+
if (staffIds === null) {
|
20 |
+
$staff.each(function(index, value){
|
21 |
+
this.checked = true;
|
22 |
+
$tabs.filter('[data-staff_id=' + this.value + ']').show();
|
23 |
+
});
|
24 |
+
} else if (staffIds != '') {
|
25 |
+
$.each(staffIds.split(','), function (index, value){
|
26 |
+
$staff.filter('[value=' + value + ']').prop('checked', true);
|
27 |
+
$tabs.filter('[data-staff_id=' + value + ']').show();
|
28 |
+
});
|
29 |
+
} else {
|
30 |
+
$('.dropdown-toggle').dropdown('toggle');
|
31 |
+
}
|
32 |
+
|
33 |
+
$tabs.filter('[data-staff_id=' + tabId + ']').addClass('active');
|
34 |
+
if ($tabs.filter('li.active').length == 0) {
|
35 |
+
$tabs.eq(0).addClass('active').show();
|
36 |
+
$staff.filter('[value=' + $tabs.eq(0).data('staff_id') + ']').prop('checked', true);
|
37 |
+
}
|
38 |
+
updateStaffButton();
|
39 |
+
|
40 |
+
// Init FullCalendar.
|
41 |
+
$fullCalendar.fullCalendar({
|
42 |
+
// General Display.
|
43 |
+
firstDay: BooklyL10n.startOfWeek,
|
44 |
+
header: {
|
45 |
+
left: 'prev,next today',
|
46 |
+
center: 'title',
|
47 |
+
right: views
|
48 |
},
|
49 |
+
height: heightFC(),
|
50 |
+
// Views.
|
51 |
+
defaultView: lastView,
|
52 |
+
scrollTime: firstHour+':00:00',
|
53 |
+
views: {
|
54 |
+
agendaWeek: {
|
55 |
+
columnFormat: 'ddd, D'
|
56 |
+
},
|
57 |
+
multiStaffDay: {
|
58 |
+
staffMembers: staffMembers
|
59 |
+
}
|
60 |
},
|
61 |
+
eventBackgroundColor: 'silver',
|
62 |
+
// Agenda Options.
|
63 |
+
allDaySlot: false,
|
64 |
+
allDayText: BooklyL10n.allDay,
|
65 |
+
axisFormat: BooklyL10n.mjsTimeFormat,
|
66 |
+
slotDuration: BooklyL10n.slotDuration,
|
67 |
+
// Text/Time Customization.
|
68 |
+
timeFormat: BooklyL10n.mjsTimeFormat,
|
69 |
+
displayEventEnd: true,
|
70 |
+
buttonText : {
|
71 |
+
today: BooklyL10n.today,
|
72 |
+
month: BooklyL10n.month,
|
73 |
+
week: BooklyL10n.week,
|
74 |
+
day: BooklyL10n.day
|
75 |
},
|
76 |
+
monthNames: BooklyL10n.longMonths,
|
77 |
+
monthNamesShort: BooklyL10n.shortMonths,
|
78 |
+
dayNames: BooklyL10n.longDays,
|
79 |
+
dayNamesShort: BooklyL10n.shortDays,
|
80 |
+
// Event Dragging & Resizing.
|
81 |
+
editable: false,
|
82 |
+
// Event Data.
|
83 |
+
eventSources: [{
|
84 |
+
url: ajaxurl,
|
85 |
+
data: {
|
86 |
+
action : 'ab_get_staff_appointments',
|
87 |
+
staff_ids : function() {
|
88 |
+
var ids = [];
|
89 |
+
if ($tabs.filter('.active').data('staff_id') == 0) {
|
90 |
+
for (var i = 0; i < staffMembers.length; ++i) {
|
91 |
+
ids.push(staffMembers[i].id);
|
92 |
+
}
|
93 |
+
} else {
|
94 |
+
ids.push($tabs.filter('.active').data('staff_id'));
|
95 |
+
}
|
96 |
+
return ids;
|
97 |
+
}
|
98 |
+
}
|
99 |
+
}],
|
100 |
+
// Event Rendering.
|
101 |
eventRender : function(calEvent, $event) {
|
102 |
+
var body = '<div class="fc-service-name">' + calEvent.title + '<i class="delete-event icon-rt glyphicon glyphicon-trash"></i></div>';
|
103 |
+
|
104 |
+
if (calEvent.desc) {
|
105 |
+
body += calEvent.desc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
106 |
}
|
107 |
+
|
108 |
+
$event.find('.fc-title').html(body);
|
109 |
+
|
110 |
+
$event.find('i.delete-event').on('click', function(e) {
|
111 |
+
e.stopPropagation();
|
112 |
+
if (confirm(BooklyL10n.are_you_sure)) {
|
113 |
+
$.post(ajaxurl, {'action' : 'ab_delete_appointment', 'appointment_id' : calEvent.id }, function () {
|
114 |
+
$fullCalendar.fullCalendar('removeEvents', calEvent.id);
|
115 |
+
});
|
116 |
+
}
|
117 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
},
|
119 |
+
eventAfterRender : function(calEvent, $calEventList, calendar) {
|
120 |
+
$calEventList.each(function () {
|
121 |
+
var $calEvent = $(this);
|
122 |
+
var titleHeight = $calEvent.find('.fc-title').height();
|
123 |
+
var origHeight = $calEvent.height();
|
124 |
+
|
125 |
+
if ( origHeight < titleHeight ) {
|
126 |
+
var $info = $('<i class="icon-rt glyphicon glyphicon-info-sign"></i>');
|
127 |
+
var $delete = $('.delete-event', $calEvent);
|
128 |
+
|
129 |
+
$delete.hide();
|
130 |
+
$('.fc-content', $calEvent).append($info);
|
131 |
+
$('.fc-content', $calEvent).append($delete);
|
132 |
+
|
133 |
+
var z_index = $calEvent.zIndex();
|
134 |
+
// Mouse handlers.
|
135 |
+
$info.on('mouseenter', function () {
|
136 |
+
$calEvent.css({height: (titleHeight + 30), 'z-index': 64});
|
137 |
+
$info.hide();
|
138 |
+
$delete.show();
|
139 |
+
$calEvent.removeClass('fc-short');
|
140 |
+
});
|
141 |
+
$calEvent.on('mouseleave', function () {
|
142 |
+
$calEvent.css({height: origHeight, 'z-index': z_index});
|
143 |
+
$delete.hide();
|
144 |
+
$info.show();
|
145 |
+
$calEvent.addClass('fc-short');
|
146 |
+
});
|
147 |
+
}
|
148 |
+
});
|
149 |
},
|
150 |
+
// Clicking & Hovering.
|
151 |
+
dayClick: function(date, jsEvent, view) {
|
152 |
+
var staff_id, visible_staff_id;
|
153 |
+
if (view.type == 'multiStaffDay') {
|
154 |
+
var cell = view.coordMap.getCell(jsEvent.pageX, jsEvent.pageY);
|
155 |
+
var staffMembers = view.opt('staffMembers');
|
156 |
+
staff_id = staffMembers[cell.col].id;
|
157 |
+
visible_staff_id = 0;
|
158 |
+
} else {
|
159 |
+
staff_id = visible_staff_id = $tabs.filter('.active').data('staff_id');
|
160 |
+
}
|
161 |
+
|
162 |
+
showAppointmentDialog(
|
163 |
+
null,
|
164 |
+
staff_id,
|
165 |
+
date,
|
166 |
+
null,
|
167 |
+
function(event) {
|
168 |
+
if (visible_staff_id == event.staffId || visible_staff_id == 0) {
|
169 |
+
// Create event in calendar.
|
170 |
+
$fullCalendar.fullCalendar('renderEvent', event );
|
171 |
+
} else {
|
172 |
+
// Switch to the event owner tab.
|
173 |
+
jQuery('li[data-staff_id=' + event.staffId + ']').click();
|
174 |
+
}
|
175 |
+
}
|
176 |
+
);
|
177 |
},
|
178 |
+
eventClick: function(calEvent, jsEvent, view) {
|
179 |
+
var visible_staff_id;
|
180 |
+
if (view.type == 'multiStaffDay') {
|
181 |
+
visible_staff_id = 0;
|
182 |
+
} else {
|
183 |
+
visible_staff_id = calEvent.staffId;
|
184 |
+
}
|
185 |
+
|
186 |
+
showAppointmentDialog(
|
187 |
+
calEvent.id,
|
188 |
+
calEvent.staffId,
|
189 |
+
calEvent.start,
|
190 |
+
calEvent.end,
|
191 |
+
function(event) {
|
192 |
+
if (visible_staff_id == event.staffId || visible_staff_id == 0) {
|
193 |
+
// Update event in calendar.
|
194 |
+
jQuery.extend(calEvent, event);
|
195 |
+
$fullCalendar.fullCalendar('updateEvent', calEvent);
|
196 |
+
} else {
|
197 |
+
// Switch to the event owner tab.
|
198 |
+
jQuery('li[data-staff_id=' + event.staffId + ']').click();
|
199 |
+
}
|
200 |
+
}
|
201 |
+
);
|
202 |
},
|
203 |
+
loading: function (bool) {
|
204 |
+
bool ? $('.ab-loading-inner').show() : $('.ab-loading-inner').hide();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
},
|
206 |
+
viewRender: function(view, element){
|
207 |
+
setCookie('bookly_cal_view',view.type);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
208 |
}
|
209 |
+
});
|
210 |
+
|
211 |
+
$('.fc-agendaDay-button').addClass('fc-corner-right');
|
212 |
+
if ($tabs.filter('.active').data('staff_id') == 0) {
|
213 |
+
$('.fc-agendaDay-button').hide();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
214 |
} else {
|
215 |
+
$('.fc-multiStaffDay-button').hide();
|
216 |
}
|
|
|
217 |
|
218 |
+
// Init date picker for fast navigation in FullCalendar.
|
219 |
+
var $fcDatePicker = $('<input type=hidden />');
|
220 |
+
$('.fc-toolbar .fc-center h2').before($fcDatePicker).on('click', function() {
|
221 |
+
$fcDatePicker.datepicker('setDate', $fullCalendar.fullCalendar('getDate').toDate()).datepicker('show');
|
222 |
+
});
|
223 |
+
$fcDatePicker.datepicker({
|
224 |
+
dayNamesMin : BooklyL10n.shortDays,
|
225 |
+
monthNames : BooklyL10n.longMonths,
|
226 |
+
monthNamesShort : BooklyL10n.shortMonths,
|
227 |
+
firstDay : BooklyL10n.startOfWeek,
|
228 |
+
beforeShow: function(input, inst){
|
229 |
+
inst.dpDiv.queue(function() {
|
230 |
+
inst.dpDiv.css({marginTop: '35px'});
|
231 |
+
inst.dpDiv.dequeue();
|
232 |
+
});
|
233 |
+
},
|
234 |
+
onSelect: function(dateText, inst) {
|
235 |
+
var d = new Date(dateText);
|
236 |
+
$fullCalendar.fullCalendar('gotoDate', d);
|
237 |
+
if( $fullCalendar.fullCalendar('getView').type != 'agendaDay' &&
|
238 |
+
$fullCalendar.fullCalendar('getView').type != 'multiStaffDay' ){
|
239 |
+
$fullCalendar.find('.fc-day').removeClass('ab-fcday-active');
|
240 |
+
$fullCalendar.find('.fc-day[data-date="' + moment(d).format('YYYY-MM-DD') + '"]').addClass('ab-fcday-active');
|
241 |
+
}
|
242 |
+
},
|
243 |
+
onClose: function(dateText, inst) {
|
244 |
+
inst.dpDiv.queue(function() {
|
245 |
+
inst.dpDiv.css({marginTop: '0'});
|
246 |
+
inst.dpDiv.dequeue();
|
247 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
}
|
249 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
250 |
|
251 |
+
$(window).on('resize', function() {
|
252 |
+
$fullCalendar.fullCalendar('option', 'height', heightFC());
|
253 |
+
});
|
254 |
|
255 |
+
// Click on tabs.
|
256 |
+
$tabs.on('click', function(e) {
|
257 |
+
e.preventDefault();
|
258 |
+
$tabs.removeClass('active');
|
259 |
+
$(this).addClass('active');
|
260 |
+
|
261 |
+
var staff_id = $(this).data('staff_id');
|
262 |
+
setCookie('bookly_cal_tab_id', staff_id);
|
263 |
+
|
264 |
+
if (staff_id == 0) {
|
265 |
+
$('.fc-agendaDay-button').hide();
|
266 |
+
$('.fc-multiStaffDay-button').show();
|
267 |
+
$fullCalendar.fullCalendar('changeView', 'multiStaffDay');
|
268 |
+
$fullCalendar.fullCalendar('refetchEvents');
|
269 |
+
} else {
|
270 |
+
$('.fc-multiStaffDay-button').hide();
|
271 |
+
$('.fc-agendaDay-button').show();
|
272 |
+
var view = $fullCalendar.fullCalendar('getView');
|
273 |
+
if (view.type == 'multiStaffDay') {
|
274 |
+
$fullCalendar.fullCalendar('changeView', 'agendaDay');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
275 |
}
|
276 |
+
$fullCalendar.fullCalendar('refetchEvents');
|
277 |
+
}
|
278 |
+
});
|
|
|
|
|
|
|
|
|
|
|
279 |
|
280 |
+
$('.dropdown-menu').on('click', function (e) {
|
281 |
+
e.stopPropagation();
|
282 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
283 |
|
284 |
+
/**
|
285 |
+
* On show all staff checkbox click.
|
286 |
+
*/
|
287 |
+
$showAll.on('change', function () {
|
288 |
+
$tabs.filter('[data-staff_id!=0]').toggle(this.checked);
|
289 |
+
$staff
|
290 |
+
.prop('checked', this.checked)
|
291 |
+
.filter(':first').triggerHandler('change');
|
292 |
+
});
|
293 |
+
|
294 |
+
/**
|
295 |
+
* On staff checkbox click.
|
296 |
+
*/
|
297 |
+
$staff.on('change', function (e) {
|
298 |
+
updateStaffButton();
|
299 |
+
|
300 |
+
$tabs.filter('[data-staff_id=' + this.value + ']').toggle(this.checked);
|
301 |
+
if ($tabs.filter(':visible.active').length == 0 ) {
|
302 |
+
$tabs.filter(':visible:first').triggerHandler('click');
|
303 |
+
} else if ($tabs.filter('.active').data('staff_id') == 0) {
|
304 |
+
var view = $fullCalendar.fullCalendar('getView');
|
305 |
+
if (view.type == 'multiStaffDay') {
|
306 |
+
view.displayView($fullCalendar.fullCalendar('getDate'));
|
307 |
+
}
|
308 |
+
$fullCalendar.fullCalendar('refetchEvents');
|
309 |
+
}
|
310 |
+
});
|
311 |
|
312 |
+
function updateStaffButton() {
|
313 |
+
$showAll.prop('checked', $staff.filter(':not(:checked)').length == 0);
|
|
|
|
|
|
|
|
|
|
|
|
|
314 |
|
315 |
+
// Update staffMembers array.
|
316 |
+
var ids = [];
|
317 |
+
staffMembers.length = 0;
|
318 |
+
$staff.filter(':checked').each(function() {
|
319 |
+
staffMembers.push({id: this.value, name: this.getAttribute('data-staff_name')});
|
320 |
+
ids.push(this.value);
|
321 |
+
});
|
322 |
+
setCookie('bookly_cal_st_ids', ids);
|
323 |
+
|
324 |
+
// Update button text.
|
325 |
+
var number = $staff.filter(':checked').length;
|
326 |
+
if (number == 0) {
|
327 |
+
$staffButton.text(BooklyL10n.noStaffSelected);
|
328 |
+
} else if (number == 1) {
|
329 |
+
$staffButton.text($staff.filter(':checked').data('staff_name'));
|
330 |
+
} else {
|
331 |
+
$staffButton.text(number + '/' + $staff.length);
|
332 |
+
}
|
333 |
}
|
334 |
|
335 |
+
/**
|
336 |
+
* Set cookie.
|
337 |
+
*
|
338 |
+
* @param key
|
339 |
+
* @param value
|
340 |
+
*/
|
341 |
+
function setCookie(key, value) {
|
342 |
+
var expires = new Date();
|
343 |
+
expires.setTime(expires.getTime() + (1 * 24 * 60 * 60 * 1000));
|
344 |
+
document.cookie = key + '=' + value + ';expires=' + expires.toUTCString();
|
345 |
}
|
346 |
|
347 |
+
/**
|
348 |
+
* Get cookie.
|
349 |
+
*
|
350 |
+
* @param key
|
351 |
+
* @return {*}
|
352 |
+
*/
|
353 |
+
function getCookie(key) {
|
354 |
+
var keyValue = document.cookie.match('(^|;) ?' + key + '=([^;]*)(;|$)');
|
355 |
+
return keyValue ? keyValue[2] : null;
|
356 |
+
}
|
357 |
|
358 |
+
/**
|
359 |
+
* Calculate height of FullCalendar.
|
360 |
+
*
|
361 |
+
* @return {number}
|
362 |
+
*/
|
363 |
+
function heightFC() {
|
364 |
+
var window_height = $(window).height(),
|
365 |
+
wp_admin_bar_height = $('#wpadminbar').height(),
|
366 |
+
ab_calendar_tabs_height = $('#full_calendar_wrapper .tabbable').outerHeight(true),
|
367 |
+
height_to_reduce = wp_admin_bar_height + ab_calendar_tabs_height,
|
368 |
+
$wrap = $('#wpbody-content .wrap');
|
369 |
+
|
370 |
+
if ($wrap.css('margin-top')) {
|
371 |
+
height_to_reduce += parseInt($wrap.css('margin-top').replace('px', ''), 10);
|
372 |
+
}
|
373 |
|
374 |
+
if ($wrap.css('margin-bottom')) {
|
375 |
+
height_to_reduce += parseInt($wrap.css('margin-bottom').replace('px', ''), 10);
|
376 |
+
}
|
|
|
|
|
|
|
|
|
|
|
377 |
|
378 |
+
var res = window_height - height_to_reduce - 130;
|
379 |
|
380 |
+
return res > 620 ? res : 620;
|
381 |
+
}
|
|
|
382 |
|
|
|
|
|
|
|
383 |
});
|
backend/modules/calendar/resources/js/calendar_daypicker.js
DELETED
@@ -1,126 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* Day calendar datepicker.
|
3 |
-
*/
|
4 |
-
function DayPicker() {
|
5 |
-
// Private functions and variables.
|
6 |
-
var widget = {
|
7 |
-
$container : null,
|
8 |
-
$month_days : null,
|
9 |
-
$prev_date_handler : null,
|
10 |
-
$next_date_handler : null,
|
11 |
-
$picker : null, // jQuery UI DatePicker.
|
12 |
-
$calendar : null, // WeekCalendar instance.
|
13 |
-
first_day : null,
|
14 |
-
rebuildDayLine : function(date) {
|
15 |
-
var timestamp = +date / 1000,
|
16 |
-
seconds_in_day = 60 * 60 * 24;
|
17 |
-
for (var i = 1; i <= 7; ++ i) {
|
18 |
-
var next_day_timestamp = (timestamp + (i * seconds_in_day)) * 1000,
|
19 |
-
next_day = new Date(next_day_timestamp),
|
20 |
-
$day_of_month = jQuery(this.$month_days.get(i - 1));
|
21 |
-
$day_of_month
|
22 |
-
.text(next_day.getDate())
|
23 |
-
.data('date_timestamp', next_day_timestamp / 1000);
|
24 |
-
}
|
25 |
-
},
|
26 |
-
/**
|
27 |
-
* Constructor.
|
28 |
-
*/
|
29 |
-
init : function() {
|
30 |
-
this.$container = jQuery('div#day-calendar-picker');
|
31 |
-
this.$month_days = this.$container.find('.ab-day-of-month');
|
32 |
-
this.$prev_date_handler = this.$container.find('.ab-week-picker-arrow-prev');
|
33 |
-
this.$next_date_handler = this.$container.find('.ab-week-picker-arrow-next');
|
34 |
-
this.$picker = this.$container.find('#appendedInput');
|
35 |
-
this.first_day = this.$container.data('first_day');
|
36 |
-
// Init datepicker.
|
37 |
-
this.$picker.datepicker({
|
38 |
-
dateFormat : BooklyL10n['dateFormat'],
|
39 |
-
showOtherMonths : true,
|
40 |
-
selectOtherMonths : true,
|
41 |
-
firstDay : widget.first_day,
|
42 |
-
monthNames : BooklyL10n['longMonths'],
|
43 |
-
monthNamesShort : BooklyL10n['shortMonths'],
|
44 |
-
dayNames : BooklyL10n['longDays'],
|
45 |
-
dayNamesMin : BooklyL10n['shortDays'],
|
46 |
-
dayNamesShort : BooklyL10n['shortDays'],
|
47 |
-
onSelect : function() {
|
48 |
-
var date = widget.$picker.datepicker('getDate');
|
49 |
-
widget.rebuildDayLine(date);
|
50 |
-
if (widget.$calendar) {
|
51 |
-
widget.$calendar.weekCalendar('gotoWeek', date);
|
52 |
-
}
|
53 |
-
widget.$month_days.parent().removeClass('active');
|
54 |
-
}
|
55 |
-
});
|
56 |
-
// Handle events.
|
57 |
-
this.$month_days.on('click', function(e) {
|
58 |
-
e.preventDefault();
|
59 |
-
var $clicked = jQuery(this),
|
60 |
-
$clicked_day_date = new Date(parseInt($clicked.data('date_timestamp'), 10) * 1000);
|
61 |
-
widget.rebuildDayLine($clicked_day_date);
|
62 |
-
widget.$picker.datepicker('setDate', $clicked_day_date);
|
63 |
-
widget.$month_days.parent().removeClass('active');
|
64 |
-
$clicked.parent().addClass('active');
|
65 |
-
if (widget.$calendar) {
|
66 |
-
widget.$calendar.weekCalendar('gotoWeek', $clicked_day_date);
|
67 |
-
}
|
68 |
-
});
|
69 |
-
this.$prev_date_handler.on('click', function() {
|
70 |
-
var date = new Date();
|
71 |
-
date.setDate(widget.$picker.datepicker('getDate').getDate() - 1);
|
72 |
-
widget.rebuildDayLine(date);
|
73 |
-
widget.$picker.datepicker('setDate', date);
|
74 |
-
if (widget.$calendar) {
|
75 |
-
widget.$calendar.weekCalendar('gotoWeek', date);
|
76 |
-
}
|
77 |
-
});
|
78 |
-
this.$next_date_handler.on('click', function() {
|
79 |
-
var date = new Date();
|
80 |
-
date.setDate(widget.$picker.datepicker('getDate').getDate() + 1);
|
81 |
-
widget.rebuildDayLine(date);
|
82 |
-
widget.$picker.datepicker('setDate', date);
|
83 |
-
if (widget.$calendar) {
|
84 |
-
widget.$calendar.weekCalendar('gotoWeek', date);
|
85 |
-
}
|
86 |
-
});
|
87 |
-
}
|
88 |
-
};
|
89 |
-
|
90 |
-
// Init.
|
91 |
-
widget.init();
|
92 |
-
|
93 |
-
// Return public methods.
|
94 |
-
return {
|
95 |
-
show : function() {
|
96 |
-
widget.$container.show();
|
97 |
-
},
|
98 |
-
hide : function() {
|
99 |
-
widget.$container.hide();
|
100 |
-
},
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Set specific date to the widget (and update $calendar if update_week_calendar is true).
|
104 |
-
*
|
105 |
-
* @param date
|
106 |
-
* @param update_week_calendar
|
107 |
-
*/
|
108 |
-
setDate : function(date, update_week_calendar) {
|
109 |
-
widget.rebuildDayLine(date);
|
110 |
-
widget.$picker.datepicker('setDate', date);
|
111 |
-
if (widget.$calendar && (update_week_calendar === undefined || update_week_calendar)) {
|
112 |
-
widget.$calendar.weekCalendar('gotoWeek', date);
|
113 |
-
}
|
114 |
-
},
|
115 |
-
getDate : function() {
|
116 |
-
return widget.$picker.datepicker('getDate');
|
117 |
-
},
|
118 |
-
/**
|
119 |
-
* Attach WeekCalendar to the picker.
|
120 |
-
* @param WeekCalendar $calendar
|
121 |
-
*/
|
122 |
-
attachCalendar : function($calendar) {
|
123 |
-
widget.$calendar = $calendar;
|
124 |
-
}
|
125 |
-
};
|
126 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/js/calendar_weekpicker.js
DELETED
@@ -1,168 +0,0 @@
|
|
1 |
-
/**
|
2 |
-
* Week calendar datepicker.
|
3 |
-
*/
|
4 |
-
function WeekPicker() {
|
5 |
-
// Private functions and variables.
|
6 |
-
var widget = {
|
7 |
-
$container : null,
|
8 |
-
$picker : null, // jQuery UI DatePicker.
|
9 |
-
$output : null, // Place to display week-start and week-end dates.
|
10 |
-
$calendar : null, // WeekCalendar instance.
|
11 |
-
start_date : null,
|
12 |
-
end_date : null,
|
13 |
-
first_day : null,
|
14 |
-
date_format : null,
|
15 |
-
/**
|
16 |
-
* Set start and end dates based on Date object.
|
17 |
-
* @param Date date.
|
18 |
-
*/
|
19 |
-
updateStartAndEndDates : function(date) {
|
20 |
-
var seconds_in_one_day = 86400000;
|
21 |
-
var days_to_rewind = date.getDay() <= 0 ? 7 - this.first_day : date.getDay() - this.first_day;
|
22 |
-
var days_to_add = 6;
|
23 |
-
this.start_date = new Date(date.valueOf() - days_to_rewind * seconds_in_one_day); //rewind to start day
|
24 |
-
this.end_date = new Date(this.start_date.valueOf() + days_to_add * seconds_in_one_day); //add 6 days to get last day
|
25 |
-
},
|
26 |
-
/**
|
27 |
-
* Highlight all days in currently selected week.
|
28 |
-
*/
|
29 |
-
highlightSelectedWeek : function() {
|
30 |
-
window.setTimeout(function () {
|
31 |
-
widget.$picker.find('.ui-datepicker-current-day a').addClass('ui-state-active')
|
32 |
-
}, 1);
|
33 |
-
},
|
34 |
-
/**
|
35 |
-
* Display start and end dates of the selected week.
|
36 |
-
* @param Date start_date
|
37 |
-
* @param Date end_date
|
38 |
-
*/
|
39 |
-
outputFormattedDate : function() {
|
40 |
-
// show formatted date values
|
41 |
-
var formatted_start_date = jQuery.datepicker.formatDate(this.date_format, this.start_date, {monthNamesShort: BooklyL10n['shortMonths'], monthNames : BooklyL10n['longMonths']}),
|
42 |
-
formatted_end_date = jQuery.datepicker.formatDate(this.date_format, this.end_date, {monthNamesShort: BooklyL10n['shortMonths'], monthNames : BooklyL10n['longMonths']});
|
43 |
-
this.$output.val(BooklyL10n['Week'] + formatted_start_date + ' - ' + formatted_end_date);
|
44 |
-
},
|
45 |
-
/**
|
46 |
-
* Set specific date to the widget (and update $calendar if update_week_calendar is true).
|
47 |
-
*
|
48 |
-
* @param date
|
49 |
-
* @param update_week_calendar
|
50 |
-
*/
|
51 |
-
setDate : function(date, update_week_calendar) {
|
52 |
-
this.updateStartAndEndDates(date);
|
53 |
-
this.$picker.datepicker('setDate', date);
|
54 |
-
this.outputFormattedDate();
|
55 |
-
this.highlightSelectedWeek();
|
56 |
-
if (this.$calendar && (update_week_calendar === undefined || update_week_calendar)) {
|
57 |
-
this.$calendar.weekCalendar('gotoWeek', this.start_date);
|
58 |
-
}
|
59 |
-
},
|
60 |
-
/**
|
61 |
-
* Constructor.
|
62 |
-
*/
|
63 |
-
init : function() {
|
64 |
-
this.$container = jQuery('div#week-calendar-picker');
|
65 |
-
this.$picker = this.$container.find('div.ab-week-picker');
|
66 |
-
this.$output = this.$container.find('input.ab-date-calendar');
|
67 |
-
this.first_day = this.$container.data('first_day');
|
68 |
-
this.date_format = BooklyL10n['dateFormat'];
|
69 |
-
// Init start and end dates.
|
70 |
-
this.updateStartAndEndDates(new Date());
|
71 |
-
// Init datepicker.
|
72 |
-
this.$picker.datepicker({
|
73 |
-
showOtherMonths : true,
|
74 |
-
selectOtherMonths : true,
|
75 |
-
firstDay : widget.first_day,
|
76 |
-
monthNames : BooklyL10n['longMonths'],
|
77 |
-
monthNamesShort : BooklyL10n['shortMonths'],
|
78 |
-
dayNames : BooklyL10n['longDays'],
|
79 |
-
dayNamesMin : BooklyL10n['shortDays'],
|
80 |
-
dayNamesShort : BooklyL10n['shortDays'],
|
81 |
-
onSelect : function(dateText, inst) {
|
82 |
-
widget.updateStartAndEndDates(widget.$picker.datepicker('getDate'));
|
83 |
-
widget.outputFormattedDate();
|
84 |
-
widget.highlightSelectedWeek();
|
85 |
-
if (widget.$calendar) {
|
86 |
-
widget.$calendar.weekCalendar('gotoWeek', widget.start_date);
|
87 |
-
}
|
88 |
-
},
|
89 |
-
beforeShowDay : function(date) {
|
90 |
-
var cssClass = '';
|
91 |
-
if ((date >= widget.start_date || date.getDate() == widget.start_date.getDate()) && date <= widget.end_date) {
|
92 |
-
cssClass = 'ui-datepicker-current-day';
|
93 |
-
}
|
94 |
-
return [true, cssClass];
|
95 |
-
},
|
96 |
-
onChangeMonthYear : function(year, month, inst) {
|
97 |
-
widget.highlightSelectedWeek();
|
98 |
-
}
|
99 |
-
});
|
100 |
-
this.highlightSelectedWeek();
|
101 |
-
// Display start and end dates.
|
102 |
-
this.outputFormattedDate();
|
103 |
-
// Handle events.
|
104 |
-
this.$container
|
105 |
-
.on('mousemove', '.ui-datepicker-calendar tr', function() {
|
106 |
-
jQuery(this).find('td a').addClass('ui-state-hover');
|
107 |
-
})
|
108 |
-
.on('mouseleave', '.ui-datepicker-calendar tr', function() {
|
109 |
-
jQuery(this).find('td a').removeClass('ui-state-hover');
|
110 |
-
});
|
111 |
-
jQuery('body').click(function(e) {
|
112 |
-
jQuery('.dropdown-menu:visible').removeClass('open').hide();
|
113 |
-
if (widget.$picker.is(':visible')) {
|
114 |
-
widget.$picker.hide();
|
115 |
-
}
|
116 |
-
});
|
117 |
-
this.$picker.click(function(e) {
|
118 |
-
e.stopPropagation();
|
119 |
-
});
|
120 |
-
// open week picker
|
121 |
-
this.$output.on('click', function(e) {
|
122 |
-
widget.$picker.show();
|
123 |
-
e.stopPropagation();
|
124 |
-
});
|
125 |
-
// do not close week picker when the previous or next arrow is clicked
|
126 |
-
this.$container.find('.prev, .next').on('click', function(e) {
|
127 |
-
e.stopPropagation();
|
128 |
-
});
|
129 |
-
// handle click on the "previous week" arrow
|
130 |
-
this.$container.find('.prev').on('click', function() {
|
131 |
-
var date = widget.$picker.datepicker('getDate');
|
132 |
-
date.addDays(-7);
|
133 |
-
widget.setDate(date);
|
134 |
-
});
|
135 |
-
// handle click on the "next week" arrow
|
136 |
-
this.$container.find('.next').on('click', function() {
|
137 |
-
var date = widget.$picker.datepicker('getDate');
|
138 |
-
date.addDays(7);
|
139 |
-
widget.setDate(date);
|
140 |
-
});
|
141 |
-
}
|
142 |
-
};
|
143 |
-
|
144 |
-
// Init.
|
145 |
-
widget.init();
|
146 |
-
// Return public methods.
|
147 |
-
return {
|
148 |
-
show : function() {
|
149 |
-
widget.$container.show();
|
150 |
-
},
|
151 |
-
hide : function() {
|
152 |
-
widget.$container.hide();
|
153 |
-
},
|
154 |
-
setDate : function(date, update_week_calendar) {
|
155 |
-
widget.setDate(date, update_week_calendar);
|
156 |
-
},
|
157 |
-
getStartDate : function() {
|
158 |
-
return widget.start_date;
|
159 |
-
},
|
160 |
-
/**
|
161 |
-
* Attach WeekCalendar to the picker.
|
162 |
-
* @param WeekCalendar $calendar
|
163 |
-
*/
|
164 |
-
attachCalendar : function($calendar) {
|
165 |
-
widget.$calendar = $calendar;
|
166 |
-
}
|
167 |
-
};
|
168 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/js/chosen.jquery.js
DELETED
@@ -1,1229 +0,0 @@
|
|
1 |
-
/*!
|
2 |
-
Chosen, a Select Box Enhancer for jQuery and Prototype
|
3 |
-
by Patrick Filler for Harvest, http://getharvest.com
|
4 |
-
|
5 |
-
Version 1.2.0
|
6 |
-
Full source at https://github.com/harvesthq/chosen
|
7 |
-
Copyright (c) 2011-2014 Harvest http://getharvest.com
|
8 |
-
|
9 |
-
MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md
|
10 |
-
This file is generated by `grunt build`, do not edit it by hand.
|
11 |
-
*/
|
12 |
-
|
13 |
-
(function() {
|
14 |
-
var $, AbstractChosen, Chosen, SelectParser, _ref,
|
15 |
-
__hasProp = {}.hasOwnProperty,
|
16 |
-
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
|
17 |
-
|
18 |
-
SelectParser = (function() {
|
19 |
-
function SelectParser() {
|
20 |
-
this.options_index = 0;
|
21 |
-
this.parsed = [];
|
22 |
-
}
|
23 |
-
|
24 |
-
SelectParser.prototype.add_node = function(child) {
|
25 |
-
if (child.nodeName.toUpperCase() === "OPTGROUP") {
|
26 |
-
return this.add_group(child);
|
27 |
-
} else {
|
28 |
-
return this.add_option(child);
|
29 |
-
}
|
30 |
-
};
|
31 |
-
|
32 |
-
SelectParser.prototype.add_group = function(group) {
|
33 |
-
var group_position, option, _i, _len, _ref, _results;
|
34 |
-
group_position = this.parsed.length;
|
35 |
-
this.parsed.push({
|
36 |
-
array_index: group_position,
|
37 |
-
group: true,
|
38 |
-
label: this.escapeExpression(group.label),
|
39 |
-
children: 0,
|
40 |
-
disabled: group.disabled
|
41 |
-
});
|
42 |
-
_ref = group.childNodes;
|
43 |
-
_results = [];
|
44 |
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
45 |
-
option = _ref[_i];
|
46 |
-
_results.push(this.add_option(option, group_position, group.disabled));
|
47 |
-
}
|
48 |
-
return _results;
|
49 |
-
};
|
50 |
-
|
51 |
-
SelectParser.prototype.add_option = function(option, group_position, group_disabled) {
|
52 |
-
if (option.nodeName.toUpperCase() === "OPTION") {
|
53 |
-
if (option.text !== "") {
|
54 |
-
if (group_position != null) {
|
55 |
-
this.parsed[group_position].children += 1;
|
56 |
-
}
|
57 |
-
this.parsed.push({
|
58 |
-
array_index: this.parsed.length,
|
59 |
-
options_index: this.options_index,
|
60 |
-
value: option.value,
|
61 |
-
text: option.text,
|
62 |
-
html: option.innerHTML,
|
63 |
-
selected: option.selected,
|
64 |
-
disabled: group_disabled === true ? group_disabled : option.disabled,
|
65 |
-
group_array_index: group_position,
|
66 |
-
classes: option.className,
|
67 |
-
style: option.style.cssText
|
68 |
-
});
|
69 |
-
} else {
|
70 |
-
this.parsed.push({
|
71 |
-
array_index: this.parsed.length,
|
72 |
-
options_index: this.options_index,
|
73 |
-
empty: true
|
74 |
-
});
|
75 |
-
}
|
76 |
-
return this.options_index += 1;
|
77 |
-
}
|
78 |
-
};
|
79 |
-
|
80 |
-
SelectParser.prototype.escapeExpression = function(text) {
|
81 |
-
var map, unsafe_chars;
|
82 |
-
if ((text == null) || text === false) {
|
83 |
-
return "";
|
84 |
-
}
|
85 |
-
if (!/[\&\<\>\"\'\`]/.test(text)) {
|
86 |
-
return text;
|
87 |
-
}
|
88 |
-
map = {
|
89 |
-
"<": "<",
|
90 |
-
">": ">",
|
91 |
-
'"': """,
|
92 |
-
"'": "'",
|
93 |
-
"`": "`"
|
94 |
-
};
|
95 |
-
unsafe_chars = /&(?!\w+;)|[\<\>\"\'\`]/g;
|
96 |
-
return text.replace(unsafe_chars, function(chr) {
|
97 |
-
return map[chr] || "&";
|
98 |
-
});
|
99 |
-
};
|
100 |
-
|
101 |
-
return SelectParser;
|
102 |
-
|
103 |
-
})();
|
104 |
-
|
105 |
-
SelectParser.select_to_array = function(select) {
|
106 |
-
var child, parser, _i, _len, _ref;
|
107 |
-
parser = new SelectParser();
|
108 |
-
_ref = select.childNodes;
|
109 |
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
110 |
-
child = _ref[_i];
|
111 |
-
parser.add_node(child);
|
112 |
-
}
|
113 |
-
return parser.parsed;
|
114 |
-
};
|
115 |
-
|
116 |
-
AbstractChosen = (function() {
|
117 |
-
function AbstractChosen(form_field, options) {
|
118 |
-
this.form_field = form_field;
|
119 |
-
this.options = options != null ? options : {};
|
120 |
-
if (!AbstractChosen.browser_is_supported()) {
|
121 |
-
return;
|
122 |
-
}
|
123 |
-
this.is_multiple = this.form_field.multiple;
|
124 |
-
this.set_default_text();
|
125 |
-
this.set_default_values();
|
126 |
-
this.setup();
|
127 |
-
this.set_up_html();
|
128 |
-
this.register_observers();
|
129 |
-
}
|
130 |
-
|
131 |
-
AbstractChosen.prototype.set_default_values = function() {
|
132 |
-
var _this = this;
|
133 |
-
this.click_test_action = function(evt) {
|
134 |
-
return _this.test_active_click(evt);
|
135 |
-
};
|
136 |
-
this.activate_action = function(evt) {
|
137 |
-
return _this.activate_field(evt);
|
138 |
-
};
|
139 |
-
this.active_field = false;
|
140 |
-
this.mouse_on_container = false;
|
141 |
-
this.results_showing = false;
|
142 |
-
this.result_highlighted = null;
|
143 |
-
this.allow_single_deselect = (this.options.allow_single_deselect != null) && (this.form_field.options[0] != null) && this.form_field.options[0].text === "" ? this.options.allow_single_deselect : false;
|
144 |
-
this.disable_search_threshold = this.options.disable_search_threshold || 0;
|
145 |
-
this.disable_search = this.options.disable_search || false;
|
146 |
-
this.enable_split_word_search = this.options.enable_split_word_search != null ? this.options.enable_split_word_search : true;
|
147 |
-
this.group_search = this.options.group_search != null ? this.options.group_search : true;
|
148 |
-
this.search_contains = this.options.search_contains || false;
|
149 |
-
this.single_backstroke_delete = this.options.single_backstroke_delete != null ? this.options.single_backstroke_delete : true;
|
150 |
-
this.max_selected_options = this.options.max_selected_options || Infinity;
|
151 |
-
this.inherit_select_classes = this.options.inherit_select_classes || false;
|
152 |
-
this.display_selected_options = this.options.display_selected_options != null ? this.options.display_selected_options : true;
|
153 |
-
return this.display_disabled_options = this.options.display_disabled_options != null ? this.options.display_disabled_options : true;
|
154 |
-
};
|
155 |
-
|
156 |
-
AbstractChosen.prototype.set_default_text = function() {
|
157 |
-
if (this.form_field.getAttribute("data-placeholder")) {
|
158 |
-
this.default_text = this.form_field.getAttribute("data-placeholder");
|
159 |
-
} else if (this.is_multiple) {
|
160 |
-
this.default_text = this.options.placeholder_text_multiple || this.options.placeholder_text || AbstractChosen.default_multiple_text;
|
161 |
-
} else {
|
162 |
-
this.default_text = this.options.placeholder_text_single || this.options.placeholder_text || AbstractChosen.default_single_text;
|
163 |
-
}
|
164 |
-
return this.results_none_found = this.form_field.getAttribute("data-no_results_text") || this.options.no_results_text || AbstractChosen.default_no_result_text;
|
165 |
-
};
|
166 |
-
|
167 |
-
AbstractChosen.prototype.mouse_enter = function() {
|
168 |
-
return this.mouse_on_container = true;
|
169 |
-
};
|
170 |
-
|
171 |
-
AbstractChosen.prototype.mouse_leave = function() {
|
172 |
-
return this.mouse_on_container = false;
|
173 |
-
};
|
174 |
-
|
175 |
-
AbstractChosen.prototype.input_focus = function(evt) {
|
176 |
-
var _this = this;
|
177 |
-
if (this.is_multiple) {
|
178 |
-
if (!this.active_field) {
|
179 |
-
return setTimeout((function() {
|
180 |
-
return _this.container_mousedown();
|
181 |
-
}), 50);
|
182 |
-
}
|
183 |
-
} else {
|
184 |
-
if (!this.active_field) {
|
185 |
-
return this.activate_field();
|
186 |
-
}
|
187 |
-
}
|
188 |
-
};
|
189 |
-
|
190 |
-
AbstractChosen.prototype.input_blur = function(evt) {
|
191 |
-
var _this = this;
|
192 |
-
if (!this.mouse_on_container) {
|
193 |
-
this.active_field = false;
|
194 |
-
return setTimeout((function() {
|
195 |
-
return _this.blur_test();
|
196 |
-
}), 100);
|
197 |
-
}
|
198 |
-
};
|
199 |
-
|
200 |
-
AbstractChosen.prototype.results_option_build = function(options) {
|
201 |
-
var content, data, _i, _len, _ref;
|
202 |
-
content = '';
|
203 |
-
_ref = this.results_data;
|
204 |
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
205 |
-
data = _ref[_i];
|
206 |
-
if (data.group) {
|
207 |
-
content += this.result_add_group(data);
|
208 |
-
} else {
|
209 |
-
content += this.result_add_option(data);
|
210 |
-
}
|
211 |
-
if (options != null ? options.first : void 0) {
|
212 |
-
if (data.selected && this.is_multiple) {
|
213 |
-
this.choice_build(data);
|
214 |
-
} else if (data.selected && !this.is_multiple) {
|
215 |
-
this.single_set_selected_text(data.text);
|
216 |
-
}
|
217 |
-
}
|
218 |
-
}
|
219 |
-
return content;
|
220 |
-
};
|
221 |
-
|
222 |
-
AbstractChosen.prototype.result_add_option = function(option) {
|
223 |
-
var classes, option_el;
|
224 |
-
if (!option.search_match) {
|
225 |
-
return '';
|
226 |
-
}
|
227 |
-
if (!this.include_option_in_results(option)) {
|
228 |
-
return '';
|
229 |
-
}
|
230 |
-
classes = [];
|
231 |
-
if (!option.disabled && !(option.selected && this.is_multiple)) {
|
232 |
-
classes.push("active-result");
|
233 |
-
}
|
234 |
-
if (option.disabled && !(option.selected && this.is_multiple)) {
|
235 |
-
classes.push("disabled-result");
|
236 |
-
}
|
237 |
-
if (option.selected) {
|
238 |
-
classes.push("result-selected");
|
239 |
-
}
|
240 |
-
if (option.group_array_index != null) {
|
241 |
-
classes.push("group-option");
|
242 |
-
}
|
243 |
-
if (option.classes !== "") {
|
244 |
-
classes.push(option.classes);
|
245 |
-
}
|
246 |
-
option_el = document.createElement("li");
|
247 |
-
option_el.className = classes.join(" ");
|
248 |
-
option_el.style.cssText = option.style;
|
249 |
-
option_el.setAttribute("data-option-array-index", option.array_index);
|
250 |
-
option_el.innerHTML = option.search_text;
|
251 |
-
return this.outerHTML(option_el);
|
252 |
-
};
|
253 |
-
|
254 |
-
AbstractChosen.prototype.result_add_group = function(group) {
|
255 |
-
var group_el;
|
256 |
-
if (!(group.search_match || group.group_match)) {
|
257 |
-
return '';
|
258 |
-
}
|
259 |
-
if (!(group.active_options > 0)) {
|
260 |
-
return '';
|
261 |
-
}
|
262 |
-
group_el = document.createElement("li");
|
263 |
-
group_el.className = "group-result";
|
264 |
-
group_el.innerHTML = group.search_text;
|
265 |
-
return this.outerHTML(group_el);
|
266 |
-
};
|
267 |
-
|
268 |
-
AbstractChosen.prototype.results_update_field = function() {
|
269 |
-
this.set_default_text();
|
270 |
-
if (!this.is_multiple) {
|
271 |
-
this.results_reset_cleanup();
|
272 |
-
}
|
273 |
-
this.result_clear_highlight();
|
274 |
-
this.results_build();
|
275 |
-
if (this.results_showing) {
|
276 |
-
return this.winnow_results();
|
277 |
-
}
|
278 |
-
};
|
279 |
-
|
280 |
-
AbstractChosen.prototype.reset_single_select_options = function() {
|
281 |
-
var result, _i, _len, _ref, _results;
|
282 |
-
_ref = this.results_data;
|
283 |
-
_results = [];
|
284 |
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
285 |
-
result = _ref[_i];
|
286 |
-
if (result.selected) {
|
287 |
-
_results.push(result.selected = false);
|
288 |
-
} else {
|
289 |
-
_results.push(void 0);
|
290 |
-
}
|
291 |
-
}
|
292 |
-
return _results;
|
293 |
-
};
|
294 |
-
|
295 |
-
AbstractChosen.prototype.results_toggle = function() {
|
296 |
-
if (this.results_showing) {
|
297 |
-
return this.results_hide();
|
298 |
-
} else {
|
299 |
-
return this.results_show();
|
300 |
-
}
|
301 |
-
};
|
302 |
-
|
303 |
-
AbstractChosen.prototype.results_search = function(evt) {
|
304 |
-
if (this.results_showing) {
|
305 |
-
return this.winnow_results();
|
306 |
-
} else {
|
307 |
-
return this.results_show();
|
308 |
-
}
|
309 |
-
};
|
310 |
-
|
311 |
-
AbstractChosen.prototype.winnow_results = function() {
|
312 |
-
var escapedSearchText, option, regex, results, results_group, searchText, startpos, text, zregex, _i, _len, _ref;
|
313 |
-
this.no_results_clear();
|
314 |
-
results = 0;
|
315 |
-
searchText = this.get_search_text();
|
316 |
-
escapedSearchText = searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
|
317 |
-
zregex = new RegExp(escapedSearchText, 'i');
|
318 |
-
regex = this.get_search_regex(escapedSearchText);
|
319 |
-
_ref = this.results_data;
|
320 |
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
321 |
-
option = _ref[_i];
|
322 |
-
option.search_match = false;
|
323 |
-
results_group = null;
|
324 |
-
if (this.include_option_in_results(option)) {
|
325 |
-
if (option.group) {
|
326 |
-
option.group_match = false;
|
327 |
-
option.active_options = 0;
|
328 |
-
}
|
329 |
-
if ((option.group_array_index != null) && this.results_data[option.group_array_index]) {
|
330 |
-
results_group = this.results_data[option.group_array_index];
|
331 |
-
if (results_group.active_options === 0 && results_group.search_match) {
|
332 |
-
results += 1;
|
333 |
-
}
|
334 |
-
results_group.active_options += 1;
|
335 |
-
}
|
336 |
-
if (!(option.group && !this.group_search)) {
|
337 |
-
option.search_text = option.group ? option.label : option.text;
|
338 |
-
option.search_match = this.search_string_match(option.search_text, regex);
|
339 |
-
if (option.search_match && !option.group) {
|
340 |
-
results += 1;
|
341 |
-
}
|
342 |
-
if (option.search_match) {
|
343 |
-
if (searchText.length) {
|
344 |
-
startpos = option.search_text.search(zregex);
|
345 |
-
text = option.search_text.substr(0, startpos + searchText.length) + '</em>' + option.search_text.substr(startpos + searchText.length);
|
346 |
-
option.search_text = text.substr(0, startpos) + '<em>' + text.substr(startpos);
|
347 |
-
}
|
348 |
-
if (results_group != null) {
|
349 |
-
results_group.group_match = true;
|
350 |
-
}
|
351 |
-
} else if ((option.group_array_index != null) && this.results_data[option.group_array_index].search_match) {
|
352 |
-
option.search_match = true;
|
353 |
-
}
|
354 |
-
}
|
355 |
-
}
|
356 |
-
}
|
357 |
-
this.result_clear_highlight();
|
358 |
-
if (results < 1 && searchText.length) {
|
359 |
-
this.update_results_content("");
|
360 |
-
return this.no_results(searchText);
|
361 |
-
} else {
|
362 |
-
this.update_results_content(this.results_option_build());
|
363 |
-
return this.winnow_results_set_highlight();
|
364 |
-
}
|
365 |
-
};
|
366 |
-
|
367 |
-
AbstractChosen.prototype.get_search_regex = function(escaped_search_string) {
|
368 |
-
var regex_anchor;
|
369 |
-
regex_anchor = this.search_contains ? "" : "^";
|
370 |
-
return new RegExp(regex_anchor + escaped_search_string, 'i');
|
371 |
-
};
|
372 |
-
|
373 |
-
AbstractChosen.prototype.search_string_match = function(search_string, regex) {
|
374 |
-
var part, parts, _i, _len;
|
375 |
-
if (regex.test(search_string)) {
|
376 |
-
return true;
|
377 |
-
} else if (this.enable_split_word_search && (search_string.indexOf(" ") >= 0 || search_string.indexOf("[") === 0)) {
|
378 |
-
parts = search_string.replace(/\[|\]/g, "").split(" ");
|
379 |
-
if (parts.length) {
|
380 |
-
for (_i = 0, _len = parts.length; _i < _len; _i++) {
|
381 |
-
part = parts[_i];
|
382 |
-
if (regex.test(part)) {
|
383 |
-
return true;
|
384 |
-
}
|
385 |
-
}
|
386 |
-
}
|
387 |
-
}
|
388 |
-
};
|
389 |
-
|
390 |
-
AbstractChosen.prototype.choices_count = function() {
|
391 |
-
var option, _i, _len, _ref;
|
392 |
-
if (this.selected_option_count != null) {
|
393 |
-
return this.selected_option_count;
|
394 |
-
}
|
395 |
-
this.selected_option_count = 0;
|
396 |
-
_ref = this.form_field.options;
|
397 |
-
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
398 |
-
option = _ref[_i];
|
399 |
-
if (option.selected) {
|
400 |
-
this.selected_option_count += 1;
|
401 |
-
}
|
402 |
-
}
|
403 |
-
return this.selected_option_count;
|
404 |
-
};
|
405 |
-
|
406 |
-
AbstractChosen.prototype.choices_click = function(evt) {
|
407 |
-
evt.preventDefault();
|
408 |
-
if (!(this.results_showing || this.is_disabled)) {
|
409 |
-
return this.results_show();
|
410 |
-
}
|
411 |
-
};
|
412 |
-
|
413 |
-
AbstractChosen.prototype.keyup_checker = function(evt) {
|
414 |
-
var stroke, _ref;
|
415 |
-
stroke = (_ref = evt.which) != null ? _ref : evt.keyCode;
|
416 |
-
this.search_field_scale();
|
417 |
-
switch (stroke) {
|
418 |
-
case 8:
|
419 |
-
if (this.is_multiple && this.backstroke_length < 1 && this.choices_count() > 0) {
|
420 |
-
return this.keydown_backstroke();
|
421 |
-
} else if (!this.pending_backstroke) {
|
422 |
-
this.result_clear_highlight();
|
423 |
-
return this.results_search();
|
424 |
-
}
|
425 |
-
break;
|
426 |
-
case 13:
|
427 |
-
evt.preventDefault();
|
428 |
-
if (this.results_showing) {
|
429 |
-
return this.result_select(evt);
|
430 |
-
}
|
431 |
-
break;
|
432 |
-
case 27:
|
433 |
-
if (this.results_showing) {
|
434 |
-
this.results_hide();
|
435 |
-
}
|
436 |
-
return true;
|
437 |
-
case 9:
|
438 |
-
case 38:
|
439 |
-
case 40:
|
440 |
-
case 16:
|
441 |
-
case 91:
|
442 |
-
case 17:
|
443 |
-
break;
|
444 |
-
default:
|
445 |
-
return this.results_search();
|
446 |
-
}
|
447 |
-
};
|
448 |
-
|
449 |
-
AbstractChosen.prototype.clipboard_event_checker = function(evt) {
|
450 |
-
var _this = this;
|
451 |
-
return setTimeout((function() {
|
452 |
-
return _this.results_search();
|
453 |
-
}), 50);
|
454 |
-
};
|
455 |
-
|
456 |
-
AbstractChosen.prototype.container_width = function() {
|
457 |
-
if (this.options.width != null) {
|
458 |
-
return this.options.width;
|
459 |
-
} else {
|
460 |
-
return "" + this.form_field.offsetWidth + "px";
|
461 |
-
}
|
462 |
-
};
|
463 |
-
|
464 |
-
AbstractChosen.prototype.include_option_in_results = function(option) {
|
465 |
-
if (this.is_multiple && (!this.display_selected_options && option.selected)) {
|
466 |
-
return false;
|
467 |
-
}
|
468 |
-
if (!this.display_disabled_options && option.disabled) {
|
469 |
-
return false;
|
470 |
-
}
|
471 |
-
if (option.empty) {
|
472 |
-
return false;
|
473 |
-
}
|
474 |
-
return true;
|
475 |
-
};
|
476 |
-
|
477 |
-
AbstractChosen.prototype.search_results_touchstart = function(evt) {
|
478 |
-
this.touch_started = true;
|
479 |
-
return this.search_results_mouseover(evt);
|
480 |
-
};
|
481 |
-
|
482 |
-
AbstractChosen.prototype.search_results_touchmove = function(evt) {
|
483 |
-
this.touch_started = false;
|
484 |
-
return this.search_results_mouseout(evt);
|
485 |
-
};
|
486 |
-
|
487 |
-
AbstractChosen.prototype.search_results_touchend = function(evt) {
|
488 |
-
if (this.touch_started) {
|
489 |
-
return this.search_results_mouseup(evt);
|
490 |
-
}
|
491 |
-
};
|
492 |
-
|
493 |
-
AbstractChosen.prototype.outerHTML = function(element) {
|
494 |
-
var tmp;
|
495 |
-
if (element.outerHTML) {
|
496 |
-
return element.outerHTML;
|
497 |
-
}
|
498 |
-
tmp = document.createElement("div");
|
499 |
-
tmp.appendChild(element);
|
500 |
-
return tmp.innerHTML;
|
501 |
-
};
|
502 |
-
|
503 |
-
AbstractChosen.browser_is_supported = function() {
|
504 |
-
if (window.navigator.appName === "Microsoft Internet Explorer") {
|
505 |
-
return document.documentMode >= 8;
|
506 |
-
}
|
507 |
-
if (/iP(od|hone)/i.test(window.navigator.userAgent)) {
|
508 |
-
return false;
|
509 |
-
}
|
510 |
-
if (/Android/i.test(window.navigator.userAgent)) {
|
511 |
-
if (/Mobile/i.test(window.navigator.userAgent)) {
|
512 |
-
return false;
|
513 |
-
}
|
514 |
-
}
|
515 |
-
return true;
|
516 |
-
};
|
517 |
-
|
518 |
-
AbstractChosen.default_multiple_text = "Select Some Options";
|
519 |
-
|
520 |
-
AbstractChosen.default_single_text = "Select an Option";
|
521 |
-
|
522 |
-
AbstractChosen.default_no_result_text = "No results match";
|
523 |
-
|
524 |
-
return AbstractChosen;
|
525 |
-
|
526 |
-
})();
|
527 |
-
|
528 |
-
$ = jQuery;
|
529 |
-
|
530 |
-
$.fn.extend({
|
531 |
-
chosen: function(options) {
|
532 |
-
if (!AbstractChosen.browser_is_supported()) {
|
533 |
-
return this;
|
534 |
-
}
|
535 |
-
return this.each(function(input_field) {
|
536 |
-
var $this, chosen;
|
537 |
-
$this = $(this);
|
538 |
-
chosen = $this.data('chosen');
|
539 |
-
if (options === 'destroy' && chosen instanceof Chosen) {
|
540 |
-
chosen.destroy();
|
541 |
-
} else if (!(chosen instanceof Chosen)) {
|
542 |
-
$this.data('chosen', new Chosen(this, options));
|
543 |
-
}
|
544 |
-
});
|
545 |
-
}
|
546 |
-
});
|
547 |
-
|
548 |
-
Chosen = (function(_super) {
|
549 |
-
__extends(Chosen, _super);
|
550 |
-
|
551 |
-
function Chosen() {
|
552 |
-
_ref = Chosen.__super__.constructor.apply(this, arguments);
|
553 |
-
return _ref;
|
554 |
-
}
|
555 |
-
|
556 |
-
Chosen.prototype.setup = function() {
|
557 |
-
this.form_field_jq = $(this.form_field);
|
558 |
-
this.current_selectedIndex = this.form_field.selectedIndex;
|
559 |
-
return this.is_rtl = this.form_field_jq.hasClass("chosen-rtl");
|
560 |
-
};
|
561 |
-
|
562 |
-
Chosen.prototype.set_up_html = function() {
|
563 |
-
var container_classes, container_props;
|
564 |
-
container_classes = ["chosen-container"];
|
565 |
-
container_classes.push("chosen-container-" + (this.is_multiple ? "multi" : "single"));
|
566 |
-
if (this.inherit_select_classes && this.form_field.className) {
|
567 |
-
container_classes.push(this.form_field.className);
|
568 |
-
}
|
569 |
-
if (this.is_rtl) {
|
570 |
-
container_classes.push("chosen-rtl");
|
571 |
-
}
|
572 |
-
container_props = {
|
573 |
-
'class': container_classes.join(' '),
|
574 |
-
'style': "width: " + (this.container_width()) + ";",
|
575 |
-
'title': this.form_field.title
|
576 |
-
};
|
577 |
-
if (this.form_field.id.length) {
|
578 |
-
container_props.id = this.form_field.id.replace(/[^\w]/g, '_') + "_chosen";
|
579 |
-
}
|
580 |
-
this.container = $("<div />", container_props);
|
581 |
-
if (this.is_multiple) {
|
582 |
-
this.container.html('<ul class="chosen-choices"><li class="search-field"><input type="text" value="' + this.default_text + '" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chosen-drop"><ul class="chosen-results"></ul></div>');
|
583 |
-
} else {
|
584 |
-
this.container.html('<a class="chosen-single chosen-default" tabindex="-1"><span>' + this.default_text + '</span><div><b></b></div></a><div class="chosen-drop"><div class="chosen-search"><input type="text" autocomplete="off" /></div><ul class="chosen-results"></ul></div>');
|
585 |
-
}
|
586 |
-
this.form_field_jq.hide().after(this.container);
|
587 |
-
this.dropdown = this.container.find('div.chosen-drop').first();
|
588 |
-
this.search_field = this.container.find('input').first();
|
589 |
-
this.search_results = this.container.find('ul.chosen-results').first();
|
590 |
-
this.search_field_scale();
|
591 |
-
this.search_no_results = this.container.find('li.no-results').first();
|
592 |
-
if (this.is_multiple) {
|
593 |
-
this.search_choices = this.container.find('ul.chosen-choices').first();
|
594 |
-
this.search_container = this.container.find('li.search-field').first();
|
595 |
-
} else {
|
596 |
-
this.search_container = this.container.find('div.chosen-search').first();
|
597 |
-
this.selected_item = this.container.find('.chosen-single').first();
|
598 |
-
}
|
599 |
-
this.results_build();
|
600 |
-
this.set_tab_index();
|
601 |
-
this.set_label_behavior();
|
602 |
-
return this.form_field_jq.trigger("chosen:ready", {
|
603 |
-
chosen: this
|
604 |
-
});
|
605 |
-
};
|
606 |
-
|
607 |
-
Chosen.prototype.register_observers = function() {
|
608 |
-
var _this = this;
|
609 |
-
this.container.bind('touchstart.chosen', function(evt) {
|
610 |
-
_this.container_mousedown(evt);
|
611 |
-
});
|
612 |
-
this.container.bind('touchend.chosen', function(evt) {
|
613 |
-
_this.container_mouseup(evt);
|
614 |
-
});
|
615 |
-
this.container.bind('mousedown.chosen', function(evt) {
|
616 |
-
_this.container_mousedown(evt);
|
617 |
-
});
|
618 |
-
this.container.bind('mouseup.chosen', function(evt) {
|
619 |
-
_this.container_mouseup(evt);
|
620 |
-
});
|
621 |
-
this.container.bind('mouseenter.chosen', function(evt) {
|
622 |
-
_this.mouse_enter(evt);
|
623 |
-
});
|
624 |
-
this.container.bind('mouseleave.chosen', function(evt) {
|
625 |
-
_this.mouse_leave(evt);
|
626 |
-
});
|
627 |
-
this.search_results.bind('mouseup.chosen', function(evt) {
|
628 |
-
_this.search_results_mouseup(evt);
|
629 |
-
});
|
630 |
-
this.search_results.bind('mouseover.chosen', function(evt) {
|
631 |
-
_this.search_results_mouseover(evt);
|
632 |
-
});
|
633 |
-
this.search_results.bind('mouseout.chosen', function(evt) {
|
634 |
-
_this.search_results_mouseout(evt);
|
635 |
-
});
|
636 |
-
this.search_results.bind('mousewheel.chosen DOMMouseScroll.chosen', function(evt) {
|
637 |
-
_this.search_results_mousewheel(evt);
|
638 |
-
});
|
639 |
-
this.search_results.bind('touchstart.chosen', function(evt) {
|
640 |
-
_this.search_results_touchstart(evt);
|
641 |
-
});
|
642 |
-
this.search_results.bind('touchmove.chosen', function(evt) {
|
643 |
-
_this.search_results_touchmove(evt);
|
644 |
-
});
|
645 |
-
this.search_results.bind('touchend.chosen', function(evt) {
|
646 |
-
_this.search_results_touchend(evt);
|
647 |
-
});
|
648 |
-
this.form_field_jq.bind("chosen:updated.chosen", function(evt) {
|
649 |
-
_this.results_update_field(evt);
|
650 |
-
});
|
651 |
-
this.form_field_jq.bind("chosen:activate.chosen", function(evt) {
|
652 |
-
_this.activate_field(evt);
|
653 |
-
});
|
654 |
-
this.form_field_jq.bind("chosen:open.chosen", function(evt) {
|
655 |
-
_this.container_mousedown(evt);
|
656 |
-
});
|
657 |
-
this.form_field_jq.bind("chosen:close.chosen", function(evt) {
|
658 |
-
_this.input_blur(evt);
|
659 |
-
});
|
660 |
-
this.search_field.bind('blur.chosen', function(evt) {
|
661 |
-
_this.input_blur(evt);
|
662 |
-
});
|
663 |
-
this.search_field.bind('keyup.chosen', function(evt) {
|
664 |
-
_this.keyup_checker(evt);
|
665 |
-
});
|
666 |
-
this.search_field.bind('keydown.chosen', function(evt) {
|
667 |
-
_this.keydown_checker(evt);
|
668 |
-
});
|
669 |
-
this.search_field.bind('focus.chosen', function(evt) {
|
670 |
-
_this.input_focus(evt);
|
671 |
-
});
|
672 |
-
this.search_field.bind('cut.chosen', function(evt) {
|
673 |
-
_this.clipboard_event_checker(evt);
|
674 |
-
});
|
675 |
-
this.search_field.bind('paste.chosen', function(evt) {
|
676 |
-
_this.clipboard_event_checker(evt);
|
677 |
-
});
|
678 |
-
if (this.is_multiple) {
|
679 |
-
return this.search_choices.bind('click.chosen', function(evt) {
|
680 |
-
_this.choices_click(evt);
|
681 |
-
});
|
682 |
-
} else {
|
683 |
-
return this.container.bind('click.chosen', function(evt) {
|
684 |
-
evt.preventDefault();
|
685 |
-
});
|
686 |
-
}
|
687 |
-
};
|
688 |
-
|
689 |
-
Chosen.prototype.destroy = function() {
|
690 |
-
$(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
|
691 |
-
if (this.search_field[0].tabIndex) {
|
692 |
-
this.form_field_jq[0].tabIndex = this.search_field[0].tabIndex;
|
693 |
-
}
|
694 |
-
this.container.remove();
|
695 |
-
this.form_field_jq.removeData('chosen');
|
696 |
-
return this.form_field_jq.show();
|
697 |
-
};
|
698 |
-
|
699 |
-
Chosen.prototype.search_field_disabled = function() {
|
700 |
-
this.is_disabled = this.form_field_jq[0].disabled;
|
701 |
-
if (this.is_disabled) {
|
702 |
-
this.container.addClass('chosen-disabled');
|
703 |
-
this.search_field[0].disabled = true;
|
704 |
-
if (!this.is_multiple) {
|
705 |
-
this.selected_item.unbind("focus.chosen", this.activate_action);
|
706 |
-
}
|
707 |
-
return this.close_field();
|
708 |
-
} else {
|
709 |
-
this.container.removeClass('chosen-disabled');
|
710 |
-
this.search_field[0].disabled = false;
|
711 |
-
if (!this.is_multiple) {
|
712 |
-
return this.selected_item.bind("focus.chosen", this.activate_action);
|
713 |
-
}
|
714 |
-
}
|
715 |
-
};
|
716 |
-
|
717 |
-
Chosen.prototype.container_mousedown = function(evt) {
|
718 |
-
if (!this.is_disabled) {
|
719 |
-
if (evt && evt.type === "mousedown" && !this.results_showing) {
|
720 |
-
evt.preventDefault();
|
721 |
-
}
|
722 |
-
if (!((evt != null) && ($(evt.target)).hasClass("search-choice-close"))) {
|
723 |
-
if (!this.active_field) {
|
724 |
-
if (this.is_multiple) {
|
725 |
-
this.search_field.val("");
|
726 |
-
}
|
727 |
-
$(this.container[0].ownerDocument).bind('click.chosen', this.click_test_action);
|
728 |
-
this.results_show();
|
729 |
-
} else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chosen-single").length)) {
|
730 |
-
evt.preventDefault();
|
731 |
-
this.results_toggle();
|
732 |
-
}
|
733 |
-
return this.activate_field();
|
734 |
-
}
|
735 |
-
}
|
736 |
-
};
|
737 |
-
|
738 |
-
Chosen.prototype.container_mouseup = function(evt) {
|
739 |
-
if (evt.target.nodeName === "ABBR" && !this.is_disabled) {
|
740 |
-
return this.results_reset(evt);
|
741 |
-
}
|
742 |
-
};
|
743 |
-
|
744 |
-
Chosen.prototype.search_results_mousewheel = function(evt) {
|
745 |
-
var delta;
|
746 |
-
if (evt.originalEvent) {
|
747 |
-
delta = evt.originalEvent.deltaY || -evt.originalEvent.wheelDelta || evt.originalEvent.detail;
|
748 |
-
}
|
749 |
-
if (delta != null) {
|
750 |
-
evt.preventDefault();
|
751 |
-
if (evt.type === 'DOMMouseScroll') {
|
752 |
-
delta = delta * 40;
|
753 |
-
}
|
754 |
-
return this.search_results.scrollTop(delta + this.search_results.scrollTop());
|
755 |
-
}
|
756 |
-
};
|
757 |
-
|
758 |
-
Chosen.prototype.blur_test = function(evt) {
|
759 |
-
if (!this.active_field && this.container.hasClass("chosen-container-active")) {
|
760 |
-
return this.close_field();
|
761 |
-
}
|
762 |
-
};
|
763 |
-
|
764 |
-
Chosen.prototype.close_field = function() {
|
765 |
-
$(this.container[0].ownerDocument).unbind("click.chosen", this.click_test_action);
|
766 |
-
this.active_field = false;
|
767 |
-
this.results_hide();
|
768 |
-
this.container.removeClass("chosen-container-active");
|
769 |
-
this.clear_backstroke();
|
770 |
-
this.show_search_field_default();
|
771 |
-
return this.search_field_scale();
|
772 |
-
};
|
773 |
-
|
774 |
-
Chosen.prototype.activate_field = function() {
|
775 |
-
this.container.addClass("chosen-container-active");
|
776 |
-
this.active_field = true;
|
777 |
-
this.search_field.val(this.search_field.val());
|
778 |
-
return this.search_field.focus();
|
779 |
-
};
|
780 |
-
|
781 |
-
Chosen.prototype.test_active_click = function(evt) {
|
782 |
-
var active_container;
|
783 |
-
active_container = $(evt.target).closest('.chosen-container');
|
784 |
-
if (active_container.length && this.container[0] === active_container[0]) {
|
785 |
-
return this.active_field = true;
|
786 |
-
} else {
|
787 |
-
return this.close_field();
|
788 |
-
}
|
789 |
-
};
|
790 |
-
|
791 |
-
Chosen.prototype.results_build = function() {
|
792 |
-
this.parsing = true;
|
793 |
-
this.selected_option_count = null;
|
794 |
-
this.results_data = SelectParser.select_to_array(this.form_field);
|
795 |
-
if (this.is_multiple) {
|
796 |
-
this.search_choices.find("li.search-choice").remove();
|
797 |
-
} else if (!this.is_multiple) {
|
798 |
-
this.single_set_selected_text();
|
799 |
-
if (this.disable_search || this.form_field.options.length <= this.disable_search_threshold) {
|
800 |
-
this.search_field[0].readOnly = true;
|
801 |
-
this.container.addClass("chosen-container-single-nosearch");
|
802 |
-
} else {
|
803 |
-
this.search_field[0].readOnly = false;
|
804 |
-
this.container.removeClass("chosen-container-single-nosearch");
|
805 |
-
}
|
806 |
-
}
|
807 |
-
this.update_results_content(this.results_option_build({
|
808 |
-
first: true
|
809 |
-
}));
|
810 |
-
this.search_field_disabled();
|
811 |
-
this.show_search_field_default();
|
812 |
-
this.search_field_scale();
|
813 |
-
return this.parsing = false;
|
814 |
-
};
|
815 |
-
|
816 |
-
Chosen.prototype.result_do_highlight = function(el) {
|
817 |
-
var high_bottom, high_top, maxHeight, visible_bottom, visible_top;
|
818 |
-
if (el.length) {
|
819 |
-
this.result_clear_highlight();
|
820 |
-
this.result_highlight = el;
|
821 |
-
this.result_highlight.addClass("highlighted");
|
822 |
-
maxHeight = parseInt(this.search_results.css("maxHeight"), 10);
|
823 |
-
visible_top = this.search_results.scrollTop();
|
824 |
-
visible_bottom = maxHeight + visible_top;
|
825 |
-
high_top = this.result_highlight.position().top + this.search_results.scrollTop();
|
826 |
-
high_bottom = high_top + this.result_highlight.outerHeight();
|
827 |
-
if (high_bottom >= visible_bottom) {
|
828 |
-
return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0);
|
829 |
-
} else if (high_top < visible_top) {
|
830 |
-
return this.search_results.scrollTop(high_top);
|
831 |
-
}
|
832 |
-
}
|
833 |
-
};
|
834 |
-
|
835 |
-
Chosen.prototype.result_clear_highlight = function() {
|
836 |
-
if (this.result_highlight) {
|
837 |
-
this.result_highlight.removeClass("highlighted");
|
838 |
-
}
|
839 |
-
return this.result_highlight = null;
|
840 |
-
};
|
841 |
-
|
842 |
-
Chosen.prototype.results_show = function() {
|
843 |
-
if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
|
844 |
-
this.form_field_jq.trigger("chosen:maxselected", {
|
845 |
-
chosen: this
|
846 |
-
});
|
847 |
-
return false;
|
848 |
-
}
|
849 |
-
this.container.addClass("chosen-with-drop");
|
850 |
-
this.results_showing = true;
|
851 |
-
this.search_field.focus();
|
852 |
-
this.search_field.val(this.search_field.val());
|
853 |
-
this.winnow_results();
|
854 |
-
return this.form_field_jq.trigger("chosen:showing_dropdown", {
|
855 |
-
chosen: this
|
856 |
-
});
|
857 |
-
};
|
858 |
-
|
859 |
-
Chosen.prototype.update_results_content = function(content) {
|
860 |
-
return this.search_results.html(content);
|
861 |
-
};
|
862 |
-
|
863 |
-
Chosen.prototype.results_hide = function() {
|
864 |
-
if (this.results_showing) {
|
865 |
-
this.result_clear_highlight();
|
866 |
-
this.container.removeClass("chosen-with-drop");
|
867 |
-
this.form_field_jq.trigger("chosen:hiding_dropdown", {
|
868 |
-
chosen: this
|
869 |
-
});
|
870 |
-
}
|
871 |
-
return this.results_showing = false;
|
872 |
-
};
|
873 |
-
|
874 |
-
Chosen.prototype.set_tab_index = function(el) {
|
875 |
-
var ti;
|
876 |
-
if (this.form_field.tabIndex) {
|
877 |
-
ti = this.form_field.tabIndex;
|
878 |
-
this.form_field.tabIndex = -1;
|
879 |
-
return this.search_field[0].tabIndex = ti;
|
880 |
-
}
|
881 |
-
};
|
882 |
-
|
883 |
-
Chosen.prototype.set_label_behavior = function() {
|
884 |
-
var _this = this;
|
885 |
-
this.form_field_label = this.form_field_jq.parents("label");
|
886 |
-
if (!this.form_field_label.length && this.form_field.id.length) {
|
887 |
-
this.form_field_label = $("label[for='" + this.form_field.id + "']");
|
888 |
-
}
|
889 |
-
if (this.form_field_label.length > 0) {
|
890 |
-
return this.form_field_label.bind('click.chosen', function(evt) {
|
891 |
-
if (_this.is_multiple) {
|
892 |
-
return _this.container_mousedown(evt);
|
893 |
-
} else {
|
894 |
-
return _this.activate_field();
|
895 |
-
}
|
896 |
-
});
|
897 |
-
}
|
898 |
-
};
|
899 |
-
|
900 |
-
Chosen.prototype.show_search_field_default = function() {
|
901 |
-
if (this.is_multiple && this.choices_count() < 1 && !this.active_field) {
|
902 |
-
this.search_field.val(this.default_text);
|
903 |
-
return this.search_field.addClass("default");
|
904 |
-
} else {
|
905 |
-
this.search_field.val("");
|
906 |
-
return this.search_field.removeClass("default");
|
907 |
-
}
|
908 |
-
};
|
909 |
-
|
910 |
-
Chosen.prototype.search_results_mouseup = function(evt) {
|
911 |
-
var target;
|
912 |
-
target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
|
913 |
-
if (target.length) {
|
914 |
-
this.result_highlight = target;
|
915 |
-
this.result_select(evt);
|
916 |
-
return this.search_field.focus();
|
917 |
-
}
|
918 |
-
};
|
919 |
-
|
920 |
-
Chosen.prototype.search_results_mouseover = function(evt) {
|
921 |
-
var target;
|
922 |
-
target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first();
|
923 |
-
if (target) {
|
924 |
-
return this.result_do_highlight(target);
|
925 |
-
}
|
926 |
-
};
|
927 |
-
|
928 |
-
Chosen.prototype.search_results_mouseout = function(evt) {
|
929 |
-
if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) {
|
930 |
-
return this.result_clear_highlight();
|
931 |
-
}
|
932 |
-
};
|
933 |
-
|
934 |
-
Chosen.prototype.choice_build = function(item) {
|
935 |
-
var choice, close_link,
|
936 |
-
_this = this;
|
937 |
-
choice = $('<li />', {
|
938 |
-
"class": "search-choice"
|
939 |
-
}).html("<span>" + item.html + "</span>");
|
940 |
-
if (item.disabled) {
|
941 |
-
choice.addClass('search-choice-disabled');
|
942 |
-
} else {
|
943 |
-
close_link = $('<a />', {
|
944 |
-
"class": 'search-choice-close',
|
945 |
-
'data-option-array-index': item.array_index
|
946 |
-
});
|
947 |
-
close_link.bind('click.chosen', function(evt) {
|
948 |
-
return _this.choice_destroy_link_click(evt);
|
949 |
-
});
|
950 |
-
choice.append(close_link);
|
951 |
-
}
|
952 |
-
return this.search_container.before(choice);
|
953 |
-
};
|
954 |
-
|
955 |
-
Chosen.prototype.choice_destroy_link_click = function(evt) {
|
956 |
-
evt.preventDefault();
|
957 |
-
evt.stopPropagation();
|
958 |
-
if (!this.is_disabled) {
|
959 |
-
return this.choice_destroy($(evt.target));
|
960 |
-
}
|
961 |
-
};
|
962 |
-
|
963 |
-
Chosen.prototype.choice_destroy = function(link) {
|
964 |
-
if (this.result_deselect(link[0].getAttribute("data-option-array-index"))) {
|
965 |
-
this.show_search_field_default();
|
966 |
-
if (this.is_multiple && this.choices_count() > 0 && this.search_field.val().length < 1) {
|
967 |
-
this.results_hide();
|
968 |
-
}
|
969 |
-
link.parents('li').first().remove();
|
970 |
-
return this.search_field_scale();
|
971 |
-
}
|
972 |
-
};
|
973 |
-
|
974 |
-
Chosen.prototype.results_reset = function() {
|
975 |
-
this.reset_single_select_options();
|
976 |
-
this.form_field.options[0].selected = true;
|
977 |
-
this.single_set_selected_text();
|
978 |
-
this.show_search_field_default();
|
979 |
-
this.results_reset_cleanup();
|
980 |
-
this.form_field_jq.trigger("change");
|
981 |
-
if (this.active_field) {
|
982 |
-
return this.results_hide();
|
983 |
-
}
|
984 |
-
};
|
985 |
-
|
986 |
-
Chosen.prototype.results_reset_cleanup = function() {
|
987 |
-
this.current_selectedIndex = this.form_field.selectedIndex;
|
988 |
-
return this.selected_item.find("abbr").remove();
|
989 |
-
};
|
990 |
-
|
991 |
-
Chosen.prototype.result_select = function(evt) {
|
992 |
-
var high, item;
|
993 |
-
if (this.result_highlight) {
|
994 |
-
high = this.result_highlight;
|
995 |
-
this.result_clear_highlight();
|
996 |
-
if (this.is_multiple && this.max_selected_options <= this.choices_count()) {
|
997 |
-
this.form_field_jq.trigger("chosen:maxselected", {
|
998 |
-
chosen: this
|
999 |
-
});
|
1000 |
-
return false;
|
1001 |
-
}
|
1002 |
-
if (this.is_multiple) {
|
1003 |
-
high.removeClass("active-result");
|
1004 |
-
} else {
|
1005 |
-
this.reset_single_select_options();
|
1006 |
-
}
|
1007 |
-
item = this.results_data[high[0].getAttribute("data-option-array-index")];
|
1008 |
-
item.selected = true;
|
1009 |
-
this.form_field.options[item.options_index].selected = true;
|
1010 |
-
this.selected_option_count = null;
|
1011 |
-
if (this.is_multiple) {
|
1012 |
-
this.choice_build(item);
|
1013 |
-
} else {
|
1014 |
-
this.single_set_selected_text(item.text);
|
1015 |
-
}
|
1016 |
-
if (!((evt.metaKey || evt.ctrlKey) && this.is_multiple)) {
|
1017 |
-
this.results_hide();
|
1018 |
-
}
|
1019 |
-
this.search_field.val("");
|
1020 |
-
if (this.is_multiple || this.form_field.selectedIndex !== this.current_selectedIndex) {
|
1021 |
-
this.form_field_jq.trigger("change", {
|
1022 |
-
'selected': this.form_field.options[item.options_index].value
|
1023 |
-
});
|
1024 |
-
}
|
1025 |
-
this.current_selectedIndex = this.form_field.selectedIndex;
|
1026 |
-
return this.search_field_scale();
|
1027 |
-
}
|
1028 |
-
};
|
1029 |
-
|
1030 |
-
Chosen.prototype.single_set_selected_text = function(text) {
|
1031 |
-
if (text == null) {
|
1032 |
-
text = this.default_text;
|
1033 |
-
}
|
1034 |
-
if (text === this.default_text) {
|
1035 |
-
this.selected_item.addClass("chosen-default");
|
1036 |
-
} else {
|
1037 |
-
this.single_deselect_control_build();
|
1038 |
-
this.selected_item.removeClass("chosen-default");
|
1039 |
-
}
|
1040 |
-
return this.selected_item.find("span").text(text);
|
1041 |
-
};
|
1042 |
-
|
1043 |
-
Chosen.prototype.result_deselect = function(pos) {
|
1044 |
-
var result_data;
|
1045 |
-
result_data = this.results_data[pos];
|
1046 |
-
if (!this.form_field.options[result_data.options_index].disabled) {
|
1047 |
-
result_data.selected = false;
|
1048 |
-
this.form_field.options[result_data.options_index].selected = false;
|
1049 |
-
this.selected_option_count = null;
|
1050 |
-
this.result_clear_highlight();
|
1051 |
-
if (this.results_showing) {
|
1052 |
-
this.winnow_results();
|
1053 |
-
}
|
1054 |
-
this.form_field_jq.trigger("change", {
|
1055 |
-
deselected: this.form_field.options[result_data.options_index].value
|
1056 |
-
});
|
1057 |
-
this.search_field_scale();
|
1058 |
-
return true;
|
1059 |
-
} else {
|
1060 |
-
return false;
|
1061 |
-
}
|
1062 |
-
};
|
1063 |
-
|
1064 |
-
Chosen.prototype.single_deselect_control_build = function() {
|
1065 |
-
if (!this.allow_single_deselect) {
|
1066 |
-
return;
|
1067 |
-
}
|
1068 |
-
if (!this.selected_item.find("abbr").length) {
|
1069 |
-
this.selected_item.find("span").first().after("<abbr class=\"search-choice-close\"></abbr>");
|
1070 |
-
}
|
1071 |
-
return this.selected_item.addClass("chosen-single-with-deselect");
|
1072 |
-
};
|
1073 |
-
|
1074 |
-
Chosen.prototype.get_search_text = function() {
|
1075 |
-
if (this.search_field.val() === this.default_text) {
|
1076 |
-
return "";
|
1077 |
-
} else {
|
1078 |
-
return $('<div/>').text($.trim(this.search_field.val())).html();
|
1079 |
-
}
|
1080 |
-
};
|
1081 |
-
|
1082 |
-
Chosen.prototype.winnow_results_set_highlight = function() {
|
1083 |
-
var do_high, selected_results;
|
1084 |
-
selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : [];
|
1085 |
-
do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first();
|
1086 |
-
if (do_high != null) {
|
1087 |
-
return this.result_do_highlight(do_high);
|
1088 |
-
}
|
1089 |
-
};
|
1090 |
-
|
1091 |
-
Chosen.prototype.no_results = function(terms) {
|
1092 |
-
var no_results_html;
|
1093 |
-
no_results_html = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>');
|
1094 |
-
no_results_html.find("span").first().html(terms);
|
1095 |
-
this.search_results.append(no_results_html);
|
1096 |
-
return this.form_field_jq.trigger("chosen:no_results", {
|
1097 |
-
chosen: this
|
1098 |
-
});
|
1099 |
-
};
|
1100 |
-
|
1101 |
-
Chosen.prototype.no_results_clear = function() {
|
1102 |
-
return this.search_results.find(".no-results").remove();
|
1103 |
-
};
|
1104 |
-
|
1105 |
-
Chosen.prototype.keydown_arrow = function() {
|
1106 |
-
var next_sib;
|
1107 |
-
if (this.results_showing && this.result_highlight) {
|
1108 |
-
next_sib = this.result_highlight.nextAll("li.active-result").first();
|
1109 |
-
if (next_sib) {
|
1110 |
-
return this.result_do_highlight(next_sib);
|
1111 |
-
}
|
1112 |
-
} else {
|
1113 |
-
return this.results_show();
|
1114 |
-
}
|
1115 |
-
};
|
1116 |
-
|
1117 |
-
Chosen.prototype.keyup_arrow = function() {
|
1118 |
-
var prev_sibs;
|
1119 |
-
if (!this.results_showing && !this.is_multiple) {
|
1120 |
-
return this.results_show();
|
1121 |
-
} else if (this.result_highlight) {
|
1122 |
-
prev_sibs = this.result_highlight.prevAll("li.active-result");
|
1123 |
-
if (prev_sibs.length) {
|
1124 |
-
return this.result_do_highlight(prev_sibs.first());
|
1125 |
-
} else {
|
1126 |
-
if (this.choices_count() > 0) {
|
1127 |
-
this.results_hide();
|
1128 |
-
}
|
1129 |
-
return this.result_clear_highlight();
|
1130 |
-
}
|
1131 |
-
}
|
1132 |
-
};
|
1133 |
-
|
1134 |
-
Chosen.prototype.keydown_backstroke = function() {
|
1135 |
-
var next_available_destroy;
|
1136 |
-
if (this.pending_backstroke) {
|
1137 |
-
this.choice_destroy(this.pending_backstroke.find("a").first());
|
1138 |
-
return this.clear_backstroke();
|
1139 |
-
} else {
|
1140 |
-
next_available_destroy = this.search_container.siblings("li.search-choice").last();
|
1141 |
-
if (next_available_destroy.length && !next_available_destroy.hasClass("search-choice-disabled")) {
|
1142 |
-
this.pending_backstroke = next_available_destroy;
|
1143 |
-
if (this.single_backstroke_delete) {
|
1144 |
-
return this.keydown_backstroke();
|
1145 |
-
} else {
|
1146 |
-
return this.pending_backstroke.addClass("search-choice-focus");
|
1147 |
-
}
|
1148 |
-
}
|
1149 |
-
}
|
1150 |
-
};
|
1151 |
-
|
1152 |
-
Chosen.prototype.clear_backstroke = function() {
|
1153 |
-
if (this.pending_backstroke) {
|
1154 |
-
this.pending_backstroke.removeClass("search-choice-focus");
|
1155 |
-
}
|
1156 |
-
return this.pending_backstroke = null;
|
1157 |
-
};
|
1158 |
-
|
1159 |
-
Chosen.prototype.keydown_checker = function(evt) {
|
1160 |
-
var stroke, _ref1;
|
1161 |
-
stroke = (_ref1 = evt.which) != null ? _ref1 : evt.keyCode;
|
1162 |
-
this.search_field_scale();
|
1163 |
-
if (stroke !== 8 && this.pending_backstroke) {
|
1164 |
-
this.clear_backstroke();
|
1165 |
-
}
|
1166 |
-
switch (stroke) {
|
1167 |
-
case 8:
|
1168 |
-
this.backstroke_length = this.search_field.val().length;
|
1169 |
-
break;
|
1170 |
-
case 9:
|
1171 |
-
if (this.results_showing && !this.is_multiple) {
|
1172 |
-
this.result_select(evt);
|
1173 |
-
}
|
1174 |
-
this.mouse_on_container = false;
|
1175 |
-
break;
|
1176 |
-
case 13:
|
1177 |
-
if (this.results_showing) {
|
1178 |
-
evt.preventDefault();
|
1179 |
-
}
|
1180 |
-
break;
|
1181 |
-
case 32:
|
1182 |
-
if (this.disable_search) {
|
1183 |
-
evt.preventDefault();
|
1184 |
-
}
|
1185 |
-
break;
|
1186 |
-
case 38:
|
1187 |
-
evt.preventDefault();
|
1188 |
-
this.keyup_arrow();
|
1189 |
-
break;
|
1190 |
-
case 40:
|
1191 |
-
evt.preventDefault();
|
1192 |
-
this.keydown_arrow();
|
1193 |
-
break;
|
1194 |
-
}
|
1195 |
-
};
|
1196 |
-
|
1197 |
-
Chosen.prototype.search_field_scale = function() {
|
1198 |
-
var div, f_width, h, style, style_block, styles, w, _i, _len;
|
1199 |
-
if (this.is_multiple) {
|
1200 |
-
h = 0;
|
1201 |
-
w = 0;
|
1202 |
-
style_block = "position:absolute; left: -1000px; top: -1000px; display:none;";
|
1203 |
-
styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing'];
|
1204 |
-
for (_i = 0, _len = styles.length; _i < _len; _i++) {
|
1205 |
-
style = styles[_i];
|
1206 |
-
style_block += style + ":" + this.search_field.css(style) + ";";
|
1207 |
-
}
|
1208 |
-
div = $('<div />', {
|
1209 |
-
'style': style_block
|
1210 |
-
});
|
1211 |
-
div.text(this.search_field.val());
|
1212 |
-
$('body').append(div);
|
1213 |
-
w = div.width() + 25;
|
1214 |
-
div.remove();
|
1215 |
-
f_width = this.container.outerWidth();
|
1216 |
-
if (w > f_width - 10) {
|
1217 |
-
w = f_width - 10;
|
1218 |
-
}
|
1219 |
-
return this.search_field.css({
|
1220 |
-
'width': w + 'px'
|
1221 |
-
});
|
1222 |
-
}
|
1223 |
-
};
|
1224 |
-
|
1225 |
-
return Chosen;
|
1226 |
-
|
1227 |
-
})(AbstractChosen);
|
1228 |
-
|
1229 |
-
}).call(this);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/js/fc-multistaff-view.js
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
(function($) {
|
2 |
+
var FC = $.fullCalendar; // a reference to FullCalendar's root namespace
|
3 |
+
|
4 |
+
var MultiStaffView = FC.views.agenda.class.extend({
|
5 |
+
initialize: function() {
|
6 |
+
FC.views.agenda.class.prototype.initialize.apply(this, arguments);
|
7 |
+
|
8 |
+
this.timeGrid.rangeUpdated = function() {
|
9 |
+
var view = this.view;
|
10 |
+
var colDates = [];
|
11 |
+
var date;
|
12 |
+
|
13 |
+
date = this.start.clone();
|
14 |
+
while (date.isBefore(this.end)) {
|
15 |
+
for (var i = 0; i < this.view.opt('staffMembers').length; ++ i) {
|
16 |
+
// For each staff create separate column.
|
17 |
+
colDates.push(date.clone());
|
18 |
+
}
|
19 |
+
date.add(1, 'day');
|
20 |
+
date = view.skipHiddenDays(date);
|
21 |
+
}
|
22 |
+
|
23 |
+
if (this.isRTL) {
|
24 |
+
colDates.reverse();
|
25 |
+
}
|
26 |
+
|
27 |
+
this.colDates = colDates;
|
28 |
+
this.colCnt = colDates.length;
|
29 |
+
this.rowCnt = Math.ceil((this.maxTime - this.minTime) / this.snapDuration);
|
30 |
+
};
|
31 |
+
|
32 |
+
this.timeGrid.groupSegCols = function(segs) {
|
33 |
+
var segCols = [];
|
34 |
+
var i;
|
35 |
+
|
36 |
+
for (i = 0; i < this.colCnt; i++) {
|
37 |
+
segCols.push([]);
|
38 |
+
}
|
39 |
+
|
40 |
+
var staffCols = {};
|
41 |
+
for (var i = 0; i < this.view.opt('staffMembers').length; ++ i) {
|
42 |
+
staffCols[this.view.opt('staffMembers')[i].id] = i;
|
43 |
+
}
|
44 |
+
|
45 |
+
for (i = 0; i < segs.length; i++) {
|
46 |
+
segCols[staffCols[segs[i].event.staffId]].push(segs[i]);
|
47 |
+
}
|
48 |
+
|
49 |
+
return segCols;
|
50 |
+
};
|
51 |
+
|
52 |
+
this.timeGrid.rangeToSegs = function(range) {
|
53 |
+
var colCnt = this.colCnt;
|
54 |
+
var segs = [];
|
55 |
+
var seg;
|
56 |
+
var col;
|
57 |
+
var colDate;
|
58 |
+
var colRange;
|
59 |
+
|
60 |
+
// Take staff id into account too.
|
61 |
+
range = {
|
62 |
+
start: range.start.clone().stripZone(),
|
63 |
+
end: range.end.clone().stripZone(),
|
64 |
+
staffId: range.event.staffId
|
65 |
+
};
|
66 |
+
|
67 |
+
for (col = 0; col < colCnt; col++) {
|
68 |
+
colDate = this.colDates[col];
|
69 |
+
colRange = {
|
70 |
+
start: colDate.clone().time(this.minTime),
|
71 |
+
end: colDate.clone().time(this.maxTime),
|
72 |
+
staffId: this.view.opt('staffMembers')[col].id
|
73 |
+
};
|
74 |
+
seg = intersectionToSeg(range, colRange);
|
75 |
+
if (seg) {
|
76 |
+
seg.col = col;
|
77 |
+
segs.push(seg);
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
return segs;
|
82 |
+
};
|
83 |
+
|
84 |
+
this.timeGrid.headHtml = function() {
|
85 |
+
var rowCellHtml = '';
|
86 |
+
var col;
|
87 |
+
|
88 |
+
for (col = 0; col < this.colCnt; col++) {
|
89 |
+
rowCellHtml += '<th class="fc-day-header fc-widget-header fc-mon">' + this.view.opt('staffMembers')[col].name + '</th>'
|
90 |
+
}
|
91 |
+
|
92 |
+
rowCellHtml = this.bookendCells(rowCellHtml, 'head', 0);
|
93 |
+
|
94 |
+
return '' +
|
95 |
+
'<div class="fc-row ' + this.view.widgetHeaderClass + '">' +
|
96 |
+
'<table>' +
|
97 |
+
'<thead>' +
|
98 |
+
'<tr>' + rowCellHtml + '</tr>' +
|
99 |
+
'</thead>' +
|
100 |
+
'</table>' +
|
101 |
+
'</div>';
|
102 |
+
};
|
103 |
+
}
|
104 |
+
});
|
105 |
+
|
106 |
+
|
107 |
+
FC.views.multiStaff = {
|
108 |
+
'class': MultiStaffView, // register our class with the view system
|
109 |
+
defaults: {
|
110 |
+
staffMembers: [],
|
111 |
+
allDaySlot: true,
|
112 |
+
allDayText: 'all-day',
|
113 |
+
slotDuration: '00:30:00',
|
114 |
+
minTime: '00:00:00',
|
115 |
+
maxTime: '24:00:00',
|
116 |
+
slotEventOverlap: true // a bad name. confused with overlap/constraint system
|
117 |
+
}
|
118 |
+
};
|
119 |
+
|
120 |
+
FC.views.multiStaffDay = {
|
121 |
+
type: 'multiStaff',
|
122 |
+
duration: { days: 1 }
|
123 |
+
};
|
124 |
+
|
125 |
+
function intersectionToSeg(subjectRange, constraintRange) {
|
126 |
+
var subjectStart = subjectRange.start;
|
127 |
+
var subjectEnd = subjectRange.end;
|
128 |
+
var constraintStart = constraintRange.start;
|
129 |
+
var constraintEnd = constraintRange.end;
|
130 |
+
var segStart, segEnd;
|
131 |
+
var isStart, isEnd;
|
132 |
+
|
133 |
+
// Take staff id into account too.
|
134 |
+
if (subjectEnd > constraintStart && subjectStart < constraintEnd && subjectRange.staffId == constraintRange.staffId) {
|
135 |
+
|
136 |
+
if (subjectStart >= constraintStart) {
|
137 |
+
segStart = subjectStart.clone();
|
138 |
+
isStart = true;
|
139 |
+
} else {
|
140 |
+
segStart = constraintStart.clone();
|
141 |
+
isStart = false;
|
142 |
+
}
|
143 |
+
|
144 |
+
if (subjectEnd <= constraintEnd) {
|
145 |
+
segEnd = subjectEnd.clone();
|
146 |
+
isEnd = true;
|
147 |
+
} else {
|
148 |
+
segEnd = constraintEnd.clone();
|
149 |
+
isEnd = false;
|
150 |
+
}
|
151 |
+
|
152 |
+
return {
|
153 |
+
start: segStart,
|
154 |
+
end: segEnd,
|
155 |
+
isStart: isStart,
|
156 |
+
isEnd: isEnd
|
157 |
+
};
|
158 |
+
}
|
159 |
+
}
|
160 |
+
})(jQuery);
|
backend/modules/calendar/resources/js/fullcalendar.min.js
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*!
|
2 |
+
* FullCalendar v2.3.2
|
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 J(a,La)}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,La)?(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===Ma&&(Ma=t()),Ma}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(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 B(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days"),ms:a.time()-c.time()})}function C(a,c){return b.duration({days:a.clone().stripTime().diff(c.clone().stripTime(),"days")})}function D(a,c,d){return b.duration(Math.round(a.diff(c,d,!0)),d)}function E(a,b){var c,d,e;for(c=0;c<Ra.length&&(d=Ra[c],e=F(d,a,b),!(e>=1&&W(e)));c++);return d}function F(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 G(a){return Boolean(a.hours()||a.minutes()||a.seconds()||a.milliseconds())}function H(a){return"[object Date]"===Object.prototype.toString.call(a)||a instanceof Date}function I(a){return/^\d+\:\d+(?:\:\d+\.?(?:\d{3})?)?$/.test(a)}function J(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]=J(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 K(a){var b=function(){};return b.prototype=a,new b}function L(a,b){for(var c in a)N(a,c)&&(b[c]=a[c])}function M(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 N(a,b){return Sa.call(a,b)}function O(b){return/undefined|null|boolean|number|string/.test(a.type(b))}function P(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 Q(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a]}function R(a){return(a+"").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/'/g,"'").replace(/"/g,""").replace(/\n/g,"<br />")}function S(a){return a.replace(/&.*?;/g,"")}function T(b){var c=[];return a.each(b,function(a,b){null!=b&&c.push(a+":"+b)}),c.join(";")}function U(a){return a.charAt(0).toUpperCase()+a.slice(1)}function V(a,b){return a-b}function W(a){return a%1===0}function X(a,b){var c=a[b];return function(){return c.apply(a,arguments)}}function Y(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 Z(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),_(j,i)):H(j)||void 0===j?i=b.apply(null,c):(f=!1,g=!1,k?Ta.test(j)?(j+="-01",c=[j],f=!0,g=!0):(h=Ua.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 $(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=Ja.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 _(a,b){a._ambigTime?b._ambigTime=!0:b._ambigTime&&(b._ambigTime=!1),a._ambigZone?b._ambigZone=!0:b._ambigZone&&(b._ambigZone=!1)}function aa(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 ba(a,b){return Wa.format.call(a,b)}function ca(a,b){return da(a,ia(b))}function da(a,b){var c,d="";for(c=0;c<b.length;c++)d+=ea(a,b[c]);return d}function ea(a,b){var c,d;return"string"==typeof b?b:(c=b.token)?Xa[c]?Xa[c](a):ba(a,c):b.maybe&&(d=da(a,b.maybe),d.match(/[1-9]/))?d:""}function fa(a,b,c,d,e){var f;return a=Ja.moment.parseZone(a),b=Ja.moment.parseZone(b),f=(a.localeData||a.lang).call(a),c=f.longDateFormat(c)||c,d=d||" - ",ga(a,b,ia(c),d,e)}function ga(a,b,c,d,e){var f,g,h,i,j="",k="",l="",m="",n="";for(g=0;g<c.length&&(f=ha(a,b,c[g]),f!==!1);g++)j+=f;for(h=c.length-1;h>g&&(f=ha(a,b,c[h]),f!==!1);h--)k=f+k;for(i=g;h>=i;i++)l+=ea(a,c[i]),m+=ea(b,c[i]);return(l||m)&&(n=e?m+d+l:l+d+m),j+n+k}function ha(a,b,c){var d,e;return"string"==typeof c?c:(d=c.token)&&(e=Ya[d.charAt(0)],e&&a.isSame(b,e))?ba(a,d):!1}function ia(a){return a in Za?Za[a]:Za[a]=ja(a)}function ja(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:ja(b[2])}):b[3]?c.push({token:b[3]}):b[5]&&c.push(b[5]);return c}function ka(){}function la(a,b){return a||b?a&&b?a.grid===b.grid&&a.row===b.row&&a.col===b.col:!1:!0}function ma(a){var b=oa(a);return"background"===b||"inverse-background"===b}function na(a){return"inverse-background"===oa(a)}function oa(a){return Q((a.source||{}).rendering,a.rendering)}function pa(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 qa(a,b){return a.eventStartMS-b.eventStartMS}function ra(a,b){return a.eventStartMS-b.eventStartMS||b.eventDurationMS-a.eventDurationMS||b.event.allDay-a.event.allDay||(a.event.title||"").localeCompare(b.event.title)}function sa(c){var d,e,f,g,h=Ja.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 ta(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 ua(a,b){return a.leftCol-b.leftCol}function va(a){var b,c,d;if(a.sort(ra),b=wa(a),xa(b),c=b[0]){for(d=0;d<c.length;d++)ya(c[d]);for(d=0;d<c.length;d++)za(c[d],0,0)}}function wa(a){var b,c,d,e=[];for(b=0;b<a.length;b++){for(c=a[b],d=0;d<e.length&&Aa(c,e[d]).length;d++);c.level=d,(e[d]||(e[d]=[])).push(c)}return e}function xa(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++)Aa(e,a[f],e.forwardSegs)}function ya(a){var b,c,d=a.forwardSegs,e=0;if(void 0===a.forwardPressure){for(b=0;b<d.length;b++)c=d[b],ya(c),e=Math.max(e,1+c.forwardPressure);a.forwardPressure=e}}function za(a,b,c){var d,e=a.forwardSegs;if(void 0===a.forwardCoord)for(e.length?(e.sort(Ca),za(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++)za(e[d],0,a.forwardCoord)}function Aa(a,b,c){c=c||[];for(var d=0;d<b.length;d++)Ba(a,b[d])&&c.push(b[d]);return c}function Ba(a,b){return a.bottom>b.top&&a.top<b.bottom}function Ca(a,b){return b.forwardPressure-a.forwardPressure||(a.backwardCoord||0)-(b.backwardCoord||0)||ra(a,b)}function Da(c,d){function e(){U?h()&&(k(),i()):f()}function f(){V=P.theme?"ui":"fc",c.addClass("fc"),P.isRTL?c.addClass("fc-rtl"):c.addClass("fc-ltr"),P.theme?c.addClass("ui-widget"):c.addClass("fc-unthemed"),U=a("<div class='fc-view-container'/>").prependTo(c),S=O.header=new Ga(O,P),T=S.render(),T&&c.prepend(T),i(P.defaultView),P.handleWindowResize&&(Z=Y(m,P.windowResizeDelay),a(window).resize(Z))}function g(){W&&W.removeElement(),S.removeElement(),U.remove(),c.removeClass("fc fc-ltr fc-rtl fc-unthemed ui-widget"),Z&&a(window).unbind("resize",Z)}function h(){return c.is(":visible")}function i(b){da++,W&&b&&W.type!==b&&(S.deactivateButton(W.type),H(),W.removeElement(),W=O.view=null),!W&&b&&(W=O.view=ca[b]||(ca[b]=O.instantiateView(b)),W.setElement(a("<div class='fc-view fc-"+b+"-view' />").appendTo(U)),S.activateButton(b)),W&&($=W.massageCurrentDate($),W.displaying&&$.isWithin(W.intervalStart,W.intervalEnd)||h()&&(H(),W.display($),I(),u(),v(),q())),I(),da--}function j(a){return h()?(a&&l(),da++,W.updateSize(!0),da--,!0):void 0}function k(){h()&&l()}function l(){X="number"==typeof P.contentHeight?P.contentHeight:"number"==typeof P.height?P.height-(T?T.outerHeight(!0):0):Math.round(U.width()/Math.max(P.aspectRatio,.5))}function m(a){!da&&a.target===window&&W.start&&j(!0)&&W.trigger("windowResize",ba)}function n(){p(),r()}function o(){h()&&(H(),W.displayEvents(ea),I())}function p(){H(),W.clearEvents(),I()}function q(){!P.lazyFetching||_(W.start,W.end)?r():o()}function r(){aa(W.start,W.end)}function s(a){ea=a,o()}function t(){o()}function u(){S.updateTitle(W.title)}function v(){var a=O.getNow();a.isWithin(W.intervalStart,W.intervalEnd)?S.disableButton("today"):S.enableButton("today")}function w(a,b){W.select(O.buildSelectRange.apply(O,arguments))}function x(){W&&W.unselect()}function y(){$=W.computePrevDate($),i()}function z(){$=W.computeNextDate($),i()}function A(){$.add(-1,"years"),i()}function B(){$.add(1,"years"),i()}function C(){$=O.getNow(),i()}function D(a){$=O.moment(a),i()}function E(a){$.add(b.duration(a)),i()}function F(a,b){var c;b=b||"day",c=O.getViewSpec(b)||O.getUnitViewSpec(b),$=a,i(c?c.type:null)}function G(){return $.clone()}function H(){U.css({width:"100%",height:U.height(),overflow:"hidden"})}function I(){U.css({width:"",height:"",overflow:""})}function J(){return O}function L(){return W}function M(a,b){return void 0===b?P[a]:void(("height"==a||"contentHeight"==a||"aspectRatio"==a)&&(P[a]=b,j(!0)))}function N(a,b){return P[a]?P[a].apply(b||ba,Array.prototype.slice.call(arguments,2)):void 0}var O=this;O.initOptions(d||{});var P=this.options;O.render=e,O.destroy=g,O.refetchEvents=n,O.reportEvents=s,O.reportEventChange=t,O.rerenderEvents=o,O.changeView=i,O.select=w,O.unselect=x,O.prev=y,O.next=z,O.prevYear=A,O.nextYear=B,O.today=C,O.gotoDate=D,O.incrementDate=E,O.zoomTo=F,O.getDate=G,O.getCalendar=J,O.getView=L,O.option=M,O.trigger=N;var Q=K(Fa(P.lang));if(P.monthNames&&(Q._months=P.monthNames),P.monthNamesShort&&(Q._monthsShort=P.monthNamesShort),P.dayNames&&(Q._weekdays=P.dayNames),P.dayNamesShort&&(Q._weekdaysShort=P.dayNamesShort),null!=P.firstDay){var R=K(Q._week);R.dow=P.firstDay,Q._week=R}Q._fullCalendar_weekCalc=function(a){return"function"==typeof a?a:"local"===a?a:"iso"===a||"ISO"===a?"ISO":void 0}(P.weekNumberCalculation),O.defaultAllDayEventDuration=b.duration(P.defaultAllDayEventDuration),O.defaultTimedEventDuration=b.duration(P.defaultTimedEventDuration),O.moment=function(){var a;return"local"===P.timezone?(a=Ja.moment.apply(null,arguments),a.hasTime()&&a.local()):a="UTC"===P.timezone?Ja.moment.utc.apply(null,arguments):Ja.moment.parseZone.apply(null,arguments),"_locale"in a?a._locale=Q:a._lang=Q,a},O.getIsAmbigTimezone=function(){return"local"!==P.timezone&&"UTC"!==P.timezone},O.rezoneDate=function(a){return O.moment(a.toArray())},O.getNow=function(){var a=P.now;return"function"==typeof a&&(a=a()),O.moment(a)},O.getEventEnd=function(a){return a.end?a.end.clone():O.getDefaultEventEnd(a.allDay,a.start)},O.getDefaultEventEnd=function(a,b){var c=b.clone();return a?c.stripTime().add(O.defaultAllDayEventDuration):c.add(O.defaultTimedEventDuration),O.getIsAmbigTimezone()&&c.stripZone(),c},O.humanizeDuration=function(a){return(a.locale||a.lang).call(a,P.lang).humanize()},Ha.call(O,P);var S,T,U,V,W,X,Z,$,_=O.isFetchNeeded,aa=O.fetchEvents,ba=c[0],ca={},da=0,ea=[];$=null!=P.defaultDate?O.moment(P.defaultDate):O.getNow(),O.getSuggestedViewHeight=function(){return void 0===X&&k(),X},O.isHeightAuto=function(){return"auto"===P.contentHeight||"auto"===P.height},O.initialize()}function Ea(b){a.each(nb,function(a,c){null==b[a]&&(b[a]=c(b))})}function Fa(a){var c=b.localeData||b.langData;return c.call(b,a)||c.call(b,"en")}function Ga(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;"title"==e?(g=g.add(a("<h2> </h2>")),h=!1):(f=b.getViewSpec(e),f?(i=function(){b.changeView(e)},p.push(e),j=f.buttonTextOverride,k=f.buttonTextDefault):b[e]&&(i=function(){b[e]()},j=(b.overrides.buttonText||{})[e],k=c.buttonText[e]),i&&(l=c.themeButtonIcons[e],m=c.buttonIcons[e],o=j?R(j):l&&c.theme?"<span class='ui-icon ui-icon-"+l+"'></span>":m&&!c.theme?"<span class='fc-icon fc-icon-"+m+"'></span>":R(k),q=["fc-"+e+"-button",n+"-button",n+"-state-default"],r=a('<button type="button" class="'+q.join(" ")+'">'+o+"</button>").click(function(){r.hasClass(n+"-state-disabled")||(i(),(r.hasClass(n+"-state-active")||r.hasClass(n+"-state-disabled"))&&r.removeClass(n+"-state-hover"))}).mousedown(function(){r.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-down")}).mouseup(function(){r.removeClass(n+"-state-down")}).hover(function(){r.not("."+n+"-state-active").not("."+n+"-state-disabled").addClass(n+"-state-hover")},function(){r.removeClass(n+"-state-hover").removeClass(n+"-state-down")}),g=g.add(r)))}),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 Ha(c){function d(a,b){return!N||a.clone().stripZone()<N.clone().stripZone()||b.clone().stripZone()>R.clone().stripZone()}function e(a,b){N=a,R=b,X=[];var c=++V,d=U.length;W=d;for(var e=0;d>e;e++)f(U[e],c)}function f(b,c){g(b,function(d){var e,f,g,h=a.isArray(b.events);if(c==V){if(d)for(e=0;e<d.length;e++)f=d[e],g=h?f:s(f,b),g&&X.push.apply(X,x(g));W--,W||S(X)}})}function g(b,d){var e,f,h=Ja.sourceFetchers;for(e=0;e<h.length;e++){if(f=h[e].call(M,b,N.clone(),R.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)?(M.pushLoading(),i.call(M,N.clone(),R.clone(),c.timezone,function(a){d(a),M.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=Q(b.startParam,c.startParam),q=Q(b.endParam,c.endParam),r=Q(b.timezoneParam,c.timezoneParam);p&&(o[p]=N.format()),q&&(o[q]=R.format()),c.timezone&&"local"!=c.timezone&&(o[r]=c.timezone),M.pushLoading(),a.ajax(a.extend({},ob,b,{data:o,success:function(b){b=b||[];var c=P(l,this,arguments);a.isArray(c)&&(b=c),d(b)},error:function(){P(m,this,arguments),d()},complete:function(){P(n,this,arguments),M.popLoading()}}))}else d()}}function h(a){var b=i(a);b&&(U.push(b),W++,f(b,V))}function i(b){var c,d,e=Ja.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(M,c);return c}}function j(b){U=a.grep(U,function(a){return!k(a,b)}),X=a.grep(X,function(a){return!k(a.source,b)}),S(X)}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=M.moment(a.start),a.end?a.end=M.moment(a.end):a.end=null,y(a,n(a)),S(X)}function n(b){var c={};return a.each(b,function(a,b){o(a)&&void 0!==b&&O(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&&(T.events.push(e),e.source=T),X.push(e));return S(X),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}),X=a.grep(X,b,!0),d=0;d<U.length;d++)a.isArray(U[d].events)&&(U[d].events=a.grep(U[d].events,b,!0));S(X)}function r(b){return a.isFunction(b)?a.grep(X,b):null!=b?(b+="",a.grep(X,function(a){return a._id==b})):X}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"+pb++: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,I(f)&&(f=b.duration(f)),I(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=M.moment(f),!f.isValid()))return!1;g&&(g=M.moment(g),g.isValid()||(g=null)),h=d.allDay,void 0===h&&(h=Q(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),Ia(d)}function u(a){v(a),a.end&&!a.end.isAfter(a.start)&&(a.end=null),a.end||(c.forceEventDuration?a.end=M.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=M.rezoneDate(a.start)),a.end&&!a.end.hasTime()&&(a.end=M.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=M.getDefaultEventEnd(c,b.start)),b}function x(b,c,d){var e,f,g,h,i,j,k,l,m,n=[];if(c=c||N,d=d||R,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?D(a,b,d):c.allDay?C(a,b):B(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():M.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=M.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=M.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),Ia(j),i.push(function(){a.extend(j,k),Ia(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=M.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 E(a,b){var d=b.source||{},e=Q(b.constraint,d.constraint,c.eventConstraint),f=Q(b.overlap,d.overlap,c.eventOverlap);return a=w(a),H(a,e,f,b)}function F(a){return H(a,c.selectConstraint,c.selectOverlap)}function G(b,c){var d,e;return c&&(d=a.extend({},c,b),e=x(s(d))[0]),e?E(b,e):(b=w(b),F(b))}function H(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=J(c),g=!1,i=0;i<f.length;i++)if(K(f[i],b)){g=!0;break}if(!g)return!1}for(h=M.getPeerEvents(e,b),i=0;i<h.length;i++)if(j=h[i],L(j,b)){if(d===!1)return!1;if("function"==typeof d&&!d(j,e))return!1;if(e){if(k=Q(j.overlap,(j.source||{}).overlap),k===!1)return!1;if("function"==typeof k&&!k(e,j))return!1}}return!0}function J(a){return"businessHours"===a?A():"object"==typeof a?x(s(a)):r(a)}function K(a,b){var c=a.start.clone().stripZone(),d=M.getEventEnd(a).stripZone();return b.start>=c&&b.end<=d}function L(a,b){var c=a.start.clone().stripZone(),d=M.getEventEnd(a).stripZone();return b.start<d&&b.end>c}var M=this;M.isFetchNeeded=d,M.fetchEvents=e,M.addEventSource=h,M.removeEventSource=j,M.updateEvent=m,M.renderEvent=p,M.removeEvents=q,M.clientEvents=r,M.mutateEvent=y,M.normalizeEventRange=u,M.normalizeEventRangeTimes=v,M.ensureVisibleEventRange=w;var N,R,S=M.reportEvents,T={events:[]},U=[T],V=0,W=0,X=[];a.each((c.events?[c.events]:[]).concat(c.eventSources||[]),function(a,b){var c=i(b);c&&U.push(c)}),M.getBusinessHoursEvents=A,M.isEventRangeAllowed=E,M.isSelectionRangeAllowed=F,M.isExternalDropRangeAllowed=G,M.getEventCache=function(){return X}}function Ia(a){a._allDay=a.allDay,a._start=a.start.clone(),a._end=a.end?a.end.clone():null}var Ja=a.fullCalendar={version:"2.3.2"},Ka=Ja.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 jb(h,b),h.data("fullCalendar",i),i.render())}),d};var La=["header","buttonText","buttonIcons","themeButtonIcons"];Ja.intersectionToSeg=A,Ja.applyAll=P,Ja.debounce=Y,Ja.isInt=W,Ja.htmlEscape=R,Ja.cssToStr=T,Ja.proxy=X,Ja.capitaliseFirstLetter=U,Ja.getClientRect=p,Ja.getContentRect=q,Ja.getScrollbarWidths=r;var Ma=null;Ja.computeIntervalUnit=E,Ja.durationHasTime=G;var Na,Oa,Pa,Qa=["sun","mon","tue","wed","thu","fri","sat"],Ra=["year","month","week","day","hour","minute","second","millisecond"],Sa={}.hasOwnProperty,Ta=/^\s*\d{4}-\d\d$/,Ua=/^\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+)?)?)?)?)?$/,Va=b.fn,Wa=a.extend({},Va);Ja.moment=function(){return Z(arguments)},Ja.moment.utc=function(){var a=Z(arguments,!0);return a.hasTime()&&a.utc(),a},Ja.moment.parseZone=function(){return Z(arguments,!0,!0)},Va.clone=function(){var a=Wa.clone.apply(this,arguments);return _(this,a),this._fullCalendar&&(a._fullCalendar=!0),a},Va.week=Va.weeks=function(a){var b=(this._locale||this._lang)._fullCalendar_weekCalc;return null==a&&"function"==typeof b?b(this):"ISO"===b?Wa.isoWeek.apply(this,arguments):Wa.week.apply(this,arguments)},Va.time=function(a){if(!this._fullCalendar)return Wa.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())},Va.stripTime=function(){var a;return this._ambigTime||(a=this.toArray(),this.utc(),Oa(this,a.slice(0,3)),this._ambigTime=!0,this._ambigZone=!0),this},Va.hasTime=function(){return!this._ambigTime},Va.stripZone=function(){var a,b;return this._ambigZone||(a=this.toArray(),b=this._ambigTime,this.utc(),Oa(this,a),this._ambigTime=b||!1,this._ambigZone=!0),this},Va.hasZone=function(){return!this._ambigZone},Va.local=function(){var a=this.toArray(),b=this._ambigZone;return Wa.local.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,b&&Pa(this,a),this},Va.utc=function(){return Wa.utc.apply(this,arguments),this._ambigTime=!1,this._ambigZone=!1,this},a.each(["zone","utcOffset"],function(a,b){Wa[b]&&(Va[b]=function(a){return null!=a&&(this._ambigTime=!1,this._ambigZone=!1),Wa[b].apply(this,arguments)})}),Va.format=function(){return this._fullCalendar&&arguments[0]?ca(this,arguments[0]):this._ambigTime?ba(this,"YYYY-MM-DD"):this._ambigZone?ba(this,"YYYY-MM-DD[T]HH:mm:ss"):Wa.format.apply(this,arguments)},Va.toISOString=function(){return this._ambigTime?ba(this,"YYYY-MM-DD"):this._ambigZone?ba(this,"YYYY-MM-DD[T]HH:mm:ss"):Wa.toISOString.apply(this,arguments)},Va.isWithin=function(a,b){var c=$([this,a,b]);return c[0]>=c[1]&&c[0]<c[2]},Va.isSame=function(a,b){var c;return this._fullCalendar?b?(c=$([this,a],!0),Wa.isSame.call(c[0],c[1],b)):(a=Ja.moment.parseZone(a),Wa.isSame.call(this,a)&&Boolean(this._ambigTime)===Boolean(a._ambigTime)&&Boolean(this._ambigZone)===Boolean(a._ambigZone)):Wa.isSame.apply(this,arguments)},a.each(["isBefore","isAfter"],function(a,b){Va[b]=function(a,c){var d;return this._fullCalendar?(d=$([this,a]),Wa[b].call(d[0],d[1],c)):Wa[b].apply(this,arguments)}}),Na="_d"in b()&&"updateOffset"in b,Oa=Na?function(a,c){a._d.setTime(Date.UTC.apply(Date,c)),b.updateOffset(a,!1)}:aa,Pa=Na?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)}:aa;var Xa={t:function(a){return ba(a,"a").charAt(0)},T:function(a){return ba(a,"A").charAt(0)}};Ja.formatRange=fa;var Ya={Y:"year",M:"month",D:"day",d:"day",A:"second",a:"second",T:"second",t:"second",H:"second",h:"second",m:"second",s:"second"},Za={};Ja.Class=ka,ka.extend=function(a){var b,c=this;return a=a||{},N(a,"constructor")&&(b=a.constructor),"function"!=typeof b&&(b=a.constructor=function(){c.apply(this,arguments)}),b.prototype=K(c.prototype),L(a,b.prototype),M(a,b.prototype),L(c,b),b},ka.mixin=function(a){L(a.prototype||a,this.prototype)};var $a=ka.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=X(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))}}),_a=ka.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}}),ab=ka.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()}}),bb=Ja.DragListener=ka.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,
|
7 |
+
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=Y(X(this,"scrollHandler"),100),this.scrollEl.on("scroll",this.scrollHandlerProxy))),a(document).on("mousemove",this.mousemoveProxy=X(this,"mousemove")).on("mouseup",this.mouseupProxy=X(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(X(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(){}}),cb=bb.extend({coordMap:null,origCell:null,cell:null,coordAdjust:null,constructor:function(a,b){bb.prototype.constructor.call(this,b),this.coordMap=a},listenStart:function(a){var b,c,d,e=this.subjectEl;bb.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;bb.prototype.dragStart.apply(this,arguments),b=this.getCell(a.pageX,a.pageY),b&&this.cellOver(b)},drag:function(a,b,c){var d;bb.prototype.drag.apply(this,arguments),d=this.getCell(c.pageX,c.pageY),la(d,this.cell)||(this.cell&&this.cellOut(),d&&this.cellOver(d))},dragStop:function(){this.cellDone(),bb.prototype.dragStop.apply(this,arguments)},cellOver:function(a){this.cell=a,this.trigger("cellOver",a,la(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(){bb.prototype.listenStop.apply(this,arguments),this.origCell=this.cell=null,this.coordMap.clear()},scrollStop:function(){bb.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)}}),db=ka.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=X(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())}}),eb=ka.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+U(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||""}}}),fb=Ja.Grid=eb.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(){eb.apply(this,arguments),this.coordMap=new _a(this),this.elsByFill={},this.externalDragStartProxy=X(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?D(a,b,this.largeUnit):B(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 cb(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?K(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(V),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=T(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()]+'">'+R(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}});fb.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],ma(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 db(a.el,{parentEl:e.el,opacity:e.opt("dragOpacity"),revertDuration:e.opt("dragRevertDuration"),zIndex:2}),l=new cb(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&&G(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=sa(a);d=new cb(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 cb(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&&G(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=pa(b),e=[];return a.each(d,function(a,b){b.length&&e.push.apply(e,na(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(qa),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}}),Ja.compareSegs=ra,Ja.dataAttrPrefix="";var gb=fb.extend({numbersVisible:!1,bottomCoordPadding:0,breakOnWeeks:null,cellDates:null,dayToCellOffsets:null,rowEls:null,dayEls:null,helperEls:null,constructor:function(){fb.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=fb.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}});gb.mixin({rowStructs:null,unrenderEvents:function(){this.removeSegPopover(),fb.prototype.unrenderEvents.apply(this,arguments)},getEventSegs:function(){return fb.prototype.getEventSegs.call(this).concat(this.popoverSegs||[])},renderBgSegs:function(b){var c=a.grep(b,function(a){return a.event.allDay});return fb.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=T(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">'+R(c)+"</span>")),d='<span class="fc-title">'+(R(f.title||"")||" ")+"</span>",'<a class="'+j.join(" ")+'"'+(f.url?' href="'+R(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(a.sort(ra),b=0;b<a.length;b++){for(c=a[b],d=0;d<e.length&&ta(c,e[d]);d++);c.level=d,(e[d]||(e[d]=[])).push(c)}for(d=0;d<e.length;d++)e[d].sort(ua);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}}),gb.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)}},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 $a(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">'+R(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,
|
8 |
+
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=A(a,g);return b?[b]:[]}),b.sort(ra),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 hb=fb.extend({slotDuration:null,snapDuration:null,minTime:null,maxTime:null,colDates:null,axisFormat:null,dayEls:null,slatEls:null,slatTops:null,helperEl:null,businessHourSegs:null,constructor:function(){fb.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=this.slotDuration.asMinutes()%15===0,i=b.duration(+this.minTime);i<this.maxTime;)a=this.start.clone().time(i),c=a.minutes(),d='<td class="fc-axis fc-time '+e.widgetContentClass+'" '+e.axisStyleAttr()+">"+(h&&c?"":"<span>"+R(a.format(this.axisFormat))+"</span>")+"</td>",g+="<tr "+(c?'class="fc-minor"':"")+">"+(f?"":d)+'<td class="'+e.widgetContentClass+'"/>'+(f?d:"")+"</tr>",i.add(this.slotDuration);return g},processOptions:function(){var a=this.view,c=a.opt("slotDuration"),d=a.opt("snapDuration");c=b.duration(c),d=d?b.duration(d):c,this.slotDuration=c,this.snapDuration=d,this.cellDuration=d,this.minTime=b.duration(a.opt("minTime")),this.maxTime=b.duration(a.opt("maxTime")),this.axisFormat=a.opt("axisFormat")||a.opt("smallTimeFormat")},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=A(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}});hb.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],va(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},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=T(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="'+R(g.url)+'"':"")+(l?' style="'+l+'"':"")+'><div class="fc-content">'+(c?'<div class="fc-time" data-start="'+R(e)+'" data-full="'+R(d)+'"><span>'+R(c)+"</span></div>":"")+(g.title?'<div class="fc-title">'+R(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}});var ib=Ja.View=ka.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,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.documentMousedownProxy=X(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=E(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)),fa(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 Q(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 Q(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}}),jb=Ja.Calendar=ka.extend({dirDefaults:null,langDefaults:null,overrides:null,options:null,viewSpecCache:null,view:null,header:null,loadingLevel:0,constructor:Da,initialize:function(){},initOptions:function(a){var b,e,f,g;a=d(a),b=a.lang,e=kb[b],e||(b=jb.defaults.lang,e=kb[b]||{}),f=Q(a.isRTL,e.isRTL,jb.defaults.isRTL),g=f?jb.rtlDefaults:{},this.dirDefaults=g,this.langDefaults=e,this.overrides=a,this.options=c([jb.defaults,g,e,a]),Ea(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(Ja.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=Ka[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=J(i),d.type=a,d["class"]?(f&&(f=b.duration(f),f.valueOf()&&(d.duration=f,g=E(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([jb.defaults,a.defaults,this.dirDefaults,this.langDefaults,this.overrides,a.overrides]),Ea(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(jb.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}}});jb.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:"*",eventLimit:!1,eventLimitText:"more",eventLimitClick:"popover",dayPopoverFormat:"LL",handleWindowResize:!0,windowResizeDelay:200},jb.englishDefaults={dayPopoverFormat:"dddd, MMMM D"},jb.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 kb=Ja.langs={};Ja.datepickerLang=function(b,c,d){var e=kb[b]||(kb[b]={});e.isRTL=d.isRTL,e.weekNumberTitle=d.weekHeader,a.each(lb,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))},Ja.lang=function(b,d){var e,f;e=kb[b]||(kb[b]={}),d&&(e=kb[b]=c([e,d])),f=Fa(b),a.each(mb,function(a,b){null==e[a]&&(e[a]=b(f,e))}),jb.defaults.lang=b};var lb={buttonText:function(a){return{prev:S(a.prevText),next:S(a.nextText),today:S(a.currentText)}},monthYearFormat:function(a){return a.showMonthAfterYear?"YYYY["+a.yearSuffix+"] MMMM":"MMMM YYYY["+a.yearSuffix+"]"}},mb={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,"")}},nb={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"}};Ja.lang("en",jb.englishDefaults),Ja.sourceNormalizers=[],Ja.sourceFetchers=[];var ob={dataType:"json",cache:!1},pb=1;jb.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 qb=ib.extend({dayGrid:null,dayNumbersVisible:!1,weekNumbersVisible:!1,weekNumberWidth:null,headRowEl:null,initialize:function(){this.dayGrid=new gb(this),this.coordMap=this.dayGrid.coordMap},setRange:function(a){ib.prototype.setRange.call(this,a),this.dayGrid.breakOnWeeks=/year|month|week/.test(this.intervalUnit),this.dayGrid.setRange(a)},computeRange:function(a){var b=ib.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>"+R(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()}}),rb=qb.extend({computeRange:function(a){var b,c=qb.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")}});Ka.basic={"class":qb},Ka.basicDay={type:"basic",duration:{days:1}},Ka.basicWeek={type:"basic",duration:{weeks:1}},Ka.month={"class":rb,duration:{months:1},defaults:{fixedWeekCount:!0}};var sb=ib.extend({timeGrid:null,dayGrid:null,axisWidth:null,noScrollRowEls:null,bottomRuleEl:null,bottomRuleHeight:null,initialize:function(){this.timeGrid=new hb(this),this.opt("allDaySlot")?(this.dayGrid=new gb(this),this.coordMap=new ab([this.dayGrid.coordMap,this.timeGrid.coordMap])):this.coordMap=this.timeGrid.coordMap},setRange:function(a){ib.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>"+R(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")||R(this.opt("allDayText")))+"</span></td>"},slotBgIntroHtml:function(){return'<td class="fc-axis '+this.widgetContentClass+'" '+this.axisStyleAttr()+"></td>"},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),ib.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=tb),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()}}),tb=5;return Ka.agenda={"class":sb,defaults:{allDaySlot:!0,allDayText:"all-day",slotDuration:"00:30:00",minTime:"00:00:00",maxTime:"24:00:00",slotEventOverlap:!0}},Ka.agendaDay={type:"agenda",duration:{days:1}},Ka.agendaWeek={type:"agenda",duration:{weeks:1}},Ja});
|
backend/modules/calendar/resources/js/jquery.weekcalendar.js
DELETED
@@ -1,2951 +0,0 @@
|
|
1 |
-
/*
|
2 |
-
* jQuery.weekCalendar v2.0-dev
|
3 |
-
*
|
4 |
-
* for support join us at the google group:
|
5 |
-
* - http://groups.google.com/group/jquery-week-calendar
|
6 |
-
* have a look to the wiki for documentation:
|
7 |
-
* - http://wiki.github.com/themouette/jquery-week-calendar/
|
8 |
-
* something went bad ? report an issue:
|
9 |
-
* - http://github.com/themouette/jquery-week-calendar/issues
|
10 |
-
* get the last version on github:
|
11 |
-
* - http://github.com/themouette/jquery-week-calendar
|
12 |
-
*
|
13 |
-
* Copyright (c) 2009 Rob Monie
|
14 |
-
* Copyright (c) 2010 Julien MUETTON
|
15 |
-
* Dual licensed under the MIT and GPL licenses:
|
16 |
-
* http://www.opensource.org/licenses/mit-license.php
|
17 |
-
* http://www.gnu.org/licenses/gpl.html
|
18 |
-
*
|
19 |
-
* If you're after a monthly calendar plugin, check out this one :
|
20 |
-
* http://arshaw.com/fullcalendar/
|
21 |
-
*/
|
22 |
-
|
23 |
-
(function($) {
|
24 |
-
// check the jquery version
|
25 |
-
var _v = $.fn.jquery.split('.'),
|
26 |
-
_jQuery14OrLower = (10 * _v[0] + _v[1]) < 15;
|
27 |
-
|
28 |
-
$.widget('ui.weekCalendar', (function() {
|
29 |
-
var _currentAjaxCall, _hourLineTimeout;
|
30 |
-
|
31 |
-
return {
|
32 |
-
options: {
|
33 |
-
date: new Date(),
|
34 |
-
timeFormat: null,
|
35 |
-
dateFormat: 'M d, Y',
|
36 |
-
alwaysDisplayTimeMinutes: true,
|
37 |
-
use24Hour: false,
|
38 |
-
daysToShow: 7,
|
39 |
-
minBodyHeight: 100,
|
40 |
-
firstDayOfWeek: function(calendar) {
|
41 |
-
if ($(calendar).weekCalendar('option', 'daysToShow') != 5) {
|
42 |
-
return 0;
|
43 |
-
} else {
|
44 |
-
//workweek
|
45 |
-
return 1;
|
46 |
-
}
|
47 |
-
}, // 0 = Sunday, 1 = Monday, 2 = Tuesday, ... , 6 = Saturday
|
48 |
-
useShortDayNames: false,
|
49 |
-
timeSeparator: ' to ',
|
50 |
-
startParam: 'start',
|
51 |
-
endParam: 'end',
|
52 |
-
businessHours: {start: 8, end: 18, limitDisplay: false},
|
53 |
-
newEventText: 'New Event',
|
54 |
-
timeslotHeight: 20,
|
55 |
-
defaultEventLength: 2,
|
56 |
-
timeslotsPerHour: 4,
|
57 |
-
minDate: null,
|
58 |
-
maxDate: null,
|
59 |
-
showHeader: true,
|
60 |
-
buttons: true,
|
61 |
-
buttonText: {
|
62 |
-
today: 'today',
|
63 |
-
lastWeek: 'previous',
|
64 |
-
nextWeek: 'next'
|
65 |
-
},
|
66 |
-
switchDisplay: {},
|
67 |
-
scrollToHourMillis: 500,
|
68 |
-
allowEventDelete: false,
|
69 |
-
allowCalEventOverlap: false,
|
70 |
-
overlapEventsSeparate: false,
|
71 |
-
totalEventsWidthPercentInOneColumn: 100,
|
72 |
-
readonly: false,
|
73 |
-
allowEventCreation: true,
|
74 |
-
hourLine: false,
|
75 |
-
deletable: function(calEvent, element) {
|
76 |
-
return true;
|
77 |
-
},
|
78 |
-
draggable: function(calEvent, element) {
|
79 |
-
return true;
|
80 |
-
},
|
81 |
-
resizable: function(calEvent, element) {
|
82 |
-
return true;
|
83 |
-
},
|
84 |
-
eventClick: function(calEvent, element, dayFreeBusyManager,
|
85 |
-
calendar, clickEvent) {
|
86 |
-
},
|
87 |
-
eventRender: function(calEvent, element) {
|
88 |
-
return element;
|
89 |
-
},
|
90 |
-
eventAfterRender: function(calEvent, element) {
|
91 |
-
return element;
|
92 |
-
},
|
93 |
-
eventRefresh: function(calEvent, element) {
|
94 |
-
return element;
|
95 |
-
},
|
96 |
-
eventDrag: function(calEvent, element) {
|
97 |
-
},
|
98 |
-
eventDrop: function(calEvent, element) {
|
99 |
-
},
|
100 |
-
eventResize: function(calEvent, element) {
|
101 |
-
},
|
102 |
-
eventNew: function(calEvent, element, dayFreeBusyManager,
|
103 |
-
calendar, mouseupEvent) {
|
104 |
-
},
|
105 |
-
eventMouseover: function(calEvent, $event) {
|
106 |
-
},
|
107 |
-
eventMouseout: function(calEvent, $event) {
|
108 |
-
},
|
109 |
-
eventDelete: function(calEvent, element, dayFreeBusyManager,
|
110 |
-
calendar, clickEvent) {
|
111 |
-
calendar.weekCalendar('removeEvent',calEvent.id);
|
112 |
-
},
|
113 |
-
calendarBeforeLoad: function(calendar) {
|
114 |
-
},
|
115 |
-
calendarAfterLoad: function(calendar) {
|
116 |
-
},
|
117 |
-
noEvents: function() {
|
118 |
-
},
|
119 |
-
eventHeader: function(calEvent, calendar) {
|
120 |
-
var options = calendar.weekCalendar('option');
|
121 |
-
var one_hour = 3600000;
|
122 |
-
var displayTitleWithTime = calEvent.end.getTime() - calEvent.start.getTime() <= (one_hour / options.timeslotsPerHour);
|
123 |
-
if (displayTitleWithTime) {
|
124 |
-
return calendar.weekCalendar(
|
125 |
-
'formatTime', calEvent.start) +
|
126 |
-
': ' + calEvent.title;
|
127 |
-
} else {
|
128 |
-
return calendar.weekCalendar(
|
129 |
-
'formatTime', calEvent.start) +
|
130 |
-
options.timeSeparator +
|
131 |
-
calendar.weekCalendar(
|
132 |
-
'formatTime', calEvent.end);
|
133 |
-
}
|
134 |
-
},
|
135 |
-
eventBody: function(calEvent, calendar) {
|
136 |
-
return calEvent.title;
|
137 |
-
},
|
138 |
-
shortMonths: BooklyL10n['shortMonths'],
|
139 |
-
longMonths: BooklyL10n['longMonths'],
|
140 |
-
shortDays: BooklyL10n['shortDays'],
|
141 |
-
longDays: BooklyL10n['longDays'],
|
142 |
-
/* multi-users options */
|
143 |
-
/**
|
144 |
-
* the available users for calendar.
|
145 |
-
* if you want to display users separately, enable the
|
146 |
-
* showAsSeparateUsers option.
|
147 |
-
* if you provide a list of user and do not enable showAsSeparateUsers
|
148 |
-
* option, then only the events that belongs to one or several of
|
149 |
-
* given users will be displayed
|
150 |
-
* @type {array}
|
151 |
-
*/
|
152 |
-
users: [],
|
153 |
-
/**
|
154 |
-
* should the calendar be displayed with separate column for each
|
155 |
-
* users.
|
156 |
-
* note that this option does nothing if you do not provide at least
|
157 |
-
* one user.
|
158 |
-
* @type {boolean}
|
159 |
-
*/
|
160 |
-
showAsSeparateUsers: true,
|
161 |
-
/**
|
162 |
-
* callback used to read user id from a user object.
|
163 |
-
* @param {Object} user the user to retrieve the id from.
|
164 |
-
* @param {number} index the user index from user list.
|
165 |
-
* @param {jQuery} calendar the calendar object.
|
166 |
-
* @return {int|String} the user id.
|
167 |
-
*/
|
168 |
-
getUserId: function(user, index, calendar) {
|
169 |
-
return index;
|
170 |
-
},
|
171 |
-
/**
|
172 |
-
* callback used to read user name from a user object.
|
173 |
-
* @param {Object} user the user to retrieve the name from.
|
174 |
-
* @param {number} index the user index from user list.
|
175 |
-
* @param {jQuery} calendar the calendar object.
|
176 |
-
* @return {String} the user name.
|
177 |
-
*/
|
178 |
-
getUserName: function(user, index, calendar) {
|
179 |
-
return user;
|
180 |
-
},
|
181 |
-
/**
|
182 |
-
* reads the id(s) of user(s) for who the event should be displayed.
|
183 |
-
* @param {Object} calEvent the calEvent to read informations from.
|
184 |
-
* @param {jQuery} calendar the calendar object.
|
185 |
-
* @return {number|String|Array} the user id(s) to appened events for.
|
186 |
-
*/
|
187 |
-
getEventUserId: function(calEvent, calendar) {
|
188 |
-
return calEvent.userId;
|
189 |
-
},
|
190 |
-
/**
|
191 |
-
* sets user id(s) to the calEvent
|
192 |
-
* @param {Object} calEvent the calEvent to set informations to.
|
193 |
-
* @param {jQuery} calendar the calendar object.
|
194 |
-
* @return {Object} the calEvent with modified user id.
|
195 |
-
*/
|
196 |
-
setEventUserId: function(userId, calEvent, calendar) {
|
197 |
-
calEvent.userId = userId;
|
198 |
-
return calEvent;
|
199 |
-
},
|
200 |
-
/* freeBusy options */
|
201 |
-
/**
|
202 |
-
* should the calendar display freebusys ?
|
203 |
-
* @type {boolean}
|
204 |
-
*/
|
205 |
-
displayFreeBusys: false,
|
206 |
-
/**
|
207 |
-
* read the id(s) for who the freebusy is available
|
208 |
-
* @param {Object} calEvent the calEvent to read informations from.
|
209 |
-
* @param {jQuery} calendar the calendar object.
|
210 |
-
* @return {number|String|Array} the user id(s) to appened events for.
|
211 |
-
*/
|
212 |
-
getFreeBusyUserId: function(calFreeBusy, calendar) {
|
213 |
-
return calFreeBusy.userId;
|
214 |
-
},
|
215 |
-
/**
|
216 |
-
* the default freeBusy object, used to manage default state
|
217 |
-
* @type {Object}
|
218 |
-
*/
|
219 |
-
defaultFreeBusy: {free: false},
|
220 |
-
/**
|
221 |
-
* function used to display the freeBusy element
|
222 |
-
* @type {Function}
|
223 |
-
* @param {Object} freeBusy the freeBusy timeslot to render.
|
224 |
-
* @param {jQuery} $freeBusy the freeBusy HTML element.
|
225 |
-
* @param {jQuery} calendar the calendar element.
|
226 |
-
*/
|
227 |
-
freeBusyRender: function(freeBusy, $freeBusy, calendar) {
|
228 |
-
if (!freeBusy.free) {
|
229 |
-
$freeBusy.addClass('free-busy-busy');
|
230 |
-
}
|
231 |
-
else {
|
232 |
-
$freeBusy.addClass('free-busy-free');
|
233 |
-
}
|
234 |
-
return $freeBusy;
|
235 |
-
},
|
236 |
-
/* other options */
|
237 |
-
/**
|
238 |
-
* true means start on first day of week, false means starts on
|
239 |
-
* startDate.
|
240 |
-
* @param {jQuery} calendar the calendar object.
|
241 |
-
* @type {Function|bool}
|
242 |
-
*/
|
243 |
-
startOnFirstDayOfWeek: function(calendar) {
|
244 |
-
return $(calendar).weekCalendar('option', 'daysToShow') >= 5;
|
245 |
-
},
|
246 |
-
/**
|
247 |
-
* should the columns be rendered alternatively using odd/even
|
248 |
-
* class
|
249 |
-
* @type {boolean}
|
250 |
-
*/
|
251 |
-
displayOddEven: false,
|
252 |
-
textSize: 13,
|
253 |
-
/**
|
254 |
-
* the title attribute for the calendar. possible placeholders are:
|
255 |
-
* <ul>
|
256 |
-
* <li>%start%</li>
|
257 |
-
* <li>%end%</li>
|
258 |
-
* <li>%date%</li>
|
259 |
-
* </ul>
|
260 |
-
* @type {Function|string}
|
261 |
-
* @param {number} option daysToShow.
|
262 |
-
* @return {String} the title attribute for the calendar.
|
263 |
-
*/
|
264 |
-
title: '%start% - %end%',
|
265 |
-
/**
|
266 |
-
* default options to pass to callback
|
267 |
-
* you can pass a function returning an object or a litteral object
|
268 |
-
* @type {object|function(#calendar)}
|
269 |
-
*/
|
270 |
-
jsonOptions: {},
|
271 |
-
headerSeparator: '<br />',
|
272 |
-
/**
|
273 |
-
* returns formatted header for day display
|
274 |
-
* @type {function(date,calendar)}
|
275 |
-
*/
|
276 |
-
getHeaderDate: null,
|
277 |
-
preventDragOnEventCreation: false,
|
278 |
-
/**
|
279 |
-
* the event on which to bind calendar resize
|
280 |
-
* @type {string}
|
281 |
-
*/
|
282 |
-
resizeEvent: 'resize.weekcalendar'
|
283 |
-
},
|
284 |
-
|
285 |
-
/***********************
|
286 |
-
* Initialise calendar *
|
287 |
-
***********************/
|
288 |
-
_create: function() {
|
289 |
-
var self = this;
|
290 |
-
self._computeOptions();
|
291 |
-
self._setupEventDelegation();
|
292 |
-
self._renderCalendar();
|
293 |
-
self._loadCalEvents();
|
294 |
-
self._resizeCalendar();
|
295 |
-
|
296 |
-
if (this.options.resizeEvent) {
|
297 |
-
$(window).unbind(this.options.resizeEvent);
|
298 |
-
$(window).bind(this.options.resizeEvent, function() {
|
299 |
-
self._resizeCalendar();
|
300 |
-
});
|
301 |
-
}
|
302 |
-
|
303 |
-
},
|
304 |
-
|
305 |
-
/********************
|
306 |
-
* public functions *
|
307 |
-
********************/
|
308 |
-
/*
|
309 |
-
* Refresh the events for the currently displayed week.
|
310 |
-
*/
|
311 |
-
refresh: function() {
|
312 |
-
//reload with existing week
|
313 |
-
this._loadCalEvents(this.element.data('startDate'));
|
314 |
-
},
|
315 |
-
|
316 |
-
/*
|
317 |
-
* Clear all events currently loaded into the calendar
|
318 |
-
*/
|
319 |
-
clear: function() {
|
320 |
-
this._clearCalendar();
|
321 |
-
},
|
322 |
-
|
323 |
-
/*
|
324 |
-
* Go to this week
|
325 |
-
*/
|
326 |
-
today: function() {
|
327 |
-
this._clearCalendar();
|
328 |
-
this._loadCalEvents(new Date());
|
329 |
-
},
|
330 |
-
|
331 |
-
/*
|
332 |
-
* Go to the previous week relative to the currently displayed week
|
333 |
-
*/
|
334 |
-
prevWeek: function() {
|
335 |
-
//minus more than 1 day to be sure we're in previous week - account for daylight savings or other anomolies
|
336 |
-
var newDate = new Date(this.element.data('startDate').getTime() - (MILLIS_IN_WEEK / 6));
|
337 |
-
this._clearCalendar();
|
338 |
-
this._loadCalEvents(newDate);
|
339 |
-
},
|
340 |
-
|
341 |
-
/*
|
342 |
-
* Go to the next week relative to the currently displayed week
|
343 |
-
*/
|
344 |
-
nextWeek: function() {
|
345 |
-
//add 8 days to be sure of being in prev week - allows for daylight savings or other anomolies
|
346 |
-
var newDate = new Date(this.element.data('startDate').getTime() + MILLIS_IN_WEEK + MILLIS_IN_DAY);
|
347 |
-
this._clearCalendar();
|
348 |
-
this._loadCalEvents(newDate);
|
349 |
-
},
|
350 |
-
|
351 |
-
/*
|
352 |
-
* Reload the calendar to whatever week the date passed in falls on.
|
353 |
-
*/
|
354 |
-
gotoWeek: function(date) {
|
355 |
-
this._clearCalendar();
|
356 |
-
this._loadCalEvents(date);
|
357 |
-
},
|
358 |
-
|
359 |
-
/*
|
360 |
-
* Reload the calendar to whatever week the date passed in falls on.
|
361 |
-
*/
|
362 |
-
gotoDate: function(date) {
|
363 |
-
this._clearCalendar();
|
364 |
-
this._loadCalEvents(date);
|
365 |
-
},
|
366 |
-
|
367 |
-
/**
|
368 |
-
* change the number of days to show
|
369 |
-
*/
|
370 |
-
setDaysToShow: function(daysToShow) {
|
371 |
-
var self = this;
|
372 |
-
var hour = self._getCurrentScrollHour();
|
373 |
-
self.options.daysToShow = daysToShow;
|
374 |
-
$(self.element).html('');
|
375 |
-
self._renderCalendar();
|
376 |
-
self._loadCalEvents();
|
377 |
-
self._resizeCalendar();
|
378 |
-
self._scrollToHour(hour, false);
|
379 |
-
|
380 |
-
if (this.options.resizeEvent) {
|
381 |
-
$(window).unbind(this.options.resizeEvent);
|
382 |
-
$(window).bind(this.options.resizeEvent, function() {
|
383 |
-
self._resizeCalendar();
|
384 |
-
});
|
385 |
-
}
|
386 |
-
},
|
387 |
-
|
388 |
-
/*
|
389 |
-
* Remove an event based on it's id
|
390 |
-
*/
|
391 |
-
removeEvent: function(eventId) {
|
392 |
-
|
393 |
-
var self = this;
|
394 |
-
|
395 |
-
self.element.find('.wc-cal-event').each(function() {
|
396 |
-
if ($(this).data('calEvent').id === eventId) {
|
397 |
-
$(this).remove();
|
398 |
-
return false;
|
399 |
-
}
|
400 |
-
});
|
401 |
-
|
402 |
-
//this could be more efficient rather than running on all days regardless...
|
403 |
-
self.element.find('.wc-day-column-inner').each(function() {
|
404 |
-
self._adjustOverlappingEvents($(this));
|
405 |
-
});
|
406 |
-
},
|
407 |
-
|
408 |
-
/*
|
409 |
-
* Removes any events that have been added but not yet saved (have no id).
|
410 |
-
* This is useful to call after adding a freshly saved new event.
|
411 |
-
*/
|
412 |
-
removeUnsavedEvents: function() {
|
413 |
-
|
414 |
-
var self = this;
|
415 |
-
|
416 |
-
self.element.find('.wc-new-cal-event').each(function() {
|
417 |
-
$(this).remove();
|
418 |
-
});
|
419 |
-
|
420 |
-
//this could be more efficient rather than running on all days regardless...
|
421 |
-
self.element.find('.wc-day-column-inner').each(function() {
|
422 |
-
self._adjustOverlappingEvents($(this));
|
423 |
-
});
|
424 |
-
},
|
425 |
-
|
426 |
-
/*
|
427 |
-
* update an event in the calendar. If the event exists it refreshes
|
428 |
-
* it's rendering. If it's a new event that does not exist in the calendar
|
429 |
-
* it will be added.
|
430 |
-
*/
|
431 |
-
updateEvent: function(calEvent) {
|
432 |
-
this._updateEventInCalendar(calEvent);
|
433 |
-
},
|
434 |
-
|
435 |
-
/*
|
436 |
-
* Returns an array of timeslot start and end times based on
|
437 |
-
* the configured grid of the calendar. Returns in both date and
|
438 |
-
* formatted time based on the 'timeFormat' config option.
|
439 |
-
*/
|
440 |
-
getTimeslotTimes: function(date) {
|
441 |
-
var options = this.options;
|
442 |
-
var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
|
443 |
-
var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), firstHourDisplayed);
|
444 |
-
|
445 |
-
var times = [],
|
446 |
-
startMillis = startDate.getTime();
|
447 |
-
for (var i = 0; i < options.timeslotsPerDay; i++) {
|
448 |
-
var endMillis = startMillis + options.millisPerTimeslot;
|
449 |
-
times[i] = {
|
450 |
-
start: new Date(startMillis),
|
451 |
-
startFormatted: this.formatTime(new Date(startMillis), options.timeFormat),
|
452 |
-
end: new Date(endMillis),
|
453 |
-
endFormatted: this.formatTime(new Date(endMillis), options.timeFormat)
|
454 |
-
};
|
455 |
-
startMillis = endMillis;
|
456 |
-
}
|
457 |
-
return times;
|
458 |
-
},
|
459 |
-
|
460 |
-
formatDate: function(date, format) {
|
461 |
-
if (format) {
|
462 |
-
return this._formatDate(date, format);
|
463 |
-
} else {
|
464 |
-
return this._formatDate(date, this.options.dateFormat);
|
465 |
-
}
|
466 |
-
},
|
467 |
-
|
468 |
-
formatTime: function(date, format) {
|
469 |
-
if (format) {
|
470 |
-
return this._formatDate(date, format);
|
471 |
-
} else if (this.options.timeFormat) {
|
472 |
-
return this._formatDate(date, this.options.timeFormat);
|
473 |
-
} else if (this.options.use24Hour) {
|
474 |
-
return this._formatDate(date, 'H:i');
|
475 |
-
} else {
|
476 |
-
return this._formatDate(date, 'h:i a');
|
477 |
-
}
|
478 |
-
},
|
479 |
-
|
480 |
-
serializeEvents: function() {
|
481 |
-
var self = this;
|
482 |
-
var calEvents = [];
|
483 |
-
|
484 |
-
self.element.find('.wc-cal-event').each(function() {
|
485 |
-
calEvents.push($(this).data('calEvent'));
|
486 |
-
});
|
487 |
-
return calEvents;
|
488 |
-
},
|
489 |
-
|
490 |
-
next: function() {
|
491 |
-
if (this._startOnFirstDayOfWeek()) {
|
492 |
-
return this.nextWeek();
|
493 |
-
}
|
494 |
-
var newDate = new Date(this.element.data('startDate').getTime());
|
495 |
-
newDate.setDate(newDate.getDate() + this.options.daysToShow);
|
496 |
-
|
497 |
-
this._clearCalendar();
|
498 |
-
this._loadCalEvents(newDate);
|
499 |
-
},
|
500 |
-
|
501 |
-
prev: function() {
|
502 |
-
if (this._startOnFirstDayOfWeek()) {
|
503 |
-
return this.prevWeek();
|
504 |
-
}
|
505 |
-
var newDate = new Date(this.element.data('startDate').getTime());
|
506 |
-
newDate.setDate(newDate.getDate() - this.options.daysToShow);
|
507 |
-
|
508 |
-
this._clearCalendar();
|
509 |
-
this._loadCalEvents(newDate);
|
510 |
-
},
|
511 |
-
getCurrentFirstDay: function() {
|
512 |
-
return this._dateFirstDayOfWeek(this.options.date || new Date());
|
513 |
-
},
|
514 |
-
getCurrentLastDay: function() {
|
515 |
-
return this._addDays(this.getCurrentFirstDay(), this.options.daysToShow - 1);
|
516 |
-
},
|
517 |
-
|
518 |
-
/*********************
|
519 |
-
* private functions *
|
520 |
-
*********************/
|
521 |
-
_setOption: function(key, value) {
|
522 |
-
var self = this;
|
523 |
-
if (self.options[key] != value) {
|
524 |
-
// event callback change, no need to re-render the events
|
525 |
-
if (key == 'beforeEventNew') {
|
526 |
-
self.options[key] = value;
|
527 |
-
return;
|
528 |
-
}
|
529 |
-
|
530 |
-
// this could be made more efficient at some stage by caching the
|
531 |
-
// events array locally in a store but this should be done in conjunction
|
532 |
-
// with a proper binding model.
|
533 |
-
|
534 |
-
var currentEvents = self.element.find('.wc-cal-event').map(function() {
|
535 |
-
return $(this).data('calEvent');
|
536 |
-
});
|
537 |
-
|
538 |
-
var newOptions = {};
|
539 |
-
newOptions[key] = value;
|
540 |
-
self._renderEvents({events: currentEvents, options: newOptions}, self.element.find('.wc-day-column-inner'));
|
541 |
-
}
|
542 |
-
},
|
543 |
-
|
544 |
-
// compute dynamic options based on other config values
|
545 |
-
_computeOptions: function() {
|
546 |
-
var options = this.options;
|
547 |
-
if (options.businessHours.limitDisplay) {
|
548 |
-
options.timeslotsPerDay = options.timeslotsPerHour * (options.businessHours.end - options.businessHours.start);
|
549 |
-
options.millisToDisplay = (options.businessHours.end - options.businessHours.start) * 3600000; // 60 * 60 * 1000
|
550 |
-
options.millisPerTimeslot = options.millisToDisplay / options.timeslotsPerDay;
|
551 |
-
} else {
|
552 |
-
options.timeslotsPerDay = options.timeslotsPerHour * 24;
|
553 |
-
options.millisToDisplay = MILLIS_IN_DAY;
|
554 |
-
options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay;
|
555 |
-
}
|
556 |
-
},
|
557 |
-
|
558 |
-
/*
|
559 |
-
* Resize the calendar scrollable height based on the provided function in options.
|
560 |
-
*/
|
561 |
-
_resizeCalendar: function() {
|
562 |
-
var options = this.options;
|
563 |
-
if (options && $.isFunction(options.height)) {
|
564 |
-
var calendarHeight = options.height(this.element);
|
565 |
-
var headerHeight = this.element.find('.wc-header').outerHeight();
|
566 |
-
var navHeight = this.element.find('.wc-toolbar').outerHeight();
|
567 |
-
var scrollContainerHeight = Math.max(calendarHeight - navHeight - headerHeight, options.minBodyHeight);
|
568 |
-
var timeslotHeight = this.element.find('.wc-time-slots').outerHeight();
|
569 |
-
this.element.find('.wc-scrollable-grid').height(scrollContainerHeight);
|
570 |
-
if (timeslotHeight <= scrollContainerHeight) {
|
571 |
-
this.element.find('.wc-scrollbar-shim').width(0);
|
572 |
-
}
|
573 |
-
this._trigger('resize', this.element);
|
574 |
-
}
|
575 |
-
},
|
576 |
-
|
577 |
-
_findScrollBarWidth: function() {
|
578 |
-
var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body');
|
579 |
-
var child = parent.children();
|
580 |
-
var width = child.innerWidth() - child.height(99).innerWidth();
|
581 |
-
parent.remove();
|
582 |
-
return width || /* default to 16 that is the average */ 16;
|
583 |
-
},
|
584 |
-
|
585 |
-
/*
|
586 |
-
* configure calendar interaction events that are able to use event
|
587 |
-
* delegation for greater efficiency
|
588 |
-
*/
|
589 |
-
_setupEventDelegation: function() {
|
590 |
-
var self = this;
|
591 |
-
var options = this.options;
|
592 |
-
|
593 |
-
this.element.click(function(event) {
|
594 |
-
var $target = $(event.target),
|
595 |
-
freeBusyManager;
|
596 |
-
|
597 |
-
// click is disabled
|
598 |
-
if ($target.data('preventClick')) {
|
599 |
-
return;
|
600 |
-
}
|
601 |
-
|
602 |
-
var $calEvent = $target.hasClass('wc-cal-event') ?
|
603 |
-
$target :
|
604 |
-
$target.parents('.wc-cal-event');
|
605 |
-
if (!$calEvent.length || !$calEvent.data('calEvent')) {
|
606 |
-
return;
|
607 |
-
}
|
608 |
-
|
609 |
-
freeBusyManager = self.getFreeBusyManagerForEvent($calEvent.data('calEvent'));
|
610 |
-
|
611 |
-
if (options.allowEventDelete && $target.hasClass('wc-cal-event-delete')) {
|
612 |
-
options.eventDelete($calEvent.data('calEvent'), $calEvent, freeBusyManager, self.element, event);
|
613 |
-
} else {
|
614 |
-
options.eventClick($calEvent.data('calEvent'), $calEvent, freeBusyManager, self.element, event);
|
615 |
-
}
|
616 |
-
}).mouseover(function(event) {
|
617 |
-
var $target = $(event.target);
|
618 |
-
var $calEvent = $target.hasClass('wc-cal-event') ?
|
619 |
-
$target :
|
620 |
-
$target.parents('.wc-cal-event');
|
621 |
-
|
622 |
-
if (!$calEvent.length || !$calEvent.data('calEvent')) {
|
623 |
-
return;
|
624 |
-
}
|
625 |
-
|
626 |
-
if (self._isDraggingOrResizing($calEvent)) {
|
627 |
-
return;
|
628 |
-
}
|
629 |
-
|
630 |
-
options.eventMouseover($calEvent.data('calEvent'), $calEvent, event);
|
631 |
-
}).mouseout(function(event) {
|
632 |
-
var $target = $(event.target);
|
633 |
-
var $calEvent = $target.hasClass('wc-cal-event') ?
|
634 |
-
$target :
|
635 |
-
$target.parents('.wc-cal-event');
|
636 |
-
|
637 |
-
if (!$calEvent.length || !$calEvent.data('calEvent')) {
|
638 |
-
return;
|
639 |
-
}
|
640 |
-
|
641 |
-
if (self._isDraggingOrResizing($calEvent)) {
|
642 |
-
return;
|
643 |
-
}
|
644 |
-
|
645 |
-
options.eventMouseout($calEvent.data('calEvent'), $calEvent, event);
|
646 |
-
});
|
647 |
-
},
|
648 |
-
|
649 |
-
/**
|
650 |
-
* check if a ui draggable or resizable is currently being dragged or
|
651 |
-
* resized.
|
652 |
-
*/
|
653 |
-
_isDraggingOrResizing: function($target) {
|
654 |
-
return $target.hasClass('ui-draggable-dragging') ||
|
655 |
-
$target.hasClass('ui-resizable-resizing');
|
656 |
-
},
|
657 |
-
|
658 |
-
/*
|
659 |
-
* Render the main calendar layout
|
660 |
-
*/
|
661 |
-
_renderCalendar: function() {
|
662 |
-
var $calendarContainer, $weekDayColumns;
|
663 |
-
var self = this;
|
664 |
-
var options = this.options;
|
665 |
-
|
666 |
-
$calendarContainer = $('<div class=\"ui-widget wc-container\">').appendTo(self.element);
|
667 |
-
|
668 |
-
//render the different parts
|
669 |
-
// nav links
|
670 |
-
self._renderCalendarButtons($calendarContainer);
|
671 |
-
// header
|
672 |
-
self._renderCalendarHeader($calendarContainer);
|
673 |
-
// body
|
674 |
-
self._renderCalendarBody($calendarContainer);
|
675 |
-
|
676 |
-
$weekDayColumns = $calendarContainer.find('.wc-day-column-inner');
|
677 |
-
$weekDayColumns.each(function(i, val) {
|
678 |
-
if (!options.readonly) {
|
679 |
-
self._addDroppableToWeekDay($(this));
|
680 |
-
if (options.allowEventCreation) {
|
681 |
-
self._setupEventCreationForWeekDay($(this));
|
682 |
-
}
|
683 |
-
}
|
684 |
-
});
|
685 |
-
},
|
686 |
-
|
687 |
-
/**
|
688 |
-
* render the nav buttons on top of the calendar
|
689 |
-
*/
|
690 |
-
_renderCalendarButtons: function($calendarContainer) {
|
691 |
-
var self = this, options = this.options;
|
692 |
-
if ( !options.showHeader ) return;
|
693 |
-
if (options.buttons) {
|
694 |
-
var calendarNavHtml = '';
|
695 |
-
|
696 |
-
calendarNavHtml += '<div class=\"ui-widget-header wc-toolbar\">';
|
697 |
-
calendarNavHtml += '<div class=\"wc-display\"></div>';
|
698 |
-
calendarNavHtml += '<div class=\"wc-nav\">';
|
699 |
-
calendarNavHtml += '<button class=\"wc-prev\">' + options.buttonText.lastWeek + '</button>';
|
700 |
-
calendarNavHtml += '<button class=\"wc-today\">' + options.buttonText.today + '</button>';
|
701 |
-
calendarNavHtml += '<button class=\"wc-next\">' + options.buttonText.nextWeek + '</button>';
|
702 |
-
calendarNavHtml += '</div>';
|
703 |
-
calendarNavHtml += '<h1 class=\"wc-title\"></h1>';
|
704 |
-
calendarNavHtml += '</div>';
|
705 |
-
|
706 |
-
$(calendarNavHtml).appendTo($calendarContainer);
|
707 |
-
|
708 |
-
$calendarContainer.find('.wc-nav .wc-today')
|
709 |
-
.button({
|
710 |
-
icons: {primary: 'ui-icon-home'}})
|
711 |
-
.click(function() {
|
712 |
-
self.today();
|
713 |
-
return false;
|
714 |
-
});
|
715 |
-
|
716 |
-
$calendarContainer.find('.wc-nav .wc-prev')
|
717 |
-
.button({
|
718 |
-
text: false,
|
719 |
-
icons: {primary: 'ui-icon-seek-prev'}})
|
720 |
-
.click(function() {
|
721 |
-
self.element.weekCalendar('prev');
|
722 |
-
return false;
|
723 |
-
});
|
724 |
-
|
725 |
-
$calendarContainer.find('.wc-nav .wc-next')
|
726 |
-
.button({
|
727 |
-
text: false,
|
728 |
-
icons: {primary: 'ui-icon-seek-next'}})
|
729 |
-
.click(function() {
|
730 |
-
self.element.weekCalendar('next');
|
731 |
-
return false;
|
732 |
-
});
|
733 |
-
|
734 |
-
// now add buttons to switch display
|
735 |
-
if (this.options.switchDisplay && $.isPlainObject(this.options.switchDisplay)) {
|
736 |
-
var $container = $calendarContainer.find('.wc-display');
|
737 |
-
$.each(this.options.switchDisplay, function(label, option) {
|
738 |
-
var _id = 'wc-switch-display-' + option;
|
739 |
-
var _input = $('<input type="radio" id="' + _id + '" name="wc-switch-display" class="wc-switch-display"/>');
|
740 |
-
var _label = $('<label for="' + _id + '"></label>');
|
741 |
-
_label.html(label);
|
742 |
-
_input.val(option);
|
743 |
-
if (parseInt(self.options.daysToShow, 10) === parseInt(option, 10)) {
|
744 |
-
_input.attr('checked', 'checked');
|
745 |
-
}
|
746 |
-
$container
|
747 |
-
.append(_input)
|
748 |
-
.append(_label);
|
749 |
-
});
|
750 |
-
$container.find('input').change(function() {
|
751 |
-
self.setDaysToShow(parseInt($(this).val(), 10));
|
752 |
-
});
|
753 |
-
}
|
754 |
-
$calendarContainer.find('.wc-nav, .wc-display').buttonset();
|
755 |
-
var _height = $calendarContainer.find('.wc-nav').outerHeight();
|
756 |
-
$calendarContainer.find('.wc-title')
|
757 |
-
.height(_height)
|
758 |
-
.css('line-height', _height + 'px');
|
759 |
-
}else{
|
760 |
-
var calendarNavHtml = '';
|
761 |
-
calendarNavHtml += '<div class=\"ui-widget-header wc-toolbar\">';
|
762 |
-
calendarNavHtml += '<h1 class=\"wc-title\"></h1>';
|
763 |
-
calendarNavHtml += '</div>';
|
764 |
-
$(calendarNavHtml).appendTo($calendarContainer);
|
765 |
-
|
766 |
-
}
|
767 |
-
},
|
768 |
-
|
769 |
-
/**
|
770 |
-
* render the calendar header, including date and user header
|
771 |
-
*/
|
772 |
-
_renderCalendarHeader: function($calendarContainer) {
|
773 |
-
var self = this, options = this.options,
|
774 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
775 |
-
rowspan = '', colspan = '', calendarHeaderHtml;
|
776 |
-
|
777 |
-
if (showAsSeparatedUser) {
|
778 |
-
rowspan = ' rowspan=\"2\"';
|
779 |
-
colspan = ' colspan=\"' + options.users.length + '\" ';
|
780 |
-
}
|
781 |
-
|
782 |
-
//first row
|
783 |
-
calendarHeaderHtml = '<div class=\"ui-widget-content wc-header\">';
|
784 |
-
calendarHeaderHtml += '<table><tbody><tr><td class=\"wc-time-column-header\" style=\"width:44px\"></td>';
|
785 |
-
for (var i = 1; i <= options.daysToShow; i++) {
|
786 |
-
calendarHeaderHtml += '<td class=\"wc-day-column-header wc-day-' + i + '\"' + colspan + '></td>';
|
787 |
-
}
|
788 |
-
calendarHeaderHtml += '<td class=\"wc-scrollbar-shim\"' + rowspan + '></td></tr>';
|
789 |
-
|
790 |
-
//users row
|
791 |
-
if (showAsSeparatedUser) {
|
792 |
-
calendarHeaderHtml += '<tr><td class=\"wc-time-column-header\"></td>';
|
793 |
-
var uLength = options.users.length,
|
794 |
-
_headerClass = '';
|
795 |
-
|
796 |
-
for (var i = 1; i <= options.daysToShow; i++) {
|
797 |
-
for (var j = 0; j < uLength; j++) {
|
798 |
-
_headerClass = [];
|
799 |
-
if (j == 0) {
|
800 |
-
_headerClass.push('wc-day-column-first');
|
801 |
-
}
|
802 |
-
if (j == uLength - 1) {
|
803 |
-
_headerClass.push('wc-day-column-last');
|
804 |
-
}
|
805 |
-
if (!_headerClass.length) {
|
806 |
-
_headerClass = 'wc-day-column-middle';
|
807 |
-
}
|
808 |
-
else {
|
809 |
-
_headerClass = _headerClass.join(' ');
|
810 |
-
}
|
811 |
-
calendarHeaderHtml += '<td class=\"' + _headerClass + ' wc-user-header wc-day-' + i + ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
|
812 |
-
// calendarHeaderHtml+= "<div class=\"wc-user-header wc-day-" + i + " wc-user-" + self._getUserIdFromIndex(j) +"\" >";
|
813 |
-
calendarHeaderHtml += self._getUserName(j);
|
814 |
-
// calendarHeaderHtml+= "</div>";
|
815 |
-
calendarHeaderHtml += '</td>';
|
816 |
-
}
|
817 |
-
}
|
818 |
-
calendarHeaderHtml += '</tr>';
|
819 |
-
}
|
820 |
-
//close the header
|
821 |
-
calendarHeaderHtml += '</tbody></table></div>';
|
822 |
-
|
823 |
-
$(calendarHeaderHtml).appendTo($calendarContainer);
|
824 |
-
},
|
825 |
-
|
826 |
-
/**
|
827 |
-
* render the calendar body.
|
828 |
-
* Calendar body is composed of several distinct parts.
|
829 |
-
* Each part is displayed in a separated row to ease rendering.
|
830 |
-
* for further explanations, see each part rendering function.
|
831 |
-
*/
|
832 |
-
_renderCalendarBody: function($calendarContainer) {
|
833 |
-
var self = this, options = this.options,
|
834 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
835 |
-
$calendarBody, $calendarTableTbody;
|
836 |
-
// create the structure
|
837 |
-
$calendarBody = '<div class=\"wc-scrollable-grid\">';
|
838 |
-
$calendarBody += '<table class=\"wc-time-slots\">';
|
839 |
-
$calendarBody += '<tbody>';
|
840 |
-
$calendarBody += '</tbody>';
|
841 |
-
$calendarBody += '</table>';
|
842 |
-
$calendarBody += '</div>';
|
843 |
-
$calendarBody = $($calendarBody);
|
844 |
-
$calendarTableTbody = $calendarBody.find('tbody');
|
845 |
-
|
846 |
-
self._renderCalendarBodyTimeSlots($calendarTableTbody);
|
847 |
-
self._renderCalendarBodyOddEven($calendarTableTbody);
|
848 |
-
self._renderCalendarBodyFreeBusy($calendarTableTbody);
|
849 |
-
self._renderCalendarBodyEvents($calendarTableTbody);
|
850 |
-
|
851 |
-
$calendarBody.appendTo($calendarContainer);
|
852 |
-
|
853 |
-
//set the column height
|
854 |
-
$calendarContainer.find('.wc-full-height-column').height(options.timeslotHeight * options.timeslotsPerDay);
|
855 |
-
//set the timeslot height
|
856 |
-
$calendarContainer.find('.wc-time-slot').height(options.timeslotHeight - 1); //account for border
|
857 |
-
//init the time row header height
|
858 |
-
/**
|
859 |
-
TODO if total height for an hour is less than 11px, there is a display problem.
|
860 |
-
Find a way to handle it
|
861 |
-
*/
|
862 |
-
$calendarContainer.find('.wc-time-header-cell').css({
|
863 |
-
height: (options.timeslotHeight * options.timeslotsPerHour) - 11,
|
864 |
-
padding: 5
|
865 |
-
});
|
866 |
-
//add the user data to every impacted column
|
867 |
-
if (showAsSeparatedUser) {
|
868 |
-
for (var i = 0, uLength = options.users.length; i < uLength; i++) {
|
869 |
-
$calendarContainer.find('.wc-user-' + self._getUserIdFromIndex(i))
|
870 |
-
.data('wcUser', options.users[i])
|
871 |
-
.data('wcUserIndex', i)
|
872 |
-
.data('wcUserId', self._getUserIdFromIndex(i));
|
873 |
-
}
|
874 |
-
}
|
875 |
-
},
|
876 |
-
|
877 |
-
/**
|
878 |
-
* render the timeslots separation
|
879 |
-
*/
|
880 |
-
_renderCalendarBodyTimeSlots: function($calendarTableTbody) {
|
881 |
-
var options = this.options,
|
882 |
-
renderRow, i, j,
|
883 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
884 |
-
start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
|
885 |
-
end = (options.businessHours.limitDisplay ? options.businessHours.end : 24),
|
886 |
-
rowspan = 1;
|
887 |
-
|
888 |
-
//calculate the rowspan
|
889 |
-
if (options.displayOddEven) { rowspan += 1; }
|
890 |
-
if (options.displayFreeBusys) { rowspan += 1; }
|
891 |
-
if (rowspan > 1) {
|
892 |
-
rowspan = ' rowspan=\"' + rowspan + '\"';
|
893 |
-
}
|
894 |
-
else {
|
895 |
-
rowspan = '';
|
896 |
-
}
|
897 |
-
|
898 |
-
renderRow = '<tr class=\"wc-grid-row-timeslot\">';
|
899 |
-
renderRow += '<td class=\"wc-grid-timeslot-header\"' + rowspan + '></td>';
|
900 |
-
renderRow += '<td colspan=\"' + options.daysToShow * (showAsSeparatedUser ? options.users.length : 1) + '\">';
|
901 |
-
renderRow += '<div class=\"wc-no-height-wrapper wc-time-slot-wrapper\">';
|
902 |
-
renderRow += '<div class=\"wc-time-slots\">';
|
903 |
-
|
904 |
-
for (i = start; i < end; i++) {
|
905 |
-
for (j = 0; j < options.timeslotsPerHour - 1; j++) {
|
906 |
-
renderRow += '<div class=\"wc-time-slot\"></div>';
|
907 |
-
}
|
908 |
-
renderRow += '<div class=\"wc-time-slot wc-hour-end\"></div>';
|
909 |
-
}
|
910 |
-
|
911 |
-
renderRow += '</div>';
|
912 |
-
renderRow += '</div>';
|
913 |
-
renderRow += '</td>';
|
914 |
-
renderRow += '</tr>';
|
915 |
-
|
916 |
-
$(renderRow).appendTo($calendarTableTbody);
|
917 |
-
},
|
918 |
-
|
919 |
-
/**
|
920 |
-
* render the odd even columns
|
921 |
-
*/
|
922 |
-
_renderCalendarBodyOddEven: function($calendarTableTbody) {
|
923 |
-
if (this.options.displayOddEven) {
|
924 |
-
var options = this.options,
|
925 |
-
renderRow = '<tr class=\"wc-grid-row-oddeven\">',
|
926 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
927 |
-
oddEven,
|
928 |
-
// let's take advantage of the jquery ui framework
|
929 |
-
oddEvenClasses = {'odd': 'wc-column-odd', 'even': 'ui-state-hover wc-column-even'};
|
930 |
-
|
931 |
-
//now let's display oddEven placeholders
|
932 |
-
for (var i = 1; i <= options.daysToShow; i++) {
|
933 |
-
if (!showAsSeparatedUser) {
|
934 |
-
oddEven = (oddEven == 'odd' ? 'even' : 'odd');
|
935 |
-
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
936 |
-
renderRow += '<div class=\"wc-no-height-wrapper wc-oddeven-wrapper\">';
|
937 |
-
renderRow += '<div class=\"wc-full-height-column ' + oddEvenClasses[oddEven] + '\"></div>';
|
938 |
-
renderRow += '</div>';
|
939 |
-
renderRow += '</td>';
|
940 |
-
}
|
941 |
-
else {
|
942 |
-
var uLength = options.users.length;
|
943 |
-
for (var j = 0; j < uLength; j++) {
|
944 |
-
oddEven = (oddEven == 'odd' ? 'even' : 'odd');
|
945 |
-
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
946 |
-
renderRow += '<div class=\"wc-no-height-wrapper wc-oddeven-wrapper\">';
|
947 |
-
renderRow += '<div class=\"wc-full-height-column ' + oddEvenClasses[oddEven] + '\" ></div>';
|
948 |
-
renderRow += '</div>';
|
949 |
-
renderRow += '</td>';
|
950 |
-
}
|
951 |
-
}
|
952 |
-
}
|
953 |
-
renderRow += '</tr>';
|
954 |
-
|
955 |
-
$(renderRow).appendTo($calendarTableTbody);
|
956 |
-
}
|
957 |
-
},
|
958 |
-
|
959 |
-
/**
|
960 |
-
* render the freebusy placeholders
|
961 |
-
*/
|
962 |
-
_renderCalendarBodyFreeBusy: function($calendarTableTbody) {
|
963 |
-
if (this.options.displayFreeBusys) {
|
964 |
-
var self = this, options = this.options,
|
965 |
-
renderRow = '<tr class=\"wc-grid-row-freebusy\">',
|
966 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
967 |
-
renderRow += '</td>';
|
968 |
-
|
969 |
-
//now let's display freebusy placeholders
|
970 |
-
for (var i = 1; i <= options.daysToShow; i++) {
|
971 |
-
if (options.displayFreeBusys) {
|
972 |
-
if (!showAsSeparatedUser) {
|
973 |
-
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
974 |
-
renderRow += '<div class=\"wc-no-height-wrapper wc-freebusy-wrapper\">';
|
975 |
-
renderRow += '<div class=\"wc-full-height-column wc-column-freebusy wc-day-' + i + '\"></div>';
|
976 |
-
renderRow += '</div>';
|
977 |
-
renderRow += '</td>';
|
978 |
-
}
|
979 |
-
else {
|
980 |
-
var uLength = options.users.length;
|
981 |
-
for (var j = 0; j < uLength; j++) {
|
982 |
-
renderRow += '<td class=\"wc-day-column day-' + i + '\">';
|
983 |
-
renderRow += '<div class=\"wc-no-height-wrapper wc-freebusy-wrapper\">';
|
984 |
-
renderRow += '<div class=\"wc-full-height-column wc-column-freebusy wc-day-' + i;
|
985 |
-
renderRow += ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
|
986 |
-
renderRow += '</div>';
|
987 |
-
renderRow += '</div>';
|
988 |
-
renderRow += '</td>';
|
989 |
-
}
|
990 |
-
}
|
991 |
-
}
|
992 |
-
}
|
993 |
-
|
994 |
-
renderRow += '</tr>';
|
995 |
-
|
996 |
-
$(renderRow).appendTo($calendarTableTbody);
|
997 |
-
}
|
998 |
-
},
|
999 |
-
|
1000 |
-
/**
|
1001 |
-
* render the calendar body for event placeholders
|
1002 |
-
*/
|
1003 |
-
_renderCalendarBodyEvents: function($calendarTableTbody) {
|
1004 |
-
var self = this, options = this.options,
|
1005 |
-
renderRow,
|
1006 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
1007 |
-
start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
|
1008 |
-
end = (options.businessHours.limitDisplay ? options.businessHours.end : 24);
|
1009 |
-
renderRow = '<tr class=\"wc-grid-row-events\">';
|
1010 |
-
renderRow += '<td class=\"wc-grid-timeslot-header\">';
|
1011 |
-
for (var i = start; i < end; i++) {
|
1012 |
-
var bhClass = (options.businessHours.start <= i && options.businessHours.end > i) ? 'ui-state-active wc-business-hours' : 'ui-state-default';
|
1013 |
-
renderRow += '<div class=\"wc-hour-header ' + bhClass + '\">';
|
1014 |
-
if (options.use24Hour) {
|
1015 |
-
renderRow += '<div class=\"wc-time-header-cell\">' + self._24HourForIndex(i) + '</div>';
|
1016 |
-
}
|
1017 |
-
else {
|
1018 |
-
renderRow += '<div class=\"wc-time-header-cell\">' + self._hourForIndex(i) + '<span class=\"wc-am-pm\">' + self._amOrPm(i) + '</span></div>';
|
1019 |
-
}
|
1020 |
-
renderRow += '</div>';
|
1021 |
-
}
|
1022 |
-
renderRow += '</td>';
|
1023 |
-
|
1024 |
-
//now let's display events placeholders
|
1025 |
-
var _columnBaseClass = 'ui-state-default wc-day-column';
|
1026 |
-
for (var i = 1; i <= options.daysToShow; i++) {
|
1027 |
-
if (!showAsSeparatedUser) {
|
1028 |
-
renderRow += '<td class=\"' + _columnBaseClass + ' wc-day-column-first wc-day-column-last day-' + i + '\">';
|
1029 |
-
renderRow += '<div class=\"wc-full-height-column wc-day-column-inner day-' + i + '\"></div>';
|
1030 |
-
renderRow += '</td>';
|
1031 |
-
}
|
1032 |
-
else {
|
1033 |
-
var uLength = options.users.length;
|
1034 |
-
var columnclass;
|
1035 |
-
for (var j = 0; j < uLength; j++) {
|
1036 |
-
columnclass = [];
|
1037 |
-
if (j == 0) {
|
1038 |
-
columnclass.push('wc-day-column-first');
|
1039 |
-
}
|
1040 |
-
if (j == uLength - 1) {
|
1041 |
-
columnclass.push('wc-day-column-last');
|
1042 |
-
}
|
1043 |
-
if (!columnclass.length) {
|
1044 |
-
columnclass = 'wc-day-column-middle';
|
1045 |
-
}
|
1046 |
-
else {
|
1047 |
-
columnclass = columnclass.join(' ');
|
1048 |
-
}
|
1049 |
-
renderRow += '<td class=\"' + _columnBaseClass + ' ' + columnclass + ' day-' + i + '\">';
|
1050 |
-
renderRow += '<div class=\"wc-full-height-column wc-day-column-inner day-' + i;
|
1051 |
-
renderRow += ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
|
1052 |
-
renderRow += '</div>';
|
1053 |
-
renderRow += '</td>';
|
1054 |
-
}
|
1055 |
-
}
|
1056 |
-
}
|
1057 |
-
|
1058 |
-
renderRow += '</tr>';
|
1059 |
-
|
1060 |
-
$(renderRow).appendTo($calendarTableTbody);
|
1061 |
-
},
|
1062 |
-
|
1063 |
-
/*
|
1064 |
-
* setup mouse events for capturing new events
|
1065 |
-
*/
|
1066 |
-
_setupEventCreationForWeekDay: function($weekDay) {
|
1067 |
-
var self = this;
|
1068 |
-
var options = this.options;
|
1069 |
-
$weekDay.mousedown(function(event) {
|
1070 |
-
var $target = $(event.target);
|
1071 |
-
if ($target.hasClass('wc-day-column-inner')) {
|
1072 |
-
|
1073 |
-
var $newEvent = $('<div class=\"wc-cal-event wc-new-cal-event wc-new-cal-event-creating\"></div>');
|
1074 |
-
|
1075 |
-
$newEvent.css({lineHeight: (options.timeslotHeight - 2) + 'px', fontSize: (options.timeslotHeight / 2) + 'px'});
|
1076 |
-
$target.append($newEvent);
|
1077 |
-
|
1078 |
-
var columnOffset = $target.offset().top;
|
1079 |
-
var clickY = event.pageY - columnOffset;
|
1080 |
-
var clickYRounded = (clickY - (clickY % options.timeslotHeight)) / options.timeslotHeight;
|
1081 |
-
var topPosition = clickYRounded * options.timeslotHeight;
|
1082 |
-
$newEvent.css({top: topPosition});
|
1083 |
-
|
1084 |
-
if (!options.preventDragOnEventCreation) {
|
1085 |
-
$target.bind('mousemove.newevent', function(event) {
|
1086 |
-
$newEvent.show();
|
1087 |
-
$newEvent.addClass('ui-resizable-resizing');
|
1088 |
-
var height = Math.round(event.pageY - columnOffset - topPosition);
|
1089 |
-
var remainder = height % options.timeslotHeight;
|
1090 |
-
//snap to closest timeslot
|
1091 |
-
if (remainder < 0) {
|
1092 |
-
var useHeight = height - remainder;
|
1093 |
-
$newEvent.css('height', useHeight < options.timeslotHeight ? options.timeslotHeight : useHeight);
|
1094 |
-
} else {
|
1095 |
-
$newEvent.css('height', height + (options.timeslotHeight - remainder));
|
1096 |
-
}
|
1097 |
-
}).mouseup(function() {
|
1098 |
-
$target.unbind('mousemove.newevent');
|
1099 |
-
$newEvent.addClass('ui-corner-all');
|
1100 |
-
});
|
1101 |
-
}
|
1102 |
-
}
|
1103 |
-
|
1104 |
-
}).mouseup(function(event) {
|
1105 |
-
var $target = $(event.target);
|
1106 |
-
|
1107 |
-
var $weekDay = $target.closest('.wc-day-column-inner');
|
1108 |
-
var $newEvent = $weekDay.find('.wc-new-cal-event-creating');
|
1109 |
-
|
1110 |
-
if ($newEvent.length) {
|
1111 |
-
var createdFromSingleClick = !$newEvent.hasClass('ui-resizable-resizing');
|
1112 |
-
|
1113 |
-
//if even created from a single click only, default height
|
1114 |
-
if (createdFromSingleClick) {
|
1115 |
-
$newEvent.css({height: options.timeslotHeight * options.defaultEventLength}).show();
|
1116 |
-
}
|
1117 |
-
var top = parseInt($newEvent.css('top'));
|
1118 |
-
var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $newEvent, top);
|
1119 |
-
|
1120 |
-
$newEvent.remove();
|
1121 |
-
var newCalEvent = {start: eventDuration.start, end: eventDuration.end, title: options.newEventText};
|
1122 |
-
var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1123 |
-
|
1124 |
-
if (showAsSeparatedUser) {
|
1125 |
-
newCalEvent = self._setEventUserId(newCalEvent, $weekDay.data('wcUserId'));
|
1126 |
-
}
|
1127 |
-
else if (!options.showAsSeparateUsers && options.users && options.users.length == 1) {
|
1128 |
-
newCalEvent = self._setEventUserId(newCalEvent, self._getUserIdFromIndex(0));
|
1129 |
-
}
|
1130 |
-
|
1131 |
-
var freeBusyManager = self.getFreeBusyManagerForEvent(newCalEvent);
|
1132 |
-
|
1133 |
-
var $renderedCalEvent = self._renderEvent(newCalEvent, $weekDay);
|
1134 |
-
|
1135 |
-
if (!options.allowCalEventOverlap) {
|
1136 |
-
self._adjustForEventCollisions($weekDay, $renderedCalEvent, newCalEvent, newCalEvent);
|
1137 |
-
self._positionEvent($weekDay, $renderedCalEvent);
|
1138 |
-
} else {
|
1139 |
-
self._adjustOverlappingEvents($weekDay);
|
1140 |
-
}
|
1141 |
-
|
1142 |
-
var proceed = self._trigger('beforeEventNew', event, {
|
1143 |
-
'calEvent': newCalEvent,
|
1144 |
-
'createdFromSingleClick': createdFromSingleClick,
|
1145 |
-
'calendar': self.element
|
1146 |
-
});
|
1147 |
-
if (proceed) {
|
1148 |
-
options.eventNew(newCalEvent, $renderedCalEvent, freeBusyManager, self.element, event);
|
1149 |
-
}
|
1150 |
-
else {
|
1151 |
-
$($renderedCalEvent).remove();
|
1152 |
-
}
|
1153 |
-
}
|
1154 |
-
});
|
1155 |
-
},
|
1156 |
-
|
1157 |
-
/*
|
1158 |
-
* load calendar events for the week based on the date provided
|
1159 |
-
*/
|
1160 |
-
_loadCalEvents: function(dateWithinWeek) {
|
1161 |
-
|
1162 |
-
var date, weekStartDate, weekEndDate, $weekDayColumns;
|
1163 |
-
var self = this;
|
1164 |
-
var options = this.options;
|
1165 |
-
date = this._fixMinMaxDate(dateWithinWeek || options.date);
|
1166 |
-
// if date is not provided
|
1167 |
-
// or was not set
|
1168 |
-
// or is different than old one
|
1169 |
-
if ((!date || !date.getTime) ||
|
1170 |
-
(!options.date || !options.date.getTime) ||
|
1171 |
-
date.getTime() != options.date.getTime()
|
1172 |
-
) {
|
1173 |
-
// trigger the changedate event
|
1174 |
-
this._trigger('changedate', this.element, date);
|
1175 |
-
}
|
1176 |
-
this.options.date = date;
|
1177 |
-
weekStartDate = self._dateFirstDayOfWeek(date);
|
1178 |
-
weekEndDate = self._dateLastMilliOfWeek(date);
|
1179 |
-
|
1180 |
-
options.calendarBeforeLoad(self.element);
|
1181 |
-
|
1182 |
-
self.element.data('startDate', weekStartDate);
|
1183 |
-
self.element.data('endDate', weekEndDate);
|
1184 |
-
|
1185 |
-
$weekDayColumns = self.element.find('.wc-day-column-inner');
|
1186 |
-
|
1187 |
-
self._updateDayColumnHeader($weekDayColumns);
|
1188 |
-
|
1189 |
-
//load events by chosen means
|
1190 |
-
if (typeof options.data == 'string') {
|
1191 |
-
if (options.loading) {
|
1192 |
-
options.loading(true);
|
1193 |
-
}
|
1194 |
-
if (_currentAjaxCall) {
|
1195 |
-
// first abort current request.
|
1196 |
-
if (!_jQuery14OrLower) {
|
1197 |
-
_currentAjaxCall.abort();
|
1198 |
-
} else {
|
1199 |
-
// due to the fact that jquery 1.4 does not detect a request was
|
1200 |
-
// aborted, we need to replace the onreadystatechange and
|
1201 |
-
// execute the "complete" callback.
|
1202 |
-
_currentAjaxCall.onreadystatechange = null;
|
1203 |
-
_currentAjaxCall.abort();
|
1204 |
-
_currentAjaxCall = null;
|
1205 |
-
if (options.loading) {
|
1206 |
-
options.loading(false);
|
1207 |
-
}
|
1208 |
-
}
|
1209 |
-
}
|
1210 |
-
var jsonOptions = self._getJsonOptions();
|
1211 |
-
jsonOptions[options.startParam || 'start'] = Math.round(weekStartDate.getTime() / 1000);
|
1212 |
-
jsonOptions[options.endParam || 'end'] = Math.round(weekEndDate.getTime() / 1000);
|
1213 |
-
_currentAjaxCall = $.ajax({
|
1214 |
-
url: options.data,
|
1215 |
-
data: jsonOptions,
|
1216 |
-
dataType: 'json',
|
1217 |
-
error: function(XMLHttpRequest, textStatus, errorThrown) {
|
1218 |
-
// only prevent error with jQuery 1.5
|
1219 |
-
// see issue #34. thanks to dapplebeforedawn
|
1220 |
-
// (https://github.com/themouette/jquery-week-calendar/issues#issue/34)
|
1221 |
-
// for 1.5+, aborted request mean errorThrown == 'abort'
|
1222 |
-
// for prior version it means !errorThrown && !XMLHttpRequest.status
|
1223 |
-
// fixes #55
|
1224 |
-
if (errorThrown != 'abort' && XMLHttpRequest.status != 0) {
|
1225 |
-
alert('unable to get data, error:' + textStatus);
|
1226 |
-
}
|
1227 |
-
},
|
1228 |
-
success: function(data) {
|
1229 |
-
self._renderEvents(data, $weekDayColumns);
|
1230 |
-
},
|
1231 |
-
complete: function() {
|
1232 |
-
_currentAjaxCall = null;
|
1233 |
-
if (options.loading) {
|
1234 |
-
options.loading(false);
|
1235 |
-
}
|
1236 |
-
}
|
1237 |
-
});
|
1238 |
-
}
|
1239 |
-
else if ($.isFunction(options.data)) {
|
1240 |
-
options.data(weekStartDate, weekEndDate,
|
1241 |
-
function(data) {
|
1242 |
-
self._renderEvents(data, $weekDayColumns);
|
1243 |
-
if ($('.wc-hourline', self.element).length) {
|
1244 |
-
self._scrollToHour(new Date().getHours() + 1, true);
|
1245 |
-
} else {
|
1246 |
-
if (data.events.length) {
|
1247 |
-
self._scrollToHour(data.events[0].start.getHours() + 1, true);
|
1248 |
-
} else if (data.freebusys.length) {
|
1249 |
-
self._scrollToHour(data.freebusys[0].start.getHours() + 1, true);
|
1250 |
-
}
|
1251 |
-
}
|
1252 |
-
});
|
1253 |
-
}
|
1254 |
-
else if (options.data) {
|
1255 |
-
self._renderEvents(options.data, $weekDayColumns);
|
1256 |
-
}
|
1257 |
-
|
1258 |
-
self._disableTextSelect($weekDayColumns);
|
1259 |
-
},
|
1260 |
-
|
1261 |
-
/**
|
1262 |
-
* Draws a thin line which indicates the current time.
|
1263 |
-
*/
|
1264 |
-
_drawCurrentHourLine: function() {
|
1265 |
-
var d = new Date(),
|
1266 |
-
options = this.options,
|
1267 |
-
businessHours = options.businessHours;
|
1268 |
-
|
1269 |
-
// first, we remove the old hourline if it exists
|
1270 |
-
$('.wc-hourline', this.element).remove();
|
1271 |
-
|
1272 |
-
// the line does not need to be displayed
|
1273 |
-
if (businessHours.limitDisplay && d.getHours() > businessHours.end) {
|
1274 |
-
return;
|
1275 |
-
}
|
1276 |
-
|
1277 |
-
// then we recreate it
|
1278 |
-
var paddingStart = businessHours.limitDisplay ? businessHours.start : 0;
|
1279 |
-
var nbHours = d.getHours() - paddingStart + d.getMinutes() / 60;
|
1280 |
-
var positionTop = nbHours * options.timeslotHeight * options.timeslotsPerHour;
|
1281 |
-
var lineWidth = $('.wc-scrollable-grid .wc-today', this.element).width() + 3;
|
1282 |
-
|
1283 |
-
$('.wc-scrollable-grid .wc-today', this.element).append(
|
1284 |
-
$('<div>', {
|
1285 |
-
'class': 'wc-hourline',
|
1286 |
-
style: 'top: ' + positionTop + 'px; width: ' + lineWidth + 'px'
|
1287 |
-
})
|
1288 |
-
);
|
1289 |
-
},
|
1290 |
-
|
1291 |
-
/*
|
1292 |
-
* update the display of each day column header based on the calendar week
|
1293 |
-
*/
|
1294 |
-
_updateDayColumnHeader: function($weekDayColumns) {
|
1295 |
-
var self = this;
|
1296 |
-
var options = this.options;
|
1297 |
-
var currentDay = self._cloneDate(self.element.data('startDate'));
|
1298 |
-
var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1299 |
-
var todayClass = 'ui-state-active wc-today';
|
1300 |
-
|
1301 |
-
self.element.find('.wc-header td.wc-day-column-header').each(function(i, val) {
|
1302 |
-
$(this).html(self._getHeaderDate(currentDay));
|
1303 |
-
if (self._isToday(currentDay)) {
|
1304 |
-
$(this).addClass(todayClass);
|
1305 |
-
} else {
|
1306 |
-
$(this).removeClass(todayClass);
|
1307 |
-
}
|
1308 |
-
currentDay = self._addDays(currentDay, 1);
|
1309 |
-
|
1310 |
-
});
|
1311 |
-
|
1312 |
-
currentDay = self._cloneDate(self.element.data('startDate'));
|
1313 |
-
if (showAsSeparatedUser)
|
1314 |
-
{
|
1315 |
-
self.element.find('.wc-header td.wc-user-header').each(function(i, val) {
|
1316 |
-
if (self._isToday(currentDay)) {
|
1317 |
-
$(this).addClass(todayClass);
|
1318 |
-
} else {
|
1319 |
-
$(this).removeClass(todayClass);
|
1320 |
-
}
|
1321 |
-
currentDay = ((i + 1) % options.users.length) ? currentDay : self._addDays(currentDay, 1);
|
1322 |
-
});
|
1323 |
-
}
|
1324 |
-
|
1325 |
-
currentDay = self._cloneDate(self.element.data('startDate'));
|
1326 |
-
|
1327 |
-
$weekDayColumns.each(function(i, val) {
|
1328 |
-
|
1329 |
-
$(this).data('startDate', self._cloneDate(currentDay));
|
1330 |
-
$(this).data('endDate', new Date(currentDay.getTime() + (MILLIS_IN_DAY)));
|
1331 |
-
if (self._isToday(currentDay)) {
|
1332 |
-
$(this).parent()
|
1333 |
-
.addClass(todayClass)
|
1334 |
-
.removeClass('ui-state-default');
|
1335 |
-
} else {
|
1336 |
-
$(this).parent()
|
1337 |
-
.removeClass(todayClass)
|
1338 |
-
.addClass('ui-state-default');
|
1339 |
-
}
|
1340 |
-
|
1341 |
-
if (!showAsSeparatedUser || !((i + 1) % options.users.length)) {
|
1342 |
-
currentDay = self._addDays(currentDay, 1);
|
1343 |
-
}
|
1344 |
-
});
|
1345 |
-
|
1346 |
-
//now update the freeBusy placeholders
|
1347 |
-
if (options.displayFreeBusys) {
|
1348 |
-
currentDay = self._cloneDate(self.element.data('startDate'));
|
1349 |
-
self.element.find('.wc-grid-row-freebusy .wc-column-freebusy').each(function(i, val) {
|
1350 |
-
$(this).data('startDate', self._cloneDate(currentDay));
|
1351 |
-
$(this).data('endDate', new Date(currentDay.getTime() + (MILLIS_IN_DAY)));
|
1352 |
-
if (!showAsSeparatedUser || !((i + 1) % options.users.length)) {
|
1353 |
-
currentDay = self._addDays(currentDay, 1);
|
1354 |
-
}
|
1355 |
-
});
|
1356 |
-
}
|
1357 |
-
|
1358 |
-
// now update the calendar title
|
1359 |
-
if (this.options.title) {
|
1360 |
-
var date = this.options.date,
|
1361 |
-
start = self._cloneDate(self.element.data('startDate')),
|
1362 |
-
end = self._dateLastDayOfWeek(new Date(this._cloneDate(self.element.data('endDate')).getTime() - (MILLIS_IN_DAY))),
|
1363 |
-
title = this._getCalendarTitle(),
|
1364 |
-
date_format = options.dateFormat;
|
1365 |
-
|
1366 |
-
// replace the placeholders contained in the title
|
1367 |
-
title = title.replace('%start%', self._formatDate(start, date_format));
|
1368 |
-
title = title.replace('%end%', self._formatDate(end, date_format));
|
1369 |
-
title = title.replace('%date%', self._formatDate(date, date_format));
|
1370 |
-
|
1371 |
-
$('.wc-toolbar .wc-title', self.element).html(title);
|
1372 |
-
}
|
1373 |
-
//self._clearFreeBusys();
|
1374 |
-
},
|
1375 |
-
|
1376 |
-
/**
|
1377 |
-
* Gets the calendar raw title.
|
1378 |
-
*/
|
1379 |
-
_getCalendarTitle: function() {
|
1380 |
-
if ($.isFunction(this.options.title)) {
|
1381 |
-
return this.options.title(this.options.daysToShow);
|
1382 |
-
}
|
1383 |
-
|
1384 |
-
return this.options.title || '';
|
1385 |
-
},
|
1386 |
-
|
1387 |
-
/**
|
1388 |
-
* Render the events into the calendar
|
1389 |
-
*/
|
1390 |
-
_renderEvents: function(data, $weekDayColumns) {
|
1391 |
-
var self = this;
|
1392 |
-
var options = this.options;
|
1393 |
-
var eventsToRender, nbRenderedEvents = 0;
|
1394 |
-
|
1395 |
-
if (data.options) {
|
1396 |
-
var updateLayout = false;
|
1397 |
-
// update options
|
1398 |
-
$.each(data.options, function(key, value) {
|
1399 |
-
if (value !== options[key]) {
|
1400 |
-
options[key] = value;
|
1401 |
-
updateLayout = updateLayout || $.ui.weekCalendar.updateLayoutOptions[key];
|
1402 |
-
}
|
1403 |
-
});
|
1404 |
-
|
1405 |
-
self._computeOptions();
|
1406 |
-
|
1407 |
-
if (updateLayout) {
|
1408 |
-
var hour = self._getCurrentScrollHour();
|
1409 |
-
self.element.empty();
|
1410 |
-
self._renderCalendar();
|
1411 |
-
$weekDayColumns = self.element.find('.wc-time-slots .wc-day-column-inner');
|
1412 |
-
self._updateDayColumnHeader($weekDayColumns);
|
1413 |
-
self._resizeCalendar();
|
1414 |
-
self._scrollToHour(hour, false);
|
1415 |
-
}
|
1416 |
-
}
|
1417 |
-
this._clearCalendar();
|
1418 |
-
|
1419 |
-
if ($.isArray(data)) {
|
1420 |
-
eventsToRender = self._cleanEvents(data);
|
1421 |
-
} else if (data.events) {
|
1422 |
-
eventsToRender = self._cleanEvents(data.events);
|
1423 |
-
self._renderFreeBusys(data);
|
1424 |
-
}
|
1425 |
-
|
1426 |
-
$.each(eventsToRender, function(i, calEvent) {
|
1427 |
-
// render a multi day event as various event :
|
1428 |
-
// thanks to http://github.com/fbeauchamp/jquery-week-calendar
|
1429 |
-
var initialStart = new Date(calEvent.start);
|
1430 |
-
var initialEnd = new Date(calEvent.end);
|
1431 |
-
var maxHour = self.options.businessHours.limitDisplay ? self.options.businessHours.end : 24;
|
1432 |
-
var minHour = self.options.businessHours.limitDisplay ? self.options.businessHours.start : 0;
|
1433 |
-
var start = new Date(initialStart);
|
1434 |
-
var startDate = self._formatDate(start, 'Ymd');
|
1435 |
-
var endDate = self._formatDate(initialEnd, 'Ymd');
|
1436 |
-
var $weekDay;
|
1437 |
-
var isMultiday = false;
|
1438 |
-
|
1439 |
-
while (startDate < endDate) {
|
1440 |
-
calEvent.start = start;
|
1441 |
-
|
1442 |
-
// end of this virual calEvent is set to the end of the day
|
1443 |
-
calEvent.end.setFullYear(start.getFullYear());
|
1444 |
-
calEvent.end.setDate(start.getDate());
|
1445 |
-
calEvent.end.setMonth(start.getMonth());
|
1446 |
-
calEvent.end.setHours(maxHour, 0, 0);
|
1447 |
-
|
1448 |
-
if (($weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns))) {
|
1449 |
-
self._renderEvent(calEvent, $weekDay);
|
1450 |
-
nbRenderedEvents += 1;
|
1451 |
-
}
|
1452 |
-
|
1453 |
-
// start is set to the begin of the new day
|
1454 |
-
start.setDate(start.getDate() + 1);
|
1455 |
-
start.setHours(minHour, 0, 0);
|
1456 |
-
|
1457 |
-
startDate = self._formatDate(start, 'Ymd');
|
1458 |
-
isMultiday = true;
|
1459 |
-
}
|
1460 |
-
|
1461 |
-
if (start <= initialEnd) {
|
1462 |
-
calEvent.start = start;
|
1463 |
-
calEvent.end = initialEnd;
|
1464 |
-
|
1465 |
-
if (((isMultiday && calEvent.start.getTime() != calEvent.end.getTime()) || !isMultiday) && ($weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns))) {
|
1466 |
-
self._renderEvent(calEvent, $weekDay);
|
1467 |
-
nbRenderedEvents += 1;
|
1468 |
-
}
|
1469 |
-
}
|
1470 |
-
|
1471 |
-
// put back the initial start date
|
1472 |
-
calEvent.start = initialStart;
|
1473 |
-
});
|
1474 |
-
|
1475 |
-
$weekDayColumns.each(function() {
|
1476 |
-
self._adjustOverlappingEvents($(this));
|
1477 |
-
});
|
1478 |
-
|
1479 |
-
options.calendarAfterLoad(self.element);
|
1480 |
-
|
1481 |
-
_hourLineTimeout && clearInterval(_hourLineTimeout);
|
1482 |
-
|
1483 |
-
if (options.hourLine) {
|
1484 |
-
self._drawCurrentHourLine();
|
1485 |
-
|
1486 |
-
_hourLineTimeout = setInterval(function() {
|
1487 |
-
self._drawCurrentHourLine();
|
1488 |
-
}, 60 * 1000); // redraw the line each minute
|
1489 |
-
}
|
1490 |
-
|
1491 |
-
!nbRenderedEvents && options.noEvents();
|
1492 |
-
},
|
1493 |
-
|
1494 |
-
/*
|
1495 |
-
* Render a specific event into the day provided. Assumes correct
|
1496 |
-
* day for calEvent date
|
1497 |
-
*/
|
1498 |
-
_renderEvent: function(calEvent, $weekDay) {
|
1499 |
-
var self = this;
|
1500 |
-
var options = this.options;
|
1501 |
-
if (calEvent.start.getTime() > calEvent.end.getTime()) {
|
1502 |
-
return; // can't render a negative height
|
1503 |
-
}
|
1504 |
-
|
1505 |
-
var eventClass, eventHtml, $calEventList, $modifiedEvent;
|
1506 |
-
|
1507 |
-
eventClass = calEvent.id ? 'wc-cal-event' : 'wc-cal-event wc-new-cal-event';
|
1508 |
-
eventHtml = '<div class=\"' + eventClass + ' ui-corner-all\">';
|
1509 |
-
eventHtml += '<div class=\"wc-time ui-corner-top\"></div>';
|
1510 |
-
eventHtml += '<div class=\"wc-title\"></div></div>';
|
1511 |
-
|
1512 |
-
$weekDay.each(function() {
|
1513 |
-
var $calEvent = $(eventHtml);
|
1514 |
-
$modifiedEvent = options.eventRender(calEvent, $calEvent);
|
1515 |
-
$calEvent = $modifiedEvent ? $modifiedEvent.appendTo($(this)) : $calEvent.appendTo($(this));
|
1516 |
-
$calEvent.css({lineHeight: (options.textSize + 2) + 'px', fontSize: options.textSize + 'px'});
|
1517 |
-
|
1518 |
-
self._refreshEventDetails(calEvent, $calEvent);
|
1519 |
-
self._positionEvent($(this), $calEvent);
|
1520 |
-
|
1521 |
-
//add to event list
|
1522 |
-
if ($calEventList) {
|
1523 |
-
$calEventList = $calEventList.add($calEvent);
|
1524 |
-
}
|
1525 |
-
else {
|
1526 |
-
$calEventList = $calEvent;
|
1527 |
-
}
|
1528 |
-
});
|
1529 |
-
$calEventList.show();
|
1530 |
-
|
1531 |
-
if (!options.readonly && options.resizable(calEvent, $calEventList)) {
|
1532 |
-
self._addResizableToCalEvent(calEvent, $calEventList, $weekDay);
|
1533 |
-
}
|
1534 |
-
if (!options.readonly && options.draggable(calEvent, $calEventList)) {
|
1535 |
-
self._addDraggableToCalEvent(calEvent, $calEventList);
|
1536 |
-
}
|
1537 |
-
options.eventAfterRender(calEvent, $calEventList);
|
1538 |
-
|
1539 |
-
return $calEventList;
|
1540 |
-
|
1541 |
-
},
|
1542 |
-
addEvent: function() {
|
1543 |
-
return this._renderEvent.apply(this, arguments);
|
1544 |
-
},
|
1545 |
-
|
1546 |
-
_adjustOverlappingEvents: function($weekDay) {
|
1547 |
-
var self = this;
|
1548 |
-
if (self.options.allowCalEventOverlap) {
|
1549 |
-
var groupsList = self._groupOverlappingEventElements($weekDay);
|
1550 |
-
$.each(groupsList, function() {
|
1551 |
-
var curGroups = this;
|
1552 |
-
$.each(curGroups, function(groupIndex) {
|
1553 |
-
var curGroup = this;
|
1554 |
-
|
1555 |
-
// do we want events to be displayed as overlapping
|
1556 |
-
if (self.options.overlapEventsSeparate) {
|
1557 |
-
var newWidth = self.options.totalEventsWidthPercentInOneColumn / curGroups.length;
|
1558 |
-
var newLeft = groupIndex * newWidth;
|
1559 |
-
} else {
|
1560 |
-
// TODO what happens when the group has more than 10 elements
|
1561 |
-
var newWidth = self.options.totalEventsWidthPercentInOneColumn - ((curGroups.length - 1) * 10);
|
1562 |
-
var newLeft = groupIndex * 10;
|
1563 |
-
}
|
1564 |
-
$.each(curGroup, function() {
|
1565 |
-
// bring mouseovered event to the front
|
1566 |
-
if (!self.options.overlapEventsSeparate) {
|
1567 |
-
$(this).bind('mouseover.z-index', function() {
|
1568 |
-
var $elem = $(this);
|
1569 |
-
$.each(curGroup, function() {
|
1570 |
-
$(this).css({'z-index': '1'});
|
1571 |
-
});
|
1572 |
-
$elem.css({'z-index': '3'});
|
1573 |
-
});
|
1574 |
-
}
|
1575 |
-
$(this).css({width: newWidth + '%', left: newLeft + '%', right: 0});
|
1576 |
-
});
|
1577 |
-
});
|
1578 |
-
});
|
1579 |
-
}
|
1580 |
-
},
|
1581 |
-
|
1582 |
-
|
1583 |
-
/*
|
1584 |
-
* Find groups of overlapping events
|
1585 |
-
*/
|
1586 |
-
_groupOverlappingEventElements: function($weekDay) {
|
1587 |
-
var $events = $weekDay.find('.wc-cal-event:visible');
|
1588 |
-
var sortedEvents = $events.sort(function(a, b) {
|
1589 |
-
return $(a).data('calEvent').start.getTime() - $(b).data('calEvent').start.getTime();
|
1590 |
-
});
|
1591 |
-
|
1592 |
-
var lastEndTime = new Date(0, 0, 0);
|
1593 |
-
var groups = [];
|
1594 |
-
var curGroups = [];
|
1595 |
-
var $curEvent;
|
1596 |
-
$.each(sortedEvents, function() {
|
1597 |
-
$curEvent = $(this);
|
1598 |
-
//checks, if the current group list is not empty, if the overlapping is finished
|
1599 |
-
if (curGroups.length > 0) {
|
1600 |
-
if (lastEndTime.getTime() <= $curEvent.data('calEvent').start.getTime()) {
|
1601 |
-
//finishes the current group list by adding it to the resulting list of groups and cleans it
|
1602 |
-
|
1603 |
-
groups.push(curGroups);
|
1604 |
-
curGroups = [];
|
1605 |
-
}
|
1606 |
-
}
|
1607 |
-
|
1608 |
-
//finds the first group to fill with the event
|
1609 |
-
for (var groupIndex = 0; groupIndex < curGroups.length; groupIndex++) {
|
1610 |
-
if (curGroups[groupIndex].length > 0) {
|
1611 |
-
//checks if the event starts after the end of the last event of the group
|
1612 |
-
if (curGroups[groupIndex][curGroups[groupIndex].length - 1].data('calEvent').end.getTime() <= $curEvent.data('calEvent').start.getTime()) {
|
1613 |
-
curGroups[groupIndex].push($curEvent);
|
1614 |
-
if (lastEndTime.getTime() < $curEvent.data('calEvent').end.getTime()) {
|
1615 |
-
lastEndTime = $curEvent.data('calEvent').end;
|
1616 |
-
}
|
1617 |
-
return;
|
1618 |
-
}
|
1619 |
-
}
|
1620 |
-
}
|
1621 |
-
//if not found, creates a new group
|
1622 |
-
curGroups.push([$curEvent]);
|
1623 |
-
if (lastEndTime.getTime() < $curEvent.data('calEvent').end.getTime()) {
|
1624 |
-
lastEndTime = $curEvent.data('calEvent').end;
|
1625 |
-
}
|
1626 |
-
});
|
1627 |
-
//adds the last groups in result
|
1628 |
-
if (curGroups.length > 0) {
|
1629 |
-
groups.push(curGroups);
|
1630 |
-
}
|
1631 |
-
return groups;
|
1632 |
-
},
|
1633 |
-
|
1634 |
-
|
1635 |
-
/*
|
1636 |
-
* find the weekday in the current calendar that the calEvent falls within
|
1637 |
-
*/
|
1638 |
-
_findWeekDayForEvent: function(calEvent, $weekDayColumns) {
|
1639 |
-
|
1640 |
-
var $weekDay,
|
1641 |
-
options = this.options,
|
1642 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
1643 |
-
user_ids = this._getEventUserId(calEvent);
|
1644 |
-
|
1645 |
-
if (!$.isArray(user_ids)) {
|
1646 |
-
user_ids = [user_ids];
|
1647 |
-
}
|
1648 |
-
|
1649 |
-
$weekDayColumns.each(function(index, curDay) {
|
1650 |
-
if ($(this).data('startDate').getTime() <= calEvent.start.getTime() &&
|
1651 |
-
$(this).data('endDate').getTime() >= calEvent.end.getTime() &&
|
1652 |
-
(!showAsSeparatedUser || $.inArray($(this).data('wcUserId'), user_ids) !== -1)
|
1653 |
-
) {
|
1654 |
-
if ($weekDay) {
|
1655 |
-
$weekDay = $weekDay.add($(curDay));
|
1656 |
-
}
|
1657 |
-
else {
|
1658 |
-
$weekDay = $(curDay);
|
1659 |
-
}
|
1660 |
-
}
|
1661 |
-
});
|
1662 |
-
|
1663 |
-
return $weekDay;
|
1664 |
-
},
|
1665 |
-
|
1666 |
-
/*
|
1667 |
-
* update the events rendering in the calendar. Add if does not yet exist.
|
1668 |
-
*/
|
1669 |
-
_updateEventInCalendar: function(calEvent) {
|
1670 |
-
var self = this;
|
1671 |
-
self._cleanEvent(calEvent);
|
1672 |
-
|
1673 |
-
if (calEvent.id) {
|
1674 |
-
self.element.find('.wc-cal-event').each(function() {
|
1675 |
-
if ($(this).data('calEvent').id === calEvent.id || $(this).hasClass('wc-new-cal-event')) {
|
1676 |
-
$(this).remove();
|
1677 |
-
// return false;
|
1678 |
-
}
|
1679 |
-
});
|
1680 |
-
}
|
1681 |
-
|
1682 |
-
var $weekDays = self._findWeekDayForEvent(calEvent, self.element.find('.wc-grid-row-events .wc-day-column-inner'));
|
1683 |
-
if ($weekDays) {
|
1684 |
-
$weekDays.each(function(index, weekDay) {
|
1685 |
-
var $weekDay = $(weekDay);
|
1686 |
-
var $calEvent = self._renderEvent(calEvent, $weekDay);
|
1687 |
-
self._adjustForEventCollisions($weekDay, $calEvent, calEvent, calEvent);
|
1688 |
-
// self._refreshEventDetails(calEvent, $calEvent);
|
1689 |
-
// self._positionEvent($weekDay, $calEvent);
|
1690 |
-
self._adjustOverlappingEvents($weekDay);
|
1691 |
-
});
|
1692 |
-
}
|
1693 |
-
},
|
1694 |
-
|
1695 |
-
/*
|
1696 |
-
* Position the event element within the weekday based on it's start / end dates.
|
1697 |
-
*/
|
1698 |
-
_positionEvent: function($weekDay, $calEvent) {
|
1699 |
-
var options = this.options;
|
1700 |
-
var calEvent = $calEvent.data('calEvent');
|
1701 |
-
var pxPerMillis = $weekDay.height() / options.millisToDisplay;
|
1702 |
-
var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
|
1703 |
-
var startMillis = this._getDSTdayShift(calEvent.start).getTime() - this._getDSTdayShift(new Date(calEvent.start.getFullYear(), calEvent.start.getMonth(), calEvent.start.getDate(), firstHourDisplayed)).getTime();
|
1704 |
-
var eventMillis = this._getDSTdayShift(calEvent.end).getTime() - this._getDSTdayShift(calEvent.start).getTime();
|
1705 |
-
var pxTop = pxPerMillis * startMillis;
|
1706 |
-
var pxHeight = pxPerMillis * eventMillis;
|
1707 |
-
//var pxHeightFallback = pxPerMillis * (60 / options.timeslotsPerHour) * 60 * 1000;
|
1708 |
-
$calEvent.css({top: pxTop, height: pxHeight || (pxPerMillis * 3600000 / options.timeslotsPerHour)});
|
1709 |
-
},
|
1710 |
-
|
1711 |
-
/*
|
1712 |
-
* Determine the actual start and end times of a calevent based on it's
|
1713 |
-
* relative position within the weekday column and the starting hour of the
|
1714 |
-
* displayed calendar.
|
1715 |
-
*/
|
1716 |
-
_getEventDurationFromPositionedEventElement: function($weekDay, $calEvent, top) {
|
1717 |
-
var options = this.options;
|
1718 |
-
var startOffsetMillis = options.businessHours.limitDisplay ? options.businessHours.start * 3600000 : 0;
|
1719 |
-
var start = new Date($weekDay.data('startDate').getTime() + startOffsetMillis + Math.round(top / options.timeslotHeight) * options.millisPerTimeslot);
|
1720 |
-
var end = new Date(start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot);
|
1721 |
-
return {start: this._getDSTdayShift(start, -1), end: this._getDSTdayShift(end, -1)};
|
1722 |
-
},
|
1723 |
-
|
1724 |
-
/*
|
1725 |
-
* If the calendar does not allow event overlap, adjust the start or end date if necessary to
|
1726 |
-
* avoid overlapping of events. Typically, shortens the resized / dropped event to it's max possible
|
1727 |
-
* duration based on the overlap. If no satisfactory adjustment can be made, the event is reverted to
|
1728 |
-
* it's original location.
|
1729 |
-
*/
|
1730 |
-
_adjustForEventCollisions: function($weekDay, $calEvent, newCalEvent, oldCalEvent, maintainEventDuration) {
|
1731 |
-
var options = this.options;
|
1732 |
-
|
1733 |
-
if (options.allowCalEventOverlap) {
|
1734 |
-
return;
|
1735 |
-
}
|
1736 |
-
var adjustedStart, adjustedEnd;
|
1737 |
-
var self = this;
|
1738 |
-
|
1739 |
-
$weekDay.find('.wc-cal-event').not($calEvent).each(function() {
|
1740 |
-
var currentCalEvent = $(this).data('calEvent');
|
1741 |
-
|
1742 |
-
//has been dropped onto existing event overlapping the end time
|
1743 |
-
if (newCalEvent.start.getTime() < currentCalEvent.end.getTime() &&
|
1744 |
-
newCalEvent.end.getTime() >= currentCalEvent.end.getTime()) {
|
1745 |
-
|
1746 |
-
adjustedStart = currentCalEvent.end;
|
1747 |
-
}
|
1748 |
-
|
1749 |
-
|
1750 |
-
//has been dropped onto existing event overlapping the start time
|
1751 |
-
if (newCalEvent.end.getTime() > currentCalEvent.start.getTime() &&
|
1752 |
-
newCalEvent.start.getTime() <= currentCalEvent.start.getTime()) {
|
1753 |
-
|
1754 |
-
adjustedEnd = currentCalEvent.start;
|
1755 |
-
}
|
1756 |
-
//has been dropped inside existing event with same or larger duration
|
1757 |
-
if (oldCalEvent.resizable == false ||
|
1758 |
-
(newCalEvent.end.getTime() <= currentCalEvent.end.getTime() &&
|
1759 |
-
newCalEvent.start.getTime() >= currentCalEvent.start.getTime())) {
|
1760 |
-
|
1761 |
-
adjustedStart = oldCalEvent.start;
|
1762 |
-
adjustedEnd = oldCalEvent.end;
|
1763 |
-
return false;
|
1764 |
-
}
|
1765 |
-
|
1766 |
-
});
|
1767 |
-
|
1768 |
-
|
1769 |
-
newCalEvent.start = adjustedStart || newCalEvent.start;
|
1770 |
-
|
1771 |
-
if (adjustedStart && maintainEventDuration) {
|
1772 |
-
newCalEvent.end = new Date(adjustedStart.getTime() + (oldCalEvent.end.getTime() - oldCalEvent.start.getTime()));
|
1773 |
-
self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent);
|
1774 |
-
} else {
|
1775 |
-
newCalEvent.end = adjustedEnd || newCalEvent.end;
|
1776 |
-
}
|
1777 |
-
|
1778 |
-
|
1779 |
-
//reset if new cal event has been forced to zero size
|
1780 |
-
if (newCalEvent.start.getTime() >= newCalEvent.end.getTime()) {
|
1781 |
-
newCalEvent.start = oldCalEvent.start;
|
1782 |
-
newCalEvent.end = oldCalEvent.end;
|
1783 |
-
}
|
1784 |
-
|
1785 |
-
$calEvent.data('calEvent', newCalEvent);
|
1786 |
-
},
|
1787 |
-
|
1788 |
-
/**
|
1789 |
-
* Add draggable capabilities to an event
|
1790 |
-
*/
|
1791 |
-
_addDraggableToCalEvent: function(calEvent, $calEvent) {
|
1792 |
-
var options = this.options;
|
1793 |
-
|
1794 |
-
$calEvent.draggable({
|
1795 |
-
handle: '.wc-time',
|
1796 |
-
containment: 'div.wc-time-slots',
|
1797 |
-
snap: '.wc-day-column-inner',
|
1798 |
-
snapMode: 'inner',
|
1799 |
-
snapTolerance: options.timeslotHeight - 1,
|
1800 |
-
revert: 'invalid',
|
1801 |
-
opacity: 0.5,
|
1802 |
-
grid: [$calEvent.outerWidth() + 1, options.timeslotHeight],
|
1803 |
-
start: function(event, ui) {
|
1804 |
-
var $calEvent = ui.draggable || ui.helper;
|
1805 |
-
options.eventDrag(calEvent, $calEvent);
|
1806 |
-
}
|
1807 |
-
});
|
1808 |
-
},
|
1809 |
-
|
1810 |
-
/*
|
1811 |
-
* Add droppable capabilites to weekdays to allow dropping of calEvents only
|
1812 |
-
*/
|
1813 |
-
_addDroppableToWeekDay: function($weekDay) {
|
1814 |
-
var self = this;
|
1815 |
-
var options = this.options;
|
1816 |
-
$weekDay.droppable({
|
1817 |
-
accept: '.wc-cal-event',
|
1818 |
-
drop: function(event, ui) {
|
1819 |
-
var $calEvent = ui.draggable;
|
1820 |
-
var top = Math.round(parseInt(ui.position.top));
|
1821 |
-
var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $calEvent, top);
|
1822 |
-
var calEvent = $calEvent.data('calEvent');
|
1823 |
-
var newCalEvent = $.extend(true, {}, calEvent, {start: eventDuration.start, end: eventDuration.end});
|
1824 |
-
var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
|
1825 |
-
if (showAsSeparatedUser) {
|
1826 |
-
// we may have dragged the event on column with a new user.
|
1827 |
-
// nice way to handle that is:
|
1828 |
-
// - get the newly dragged on user
|
1829 |
-
// - check if user is part of the event
|
1830 |
-
// - if yes, nothing changes, if not, find the old owner to remove it and add new one
|
1831 |
-
var newUserId = $weekDay.data('wcUserId');
|
1832 |
-
var userIdList = self._getEventUserId(calEvent);
|
1833 |
-
var oldUserId = $(ui.draggable.parents('.wc-day-column-inner').get(0)).data('wcUserId');
|
1834 |
-
if (!$.isArray(userIdList)) {
|
1835 |
-
userIdList = [userIdList];
|
1836 |
-
}
|
1837 |
-
if ($.inArray(newUserId, userIdList) == -1) {
|
1838 |
-
// remove old user
|
1839 |
-
var _index = $.inArray(oldUserId, userIdList);
|
1840 |
-
userIdList.splice(_index, 1);
|
1841 |
-
// add new user ?
|
1842 |
-
if ($.inArray(newUserId, userIdList) == -1) {
|
1843 |
-
userIdList.push(newUserId);
|
1844 |
-
}
|
1845 |
-
}
|
1846 |
-
newCalEvent = self._setEventUserId(newCalEvent, ((userIdList.length == 1) ? userIdList[0] : userIdList));
|
1847 |
-
}
|
1848 |
-
self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, true);
|
1849 |
-
var $weekDayColumns = self.element.find('.wc-day-column-inner');
|
1850 |
-
|
1851 |
-
//trigger drop callback
|
1852 |
-
options.eventDrop(newCalEvent, calEvent, $calEvent);
|
1853 |
-
|
1854 |
-
var $newEvent = self._renderEvent(newCalEvent, self._findWeekDayForEvent(newCalEvent, $weekDayColumns));
|
1855 |
-
$calEvent.hide();
|
1856 |
-
|
1857 |
-
$calEvent.data('preventClick', true);
|
1858 |
-
|
1859 |
-
var $weekDayOld = self._findWeekDayForEvent($calEvent.data('calEvent'), self.element.find('.wc-time-slots .wc-day-column-inner'));
|
1860 |
-
|
1861 |
-
if ($weekDayOld.data('startDate') != $weekDay.data('startDate')) {
|
1862 |
-
self._adjustOverlappingEvents($weekDayOld);
|
1863 |
-
}
|
1864 |
-
self._adjustOverlappingEvents($weekDay);
|
1865 |
-
|
1866 |
-
setTimeout(function() {
|
1867 |
-
$calEvent.remove();
|
1868 |
-
}, 1000);
|
1869 |
-
|
1870 |
-
}
|
1871 |
-
});
|
1872 |
-
},
|
1873 |
-
|
1874 |
-
/*
|
1875 |
-
* Add resizable capabilities to a calEvent
|
1876 |
-
*/
|
1877 |
-
_addResizableToCalEvent: function(calEvent, $calEvent, $weekDay) {
|
1878 |
-
var self = this;
|
1879 |
-
var options = this.options;
|
1880 |
-
$calEvent.resizable({
|
1881 |
-
grid: options.timeslotHeight,
|
1882 |
-
containment: $weekDay,
|
1883 |
-
handles: 's',
|
1884 |
-
minHeight: options.timeslotHeight,
|
1885 |
-
stop: function(event, ui) {
|
1886 |
-
var $calEvent = ui.element;
|
1887 |
-
var newEnd = new Date($calEvent.data('calEvent').start.getTime() + Math.max(1, Math.round(ui.size.height / options.timeslotHeight)) * options.millisPerTimeslot);
|
1888 |
-
if (self._needDSTdayShift($calEvent.data('calEvent').start, newEnd))
|
1889 |
-
newEnd = self._getDSTdayShift(newEnd, -1);
|
1890 |
-
var newCalEvent = $.extend(true, {}, calEvent, {start: calEvent.start, end: newEnd});
|
1891 |
-
self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent);
|
1892 |
-
|
1893 |
-
//trigger resize callback
|
1894 |
-
options.eventResize(newCalEvent, calEvent, $calEvent);
|
1895 |
-
self._refreshEventDetails(newCalEvent, $calEvent);
|
1896 |
-
self._positionEvent($weekDay, $calEvent);
|
1897 |
-
self._adjustOverlappingEvents($weekDay);
|
1898 |
-
$calEvent.data('preventClick', true);
|
1899 |
-
setTimeout(function() {
|
1900 |
-
$calEvent.removeData('preventClick');
|
1901 |
-
}, 500);
|
1902 |
-
}
|
1903 |
-
});
|
1904 |
-
$('.ui-resizable-handle', $calEvent).text('=');
|
1905 |
-
},
|
1906 |
-
|
1907 |
-
/*
|
1908 |
-
* Refresh the displayed details of a calEvent in the calendar
|
1909 |
-
*/
|
1910 |
-
_refreshEventDetails: function(calEvent, $calEvent) {
|
1911 |
-
var prefix = '';
|
1912 |
-
if (!this.options.readonly &&
|
1913 |
-
this.options.allowEventDelete &&
|
1914 |
-
this.options.deletable(calEvent,$calEvent)) {
|
1915 |
-
prefix = '<div class="wc-cal-event-delete ui-icon ui-icon-close"></div>';
|
1916 |
-
}
|
1917 |
-
$calEvent.find('.wc-time').html(prefix + this.options.eventHeader(calEvent, this.element));
|
1918 |
-
$calEvent.find('.wc-title').html(this.options.eventBody(calEvent, this.element));
|
1919 |
-
|
1920 |
-
$calEvent.data('calEvent', calEvent);
|
1921 |
-
this.options.eventRefresh(calEvent, $calEvent);
|
1922 |
-
},
|
1923 |
-
|
1924 |
-
/*
|
1925 |
-
* Clear all cal events from the calendar
|
1926 |
-
*/
|
1927 |
-
_clearCalendar: function() {
|
1928 |
-
this.element.find('.wc-day-column-inner div').remove();
|
1929 |
-
this._clearFreeBusys();
|
1930 |
-
},
|
1931 |
-
|
1932 |
-
/*
|
1933 |
-
* Scroll the calendar to a specific hour
|
1934 |
-
*/
|
1935 |
-
_scrollToHour: function(hour, animate) {
|
1936 |
-
var self = this;
|
1937 |
-
var options = this.options;
|
1938 |
-
var $scrollable = this.element.find('.wc-scrollable-grid');
|
1939 |
-
var slot = hour;
|
1940 |
-
if (self.options.businessHours.limitDisplay) {
|
1941 |
-
if (hour <= self.options.businessHours.start) {
|
1942 |
-
slot = 0;
|
1943 |
-
} else if (hour >= self.options.businessHours.end) {
|
1944 |
-
slot = self.options.businessHours.end - self.options.businessHours.start - 1;
|
1945 |
-
} else {
|
1946 |
-
slot = hour - self.options.businessHours.start;
|
1947 |
-
}
|
1948 |
-
}
|
1949 |
-
|
1950 |
-
var $target = this.element.find('.wc-grid-timeslot-header .wc-hour-header:eq(' + slot + ')');
|
1951 |
-
|
1952 |
-
$scrollable.animate({scrollTop: 0}, 0, function() {
|
1953 |
-
var targetOffset = $target.offset().top;
|
1954 |
-
var scroll = targetOffset - $scrollable.offset().top - $target.outerHeight();
|
1955 |
-
if (animate) {
|
1956 |
-
$scrollable.animate({scrollTop: scroll}, options.scrollToHourMillis);
|
1957 |
-
}
|
1958 |
-
else {
|
1959 |
-
$scrollable.animate({scrollTop: scroll}, 0);
|
1960 |
-
}
|
1961 |
-
});
|
1962 |
-
},
|
1963 |
-
|
1964 |
-
/*
|
1965 |
-
* find the hour (12 hour day) for a given hour index
|
1966 |
-
*/
|
1967 |
-
_hourForIndex: function(index) {
|
1968 |
-
if (index === 0) { //midnight
|
1969 |
-
return 12;
|
1970 |
-
} else if (index < 13) { //am
|
1971 |
-
return index;
|
1972 |
-
} else { //pm
|
1973 |
-
return index - 12;
|
1974 |
-
}
|
1975 |
-
},
|
1976 |
-
|
1977 |
-
_24HourForIndex: function(index) {
|
1978 |
-
if (index === 0) { //midnight
|
1979 |
-
return '00';
|
1980 |
-
} else if (index < 10) {
|
1981 |
-
return '0' + index;
|
1982 |
-
} else {
|
1983 |
-
return index;
|
1984 |
-
}
|
1985 |
-
},
|
1986 |
-
|
1987 |
-
_amOrPm: function(hourOfDay) {
|
1988 |
-
return hourOfDay < 12 ? BooklyL10n['AM'] : BooklyL10n['PM'];
|
1989 |
-
},
|
1990 |
-
|
1991 |
-
_isToday: function(date) {
|
1992 |
-
var clonedDate = this._cloneDate(date);
|
1993 |
-
this._clearTime(clonedDate);
|
1994 |
-
var today = new Date();
|
1995 |
-
this._clearTime(today);
|
1996 |
-
return today.getTime() === clonedDate.getTime();
|
1997 |
-
},
|
1998 |
-
|
1999 |
-
/*
|
2000 |
-
* Clean events to ensure correct format
|
2001 |
-
*/
|
2002 |
-
_cleanEvents: function(events) {
|
2003 |
-
var self = this;
|
2004 |
-
$.each(events, function(i, event) {
|
2005 |
-
self._cleanEvent(event);
|
2006 |
-
});
|
2007 |
-
return events;
|
2008 |
-
},
|
2009 |
-
|
2010 |
-
/*
|
2011 |
-
* Clean specific event
|
2012 |
-
*/
|
2013 |
-
_cleanEvent: function(event) {
|
2014 |
-
if (event.date) {
|
2015 |
-
event.start = event.date;
|
2016 |
-
}
|
2017 |
-
event.start = this._cleanDate(event.start);
|
2018 |
-
event.end = this._cleanDate(event.end);
|
2019 |
-
if (!event.end) {
|
2020 |
-
event.end = this._addDays(this._cloneDate(event.start), 1);
|
2021 |
-
}
|
2022 |
-
},
|
2023 |
-
|
2024 |
-
/*
|
2025 |
-
* Disable text selection of the elements in different browsers
|
2026 |
-
*/
|
2027 |
-
_disableTextSelect: function($elements) {
|
2028 |
-
$elements.each(function() {
|
2029 |
-
if ($.browser.mozilla) {//Firefox
|
2030 |
-
$(this).css('MozUserSelect', 'none');
|
2031 |
-
} else if ($.browser.msie) {//IE
|
2032 |
-
$(this).bind('selectstart', function() {
|
2033 |
-
return false;
|
2034 |
-
});
|
2035 |
-
} else {//Opera, etc.
|
2036 |
-
$(this).mousedown(function() {
|
2037 |
-
return false;
|
2038 |
-
});
|
2039 |
-
}
|
2040 |
-
});
|
2041 |
-
},
|
2042 |
-
|
2043 |
-
/*
|
2044 |
-
* returns the date on the first millisecond of the week
|
2045 |
-
*/
|
2046 |
-
_dateFirstDayOfWeek: function(date) {
|
2047 |
-
var self = this;
|
2048 |
-
var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
2049 |
-
var adjustedDate = new Date(midnightCurrentDate);
|
2050 |
-
adjustedDate.setDate(adjustedDate.getDate() - self._getAdjustedDayIndex(midnightCurrentDate));
|
2051 |
-
|
2052 |
-
return adjustedDate;
|
2053 |
-
},
|
2054 |
-
|
2055 |
-
/*
|
2056 |
-
* returns the date on the first millisecond of the last day of the week
|
2057 |
-
*/
|
2058 |
-
_dateLastDayOfWeek: function(date) {
|
2059 |
-
var self = this;
|
2060 |
-
var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
2061 |
-
var adjustedDate = new Date(midnightCurrentDate);
|
2062 |
-
var daysToAdd = (self.options.daysToShow - 1 - self._getAdjustedDayIndex(midnightCurrentDate));
|
2063 |
-
adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
|
2064 |
-
|
2065 |
-
return adjustedDate;
|
2066 |
-
},
|
2067 |
-
|
2068 |
-
/**
|
2069 |
-
* fix the date if it is not within given options
|
2070 |
-
* minDate and maxDate
|
2071 |
-
*/
|
2072 |
-
_fixMinMaxDate: function(date) {
|
2073 |
-
var minDate, maxDate;
|
2074 |
-
date = this._cleanDate(date);
|
2075 |
-
|
2076 |
-
// not less than minDate
|
2077 |
-
if (this.options.minDate) {
|
2078 |
-
minDate = this._cleanDate(this.options.minDate);
|
2079 |
-
// midnight on minDate
|
2080 |
-
minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
|
2081 |
-
if (date.getTime() < minDate.getTime()) {
|
2082 |
-
this._trigger('reachedmindate', this.element, date);
|
2083 |
-
}
|
2084 |
-
date = this._cleanDate(Math.max(date.getTime(), minDate.getTime()));
|
2085 |
-
}
|
2086 |
-
|
2087 |
-
// not more than maxDate
|
2088 |
-
if (this.options.maxDate) {
|
2089 |
-
maxDate = this._cleanDate(this.options.maxDate);
|
2090 |
-
// apply correction for max date if not startOnFirstDayOfWeek
|
2091 |
-
// to make sure no further date is displayed.
|
2092 |
-
// otherwise, the complement will still be shown
|
2093 |
-
if (!this._startOnFirstDayOfWeek()) {
|
2094 |
-
var day = maxDate.getDate() - this.options.daysToShow + 1;
|
2095 |
-
maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), day);
|
2096 |
-
}
|
2097 |
-
// microsecond before midnight on maxDate
|
2098 |
-
maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate(), 23, 59, 59, 999);
|
2099 |
-
if (date.getTime() > maxDate.getTime()) {
|
2100 |
-
this._trigger('reachedmaxdate', this.element, date);
|
2101 |
-
}
|
2102 |
-
date = this._cleanDate(Math.min(date.getTime(), maxDate.getTime()));
|
2103 |
-
}
|
2104 |
-
|
2105 |
-
return date;
|
2106 |
-
},
|
2107 |
-
|
2108 |
-
/*
|
2109 |
-
* gets the index of the current day adjusted based on options
|
2110 |
-
*/
|
2111 |
-
_getAdjustedDayIndex: function(date) {
|
2112 |
-
if (!this._startOnFirstDayOfWeek()) {
|
2113 |
-
return 0;
|
2114 |
-
}
|
2115 |
-
|
2116 |
-
var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
2117 |
-
var currentDayOfStandardWeek = midnightCurrentDate.getDay();
|
2118 |
-
var days = [0, 1, 2, 3, 4, 5, 6];
|
2119 |
-
this._rotate(days, this._firstDayOfWeek());
|
2120 |
-
return days[currentDayOfStandardWeek];
|
2121 |
-
},
|
2122 |
-
|
2123 |
-
_firstDayOfWeek: function() {
|
2124 |
-
if ($.isFunction(this.options.firstDayOfWeek)) {
|
2125 |
-
return this.options.firstDayOfWeek(this.element);
|
2126 |
-
}
|
2127 |
-
return this.options.firstDayOfWeek;
|
2128 |
-
},
|
2129 |
-
|
2130 |
-
/*
|
2131 |
-
* returns the date on the last millisecond of the week
|
2132 |
-
*/
|
2133 |
-
_dateLastMilliOfWeek: function(date) {
|
2134 |
-
var lastDayOfWeek = this._dateLastDayOfWeek(date);
|
2135 |
-
lastDayOfWeek = this._cloneDate(lastDayOfWeek);
|
2136 |
-
lastDayOfWeek.setDate(lastDayOfWeek.getDate() + 1);
|
2137 |
-
return lastDayOfWeek;
|
2138 |
-
|
2139 |
-
},
|
2140 |
-
|
2141 |
-
/*
|
2142 |
-
* Clear the time components of a date leaving the date
|
2143 |
-
* of the first milli of day
|
2144 |
-
*/
|
2145 |
-
_clearTime: function(d) {
|
2146 |
-
d.setHours(0);
|
2147 |
-
d.setMinutes(0);
|
2148 |
-
d.setSeconds(0);
|
2149 |
-
d.setMilliseconds(0);
|
2150 |
-
return d;
|
2151 |
-
},
|
2152 |
-
|
2153 |
-
/*
|
2154 |
-
* add specific number of days to date
|
2155 |
-
*/
|
2156 |
-
_addDays: function(d, n, keepTime) {
|
2157 |
-
d.setDate(d.getDate() + n);
|
2158 |
-
if (keepTime) {
|
2159 |
-
return d;
|
2160 |
-
}
|
2161 |
-
return this._clearTime(d);
|
2162 |
-
},
|
2163 |
-
|
2164 |
-
/*
|
2165 |
-
* Rotate an array by specified number of places.
|
2166 |
-
*/
|
2167 |
-
_rotate: function(a /*array*/, p /* integer, positive integer rotate to the right, negative to the left... */) {
|
2168 |
-
for (var l = a.length, p = (Math.abs(p) >= l && (p %= l), p < 0 && (p += l), p), i, x; p; p = (Math.ceil(l / p) - 1) * p - l + (l = p)) {
|
2169 |
-
for (i = l; i > p; x = a[--i], a[i] = a[i - p], a[i - p] = x) {}
|
2170 |
-
}
|
2171 |
-
return a;
|
2172 |
-
},
|
2173 |
-
|
2174 |
-
_cloneDate: function(d) {
|
2175 |
-
return new Date(d.getTime());
|
2176 |
-
},
|
2177 |
-
|
2178 |
-
/**
|
2179 |
-
* Return a Date instance for different representations.
|
2180 |
-
* Valid representations are:
|
2181 |
-
* * timestamps
|
2182 |
-
* * Date objects
|
2183 |
-
* * textual representations (only these accepted by the Date
|
2184 |
-
* constructor)
|
2185 |
-
*
|
2186 |
-
* @return {Date} The clean date object.
|
2187 |
-
*/
|
2188 |
-
_cleanDate: function(d) {
|
2189 |
-
if (typeof d === 'string') {
|
2190 |
-
// if is numeric
|
2191 |
-
if (!isNaN(Number(d))) {
|
2192 |
-
return this._cleanDate(parseInt(d, 10));
|
2193 |
-
}
|
2194 |
-
|
2195 |
-
// this is a human readable date
|
2196 |
-
return Date.parse(d) || new Date(d);
|
2197 |
-
}
|
2198 |
-
|
2199 |
-
if (typeof d == 'number') {
|
2200 |
-
return new Date(d);
|
2201 |
-
}
|
2202 |
-
|
2203 |
-
return d;
|
2204 |
-
},
|
2205 |
-
|
2206 |
-
/*
|
2207 |
-
* date formatting is adapted from
|
2208 |
-
* http://jacwright.com/projects/javascript/date_format
|
2209 |
-
*/
|
2210 |
-
_formatDate: function(date, format) {
|
2211 |
-
var returnStr = '';
|
2212 |
-
for (var i = 0; i < format.length; i++) {
|
2213 |
-
var curChar = format.charAt(i);
|
2214 |
-
if (i != 0 && format.charAt(i - 1) == '\\') {
|
2215 |
-
returnStr += curChar;
|
2216 |
-
}
|
2217 |
-
else if (this._replaceChars[curChar]) {
|
2218 |
-
returnStr += this._replaceChars[curChar](date, this);
|
2219 |
-
} else if (curChar != '\\') {
|
2220 |
-
returnStr += curChar;
|
2221 |
-
}
|
2222 |
-
}
|
2223 |
-
return returnStr;
|
2224 |
-
},
|
2225 |
-
|
2226 |
-
_replaceChars: {
|
2227 |
-
// Day
|
2228 |
-
d: function(date) { return (date.getDate() < 10 ? '0' : '') + date.getDate(); },
|
2229 |
-
D: function(date, calendar) { return calendar.options.shortDays[date.getDay()]; },
|
2230 |
-
j: function(date) { return date.getDate(); },
|
2231 |
-
l: function(date, calendar) { return calendar.options.longDays[date.getDay()]; },
|
2232 |
-
N: function(date) { var _d = date.getDay(); return _d ? _d : 7; },
|
2233 |
-
S: function(date) { return (date.getDate() % 10 == 1 && date.getDate() != 11 ? 'st' : (date.getDate() % 10 == 2 && date.getDate() != 12 ? 'nd' : (date.getDate() % 10 == 3 && date.getDate() != 13 ? 'rd' : 'th'))); },
|
2234 |
-
w: function(date) { return date.getDay(); },
|
2235 |
-
z: function(date) { var d = new Date(date.getFullYear(), 0, 1); return Math.ceil((date - d) / 86400000); }, // Fixed now
|
2236 |
-
// Week
|
2237 |
-
W: function(date) { var d = new Date(date.getFullYear(), 0, 1); return Math.ceil((((date - d) / 86400000) + d.getDay() + 1) / 7); }, // Fixed now
|
2238 |
-
// Month
|
2239 |
-
F: function(date, calendar) { return calendar.options.longMonths[date.getMonth()]; },
|
2240 |
-
m: function(date) { return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1); },
|
2241 |
-
M: function(date, calendar) { return calendar.options.shortMonths[date.getMonth()]; },
|
2242 |
-
n: function(date) { return date.getMonth() + 1; },
|
2243 |
-
t: function(date) { var d = date; return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate() }, // Fixed now, gets #days of date
|
2244 |
-
// Year
|
2245 |
-
L: function(date) { var year = date.getFullYear(); return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)); }, // Fixed now
|
2246 |
-
o: function(date) { var d = new Date(date.valueOf()); d.setDate(d.getDate() - ((date.getDay() + 6) % 7) + 3); return d.getFullYear();}, //Fixed now
|
2247 |
-
Y: function(date) { return date.getFullYear(); },
|
2248 |
-
y: function(date) { return ('' + date.getFullYear()).substr(2); },
|
2249 |
-
// Time
|
2250 |
-
a: function(date) { return date.getHours() < 12 ? BooklyL10n['AM'] : BooklyL10n['PM']; },
|
2251 |
-
A: function(date) { return date.getHours() < 12 ? BooklyL10n['AM'] : BooklyL10n['PM']; },
|
2252 |
-
B: function(date) { return Math.floor((((date.getUTCHours() + 1) % 24) + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600) * 1000 / 24); }, // Fixed now
|
2253 |
-
g: function(date) { return date.getHours() % 12 || 12; },
|
2254 |
-
G: function(date) { return date.getHours(); },
|
2255 |
-
h: function(date) { return ((date.getHours() % 12 || 12) < 10 ? '0' : '') + (date.getHours() % 12 || 12); },
|
2256 |
-
H: function(date) { return (date.getHours() < 10 ? '0' : '') + date.getHours(); },
|
2257 |
-
i: function(date) { return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); },
|
2258 |
-
s: function(date) { return (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); },
|
2259 |
-
u: function(date) { var m = date.getMilliseconds(); return (m < 10 ? '00' : (m < 100 ? '0' : '')) + m; },
|
2260 |
-
// Timezone
|
2261 |
-
e: function(date) { return 'Not Yet Supported'; },
|
2262 |
-
I: function(date) { return 'Not Yet Supported'; },
|
2263 |
-
O: function(date) { return (-date.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(date.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(date.getTimezoneOffset() / 60)) + '00'; },
|
2264 |
-
P: function(date) { return (-date.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(date.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(date.getTimezoneOffset() / 60)) + ':00'; }, // Fixed now
|
2265 |
-
T: function(date) { var m = date.getMonth(); date.setMonth(0); var result = date.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1'); date.setMonth(m); return result;},
|
2266 |
-
Z: function(date) { return -date.getTimezoneOffset() * 60; },
|
2267 |
-
// Full Date/Time
|
2268 |
-
c: function(date, calendar) { return calendar._formatDate(date, 'Y-m-d\\TH:i:sP'); }, // Fixed now
|
2269 |
-
r: function(date, calendar) { return calendar._formatDate(date, 'D, d M Y H:i:s O'); },
|
2270 |
-
U: function(date) { return date.getTime() / 1000; }
|
2271 |
-
},
|
2272 |
-
|
2273 |
-
/* USER MANAGEMENT FUNCTIONS */
|
2274 |
-
|
2275 |
-
getUserForId: function(id) {
|
2276 |
-
return $.extend({}, this.options.users[this._getUserIndexFromId(id)]);
|
2277 |
-
},
|
2278 |
-
|
2279 |
-
/**
|
2280 |
-
* return the user name for header
|
2281 |
-
*/
|
2282 |
-
_getUserName: function(index) {
|
2283 |
-
var self = this;
|
2284 |
-
var options = this.options;
|
2285 |
-
var user = options.users[index];
|
2286 |
-
if ($.isFunction(options.getUserName)) {
|
2287 |
-
return options.getUserName(user, index, self.element);
|
2288 |
-
}
|
2289 |
-
else {
|
2290 |
-
return user;
|
2291 |
-
}
|
2292 |
-
},
|
2293 |
-
/**
|
2294 |
-
* return the user id for given index
|
2295 |
-
*/
|
2296 |
-
_getUserIdFromIndex: function(index) {
|
2297 |
-
var self = this;
|
2298 |
-
var options = this.options;
|
2299 |
-
if ($.isFunction(options.getUserId)) {
|
2300 |
-
return options.getUserId(options.users[index], index, self.element);
|
2301 |
-
}
|
2302 |
-
return index;
|
2303 |
-
},
|
2304 |
-
/**
|
2305 |
-
* returns the associated user index for given ID
|
2306 |
-
*/
|
2307 |
-
_getUserIndexFromId: function(id) {
|
2308 |
-
var self = this;
|
2309 |
-
var options = this.options;
|
2310 |
-
for (var i = 0; i < options.users.length; i++) {
|
2311 |
-
if (self._getUserIdFromIndex(i) == id) {
|
2312 |
-
return i;
|
2313 |
-
}
|
2314 |
-
}
|
2315 |
-
return 0;
|
2316 |
-
},
|
2317 |
-
/**
|
2318 |
-
* return the user ids for given calEvent.
|
2319 |
-
* default is calEvent.userId field.
|
2320 |
-
*/
|
2321 |
-
_getEventUserId: function(calEvent) {
|
2322 |
-
var self = this;
|
2323 |
-
var options = this.options;
|
2324 |
-
if (options.showAsSeparateUsers && options.users && options.users.length) {
|
2325 |
-
if ($.isFunction(options.getEventUserId)) {
|
2326 |
-
return options.getEventUserId(calEvent, self.element);
|
2327 |
-
}
|
2328 |
-
return calEvent.userId;
|
2329 |
-
}
|
2330 |
-
return [];
|
2331 |
-
},
|
2332 |
-
/**
|
2333 |
-
* sets the event user id on given calEvent
|
2334 |
-
* default is calEvent.userId field.
|
2335 |
-
*/
|
2336 |
-
_setEventUserId: function(calEvent, userId) {
|
2337 |
-
var self = this;
|
2338 |
-
var options = this.options;
|
2339 |
-
if ($.isFunction(options.setEventUserId)) {
|
2340 |
-
return options.setEventUserId(userId, calEvent, self.element);
|
2341 |
-
}
|
2342 |
-
calEvent.userId = userId;
|
2343 |
-
return calEvent;
|
2344 |
-
},
|
2345 |
-
/**
|
2346 |
-
* return the user ids for given freeBusy.
|
2347 |
-
* default is freeBusy.userId field.
|
2348 |
-
*/
|
2349 |
-
_getFreeBusyUserId: function(freeBusy) {
|
2350 |
-
var self = this;
|
2351 |
-
var options = this.options;
|
2352 |
-
if ($.isFunction(options.getFreeBusyUserId)) {
|
2353 |
-
return options.getFreeBusyUserId(freeBusy.getOption(), self.element);
|
2354 |
-
}
|
2355 |
-
return freeBusy.getOption('userId');
|
2356 |
-
},
|
2357 |
-
|
2358 |
-
/* FREEBUSY MANAGEMENT */
|
2359 |
-
|
2360 |
-
/**
|
2361 |
-
* ckean the free busy managers and remove all the freeBusy
|
2362 |
-
*/
|
2363 |
-
_clearFreeBusys: function() {
|
2364 |
-
if (this.options.displayFreeBusys) {
|
2365 |
-
var self = this,
|
2366 |
-
options = this.options,
|
2367 |
-
$freeBusyPlaceholders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy');
|
2368 |
-
$freeBusyPlaceholders.each(function() {
|
2369 |
-
$(this).data('wcFreeBusyManager', new FreeBusyManager({
|
2370 |
-
start: self._cloneDate($(this).data('startDate')),
|
2371 |
-
end: self._cloneDate($(this).data('endDate')),
|
2372 |
-
defaultFreeBusy: options.defaultFreeBusy || {}
|
2373 |
-
}));
|
2374 |
-
});
|
2375 |
-
self.element.find('.wc-grid-row-freebusy .wc-freebusy').remove();
|
2376 |
-
}
|
2377 |
-
},
|
2378 |
-
/**
|
2379 |
-
* retrieve placeholders for given freebusy
|
2380 |
-
*/
|
2381 |
-
_findWeekDaysForFreeBusy: function(freeBusy, $weekDays) {
|
2382 |
-
var $returnWeekDays,
|
2383 |
-
options = this.options,
|
2384 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
2385 |
-
self = this,
|
2386 |
-
userList = self._getFreeBusyUserId(freeBusy);
|
2387 |
-
if (!$.isArray(userList)) {
|
2388 |
-
userList = userList != 'undefined' ? [userList] : [];
|
2389 |
-
}
|
2390 |
-
if (!$weekDays) {
|
2391 |
-
$weekDays = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy');
|
2392 |
-
}
|
2393 |
-
$weekDays.each(function() {
|
2394 |
-
var manager = $(this).data('wcFreeBusyManager'),
|
2395 |
-
has_overlap = manager.isWithin(freeBusy.getStart()) ||
|
2396 |
-
manager.isWithin(freeBusy.getEnd()) ||
|
2397 |
-
freeBusy.isWithin(manager.getStart()) ||
|
2398 |
-
freeBusy.isWithin(manager.getEnd()),
|
2399 |
-
userId = $(this).data('wcUserId');
|
2400 |
-
if (has_overlap && (!showAsSeparatedUser || ($.inArray(userId, userList) != -1))) {
|
2401 |
-
$returnWeekDays = $returnWeekDays ? $returnWeekDays.add($(this)) : $(this);
|
2402 |
-
}
|
2403 |
-
});
|
2404 |
-
return $returnWeekDays;
|
2405 |
-
},
|
2406 |
-
|
2407 |
-
/**
|
2408 |
-
* used to render all freeBusys
|
2409 |
-
*/
|
2410 |
-
_renderFreeBusys: function(freeBusys) {
|
2411 |
-
if (this.options.displayFreeBusys) {
|
2412 |
-
var self = this,
|
2413 |
-
$freeBusyPlaceholders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
|
2414 |
-
freebusysToRender;
|
2415 |
-
//insert freebusys to dedicated placeholders freebusy managers
|
2416 |
-
if ($.isArray(freeBusys)) {
|
2417 |
-
freebusysToRender = self._cleanFreeBusys(freeBusys);
|
2418 |
-
} else if (freeBusys.freebusys) {
|
2419 |
-
freebusysToRender = self._cleanFreeBusys(freeBusys.freebusys);
|
2420 |
-
}
|
2421 |
-
else {
|
2422 |
-
freebusysToRender = [];
|
2423 |
-
}
|
2424 |
-
|
2425 |
-
$.each(freebusysToRender, function(index, freebusy) {
|
2426 |
-
var $placeholders = self._findWeekDaysForFreeBusy(freebusy, $freeBusyPlaceholders);
|
2427 |
-
if ($placeholders) {
|
2428 |
-
$placeholders.each(function() {
|
2429 |
-
var manager = $(this).data('wcFreeBusyManager');
|
2430 |
-
manager.insertFreeBusy(new FreeBusy(freebusy.getOption()));
|
2431 |
-
$(this).data('wcFreeBusyManager', manager);
|
2432 |
-
});
|
2433 |
-
}
|
2434 |
-
});
|
2435 |
-
|
2436 |
-
//now display freebusys on place holders
|
2437 |
-
self._refreshFreeBusys($freeBusyPlaceholders);
|
2438 |
-
}
|
2439 |
-
},
|
2440 |
-
/**
|
2441 |
-
* refresh freebusys for given placeholders
|
2442 |
-
*/
|
2443 |
-
_refreshFreeBusys: function($freeBusyPlaceholders) {
|
2444 |
-
if (this.options.displayFreeBusys && $freeBusyPlaceholders) {
|
2445 |
-
var self = this,
|
2446 |
-
options = this.options,
|
2447 |
-
start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
|
2448 |
-
end = (options.businessHours.limitDisplay ? options.businessHours.end : 24);
|
2449 |
-
|
2450 |
-
$freeBusyPlaceholders.each(function() {
|
2451 |
-
var $placehoder = $(this);
|
2452 |
-
var s = self._cloneDate($placehoder.data('startDate')),
|
2453 |
-
e = self._cloneDate(s);
|
2454 |
-
s.setHours(start);
|
2455 |
-
e.setHours(end);
|
2456 |
-
$placehoder.find('.wc-freebusy').remove();
|
2457 |
-
$.each($placehoder.data('wcFreeBusyManager').getFreeBusys(s, e), function() {
|
2458 |
-
self._renderFreeBusy(this, $placehoder);
|
2459 |
-
});
|
2460 |
-
});
|
2461 |
-
}
|
2462 |
-
},
|
2463 |
-
/**
|
2464 |
-
* render a freebusy item on dedicated placeholders
|
2465 |
-
*/
|
2466 |
-
_renderFreeBusy: function(freeBusy, $freeBusyPlaceholder) {
|
2467 |
-
if (this.options.displayFreeBusys) {
|
2468 |
-
var self = this,
|
2469 |
-
options = this.options,
|
2470 |
-
freeBusyHtml = '<div class="wc-freebusy"></div>';
|
2471 |
-
|
2472 |
-
var $fb = $(freeBusyHtml);
|
2473 |
-
$fb.data('wcFreeBusy', new FreeBusy(freeBusy.getOption()));
|
2474 |
-
this._positionFreeBusy($freeBusyPlaceholder, $fb);
|
2475 |
-
$fb = options.freeBusyRender(freeBusy.getOption(), $fb, self.element);
|
2476 |
-
if ($fb) {
|
2477 |
-
$fb.appendTo($freeBusyPlaceholder);
|
2478 |
-
}
|
2479 |
-
}
|
2480 |
-
},
|
2481 |
-
/*
|
2482 |
-
* Position the freebusy element within the weekday based on it's start / end dates.
|
2483 |
-
*/
|
2484 |
-
_positionFreeBusy: function($placeholder, $freeBusy) {
|
2485 |
-
var options = this.options;
|
2486 |
-
var freeBusy = $freeBusy.data('wcFreeBusy');
|
2487 |
-
var pxPerMillis = $placeholder.height() / options.millisToDisplay;
|
2488 |
-
var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
|
2489 |
-
var startMillis = freeBusy.getStart().getTime() - new Date(freeBusy.getStart().getFullYear(), freeBusy.getStart().getMonth(), freeBusy.getStart().getDate(), firstHourDisplayed).getTime();
|
2490 |
-
var eventMillis = freeBusy.getEnd().getTime() - freeBusy.getStart().getTime();
|
2491 |
-
var pxTop = pxPerMillis * startMillis;
|
2492 |
-
var pxHeight = pxPerMillis * eventMillis;
|
2493 |
-
$freeBusy.css({top: pxTop, height: pxHeight});
|
2494 |
-
},
|
2495 |
-
/*
|
2496 |
-
* Clean freebusys to ensure correct format
|
2497 |
-
*/
|
2498 |
-
_cleanFreeBusys: function(freebusys) {
|
2499 |
-
var self = this,
|
2500 |
-
freeBusyToReturn = [];
|
2501 |
-
if (!$.isArray(freebusys)) {
|
2502 |
-
var freebusys = [freebusys];
|
2503 |
-
}
|
2504 |
-
$.each(freebusys, function(i, freebusy) {
|
2505 |
-
freeBusyToReturn.push(new FreeBusy(self._cleanFreeBusy(freebusy)));
|
2506 |
-
});
|
2507 |
-
return freeBusyToReturn;
|
2508 |
-
},
|
2509 |
-
|
2510 |
-
/*
|
2511 |
-
* Clean specific freebusy
|
2512 |
-
*/
|
2513 |
-
_cleanFreeBusy: function(freebusy) {
|
2514 |
-
if (freebusy.date) {
|
2515 |
-
freebusy.start = freebusy.date;
|
2516 |
-
}
|
2517 |
-
freebusy.start = this._cleanDate(freebusy.start);
|
2518 |
-
freebusy.end = this._cleanDate(freebusy.end);
|
2519 |
-
return freebusy;
|
2520 |
-
},
|
2521 |
-
|
2522 |
-
/**
|
2523 |
-
* retrives the first freebusy manager matching demand.
|
2524 |
-
*/
|
2525 |
-
getFreeBusyManagersFor: function(date, users) {
|
2526 |
-
var calEvent = {
|
2527 |
-
start: date,
|
2528 |
-
end: date
|
2529 |
-
};
|
2530 |
-
this._setEventUserId(calEvent, users);
|
2531 |
-
return this.getFreeBusyManagerForEvent(calEvent);
|
2532 |
-
},
|
2533 |
-
/**
|
2534 |
-
* retrives the first freebusy manager for given event.
|
2535 |
-
*/
|
2536 |
-
getFreeBusyManagerForEvent: function(newCalEvent) {
|
2537 |
-
var self = this,
|
2538 |
-
options = this.options,
|
2539 |
-
freeBusyManager;
|
2540 |
-
if (options.displayFreeBusys) {
|
2541 |
-
var $freeBusyPlaceHoders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
|
2542 |
-
freeBusy = new FreeBusy({start: newCalEvent.start, end: newCalEvent.end}),
|
2543 |
-
showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
|
2544 |
-
userId = showAsSeparatedUser ? self._getEventUserId(newCalEvent) : null;
|
2545 |
-
if (!$.isArray(userId)) {
|
2546 |
-
userId = [userId];
|
2547 |
-
}
|
2548 |
-
$freeBusyPlaceHoders.each(function() {
|
2549 |
-
var manager = $(this).data('wcFreeBusyManager'),
|
2550 |
-
has_overlap = manager.isWithin(freeBusy.getEnd()) ||
|
2551 |
-
manager.isWithin(freeBusy.getEnd()) ||
|
2552 |
-
freeBusy.isWithin(manager.getStart()) ||
|
2553 |
-
freeBusy.isWithin(manager.getEnd());
|
2554 |
-
if (has_overlap && (!showAsSeparatedUser || $.inArray($(this).data('wcUserId'), userId) != -1)) {
|
2555 |
-
freeBusyManager = $(this).data('wcFreeBusyManager');
|
2556 |
-
return false;
|
2557 |
-
}
|
2558 |
-
});
|
2559 |
-
}
|
2560 |
-
return freeBusyManager;
|
2561 |
-
},
|
2562 |
-
/**
|
2563 |
-
* appends the freebusys to replace the old ones.
|
2564 |
-
* @param {array|object} freeBusys freebusy(s) to apply.
|
2565 |
-
*/
|
2566 |
-
updateFreeBusy: function(freeBusys) {
|
2567 |
-
var self = this,
|
2568 |
-
options = this.options;
|
2569 |
-
if (options.displayFreeBusys) {
|
2570 |
-
var $toRender,
|
2571 |
-
$freeBusyPlaceHoders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
|
2572 |
-
_freeBusys = self._cleanFreeBusys(freeBusys);
|
2573 |
-
|
2574 |
-
$.each(_freeBusys, function(index, _freeBusy) {
|
2575 |
-
|
2576 |
-
var $weekdays = self._findWeekDaysForFreeBusy(_freeBusy, $freeBusyPlaceHoders);
|
2577 |
-
//if freebusy has a placeholder
|
2578 |
-
if ($weekdays && $weekdays.length) {
|
2579 |
-
$weekdays.each(function(index, day) {
|
2580 |
-
var manager = $(day).data('wcFreeBusyManager');
|
2581 |
-
manager.insertFreeBusy(_freeBusy);
|
2582 |
-
$(day).data('wcFreeBusyManager', manager);
|
2583 |
-
});
|
2584 |
-
$toRender = $toRender ? $toRender.add($weekdays) : $weekdays;
|
2585 |
-
}
|
2586 |
-
});
|
2587 |
-
self._refreshFreeBusys($toRender);
|
2588 |
-
}
|
2589 |
-
},
|
2590 |
-
|
2591 |
-
/* NEW OPTIONS MANAGEMENT */
|
2592 |
-
|
2593 |
-
/**
|
2594 |
-
* checks wether or not the calendar should be displayed starting on first day of week
|
2595 |
-
*/
|
2596 |
-
_startOnFirstDayOfWeek: function() {
|
2597 |
-
return jQuery.isFunction(this.options.startOnFirstDayOfWeek) ? this.options.startOnFirstDayOfWeek(this.element) : this.options.startOnFirstDayOfWeek;
|
2598 |
-
},
|
2599 |
-
|
2600 |
-
/**
|
2601 |
-
* finds out the current scroll to apply it when changing the view
|
2602 |
-
*/
|
2603 |
-
_getCurrentScrollHour: function() {
|
2604 |
-
var self = this;
|
2605 |
-
var options = this.options;
|
2606 |
-
var $scrollable = this.element.find('.wc-scrollable-grid');
|
2607 |
-
var scroll = $scrollable.scrollTop();
|
2608 |
-
if (self.options.businessHours.limitDisplay) {
|
2609 |
-
scroll = scroll + options.businessHours.start * options.timeslotHeight * options.timeslotsPerHour;
|
2610 |
-
}
|
2611 |
-
return Math.round(scroll / (options.timeslotHeight * options.timeslotsPerHour)) + 1;
|
2612 |
-
},
|
2613 |
-
_getJsonOptions: function() {
|
2614 |
-
if ($.isFunction(this.options.jsonOptions)) {
|
2615 |
-
return $.extend({}, this.options.jsonOptions(this.element));
|
2616 |
-
}
|
2617 |
-
if ($.isPlainObject(this.options.jsonOptions)) {
|
2618 |
-
return $.extend({}, this.options.jsonOptions);
|
2619 |
-
}
|
2620 |
-
return {};
|
2621 |
-
},
|
2622 |
-
_getHeaderDate: function(date) {
|
2623 |
-
var options = this.options;
|
2624 |
-
if (options.getHeaderDate && $.isFunction(options.getHeaderDate))
|
2625 |
-
{
|
2626 |
-
return options.getHeaderDate(date, this.element);
|
2627 |
-
}
|
2628 |
-
var dayName = options.useShortDayNames ? options.shortDays[date.getDay()] : options.longDays[date.getDay()];
|
2629 |
-
return dayName + (options.headerSeparator) + this._formatDate(date, options.dateFormat);
|
2630 |
-
},
|
2631 |
-
|
2632 |
-
|
2633 |
-
|
2634 |
-
/**
|
2635 |
-
* returns corrected date related to DST problem
|
2636 |
-
*/
|
2637 |
-
_getDSTdayShift: function(date, shift) {
|
2638 |
-
var start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0);
|
2639 |
-
var offset1 = start.getTimezoneOffset();
|
2640 |
-
var offset2 = date.getTimezoneOffset();
|
2641 |
-
if (offset1 == offset2)
|
2642 |
-
return date;
|
2643 |
-
shift = shift ? shift : 1;
|
2644 |
-
return new Date(date.getTime() - shift * (offset1 > offset2 ? -1 : 1) * (Math.max(offset1, offset2) - Math.min(offset1, offset2)) * 60000);
|
2645 |
-
},
|
2646 |
-
_needDSTdayShift: function(date1, date2) {
|
2647 |
-
return date1.getTimezoneOffset() != date2.getTimezoneOffset();
|
2648 |
-
}
|
2649 |
-
|
2650 |
-
|
2651 |
-
|
2652 |
-
}; // end of widget function return
|
2653 |
-
})() //end of widget function closure execution
|
2654 |
-
); // end of $.widget("ui.weekCalendar"...
|
2655 |
-
|
2656 |
-
$.extend($.ui.weekCalendar, {
|
2657 |
-
version: '2.0-dev',
|
2658 |
-
updateLayoutOptions: {
|
2659 |
-
startOnFirstDayOfWeek: true,
|
2660 |
-
firstDayOfWeek: true,
|
2661 |
-
daysToShow: true,
|
2662 |
-
displayOddEven: true,
|
2663 |
-
timeFormat: true,
|
2664 |
-
dateFormat: true,
|
2665 |
-
use24Hour: true,
|
2666 |
-
useShortDayNames: true,
|
2667 |
-
businessHours: true,
|
2668 |
-
timeslotHeight: true,
|
2669 |
-
timeslotsPerHour: true,
|
2670 |
-
buttonText: true,
|
2671 |
-
height: true,
|
2672 |
-
shortMonths: true,
|
2673 |
-
longMonths: true,
|
2674 |
-
shortDays: true,
|
2675 |
-
longDays: true,
|
2676 |
-
textSize: true,
|
2677 |
-
users: true,
|
2678 |
-
showAsSeparateUsers: true,
|
2679 |
-
displayFreeBusys: true
|
2680 |
-
}
|
2681 |
-
});
|
2682 |
-
|
2683 |
-
var MILLIS_IN_DAY = 86400000;
|
2684 |
-
var MILLIS_IN_WEEK = MILLIS_IN_DAY * 7;
|
2685 |
-
|
2686 |
-
/* FREE BUSY MANAGERS */
|
2687 |
-
var FreeBusyProto = {
|
2688 |
-
getStart: function() {return this.getOption('start')},
|
2689 |
-
getEnd: function() {return this.getOption('end')},
|
2690 |
-
getOption: function() {
|
2691 |
-
if (!arguments.length) { return this.options }
|
2692 |
-
if (typeof(this.options[arguments[0]]) !== 'undefined') {
|
2693 |
-
return this.options[arguments[0]];
|
2694 |
-
}
|
2695 |
-
else if (typeof(arguments[1]) !== 'undefined') {
|
2696 |
-
return arguments[1];
|
2697 |
-
}
|
2698 |
-
return null;
|
2699 |
-
},
|
2700 |
-
setOption: function(key, value) {
|
2701 |
-
if (arguments.length == 1) {
|
2702 |
-
$.extend(this.options, arguments[0]);
|
2703 |
-
return this;
|
2704 |
-
}
|
2705 |
-
this.options[key] = value;
|
2706 |
-
return this;
|
2707 |
-
},
|
2708 |
-
isWithin: function(dateTime) {return Math.floor(dateTime.getTime() / 1000) >= Math.floor(this.getStart().getTime() / 1000) && Math.floor(dateTime.getTime() / 1000) <= Math.floor(this.getEnd().getTime() / 1000)},
|
2709 |
-
isValid: function() {return this.getStart().getTime() < this.getEnd().getTime()}
|
2710 |
-
};
|
2711 |
-
|
2712 |
-
/**
|
2713 |
-
* @constructor
|
2714 |
-
* single user freebusy manager.
|
2715 |
-
*/
|
2716 |
-
var FreeBusy = function(options) {
|
2717 |
-
this.options = $.extend({}, options || {});
|
2718 |
-
};
|
2719 |
-
$.extend(FreeBusy.prototype, FreeBusyProto);
|
2720 |
-
|
2721 |
-
var FreeBusyManager = function(options) {
|
2722 |
-
this.options = $.extend({
|
2723 |
-
defaultFreeBusy: {}
|
2724 |
-
}, options || {});
|
2725 |
-
this.freeBusys = [];
|
2726 |
-
this.freeBusys.push(new FreeBusy($.extend({
|
2727 |
-
start: this.getStart(),
|
2728 |
-
end: this.getEnd()
|
2729 |
-
}, this.options.defaultFreeBusy)));
|
2730 |
-
};
|
2731 |
-
$.extend(FreeBusyManager.prototype, FreeBusyProto, {
|
2732 |
-
/**
|
2733 |
-
* return matching freeBusys.
|
2734 |
-
* if you do not pass any argument, returns all freebusys.
|
2735 |
-
* if you only pass a start date, only matchinf freebusy will be returned.
|
2736 |
-
* if you pass 2 arguments, then all freebusys available within the time period will be returned
|
2737 |
-
* @param {Date} start [optionnal] if you do not pass end date, will return the freeBusy within which this date falls.
|
2738 |
-
* @param {Date} end [optionnal] the date where to stop the search.
|
2739 |
-
* @return {Array} an array of FreeBusy matching arguments.
|
2740 |
-
*/
|
2741 |
-
getFreeBusys: function() {
|
2742 |
-
switch (arguments.length) {
|
2743 |
-
case 0:
|
2744 |
-
return this.freeBusys;
|
2745 |
-
case 1:
|
2746 |
-
var freeBusy = [];
|
2747 |
-
var start = arguments[0];
|
2748 |
-
if (!this.isWithin(start)) {
|
2749 |
-
return freeBusy;
|
2750 |
-
}
|
2751 |
-
$.each(this.freeBusys, function() {
|
2752 |
-
if (this.isWithin(start)) {
|
2753 |
-
freeBusy.push(this);
|
2754 |
-
}
|
2755 |
-
if (Math.floor(this.getEnd().getTime() / 1000) > Math.floor(start.getTime() / 1000)) {
|
2756 |
-
return false;
|
2757 |
-
}
|
2758 |
-
});
|
2759 |
-
return freeBusy;
|
2760 |
-
default:
|
2761 |
-
//we assume only 2 first args are revealants
|
2762 |
-
var freeBusy = [];
|
2763 |
-
var start = arguments[0], end = arguments[1];
|
2764 |
-
var tmpFreeBusy = new FreeBusy({start: start, end: end});
|
2765 |
-
if (end.getTime() < start.getTime() || this.getStart().getTime() > end.getTime() || this.getEnd().getTime() < start.getTime()) {
|
2766 |
-
return freeBusy;
|
2767 |
-
}
|
2768 |
-
$.each(this.freeBusys, function() {
|
2769 |
-
if (this.getStart().getTime() >= end.getTime()) {
|
2770 |
-
return false;
|
2771 |
-
}
|
2772 |
-
if (tmpFreeBusy.isWithin(this.getStart()) && tmpFreeBusy.isWithin(this.getEnd())) {
|
2773 |
-
freeBusy.push(this);
|
2774 |
-
}
|
2775 |
-
else if (this.isWithin(tmpFreeBusy.getStart()) && this.isWithin(tmpFreeBusy.getEnd())) {
|
2776 |
-
var _f = new FreeBusy(this.getOption());
|
2777 |
-
_f.setOption('end', tmpFreeBusy.getEnd());
|
2778 |
-
_f.setOption('start', tmpFreeBusy.getStart());
|
2779 |
-
freeBusy.push(_f);
|
2780 |
-
}
|
2781 |
-
else if (this.isWithin(tmpFreeBusy.getStart()) && this.getStart().getTime() < start.getTime()) {
|
2782 |
-
var _f = new FreeBusy(this.getOption());
|
2783 |
-
_f.setOption('start', tmpFreeBusy.getStart());
|
2784 |
-
freeBusy.push(_f);
|
2785 |
-
}
|
2786 |
-
else if (this.isWithin(tmpFreeBusy.getEnd()) && this.getEnd().getTime() > end.getTime()) {
|
2787 |
-
var _f = new FreeBusy(this.getOption());
|
2788 |
-
_f.setOption('end', tmpFreeBusy.getEnd());
|
2789 |
-
freeBusy.push(_f);
|
2790 |
-
}
|
2791 |
-
});
|
2792 |
-
return freeBusy;
|
2793 |
-
}
|
2794 |
-
},
|
2795 |
-
insertFreeBusy: function(freeBusy) {
|
2796 |
-
var freeBusy = new FreeBusy(freeBusy.getOption());
|
2797 |
-
//first, if inserted freebusy is bigger than manager
|
2798 |
-
if (freeBusy.getStart().getTime() < this.getStart().getTime()) {
|
2799 |
-
freeBusy.setOption('start', this.getStart());
|
2800 |
-
}
|
2801 |
-
if (freeBusy.getEnd().getTime() > this.getEnd().getTime()) {
|
2802 |
-
freeBusy.setOption('end', this.getEnd());
|
2803 |
-
}
|
2804 |
-
var start = freeBusy.getStart(), end = freeBusy.getEnd(),
|
2805 |
-
startIndex = 0, endIndex = this.freeBusys.length - 1,
|
2806 |
-
newFreeBusys = [];
|
2807 |
-
var pushNewFreeBusy = function(_f) {if (_f.isValid()) newFreeBusys.push(_f);};
|
2808 |
-
|
2809 |
-
$.each(this.freeBusys, function(index) {
|
2810 |
-
//within the loop, we have following vars:
|
2811 |
-
// curFreeBusyItem: the current iteration freeBusy, part of manager freeBusys list
|
2812 |
-
// start: the insterted freeBusy start
|
2813 |
-
// end: the inserted freebusy end
|
2814 |
-
var curFreeBusyItem = this;
|
2815 |
-
if (curFreeBusyItem.isWithin(start) && curFreeBusyItem.isWithin(end)) {
|
2816 |
-
/*
|
2817 |
-
we are in case where inserted freebusy fits in curFreeBusyItem:
|
2818 |
-
curFreeBusyItem: *-----------------------------*
|
2819 |
-
freeBusy: *-------------*
|
2820 |
-
obviously, start and end indexes are this item.
|
2821 |
-
*/
|
2822 |
-
startIndex = index;
|
2823 |
-
endIndex = index;
|
2824 |
-
if (start.getTime() == curFreeBusyItem.getStart().getTime() && end.getTime() == curFreeBusyItem.getEnd().getTime()) {
|
2825 |
-
/*
|
2826 |
-
in this case, inserted freebusy is exactly curFreeBusyItem:
|
2827 |
-
curFreeBusyItem: *-----------------------------*
|
2828 |
-
freeBusy: *-----------------------------*
|
2829 |
-
|
2830 |
-
just replace curFreeBusyItem with freeBusy.
|
2831 |
-
*/
|
2832 |
-
var _f1 = new FreeBusy(freeBusy.getOption());
|
2833 |
-
pushNewFreeBusy(_f1);
|
2834 |
-
}
|
2835 |
-
else if (start.getTime() == curFreeBusyItem.getStart().getTime()) {
|
2836 |
-
/*
|
2837 |
-
in this case inserted freebusy starts with curFreeBusyItem:
|
2838 |
-
curFreeBusyItem: *-----------------------------*
|
2839 |
-
freeBusy: *--------------*
|
2840 |
-
|
2841 |
-
just replace curFreeBusyItem with freeBusy AND the rest.
|
2842 |
-
*/
|
2843 |
-
var _f1 = new FreeBusy(freeBusy.getOption());
|
2844 |
-
var _f2 = new FreeBusy(curFreeBusyItem.getOption());
|
2845 |
-
_f2.setOption('start', end);
|
2846 |
-
pushNewFreeBusy(_f1);
|
2847 |
-
pushNewFreeBusy(_f2);
|
2848 |
-
}
|
2849 |
-
else if (end.getTime() == curFreeBusyItem.getEnd().getTime()) {
|
2850 |
-
/*
|
2851 |
-
in this case inserted freebusy ends with curFreeBusyItem:
|
2852 |
-
curFreeBusyItem: *-----------------------------*
|
2853 |
-
freeBusy: *--------------*
|
2854 |
-
|
2855 |
-
just replace curFreeBusyItem with before part AND freeBusy.
|
2856 |
-
*/
|
2857 |
-
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2858 |
-
_f1.setOption('end', start);
|
2859 |
-
var _f2 = new FreeBusy(freeBusy.getOption());
|
2860 |
-
pushNewFreeBusy(_f1);
|
2861 |
-
pushNewFreeBusy(_f2);
|
2862 |
-
}
|
2863 |
-
else {
|
2864 |
-
/*
|
2865 |
-
in this case inserted freebusy is within curFreeBusyItem:
|
2866 |
-
curFreeBusyItem: *-----------------------------*
|
2867 |
-
freeBusy: *--------------*
|
2868 |
-
|
2869 |
-
just replace curFreeBusyItem with before part AND freeBusy AND the rest.
|
2870 |
-
*/
|
2871 |
-
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2872 |
-
var _f2 = new FreeBusy(freeBusy.getOption());
|
2873 |
-
var _f3 = new FreeBusy(curFreeBusyItem.getOption());
|
2874 |
-
_f1.setOption('end', start);
|
2875 |
-
_f3.setOption('start', end);
|
2876 |
-
pushNewFreeBusy(_f1);
|
2877 |
-
pushNewFreeBusy(_f2);
|
2878 |
-
pushNewFreeBusy(_f3);
|
2879 |
-
}
|
2880 |
-
/*
|
2881 |
-
as work is done, no need to go further.
|
2882 |
-
return false
|
2883 |
-
*/
|
2884 |
-
return false;
|
2885 |
-
}
|
2886 |
-
else if (curFreeBusyItem.isWithin(start) && curFreeBusyItem.getEnd().getTime() != start.getTime()) {
|
2887 |
-
/*
|
2888 |
-
in this case, inserted freebusy starts within curFreeBusyItem:
|
2889 |
-
curFreeBusyItem: *----------*
|
2890 |
-
freeBusy: *-------------------*
|
2891 |
-
|
2892 |
-
set start index AND insert before part, we'll insert freebusy later
|
2893 |
-
*/
|
2894 |
-
if (curFreeBusyItem.getStart().getTime() != start.getTime()) {
|
2895 |
-
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2896 |
-
_f1.setOption('end', start);
|
2897 |
-
pushNewFreeBusy(_f1);
|
2898 |
-
}
|
2899 |
-
startIndex = index;
|
2900 |
-
}
|
2901 |
-
else if (curFreeBusyItem.isWithin(end) && curFreeBusyItem.getStart().getTime() != end.getTime()) {
|
2902 |
-
/*
|
2903 |
-
in this case, inserted freebusy starts within curFreeBusyItem:
|
2904 |
-
curFreeBusyItem: *----------*
|
2905 |
-
freeBusy: *-------------------*
|
2906 |
-
|
2907 |
-
set end index AND insert freebusy AND insert after part if needed
|
2908 |
-
*/
|
2909 |
-
pushNewFreeBusy(new FreeBusy(freeBusy.getOption()));
|
2910 |
-
if (end.getTime() < curFreeBusyItem.getEnd().getTime()) {
|
2911 |
-
var _f1 = new FreeBusy(curFreeBusyItem.getOption());
|
2912 |
-
_f1.setOption('start', end);
|
2913 |
-
pushNewFreeBusy(_f1);
|
2914 |
-
}
|
2915 |
-
endIndex = index;
|
2916 |
-
return false;
|
2917 |
-
}
|
2918 |
-
});
|
2919 |
-
//now compute arguments
|
2920 |
-
var tmpFB = this.freeBusys;
|
2921 |
-
this.freeBusys = [];
|
2922 |
-
|
2923 |
-
if (startIndex) {
|
2924 |
-
this.freeBusys = this.freeBusys.concat(tmpFB.slice(0, startIndex));
|
2925 |
-
}
|
2926 |
-
this.freeBusys = this.freeBusys.concat(newFreeBusys);
|
2927 |
-
if (endIndex < tmpFB.length) {
|
2928 |
-
this.freeBusys = this.freeBusys.concat(tmpFB.slice(endIndex + 1));
|
2929 |
-
}
|
2930 |
-
/* if(start.getDate() == 1){
|
2931 |
-
console.info('insert from '+freeBusy.getStart() +' to '+freeBusy.getEnd());
|
2932 |
-
console.log('index from '+ startIndex + ' to ' + endIndex);
|
2933 |
-
var str = [];
|
2934 |
-
$.each(tmpFB, function(i){str.push(i + ": " + this.getStart().getHours() + ' > ' + this.getEnd().getHours() + ' ' + (this.getOption('free') ? 'free' : 'busy'))});
|
2935 |
-
console.log(str.join('\n'));
|
2936 |
-
|
2937 |
-
console.log('insert');
|
2938 |
-
var str = [];
|
2939 |
-
$.each(newFreeBusys, function(i){str.push(this.getStart().getHours() + ' > ' + this.getEnd().getHours())});
|
2940 |
-
console.log(str.join(', '));
|
2941 |
-
|
2942 |
-
console.log('results');
|
2943 |
-
var str = [];
|
2944 |
-
$.each(this.freeBusys, function(i){str.push(i + ": " + this.getStart().getHours() + ' > ' + this.getEnd().getHours() + ' ' + (this.getOption('free') ? 'free' :'busy'))});
|
2945 |
-
console.log(str.join('\n'));
|
2946 |
-
}*/
|
2947 |
-
return this;
|
2948 |
-
}
|
2949 |
-
});
|
2950 |
-
|
2951 |
-
})(jQuery);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/resources/js/ng-app.js
DELETED
@@ -1,379 +0,0 @@
|
|
1 |
-
;(function() {
|
2 |
-
|
3 |
-
var module = angular.module('appointmentForm', ['ui', 'newCustomerDialog']);
|
4 |
-
|
5 |
-
/**
|
6 |
-
* DataSource service.
|
7 |
-
*/
|
8 |
-
module.factory('dataSource', function($q, $rootScope, $filter) {
|
9 |
-
var ds = {
|
10 |
-
data : {
|
11 |
-
staff : [],
|
12 |
-
customers : [],
|
13 |
-
time : [],
|
14 |
-
time_interval : 900
|
15 |
-
},
|
16 |
-
form : {
|
17 |
-
id : null,
|
18 |
-
staff : null,
|
19 |
-
service : null,
|
20 |
-
date : null,
|
21 |
-
start_time : null,
|
22 |
-
end_time : null,
|
23 |
-
customer : null,
|
24 |
-
notes : null
|
25 |
-
},
|
26 |
-
loadData : function() {
|
27 |
-
var deferred = $q.defer();
|
28 |
-
jQuery.get(
|
29 |
-
ajaxurl,
|
30 |
-
{ action : 'ab_get_data_for_appointment_form' },
|
31 |
-
function(data) {
|
32 |
-
ds.data = data;
|
33 |
-
if (data.staff.length) {
|
34 |
-
ds.form.staff = data.staff[0];
|
35 |
-
}
|
36 |
-
ds.form.start_time = data.time[0];
|
37 |
-
ds.form.end_time = data.time[1];
|
38 |
-
$rootScope.$apply(deferred.resolve);
|
39 |
-
},
|
40 |
-
'json'
|
41 |
-
);
|
42 |
-
return deferred.promise;
|
43 |
-
},
|
44 |
-
findStaff : function(id) {
|
45 |
-
var result = null;
|
46 |
-
jQuery.each(ds.data.staff, function(key, item) {
|
47 |
-
if (item.id == id) {
|
48 |
-
result = item;
|
49 |
-
return false;
|
50 |
-
}
|
51 |
-
});
|
52 |
-
return result;
|
53 |
-
},
|
54 |
-
findService : function(staff_id, id) {
|
55 |
-
var result = null;
|
56 |
-
var staff = ds.findStaff(staff_id);
|
57 |
-
if (staff !== null) {
|
58 |
-
jQuery.each(staff.services, function(key, item) {
|
59 |
-
if (item.id == id) {
|
60 |
-
result = item;
|
61 |
-
return false;
|
62 |
-
}
|
63 |
-
});
|
64 |
-
}
|
65 |
-
return result;
|
66 |
-
},
|
67 |
-
findTime : function(date) {
|
68 |
-
var result = null;
|
69 |
-
var value_to_find = $filter('date')(date, 'HH:mm');
|
70 |
-
jQuery.each(ds.data.time, function(key, item) {
|
71 |
-
if (item.value === value_to_find) {
|
72 |
-
result = item;
|
73 |
-
return false;
|
74 |
-
}
|
75 |
-
});
|
76 |
-
return result;
|
77 |
-
},
|
78 |
-
findCustomer : function(id) {
|
79 |
-
var result = null;
|
80 |
-
jQuery.each(ds.data.customers, function(key, item) {
|
81 |
-
if (item.id == id) {
|
82 |
-
result = item;
|
83 |
-
return false;
|
84 |
-
}
|
85 |
-
});
|
86 |
-
return result;
|
87 |
-
},
|
88 |
-
getDataForEndTime : function() {
|
89 |
-
var result = [];
|
90 |
-
jQuery.each(ds.data.time, function(key, item) {
|
91 |
-
if (
|
92 |
-
ds.form.start_time === null ||
|
93 |
-
item.value > ds.form.start_time.value
|
94 |
-
) {
|
95 |
-
result.push(item);
|
96 |
-
}
|
97 |
-
});
|
98 |
-
return result;
|
99 |
-
},
|
100 |
-
setEndTimeBasedOnService : function() {
|
101 |
-
var i = jQuery.inArray(ds.form.start_time, ds.data.time);
|
102 |
-
var d = ds.form.service ? ds.form.service.duration : ds.data.time_interval;
|
103 |
-
if (i !== -1) {
|
104 |
-
for (; i < ds.data.time.length; ++ i) {
|
105 |
-
d -= ds.data.time_interval;
|
106 |
-
if (d < 0) {
|
107 |
-
break;
|
108 |
-
}
|
109 |
-
}
|
110 |
-
ds.form.end_time = ds.data.time[i];
|
111 |
-
}
|
112 |
-
},
|
113 |
-
getStartAndEndDates : function() {
|
114 |
-
var date = $filter('date')(ds.form.date, 'yyyy-MM-dd');
|
115 |
-
return {
|
116 |
-
start_date : date + ' ' + ds.form.start_time.value,
|
117 |
-
end_date : date + ' ' + ds.form.end_time.value
|
118 |
-
};
|
119 |
-
}
|
120 |
-
};
|
121 |
-
|
122 |
-
return ds;
|
123 |
-
});
|
124 |
-
|
125 |
-
/**
|
126 |
-
* Controller for "create/edit appointment" dialog form.
|
127 |
-
*/
|
128 |
-
module.controller('appointmentDialogCtrl', function($scope, $element, dataSource) {
|
129 |
-
// Set up initial data.
|
130 |
-
$scope.loading = true;
|
131 |
-
$scope.$week_calendar = null;
|
132 |
-
$scope.calendar_mode = 'week';
|
133 |
-
// Set up data source.
|
134 |
-
$scope.dataSource = dataSource;
|
135 |
-
$scope.form = dataSource.form; // shortcut
|
136 |
-
// Populate data source.
|
137 |
-
dataSource.loadData().then(function() {
|
138 |
-
$scope.loading = false;
|
139 |
-
});
|
140 |
-
// Error messages.
|
141 |
-
$scope.errors = {};
|
142 |
-
// Id of the staff whos events are currently being edited/created.
|
143 |
-
var current_staff_id = null;
|
144 |
-
|
145 |
-
/**
|
146 |
-
* Prepare the form for new event.
|
147 |
-
*
|
148 |
-
* @param Date start_date
|
149 |
-
*/
|
150 |
-
$scope.configureNewForm = function(staff_id, start_date) {
|
151 |
-
jQuery.extend($scope.form, {
|
152 |
-
id : null,
|
153 |
-
staff : dataSource.findStaff(staff_id),
|
154 |
-
service : null,
|
155 |
-
date : start_date,
|
156 |
-
start_time : dataSource.findTime(start_date),
|
157 |
-
end_time : null,
|
158 |
-
customer : null,
|
159 |
-
notes : null
|
160 |
-
});
|
161 |
-
$scope.errors = {};
|
162 |
-
dataSource.setEndTimeBasedOnService();
|
163 |
-
current_staff_id = staff_id;
|
164 |
-
};
|
165 |
-
|
166 |
-
/**
|
167 |
-
* Prepare the form for editing event.
|
168 |
-
*/
|
169 |
-
$scope.configureEditForm = function(appointment_id, staff_id, start_date, end_date) {
|
170 |
-
$scope.loading = true;
|
171 |
-
jQuery.post(
|
172 |
-
ajaxurl,
|
173 |
-
{ action : 'ab_get_data_for_appointment', id : appointment_id },
|
174 |
-
function(response) {
|
175 |
-
$scope.$apply(function($scope) {
|
176 |
-
if (response.status === 'ok') {
|
177 |
-
jQuery.extend($scope.form, {
|
178 |
-
id : appointment_id,
|
179 |
-
staff : $scope.dataSource.findStaff(staff_id),
|
180 |
-
service : $scope.dataSource.findService(staff_id, response.data.service_id),
|
181 |
-
date : start_date,
|
182 |
-
start_time : $scope.dataSource.findTime(start_date),
|
183 |
-
end_time : $scope.dataSource.findTime(end_date),
|
184 |
-
customer : $scope.dataSource.findCustomer(response.data.customer_id),
|
185 |
-
notes : response.data.notes
|
186 |
-
});
|
187 |
-
}
|
188 |
-
$scope.loading = false;
|
189 |
-
});
|
190 |
-
},
|
191 |
-
'json'
|
192 |
-
);
|
193 |
-
$scope.errors = {};
|
194 |
-
current_staff_id = staff_id;
|
195 |
-
};
|
196 |
-
|
197 |
-
var checkTimeInterval = function() {
|
198 |
-
var dates = $scope.dataSource.getStartAndEndDates();
|
199 |
-
jQuery.get(
|
200 |
-
ajaxurl,
|
201 |
-
{
|
202 |
-
action : 'ab_check_appointment_date_selection',
|
203 |
-
start_date : dates.start_date,
|
204 |
-
end_date : dates.end_date,
|
205 |
-
appointment_id : $scope.form.id,
|
206 |
-
staff_id : $scope.form.staff ? $scope.form.staff.id : null,
|
207 |
-
service_id : $scope.form.service ? $scope.form.service.id : null
|
208 |
-
},
|
209 |
-
function(response){
|
210 |
-
$scope.$apply(function($scope) {
|
211 |
-
$scope.errors = response;
|
212 |
-
});
|
213 |
-
},
|
214 |
-
'json'
|
215 |
-
);
|
216 |
-
};
|
217 |
-
|
218 |
-
$scope.onServiceChange = function() {
|
219 |
-
$scope.dataSource.setEndTimeBasedOnService();
|
220 |
-
checkTimeInterval();
|
221 |
-
};
|
222 |
-
|
223 |
-
$scope.onStartTimeChange = function() {
|
224 |
-
$scope.dataSource.setEndTimeBasedOnService();
|
225 |
-
checkTimeInterval();
|
226 |
-
};
|
227 |
-
|
228 |
-
$scope.onEndTimeChange = function() {
|
229 |
-
checkTimeInterval();
|
230 |
-
};
|
231 |
-
|
232 |
-
$scope.processForm = function() {
|
233 |
-
$scope.loading = true;
|
234 |
-
var dates = $scope.dataSource.getStartAndEndDates();
|
235 |
-
jQuery.post(
|
236 |
-
ajaxurl,
|
237 |
-
{
|
238 |
-
action : 'ab_save_appointment_form',
|
239 |
-
id : $scope.form.id,
|
240 |
-
staff_id : $scope.form.staff ? $scope.form.staff.id : null,
|
241 |
-
service_id : $scope.form.service ? $scope.form.service.id : null,
|
242 |
-
start_date : dates.start_date,
|
243 |
-
end_date : dates.end_date,
|
244 |
-
customer_id : $scope.form.customer ? $scope.form.customer.id : null,
|
245 |
-
notes : $scope.form.notes
|
246 |
-
},
|
247 |
-
function (response) {
|
248 |
-
$scope.$apply(function($scope) {
|
249 |
-
if (response.status === 'ok') {
|
250 |
-
if ($scope.$week_calendar) {
|
251 |
-
if ($scope.calendar_mode === 'day' || current_staff_id === response.data.userId) {
|
252 |
-
// Update/create event in current calendar when:
|
253 |
-
// - current view mode is "day"
|
254 |
-
// OR
|
255 |
-
// - ID of event owner matches the ID of active staff ("week" mode)
|
256 |
-
$scope.$week_calendar.weekCalendar('updateEvent', response.data);
|
257 |
-
} else {
|
258 |
-
// Else switch to the event owner tab ("week" mode).
|
259 |
-
jQuery('li.ab-staff-tab-' + response.data.userId).click();
|
260 |
-
}
|
261 |
-
}
|
262 |
-
// Close the dialog.
|
263 |
-
$element.dialog('close');
|
264 |
-
} else {
|
265 |
-
$scope.errors = response.errors;
|
266 |
-
}
|
267 |
-
$scope.loading = false;
|
268 |
-
});
|
269 |
-
},
|
270 |
-
'json'
|
271 |
-
);
|
272 |
-
};
|
273 |
-
|
274 |
-
// On 'Cancel' button click.
|
275 |
-
$scope.closeDialog = function() {
|
276 |
-
// Close the dialog.
|
277 |
-
$element.dialog('close');
|
278 |
-
};
|
279 |
-
|
280 |
-
$scope.createCustomer = function(customer) {
|
281 |
-
// Add new customer to the list.
|
282 |
-
n_customer = {id : customer.id, name : customer.name};
|
283 |
-
if (customer.email && customer.phone){
|
284 |
-
n_customer.name += ' (' + customer.email + ', ' + customer.phone + ')';
|
285 |
-
}else if(customer.phone){
|
286 |
-
n_customer.name += ' (' + customer.phone + ')';
|
287 |
-
}else if(customer.email){
|
288 |
-
n_customer.name += ' (' + customer.email + ')';
|
289 |
-
}
|
290 |
-
|
291 |
-
dataSource.data.customers.push(n_customer);
|
292 |
-
// Make it selected.
|
293 |
-
dataSource.form.customer = n_customer;
|
294 |
-
};
|
295 |
-
|
296 |
-
$scope.dateOptions = {
|
297 |
-
dateFormat : 'M, dd yy',
|
298 |
-
dayNamesMin : BooklyL10n['shortDays'],
|
299 |
-
monthNames : BooklyL10n['longMonths'],
|
300 |
-
monthNamesShort : BooklyL10n['shortMonths']
|
301 |
-
};
|
302 |
-
});
|
303 |
-
|
304 |
-
/**
|
305 |
-
* Directive for slide up/down.
|
306 |
-
*/
|
307 |
-
module.directive('mySlideUp', function() {
|
308 |
-
return function(scope, element, attrs) {
|
309 |
-
element.hide();
|
310 |
-
// watch the expression, and update the UI on change.
|
311 |
-
scope.$watch(attrs.mySlideUp, function(value) {
|
312 |
-
if (value) {
|
313 |
-
element.delay(0).slideDown();
|
314 |
-
} else {
|
315 |
-
element.slideUp();
|
316 |
-
}
|
317 |
-
});
|
318 |
-
};
|
319 |
-
});
|
320 |
-
|
321 |
-
module.directive('chosen',function(){
|
322 |
-
var linker = function(scope,element,attrs) {
|
323 |
-
scope.$watch(attrs['chosen'], function() {
|
324 |
-
element.trigger("chosen:updated");
|
325 |
-
});
|
326 |
-
|
327 |
-
scope.$watch(attrs['ngModel'], function() {
|
328 |
-
element.trigger("chosen:updated");
|
329 |
-
});
|
330 |
-
|
331 |
-
element.chosen({
|
332 |
-
search_contains : true,
|
333 |
-
width : '400px'
|
334 |
-
});
|
335 |
-
};
|
336 |
-
|
337 |
-
return {
|
338 |
-
restrict:'A',
|
339 |
-
link: linker
|
340 |
-
}
|
341 |
-
});
|
342 |
-
|
343 |
-
/**
|
344 |
-
* Directive for Popover jQuery plugin.
|
345 |
-
*/
|
346 |
-
module.directive('popover', function() {
|
347 |
-
return function(scope, element, attrs) {
|
348 |
-
element.popover({
|
349 |
-
trigger : 'hover',
|
350 |
-
content : attrs.popover,
|
351 |
-
html : true
|
352 |
-
});
|
353 |
-
};
|
354 |
-
});
|
355 |
-
|
356 |
-
})();
|
357 |
-
|
358 |
-
var showAppointmentDialog = function(appointment_id, staff_id, start_date, end_date, calendar, mode) {
|
359 |
-
var $scope = angular.element(document.getElementById('ab_appointment_dialog')).scope();
|
360 |
-
var title = null;
|
361 |
-
$scope.$apply(function($scope){
|
362 |
-
$scope.$week_calendar = calendar;
|
363 |
-
$scope.calendar_mode = mode;
|
364 |
-
if (appointment_id) {
|
365 |
-
$scope.configureEditForm(appointment_id, staff_id, start_date, end_date);
|
366 |
-
title = BooklyL10n['edit_appointment'];
|
367 |
-
} else {
|
368 |
-
$scope.configureNewForm(staff_id, start_date);
|
369 |
-
title = BooklyL10n['new_appointment'];
|
370 |
-
}
|
371 |
-
});
|
372 |
-
jQuery('#ab_appointment_dialog').dialog({
|
373 |
-
width: 700,
|
374 |
-
position: ['center', 150],
|
375 |
-
modal: true,
|
376 |
-
dialogClass: 'ab-appointment-popup',
|
377 |
-
title: title
|
378 |
-
});
|
379 |
-
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/templates/_appointment_form.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<style>
|
3 |
+
.search-choice { display: none; }
|
4 |
+
</style>
|
5 |
+
<div ng-controller=appointmentDialogCtrl>
|
6 |
+
<div id=ab_appointment_dialog class="modal fade">
|
7 |
+
<div class="modal-dialog">
|
8 |
+
<div ng-show=loading class="modal-content loading-indicator">
|
9 |
+
<div class="modal-body">
|
10 |
+
<span class="ab-loader"></span>
|
11 |
+
</div>
|
12 |
+
</div>
|
13 |
+
<div ng-hide=loading class="modal-content">
|
14 |
+
<form ng-submit=processForm() class=form-horizontal>
|
15 |
+
<div class="modal-header">
|
16 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
17 |
+
<h4 class="modal-title"><?php _e( 'New appointment', 'bookly' ) ?></h4>
|
18 |
+
</div>
|
19 |
+
<div class="modal-body">
|
20 |
+
|
21 |
+
<div style="padding: 0 15px;">
|
22 |
+
<div class=form-group>
|
23 |
+
<label for="ab_provider"><?php _e( 'Provider', 'bookly' ) ?></label>
|
24 |
+
<select id="ab_provider" class="field form-control" ng-model="form.staff" ng-options="s.full_name for s in dataSource.data.staff" ng-change="onStaffChange()"></select>
|
25 |
+
</div>
|
26 |
+
|
27 |
+
<div class=form-group>
|
28 |
+
<label for="ab_service"><?php _e( 'Service', 'bookly' ) ?></label>
|
29 |
+
<div my-slide-up="errors.service_required" style="color: red; margin-top: 5px;">
|
30 |
+
<?php _e( 'Please select a service', 'bookly' ) ?>
|
31 |
+
</div>
|
32 |
+
<select id="ab_service" class="field form-control" ng-model="form.service" ng-options="s.title for s in form.staff.services" ng-change="onServiceChange()">
|
33 |
+
<option value=""><?php _e( '-- Select a service --', 'bookly' ) ?></option>
|
34 |
+
</select>
|
35 |
+
</div>
|
36 |
+
|
37 |
+
<div class=form-group>
|
38 |
+
<label for="ab_date"><?php _e( 'Date', 'bookly' ) ?></label>
|
39 |
+
<input id="ab_date" class="form-control ab-auto-w" type=text ng-model=form.date ui-date="dateOptions" autocomplete="off" />
|
40 |
+
</div>
|
41 |
+
<div class="form-group">
|
42 |
+
<div ng-hide="form.service.duration == 86400">
|
43 |
+
<label for="ab_period"><?php _e( 'Period', 'bookly' ) ?></label>
|
44 |
+
<div>
|
45 |
+
<select id="ab_period" style="display: inline" class="form-control ab-auto-w" ng-model=form.start_time
|
46 |
+
ng-options="t.title for t in dataSource.data.start_time"
|
47 |
+
ng-change=onStartTimeChange()></select>
|
48 |
+
<span> <?php _e( 'to', 'bookly' ) ?> </span>
|
49 |
+
<select style="display: inline" class="form-control ab-auto-w" ng-model=form.end_time
|
50 |
+
ng-options="t.title for t in dataSource.getDataForEndTime()"
|
51 |
+
ng-change=onEndTimeChange()></select>
|
52 |
+
|
53 |
+
<div my-slide-up=errors.date_interval_warning id=date_interval_warning_msg style="color: green; margin-top: 5px;">
|
54 |
+
<?php _e( 'Selected period doesn\'t match service duration', 'bookly' ) ?>
|
55 |
+
</div>
|
56 |
+
<div my-slide-up="errors.time_interval" ng-bind="errors.time_interval" style="color: red; margin-top: 5px;"></div>
|
57 |
+
</div>
|
58 |
+
</div>
|
59 |
+
<div my-slide-up=errors.date_interval_not_available id=date_interval_not_available_msg style="color: red; margin-top: 5px;">
|
60 |
+
<?php _e( 'The selected period is occupied by another appointment', 'bookly' ) ?>
|
61 |
+
</div>
|
62 |
+
</div>
|
63 |
+
|
64 |
+
<div class=form-group>
|
65 |
+
<label>
|
66 |
+
<?php _e( 'Customers', 'bookly' ) ?>
|
67 |
+
<span ng-show="form.service" title="<?php echo esc_attr( __( 'Selected / maximum', 'bookly' ) ) ?>">({{dataSource.getTotalNumberOfPersons()}}/{{form.service.capacity}})</span>
|
68 |
+
</label>
|
69 |
+
<div my-slide-up="errors.customers_required" style="color: red; margin-top: 5px;"><?php _e( 'Please select a customer', 'bookly' ) ?></div>
|
70 |
+
<div my-slide-up="errors.overflow_capacity" ng-bind="errors.overflow_capacity" style="color: red; margin-top: 5px;"></div>
|
71 |
+
<ul class="ab-customer-list">
|
72 |
+
<li ng-repeat="customer in form.customers">
|
73 |
+
{{customer.number_of_persons}}×<i class="glyphicon glyphicon-user"></i>
|
74 |
+
<a ng-click="editCustomFields(customer)" title="<?php echo esc_attr( __( 'Edit booking details', 'bookly' ) ) ?>">{{customer.name}}</a>
|
75 |
+
<span ng-click="removeCustomer(customer)" class="glyphicon glyphicon-remove ab-pointer" title="<?php echo esc_attr( __( 'Remove customer', 'bookly' ) ) ?>"></span>
|
76 |
+
</li>
|
77 |
+
</ul>
|
78 |
+
|
79 |
+
<div ng-show="!form.service || dataSource.getTotalNumberOfPersons() < form.service.capacity">
|
80 |
+
<select id="chosen" multiple data-placeholder="<?php echo esc_attr( __( '-- Search customers --', 'bookly' ) ) ?>"
|
81 |
+
class="field chzn-select form-control" chosen="dataSource.data.customers"
|
82 |
+
ng-model="form.customers" ng-options="c.name for c in dataSource.data.customers">
|
83 |
+
</select><br/>
|
84 |
+
<a href=#ab_new_customer_dialog class="{{btn_class}}" data-backdrop={{backdrop}} data-toggle="modal"><?php _e( 'New customer', 'bookly' ) ?></a>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
|
88 |
+
<div class=form-group>
|
89 |
+
<label></label>
|
90 |
+
<input class="form-control" style="margin-top: 0" type="checkbox" ng-model=form.email_notification /> <?php _e( 'Send email notifications', 'bookly' ) ?>
|
91 |
+
<?php AB_Utils::popover( __( 'If email or SMS notifications are enabled and you want the customer or the staff member to be notified about this appointment after saving, tick this checkbox before clicking Save.', 'bookly' ), 'width:16px;margin-left:0;' ) ?>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
|
95 |
+
</div>
|
96 |
+
<div class="modal-footer">
|
97 |
+
<div class=dialog-button-wrapper>
|
98 |
+
<?php AB_Utils::submitButton() ?>
|
99 |
+
<a ng-click=closeDialog() class=ab-reset-form href="" data-dismiss="modal"><?php _e( 'Cancel', 'bookly' ) ?></a>
|
100 |
+
</div>
|
101 |
+
</div>
|
102 |
+
</form>
|
103 |
+
</div><!-- /.modal-content -->
|
104 |
+
</div><!-- /.modal-dialog -->
|
105 |
+
</div><!-- /.modal -->
|
106 |
+
<div style="margin-bottom: 2px;" class="ab-inline-block ab-create-customer" new-customer-dialog=createCustomer(customer) backdrop=false btn-class=""></div>
|
107 |
+
<?php include '_custom_fields_form.php' ?>
|
108 |
+
</div>
|
backend/modules/calendar/templates/_custom_fields_form.php
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div id="ab_custom_fields_dialog" class="modal fade">
|
3 |
+
<div class="modal-dialog">
|
4 |
+
<div class="modal-content">
|
5 |
+
<div class="modal-header">
|
6 |
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
7 |
+
<h4 class="modal-title"><?php _e( 'Edit booking details', 'bookly' ) ?></h4>
|
8 |
+
</div>
|
9 |
+
<form class="form-horizontal" ng-hide=loading style="z-index: 1050">
|
10 |
+
<div class="modal-body">
|
11 |
+
|
12 |
+
<fieldset>
|
13 |
+
<legend><?php _e( 'Participants', 'bookly' ) ?></legend>
|
14 |
+
<div class="col-md-12">
|
15 |
+
<div class="form-group">
|
16 |
+
<label for="ab-edit-number-of-persons"><?php _e( 'Number of persons', 'bookly' ) ?></label>
|
17 |
+
<select class="ab-custom-field form-control" id="ab-edit-number-of-persons"></select>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
</fieldset>
|
21 |
+
<fieldset>
|
22 |
+
<legend><?php _e( 'Custom Fields', 'bookly' ) ?></legend>
|
23 |
+
<?php foreach ( json_decode( get_option( 'ab_custom_fields' ) ) as $custom_field ): ?>
|
24 |
+
<div class="col-md-12">
|
25 |
+
<div class="form-group">
|
26 |
+
<label class="ab-formLabel"><?php echo $custom_field->label ?></label>
|
27 |
+
<div class="ab-formField" data-type="<?php echo esc_attr( $custom_field->type )?>" data-id="<?php echo esc_attr( $custom_field->id ) ?>">
|
28 |
+
|
29 |
+
<?php if ( $custom_field->type == 'text-field' ): ?>
|
30 |
+
<input type="text" class="ab-custom-field form-control" />
|
31 |
+
|
32 |
+
<?php elseif ( $custom_field->type == 'textarea' ): ?>
|
33 |
+
<textarea rows="3" class="ab-custom-field form-control"></textarea>
|
34 |
+
|
35 |
+
<?php elseif ( $custom_field->type == 'checkboxes' ): ?>
|
36 |
+
<?php foreach ( $custom_field->items as $item ): ?>
|
37 |
+
<div class="checkbox">
|
38 |
+
<label>
|
39 |
+
<input class="ab-custom-field" type="checkbox" value="<?php echo esc_attr( $item ) ?>" />
|
40 |
+
<?php echo $item ?>
|
41 |
+
</label>
|
42 |
+
</div>
|
43 |
+
<?php endforeach ?>
|
44 |
+
|
45 |
+
<?php elseif ( $custom_field->type == 'radio-buttons' ): ?>
|
46 |
+
<?php foreach ( $custom_field->items as $item ): ?>
|
47 |
+
<div class="radio">
|
48 |
+
<label>
|
49 |
+
<input type="radio" name="<?php echo $custom_field->id ?>" class="ab-custom-field" value="<?php echo esc_attr( $item ) ?>" />
|
50 |
+
<?php echo $item ?>
|
51 |
+
</label>
|
52 |
+
</div>
|
53 |
+
<?php endforeach ?>
|
54 |
+
|
55 |
+
<?php elseif ( $custom_field->type == 'drop-down' ): ?>
|
56 |
+
<select class="ab-custom-field form-control">
|
57 |
+
<option value=""></option>
|
58 |
+
<?php foreach ( $custom_field->items as $item ): ?>
|
59 |
+
<option value="<?php echo esc_attr( $item ) ?>"><?php echo $item ?></option>
|
60 |
+
<?php endforeach ?>
|
61 |
+
</select>
|
62 |
+
<?php endif ?>
|
63 |
+
</div>
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
<?php endforeach ?>
|
67 |
+
</fieldset>
|
68 |
+
|
69 |
+
</div>
|
70 |
+
<div class="modal-footer">
|
71 |
+
<input type="button" data-customer="" ng-click=saveCustomFields() class="btn btn-info ab-popup-save" value="<?php _e( 'Apply', 'bookly' ) ?>">
|
72 |
+
<input type="button" class="ab-reset-form" data-dismiss=modal value="<?php _e( 'Cancel', 'bookly' ) ?>" aria-hidden=true>
|
73 |
+
</div>
|
74 |
+
</form>
|
75 |
+
</div><!-- /.modal-content -->
|
76 |
+
</div><!-- /.modal-dialog -->
|
77 |
+
</div><!-- /.modal -->
|
backend/modules/calendar/templates/appointment_form.php
DELETED
@@ -1,93 +0,0 @@
|
|
1 |
-
<div ng-controller=appointmentDialogCtrl id=ab_appointment_dialog style="display: none">
|
2 |
-
|
3 |
-
<div ng-hide=loading class=dialog-content>
|
4 |
-
<form ng-submit=processForm() class=form-horizontal>
|
5 |
-
|
6 |
-
<div class=control-group>
|
7 |
-
<label class=control-label><?php _e('Provider', 'ab') ?></label>
|
8 |
-
<div class=controls>
|
9 |
-
<select class="field" ng-model=form.staff ng-options="s.full_name for s in dataSource.data.staff"></select>
|
10 |
-
</div>
|
11 |
-
</div>
|
12 |
-
|
13 |
-
<div class=control-group>
|
14 |
-
<label class=control-label><?php _e('Service', 'ab') ?></label>
|
15 |
-
<div class=controls>
|
16 |
-
<select class="field" ng-model=form.service ng-options="s.title for s in form.staff.services" ng-change=onServiceChange()>
|
17 |
-
<option value=""><?php _e('-- Select a service --', 'ab') ?></option>
|
18 |
-
</select>
|
19 |
-
</div>
|
20 |
-
</div>
|
21 |
-
|
22 |
-
<div class=control-group>
|
23 |
-
<label class=control-label><?php _e('Date', 'ab') ?></label>
|
24 |
-
<div class=controls>
|
25 |
-
<input class="field" type=text ng-model=form.date ui-date="dateOptions" />
|
26 |
-
</div>
|
27 |
-
</div>
|
28 |
-
|
29 |
-
<div class=control-group>
|
30 |
-
<label class=control-label><?php _e('Period', 'ab') ?></label>
|
31 |
-
<div class=controls>
|
32 |
-
<div my-slide-up=errors.date_interval_not_available id=date_interval_not_available_msg>
|
33 |
-
<?php _e( 'The selected period is occupied by another appointment!', 'ab' ) ?>
|
34 |
-
</div>
|
35 |
-
<select class="field-col-2" ng-model=form.start_time ng-options="t.title for t in dataSource.data.time" ng-change=onStartTimeChange()></select>
|
36 |
-
<span><?php _e( ' to ', 'ab' ) ?></span>
|
37 |
-
<select class="field-col-2" ng-model=form.end_time ng-options="t.title for t in dataSource.getDataForEndTime()" ng-change=onEndTimeChange()></select>
|
38 |
-
<div my-slide-up=errors.date_interval_warning id=date_interval_warning_msg>
|
39 |
-
<?php _e( 'The selected period does\'t match default duration for the selected service!', 'ab' ) ?>
|
40 |
-
</div>
|
41 |
-
</div>
|
42 |
-
</div>
|
43 |
-
|
44 |
-
<div class=control-group>
|
45 |
-
<label class=control-label><?php _e('Customer', 'ab') ?></label>
|
46 |
-
<div class=controls>
|
47 |
-
<select class="field" data-placeholder="<?php _e('-- Select a customer --', 'ab') ?>" class="chzn-select" chosen="dataSource.data.customers"
|
48 |
-
ng-model="form.customer" ng-options="c.name for c in dataSource.data.customers">
|
49 |
-
</select>
|
50 |
-
<div new-customer-dialog=createCustomer(customer) backdrop=false btn-class=""></div>
|
51 |
-
</div>
|
52 |
-
</div>
|
53 |
-
|
54 |
-
<div class=control-group>
|
55 |
-
<label class=control-label><?php _e('Notes', 'ab') ?></label>
|
56 |
-
<div class=controls>
|
57 |
-
<textarea class="field" ng-model=form.notes></textarea>
|
58 |
-
</div>
|
59 |
-
</div>
|
60 |
-
|
61 |
-
<div class=control-group>
|
62 |
-
<label class=control-label></label>
|
63 |
-
<div class=controls>
|
64 |
-
<input style="margin-top: 0" type="checkbox" id="email_notification" /> <?php _e('Send email notifications', 'ab') ?>
|
65 |
-
<img
|
66 |
-
src="<?php echo plugins_url( 'resources/images/help.png', dirname(__FILE__).'/../../../AB_Backend.php' ) ?>"
|
67 |
-
alt=""
|
68 |
-
class="ab-help-info"
|
69 |
-
popover="<?php echo esc_attr(__('If email notifications are enabled and you want the customer or the staff member to be notified about this appointment after saving, tick this checkbox before clicking Save.', 'ab')) ?>"
|
70 |
-
style="width:16px;margin-left:0;"
|
71 |
-
/>
|
72 |
-
<div id="email_notification_text" style="display: none; margin-top: 10px;"><?php _e('This function is disabled in the light verison of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $35 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here'); ?>: <a href="http://bookly.ladela.com" target="_blank">http://bookly.ladela.com</a></div>
|
73 |
-
</div>
|
74 |
-
</div>
|
75 |
-
|
76 |
-
<div class=control-group>
|
77 |
-
<label class=control-label></label>
|
78 |
-
<div class=controls>
|
79 |
-
<div class=dialog-button-wrapper>
|
80 |
-
<input type=submit class="btn btn-info ab-update-button" value="<?php _e('Save') ?>" />
|
81 |
-
<a ng-click=closeDialog() class=ab-reset-form href=""><?php _e('Cancel') ?></a>
|
82 |
-
</div>
|
83 |
-
</div>
|
84 |
-
</div>
|
85 |
-
|
86 |
-
</form>
|
87 |
-
</div>
|
88 |
-
|
89 |
-
<div ng-show=loading class=loading-indicator>
|
90 |
-
<img src="<?php echo plugins_url('resources/images/ajax_loader_32x32.gif', dirname(__FILE__) . '/../../../AB_Backend.php') ?>" alt="" />
|
91 |
-
</div>
|
92 |
-
|
93 |
-
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/calendar/templates/calendar.php
CHANGED
@@ -1,127 +1,62 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
|
4 |
-
$week_start_day = get_option('start_of_week', 1);
|
5 |
?>
|
6 |
-
<
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
<li><a href="#" class="ab-week-picker-arrow-prev">◄</a></li>
|
27 |
-
<li><a style="padding: 0" href="#"></a></li>
|
28 |
-
</ul>
|
29 |
-
</div>
|
30 |
-
<div class="input-append left" style="margin-right:-1px">
|
31 |
-
<input style="width:131px;margin-left:-2px;border-radius:0" class="span2" id="appendedInput" size="16" type="text" value="" /><span style="border-radius:0" class="add-on col-arrow">▼</span>
|
32 |
-
</div>
|
33 |
-
<div class="pagination left">
|
34 |
-
<ul>
|
35 |
-
<?php for ( $i = 1; $i <= 7; ++ $i ) : ?>
|
36 |
-
<li>
|
37 |
-
<a href="#" class="ab-day-of-month" <?php if ( 1 == $i ) : ?> style="border-radius:0"<?php endif; ?>></a>
|
38 |
</li>
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
</div>
|
43 |
-
|
44 |
-
<!--div class="btn-group right right-margin">
|
45 |
-
<a class="btn btn-info" href="#"><i class="icon-user icon-white"></i><?php _e(' All services','ab') ?></a>
|
46 |
-
<a class="btn btn-info dropdown-toggle" data-toggle="dropdown" href="#"><span class="caret"></span></a>
|
47 |
-
<ul class="dropdown-menu">
|
48 |
-
<li>
|
49 |
-
<a href="javascript:void(0)">
|
50 |
-
<input style="margin-right: 5px;" type="checkbox" id="" class="all-staff left">
|
51 |
-
<label for=""><?php _e('All staff','ab') ?></label>
|
52 |
-
</a>
|
53 |
-
</li>
|
54 |
-
</ul>
|
55 |
-
</div-->
|
56 |
-
<div class="btn-group pull-right">
|
57 |
-
<a class="btn btn-info ab-staff-filter-button" href="javascript:void(0)">
|
58 |
-
<i class="icon-user icon-white"></i>
|
59 |
-
<span id="ab-staff-button">
|
60 |
-
<?php
|
61 |
-
$staff_numb = count($collection);
|
62 |
-
if ($staff_numb == 0) {
|
63 |
-
_e(' No staff selected','ab');
|
64 |
-
} else if ($staff_numb == 1) {
|
65 |
-
echo $collection[0]->full_name;
|
66 |
-
} else {
|
67 |
-
echo $staff_numb . ' '. __('staff members','ab');
|
68 |
-
}
|
69 |
-
?>
|
70 |
-
</span>
|
71 |
-
</a>
|
72 |
-
<a class="btn btn-info dropdown-toggle ab-staff-filter-button" href="javascript:void(0)"><span class="caret"></span></a>
|
73 |
-
<ul class="dropdown-menu pull-right">
|
74 |
-
<li>
|
75 |
-
<a href="javascript:void(0)">
|
76 |
-
<input style="margin-right: 5px;" type="checkbox" checked="checked" id="ab-filter-all-staff" class="left">
|
77 |
-
<label for="ab-filter-all-staff"><?php _e('All staff','ab') ?></label>
|
78 |
-
</a>
|
79 |
-
<?php foreach ($collection as $staff) : ?>
|
80 |
-
<a style="padding-left: 35px;" href="javascript:void(0)">
|
81 |
-
<input style="margin-right: 5px;" type="checkbox" checked="checked" id="ab-filter-staff-<?php echo $staff->id ?>" value="<?php echo $staff->id ?>" class="ab-staff-option left">
|
82 |
-
<label style="padding-right: 15px;" for="ab-filter-staff-<?php echo $staff->id ?>"><?php echo $staff->full_name ?></label>
|
83 |
-
</a>
|
84 |
-
<?php endforeach ?>
|
85 |
-
</li>
|
86 |
-
</ul>
|
87 |
-
</div>
|
88 |
</div>
|
89 |
</div>
|
90 |
-
<?php if ( $collection ) : ?>
|
91 |
-
<?php
|
92 |
-
$user_names = array();
|
93 |
-
$user_ids = array();
|
94 |
-
?>
|
95 |
-
<div id="week_calendar_wrapper">
|
96 |
-
<div class="tabbable" style="margin-top: 20px;">
|
97 |
-
<ul class="nav nav-tabs" style="margin-bottom:0;border-bottom: 6px solid #1f6a8c">
|
98 |
-
<?php foreach ($collection as $i => $staff) : ?>
|
99 |
-
<li class="ab-staff-tab-<?php echo $staff->id ?> ab-calendar-tab<?php echo 0 == $i ? ' active' : '' ?>" data-staff-id="<?php echo $staff->id ?>">
|
100 |
-
<a href="#" data-toggle="tab"><?php echo $staff->full_name ?></a>
|
101 |
-
</li>
|
102 |
-
<?php
|
103 |
-
$user_names[] = $staff->full_name;
|
104 |
-
$user_ids[] = $staff->id;
|
105 |
-
?>
|
106 |
-
<?php endforeach ?>
|
107 |
-
</ul>
|
108 |
-
</div>
|
109 |
-
<div class="ab-calendar-element-container">
|
110 |
-
<div class="ab-calendar-element"></div>
|
111 |
-
</div>
|
112 |
-
</div>
|
113 |
-
<div id="day_calendar_wrapper" style="display: none">
|
114 |
-
<div class="ab-calendar-element-container">
|
115 |
-
<div class="ab-calendar-element"></div>
|
116 |
-
</div>
|
117 |
-
</div>
|
118 |
-
<?php include 'appointment_form.php' ?>
|
119 |
-
</div>
|
120 |
-
<span id="staff_ids" style="display: none"><?php echo json_encode($user_ids) ?></span>
|
121 |
-
<span id="ab_calendar_data_holder" style="display: none">
|
122 |
-
<span class="ab-calendar-first-day"><?php echo $week_start_day ?></span>
|
123 |
-
<span class="ab-calendar-time-format"><?php echo get_option( 'time_format' ) ?></span>
|
124 |
-
<span class="ab-calendar-users"><?php echo implode( '|', $user_names ) ?></span>
|
125 |
-
</span>
|
126 |
-
<?php endif; ?>
|
127 |
</div>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
$user_names = array();
|
3 |
+
$user_ids = array();
|
|
|
4 |
?>
|
5 |
+
<style>
|
6 |
+
.fc-slats tr { height: <?php echo max( 21, intval( 620 / (1440 / get_option( 'ab_settings_time_slot_length' ) ) ) ) ?>px; }
|
7 |
+
</style>
|
8 |
+
<div class="panel panel-default">
|
9 |
+
<div class="panel-heading">
|
10 |
+
<h3 class="panel-title"><?php _e( 'Calendar', 'bookly' ) ?></h3>
|
11 |
+
</div>
|
12 |
+
<div class="ab-calendar-inner panel-body">
|
13 |
+
<div ng-app=appointmentForm>
|
14 |
+
<div id="full_calendar_wrapper">
|
15 |
+
<div class="tabbable" style="margin-bottom: 15px;">
|
16 |
+
<ul class="nav nav-tabs" style="margin-bottom:0;border-bottom: 6px solid #1f6a8c">
|
17 |
+
<?php foreach ( $staff_members as $i => $staff ) : ?>
|
18 |
+
<li class="ab-calendar-tab" data-staff_id="<?php echo $staff->id ?>" style="display: none">
|
19 |
+
<a href="#" data-toggle="tab"><?php echo $staff->full_name ?></a>
|
20 |
+
</li>
|
21 |
+
<?php endforeach ?>
|
22 |
+
<?php if( AB_Utils::isCurrentUserAdmin() ): ?>
|
23 |
+
<li class="ab-calendar-tab" data-staff_id="0">
|
24 |
+
<a href="#" data-toggle="tab"><?php _e( 'All', 'bookly' ) ?></a>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
</li>
|
26 |
+
<li class="pull-right">
|
27 |
+
<div class="btn-group pull-right">
|
28 |
+
<button class="btn btn-info ab-staff-filter-button" data-toggle="dropdown">
|
29 |
+
<i class="glyphicon glyphicon-user"></i>
|
30 |
+
<span id="ab-staff-button"></span>
|
31 |
+
</button>
|
32 |
+
<button class="btn btn-info dropdown-toggle ab-staff-filter-button" data-toggle="dropdown"><span class="caret"></span></button>
|
33 |
+
<ul class="dropdown-menu pull-right">
|
34 |
+
<li>
|
35 |
+
<a href="javascript:void(0)">
|
36 |
+
<input style="margin-right: 5px;" type="checkbox" id="ab-filter-all-staff" class="left">
|
37 |
+
<label for="ab-filter-all-staff"><?php _e( 'All staff', 'bookly' ) ?></label>
|
38 |
+
</a>
|
39 |
+
<?php foreach ( $staff_members as $i => $staff ): ?>
|
40 |
+
<a style="padding-left: 35px;" href="javascript:void(0)">
|
41 |
+
<input style="margin-right: 5px;" type="checkbox" id="ab-filter-staff-<?php echo $staff->id ?>" value="<?php echo $staff->id ?>" data-staff_name="<?php echo esc_attr( $staff->full_name ) ?>" class="ab-staff-filter left" />
|
42 |
+
<label style="padding-right: 15px;" for="ab-filter-staff-<?php echo $staff->id ?>"><?php echo $staff->full_name ?></label>
|
43 |
+
</a>
|
44 |
+
<?php endforeach ?>
|
45 |
+
</li>
|
46 |
+
</ul>
|
47 |
+
</div>
|
48 |
+
</li>
|
49 |
+
<?php endif ?>
|
50 |
+
</ul>
|
51 |
+
</div>
|
52 |
+
<div class="table-responsive">
|
53 |
+
<div class="ab-loading-inner" style="display: none">
|
54 |
+
<span class="ab-loader"></span>
|
55 |
+
</div>
|
56 |
+
<div class="ab-calendar-element"></div>
|
57 |
+
</div>
|
58 |
</div>
|
59 |
+
<?php include '_appointment_form.php' ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
</div>
|
61 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
</div>
|
backend/modules/coupons/AB_CouponsController.php
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class AB_CouponsController
|
5 |
+
*/
|
6 |
+
class AB_CouponsController extends AB_Controller {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Default action
|
10 |
+
*/
|
11 |
+
public function index()
|
12 |
+
{
|
13 |
+
$this->enqueueStyles( array(
|
14 |
+
'backend' => array(
|
15 |
+
'css/bookly.main-backend.css',
|
16 |
+
'bootstrap/css/bootstrap.min.css',
|
17 |
+
),
|
18 |
+
'module' => array(
|
19 |
+
'css/coupons.css',
|
20 |
+
)
|
21 |
+
) );
|
22 |
+
|
23 |
+
$this->enqueueScripts( array(
|
24 |
+
'backend' => array(
|
25 |
+
'js/ab_popup.js' => array( 'jquery' ),
|
26 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
27 |
+
),
|
28 |
+
'module' => array(
|
29 |
+
'js/coupons.js' => array( 'jquery' ),
|
30 |
+
)
|
31 |
+
) );
|
32 |
+
|
33 |
+
wp_localize_script( 'ab-coupons.js', 'BooklyL10n', array(
|
34 |
+
'are_you_sure' => __( 'Are you sure?', 'bookly' ),
|
35 |
+
'please_select_at_least_one_coupon' => __( 'Please select at least one coupon.', 'bookly' ),
|
36 |
+
) );
|
37 |
+
|
38 |
+
$this->coupons_collection = false;
|
39 |
+
|
40 |
+
$this->render( 'index' );
|
41 |
+
}
|
42 |
+
|
43 |
+
}
|
backend/modules/coupons/resources/css/coupons.css
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#ab_coupons_wrapper .list-wrapper .list-actions { overflow: hidden; margin-top: 10px; }
|
2 |
+
#ab_coupons_wrapper .list-wrapper .list-actions .add-service { float: left }
|
3 |
+
#ab_coupons_wrapper .list-wrapper .list-actions .delete { float: right }
|
4 |
+
#coupons_list td.last,
|
5 |
+
#coupons_list th.last { width: 16px; vertical-align: middle; }
|
6 |
+
#coupons_list th, #coupons_list td { padding:5px }
|
7 |
+
#coupons_list .service-color-cell { width: 28px; }
|
8 |
+
|
9 |
+
#ab-coupons-list .displayed-value { border: 1px solid transparent; padding: 4px 12px; min-height: 20px; }
|
10 |
+
#ab-coupons-list .ab-text-focus,
|
11 |
+
#ab-coupons-list .ab-text-focus:focus { text-align: right; padding-right: 2px; width: 58px; margin: 0!important; height: 30px; }
|
12 |
+
#ab-coupons-list .displayed-value:hover {
|
13 |
+
border: 1px solid #aaa;
|
14 |
+
background: #fff;
|
15 |
+
border-radius: 3px;
|
16 |
+
-webkit-box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
|
17 |
+
-moz-box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
|
18 |
+
-o-box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
|
19 |
+
box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
|
20 |
+
}
|
backend/modules/coupons/resources/js/coupons.js
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function($) {
|
2 |
+
$('.add-coupon, .delete').on('click', function(){
|
3 |
+
$('#lite_notice').modal('show');
|
4 |
+
});
|
5 |
+
});
|
backend/modules/coupons/templates/_list.php
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="alert alert-warning" >
|
3 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
4 |
+
</div>
|
backend/modules/coupons/templates/index.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
|
3 |
+
<div id="ab_coupons_wrapper" class="panel panel-default">
|
4 |
+
<div class="panel-heading">
|
5 |
+
<h3 class="panel-title"><?php _e( 'Coupons', 'bookly' ) ?></h3>
|
6 |
+
</div>
|
7 |
+
<div class="panel-body">
|
8 |
+
<div class="list-wrapper">
|
9 |
+
<div id="ab-coupons-list">
|
10 |
+
<?php include '_list.php' ?>
|
11 |
+
</div>
|
12 |
+
</div>
|
13 |
+
</div>
|
14 |
+
<div class="panel-footer">
|
15 |
+
<div class="list-actions">
|
16 |
+
<a class="add-coupon btn btn-info" href="#"><?php _e( 'Add Coupon', 'bookly' ) ?></a>
|
17 |
+
<a class="delete btn btn-info" href="#"><?php _e( 'Delete', 'bookly' ) ?></a>
|
18 |
+
</div>
|
19 |
+
</div>
|
20 |
+
</div>
|
21 |
+
<div class="modal fade" id="lite_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
22 |
+
<div class="modal-dialog">
|
23 |
+
<div class="modal-content">
|
24 |
+
<div class="modal-header">
|
25 |
+
<h4 class="modal-title"><?php _e('Notice', 'bookly') ?></h4>
|
26 |
+
</div>
|
27 |
+
<div class="modal-body">
|
28 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
29 |
+
</div>
|
30 |
+
<div class="modal-footer">
|
31 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php _e('Close', 'bookly') ?></button>
|
32 |
+
</div>
|
33 |
+
</div><!-- /.modal-content -->
|
34 |
+
</div><!-- /.modal-dialog -->
|
35 |
+
</div><!-- /.modal -->
|
backend/modules/custom_fields/AB_CustomFieldsController.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class AB_CustomFieldsController
|
5 |
+
*/
|
6 |
+
class AB_CustomFieldsController extends AB_Controller {
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Default Action
|
10 |
+
*/
|
11 |
+
public function index()
|
12 |
+
{
|
13 |
+
$this->enqueueStyles( array(
|
14 |
+
'module' => array(
|
15 |
+
'css/custom_fields.css'
|
16 |
+
),
|
17 |
+
'frontend' => array(
|
18 |
+
'css/ladda.min.css'
|
19 |
+
),
|
20 |
+
'backend' => array(
|
21 |
+
'css/bookly.main-backend.css',
|
22 |
+
'bootstrap/css/bootstrap.min.css',
|
23 |
+
)
|
24 |
+
) );
|
25 |
+
|
26 |
+
$this->enqueueScripts( array(
|
27 |
+
'module' => array(
|
28 |
+
'js/custom_fields.js' => array( 'jquery-ui-sortable' )
|
29 |
+
),
|
30 |
+
'frontend' => array(
|
31 |
+
'js/spin.min.js' => array( 'jquery' ),
|
32 |
+
'js/ladda.min.js' => array( 'jquery' ),
|
33 |
+
)
|
34 |
+
) );
|
35 |
+
|
36 |
+
wp_localize_script( 'ab-custom_fields.js', 'BooklyL10n', array(
|
37 |
+
'custom_fields' => get_option( 'ab_custom_fields' )
|
38 |
+
) );
|
39 |
+
|
40 |
+
$this->render( 'index' );
|
41 |
+
} // index
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Save custom fields.
|
45 |
+
*/
|
46 |
+
public function executeSaveCustomFields()
|
47 |
+
{
|
48 |
+
update_option( 'ab_custom_fields', $this->getParameter( 'fields' ) );
|
49 |
+
|
50 |
+
wp_send_json_success();
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Override parent method to add 'wp_ajax_ab_' prefix
|
55 |
+
* so current 'execute*' methods look nicer.
|
56 |
+
*
|
57 |
+
* @param string $prefix
|
58 |
+
*/
|
59 |
+
protected function registerWpActions( $prefix = '' )
|
60 |
+
{
|
61 |
+
parent::registerWpActions( 'wp_ajax_ab_' );
|
62 |
+
}
|
63 |
+
}
|
backend/modules/custom_fields/resources/css/custom_fields.css
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
ul#ab-custom-fields {
|
2 |
+
list-style-type: none;
|
3 |
+
margin: 0 0 15px 0;
|
4 |
+
padding: 0;
|
5 |
+
}
|
6 |
+
ul#ab-custom-fields .input-group { margin-left: 15px; }
|
7 |
+
ul#ab-custom-fields > li {
|
8 |
+
margin: 0 0 10px;
|
9 |
+
padding: 15px 20px;
|
10 |
+
background: #fff;
|
11 |
+
border: 1px solid #ddd;
|
12 |
+
}
|
13 |
+
ul#ab-custom-fields > li .ab-field-title {
|
14 |
+
font-size: 16px;
|
15 |
+
font-weight: normal;
|
16 |
+
margin: 2px 0px 13px 0px;
|
17 |
+
line-height: normal;
|
18 |
+
}
|
19 |
+
ul#ab-custom-fields > li input[type=text] {
|
20 |
+
margin-bottom: 0;
|
21 |
+
width: 300px;
|
22 |
+
}
|
23 |
+
ul#ab-custom-fields > li input.ab-label {
|
24 |
+
width: 322px;
|
25 |
+
}
|
26 |
+
ul#ab-custom-fields > li .input-group {
|
27 |
+
margin-bottom: 0;
|
28 |
+
}
|
29 |
+
ul#ab-custom-fields > li .ab-required {
|
30 |
+
margin: -2px 0 0 0;
|
31 |
+
border-radius: 0;
|
32 |
+
-webkit-border-radius: 0;
|
33 |
+
}
|
34 |
+
ul#ab-custom-fields > li span.input-group-addon {
|
35 |
+
width: auto;
|
36 |
+
}
|
37 |
+
ul#ab-custom-fields > li span.input-group-addon label {
|
38 |
+
margin: 0;
|
39 |
+
}
|
40 |
+
ul#ab-custom-fields > li span.input-group-addon span {
|
41 |
+
display: inline-block;
|
42 |
+
position: relative;
|
43 |
+
top: 1px;
|
44 |
+
font-size: 13px;
|
45 |
+
}
|
46 |
+
ul#ab-custom-fields > li button {
|
47 |
+
margin-left: 37px;
|
48 |
+
}
|
49 |
+
ul#ab-custom-fields > li i.ab-handle{
|
50 |
+
display: block;
|
51 |
+
float: left;
|
52 |
+
margin: 0 8px 0 -8px;
|
53 |
+
line-height: 20px;
|
54 |
+
text-align: center;
|
55 |
+
cursor: move;
|
56 |
+
}
|
57 |
+
ul#ab-custom-fields > li i.ab-inner-handle {
|
58 |
+
float: left;
|
59 |
+
margin: 10px 8px 0 0;
|
60 |
+
cursor: move;
|
61 |
+
}
|
62 |
+
ul#ab-custom-fields ul.ab-items {
|
63 |
+
margin: 0 0 15px 0;
|
64 |
+
}
|
65 |
+
ul#ab-custom-fields ul.ab-items > li {
|
66 |
+
margin: 0;
|
67 |
+
padding: 15px 15px 0 15px;
|
68 |
+
background: transparent;
|
69 |
+
}
|
70 |
+
ul#ab-custom-fields li .ab-delete {
|
71 |
+
cursor: pointer;
|
72 |
+
}
|
73 |
+
#ab-add-fields { margin-bottom: 15px; }
|
74 |
+
|
75 |
+
@media screen and (max-width: 782px) {
|
76 |
+
ul#ab-custom-fields > li .ab-required {
|
77 |
+
height: 16px;
|
78 |
+
width: 16px;
|
79 |
+
}
|
80 |
+
ul#ab-custom-fields > li input[type=text] {
|
81 |
+
width: 127px;
|
82 |
+
}
|
83 |
+
ul#ab-custom-fields > li input.ab-label {
|
84 |
+
width: 150px;
|
85 |
+
}
|
86 |
+
}
|
backend/modules/custom_fields/resources/js/custom_fields.js
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function($) {
|
2 |
+
|
3 |
+
var $fields = $("ul#ab-custom-fields");
|
4 |
+
|
5 |
+
$fields.sortable({
|
6 |
+
axis : 'y',
|
7 |
+
handle : '.ab-handle'
|
8 |
+
});
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Build initial fields.
|
12 |
+
*/
|
13 |
+
restoreFields();
|
14 |
+
|
15 |
+
/**
|
16 |
+
* On "Add new field" button click.
|
17 |
+
*/
|
18 |
+
$('#ab-add-fields').on('click', 'button', function() {
|
19 |
+
addField($(this).data('type'));
|
20 |
+
});
|
21 |
+
|
22 |
+
/**
|
23 |
+
* On "Add new item" button click.
|
24 |
+
*/
|
25 |
+
$fields.on('click', 'button', function() {
|
26 |
+
addItem($(this).prev('ul'), $(this).data('type'));
|
27 |
+
});
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Delete field or checkbox/radio button/drop-down option.
|
31 |
+
*/
|
32 |
+
$fields.on('click', '.ab-delete', function() {
|
33 |
+
$(this).closest('li').fadeOut('fast', function() { $(this).remove(); });
|
34 |
+
});
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Submit custom fields form.
|
38 |
+
*/
|
39 |
+
$('#ajax-send-custom-fields').on('click', function(e) {
|
40 |
+
e.preventDefault();
|
41 |
+
var data = [];
|
42 |
+
$fields.children('li').each(function() {
|
43 |
+
var $this = $(this);
|
44 |
+
var field = {};
|
45 |
+
switch ($this.data('type')) {
|
46 |
+
case 'checkboxes':
|
47 |
+
case 'radio-buttons':
|
48 |
+
case 'drop-down':
|
49 |
+
field.items = [];
|
50 |
+
$this.find('li').each(function() {
|
51 |
+
field.items.push($(this).find('input').val());
|
52 |
+
});
|
53 |
+
case 'text-field':
|
54 |
+
case 'textarea':
|
55 |
+
field.type = $this.data('type');
|
56 |
+
field.label = $this.find('.ab-label').val();
|
57 |
+
field.required = $this.find('.ab-required').prop('checked');
|
58 |
+
field.id = $this.data('ab-field-id');
|
59 |
+
}
|
60 |
+
data.push(field);
|
61 |
+
});
|
62 |
+
|
63 |
+
var ladda = Ladda.create(this);
|
64 |
+
ladda.start();
|
65 |
+
$.ajax({
|
66 |
+
type : 'POST',
|
67 |
+
url : ajaxurl,
|
68 |
+
xhrFields : { withCredentials: true },
|
69 |
+
data : { action: 'ab_save_custom_fields', fields: JSON.stringify(data) },
|
70 |
+
complete : function() {
|
71 |
+
ladda.stop();
|
72 |
+
}
|
73 |
+
});
|
74 |
+
});
|
75 |
+
|
76 |
+
/**
|
77 |
+
* On 'Reset' click.
|
78 |
+
*/
|
79 |
+
$('button[type=reset]').on('click', function() {
|
80 |
+
$fields.empty();
|
81 |
+
restoreFields();
|
82 |
+
});
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Add new field.
|
86 |
+
*
|
87 |
+
* @param type
|
88 |
+
* @param id
|
89 |
+
* @param label
|
90 |
+
* @param required
|
91 |
+
* @return {*|jQuery}
|
92 |
+
*/
|
93 |
+
function addField(type, id, label, required) {
|
94 |
+
var $new_field = $('ul#ab-templates > li[data-type=' + type + ']').clone();
|
95 |
+
// Set id, label and required.
|
96 |
+
if (typeof id == 'undefined') {
|
97 |
+
id = Math.floor((Math.random() * 100000) + 1);
|
98 |
+
}
|
99 |
+
if (typeof label == 'undefined') {
|
100 |
+
label = '';
|
101 |
+
}
|
102 |
+
if (typeof required == 'undefined') {
|
103 |
+
required = false;
|
104 |
+
}
|
105 |
+
$new_field
|
106 |
+
.hide()
|
107 |
+
.data('ab-field-id', id)
|
108 |
+
.find('.ab-required').prop({
|
109 |
+
id : 'required-' + id,
|
110 |
+
checked : required
|
111 |
+
})
|
112 |
+
.next('label').attr('for', 'required-' + id)
|
113 |
+
.end().end()
|
114 |
+
.find('.ab-label').val(label);
|
115 |
+
// Add new field to the list.
|
116 |
+
$fields.append($new_field);
|
117 |
+
$new_field.fadeIn('fast');
|
118 |
+
// Make it sortable.
|
119 |
+
$new_field.find('ul.ab-items').sortable({
|
120 |
+
axis : 'y',
|
121 |
+
handle : '.ab-inner-handle'
|
122 |
+
});
|
123 |
+
// Set focus to label field.
|
124 |
+
$new_field.find('.ab-label').focus();
|
125 |
+
|
126 |
+
return $new_field;
|
127 |
+
}
|
128 |
+
|
129 |
+
/**
|
130 |
+
* Add new checkbox/radio button/drop-down option.
|
131 |
+
*
|
132 |
+
* @param $ul
|
133 |
+
* @param type
|
134 |
+
* @param value
|
135 |
+
* @return {*|jQuery}
|
136 |
+
*/
|
137 |
+
function addItem($ul, type, value) {
|
138 |
+
var $new_item = $('ul#ab-templates > li[data-type=' + type + ']').clone();
|
139 |
+
if (typeof value != 'undefined') {
|
140 |
+
$new_item.find('input').val(value);
|
141 |
+
}
|
142 |
+
$new_item.hide().appendTo($ul).fadeIn('fast').find('input').focus();
|
143 |
+
|
144 |
+
return $new_item;
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Restore fields from BooklyL10n.custom_fields.
|
149 |
+
*/
|
150 |
+
function restoreFields() {
|
151 |
+
if (BooklyL10n.custom_fields) {
|
152 |
+
var custom_fields = jQuery.parseJSON(BooklyL10n.custom_fields);
|
153 |
+
$.each(custom_fields, function(i, field) {
|
154 |
+
var $new_field = addField(field.type, field.id, field.label, field.required);
|
155 |
+
|
156 |
+
//add children
|
157 |
+
if (field.items) {
|
158 |
+
$.each(field.items, function(i, value) {
|
159 |
+
addItem($new_field.find('ul'), field.type + '-item', value);
|
160 |
+
});
|
161 |
+
}
|
162 |
+
});
|
163 |
+
}
|
164 |
+
$(':focus').blur();
|
165 |
+
}
|
166 |
+
});
|
backend/modules/custom_fields/templates/index.php
ADDED
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="panel panel-default">
|
3 |
+
<div class="panel-heading">
|
4 |
+
<h3 class="panel-title"><?php _e( 'Custom Fields', 'bookly' ) ?></h3>
|
5 |
+
</div>
|
6 |
+
<div class="panel-body">
|
7 |
+
<ul id="ab-custom-fields"></ul>
|
8 |
+
|
9 |
+
<div id="ab-add-fields">
|
10 |
+
<button class="button" data-type="text-field"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Text Field', 'bookly' ) ?></button>
|
11 |
+
<button class="button" data-type="textarea"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Text Area', 'bookly' ) ?></button>
|
12 |
+
<button class="button" data-type="checkboxes"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Checkbox Group', 'bookly' ) ?></button>
|
13 |
+
<button class="button" data-type="radio-buttons"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Radio Button Group', 'bookly' ) ?></button>
|
14 |
+
<button class="button" data-type="drop-down"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Drop Down', 'bookly' ) ?></button>
|
15 |
+
</div>
|
16 |
+
|
17 |
+
<ul id="ab-templates" style="display:none">
|
18 |
+
|
19 |
+
<li data-type="text-field">
|
20 |
+
<i class="ab-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
21 |
+
<h2 class="ab-field-title">
|
22 |
+
<?php _e( 'Text Field', 'bookly' ) ?>
|
23 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove field', 'bookly' ) ) ?>"></i>
|
24 |
+
</h2>
|
25 |
+
<div class="input-group">
|
26 |
+
<input class="ab-label form-control" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
27 |
+
<span class="input-group-addon">
|
28 |
+
<label>
|
29 |
+
<input class="ab-required" type="checkbox" />
|
30 |
+
<span><?php _e( 'Required field', 'bookly' ) ?></span>
|
31 |
+
</label>
|
32 |
+
</span>
|
33 |
+
</div>
|
34 |
+
</li>
|
35 |
+
|
36 |
+
<li data-type="textarea">
|
37 |
+
<i class="ab-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
38 |
+
<h2 class="ab-field-title">
|
39 |
+
<?php _e( 'Text Area', 'bookly' ) ?>
|
40 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove field', 'bookly' ) ) ?>"></i>
|
41 |
+
</h2>
|
42 |
+
<div class="input-group">
|
43 |
+
<input class="ab-label form-control" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
44 |
+
<span class="input-group-addon">
|
45 |
+
<label>
|
46 |
+
<input class="ab-required" type="checkbox" />
|
47 |
+
<span><?php _e( 'Required field', 'bookly' ) ?></span>
|
48 |
+
</label>
|
49 |
+
</span>
|
50 |
+
</div>
|
51 |
+
</li>
|
52 |
+
|
53 |
+
<li data-type="checkboxes">
|
54 |
+
<i class="ab-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
55 |
+
<h2 class="ab-field-title">
|
56 |
+
<?php _e( 'Checkbox Group', 'bookly' ) ?>
|
57 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove field', 'bookly' ) ) ?>"></i>
|
58 |
+
</h2>
|
59 |
+
<div class="input-group">
|
60 |
+
<input class="ab-label form-control" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
61 |
+
<span class="input-group-addon">
|
62 |
+
<label>
|
63 |
+
<input class="ab-required" type="checkbox" />
|
64 |
+
<span><?php _e( 'Required field', 'bookly' ) ?></span>
|
65 |
+
</label>
|
66 |
+
</span>
|
67 |
+
</div>
|
68 |
+
<ul class="ab-items"></ul>
|
69 |
+
<button class="button" data-type="checkboxes-item"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Checkbox', 'bookly' ) ?></button>
|
70 |
+
</li>
|
71 |
+
|
72 |
+
<li data-type="radio-buttons">
|
73 |
+
<i class="ab-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
74 |
+
<h2 class="ab-field-title">
|
75 |
+
<?php _e( 'Radio Button Group', 'bookly' ) ?>
|
76 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove field', 'bookly' ) ) ?>"></i>
|
77 |
+
</h2>
|
78 |
+
<div class="input-group">
|
79 |
+
<input class="ab-label form-control" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
80 |
+
<span class="input-group-addon">
|
81 |
+
<label>
|
82 |
+
<input class="ab-required" type="checkbox" />
|
83 |
+
<span><?php _e( 'Required field', 'bookly' ) ?></span>
|
84 |
+
</label>
|
85 |
+
</span>
|
86 |
+
</div>
|
87 |
+
<ul class="ab-items"></ul>
|
88 |
+
<button class="button" data-type="radio-buttons-item"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Radio Button', 'bookly' ) ?></button>
|
89 |
+
</li>
|
90 |
+
|
91 |
+
<li data-type="drop-down">
|
92 |
+
<i class="ab-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
93 |
+
<h2 class="ab-field-title">
|
94 |
+
<?php _e( 'Drop Down', 'bookly' ) ?>
|
95 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove field', 'bookly' ) ) ?>"></i>
|
96 |
+
</h2>
|
97 |
+
<div class="input-group">
|
98 |
+
<input class="ab-label form-control" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
99 |
+
<span class="input-group-addon">
|
100 |
+
<label>
|
101 |
+
<input class="ab-required" type="checkbox" />
|
102 |
+
<span><?php _e( 'Required field', 'bookly' ) ?></span>
|
103 |
+
</label>
|
104 |
+
</span>
|
105 |
+
</div>
|
106 |
+
<ul class="ab-items"></ul>
|
107 |
+
<button class="button" data-type="drop-down-item"><i class="glyphicon glyphicon-plus"></i> <?php _e( 'Option', 'bookly' ) ?></button>
|
108 |
+
</li>
|
109 |
+
|
110 |
+
<li data-type="checkboxes-item">
|
111 |
+
<i class="ab-inner-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
112 |
+
<input class="form-control ab-inline-block" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
113 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove item', 'bookly' ) ) ?>"></i>
|
114 |
+
</li>
|
115 |
+
|
116 |
+
<li data-type="radio-buttons-item">
|
117 |
+
<i class="ab-inner-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
118 |
+
<input class="form-control ab-inline-block" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
119 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove item', 'bookly' ) ) ?>"></i>
|
120 |
+
</li>
|
121 |
+
|
122 |
+
<li data-type="drop-down-item">
|
123 |
+
<i class="ab-inner-handle glyphicon glyphicon-align-justify" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"></i>
|
124 |
+
<input class="form-control ab-inline-block" type="text" value="" placeholder="<?php echo esc_attr( __( 'Enter a label', 'bookly' ) ) ?>" />
|
125 |
+
<i class="ab-delete glyphicon glyphicon-trash" title="<?php echo esc_attr( __( 'Remove item', 'bookly' ) ) ?>"></i>
|
126 |
+
</li>
|
127 |
+
|
128 |
+
</ul>
|
129 |
+
</div>
|
130 |
+
<div class="panel-footer">
|
131 |
+
<?php AB_Utils::submitButton( 'ajax-send-custom-fields' ) ?>
|
132 |
+
<?php AB_Utils::resetButton() ?>
|
133 |
+
</div>
|
134 |
+
</div>
|
backend/modules/customer/AB_CustomerController.php
CHANGED
@@ -1,156 +1,193 @@
|
|
1 |
-
<?php
|
2 |
|
3 |
-
|
4 |
|
5 |
-
|
6 |
|
7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
9 |
-
public function index()
|
10 |
-
|
|
|
11 |
$this->importCustomers();
|
12 |
}
|
13 |
|
14 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
wp_enqueue_script( 'ab-ng-new_customer_dialog', plugins_url( 'resources/js/ng-new_customer_dialog.js', dirname(__FILE__) . '/../../AB_Backend.php' ), array( 'jquery', 'ab-angularjs' ) );
|
24 |
|
25 |
-
$this->render('index');
|
26 |
}
|
27 |
|
28 |
-
/**
|
29 |
-
* Get Amount of Payments via PayPal and Last and Total Appointments
|
30 |
-
*
|
31 |
-
* @param string $query
|
32 |
-
* @return mixed $query
|
33 |
-
*/
|
34 |
-
public function getCustomerData( $query ) {
|
35 |
-
$wpdb = $this->getWpdb();
|
36 |
-
$query = $wpdb->get_results( $query );
|
37 |
-
if ( count( $query ) ) {
|
38 |
-
foreach( $query as $num => $customer_data ) {
|
39 |
-
// get Total Appointments
|
40 |
-
$query[ $num ]->total_appointments = $wpdb->get_var("
|
41 |
-
SELECT COUNT(a.id) as total_appointments
|
42 |
-
FROM ab_appointment a
|
43 |
-
WHERE a.customer_id = {$customer_data->id}
|
44 |
-
");
|
45 |
-
// get Last Appointment
|
46 |
-
$query[ $num ]->last_appointment = $wpdb->get_var("
|
47 |
-
SELECT MAX(a.start_date) as last_appointment
|
48 |
-
FROM ab_appointment a
|
49 |
-
WHERE a.customer_id = {$customer_data->id}
|
50 |
-
");
|
51 |
-
$query[ $num ]->last_appointment = AB_CommonUtils::getFormattedDateTime(
|
52 |
-
$query[ $num ]->last_appointment
|
53 |
-
);
|
54 |
-
|
55 |
-
$query[ $num ]->payments = 0;
|
56 |
-
}
|
57 |
-
}
|
58 |
-
return $query;
|
59 |
-
} // getCustomerData
|
60 |
-
|
61 |
/**
|
62 |
* Get list of customers.
|
63 |
*/
|
64 |
-
public function executeGetCustomers()
|
|
|
|
|
|
|
65 |
$response = array(
|
66 |
-
'
|
67 |
-
'
|
68 |
-
|
69 |
-
|
70 |
-
'pages' => 0,
|
71 |
-
'active_page' => 0,
|
72 |
-
)
|
73 |
);
|
74 |
|
75 |
-
$page = (
|
76 |
-
$sort = in_array( $this->
|
77 |
-
|
78 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
|
80 |
-
$items_per_page = 20;
|
81 |
-
$total = $this->getWpdb()->get_var( 'SELECT COUNT(*) FROM `ab_customer`' );
|
82 |
$pages = ceil( $total / $items_per_page );
|
83 |
if ( $page < 1 || $page > $pages ) {
|
84 |
$page = 1;
|
85 |
}
|
86 |
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
}
|
94 |
-
|
95 |
-
|
96 |
-
// LIMIT
|
97 |
-
$start = ( $page - 1) * $items_per_page;
|
98 |
-
$query .= " LIMIT {$start}, {$items_per_page}";
|
99 |
-
$customer_data = self::getCustomerData( $query );
|
100 |
-
// Populate response.
|
101 |
-
$response[ 'data' ][ 'customers' ] = $customer_data;
|
102 |
-
$response[ 'data' ][ 'total' ] = $total;
|
103 |
-
$response[ 'data' ][ 'pages' ] = $pages;
|
104 |
-
$response[ 'data' ][ 'active_page' ] = $page;
|
105 |
-
}
|
106 |
|
107 |
-
|
108 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
109 |
}
|
110 |
|
111 |
/**
|
112 |
* Create or edit a customer.
|
113 |
*/
|
114 |
-
public function executeSaveCustomer()
|
|
|
115 |
$response = array();
|
116 |
$form = new AB_CustomerForm();
|
117 |
|
118 |
do {
|
119 |
-
if ( $this->
|
120 |
-
$form->bind( $this->
|
121 |
/** @var AB_Customer $customer */
|
122 |
$customer = $form->save();
|
123 |
if ( $customer ) {
|
124 |
-
$response[ '
|
125 |
$response[ 'customer' ] = array(
|
126 |
'id' => $customer->id,
|
127 |
'name' => $customer->name,
|
|
|
128 |
'phone' => $customer->phone,
|
129 |
'email' => $customer->email,
|
130 |
'notes' => $customer->notes,
|
131 |
'jsonString' => json_encode( array(
|
132 |
-
'name'
|
133 |
-
'phone'
|
134 |
-
'email'
|
135 |
'notes' => $customer->notes
|
136 |
) )
|
137 |
);
|
138 |
break;
|
139 |
}
|
140 |
}
|
141 |
-
$response[ '
|
142 |
-
$response[ 'errors' ]
|
143 |
} while ( 0 );
|
144 |
|
145 |
-
|
146 |
-
exit ( 0 );
|
147 |
}
|
148 |
|
149 |
/**
|
150 |
* Import customers from CSV.
|
151 |
*/
|
152 |
-
private function importCustomers()
|
153 |
-
|
|
|
|
|
|
|
154 |
'text/csv',
|
155 |
'application/csv',
|
156 |
'text/comma-separated-values',
|
@@ -159,17 +196,17 @@ class AB_CustomerController extends AB_Controller {
|
|
159 |
'application/vnd.msexcel'
|
160 |
);
|
161 |
|
162 |
-
if (in_array($
|
163 |
-
$file = fopen($
|
164 |
-
while ($line = fgetcsv($file)){
|
165 |
-
if (!empty($line[0])){
|
166 |
$customer = new AB_Customer();
|
167 |
-
$customer->set('name', $line[0]);
|
168 |
-
if (isset($line[1])){
|
169 |
-
$customer->set('phone', $line[1]);
|
170 |
}
|
171 |
-
if (isset($line[2])){
|
172 |
-
$customer->set('email', $line[2]);
|
173 |
}
|
174 |
$customer->save();
|
175 |
}
|
@@ -180,27 +217,38 @@ class AB_CustomerController extends AB_Controller {
|
|
180 |
/**
|
181 |
* Get angulars template for new customer dialog.
|
182 |
*/
|
183 |
-
public function executeGetNgNewCustomerDialogTemplate()
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
185 |
exit ( 0 );
|
186 |
}
|
187 |
|
188 |
/**
|
189 |
* Delete a customer.
|
190 |
*/
|
191 |
-
public function executeDeleteCustomer()
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
)
|
|
|
196 |
}
|
|
|
197 |
}
|
198 |
|
199 |
/**
|
200 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
201 |
* so current 'execute*' methods look nicer.
|
|
|
|
|
202 |
*/
|
203 |
-
protected function registerWpActions( $prefix = '' )
|
|
|
204 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
205 |
}
|
|
|
206 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
|
3 |
+
class AB_CustomerController extends AB_Controller {
|
4 |
|
5 |
+
const page_slug = 'ab-customers';
|
6 |
|
7 |
+
protected function getPermissions()
|
8 |
+
{
|
9 |
+
return array(
|
10 |
+
'executeSaveCustomer' => 'user',
|
11 |
+
'executeGetNgNewCustomerDialogTemplate' => 'user',
|
12 |
+
);
|
13 |
+
}
|
14 |
|
15 |
+
public function index()
|
16 |
+
{
|
17 |
+
if ( $this->hasParameter( 'import-customers' ) ) {
|
18 |
$this->importCustomers();
|
19 |
}
|
20 |
|
21 |
+
$this->enqueueStyles( array(
|
22 |
+
'module' => array(
|
23 |
+
'css/customers.css' => array( 'ab-intlTelInput.css' ),
|
24 |
+
),
|
25 |
+
'backend' => array(
|
26 |
+
'css/bookly.main-backend.css',
|
27 |
+
'bootstrap/css/bootstrap.min.css',
|
28 |
+
),
|
29 |
+
'frontend' => array(
|
30 |
+
'css/intlTelInput.css',
|
31 |
+
)
|
32 |
+
) );
|
33 |
+
|
34 |
+
$this->enqueueScripts( array(
|
35 |
+
'backend' => array(
|
36 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
37 |
+
'js/angular.min.js',
|
38 |
+
'js/angular-sanitize.min.js',
|
39 |
+
'js/angular-ui-utils-0.2.1.min.js',
|
40 |
+
'js/angular-ui-date-0.0.8.js',
|
41 |
+
'js/ng-new_customer_dialog.js' => array( 'jquery', 'ab-angular.min.js' ),
|
42 |
+
),
|
43 |
+
'module' => array(
|
44 |
+
'js/ng-app.js' => array(
|
45 |
+
'jquery',
|
46 |
+
'ab-angular.min.js',
|
47 |
+
'ab-angular-ui-utils-0.2.1.min.js',
|
48 |
+
'ab-angular-ui-date-0.0.8.js',
|
49 |
+
'ab-intlTelInput.utils.js',
|
50 |
+
),
|
51 |
+
),
|
52 |
+
'frontend' => array(
|
53 |
+
'js/intlTelInput.min.js' => array( 'jquery' ),
|
54 |
+
'js/intlTelInput.utils.js' => array( 'jquery' )
|
55 |
+
)
|
56 |
+
) );
|
57 |
|
58 |
+
wp_localize_script( 'ab-ng-app.js', 'BooklyL10n', array(
|
59 |
+
'are_you_sure' => __( 'Are you sure?', 'bookly' ),
|
60 |
+
'wp_users' => $this->getWpUsers(),
|
61 |
+
'country' => get_option( 'ab_settings_phone_default_country' ),
|
62 |
+
'intlTelInput_utils' => plugins_url( 'intlTelInput.utils.js', AB_PATH . '/frontend/resources/js/intlTelInput.utils.js' ),
|
63 |
+
'please_select_at_least_one_row' => __( 'Please select at least one customer.', 'bookly' ),
|
64 |
+
) );
|
|
|
65 |
|
66 |
+
$this->render( 'index' );
|
67 |
}
|
68 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
/**
|
70 |
* Get list of customers.
|
71 |
*/
|
72 |
+
public function executeGetCustomers()
|
73 |
+
{
|
74 |
+
$wpdb = $this->getWpdb();
|
75 |
+
$items_per_page = 20;
|
76 |
$response = array(
|
77 |
+
'customers' => array(),
|
78 |
+
'total' => 0,
|
79 |
+
'pages' => 0,
|
80 |
+
'active_page' => 0,
|
|
|
|
|
|
|
81 |
);
|
82 |
|
83 |
+
$page = intval( $this->getParameter( 'page' ) );
|
84 |
+
$sort = in_array( $this->getParameter( 'sort' ), array( 'name', 'phone', 'email', 'notes', 'last_appointment', 'total_appointments', 'payments', 'wp_user' ) )
|
85 |
+
? $this->getParameter( 'sort' ) : 'name';
|
86 |
+
$order = in_array( $this->getParameter( 'order' ), array( 'asc', 'desc' ) ) ? $this->getParameter( 'order' ) : 'asc';
|
87 |
+
$filter = $wpdb->_real_escape( $this->getParameter( 'filter' ) );
|
88 |
+
|
89 |
+
$query = AB_Customer::query( 'c' );
|
90 |
+
// WHERE
|
91 |
+
if ( $filter !== '' ) {
|
92 |
+
$query->whereLike( 'c.name', "%{$filter}%")
|
93 |
+
->whereLike( 'c.phone', "%{$filter}%", 'OR' )
|
94 |
+
->whereLike( 'c.email', "%{$filter}%", 'OR' );
|
95 |
+
}
|
96 |
+
$total = $query->count();
|
97 |
|
|
|
|
|
98 |
$pages = ceil( $total / $items_per_page );
|
99 |
if ( $page < 1 || $page > $pages ) {
|
100 |
$page = 1;
|
101 |
}
|
102 |
|
103 |
+
$data = $query->select( 'c.*, MAX(a.start_date) AS last_appointment,
|
104 |
+
COUNT(a.id) AS total_appointments,
|
105 |
+
COALESCE(SUM(p.total),0) AS payments,
|
106 |
+
wpu.display_name AS wp_user' )
|
107 |
+
->leftJoin( 'AB_CustomerAppointment', 'ca', 'ca.customer_id = c.id' )
|
108 |
+
->leftJoin( 'AB_Appointment', 'a', 'a.id = ca.appointment_id' )
|
109 |
+
->leftJoin( 'AB_Payment', 'p', 'p.customer_appointment_id = ca.id' )
|
110 |
+
->tableJoin( $wpdb->users, 'wpu', 'wpu.ID = c.wp_user_id' )
|
111 |
+
->groupBy( 'c.id' )
|
112 |
+
->sortBy( $sort )
|
113 |
+
->order( $order )
|
114 |
+
->limit( $items_per_page )
|
115 |
+
->offset( ( $page - 1 ) * $items_per_page )
|
116 |
+
->fetchArray();
|
117 |
+
|
118 |
+
array_walk( $data, function ( &$row ) {
|
119 |
+
if ( $row['last_appointment'] ) {
|
120 |
+
$row['last_appointment'] = AB_DateTimeUtils::formatDateTime( $row['last_appointment'] );
|
121 |
}
|
122 |
+
$row['payments'] = AB_Utils::formatPrice( $row['payments'] );
|
123 |
+
} );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
124 |
|
125 |
+
// Populate response.
|
126 |
+
$response[ 'customers' ] = $data;
|
127 |
+
$response[ 'total' ] = $total;
|
128 |
+
$response[ 'pages' ] = $pages;
|
129 |
+
$response[ 'active_page' ] = $page;
|
130 |
+
|
131 |
+
wp_send_json_success( $response );
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Get WP users array.
|
136 |
+
*
|
137 |
+
* @return array
|
138 |
+
*/
|
139 |
+
public function getWpUsers()
|
140 |
+
{
|
141 |
+
return get_users( array( 'fields' => array( 'ID', 'display_name' ), 'orderby' => 'display_name' ) );
|
142 |
}
|
143 |
|
144 |
/**
|
145 |
* Create or edit a customer.
|
146 |
*/
|
147 |
+
public function executeSaveCustomer()
|
148 |
+
{
|
149 |
$response = array();
|
150 |
$form = new AB_CustomerForm();
|
151 |
|
152 |
do {
|
153 |
+
if ( $this->getParameter( 'name' ) !== '' ) {
|
154 |
+
$form->bind( $this->getPostParameters() );
|
155 |
/** @var AB_Customer $customer */
|
156 |
$customer = $form->save();
|
157 |
if ( $customer ) {
|
158 |
+
$response[ 'success' ] = true;
|
159 |
$response[ 'customer' ] = array(
|
160 |
'id' => $customer->id,
|
161 |
'name' => $customer->name,
|
162 |
+
'wp_user_id' => $customer->wp_user_id,
|
163 |
'phone' => $customer->phone,
|
164 |
'email' => $customer->email,
|
165 |
'notes' => $customer->notes,
|
166 |
'jsonString' => json_encode( array(
|
167 |
+
'name' => $customer->name,
|
168 |
+
'phone' => $customer->phone,
|
169 |
+
'email' => $customer->email,
|
170 |
'notes' => $customer->notes
|
171 |
) )
|
172 |
);
|
173 |
break;
|
174 |
}
|
175 |
}
|
176 |
+
$response[ 'success' ] = false;
|
177 |
+
$response[ 'errors' ] = array( 'name' => array( 'required' ) );
|
178 |
} while ( 0 );
|
179 |
|
180 |
+
wp_send_json( $response );
|
|
|
181 |
}
|
182 |
|
183 |
/**
|
184 |
* Import customers from CSV.
|
185 |
*/
|
186 |
+
private function importCustomers()
|
187 |
+
{
|
188 |
+
@ini_set( 'auto_detect_line_endings', true );
|
189 |
+
|
190 |
+
$csv_mime_types = array(
|
191 |
'text/csv',
|
192 |
'application/csv',
|
193 |
'text/comma-separated-values',
|
196 |
'application/vnd.msexcel'
|
197 |
);
|
198 |
|
199 |
+
if ( in_array( $_FILES[ 'import_customers_file' ][ 'type' ], $csv_mime_types ) ) {
|
200 |
+
$file = fopen ( $_FILES[ 'import_customers_file' ][ 'tmp_name' ], 'r' );
|
201 |
+
while ( $line = fgetcsv( $file, null, $this->getParameter( 'import_customers_delimiter' ) ) ) {
|
202 |
+
if ( !empty ( $line[ 0 ] ) ) {
|
203 |
$customer = new AB_Customer();
|
204 |
+
$customer->set( 'name', $line[ 0 ] );
|
205 |
+
if ( isset ( $line[ 1 ] ) ) {
|
206 |
+
$customer->set( 'phone', $line[ 1 ] );
|
207 |
}
|
208 |
+
if ( isset ( $line[ 2 ] ) ) {
|
209 |
+
$customer->set( 'email', $line[ 2 ] );
|
210 |
}
|
211 |
$customer->save();
|
212 |
}
|
217 |
/**
|
218 |
* Get angulars template for new customer dialog.
|
219 |
*/
|
220 |
+
public function executeGetNgNewCustomerDialogTemplate()
|
221 |
+
{
|
222 |
+
$this->render( 'ng-new_customer_dialog', array(
|
223 |
+
'custom_fields' => json_decode( get_option( 'ab_custom_fields' ) ),
|
224 |
+
'module' => $this->getParameter( 'module' ),
|
225 |
+
'wp_users' => $this->getWpUsers()
|
226 |
+
) );
|
227 |
exit ( 0 );
|
228 |
}
|
229 |
|
230 |
/**
|
231 |
* Delete a customer.
|
232 |
*/
|
233 |
+
public function executeDeleteCustomer()
|
234 |
+
{
|
235 |
+
foreach ( $this->getParameter( 'ids' ) as $id ) {
|
236 |
+
$customer = new AB_Customer();
|
237 |
+
$customer->load( $id );
|
238 |
+
$customer->deleteWithWPUser( (bool) $this->getParameter( 'with_wp_user' ) );
|
239 |
}
|
240 |
+
wp_send_json_success();
|
241 |
}
|
242 |
|
243 |
/**
|
244 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
245 |
* so current 'execute*' methods look nicer.
|
246 |
+
*
|
247 |
+
* @param string $prefix
|
248 |
*/
|
249 |
+
protected function registerWpActions( $prefix = '' )
|
250 |
+
{
|
251 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
252 |
}
|
253 |
+
|
254 |
}
|
backend/modules/customer/forms/AB_CustomerForm.php
CHANGED
@@ -1,8 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_Customer.php';
|
6 |
|
7 |
/**
|
8 |
* Class AB_CustomerForm
|
@@ -12,17 +8,21 @@ class AB_CustomerForm extends AB_Form {
|
|
12 |
/**
|
13 |
* Constructor.
|
14 |
*/
|
15 |
-
public function __construct()
|
|
|
16 |
parent::$entity_class = 'AB_Customer';
|
17 |
parent::__construct();
|
18 |
}
|
19 |
|
20 |
-
public function configure()
|
21 |
-
|
|
|
22 |
'name',
|
|
|
23 |
'phone',
|
24 |
'email',
|
25 |
'notes'
|
26 |
-
));
|
27 |
}
|
|
|
28 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_CustomerForm
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_Customer';
|
14 |
parent::__construct();
|
15 |
}
|
16 |
|
17 |
+
public function configure()
|
18 |
+
{
|
19 |
+
$this->setFields( array(
|
20 |
'name',
|
21 |
+
'wp_user_id',
|
22 |
'phone',
|
23 |
'email',
|
24 |
'notes'
|
25 |
+
) );
|
26 |
}
|
27 |
+
|
28 |
}
|
backend/modules/customer/resources/css/customers.css
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* intlTelInput.js */
|
2 |
+
.iti-flag{background-image:url("../../../../../frontend/resources/images/flags.png");}
|
3 |
+
@media only screen and (min-resolution: 2dppx){.iti-flag{background-image:url("../../../../../frontend/resources/images/flags@2x.png")}}
|
4 |
+
#ab_customers_list .intl-tel-input,
|
5 |
+
#ab_customers_list td.ab-phone .displayed-value { width: 170px; }
|
6 |
+
.ab-customers-list .table-responsive { overflow: visible; }
|
7 |
+
/* media query */
|
8 |
+
@media screen and (max-width: 782px) {
|
9 |
+
.ab-customers-list .table-responsive { overflow-y: hidden; }
|
10 |
+
}
|
backend/modules/customer/resources/js/ng-app.js
CHANGED
@@ -1,226 +1,356 @@
|
|
1 |
;(function() {
|
|
|
2 |
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
}
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
|
|
|
|
83 |
$scope.css_class = {
|
84 |
-
name
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
89 |
total_appointments : '',
|
90 |
-
payments
|
91 |
};
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
customer.edit_name = false;
|
122 |
-
customer.edit_phone = false;
|
123 |
-
customer.edit_email = false;
|
124 |
-
customer.edit_notes = false;
|
125 |
-
customer.errors = {};
|
126 |
-
|
127 |
-
$scope.loading = true;
|
128 |
-
jQuery.ajax({
|
129 |
-
url : ajaxurl,
|
130 |
-
type : 'POST',
|
131 |
-
data : {
|
132 |
-
action : 'ab_save_customer',
|
133 |
-
id : customer.id,
|
134 |
-
name : customer.name,
|
135 |
-
phone : customer.phone,
|
136 |
-
email : customer.email,
|
137 |
-
notes : customer.notes
|
138 |
-
},
|
139 |
-
dataType : 'json',
|
140 |
-
success : function(response) {
|
141 |
-
$scope.$apply(function($scope) {
|
142 |
-
if (response.status === 'error') {
|
143 |
-
jQuery.each(response.errors, function(field, errors) {
|
144 |
-
customer.errors[field] = {};
|
145 |
-
customer['edit_' + field] = true;
|
146 |
-
jQuery.each(errors, function(key, error) {
|
147 |
-
customer.errors[field][error] = true;
|
148 |
-
});
|
149 |
});
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
});
|
158 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
159 |
});
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
dataType : 'json',
|
187 |
-
success : function(response) {
|
188 |
-
$scope.$apply(function($scope) {
|
189 |
-
jQuery.each(dataSource.customers, function(index, value) {
|
190 |
-
if(value.id == customer.id) {
|
191 |
-
dataSource.customers.splice(index, 1);
|
192 |
-
$scope.reload(params.page);
|
193 |
-
return false;
|
194 |
-
}
|
195 |
});
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
};
|
224 |
-
|
|
|
|
|
|
|
|
|
|
|
225 |
|
226 |
})();
|
1 |
;(function() {
|
2 |
+
var module = angular.module('customers', ['ui.utils', 'ui.date', 'newCustomerDialog', 'ngSanitize']);
|
3 |
|
4 |
+
module.factory('dataSource', function($q, $rootScope) {
|
5 |
+
var ds = {
|
6 |
+
customers : [],
|
7 |
+
total : 0,
|
8 |
+
pages : [],
|
9 |
+
form : {
|
10 |
+
new_customer : {
|
11 |
+
name : null,
|
12 |
+
wp_user_id : null,
|
13 |
+
phone : null,
|
14 |
+
email : null,
|
15 |
+
notes : null
|
16 |
+
}
|
17 |
+
},
|
18 |
+
loadData : function(params) {
|
19 |
+
var deferred = $q.defer();
|
20 |
+
jQuery.ajax({
|
21 |
+
url : ajaxurl,
|
22 |
+
type : 'POST',
|
23 |
+
data : jQuery.extend({ action : 'ab_get_customers' }, params),
|
24 |
+
dataType : 'json',
|
25 |
+
success : function(response) {
|
26 |
+
if (response.success) {
|
27 |
+
|
28 |
+
ds.customers = response.data.customers;
|
29 |
+
ds.total = response.data.total;
|
30 |
+
ds.pages = [];
|
31 |
+
ds.paginator = {beg : false, end: false};
|
32 |
+
var neighbor = 5;
|
33 |
+
var beg = Math.max(1, response.data.active_page - neighbor);
|
34 |
+
var end = Math.min(response.data.pages, (response.data.active_page + neighbor));
|
35 |
+
if (beg > 1) {
|
36 |
+
ds.paginator.beg = true;
|
37 |
+
beg++;
|
38 |
+
}
|
39 |
+
for (var i = beg; i < end; i++) {
|
40 |
+
ds.pages.push({ number : i, active : response.data.active_page == i });
|
41 |
+
}
|
42 |
+
if (end >= response.data.pages) {
|
43 |
+
ds.pages.push({number: response.data.pages, active: response.data.active_page == response.data.pages});
|
44 |
+
} else {
|
45 |
+
ds.paginator.end = {number: response.data.pages, active: false};
|
46 |
+
}
|
47 |
+
for (var i = 0; i < ds.customers.length; ++ i) {
|
48 |
+
for (var j = 0; j < BooklyL10n.wp_users.length; ++ j) {
|
49 |
+
if (ds.customers[i].wp_user_id == BooklyL10n.wp_users[j].ID) {
|
50 |
+
ds.customers[i].wp_user = BooklyL10n.wp_users[j];
|
51 |
+
break;
|
52 |
+
}
|
53 |
+
}
|
54 |
+
}
|
55 |
+
}
|
56 |
+
$rootScope.$apply(deferred.resolve);
|
57 |
+
},
|
58 |
+
error : function() {
|
59 |
+
ds.customers = [];
|
60 |
+
ds.total = 0;
|
61 |
+
$rootScope.$apply(deferred.resolve);
|
62 |
+
}
|
63 |
+
});
|
64 |
+
return deferred.promise;
|
65 |
}
|
66 |
+
};
|
67 |
+
ds.wp_users = BooklyL10n.wp_users;
|
68 |
+
return ds;
|
69 |
+
});
|
70 |
+
|
71 |
+
module.factory('intlTelInputSrv', function() {
|
72 |
+
var srv = {
|
73 |
+
elements: {},
|
74 |
+
init: function(id, element) {
|
75 |
+
if (srv.elements[id]) {
|
76 |
+
srv.destroy(id);
|
77 |
+
}
|
78 |
+
srv.elements[id] = element;
|
79 |
+
srv.elements[id].intlTelInput({
|
80 |
+
preferredCountries: [BooklyL10n.country],
|
81 |
+
defaultCountry: BooklyL10n.country,
|
82 |
+
geoIpLookup: function(callback) {
|
83 |
+
jQuery.get(ajaxurl, {action: 'ab_ip_info'}, function() {}, 'json' ).always(function(resp) {
|
84 |
+
var countryCode = (resp && resp.country) ? resp.country : '';
|
85 |
+
callback(countryCode);
|
86 |
+
});
|
87 |
+
},
|
88 |
+
utilsScript: BooklyL10n.intlTelInput_utils
|
89 |
+
});
|
90 |
+
},
|
91 |
+
destroy: function(id) {
|
92 |
+
if (srv.elements[id]) {
|
93 |
+
srv.elements[id].val(srv.getNumber(id));
|
94 |
+
srv.elements[id].intlTelInput('destroy');
|
95 |
+
delete srv.elements[id];
|
96 |
+
}
|
97 |
+
},
|
98 |
+
getNumber: function(id) {
|
99 |
+
return srv.elements[id] ? srv.elements[id].intlTelInput('getNumber') : null;
|
100 |
+
}
|
101 |
+
};
|
102 |
+
|
103 |
+
return srv;
|
104 |
+
});
|
105 |
+
|
106 |
+
module.controller('customersCtrl', function($scope, dataSource, intlTelInputSrv) {
|
107 |
+
// Set up initial data.
|
108 |
+
var params = {
|
109 |
+
page : 1,
|
110 |
+
sort : 'name',
|
111 |
+
order : 'asc',
|
112 |
+
filter : ''
|
113 |
+
};
|
114 |
+
$scope.loading = true;
|
115 |
$scope.css_class = {
|
116 |
+
name : 'asc',
|
117 |
+
wp_user : '',
|
118 |
+
phone : '',
|
119 |
+
email : '',
|
120 |
+
notes : '',
|
121 |
+
last_appointment : '',
|
122 |
total_appointments : '',
|
123 |
+
payments : ''
|
124 |
};
|
125 |
+
// Set up data source (data will be loaded in reload function).
|
126 |
+
$scope.dataSource = dataSource;
|
127 |
+
|
128 |
+
$scope.reload = function( opt ) {
|
129 |
+
$scope.loading = true;
|
130 |
+
if (opt !== undefined) {
|
131 |
+
if (opt.sort !== undefined) {
|
132 |
+
if (params.sort === opt.sort) {
|
133 |
+
// Toggle order when sorting by the same field.
|
134 |
+
params.order = params.order === 'asc' ? 'desc' : 'asc';
|
135 |
+
} else {
|
136 |
+
params.order = 'asc';
|
137 |
+
}
|
138 |
+
$scope.css_class = {
|
139 |
+
name : '',
|
140 |
+
wp_user : '',
|
141 |
+
phone : '',
|
142 |
+
email : '',
|
143 |
+
notes : '',
|
144 |
+
last_appointment : '',
|
145 |
+
total_appointments : '',
|
146 |
+
payments : ''
|
147 |
+
};
|
148 |
+
$scope.css_class[opt.sort] = params.order;
|
149 |
+
}
|
150 |
+
jQuery.extend(params, opt);
|
151 |
+
}
|
152 |
+
dataSource.loadData(params).then(function() {
|
153 |
+
$scope.loading = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
154 |
});
|
155 |
+
};
|
156 |
+
|
157 |
+
var filter_delay = null;
|
158 |
+
$scope.$watch('filter', function() {
|
159 |
+
if (filter_delay !== null) {
|
160 |
+
clearTimeout(filter_delay);
|
161 |
+
}
|
162 |
+
filter_delay = setTimeout(function() {
|
163 |
+
filter_delay = null;
|
164 |
+
$scope.$apply(function($scope) {
|
165 |
+
$scope.reload({filter: $scope.filter});
|
166 |
+
});
|
167 |
+
}, 400);
|
168 |
});
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Edit customer.
|
172 |
+
*
|
173 |
+
* @param object customer
|
174 |
+
*/
|
175 |
+
$scope.saveCustomer = function(customer) {
|
176 |
+
customer.edit_name = false;
|
177 |
+
customer.edit_wp_user = false;
|
178 |
+
customer.edit_phone = false;
|
179 |
+
customer.edit_email = false;
|
180 |
+
customer.edit_notes = false;
|
181 |
+
customer.errors = {};
|
182 |
+
|
183 |
+
$scope.loading = true;
|
184 |
+
jQuery.ajax({
|
185 |
+
url : ajaxurl,
|
186 |
+
type : 'POST',
|
187 |
+
data : {
|
188 |
+
action : 'ab_save_customer',
|
189 |
+
id : customer.id,
|
190 |
+
wp_user_id : customer.wp_user ? customer.wp_user.ID : null,
|
191 |
+
name : customer.name,
|
192 |
+
phone : customer.phone,
|
193 |
+
email : customer.email,
|
194 |
+
notes : customer.notes
|
195 |
+
},
|
196 |
+
dataType : 'json',
|
197 |
+
success : function(response) {
|
198 |
+
$scope.$apply(function($scope) {
|
199 |
+
if ( response.success == false) {
|
200 |
+
jQuery.each(response.errors, function(field, errors) {
|
201 |
+
customer.errors[field] = {};
|
202 |
+
customer['edit_' + field] = true;
|
203 |
+
jQuery.each(errors, function(key, error) {
|
204 |
+
customer.errors[field][error] = true;
|
205 |
+
});
|
206 |
+
});
|
207 |
+
}
|
208 |
+
$scope.loading = false;
|
209 |
+
});
|
210 |
+
},
|
211 |
+
error : function(response) {
|
212 |
+
$scope.$apply(function($scope) {
|
213 |
+
$scope.loading = false;
|
214 |
+
});
|
215 |
+
}
|
216 |
+
});
|
217 |
+
};
|
218 |
+
|
219 |
+
$scope.saveCustomerPhone = function(customer) {
|
220 |
+
if (customer.edit_phone) {
|
221 |
+
customer.phone = intlTelInputSrv.getNumber(customer.id);
|
222 |
+
$scope.saveCustomer(customer);
|
223 |
+
}
|
224 |
+
};
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Callback for creating new customer.
|
228 |
+
*
|
229 |
+
* @param object customer
|
230 |
+
*/
|
231 |
+
$scope.createCustomer = function(customer) {
|
232 |
+
dataSource.customers.push(customer);
|
233 |
+
$scope.reload(params.page);
|
234 |
+
};
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Delete customer.
|
238 |
+
*/
|
239 |
+
$scope.deleteCustomers = function() {
|
240 |
+
var ids = [];
|
241 |
+
jQuery('table input[type=checkbox]:checked').each(function() {
|
242 |
+
ids.push(jQuery(this).data('customer_id'));
|
243 |
+
});
|
244 |
+
if (ids.length) {
|
245 |
+
if (delete_customers_choice === null) {
|
246 |
+
$modal.data('customer_ids', ids).modal('show');
|
247 |
+
} else {
|
248 |
+
deleteCustomers(ids, delete_customers_choice);
|
249 |
+
}
|
250 |
+
} else {
|
251 |
+
alert(BooklyL10n.please_select_at_least_one_row);
|
252 |
+
}
|
253 |
+
};
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Popup for deleting customer.
|
257 |
+
*/
|
258 |
+
var delete_customers_choice = null;
|
259 |
+
var deleteCustomers = function(ids, with_wp_user) {
|
260 |
+
$scope.loading = true;
|
261 |
+
jQuery.ajax({
|
262 |
+
url: ajaxurl,
|
263 |
+
type: 'POST',
|
264 |
+
data: {
|
265 |
+
action: 'ab_delete_customer',
|
266 |
+
ids : ids,
|
267 |
+
with_wp_user: with_wp_user ? 1 : 0
|
268 |
+
},
|
269 |
+
dataType : 'json',
|
270 |
+
success : function (response) {
|
271 |
+
$scope.$apply(function ($scope) {
|
272 |
+
$scope.reload();
|
273 |
+
});
|
274 |
+
}
|
275 |
+
});
|
276 |
+
};
|
277 |
+
var $modal = jQuery('#ab-customer-delete');
|
278 |
+
$modal
|
279 |
+
.on('click', '.ab-yes', function () {
|
280 |
+
$modal.modal('hide');
|
281 |
+
if ( jQuery('#ab-remember-my-choice').prop('checked') ) {
|
282 |
+
delete_customers_choice = true;
|
283 |
+
}
|
284 |
+
deleteCustomers($modal.data('customer_ids'), true);
|
285 |
+
})
|
286 |
+
.on('click', '.ab-no', function () {
|
287 |
+
if ( jQuery('#ab-remember-my-choice').prop('checked') ) {
|
288 |
+
delete_customers_choice = false;
|
289 |
+
}
|
290 |
+
deleteCustomers($modal.data('customer_ids'), false);
|
291 |
+
});
|
292 |
+
|
293 |
});
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Directive for setting focus to element.
|
297 |
+
*/
|
298 |
+
module.directive('focusMe', function($timeout) {
|
299 |
+
return {
|
300 |
+
link: function(scope, element, attrs) {
|
301 |
+
scope.$watch(attrs.focusMe, function(value) {
|
302 |
+
if (value) {
|
303 |
+
$timeout(function() {
|
304 |
+
element[0].focus();
|
305 |
+
});
|
306 |
+
}
|
307 |
+
});
|
308 |
+
}
|
309 |
+
};
|
310 |
+
});
|
311 |
+
|
312 |
+
module.directive('intlTelInput', ['intlTelInputSrv', function(intlTelInputSrv) {
|
313 |
+
return function(scope, element, attrs) {
|
314 |
+
scope.$watch(attrs.intlTelInput, function(value) {
|
315 |
+
if (value) {
|
316 |
+
intlTelInputSrv.init(scope.$eval(attrs.intlTelInputId), element);
|
317 |
+
} else {
|
318 |
+
intlTelInputSrv.destroy(scope.$eval(attrs.intlTelInputId));
|
319 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
320 |
});
|
321 |
+
};
|
322 |
+
}]);
|
323 |
+
|
324 |
+
module.directive('clickOutside', ['$document', function ($document) {
|
325 |
+
return {
|
326 |
+
restrict: 'A',
|
327 |
+
scope: {
|
328 |
+
clickOutside: '&'
|
329 |
+
},
|
330 |
+
link: function ($scope, elem, attr) {
|
331 |
+
$document.on('click', function (e) {
|
332 |
+
var element;
|
333 |
+
|
334 |
+
if (!e.target) return;
|
335 |
+
|
336 |
+
for (element = e.target; element; element = element.parentNode) {
|
337 |
+
if (element == elem.get(0)) {
|
338 |
+
return;
|
339 |
+
}
|
340 |
+
}
|
341 |
+
|
342 |
+
$scope.$apply(function($scope) {
|
343 |
+
$scope.$eval($scope.clickOutside);
|
344 |
+
});
|
345 |
+
});
|
346 |
+
}
|
347 |
+
};
|
348 |
+
}]);
|
349 |
+
|
350 |
+
module.filter('nl2br', function() {
|
351 |
+
return function(input) {
|
352 |
+
return ('' + input).split('\n').join('<br>');
|
353 |
+
};
|
354 |
+
});
|
355 |
|
356 |
})();
|
backend/modules/customer/templates/_import.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div id="ab_import_customers_dialog" class="modal fade" tabindex=-1 role="dialog" aria-labelledby="importCustomersModalLabel" aria-hidden="true">
|
3 |
+
<div class="modal-dialog">
|
4 |
+
<form class="form-horizontal" enctype="multipart/form-data" action="<?php echo AB_Utils::escAdminUrl( AB_CustomerController::page_slug ) ?>" method="POST">
|
5 |
+
<div class="modal-content">
|
6 |
+
<div class="modal-header">
|
7 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
8 |
+
<h4 class="modal-title"><?php _e( 'Import', 'bookly' ) ?></h4>
|
9 |
+
</div>
|
10 |
+
<div class="modal-body">
|
11 |
+
<div class="container-fluid">
|
12 |
+
<div class="form-group">
|
13 |
+
<label><?php _e( 'Note', 'bookly' ) ?></label>
|
14 |
+
<?php _e( 'You may import list of clients in CSV format. The file needs to have three columns: Name, Phone and Email.', 'bookly' ) ?>
|
15 |
+
</div>
|
16 |
+
<div class="form-group">
|
17 |
+
<label for="import_customers_file"><?php _e( 'Select file', 'bookly' ) ?></label>
|
18 |
+
<input name="import_customers_file" id="import_customers_file" type="file">
|
19 |
+
</div>
|
20 |
+
<div class="form-group">
|
21 |
+
<label for="import_customers_delimiter"><?php _e( 'Delimiter', 'bookly' ) ?></label>
|
22 |
+
<select name="import_customers_delimiter" id="import_customers_delimiter" class="form-control">
|
23 |
+
<option value=","><?php _e( 'Comma (,)', 'bookly' ) ?></option>
|
24 |
+
<option value=";"><?php _e( 'Semicolon (;)', 'bookly' ) ?></option>
|
25 |
+
</select>
|
26 |
+
</div>
|
27 |
+
<input type="hidden" name="import">
|
28 |
+
</div>
|
29 |
+
</div>
|
30 |
+
<div class="modal-footer">
|
31 |
+
<button type="submit" class="btn btn-info ab-popup-save" name="import-customers"><?php _e( 'Import', 'bookly' ) ?></button>
|
32 |
+
<button class="ab-reset-form" data-dismiss="modal" aria-hidden="true"><?php _e( 'Cancel', 'bookly' ) ?></button>
|
33 |
+
</div>
|
34 |
+
</div>
|
35 |
+
</form>
|
36 |
+
</div>
|
37 |
+
</div>
|
backend/modules/customer/templates/index.php
CHANGED
@@ -1,106 +1,136 @@
|
|
1 |
-
|
2 |
-
<div
|
3 |
-
|
4 |
-
|
5 |
-
<label class=control-label><?php _e( 'Quick search customer', 'ab' ) ?></label>
|
6 |
-
<div class=controls>
|
7 |
-
<input type=text ng-model=filter />
|
8 |
</div>
|
9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
</div>
|
22 |
-
|
23 |
-
|
24 |
-
<
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
</div>
|
28 |
-
|
29 |
-
|
30 |
-
<label class=control-label><?php _e( 'Select file:' , 'ab' ) ?></label>
|
31 |
-
<div class=controls>
|
32 |
-
<input name="importCustomers" type="file" id="importCustomers">
|
33 |
</div>
|
34 |
-
</div>
|
35 |
</div>
|
36 |
-
<div class=
|
37 |
-
|
38 |
-
<input type="hidden" name="import">
|
39 |
-
<input type="submit" class="btn btn-info ab-popup-save ab-update-button" value="<?php _e( 'Import' , 'ab' ) ?>" />
|
40 |
-
<button class=ab-reset-form data-dismiss=modal aria-hidden=true><?php _e( 'Cancel' , 'ab' ) ?></button>
|
41 |
-
</div>
|
42 |
</div>
|
43 |
-
</form>
|
44 |
</div>
|
45 |
-
</div>
|
46 |
</div>
|
47 |
-
|
48 |
|
49 |
-
|
50 |
-
<
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
<div ng-click="customer.edit_phone = true" ng-hide=customer.edit_phone class=displayed-value>{{customer.phone}}</div>
|
70 |
-
<input class=ab-value ng-model=customer.phone ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_phone focus-me=customer.edit_phone />
|
71 |
-
</td>
|
72 |
-
<td>
|
73 |
-
<div ng-click="customer.edit_email = true" ng-hide=customer.edit_email class=displayed-value>{{customer.email}}</div>
|
74 |
-
<input class=ab-value ng-model=customer.email ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_email focus-me=customer.edit_email />
|
75 |
-
</td>
|
76 |
-
<td>
|
77 |
-
<div ng-click="customer.edit_notes = true" ng-hide=customer.edit_notes class=displayed-value ng-bind-html="customer.notes | nl2br"></div>
|
78 |
-
<textarea class=ab-value ng-model="customer.notes" ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_notes focus-me=customer.edit_notes></textarea>
|
79 |
-
</td>
|
80 |
-
<td>
|
81 |
-
<div ng-model=customer.last_appointment class=displayed-value>{{customer.last_appointment}}</div>
|
82 |
-
</td>
|
83 |
-
<td>
|
84 |
-
<div ng-model=customer.total_appointments class=displayed-value>{{customer.total_appointments}}</div>
|
85 |
-
</td>
|
86 |
-
<td>
|
87 |
-
<div ng-model=customer.payments class=displayed-value>{{customer.payments}}</div>
|
88 |
-
</td>
|
89 |
-
<td><a href="" ng-click="deleteCustomer(customer)" role="button" class="btn btn-danger" id="{{customer.id}}" name="customer_delete"><?php _e( 'Delete', 'ab' ) ?></a></td>
|
90 |
-
</tr>
|
91 |
-
<tr ng-hide="dataSource.customers.length || loading"><td colspan=6><?php _e( 'No customers', 'ab' ); ?></td></tr>
|
92 |
-
</tbody>
|
93 |
-
</table>
|
94 |
-
<div class="btn-toolbar" ng-hide="dataSource.pages.length == 1">
|
95 |
-
<div class="btn-group">
|
96 |
-
<button ng-click=reload({page:page.number}) class="btn" ng-repeat="page in dataSource.pages" ng-switch on=page.active>
|
97 |
-
<span ng-switch-when=true>{{page.number}}</span>
|
98 |
-
<a href="" ng-switch-default>{{page.number}}</a>
|
99 |
-
</button>
|
100 |
</div>
|
101 |
-
</div>
|
102 |
-
<div ng-show=loading class=loading-indicator>
|
103 |
-
<img src="<?php echo plugins_url('resources/images/ajax_loader_32x32.gif', dirname(__FILE__) . '/../../../AB_Backend.php') ?>" alt="" />
|
104 |
-
</div>
|
105 |
-
|
106 |
</div>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="panel panel-default">
|
3 |
+
<div class="panel-heading">
|
4 |
+
<h3 class="panel-title"><?php _e( 'Customers', 'bookly' ) ?></h3>
|
|
|
|
|
|
|
5 |
</div>
|
6 |
+
<div class="panel-body ab-customers-list">
|
7 |
+
<div ng-app="customers" ng-controller="customersCtrl" class="form-horizontal ng-cloak">
|
8 |
+
<div class="row">
|
9 |
+
<div class="col-md-6 col-xs-12">
|
10 |
+
<div class="control-group">
|
11 |
+
<label for="ab_filter"><?php _e( 'Quick search customer', 'bookly' ) ?></label>
|
12 |
+
<div class=controls>
|
13 |
+
<input id="ab_filter" style="display: inline-block;width: auto;margin-bottom: 20px" class="form-control" type=text ng-model=filter />
|
14 |
+
</div>
|
15 |
+
</div>
|
16 |
+
</div>
|
17 |
+
<div class="col-md-6 col-xs-12">
|
18 |
+
<div style="display: inline;" new-customer-dialog="createCustomer(customer)" backdrop="true" btn-class="btn btn-info"></div>
|
19 |
+
<a href="#ab_import_customers_dialog" class="btn btn-info pull-right" data-toggle="modal"><?php _e( 'Import', 'bookly' ) ?></a>
|
20 |
+
<a style="margin-right: 5px;" href=#ab_new_customer_dialog class="btn btn-info pull-right" data-backdrop=true data-toggle="modal"><?php _e( 'New customer', 'bookly' ) ?></a>
|
21 |
+
<?php include "_import.php" ?>
|
22 |
+
</div>
|
23 |
+
</div>
|
24 |
|
25 |
+
<div class="table-responsive">
|
26 |
+
<table id="ab_customers_list" class="table table-striped" cellspacing=0 cellpadding=0 border=0 style="clear: both;">
|
27 |
+
<thead>
|
28 |
+
<tr>
|
29 |
+
<th style="width: 150px" ng-class=css_class.name><a href="" ng-click=reload({sort:'name'})><?php _e( 'Name', 'bookly' ) ?></a></th>
|
30 |
+
<th style="width: 150px" ng-class=css_class.wp_user><a href="" ng-click=reload({sort:'wp_user'})><?php _e( 'User', 'bookly' ) ?></a></th>
|
31 |
+
<th style="width: 100px" ng-class=css_class.phone><a href="" ng-click=reload({sort:'phone'})><?php _e( 'Phone', 'bookly' ) ?></a></th>
|
32 |
+
<th style="width: 250px" ng-class=css_class.email><a href="" ng-click=reload({sort:'email'})><?php _e( 'Email', 'bookly' ) ?></a></th>
|
33 |
+
<th style="width: 250px" ng-class=css_class.notes><a href="" ng-click=reload({sort:'notes'})><?php _e( 'Notes', 'bookly' ) ?></a></th>
|
34 |
+
<th ng-class=css_class.last_appointment><a href="" ng-click=reload({sort:'last_appointment'})><?php _e( 'Last appointment', 'bookly' ) ?></a></th>
|
35 |
+
<th ng-class=css_class.total_appointments><a href="" ng-click=reload({sort:'total_appointments'})><?php _e( 'Total appointments', 'bookly') ?></a></th>
|
36 |
+
<th ng-class=css_class.payments><a href="" ng-click=reload({sort:'payments'})><?php _e( 'Payments', 'bookly') ?></a></th>
|
37 |
+
<th></th>
|
38 |
+
</tr>
|
39 |
+
</thead>
|
40 |
+
<tbody>
|
41 |
+
<tr ng-repeat="customer in dataSource.customers">
|
42 |
+
<td>
|
43 |
+
<div ng-click="customer.edit_name = true" ng-hide=customer.edit_name class=displayed-value>{{customer.name}}</div>
|
44 |
+
<span ng-show=customer.errors.name.required><?php _e( 'Required', 'bookly' ) ?></span>
|
45 |
+
<input class="form-control ab-value" ng-model=customer.name ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_name focus-me=customer.edit_name required />
|
46 |
+
</td>
|
47 |
+
<td>
|
48 |
+
<div ng-click="customer.edit_wp_user = true" ng-hide=customer.edit_wp_user class=displayed-value>{{customer.wp_user.display_name}}</div>
|
49 |
+
<select ng-model="customer.wp_user" ng-options="wp_user as wp_user.display_name for wp_user in dataSource.wp_users" ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_wp_user
|
50 |
+
focus-me=customer.edit_wp_user class="form-control">
|
51 |
+
<option value=""></option>
|
52 |
+
</select>
|
53 |
+
</td>
|
54 |
+
<td class="ab-phone" click-outside="saveCustomerPhone(customer)">
|
55 |
+
<div ng-click="customer.edit_phone = true" ng-hide=customer.edit_phone class=displayed-value>{{customer.phone}}</div>
|
56 |
+
<input class="form-control ab-value" intl-tel-input=customer.edit_phone intl-tel-input-id=customer.id ng-model=customer.phone ng-show=customer.edit_phone focus-me=customer.edit_phone />
|
57 |
+
</td>
|
58 |
+
<td>
|
59 |
+
<div ng-click="customer.edit_email = true" ng-hide=customer.edit_email class=displayed-value>{{customer.email}}</div>
|
60 |
+
<input class="form-control ab-value" ng-model=customer.email ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_email focus-me=customer.edit_email />
|
61 |
+
</td>
|
62 |
+
<td>
|
63 |
+
<div ng-click="customer.edit_notes = true" ng-hide=customer.edit_notes class=displayed-value ng-bind-html="customer.notes | nl2br"></div>
|
64 |
+
<textarea class="form-control ab-value" ng-model="customer.notes" ui-event="{blur:'saveCustomer(customer)'}" ng-show=customer.edit_notes focus-me=customer.edit_notes></textarea>
|
65 |
+
</td>
|
66 |
+
<td>
|
67 |
+
<div ng-model=customer.last_appointment >{{customer.last_appointment}}</div>
|
68 |
+
</td>
|
69 |
+
<td class="text-right">
|
70 |
+
<div ng-model=customer.total_appointments >{{customer.total_appointments}}</div>
|
71 |
+
</td>
|
72 |
+
<td class="text-right">
|
73 |
+
<div ng-model=customer.payments >{{customer.payments}}</div>
|
74 |
+
</td>
|
75 |
+
<td><input type="checkbox" data-customer_id="{{customer.id}}"></td>
|
76 |
+
</tr>
|
77 |
+
</tbody>
|
78 |
+
</table>
|
79 |
+
<div ng-hide="dataSource.customers.length || loading">
|
80 |
+
<td colspan=9><div class="alert alert-info"><?php _e( 'No customers.', 'bookly' ) ?></div></td>
|
81 |
+
</div>
|
82 |
</div>
|
83 |
+
|
84 |
+
<div class="btn-toolbar">
|
85 |
+
<div class="col-xs-8">
|
86 |
+
<div ng-show="dataSource.pages.length > 1">
|
87 |
+
<div class="btn-group" ng-show="dataSource.paginator.beg">
|
88 |
+
<button ng-click=reload({page:1}) class="btn btn-default">
|
89 |
+
1
|
90 |
+
</button>
|
91 |
+
</div>
|
92 |
+
<div class="btn-group">
|
93 |
+
<button ng-click=reload({page:page.number}) class="btn btn-default" ng-class="{'active': page.active}" ng-repeat="page in dataSource.pages">
|
94 |
+
{{page.number}}
|
95 |
+
</button>
|
96 |
+
</div>
|
97 |
+
<div class="btn-group" ng-show="dataSource.paginator.end != false">
|
98 |
+
<button ng-click=reload({page:dataSource.paginator.end.number}) class="btn btn-default">
|
99 |
+
{{dataSource.paginator.end.number}}
|
100 |
+
</button>
|
101 |
+
</div>
|
102 |
+
</div>
|
103 |
</div>
|
104 |
+
<div class="col-xs-4">
|
105 |
+
<a class="btn btn-info pull-right" ng-click="deleteCustomers()"><?php _e( 'Delete', 'bookly' ) ?></a>
|
|
|
|
|
|
|
106 |
</div>
|
|
|
107 |
</div>
|
108 |
+
<div ng-show="loading" class="loading-indicator">
|
109 |
+
<span class="ab-loader"></span>
|
|
|
|
|
|
|
|
|
110 |
</div>
|
|
|
111 |
</div>
|
|
|
112 |
</div>
|
113 |
+
</div>
|
114 |
|
115 |
+
<div class="modal fade" id="ab-customer-delete">
|
116 |
+
<div class="modal-dialog">
|
117 |
+
<div class="modal-content">
|
118 |
+
<div class="modal-header">
|
119 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
120 |
+
<h4 class="modal-title"><?php _e( 'Delete customers', 'bookly' ) ?></h4>
|
121 |
+
</div>
|
122 |
+
<div class="modal-body">
|
123 |
+
<?php _e( 'You are about to delete customers which may have WordPress accounts associated to them. Do you want to delete those accounts too (if there are any)?', 'bookly' ) ?>
|
124 |
+
<div class="checkbox">
|
125 |
+
<label>
|
126 |
+
<input id="ab-remember-my-choice" type="checkbox"> <?php _e( 'Remember my choice', 'bookly' ) ?>
|
127 |
+
</label>
|
128 |
+
</div>
|
129 |
+
</div>
|
130 |
+
<div class="modal-footer">
|
131 |
+
<button type="button" class="btn btn-default ab-no" data-dismiss="modal"><?php _e( 'No, delete just customers', 'bookly' ) ?></button>
|
132 |
+
<button type="button" class="btn btn-info ab-yes"><?php _e( 'Yes', 'bookly' ) ?></button>
|
133 |
+
</div>
|
134 |
+
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
</div>
|
|
|
|
|
|
|
|
|
|
|
136 |
</div>
|
backend/modules/customer/templates/ng-new_customer_dialog.php
CHANGED
@@ -1,49 +1,110 @@
|
|
|
|
1 |
<div>
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
</div>
|
17 |
-
|
18 |
-
|
19 |
-
<label class=control-label><?php _e( 'Phone' , 'ab' ) ?></label>
|
20 |
-
<div class=controls>
|
21 |
-
<input type=text ng-model=form.phone />
|
22 |
-
</div>
|
23 |
-
</div>
|
24 |
-
<div class=control-group>
|
25 |
-
<label class=control-label><?php _e( 'Email' , 'ab' ) ?></label>
|
26 |
-
<div class=controls>
|
27 |
-
<input type=text ng-model=form.email />
|
28 |
-
</div>
|
29 |
-
</div>
|
30 |
-
<div class=control-group>
|
31 |
-
<label class=control-label><?php _e( 'Notes' , 'ab' ) ?></label>
|
32 |
-
<div class=controls>
|
33 |
-
<textarea ng-model=form.notes></textarea>
|
34 |
-
</div>
|
35 |
-
</div>
|
36 |
-
</div>
|
37 |
-
<div class=modal-footer>
|
38 |
-
<div class=ab-modal-button>
|
39 |
-
<button ng-click=processForm() class="btn btn-info ab-popup-save ab-update-button"><?php _e( 'Save customer' , 'ab' ) ?></button>
|
40 |
-
<button class=ab-reset-form data-dismiss=modal aria-hidden=true><?php _e( 'Cancel' , 'ab' ) ?></button>
|
41 |
-
</div>
|
42 |
-
</div>
|
43 |
-
</form>
|
44 |
-
<div ng-show=loading class=loading-indicator>
|
45 |
-
<img src="<?php echo plugins_url( 'resources/images/ajax_loader_32x32.gif', dirname(__FILE__) . '/../../../AB_Backend.php' ) ?>" alt="" />
|
46 |
-
</div>
|
47 |
-
</div>
|
48 |
-
</div>
|
49 |
</div>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
<div>
|
3 |
+
<div id="ab_new_customer_dialog" class="modal fade">
|
4 |
+
<div class="modal-dialog">
|
5 |
+
<form style="margin-bottom: 0;" ng-hide=loading>
|
6 |
+
<div class="modal-content">
|
7 |
+
<div class="modal-header">
|
8 |
+
<button type=button class=close data-dismiss=modal aria-hidden=true>×</button>
|
9 |
+
<h4 class="modal-title"><?php _e( 'New Customer', 'bookly' ) ?></h4>
|
10 |
+
</div>
|
11 |
+
<div class="modal-body">
|
12 |
+
<fieldset>
|
13 |
+
<legend><?php _e( 'Personal Information', 'bookly' ) ?></legend>
|
14 |
+
<div class="col-md-12">
|
15 |
+
<div class="form-group">
|
16 |
+
<label for="wp_user"><?php _e( 'User', 'bookly' ) ?></label>
|
17 |
+
<select ng-model="form.wp_user_id" class="form-control" id="wp_user">
|
18 |
+
<option value=""></option>
|
19 |
+
<?php foreach ( $wp_users as $wp_user ): ?>
|
20 |
+
<option value="<?php echo $wp_user->ID ?>">
|
21 |
+
<?php echo $wp_user->display_name ?>
|
22 |
+
</option>
|
23 |
+
<?php endforeach ?>
|
24 |
+
</select>
|
25 |
+
</div>
|
26 |
+
|
27 |
+
<div class="form-group">
|
28 |
+
<label for="username"><?php _e( 'Name', 'bookly' ) ?></label>
|
29 |
+
<input class="form-control" type="text" ng-model="form.name" id="username"/>
|
30 |
+
<span style="font-size: 11px;color: red" ng-show="errors.name.required"><?php _e( 'Required', 'bookly' ) ?></span>
|
31 |
+
</div>
|
32 |
+
<div class="form-group">
|
33 |
+
<label for="phone"><?php _e( 'Phone', 'bookly' ) ?></label><br/>
|
34 |
+
<input class="form-control" type="text" ng-model=form.phone id="phone"/>
|
35 |
+
</div>
|
36 |
+
<div class="form-group">
|
37 |
+
<label for="email"><?php _e( 'Email', 'bookly' ) ?></label>
|
38 |
+
<input class="form-control" type="text" ng-model=form.email id="email"/>
|
39 |
+
</div>
|
40 |
+
<div class="form-group">
|
41 |
+
<label for="notes"><?php _e( 'Notes', 'bookly' ) ?></label>
|
42 |
+
<textarea class="form-control" ng-model=form.notes id="notes"></textarea>
|
43 |
+
</div>
|
44 |
+
</div>
|
45 |
+
</fieldset>
|
46 |
+
|
47 |
+
<?php if ( $module !== 'customer' ): ?>
|
48 |
+
<fieldset>
|
49 |
+
<legend><?php _e( 'Custom Fields', 'bookly' ) ?></legend>
|
50 |
+
<div class="new-customer-custom-fields">
|
51 |
+
<div class="col-md-12">
|
52 |
+
<?php foreach ( $custom_fields as $custom_field ): ?>
|
53 |
+
<div class="form-group">
|
54 |
+
<label><?php echo $custom_field->label ?></label>
|
55 |
+
<div class="ab-formField" data-type="<?php echo $custom_field->type ?>" data-id="<?php echo $custom_field->id ?>">
|
56 |
+
<?php if ( $custom_field->type == 'text-field' ): ?>
|
57 |
+
<input type="text" class="form-control ab-custom-field" />
|
58 |
+
|
59 |
+
<?php elseif ( $custom_field->type == 'textarea' ): ?>
|
60 |
+
<textarea rows="3" class="form-control ab-custom-field"></textarea>
|
61 |
+
|
62 |
+
<?php elseif ( $custom_field->type == 'checkboxes' ): ?>
|
63 |
+
<?php foreach ( $custom_field->items as $item ): ?>
|
64 |
+
<div class="checkbox">
|
65 |
+
<label>
|
66 |
+
<input class="ab-custom-field" type="checkbox" value="<?php echo esc_attr( $item ) ?>" />
|
67 |
+
<?php echo $item ?>
|
68 |
+
</label>
|
69 |
+
</div>
|
70 |
+
<?php endforeach ?>
|
71 |
+
|
72 |
+
<?php elseif ( $custom_field->type == 'radio-buttons' ): ?>
|
73 |
+
<?php foreach ( $custom_field->items as $item ): ?>
|
74 |
+
<div class="radio">
|
75 |
+
<label>
|
76 |
+
<input type="radio" name="<?php echo $custom_field->id ?>" class="ab-custom-field" value="<?php echo esc_attr( $item ) ?>" />
|
77 |
+
<?php echo $item ?>
|
78 |
+
</label>
|
79 |
+
</div>
|
80 |
+
<?php endforeach ?>
|
81 |
+
|
82 |
+
<?php elseif ( $custom_field->type == 'drop-down' ): ?>
|
83 |
+
<select class="form-control ab-custom-field">
|
84 |
+
<option value=""></option>
|
85 |
+
<?php foreach ( $custom_field->items as $item ): ?>
|
86 |
+
<option value="<?php echo esc_attr( $item ) ?>"><?php echo $item ?></option>
|
87 |
+
<?php endforeach ?>
|
88 |
+
</select>
|
89 |
+
|
90 |
+
<?php endif ?>
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
<?php endforeach ?>
|
94 |
+
</div>
|
95 |
+
</div>
|
96 |
+
</fieldset>
|
97 |
+
<?php endif ?>
|
98 |
+
</div>
|
99 |
+
<div class="modal-footer">
|
100 |
+
<button ng-click=processForm() class="btn btn-info ab-popup-save"><?php _e( 'Create customer', 'bookly' ) ?></button>
|
101 |
+
<button class=ab-reset-form data-dismiss=modal aria-hidden=true><?php _e( 'Cancel', 'bookly' ) ?></button>
|
102 |
+
</div>
|
103 |
+
</div><!-- /.modal-content -->
|
104 |
+
</form>
|
105 |
+
<div ng-show=loading class=loading-indicator>
|
106 |
+
<span class="ab-loader"></span>
|
107 |
</div>
|
108 |
+
</div><!-- /.modal-dialog -->
|
109 |
+
</div><!-- /.modal -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
110 |
</div>
|
backend/modules/export/AB_ExportController.php
DELETED
@@ -1,123 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Class AB_ExportController
|
7 |
-
*/
|
8 |
-
class AB_ExportController extends AB_Controller {
|
9 |
-
|
10 |
-
public function index() {
|
11 |
-
$path = dirname( dirname( __FILE__ ) );
|
12 |
-
wp_enqueue_style( 'ab-style', plugins_url( 'resources/css/ab_style.css', $path ) );
|
13 |
-
wp_enqueue_style( 'ab-bootstrap', plugins_url( 'resources/bootstrap/css/bootstrap.min.css', $path ) );
|
14 |
-
wp_enqueue_script( 'ab-bootstrap', plugins_url( 'resources/bootstrap/js/bootstrap.min.js', $path ), array( 'jquery' ) );
|
15 |
-
wp_enqueue_script( 'ab-date', plugins_url( 'resources/js/date.js', $path ), array( 'jquery' ) );
|
16 |
-
wp_enqueue_script( 'ab-daterangepicker-js', plugins_url( 'resources/js/daterangepicker.js', $path ), array( 'jquery' ) );
|
17 |
-
wp_enqueue_style( 'ab-daterangepicker-css', plugins_url( 'resources/css/daterangepicker.css', $path ) );
|
18 |
-
wp_enqueue_script( 'ab-bootstrap-select-js', plugins_url( 'resources/js/bootstrap-select.min.js', $path ));
|
19 |
-
wp_enqueue_style( 'ab-bootstrap-select-css', plugins_url( 'resources/css/bootstrap-select.min.css', $path ));
|
20 |
-
wp_localize_script( 'ab-daterangepicker-js', 'BooklyL10n', array(
|
21 |
-
'today' => __( 'Today', 'ab' ),
|
22 |
-
'yesterday' => __( 'Yesterday', 'ab' ),
|
23 |
-
'last_7' => __( 'Last 7 Days', 'ab' ),
|
24 |
-
'last_30' => __( 'Last 30 Days', 'ab' ),
|
25 |
-
'this_month' => __( 'This Month', 'ab' ),
|
26 |
-
'last_month' => __( 'Last Month', 'ab' ),
|
27 |
-
'custom_range' => __( 'Custom Range', 'ab' ),
|
28 |
-
'apply' => __( 'Apply', 'ab' ),
|
29 |
-
'clear' => __( 'Clear', 'ab' ),
|
30 |
-
'to' => __( 'To', 'ab' ),
|
31 |
-
'from' => __( 'From', 'ab' ),
|
32 |
-
'month' => array(
|
33 |
-
0 => __( 'January', 'ab' ),
|
34 |
-
1 => __( 'February', 'ab' ),
|
35 |
-
2 => __( 'March', 'ab' ),
|
36 |
-
3 => __( 'April', 'ab' ),
|
37 |
-
4 => __( 'May', 'ab' ),
|
38 |
-
5 => __( 'June', 'ab' ),
|
39 |
-
6 => __( 'July', 'ab' ),
|
40 |
-
7 => __( 'August', 'ab' ),
|
41 |
-
8 => __( 'September', 'ab' ),
|
42 |
-
9 => __( 'October', 'ab' ),
|
43 |
-
10 => __( 'November', 'ab' ),
|
44 |
-
11 => __( 'December', 'ab' )
|
45 |
-
),
|
46 |
-
'day' => array(
|
47 |
-
'Mon' => __( 'Mon', 'ab' ),
|
48 |
-
'Tue' => __( 'Tue', 'ab' ),
|
49 |
-
'Wed' => __( 'Wed', 'ab' ),
|
50 |
-
'Thu' => __( 'Thu', 'ab' ),
|
51 |
-
'Fri' => __( 'Fri', 'ab' ),
|
52 |
-
'Sat' => __( 'Sat', 'ab' ),
|
53 |
-
'Sun' => __( 'Sun', 'ab' )
|
54 |
-
)
|
55 |
-
));
|
56 |
-
$this->render( 'index' );
|
57 |
-
} // index
|
58 |
-
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Export Appointment to CSV
|
62 |
-
*/
|
63 |
-
public function executeExportToCSV ( ) {
|
64 |
-
$_post = $this->getPost();
|
65 |
-
$start_date = new DateTime($_post['date_start']);
|
66 |
-
$start_date = $start_date->format('Y-m-d H:i:s');
|
67 |
-
$end_date = new DateTime($_post['date_end']);
|
68 |
-
$end_date->modify( '+1 day' );
|
69 |
-
$end_date = $end_date->format('Y-m-d H:i:s');
|
70 |
-
|
71 |
-
header('Content-Type: text/csv; charset=' . (WPLANG == 'ru_RU') ? 'windows-1251': 'utf-8');
|
72 |
-
header('Content-Disposition: attachment; filename=appointment.csv');
|
73 |
-
|
74 |
-
if (WPLANG == 'ru_RU'){
|
75 |
-
$headings = array(
|
76 |
-
iconv('utf-8', 'windows-1251', __('Customer name', 'ab')),
|
77 |
-
iconv('utf-8', 'windows-1251', __('Service title', 'ab')),
|
78 |
-
iconv('utf-8', 'windows-1251', __('Start date', 'ab')),
|
79 |
-
iconv('utf-8', 'windows-1251', __('End date', 'ab')),
|
80 |
-
iconv('utf-8', 'windows-1251', __('Notes', 'ab')));
|
81 |
-
}else{
|
82 |
-
$headings = array(
|
83 |
-
__('Customer name', 'ab'),
|
84 |
-
__('Service title', 'ab'),
|
85 |
-
__('Start date', 'ab'),
|
86 |
-
__('End date', 'ab'),
|
87 |
-
__('Notes', 'ab'));
|
88 |
-
}
|
89 |
-
$output = fopen('php://output', 'w');
|
90 |
-
fputcsv($output, $headings);
|
91 |
-
|
92 |
-
$appointments = $this->getWpdb()->get_results("
|
93 |
-
SELECT c.name AS customer_name,
|
94 |
-
s.title AS service_title,
|
95 |
-
a.start_date AS start_date,
|
96 |
-
a.end_date AS end_date,
|
97 |
-
a.notes AS notes
|
98 |
-
FROM ab_appointment a
|
99 |
-
LEFT JOIN ab_service s ON a.service_id = s.id
|
100 |
-
LEFT JOIN ab_customer c ON a.customer_id = c.id
|
101 |
-
WHERE a.start_date between '{$start_date}' AND '{$end_date}'
|
102 |
-
ORDER BY a.start_date DESC
|
103 |
-
", ARRAY_A);
|
104 |
-
|
105 |
-
foreach( $appointments as $appointment ) {
|
106 |
-
if (WPLANG == 'ru_RU'){
|
107 |
-
$appointment['customer_name'] = iconv('utf-8', 'windows-1251', $appointment['customer_name']);
|
108 |
-
$appointment['notes'] = iconv('utf-8', 'windows-1251', $appointment['notes']);
|
109 |
-
$appointment['service_title'] = iconv('utf-8', 'windows-1251', $appointment['service_title']);
|
110 |
-
}
|
111 |
-
fputcsv($output, $appointment);
|
112 |
-
}
|
113 |
-
fclose($output);
|
114 |
-
exit();
|
115 |
-
}
|
116 |
-
/**
|
117 |
-
* Override parent method to add 'wp_ajax_ab_' prefix
|
118 |
-
* so current 'execute*' methods look nicer.
|
119 |
-
*/
|
120 |
-
protected function registerWpActions( $prefix = '' ) {
|
121 |
-
parent::registerWpActions( 'wp_ajax_ab_' );
|
122 |
-
}
|
123 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/export/templates/index.php
DELETED
@@ -1,47 +0,0 @@
|
|
1 |
-
<div class="ab-title"><?php _e( 'Export appointments', 'ab' ); ?></div>
|
2 |
-
<div class=ab-nav-payment>
|
3 |
-
<form action="<?php echo get_admin_url(); ?>admin-ajax.php?action=ab_export_to_csv" method="post" style="margin: 0">
|
4 |
-
<div id=reportrange class="pull-left ab-reportrange" style="margin-bottom: 10px">
|
5 |
-
|
6 |
-
<i class="icon-calendar icon-large"></i>
|
7 |
-
<span data-date="<?php echo date( 'F j, Y', strtotime( '-30 day' ) ) ?> - <?php echo date( 'F j, Y' ) ?>"><?php echo date_i18n( get_option( 'date_format' ), strtotime( '-30 day' ) ) ?> - <?php echo date_i18n( get_option( 'date_format' ) ) ?></span> <b style="margin-top: 8px;" class=caret></b>
|
8 |
-
|
9 |
-
</div>
|
10 |
-
<input type="hidden" id="date_start" name="date_start" value="<?php echo date_i18n( get_option( 'date_format' ) ) ?>"/>
|
11 |
-
<input type="hidden" id="date_end" name="date_end" value="<?php echo date_i18n( get_option( 'date_format' ) ) ?>"/>
|
12 |
-
<input type="submit" class="btn btn-info right-margin left" value="<?php _e('Export to CSV','ab') ?>">
|
13 |
-
</form>
|
14 |
-
|
15 |
-
</div>
|
16 |
-
<script type="text/javascript">
|
17 |
-
jQuery(function($) {
|
18 |
-
var data = {},
|
19 |
-
$report_range = $('#reportrange span'),
|
20 |
-
picker_ranges = {},
|
21 |
-
l10nRanges = {
|
22 |
-
response: function(start, end) {
|
23 |
-
return $.post(ajaxurl, {action: 'ab_l10n_ranges', start: start, end: end});
|
24 |
-
},
|
25 |
-
l10n: function(start, end) {
|
26 |
-
this.response(start, end).done(function(response) {
|
27 |
-
var ranges = JSON.parse(response);
|
28 |
-
$report_range.data('date', start.toString('MMMM d, yyyy') + ' - ' + end.toString('MMMM d, yyyy'));
|
29 |
-
$report_range.html(ranges.start + ' - ' + ranges.end);
|
30 |
-
});
|
31 |
-
}
|
32 |
-
};
|
33 |
-
|
34 |
-
picker_ranges[BooklyL10n.today] = ['today', 'today'];
|
35 |
-
picker_ranges[BooklyL10n.yesterday] = ['yesterday', 'yesterday'];
|
36 |
-
picker_ranges[BooklyL10n.last_7] = [Date.today().add({ days: -6 }), 'today'];
|
37 |
-
picker_ranges[BooklyL10n.last_30] = [Date.today().add({ days: -30 }), 'today','selected'];
|
38 |
-
picker_ranges[BooklyL10n.this_month] = [Date.today().moveToFirstDayOfMonth(), Date.today().moveToLastDayOfMonth()];
|
39 |
-
picker_ranges[BooklyL10n.last_month] = [Date.today().moveToFirstDayOfMonth().add({ months: -1 }), Date.today().moveToFirstDayOfMonth().add({ days: -1 })];
|
40 |
-
|
41 |
-
$('#reportrange').daterangepicker({ranges: picker_ranges}, function(start, end) {
|
42 |
-
l10nRanges.l10n(start, end);
|
43 |
-
$('#date_start').val(start);
|
44 |
-
$('#date_end').val(end);
|
45 |
-
});
|
46 |
-
});
|
47 |
-
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/notifications/AB_NotificationsController.php
CHANGED
@@ -1,53 +1,57 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
5 |
class AB_NotificationsController extends AB_Controller {
|
6 |
|
7 |
-
public function index()
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
}
|
52 |
|
53 |
// Protected methods.
|
@@ -55,8 +59,12 @@ class AB_NotificationsController extends AB_Controller {
|
|
55 |
/**
|
56 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
57 |
* so current 'execute*' methods look nicer.
|
|
|
|
|
58 |
*/
|
59 |
-
protected function registerWpActions( $prefix = '' )
|
|
|
60 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
61 |
}
|
|
|
62 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
class AB_NotificationsController extends AB_Controller {
|
4 |
|
5 |
+
public function index()
|
6 |
+
{
|
7 |
+
$this->enqueueStyles( array(
|
8 |
+
'frontend' => array(
|
9 |
+
'css/ladda.min.css'
|
10 |
+
),
|
11 |
+
'module' => array(
|
12 |
+
'css/notifications.css'
|
13 |
+
),
|
14 |
+
'backend' => array(
|
15 |
+
'css/bookly.main-backend.css',
|
16 |
+
'bootstrap/css/bootstrap.min.css',
|
17 |
+
)
|
18 |
+
) );
|
19 |
+
|
20 |
+
$this->enqueueScripts( array(
|
21 |
+
'backend' => array(
|
22 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
23 |
+
),
|
24 |
+
'module' => array(
|
25 |
+
'js/notification.js' => array( 'jquery' ),
|
26 |
+
),
|
27 |
+
'frontend' => array(
|
28 |
+
'js/spin.min.js' => array( 'jquery' ),
|
29 |
+
'js/ladda.min.js' => array( 'jquery' ),
|
30 |
+
)
|
31 |
+
) );
|
32 |
+
|
33 |
+
$this->form = new AB_NotificationsForm( 'email' );
|
34 |
+
$this->message = '';
|
35 |
+
// Save action.
|
36 |
+
if ( !empty ( $_POST ) ) {
|
37 |
+
$this->message = __( 'Notification settings were updated successfully.', 'bookly' );
|
38 |
+
// sender name
|
39 |
+
if ( $this->hasParameter( 'ab_settings_sender_name' ) ) {
|
40 |
+
update_option( 'ab_settings_sender_name', $this->getParameter( 'ab_settings_sender_name' ) );
|
41 |
+
}
|
42 |
+
// sender email
|
43 |
+
if ( $this->hasParameter( 'ab_settings_sender_email' ) ) {
|
44 |
+
update_option( 'ab_settings_sender_email', $this->getParameter( 'ab_settings_sender_email' ) );
|
45 |
+
}
|
46 |
+
if ( $this->hasParameter( 'ab_email_notification_reply_to_customers' ) ) {
|
47 |
+
update_option( 'ab_email_notification_reply_to_customers', $this->getParameter( 'ab_email_notification_reply_to_customers' ) );
|
48 |
+
}
|
49 |
+
if ( $this->hasParameter( 'ab_email_content_type' ) ) {
|
50 |
+
update_option( 'ab_email_content_type', $this->getParameter( 'ab_email_content_type' ) );
|
51 |
+
}
|
52 |
+
}
|
53 |
+
|
54 |
+
$this->render( 'index' );
|
55 |
}
|
56 |
|
57 |
// Protected methods.
|
59 |
/**
|
60 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
61 |
* so current 'execute*' methods look nicer.
|
62 |
+
*
|
63 |
+
* @param string $prefix
|
64 |
*/
|
65 |
+
protected function registerWpActions( $prefix = '' )
|
66 |
+
{
|
67 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
68 |
}
|
69 |
+
|
70 |
}
|
backend/modules/notifications/forms/AB_NotificationsForm.php
ADDED
@@ -0,0 +1,166 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
class AB_NotificationsForm extends AB_Form {
|
4 |
+
|
5 |
+
public $types = array(
|
6 |
+
'client_new_appointment',
|
7 |
+
'staff_new_appointment',
|
8 |
+
'staff_cancelled_appointment',
|
9 |
+
'client_new_wp_user',
|
10 |
+
'client_reminder',
|
11 |
+
'client_follow_up',
|
12 |
+
'staff_agenda',
|
13 |
+
);
|
14 |
+
public $gateway;
|
15 |
+
|
16 |
+
public function __construct( $gateway = 'email' )
|
17 |
+
{
|
18 |
+
/*
|
19 |
+
* make Visual Mode as default (instead of Text Mode)
|
20 |
+
* allowed: tinymce - Visual Mode, html - Text Mode, test - no one Mode selected
|
21 |
+
*/
|
22 |
+
add_filter( 'wp_default_editor', create_function( '', 'return \'tinymce\';' ) );
|
23 |
+
$this->gateway = $gateway;
|
24 |
+
$this->setFields( array(
|
25 |
+
'active',
|
26 |
+
'subject',
|
27 |
+
'message',
|
28 |
+
'copy',
|
29 |
+
) );
|
30 |
+
|
31 |
+
$this->load();
|
32 |
+
}
|
33 |
+
|
34 |
+
public function bind( array $_post = array(), array $files = array() )
|
35 |
+
{
|
36 |
+
foreach ( $this->types as $type ) {
|
37 |
+
foreach ( $this->fields as $field ) {
|
38 |
+
if ( isset($_post[ $type ][ $field ] ) ) {
|
39 |
+
$this->data[ $type ][ $field ] = $_post[ $type ][ $field ];
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
}
|
44 |
+
|
45 |
+
/**
|
46 |
+
* @return bool|void
|
47 |
+
*/
|
48 |
+
public function save()
|
49 |
+
{
|
50 |
+
return;
|
51 |
+
}
|
52 |
+
|
53 |
+
public function load()
|
54 |
+
{
|
55 |
+
foreach ( $this->types as $type ) {
|
56 |
+
if ( ( $object = new AB_Notification() ) && $object->loadBy( array( 'type' => $type, 'gateway' => $this->gateway ) ) ) {
|
57 |
+
$this->data[ $type ][ 'active' ] = $object->get( 'active' );
|
58 |
+
$this->data[ $type ][ 'subject' ] = $object->get( 'subject' );
|
59 |
+
$this->data[ $type ][ 'message' ] = $object->get( 'message' );
|
60 |
+
$this->data[ $type ][ 'name' ] = $this->getNotificationName( $type );
|
61 |
+
if ( $type == 'staff_new_appointment' || $type == 'staff_cancelled_appointment' ) {
|
62 |
+
$this->data[ $type ][ 'copy' ] = $object->get( 'copy' );
|
63 |
+
}
|
64 |
+
}
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* @param $type
|
70 |
+
* @return mixed
|
71 |
+
*/
|
72 |
+
public function getNotificationName ( $type )
|
73 |
+
{
|
74 |
+
$notifications_name = array(
|
75 |
+
'client_new_appointment' => __( 'Notification to customer about appointment details', 'bookly' ),
|
76 |
+
'staff_new_appointment' => __( 'Notification to staff member about appointment details', 'bookly' ),
|
77 |
+
'staff_cancelled_appointment' => __( 'Notification to staff member about appointment cancellation', 'bookly' ),
|
78 |
+
'client_new_wp_user' => __( 'Notification to customer about their WordPress user login details', 'bookly' ),
|
79 |
+
'client_reminder' => __( 'Evening reminder to customer about next day appointment (requires cron setup)', 'bookly' ),
|
80 |
+
'client_follow_up' => __( 'Follow-up message in the same day after appointment (requires cron setup)', 'bookly' ),
|
81 |
+
'staff_agenda' => __( 'Evening notification with the next day agenda to staff member (requires cron setup)', 'bookly' ),
|
82 |
+
);
|
83 |
+
|
84 |
+
return $notifications_name[ $type ];
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Render the "active" form
|
89 |
+
*
|
90 |
+
* @param $type
|
91 |
+
* @return string
|
92 |
+
*/
|
93 |
+
public function renderActive( $type )
|
94 |
+
{
|
95 |
+
$title = isset( $this->data[ $type ]['name'] ) ? $this->data[ $type ]['name'] : '';
|
96 |
+
|
97 |
+
return $title;
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* @param $type
|
102 |
+
* @return string
|
103 |
+
*/
|
104 |
+
public function renderSubject( $type )
|
105 |
+
{
|
106 |
+
$id = $type . '_subject';
|
107 |
+
$name = $type . '[subject]';
|
108 |
+
$value = isset( $this->data[ $type ]['subject'] ) ? $this->data[$type]['subject'] : '';
|
109 |
+
|
110 |
+
return "<label class='ab-form-label' for='{$id}' style='margin-top: 19px;'>" . __( 'Subject', 'bookly' ) . "</label><input type='text' size='70' id='{$id}' name='{$name}' value='{$value}' class='form-control' />";
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* @param $type
|
115 |
+
* @return string
|
116 |
+
*/
|
117 |
+
public function renderMessage( $type )
|
118 |
+
{
|
119 |
+
$id = $type.'_message';
|
120 |
+
$name = $type.'[message]';
|
121 |
+
$value = isset( $this->data[$type]['message'] ) ? $this->data[$type]['message'] : '';
|
122 |
+
|
123 |
+
if ( 'sms' == $this->gateway ) {
|
124 |
+
return "<textarea rows='6' id='{$id}' name='{$name}' class='ab-sms-message pull-left'>".esc_textarea( $value )."</textarea>";
|
125 |
+
} else {
|
126 |
+
$settings = array(
|
127 |
+
'textarea_name' => $name,
|
128 |
+
'media_buttons' => false,
|
129 |
+
'tinymce' => array(
|
130 |
+
'theme_advanced_buttons1' => 'formatselect,|,bold,italic,underline,|,'.
|
131 |
+
'bullist,blockquote,|,justifyleft,justifycenter'.
|
132 |
+
',justifyright,justifyfull,|,link,unlink,|'.
|
133 |
+
',spellchecker,wp_fullscreen,wp_adv'
|
134 |
+
)
|
135 |
+
);
|
136 |
+
|
137 |
+
wp_editor( $value, $id, $settings );
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Render the "copy" form
|
143 |
+
*
|
144 |
+
* @param $type
|
145 |
+
* @return string
|
146 |
+
*/
|
147 |
+
public function renderCopy( $type )
|
148 |
+
{
|
149 |
+
$id = $type . '_copy';
|
150 |
+
$name = $type . '[copy]';
|
151 |
+
$checked = checked( ( isset( $this->data[ $type ]['copy'] ) && intval( $this->data[ $type ]['copy'] ) ), true, false );
|
152 |
+
$title = __( 'Send copy to administrators', 'bookly' );
|
153 |
+
|
154 |
+
return "<div class='ab-form-row'>
|
155 |
+
<label class='ab-form-label'></label>
|
156 |
+
<div>
|
157 |
+
<legend>
|
158 |
+
<input name='{$name}' type=hidden value=0 />
|
159 |
+
<input id='{$id}' name='{$name}' type=checkbox value=1 {$checked} />
|
160 |
+
<label for='{$id}'> {$title}</label>
|
161 |
+
</legend>
|
162 |
+
</div>
|
163 |
+
</div>";
|
164 |
+
}
|
165 |
+
|
166 |
+
}
|
backend/modules/notifications/resources/css/notifications.css
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* notifications */
|
2 |
+
.ab-notifications tr td { padding-left: 10px; }
|
3 |
+
.ab-notifications input[type=text],
|
4 |
+
.ab-notifications select { margin-top: 10px; min-width: 250px; }
|
5 |
+
.ab-notifications .ab-form-field { padding-top: 10px; }
|
6 |
+
.ab-notifications .ab-toggle-arrow { position: absolute; right: 0; top: 9px; width: 24px; height: 24px; cursor: pointer; }
|
7 |
+
.ab-notifications .ab-form-label { display: block; float: left; margin-top: 3px; min-width: 80px; }
|
8 |
+
.ab-notifications .ab-form-row { padding: 3px 0; overflow: hidden; }
|
9 |
+
.ab-notifications .ab-form-row input[type="text"] { width: 700px!important; position: relative; z-index: 9; }
|
10 |
+
.ab-notifications #message_editor { margin-top: -20px; }
|
11 |
+
.ab-notifications legend { margin: 0; border: 0; line-height: normal; }
|
12 |
+
.ab-notifications legend input { margin: 0!important; }
|
13 |
+
.ab-notifications legend label { display: inline; font-size: 17px; }
|
14 |
+
.ab-notifications #message_editor .wp-editor-wrap { margin-left: 81px; }
|
15 |
+
.ab-notifications .panel-title > input { margin: 0 5px 0 0; }
|
16 |
+
.ab-notifications .ab-codes table tr td { padding: 0 20px 0 0; font-size: 12px;}
|
17 |
+
.ab-notifications .ab-codes table tr td input { cursor: pointer; border: none; width: 250px; }
|
18 |
+
.ab-notifications .wp-editor-tools { position: relative; top: 26px; }
|
19 |
+
.ab-notifications a[data-toggle="collapse"] {
|
20 |
+
outline: none;
|
21 |
+
box-shadow: none;
|
22 |
+
padding-right: 25px;
|
23 |
+
background: url("../../../../resources/images/notifications-arrow-up.png") 100% 50% no-repeat;
|
24 |
+
background-size: 17px 17px;
|
25 |
+
}
|
26 |
+
.ab-notifications a[data-toggle="collapse"].collapsed {
|
27 |
+
background: url("../../../../resources/images/notifications-arrow-down.png") 100% 50% no-repeat;
|
28 |
+
background-size: 17px 17px;
|
29 |
+
}
|
backend/modules/notifications/resources/js/notification.js
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function($) {
|
2 |
+
|
3 |
+
Ladda.bind( 'button[type=submit]' );
|
4 |
+
|
5 |
+
// menu fix for WP 3.8.1
|
6 |
+
$('#toplevel_page_ab-system > ul').css('margin-left', '0px');
|
7 |
+
|
8 |
+
/* exclude checkboxes in form */
|
9 |
+
var $checkboxes = $('.ab-notifications .panel-title > input:checkbox[id!=_active]');
|
10 |
+
|
11 |
+
$checkboxes.change(function () {
|
12 |
+
$(this).parents('.panel-heading').next().collapse(this.checked ? 'show' : 'hide');
|
13 |
+
$('#lite_notice').modal('show');
|
14 |
+
});
|
15 |
+
|
16 |
+
// filter sender name and email
|
17 |
+
var escapeXSS = function (infected) {
|
18 |
+
var regexp = /([<|(]("[^"]*"|'[^']*'|[^'">])*[>|)])/gi;
|
19 |
+
return infected.replace(regexp, '');
|
20 |
+
};
|
21 |
+
$('input.ab-sender').on('change', function() {
|
22 |
+
var $val = $(this).val();
|
23 |
+
$(this).val(escapeXSS($val));
|
24 |
+
});
|
25 |
+
|
26 |
+
$('.ab-popover').popover({
|
27 |
+
trigger : 'hover'
|
28 |
+
});
|
29 |
+
|
30 |
+
});
|
backend/modules/notifications/templates/_codes.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<tr><td><input value="[[APPOINTMENT_DATE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('date of appointment', 'bookly') ?></td></tr>
|
3 |
+
<tr><td><input value="[[APPOINTMENT_TIME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('time of appointment', 'bookly') ?></td></tr>
|
4 |
+
<tr><td><input value="[[CANCEL_APPOINTMENT]]" readonly="readonly" onclick="this.select()" /> - <?php _e('cancel appointment link', 'bookly') ?></td></tr>
|
5 |
+
<tr><td><input value="[[CANCEL_APPOINTMENT_URL]]" readonly="readonly" onclick="this.select()" /> - <?php echo esc_html( __('URL for cancel appointment link (to use inside <a> tag)', 'bookly') ) ?></td></tr>
|
6 |
+
<tr><td><input value="[[CATEGORY_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of category', 'bookly') ?></td></tr>
|
7 |
+
<tr><td><input value="[[CLIENT_EMAIL]]" readonly="readonly" onclick="this.select()" /> - <?php _e('email of client', 'bookly') ?></td></tr>
|
8 |
+
<tr><td><input value="[[CLIENT_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of client', 'bookly') ?></td></tr>
|
9 |
+
<tr><td><input value="[[CLIENT_PHONE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('phone of client', 'bookly') ?></td></tr>
|
10 |
+
<tr><td><input value="[[COMPANY_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of your company', 'bookly') ?></td></tr>
|
11 |
+
<tr><td><input value="[[COMPANY_LOGO]]" readonly="readonly" onclick="this.select()" /> - <?php _e('your company logo', 'bookly') ?></td></tr>
|
12 |
+
<tr><td><input value="[[COMPANY_ADDRESS]]" readonly="readonly" onclick="this.select()" /> - <?php _e('address of your company', 'bookly') ?></td></tr>
|
13 |
+
<tr><td><input value="[[COMPANY_PHONE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('your company phone', 'bookly') ?></td></tr>
|
14 |
+
<tr><td><input value="[[COMPANY_WEBSITE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('this web-site address', 'bookly') ?></td></tr>
|
15 |
+
<tr><td><input value="[[CUSTOM_FIELDS]]" readonly="readonly" onclick="this.select()" /> - <?php _e('combined values of all custom fields', 'bookly') ?></td></tr>
|
16 |
+
<tr><td><input value="[[CUSTOM_FIELDS_2C]]" readonly="readonly" onclick="this.select()" /> - <?php _e('combined values of all custom fields (formatted in 2 columns)', 'bookly') ?></td></tr>
|
17 |
+
<tr><td><input value="[[NUMBER_OF_PERSONS]]" readonly="readonly" onclick="this.select()" /> - <?php _e('number of persons', 'bookly') ?></td></tr>
|
18 |
+
<tr><td><input value="[[SERVICE_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of service', 'bookly') ?></td></tr>
|
19 |
+
<tr><td><input value="[[SERVICE_PRICE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('price of service', 'bookly') ?></td></tr>
|
20 |
+
<tr><td><input value="[[STAFF_EMAIL]]" readonly="readonly" onclick="this.select()" /> - <?php _e('email of staff', 'bookly') ?></td></tr>
|
21 |
+
<tr><td><input value="[[STAFF_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of staff', 'bookly') ?></td></tr>
|
22 |
+
<tr><td><input value="[[STAFF_PHONE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('phone of staff', 'bookly') ?></td></tr>
|
23 |
+
<tr><td><input value="[[STAFF_PHOTO]]" readonly="readonly" onclick="this.select()" /> - <?php _e('photo of staff', 'bookly') ?></td></tr>
|
24 |
+
<tr><td><input value="[[TOTAL_PRICE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('total price of booking (service price multiplied by the number of persons)', 'bookly') ?></td></tr>
|
backend/modules/notifications/templates/_codes_client_new_wp_user.php
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<tr><td><input value="[[CLIENT_EMAIL]]" readonly="readonly" onclick="this.select()" /> - <?php _e('email of client', 'bookly') ?></td></tr>
|
3 |
+
<tr><td><input value="[[CLIENT_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of client', 'bookly') ?></td></tr>
|
4 |
+
<tr><td><input value="[[CLIENT_PHONE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('phone of client', 'bookly') ?></td></tr>
|
5 |
+
<tr><td><input value="[[COMPANY_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of your company', 'bookly') ?></td></tr>
|
6 |
+
<tr><td><input value="[[COMPANY_LOGO]]" readonly="readonly" onclick="this.select()" /> - <?php _e('your company logo', 'bookly') ?></td></tr>
|
7 |
+
<tr><td><input value="[[COMPANY_ADDRESS]]" readonly="readonly" onclick="this.select()" /> - <?php _e('address of your company', 'bookly') ?></td></tr>
|
8 |
+
<tr><td><input value="[[COMPANY_PHONE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('your company phone', 'bookly') ?></td></tr>
|
9 |
+
<tr><td><input value="[[COMPANY_WEBSITE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('this web-site address', 'bookly') ?></td></tr>
|
10 |
+
<tr><td><input value="[[NEW_USERNAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('customer new username', 'bookly') ?></td></tr>
|
11 |
+
<tr><td><input value="[[NEW_PASSWORD]]" readonly="readonly" onclick="this.select()" /> - <?php _e('customer new password', 'bookly') ?></td></tr>
|
12 |
+
<tr><td><input value="[[SITE_ADDRESS]]" readonly="readonly" onclick="this.select()" /> - <?php _e('site address', 'bookly') ?></td></tr>
|
backend/modules/notifications/templates/_codes_staff_agenda.php
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<tr><td><input value="[[TOMORROW_DATE]]" readonly="readonly" onclick="this.select()" /> - <?php _e('date of next day', 'bookly') ?></td></tr>
|
3 |
+
<tr><td><input value="[[NEXT_DAY_AGENDA]]" readonly="readonly" onclick="this.select()" /> - <?php _e('staff agenda for next day', 'bookly') ?></td></tr>
|
4 |
+
<tr><td><input value="[[STAFF_NAME]]" readonly="readonly" onclick="this.select()" /> - <?php _e('name of staff', 'bookly') ?></td></tr>
|
backend/modules/notifications/templates/_tags_client_info.php
DELETED
@@ -1,48 +0,0 @@
|
|
1 |
-
<tr>
|
2 |
-
<th><?php _e('Subject', 'ab') ?></th>
|
3 |
-
<th><?php _e('Message', 'ab') ?></th>
|
4 |
-
</tr>
|
5 |
-
<tr>
|
6 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
7 |
-
<td><?php _e('[[CLIENT_NAME]] - name of client', 'ab') ?></td>
|
8 |
-
</tr>
|
9 |
-
<tr>
|
10 |
-
<td></td>
|
11 |
-
<td><?php _e('[[STAFF_NAME]] - name of staff', 'ab') ?></td>
|
12 |
-
</tr>
|
13 |
-
<tr>
|
14 |
-
<td></td>
|
15 |
-
<td><?php _e('[[APPOINTMENT_DATE]] - date of appointment', 'ab') ?></td>
|
16 |
-
</tr>
|
17 |
-
<tr>
|
18 |
-
<td></td>
|
19 |
-
<td><?php _e('[[APPOINTMENT_TIME]] - time of appointment', 'ab') ?></td>
|
20 |
-
</tr>
|
21 |
-
<tr>
|
22 |
-
<td></td>
|
23 |
-
<td><?php _e('[[SERVICE_NAME]] - name of service', 'ab') ?></td>
|
24 |
-
</tr>
|
25 |
-
<tr>
|
26 |
-
<td></td>
|
27 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
28 |
-
</tr>
|
29 |
-
<tr>
|
30 |
-
<td></td>
|
31 |
-
<td><?php _e('[[COMPANY_LOGO]] - company logo', 'ab') ?></td>
|
32 |
-
</tr>
|
33 |
-
<tr>
|
34 |
-
<td></td>
|
35 |
-
<td><?php _e('[[COMPANY_ADDRESS]] - address of your company', 'ab') ?></td>
|
36 |
-
</tr>
|
37 |
-
<tr>
|
38 |
-
<td></td>
|
39 |
-
<td><?php _e('[[COMPANY_PHONE]] - company phone', 'ab') ?></td>
|
40 |
-
</tr>
|
41 |
-
<tr>
|
42 |
-
<td></td>
|
43 |
-
<td><?php _e('[[COMPANY_WEBSITE]] - this web-site address', 'ab') ?></td>
|
44 |
-
</tr>
|
45 |
-
<tr>
|
46 |
-
<td></td>
|
47 |
-
<td><?php _e('[[CANCEL_APPOINTMENT]] - cancel appointment link', 'ab') ?></td>
|
48 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/notifications/templates/_tags_evening_after.php
DELETED
@@ -1,40 +0,0 @@
|
|
1 |
-
<tr>
|
2 |
-
<th><?php _e('Subject', 'ab') ?></th>
|
3 |
-
<th><?php _e('Message', 'ab') ?></th>
|
4 |
-
</tr>
|
5 |
-
<tr>
|
6 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
7 |
-
<td><?php _e('[[CLIENT_NAME]] - name of client', 'ab') ?></td>
|
8 |
-
</tr>
|
9 |
-
<tr>
|
10 |
-
<td></td>
|
11 |
-
<td><?php _e('[[APPOINTMENT_DATE]] - date of appointment', 'ab') ?></td>
|
12 |
-
</tr>
|
13 |
-
<tr>
|
14 |
-
<td></td>
|
15 |
-
<td><?php _e('[[APPOINTMENT_TIME]] - time of appointment', 'ab') ?></td>
|
16 |
-
</tr>
|
17 |
-
<tr>
|
18 |
-
<td></td>
|
19 |
-
<td><?php _e('[[SERVICE_NAME]] - name of service', 'ab') ?></td>
|
20 |
-
</tr>
|
21 |
-
<tr>
|
22 |
-
<td></td>
|
23 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
24 |
-
</tr>
|
25 |
-
<tr>
|
26 |
-
<td></td>
|
27 |
-
<td><?php _e('[[COMPANY_LOGO]] - company logo', 'ab') ?></td>
|
28 |
-
</tr>
|
29 |
-
<tr>
|
30 |
-
<td></td>
|
31 |
-
<td><?php _e('[[COMPANY_ADDRESS]] - address of your company', 'ab') ?></td>
|
32 |
-
</tr>
|
33 |
-
<tr>
|
34 |
-
<td></td>
|
35 |
-
<td><?php _e('[[COMPANY_PHONE]] - company phone', 'ab') ?></td>
|
36 |
-
</tr>
|
37 |
-
<tr>
|
38 |
-
<td></td>
|
39 |
-
<td><?php _e('[[COMPANY_WEBSITE]] - this web-site address', 'ab') ?></td>
|
40 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/notifications/templates/_tags_evening_next_day.php
DELETED
@@ -1,40 +0,0 @@
|
|
1 |
-
<tr>
|
2 |
-
<th><?php _e('Subject', 'ab') ?></th>
|
3 |
-
<th><?php _e('Message', 'ab') ?></th>
|
4 |
-
</tr>
|
5 |
-
<tr>
|
6 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
7 |
-
<td><?php _e('[[CLIENT_NAME]] - name of client', 'ab') ?></td>
|
8 |
-
</tr>
|
9 |
-
<tr>
|
10 |
-
<td></td>
|
11 |
-
<td><?php _e('[[APPOINTMENT_DATE]] - date of appointment', 'ab') ?></td>
|
12 |
-
</tr>
|
13 |
-
<tr>
|
14 |
-
<td></td>
|
15 |
-
<td><?php _e('[[APPOINTMENT_TIME]] - time of appointment', 'ab') ?></td>
|
16 |
-
</tr>
|
17 |
-
<tr>
|
18 |
-
<td></td>
|
19 |
-
<td><?php _e('[[SERVICE_NAME]] - name of service', 'ab') ?></td>
|
20 |
-
</tr>
|
21 |
-
<tr>
|
22 |
-
<td></td>
|
23 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
24 |
-
</tr>
|
25 |
-
<tr>
|
26 |
-
<td></td>
|
27 |
-
<td><?php _e('[[COMPANY_LOGO]] - company logo', 'ab') ?></td>
|
28 |
-
</tr>
|
29 |
-
<tr>
|
30 |
-
<td></td>
|
31 |
-
<td><?php _e('[[COMPANY_ADDRESS]] - address of your company', 'ab') ?></td>
|
32 |
-
</tr>
|
33 |
-
<tr>
|
34 |
-
<td></td>
|
35 |
-
<td><?php _e('[[COMPANY_PHONE]] - company phone', 'ab') ?></td>
|
36 |
-
</tr>
|
37 |
-
<tr>
|
38 |
-
<td></td>
|
39 |
-
<td><?php _e('[[COMPANY_WEBSITE]] - this web-site address', 'ab') ?></td>
|
40 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/notifications/templates/_tags_event_next_day.php
DELETED
@@ -1,8 +0,0 @@
|
|
1 |
-
<tr>
|
2 |
-
<th><?php _e('Subject', 'ab') ?></th>
|
3 |
-
<th><?php _e('Message', 'ab') ?></th>
|
4 |
-
</tr>
|
5 |
-
<tr>
|
6 |
-
<td><?php _e('[[TOMORROW_DATE]] - date of next day', 'ab') ?></td>
|
7 |
-
<td><?php _e('[[NEXT_DAY_AGENDA]] - staff agenda for next day', 'ab') ?></td>
|
8 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/notifications/templates/_tags_provider_info.php
DELETED
@@ -1,60 +0,0 @@
|
|
1 |
-
<tr>
|
2 |
-
<th><?php _e('Subject', 'ab') ?></th>
|
3 |
-
<th><?php _e('Message', 'ab') ?></th>
|
4 |
-
</tr>
|
5 |
-
<tr>
|
6 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
7 |
-
<td><?php _e('[[CLIENT_NAME]] - name of client', 'ab') ?></td>
|
8 |
-
</tr>
|
9 |
-
<tr>
|
10 |
-
<td></td>
|
11 |
-
<td><?php _e('[[CLIENT_PHONE]] - сlient phone', 'ab') ?></td>
|
12 |
-
</tr>
|
13 |
-
<tr>
|
14 |
-
<td></td>
|
15 |
-
<td><?php _e('[[CLIENT_EMAIL]] - сlient email', 'ab') ?></td>
|
16 |
-
</tr>
|
17 |
-
<tr>
|
18 |
-
<td></td>
|
19 |
-
<td><?php _e('[[CLIENT_NOTES]] - сlient notes', 'ab') ?></td>
|
20 |
-
</tr>
|
21 |
-
<tr>
|
22 |
-
<td></td>
|
23 |
-
<td><?php _e('[[STAFF_NAME]] - name of staff', 'ab') ?></td>
|
24 |
-
</tr>
|
25 |
-
<tr>
|
26 |
-
<td></td>
|
27 |
-
<td><?php _e('[[APPOINTMENT_DATE]] - date of appointment', 'ab') ?></td>
|
28 |
-
</tr>
|
29 |
-
<tr>
|
30 |
-
<td></td>
|
31 |
-
<td><?php _e('[[APPOINTMENT_TIME]] - time of appointment', 'ab') ?></td>
|
32 |
-
</tr>
|
33 |
-
<tr>
|
34 |
-
<td></td>
|
35 |
-
<td><?php _e('[[SERVICE_NAME]] - name of service', 'ab') ?></td>
|
36 |
-
</tr>
|
37 |
-
<tr>
|
38 |
-
<td></td>
|
39 |
-
<td><?php _e('[[COMPANY_NAME]] - name of the company', 'ab') ?></td>
|
40 |
-
</tr>
|
41 |
-
<tr>
|
42 |
-
<td></td>
|
43 |
-
<td><?php _e('[[COMPANY_LOGO]] - company logo', 'ab') ?></td>
|
44 |
-
</tr>
|
45 |
-
<tr>
|
46 |
-
<td></td>
|
47 |
-
<td><?php _e('[[COMPANY_ADDRESS]] - address of your company', 'ab') ?></td>
|
48 |
-
</tr>
|
49 |
-
<tr>
|
50 |
-
<td></td>
|
51 |
-
<td><?php _e('[[COMPANY_PHONE]] - company phone', 'ab') ?></td>
|
52 |
-
</tr>
|
53 |
-
<tr>
|
54 |
-
<td></td>
|
55 |
-
<td><?php _e('[[COMPANY_WEBSITE]] - this web-site address', 'ab') ?></td>
|
56 |
-
</tr>
|
57 |
-
<tr>
|
58 |
-
<td></td>
|
59 |
-
<td><?php _e('[[CANCEL_APPOINTMENT]] - cancel appointment link', 'ab') ?></td>
|
60 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/notifications/templates/index.php
CHANGED
@@ -1,122 +1,137 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
-
|
3 |
-
<div style="min-width: 800px;margin-top: -20px">
|
4 |
-
<form method="post">
|
5 |
-
<div class="ab-notifications">
|
6 |
-
<?php
|
7 |
-
$sender_name = get_option( 'ab_settings_sender_name' ) == '' ?
|
8 |
get_option( 'blogname' ) : get_option( 'ab_settings_sender_name' );
|
9 |
-
|
10 |
get_option( 'admin_email' ) : get_option( 'ab_settings_sender_email' );
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
<label for="sender_email" style="display: inline;"><?php _e( 'Sender email', 'ab' ); ?></label>
|
17 |
-
<input id="sender_email" name="sender_email" class="ab-sender" type="text" value="<?php echo $sender_email; ?>"/>
|
18 |
</div>
|
19 |
-
|
20 |
-
|
21 |
-
<div class="ab-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
</
|
52 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
</div>
|
54 |
-
|
55 |
</div>
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
61 |
</div>
|
62 |
-
</form>
|
63 |
</div>
|
64 |
-
|
65 |
-
<div class="modal fade" id="
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
</div><!-- /.modal -->
|
80 |
-
|
81 |
-
<script type="text/javascript">
|
82 |
-
jQuery(function($) {
|
83 |
-
// menu fix for WP 3.8.1
|
84 |
-
$('#toplevel_page_ab-system > ul').css('margin-left', '0px');
|
85 |
-
// Show-hide Notifications
|
86 |
-
$('input:checkbox[id!=_active]').each(function() {
|
87 |
-
$(this).change(function() {
|
88 |
-
if ( $(this).attr('checked') ) {
|
89 |
-
$(this).parent().next('div.ab-form-field').show(200);
|
90 |
-
$(this).parents('.ab-notifications').find('.ab-toggle-arrow').css('background','url(<?php echo plugins_url( 'resources/images/notifications-arrow-up.png', dirname(__FILE__).'/../../../AB_Backend.php' ) ?>) 100% 0 no-repeat');
|
91 |
-
} else {
|
92 |
-
$(this).parent().next('div.ab-form-field').hide(200);
|
93 |
-
$(this).parents('.ab-notifications').find('.ab-toggle-arrow').css('background','url(<?php echo plugins_url( 'resources/images/notifications-arrow-down.png', dirname(__FILE__).'/../../../AB_Backend.php' ) ?>) 100% 0 no-repeat');
|
94 |
-
}
|
95 |
-
}).change();
|
96 |
-
});
|
97 |
-
$('.ab-toggle-arrow').click(function() {
|
98 |
-
$(this).nextAll('.ab-form-field').toggle(200, function() {
|
99 |
-
if ( $('.ab-form-field').css('display') == 'block' ) {
|
100 |
-
$(this).prevAll('.ab-toggle-arrow').css('background','url(<?php echo plugins_url( 'resources/images/notifications-arrow-up.png', dirname(__FILE__).'/../../../AB_Backend.php' ) ?>) 100% 0 no-repeat');
|
101 |
-
} else {
|
102 |
-
$(this).prevAll('.ab-toggle-arrow').css('background','url(<?php echo plugins_url( 'resources/images/notifications-arrow-down.png', dirname(__FILE__).'/../../../AB_Backend.php' ) ?>) 100% 0 no-repeat');
|
103 |
-
}
|
104 |
-
});
|
105 |
-
});
|
106 |
-
// filter sender name and email
|
107 |
-
var escapeXSS = function (infected) {
|
108 |
-
var regexp = /([<|(]("[^"]*"|'[^']*'|[^'">])*[>|)])/gi;
|
109 |
-
return infected.replace(regexp, '');
|
110 |
-
};
|
111 |
-
$('input.ab-sender').on('change', function() {
|
112 |
-
var $val = $(this).val();
|
113 |
-
$(this).val(escapeXSS($val));
|
114 |
-
});
|
115 |
-
|
116 |
-
$("input[id$='_active']").change(function(){
|
117 |
-
if ($(this).is(':checked')){
|
118 |
-
$('#light_notice').modal('show');
|
119 |
-
}
|
120 |
-
});
|
121 |
-
});
|
122 |
-
</script>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
$ab_settings_sender_name = get_option( 'ab_settings_sender_name' ) == '' ?
|
|
|
|
|
|
|
|
|
|
|
3 |
get_option( 'blogname' ) : get_option( 'ab_settings_sender_name' );
|
4 |
+
$ab_settings_sender_email = get_option( 'ab_settings_sender_email' ) == '' ?
|
5 |
get_option( 'admin_email' ) : get_option( 'ab_settings_sender_email' );
|
6 |
+
?>
|
7 |
+
<form method="post">
|
8 |
+
<div class="panel panel-default">
|
9 |
+
<div class="panel-heading">
|
10 |
+
<h3 class="panel-title"><?php _e( 'Email Notifications', 'bookly' ) ?></h3>
|
|
|
|
|
11 |
</div>
|
12 |
+
<div class="panel-body">
|
13 |
+
<?php AB_Utils::notice( $message ) ?>
|
14 |
+
<div class="ab-notifications">
|
15 |
+
<table>
|
16 |
+
<tr><!-- sender name -->
|
17 |
+
<td>
|
18 |
+
<label for="ab_settings_sender_name" style="display: inline;"><?php _e( 'Sender name', 'bookly' ) ?></label>
|
19 |
+
</td>
|
20 |
+
<td>
|
21 |
+
<input id="ab_settings_sender_name" name="ab_settings_sender_name" class="form-control ab-inline-block ab-auto-w ab-sender" type="text" value="<?php echo esc_attr( $ab_settings_sender_name ) ?>"/>
|
22 |
+
</td>
|
23 |
+
<td></td>
|
24 |
+
</tr>
|
25 |
+
<tr><!-- sender email -->
|
26 |
+
<td>
|
27 |
+
<label for="ab_settings_sender_email" style="display: inline;"><?php _e( 'Sender email', 'bookly' ) ?></label>
|
28 |
+
</td>
|
29 |
+
<td>
|
30 |
+
<input id="ab_settings_sender_email" name="ab_settings_sender_email" class="form-control ab-inline-block ab-auto-w ab-sender" type="text" value="<?php echo esc_attr( $ab_settings_sender_email ) ?>"/>
|
31 |
+
</td>
|
32 |
+
<td></td>
|
33 |
+
</tr>
|
34 |
+
<tr>
|
35 |
+
<td>
|
36 |
+
<label for="ab_email_notification_reply_to_customers" style="display: inline;"><?php _e( 'Reply directly to customers', 'bookly' ) ?></label>
|
37 |
+
</td>
|
38 |
+
<td>
|
39 |
+
<?php AB_Utils::optionToggle( 'ab_email_notification_reply_to_customers' ) ?>
|
40 |
+
</td>
|
41 |
+
<td>
|
42 |
+
<?php AB_Utils::popover( __( 'If this option is enabled then the email address of the customer is used as a sender email address for notifications sent to staff members and administrators.', 'bookly' ) ) ?>
|
43 |
+
</td>
|
44 |
+
</tr>
|
45 |
+
<tr>
|
46 |
+
<td>
|
47 |
+
<label for="ab_email_content_type" style="display: inline;"><?php _e( 'Send emails as', 'bookly' ) ?></label>
|
48 |
+
</td>
|
49 |
+
<td>
|
50 |
+
<?php AB_Utils::optionToggle( 'ab_email_content_type', array( 't' => array( 'html', __( 'HTML', 'bookly' ) ), 'f' => array( 'plain', __( 'Text', 'bookly' ) ) ) ) ?>
|
51 |
+
</td>
|
52 |
+
<td>
|
53 |
+
<?php AB_Utils::popover( __( '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' ) ) ?>
|
54 |
+
</td>
|
55 |
+
</tr>
|
56 |
+
</table>
|
57 |
+
</div>
|
58 |
+
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
|
59 |
+
<?php $notif_id = 0; ?>
|
60 |
+
<?php foreach ( $form->types as $type ): ?>
|
61 |
+
<?php $notif_id += 1;
|
62 |
+
$form_data = $form->getData();
|
63 |
+
$active = isset($form_data[ $type ]['active']) ? $form_data[ $type ]['active'] : false;
|
64 |
+
?>
|
65 |
+
<div class="panel panel-default ab-notifications">
|
66 |
+
<div class="panel-heading" role="tab" id="headingOne">
|
67 |
+
<h4 class="panel-title">
|
68 |
+
<input name="<?php echo $type ?>[active]" value="0" type="checkbox" checked="checked" class="hidden">
|
69 |
+
<input id="<?php echo $type ?>_active" name="<?php echo $type ?>[active]" value="1" type="checkbox" <?php checked( $active ) ?> />
|
70 |
+
<a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#collapse_<?php echo $notif_id ?>">
|
71 |
+
<?php echo $form->renderActive( $type ) ?>
|
72 |
+
</a>
|
73 |
+
</h4>
|
74 |
+
</div>
|
75 |
+
<div id="collapse_<?php echo $notif_id ?>" class="panel-collapse collapse">
|
76 |
+
<div class="panel-body">
|
77 |
+
<div class="ab-form-field">
|
78 |
+
<div class="ab-form-row">
|
79 |
+
<?php echo $form->renderSubject( $type ) ?>
|
80 |
+
</div>
|
81 |
+
<div id="message_editor" class="ab-form-row">
|
82 |
+
<label class="ab-form-label" style="margin-top: 35px;"><?php _e( 'Message', 'bookly' ) ?></label>
|
83 |
+
<?php echo $form->renderMessage( $type ) ?>
|
84 |
+
</div>
|
85 |
+
<?php if ( $type == 'staff_new_appointment' || $type == 'staff_cancelled_appointment' ): ?>
|
86 |
+
<?php echo $form->renderCopy( $type ) ?>
|
87 |
+
<?php endif ?>
|
88 |
+
<div class="ab-form-row">
|
89 |
+
<label class="ab-form-label"><?php _e( 'Codes', 'bookly' ) ?></label>
|
90 |
+
<div class="ab-codes left">
|
91 |
+
<table>
|
92 |
+
<tbody>
|
93 |
+
<?php
|
94 |
+
switch ( $type ) {
|
95 |
+
case 'staff_agenda': include '_codes_staff_agenda.php'; break;
|
96 |
+
case 'client_new_wp_user': include '_codes_client_new_wp_user.php'; break;
|
97 |
+
default: include '_codes.php';
|
98 |
+
}
|
99 |
+
?>
|
100 |
+
</tbody>
|
101 |
+
</table>
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
</div>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
</div>
|
108 |
+
<?php endforeach ?>
|
109 |
</div>
|
110 |
+
<div class="ab-notifications">
|
111 |
+
<?php
|
112 |
+
echo '<i>' . __( 'To send scheduled notifications please execute the following script hourly with your cron:', 'bookly' ) . '</i><br />';
|
113 |
+
echo '<b>php -f ' . realpath( AB_PATH . '/lib/utils/send_notifications_cron.php' ) . '</b>';
|
114 |
+
?>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
<div class="panel-footer">
|
118 |
+
<?php AB_Utils::submitButton() ?>
|
119 |
+
<?php AB_Utils::resetButton() ?>
|
120 |
</div>
|
|
|
121 |
</div>
|
122 |
+
</form>
|
123 |
+
<div class="modal fade" id="lite_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
124 |
+
<div class="modal-dialog">
|
125 |
+
<div class="modal-content">
|
126 |
+
<div class="modal-header">
|
127 |
+
<h4 class="modal-title"><?php _e('Notice', 'bookly') ?></h4>
|
128 |
+
</div>
|
129 |
+
<div class="modal-body">
|
130 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
131 |
+
</div>
|
132 |
+
<div class="modal-footer">
|
133 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php _e('Close', 'bookly') ?></button>
|
134 |
+
</div>
|
135 |
+
</div><!-- /.modal-content -->
|
136 |
+
</div><!-- /.modal-dialog -->
|
137 |
+
</div><!-- /.modal -->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/payment/AB_PaymentController.php
CHANGED
@@ -1,59 +1,84 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
5 |
class AB_PaymentController extends AB_Controller {
|
6 |
|
7 |
public function index() {
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
'
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
'clear' => __( 'Clear', 'ab' ),
|
27 |
-
'to' => __( 'To', 'ab' ),
|
28 |
-
'from' => __( 'From', 'ab' ),
|
29 |
-
'month' => array(
|
30 |
-
0 => __( 'January', 'ab' ),
|
31 |
-
1 => __( 'February', 'ab' ),
|
32 |
-
2 => __( 'March', 'ab' ),
|
33 |
-
3 => __( 'April', 'ab' ),
|
34 |
-
4 => __( 'May', 'ab' ),
|
35 |
-
5 => __( 'June', 'ab' ),
|
36 |
-
6 => __( 'July', 'ab' ),
|
37 |
-
7 => __( 'August', 'ab' ),
|
38 |
-
8 => __( 'September', 'ab' ),
|
39 |
-
9 => __( 'October', 'ab' ),
|
40 |
-
10 => __( 'November', 'ab' ),
|
41 |
-
11 => __( 'December', 'ab' )
|
42 |
-
),
|
43 |
-
'day' => array(
|
44 |
-
'Mon' => __( 'Mon', 'ab' ),
|
45 |
-
'Tue' => __( 'Tue', 'ab' ),
|
46 |
-
'Wed' => __( 'Wed', 'ab' ),
|
47 |
-
'Thu' => __( 'Thu', 'ab' ),
|
48 |
-
'Fri' => __( 'Fri', 'ab' ),
|
49 |
-
'Sat' => __( 'Sat', 'ab' ),
|
50 |
-
'Sun' => __( 'Sun', 'ab' )
|
51 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
));
|
53 |
|
54 |
-
$this->
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
$this->render( 'index' );
|
57 |
}
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
class AB_PaymentController extends AB_Controller {
|
4 |
|
5 |
public function index() {
|
6 |
+
/** @var WP_Locale $wp_locale */
|
7 |
+
global $wp_locale;
|
8 |
+
|
9 |
+
$this->enqueueStyles( array(
|
10 |
+
'backend' => array(
|
11 |
+
'css/bookly.main-backend.css',
|
12 |
+
'bootstrap/css/bootstrap.min.css',
|
13 |
+
'css/daterangepicker.css',
|
14 |
+
'css/bootstrap-select.min.css',
|
15 |
+
)
|
16 |
+
) );
|
17 |
+
|
18 |
+
$this->enqueueScripts( array(
|
19 |
+
'backend' => array(
|
20 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
21 |
+
'js/moment.min.js',
|
22 |
+
'js/daterangepicker.js' => array( 'jquery' ),
|
23 |
+
'js/bootstrap-select.min.js',
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
)
|
25 |
+
) );
|
26 |
+
|
27 |
+
wp_localize_script( 'ab-daterangepicker.js', 'BooklyL10n', array(
|
28 |
+
'today' => __( 'Today', 'bookly' ),
|
29 |
+
'yesterday' => __( 'Yesterday', 'bookly' ),
|
30 |
+
'last_7' => __( 'Last 7 Days', 'bookly' ),
|
31 |
+
'last_30' => __( 'Last 30 Days', 'bookly' ),
|
32 |
+
'this_month' => __( 'This Month', 'bookly' ),
|
33 |
+
'last_month' => __( 'Last Month', 'bookly' ),
|
34 |
+
'custom_range' => __( 'Custom Range', 'bookly' ),
|
35 |
+
'apply' => __( 'Apply', 'bookly' ),
|
36 |
+
'cancel' => __( 'Cancel', 'bookly' ),
|
37 |
+
'to' => __( 'To', 'bookly' ),
|
38 |
+
'from' => __( 'From', 'bookly' ),
|
39 |
+
'months' => array_values( $wp_locale->month ),
|
40 |
+
'days' => array_values( $wp_locale->weekday_abbrev ),
|
41 |
+
'startOfWeek' => (int) get_option( 'start_of_week' ),
|
42 |
+
'mjsDateFormat' => AB_DateTimeUtils::convertFormat( 'date', AB_DateTimeUtils::FORMAT_MOMENT_JS ),
|
43 |
));
|
44 |
|
45 |
+
$this->collection = false;
|
46 |
+
|
47 |
+
$this->types = array();
|
48 |
+
$this->customers = array();
|
49 |
+
$this->providers = array();
|
50 |
+
$this->services = array();
|
51 |
|
52 |
$this->render( 'index' );
|
53 |
}
|
54 |
|
55 |
+
/**
|
56 |
+
* Sort payments.
|
57 |
+
*/
|
58 |
+
public function executeSortPayments()
|
59 |
+
{
|
60 |
+
$this->executeFilterPayments();
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Filter payments.
|
65 |
+
*/
|
66 |
+
public function executeFilterPayments()
|
67 |
+
{
|
68 |
+
$this->render( '_body', array( 'collection' => false ) );
|
69 |
+
exit;
|
70 |
+
}
|
71 |
+
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Override parent method to add 'wp_ajax_ab_' prefix
|
75 |
+
* so current 'execute*' methods look nicer.
|
76 |
+
*
|
77 |
+
* @param string $prefix
|
78 |
+
*/
|
79 |
+
protected function registerWpActions( $prefix = '' )
|
80 |
+
{
|
81 |
+
parent::registerWpActions( 'wp_ajax_ab_' );
|
82 |
+
}
|
83 |
+
|
84 |
}
|
backend/modules/payment/templates/_alert.php
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<div
|
3 |
-
|
4 |
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="alert alert-warning" >
|
3 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
4 |
</div>
|
backend/modules/payment/templates/index.php
CHANGED
@@ -1,80 +1,148 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
<
|
18 |
-
<
|
19 |
-
<?php
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
</div>
|
37 |
</div>
|
|
|
|
|
|
|
|
|
|
|
38 |
</div>
|
39 |
-
<div id=ab-alert-div class=alert style="display: none"></div>
|
40 |
-
<table class="table table-bordered" cellspacing=0 cellpadding=0 border=0 id=ab_payments_list style="clear: both;">
|
41 |
-
<thead>
|
42 |
-
<tr>
|
43 |
-
<th width=150 class="desc active" order-by=created><a href="javascript:void(0)"><?php _e( 'Date', 'ab' ) ?></a></th>
|
44 |
-
<th width=100 order-by=type><a href="javascript:void(0)"><?php _e( 'Type', 'ab' ) ?></a></th>
|
45 |
-
<th width=150 order-by=customer><a href="javascript:void(0)"><?php _e( 'Customer', 'ab' ) ?></a></th>
|
46 |
-
<th width=150 order-by=provider><a href="javascript:void(0)"><?php _e( 'Provider', 'ab' ) ?></a></th>
|
47 |
-
<th width=150 order-by=service><a href="javascript:void(0)"><?php _e( 'Service', 'ab' ) ?></a></th>
|
48 |
-
<th width=50 order-by=amount><a href="javascript:void(0)"><?php _e( 'Amount', 'ab') ?></a></th>
|
49 |
-
<th width=150 order-by=date><a href="javascript:void(0)"><?php _e( 'Appointment Date', 'ab' ) ?></a></th>
|
50 |
-
</tr>
|
51 |
-
</thead>
|
52 |
-
<tbody id=ab-tb-body>
|
53 |
-
</tbody>
|
54 |
-
</table>
|
55 |
-
<?php include '_alert.php'; ?>
|
56 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
<script type="text/javascript">
|
59 |
jQuery(function($) {
|
60 |
-
|
61 |
$report_range = $('#reportrange span'),
|
62 |
-
picker_ranges = {}
|
63 |
-
l10nRanges = {};
|
64 |
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
|
72 |
$('.selectpicker').selectpicker({style: 'btn-info', size: 5});
|
73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
|
75 |
-
|
76 |
-
|
|
|
|
|
|
|
77 |
});
|
78 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
});
|
80 |
</script>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
/**
|
3 |
+
* @var array $customers
|
4 |
+
* @var array $types
|
5 |
+
* @var array $providers
|
6 |
+
* @var array $services
|
7 |
+
*/
|
8 |
+
?>
|
9 |
+
|
10 |
+
<div class="panel panel-default">
|
11 |
+
<div class="panel-heading">
|
12 |
+
<h3 class="panel-title"><?php _e( 'Payments', 'bookly' ) ?></h3>
|
13 |
+
</div>
|
14 |
+
<div class="panel-body">
|
15 |
+
<div class=ab-nav-payment>
|
16 |
+
<div class=row-fluid>
|
17 |
+
<div id=reportrange class="ab-reportrange ab-inline-block">
|
18 |
+
<i class="glyphicon glyphicon-calendar"></i>
|
19 |
+
<span data-date="<?php echo date( 'Y-m-d', strtotime( '-30 day' ) ) ?> - <?php echo date( 'Y-m-d' ) ?>"><?php echo date_i18n( get_option( 'date_format' ), strtotime( '-30 day' ) ) ?> - <?php echo date_i18n( get_option( 'date_format' ) ) ?></span> <b style="margin-top: 8px;" class=caret></b>
|
20 |
+
</div>
|
21 |
+
<div class=ab-inline-block>
|
22 |
+
<select id=ab-type-filter class=selectpicker>
|
23 |
+
<option value="-1"><?php _e( 'All payment types', 'bookly' ) ?></option>
|
24 |
+
<?php foreach ( $types as $type ): ?>
|
25 |
+
<option value="<?php echo esc_attr( $type ) ?>">
|
26 |
+
<?php
|
27 |
+
switch( $type ) {
|
28 |
+
case 'paypal':
|
29 |
+
echo 'PayPal'; break;
|
30 |
+
case 'authorizeNet':
|
31 |
+
echo 'authorizeNet'; break;
|
32 |
+
case 'stripe':
|
33 |
+
echo 'Stripe'; break;
|
34 |
+
default:
|
35 |
+
_e( 'Local', 'bookly' ); break;
|
36 |
+
}
|
37 |
+
?>
|
38 |
+
</option>
|
39 |
+
<?php endforeach ?>
|
40 |
+
</select>
|
41 |
+
<select id=ab-customer-filter class=selectpicker>
|
42 |
+
<option value="-1"><?php _e( 'All customers', 'bookly' ) ?></option>
|
43 |
+
<?php foreach ( $customers as $customer ): ?>
|
44 |
+
<option><?php echo esc_html( $customer ) ?></option>
|
45 |
+
<?php endforeach ?>
|
46 |
+
</select>
|
47 |
+
<select id=ab-provider-filter class=selectpicker>
|
48 |
+
<option value="-1"><?php _e( 'All providers', 'bookly' ) ?></option>
|
49 |
+
<?php foreach ( $providers as $provider ): ?>
|
50 |
+
<option><?php echo esc_html( $provider ) ?></option>
|
51 |
+
<?php endforeach ?>
|
52 |
+
</select>
|
53 |
+
<select id=ab-service-filter class=selectpicker>
|
54 |
+
<option value="-1"><?php _e( 'All services', 'bookly' ) ?></option>
|
55 |
+
<?php foreach ( $services as $service ): ?>
|
56 |
+
<option><?php echo esc_html( $service ) ?></option>
|
57 |
+
<?php endforeach ?>
|
58 |
+
</select>
|
59 |
+
<a id=ab-filter-submit href="#" class="btn btn-primary"><?php _e( 'Filter', 'bookly' ) ?></a>
|
60 |
+
</div>
|
61 |
</div>
|
62 |
</div>
|
63 |
+
<div id=ab-alert-div class=alert style="display: none"></div>
|
64 |
+
<?php include '_alert.php' ?>
|
65 |
+
<div style="display: none" class="loading-indicator">
|
66 |
+
<span class="ab-loader"></span>
|
67 |
+
</div>
|
68 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
69 |
</div>
|
70 |
+
<div class="modal fade" id="lite_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
71 |
+
<div class="modal-dialog">
|
72 |
+
<div class="modal-content">
|
73 |
+
<div class="modal-header">
|
74 |
+
<h4 class="modal-title"><?php _e('Notice', 'bookly') ?></h4>
|
75 |
+
</div>
|
76 |
+
<div class="modal-body">
|
77 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
78 |
+
</div>
|
79 |
+
<div class="modal-footer">
|
80 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php _e('Close', 'bookly') ?></button>
|
81 |
+
</div>
|
82 |
+
</div><!-- /.modal-content -->
|
83 |
+
</div><!-- /.modal-dialog -->
|
84 |
+
</div><!-- /.modal -->
|
85 |
|
86 |
<script type="text/javascript">
|
87 |
jQuery(function($) {
|
88 |
+
var data = {},
|
89 |
$report_range = $('#reportrange span'),
|
90 |
+
picker_ranges = {};
|
|
|
91 |
|
92 |
+
picker_ranges[BooklyL10n.today] = [moment(), moment()];
|
93 |
+
picker_ranges[BooklyL10n.yesterday] = [moment().subtract(1, 'days'), moment().subtract(1, 'days')];
|
94 |
+
picker_ranges[BooklyL10n.last_7] = [moment().subtract(7, 'days'), moment()];
|
95 |
+
picker_ranges[BooklyL10n.last_30] = [moment().subtract(30, 'days'), moment()];
|
96 |
+
picker_ranges[BooklyL10n.this_month] = [moment().startOf('month'), moment().endOf('month')];
|
97 |
+
picker_ranges[BooklyL10n.last_month] = [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')];
|
98 |
|
99 |
$('.selectpicker').selectpicker({style: 'btn-info', size: 5});
|
100 |
|
101 |
+
function ajaxData(object) {
|
102 |
+
data['customer'] = $('#ab-customer-filter').val();
|
103 |
+
data['provider'] = $('#ab-provider-filter').val();
|
104 |
+
data['service'] = $('#ab-service-filter').val();
|
105 |
+
data['range'] = $report_range.data('date'); //text();
|
106 |
+
data['type'] = $('#ab-type-filter').val();
|
107 |
+
data['key'] = $('#search_customers').val();
|
108 |
+
|
109 |
+
|
110 |
+
return data;
|
111 |
+
}
|
112 |
|
113 |
+
// sort order
|
114 |
+
$('#ab_payments_list th a').on('click', function() {
|
115 |
+
var data = { action:'ab_sort_payments', data: ajaxData(this) };
|
116 |
+
$('.loading-indicator').show();
|
117 |
+
$('#ab_payments_list tbody').load(ajaxurl, data, function() {$('.loading-indicator').hide();});
|
118 |
});
|
119 |
|
120 |
+
$('#reportrange').daterangepicker(
|
121 |
+
{
|
122 |
+
startDate: moment().subtract(30, 'days'), // by default selected is "Last 30 days"
|
123 |
+
ranges: picker_ranges,
|
124 |
+
locale: {
|
125 |
+
applyLabel: BooklyL10n.apply,
|
126 |
+
cancelLabel: BooklyL10n.cancel,
|
127 |
+
fromLabel: BooklyL10n.from,
|
128 |
+
toLabel: BooklyL10n.to,
|
129 |
+
customRangeLabel: BooklyL10n.custom_range,
|
130 |
+
daysOfWeek: BooklyL10n.days,
|
131 |
+
monthNames: BooklyL10n.months,
|
132 |
+
firstDay: parseInt(BooklyL10n.startOfWeek),
|
133 |
+
format: BooklyL10n.mjsDateFormat
|
134 |
+
}
|
135 |
+
},
|
136 |
+
function(start, end) {
|
137 |
+
var format = 'YYYY-MM-DD';
|
138 |
+
$report_range
|
139 |
+
.data('date', start.format(format) + ' - ' + end.format(format))
|
140 |
+
.html(start.format(BooklyL10n.mjsDateFormat) + ' - ' + end.format(BooklyL10n.mjsDateFormat));
|
141 |
+
}
|
142 |
+
);
|
143 |
+
|
144 |
+
$('#ab-filter-submit').on('click', function() {
|
145 |
+
$('#lite_notice').modal('show');
|
146 |
+
});
|
147 |
});
|
148 |
</script>
|
backend/modules/service/AB_ServiceController.php
CHANGED
@@ -1,19 +1,55 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include 'forms/AB_CategoryForm.php';
|
6 |
-
include 'forms/AB_ServiceForm.php';
|
7 |
|
8 |
/**
|
9 |
* Class AB_ServiceController
|
10 |
*/
|
11 |
class AB_ServiceController extends AB_Controller {
|
12 |
|
|
|
13 |
/**
|
14 |
-
*
|
15 |
*/
|
16 |
-
public function index()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
$this->staff_collection = $this->getStaffCollection();
|
18 |
$this->category_collection = $this->getCategoryCollection();
|
19 |
$this->service_collection = $this->getServiceCollection();
|
@@ -23,26 +59,31 @@ class AB_ServiceController extends AB_Controller {
|
|
23 |
/**
|
24 |
*
|
25 |
*/
|
26 |
-
public function executeCategoryServices()
|
|
|
27 |
$this->setDataForServiceList();
|
28 |
-
$this->render( '
|
29 |
exit;
|
30 |
}
|
31 |
|
32 |
/**
|
33 |
*
|
34 |
*/
|
35 |
-
public function executeCategoryForm()
|
|
|
36 |
$this->form = new AB_CategoryForm();
|
37 |
|
38 |
-
if (
|
39 |
-
$this->form->bind( $this->
|
40 |
if ( $category = $this->form->save() ) {
|
41 |
-
echo "<
|
|
|
42 |
<span class='left displayed-value'>{$category->name}</span>
|
43 |
<a href='#' class='left ab-hidden ab-edit'></a>
|
44 |
<input class=value type=text name=name value='{$category->name}' style='display: none' />
|
45 |
-
<a href='#' class='left ab-hidden ab-delete'></a></
|
|
|
|
|
46 |
exit;
|
47 |
}
|
48 |
}
|
@@ -52,113 +93,177 @@ class AB_ServiceController extends AB_Controller {
|
|
52 |
/**
|
53 |
* Update category.
|
54 |
*/
|
55 |
-
public function executeUpdateCategory()
|
|
|
56 |
$form = new AB_CategoryForm();
|
57 |
-
$form->bind( $this->
|
58 |
-
$form->save();
|
|
|
|
|
59 |
}
|
60 |
|
61 |
/**
|
62 |
-
*
|
63 |
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
65 |
|
66 |
-
|
|
|
|
|
|
|
|
|
67 |
$category = new AB_Category();
|
68 |
$category->set( 'id', $this->getParameter( 'id', 0 ) );
|
69 |
$category->delete();
|
70 |
-
|
71 |
-
|
72 |
|
73 |
-
public function executeAddService()
|
|
|
74 |
$form = new AB_ServiceForm();
|
75 |
-
$form->bind( $this->
|
|
|
76 |
$service = $form->save();
|
77 |
$this->setDataForServiceList( $service->get( 'category_id' ) );
|
78 |
-
$this->render( '
|
79 |
-
exit;
|
80 |
}
|
81 |
|
82 |
-
public function executeRemoveServices()
|
83 |
-
|
84 |
-
$service_ids =
|
85 |
-
if ( is_array( $service_ids ) && ! empty( $service_ids ) ) {
|
86 |
-
|
87 |
}
|
88 |
}
|
89 |
|
90 |
-
public function executeAssignStaff()
|
91 |
-
|
92 |
-
$service_id =
|
93 |
-
$staff_ids =
|
94 |
|
95 |
if ( $service_id ) {
|
96 |
-
|
97 |
-
$wpDb->query( $wpDb->prepare( 'DELETE FROM ab_staff_service WHERE service_id = %d', $service_id ) );
|
98 |
$service = new AB_Service();
|
99 |
if ( ! empty( $staff_ids ) && $service->load( $service_id ) ) {
|
100 |
foreach ( $staff_ids as $staff_id ) {
|
101 |
$staff_service = new AB_StaffService();
|
102 |
-
$staff_service->set( 'staff_id',
|
103 |
$staff_service->set( 'service_id', $service_id );
|
104 |
-
$staff_service->set( 'price',
|
105 |
$staff_service->save();
|
106 |
}
|
107 |
}
|
108 |
-
|
109 |
-
exit;
|
110 |
}
|
|
|
111 |
}
|
112 |
|
113 |
-
public function executeUpdateServiceValue()
|
|
|
|
|
|
|
|
|
114 |
$form = new AB_ServiceForm();
|
115 |
-
$form->bind($this->
|
116 |
-
$form->save();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
117 |
}
|
118 |
|
119 |
-
|
120 |
-
|
121 |
-
|
|
|
|
|
|
|
|
|
122 |
}
|
123 |
|
124 |
-
$this->service_collection = $this->getServiceCollection($category_id);
|
125 |
$this->staff_collection = $this->getStaffCollection();
|
126 |
$this->category_collection = $this->getCategoryCollection();
|
127 |
}
|
128 |
|
129 |
-
|
130 |
-
|
|
|
|
|
|
|
|
|
131 |
}
|
132 |
|
|
|
|
|
|
|
133 |
private function getStaffCollection() {
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
);
|
151 |
-
|
152 |
-
|
153 |
-
service.*,
|
154 |
-
COUNT(staff.id) AS "total_staff",
|
155 |
-
GROUP_CONCAT(DISTINCT staff.id) AS "staff_ids"
|
156 |
-
FROM ab_service service
|
157 |
-
LEFT JOIN ab_staff_service staff_service ON service.id = staff_service.service_id
|
158 |
-
LEFT JOIN ab_staff staff ON staff.id = staff_service.staff_id
|
159 |
-
GROUP BY service.id, "total_staff"';
|
160 |
-
}
|
161 |
-
return $this->getWpdb()->get_results($query);
|
162 |
}
|
163 |
|
164 |
// Protected methods.
|
@@ -166,9 +271,12 @@ class AB_ServiceController extends AB_Controller {
|
|
166 |
/**
|
167 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
168 |
* so current 'execute*' methods look nicer.
|
|
|
|
|
169 |
*/
|
170 |
-
protected function registerWpActions( $prefix = '' )
|
|
|
171 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
172 |
}
|
173 |
|
174 |
-
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_ServiceController
|
5 |
*/
|
6 |
class AB_ServiceController extends AB_Controller {
|
7 |
|
8 |
+
const page_slug = 'ab-services';
|
9 |
/**
|
10 |
+
* Index page.
|
11 |
*/
|
12 |
+
public function index()
|
13 |
+
{
|
14 |
+
$this->enqueueStyles( array(
|
15 |
+
'wp' => array(
|
16 |
+
'wp-color-picker',
|
17 |
+
),
|
18 |
+
'frontend' => array(
|
19 |
+
'css/ladda.min.css',
|
20 |
+
),
|
21 |
+
'backend' => array(
|
22 |
+
'css/bookly.main-backend.css',
|
23 |
+
'bootstrap/css/bootstrap.min.css',
|
24 |
+
),
|
25 |
+
'module' => array(
|
26 |
+
'css/service.css',
|
27 |
+
)
|
28 |
+
) );
|
29 |
+
|
30 |
+
$this->enqueueScripts( array(
|
31 |
+
'wp' => array(
|
32 |
+
'wp-color-picker',
|
33 |
+
),
|
34 |
+
'backend' => array(
|
35 |
+
'js/ab_popup.js' => array( 'jquery' ),
|
36 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
37 |
+
),
|
38 |
+
'module' => array(
|
39 |
+
'js/service.js' => array( 'jquery-ui-sortable', 'jquery' ),
|
40 |
+
),
|
41 |
+
'frontend' => array(
|
42 |
+
'js/spin.min.js' => array( 'jquery' ),
|
43 |
+
'js/ladda.min.js' => array( 'ab-spin.min.js', 'jquery' ),
|
44 |
+
)
|
45 |
+
) );
|
46 |
+
|
47 |
+
wp_localize_script( 'ab-service.js', 'BooklyL10n', array(
|
48 |
+
'are_you_sure' => __( 'Are you sure?', 'bookly' ),
|
49 |
+
'no_staff_selected' => __( 'No staff selected', 'bookly' ),
|
50 |
+
'please_select_at_least_one_service' => __( 'Please select at least one service.', 'bookly' ),
|
51 |
+
) );
|
52 |
+
|
53 |
$this->staff_collection = $this->getStaffCollection();
|
54 |
$this->category_collection = $this->getCategoryCollection();
|
55 |
$this->service_collection = $this->getServiceCollection();
|
59 |
/**
|
60 |
*
|
61 |
*/
|
62 |
+
public function executeCategoryServices()
|
63 |
+
{
|
64 |
$this->setDataForServiceList();
|
65 |
+
$this->render( '_list' );
|
66 |
exit;
|
67 |
}
|
68 |
|
69 |
/**
|
70 |
*
|
71 |
*/
|
72 |
+
public function executeCategoryForm()
|
73 |
+
{
|
74 |
$this->form = new AB_CategoryForm();
|
75 |
|
76 |
+
if ( ! empty ( $_POST ) ) {
|
77 |
+
$this->form->bind( $this->getPostParameters() );
|
78 |
if ( $category = $this->form->save() ) {
|
79 |
+
echo "<li class='ab-category-item' data-id='{$category->id}'>
|
80 |
+
<span class='ab-handle'><i class='ab-inner-handle glyphicon glyphicon-move'></i></span>
|
81 |
<span class='left displayed-value'>{$category->name}</span>
|
82 |
<a href='#' class='left ab-hidden ab-edit'></a>
|
83 |
<input class=value type=text name=name value='{$category->name}' style='display: none' />
|
84 |
+
<a href='#' class='left ab-hidden ab-delete'></a></li>";
|
85 |
+
// Register string for translate in WPML.
|
86 |
+
do_action( 'wpml_register_single_string', 'bookly', 'category_' . $category->id, $category->name );
|
87 |
exit;
|
88 |
}
|
89 |
}
|
93 |
/**
|
94 |
* Update category.
|
95 |
*/
|
96 |
+
public function executeUpdateCategory()
|
97 |
+
{
|
98 |
$form = new AB_CategoryForm();
|
99 |
+
$form->bind( $this->getPostParameters() );
|
100 |
+
$category = $form->save();
|
101 |
+
// Register string for translate in WPML.
|
102 |
+
do_action( 'wpml_register_single_string', 'bookly', 'category_' . $category->id, $category->name );
|
103 |
}
|
104 |
|
105 |
/**
|
106 |
+
* Update category position.
|
107 |
*/
|
108 |
+
public function executeUpdateCategoryPosition()
|
109 |
+
{
|
110 |
+
$category_sorts = $this->getParameter( 'position' );
|
111 |
+
foreach ( $category_sorts as $position => $category_id ) {
|
112 |
+
$category_sort = new AB_Category();
|
113 |
+
$category_sort->load( $category_id );
|
114 |
+
$category_sort->set( 'position', $position );
|
115 |
+
$category_sort->save();
|
116 |
+
}
|
117 |
+
}
|
118 |
|
119 |
+
/**
|
120 |
+
* Update services position.
|
121 |
+
*/
|
122 |
+
public function executeUpdateServicesPosition()
|
123 |
+
{
|
124 |
+
$services_sorts = $this->getParameter( 'position' );
|
125 |
+
foreach ( $services_sorts as $position => $service_ids ) {
|
126 |
+
$services_sort = new AB_Service();
|
127 |
+
$services_sort->load( $service_ids );
|
128 |
+
$services_sort->set( 'position', $position );
|
129 |
+
$services_sort->save();
|
130 |
+
}
|
131 |
+
}
|
132 |
|
133 |
+
/**
|
134 |
+
* Delete category.
|
135 |
+
*/
|
136 |
+
public function executeDeleteCategory()
|
137 |
+
{
|
138 |
$category = new AB_Category();
|
139 |
$category->set( 'id', $this->getParameter( 'id', 0 ) );
|
140 |
$category->delete();
|
141 |
+
}
|
|
|
142 |
|
143 |
+
public function executeAddService()
|
144 |
+
{
|
145 |
$form = new AB_ServiceForm();
|
146 |
+
$form->bind( $this->getPostParameters() );
|
147 |
+
$form->getObject()->set( 'duration', get_option( 'ab_settings_time_slot_length' ) * 60 );
|
148 |
$service = $form->save();
|
149 |
$this->setDataForServiceList( $service->get( 'category_id' ) );
|
150 |
+
wp_send_json_success( array( 'html' => $this->render( '_list', array(), false ), 'service_id' => $service->get( 'id' ) ) );
|
|
|
151 |
}
|
152 |
|
153 |
+
public function executeRemoveServices()
|
154 |
+
{
|
155 |
+
$service_ids = $this->getParameter( 'service_ids', array() );
|
156 |
+
if ( is_array( $service_ids ) && ! empty ( $service_ids ) ) {
|
157 |
+
AB_Service::query( 's' )->delete()->whereIn( 's.id', $service_ids )->execute();
|
158 |
}
|
159 |
}
|
160 |
|
161 |
+
public function executeAssignStaff()
|
162 |
+
{
|
163 |
+
$service_id = $this->getParameter( 'service_id', 0 );
|
164 |
+
$staff_ids = $this->getParameter( 'staff_ids', array() );
|
165 |
|
166 |
if ( $service_id ) {
|
167 |
+
AB_StaffService::query()->delete()->where( 'service_id', $service_id )->execute();
|
|
|
168 |
$service = new AB_Service();
|
169 |
if ( ! empty( $staff_ids ) && $service->load( $service_id ) ) {
|
170 |
foreach ( $staff_ids as $staff_id ) {
|
171 |
$staff_service = new AB_StaffService();
|
172 |
+
$staff_service->set( 'staff_id', $staff_id );
|
173 |
$staff_service->set( 'service_id', $service_id );
|
174 |
+
$staff_service->set( 'price', $service->get( 'price' ) );
|
175 |
$staff_service->save();
|
176 |
}
|
177 |
}
|
178 |
+
wp_send_json_success( count( $staff_ids ) );
|
|
|
179 |
}
|
180 |
+
wp_send_json_error();
|
181 |
}
|
182 |
|
183 |
+
public function executeUpdateServiceValue()
|
184 |
+
{
|
185 |
+
/** @var $wpdb wpdb */
|
186 |
+
global $wpdb;
|
187 |
+
|
188 |
$form = new AB_ServiceForm();
|
189 |
+
$form->bind( $this->getPostParameters() );
|
190 |
+
$service = $form->save();
|
191 |
+
|
192 |
+
if ( $this->getParameter( 'update_staff', false ) ) {
|
193 |
+
if ( $this->getParameter( 'price' ) ) {
|
194 |
+
$wpdb->update( AB_StaffService::getTableName(), array( 'price' => $this->getParameter( 'price' ) ), array( 'service_id' => $this->getParameter( 'id' ) ) );
|
195 |
+
}
|
196 |
+
if ( $this->getParameter( 'capacity' ) ) {
|
197 |
+
$wpdb->update( AB_StaffService::getTableName(), array( 'capacity' => $this->getParameter( 'capacity' ) ), array( 'service_id' => $this->getParameter( 'id' ) ) );
|
198 |
+
}
|
199 |
+
}
|
200 |
+
// Register string for translate in WPML.
|
201 |
+
if ( $this->hasParameter( 'title' ) ) {
|
202 |
+
do_action( 'wpml_register_single_string', 'bookly', 'service_' . $service->id, $service->title );
|
203 |
+
}
|
204 |
+
|
205 |
+
$staff_ids = $this->getParameter( 'staff_ids', array() );
|
206 |
+
if ( $service->id ) {
|
207 |
+
AB_StaffService::query()->delete()->where( 'service_id', $service->id )->execute();
|
208 |
+
if ( ! empty( $staff_ids ) ) {
|
209 |
+
foreach ( $staff_ids as $staff_id ) {
|
210 |
+
$staff_service = new AB_StaffService();
|
211 |
+
$staff_service->set( 'staff_id', $staff_id );
|
212 |
+
$staff_service->set( 'service_id', $service->id );
|
213 |
+
$staff_service->set( 'price', $service->get( 'price' ) );
|
214 |
+
$staff_service->save();
|
215 |
+
}
|
216 |
+
}
|
217 |
+
}
|
218 |
+
|
219 |
+
wp_send_json_success( array( 'title' => $service->title, 'price' => AB_Utils::formatPrice( $service->price ), 'color' => $service->color, 'nice_duration' => AB_DateTimeUtils::secondsToInterval( $service->duration ) ) );
|
220 |
}
|
221 |
|
222 |
+
/**
|
223 |
+
* @param int $category_id
|
224 |
+
*/
|
225 |
+
private function setDataForServiceList( $category_id = 0 )
|
226 |
+
{
|
227 |
+
if ( ! $category_id ) {
|
228 |
+
$category_id = $this->getParameter( 'category_id', 0 );
|
229 |
}
|
230 |
|
231 |
+
$this->service_collection = $this->getServiceCollection( $category_id );
|
232 |
$this->staff_collection = $this->getStaffCollection();
|
233 |
$this->category_collection = $this->getCategoryCollection();
|
234 |
}
|
235 |
|
236 |
+
/**
|
237 |
+
* @return mixed
|
238 |
+
*/
|
239 |
+
private function getCategoryCollection()
|
240 |
+
{
|
241 |
+
return AB_Category::query()->sortBy( 'position' )->fetchArray();
|
242 |
}
|
243 |
|
244 |
+
/**
|
245 |
+
* @return mixed
|
246 |
+
*/
|
247 |
private function getStaffCollection() {
|
248 |
+
|
249 |
+
return AB_Staff::query()->fetchArray();
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* @param int $id
|
254 |
+
* @return mixed
|
255 |
+
*/
|
256 |
+
private function getServiceCollection( $id = 0 )
|
257 |
+
{
|
258 |
+
$services = AB_Service::query( 's' )
|
259 |
+
->select( 's.*, COUNT(staff.id) AS total_staff, GROUP_CONCAT(DISTINCT staff.id) AS staff_ids' )
|
260 |
+
->leftJoin( 'AB_StaffService', 'ss', 'ss.service_id = s.id' )
|
261 |
+
->leftJoin( 'AB_Staff', 'staff', 'staff.id = ss.staff_id' )
|
262 |
+
->whereRaw( 's.category_id = %d OR !%d', array( $id, $id ) )
|
263 |
+
->groupBy( 's.id' )
|
264 |
+
->sortBy( 'ISNULL(s.position), s.position' );
|
265 |
+
|
266 |
+
return $services->fetchArray();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
}
|
268 |
|
269 |
// Protected methods.
|
271 |
/**
|
272 |
* Override parent method to add 'wp_ajax_ab_' prefix
|
273 |
* so current 'execute*' methods look nicer.
|
274 |
+
*
|
275 |
+
* @param string $prefix
|
276 |
*/
|
277 |
+
protected function registerWpActions( $prefix = '' )
|
278 |
+
{
|
279 |
parent::registerWpActions( 'wp_ajax_ab_' );
|
280 |
}
|
281 |
|
282 |
+
}
|
backend/modules/service/forms/AB_CategoryForm.php
CHANGED
@@ -1,6 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
5 |
/**
|
6 |
* Class AB_CategoryForm
|
@@ -10,7 +8,8 @@ class AB_CategoryForm extends AB_Form {
|
|
10 |
/**
|
11 |
* Constructor.
|
12 |
*/
|
13 |
-
public function __construct()
|
|
|
14 |
parent::$entity_class = 'AB_Category';
|
15 |
parent::__construct();
|
16 |
}
|
@@ -18,7 +17,8 @@ class AB_CategoryForm extends AB_Form {
|
|
18 |
/**
|
19 |
* Configure the form.
|
20 |
*/
|
21 |
-
public function configure()
|
|
|
22 |
$this->setFields( array( 'name' ) );
|
23 |
}
|
24 |
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_CategoryForm
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_Category';
|
14 |
parent::__construct();
|
15 |
}
|
17 |
/**
|
18 |
* Configure the form.
|
19 |
*/
|
20 |
+
public function configure()
|
21 |
+
{
|
22 |
$this->setFields( array( 'name' ) );
|
23 |
}
|
24 |
|
backend/modules/service/forms/AB_ServiceForm.php
CHANGED
@@ -1,24 +1,22 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_Service.php';
|
6 |
|
7 |
/**
|
8 |
* Class AB_ServiceForm
|
9 |
*/
|
10 |
-
class AB_ServiceForm extends AB_Form
|
11 |
-
|
12 |
/**
|
13 |
* Constructor.
|
14 |
*/
|
15 |
-
public function __construct()
|
|
|
16 |
parent::$entity_class = 'AB_Service';
|
17 |
parent::__construct();
|
18 |
}
|
19 |
|
20 |
-
public function configure()
|
21 |
-
|
|
|
22 |
}
|
23 |
|
24 |
/**
|
@@ -27,20 +25,23 @@ class AB_ServiceForm extends AB_Form {
|
|
27 |
* @param array $post
|
28 |
* @param array $files
|
29 |
*/
|
30 |
-
public function bind( array $post, array $files = array() )
|
31 |
-
|
|
|
32 |
$post['category_id'] = null;
|
33 |
}
|
34 |
-
parent::bind($post, $files);
|
35 |
}
|
36 |
|
37 |
-
public function save()
|
|
|
38 |
if ( $this->isNew() ) {
|
39 |
-
|
40 |
-
|
41 |
-
$this->data[ 'color' ] = $colors[mt_rand(0, count($colors) - 1)];
|
42 |
}
|
|
|
43 |
|
44 |
return parent::save();
|
45 |
}
|
|
|
46 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_ServiceForm
|
5 |
*/
|
6 |
+
class AB_ServiceForm extends AB_Form
|
7 |
+
{
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_Service';
|
14 |
parent::__construct();
|
15 |
}
|
16 |
|
17 |
+
public function configure()
|
18 |
+
{
|
19 |
+
$this->setFields( array( 'id', 'title', 'duration', 'price', 'category_id', 'color', 'capacity', 'padding_left', 'padding_right' ) );
|
20 |
}
|
21 |
|
22 |
/**
|
25 |
* @param array $post
|
26 |
* @param array $files
|
27 |
*/
|
28 |
+
public function bind( array $post, array $files = array() )
|
29 |
+
{
|
30 |
+
if ( array_key_exists( 'category_id', $post ) && !$post['category_id'] ) {
|
31 |
$post['category_id'] = null;
|
32 |
}
|
33 |
+
parent::bind( $post, $files );
|
34 |
}
|
35 |
|
36 |
+
public function save()
|
37 |
+
{
|
38 |
if ( $this->isNew() ) {
|
39 |
+
// When adding new service - set its color randomly.
|
40 |
+
$this->data['color'] = sprintf( '#%06X', mt_rand( 0, 0x64FFFF ) );
|
|
|
41 |
}
|
42 |
+
$this->data['capacity'] = 1;
|
43 |
|
44 |
return parent::save();
|
45 |
}
|
46 |
+
|
47 |
}
|
backend/modules/service/resources/css/service.css
CHANGED
@@ -1,45 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
.ab-category-item {
|
2 |
-
width: 110px;
|
3 |
padding: 10px;
|
4 |
padding-left: 50px;
|
5 |
vertical-align: middle;
|
6 |
-
-moz-border-radius: 5px;
|
7 |
border-radius: 5px;
|
8 |
cursor: pointer;
|
9 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
.ab-active {
|
11 |
background-color: #ccc;
|
12 |
}
|
13 |
|
14 |
-
.wp-picker-
|
15 |
-
border-color: black;
|
16 |
-
margin-left: 35px;
|
17 |
-
margin-top: 6px;
|
18 |
-
}
|
19 |
|
20 |
#services_list .service-color-wrapper .wp-picker-open + .wp-picker-input-wrap {
|
21 |
display: block;
|
22 |
margin-left: 50px;
|
23 |
margin-top: 20px;
|
24 |
}
|
|
|
|
|
|
|
|
|
25 |
|
26 |
.wp-picker-container, .wp-picker-container:active {
|
27 |
display: inline-block;
|
28 |
outline: 0 none;
|
29 |
position: absolute;
|
30 |
-
|
31 |
-
}
|
32 |
|
33 |
/** Services list **/
|
34 |
-
#ab_services_wrapper .
|
|
|
35 |
#ab_services_wrapper .list-wrapper .list-actions { overflow: hidden; margin-top: 10px; }
|
36 |
#ab_services_wrapper .list-wrapper .list-actions .add-service { float: left }
|
37 |
#ab_services_wrapper .list-wrapper .list-actions .delete { float: right }
|
38 |
|
39 |
#services_list td.last,
|
40 |
-
#services_list th.last { width: 16px;
|
41 |
-
#services_list
|
42 |
-
#services_list
|
|
|
43 |
#services_list .service-color-cell { width: 28px; }
|
44 |
#services_list .service-color-wrapper .wp-color-result { padding-left: 25px; margin: 0; top: auto; }
|
45 |
#services_list .service-color-wrapper .wp-color-result.wp-picker-open { top: auto }
|
@@ -47,7 +66,79 @@
|
|
47 |
#services_list .service-color-wrapper .wp-color-result.wp-picker-open:after { content: none }
|
48 |
#services_list .service-color-wrapper .wp-picker-open + .wp-picker-input-wrap { display: block; visibility: hidden; margin-top: -25px; margin-left: 34px; }
|
49 |
#services_list .service-color-wrapper .button { margin-left: 0 }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
#new_category_popup .ab-popup { width: 187px }
|
52 |
.staff-popup-wrapper .staff-row { white-space: nowrap; margin: 0; }
|
53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#ab_services_wrapper .table-responsive { overflow: visible!important; }
|
2 |
+
@media screen and (max-width: 767px) {
|
3 |
+
#ab_services_wrapper .table-responsive {
|
4 |
+
overflow-y: visible!important;
|
5 |
+
overflow-x: auto!important;
|
6 |
+
}
|
7 |
+
.ab-col-responsive {
|
8 |
+
margin-bottom: 15px;
|
9 |
+
}
|
10 |
+
#services_list .panel.panel-default {
|
11 |
+
margin-right: 0;
|
12 |
+
}
|
13 |
+
}
|
14 |
.ab-category-item {
|
|
|
15 |
padding: 10px;
|
16 |
padding-left: 50px;
|
17 |
vertical-align: middle;
|
|
|
18 |
border-radius: 5px;
|
19 |
cursor: pointer;
|
20 |
}
|
21 |
+
.ab-main-category-item {
|
22 |
+
padding-left: 40px;
|
23 |
+
font-size: 17px;
|
24 |
+
background-image: url("../../../../resources/images/box-big.png");
|
25 |
+
background-position: 5px 50%;
|
26 |
+
background-repeat: no-repeat;
|
27 |
+
}
|
28 |
.ab-active {
|
29 |
background-color: #ccc;
|
30 |
}
|
31 |
|
32 |
+
.wp-picker-holder { margin-top: 10px; left: -268px; z-index: 2; position: absolute; }
|
|
|
|
|
|
|
|
|
33 |
|
34 |
#services_list .service-color-wrapper .wp-picker-open + .wp-picker-input-wrap {
|
35 |
display: block;
|
36 |
margin-left: 50px;
|
37 |
margin-top: 20px;
|
38 |
}
|
39 |
+
.service-color-wrapper {
|
40 |
+
height: 24px;
|
41 |
+
width: 27px;
|
42 |
+
}
|
43 |
|
44 |
.wp-picker-container, .wp-picker-container:active {
|
45 |
display: inline-block;
|
46 |
outline: 0 none;
|
47 |
position: absolute;
|
48 |
+
}
|
|
|
49 |
|
50 |
/** Services list **/
|
51 |
+
#ab_services_wrapper .ab-right-content .ab-category-title { margin: 10px 0 15px 0; font-weight: normal; }
|
52 |
+
#ab_services_wrapper .list-wrapper { max-width: 575px; }
|
53 |
#ab_services_wrapper .list-wrapper .list-actions { overflow: hidden; margin-top: 10px; }
|
54 |
#ab_services_wrapper .list-wrapper .list-actions .add-service { float: left }
|
55 |
#ab_services_wrapper .list-wrapper .list-actions .delete { float: right }
|
56 |
|
57 |
#services_list td.last,
|
58 |
+
#services_list th.last { width: 16px; }
|
59 |
+
#services_list td .btn-group { min-width: 85px; }
|
60 |
+
#services_list td,
|
61 |
+
#services_list th { vertical-align: middle; }
|
62 |
#services_list .service-color-cell { width: 28px; }
|
63 |
#services_list .service-color-wrapper .wp-color-result { padding-left: 25px; margin: 0; top: auto; }
|
64 |
#services_list .service-color-wrapper .wp-color-result.wp-picker-open { top: auto }
|
66 |
#services_list .service-color-wrapper .wp-color-result.wp-picker-open:after { content: none }
|
67 |
#services_list .service-color-wrapper .wp-picker-open + .wp-picker-input-wrap { display: block; visibility: hidden; margin-top: -25px; margin-left: 34px; }
|
68 |
#services_list .service-color-wrapper .button { margin-left: 0 }
|
69 |
+
#services_list .panel.panel-default { margin-right: 0; }
|
70 |
+
#services_list .panel.panel-default.service .panel-heading { padding: 10px; overflow: hidden; }
|
71 |
+
#services_list .panel.panel-default.service .panel-collapse { width: 100%!important; }
|
72 |
+
#services_list .panel.panel-default.service .panel-heading .badge { margin: 0 5px; margin-top: -3px; }
|
73 |
+
#services_list .ab-padding-before-after select { width: 46%!important; }
|
74 |
+
#services_list a[data-toggle="collapse"] {
|
75 |
+
outline: none;
|
76 |
+
box-shadow: none;
|
77 |
+
padding-right: 25px;
|
78 |
+
background: url("../../../../resources/images/notifications-arrow-up.png") 100% 50% no-repeat;
|
79 |
+
background-size: 17px 17px;
|
80 |
+
}
|
81 |
+
#services_list a[data-toggle="collapse"].collapsed {
|
82 |
+
background: url("../../../../resources/images/notifications-arrow-down.png") 100% 50% no-repeat;
|
83 |
+
background-size: 17px 17px;
|
84 |
+
}
|
85 |
+
|
86 |
+
.table tbody > tr td:first-child { vertical-align: middle; }
|
87 |
+
|
88 |
+
#ab-services-list,
|
89 |
+
#ab-services-list li { margin: 0; }
|
90 |
+
#ab-services-list .table { margin: 0; }
|
91 |
+
#ab-services-list .table .ab-handle { cursor: move; }
|
92 |
+
#ab-services-list .ab-popover { margin: 29px 0 0 -20px; }
|
93 |
+
#ab-services-list .service-color-wrapper { margin: 5px 0 0 -20px; }
|
94 |
|
95 |
#new_category_popup .ab-popup { width: 187px }
|
96 |
.staff-popup-wrapper .staff-row { white-space: nowrap; margin: 0; }
|
97 |
|
98 |
+
#ab-category-item-list { padding: 0; margin: 20px 0; }
|
99 |
+
#ab-category-item-list .ab-category-item {
|
100 |
+
width: auto;
|
101 |
+
height: auto;
|
102 |
+
padding: 5px;
|
103 |
+
margin-top: 5px;
|
104 |
+
position: relative;
|
105 |
+
white-space: nowrap;
|
106 |
+
overflow: hidden;
|
107 |
+
padding-left: 45px;
|
108 |
+
background-image: url("../../../../resources/images/box-small.png");
|
109 |
+
background-position: 22px 50%;
|
110 |
+
background-repeat: no-repeat;
|
111 |
+
}
|
112 |
+
#ab-category-item-list .ab-category-item .ab-handle {
|
113 |
+
display: block;
|
114 |
+
width: 20px;
|
115 |
+
position: absolute;
|
116 |
+
top: 0;
|
117 |
+
left: 0;
|
118 |
+
bottom: 0;
|
119 |
+
z-index: 999;
|
120 |
+
text-align: center;
|
121 |
+
padding: 5px 0;
|
122 |
+
cursor: move;
|
123 |
+
}
|
124 |
+
#ab-category-item-list .ab-category-item > span { padding-right: 5px; }
|
125 |
+
#ab-category-item-list .ab-category-item:hover span { text-decoration: underline; }
|
126 |
+
#ab-category-item-list .ab-category-item .ab-edit,
|
127 |
+
#ab-category-item-list .ab-category-item .ab-delete {
|
128 |
+
display: inline-block;
|
129 |
+
width: 21px;
|
130 |
+
height: 16px;
|
131 |
+
background: url("../../../../resources/images/edit.png") 5px 0 no-repeat;
|
132 |
+
padding: 0 5px;
|
133 |
+
visibility: hidden;
|
134 |
+
}
|
135 |
+
#ab-category-item-list .ab-category-item:hover .ab-edit,
|
136 |
+
#ab-category-item-list .ab-category-item:hover .ab-delete { visibility: visible; }
|
137 |
+
#ab-category-item-list .ab-category-item:hover .ab-delete { background: url("../../../../resources/images/delete.png") 5px 0 no-repeat; padding-left: 5px; }
|
138 |
+
#ab-category-item-list .ab-category-item .ab-edit { padding-right: 0; }
|
139 |
+
|
140 |
+
@media only screen and (max-width: 640px) {
|
141 |
+
.wp-picker-container,
|
142 |
+
.wp-picker-container:active { position: static; }
|
143 |
+
}
|
144 |
+
|
backend/modules/service/resources/js/service.js
CHANGED
@@ -1,289 +1,344 @@
|
|
1 |
jQuery(function($) {
|
2 |
-
|
|
|
|
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
|
|
|
|
|
|
27 |
|
28 |
-
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
41 |
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
|
|
77 |
});
|
78 |
-
}
|
79 |
-
})
|
80 |
|
81 |
-
//
|
82 |
-
|
83 |
-
//
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
$.post(ajaxurl, data, function(response) {
|
92 |
-
|
93 |
-
$.each($('#services_list').find('select[name="category_id"]'), function(key, value) {
|
94 |
-
$(value).find('option[value="' + $item.data('id') + '"]').remove();
|
95 |
-
});
|
96 |
-
// Remove category item from DOM.
|
97 |
-
$item.remove();
|
98 |
-
if ($item.is('.ab-active')) {
|
99 |
-
location.reload(true);
|
100 |
-
}
|
101 |
});
|
102 |
-
}
|
103 |
-
|
|
|
|
|
104 |
|
|
|
|
|
|
|
|
|
105 |
|
106 |
-
|
107 |
-
|
|
|
|
|
108 |
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
data[field] = value;
|
126 |
-
$.post(ajaxurl, data, function(response) {
|
127 |
-
$this.hide();
|
128 |
-
$this.prev('.displayed-value').text(value).show();
|
129 |
});
|
130 |
-
}
|
131 |
-
})
|
132 |
|
133 |
-
//
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
selected_category_id = parseInt(value);
|
147 |
-
if (services_category_id && selected_category_id != services_category_id) {
|
148 |
-
if ($('#services_list > tbody > tr').length == 1) {
|
149 |
-
$('#services_list > tbody > tr').remove();
|
150 |
-
$('#services_list').hide();
|
151 |
-
$no_result.show();
|
152 |
-
} else {
|
153 |
-
$row.removeClass('last').prev().addClass('last');
|
154 |
-
$row.remove();
|
155 |
-
}
|
156 |
}
|
157 |
-
|
158 |
});
|
159 |
-
}
|
160 |
-
})
|
161 |
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
$.post(ajaxurl, data, function(response) {
|
171 |
-
refreshList(response);
|
172 |
-
});
|
173 |
-
})
|
174 |
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
$(
|
181 |
-
|
182 |
-
}
|
183 |
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
207 |
}
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
215 |
}
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
221 |
});
|
222 |
-
|
223 |
-
|
|
|
|
|
224 |
|
225 |
-
// On change in `select staff` checkbox.
|
226 |
-
.on('change', 'input.all-staff, input.staff', function(){
|
227 |
-
var $this = $(this),
|
228 |
-
$row = $this.parents('.service-row'),
|
229 |
-
staff_ids = [],
|
230 |
-
data = { action: 'ab_assign_staff', service_id: $row.attr('id') };
|
231 |
-
if ($this.hasClass('all-staff')) {
|
232 |
-
$row.find('.staff').prop('checked', $this.prop('checked'));
|
233 |
-
} else {
|
234 |
-
$row.find('.all-staff').prop(
|
235 |
-
'checked',
|
236 |
-
$row.find('.staff:not(:checked)').length == 0
|
237 |
-
);
|
238 |
-
}
|
239 |
-
$row.find('.staff:checked').each(function(){
|
240 |
-
staff_ids.push($(this).val());
|
241 |
-
});
|
242 |
-
data['staff_ids[]'] = staff_ids;
|
243 |
-
$.post(ajaxurl, data, function(response) {
|
244 |
-
if (response) {
|
245 |
-
$row.find('.staff-count').text(response);
|
246 |
-
}
|
247 |
-
});
|
248 |
-
});
|
249 |
|
250 |
-
function refreshList(response) {
|
251 |
-
var $list = $('#ab-services-list');
|
252 |
-
$list.html(response);
|
253 |
doNotCloseDropDowns();
|
254 |
-
initColorPicker($
|
|
|
|
|
255 |
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
});
|
274 |
-
}
|
275 |
|
276 |
-
|
277 |
-
|
278 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
});
|
280 |
-
}
|
281 |
-
|
282 |
-
initColorPicker($('.service-color'));
|
283 |
-
doNotCloseDropDowns();
|
284 |
-
|
285 |
-
$.ajaxSetup({
|
286 |
-
mode: 'abort',
|
287 |
-
port: 'ab_service'
|
288 |
-
});
|
289 |
});
|
1 |
jQuery(function($) {
|
2 |
+
var $no_result = $('#ab_services_wrapper .no-result');
|
3 |
+
// Remember user choice in the modal dialog.
|
4 |
+
var update_staff_choice = null;
|
5 |
|
6 |
+
// On new category form submit.
|
7 |
+
$('#new-category-form').on('submit', function(event) {
|
8 |
+
var data = $(this).serialize();
|
9 |
+
$.post(ajaxurl, data, function(response) {
|
10 |
+
$('.ab-category-item-list').append(response);
|
11 |
+
$('#new_category_popup').ab_popup('close');
|
12 |
+
// add created category to services
|
13 |
+
$.each($('#services_list').find('select[name="category_id"]'), function(key, value) {
|
14 |
+
var $new_category = $('.ab-category-item:last');
|
15 |
+
$(value).append('<option value="' + $new_category.data('id') + '">'
|
16 |
+
+ $new_category.find('input').val() + ' </option>');
|
17 |
+
});
|
18 |
+
});
|
19 |
+
return false;
|
20 |
+
});
|
21 |
|
22 |
+
// Preventing multiple creation of new category by pressing Enter-key
|
23 |
+
$('input[value="ab_category_form"]').parent().find('input:first').one('keypress', function(e) {
|
24 |
+
var code = (e.keyCode ? e.keyCode : e.which);
|
25 |
+
if (code == 13) {
|
26 |
+
$(this).trigger(e).blur();
|
27 |
+
}
|
28 |
+
});
|
29 |
+
|
30 |
+
// Categories list delegated events.
|
31 |
+
$('#ab-categories-list')
|
32 |
|
33 |
+
// On category item click.
|
34 |
+
.on('click', '.ab-category-item', function() {
|
35 |
+
var $clicked = $(this);
|
36 |
+
$.get(ajaxurl, {action:'ab_category_services', category_id: $clicked.data('id')}, function(response) {
|
37 |
+
$('.ab-category-item').not($clicked).removeClass('ab-active');
|
38 |
+
$('.ab-category-title').text($clicked.text());
|
39 |
+
$clicked.addClass('ab-active');
|
40 |
+
refreshList(response,0);
|
41 |
+
});
|
42 |
+
})
|
43 |
|
44 |
+
// On edit category click.
|
45 |
+
.on('click', '.ab-category-item .ab-edit', function(e) {
|
46 |
+
// Keep category item click from being executed.
|
47 |
+
e.stopPropagation();
|
48 |
+
// Prevent navigating to '#'.
|
49 |
+
e.preventDefault();
|
50 |
+
// Hide edit button.
|
51 |
+
$(this).hide()
|
52 |
+
// Hide displayed category name and delete button.
|
53 |
+
.siblings('.displayed-value, .ab-delete').hide().end()
|
54 |
+
// Show input field.
|
55 |
+
.nextAll('.value').show().focus();
|
56 |
+
})
|
57 |
|
58 |
+
// On blur of category edit input.
|
59 |
+
.on('blur', '.ab-category-item input.value', function() {
|
60 |
+
var $this = $(this),
|
61 |
+
$item = $this.closest('.ab-category-item'),
|
62 |
+
field = $this.attr('name'),
|
63 |
+
value = $this.attr('value'),
|
64 |
+
id = $item.data('id');
|
65 |
+
if (value) {
|
66 |
+
var data = { action: 'ab_update_category', id: id };
|
67 |
+
data[field] = value;
|
68 |
+
$.post(ajaxurl, data, function(response) {
|
69 |
+
// Hide input field.
|
70 |
+
$this.hide()
|
71 |
+
// Show modified category name.
|
72 |
+
.prevAll('.displayed-value').text(value).show().end()
|
73 |
+
// Show edit and delete buttons.
|
74 |
+
.siblings('.ab-edit, .ab-delete').show();
|
75 |
+
// update edited category's name for services
|
76 |
+
$.each($('#services_list').find('select[name="category_id"]'), function(k, v) {
|
77 |
+
$(v).find('option:selected[value="' + id + '"]').text(value);
|
78 |
+
});
|
79 |
+
});
|
80 |
+
}
|
81 |
+
})
|
82 |
|
83 |
+
// On delete category click.
|
84 |
+
.on('click', '.ab-category-item .ab-delete', function(e) {
|
85 |
+
// Keep category item click from being executed.
|
86 |
+
e.stopPropagation();
|
87 |
+
// Prevent navigating to '#'.
|
88 |
+
e.preventDefault();
|
89 |
+
// Ask user if he is sure.
|
90 |
+
if (confirm(BooklyL10n.are_you_sure)) {
|
91 |
+
var $item = $(this).closest('.ab-category-item');
|
92 |
+
var data = { action: 'ab_delete_category', id: $item.data('id') };
|
93 |
+
$.post(ajaxurl, data, function(response) {
|
94 |
+
// Remove category item from Services
|
95 |
+
$.each($('#services_list').find('select[name="category_id"]'), function(key, value) {
|
96 |
+
$(value).find('option[value="' + $item.data('id') + '"]').remove();
|
97 |
+
});
|
98 |
+
// Remove category item from DOM.
|
99 |
+
$item.remove();
|
100 |
+
if ($item.is('.ab-active')) {
|
101 |
+
location.reload(true);
|
102 |
+
}
|
103 |
+
});
|
104 |
+
}
|
105 |
});
|
|
|
|
|
106 |
|
107 |
+
// Services list delegated events.
|
108 |
+
$('#ab_services_wrapper')
|
109 |
+
// On click on 'Add Service' button.
|
110 |
+
.on('click', 'a.add-service', function(e) {
|
111 |
+
e.preventDefault();
|
112 |
+
var selected_category_id = $('#ab-categories-list .ab-active').data('id'),
|
113 |
+
data = { action: 'ab_add_service' };
|
114 |
+
if (selected_category_id) {
|
115 |
+
data['category_id'] = selected_category_id;
|
116 |
+
}
|
117 |
$.post(ajaxurl, data, function(response) {
|
118 |
+
refreshList(response.data.html,response.data.service_id);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
});
|
120 |
+
})
|
121 |
+
// On click on 'Delete' button.
|
122 |
+
.on('click', 'a.delete', function(e){
|
123 |
+
e.preventDefault();
|
124 |
|
125 |
+
var for_delete = $('input:checkbox.service-checker:checked'),
|
126 |
+
data = { action: 'ab_remove_services' },
|
127 |
+
services = [],
|
128 |
+
$panels = [];
|
129 |
|
130 |
+
if (!for_delete.length) {
|
131 |
+
alert(BooklyL10n.please_select_at_least_one_service);
|
132 |
+
return false;
|
133 |
+
}
|
134 |
|
135 |
+
for_delete.each(function(){
|
136 |
+
var panel = $(this).parents('.panel.service');
|
137 |
+
$panels.push(panel);
|
138 |
+
services.push(panel.data('service_id'));
|
139 |
+
});
|
140 |
+
data['service_ids[]'] = services;
|
141 |
+
$.post(ajaxurl, data, function() {
|
142 |
+
$.each($panels, function () {
|
143 |
+
$(this).fadeOut(200, function () {
|
144 |
+
$(this).remove();
|
145 |
+
});
|
146 |
+
});
|
147 |
+
});
|
148 |
+
})
|
149 |
|
150 |
+
.on('change', 'input.all-staff, input.staff', function(){
|
151 |
+
var $panel = $(this).parents('.panel.service');
|
152 |
+
if ($(this).hasClass('all-staff')) {
|
153 |
+
$panel.find('.staff').prop('checked', $(this).prop('checked'));
|
154 |
+
} else {
|
155 |
+
$panel.find('.all-staff').prop('checked', $panel.find('.staff:not(:checked)').length == 0);
|
156 |
+
}
|
157 |
+
updateStaffButton($panel);
|
|
|
|
|
|
|
|
|
158 |
});
|
|
|
|
|
159 |
|
160 |
+
// Modal window events.
|
161 |
+
var $modal = $('#ab-staff-update');
|
162 |
+
$modal
|
163 |
+
.on('click', '.ab-yes', function() {
|
164 |
+
$modal.modal('hide');
|
165 |
+
if ( $('#ab-remember-my-choice').prop('checked') ) {
|
166 |
+
update_staff_choice = true;
|
167 |
+
}
|
168 |
+
submitServiceFrom($modal.data('input'),true);
|
169 |
+
})
|
170 |
+
.on('click', '.ab-no', function() {
|
171 |
+
if ( $('#ab-remember-my-choice').prop('checked') ) {
|
172 |
+
update_staff_choice = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
}
|
174 |
+
submitServiceFrom($modal.data('input'),false);
|
175 |
});
|
|
|
|
|
176 |
|
177 |
+
function refreshList(response,service_id) {
|
178 |
+
var $list = $('#ab-services-list');
|
179 |
+
$list.html(response);
|
180 |
+
makeServicesSortable();
|
181 |
+
doNotCloseDropDowns();
|
182 |
+
initColorPicker($list.find('.service-color'));
|
183 |
+
initPopovers();
|
184 |
+
initServiceFormButtons();
|
|
|
|
|
|
|
|
|
185 |
|
186 |
+
if (response.indexOf('panel') >= 0) {
|
187 |
+
$no_result.hide();
|
188 |
+
} else {
|
189 |
+
$no_result.show();
|
190 |
+
}
|
191 |
+
$('#service_' + service_id).collapse('show');
|
192 |
+
$('#service_' + service_id).find('input[name=title]').focus();
|
193 |
+
}
|
194 |
|
195 |
+
function initColorPicker($jquery_collection) {
|
196 |
+
$jquery_collection.each(function(){
|
197 |
+
$(this).data('last_color', $(this).val());
|
198 |
+
});
|
199 |
+
$jquery_collection.wpColorPicker();
|
200 |
+
}
|
201 |
+
|
202 |
+
function doNotCloseDropDowns() {
|
203 |
+
$('#ab-services-list .dropdown-menu').on('click', function(e) {
|
204 |
+
e.stopPropagation();
|
205 |
+
});
|
206 |
+
}
|
207 |
+
|
208 |
+
function initPopovers() {
|
209 |
+
// Popovers initialization.
|
210 |
+
$('.ab-popover').popover({
|
211 |
+
trigger : 'hover'
|
212 |
+
});
|
213 |
+
}
|
214 |
+
|
215 |
+
function submitServiceFrom($form, update_staff) {
|
216 |
+
$form.find('input[name=update_staff]').val( update_staff ? 1 : 0 );
|
217 |
+
var ladda = Ladda.create( $form.find('button[type=submit]').get(0) );
|
218 |
+
ladda.start();
|
219 |
+
$.post(ajaxurl, $form.serialize(), function (response) {
|
220 |
+
if (response.success) {
|
221 |
+
var $panel = $form.parents('.panel.service'),
|
222 |
+
$price = $form.find('[name=price]'),
|
223 |
+
$capacity = $form.find('[name=capacity]');
|
224 |
+
$panel.find('span.badge').css('background-color', response.data.color);
|
225 |
+
$panel.find('.panel-title a').html(response.data.title);
|
226 |
+
$panel.find('.panel-title .ab-right-nav small').html(response.data.nice_duration + '<div class="ab-inline-block" style="width: 75px;text-align: right">' + response.data.price + '</div>');
|
227 |
+
$price.data('last_value', $price.val());
|
228 |
+
$capacity.data('last_value', $capacity.val());
|
229 |
+
$('.notice-dismiss').unbind('click.wp-dismiss-notice').on('click', function(){
|
230 |
+
$(this).parents('.notice').fadeOut();
|
231 |
+
});
|
232 |
+
$('.notice-success').show();
|
233 |
}
|
234 |
+
}, 'json').always(function() {
|
235 |
+
ladda.stop();
|
236 |
+
} );
|
237 |
+
}
|
238 |
+
|
239 |
+
function updateStaffButton($panel) {
|
240 |
+
var staff_checked = $panel.find('.staff:checked').length;
|
241 |
+
if (staff_checked == 0) {
|
242 |
+
$panel.find('.staff-count').text(BooklyL10n.no_staff_selected);
|
243 |
+
} else if (staff_checked == 1) {
|
244 |
+
$panel.find('.staff-count').text($panel.find('.staff:checked').data('staff_name'));
|
245 |
+
} else {
|
246 |
+
$panel.find('.staff-count').text(staff_checked + '/' + $panel.find('.staff').length);
|
247 |
+
}
|
248 |
+
}
|
249 |
+
|
250 |
+
function initServiceFormButtons() {
|
251 |
+
$('.ajax-service-send').on('click', function (e) {
|
252 |
+
e.preventDefault();
|
253 |
+
var $form = $(this).parents('form'),
|
254 |
+
show_modal = false;
|
255 |
+
if(update_staff_choice === null) {
|
256 |
+
$('.ab-question', $form).each(function () {
|
257 |
+
if ($(this).data('last_value') != $(this).val()) {
|
258 |
+
show_modal = true;
|
259 |
+
}
|
260 |
+
});
|
261 |
}
|
262 |
+
if(show_modal){
|
263 |
+
$modal.data('input', $form).modal('show');
|
264 |
+
}else{
|
265 |
+
submitServiceFrom($form, update_staff_choice);
|
266 |
+
}
|
267 |
+
});
|
268 |
+
$('.js-reset').on('click', function (e) {
|
269 |
+
$(this).parents('form').trigger('reset');
|
270 |
+
var $color = $(this).parents('form').find('.service-color'),
|
271 |
+
$panel = $(this).parents('.panel.service');
|
272 |
+
$color.val($color.data('last_color')).trigger('change');
|
273 |
+
updateStaffButton($panel);
|
274 |
});
|
275 |
+
$('.ab-question').each( function(){
|
276 |
+
$(this).data('last_value', $(this).val());
|
277 |
+
});
|
278 |
+
}
|
279 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
280 |
|
|
|
|
|
|
|
281 |
doNotCloseDropDowns();
|
282 |
+
initColorPicker($('.service-color'));
|
283 |
+
initPopovers();
|
284 |
+
initServiceFormButtons();
|
285 |
|
286 |
+
var $category = $('ul#ab-category-item-list');
|
287 |
+
$category.sortable({
|
288 |
+
axis : 'y',
|
289 |
+
handle : '.ab-handle',
|
290 |
+
update : function( event, ui ) {
|
291 |
+
var data = [];
|
292 |
+
$category.children('li').each(function() {
|
293 |
+
var $this = $(this);
|
294 |
+
var position = $this.data('id');
|
295 |
+
data.push(position);
|
296 |
+
});
|
297 |
+
$.ajax({
|
298 |
+
type : 'POST',
|
299 |
+
url : ajaxurl,
|
300 |
+
data : { action: 'ab_update_category_position', position: data }
|
301 |
+
});
|
302 |
+
}
|
303 |
});
|
|
|
304 |
|
305 |
+
function makeServicesSortable() {
|
306 |
+
if ($('.ab-main-category-item').hasClass('ab-active')) {
|
307 |
+
var $services = $('#services_list'),
|
308 |
+
fixHelper = function(e, ui) {
|
309 |
+
ui.children().each(function() {
|
310 |
+
$(this).width($(this).width());
|
311 |
+
});
|
312 |
+
return ui;
|
313 |
+
};
|
314 |
+
$services.sortable({
|
315 |
+
helper : fixHelper,
|
316 |
+
axis : 'y',
|
317 |
+
handle : '.ab-handle',
|
318 |
+
update : function( event, ui ) {
|
319 |
+
var data = [];
|
320 |
+
$services.children('div').each(function() {
|
321 |
+
data.push($(this).data('service_id'));
|
322 |
+
});
|
323 |
+
$.ajax({
|
324 |
+
type : 'POST',
|
325 |
+
url : ajaxurl,
|
326 |
+
data : { action: 'ab_update_services_position', position: data }
|
327 |
+
});
|
328 |
+
}
|
329 |
+
});
|
330 |
+
} else {
|
331 |
+
$('#services_list .ab-handle').hide();
|
332 |
+
}
|
333 |
+
}
|
334 |
+
makeServicesSortable();
|
335 |
+
$('.panel.service').each(function(){
|
336 |
+
updateStaffButton($(this));
|
337 |
+
});
|
338 |
+
$('[name=capacity]').on('change',function(){
|
339 |
+
if ($(this).val() > 1) {
|
340 |
+
$('#lite_notice').modal('show');
|
341 |
+
$(this).val(1) ;
|
342 |
+
}
|
343 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
344 |
});
|
backend/modules/service/templates/_list.php
ADDED
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
$time_interval = get_option( 'ab_settings_time_slot_length' );
|
3 |
+
?>
|
4 |
+
<?php AB_Utils::notice( __( 'Settings saved.', 'bookly' ), 'notice-success', false ) ?>
|
5 |
+
<?php if ( ! empty( $service_collection ) ) : ?>
|
6 |
+
<div class="panel-group" id="services_list" role="tablist" aria-multiselectable="true">
|
7 |
+
<?php foreach ( $service_collection as $i => $service ) : ?>
|
8 |
+
<?php $service_id = $service['id'];
|
9 |
+
$assigned_staff_ids = $service['staff_ids'] ? explode( ',', $service['staff_ids'] ) : array();
|
10 |
+
$all_staff_selected = count( $assigned_staff_ids ) == count( $staff_collection );
|
11 |
+
?>
|
12 |
+
<div class="panel panel-default service" data-service_id="<?php echo $service_id ?>">
|
13 |
+
<div class="panel-heading" role="tab" id="s_<?php echo esc_html( $service_id ) ?>">
|
14 |
+
<h4 class="panel-title">
|
15 |
+
<span class="ab-handle ab-move" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>"><i class="ab-inner-handle glyphicon glyphicon-align-justify"></i></span>
|
16 |
+
<span class="badge" style="background-color: <?php echo esc_attr( $service['color'] ) ?>"> </span>
|
17 |
+
<a role="button" class="collapsed" data-toggle="collapse" data-parent="#services_list" href="#service_<?php echo esc_html( $service_id ) ?>" aria-expanded="false" aria-controls="service_<?php echo esc_html( $service_id ) ?>">
|
18 |
+
<?php echo esc_html( $service['title'] ) ?>
|
19 |
+
</a>
|
20 |
+
<div class="pull-right">
|
21 |
+
<div class="ab-right-nav ab-inline-block">
|
22 |
+
<small>
|
23 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $service['duration'] ) ?>
|
24 |
+
<div class="ab-inline-block" style="width: 75px;text-align: right">
|
25 |
+
<?php echo AB_Utils::formatPrice( $service['price'] ) ?>
|
26 |
+
</div>
|
27 |
+
</small>
|
28 |
+
</div>
|
29 |
+
|
30 |
+
<input style="margin: 0 0 0 5px" type="checkbox" class="service-checker"/>
|
31 |
+
</div>
|
32 |
+
</h4>
|
33 |
+
</div>
|
34 |
+
<div id="service_<?php echo esc_html( $service_id ) ?>" class="panel-collapse collapse" role="tabpanel" aria-labelledby="s_<?php echo esc_html( $service_id ) ?>" style="height: 0px;">
|
35 |
+
<div class="panel-body">
|
36 |
+
<form method="post">
|
37 |
+
<div class="form-group">
|
38 |
+
<label for="title_<?php echo $service_id ?>"><?php _e( 'Title', 'bookly' ) ?></label>
|
39 |
+
<div class="row">
|
40 |
+
<div class="col-sm-11 col-xs-10">
|
41 |
+
<input id="title_<?php echo $service_id ?>" class="form-control" type="text" name="title" value="<?php echo esc_attr( $service['title'] ) ?>" />
|
42 |
+
</div>
|
43 |
+
<div class="col-sm-1 col-xs-2">
|
44 |
+
<div class="service-color-wrapper">
|
45 |
+
<input type="hidden" class="service-color" name="color" value="<?php echo esc_attr( $service['color'] ) ?>" data-last_color='' />
|
46 |
+
</div>
|
47 |
+
</div>
|
48 |
+
</div>
|
49 |
+
</div>
|
50 |
+
<div class="form-group">
|
51 |
+
<div class="row">
|
52 |
+
<div class="col-sm-5 col-xs-10 ab-col-responsive">
|
53 |
+
<label for="duration_<?php echo $service_id ?>"><?php _e( 'Duration', 'bookly' ) ?></label>
|
54 |
+
<select id="duration_<?php echo $service_id ?>" class="form-control" name="duration">
|
55 |
+
<?php for ( $j = $time_interval; $j <= 720; $j += $time_interval ) : ?>
|
56 |
+
<?php if ( $service['duration'] / 60 > $j - $time_interval && $service['duration'] / 60 < $j ): ?>
|
57 |
+
<option value="<?php echo esc_attr( $service['duration'] ) ?>" selected>
|
58 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $service['duration'] ) ?>
|
59 |
+
</option>
|
60 |
+
<?php endif ?>
|
61 |
+
<option value="<?php echo $j * 60 ?>" <?php selected( $service['duration'], $j * 60 ) ?>>
|
62 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $j * 60 ) ?>
|
63 |
+
</option>
|
64 |
+
<?php endfor ?>
|
65 |
+
<option value="86400" <?php selected( $service['duration'], DAY_IN_SECONDS ) ?>>
|
66 |
+
<?php _e( 'All day', 'bookly' ) ?>
|
67 |
+
</option>
|
68 |
+
</select>
|
69 |
+
</div>
|
70 |
+
<div class="col-sm-6 col-xs-10 ab-padding-before-after">
|
71 |
+
<label for="padding_left_<?php echo $service_id ?>"><?php _e( 'Padding time (before and after)', 'bookly' ) ?></label>
|
72 |
+
<div style="clear: both;"></div>
|
73 |
+
<select id="padding_left_<?php echo $service_id ?>" class="form-control ab-auto-w pull-left" name="padding_left">
|
74 |
+
<option value="0"><?php _e( 'OFF', 'bookly' ) ?></option>
|
75 |
+
<?php for ( $j = $time_interval; $j <= 720; $j += $time_interval ) : ?>
|
76 |
+
<?php if ( $service['duration'] / 60 > $j - $time_interval && $service['duration'] / 60 < $j ): ?>
|
77 |
+
<option value="<?php echo esc_attr( $service['duration'] ) ?>" selected>
|
78 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $service['duration'] ) ?>
|
79 |
+
</option>
|
80 |
+
<?php endif ?>
|
81 |
+
<option value="<?php echo $j * 60 ?>" <?php selected( $service['padding_left'], $j * 60 ) ?>>
|
82 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $j * 60 ) ?>
|
83 |
+
</option>
|
84 |
+
<?php endfor ?>
|
85 |
+
</select>
|
86 |
+
<select id="padding_right_<?php echo $service_id ?>" class="form-control ab-auto-w pull-right" name="padding_right">
|
87 |
+
<option value="0"><?php _e( 'OFF', 'bookly' ) ?></option>
|
88 |
+
<?php for ( $j = $time_interval; $j <= 720; $j += $time_interval ) : ?>
|
89 |
+
<?php if ( $service['duration'] / 60 > $j - $time_interval && $service['duration'] / 60 < $j ): ?>
|
90 |
+
<option value="<?php echo esc_attr( $service['duration'] ) ?>" selected>
|
91 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $service['duration'] ) ?>
|
92 |
+
</option>
|
93 |
+
<?php endif ?>
|
94 |
+
<option value="<?php echo $j * 60 ?>" <?php selected( $service['padding_right'], $j * 60 ) ?>>
|
95 |
+
<?php echo AB_DateTimeUtils::secondsToInterval( $j * 60 ) ?>
|
96 |
+
</option>
|
97 |
+
<?php endfor ?>
|
98 |
+
</select>
|
99 |
+
</div>
|
100 |
+
<div class="col-sm-1 col-xs-2">
|
101 |
+
<?php AB_Utils::popover( __( 'Set padding time before and/or after an appointment. For example, if you require 15 minutes to prepare for the next appointment then you should set "padding before" to 15 min. If there is an appointment from 8:00 to 9:00 then the next available time slot will be 9:15 rather than 9:00.', 'bookly' ) ) ?>
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
</div>
|
105 |
+
<div class="form-group">
|
106 |
+
<div class="row">
|
107 |
+
<div class="col-xs-5">
|
108 |
+
<label for="price_<?php echo $service_id ?>"><?php _e( 'Price', 'bookly' ) ?></label>
|
109 |
+
<input id="price_<?php echo $service_id ?>" class="form-control ab-question" type="number" min="0.00" step="any" name="price" value="<?php echo esc_attr( $service['price'] ) ?>"/>
|
110 |
+
</div>
|
111 |
+
<div class="col-sm-3 col-xs-5">
|
112 |
+
<label for="capacity_<?php echo $service_id ?>"><?php _e( 'Capacity', 'bookly' ) ?></label>
|
113 |
+
<input id="capacity_<?php echo $service_id ?>" class="form-control ab-question" type="number" min="1" step="1" name="capacity" value="<?php echo esc_attr( $service['capacity'] ) ?>"/>
|
114 |
+
</div>
|
115 |
+
<div class="col-xs-1">
|
116 |
+
<?php AB_Utils::popover( __( 'The maximum number of customers allowed to book the service for the certain time period.', 'bookly' ) ) ?>
|
117 |
+
</div>
|
118 |
+
</div>
|
119 |
+
</div>
|
120 |
+
<div class="form-group">
|
121 |
+
<div class="row">
|
122 |
+
<div class="col-xs-5">
|
123 |
+
<label for="category_<?php echo $service_id ?>"><?php _e( 'Category', 'bookly' ) ?></label>
|
124 |
+
<select id="category_<?php echo $service_id ?>" class="form-control" name="category_id">
|
125 |
+
<option value="0"></option>
|
126 |
+
<?php foreach ( $category_collection as $category ) : ?>
|
127 |
+
<option value="<?php echo $category['id'] ?>" <?php selected( $category['id'], $service['category_id'] ) ?>>
|
128 |
+
<?php echo esc_html( $category['name'] ) ?>
|
129 |
+
</option>
|
130 |
+
<?php endforeach ?>
|
131 |
+
</select>
|
132 |
+
</div>
|
133 |
+
<div class="col-xs-7">
|
134 |
+
<label><?php _e( 'Providers', 'bookly' ) ?></label>
|
135 |
+
<div style="clear: both"></div>
|
136 |
+
<div class="btn-group">
|
137 |
+
<button class="btn btn-info" data-toggle="dropdown"><i class="glyphicon glyphicon-user"></i> <span class=staff-count><?php echo $service['total_staff'] ?></span>
|
138 |
+
</button>
|
139 |
+
<button class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
140 |
+
<span class="caret"></span>
|
141 |
+
</button>
|
142 |
+
<ul class="dropdown-menu staff-list">
|
143 |
+
<li>
|
144 |
+
<a href="javascript:void(0)">
|
145 |
+
<input type="checkbox" id="service_<?php echo $service_id ?>_all_staff" class="all-staff" <?php checked( $all_staff_selected ) ?>"/>
|
146 |
+
<label class="ab-inline" for="service_<?php echo $service_id ?>_all_staff"><?php _e( 'All staff', 'bookly' ) ?></label>
|
147 |
+
</a>
|
148 |
+
</li>
|
149 |
+
<?php foreach ( $staff_collection as $i => $staff ) : ?>
|
150 |
+
<li>
|
151 |
+
<a href="javascript:void(0)" style="padding-left: 30px">
|
152 |
+
<input type="checkbox" name="staff_ids[]" class="staff" value="<?php echo $staff['id'] ?>" <?php checked( in_array( $staff['id'], $assigned_staff_ids ) ) ?> data-staff_name="<?php echo esc_attr( $staff['full_name'] ) ?>" />
|
153 |
+
<label class="ab-inline" for="service_<?php echo $service_id . '_staff_' . $i ?>">
|
154 |
+
<?php echo esc_html( $staff['full_name'] ) ?>
|
155 |
+
</label>
|
156 |
+
</a>
|
157 |
+
</li>
|
158 |
+
<?php endforeach ?>
|
159 |
+
</ul>
|
160 |
+
</div>
|
161 |
+
</div>
|
162 |
+
</div>
|
163 |
+
</div>
|
164 |
+
<div class="form-group">
|
165 |
+
<input type="hidden" name="action" value="ab_update_service_value">
|
166 |
+
<input type="hidden" name="id" value="<?php echo esc_html( $service_id ) ?>">
|
167 |
+
<input type="hidden" name="update_staff" value="0">
|
168 |
+
<?php AB_Utils::submitButton( null, 'ajax-service-send' ) ?>
|
169 |
+
<?php AB_Utils::resetButton( null, 'js-reset' ) ?>
|
170 |
+
</div>
|
171 |
+
</form>
|
172 |
+
</div>
|
173 |
+
</div>
|
174 |
+
</div>
|
175 |
+
<?php endforeach ?>
|
176 |
+
</div>
|
177 |
+
<?php endif ?>
|
backend/modules/service/templates/index.php
CHANGED
@@ -1,60 +1,105 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
|
3 |
-
<div
|
4 |
-
<div class="
|
5 |
-
|
6 |
-
<div class="ab-category-item ab-active ab-main-category-item" data-id=""><?php _e('All Services','ab') ?></div>
|
7 |
-
<div class="ab-category-item-list">
|
8 |
-
<?php if (count($category_collection)): ?>
|
9 |
-
<?php foreach ($category_collection as $category):?>
|
10 |
-
<div class="ab-category-item" data-id="<?php echo $category->id ?>">
|
11 |
-
<span class="left displayed-value"><?php esc_html_e( $category->name ) ?></span>
|
12 |
-
<a href="#" class="left ab-hidden ab-edit"></a>
|
13 |
-
<input class="value ab-value" type="text" name="name" value="<?php esc_attr_e( $category->name ) ?>" style="display: none" />
|
14 |
-
<a href="#" class="left ab-hidden ab-delete"></a>
|
15 |
-
</div>
|
16 |
-
<?php endforeach ?>
|
17 |
-
<?php endif ?>
|
18 |
-
</div>
|
19 |
-
</div>
|
20 |
-
<input type="hidden" id="color" />
|
21 |
-
<div id="new_category_popup" class="ab-popup-wrapper">
|
22 |
-
<input class="btn btn-info ab-popup-trigger" data- type="submit" value="<?php _e('New Category','ab') ?>" />
|
23 |
-
<div class="ab-popup" style="display: none">
|
24 |
-
<div class="ab-arrow"></div>
|
25 |
-
<div class="ab-content">
|
26 |
-
<form method="post" id="new-category-form">
|
27 |
-
<table class="form-horizontal">
|
28 |
-
<tr>
|
29 |
-
<td>
|
30 |
-
<input class="ab-clear-text" style="width: 170px" type="text" name="name" />
|
31 |
-
<input type="hidden" name="action" value="ab_category_form" />
|
32 |
-
</td>
|
33 |
-
</tr>
|
34 |
-
<tr>
|
35 |
-
<td>
|
36 |
-
<input type="submit" class="btn btn-info ab-popup-save ab-update-button" value="<?php _e('Save category','ab') ?>" />
|
37 |
-
<a class="ab-popup-close" href="#"><?php _e('Cancel','ab') ?></a>
|
38 |
-
</td>
|
39 |
-
</tr>
|
40 |
-
</table>
|
41 |
-
<a class="ab-popup-close ab-popup-close-icon" href="#"></a>
|
42 |
-
</form>
|
43 |
-
</div>
|
44 |
-
</div>
|
45 |
</div>
|
46 |
-
|
47 |
-
<div class="ab-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
</div>
|
58 |
</div>
|
59 |
</div>
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
|
3 |
+
<div class="panel panel-default">
|
4 |
+
<div class="panel-heading">
|
5 |
+
<h3 class="panel-title"><?php _e( 'Services', 'bookly' ) ?></h3>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
</div>
|
7 |
+
<div class="panel-body">
|
8 |
+
<div class="ab-wrapper-container">
|
9 |
+
<div class="row">
|
10 |
+
<div class="ab-left-bar col-md-3 col-sm-3 col-xs-12 col-lg-3">
|
11 |
+
<div id="ab-categories-list">
|
12 |
+
<div class="ab-category-item ab-active ab-main-category-item" data-id=""><?php _e( 'All Services', 'bookly' ) ?></div>
|
13 |
+
<ul id="ab-category-item-list" class="ab-category-item-list">
|
14 |
+
<?php foreach ( $category_collection as $category ): ?>
|
15 |
+
<li class="ab-category-item" data-id="<?php echo $category['id'] ?>">
|
16 |
+
<span class="ab-handle" title="<?php esc_attr_e( 'Reorder', 'bookly' ) ?>">
|
17 |
+
<i class="ab-inner-handle glyphicon glyphicon-align-justify"></i>
|
18 |
+
</span>
|
19 |
+
<span class="left displayed-value"><?php echo esc_html( $category['name'] ) ?></span>
|
20 |
+
<a href="#" class="left ab-hidden ab-edit"></a>
|
21 |
+
<input class="form-control value ab-value" type="text" name="name" value="<?php echo esc_attr( $category['name'] ) ?>" style="display: none" />
|
22 |
+
<a href="#" class="left ab-hidden ab-delete"></a>
|
23 |
+
</li>
|
24 |
+
<?php endforeach ?>
|
25 |
+
</ul>
|
26 |
+
</div>
|
27 |
+
<input type="hidden" id="color" />
|
28 |
+
<div id="new_category_popup" class="ab-popup-wrapper">
|
29 |
+
<input class="btn btn-info ab-popup-trigger" type="submit" value="<?php _e( 'New Category', 'bookly' ) ?>" />
|
30 |
+
<div class="ab-popup" style="display: none; margin-top: 10px;">
|
31 |
+
<div class="ab-arrow"></div>
|
32 |
+
<div class="ab-content">
|
33 |
+
<form method="post" id="new-category-form">
|
34 |
+
<table class="form-horizontal">
|
35 |
+
<tr>
|
36 |
+
<td>
|
37 |
+
<input class="form-control ab-clear-text" style="width: 170px" type="text" name="name" />
|
38 |
+
<input type="hidden" name="action" value="ab_category_form" />
|
39 |
+
</td>
|
40 |
+
</tr>
|
41 |
+
<tr>
|
42 |
+
<td>
|
43 |
+
<?php AB_Utils::submitButton() ?>
|
44 |
+
<a class="ab-popup-close" href="#"><?php _e( 'Cancel', 'bookly' ) ?></a>
|
45 |
+
</td>
|
46 |
+
</tr>
|
47 |
+
</table>
|
48 |
+
<a class="ab-popup-close ab-popup-close-icon" href="#"></a>
|
49 |
+
</form>
|
50 |
+
</div>
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
+
</div>
|
54 |
+
<div class="ab-right-content col-md-9 col-sm-9 col-xs-12 col-lg-9" id="ab_services_wrapper">
|
55 |
+
<h2 class="ab-category-title"><?php _e( 'All Services', 'bookly' ) ?></h2>
|
56 |
+
<div class="no-result"<?php if ( ! empty ( $service_collection ) ) : ?> style="display: none"<?php endif ?>><?php _e( 'No services found. Please add services.', 'bookly' ) ?></div>
|
57 |
+
<div class="list-wrapper">
|
58 |
+
<div id="ab-services-list">
|
59 |
+
<?php include '_list.php' ?>
|
60 |
+
</div>
|
61 |
+
<div class="list-actions">
|
62 |
+
<a class="add-service btn btn-info" href="#"><?php _e( 'Add Service', 'bookly' ) ?></a>
|
63 |
+
<a class="delete btn btn-info" href="#"><?php _e( 'Delete', 'bookly' ) ?></a>
|
64 |
+
</div>
|
65 |
+
</div>
|
66 |
+
</div>
|
67 |
+
</div>
|
68 |
+
<div id="ab-staff-update" class="modal fade">
|
69 |
+
<div class="modal-dialog">
|
70 |
+
<div class="modal-content">
|
71 |
+
<div class="modal-header">
|
72 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
73 |
+
<h4 class="modal-title"><?php _e( 'Update service setting', 'bookly' ) ?></h4>
|
74 |
+
</div>
|
75 |
+
<div class="modal-body" style="white-space: normal">
|
76 |
+
<span class="help-block"><?php _e( 'You are about to change a service setting which is also configured separately for each staff member. Do you want to update it in staff settings too?', 'bookly' ) ?></span>
|
77 |
+
<label>
|
78 |
+
<input style="margin: 0" id="ab-remember-my-choice" type="checkbox" /> <?php _e( 'Remember my choice', 'bookly' ) ?>
|
79 |
+
</label>
|
80 |
+
</div>
|
81 |
+
<div class="modal-footer">
|
82 |
+
<button type="reset" class="btn btn-default ab-no" data-dismiss="modal" aria-hidden="true"><?php _e( 'No, update just here in services', 'bookly' ) ?></button>
|
83 |
+
<button type="submit" class="btn btn-primary ab-yes"><?php _e( 'Yes', 'bookly' ) ?></button>
|
84 |
+
</div>
|
85 |
+
</div><!-- /.modal-content -->
|
86 |
+
</div><!-- /.modal-dialog -->
|
87 |
+
</div><!-- /.modal -->
|
88 |
</div>
|
89 |
</div>
|
90 |
</div>
|
91 |
+
<div class="modal fade" id="lite_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
92 |
+
<div class="modal-dialog">
|
93 |
+
<div class="modal-content">
|
94 |
+
<div class="modal-header">
|
95 |
+
<h4 class="modal-title"><?php _e('Notice', 'bookly') ?></h4>
|
96 |
+
</div>
|
97 |
+
<div class="modal-body">
|
98 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
99 |
+
</div>
|
100 |
+
<div class="modal-footer">
|
101 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php _e('Close', 'bookly') ?></button>
|
102 |
+
</div>
|
103 |
+
</div><!-- /.modal-content -->
|
104 |
+
</div><!-- /.modal-dialog -->
|
105 |
+
</div><!-- /.modal -->
|
backend/modules/service/templates/list.php
DELETED
@@ -1,31 +0,0 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<?php if ( count( $service_collection ) ) : ?>
|
3 |
-
<table class="table table-striped" cellspacing="0" cellpadding="0" border="0" id="services_list">
|
4 |
-
<thead>
|
5 |
-
<tr>
|
6 |
-
<th class="first"> </th>
|
7 |
-
<th><?php echo _e( 'Title', 'ab' ) ?></th>
|
8 |
-
<th width='95'><?php echo _e( 'Duration', 'ab' ) ?></th>
|
9 |
-
<th><?php echo _e( 'Price', 'ab' ) ?></th>
|
10 |
-
<th width='65'><?php echo _e( 'Staff', 'ab' ) ?></th>
|
11 |
-
<th><?php echo _e( 'Category', 'ab' ) ?></th>
|
12 |
-
<th class="last"> </th>
|
13 |
-
</tr>
|
14 |
-
</thead>
|
15 |
-
<tbody>
|
16 |
-
<?php
|
17 |
-
foreach ( $service_collection as $i => $service ) {
|
18 |
-
$row_class = 'service-row ';
|
19 |
-
$row_class .= $i % 2 ? 'even' : 'odd';
|
20 |
-
if ( 0 == $i ) {
|
21 |
-
$row_class .= ' first';
|
22 |
-
}
|
23 |
-
if ( ! isset( $service_collection[$i + 1] ) ) {
|
24 |
-
$row_class .= ' last';
|
25 |
-
}
|
26 |
-
include dirname(__FILE__) . DIRECTORY_SEPARATOR . 'list_item.php';
|
27 |
-
}
|
28 |
-
?>
|
29 |
-
</tbody>
|
30 |
-
</table>
|
31 |
-
<?php endif ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/service/templates/list_item.php
DELETED
@@ -1,96 +0,0 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<tr id="<?php echo $service->id ?>" class="<?php echo $row_class ?>">
|
3 |
-
<td class="first service-color-cell">
|
4 |
-
<div class="service-color-wrapper">
|
5 |
-
<input type="hidden" class="service-color" name="color" value="<?php echo $service->color ?>" />
|
6 |
-
</div>
|
7 |
-
</td>
|
8 |
-
<td class="title editable-cell">
|
9 |
-
<?php if ( $service->title ) : ?>
|
10 |
-
<div class="displayed-value"><?php esc_html_e( $service->title ) ?></div>
|
11 |
-
<input class="value ab-value" type="text" name="title" value="<?php esc_attr_e( $service->title ) ?>" style="display: none" />
|
12 |
-
<?php else : ?>
|
13 |
-
<div class="displayed-value" style="display: none"></div>
|
14 |
-
<input class="value ab-value" type="text" name="title" />
|
15 |
-
<?php endif; ?>
|
16 |
-
</td>
|
17 |
-
<td>
|
18 |
-
<select name="duration">
|
19 |
-
<?php
|
20 |
-
$time_interval = get_option( 'ab_settings_time_slot_length' );
|
21 |
-
?>
|
22 |
-
<!-- Build service duration choices with the range from Time Interval Option to 12. -->
|
23 |
-
<?php for ( $j = $time_interval; $j <= 720; $j += $time_interval ) : ?>
|
24 |
-
<?php
|
25 |
-
$duration = $j * 60;
|
26 |
-
$duration_output = AB_Service::durationToString( $duration );
|
27 |
-
$selected = $service->duration == $duration ? ' selected="selected"' : '';
|
28 |
-
?>
|
29 |
-
<option value="<?php echo $duration ?>"<?php echo $selected ?>>
|
30 |
-
<?php echo $duration_output ?>
|
31 |
-
</option>
|
32 |
-
<?php endfor; ?>
|
33 |
-
</select>
|
34 |
-
</td>
|
35 |
-
<td align='right' class="editable-cell price">
|
36 |
-
<div class="displayed-value ab-rtext"><?php echo $service->price ?></div>
|
37 |
-
<?php if ( $service->price ) : ?>
|
38 |
-
<input class="value ab-text-focus" type="number" min="0.00" step="any" name="price" value="<?php esc_attr_e( $service->price ) ?>" style="display: none" />
|
39 |
-
<?php else : ?>
|
40 |
-
<input class="value ab-text-focus" type="number" min="0.00" step="any" name="price" />
|
41 |
-
<?php endif; ?>
|
42 |
-
</td>
|
43 |
-
<td>
|
44 |
-
<?php if ( count( $staff_collection ) ) : ?>
|
45 |
-
<div class="btn-group">
|
46 |
-
<?php
|
47 |
-
$assigned_staff_ids = $service->staff_ids ? explode(',', $service->staff_ids) : array();
|
48 |
-
$all_staff_selected = count( $assigned_staff_ids ) == count( $staff_collection );
|
49 |
-
?>
|
50 |
-
<button class="btn btn-info"><i class="icon-user icon-white"></i> <span class=staff-count><?php echo $service->total_staff ?></span></button>
|
51 |
-
<button class="btn btn-info dropdown-toggle" data-toggle="dropdown">
|
52 |
-
<span class="caret"></span>
|
53 |
-
</button>
|
54 |
-
<ul class="dropdown-menu">
|
55 |
-
<li>
|
56 |
-
<a href="javascript:void(0)">
|
57 |
-
<input type="checkbox" id="service_<?php echo $service->id ?>_all_staff" class="all-staff"<?php if ( $all_staff_selected ) : ?> checked="checked" <?php endif; ?> />
|
58 |
-
<label class="inline" for="service_<?php echo $service->id ?>_all_staff"><?php _e('All staff','ab') ?></label>
|
59 |
-
</a>
|
60 |
-
</li>
|
61 |
-
<?php foreach ( $staff_collection as $i => $staff ) : ?>
|
62 |
-
<li>
|
63 |
-
<a href="javascript:void(0)" style="padding-left: 30px">
|
64 |
-
<?php $staff_checked = in_array( $staff->id, $assigned_staff_ids ) ?>
|
65 |
-
<input type="checkbox" name="staff_ids[]" class="staff" id="service_<?php echo $service->id ?>_staff_<?php echo $i ?>" value="<?php echo $staff->id ?>"<?php if ( $staff_checked ) : ?> checked="checked"<?php endif; ?>/>
|
66 |
-
<label class="inline" for="service_<?php echo $service->id ?>_staff_<?php echo $i ?>">
|
67 |
-
<?php esc_html_e( $staff->full_name ) ?>
|
68 |
-
</label>
|
69 |
-
</a>
|
70 |
-
</li>
|
71 |
-
<?php endforeach; ?>
|
72 |
-
</ul>
|
73 |
-
</div>
|
74 |
-
<?php else : ?>
|
75 |
-
|
76 |
-
<?php endif; ?>
|
77 |
-
</td>
|
78 |
-
<td>
|
79 |
-
<?php if ( count( $category_collection ) ) : ?>
|
80 |
-
<select name="category_id">
|
81 |
-
<option value="0"></option>
|
82 |
-
<?php foreach ( $category_collection as $category ) : ?>
|
83 |
-
<?php $selected = $category->id == $service->category_id ? ' selected="selected"' : '' ?>
|
84 |
-
<option value="<?php echo $category->id ?>"<?php echo $selected ?>>
|
85 |
-
<?php esc_html_e( $category->name ) ?>
|
86 |
-
</option>
|
87 |
-
<?php endforeach; ?>
|
88 |
-
</select>
|
89 |
-
<?php else: ?>
|
90 |
-
|
91 |
-
<?php endif; ?>
|
92 |
-
</td>
|
93 |
-
<td class="last">
|
94 |
-
<input type="checkbox" class="row-checker" />
|
95 |
-
</td>
|
96 |
-
</tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/settings/AB_SettingsController.php
CHANGED
@@ -1,153 +1,197 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include 'forms/AB_CompanyForm.php';
|
6 |
-
include 'forms/AB_PaymentsForm.php';
|
7 |
-
include 'forms/AB_BusinessHoursForm.php';
|
8 |
|
9 |
/**
|
10 |
* Class AB_SettingsController
|
11 |
*/
|
12 |
class AB_SettingsController extends AB_Controller {
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
}
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
&& $_GET[ 'type' ] != '_import' && $_GET[ 'type' ] != '_general' ) {
|
50 |
-
$this->form->bind( $this->getPost(), $_FILES );
|
51 |
-
$this->form->save();
|
52 |
-
}
|
53 |
-
}
|
54 |
-
|
55 |
-
// get holidays
|
56 |
-
$this->holidays = $this->getHolidays();
|
57 |
-
|
58 |
-
$this->render( 'index' );
|
59 |
-
} // index
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Ajax request for Holidays calendar
|
63 |
-
*/
|
64 |
-
public function executeSettingsHoliday() {
|
65 |
-
$id = $this->getParameter( 'id', false );
|
66 |
-
$holiday = $this->getParameter( 'holiday' ) == 'true';
|
67 |
-
$repeat = $this->getParameter( 'repeat' ) == 'true';
|
68 |
-
$day = $this->getParameter( 'day', false );
|
69 |
-
|
70 |
-
// update or delete the event
|
71 |
-
if ( $id ) {
|
72 |
-
if ( $holiday ) {
|
73 |
-
$this->getWpdb()->update( 'ab_holiday', array('repeat_event' => intval( $repeat ) ), array( 'id' => $id ), array( '%d' ) );
|
74 |
-
$this->getWpdb()->update( 'ab_holiday', array( 'repeat_event' => intval( $repeat ) ), array( 'parent_id' => $id ), array( '%d' ) );
|
75 |
-
} else {
|
76 |
-
$this->getWpdb()->delete( 'ab_holiday', array( 'id' => $id ), array( '%d' ) );
|
77 |
-
$this->getWpdb()->delete( 'ab_holiday', array( 'parent_id' => $id ), array( '%d' ) );
|
78 |
-
}
|
79 |
-
// add the new event
|
80 |
-
} elseif ( $holiday && $day ) {
|
81 |
-
$day = new DateTime( $day );
|
82 |
-
$this->getWpdb()->insert( 'ab_holiday', array( 'holiday' => $day->format( 'Y-m-d H:i:s' ), 'repeat_event' => intval( $repeat ) ), array( '%s', '%d' ) );
|
83 |
-
$parent_id = $this->getWpdb()->insert_id;
|
84 |
-
$staff = $this->getWpdb()->get_results( 'SELECT id FROM ab_staff' );
|
85 |
-
foreach ( $staff as $employee ) {
|
86 |
-
$this->getWpdb()->insert( 'ab_holiday',
|
87 |
-
array(
|
88 |
-
'holiday' => date( 'Y-m-d H:i:s', $day->format( 'U' ) ),
|
89 |
-
'repeat_event' => intval( $repeat ),
|
90 |
-
'staff_id' => $employee->id,
|
91 |
-
'parent_id' => $parent_id
|
92 |
-
),
|
93 |
-
array( '%s', '%d', '%d' )
|
94 |
-
);
|
95 |
-
}
|
96 |
-
}
|
97 |
-
|
98 |
-
// and return refreshed events
|
99 |
-
echo $this->getHolidays();
|
100 |
-
exit;
|
101 |
-
}
|
102 |
-
|
103 |
-
protected function getHolidays() {
|
104 |
-
$collection = $this->getWpdb()->get_results( "SELECT * FROM ab_holiday WHERE staff_id IS NULL" );
|
105 |
-
$holidays = array();
|
106 |
-
if ( count( $collection ) ) {
|
107 |
-
foreach ( $collection as $holiday ) {
|
108 |
-
$holidays[ $holiday->id ] = array(
|
109 |
-
'm' => intval( date( 'm', strtotime( $holiday->holiday ) ) ),
|
110 |
-
'd' => intval( date( 'd', strtotime( $holiday->holiday ) ) ),
|
111 |
-
'title' => $holiday->title,
|
112 |
-
);
|
113 |
-
// if not repeated holiday, add the year
|
114 |
-
if ( ! $holiday->repeat_event ) {
|
115 |
-
$holidays[ $holiday->id ][ 'y' ] = intval( date( 'Y', strtotime( $holiday->holiday ) ) );
|
116 |
-
}
|
117 |
-
}
|
118 |
-
}
|
119 |
-
|
120 |
-
return json_encode( (object) $holidays );
|
121 |
-
}
|
122 |
|
123 |
/**
|
124 |
-
*
|
125 |
*/
|
126 |
-
public function
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
* Ajax request to dismiss admin notice for current user.
|
139 |
*/
|
140 |
-
public function executeDismissAdminNotice()
|
141 |
-
|
|
|
|
|
142 |
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
}
|
145 |
|
146 |
-
/**
|
147 |
-
* Override parent method to add 'wp_ajax_ab_' prefix
|
148 |
-
* so current 'execute*' methods look nicer.
|
149 |
-
*/
|
150 |
-
protected function registerWpActions( $prefix = '' ) {
|
151 |
-
parent::registerWpActions( 'wp_ajax_ab_' );
|
152 |
-
}
|
153 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_SettingsController
|
5 |
*/
|
6 |
class AB_SettingsController extends AB_Controller {
|
7 |
|
8 |
+
const page_slug = 'ab-settings';
|
9 |
+
|
10 |
+
public function index()
|
11 |
+
{
|
12 |
+
/** @var WP_Locale $wp_locale */
|
13 |
+
global $wp_locale;
|
14 |
+
|
15 |
+
$this->enqueueStyles( array(
|
16 |
+
'frontend' => array(
|
17 |
+
'css/ladda.min.css'
|
18 |
+
),
|
19 |
+
'backend' => array(
|
20 |
+
'css/bookly.main-backend.css',
|
21 |
+
'bootstrap/css/bootstrap.min.css',
|
22 |
+
'css/jCal.css',
|
23 |
+
)
|
24 |
+
) );
|
25 |
+
|
26 |
+
$this->enqueueScripts( array(
|
27 |
+
'backend' => array(
|
28 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
29 |
+
'js/jCal.js' => array( 'jquery' ),
|
30 |
+
),
|
31 |
+
'module' => array(
|
32 |
+
'js/settings.js' => array( 'jquery', 'ab-intlTelInput.min.js' ),
|
33 |
+
),
|
34 |
+
'frontend' => array(
|
35 |
+
'js/intlTelInput.min.js' => array( 'jquery' ),
|
36 |
+
'js/spin.min.js' => array( 'jquery' ),
|
37 |
+
'js/ladda.min.js' => array( 'jquery' ),
|
38 |
+
)
|
39 |
+
) );
|
40 |
+
|
41 |
+
wp_localize_script( 'ab-jCal.js', 'BooklyL10n', array(
|
42 |
+
'we_are_not_working' => __( 'We are not working on this day', 'bookly' ),
|
43 |
+
'repeat' => __( 'Repeat every year', 'bookly' ),
|
44 |
+
'months' => array_values( $wp_locale->month ),
|
45 |
+
'days' => array_values( $wp_locale->weekday_abbrev )
|
46 |
+
) );
|
47 |
+
$this->message = '';
|
48 |
+
// Save the settings.
|
49 |
+
if ( ! empty ( $_POST ) ) {
|
50 |
+
switch ( $this->getParameter( 'type' ) ) {
|
51 |
+
case '_payments': // Payments form.
|
52 |
+
update_option( 'ab_settings_pay_locally', (int)$this->getParameter( 'ab_settings_pay_locally' ) );
|
53 |
+
break;
|
54 |
+
case '_hours': // Business hours form.
|
55 |
+
$this->form = new AB_BusinessHoursForm();
|
56 |
+
break;
|
57 |
+
case '_general': // General form.
|
58 |
+
$ab_settings_time_slot_length = $this->getParameter( 'ab_settings_time_slot_length' );
|
59 |
+
if ( in_array( $ab_settings_time_slot_length, array( 5, 10, 12, 15, 20, 30, 60, 90, 120, 180, 240, 360 ) ) ) {
|
60 |
+
update_option( 'ab_settings_time_slot_length', $ab_settings_time_slot_length );
|
61 |
+
}
|
62 |
+
update_option( 'ab_settings_minimum_time_prior_booking', (int)$this->getParameter( 'ab_settings_minimum_time_prior_booking' ) );
|
63 |
+
update_option( 'ab_settings_maximum_available_days_for_booking', (int)$this->getParameter( 'ab_settings_maximum_available_days_for_booking' ) );
|
64 |
+
update_option( 'ab_settings_use_client_time_zone', (int)$this->getParameter( 'ab_settings_use_client_time_zone' ) );
|
65 |
+
update_option( 'ab_settings_cancel_page_url', $this->getParameter( 'ab_settings_cancel_page_url' ) );
|
66 |
+
update_option( 'ab_settings_final_step_url', $this->getParameter( 'ab_settings_final_step_url' ) );
|
67 |
+
update_option( 'ab_settings_allow_staff_members_edit_profile', (int)$this->getParameter( 'ab_settings_allow_staff_members_edit_profile' ) );
|
68 |
+
update_option( 'ab_settings_link_assets_method', $this->getParameter( 'ab_settings_link_assets_method' ) );
|
69 |
+
$this->message = __( 'Settings saved.', 'bookly' );
|
70 |
+
break;
|
71 |
+
case '_google_calendar': // Google calendar form.
|
72 |
+
$this->message = __( 'Settings saved.', 'bookly' );
|
73 |
+
break;
|
74 |
+
case '_holidays': // Holidays form.
|
75 |
+
// Company form.
|
76 |
+
break;
|
77 |
+
case '_customers': // Customers form.
|
78 |
+
update_option( 'ab_settings_create_account', (int)$this->getParameter( 'ab_settings_create_account' ) );
|
79 |
+
update_option( 'ab_settings_phone_default_country', $this->getParameter( 'ab_settings_phone_default_country' ) );
|
80 |
+
update_option( 'ab_sms_default_country_code', $this->getParameter( 'ab_sms_default_country_code' ) );
|
81 |
+
$this->message = __( 'Settings saved.', 'bookly' );
|
82 |
+
break;
|
83 |
+
case '_woocommerce': // WooCommerce form.
|
84 |
+
$this->message = __( 'Settings saved.', 'bookly' );
|
85 |
+
break;
|
86 |
+
case '_company': // Company form.
|
87 |
+
$this->form = new AB_CompanyForm();
|
88 |
+
break;
|
89 |
+
}
|
90 |
+
if ( in_array( $this->getParameter( 'type' ), array ( '_hours', '_company' ) ) ) {
|
91 |
+
$this->form->bind( $this->getPostParameters(), $_FILES );
|
92 |
+
$this->form->save();
|
93 |
+
$this->message = __( 'Settings saved.', 'bookly' );
|
94 |
}
|
95 |
+
}
|
96 |
+
|
97 |
+
// Get holidays.
|
98 |
+
$this->holidays = $this->getHolidays();
|
99 |
+
$this->candidates = $this->getCandidatesBooklyProduct();
|
100 |
+
|
101 |
+
$this->render( 'index' );
|
102 |
+
} // index
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
|
104 |
/**
|
105 |
+
* Ajax request for Holidays calendar
|
106 |
*/
|
107 |
+
public function executeSettingsHoliday()
|
108 |
+
{
|
109 |
+
$id = $this->getParameter( 'id', false );
|
110 |
+
$holiday = $this->getParameter( 'holiday' ) == 'true';
|
111 |
+
$repeat = $this->getParameter( 'repeat' ) == 'true';
|
112 |
+
$day = $this->getParameter( 'day', false );
|
113 |
+
|
114 |
+
// update or delete the event
|
115 |
+
if ( $id ) {
|
116 |
+
if ( $holiday ) {
|
117 |
+
$this->getWpdb()->update( AB_Holiday::getTableName(), array( 'repeat_event' => intval( $repeat ) ), array( 'id' => $id ), array( '%d' ) );
|
118 |
+
$this->getWpdb()->update( AB_Holiday::getTableName(), array( 'repeat_event' => intval( $repeat ) ), array( 'parent_id' => $id ), array( '%d' ) );
|
119 |
+
} else {
|
120 |
+
AB_Holiday::query()->delete()->where( 'id', $id )->where( 'parent_id', $id, 'OR' )->execute();
|
121 |
+
}
|
122 |
+
// add the new event
|
123 |
+
} elseif ( $holiday && $day ) {
|
124 |
+
$holiday = new AB_Holiday( array( 'date' => $day, 'repeat_event' => intval( $repeat ) ) );
|
125 |
+
$holiday->save();
|
126 |
+
foreach ( AB_Staff::query()->fetchArray() as $employee ) {
|
127 |
+
$staff_holiday = new AB_Holiday( array( 'date' => $day, 'repeat_event' => intval( $repeat ), 'staff_id' => $employee['id'], 'parent_id' => $holiday->get( 'id' ) ) );
|
128 |
+
$staff_holiday->save();
|
129 |
+
}
|
130 |
}
|
131 |
+
|
132 |
+
// and return refreshed events
|
133 |
+
echo $this->getHolidays();
|
134 |
+
exit;
|
135 |
+
}
|
136 |
+
|
137 |
+
/**
|
138 |
+
* @return mixed|string|void
|
139 |
+
*/
|
140 |
+
protected function getHolidays()
|
141 |
+
{
|
142 |
+
$collection = AB_Holiday::query()->where( 'staff_id', null )->fetchArray();
|
143 |
+
$holidays = array();
|
144 |
+
if ( count( $collection ) ) {
|
145 |
+
foreach ( $collection as $holiday ) {
|
146 |
+
$holidays[ $holiday['id'] ] = array(
|
147 |
+
'm' => intval( date( 'm', strtotime( $holiday['date'] ) ) ),
|
148 |
+
'd' => intval( date( 'd', strtotime( $holiday['date'] ) ) ),
|
149 |
+
'title' => $holiday['title'],
|
150 |
+
);
|
151 |
+
// if not repeated holiday, add the year
|
152 |
+
if ( ! $holiday['repeat_event'] ) {
|
153 |
+
$holidays[ $holiday['id'] ]['y'] = intval( date( 'Y', strtotime( $holiday['date'] ) ) );
|
154 |
+
}
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
return json_encode( $holidays );
|
159 |
+
}
|
160 |
+
|
161 |
+
protected function getCandidatesBooklyProduct()
|
162 |
+
{
|
163 |
+
$goods = array( array( 'id' => 0, 'name' => __( 'Select product', 'bookly' ) ) );
|
164 |
+
$args = array(
|
165 |
+
'numberposts' => 0,
|
166 |
+
'post_type' => 'product',
|
167 |
+
'suppress_filters' => true
|
168 |
+
);
|
169 |
+
$collection = get_posts( $args );
|
170 |
+
foreach ( $collection as $item ) {
|
171 |
+
$goods[] = array( 'id' => $item->ID, 'name' => $item->post_title );
|
172 |
+
}
|
173 |
+
wp_reset_postdata();
|
174 |
+
|
175 |
+
return $goods;
|
176 |
}
|
177 |
|
178 |
/**
|
179 |
* Ajax request to dismiss admin notice for current user.
|
180 |
*/
|
181 |
+
public function executeDismissAdminNotice()
|
182 |
+
{
|
183 |
+
update_user_meta( get_current_user_id(), 'ab_dismiss_admin_notice', 1 );
|
184 |
+
}
|
185 |
|
186 |
+
/**
|
187 |
+
* Override parent method to add 'wp_ajax_ab_' prefix
|
188 |
+
* so current 'execute*' methods look nicer.
|
189 |
+
*
|
190 |
+
* @param string $prefix
|
191 |
+
*/
|
192 |
+
protected function registerWpActions( $prefix = '' )
|
193 |
+
{
|
194 |
+
parent::registerWpActions( 'wp_ajax_ab_' );
|
195 |
}
|
196 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
197 |
}
|
backend/modules/settings/forms/AB_BusinessHoursForm.php
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
|
|
|
|
|
|
5 |
class AB_BusinessHoursForm extends AB_Form {
|
6 |
|
7 |
-
public function __construct()
|
|
|
8 |
$this->setFields(array(
|
9 |
'ab_settings_monday_start',
|
10 |
'ab_settings_monday_end',
|
@@ -23,33 +25,38 @@ class AB_BusinessHoursForm extends AB_Form {
|
|
23 |
));
|
24 |
}
|
25 |
|
26 |
-
public function save()
|
27 |
-
|
28 |
foreach ( $this->data as $field => $value ) {
|
29 |
update_option( $field, $value );
|
30 |
}
|
31 |
}
|
32 |
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
|
|
|
|
|
|
40 |
$option_name = $field_name . ( $is_start ? '_start' : '_end' );
|
41 |
-
|
42 |
$selected_value = get_option( $option_name );
|
43 |
-
$output = "<select
|
44 |
|
45 |
-
|
|
|
|
|
|
|
46 |
|
47 |
while ( $time_output <= $time_end ) {
|
48 |
-
$value = $time_output
|
49 |
-
$op_name =
|
50 |
-
$
|
51 |
-
$
|
52 |
-
$time_output->modify( $ts_length );
|
53 |
}
|
54 |
|
55 |
$output .= '</select>';
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
+
/**
|
4 |
+
* Class AB_BusinessHoursForm
|
5 |
+
*/
|
6 |
class AB_BusinessHoursForm extends AB_Form {
|
7 |
|
8 |
+
public function __construct()
|
9 |
+
{
|
10 |
$this->setFields(array(
|
11 |
'ab_settings_monday_start',
|
12 |
'ab_settings_monday_end',
|
25 |
));
|
26 |
}
|
27 |
|
28 |
+
public function save()
|
29 |
+
{
|
30 |
foreach ( $this->data as $field => $value ) {
|
31 |
update_option( $field, $value );
|
32 |
}
|
33 |
}
|
34 |
|
35 |
+
/**
|
36 |
+
* @param string $field_name
|
37 |
+
* @param bool $is_start
|
38 |
+
* @return string
|
39 |
+
*/
|
40 |
+
public function renderField( $field_name = 'ab_settings_monday', $is_start = true )
|
41 |
+
{
|
42 |
+
$ts_length = AB_Config::getTimeSlotLength();
|
43 |
+
$time_output = AB_StaffScheduleItem::WORKING_START_TIME;
|
44 |
+
$time_end = AB_StaffScheduleItem::WORKING_END_TIME;
|
45 |
$option_name = $field_name . ( $is_start ? '_start' : '_end' );
|
46 |
+
$class_name = $is_start ? 'select_start' : 'select_end';
|
47 |
$selected_value = get_option( $option_name );
|
48 |
+
$output = "<select class='form-control ab-auto-w {$class_name}' name={$option_name}>";
|
49 |
|
50 |
+
if ( $is_start ) {
|
51 |
+
$output .= "<option value=''>" . __( 'OFF', 'bookly' ) . "</option>";
|
52 |
+
$time_end -= $ts_length;
|
53 |
+
}
|
54 |
|
55 |
while ( $time_output <= $time_end ) {
|
56 |
+
$value = AB_DateTimeUtils::buildTimeString( $time_output, false );
|
57 |
+
$op_name = AB_DateTimeUtils::formatTime( $time_output );
|
58 |
+
$output .= "<option value='{$value}'".selected( $value, $selected_value, false ).">{$op_name}</option>";
|
59 |
+
$time_output += $ts_length;
|
|
|
60 |
}
|
61 |
|
62 |
$output .= '</select>';
|
backend/modules/settings/forms/AB_CompanyForm.php
CHANGED
@@ -1,10 +1,12 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
|
|
|
|
|
|
5 |
class AB_CompanyForm extends AB_Form {
|
6 |
|
7 |
-
public function __construct()
|
|
|
8 |
$this->setFields(array(
|
9 |
'ab_settings_company_name',
|
10 |
'ab_settings_company_logo',
|
@@ -16,31 +18,35 @@ class AB_CompanyForm extends AB_Form {
|
|
16 |
));
|
17 |
}
|
18 |
|
19 |
-
|
20 |
-
|
|
|
|
|
|
|
|
|
21 |
parent::bind( $post, $files );
|
22 |
|
23 |
-
//
|
24 |
if ( isset( $post['ab_remove_logo'] ) && file_exists( get_option( 'ab_settings_company_logo_path' ) ) ) {
|
25 |
unlink( get_option( 'ab_settings_company_logo_path' ) );
|
26 |
update_option( 'ab_settings_company_logo_path', '' );
|
27 |
update_option( 'ab_settings_company_logo_url', '' );
|
28 |
}
|
29 |
|
30 |
-
//
|
31 |
-
if ( isset ($files['ab_settings_company_logo']) && $files['ab_settings_company_logo']['tmp_name'] ) {
|
32 |
|
33 |
-
if ( in_array( $files['ab_settings_company_logo']['type'], array(
|
34 |
-
$
|
35 |
-
if ( $
|
36 |
-
$
|
37 |
-
$
|
38 |
-
$
|
39 |
|
40 |
-
$this->data['ab_settings_company_logo_path'] = $
|
41 |
-
$this->data['ab_settings_company_logo_url'] = $
|
42 |
|
43 |
-
//
|
44 |
if ( file_exists( get_option( 'ab_settings_company_logo_path' ) ) ) {
|
45 |
unlink( get_option( 'ab_settings_company_logo_path' ) );
|
46 |
}
|
@@ -49,8 +55,8 @@ class AB_CompanyForm extends AB_Form {
|
|
49 |
}
|
50 |
}
|
51 |
|
52 |
-
public function save()
|
53 |
-
|
54 |
foreach ( $this->data as $field => $value ) {
|
55 |
update_option( $field, $value );
|
56 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
+
/**
|
4 |
+
* Class AB_CompanyForm
|
5 |
+
*/
|
6 |
class AB_CompanyForm extends AB_Form {
|
7 |
|
8 |
+
public function __construct()
|
9 |
+
{
|
10 |
$this->setFields(array(
|
11 |
'ab_settings_company_name',
|
12 |
'ab_settings_company_logo',
|
18 |
));
|
19 |
}
|
20 |
|
21 |
+
/**
|
22 |
+
* @param array $post
|
23 |
+
* @param array $files
|
24 |
+
*/
|
25 |
+
public function bind( array $post, array $files = array() )
|
26 |
+
{
|
27 |
parent::bind( $post, $files );
|
28 |
|
29 |
+
// Remove the old image.
|
30 |
if ( isset( $post['ab_remove_logo'] ) && file_exists( get_option( 'ab_settings_company_logo_path' ) ) ) {
|
31 |
unlink( get_option( 'ab_settings_company_logo_path' ) );
|
32 |
update_option( 'ab_settings_company_logo_path', '' );
|
33 |
update_option( 'ab_settings_company_logo_url', '' );
|
34 |
}
|
35 |
|
36 |
+
// And add new.
|
37 |
+
if ( isset ( $files['ab_settings_company_logo'] ) && $files['ab_settings_company_logo']['tmp_name'] ) {
|
38 |
|
39 |
+
if ( in_array( $files['ab_settings_company_logo']['type'], array( 'image/gif', 'image/jpeg', 'image/png' ) ) ) {
|
40 |
+
$uploaded = wp_handle_upload( $files['ab_settings_company_logo'], array( 'test_form' => false ) );
|
41 |
+
if ( $uploaded ) {
|
42 |
+
$editor = wp_get_image_editor( $uploaded['file'] );
|
43 |
+
$editor->resize( 200, 200 );
|
44 |
+
$editor->save( $uploaded['file'] );
|
45 |
|
46 |
+
$this->data['ab_settings_company_logo_path'] = $uploaded['file'];
|
47 |
+
$this->data['ab_settings_company_logo_url'] = $uploaded['url'];
|
48 |
|
49 |
+
// Remove old image.
|
50 |
if ( file_exists( get_option( 'ab_settings_company_logo_path' ) ) ) {
|
51 |
unlink( get_option( 'ab_settings_company_logo_path' ) );
|
52 |
}
|
55 |
}
|
56 |
}
|
57 |
|
58 |
+
public function save()
|
59 |
+
{
|
60 |
foreach ( $this->data as $field => $value ) {
|
61 |
update_option( $field, $value );
|
62 |
}
|
backend/modules/settings/forms/AB_PaymentsForm.php
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
class AB_PaymentsForm extends AB_Form {
|
6 |
-
|
7 |
-
public function __construct() {
|
8 |
-
$this->setFields(array(
|
9 |
-
'ab_settings_pay_locally',
|
10 |
-
'ab_paypal_currency'
|
11 |
-
));
|
12 |
-
}
|
13 |
-
|
14 |
-
public function save() {
|
15 |
-
foreach ( $this->data as $field => $value ) {
|
16 |
-
update_option( $field, $value );
|
17 |
-
}
|
18 |
-
}
|
19 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/settings/resources/js/settings.js
CHANGED
@@ -1,7 +1,12 @@
|
|
1 |
jQuery(function ($) {
|
2 |
-
var $form
|
3 |
-
$all_tabs
|
4 |
-
$all_forms
|
|
|
|
|
|
|
|
|
|
|
5 |
$('.select_start', $form).on('change', function () {
|
6 |
var $row = $(this).parent(),
|
7 |
$end_select = $('.select_end', $row),
|
@@ -45,8 +50,9 @@ jQuery(function ($) {
|
|
45 |
}
|
46 |
}).trigger('change');
|
47 |
|
48 |
-
// Reset
|
49 |
-
$('#ab-hours-reset', $form).on('click', function () {
|
|
|
50 |
$('.select_start', $form).each(function () {
|
51 |
$(this).val($(this).data('default_value'));
|
52 |
$(this).trigger('click');
|
@@ -59,7 +65,7 @@ jQuery(function ($) {
|
|
59 |
$('.select_start', $form).trigger('change');
|
60 |
});
|
61 |
|
62 |
-
// Tabs Onclick Handlers
|
63 |
$all_tabs.on('click', function() {
|
64 |
$('.ab-active').removeClass('ab-active');
|
65 |
$(this).addClass('ab-active');
|
@@ -88,6 +94,38 @@ jQuery(function ($) {
|
|
88 |
$all_forms.addClass('hidden');
|
89 |
$('#general-form').removeClass('hidden');
|
90 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
|
92 |
// Company Tab
|
93 |
$('#ab-delete-logo').on('click', function() {
|
@@ -100,17 +138,29 @@ jQuery(function ($) {
|
|
100 |
$('#ab-show-logo').show(300);
|
101 |
});
|
102 |
|
103 |
-
|
104 |
-
|
105 |
-
$('#light_notice').modal('show');
|
106 |
});
|
107 |
|
108 |
-
$('.ab-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
114 |
});
|
115 |
-
});
|
116 |
|
|
1 |
jQuery(function ($) {
|
2 |
+
var $form = $('#business-hours'),
|
3 |
+
$all_tabs = $('#ab_settings_company, #ab_settings_payments, #ab_settings_hours, #ab_settings_holidays, #ab_settings_purchase_code, #ab_settings_google_calendar, #ab_settings_general, #ab_settings_woocommerce, #ab_settings_customers'),
|
4 |
+
$all_forms = $('#company-form, #payments-form, #hours-form, #holidays-form, #purchase-code-form, #general-form, #google-calendar-form, #woocommerce-form, #customers-form'),
|
5 |
+
$final_step_url = $('input[name=ab_settings_final_step_url]'),
|
6 |
+
$final_step_url_mode = $('#ab_settings_final_step_url_mode');
|
7 |
+
|
8 |
+
Ladda.bind( 'button[type=submit]' );
|
9 |
+
|
10 |
$('.select_start', $form).on('change', function () {
|
11 |
var $row = $(this).parent(),
|
12 |
$end_select = $('.select_end', $row),
|
50 |
}
|
51 |
}).trigger('change');
|
52 |
|
53 |
+
// Reset.
|
54 |
+
$('#ab-hours-reset', $form).on('click', function ( e ) {
|
55 |
+
e.preventDefault();
|
56 |
$('.select_start', $form).each(function () {
|
57 |
$(this).val($(this).data('default_value'));
|
58 |
$(this).trigger('click');
|
65 |
$('.select_start', $form).trigger('change');
|
66 |
});
|
67 |
|
68 |
+
// Tabs Onclick Handlers.
|
69 |
$all_tabs.on('click', function() {
|
70 |
$('.ab-active').removeClass('ab-active');
|
71 |
$(this).addClass('ab-active');
|
94 |
$all_forms.addClass('hidden');
|
95 |
$('#general-form').removeClass('hidden');
|
96 |
});
|
97 |
+
$('#ab_settings_woocommerce').on('click', function() {
|
98 |
+
$all_forms.addClass('hidden');
|
99 |
+
$('#woocommerce-form').removeClass('hidden');
|
100 |
+
});
|
101 |
+
$('#ab_settings_google_calendar').on('click', function() {
|
102 |
+
$all_forms.addClass('hidden');
|
103 |
+
$('#google-calendar-form').removeClass('hidden');
|
104 |
+
});
|
105 |
+
|
106 |
+
// Customers Tab
|
107 |
+
var $customers_tab = $('#ab_settings_customers'),
|
108 |
+
$default_country = $('#ab_settings_phone_default_country'),
|
109 |
+
$default_country_code = $('#ab_sms_default_country_code');
|
110 |
+
|
111 |
+
$customers_tab.on('click', function() {
|
112 |
+
$all_forms.addClass('hidden');
|
113 |
+
$('#customers-form').removeClass('hidden');
|
114 |
+
}).on('click.fill', function() {
|
115 |
+
$.each($.fn.intlTelInput.getCountryData(), function( index, value ) {
|
116 |
+
$default_country.append('<option value="'+value.iso2 + '" data-code="' + value.dialCode + '">'+ value.name + ' +' + value.dialCode + '</option>' );
|
117 |
+
});
|
118 |
+
$(this).unbind('click.fill');
|
119 |
+
$default_country.val( $default_country.data('country') );
|
120 |
+
});
|
121 |
+
|
122 |
+
$default_country.on('change', function() {
|
123 |
+
$default_country_code.val($default_country.find('option:selected').data('code'));
|
124 |
+
});
|
125 |
+
|
126 |
+
if ($customers_tab.hasClass('ab-active')){
|
127 |
+
$customers_tab.trigger('click.fill');
|
128 |
+
}
|
129 |
|
130 |
// Company Tab
|
131 |
$('#ab-delete-logo').on('click', function() {
|
138 |
$('#ab-show-logo').show(300);
|
139 |
});
|
140 |
|
141 |
+
$('#ab_settings_google_client_id,#ab_settings_google_client_secret,#ab_settings_google_two_way_sync,#ab_settings_google_limit_events,#ab_settings_google_event_title,#ab_woocommerce,#ab_settings_coupons,#ab_paypal_type,#ab_authorizenet_type,#ab_stripe,#ab_2checkout').on('click', function(){
|
142 |
+
$('#lite_notice').modal('show');
|
|
|
143 |
});
|
144 |
|
145 |
+
$('.ab-popover').popover({
|
146 |
+
trigger : 'hover'
|
147 |
+
});
|
148 |
+
|
149 |
+
$('.ab-popover-ext').popover({
|
150 |
+
content: function() {
|
151 |
+
return $('#' + $(this).data('ext_id')).html();
|
152 |
+
},
|
153 |
+
html: true
|
154 |
+
});
|
155 |
+
|
156 |
+
if ($final_step_url.val()) { $final_step_url_mode.val(1); }
|
157 |
+
$final_step_url_mode.change(function(){
|
158 |
+
|
159 |
+
if (this.value == 0){
|
160 |
+
$final_step_url.hide().val('');
|
161 |
+
}else{
|
162 |
+
$final_step_url.show();
|
163 |
+
}
|
164 |
});
|
|
|
165 |
|
166 |
+
});
|
backend/modules/settings/templates/_companyForm.php
CHANGED
@@ -1,25 +1,21 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<form method="post" action="<?php echo
|
3 |
-
|
4 |
-
<?php if (isset($message_c)) : ?>
|
5 |
-
<div id="message" style="margin: 0px!important;" class="updated below-h2">
|
6 |
-
<button type="button" class="close" data-dismiss="alert">×</button>
|
7 |
-
<p><?php echo $message_c ?></p>
|
8 |
-
</div>
|
9 |
-
<?php endif ?>
|
10 |
-
|
11 |
<table class="form-horizontal">
|
12 |
<tr>
|
13 |
-
<td
|
14 |
-
|
|
|
|
|
15 |
</tr>
|
16 |
<tr>
|
17 |
-
<td valign="top"
|
|
|
|
|
18 |
<td>
|
19 |
<?php if ( get_option( 'ab_settings_company_logo_url' ) ): ?>
|
20 |
<div id="ab-show-logo">
|
21 |
-
<img src="<?php echo get_option( 'ab_settings_company_logo_url' ) ?>" alt="<?php
|
22 |
-
<a id="ab-delete-logo" href="javascript:void(0)"><?php _e( 'Delete','
|
23 |
<br/>
|
24 |
</div>
|
25 |
<?php endif ?>
|
@@ -27,22 +23,28 @@
|
|
27 |
</td>
|
28 |
</tr>
|
29 |
<tr>
|
30 |
-
<td valign="top"
|
31 |
-
|
|
|
|
|
32 |
</tr>
|
33 |
<tr>
|
34 |
-
<td
|
35 |
-
|
|
|
|
|
36 |
</tr>
|
37 |
<tr>
|
38 |
-
<td
|
39 |
-
|
|
|
|
|
40 |
</tr>
|
41 |
<tr>
|
42 |
<td></td>
|
43 |
<td>
|
44 |
-
|
45 |
-
|
46 |
</td>
|
47 |
</tr>
|
48 |
</table>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<form method="post" action="<?php echo esc_url( add_query_arg( 'type', '_company' ) ) ?>" enctype="multipart/form-data" class="ab-settings-form">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
<table class="form-horizontal">
|
4 |
<tr>
|
5 |
+
<td>
|
6 |
+
<label for="ab_settings_company_name"><?php _e( 'Company name', 'bookly' ) ?></label>
|
7 |
+
</td>
|
8 |
+
<td><input id="ab_settings_company_name" class="form-control" type="text" name="ab_settings_company_name" value="<?php echo esc_attr( get_option( 'ab_settings_company_name' ) ) ?>" reset="<?php echo esc_attr( get_option( 'ab_settings_company_name' ) ) ?>"/></td>
|
9 |
</tr>
|
10 |
<tr>
|
11 |
+
<td valign="top">
|
12 |
+
<label for="ab_settings_company_logo"><?php _e( 'Company logo', 'bookly' ) ?></label>
|
13 |
+
</td>
|
14 |
<td>
|
15 |
<?php if ( get_option( 'ab_settings_company_logo_url' ) ): ?>
|
16 |
<div id="ab-show-logo">
|
17 |
+
<img src="<?php echo esc_attr( get_option( 'ab_settings_company_logo_url' ) ) ?>" alt="<?php echo esc_attr( __( 'Company logo', 'bookly' ) ) ?>"/>
|
18 |
+
<a id="ab-delete-logo" href="javascript:void(0)"><?php _e( 'Delete', 'bookly' ) ?></a>
|
19 |
<br/>
|
20 |
</div>
|
21 |
<?php endif ?>
|
23 |
</td>
|
24 |
</tr>
|
25 |
<tr>
|
26 |
+
<td valign="top">
|
27 |
+
<label for="ab_settings_company_address"><?php _e( 'Address', 'bookly' ) ?></label>
|
28 |
+
</td>
|
29 |
+
<td><textarea id="ab_settings_company_address" class="form-control" rows="5" name="ab_settings_company_address"><?php echo esc_attr( get_option( 'ab_settings_company_address' ) ) ?></textarea></td>
|
30 |
</tr>
|
31 |
<tr>
|
32 |
+
<td>
|
33 |
+
<label for="ab_settings_company_phone"><?php _e( 'Phone', 'bookly' ) ?></label>
|
34 |
+
</td>
|
35 |
+
<td><input id="ab_settings_company_phone" class="form-control" type="text" name="ab_settings_company_phone" value="<?php echo esc_attr( get_option( 'ab_settings_company_phone' ) ) ?>" /></td>
|
36 |
</tr>
|
37 |
<tr>
|
38 |
+
<td>
|
39 |
+
<label for="ab_settings_company_website"><?php _e( 'Website', 'bookly' ) ?></label>
|
40 |
+
</td>
|
41 |
+
<td><input id="ab_settings_company_website" class="form-control" type="text" name="ab_settings_company_website" value="<?php echo esc_attr( get_option( 'ab_settings_company_website' ) ) ?>" /></td>
|
42 |
</tr>
|
43 |
<tr>
|
44 |
<td></td>
|
45 |
<td>
|
46 |
+
<?php AB_Utils::submitButton() ?>
|
47 |
+
<?php AB_Utils::resetButton( 'ab-settings-company-reset' ) ?>
|
48 |
</td>
|
49 |
</tr>
|
50 |
</table>
|
backend/modules/settings/templates/_customers.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<form method="post" action="<?php echo esc_url( add_query_arg( 'type', '_customers' ) ) ?>" enctype="multipart/form-data" class="ab-settings-form">
|
3 |
+
<table class="form-horizontal">
|
4 |
+
<tr>
|
5 |
+
<td>
|
6 |
+
<label for="ab_settings_create_account"><?php _e( 'Create WordPress user account for customers', 'bookly' ) ?></label>
|
7 |
+
</td>
|
8 |
+
<td>
|
9 |
+
<?php AB_Utils::optionToggle( 'ab_settings_create_account' ) ?>
|
10 |
+
</td>
|
11 |
+
<td>
|
12 |
+
<?php AB_Utils::popover( __( 'If this setting is enabled then Bookly will be creating WordPress user accounts for all new customers. If the user is logged in then the new customer will be associated with the existing user account.', 'bookly' ) ) ?>
|
13 |
+
</td>
|
14 |
+
</tr>
|
15 |
+
<tr>
|
16 |
+
<td>
|
17 |
+
<label for="ab_settings_phone_default_country"><?php _e( 'Phone field default country', 'bookly' ) ?></label>
|
18 |
+
</td>
|
19 |
+
<td class="ab-valign-top">
|
20 |
+
<select class="form-control" name="ab_settings_phone_default_country" id="ab_settings_phone_default_country" data-country="<?php echo get_option( 'ab_settings_phone_default_country' ) ?>">
|
21 |
+
<option value="auto"><?php _e( 'Guess country by user\'s IP address', 'bookly' ) ?></option>
|
22 |
+
<option disabled><?php echo str_repeat( '─', 30 ) ?></option>
|
23 |
+
</select>
|
24 |
+
</td>
|
25 |
+
<td>
|
26 |
+
<?php AB_Utils::popover( __( 'Select default country for the phone field in the \'Details\' step of booking. You can also let Bookly determine the country based on the IP address of the client.', 'bookly' ) ) ?>
|
27 |
+
</td>
|
28 |
+
</tr>
|
29 |
+
<tr>
|
30 |
+
<td>
|
31 |
+
<label for="ab_sms_default_country_code"><?php _e( 'Default country code', 'bookly' ) ?></label>
|
32 |
+
</td>
|
33 |
+
<td>
|
34 |
+
<input type="text" name="ab_sms_default_country_code" id="ab_sms_default_country_code" value="<?php echo esc_attr( get_option( 'ab_sms_default_country_code' ) ) ?>" class="form-control" />
|
35 |
+
</td>
|
36 |
+
<td>
|
37 |
+
<?php AB_Utils::popover( __( 'Your clients must have their phone numbers in international format in order to receive text messages. However you can specify a default country code that will be used as a prefix for all phone numbers that do not start with "+" or "00". E.g. if you enter "1" as the default country code and a client enters their phone as "(600) 555-2222" the resulting phone number to send the SMS to will be "+1600555222".', 'bookly' ) ) ?>
|
38 |
+
</td>
|
39 |
+
</tr>
|
40 |
+
<tr>
|
41 |
+
<td></td>
|
42 |
+
<td>
|
43 |
+
<?php AB_Utils::submitButton() ?>
|
44 |
+
<?php AB_Utils::resetButton( 'ab-payments-reset' ) ?>
|
45 |
+
</td>
|
46 |
+
</tr>
|
47 |
+
</table>
|
48 |
+
</form>
|
backend/modules/settings/templates/_generalForm.php
CHANGED
@@ -1,103 +1,122 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<form method="post" action="<?php echo
|
3 |
-
|
4 |
-
<?php if (isset($message_g)) : ?>
|
5 |
-
<div id="message" style="margin: 0px!important;" class="updated below-h2">
|
6 |
-
<button type="button" class="close" data-dismiss="alert">×</button>
|
7 |
-
<p><?php echo $message_g ?></p>
|
8 |
-
</div>
|
9 |
-
<?php endif ?>
|
10 |
-
|
11 |
<table class="form-horizontal">
|
12 |
<tr>
|
13 |
-
<td><?php _e('Time slot length','ab') ?></td>
|
14 |
<td>
|
15 |
-
<
|
|
|
|
|
|
|
16 |
<?php
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
<?php } ?>
|
24 |
</select>
|
25 |
-
|
26 |
-
<td>
|
27 |
-
|
28 |
-
src="<?php echo plugins_url( 'resources/images/help.png', dirname(__FILE__).'/../../../AB_Backend.php' ) ?>"
|
29 |
-
alt=""
|
30 |
-
class="ab-help-info"
|
31 |
-
data-help_id="ab-staff-slot"
|
32 |
-
rel='popover'
|
33 |
-
/>
|
34 |
</td>
|
35 |
</tr>
|
36 |
<tr>
|
37 |
<td>
|
38 |
-
<label><?php _e( '
|
39 |
</td>
|
40 |
-
<td
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
|
|
|
|
|
|
|
|
46 |
</td>
|
47 |
</tr>
|
48 |
<tr>
|
49 |
<td>
|
50 |
-
<label><?php _e( '
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
</td>
|
|
|
|
|
52 |
<td>
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
|
|
|
|
58 |
</td>
|
|
|
|
|
59 |
<td>
|
60 |
-
<
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
</td>
|
68 |
</tr>
|
69 |
<tr>
|
70 |
<td>
|
71 |
-
<label><?php _e( '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
</td>
|
|
|
|
|
73 |
<td>
|
74 |
-
<
|
|
|
|
|
|
|
75 |
</td>
|
|
|
|
|
|
|
|
|
|
|
76 |
<td>
|
77 |
-
<
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
|
|
|
|
|
|
84 |
</td>
|
85 |
</tr>
|
86 |
<tr>
|
87 |
<td></td>
|
88 |
-
<td>
|
89 |
-
|
90 |
-
|
91 |
</td>
|
92 |
</tr>
|
93 |
</table>
|
94 |
-
</form>
|
95 |
-
<div id="ab-staff-slot" style="display: none">
|
96 |
-
<p><?php _e('Select the time interval that will be used in frontend and backend, e.g. in calendar, second step of the booking process, while indicating the working hours, etc.', 'ab') ?></p>
|
97 |
-
</div>
|
98 |
-
<div id="ab-staff-zone" style="display: none">
|
99 |
-
<p><?php _e('The value is taken from client’s browser.', 'ab') ?></p>
|
100 |
-
</div>
|
101 |
-
<div id="ab-staff-cancel" style="display: none">
|
102 |
-
<p><?php _e('Insert the URL of the page that is shown to clients after they have cancelled their booking.', 'ab') ?></p>
|
103 |
-
</div>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<form method="post" action="<?php echo esc_url( add_query_arg( 'type', '_general' ) ) ?>" enctype="multipart/form-data" class="ab-settings-form">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
<table class="form-horizontal">
|
4 |
<tr>
|
|
|
5 |
<td>
|
6 |
+
<label for="ab_settings_time_slot_length"><?php _e( 'Time slot length', 'bookly' ) ?></label>
|
7 |
+
</td>
|
8 |
+
<td class="ab-valign-top">
|
9 |
+
<select class="form-control" name="ab_settings_time_slot_length" id="ab_settings_time_slot_length">
|
10 |
<?php
|
11 |
+
foreach ( array( 5, 10, 12, 15, 20, 30, 60, 90, 120, 180, 240, 360 ) as $duration ) {
|
12 |
+
$duration_output = AB_DateTimeUtils::secondsToInterval( $duration * 60 );
|
13 |
+
?>
|
14 |
+
<option value="<?php echo $duration ?>" <?php selected( get_option( 'ab_settings_time_slot_length' ), $duration ) ?>>
|
15 |
+
<?php echo $duration_output ?>
|
16 |
+
</option>
|
17 |
<?php } ?>
|
18 |
</select>
|
19 |
+
</td>
|
20 |
+
<td class="ab-valign-top">
|
21 |
+
<?php AB_Utils::popover( __( 'Select the time interval that will be used in frontend and backend, e.g. in calendar, second step of the booking process, while indicating the working hours, etc.', 'bookly' ) ) ?>
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</td>
|
23 |
</tr>
|
24 |
<tr>
|
25 |
<td>
|
26 |
+
<label for="ab_settings_minimum_time_prior_booking"><?php _e( 'Minimum time requirement prior to booking', 'bookly' ) ?></label>
|
27 |
</td>
|
28 |
+
<td class="ab-valign-top">
|
29 |
+
<select class="form-control" name="ab_settings_minimum_time_prior_booking" id="ab_settings_minimum_time_prior_booking">
|
30 |
+
<option value="0" <?php selected( get_option( 'ab_settings_minimum_time_prior_booking' ), 0 ) ?>><?php _e( 'Disabled', 'bookly' ) ?></option>
|
31 |
+
<?php foreach ( array_merge( range( 1, 12 ), array( 24, 48 ) ) as $hour ): ?>
|
32 |
+
<option value="<?php echo $hour ?>" <?php selected( get_option( 'ab_settings_minimum_time_prior_booking' ), $hour ) ?>><?php echo AB_DateTimeUtils::secondsToInterval( $hour * 3600 ) ?></option>
|
33 |
+
<?php endforeach ?>
|
34 |
+
</select>
|
35 |
+
</td>
|
36 |
+
<td class="ab-valign-top">
|
37 |
+
<?php AB_Utils::popover( __( 'Set a minimum amount of time before the chosen appointment (for example, require the customer to book at least 1 hour before the appointment time).', 'bookly' ) ) ?>
|
38 |
</td>
|
39 |
</tr>
|
40 |
<tr>
|
41 |
<td>
|
42 |
+
<label for="ab_settings_maximum_available_days_for_booking"><?php _e( 'Number of days available for booking', 'bookly' ) ?></label>
|
43 |
+
</td>
|
44 |
+
<td class="ab-valign-top">
|
45 |
+
<input class="form-control" type="number" id="ab_settings_maximum_available_days_for_booking" name="ab_settings_maximum_available_days_for_booking" min="1" max="365" value="<?php echo esc_attr( get_option( 'ab_settings_maximum_available_days_for_booking', 365 ) ) ?>" />
|
46 |
+
</td>
|
47 |
+
<td class="ab-valign-top">
|
48 |
+
<?php AB_Utils::popover( __( 'Specify the number of days that should be available for booking at step 2 starting from the current day.', 'bookly' ) ) ?>
|
49 |
</td>
|
50 |
+
</tr>
|
51 |
+
<tr>
|
52 |
<td>
|
53 |
+
<label for="ab_settings_use_client_time_zone"><?php _e( 'Display available time slots in client\'s time zone', 'bookly' ) ?></label>
|
54 |
+
</td>
|
55 |
+
<td class="ab-valign-top">
|
56 |
+
<?php AB_Utils::optionToggle( 'ab_settings_use_client_time_zone' ) ?>
|
57 |
+
</td>
|
58 |
+
<td class="ab-valign-top">
|
59 |
+
<?php AB_Utils::popover( __( 'The value is taken from client’s browser.', 'bookly' ) ) ?>
|
60 |
</td>
|
61 |
+
</tr>
|
62 |
+
<tr>
|
63 |
<td>
|
64 |
+
<label for="ab_settings_cancel_page_url"><?php _e( 'Cancel appointment page URL', 'bookly' ) ?></label>
|
65 |
+
</td>
|
66 |
+
<td class="ab-valign-top">
|
67 |
+
<input class="form-control" type="text" name="ab_settings_cancel_page_url" id="ab_settings_cancel_page_url" value="<?php echo esc_attr( get_option( 'ab_settings_cancel_page_url' ) ) ?>" placeholder="<?php echo esc_attr( __( 'Enter a URL', 'bookly' ) ) ?>" />
|
68 |
+
</td>
|
69 |
+
<td class="ab-valign-top">
|
70 |
+
<?php AB_Utils::popover( __( 'Insert a URL of a page that is shown to clients after they have cancelled their booking.', 'bookly' ) ) ?>
|
71 |
</td>
|
72 |
</tr>
|
73 |
<tr>
|
74 |
<td>
|
75 |
+
<label for="ab_settings_final_step_url_mode"><?php _e( 'Final step URL', 'bookly' ) ?></label>
|
76 |
+
</td>
|
77 |
+
<td class="ab-valign-top">
|
78 |
+
<select class="form-control" id="ab_settings_final_step_url_mode">
|
79 |
+
<?php foreach ( array( __( 'Disabled', 'bookly' ) => 0, __( 'Enabled', 'bookly' ) => 1 ) as $text => $mode ): ?>
|
80 |
+
<option value="<?php echo esc_attr( $mode ) ?>" <?php selected( get_option( 'ab_settings_final_step_url' ), $mode ) ?> ><?php echo $text ?></option>
|
81 |
+
<?php endforeach ?>
|
82 |
+
</select>
|
83 |
+
<input class="form-control" style="margin-top: 5px; <?php echo get_option( 'ab_settings_final_step_url' ) == ''? 'display: none':''; ?>" type="text" name="ab_settings_final_step_url" value="<?php echo esc_attr( get_option( 'ab_settings_final_step_url' ) ) ?>" placeholder="<?php echo esc_attr( __( 'Enter a URL', 'bookly' ) ) ?>" />
|
84 |
+
</td>
|
85 |
+
<td class="ab-valign-top">
|
86 |
+
<?php AB_Utils::popover( __( 'Set a URL of a page that the user will be forwarded to after successful booking. If disabled then the default step 5 is displayed.', 'bookly' ) ) ?>
|
87 |
</td>
|
88 |
+
</tr>
|
89 |
+
<tr>
|
90 |
<td>
|
91 |
+
<label for="ab_settings_allow_staff_members_edit_profile"><?php _e( 'Allow staff members to edit their profiles', 'bookly' ) ?></label>
|
92 |
+
</td>
|
93 |
+
<td class="ab-valign-top">
|
94 |
+
<?php AB_Utils::optionToggle( 'ab_settings_allow_staff_members_edit_profile' ) ?>
|
95 |
</td>
|
96 |
+
<td class="ab-valign-top">
|
97 |
+
<?php AB_Utils::popover( __( 'If this option is enabled then all staff members who are associated with WordPress users will be able to edit their own profiles, services, schedule and days off.', 'bookly' ) ) ?>
|
98 |
+
</td>
|
99 |
+
</tr>
|
100 |
+
<tr>
|
101 |
<td>
|
102 |
+
<label for="ab_settings_link_assets_method"><?php _e( 'Method to include Bookly JavaScript and CSS files on the page', 'bookly' ) ?></label>
|
103 |
+
</td>
|
104 |
+
<td class="ab-valign-top">
|
105 |
+
<select class="form-control" name="ab_settings_link_assets_method" id="ab_settings_link_assets_method">
|
106 |
+
<option value="enqueue" <?php selected( get_option( 'ab_settings_link_assets_method' ), 'enqueue' ) ?>>Enqueue</option>
|
107 |
+
<option value="print" <?php selected( get_option( 'ab_settings_link_assets_method' ), 'print' ) ?>>Print</option>
|
108 |
+
</select>
|
109 |
+
</td>
|
110 |
+
<td class="ab-valign-top">
|
111 |
+
<?php AB_Utils::popover( __( 'With "Enqueue" method the JavaScript and CSS files of Bookly will be included on all pages of your website. This method should work with all themes. With "Print" method the files will be included only on the pages which contain Bookly booking form. This method may not work with all themes.', 'bookly' ) ) ?>
|
112 |
</td>
|
113 |
</tr>
|
114 |
<tr>
|
115 |
<td></td>
|
116 |
+
<td colspan="2">
|
117 |
+
<?php AB_Utils::submitButton() ?>
|
118 |
+
<?php AB_Utils::resetButton() ?>
|
119 |
</td>
|
120 |
</tr>
|
121 |
</table>
|
122 |
+
</form>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/settings/templates/_googleCalendarForm.php
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<form method="post" action="<?php echo esc_url( add_query_arg( 'type', '_google_calendar' ) ) ?>" enctype="multipart/form-data" class="ab-settings-form">
|
3 |
+
<table class="form-horizontal">
|
4 |
+
<tr>
|
5 |
+
<td colspan="3">
|
6 |
+
<fieldset class="ab-instruction">
|
7 |
+
<legend><?php _e( 'Instructions', 'bookly' ) ?></legend>
|
8 |
+
<div>
|
9 |
+
<div style="margin-bottom: 10px">
|
10 |
+
<?php _e( 'To find your client ID and client secret, do the following:', 'bookly' ) ?>
|
11 |
+
</div>
|
12 |
+
<ol>
|
13 |
+
<li><?php _e( 'Go to the <a href="https://console.developers.google.com/" target="_blank">Google Developers Console</a>.', 'bookly' ) ?></li>
|
14 |
+
<li><?php _e( 'Select a project, or create a new one.', 'bookly' ) ?></li>
|
15 |
+
<li><?php _e( 'In the sidebar on the left, expand <b>APIs & auth</b>. Next, click <b>APIs</b>. In the list of APIs, make sure the status is <b>ON</b> for the Google Calendar API.', 'bookly' ) ?></li>
|
16 |
+
<li><?php _e( 'In the sidebar on the left, select <b>Credentials</b>.', 'bookly' ) ?></li>
|
17 |
+
<li><?php _e( 'Create your project\'s OAuth 2.0 credentials by clicking <b>Create new Client ID</b>, selecting <b>Web application</b>, and providing the information needed to create the credentials. For <b>AUTHORIZED REDIRECT URIS</b> enter the <b>Redirect URI</b> found below on this page.', 'bookly' ) ?></li>
|
18 |
+
<li><?php _e( 'Look for the <b>Client ID</b> and <b>Client secret</b> in the table associated with each of your credentials.', 'bookly' ) ?></li>
|
19 |
+
<li><?php _e( 'Go to Staff Members, select a staff member and click on "Connect" which is located at the bottom of the page.', 'bookly' ) ?></li>
|
20 |
+
</ol>
|
21 |
+
</div>
|
22 |
+
</fieldset>
|
23 |
+
</td>
|
24 |
+
</tr>
|
25 |
+
<tr>
|
26 |
+
<td colspan="3">
|
27 |
+
<div class="ab-payments-title"><?php _e( 'Google Calendar', 'bookly' ) ?></div>
|
28 |
+
</td>
|
29 |
+
</tr>
|
30 |
+
<tr>
|
31 |
+
<td>
|
32 |
+
<label for="ab_settings_google_client_id"><?php _e( 'Client ID', 'bookly' ) ?></label>
|
33 |
+
</td>
|
34 |
+
<td>
|
35 |
+
<input id="ab_settings_google_client_id" class="form-control" type="text" />
|
36 |
+
</td>
|
37 |
+
<td>
|
38 |
+
<?php AB_Utils::popover( __( 'The client ID obtained from the Developers Console', 'bookly' ) ) ?>
|
39 |
+
</td>
|
40 |
+
</tr>
|
41 |
+
<tr>
|
42 |
+
<td>
|
43 |
+
<label for="ab_settings_google_client_secret"><?php _e( 'Client secret', 'bookly' ) ?></label>
|
44 |
+
</td>
|
45 |
+
<td>
|
46 |
+
<input id="ab_settings_google_client_secret" class="form-control" type="text" />
|
47 |
+
</td>
|
48 |
+
<td>
|
49 |
+
<?php AB_Utils::popover( __( 'The client secret obtained from the Developers Console', 'bookly' ) ) ?>
|
50 |
+
</td>
|
51 |
+
</tr>
|
52 |
+
<tr>
|
53 |
+
<td>
|
54 |
+
<label for="ab_redirect_uri"><?php _e( 'Redirect URI', 'bookly' ) ?></label>
|
55 |
+
</td>
|
56 |
+
<td>
|
57 |
+
<input id="ab_redirect_uri" class="form-control" type="text" readonly value="<?php echo admin_url( 'admin.php' ) . '?page='.AB_StaffController::page_slug ?>" onclick="this.select();" style="cursor: pointer;" />
|
58 |
+
</td>
|
59 |
+
<td>
|
60 |
+
<?php AB_Utils::popover( __( 'Enter this URL as a redirect URI in the Developers Console', 'bookly' ) ) ?>
|
61 |
+
</td>
|
62 |
+
</tr>
|
63 |
+
<tr>
|
64 |
+
<td>
|
65 |
+
<label for="ab_settings_google_two_way_sync"><?php _e( '2 way sync', 'bookly' ) ?></label>
|
66 |
+
</td>
|
67 |
+
<td>
|
68 |
+
<?php AB_Utils::optionToggle( 'ab_settings_google_two_way_sync', array( 'f' => array( '0', __( 'Disabled', 'bookly' ), 't' => array( '1', __( 'Enabled', 'bookly' ) ) ) ) ) ?>
|
69 |
+
</td>
|
70 |
+
<td>
|
71 |
+
<?php AB_Utils::popover( __( 'By default Bookly pushes new appointments and any further changes to Google Calendar. If you enable this option then Bookly will fetch events from Google Calendar and remove corresponding time slots before displaying the second step of the booking form (this may lead to a delay when users click Next at the first step).', 'bookly' ) ) ?>
|
72 |
+
</td>
|
73 |
+
</tr>
|
74 |
+
<tr>
|
75 |
+
<td>
|
76 |
+
<label for="ab_settings_google_limit_events"><?php _e( 'Limit number of fetched events', 'bookly' ) ?></label>
|
77 |
+
</td>
|
78 |
+
<td>
|
79 |
+
<select id="ab_settings_google_limit_events" class="form-control">
|
80 |
+
<?php foreach ( array( __( 'Disabled', 'bookly' ) => '0', 25 => 25, 50 => 50, 100 => 100, 250 => 250, 500 => 500, 1000 => 1000, 2500 => 2500 ) as $text => $limit ): ?>
|
81 |
+
<option value="<?php echo $limit ?>" <?php selected( get_option( 'ab_settings_google_limit_events' ), $limit ) ?> ><?php echo $text ?></option>
|
82 |
+
<?php endforeach ?>
|
83 |
+
</select>
|
84 |
+
</td>
|
85 |
+
<td>
|
86 |
+
<?php AB_Utils::popover( __( 'If there is a lot of events in Google Calendar sometimes this leads to a lack of memory in PHP when Bookly tries to fetch all events. You can limit the number of fetched events here. This only works when 2 way sync is enabled.', 'bookly' ) ) ?>
|
87 |
+
</td>
|
88 |
+
</tr>
|
89 |
+
<tr>
|
90 |
+
<td>
|
91 |
+
<label for="ab_settings_google_event_title"><?php _e( 'Template for event title', 'bookly' ) ?></label>
|
92 |
+
</td>
|
93 |
+
<td>
|
94 |
+
<input id="ab_settings_google_event_title" class="form-control" type="text" value="[[SERVICE_NAME]]" >
|
95 |
+
</td>
|
96 |
+
<td>
|
97 |
+
<?php AB_Utils::popover( __( 'Configure what information should be places in the title of Google Calendar event. Available codes are [[SERVICE_NAME]], [[STAFF_NAME]] and [[CLIENT_NAMES]].', 'bookly' ) ) ?>
|
98 |
+
</td>
|
99 |
+
</tr>
|
100 |
+
|
101 |
+
<tr>
|
102 |
+
<td></td>
|
103 |
+
<td>
|
104 |
+
<?php AB_Utils::submitButton() ?>
|
105 |
+
<?php AB_Utils::resetButton() ?>
|
106 |
+
</td>
|
107 |
+
<td></td>
|
108 |
+
</tr>
|
109 |
+
</table>
|
110 |
+
</form>
|
backend/modules/settings/templates/_holidaysForm.php
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<div id="ab-annual-calendar-scroll" style="text-align: center;">
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
</div>
|
9 |
<div id="ab-annual-calendar"></div>
|
10 |
|
@@ -12,13 +12,13 @@
|
|
12 |
jQuery(function($) {
|
13 |
var d = new Date();
|
14 |
$('#ab-annual-calendar').jCal({
|
15 |
-
day:
|
16 |
-
days:
|
17 |
-
showMonths:
|
18 |
scrollSpeed: 350,
|
19 |
events: <?php echo $holidays ?>,
|
20 |
action: 'ab_settings_holiday',
|
21 |
-
dayOffset: <?php echo get_option('start_of_week'
|
22 |
});
|
23 |
});
|
24 |
</script>
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div id="ab-annual-calendar-scroll" style="text-align: center; max-width: 715px;">
|
3 |
+
<div class="input-prepend input-append form-inline">
|
4 |
+
<span class="prev glyphicon glyphicon-triangle-left"></span>
|
5 |
+
<input style="width: 70px; text-align: center;background: white" class="jcal_year form-control" readonly="readonly" id="appendedPrependedInput" size="16" type="text" value="">
|
6 |
+
<span class="next glyphicon glyphicon-triangle-right"></span>
|
7 |
+
</div>
|
8 |
</div>
|
9 |
<div id="ab-annual-calendar"></div>
|
10 |
|
12 |
jQuery(function($) {
|
13 |
var d = new Date();
|
14 |
$('#ab-annual-calendar').jCal({
|
15 |
+
day: new Date(d.getFullYear(), 0, 1),
|
16 |
+
days: 1,
|
17 |
+
showMonths: 12,
|
18 |
scrollSpeed: 350,
|
19 |
events: <?php echo $holidays ?>,
|
20 |
action: 'ab_settings_holiday',
|
21 |
+
dayOffset: <?php echo (int) get_option( 'start_of_week' ) ?>
|
22 |
});
|
23 |
});
|
24 |
</script>
|
backend/modules/settings/templates/_hoursForm.php
CHANGED
@@ -1,30 +1,30 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
<table>
|
13 |
-
<?php foreach ( array( 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' ) as $day ): ?>
|
14 |
<tr>
|
15 |
-
<td><?php _e( ucfirst( $day ) ) ?></td>
|
16 |
<td>
|
17 |
-
|
18 |
-
|
19 |
-
|
|
|
|
|
|
|
20 |
</td>
|
21 |
</tr>
|
22 |
-
<?php
|
|
|
23 |
<tr>
|
24 |
<td></td>
|
25 |
<td>
|
26 |
-
|
27 |
-
|
28 |
</td>
|
29 |
</tr>
|
30 |
</table>
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
$start_of_week = (int) get_option( 'start_of_week' );
|
3 |
+
?>
|
4 |
+
<form method="post" action="<?php echo esc_url( add_query_arg( 'type', '_hours' ) ) ?>" class="ab-settings-form" id="business-hours">
|
5 |
+
<?php $form = new AB_BusinessHoursForm() ?>
|
6 |
+
<table class="form-inline">
|
7 |
+
<tbody>
|
8 |
+
<?php for( $i = 0; $i < 7; $i++):
|
9 |
+
$day = strtolower( AB_DateTimeUtils::getWeekDayByNumber( ( $i + $start_of_week ) % 7 ) );
|
10 |
+
?>
|
|
|
|
|
|
|
11 |
<tr>
|
|
|
12 |
<td>
|
13 |
+
<label><?php _e( ucfirst( $day ) ) ?> </label>
|
14 |
+
</td>
|
15 |
+
<td>
|
16 |
+
<?php echo $form->renderField( 'ab_settings_' . $day ) ?>
|
17 |
+
<span> <?php _e( 'to', 'bookly' ) ?> </span>
|
18 |
+
<?php echo $form->renderField( 'ab_settings_' . $day, false ) ?>
|
19 |
</td>
|
20 |
</tr>
|
21 |
+
<?php endfor ?>
|
22 |
+
</tbody>
|
23 |
<tr>
|
24 |
<td></td>
|
25 |
<td>
|
26 |
+
<?php AB_Utils::submitButton() ?>
|
27 |
+
<?php AB_Utils::resetButton( 'ab-hours-reset' ) ?>
|
28 |
</td>
|
29 |
</tr>
|
30 |
</table>
|
backend/modules/settings/templates/_paymentsForm.php
CHANGED
@@ -1,68 +1,64 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<form method="post" action="<?php echo
|
3 |
-
<?php if (isset($message_p)) : ?>
|
4 |
-
<div id="message" style="margin: 0px!important;" class="updated below-h2">
|
5 |
-
<button type="button" class="close" data-dismiss="alert">×</button>
|
6 |
-
<p><?php echo $message_p ?></p>
|
7 |
-
</div>
|
8 |
-
<?php endif ?>
|
9 |
<table class="form-horizontal">
|
10 |
-
<tr>
|
11 |
-
<td style="width: 170px;"><?php _e( 'Currency','ab' ) ?></td>
|
12 |
-
<td>
|
13 |
-
<select name="ab_paypal_currency" style="width: 200px;">
|
14 |
-
<?php foreach ( PayPal::getCurrencyCodes() as $code ): ?>
|
15 |
-
<option value="<?php echo $code ?>" <?php selected( get_option( 'ab_paypal_currency' ), $code ); ?> ><?php echo $code ?></option>
|
16 |
-
<?php endforeach ?>
|
17 |
-
</select>
|
18 |
-
</td>
|
19 |
-
</tr>
|
20 |
<tr>
|
21 |
-
<td
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
</tr>
|
23 |
<tr>
|
24 |
<td colspan="2">
|
25 |
-
|
26 |
-
<?php foreach ( array( __( 'Disabled', 'ab' ) => '0', __( 'Enabled', 'ab' ) => '1' ) as $text => $mode ): ?>
|
27 |
-
<option value="<?php echo $mode ?>" <?php selected( get_option( 'ab_settings_pay_locally' ), $mode ); ?> ><?php echo $text ?></option>
|
28 |
-
<?php endforeach ?>
|
29 |
-
</select>
|
30 |
</td>
|
31 |
</tr>
|
32 |
<tr>
|
33 |
-
<td colspan="2"><div class="ab-payments-title"
|
34 |
</tr>
|
35 |
<tr>
|
36 |
<td colspan="2">
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
</td>
|
43 |
</tr>
|
44 |
<tr>
|
45 |
<td colspan="2">
|
46 |
-
|
47 |
-
|
48 |
</td>
|
49 |
<td></td>
|
50 |
</tr>
|
51 |
</table>
|
52 |
-
</form>
|
53 |
-
|
54 |
-
<div class="modal fade" id="light_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
55 |
-
<div class="modal-dialog">
|
56 |
-
<div class="modal-content">
|
57 |
-
<div class="modal-header">
|
58 |
-
<h4 class="modal-title">Notice</h4>
|
59 |
-
</div>
|
60 |
-
<div class="modal-body">
|
61 |
-
<?php _e('This function is disabled in the light verison of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $35 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here'); ?>: <a href="http://bookly.ladela.com" target="_blank">http://bookly.ladela.com</a>
|
62 |
-
</div>
|
63 |
-
<div class="modal-footer">
|
64 |
-
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
65 |
-
</div>
|
66 |
-
</div><!-- /.modal-content -->
|
67 |
-
</div><!-- /.modal-dialog -->
|
68 |
-
</div><!-- /.modal -->
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<form method="post" action="<?php echo esc_url( add_query_arg( 'type', '_payments' ) ) ?>" class="ab-settings-form">
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
<table class="form-horizontal">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
<tr>
|
5 |
+
<td style="width: 170px;">
|
6 |
+
<label for="ab_paypal_currency"><?php _e( 'Currency', 'bookly' ) ?></label>
|
7 |
+
</td>
|
8 |
+
<td>
|
9 |
+
<select id="ab_paypal_currency" class="form-control" name="ab_paypal_currency">
|
10 |
+
<?php foreach ( array( 'AUD', 'BRL', 'CAD', 'CHF', 'CLP', 'COP', 'CZK', 'DKK', 'EUR', 'GBP', 'GTQ', 'HKD', 'HUF', 'IDR', 'INR', 'ILS', 'JPY', 'KRW', 'KZT', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'QAR', 'RON', 'RMB', 'RUB', 'SAR', 'SEK', 'SGD', 'THB', 'TRY', 'TWD', 'UGX', 'USD', 'ZAR' ) as $code ): ?>
|
11 |
+
<option value="<?php echo $code ?>" <?php selected( get_option( 'ab_paypal_currency' ), $code ) ?> ><?php echo $code ?></option>
|
12 |
+
<?php endforeach ?>
|
13 |
+
</select>
|
14 |
+
</td>
|
15 |
+
</tr>
|
16 |
+
<tr>
|
17 |
+
<td style="width: 170px;">
|
18 |
+
<label for="ab_settings_coupons"><?php _e( 'Coupons', 'bookly' ) ?></label>
|
19 |
+
</td>
|
20 |
+
<td>
|
21 |
+
<?php AB_Utils::optionToggle( 'ab_settings_coupons' ) ?>
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
<tr>
|
25 |
+
<td colspan="2"><div class="ab-payments-title"><?php _e( 'Service paid locally', 'bookly' ) ?></div></td>
|
26 |
</tr>
|
27 |
<tr>
|
28 |
<td colspan="2">
|
29 |
+
<?php AB_Utils::optionToggle( 'ab_settings_pay_locally' ) ?>
|
|
|
|
|
|
|
|
|
30 |
</td>
|
31 |
</tr>
|
32 |
<tr>
|
33 |
+
<td colspan="2"><div class="ab-payments-title">PayPal</div></td>
|
34 |
</tr>
|
35 |
<tr>
|
36 |
<td colspan="2">
|
37 |
+
<?php AB_Utils::optionToggle( 'ab_paypal_type', array( 'f' => array( 'disabled', __( 'Disabled', 'bookly' ) ), 't' => array( 'ec', 'PayPal Express Checkout' ) ) ) ?>
|
38 |
+
</td>
|
39 |
+
</tr>
|
40 |
+
<tr>
|
41 |
+
<td colspan="2"><div class="ab-payments-title">Authorize.Net</div></td>
|
42 |
+
</tr>
|
43 |
+
<tr>
|
44 |
+
<td colspan="2">
|
45 |
+
<?php AB_Utils::optionToggle( 'ab_authorizenet_type', array( 'f' => array( 'disabled', __( 'Disabled', 'bookly' ) ), 't' => array( 'aim', 'Authorize.Net AIM' ) ) ) ?>
|
46 |
+
</td>
|
47 |
+
</tr>
|
48 |
+
<tr>
|
49 |
+
<td colspan="2"><div class="ab-payments-title">Stripe</div></td>
|
50 |
+
</tr>
|
51 |
+
<tr>
|
52 |
+
<td colspan="2">
|
53 |
+
<?php AB_Utils::optionToggle( 'ab_stripe' ) ?>
|
54 |
</td>
|
55 |
</tr>
|
56 |
<tr>
|
57 |
<td colspan="2">
|
58 |
+
<?php AB_Utils::submitButton() ?>
|
59 |
+
<?php AB_Utils::resetButton( 'ab-payments-reset' ) ?>
|
60 |
</td>
|
61 |
<td></td>
|
62 |
</tr>
|
63 |
</table>
|
64 |
+
</form>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/settings/templates/_purchaseCodeForm.php
DELETED
@@ -1,26 +0,0 @@
|
|
1 |
-
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<form enctype="multipart/form-data" method="post" action="<?php echo $current_url . '&type=_purchase_code' ?>" class="ab-staff-form" id="purchase_code">
|
3 |
-
<?php if ( isset ( $message_pc ) ) : ?>
|
4 |
-
<div class="alert">
|
5 |
-
<button type="button" class="close" data-dismiss="alert">×</button>
|
6 |
-
<?php echo $message_pc ?>
|
7 |
-
</div>
|
8 |
-
<?php endif ?>
|
9 |
-
|
10 |
-
<table class="form-horizontal">
|
11 |
-
<tr>
|
12 |
-
<td><?php _e( 'Purchase Code', 'ab' ) ?></td>
|
13 |
-
<td>
|
14 |
-
<label for="purchase_code"></label>
|
15 |
-
<input class="purchase-code" type="text" size="255" name="ab_envato_purchase_code" value="<?php echo get_option( 'ab_envato_purchase_code' ) ?>" />
|
16 |
-
</td>
|
17 |
-
</tr>
|
18 |
-
<tr>
|
19 |
-
<td></td>
|
20 |
-
<td>
|
21 |
-
<input type="submit" value="<?php _e( 'Save', 'ab' ) ?>" class="btn btn-info ab-update-button" />
|
22 |
-
<button class="ab-reset-form" type="reset"><?php _e( ' Reset ', 'ab' ) ?></button>
|
23 |
-
</td>
|
24 |
-
</tr>
|
25 |
-
</table>
|
26 |
-
</form>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
backend/modules/settings/templates/_woocommerce.php
ADDED
@@ -0,0 +1,77 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<form enctype="multipart/form-data" method="post" action="<?php echo esc_url( add_query_arg( 'type', '_woocommerce' ) ) ?>" class="ab-settings-form" id="woocommerce">
|
3 |
+
<table class="form-horizontal">
|
4 |
+
<tr>
|
5 |
+
<td colspan="2">
|
6 |
+
<fieldset class="ab-instruction">
|
7 |
+
<legend><?php _e( 'Instructions', 'bookly' ) ?></legend>
|
8 |
+
<div>
|
9 |
+
<div style="margin-bottom: 10px">
|
10 |
+
<?php _e( 'You need to install and activate WooCommerce plugin before using the options below.<br/><br/>Once the plugin is activated do the following steps:', 'bookly' ) ?>
|
11 |
+
</div>
|
12 |
+
<ol>
|
13 |
+
<li><?php _e( 'Create a product in WooCommerce that can be placed in cart.', 'bookly' ) ?></li>
|
14 |
+
<li><?php _e( 'In the form below enable WooCommerce option.', 'bookly' ) ?></li>
|
15 |
+
<li><?php _e( 'Select the product that you created at step 1 in the drop down list of products.', 'bookly' ) ?></li>
|
16 |
+
<li><?php _e( 'If needed, edit item data which will be displayed in the cart.', 'bookly' ) ?></li>
|
17 |
+
</ol>
|
18 |
+
<div style="margin-top: 10px">
|
19 |
+
<?php _e( 'Note that once you have enabled WooCommerce option in Bookly the built-in payment methods will no longer work. All your customers will be redirected to WooCommerce cart instead of standard payment step.', 'bookly' ) ?>
|
20 |
+
</div>
|
21 |
+
</div>
|
22 |
+
</fieldset>
|
23 |
+
</td>
|
24 |
+
</tr>
|
25 |
+
<tr>
|
26 |
+
<td colspan="2"><div class="ab-payments-title">WooCommerce</div></td>
|
27 |
+
</tr>
|
28 |
+
<tr>
|
29 |
+
<td>
|
30 |
+
<?php AB_Utils::optionToggle( 'ab_woocommerce' ) ?>
|
31 |
+
</td>
|
32 |
+
</tr>
|
33 |
+
<tr>
|
34 |
+
<td colspan="2">
|
35 |
+
<?php _e( 'Booking product', 'bookly' ) ?>
|
36 |
+
<select class="form-control" name="ab_woocommerce_product">
|
37 |
+
<?php foreach ( $candidates as $item ) : ?>
|
38 |
+
<option value="<?php echo $item['id'] ?>" <?php selected( get_option( 'ab_woocommerce_product' ), $item['id'] ); ?>>
|
39 |
+
<?php echo $item['name'] ?>
|
40 |
+
</option>
|
41 |
+
<?php endforeach ?>
|
42 |
+
</select>
|
43 |
+
</td>
|
44 |
+
</tr>
|
45 |
+
<tr>
|
46 |
+
<td colspan="2"><div class="ab-payments-title"><?php _e( 'Cart item data', 'bookly' ) ?></td>
|
47 |
+
</tr>
|
48 |
+
<tr>
|
49 |
+
<td colspan="2"><input class="form-control" type="text" name="ab_woocommerce_cart_info_name" value="<?php echo esc_attr( get_option( 'ab_woocommerce_cart_info_name' ) ) ?>" placeholder="<?php echo esc_attr( __( 'Enter a name', 'bookly' ) ) ?>" /></td>
|
50 |
+
</tr>
|
51 |
+
<tr>
|
52 |
+
<td colspan="2">
|
53 |
+
<textarea class="form-control" rows="8" name="ab_woocommerce_cart_info_value" style="width: 100%" placeholder="<?php _e( 'Enter a value', 'bookly' ) ?>"><?php echo esc_textarea( get_option( 'ab_woocommerce_cart_info_value' ) ) ?></textarea>
|
54 |
+
</td>
|
55 |
+
</tr>
|
56 |
+
<tr>
|
57 |
+
<td>
|
58 |
+
<div class="ab-codes">
|
59 |
+
<table>
|
60 |
+
<tr><td><input value="[[APPOINTMENT_DATE]]" readonly="readonly" onclick="this.select()"> - <?php _e('date of appointment', 'bookly') ?></td></tr>
|
61 |
+
<tr><td><input value="[[APPOINTMENT_TIME]]" readonly="readonly" onclick="this.select()"> - <?php _e('time of appointment', 'bookly') ?></td></tr>
|
62 |
+
<tr><td><input value="[[CATEGORY_NAME]]" readonly="readonly" onclick="this.select()"> - <?php _e('name of category', 'bookly') ?></td></tr>
|
63 |
+
<tr><td><input value="[[SERVICE_NAME]]" readonly="readonly" onclick="this.select()"> - <?php _e('name of service', 'bookly') ?></td></tr>
|
64 |
+
<tr><td><input value="[[SERVICE_PRICE]]" readonly="readonly" onclick="this.select()"> - <?php _e('price of service', 'bookly') ?></td></tr>
|
65 |
+
<tr><td><input value="[[STAFF_NAME]]" readonly="readonly" onclick="this.select()"> - <?php _e('name of staff', 'bookly') ?></td></tr>
|
66 |
+
</table>
|
67 |
+
</div>
|
68 |
+
</td>
|
69 |
+
</tr>
|
70 |
+
<tr>
|
71 |
+
<td colspan="2">
|
72 |
+
<?php AB_Utils::submitButton() ?>
|
73 |
+
<?php AB_Utils::resetButton() ?>
|
74 |
+
</td>
|
75 |
+
</tr>
|
76 |
+
</table>
|
77 |
+
</form>
|
backend/modules/settings/templates/admin_notice.php
CHANGED
@@ -1,8 +1,9 @@
|
|
|
|
1 |
<div id=ab_admin_notice class=update-nag>
|
2 |
<h3>Bookly</h3>
|
3 |
-
<p><?php _e( 'Please do not forget to specify your purchase code in Bookly <a href="admin.php?page=ab-
|
4 |
-
<p><?php _e( '<b>Important!</b> Please be aware that if your copy of Bookly was not downloaded from Codecanyon (the only channel of Bookly distribution), you may put your website under significant risk - it is very likely that it
|
5 |
-
<a id="ab_dismiss" href="#"><?php _e( 'Dismiss', '
|
6 |
</div>
|
7 |
|
8 |
<script type="text/javascript">
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
<div id=ab_admin_notice class=update-nag>
|
3 |
<h3>Bookly</h3>
|
4 |
+
<p><?php _e( 'Please do not forget to specify your purchase code in Bookly <a href="admin.php?page=ab-settings">settings</a>. Upon providing the code you will have access to free updates of Bookly. Updates may contain functionality improvements and important security fixes.', 'bookly' ) ?></p>
|
5 |
+
<p><?php _e( '<b>Important!</b> Please be aware that if your copy of Bookly was not downloaded from Codecanyon (the only channel of Bookly distribution), you may put your website under significant risk - it is very likely that it contains a malicious code, a trojan or a backdoor. Please consider buying a licensed copy of Bookly <a href="http://booking-wp-plugin.com" target="_blank">here</a>.', 'bookly' ) ?></p>
|
6 |
+
<a id="ab_dismiss" href="#"><?php _e( 'Dismiss', 'bookly' ) ?></a>
|
7 |
</div>
|
8 |
|
9 |
<script type="text/javascript">
|
backend/modules/settings/templates/index.php
CHANGED
@@ -1,32 +1,70 @@
|
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
-
<div class="
|
3 |
-
<div
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
</div>
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
</div
|
1 |
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<div class="panel panel-default">
|
3 |
+
<div class="panel-heading">
|
4 |
+
<h3 class="panel-title"><?php _e( 'Settings', 'bookly' ) ?></h3>
|
5 |
+
</div>
|
6 |
+
<div class="panel-body">
|
7 |
+
<div class="row">
|
8 |
+
<div class="ab-settings ab-left-bar col-md-3 col-sm-3 col-xs-12 col-lg-3">
|
9 |
+
<?php $type = isset ( $_GET[ 'type' ] ) ? $_GET[ 'type' ] : '_general' ?>
|
10 |
+
<div id="ab_settings_general" class="ab-left-tab <?php echo $type == '_general' ? 'ab-active' : '' ?>"><?php _e( 'General', 'bookly' ) ?></div>
|
11 |
+
<div id="ab_settings_company" class="ab-left-tab <?php echo $type == '_company' ? 'ab-active' : '' ?>"><?php _e( 'Company', 'bookly' ) ?></div>
|
12 |
+
<div id="ab_settings_customers" class="ab-left-tab <?php echo $type == '_customers' ? 'ab-active' : '' ?>"><?php _e( 'Customers', 'bookly' ) ?></div>
|
13 |
+
<div id="ab_settings_google_calendar" class="ab-left-tab <?php echo $type == '_google_calendar' ? 'ab-active' : '' ?>"><?php _e( 'Google Calendar', 'bookly' ) ?></div>
|
14 |
+
<div id="ab_settings_woocommerce" class="ab-left-tab <?php echo $type == '_woocommerce' ? 'ab-active' : '' ?>">WooCommerce</div>
|
15 |
+
<div id="ab_settings_payments" class="ab-left-tab <?php echo $type == '_payments' ? 'ab-active' : '' ?>"><?php _e( 'Payments', 'bookly' ) ?></div>
|
16 |
+
<div id="ab_settings_hours" class="ab-left-tab <?php echo $type == '_hours' ? 'ab-active' : '' ?>"><?php _e( 'Business hours', 'bookly' ) ?></div>
|
17 |
+
<div id="ab_settings_holidays" class="ab-left-tab <?php echo $type == '_holidays' ? 'ab-active' : '' ?>"><?php _e( 'Holidays', 'bookly' ) ?></div>
|
18 |
+
</div>
|
19 |
+
<div class="ab-right-content col-md-9 col-sm-9 col-xs-12 col-lg-9" id="content_wrapper">
|
20 |
+
<div id="general-form" class="<?php echo ( $type == '_general' ) ? '' : 'hidden' ?>">
|
21 |
+
<?php ( $type == '_general' ) && AB_Utils::notice( $message ) ?>
|
22 |
+
<?php include '_generalForm.php' ?>
|
23 |
+
</div>
|
24 |
+
<div id="company-form" class="<?php echo ( $type == '_company' ) ? '' : 'hidden' ?>">
|
25 |
+
<?php ( $type == '_company' ) && AB_Utils::notice( $message ) ?>
|
26 |
+
<?php include '_companyForm.php' ?>
|
27 |
+
</div>
|
28 |
+
<div id="customers-form" class="<?php echo ( $type == '_customers' ) ? '' : 'hidden' ?>">
|
29 |
+
<?php ( $type == '_customers' ) && AB_Utils::notice( $message ) ?>
|
30 |
+
<?php include '_customers.php' ?>
|
31 |
+
</div>
|
32 |
+
<div id="google-calendar-form" class="<?php echo ( $type == '_google_calendar' ) ? '' : 'hidden' ?>">
|
33 |
+
<?php ( $type == '_google_calendar' ) && AB_Utils::notice( $message ) ?>
|
34 |
+
<?php include '_googleCalendarForm.php' ?>
|
35 |
+
</div>
|
36 |
+
<div id="payments-form" class="<?php echo ( $type == '_payments' ) ? '' : 'hidden' ?>">
|
37 |
+
<?php ( $type == '_payments' ) && AB_Utils::notice( $message ) ?>
|
38 |
+
<?php include '_paymentsForm.php' ?>
|
39 |
+
</div>
|
40 |
+
<div id="hours-form" class="<?php echo ( $type == '_hours' ) ? '' : 'hidden' ?>">
|
41 |
+
<?php ( $type == '_hours' ) && AB_Utils::notice( $message ) ?>
|
42 |
+
<?php include '_hoursForm.php' ?>
|
43 |
+
</div>
|
44 |
+
<div id="holidays-form" class="<?php echo ( $type == '_holidays' ) ? '' : 'hidden' ?>">
|
45 |
+
<?php ( $type == '_holidays' ) && AB_Utils::notice( $message ) ?>
|
46 |
+
<?php include '_holidaysForm.php' ?>
|
47 |
+
</div>
|
48 |
+
<div id="woocommerce-form" class="<?php echo ( $type == '_woocommerce' ) ? '' : 'hidden' ?>">
|
49 |
+
<?php ( $type == '_woocommerce' ) && AB_Utils::notice( $message ) ?>
|
50 |
+
<?php include '_woocommerce.php' ?>
|
51 |
+
</div>
|
52 |
+
</div>
|
53 |
</div>
|
54 |
+
</div>
|
55 |
+
</div>
|
56 |
+
<div class="modal fade" id="lite_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
57 |
+
<div class="modal-dialog">
|
58 |
+
<div class="modal-content">
|
59 |
+
<div class="modal-header">
|
60 |
+
<h4 class="modal-title"><?php _e('Notice', 'bookly') ?></h4>
|
61 |
+
</div>
|
62 |
+
<div class="modal-body">
|
63 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
64 |
+
</div>
|
65 |
+
<div class="modal-footer">
|
66 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php _e('Close', 'bookly') ?></button>
|
67 |
+
</div>
|
68 |
+
</div><!-- /.modal-content -->
|
69 |
+
</div><!-- /.modal-dialog -->
|
70 |
+
</div><!-- /.modal -->
|
backend/modules/sms/AB_SmsController.php
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Class AB_SmsController
|
5 |
+
*/
|
6 |
+
class AB_SmsController extends AB_Controller {
|
7 |
+
|
8 |
+
const page_slug = 'ab-sms';
|
9 |
+
|
10 |
+
public function index()
|
11 |
+
{
|
12 |
+
$this->enqueueStyles(
|
13 |
+
array(
|
14 |
+
'backend' => array(
|
15 |
+
'css/bookly.main-backend.css',
|
16 |
+
'bootstrap/css/bootstrap.min.css',
|
17 |
+
),
|
18 |
+
'module' => array(
|
19 |
+
'css/sms.css',
|
20 |
+
'css/flags.css',
|
21 |
+
)
|
22 |
+
)
|
23 |
+
);
|
24 |
+
|
25 |
+
$this->enqueueScripts(
|
26 |
+
array(
|
27 |
+
'backend' => array(
|
28 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
29 |
+
),
|
30 |
+
'module' => array(
|
31 |
+
'js/sms.js' => array( 'jquery' ),
|
32 |
+
),
|
33 |
+
)
|
34 |
+
);
|
35 |
+
|
36 |
+
$this->prices = array();
|
37 |
+
$this->sms = new AB_SMS();
|
38 |
+
|
39 |
+
if( $response = $this->sms->getPriceList() ){
|
40 |
+
$this->prices = $response->list;
|
41 |
+
}
|
42 |
+
|
43 |
+
$this->render( 'index' );
|
44 |
+
} // index
|
45 |
+
|
46 |
+
}
|
backend/modules/sms/resources/css/flags.css
ADDED
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.flag {
|
2 |
+
width: 32px;
|
3 |
+
height: 28px;
|
4 |
+
display: block;
|
5 |
+
background:url(flags.png) no-repeat;
|
6 |
+
margin-top: -8px;
|
7 |
+
}
|
8 |
+
|
9 |
+
.flag.flag-ad {background-position: -32px 0}
|
10 |
+
.flag.flag-ae {background-position: -64px 0}
|
11 |
+
.flag.flag-af {background-position: -96px 0}
|
12 |
+
.flag.flag-ag {background-position: -128px 0}
|
13 |
+
.flag.flag-ai {background-position: -160px 0}
|
14 |
+
.flag.flag-al {background-position: -192px 0}
|
15 |
+
.flag.flag-am {background-position: -224px 0}
|
16 |
+
.flag.flag-an {background-position: -256px 0}
|
17 |
+
.flag.flag-ao {background-position: -288px 0}
|
18 |
+
.flag.flag-ar {background-position: -320px 0}
|
19 |
+
.flag.flag-as {background-position: -352px 0}
|
20 |
+
.flag.flag-at {background-position: -384px 0}
|
21 |
+
.flag.flag-au {background-position: -416px 0}
|
22 |
+
.flag.flag-aw {background-position: -448px 0}
|
23 |
+
.flag.flag-az {background-position: 0 -32px}
|
24 |
+
.flag.flag-ba {background-position: -32px -32px}
|
25 |
+
.flag.flag-bb {background-position: -64px -32px}
|
26 |
+
.flag.flag-bd {background-position: -96px -32px}
|
27 |
+
.flag.flag-be {background-position: -128px -32px}
|
28 |
+
.flag.flag-bf {background-position: -160px -32px}
|
29 |
+
.flag.flag-bg {background-position: -192px -32px}
|
30 |
+
.flag.flag-bh {background-position: -224px -32px}
|
31 |
+
.flag.flag-bi {background-position: -256px -32px}
|
32 |
+
.flag.flag-bj {background-position: -288px -32px}
|
33 |
+
.flag.flag-bm {background-position: -320px -32px}
|
34 |
+
.flag.flag-bn {background-position: -352px -32px}
|
35 |
+
.flag.flag-bo {background-position: -384px -32px}
|
36 |
+
.flag.flag-br {background-position: -416px -32px}
|
37 |
+
.flag.flag-bs {background-position: -448px -32px}
|
38 |
+
.flag.flag-bt {background-position: 0 -64px}
|
39 |
+
.flag.flag-bw {background-position: -32px -64px}
|
40 |
+
.flag.flag-by {background-position: -64px -64px}
|
41 |
+
.flag.flag-bz {background-position: -96px -64px}
|
42 |
+
.flag.flag-ca {background-position: -128px -64px}
|
43 |
+
.flag.flag-cd {background-position: -160px -64px}
|
44 |
+
.flag.flag-cf {background-position: -192px -64px}
|
45 |
+
.flag.flag-cg {background-position: -224px -64px}
|
46 |
+
.flag.flag-ch {background-position: -256px -64px}
|
47 |
+
.flag.flag-ci {background-position: -288px -64px}
|
48 |
+
.flag.flag-ck {background-position: -320px -64px}
|
49 |
+
.flag.flag-cl {background-position: -352px -64px}
|
50 |
+
.flag.flag-cm {background-position: -384px -64px}
|
51 |
+
.flag.flag-cn {background-position: -416px -64px}
|
52 |
+
.flag.flag-co {background-position: -448px -64px}
|
53 |
+
.flag.flag-cr {background-position: 0 -96px}
|
54 |
+
.flag.flag-cu {background-position: -32px -96px}
|
55 |
+
.flag.flag-cv {background-position: -64px -96px}
|
56 |
+
.flag.flag-cy {background-position: -96px -96px}
|
57 |
+
.flag.flag-cz {background-position: -128px -96px}
|
58 |
+
.flag.flag-de {background-position: -160px -96px}
|
59 |
+
.flag.flag-dj {background-position: -192px -96px}
|
60 |
+
.flag.flag-dk {background-position: -224px -96px}
|
61 |
+
.flag.flag-dm {background-position: -256px -96px}
|
62 |
+
.flag.flag-do {background-position: -288px -96px}
|
63 |
+
.flag.flag-dz {background-position: -320px -96px}
|
64 |
+
.flag.flag-ec {background-position: -352px -96px}
|
65 |
+
.flag.flag-ee {background-position: -384px -96px}
|
66 |
+
.flag.flag-eg {background-position: -416px -96px}
|
67 |
+
.flag.flag-eh {background-position: -448px -96px}
|
68 |
+
.flag.flag-er {background-position: 0 -128px}
|
69 |
+
.flag.flag-es {background-position: -32px -128px}
|
70 |
+
.flag.flag-et {background-position: -64px -128px}
|
71 |
+
.flag.flag-fi {background-position: -96px -128px}
|
72 |
+
.flag.flag-fj {background-position: -128px -128px}
|
73 |
+
.flag.flag-fm {background-position: -160px -128px}
|
74 |
+
.flag.flag-fo {background-position: -192px -128px}
|
75 |
+
.flag.flag-fr {background-position: -224px -128px}
|
76 |
+
.flag.flag-ga {background-position: -256px -128px}
|
77 |
+
.flag.flag-gb {background-position: -288px -128px}
|
78 |
+
.flag.flag-gd {background-position: -320px -128px}
|
79 |
+
.flag.flag-ge {background-position: -352px -128px}
|
80 |
+
.flag.flag-gg {background-position: -384px -128px}
|
81 |
+
.flag.flag-gh {background-position: -416px -128px}
|
82 |
+
.flag.flag-gi {background-position: -448px -128px}
|
83 |
+
.flag.flag-gl {background-position: 0 -160px}
|
84 |
+
.flag.flag-gm {background-position: -32px -160px}
|
85 |
+
.flag.flag-gn {background-position: -64px -160px}
|
86 |
+
.flag.flag-gp {background-position: -96px -160px}
|
87 |
+
.flag.flag-gq {background-position: -128px -160px}
|
88 |
+
.flag.flag-gr {background-position: -160px -160px}
|
89 |
+
.flag.flag-gt {background-position: -192px -160px}
|
90 |
+
.flag.flag-gu {background-position: -224px -160px}
|
91 |
+
.flag.flag-gw {background-position: -256px -160px}
|
92 |
+
.flag.flag-gy {background-position: -288px -160px}
|
93 |
+
.flag.flag-hk {background-position: -320px -160px}
|
94 |
+
.flag.flag-hn {background-position: -352px -160px}
|
95 |
+
.flag.flag-hr {background-position: -384px -160px}
|
96 |
+
.flag.flag-ht {background-position: -416px -160px}
|
97 |
+
.flag.flag-hu {background-position: -448px -160px}
|
98 |
+
.flag.flag-id {background-position: 0 -192px}
|
99 |
+
.flag.flag-ie {background-position: -32px -192px}
|
100 |
+
.flag.flag-il {background-position: -64px -192px}
|
101 |
+
.flag.flag-im {background-position: -96px -192px}
|
102 |
+
.flag.flag-in {background-position: -128px -192px}
|
103 |
+
.flag.flag-iq {background-position: -160px -192px}
|
104 |
+
.flag.flag-ir {background-position: -192px -192px}
|
105 |
+
.flag.flag-is {background-position: -224px -192px}
|
106 |
+
.flag.flag-it {background-position: -256px -192px}
|
107 |
+
.flag.flag-je {background-position: -288px -192px}
|
108 |
+
.flag.flag-jm {background-position: -320px -192px}
|
109 |
+
.flag.flag-jo {background-position: -352px -192px}
|
110 |
+
.flag.flag-jp {background-position: -384px -192px}
|
111 |
+
.flag.flag-ke {background-position: -416px -192px}
|
112 |
+
.flag.flag-kg {background-position: -448px -192px}
|
113 |
+
.flag.flag-kh {background-position: 0 -224px}
|
114 |
+
.flag.flag-ki {background-position: -32px -224px}
|
115 |
+
.flag.flag-km {background-position: -64px -224px}
|
116 |
+
.flag.flag-kn {background-position: -96px -224px}
|
117 |
+
.flag.flag-kp {background-position: -128px -224px}
|
118 |
+
.flag.flag-kr {background-position: -160px -224px}
|
119 |
+
.flag.flag-kw {background-position: -192px -224px}
|
120 |
+
.flag.flag-ky {background-position: -224px -224px}
|
121 |
+
.flag.flag-kz {background-position: -256px -224px}
|
122 |
+
.flag.flag-la {background-position: -288px -224px}
|
123 |
+
.flag.flag-lb {background-position: -320px -224px}
|
124 |
+
.flag.flag-lc {background-position: -352px -224px}
|
125 |
+
.flag.flag-li {background-position: -384px -224px}
|
126 |
+
.flag.flag-lk {background-position: -416px -224px}
|
127 |
+
.flag.flag-lr {background-position: -448px -224px}
|
128 |
+
.flag.flag-ls {background-position: 0 -256px}
|
129 |
+
.flag.flag-lt {background-position: -32px -256px}
|
130 |
+
.flag.flag-lu {background-position: -64px -256px}
|
131 |
+
.flag.flag-lv {background-position: -96px -256px}
|
132 |
+
.flag.flag-ly {background-position: -128px -256px}
|
133 |
+
.flag.flag-ma {background-position: -160px -256px}
|
134 |
+
.flag.flag-mc {background-position: -192px -256px}
|
135 |
+
.flag.flag-md {background-position: -224px -256px}
|
136 |
+
.flag.flag-me {background-position: -256px -256px}
|
137 |
+
.flag.flag-mg {background-position: -288px -256px}
|
138 |
+
.flag.flag-mh {background-position: -320px -256px}
|
139 |
+
.flag.flag-mk {background-position: -352px -256px}
|
140 |
+
.flag.flag-ml {background-position: -384px -256px}
|
141 |
+
.flag.flag-mm {background-position: -416px -256px}
|
142 |
+
.flag.flag-mn {background-position: -448px -256px}
|
143 |
+
.flag.flag-mo {background-position: 0 -288px}
|
144 |
+
.flag.flag-mq {background-position: -32px -288px}
|
145 |
+
.flag.flag-mr {background-position: -64px -288px}
|
146 |
+
.flag.flag-ms {background-position: -96px -288px}
|
147 |
+
.flag.flag-mt {background-position: -128px -288px}
|
148 |
+
.flag.flag-mu {background-position: -160px -288px}
|
149 |
+
.flag.flag-mv {background-position: -192px -288px}
|
150 |
+
.flag.flag-mw {background-position: -224px -288px}
|
151 |
+
.flag.flag-mx {background-position: -256px -288px}
|
152 |
+
.flag.flag-my {background-position: -288px -288px}
|
153 |
+
.flag.flag-mz {background-position: -320px -288px}
|
154 |
+
.flag.flag-na {background-position: -352px -288px}
|
155 |
+
.flag.flag-nc {background-position: -384px -288px}
|
156 |
+
.flag.flag-ne {background-position: -416px -288px}
|
157 |
+
.flag.flag-ng {background-position: -448px -288px}
|
158 |
+
.flag.flag-ni {background-position: 0 -320px}
|
159 |
+
.flag.flag-nl {background-position: -32px -320px}
|
160 |
+
.flag.flag-no {background-position: -64px -320px}
|
161 |
+
.flag.flag-np {background-position: -96px -320px}
|
162 |
+
.flag.flag-nr {background-position: -128px -320px}
|
163 |
+
.flag.flag-nz {background-position: -160px -320px}
|
164 |
+
.flag.flag-om {background-position: -192px -320px}
|
165 |
+
.flag.flag-pa {background-position: -224px -320px}
|
166 |
+
.flag.flag-pe {background-position: -256px -320px}
|
167 |
+
.flag.flag-pf {background-position: -288px -320px}
|
168 |
+
.flag.flag-pg {background-position: -320px -320px}
|
169 |
+
.flag.flag-ph {background-position: -352px -320px}
|
170 |
+
.flag.flag-pk {background-position: -384px -320px}
|
171 |
+
.flag.flag-pl {background-position: -416px -320px}
|
172 |
+
.flag.flag-pr {background-position: -448px -320px}
|
173 |
+
.flag.flag-ps {background-position: 0 -352px}
|
174 |
+
.flag.flag-pt {background-position: -32px -352px}
|
175 |
+
.flag.flag-pw {background-position: -64px -352px}
|
176 |
+
.flag.flag-py {background-position: -96px -352px}
|
177 |
+
.flag.flag-qa {background-position: -128px -352px}
|
178 |
+
.flag.flag-re {background-position: -160px -352px}
|
179 |
+
.flag.flag-ro {background-position: -192px -352px}
|
180 |
+
.flag.flag-rs {background-position: -224px -352px}
|
181 |
+
.flag.flag-ru {background-position: -256px -352px}
|
182 |
+
.flag.flag-rw {background-position: -288px -352px}
|
183 |
+
.flag.flag-sa {background-position: -320px -352px}
|
184 |
+
.flag.flag-sb {background-position: -352px -352px}
|
185 |
+
.flag.flag-sc {background-position: -384px -352px}
|
186 |
+
.flag.flag-sd {background-position: -416px -352px}
|
187 |
+
.flag.flag-se {background-position: -448px -352px}
|
188 |
+
.flag.flag-sg {background-position: 0 -384px}
|
189 |
+
.flag.flag-si {background-position: -32px -384px}
|
190 |
+
.flag.flag-sk {background-position: -64px -384px}
|
191 |
+
.flag.flag-sl {background-position: -96px -384px}
|
192 |
+
.flag.flag-sm {background-position: -128px -384px}
|
193 |
+
.flag.flag-sn {background-position: -160px -384px}
|
194 |
+
.flag.flag-so {background-position: -192px -384px}
|
195 |
+
.flag.flag-sr {background-position: -224px -384px}
|
196 |
+
.flag.flag-st {background-position: -256px -384px}
|
197 |
+
.flag.flag-sv {background-position: -288px -384px}
|
198 |
+
.flag.flag-sy {background-position: -320px -384px}
|
199 |
+
.flag.flag-sz {background-position: -352px -384px}
|
200 |
+
.flag.flag-tc {background-position: -384px -384px}
|
201 |
+
.flag.flag-td {background-position: -416px -384px}
|
202 |
+
.flag.flag-tg {background-position: -448px -384px}
|
203 |
+
.flag.flag-th {background-position: 0 -416px}
|
204 |
+
.flag.flag-tj {background-position: -32px -416px}
|
205 |
+
.flag.flag-tl {background-position: -64px -416px}
|
206 |
+
.flag.flag-tm {background-position: -96px -416px}
|
207 |
+
.flag.flag-tn {background-position: -128px -416px}
|
208 |
+
.flag.flag-to {background-position: -160px -416px}
|
209 |
+
.flag.flag-tr {background-position: -192px -416px}
|
210 |
+
.flag.flag-tt {background-position: -224px -416px}
|
211 |
+
.flag.flag-tv {background-position: -256px -416px}
|
212 |
+
.flag.flag-tw {background-position: -288px -416px}
|
213 |
+
.flag.flag-tz {background-position: -320px -416px}
|
214 |
+
.flag.flag-ua {background-position: -352px -416px}
|
215 |
+
.flag.flag-ug {background-position: -384px -416px}
|
216 |
+
.flag.flag-us {background-position: -416px -416px}
|
217 |
+
.flag.flag-uy {background-position: -448px -416px}
|
218 |
+
.flag.flag-uz {background-position: 0 -448px}
|
219 |
+
.flag.flag-va {background-position: -32px -448px}
|
220 |
+
.flag.flag-vc {background-position: -64px -448px}
|
221 |
+
.flag.flag-ve {background-position: -96px -448px}
|
222 |
+
.flag.flag-vg {background-position: -128px -448px}
|
223 |
+
.flag.flag-vi {background-position: -160px -448px}
|
224 |
+
.flag.flag-vn {background-position: -192px -448px}
|
225 |
+
.flag.flag-vu {background-position: -224px -448px}
|
226 |
+
.flag.flag-ws {background-position: -256px -448px}
|
227 |
+
.flag.flag-ye {background-position: -288px -448px}
|
228 |
+
.flag.flag-za {background-position: -320px -448px}
|
229 |
+
.flag.flag-zm {background-position: -352px -448px}
|
230 |
+
.flag.flag-zw {background-position: -384px -448px}
|
backend/modules/sms/resources/css/flags.png
ADDED
Binary file
|
backend/modules/sms/resources/css/sms.css
ADDED
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/* notifications */
|
2 |
+
.ab-notifications table td { padding-left: 20px; padding-top: 10px; }
|
3 |
+
.ab-notifications .ab-form-field { padding-top: 10px; }
|
4 |
+
.ab-notifications .ab-toggle-arrow { position: absolute; right: 0; top: 9px; width: 24px; height: 24px; cursor: pointer; }
|
5 |
+
.ab-notifications .ab-form-label { display: block; float: left; margin-top: 3px; min-width: 80px; }
|
6 |
+
.ab-notifications .ab-form-row { padding: 3px 0; overflow: hidden; }
|
7 |
+
.ab-notifications .ab-form-row input[type="text"] { width: 700px!important; position: relative; z-index: 9; }
|
8 |
+
.ab-notifications #message_editor { margin-top: -20px; }
|
9 |
+
.ab-notifications #message_editor .wp-editor-wrap { margin-left: 81px; }
|
10 |
+
.ab-notifications legend { margin: 0; border: 0; line-height: normal; }
|
11 |
+
.ab-notifications legend input { margin: 0!important; }
|
12 |
+
.ab-notifications legend label { display: inline; font-size: 17px; }
|
13 |
+
.ab-notifications .ab-codes table tr td { padding: 0 20px 0 0; font-size: 12px;}
|
14 |
+
.ab-notifications .ab-codes table tr td input { cursor: pointer; border: none; width: 250px; }
|
15 |
+
.ab-notifications .ab-codes .ab-codes-inner {
|
16 |
+
max-width: 320px;
|
17 |
+
display: inline-block;
|
18 |
+
vertical-align: top;
|
19 |
+
border: 1px solid silver;
|
20 |
+
box-sizing: border-box;
|
21 |
+
padding: 10px;
|
22 |
+
margin-right: 15px;
|
23 |
+
margin-bottom: 20px;
|
24 |
+
}
|
25 |
+
.ab-notifications .ab-codes .ab-codes-inner input { cursor: pointer; border: none; width: 250px; }
|
26 |
+
.ab-notifications .ab-codes .ab-codes-inner legend {
|
27 |
+
display: inline-block;
|
28 |
+
width: auto;
|
29 |
+
padding: 0 10px 0px 10px;
|
30 |
+
font-size: 17px;
|
31 |
+
font-weight: bold;
|
32 |
+
}
|
33 |
+
.ab-notifications .panel-title > input { margin: 0 5px 0 0; }
|
34 |
+
.ab-notifications a[data-toggle="collapse"] {
|
35 |
+
outline: none;
|
36 |
+
box-shadow: none;
|
37 |
+
padding-right: 25px;
|
38 |
+
background: url("../../../../resources/images/notifications-arrow-up.png") 100% 50% no-repeat;
|
39 |
+
background-size: 17px 17px;
|
40 |
+
}
|
41 |
+
.ab-notifications a[data-toggle="collapse"].collapsed {
|
42 |
+
background: url("../../../../resources/images/notifications-arrow-down.png") 100% 50% no-repeat;
|
43 |
+
background-size: 17px 17px;
|
44 |
+
}
|
45 |
+
.ab-sms-holder > textarea { width: 370px; }
|
46 |
+
.ab-logout {
|
47 |
+
border: 0;
|
48 |
+
background: none;
|
49 |
+
width: 100%;
|
50 |
+
padding: 0;
|
51 |
+
text-align: left;
|
52 |
+
}
|
53 |
+
#sms_tabs { margin: 15px 0; }
|
backend/modules/sms/resources/js/sms.js
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(function($) {
|
2 |
+
$('.panel a, .panel input, .panel button').on('click', function(e){
|
3 |
+
e.preventDefault();
|
4 |
+
$('#lite_notice').modal('show');
|
5 |
+
});
|
6 |
+
});
|
backend/modules/sms/templates/_price.php
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly ?>
|
2 |
+
<table class="table table-striped">
|
3 |
+
<thead>
|
4 |
+
<tr>
|
5 |
+
<th></th>
|
6 |
+
<th><?php _e( 'Country', 'bookly' ) ?></th>
|
7 |
+
<th class="text-right"><?php _e( 'Code', 'bookly' ) ?></th>
|
8 |
+
<th class="text-right"><?php _e( 'Price', 'bookly' ) ?></th>
|
9 |
+
</tr>
|
10 |
+
</thead>
|
11 |
+
<tbody id="pricelist">
|
12 |
+
<?php if ( $prices ) : ?>
|
13 |
+
<?php foreach ( $prices as $price ) : ?>
|
14 |
+
<tr><td><i class="flag flag-<?php echo esc_attr( $price->country_iso_code ) ?>"></i></td><td><?php echo $price->country_name ?></td><td class="text-right"><?php echo $price->phone_code ?></td><td class="text-right">$<?php echo rtrim( $price->price, '0' ) ?></td></tr>
|
15 |
+
<?php endforeach ?>
|
16 |
+
<?php else : ?>
|
17 |
+
<tr><td colspan="4"><span class="ab-loader"></span></td></tr>
|
18 |
+
<?php endif ?>
|
19 |
+
</tbody>
|
20 |
+
</table>
|
21 |
+
<p><?php _e( 'If you do not see your country in the list please contact us at <a href="mailto:support@ladela.com">support@ladela.com</a>.', 'bookly' ) ?></p>
|
backend/modules/sms/templates/index.php
ADDED
@@ -0,0 +1,110 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
/** @var AB_SMS $sms */
|
3 |
+
?>
|
4 |
+
<div class="panel panel-default">
|
5 |
+
<div class="panel-heading">
|
6 |
+
<h3 class="panel-title"><?php _e( 'SMS Notifications', 'bookly' ) ?></h3>
|
7 |
+
</div>
|
8 |
+
<div class="panel-body">
|
9 |
+
<div class="ab-wrapper-container">
|
10 |
+
<div class="row">
|
11 |
+
<div class="col-xs-12">
|
12 |
+
<div
|
13 |
+
class="alert alert-info"><?php _e( 'SMS Notifications (or "Bookly SMS") is a service for notifying your customers via text messages which are sent to mobile phones.<br/>It is necessary to register in order to start using this service.<br/>After registration you will need to configure notification messages and top up your balance in order to start sending SMS.', 'bookly' ) ?></div>
|
14 |
+
</div>
|
15 |
+
</div>
|
16 |
+
<div class="row">
|
17 |
+
<div class="col-xs-3">
|
18 |
+
<form method="post" class="ab-login-form well">
|
19 |
+
|
20 |
+
<fieldset>
|
21 |
+
<legend><?php _e( 'Login', 'bookly' ) ?></legend>
|
22 |
+
<div class="form-group">
|
23 |
+
<label for="ab_username"><?php _e( 'Email', 'bookly' ) ?></label>
|
24 |
+
<input id="ab_username" class="form-control" type="text" required="required" value="" name="username"/>
|
25 |
+
</div>
|
26 |
+
<div class="form-group">
|
27 |
+
<label for="ab_password"><?php _e( 'Password', 'bookly' ) ?></label>
|
28 |
+
<input id="ab_password" class="form-control" type="password" required="required" name="password"/>
|
29 |
+
</div>
|
30 |
+
<div class="form-group">
|
31 |
+
<button type="submit" name="form-login" class="btn btn-info"><?php _e( 'Log In', 'bookly' ) ?></button>
|
32 |
+
<a href="#" class="show-register-form"><?php _e( 'Registration', 'bookly' ) ?></a>
|
33 |
+
<a href="#" class="show-forgot-form"><?php _e( 'Forgot password', 'bookly' ) ?></a>
|
34 |
+
</div>
|
35 |
+
</fieldset>
|
36 |
+
|
37 |
+
</form>
|
38 |
+
|
39 |
+
<form method="post" class="ab-register-form well" style="display: none;">
|
40 |
+
<fieldset>
|
41 |
+
<legend><?php _e( 'Registration', 'bookly' ) ?></legend>
|
42 |
+
<div class="form-group">
|
43 |
+
<label for="ab_r_username"><?php _e( 'Email', 'bookly' ) ?></label>
|
44 |
+
<input id="ab_r_username" name="username" class="form-control" required="required" value="" type="text"/>
|
45 |
+
</div>
|
46 |
+
<div class="form-group">
|
47 |
+
<label for="ab_r_password"><?php _e( 'Password', 'bookly' ) ?></label>
|
48 |
+
<input id="ab_r_password" name="password" class="form-control" required="required" value="" type="password"/>
|
49 |
+
</div>
|
50 |
+
<div class="form-group">
|
51 |
+
<label for="ab_r_repeat_password"><?php _e( 'Repeat password', 'bookly' ) ?></label>
|
52 |
+
<input id="ab_r_repeat_password" name="password_repeat" class="form-control" required="required" value="" type="password"/>
|
53 |
+
</div>
|
54 |
+
<div class="form-group">
|
55 |
+
<label for="ab_r_tos"><?php _e( 'Accept <a href="javascript:void(0)" data-toggle="modal" data-target="#ab-tos">Terms & Conditions</a>', 'bookly' ) ?></label>
|
56 |
+
<input id="ab_r_tos" name="accept_tos" class="form-control" required="required" value="1" type="checkbox" style="margin:0"/>
|
57 |
+
</div>
|
58 |
+
|
59 |
+
<div class="form-group">
|
60 |
+
<button type="submit" name="form-registration" class="btn btn-info"><?php _e( 'Register', 'bookly' ) ?></button>
|
61 |
+
<a href="#" class="show-login-form"><?php _e( 'Log In', 'bookly' ) ?></a>
|
62 |
+
</div>
|
63 |
+
</fieldset>
|
64 |
+
</form>
|
65 |
+
|
66 |
+
<form method="post" class="ab-forgot-form well" style="display: none;">
|
67 |
+
<fieldset>
|
68 |
+
<legend><?php _e( 'Forgot password', 'bookly' ) ?></legend>
|
69 |
+
<div class="form-group">
|
70 |
+
<input name="username" class="form-control" value="" type="text" placeholder="<?php echo esc_attr( __( 'Email', 'bookly' ) ) ?>"/>
|
71 |
+
</div>
|
72 |
+
<div class="form-group hidden">
|
73 |
+
<input name="code" class="form-control" value="" type="text" placeholder="<?php echo esc_attr( __( 'Enter code from email', 'bookly' ) ) ?>"/>
|
74 |
+
</div>
|
75 |
+
<div class="form-group hidden">
|
76 |
+
<input name="password" class="form-control" value="" type="password" placeholder="<?php echo esc_attr( __( 'New password', 'bookly' ) ) ?>"/>
|
77 |
+
</div>
|
78 |
+
<div class="form-group hidden">
|
79 |
+
<input name="password_repeat" class="form-control" value="" type="password" placeholder="<?php echo esc_attr( __( 'Repeat new password', 'bookly' ) ) ?>"/>
|
80 |
+
</div>
|
81 |
+
<div class="form-group">
|
82 |
+
<button class="btn btn-info form-forgot-next" data-step="0"><?php _e( 'Next', 'bookly' ) ?></button>
|
83 |
+
<a href="#" class="show-login-form"><?php _e( 'Log In', 'bookly' ) ?></a>
|
84 |
+
</div>
|
85 |
+
</fieldset>
|
86 |
+
</form>
|
87 |
+
</div>
|
88 |
+
<div class="col-xs-9">
|
89 |
+
<?php include "_price.php" ?>
|
90 |
+
</div>
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
</div>
|
94 |
+
</div>
|
95 |
+
<div class="modal fade" id="lite_notice" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
96 |
+
<div class="modal-dialog">
|
97 |
+
<div class="modal-content">
|
98 |
+
<div class="modal-header">
|
99 |
+
<h4 class="modal-title"><?php _e('Notice', 'bookly') ?></h4>
|
100 |
+
</div>
|
101 |
+
<div class="modal-body">
|
102 |
+
<?php _e('This function is disabled in the lite version of Bookly. If you find the plugin useful for your business please consider buying a licence for the full version. It costs just $46 and for this money you will get many useful functions, lifetime free update and excellent support! More information can be found here', 'bookly'); ?>: <a href="http://booking-wp-plugin.com" target="_blank">http://booking-wp-plugin.com</a>
|
103 |
+
</div>
|
104 |
+
<div class="modal-footer">
|
105 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php _e('Close', 'bookly') ?></button>
|
106 |
+
</div>
|
107 |
+
</div><!-- /.modal-content -->
|
108 |
+
</div><!-- /.modal-dialog -->
|
109 |
+
</div><!-- /.modal -->
|
110 |
+
|
backend/modules/staff/AB_StaffController.php
CHANGED
@@ -1,13 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include 'forms/AB_StaffMemberNewForm.php';
|
6 |
-
include 'forms/AB_StaffMemberEditForm.php';
|
7 |
-
include 'forms/AB_StaffServicesForm.php';
|
8 |
-
include 'forms/AB_StaffScheduleForm.php';
|
9 |
-
include 'forms/AB_StaffScheduleItemBreakForm.php';
|
10 |
-
include 'forms/widget/AB_TimeChoiceWidget.php';
|
11 |
|
12 |
/**
|
13 |
* Class AB_StaffController
|
@@ -20,114 +11,190 @@ include 'forms/widget/AB_TimeChoiceWidget.php';
|
|
20 |
*/
|
21 |
class AB_StaffController extends AB_Controller {
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
'
|
37 |
-
'
|
38 |
-
'
|
39 |
-
|
40 |
-
|
41 |
-
'
|
42 |
-
'
|
43 |
-
'
|
44 |
-
|
45 |
-
|
46 |
-
'
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
),
|
50 |
-
'
|
51 |
-
'
|
52 |
-
|
53 |
-
|
54 |
-
'
|
55 |
-
'
|
56 |
-
'
|
57 |
-
'Sun' => __( 'Sun', 'ab' )
|
58 |
)
|
59 |
) );
|
60 |
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
$this->form = new AB_StaffMemberNewForm();
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
|
70 |
$this->render( 'list' );
|
71 |
}
|
72 |
|
73 |
-
public function
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
$this->form = new AB_StaffServicesForm();
|
75 |
-
$this->form->load(
|
76 |
-
$this->staff_id =
|
77 |
$this->render( 'services' );
|
78 |
exit;
|
79 |
}
|
80 |
|
81 |
-
public function executeStaffSchedule()
|
|
|
82 |
$staff = new AB_Staff();
|
83 |
-
$staff->load(
|
84 |
-
$this->
|
|
|
85 |
$this->render( 'schedule' );
|
86 |
exit;
|
87 |
}
|
88 |
|
89 |
-
public function executeStaffScheduleUpdate()
|
|
|
90 |
$this->form = new AB_StaffScheduleForm();
|
91 |
-
$this->form->bind($this->
|
92 |
$this->form->save();
|
93 |
-
|
|
|
94 |
}
|
95 |
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
-
|
100 |
-
|
101 |
-
$
|
102 |
-
$
|
|
|
|
|
103 |
|
104 |
-
if (
|
105 |
-
|
106 |
'success' => false,
|
107 |
-
'error_msg' => __( 'The start time must be less than the end one', '
|
108 |
) );
|
109 |
-
exit;
|
110 |
}
|
111 |
|
112 |
$staffScheduleItem = new AB_StaffScheduleItem();
|
113 |
-
$staffScheduleItem->load( $
|
114 |
|
115 |
-
$
|
|
|
116 |
|
117 |
$in_working_time = $working_start <= $start_time && $start_time <= $working_end
|
118 |
&& $working_start <= $end_time && $end_time <= $working_end;
|
119 |
if ( !$in_working_time || ! $staffScheduleItem->isBreakIntervalAvailable( $start_time, $end_time, $break_id ) ) {
|
120 |
-
|
121 |
'success' => false,
|
122 |
-
'error_msg' => __( 'The requested interval is not available', '
|
123 |
) );
|
124 |
-
exit;
|
125 |
}
|
126 |
|
127 |
-
$
|
128 |
-
$
|
129 |
-
$
|
130 |
-
$formatted_interval = $formatted_interval_start . ' - ' . $formatted_interval_end;
|
131 |
|
132 |
if ( $break_id ) {
|
133 |
$break = new AB_ScheduleItemBreak();
|
@@ -136,183 +203,272 @@ class AB_StaffController extends AB_Controller {
|
|
136 |
$break->set( 'end_time', $end_time );
|
137 |
$break->save();
|
138 |
|
139 |
-
|
140 |
'success' => true,
|
141 |
'new_interval' => $formatted_interval,
|
142 |
) );
|
143 |
} else {
|
144 |
$this->form = new AB_StaffScheduleItemBreakForm();
|
145 |
-
$this->form->bind( $this->
|
146 |
|
147 |
$staffScheduleItemBreak = $this->form->save();
|
148 |
if ( $staffScheduleItemBreak ) {
|
149 |
-
$breakStart = new AB_TimeChoiceWidget( array( 'use_empty' => false ) );
|
150 |
$break_start_choices = $breakStart->render(
|
151 |
'',
|
152 |
$start_time,
|
153 |
-
array(
|
154 |
-
|
155 |
-
'data-default_value' => AB_StaffScheduleItem::WORKING_START_TIME
|
156 |
)
|
157 |
);
|
158 |
-
$breakEnd = new AB_TimeChoiceWidget( array( 'use_empty' => false ) );
|
159 |
$break_end_choices = $breakEnd->render(
|
160 |
'',
|
161 |
$end_time,
|
162 |
-
array(
|
163 |
-
|
164 |
-
'data-default_value' => date( 'H:i:s', strtotime( AB_StaffScheduleItem::WORKING_START_TIME . ' + 1 hour' ) )
|
165 |
)
|
166 |
);
|
167 |
-
|
168 |
'success' => true,
|
169 |
-
'item_content' =>
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
<div class="ab-content">
|
176 |
-
<table cellspacing="0" cellpadding="0">
|
177 |
-
<tr>
|
178 |
-
<td>' . $break_start_choices . ' <span class="hide-on-non-working-day">' . __( 'to', 'ab') . '</span> ' . $break_end_choices . '</td>
|
179 |
-
</tr>
|
180 |
-
<tr>
|
181 |
-
<td>
|
182 |
-
<a class="btn btn-info ab-popup-save ab-save-break">' . __('Save break','ab') . '</a>
|
183 |
-
<a class="ab-popup-close" href="#">' . __('Cancel', 'ab') . '</a>
|
184 |
-
</td>
|
185 |
-
</tr>
|
186 |
-
</table>
|
187 |
-
<a class="ab-popup-close ab-popup-close-icon" href="javascript:void(0)"></a>
|
188 |
-
</div>
|
189 |
-
</div>
|
190 |
-
</div>
|
191 |
-
<img class="delete-break" src="' . plugins_url( 'resources/images/delete_cross.png', dirname(__FILE__).'/../../AB_Backend.php' ) . '" />
|
192 |
-
</div>'
|
193 |
) );
|
194 |
} else {
|
195 |
-
|
196 |
'success' => false,
|
197 |
-
'error_msg' => __( 'Error adding the break interval', '
|
198 |
) );
|
199 |
}
|
200 |
}
|
201 |
-
|
202 |
-
exit;
|
203 |
}
|
204 |
|
205 |
-
public function executeDeleteStaffScheduleBreak()
|
|
|
206 |
$break = new AB_ScheduleItemBreak();
|
207 |
-
$break->load(
|
208 |
$break->delete();
|
209 |
-
|
|
|
210 |
}
|
211 |
|
212 |
-
public function executeStaffServicesUpdate()
|
|
|
213 |
$this->form = new AB_StaffServicesForm();
|
214 |
-
$this->form->bind($this->
|
215 |
$this->form->save();
|
216 |
-
|
|
|
217 |
}
|
218 |
|
219 |
-
public function executeEditStaff()
|
|
|
220 |
$this->form = new AB_StaffMemberEditForm();
|
221 |
$this->staff = new AB_Staff();
|
222 |
-
$this->staff->load(
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
exit;
|
231 |
}
|
232 |
|
233 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
234 |
$form = new AB_StaffMemberEditForm();
|
235 |
-
$form->bind($this->
|
236 |
-
$form->save();
|
|
|
237 |
// Set staff id to load the form for.
|
238 |
-
$this->active_staff_id =
|
239 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
}
|
241 |
|
242 |
-
public function
|
|
|
243 |
$staff = new AB_Staff();
|
244 |
-
$staff->load( $this->
|
245 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 |
$staff->set( 'avatar_url', '' );
|
247 |
$staff->set( 'avatar_path', '' );
|
248 |
$staff->save();
|
249 |
-
|
250 |
}
|
251 |
|
252 |
-
public function executeStaffHolidays()
|
253 |
-
|
|
|
254 |
$this->holidays = $this->getHolidays( $this->id );
|
255 |
-
$this->render('holidays');
|
256 |
exit;
|
257 |
}
|
258 |
|
259 |
-
public function executeStaffHolidaysUpdate()
|
260 |
-
|
261 |
-
$id =
|
262 |
-
$holiday = $this->getParameter('holiday') == 'true';
|
263 |
-
$repeat = $this->getParameter('repeat') == 'true';
|
264 |
-
$day = $this->getParameter('day', false);
|
265 |
-
$staff_id = $this->getParameter('staff_id');
|
266 |
|
267 |
if ( $staff_id ) {
|
268 |
-
//
|
269 |
if ( $id ) {
|
270 |
if ( $holiday ) {
|
271 |
-
$this->getWpdb()->update(
|
272 |
} else {
|
273 |
-
|
274 |
}
|
275 |
-
//
|
276 |
-
}
|
277 |
-
$day
|
278 |
-
$this->getWpdb()->insert( 'ab_holiday', array( 'holiday' => date( 'Y-m-d H:i:s', $day->format( 'U' ) ), 'repeat_event' => intval( $repeat ), 'staff_id' => $staff_id ), array( '%s', '%d', '%d' ) );
|
279 |
}
|
280 |
|
281 |
-
//
|
282 |
-
echo $this->getHolidays($staff_id);
|
283 |
}
|
284 |
exit;
|
285 |
}
|
286 |
|
287 |
-
|
288 |
-
|
289 |
// Protected methods.
|
290 |
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
*/
|
295 |
-
protected function registerWpActions( $prefix = '' ) {
|
296 |
-
parent::registerWpActions( 'wp_ajax_ab_' );
|
297 |
-
}
|
298 |
-
|
299 |
-
protected function getHolidays($id) {
|
300 |
-
$collection = $this->getWpdb()->get_results( $this->getWpdb()->prepare( "SELECT * FROM ab_holiday WHERE staff_id = %d", $id ) );
|
301 |
$holidays = array();
|
302 |
if ( count( $collection ) ) {
|
303 |
foreach ( $collection as $holiday ) {
|
304 |
-
$holidays[$holiday
|
305 |
-
'm'
|
306 |
-
'd'
|
307 |
-
'title' => $holiday
|
308 |
);
|
309 |
// if not repeated holiday, add the year
|
310 |
-
if ( ! $holiday
|
311 |
-
$holidays[$holiday
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
}
|
|
|
|
|
313 |
}
|
|
|
|
|
314 |
}
|
315 |
|
316 |
-
return
|
317 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
318 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_StaffController
|
11 |
*/
|
12 |
class AB_StaffController extends AB_Controller {
|
13 |
|
14 |
+
const page_slug = 'ab-system-staff';
|
15 |
+
|
16 |
+
protected function getPermissions()
|
17 |
+
{
|
18 |
+
return get_option( 'ab_settings_allow_staff_members_edit_profile' ) ? array( '_this' => 'user' ) : array();
|
19 |
+
}
|
20 |
+
|
21 |
+
public function index()
|
22 |
+
{
|
23 |
+
/** @var WP_Locale $wp_locale */
|
24 |
+
global $wp_locale;
|
25 |
+
|
26 |
+
$this->enqueueStyles( array(
|
27 |
+
'frontend' => array(
|
28 |
+
'css/intlTelInput.css',
|
29 |
+
'css/ladda.min.css',
|
30 |
+
),
|
31 |
+
'backend' => array(
|
32 |
+
'css/bookly.main-backend.css',
|
33 |
+
'bootstrap/css/bootstrap.min.css',
|
34 |
+
'css/jCal.css',
|
35 |
+
),
|
36 |
+
'module' => array(
|
37 |
+
'css/staff.css'
|
38 |
+
)
|
39 |
+
) );
|
40 |
+
|
41 |
+
$this->enqueueScripts( array(
|
42 |
+
'backend' => array(
|
43 |
+
'bootstrap/js/bootstrap.min.js' => array( 'jquery' ),
|
44 |
+
'js/ab_popup.js' => array( 'jquery' ),
|
45 |
+
'js/jCal.js' => array( 'jquery' ),
|
46 |
),
|
47 |
+
'module' => array(
|
48 |
+
'js/staff.js' => array( 'jquery-ui-sortable', 'jquery' ),
|
49 |
+
),
|
50 |
+
'frontend' => array(
|
51 |
+
'js/intlTelInput.min.js' => array( 'jquery' ),
|
52 |
+
'js/spin.min.js' => array( 'jquery' ),
|
53 |
+
'js/ladda.min.js' => array( 'jquery' ),
|
|
|
54 |
)
|
55 |
) );
|
56 |
|
57 |
+
wp_localize_script( 'ab-staff.js', 'BooklyL10n', array(
|
58 |
+
'are_you_sure' => __( 'Are you sure?', 'bookly' ),
|
59 |
+
'we_are_not_working' => __( 'We are not working on this day', 'bookly' ),
|
60 |
+
'repeat' => __( 'Repeat every year', 'bookly' ),
|
61 |
+
'months' => array_values( $wp_locale->month ),
|
62 |
+
'days' => array_values( $wp_locale->weekday_abbrev ),
|
63 |
+
'country' => get_option( 'ab_settings_phone_default_country' ),
|
64 |
+
'intlTelInput_utils' => plugins_url( 'intlTelInput.utils.js', AB_PATH . '/frontend/resources/js/intlTelInput.utils.js' ),
|
65 |
+
) );
|
66 |
|
67 |
$this->form = new AB_StaffMemberNewForm();
|
68 |
+
|
69 |
+
$this->staff_members =AB_Staff::query()->sortBy( 'position' )->limit(1)->fetchArray();
|
70 |
+
|
71 |
+
$this->active_staff_id = 1;
|
72 |
|
73 |
$this->render( 'list' );
|
74 |
}
|
75 |
|
76 |
+
public function executeCreateStaff()
|
77 |
+
{
|
78 |
+
$this->form = new AB_StaffMemberNewForm();
|
79 |
+
$this->form->bind( $this->getPostParameters() );
|
80 |
+
|
81 |
+
$staff = $this->form->save();
|
82 |
+
if ( $staff ) {
|
83 |
+
$this->render( 'list_item', array( 'staff' => $staff ) );
|
84 |
+
// Register string for translate in WPML.
|
85 |
+
do_action( 'wpml_register_single_string', 'bookly', 'staff_' . $staff->get( 'id' ), $staff->get( 'full_name' ) );
|
86 |
+
}
|
87 |
+
exit;
|
88 |
+
}
|
89 |
+
|
90 |
+
public function executeUpdateStaffPosition()
|
91 |
+
{
|
92 |
+
$staff_sorts = $this->getParameter( 'position' );
|
93 |
+
foreach ( $staff_sorts as $position => $staff_id ) {
|
94 |
+
$staff_sort = new AB_Staff();
|
95 |
+
$staff_sort->load( $staff_id );
|
96 |
+
$staff_sort->set( 'position', $position );
|
97 |
+
$staff_sort->save();
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
public function executeStaffServices()
|
102 |
+
{
|
103 |
$this->form = new AB_StaffServicesForm();
|
104 |
+
$this->form->load( 1 );
|
105 |
+
$this->staff_id = 1;
|
106 |
$this->render( 'services' );
|
107 |
exit;
|
108 |
}
|
109 |
|
110 |
+
public function executeStaffSchedule()
|
111 |
+
{
|
112 |
$staff = new AB_Staff();
|
113 |
+
$staff->load( 1 );
|
114 |
+
$this->schedule_items = $staff->getScheduleItems();
|
115 |
+
$this->staff_id = 1;
|
116 |
$this->render( 'schedule' );
|
117 |
exit;
|
118 |
}
|
119 |
|
120 |
+
public function executeStaffScheduleUpdate()
|
121 |
+
{
|
122 |
$this->form = new AB_StaffScheduleForm();
|
123 |
+
$this->form->bind( $this->getPostParameters() );
|
124 |
$this->form->save();
|
125 |
+
|
126 |
+
wp_send_json_success();
|
127 |
}
|
128 |
|
129 |
+
/**
|
130 |
+
*
|
131 |
+
* @throws Exception
|
132 |
+
*/
|
133 |
+
public function executeResetBreaks()
|
134 |
+
{
|
135 |
+
$breaks = $this->getParameter( 'breaks' );
|
136 |
+
|
137 |
+
// Remove all breaks for staff member.
|
138 |
+
$break = new AB_ScheduleItemBreak();
|
139 |
+
$break->removeBreaksByStaffId( 1 );
|
140 |
+
$html_breaks = array();
|
141 |
+
|
142 |
+
// Restore previous breaks.
|
143 |
+
if ( isset( $breaks['breaks'] ) && is_array( $breaks['breaks'] ) ) {
|
144 |
+
foreach ($breaks['breaks'] as $day) {
|
145 |
+
$schedule_item_break = new AB_ScheduleItemBreak();
|
146 |
+
$schedule_item_break->setFields($day);
|
147 |
+
$schedule_item_break->save();
|
148 |
+
}
|
149 |
+
}
|
150 |
+
|
151 |
+
$staff = new AB_Staff();
|
152 |
+
$staff->load( 1 );
|
153 |
+
|
154 |
+
// Make array with breaks (html) for each day.
|
155 |
+
foreach ( $staff->getScheduleItems() as $item ) {
|
156 |
+
/** @var AB_StaffScheduleItem $item */
|
157 |
+
$html_breaks[ $item->get( 'id' )] = $this->render( '_breaks', array(
|
158 |
+
'day_is_not_available' => null === $item->get( 'start_time' ),
|
159 |
+
'item' => $item,
|
160 |
+
), false );
|
161 |
+
}
|
162 |
+
|
163 |
+
wp_send_json( $html_breaks );
|
164 |
+
}
|
165 |
|
166 |
+
public function executeStaffScheduleHandleBreak()
|
167 |
+
{
|
168 |
+
$start_time = $this->getParameter( 'start_time' );
|
169 |
+
$end_time = $this->getParameter( 'end_time' );
|
170 |
+
$working_start = $this->getParameter( 'working_start' );
|
171 |
+
$working_end = $this->getParameter( 'working_end' );
|
172 |
|
173 |
+
if ( AB_DateTimeUtils::timeToSeconds( $start_time ) >= AB_DateTimeUtils::timeToSeconds( $end_time ) ) {
|
174 |
+
wp_send_json( array(
|
175 |
'success' => false,
|
176 |
+
'error_msg' => __( 'The start time must be less than the end one', 'bookly' ),
|
177 |
) );
|
|
|
178 |
}
|
179 |
|
180 |
$staffScheduleItem = new AB_StaffScheduleItem();
|
181 |
+
$staffScheduleItem->load( $this->getParameter( 'staff_schedule_item_id' ) );
|
182 |
|
183 |
+
$bound = array( $staffScheduleItem->get( 'start_time' ), $staffScheduleItem->get( 'end_time' ) );
|
184 |
+
$break_id = $this->getParameter( 'break_id', 0 );
|
185 |
|
186 |
$in_working_time = $working_start <= $start_time && $start_time <= $working_end
|
187 |
&& $working_start <= $end_time && $end_time <= $working_end;
|
188 |
if ( !$in_working_time || ! $staffScheduleItem->isBreakIntervalAvailable( $start_time, $end_time, $break_id ) ) {
|
189 |
+
wp_send_json( array(
|
190 |
'success' => false,
|
191 |
+
'error_msg' => __( 'The requested interval is not available', 'bookly' ),
|
192 |
) );
|
|
|
193 |
}
|
194 |
|
195 |
+
$formatted_start = AB_DateTimeUtils::formatTime( AB_DateTimeUtils::timeToSeconds( $start_time ) );
|
196 |
+
$formatted_end = AB_DateTimeUtils::formatTime( AB_DateTimeUtils::timeToSeconds( $end_time ) );
|
197 |
+
$formatted_interval = $formatted_start . ' - ' . $formatted_end;
|
|
|
198 |
|
199 |
if ( $break_id ) {
|
200 |
$break = new AB_ScheduleItemBreak();
|
203 |
$break->set( 'end_time', $end_time );
|
204 |
$break->save();
|
205 |
|
206 |
+
wp_send_json( array(
|
207 |
'success' => true,
|
208 |
'new_interval' => $formatted_interval,
|
209 |
) );
|
210 |
} else {
|
211 |
$this->form = new AB_StaffScheduleItemBreakForm();
|
212 |
+
$this->form->bind( $this->getPostParameters() );
|
213 |
|
214 |
$staffScheduleItemBreak = $this->form->save();
|
215 |
if ( $staffScheduleItemBreak ) {
|
216 |
+
$breakStart = new AB_TimeChoiceWidget( array( 'use_empty' => false, 'type' => 'from', 'bound' => $bound ) );
|
217 |
$break_start_choices = $breakStart->render(
|
218 |
'',
|
219 |
$start_time,
|
220 |
+
array( 'class' => 'break-start form-control',
|
221 |
+
'data-default_value' => AB_StaffScheduleItem::WORKING_START_TIME
|
|
|
222 |
)
|
223 |
);
|
224 |
+
$breakEnd = new AB_TimeChoiceWidget( array( 'use_empty' => false, 'type' => 'bound', 'bound' => $bound ) );
|
225 |
$break_end_choices = $breakEnd->render(
|
226 |
'',
|
227 |
$end_time,
|
228 |
+
array( 'class' => 'break-end form-control',
|
229 |
+
'data-default_value' => date( 'H:i:s', strtotime( AB_StaffScheduleItem::WORKING_START_TIME . ' + 1 hour' ) )
|
|
|
230 |
)
|
231 |
);
|
232 |
+
wp_send_json( array(
|
233 |
'success' => true,
|
234 |
+
'item_content' => $this->render( '_break', array(
|
235 |
+
'staff_schedule_item_break_id' => $staffScheduleItemBreak->get( 'id' ),
|
236 |
+
'formatted_interval' => $formatted_interval,
|
237 |
+
'break_start_choices' => $break_start_choices,
|
238 |
+
'break_end_choices' => $break_end_choices,
|
239 |
+
), false),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
) );
|
241 |
} else {
|
242 |
+
wp_send_json( array(
|
243 |
'success' => false,
|
244 |
+
'error_msg' => __( 'Error adding the break interval', 'bookly' ),
|
245 |
) );
|
246 |
}
|
247 |
}
|
|
|
|
|
248 |
}
|
249 |
|
250 |
+
public function executeDeleteStaffScheduleBreak()
|
251 |
+
{
|
252 |
$break = new AB_ScheduleItemBreak();
|
253 |
+
$break->load( 1 );
|
254 |
$break->delete();
|
255 |
+
|
256 |
+
wp_send_json_success();
|
257 |
}
|
258 |
|
259 |
+
public function executeStaffServicesUpdate()
|
260 |
+
{
|
261 |
$this->form = new AB_StaffServicesForm();
|
262 |
+
$this->form->bind( $this->getPostParameters() );
|
263 |
$this->form->save();
|
264 |
+
|
265 |
+
wp_send_json_success();
|
266 |
}
|
267 |
|
268 |
+
public function executeEditStaff()
|
269 |
+
{
|
270 |
$this->form = new AB_StaffMemberEditForm();
|
271 |
$this->staff = new AB_Staff();
|
272 |
+
$this->staff->load( 1 );
|
273 |
+
$staff_errors = array();
|
274 |
+
|
275 |
+
$this->authUrl = false;
|
276 |
+
// Register string for translate in WPML.
|
277 |
+
do_action( 'wpml_register_single_string', 'bookly', 'staff_' . $this->staff->get( 'id' ), $this->staff->get( 'full_name' ) );
|
278 |
+
|
279 |
+
$this->render( 'edit', array( 'staff_errors' => $staff_errors ) );
|
280 |
exit;
|
281 |
}
|
282 |
|
283 |
+
/**
|
284 |
+
* Update staff from POST request.
|
285 |
+
* @see AB_Backend.php
|
286 |
+
*/
|
287 |
+
public function updateStaff()
|
288 |
+
{
|
289 |
+
if ( ! AB_Utils::isCurrentUserAdmin() ) {
|
290 |
+
// Check permissions to prevent one staff member from updating profile of another staff member.
|
291 |
+
do {
|
292 |
+
if ( get_option( 'ab_settings_allow_staff_members_edit_profile' ) ) {
|
293 |
+
$staff = new AB_Staff();
|
294 |
+
$staff->load( 1 );
|
295 |
+
if ( $staff->get( 'wp_user_id' ) == get_current_user_id() ) {
|
296 |
+
unset ( $_POST['wp_user_id'] );
|
297 |
+
break;
|
298 |
+
}
|
299 |
+
}
|
300 |
+
do_action( 'admin_page_access_denied' );
|
301 |
+
wp_die( __( 'Bookly: You do not have sufficient permissions to access this page.', 'bookly' ) );
|
302 |
+
} while ( 0 );
|
303 |
+
}
|
304 |
+
|
305 |
$form = new AB_StaffMemberEditForm();
|
306 |
+
$form->bind( $this->getPostParameters(), $_FILES );
|
307 |
+
$result = $form->save();
|
308 |
+
|
309 |
// Set staff id to load the form for.
|
310 |
+
$this->active_staff_id = 1;
|
311 |
+
|
312 |
+
if ( $result === false && array_key_exists( 'google_calendar', $form->getErrors() ) ) {
|
313 |
+
$errors = $form->getErrors();
|
314 |
+
$_SESSION['google_calendar_error'] = $errors['google_calendar'];
|
315 |
+
} else {
|
316 |
+
$_SESSION['bookly_updated'] = true;
|
317 |
+
}
|
318 |
}
|
319 |
|
320 |
+
public function executeDeleteStaff()
|
321 |
+
{
|
322 |
$staff = new AB_Staff();
|
323 |
+
$staff->load( $this->getParameter( 'id' ) );
|
324 |
+
$staff->delete();
|
325 |
+
$form = new AB_StaffMemberForm();
|
326 |
+
wp_send_json( $form->getUsersForStaff() );
|
327 |
+
}
|
328 |
+
|
329 |
+
public function executeDeleteStaffAvatar()
|
330 |
+
{
|
331 |
+
$staff = new AB_Staff();
|
332 |
+
$staff->load( 1 );
|
333 |
+
if ( file_exists( $staff->get( 'avatar_path' ) ) ) {
|
334 |
+
unlink( $staff->get( 'avatar_path' ) );
|
335 |
+
}
|
336 |
$staff->set( 'avatar_url', '' );
|
337 |
$staff->set( 'avatar_path', '' );
|
338 |
$staff->save();
|
339 |
+
wp_send_json_success();
|
340 |
}
|
341 |
|
342 |
+
public function executeStaffHolidays()
|
343 |
+
{
|
344 |
+
$this->id = $this->getParameter( 'id', 0 );
|
345 |
$this->holidays = $this->getHolidays( $this->id );
|
346 |
+
$this->render( 'holidays' );
|
347 |
exit;
|
348 |
}
|
349 |
|
350 |
+
public function executeStaffHolidaysUpdate()
|
351 |
+
{
|
352 |
+
$id = 1;
|
353 |
+
$holiday = $this->getParameter( 'holiday' ) == 'true';
|
354 |
+
$repeat = $this->getParameter( 'repeat' ) == 'true';
|
355 |
+
$day = $this->getParameter( 'day', false );
|
356 |
+
$staff_id = $this->getParameter( 'staff_id' );
|
357 |
|
358 |
if ( $staff_id ) {
|
359 |
+
// Update or delete the event.
|
360 |
if ( $id ) {
|
361 |
if ( $holiday ) {
|
362 |
+
$this->getWpdb()->update( AB_Holiday::getTableName(), array( 'repeat_event' => intval( $repeat ) ), array( 'id' => $id ), array( '%d' ) );
|
363 |
} else {
|
364 |
+
AB_Holiday::query()->delete()->where( 'id', $id )->execute();
|
365 |
}
|
366 |
+
// Add the new event.
|
367 |
+
} elseif ( $holiday && $day ) {
|
368 |
+
$this->getWpdb()->insert( AB_Holiday::getTableName(), array( 'date' => $day, 'repeat_event' => intval( $repeat ), 'staff_id' => $staff_id ), array( '%s', '%d', '%d' ) );
|
|
|
369 |
}
|
370 |
|
371 |
+
// And return refreshed events.
|
372 |
+
echo $this->getHolidays( $staff_id );
|
373 |
}
|
374 |
exit;
|
375 |
}
|
376 |
|
|
|
|
|
377 |
// Protected methods.
|
378 |
|
379 |
+
protected function getHolidays( $id )
|
380 |
+
{
|
381 |
+
$collection = AB_Holiday::query( 'h' )->where( 'h.staff_id', 1 )->fetchArray();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
$holidays = array();
|
383 |
if ( count( $collection ) ) {
|
384 |
foreach ( $collection as $holiday ) {
|
385 |
+
$holidays[$holiday['id']] = array(
|
386 |
+
'm' => intval( date( 'm', strtotime( $holiday['date'] ) ) ),
|
387 |
+
'd' => intval( date( 'd', strtotime( $holiday['date'] ) ) ),
|
388 |
+
'title' => $holiday['title'],
|
389 |
);
|
390 |
// if not repeated holiday, add the year
|
391 |
+
if ( ! $holiday['repeat_event'] ) {
|
392 |
+
$holidays[ $holiday['id'] ]['y'] = intval( date( 'Y', strtotime( $holiday['date'] ) ) );
|
393 |
+
}
|
394 |
+
}
|
395 |
+
}
|
396 |
+
|
397 |
+
return json_encode( $holidays );
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* Extend parent method to control access on staff member level.
|
402 |
+
*
|
403 |
+
* @param string $action
|
404 |
+
* @return bool
|
405 |
+
*/
|
406 |
+
protected function hasAccess( $action )
|
407 |
+
{
|
408 |
+
if ( parent::hasAccess( $action ) ) {
|
409 |
+
|
410 |
+
if ( ! AB_Utils::isCurrentUserAdmin() ) {
|
411 |
+
$staff = new AB_Staff();
|
412 |
+
|
413 |
+
switch ( $action ) {
|
414 |
+
case 'executeEditStaff':
|
415 |
+
case 'executeDeleteStaffAvatar':
|
416 |
+
case 'executeStaffServices':
|
417 |
+
case 'executeStaffSchedule':
|
418 |
+
case 'executeStaffHolidays':
|
419 |
+
$staff->load( 1 );
|
420 |
+
break;
|
421 |
+
case 'executeStaffServicesUpdate':
|
422 |
+
case 'executeStaffHolidaysUpdate':
|
423 |
+
$staff->load( $this->getParameter( 'staff_id' ) );
|
424 |
+
break;
|
425 |
+
case 'executeStaffScheduleHandleBreak':
|
426 |
+
$staffScheduleItem = new AB_StaffScheduleItem();
|
427 |
+
$staffScheduleItem->load( $this->getParameter( 'staff_schedule_item_id' ) );
|
428 |
+
$staff->load( $staffScheduleItem->get( 'staff_id' ) );
|
429 |
+
break;
|
430 |
+
case 'executeDeleteStaffScheduleBreak':
|
431 |
+
$break = new AB_ScheduleItemBreak();
|
432 |
+
$break->load( 1 );
|
433 |
+
$staffScheduleItem = new AB_StaffScheduleItem();
|
434 |
+
$staffScheduleItem->load( $break->get( 'staff_schedule_item_id' ) );
|
435 |
+
$staff->load( $staffScheduleItem->get( 'staff_id' ) );
|
436 |
+
break;
|
437 |
+
case 'executeStaffScheduleUpdate':
|
438 |
+
if ( $this->hasParameter( 'days' ) ) {
|
439 |
+
foreach ( $this->getParameter( 'days' ) as $id => $day_index ) {
|
440 |
+
$staffScheduleItem = new AB_StaffScheduleItem();
|
441 |
+
$staffScheduleItem->load( $id );
|
442 |
+
$staff = new AB_Staff();
|
443 |
+
$staff->load( $staffScheduleItem->get( 'staff_id' ) );
|
444 |
+
if ( $staff->get( 'wp_user_id' ) != get_current_user_id() ) {
|
445 |
+
return false;
|
446 |
+
}
|
447 |
+
}
|
448 |
+
}
|
449 |
+
break;
|
450 |
+
default:
|
451 |
+
return false;
|
452 |
}
|
453 |
+
|
454 |
+
return $staff->get( 'wp_user_id' ) == get_current_user_id();
|
455 |
}
|
456 |
+
|
457 |
+
return true;
|
458 |
}
|
459 |
|
460 |
+
return false;
|
461 |
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* Override parent method to add 'wp_ajax_ab_' prefix
|
465 |
+
* so current 'execute*' methods look nicer.
|
466 |
+
*
|
467 |
+
* @param string $prefix
|
468 |
+
*/
|
469 |
+
protected function registerWpActions( $prefix = '' )
|
470 |
+
{
|
471 |
+
parent::registerWpActions( 'wp_ajax_ab_' );
|
472 |
+
}
|
473 |
+
|
474 |
}
|
backend/modules/staff/forms/AB_StaffMemberEditForm.php
CHANGED
@@ -1,40 +1,59 @@
|
|
1 |
-
<?php
|
2 |
-
if ( !
|
3 |
-
if ( !function_exists( 'wp_handle_upload' ) ) require_once(ABSPATH . 'wp-admin/includes/file.php');
|
4 |
-
include dirname(__FILE__) . '/../../../../lib/AB_ImageResize.php';
|
5 |
|
6 |
class AB_StaffMemberEditForm extends AB_StaffMemberForm {
|
7 |
|
8 |
-
|
|
|
|
|
|
|
9 |
$this->setFields( array(
|
10 |
'wp_user_id',
|
11 |
'full_name',
|
12 |
-
|
13 |
'phone',
|
14 |
-
'avatar'
|
|
|
15 |
) );
|
16 |
}
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
|
|
23 |
parent::bind( $post );
|
24 |
|
25 |
-
if ( isset ( $files[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
if ( $movefile ) {
|
30 |
-
$imageResize = new AB_ImageResize( $movefile[ 'file' ] );
|
31 |
-
$imageResize->resizeImage( 80, 80 );
|
32 |
-
$imageResize->saveImage( $movefile[ 'file' ], 80 );
|
33 |
|
34 |
-
|
35 |
-
$
|
|
|
|
|
|
|
|
|
36 |
}
|
37 |
}
|
38 |
}
|
39 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
2 |
+
if ( ! function_exists( 'wp_handle_upload' ) ) { require_once( ABSPATH . 'wp-admin/includes/file.php' ); }
|
|
|
|
|
3 |
|
4 |
class AB_StaffMemberEditForm extends AB_StaffMemberForm {
|
5 |
|
6 |
+
private $errors = array();
|
7 |
+
|
8 |
+
public function configure()
|
9 |
+
{
|
10 |
$this->setFields( array(
|
11 |
'wp_user_id',
|
12 |
'full_name',
|
13 |
+
'email',
|
14 |
'phone',
|
15 |
+
'avatar',
|
16 |
+
'position',
|
17 |
) );
|
18 |
}
|
19 |
|
20 |
+
/**
|
21 |
+
* @param array $post
|
22 |
+
* @param array $files
|
23 |
+
*/
|
24 |
+
public function bind( array $post, array $files = array() )
|
25 |
+
{
|
26 |
parent::bind( $post );
|
27 |
|
28 |
+
if ( isset ( $files['avatar'] ) && $files['avatar']['tmp_name'] ) {
|
29 |
+
|
30 |
+
if ( in_array( $files['avatar']['type'], array( 'image/gif', 'image/jpeg', 'image/png' ) ) ) {
|
31 |
+
$uploaded = wp_handle_upload( $files['avatar'], array( 'test_form' => false ) );
|
32 |
+
if ( $uploaded ) {
|
33 |
+
$editor = wp_get_image_editor( $uploaded['file'] );
|
34 |
+
$editor->resize( 200, 200 );
|
35 |
+
$editor->save( $uploaded['file'] );
|
36 |
|
37 |
+
$this->data['avatar_path'] = $uploaded['file'];
|
38 |
+
$this->data['avatar_url'] = $uploaded['url'];
|
|
|
|
|
|
|
|
|
39 |
|
40 |
+
// Remove old image.
|
41 |
+
$staff = new AB_Staff();
|
42 |
+
$staff->load( $post['id'] );
|
43 |
+
if ( file_exists( $staff->get( 'avatar_path' ) ) ) {
|
44 |
+
unlink( $staff->get( 'avatar_path' ) );
|
45 |
+
}
|
46 |
}
|
47 |
}
|
48 |
}
|
49 |
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* @return array
|
53 |
+
*/
|
54 |
+
public function getErrors()
|
55 |
+
{
|
56 |
+
return $this->errors;
|
57 |
+
}
|
58 |
+
|
59 |
}
|
backend/modules/staff/forms/AB_StaffMemberForm.php
CHANGED
@@ -1,7 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_Staff.php';
|
5 |
|
6 |
/**
|
7 |
* Class AB_StaffMemberForm
|
@@ -13,7 +10,8 @@ class AB_StaffMemberForm extends AB_Form {
|
|
13 |
/**
|
14 |
* Constructor.
|
15 |
*/
|
16 |
-
public function __construct()
|
|
|
17 |
parent::$entity_class = 'AB_Staff';
|
18 |
parent::__construct();
|
19 |
}
|
@@ -30,21 +28,35 @@ class AB_StaffMemberForm extends AB_Form {
|
|
30 |
* @param integer $staff_id If null then it means new staff
|
31 |
* @return array
|
32 |
*/
|
33 |
-
public function getUsersForStaff($staff_id = null)
|
|
|
34 |
/** @var wpdb $wpdb */
|
35 |
global $wpdb;
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
WHERE ID NOT IN(SELECT DISTINCT IFNULL( wp_user_id, 0 ) FROM ab_staff %s)
|
41 |
ORDER BY display_name',
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
}
|
|
|
50 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_StaffMemberForm
|
10 |
/**
|
11 |
* Constructor.
|
12 |
*/
|
13 |
+
public function __construct()
|
14 |
+
{
|
15 |
parent::$entity_class = 'AB_Staff';
|
16 |
parent::__construct();
|
17 |
}
|
28 |
* @param integer $staff_id If null then it means new staff
|
29 |
* @return array
|
30 |
*/
|
31 |
+
public function getUsersForStaff( $staff_id = null )
|
32 |
+
{
|
33 |
/** @var wpdb $wpdb */
|
34 |
global $wpdb;
|
35 |
+
if ( ! is_multisite() ) {
|
36 |
+
$query = sprintf(
|
37 |
+
'SELECT ID, user_email, display_name FROM ' . $wpdb->users . '
|
38 |
+
WHERE ID NOT IN(SELECT DISTINCT IFNULL( wp_user_id, 0 ) FROM ' . AB_Staff::getTableName() . ' %s)
|
|
|
39 |
ORDER BY display_name',
|
40 |
+
$staff_id !== null
|
41 |
+
? "WHERE " . AB_Staff::getTableName() . ".id <> $staff_id"
|
42 |
+
: ''
|
43 |
+
);
|
44 |
+
$users = $wpdb->get_results( $query );
|
45 |
+
} else {
|
46 |
+
// In Multisite show users only for current blog.
|
47 |
+
if( $staff_id == null ) {
|
48 |
+
$query = AB_Staff::query( 's' )->select( 'DISTINCT wp_user_id' )->whereNot( 'wp_user_id', null );
|
49 |
+
} else {
|
50 |
+
$query = AB_Staff::query( 's' )->select( 'wp_user_id' )->whereNot( 'id', $staff_id );
|
51 |
+
}
|
52 |
+
$occupied_wp_users = array();
|
53 |
+
foreach ( $query->fetchArray() as $staff ) {
|
54 |
+
$occupied_wp_users[] = $staff['wp_user_id'];
|
55 |
+
}
|
56 |
+
$users = get_users( array( 'blog_id' => get_current_blog_id(), 'orderby' => 'display_name', 'exclude' => $occupied_wp_users ) );
|
57 |
+
}
|
58 |
+
|
59 |
+
return $users;
|
60 |
}
|
61 |
+
|
62 |
}
|
backend/modules/staff/forms/AB_StaffMemberNewForm.php
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
-
<?php
|
2 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
3 |
-
include 'AB_StaffMemberForm.php';
|
4 |
|
5 |
/**
|
6 |
* Class AB_StaffMemberNewForm
|
7 |
*/
|
8 |
class AB_StaffMemberNewForm extends AB_StaffMemberForm {
|
9 |
|
10 |
-
public function configure()
|
|
|
11 |
$this->setFields( array( 'wp_user_id', 'full_name' ) );
|
12 |
}
|
13 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_StaffMemberNewForm
|
5 |
*/
|
6 |
class AB_StaffMemberNewForm extends AB_StaffMemberForm {
|
7 |
|
8 |
+
public function configure()
|
9 |
+
{
|
10 |
$this->setFields( array( 'wp_user_id', 'full_name' ) );
|
11 |
}
|
12 |
}
|
backend/modules/staff/forms/AB_StaffScheduleForm.php
CHANGED
@@ -1,6 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
5 |
/**
|
6 |
* Class AB_StaffScheduleForm
|
@@ -10,31 +8,27 @@ class AB_StaffScheduleForm extends AB_Form {
|
|
10 |
/**
|
11 |
* Constructor.
|
12 |
*/
|
13 |
-
public function __construct()
|
|
|
14 |
parent::$entity_class = 'AB_StaffScheduleItem';
|
15 |
parent::__construct();
|
16 |
}
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
*/
|
21 |
-
private $wpdb;
|
22 |
-
|
23 |
-
public function configure() {
|
24 |
-
global $wpdb;
|
25 |
-
$this->wpdb = $wpdb;
|
26 |
$this->setFields( array( 'days', 'staff_id', 'start_time', 'end_time' ) );
|
27 |
}
|
28 |
|
29 |
-
public function save()
|
|
|
30 |
if ( isset($this->data['days']) ) {
|
31 |
-
foreach ( $this->data['days'] as $id => $
|
32 |
$staffScheduleItem = new AB_StaffScheduleItem();
|
33 |
$staffScheduleItem->load( $id );
|
34 |
-
$staffScheduleItem->set( '
|
35 |
-
if ($this->data['start_time'][$
|
36 |
-
$staffScheduleItem->set( 'start_time', $this->data['start_time'][$
|
37 |
-
$staffScheduleItem->set( 'end_time', $this->data['end_time'][$
|
38 |
} else {
|
39 |
$staffScheduleItem->set( 'start_time', null );
|
40 |
$staffScheduleItem->set( 'end_time', null );
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_StaffScheduleForm
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_StaffScheduleItem';
|
14 |
parent::__construct();
|
15 |
}
|
16 |
|
17 |
+
public function configure()
|
18 |
+
{
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
$this->setFields( array( 'days', 'staff_id', 'start_time', 'end_time' ) );
|
20 |
}
|
21 |
|
22 |
+
public function save()
|
23 |
+
{
|
24 |
if ( isset($this->data['days']) ) {
|
25 |
+
foreach ( $this->data['days'] as $id => $day_index ) {
|
26 |
$staffScheduleItem = new AB_StaffScheduleItem();
|
27 |
$staffScheduleItem->load( $id );
|
28 |
+
$staffScheduleItem->set( 'day_index', $day_index );
|
29 |
+
if ($this->data['start_time'][$day_index]) {
|
30 |
+
$staffScheduleItem->set( 'start_time', $this->data['start_time'][$day_index] );
|
31 |
+
$staffScheduleItem->set( 'end_time', $this->data['end_time'][$day_index] );
|
32 |
} else {
|
33 |
$staffScheduleItem->set( 'start_time', null );
|
34 |
$staffScheduleItem->set( 'end_time', null );
|
backend/modules/staff/forms/AB_StaffScheduleItemBreakForm.php
CHANGED
@@ -1,8 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_ScheduleItemBreak.php';
|
6 |
|
7 |
/**
|
8 |
* Class AB_StaffScheduleItemBreakForm
|
@@ -12,16 +8,19 @@ class AB_StaffScheduleItemBreakForm extends AB_Form {
|
|
12 |
/**
|
13 |
* Constructor.
|
14 |
*/
|
15 |
-
public function __construct()
|
|
|
16 |
parent::$entity_class = 'AB_ScheduleItemBreak';
|
17 |
parent::__construct();
|
18 |
}
|
19 |
|
20 |
-
public function configure()
|
|
|
21 |
$this->setFields( array(
|
22 |
'staff_schedule_item_id',
|
23 |
'start_time',
|
24 |
'end_time'
|
25 |
) );
|
26 |
}
|
27 |
-
|
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_StaffScheduleItemBreakForm
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_ScheduleItemBreak';
|
14 |
parent::__construct();
|
15 |
}
|
16 |
|
17 |
+
public function configure()
|
18 |
+
{
|
19 |
$this->setFields( array(
|
20 |
'staff_schedule_item_id',
|
21 |
'start_time',
|
22 |
'end_time'
|
23 |
) );
|
24 |
}
|
25 |
+
|
26 |
+
}
|
backend/modules/staff/forms/AB_StaffServicesForm.php
CHANGED
@@ -1,9 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
-
|
5 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_Category.php';
|
6 |
-
include dirname(__FILE__) . '/../../../../lib/entities/AB_StaffService.php';
|
7 |
|
8 |
/**
|
9 |
* Class AB_StaffServicesForm
|
@@ -13,7 +8,8 @@ class AB_StaffServicesForm extends AB_Form {
|
|
13 |
/**
|
14 |
* Constructor.
|
15 |
*/
|
16 |
-
public function __construct()
|
|
|
17 |
parent::$entity_class = 'AB_StaffService';
|
18 |
parent::__construct();
|
19 |
}
|
@@ -43,45 +39,34 @@ class AB_StaffServicesForm extends AB_Form {
|
|
43 |
*/
|
44 |
private $uncategorized_services = array();
|
45 |
|
46 |
-
public function configure()
|
|
|
47 |
global $wpdb;
|
48 |
$this->wpdb = $wpdb;
|
49 |
-
$this->setFields( array( 'price', 'service', 'staff_id' ) );
|
50 |
}
|
51 |
|
52 |
-
public function load($staff_id)
|
53 |
-
|
54 |
-
|
55 |
-
FROM ab_category c
|
56 |
-
INNER JOIN ab_service s ON c.id = s.category_id
|
57 |
-
', ARRAY_A );
|
58 |
-
|
59 |
if ( !$data ) {
|
60 |
$data = array();
|
61 |
}
|
62 |
|
63 |
-
$uncategorized_services =
|
64 |
-
foreach ( $uncategorized_services as $uncategorized_service ) {
|
65 |
-
$abService = new AB_Service();
|
66 |
-
$abService->setData($uncategorized_service);
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
', $staff_id) );
|
76 |
-
|
77 |
-
if ( $rows ) {
|
78 |
-
foreach ($rows as $row) {
|
79 |
-
$this->selected[$row->service_id] = $row->price;
|
80 |
}
|
81 |
}
|
82 |
|
83 |
-
foreach ($data as $row) {
|
84 |
-
if ( !isset($this->collection[ $row['category_id'] ]) ) {
|
85 |
$abCategory = new AB_Category();
|
86 |
$abCategory->set( 'id', $row['category_id'] );
|
87 |
$abCategory->set( 'name', $row['category_name'] );
|
@@ -89,23 +74,24 @@ class AB_StaffServicesForm extends AB_Form {
|
|
89 |
}
|
90 |
unset( $row['category_name'] );
|
91 |
|
92 |
-
$abService = new AB_Service();
|
93 |
-
$abService->
|
94 |
-
$this->
|
95 |
-
$this->collection[ $row['category_id'] ]->addService($abService);
|
96 |
}
|
97 |
}
|
98 |
|
99 |
-
public function save()
|
|
|
100 |
$staff_id = $this->data['staff_id'];
|
101 |
if ( $staff_id ) {
|
102 |
-
|
103 |
-
if ( isset($this->data['service']) ) {
|
104 |
foreach ( $this->data['service'] as $service_id ) {
|
105 |
$staffService = new AB_StaffService();
|
106 |
$staffService->set( 'service_id', $service_id );
|
107 |
$staffService->set( 'staff_id', $staff_id );
|
108 |
$staffService->set( 'price', $this->data['price'][ $service_id ] );
|
|
|
109 |
$staffService->save();
|
110 |
}
|
111 |
}
|
@@ -115,15 +101,17 @@ class AB_StaffServicesForm extends AB_Form {
|
|
115 |
/**
|
116 |
* @return AB_Category[]|array
|
117 |
*/
|
118 |
-
public function getCollection()
|
|
|
119 |
return $this->collection;
|
120 |
}
|
121 |
|
122 |
/**
|
123 |
* @return array
|
124 |
*/
|
125 |
-
public function getSelected()
|
126 |
-
|
|
|
127 |
}
|
128 |
|
129 |
/**
|
@@ -133,4 +121,5 @@ class AB_StaffServicesForm extends AB_Form {
|
|
133 |
{
|
134 |
return $this->uncategorized_services;
|
135 |
}
|
|
|
136 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
/**
|
4 |
* Class AB_StaffServicesForm
|
8 |
/**
|
9 |
* Constructor.
|
10 |
*/
|
11 |
+
public function __construct()
|
12 |
+
{
|
13 |
parent::$entity_class = 'AB_StaffService';
|
14 |
parent::__construct();
|
15 |
}
|
39 |
*/
|
40 |
private $uncategorized_services = array();
|
41 |
|
42 |
+
public function configure()
|
43 |
+
{
|
44 |
global $wpdb;
|
45 |
$this->wpdb = $wpdb;
|
46 |
+
$this->setFields( array( 'price', 'service', 'staff_id', 'capacity' ) );
|
47 |
}
|
48 |
|
49 |
+
public function load( $staff_id )
|
50 |
+
{
|
51 |
+
$data = AB_Category::query( 'c' )->select( 'c.name AS category_name, s.*' )->innerJoin( 'AB_Service', 's', 's.category_id = c.id' )->fetchArray();
|
|
|
|
|
|
|
|
|
52 |
if ( !$data ) {
|
53 |
$data = array();
|
54 |
}
|
55 |
|
56 |
+
$this->uncategorized_services = AB_Service::query( 's' )->where( 's.category_id', null )->fetchArray();
|
|
|
|
|
|
|
57 |
|
58 |
+
$staff_services = AB_StaffService::query( 'ss' )
|
59 |
+
->select( 'ss.service_id, ss.price, ss.capacity' )
|
60 |
+
->where( 'ss.staff_id', $staff_id )
|
61 |
+
->fetchArray();
|
62 |
+
if ( $staff_services ) {
|
63 |
+
foreach ( $staff_services as $staff_service ) {
|
64 |
+
$this->selected[ $staff_service['service_id'] ] = array( 'price' => $staff_service['price'], 'capacity' => $staff_service['capacity'] );
|
|
|
|
|
|
|
|
|
|
|
65 |
}
|
66 |
}
|
67 |
|
68 |
+
foreach ( $data as $row ) {
|
69 |
+
if ( ! isset( $this->collection[ $row['category_id'] ] ) ) {
|
70 |
$abCategory = new AB_Category();
|
71 |
$abCategory->set( 'id', $row['category_id'] );
|
72 |
$abCategory->set( 'name', $row['category_name'] );
|
74 |
}
|
75 |
unset( $row['category_name'] );
|
76 |
|
77 |
+
$abService = new AB_Service( $row );
|
78 |
+
$this->category_services[ $row['category_id'] ][] = $abService->get( 'id' );
|
79 |
+
$this->collection[ $row['category_id'] ]->addService( $abService );
|
|
|
80 |
}
|
81 |
}
|
82 |
|
83 |
+
public function save()
|
84 |
+
{
|
85 |
$staff_id = $this->data['staff_id'];
|
86 |
if ( $staff_id ) {
|
87 |
+
AB_StaffService::query()->delete()->where( 'staff_id', $staff_id )->execute();
|
88 |
+
if ( isset( $this->data['service'] ) ) {
|
89 |
foreach ( $this->data['service'] as $service_id ) {
|
90 |
$staffService = new AB_StaffService();
|
91 |
$staffService->set( 'service_id', $service_id );
|
92 |
$staffService->set( 'staff_id', $staff_id );
|
93 |
$staffService->set( 'price', $this->data['price'][ $service_id ] );
|
94 |
+
$staffService->set( 'capacity', $this->data['capacity'][ $service_id ] );
|
95 |
$staffService->save();
|
96 |
}
|
97 |
}
|
101 |
/**
|
102 |
* @return AB_Category[]|array
|
103 |
*/
|
104 |
+
public function getCollection()
|
105 |
+
{
|
106 |
return $this->collection;
|
107 |
}
|
108 |
|
109 |
/**
|
110 |
* @return array
|
111 |
*/
|
112 |
+
public function getSelected()
|
113 |
+
{
|
114 |
+
return $this->selected;
|
115 |
}
|
116 |
|
117 |
/**
|
121 |
{
|
122 |
return $this->uncategorized_services;
|
123 |
}
|
124 |
+
|
125 |
}
|
backend/modules/staff/forms/widget/AB_TimeChoiceWidget.php
CHANGED
@@ -1,6 +1,4 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
if ( !defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
4 |
|
5 |
class AB_TimeChoiceWidget {
|
6 |
/**
|
@@ -13,29 +11,39 @@ class AB_TimeChoiceWidget {
|
|
13 |
*
|
14 |
* @param array $options
|
15 |
*/
|
16 |
-
public function __construct( array $options = array() )
|
|
|
17 |
// Handle widget options.
|
18 |
$options = array_merge( array(
|
19 |
-
'use_empty'
|
20 |
-
'empty_value' => null
|
|
|
21 |
), $options );
|
22 |
|
23 |
// Insert empty value if required.
|
24 |
-
if ( $options[
|
25 |
-
$this->values[
|
26 |
}
|
27 |
|
28 |
-
$
|
29 |
-
|
30 |
-
|
31 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
// Run the loop.
|
34 |
-
while ( $time_start
|
35 |
-
$this->values[ $time_start
|
36 |
-
$time_start
|
37 |
}
|
38 |
-
$this->values[ $time_end->format( 'H:i:s' ) ] = $time_end->format( $tf );
|
39 |
}
|
40 |
|
41 |
/**
|
@@ -47,16 +55,28 @@ class AB_TimeChoiceWidget {
|
|
47 |
*
|
48 |
* @return string
|
49 |
*/
|
50 |
-
public function render( $name, $value = null, array $attributes = array() )
|
51 |
-
|
|
|
52 |
$attributes_str = '';
|
|
|
53 |
foreach ( $this->values as $option_value => $option_text ) {
|
54 |
-
|
55 |
-
|
56 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
'<option value="%s"%s>%s</option>',
|
58 |
$option_value,
|
59 |
-
($
|
60 |
$option_text
|
61 |
);
|
62 |
}
|
@@ -64,21 +84,7 @@ class AB_TimeChoiceWidget {
|
|
64 |
$attributes_str .= sprintf( ' %s="%s"', $attr_name, $attr_value );
|
65 |
}
|
66 |
|
67 |
-
return sprintf( '<select name="%s"%s>%s</select>', $name, $
|
68 |
}
|
69 |
|
70 |
-
public function renderOptions( $start, $selected = '' ) {
|
71 |
-
$options = array();
|
72 |
-
foreach ( $this->values as $option_value => $option_text ) {
|
73 |
-
if ( $start && strval( $option_value ) < strval( $start ) ) continue;
|
74 |
-
$options[ ] = sprintf(
|
75 |
-
'<option value="%s"%s>%s</option>',
|
76 |
-
$option_value,
|
77 |
-
(strval( $selected ) == strval( $option_value ) ? 'selected="selected"' : ''),
|
78 |
-
$option_text
|
79 |
-
);
|
80 |
-
}
|
81 |
-
|
82 |
-
return $options;
|
83 |
-
}
|
84 |
}
|
1 |
+
<?php if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
|
|
|
|
2 |
|
3 |
class AB_TimeChoiceWidget {
|
4 |
/**
|
11 |
*
|
12 |
* @param array $options
|
13 |
*/
|
14 |
+
public function __construct( array $options = array() )
|
15 |
+
{
|
16 |
// Handle widget options.
|
17 |
$options = array_merge( array(
|
18 |
+
'use_empty' => true,
|
19 |
+
'empty_value' => null,
|
20 |
+
'type' => 'from',
|
21 |
), $options );
|
22 |
|
23 |
// Insert empty value if required.
|
24 |
+
if ( $options['use_empty'] ) {
|
25 |
+
$this->values[null] = $options['empty_value'];
|
26 |
}
|
27 |
|
28 |
+
$ts_length = AB_Config::getTimeSlotLength();
|
29 |
+
if ( isset( $options['bound'] ) ) {
|
30 |
+
$time_start = AB_DateTimeUtils::timeToSeconds( $options['bound'][0] );
|
31 |
+
$time_end = AB_DateTimeUtils::timeToSeconds( $options['bound'][1] );
|
32 |
+
} else {
|
33 |
+
$time_start = AB_StaffScheduleItem::WORKING_START_TIME;
|
34 |
+
$time_end = AB_StaffScheduleItem::WORKING_END_TIME;
|
35 |
+
}
|
36 |
+
if ( $options['type'] == 'from' ) {
|
37 |
+
$time_end -= $ts_length; // Exclude last slot.
|
38 |
+
} elseif ( $options['type'] == 'to' ) {
|
39 |
+
$time_end *= 2; // Create slots for 2 days.
|
40 |
+
}
|
41 |
|
42 |
// Run the loop.
|
43 |
+
while ( $time_start <= $time_end ) {
|
44 |
+
$this->values[ AB_DateTimeUtils::buildTimeString( $time_start ) ] = AB_DateTimeUtils::formatTime( $time_start );
|
45 |
+
$time_start += $ts_length;
|
46 |
}
|
|
|
47 |
}
|
48 |
|
49 |
/**
|
55 |
*
|
56 |
* @return string
|
57 |
*/
|
58 |
+
public function render( $name, $value = null, array $attributes = array() )
|
59 |
+
{
|
60 |
+
$options = '';
|
61 |
$attributes_str = '';
|
62 |
+
$exist_slot = false;
|
63 |
foreach ( $this->values as $option_value => $option_text ) {
|
64 |
+
if ( $exist_slot === false ) {
|
65 |
+
if ( $value == $option_value ) {
|
66 |
+
$exist_slot = true;
|
67 |
+
} elseif ( $value < $option_value ) {
|
68 |
+
$options .= sprintf(
|
69 |
+
'<option value="%s" selected="selected">%s</option>',
|
70 |
+
$value,
|
71 |
+
AB_DateTimeUtils::formatTime( $value )
|
72 |
+
);
|
73 |
+
$exist_slot = true;
|
74 |
+
}
|
75 |
+
}
|
76 |
+
$options .= sprintf(
|
77 |
'<option value="%s"%s>%s</option>',
|
78 |
$option_value,
|
79 |
+
selected( $value, $option_value, false ),
|
80 |
$option_text
|
81 |
);
|
82 |
}
|
84 |
$attributes_str .= sprintf( ' %s="%s"', $attr_name, $attr_value );
|
85 |
}
|
86 |
|
87 |
+
return sprintf( '<select name="%s" data-default_value="%s"%s>%s</select>', $name, $value, $attributes_str, $options );
|
88 |
}
|
89 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
}
|
backend/modules/staff/resources/css/staff.css
CHANGED
@@ -1,27 +1,56 @@
|
|
1 |
#ab-staff-schedule > table { width: 100% }
|
2 |
-
#ab-staff-schedule .staff-schedule-item-row > td { padding: 10px
|
3 |
#ab-staff-schedule .staff-schedule-item-row.ab-last-row > td { border: 0; }
|
4 |
#ab-staff-schedule .staff-schedule-item-row > td.first { width: 115px }
|
5 |
#ab-staff-schedule .staff-schedule-item-row td.add-break { width: 80px }
|
6 |
-
#ab-staff-schedule .staff-schedule-item-row td.working-intervals {
|
7 |
-
#ab-staff-schedule .staff-schedule-item-row .break-interval-wrapper {
|
8 |
-
#ab-staff-schedule .staff-schedule-item-row .break-interval-wrapper img {
|
9 |
-
border: 0 none;
|
10 |
-
cursor: pointer;
|
11 |
-
display: block;
|
12 |
-
float: left;
|
13 |
-
margin-left: 5px;
|
14 |
-
margin-top: 2px;
|
15 |
-
width: 12px;
|
16 |
-
}
|
17 |
#ab-staff-schedule .staff-schedule-item-row .breaks-list { width: 100% }
|
18 |
#ab-staff-schedule .staff-schedule-item-row .breaks-list .breaks-list-label { width: 60px }
|
19 |
#ab-staff-schedule .staff-schedule-item-row .ab-popup-wrapper .error { padding: 3px; margin: 5px; }
|
20 |
-
#ab-staff-schedule .staff-schedule-item-row .breaks-list .ab-popup-wrapper {
|
|
|
|
|
|
|
|
|
21 |
#ab-staff-schedule .error { margin: 0 }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
#ab-staff-list { margin-left: 0; }
|
23 |
-
#ab-
|
24 |
-
|
25 |
-
.
|
26 |
-
|
27 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
#ab-staff-schedule > table { width: 100% }
|
2 |
+
#ab-staff-schedule .staff-schedule-item-row > td { padding: 10px 5px; border-bottom: 1px solid #DDDDDD; }
|
3 |
#ab-staff-schedule .staff-schedule-item-row.ab-last-row > td { border: 0; }
|
4 |
#ab-staff-schedule .staff-schedule-item-row > td.first { width: 115px }
|
5 |
#ab-staff-schedule .staff-schedule-item-row td.add-break { width: 80px }
|
6 |
+
#ab-staff-schedule .staff-schedule-item-row td.working-intervals { white-space: nowrap; }
|
7 |
+
#ab-staff-schedule .staff-schedule-item-row .break-interval-wrapper { white-space: nowrap; }
|
8 |
+
#ab-staff-schedule .staff-schedule-item-row .break-interval-wrapper img { border: 0 none; cursor: pointer; display: inline-block; margin-left: 5px; margin-top: 2px; width: 12px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
#ab-staff-schedule .staff-schedule-item-row .breaks-list { width: 100% }
|
10 |
#ab-staff-schedule .staff-schedule-item-row .breaks-list .breaks-list-label { width: 60px }
|
11 |
#ab-staff-schedule .staff-schedule-item-row .ab-popup-wrapper .error { padding: 3px; margin: 5px; }
|
12 |
+
#ab-staff-schedule .staff-schedule-item-row .breaks-list .ab-popup-wrapper { margin-left: 5px; display: inline-block; }
|
13 |
+
#ab-staff-schedule .staff-schedule-item-row .working-start,
|
14 |
+
#ab-staff-schedule .staff-schedule-item-row .working-end { width: 90px!important; margin-bottom: 0; font-size: 13px; }
|
15 |
+
#ab-staff-schedule .staff-schedule-item-row .break-end,
|
16 |
+
#ab-staff-schedule .staff-schedule-item-row .break-start { width: auto; margin-bottom: 0; }
|
17 |
#ab-staff-schedule .error { margin: 0 }
|
18 |
+
|
19 |
+
#ab-edit-staff .ab-staff-tab-content { position: relative; }
|
20 |
+
.ab-nav-head { overflow: hidden; position: relative; margin-bottom: 20px; }
|
21 |
+
.ab-nav-head h2 { margin: 0; padding-right: 20px; }
|
22 |
+
.tabbable .tab-content .tab-pane { padding-top: 15px; }
|
23 |
+
|
24 |
+
#ab-staff-services ul ul li { margin-left: 20px; }
|
25 |
+
#ab-staff-services ul ul li.ab-services-category { margin: 25px 0px 15px 20px; position: relative; }
|
26 |
+
#ab-staff-services ul .ab-title-service { position: absolute; right: 0px; top: 1px; }
|
27 |
+
#ab-staff-services ul .ab-title-service > div { display: inline-block; width: 60px; text-align: center; }
|
28 |
+
#ab-staff-services ul .ab-title-service > div:first-child { margin-right: 5px; }
|
29 |
+
#ab-staff-services ul ul li ul li { margin-left: 20px; overflow: hidden; }
|
30 |
+
#ab-staff-services ul ul li ul li .ab-price { width: 70px; margin: 0 0 0 5px; text-align: right; height: 30px!important; }
|
31 |
+
#ab-staff-services ul ul li ul li .ab-list-title { margin: 5px 5px 0 0; }
|
32 |
+
#ab-staff-services { max-width: 590px; }
|
33 |
+
#ab-staff-services #ajax-send-service { margin-left: 40px; }
|
34 |
+
|
35 |
#ab-staff-list { margin-left: 0; }
|
36 |
+
#ab-staff-list .ab-staff-member .ab-avatar { max-width: 35px; max-height: 35px; margin-right: 10px; }
|
37 |
+
#ab-staff-list .ab-staff-member { padding: 5px; padding-left: 25px; margin: 3px 0; overflow: hidden; cursor: pointer; position: relative; border-radius: 5px; }
|
38 |
+
#ab-staff-list .ab-staff-member .ab-handle { position: absolute; left: 5px; top: 50%; cursor: move; margin-top: -10px; }
|
39 |
+
#ab-staff-list .ab-staff-member:hover,
|
40 |
+
#ab-staff-list .ab-staff-member.ab-active { background: #d6d6d6; }
|
41 |
+
|
42 |
+
#ab-staff-details-container .ab-staff-form .control-label { text-align: left!important; }
|
43 |
+
.ab-staff-form { max-width: 450px; }
|
44 |
+
|
45 |
+
.ab-calendar-tabs .ab-text-align,
|
46 |
+
.ab-left-bar #ab-staff-list .ab-staff-member .ab-text-align { height: 35px; display: table-cell; vertical-align: middle; }
|
47 |
+
|
48 |
+
/* media query */
|
49 |
+
@media screen and (max-width: 782px) {
|
50 |
+
.ab-nav-tabs li a {
|
51 |
+
padding: 5px 10px;
|
52 |
+
}
|
53 |
+
.ab-nav-head {
|
54 |
+
margin-top: 20px;
|
55 |
+
}
|
56 |
+
}
|
backend/modules/staff/resources/js/staff.js
CHANGED
@@ -1,27 +1,33 @@
|
|
1 |
jQuery(function($) {
|
2 |
|
3 |
var $name_input = $('#ab-newstaff-fullname'),
|
|
|
4 |
$list_item_number = $('#ab-list-item-number'),
|
5 |
$wp_user_select = $('#ab-newstaff-wpuser'),
|
|
|
6 |
$staff_member = $('.ab-staff-member'),
|
7 |
$edit_form = $('#ab-edit-staff-member'),
|
8 |
$new_form = $('#ab-new-satff');
|
9 |
|
|
|
|
|
|
|
|
|
10 |
// Saves new staff form
|
11 |
-
$('#ab-save-newstaff').
|
12 |
-
|
13 |
});
|
14 |
|
15 |
// Save new staff on enter press
|
16 |
-
$name_input.
|
17 |
var code = (e.keyCode ? e.keyCode : e.which);
|
18 |
if (code == 13) {
|
19 |
-
|
20 |
}
|
21 |
});
|
22 |
|
23 |
// Close new staff form on esc
|
24 |
-
$new_form.
|
25 |
var code = (e.keyCode ? e.keyCode : e.which);
|
26 |
if (code == 27) {
|
27 |
$('.ab-popup-wrapper').ab_popup('close');
|
@@ -35,51 +41,57 @@ jQuery(function($) {
|
|
35 |
|
36 |
var staff_id = $(this).data('staff-id');
|
37 |
var active_tab_id = $('ul.nav li.active a').attr('id');
|
|
|
38 |
$.get(ajaxurl, { action: 'ab_edit_staff', id: staff_id }, function (response) {
|
39 |
$edit_form.html(response);
|
40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
// Deletes staff avatar
|
42 |
-
$('#ab-delete-avatar').
|
43 |
$.post(ajaxurl, { action: 'ab_delete_staff_avatar', id: staff_id }, function () {
|
44 |
$('#ab-staff-avatar-image', $edit_form).remove();
|
45 |
});
|
46 |
});
|
47 |
|
48 |
-
$('#ab-update-staff').
|
49 |
if (!validateForm($edit_form)) {
|
50 |
e.preventDefault(e);
|
51 |
e.stopPropagation(e);
|
|
|
|
|
52 |
}
|
53 |
});
|
54 |
|
55 |
-
$('#ab-staff-wpuser').
|
56 |
if ($(this).val()) {
|
57 |
$('#ab-staff-full-name').val($(this).find(':selected').text());
|
58 |
$('#ab-staff-email').val($(this).find(':selected').data('email'));
|
59 |
}
|
60 |
});
|
61 |
|
62 |
-
helpInit();
|
63 |
-
|
64 |
-
var service_container = $('#ab-staff-services-container'),
|
65 |
-
details_container = $('#ab-staff-details-container'),
|
66 |
-
schedule_container = $('#ab-staff-schedule-container'),
|
67 |
-
holidays_container = $('#ab-staff-holidays-container'),
|
68 |
-
$schedule_form,
|
69 |
-
services_form,
|
70 |
-
tabs = $('.ab-list-link', $edit_form);
|
71 |
-
|
72 |
// Opens services tab
|
73 |
-
$('#ab-staff-services-tab').
|
74 |
activateTab.call($(this));
|
75 |
service_container.show();
|
76 |
|
77 |
// Loads services form
|
78 |
if (!service_container.children().length) {
|
|
|
79 |
$.post(ajaxurl, { action: 'ab_staff_services', id: staff_id }, function (response) {
|
80 |
service_container.html(response);
|
81 |
services_form = $('form', service_container);
|
82 |
-
|
83 |
var auto_tick_checkboxes = function() {
|
84 |
// Handle 'select category' checkbox.
|
85 |
$('.ab-services-category .ab-category-checkbox').each(function() {
|
@@ -95,170 +107,199 @@ jQuery(function($) {
|
|
95 |
);
|
96 |
};
|
97 |
|
98 |
-
// Select all services related to
|
99 |
$('.ab-category-checkbox', services_form).bind('click', function () {
|
100 |
-
$('.ab-category-services .ab-category-' + $(this).data('category-id')).
|
101 |
auto_tick_checkboxes();
|
102 |
});
|
103 |
|
104 |
-
//
|
105 |
-
$('#ab-all-services').
|
106 |
-
$('.ab-service-checkbox', services_form).
|
107 |
-
$('.ab-category-checkbox').
|
108 |
});
|
109 |
|
110 |
// Select service
|
111 |
-
$('.ab-service-checkbox', services_form).
|
112 |
var $this = $(this);
|
113 |
var $price = $this.closest('li').find('.ab-price');
|
114 |
$this.is(':checked') ? $price.removeAttr('disabled') : $price.attr('disabled', true);
|
115 |
auto_tick_checkboxes();
|
116 |
});
|
117 |
|
118 |
-
$('.ab-service-checkbox',services_form).
|
119 |
-
var $
|
120 |
-
$(this).is(':checked') ? $
|
121 |
});
|
122 |
|
123 |
// Saves services
|
124 |
-
$('#
|
125 |
-
|
|
|
|
|
126 |
$.post(ajaxurl, services_form.serialize(), function (response) {
|
127 |
-
|
|
|
|
|
|
|
128 |
});
|
129 |
});
|
130 |
|
|
|
|
|
|
|
|
|
|
|
131 |
auto_tick_checkboxes();
|
|
|
|
|
|
|
|
1 |
jQuery(function($) {
|
2 |
|
3 |
var $name_input = $('#ab-newstaff-fullname'),
|
4 |
+
$email_input = $('#ab-newstaff-email'),
|
5 |
$list_item_number = $('#ab-list-item-number'),
|
6 |
$wp_user_select = $('#ab-newstaff-wpuser'),
|
7 |
+
$staff_list = $('#ab-staff-list'),
|
8 |
$staff_member = $('.ab-staff-member'),
|
9 |
$edit_form = $('#ab-edit-staff-member'),
|
10 |
$new_form = $('#ab-new-satff');
|
11 |
|
12 |
+
function saveNewForm() {
|
13 |
+
$('#lite_notice').modal('show');
|
14 |
+
}
|
15 |
+
|
16 |
// Saves new staff form
|
17 |
+
$('#ab-save-newstaff').on('click', function () {
|
18 |
+
saveNewForm();
|
19 |
});
|
20 |
|
21 |
// Save new staff on enter press
|
22 |
+
$name_input.on('keypress', function (e) {
|
23 |
var code = (e.keyCode ? e.keyCode : e.which);
|
24 |
if (code == 13) {
|
25 |
+
saveNewForm();
|
26 |
}
|
27 |
});
|
28 |
|
29 |
// Close new staff form on esc
|
30 |
+
$new_form.on('keypress', function (e) {
|
31 |
var code = (e.keyCode ? e.keyCode : e.which);
|
32 |
if (code == 27) {
|
33 |
$('.ab-popup-wrapper').ab_popup('close');
|
41 |
|
42 |
var staff_id = $(this).data('staff-id');
|
43 |
var active_tab_id = $('ul.nav li.active a').attr('id');
|
44 |
+
$edit_form.html('<div class="loading-indicator"><span class="ab-loader"></span></div>');
|
45 |
$.get(ajaxurl, { action: 'ab_edit_staff', id: staff_id }, function (response) {
|
46 |
$edit_form.html(response);
|
47 |
|
48 |
+
var service_container = $('#ab-staff-services-container'),
|
49 |
+
loading_indicator = $('.loading-indicator'),
|
50 |
+
details_container = $('#ab-staff-details-container'),
|
51 |
+
schedule_container = $('#ab-staff-schedule-container'),
|
52 |
+
holidays_container = $('#ab-staff-holidays-container'),
|
53 |
+
$schedule_form,
|
54 |
+
services_form;
|
55 |
+
|
56 |
+
initHelps();
|
57 |
+
initNotices();
|
58 |
+
Ladda.bind( 'button[type=submit]' );
|
59 |
+
|
60 |
// Deletes staff avatar
|
61 |
+
$('#ab-delete-avatar').on('click', function () {
|
62 |
$.post(ajaxurl, { action: 'ab_delete_staff_avatar', id: staff_id }, function () {
|
63 |
$('#ab-staff-avatar-image', $edit_form).remove();
|
64 |
});
|
65 |
});
|
66 |
|
67 |
+
$('#ab-update-staff').on('click', function (e) {
|
68 |
if (!validateForm($edit_form)) {
|
69 |
e.preventDefault(e);
|
70 |
e.stopPropagation(e);
|
71 |
+
} else {
|
72 |
+
$edit_form.phone = $("#ab-staff-phone").intlTelInput('getNumber');
|
73 |
}
|
74 |
});
|
75 |
|
76 |
+
$('#ab-staff-wpuser').on('change', function () {
|
77 |
if ($(this).val()) {
|
78 |
$('#ab-staff-full-name').val($(this).find(':selected').text());
|
79 |
$('#ab-staff-email').val($(this).find(':selected').data('email'));
|
80 |
}
|
81 |
});
|
82 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
83 |
// Opens services tab
|
84 |
+
$('#ab-staff-services-tab').on('click', function () {
|
85 |
activateTab.call($(this));
|
86 |
service_container.show();
|
87 |
|
88 |
// Loads services form
|
89 |
if (!service_container.children().length) {
|
90 |
+
loading_indicator.show();
|
91 |
$.post(ajaxurl, { action: 'ab_staff_services', id: staff_id }, function (response) {
|
92 |
service_container.html(response);
|
93 |
services_form = $('form', service_container);
|
94 |
+
|
95 |
var auto_tick_checkboxes = function() {
|
96 |
// Handle 'select category' checkbox.
|
97 |
$('.ab-services-category .ab-category-checkbox').each(function() {
|
107 |
);
|
108 |
};
|
109 |
|
110 |
+
// Select all services related to chosen category
|
111 |
$('.ab-category-checkbox', services_form).bind('click', function () {
|
112 |
+
$('.ab-category-services .ab-category-' + $(this).data('category-id')).prop('checked', $(this).is(':checked')).change();
|
113 |
auto_tick_checkboxes();
|
114 |
});
|
115 |
|
116 |
+
// Check and uncheck all services
|
117 |
+
$('#ab-all-services').on('click', function () {
|
118 |
+
$('.ab-service-checkbox', services_form).prop('checked', $(this).is(':checked')).change();
|
119 |
+
$('.ab-category-checkbox').prop('checked', $(this).is(':checked'));
|
120 |
});
|
121 |
|
122 |
// Select service
|
123 |
+
$('.ab-service-checkbox', services_form).on('click', function () {
|
124 |
var $this = $(this);
|
125 |
var $price = $this.closest('li').find('.ab-price');
|
126 |
$this.is(':checked') ? $price.removeAttr('disabled') : $price.attr('disabled', true);
|
127 |
auto_tick_checkboxes();
|
128 |
});
|
129 |
|
130 |
+
$('.ab-service-checkbox',services_form).on('change', function(){
|
131 |
+
var $input_fields = $('.ab-price[name="price['+$(this).val()+']"]').add('.ab-price[name="capacity['+$(this).val()+']"]');
|
132 |
+
$(this).is(':checked') ? $input_fields.removeAttr('disabled') : $input_fields.attr('disabled', true);
|
133 |
});
|
134 |
|
135 |
// Saves services
|
136 |
+
$('#ajax-send-service').on('click', function (e) {
|
137 |
+
e.preventDefault();
|
138 |
+
var ladda = Ladda.create(this);
|
139 |
+
ladda.start();
|
140 |
$.post(ajaxurl, services_form.serialize(), function (response) {
|
141 |
+
ladda.stop();
|
142 |
+
if (response.success) {
|
143 |
+
showSuccessNotice();
|
144 |
+
}
|
145 |
});
|
146 |
});
|
147 |
|
148 |
+
// After reset auto tick group checkboxes.
|
149 |
+
$('button[type=reset]').on('click', function() {
|
150 |
+
setTimeout(auto_tick_checkboxes, 0);
|
151 |
+
});
|
152 |
+
|
153 |
auto_tick_checkboxes();
|
154 |
+
loading_indicator.hide();
|
155 |
+
|
156 |
+
services_form.find('input[name^="capacity"]').on('change', function(){
|
157 |
+
|