Version Description
Download this release
Release Info
Developer | theseed |
Plugin | All-in-One Event Calendar |
Version | 1.0 |
Comparing to | |
See all releases |
Version 1.0
- all-in-one-events-calendar.php +215 -0
- app/controller/class-ai1ec-app-controller.php +385 -0
- app/controller/class-ai1ec-calendar-controller.php +484 -0
- app/controller/class-ai1ec-events-controller.php +790 -0
- app/controller/class-ai1ec-exporter-controller.php +82 -0
- app/controller/class-ai1ec-importer-controller.php +201 -0
- app/controller/class-ai1ec-settings-controller.php +325 -0
- app/exception/class-ai1ec-event-not-found.php +18 -0
- app/exception/class-ai1ec-file-not-found.php +18 -0
- app/exception/class-ai1ec-file-not-provided.php +18 -0
- app/exception/class-ai1ec-invalid-argument.php +18 -0
- app/helper/class-ai1ec-app-helper.php +636 -0
- app/helper/class-ai1ec-calendar-helper.php +542 -0
- app/helper/class-ai1ec-events-helper.php +895 -0
- app/helper/class-ai1ec-exporter-helper.php +130 -0
- app/helper/class-ai1ec-importer-helper.php +233 -0
- app/helper/class-ai1ec-settings-helper.php +329 -0
- app/helper/class-ai1ec-view-helper.php +182 -0
- app/model/class-ai1ec-event.php +794 -0
- app/model/class-ai1ec-exporter.php +29 -0
- app/model/class-ai1ec-importer.php +30 -0
- app/model/class-ai1ec-settings.php +288 -0
- app/view/admin_notices.php +3 -0
- app/view/agenda.php +119 -0
- app/view/box_event_contact.php +35 -0
- app/view/box_event_cost.php +15 -0
- app/view/box_event_location.php +42 -0
- app/view/box_eventbrite.php +116 -0
- app/view/box_general_settings.php +37 -0
- app/view/box_ics_import_settings.php +26 -0
- app/view/box_publish_button.php +5 -0
- app/view/box_the_seed_studio.php +41 -0
- app/view/box_time_and_date.php +83 -0
- app/view/calendar.php +109 -0
- app/view/donate_button.php +6 -0
- app/view/event-excerpt.php +9 -0
- app/view/event-map.php +8 -0
- app/view/event-multi.php +56 -0
- app/view/event-single-footer.php +13 -0
- app/view/event-single.php +63 -0
- app/view/event_categories-color_picker.php +27 -0
- app/view/feed_row.php +23 -0
- app/view/import.php +14 -0
- app/view/month.php +84 -0
- app/view/save_successful.php +7 -0
- app/view/settings.php +24 -0
- app/view/subscription_button.php +6 -0
- css/add_new_event.css +1 -0
- css/calendar.css +1 -0
- css/colorpicker.css +1 -0
- css/event.css +1 -0
- css/general.css +1 -0
- css/jquery.autocomplete.css +1 -0
- css/selector.css +1 -0
- css/settings.css +1 -0
- img/agenda-view.png +0 -0
- img/ajax-loader.gif +0 -0
- img/blank.gif +0 -0
- img/color-picker.png +0 -0
- img/colorpicker_background.png +0 -0
- img/colorpicker_hex.png +0 -0
- img/colorpicker_hsb_b.png +0 -0
- img/colorpicker_hsb_h.png +0 -0
- img/colorpicker_hsb_s.png +0 -0
- img/colorpicker_indic.gif +0 -0
- img/colorpicker_overlay.png +0 -0
- img/colorpicker_rgb_b.png +0 -0
- img/colorpicker_rgb_g.png +0 -0
- img/colorpicker_rgb_r.png +0 -0
- img/colorpicker_select.gif +0 -0
- img/colorpicker_submit.png +0 -0
- img/custom_background.png +0 -0
- img/custom_hex.png +0 -0
- img/custom_hsb_b.png +0 -0
- img/custom_hsb_h.png +0 -0
- img/custom_hsb_s.png +0 -0
- img/custom_indic.gif +0 -0
- img/custom_rgb_b.png +0 -0
- img/custom_rgb_g.png +0 -0
- img/custom_rgb_r.png +0 -0
- img/custom_submit.png +0 -0
- img/google-calendar.png +0 -0
- img/ics-icon.png +0 -0
- img/indicator.gif +0 -0
- img/month-view.png +0 -0
- img/slider.png +0 -0
- js/add_new_event.js +1 -0
- js/calendar.js +1 -0
- js/colorpicker.js +1 -0
- js/element-selector.js +1 -0
- js/event.js +1 -0
- js/geo_autocomplete.js +1 -0
- js/jquery.autocomplete_geomod.js +1 -0
- js/jquery.calendrical.js +1 -0
- js/jquery.inputdate.js +1 -0
- js/jquery.scrollTo-min.js +1 -0
- js/jquery.timespan.js +1 -0
- js/settings.js +1 -0
- lib/SG_iCal.php +126 -0
- lib/blocks/SG_iCal_VCalendar.php +64 -0
- lib/blocks/SG_iCal_VEvent.php +292 -0
- lib/blocks/SG_iCal_VTimeZone.php +95 -0
- lib/helpers/SG_iCal_Duration.php +56 -0
- lib/helpers/SG_iCal_Factory.php +42 -0
- lib/helpers/SG_iCal_Freq.php +554 -0
- lib/helpers/SG_iCal_Line.php +165 -0
- lib/helpers/SG_iCal_Parser.php +197 -0
- lib/helpers/SG_iCal_Query.php +84 -0
- lib/helpers/SG_iCal_Recurrence.php +221 -0
- lib/iCalUtilityFunctions.class.php +1505 -0
- lib/iCalcreator.class.php +6897 -0
- lib/lgpl.txt +504 -0
- readme.txt +69 -0
- screenshot-1.png +0 -0
- screenshot-10.png +0 -0
- screenshot-2.png +0 -0
- screenshot-3.png +0 -0
- screenshot-4.png +0 -0
- screenshot-5.png +0 -0
- screenshot-6.png +0 -0
- screenshot-7.png +0 -0
- screenshot-8.png +0 -0
- screenshot-9.png +0 -0
all-in-one-events-calendar.php
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: All-in-One Events Calendar Plugin
|
4 |
+
* Plugin URI: http://theseedstudio.com/software/all-in-one-events-calendar-wordpress/
|
5 |
+
* Description: An events calendar system with month and agenda calendar views, color-coded categories, recurring events, and import/export of iCalendar (.ics) feeds.
|
6 |
+
* Version: 1.0
|
7 |
+
* Author: The Seed Studio
|
8 |
+
* Author URI: http://theseedstudio.com/
|
9 |
+
*/
|
10 |
+
@set_time_limit( 0 );
|
11 |
+
@ini_set( "memory_limit", "256M" );
|
12 |
+
@ini_set( "max_input_time", "-1" );
|
13 |
+
|
14 |
+
// ===============
|
15 |
+
// = Plugin Name =
|
16 |
+
// ===============
|
17 |
+
define( 'AI1EC_PLUGIN_NAME', basename( dirname( __FILE__ ) ) );
|
18 |
+
|
19 |
+
// ====================
|
20 |
+
// = Database Version =
|
21 |
+
// ====================
|
22 |
+
define( 'AI1EC_DB_VERSION', 107 );
|
23 |
+
|
24 |
+
// ================
|
25 |
+
// = Cron Version =
|
26 |
+
// ================
|
27 |
+
define( 'AI1EC_CRON_VERSION', 102 );
|
28 |
+
|
29 |
+
// ===============
|
30 |
+
// = Plugin Path =
|
31 |
+
// ===============
|
32 |
+
define( 'AI1EC_PATH', dirname( __FILE__ ) );
|
33 |
+
|
34 |
+
// ===============
|
35 |
+
// = Images Path =
|
36 |
+
// ===============
|
37 |
+
define( 'AI1EC_IMAGE_PATH', AI1EC_PATH . '/img' );
|
38 |
+
|
39 |
+
// ============
|
40 |
+
// = CSS Path =
|
41 |
+
// ============
|
42 |
+
define( 'AI1EC_CSS_PATH', AI1EC_PATH . '/css' );
|
43 |
+
|
44 |
+
// ===========
|
45 |
+
// = JS Path =
|
46 |
+
// ===========
|
47 |
+
define( 'AI1EC_JS_PATH', AI1EC_PATH . '/js' );
|
48 |
+
|
49 |
+
// ============
|
50 |
+
// = Lib Path =
|
51 |
+
// ============
|
52 |
+
define( 'AI1EC_LIB_PATH', AI1EC_PATH . '/lib' );
|
53 |
+
|
54 |
+
// ============
|
55 |
+
// = App Path =
|
56 |
+
// ============
|
57 |
+
define( 'AI1EC_APP_PATH', AI1EC_PATH . '/app' );
|
58 |
+
|
59 |
+
// ===================
|
60 |
+
// = Controller Path =
|
61 |
+
// ===================
|
62 |
+
define( 'AI1EC_CONTROLLER_PATH', AI1EC_APP_PATH . '/controller' );
|
63 |
+
|
64 |
+
// ==============
|
65 |
+
// = Model Path =
|
66 |
+
// ==============
|
67 |
+
define( 'AI1EC_MODEL_PATH', AI1EC_APP_PATH . '/model' );
|
68 |
+
|
69 |
+
// =============
|
70 |
+
// = View Path =
|
71 |
+
// =============
|
72 |
+
define( 'AI1EC_VIEW_PATH', AI1EC_APP_PATH . '/view' );
|
73 |
+
|
74 |
+
// ===============
|
75 |
+
// = Helper Path =
|
76 |
+
// ===============
|
77 |
+
define( 'AI1EC_HELPER_PATH', AI1EC_APP_PATH . '/helper' );
|
78 |
+
|
79 |
+
// ==================
|
80 |
+
// = Exception Path =
|
81 |
+
// ==================
|
82 |
+
define( 'AI1EC_EXCEPTION_PATH', AI1EC_APP_PATH . '/exception' );
|
83 |
+
|
84 |
+
// ==============
|
85 |
+
// = Plugin Url =
|
86 |
+
// ==============
|
87 |
+
define( 'AI1EC_URL', plugins_url( '', __FILE__ ) );
|
88 |
+
|
89 |
+
// ==============
|
90 |
+
// = Images URL =
|
91 |
+
// ==============
|
92 |
+
define( 'AI1EC_IMAGE_URL', AI1EC_URL . '/img' );
|
93 |
+
|
94 |
+
// ===========
|
95 |
+
// = CSS URL =
|
96 |
+
// ===========
|
97 |
+
define( 'AI1EC_CSS_URL', AI1EC_URL . '/css' );
|
98 |
+
|
99 |
+
// ==========
|
100 |
+
// = JS URL =
|
101 |
+
// ==========
|
102 |
+
define( 'AI1EC_JS_URL', AI1EC_URL . '/js' );
|
103 |
+
|
104 |
+
// =============
|
105 |
+
// = POST TYPE =
|
106 |
+
// =============
|
107 |
+
define( 'AI1EC_POST_TYPE', 'ai1ec_event' );
|
108 |
+
|
109 |
+
// ======================================
|
110 |
+
// = FAKE CATEGORY ID FOR CALENDAR PAGE =
|
111 |
+
// ======================================
|
112 |
+
define( 'AI1EC_FAKE_CATEGORY_ID', -4113473042 ); // Numeric-only 1337-speak of AI1EC_CALENDAR - ID must be numeric
|
113 |
+
|
114 |
+
// ==============
|
115 |
+
// = SCRIPT URL =
|
116 |
+
// ==============
|
117 |
+
$ai1ec_script_url = get_option( 'home' ) . '/?plugin=' . AI1EC_PLUGIN_NAME;
|
118 |
+
define( 'AI1EC_SCRIPT_URL', $ai1ec_script_url );
|
119 |
+
|
120 |
+
// ==================================================
|
121 |
+
// = Convert https/http to ical in AI1EC_SCRIPT_URL =
|
122 |
+
// ==================================================
|
123 |
+
$tmp = '';
|
124 |
+
if( strpos( AI1EC_SCRIPT_URL, 'https' ) === false ) {
|
125 |
+
$tmp = str_replace( 'http', 'webcal', AI1EC_SCRIPT_URL );
|
126 |
+
} else {
|
127 |
+
$tmp = str_replace( 'https', 'webcal', AI1EC_SCRIPT_URL );
|
128 |
+
}
|
129 |
+
|
130 |
+
// ==============
|
131 |
+
// = EXPORT URL =
|
132 |
+
// ==============
|
133 |
+
define( 'AI1EC_EXPORT_URL', $tmp . '&controller=ai1ec_exporter_controller&action=export_events' );
|
134 |
+
|
135 |
+
// ====================================
|
136 |
+
// = Include iCal parsers and helpers =
|
137 |
+
// ====================================
|
138 |
+
require_once( AI1EC_LIB_PATH . '/iCalcreator.class.php' );
|
139 |
+
require_once( AI1EC_LIB_PATH . '/iCalUtilityFunctions.class.php' );
|
140 |
+
require_once( AI1EC_LIB_PATH . '/SG_iCal.php' );
|
141 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Line.php' );
|
142 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Duration.php' );
|
143 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Freq.php' );
|
144 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Recurrence.php' );
|
145 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Parser.php' );
|
146 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Query.php' );
|
147 |
+
require_once( AI1EC_LIB_PATH . '/helpers/SG_iCal_Factory.php' );
|
148 |
+
|
149 |
+
// ===============================
|
150 |
+
// = The autoload function =
|
151 |
+
// ===============================
|
152 |
+
function ai1ec_autoload( $class_name )
|
153 |
+
{
|
154 |
+
// Convert class name to filename format.
|
155 |
+
$class_name = strtr( strtolower( $class_name ), '_', '-' );
|
156 |
+
|
157 |
+
// Search each path for the class.
|
158 |
+
foreach( array( AI1EC_CONTROLLER_PATH, AI1EC_MODEL_PATH, AI1EC_HELPER_PATH, AI1EC_EXCEPTION_PATH, AI1EC_LIB_PATH )
|
159 |
+
as $path )
|
160 |
+
{
|
161 |
+
if( file_exists( "$path/class-$class_name.php" ) )
|
162 |
+
require_once( "$path/class-$class_name.php" );
|
163 |
+
}
|
164 |
+
}
|
165 |
+
spl_autoload_register( 'ai1ec_autoload' );
|
166 |
+
|
167 |
+
// ===============================
|
168 |
+
// = Initialize and setup MODELS =
|
169 |
+
// ===============================
|
170 |
+
global $ai1ec_settings;
|
171 |
+
|
172 |
+
$ai1ec_settings = Ai1ec_Settings::get_instance();
|
173 |
+
|
174 |
+
|
175 |
+
// ================================
|
176 |
+
// = Initialize and setup HELPERS =
|
177 |
+
// ================================
|
178 |
+
global $ai1ec_view_helper,
|
179 |
+
$ai1ec_settings_helper,
|
180 |
+
$ai1ec_calendar_helper,
|
181 |
+
$ai1ec_app_helper,
|
182 |
+
$ai1ec_events_helper,
|
183 |
+
$ai1ec_importer_helper,
|
184 |
+
$ai1ec_exporter_helper;
|
185 |
+
|
186 |
+
$ai1ec_view_helper = Ai1ec_View_Helper::get_instance();
|
187 |
+
$ai1ec_settings_helper = Ai1ec_Settings_Helper::get_instance();
|
188 |
+
$ai1ec_calendar_helper = Ai1ec_Calendar_Helper::get_instance();
|
189 |
+
$ai1ec_app_helper = Ai1ec_App_Helper::get_instance();
|
190 |
+
$ai1ec_events_helper = Ai1ec_Events_Helper::get_instance();
|
191 |
+
$ai1ec_importer_helper = Ai1ec_Importer_Helper::get_instance();
|
192 |
+
$ai1ec_exporter_helper = Ai1ec_Exporter_Helper::get_instance();
|
193 |
+
|
194 |
+
|
195 |
+
// ====================================
|
196 |
+
// = Initialize and setup CONTROLLERS =
|
197 |
+
// ====================================
|
198 |
+
global $ai1ec_app_controller,
|
199 |
+
$ai1ec_settings_controller,
|
200 |
+
$ai1ec_events_controller,
|
201 |
+
$ai1ec_calendar_controller,
|
202 |
+
$ai1ec_importer_controller,
|
203 |
+
$ai1ec_exporter_controller;
|
204 |
+
|
205 |
+
$ai1ec_app_controller = Ai1ec_App_Controller::get_instance();
|
206 |
+
$ai1ec_settings_controller = Ai1ec_Settings_Controller::get_instance();
|
207 |
+
$ai1ec_events_controller = Ai1ec_Events_Controller::get_instance();
|
208 |
+
$ai1ec_calendar_controller = Ai1ec_Calendar_Controller::get_instance();
|
209 |
+
$ai1ec_importer_controller = Ai1ec_Importer_Controller::get_instance();
|
210 |
+
$ai1ec_exporter_controller = Ai1ec_Exporter_Controller::get_instance();
|
211 |
+
|
212 |
+
// ===================
|
213 |
+
// = Call admin menu =
|
214 |
+
// ===================
|
215 |
+
$ai1ec_app_controller->setup_menus();
|
app/controller/class-ai1ec-app-controller.php
ADDED
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-app-controller.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Ai1ec_App_Controller class
|
12 |
+
*
|
13 |
+
* @package Controllers
|
14 |
+
* @author The Seed Studio
|
15 |
+
**/
|
16 |
+
class Ai1ec_App_Controller {
|
17 |
+
/**
|
18 |
+
* _instance class variable
|
19 |
+
*
|
20 |
+
* Class instance
|
21 |
+
*
|
22 |
+
* @var null | object
|
23 |
+
**/
|
24 |
+
private static $_instance = NULL;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* page_content class variable
|
28 |
+
*
|
29 |
+
* String storing page content for output by the_content()
|
30 |
+
*
|
31 |
+
* @var null | string
|
32 |
+
**/
|
33 |
+
private $page_content = NULL;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* get_instance function
|
37 |
+
*
|
38 |
+
* Return singleton instance
|
39 |
+
*
|
40 |
+
* @return object
|
41 |
+
**/
|
42 |
+
static function get_instance() {
|
43 |
+
if( self::$_instance === NULL ) {
|
44 |
+
self::$_instance = new self();
|
45 |
+
}
|
46 |
+
|
47 |
+
return self::$_instance;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Constructor
|
52 |
+
*
|
53 |
+
* Default constructor - application initialization
|
54 |
+
**/
|
55 |
+
private function __construct()
|
56 |
+
{
|
57 |
+
global $wpdb,
|
58 |
+
$ai1ec_app_helper,
|
59 |
+
$ai1ec_events_controller,
|
60 |
+
$ai1ec_importer_controller,
|
61 |
+
$ai1ec_settings_controller,
|
62 |
+
$ai1ec_settings;
|
63 |
+
|
64 |
+
// register_activation_hook
|
65 |
+
register_activation_hook( AI1EC_PLUGIN_NAME . '/' . AI1EC_PLUGIN_NAME . '.php', array( &$this, 'rewrite_flush' ) );
|
66 |
+
|
67 |
+
// Configure MySQL to operate in GMT time
|
68 |
+
$wpdb->query( "SET time_zone = '+0:00'" );
|
69 |
+
|
70 |
+
// Install/update database schema as necessary
|
71 |
+
$this->install_schema();
|
72 |
+
|
73 |
+
// Install/update cron as necessary
|
74 |
+
$this->install_cron();
|
75 |
+
|
76 |
+
// ===========
|
77 |
+
// = ACTIONS =
|
78 |
+
// ===========
|
79 |
+
// Create custom post type
|
80 |
+
add_action( 'init', array( &$ai1ec_app_helper, 'create_post_type' ) );
|
81 |
+
// Handle ICS export requests
|
82 |
+
add_action( 'init', array( &$this, 'parse_standalone_request' ) );
|
83 |
+
// General initialization
|
84 |
+
add_action( 'init', array( &$ai1ec_events_controller, 'init' ) );
|
85 |
+
// Register The Events Calendar importer
|
86 |
+
add_action( 'admin_init', array( &$ai1ec_importer_controller, 'register_importer' ) );
|
87 |
+
// add content for our custom columns
|
88 |
+
add_action( "manage_posts_custom_column", array( &$ai1ec_app_helper, 'custom_columns' ), 10, 2 );
|
89 |
+
// Add filtering dropdowns for event categories and tags
|
90 |
+
add_action( 'restrict_manage_posts', array( &$ai1ec_app_helper, 'taxonomy_filter_restrict_manage_posts' ) );
|
91 |
+
// Trigger display of page in front-end depending on request
|
92 |
+
add_action( 'template_redirect', array( &$this, 'route_request' ) );
|
93 |
+
// Add meta boxes to event creation/edit form
|
94 |
+
add_action( 'add_meta_boxes', array( &$ai1ec_app_helper, 'add_meta_boxes' ) );
|
95 |
+
// Save event data when post is saved
|
96 |
+
add_action( 'save_post', array( &$ai1ec_events_controller, 'save_post' ) );
|
97 |
+
// Delete event data when post is deleted
|
98 |
+
add_action( 'delete_post', array( &$ai1ec_events_controller, 'delete_post' ) );
|
99 |
+
// cron job hook
|
100 |
+
add_action( 'ai1ec_cron', array( &$ai1ec_importer_controller, 'cron' ) );
|
101 |
+
add_action( 'events_categories_add_form_fields', array( &$ai1ec_events_controller, 'events_categories_add_form_fields' ) );
|
102 |
+
add_action( 'events_categories_edit_form_fields', array( &$ai1ec_events_controller, 'events_categories_edit_form_fields' ) );
|
103 |
+
add_action( 'created_events_categories', array( &$ai1ec_events_controller, 'created_events_categories' ) );
|
104 |
+
add_action( 'edited_events_categories', array( &$ai1ec_events_controller, 'edited_events_categories' ) );
|
105 |
+
add_action( 'admin_notices', array( &$ai1ec_app_helper, 'admin_notices' ) );
|
106 |
+
add_action( 'admin_enqueue_scripts', array( &$ai1ec_settings_controller, 'admin_enqueue_scripts' ) );
|
107 |
+
|
108 |
+
// ===========
|
109 |
+
// = FILTERS =
|
110 |
+
// ===========
|
111 |
+
add_filter( 'posts_orderby', array( &$ai1ec_app_helper, 'orderby' ), 10, 2 );
|
112 |
+
// add custom column names and change existing columns
|
113 |
+
add_filter( 'manage_ai1ec_event_posts_columns', array( &$ai1ec_app_helper, 'change_columns' ) );
|
114 |
+
// filter the post lists by custom filters
|
115 |
+
add_filter( 'parse_query', array( &$ai1ec_app_helper, 'taxonomy_filter_post_type_request' ) );
|
116 |
+
// Filter event post content, in single- and multi-post views
|
117 |
+
add_filter( 'the_content', array( &$ai1ec_events_controller, 'event_content' ) );
|
118 |
+
// Override excerpt filters for proper event display in excerpt form
|
119 |
+
add_filter( 'get_the_excerpt', array( &$ai1ec_events_controller, 'event_excerpt' ), 11 );
|
120 |
+
add_filter( 'the_excerpt', array( &$ai1ec_events_controller, 'event_excerpt_noautop' ), 11 );
|
121 |
+
remove_filter( 'the_excerpt', 'wpautop', 10 );
|
122 |
+
// Update event post update messages
|
123 |
+
add_filter( 'post_updated_messages', array( &$ai1ec_events_controller, 'post_updated_messages' ) );
|
124 |
+
// Sort the custom columns
|
125 |
+
add_filter( 'manage_edit-ai1ec_event_sortable_columns', array( &$ai1ec_app_helper, 'sortable_columns' ) );
|
126 |
+
add_filter( 'map_meta_cap', array( &$ai1ec_app_helper, 'map_meta_cap' ), 10, 4 );
|
127 |
+
// Inject event categories, only in front-end, depending on setting
|
128 |
+
if( $ai1ec_settings->inject_categories && ! is_admin() ) {
|
129 |
+
add_filter( 'get_terms', array( &$ai1ec_app_helper, 'inject_categories' ), 10, 3 );
|
130 |
+
add_filter( 'wp_list_categories', array( &$ai1ec_app_helper, 'selected_category_link' ), 10, 2 );
|
131 |
+
}
|
132 |
+
// Rewrite event category URLs to point to calendar page
|
133 |
+
add_filter( 'term_link', array( &$ai1ec_app_helper, 'calendar_term_link' ), 10, 3 );
|
134 |
+
|
135 |
+
// ========
|
136 |
+
// = AJAX =
|
137 |
+
// ========
|
138 |
+
// Add iCalendar feed
|
139 |
+
add_action( 'wp_ajax_ai1ec_add_ics', array( &$ai1ec_settings_controller, 'add_ics_feed' ) );
|
140 |
+
// Delete iCalendar feed
|
141 |
+
add_action( 'wp_ajax_ai1ec_delete_ics', array( &$ai1ec_settings_controller, 'delete_ics_feed' ) );
|
142 |
+
// Flush iCalendar feed
|
143 |
+
add_action( 'wp_ajax_ai1ec_flush_ics', array( &$ai1ec_settings_controller, 'flush_ics_feed' ) );
|
144 |
+
// Update iCalendar feed
|
145 |
+
add_action( 'wp_ajax_ai1ec_update_ics', array( &$ai1ec_settings_controller, 'update_ics_feed' ) );
|
146 |
+
}
|
147 |
+
|
148 |
+
/**
|
149 |
+
* rewrite_flush function
|
150 |
+
*
|
151 |
+
* Get permalinks to work when activating the plugin
|
152 |
+
*
|
153 |
+
* @return void
|
154 |
+
**/
|
155 |
+
function rewrite_flush() {
|
156 |
+
global $ai1ec_app_helper;
|
157 |
+
$ai1ec_app_helper->create_post_type();
|
158 |
+
flush_rewrite_rules( true );
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* install_schema function
|
163 |
+
*
|
164 |
+
* This function sets up the database, and upgrades it if it is out of date.
|
165 |
+
*
|
166 |
+
* @return void
|
167 |
+
**/
|
168 |
+
function install_schema() {
|
169 |
+
global $wpdb;
|
170 |
+
|
171 |
+
// If existing DB version is not consistent with current plugin's version,
|
172 |
+
// or does not exist, then create/update table structure using dbDelta().
|
173 |
+
if( get_option( 'ai1ec_db_version' ) != AI1EC_DB_VERSION )
|
174 |
+
{
|
175 |
+
// =======================
|
176 |
+
// = Create table events =
|
177 |
+
// =======================
|
178 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
179 |
+
$sql = "CREATE TABLE $table_name (
|
180 |
+
post_id bigint(20) NOT NULL,
|
181 |
+
start datetime NOT NULL,
|
182 |
+
end datetime,
|
183 |
+
allday tinyint(1) NOT NULL,
|
184 |
+
recurrence_rules longtext,
|
185 |
+
exception_rules longtext,
|
186 |
+
recurrence_dates longtext,
|
187 |
+
exception_dates longtext,
|
188 |
+
venue varchar(255),
|
189 |
+
country varchar(255),
|
190 |
+
address varchar(255),
|
191 |
+
city varchar(255),
|
192 |
+
province varchar(255),
|
193 |
+
postal_code varchar(32),
|
194 |
+
show_map tinyint(1),
|
195 |
+
contact_name varchar(255),
|
196 |
+
contact_phone varchar(32),
|
197 |
+
contact_email varchar(128),
|
198 |
+
cost varchar(255),
|
199 |
+
ical_feed_url varchar(255),
|
200 |
+
ical_source_url varchar(255),
|
201 |
+
ical_organizer varchar(255),
|
202 |
+
ical_contact varchar(255),
|
203 |
+
ical_uid varchar(255),
|
204 |
+
PRIMARY KEY (post_id)
|
205 |
+
) CHARACTER SET utf8;";
|
206 |
+
|
207 |
+
// ==========================
|
208 |
+
// = Create table instances =
|
209 |
+
// ==========================
|
210 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_instances';
|
211 |
+
$sql .= "CREATE TABLE $table_name (
|
212 |
+
id bigint(20) NOT NULL AUTO_INCREMENT,
|
213 |
+
post_id bigint(20) NOT NULL,
|
214 |
+
start datetime NOT NULL,
|
215 |
+
end datetime NOT NULL,
|
216 |
+
PRIMARY KEY (id)
|
217 |
+
) CHARACTER SET utf8;";
|
218 |
+
|
219 |
+
// ======================
|
220 |
+
// = Create table feeds =
|
221 |
+
// ======================
|
222 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
223 |
+
$sql .= "CREATE TABLE $table_name (
|
224 |
+
feed_id bigint(20) NOT NULL AUTO_INCREMENT,
|
225 |
+
feed_url varchar(255) NOT NULL,
|
226 |
+
feed_category bigint(20) NOT NULL,
|
227 |
+
feed_tags varchar(255) NOT NULL,
|
228 |
+
PRIMARY KEY (feed_id)
|
229 |
+
) CHARACTER SET utf8;";
|
230 |
+
|
231 |
+
// ================================
|
232 |
+
// = Create table category colors =
|
233 |
+
// ================================
|
234 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_category_colors';
|
235 |
+
$sql .= "CREATE TABLE $table_name (
|
236 |
+
term_id bigint(20) NOT NULL,
|
237 |
+
term_color varchar(255) NOT NULL,
|
238 |
+
PRIMARY KEY (term_id)
|
239 |
+
) CHARACTER SET utf8;";
|
240 |
+
|
241 |
+
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
|
242 |
+
dbDelta( $sql );
|
243 |
+
|
244 |
+
update_option( 'ai1ec_db_version', AI1EC_DB_VERSION );
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* install_cron function
|
250 |
+
*
|
251 |
+
* This function sets up the cron job for updating the events, and upgrades it if it is out of date.
|
252 |
+
*
|
253 |
+
* @return void
|
254 |
+
**/
|
255 |
+
function install_cron() {
|
256 |
+
// If existing CRON version is not consistent with current plugin's version,
|
257 |
+
// or does not exist, then create/update cron using
|
258 |
+
if( get_option( 'ai1ec_cron_version' ) != AI1EC_CRON_VERSION ) {
|
259 |
+
global $ai1ec_settings;
|
260 |
+
// delete our scheduled crons
|
261 |
+
wp_clear_scheduled_hook( 'ai1ec_cron' );
|
262 |
+
// set the new cron
|
263 |
+
wp_schedule_event( time(), $ai1ec_settings->cron_freq, 'ai1ec_cron' );
|
264 |
+
// update the cron version
|
265 |
+
update_option( 'ai1ec_cron_version', AI1EC_CRON_VERSION );
|
266 |
+
}
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* setup_menus function
|
271 |
+
* Adds the hook to admin_menu that is pointing to menu member function
|
272 |
+
*
|
273 |
+
* @return void
|
274 |
+
**/
|
275 |
+
function setup_menus() {
|
276 |
+
add_action( "admin_menu", array( &$this, "menu" ) );
|
277 |
+
}
|
278 |
+
|
279 |
+
/**
|
280 |
+
* menu function
|
281 |
+
* Display the admin menu items using the add_menu_page WP function.
|
282 |
+
*
|
283 |
+
* @return void
|
284 |
+
**/
|
285 |
+
function menu() {
|
286 |
+
global $ai1ec_settings_controller,
|
287 |
+
$ai1ec_settings_helper,
|
288 |
+
$ai1ec_settings;
|
289 |
+
|
290 |
+
// =================
|
291 |
+
// = Settings Page =
|
292 |
+
// =================
|
293 |
+
$ai1ec_settings->settings_page = add_submenu_page(
|
294 |
+
'edit.php?post_type=' . AI1EC_POST_TYPE,
|
295 |
+
__( 'Settings', AI1EC_PLUGIN_NAME ),
|
296 |
+
__( 'Settings', AI1EC_PLUGIN_NAME ),
|
297 |
+
'manage_options',
|
298 |
+
AI1EC_PLUGIN_NAME . "-settings",
|
299 |
+
array( &$ai1ec_settings_controller, "view" )
|
300 |
+
);
|
301 |
+
// Create a hook for adding meta boxes
|
302 |
+
add_action( "load-{$ai1ec_settings->settings_page}", array( &$ai1ec_settings_helper, 'add_meta_boxes') );
|
303 |
+
// Load the meta boxes
|
304 |
+
add_action( "load-{$ai1ec_settings->settings_page}", array( &$ai1ec_settings_controller, 'add_meta_boxes' ) );
|
305 |
+
// Use registered handlers to hook loading of styles/scripts
|
306 |
+
add_action( 'admin_print_styles-' . $ai1ec_settings->settings_page, array( &$ai1ec_settings_controller, 'admin_print_styles' ) );
|
307 |
+
add_action( 'admin_print_scripts-' . $ai1ec_settings->settings_page, array( &$ai1ec_settings_controller, 'admin_print_scripts' ) );
|
308 |
+
}
|
309 |
+
|
310 |
+
|
311 |
+
/**
|
312 |
+
* route_request function
|
313 |
+
*
|
314 |
+
* Determines if the page viewed should be handled by this plugin, and if so
|
315 |
+
* schedule new content to be displayed.
|
316 |
+
*
|
317 |
+
* @return void
|
318 |
+
**/
|
319 |
+
function route_request() {
|
320 |
+
global $ai1ec_settings,
|
321 |
+
$ai1ec_calendar_controller,
|
322 |
+
$ai1ec_events_controller;
|
323 |
+
|
324 |
+
// Find out if we're on the calendar page
|
325 |
+
if( is_page( $ai1ec_settings->calendar_page_id ) )
|
326 |
+
{
|
327 |
+
ob_start();
|
328 |
+
// Render view
|
329 |
+
$ai1ec_calendar_controller->view();
|
330 |
+
// Save page content to local variable
|
331 |
+
$this->page_content = ob_get_contents();
|
332 |
+
ob_end_clean();
|
333 |
+
|
334 |
+
// Replace page content
|
335 |
+
add_filter( 'the_content', array( &$this, 'append_content' ) );
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
/**
|
340 |
+
* parse_standalone_request function
|
341 |
+
*
|
342 |
+
* @return void
|
343 |
+
**/
|
344 |
+
function parse_standalone_request() {
|
345 |
+
global $ai1ec_exporter_controller,
|
346 |
+
$ai1ec_app_helper;
|
347 |
+
|
348 |
+
$plugin = $ai1ec_app_helper->get_param('plugin');
|
349 |
+
$action = $ai1ec_app_helper->get_param('action');
|
350 |
+
$controller = $ai1ec_app_helper->get_param('controller');
|
351 |
+
|
352 |
+
if( ! empty( $plugin ) && $plugin == AI1EC_PLUGIN_NAME && ! empty( $controller ) && ! empty( $action ) ) {
|
353 |
+
if( $controller == "ai1ec_exporter_controller" ) :
|
354 |
+
switch( $action ) :
|
355 |
+
case 'export_events':
|
356 |
+
$ai1ec_exporter_controller->export_events();
|
357 |
+
break;
|
358 |
+
endswitch;
|
359 |
+
endif; // ai1ec_exporter_controller
|
360 |
+
}
|
361 |
+
}
|
362 |
+
|
363 |
+
/**
|
364 |
+
* append_content function
|
365 |
+
*
|
366 |
+
* Append locally generated content to normal page content (if in the loop;
|
367 |
+
* don't want to do it for all instances of the_content() on the page!)
|
368 |
+
*
|
369 |
+
* @param string $content Post/Page content
|
370 |
+
* @return string Post/Page content
|
371 |
+
**/
|
372 |
+
function append_content( $content )
|
373 |
+
{
|
374 |
+
// Enclose entire content (including any admin-provided page content) in
|
375 |
+
// the calendar container div
|
376 |
+
if( in_the_loop() )
|
377 |
+
$content =
|
378 |
+
'<div id="ai1ec-container" class="ai1ec-container">' .
|
379 |
+
$content . $this->page_content .
|
380 |
+
'</div>';
|
381 |
+
|
382 |
+
return $content;
|
383 |
+
}
|
384 |
+
}
|
385 |
+
// END class
|
app/controller/class-ai1ec-calendar-controller.php
ADDED
@@ -0,0 +1,484 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-calendar-controller.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Calendar_Controller class
|
11 |
+
*
|
12 |
+
* @package Controllers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Calendar_Controller {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* request class variable
|
27 |
+
*
|
28 |
+
* Stores a custom $_REQUEST array for all calendar requests
|
29 |
+
*
|
30 |
+
* @var array
|
31 |
+
**/
|
32 |
+
private $request = array();
|
33 |
+
|
34 |
+
/**
|
35 |
+
* __construct function
|
36 |
+
*
|
37 |
+
* Default constructor - calendar initialization
|
38 |
+
**/
|
39 |
+
private function __construct() {
|
40 |
+
// ===========
|
41 |
+
// = ACTIONS =
|
42 |
+
// ===========
|
43 |
+
// Handle AJAX requests
|
44 |
+
// Strange! Now regular WordPress requests will respond to the below AJAX
|
45 |
+
// hooks! Thus we need to check to make sure we are being called by the
|
46 |
+
// AJAX script before returning AJAX responses.
|
47 |
+
if( basename( $_SERVER['SCRIPT_NAME'] ) == 'admin-ajax.php' )
|
48 |
+
{
|
49 |
+
add_action( 'wp_ajax_ai1ec_month', array( &$this, 'ajax_month' ) );
|
50 |
+
add_action( 'wp_ajax_ai1ec_agenda', array( &$this, 'ajax_agenda' ) );
|
51 |
+
add_action( 'wp_ajax_nopriv_ai1ec_month', array( &$this, 'ajax_month' ) );
|
52 |
+
add_action( 'wp_ajax_nopriv_ai1ec_agenda', array( &$this, 'ajax_agenda' ) );
|
53 |
+
add_action( 'wp_ajax_ai1ec_term_filter', array( &$this, 'ajax_term_filter' ) );
|
54 |
+
add_action( 'wp_ajax_nopriv_ai1ec_term_filter', array( &$this, 'ajax_term_filter' ) );
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* process_request function
|
60 |
+
*
|
61 |
+
* Initialize/validate custom request array, based on contents of $_REQUEST,
|
62 |
+
* to keep track of this component's request variables.
|
63 |
+
*
|
64 |
+
* @return void
|
65 |
+
**/
|
66 |
+
function process_request()
|
67 |
+
{
|
68 |
+
global $ai1ec_settings;
|
69 |
+
|
70 |
+
// Find out which view of the calendar page was requested, then validate
|
71 |
+
// request parameters accordingly and save them to our custom request
|
72 |
+
// object
|
73 |
+
$this->request['action'] = $_REQUEST['action'];
|
74 |
+
if( ! in_array( $this->request['action'],
|
75 |
+
array( 'ai1ec_month', 'ai1ec_agenda', 'ai1ec_term_filter' ) ) )
|
76 |
+
$this->request['action'] = 'ai1ec_' . $ai1ec_settings->default_calendar_view;
|
77 |
+
|
78 |
+
switch( $this->request['action'] )
|
79 |
+
{
|
80 |
+
case 'ai1ec_month':
|
81 |
+
$this->request['ai1ec_month_offset'] =
|
82 |
+
$_REQUEST['ai1ec_month_offset'] ?
|
83 |
+
intval( $_REQUEST['ai1ec_month_offset'] ) : 0;
|
84 |
+
// Parse active event parameter as an integer ID
|
85 |
+
$this->request['ai1ec_active_event'] = intval( $_REQUEST['ai1ec_active_event'] );
|
86 |
+
// Category/tag filter parameters
|
87 |
+
$this->request['ai1ec_cat_ids'] = $_REQUEST['ai1ec_cat_ids'];
|
88 |
+
$this->request['ai1ec_tag_ids'] = $_REQUEST['ai1ec_tag_ids'];
|
89 |
+
break;
|
90 |
+
|
91 |
+
case 'ai1ec_agenda':
|
92 |
+
$this->request['ai1ec_page_offset'] =
|
93 |
+
$_REQUEST['ai1ec_page_offset'] ?
|
94 |
+
intval( $_REQUEST['ai1ec_page_offset'] ) : 0;
|
95 |
+
// Parse active event parameter as an integer ID
|
96 |
+
$this->request['ai1ec_active_event'] = intval( $_REQUEST['ai1ec_active_event'] );
|
97 |
+
// Category/tag filter parameters
|
98 |
+
$this->request['ai1ec_cat_ids'] = $_REQUEST['ai1ec_cat_ids'];
|
99 |
+
$this->request['ai1ec_tag_ids'] = $_REQUEST['ai1ec_tag_ids'];
|
100 |
+
break;
|
101 |
+
|
102 |
+
case 'ai1ec_term_filter':
|
103 |
+
$this->request['ai1ec_post_ids'] = $_REQUEST['ai1ec_post_ids'];
|
104 |
+
$this->request['ai1ec_term_ids'] = $_REQUEST['ai1ec_term_ids'];
|
105 |
+
break;
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* get_instance function
|
111 |
+
*
|
112 |
+
* Return singleton instance
|
113 |
+
*
|
114 |
+
* @return object
|
115 |
+
**/
|
116 |
+
static function get_instance() {
|
117 |
+
if( self::$_instance === NULL ) {
|
118 |
+
self::$_instance = new self();
|
119 |
+
}
|
120 |
+
|
121 |
+
return self::$_instance;
|
122 |
+
}
|
123 |
+
|
124 |
+
/**
|
125 |
+
* view function
|
126 |
+
*
|
127 |
+
* Display requested calendar page.
|
128 |
+
*
|
129 |
+
* @return void
|
130 |
+
**/
|
131 |
+
function view()
|
132 |
+
{
|
133 |
+
global $ai1ec_view_helper,
|
134 |
+
$ai1ec_settings,
|
135 |
+
$ai1ec_events_helper;
|
136 |
+
|
137 |
+
$this->process_request();
|
138 |
+
|
139 |
+
// Set body class
|
140 |
+
add_filter( 'body_class', array( &$this, 'body_class' ) );
|
141 |
+
// Queue any styles, scripts
|
142 |
+
$this->load_css();
|
143 |
+
$this->load_js();
|
144 |
+
|
145 |
+
// Define arguments for specific calendar sub-view (month, agenda, etc.)
|
146 |
+
$args = array(
|
147 |
+
'active_event' => $this->request['ai1ec_active_event'],
|
148 |
+
);
|
149 |
+
|
150 |
+
// Find out which view of the calendar page was requested
|
151 |
+
switch( $this->request['action'] )
|
152 |
+
{
|
153 |
+
case 'ai1ec_month':
|
154 |
+
$args['month_offset'] = $this->request['ai1ec_month_offset'];
|
155 |
+
$view = $this->get_month_view( $args );
|
156 |
+
break;
|
157 |
+
|
158 |
+
case 'ai1ec_agenda':
|
159 |
+
$args['page_offset'] = $this->request['ai1ec_page_offset'];
|
160 |
+
$view = $this->get_agenda_view( $args );
|
161 |
+
break;
|
162 |
+
}
|
163 |
+
|
164 |
+
if( $ai1ec_settings->show_create_event_button && current_user_can( 'edit_ai1ec_events' ) )
|
165 |
+
$create_event_url = admin_url( 'post-new.php?post_type=' . AI1EC_POST_TYPE );
|
166 |
+
else
|
167 |
+
$create_event_url = false;
|
168 |
+
|
169 |
+
// Validate preselected category/tag IDs
|
170 |
+
$cat_ids = join( ',', array_filter( split( ',', $this->request['ai1ec_cat_ids'] ), 'is_numeric' ) );
|
171 |
+
$tag_ids = join( ',', array_filter( split( ',', $this->request['ai1ec_tag_ids'] ), 'is_numeric' ) );
|
172 |
+
|
173 |
+
$categories = get_terms( 'events_categories', array( 'orderby' => 'name' ) );
|
174 |
+
foreach( $categories as &$cat ) {
|
175 |
+
$cat->color = $ai1ec_events_helper->get_category_color_square( $cat->term_id );
|
176 |
+
}
|
177 |
+
// Define new arguments for overall calendar view
|
178 |
+
$args = array(
|
179 |
+
'view' => $view,
|
180 |
+
'create_event_url' => $create_event_url,
|
181 |
+
'categories' => $categories,
|
182 |
+
'tags' => get_terms( 'events_tags', array( 'orderby' => 'name' ) ),
|
183 |
+
'selected_cat_ids' => $cat_ids,
|
184 |
+
'selected_tag_ids' => $tag_ids,
|
185 |
+
);
|
186 |
+
|
187 |
+
// Feed month view into generic calendar view
|
188 |
+
$ai1ec_view_helper->display( 'calendar.php', $args );
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* get_month_view function
|
193 |
+
*
|
194 |
+
* Return the embedded month view of the calendar, optionally filtered by
|
195 |
+
* event categories and tags.
|
196 |
+
*
|
197 |
+
* @param array $args associative array with any of these elements:
|
198 |
+
* int month_offset => specifies which month to display relative to the
|
199 |
+
* current month
|
200 |
+
* int active_event => specifies which event to make visible when
|
201 |
+
* page is loaded
|
202 |
+
* array categories => restrict events returned to the given set of
|
203 |
+
* event category slugs
|
204 |
+
* array tags => restrict events returned to the given set of
|
205 |
+
* event tag names
|
206 |
+
*
|
207 |
+
* @return string returns string of view output
|
208 |
+
**/
|
209 |
+
function get_month_view( $args )
|
210 |
+
{
|
211 |
+
global $ai1ec_view_helper,
|
212 |
+
$ai1ec_events_helper,
|
213 |
+
$ai1ec_calendar_helper;
|
214 |
+
|
215 |
+
extract( $args );
|
216 |
+
|
217 |
+
// Get components of localized time
|
218 |
+
$bits = $ai1ec_events_helper->gmgetdate( $ai1ec_events_helper->gmt_to_local( time() ) );
|
219 |
+
// Use first day of the month as reference timestamp
|
220 |
+
$timestamp = gmmktime( 0, 0, 0, $bits['mon'], 1, $bits['year'] );
|
221 |
+
// Incorporate month offset into date, so we are looking at right month
|
222 |
+
$timestamp = strtotime(
|
223 |
+
$month_offset > 0 ? "+$month_offset months" : "$month_offset months",
|
224 |
+
$timestamp );
|
225 |
+
|
226 |
+
$days_events = $ai1ec_calendar_helper->get_events_for_month( $timestamp, $categories, $tags );
|
227 |
+
$cell_array = $ai1ec_calendar_helper->get_month_cell_array( $timestamp, $days_events );
|
228 |
+
$pagination_links = $ai1ec_calendar_helper->get_month_pagination_links( $month_offset );
|
229 |
+
|
230 |
+
$view_args = array(
|
231 |
+
'title' => strftime( '%B %Y', $timestamp ),
|
232 |
+
'weekdays' => $ai1ec_calendar_helper->get_weekdays(),
|
233 |
+
'cell_array' => $cell_array,
|
234 |
+
'pagination_links' => $pagination_links,
|
235 |
+
'active_event' => $active_event,
|
236 |
+
);
|
237 |
+
return $ai1ec_view_helper->get_view( 'month.php', $view_args );
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* get_agenda_view function
|
242 |
+
*
|
243 |
+
* Return the embedded agenda view of the calendar, optionally filtered by
|
244 |
+
* event categories and tags.
|
245 |
+
*
|
246 |
+
* @param array $args associative array with any of these elements:
|
247 |
+
* int page_offset => specifies which page to display relative to today's page
|
248 |
+
* int active_event => specifies which event to make visible when
|
249 |
+
* page is loaded
|
250 |
+
* array categories => restrict events returned to the given set of
|
251 |
+
* event category slugs
|
252 |
+
* array tags => restrict events returned to the given set of
|
253 |
+
* event tag names
|
254 |
+
*
|
255 |
+
* @return string returns string of view output
|
256 |
+
**/
|
257 |
+
function get_agenda_view( $args )
|
258 |
+
{
|
259 |
+
global $ai1ec_view_helper,
|
260 |
+
$ai1ec_events_helper,
|
261 |
+
$ai1ec_calendar_helper,
|
262 |
+
$ai1ec_settings;
|
263 |
+
|
264 |
+
extract( $args );
|
265 |
+
|
266 |
+
// Get localized time
|
267 |
+
$timestamp = $ai1ec_events_helper->gmt_to_local( time() );
|
268 |
+
|
269 |
+
// Get events, then classify into date array
|
270 |
+
$event_results = $ai1ec_calendar_helper->get_events_relative_to(
|
271 |
+
$timestamp,
|
272 |
+
$ai1ec_settings->agenda_events_per_page,
|
273 |
+
$page_offset
|
274 |
+
);
|
275 |
+
$dates = $ai1ec_calendar_helper->get_agenda_date_array( $event_results['events'] );
|
276 |
+
|
277 |
+
$pagination_links =
|
278 |
+
$ai1ec_calendar_helper->get_agenda_pagination_links(
|
279 |
+
$page_offset, $event_results['prev'], $event_results['next'] );
|
280 |
+
|
281 |
+
// Incorporate offset into date
|
282 |
+
$args = array(
|
283 |
+
'title' => __( 'Agenda' ),
|
284 |
+
'dates' => $dates,
|
285 |
+
'page_offset' => $page_offset,
|
286 |
+
'pagination_links' => $pagination_links,
|
287 |
+
'active_event' => $active_event,
|
288 |
+
);
|
289 |
+
return $ai1ec_view_helper->get_view( 'agenda.php', $args );
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* ajax_month function
|
294 |
+
*
|
295 |
+
* AJAX request handler for month view.
|
296 |
+
*
|
297 |
+
* @return void
|
298 |
+
**/
|
299 |
+
function ajax_month() {
|
300 |
+
global $ai1ec_view_helper;
|
301 |
+
|
302 |
+
$this->process_request();
|
303 |
+
|
304 |
+
// View arguments
|
305 |
+
$args = array(
|
306 |
+
'month_offset' => $this->request['ai1ec_month_offset'],
|
307 |
+
'active_event' => $this->request['ai1ec_active_event'],
|
308 |
+
);
|
309 |
+
|
310 |
+
// Return this data structure to the client
|
311 |
+
$data = array(
|
312 |
+
'body_class' => join( ' ', $this->body_class() ),
|
313 |
+
'html' => $this->get_month_view( $args ),
|
314 |
+
);
|
315 |
+
$ai1ec_view_helper->json_response( $data );
|
316 |
+
}
|
317 |
+
|
318 |
+
/**
|
319 |
+
* ajax_agenda function
|
320 |
+
*
|
321 |
+
* AJAX request handler for agenda view.
|
322 |
+
*
|
323 |
+
* @return void
|
324 |
+
**/
|
325 |
+
function ajax_agenda() {
|
326 |
+
global $ai1ec_view_helper;
|
327 |
+
|
328 |
+
$this->process_request();
|
329 |
+
|
330 |
+
// View arguments
|
331 |
+
$args = array(
|
332 |
+
'page_offset' => $this->request['ai1ec_page_offset'],
|
333 |
+
'active_event' => $this->request['ai1ec_active_event'],
|
334 |
+
);
|
335 |
+
|
336 |
+
// Return this data structure to the client
|
337 |
+
$data = array(
|
338 |
+
'body_class' => join( ' ', $this->body_class() ),
|
339 |
+
'html' => $this->get_agenda_view( $args ),
|
340 |
+
);
|
341 |
+
$ai1ec_view_helper->json_response( $data );
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* ajax_term_filter function
|
346 |
+
*
|
347 |
+
* AJAX request handler that takes a comma-separated list of event IDs and
|
348 |
+
* comma-separated list of term IDs and returns those event IDs within the
|
349 |
+
* set that have any of the term IDs.
|
350 |
+
*
|
351 |
+
* @return void
|
352 |
+
**/
|
353 |
+
function ajax_term_filter() {
|
354 |
+
global $ai1ec_view_helper, $ai1ec_events_helper;
|
355 |
+
|
356 |
+
$this->process_request();
|
357 |
+
|
358 |
+
$post_ids = array_unique( explode( ',', $this->request['ai1ec_post_ids'] ) );
|
359 |
+
|
360 |
+
if( $this->request['ai1ec_term_ids'] ) {
|
361 |
+
$term_ids = explode( ',', $this->request['ai1ec_term_ids'] );
|
362 |
+
$matching_ids = $ai1ec_events_helper->filter_by_terms( $post_ids, $term_ids );
|
363 |
+
} else {
|
364 |
+
// If no term IDs were provided for filtering, then return all posts
|
365 |
+
$matching_ids = $post_ids;
|
366 |
+
}
|
367 |
+
|
368 |
+
$unmatching_ids = array_diff( $post_ids, $matching_ids );
|
369 |
+
|
370 |
+
$data = array(
|
371 |
+
'matching_ids' => $matching_ids,
|
372 |
+
'unmatching_ids' => $unmatching_ids,
|
373 |
+
);
|
374 |
+
$ai1ec_view_helper->json_response( $data );
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* body_class function
|
379 |
+
*
|
380 |
+
* Append custom classes to body element.
|
381 |
+
*
|
382 |
+
* @return void
|
383 |
+
**/
|
384 |
+
function body_class( $classes = array() ) {
|
385 |
+
$classes[] = 'ai1ec-calendar';
|
386 |
+
|
387 |
+
// Reformat action for body class
|
388 |
+
$action = $this->request['action'];
|
389 |
+
$action = strtr( $action, '_', '-' );
|
390 |
+
$action = preg_replace( '/^ai1ec-/', '', $action );
|
391 |
+
|
392 |
+
$classes[] = "ai1ec-action-$action";
|
393 |
+
if( ! $this->request['ai1ec_month_offset'] &&
|
394 |
+
! $this->request['ai1ec_page_offset'] ) {
|
395 |
+
$classes[] = 'ai1ec-today';
|
396 |
+
}
|
397 |
+
return $classes;
|
398 |
+
}
|
399 |
+
|
400 |
+
/**
|
401 |
+
* load_css function
|
402 |
+
*
|
403 |
+
* Enqueue any CSS files required by the calendar views, as well as embeds any
|
404 |
+
* CSS rules necessary for calendar container replacement.
|
405 |
+
*
|
406 |
+
* @return void
|
407 |
+
**/
|
408 |
+
function load_css()
|
409 |
+
{
|
410 |
+
global $ai1ec_settings;
|
411 |
+
|
412 |
+
wp_enqueue_style( 'ai1ec-general', AI1EC_CSS_URL . '/general.css', array(), 1 );
|
413 |
+
wp_enqueue_style( 'ai1ec-calendar', AI1EC_CSS_URL . '/calendar.css', array(), 1 );
|
414 |
+
|
415 |
+
if( $ai1ec_settings->calendar_css_selector )
|
416 |
+
add_action( 'wp_head', array( &$this, 'selector_css' ) );
|
417 |
+
}
|
418 |
+
|
419 |
+
/**
|
420 |
+
* selector_css function
|
421 |
+
*
|
422 |
+
* Inserts dynamic CSS rules into <head> section of page to replace
|
423 |
+
* desired CSS selector with calendar.
|
424 |
+
*/
|
425 |
+
function selector_css() {
|
426 |
+
global $ai1ec_view_helper, $ai1ec_settings;
|
427 |
+
|
428 |
+
$ai1ec_view_helper->display_css(
|
429 |
+
'selector.css',
|
430 |
+
array( 'selector' => $ai1ec_settings->calendar_css_selector )
|
431 |
+
);
|
432 |
+
}
|
433 |
+
|
434 |
+
/**
|
435 |
+
* load_js function
|
436 |
+
*
|
437 |
+
* Enqueue any JavaScript files required by the calendar views.
|
438 |
+
*
|
439 |
+
* @return void
|
440 |
+
**/
|
441 |
+
function load_js()
|
442 |
+
{
|
443 |
+
global $ai1ec_settings;
|
444 |
+
|
445 |
+
// Include scrollTo jQuery plugin
|
446 |
+
wp_enqueue_script( 'jquery.scrollTo', AI1EC_JS_URL . '/jquery.scrollTo-min.js', array( 'jquery' ), 1 );
|
447 |
+
// Include element selector function
|
448 |
+
wp_enqueue_script( 'ai1ec-element-selector', AI1EC_JS_URL . '/element-selector.js', array( 'jquery', 'jquery.scrollTo' ), 1 );
|
449 |
+
// Include custom script
|
450 |
+
wp_enqueue_script( 'ai1ec-calendar', AI1EC_JS_URL . '/calendar.js', array( 'jquery', 'jquery.scrollTo' ), 1 );
|
451 |
+
|
452 |
+
$data = array(
|
453 |
+
// Point script to AJAX URL
|
454 |
+
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
455 |
+
// What this view defaults to, in case there is no #hash appended
|
456 |
+
'default_hash' => '#' . http_build_query( $this->request ),
|
457 |
+
'export_url' => AI1EC_EXPORT_URL,
|
458 |
+
// Body classes if need to be set manually
|
459 |
+
'body_class' => join( ' ', $this->body_class() ),
|
460 |
+
);
|
461 |
+
// Replace desired CSS selector with calendar, if selector has been set
|
462 |
+
if( $ai1ec_settings->calendar_css_selector )
|
463 |
+
{
|
464 |
+
$page = get_post( $ai1ec_settings->calendar_post_id );
|
465 |
+
$data['selector'] = $ai1ec_settings->calendar_css_selector;
|
466 |
+
$data['title'] = $page->post_title;
|
467 |
+
}
|
468 |
+
|
469 |
+
wp_localize_script( 'ai1ec-calendar', 'ai1ec_calendar', $data );
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* function is_category_requested
|
474 |
+
*
|
475 |
+
* Returns the comma-separated list of category IDs that the calendar page
|
476 |
+
* was requested to be prefiltered by.
|
477 |
+
*
|
478 |
+
* @return string
|
479 |
+
*/
|
480 |
+
function get_requested_categories() {
|
481 |
+
return $this->request['ai1ec_cat_ids'];
|
482 |
+
}
|
483 |
+
}
|
484 |
+
// END class
|
app/controller/class-ai1ec-events-controller.php
ADDED
@@ -0,0 +1,790 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-events-controller.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Events_Controller class
|
11 |
+
*
|
12 |
+
* @package Controllers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Events_Controller {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* get_instance function
|
27 |
+
*
|
28 |
+
* Return singleton instance
|
29 |
+
*
|
30 |
+
* @return object
|
31 |
+
**/
|
32 |
+
static function get_instance() {
|
33 |
+
if( self::$_instance === NULL ) {
|
34 |
+
self::$_instance = new self();
|
35 |
+
}
|
36 |
+
|
37 |
+
return self::$_instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructor
|
42 |
+
*
|
43 |
+
**/
|
44 |
+
private function __construct() { }
|
45 |
+
|
46 |
+
/**
|
47 |
+
* delete_hook function
|
48 |
+
*
|
49 |
+
* If the deleted post is an event
|
50 |
+
* then all entries that match the post_id are
|
51 |
+
* removed from ai1ec_events and ai1ec_event_instances tables
|
52 |
+
*
|
53 |
+
* @param int $pid Post ID
|
54 |
+
*
|
55 |
+
* @return bool | int
|
56 |
+
**/
|
57 |
+
function delete_post( $pid ) {
|
58 |
+
global $wpdb;
|
59 |
+
|
60 |
+
$sql = "SELECT
|
61 |
+
ID
|
62 |
+
FROM
|
63 |
+
$wpdb->posts
|
64 |
+
WHERE
|
65 |
+
ID = %d AND
|
66 |
+
post_type = '" . AI1EC_POST_TYPE . "'";
|
67 |
+
|
68 |
+
// is this post an event?
|
69 |
+
if( $wpdb->get_var( $wpdb->prepare( $sql, $pid ) ) ) {
|
70 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
71 |
+
$sql = "DELETE FROM
|
72 |
+
$table_name
|
73 |
+
WHERE
|
74 |
+
post_id = %d";
|
75 |
+
// delete from ai1ec_events
|
76 |
+
$wpdb->query( $wpdb->prepare( $sql, $pid ) );
|
77 |
+
|
78 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_instances';
|
79 |
+
$sql = "DELETE FROM
|
80 |
+
$table_name
|
81 |
+
WHERE
|
82 |
+
post_id = %d";
|
83 |
+
// delete from ai1ec_event_instances
|
84 |
+
return $wpdb->query( $wpdb->prepare( $sql, $pid ) );
|
85 |
+
}
|
86 |
+
return true;
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* init function
|
91 |
+
*
|
92 |
+
* This function is executed when admin_head hook is called.
|
93 |
+
* Adds CSS and JS files.
|
94 |
+
*
|
95 |
+
* @return void
|
96 |
+
**/
|
97 |
+
function init()
|
98 |
+
{
|
99 |
+
global $ai1ec_events_helper;
|
100 |
+
|
101 |
+
// Initialize dashboard view
|
102 |
+
if( is_admin() ) {
|
103 |
+
// ======
|
104 |
+
// = JS =
|
105 |
+
// ======
|
106 |
+
// Include timespan helper functions
|
107 |
+
wp_enqueue_script( 'jquery.calendrical', AI1EC_JS_URL . '/jquery.calendrical.js', array( 'jquery' ) );
|
108 |
+
// Include timespan plugin
|
109 |
+
wp_enqueue_script( 'jquery.timespan', AI1EC_JS_URL . '/jquery.timespan.js', array( 'jquery', 'jquery.calendrical' ) );
|
110 |
+
// Include timespan plugin
|
111 |
+
wp_enqueue_script( 'jquery.inputdate', AI1EC_JS_URL . '/jquery.inputdate.js', array( 'jquery', 'jquery.calendrical' ) );
|
112 |
+
// Include Google Maps API
|
113 |
+
wp_enqueue_script( 'gmap_api', 'http://maps.google.com/maps/api/js?sensor=false' );
|
114 |
+
// Include autocomplete_geomod plugin
|
115 |
+
wp_enqueue_script( 'autocomplete_geomod', AI1EC_JS_URL . '/jquery.autocomplete_geomod.js', array( 'jquery' ) );
|
116 |
+
// Include geo_autocomplete plugin
|
117 |
+
wp_enqueue_script( 'geo_autocomplete', AI1EC_JS_URL . '/geo_autocomplete.js', array( 'jquery', 'autocomplete_geomod' ) );
|
118 |
+
// Include element selector function
|
119 |
+
wp_enqueue_script( 'ai1ec-element-selector', AI1EC_JS_URL . '/element-selector.js', array( 'jquery' ) );
|
120 |
+
// Include jQuery Tools form elements
|
121 |
+
wp_enqueue_script( 'jquery.tools-form', 'http://cdn.jquerytools.org/1.2.5/form/jquery.tools.min.js', array( 'jquery' ), '1.2.5' );
|
122 |
+
// Include add new event script
|
123 |
+
wp_enqueue_script( 'ai1ec-add_new_event', AI1EC_JS_URL . '/add_new_event.js', array( 'jquery', 'jquery.timespan', 'ai1ec-element-selector', 'jquery.tools-form' ) );
|
124 |
+
wp_enqueue_script( 'ai1ec-color-picker', AI1EC_JS_URL . '/colorpicker.js', array( 'jquery' ) );
|
125 |
+
|
126 |
+
// Supply custom value to JavaScript from PHP
|
127 |
+
wp_localize_script( 'ai1ec-add_new_event', 'ai1ec_add_new_event', array(
|
128 |
+
// Current time, used for date/time pickers
|
129 |
+
'now' => $ai1ec_events_helper->gmt_to_local( time() ),
|
130 |
+
) );
|
131 |
+
|
132 |
+
// =======
|
133 |
+
// = CSS =
|
134 |
+
// =======
|
135 |
+
// include autocomplete style
|
136 |
+
wp_enqueue_style( 'autocomplete', AI1EC_CSS_URL . '/jquery.autocomplete.css' );
|
137 |
+
// include colorpicker style
|
138 |
+
wp_enqueue_style( 'colorpicker', AI1EC_CSS_URL . '/colorpicker.css' );
|
139 |
+
// include add new event style
|
140 |
+
wp_enqueue_style( 'ai1ec_add_new_event', AI1EC_CSS_URL . '/add_new_event.css' );
|
141 |
+
}
|
142 |
+
// Initialize front-end view
|
143 |
+
else
|
144 |
+
{
|
145 |
+
// ======
|
146 |
+
// = JS =
|
147 |
+
// ======
|
148 |
+
wp_enqueue_script( 'ai1ec-event', AI1EC_JS_URL . '/event.js', array( 'jquery' ), 1 );
|
149 |
+
|
150 |
+
// =======
|
151 |
+
// = CSS =
|
152 |
+
// =======
|
153 |
+
wp_enqueue_style( 'ai1ec-general', AI1EC_CSS_URL . '/general.css', array(), 1 );
|
154 |
+
wp_enqueue_style( 'ai1ec-event', AI1EC_CSS_URL . '/event.css', array(), 1 );
|
155 |
+
}
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* meta_box_view function
|
160 |
+
*
|
161 |
+
* Add Events Calculator box to the Add New Event page
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
**/
|
165 |
+
function meta_box_view() {
|
166 |
+
global $ai1ec_view_helper,
|
167 |
+
$ai1ec_events_helper,
|
168 |
+
$post,
|
169 |
+
$wpdb,
|
170 |
+
$ai1ec_settings;
|
171 |
+
|
172 |
+
try
|
173 |
+
{
|
174 |
+
$event = new Ai1ec_Event( $post->ID );
|
175 |
+
|
176 |
+
// Existing event was found. Initialize form values with values from
|
177 |
+
// event object.
|
178 |
+
|
179 |
+
$all_day_event = $event->allday ? 'checked="checked"' : '';
|
180 |
+
|
181 |
+
$start_timestamp = $ai1ec_events_helper->gmt_to_local( $event->start );
|
182 |
+
$end_timestamp = $ai1ec_events_helper->gmt_to_local( $event->end );
|
183 |
+
|
184 |
+
$show_map = $event->show_map;
|
185 |
+
$google_map = $show_map ? 'checked="checked"' : '';
|
186 |
+
|
187 |
+
$venue = $event->venue;
|
188 |
+
$country = $event->country;
|
189 |
+
$address = $event->address;
|
190 |
+
$city = $event->city;
|
191 |
+
$province = $event->province;
|
192 |
+
$postal_code = $event->postal_code;
|
193 |
+
$contact_name = $event->contact_name;
|
194 |
+
$contact_phone = $event->contact_phone;
|
195 |
+
$contact_email = $event->contact_email;
|
196 |
+
$cost = $event->cost;
|
197 |
+
}
|
198 |
+
catch( Ai1ec_Event_Not_Found $e ) {
|
199 |
+
// Event does not exist.
|
200 |
+
// Leave form fields undefined (= zero-length strings)
|
201 |
+
$event = null;
|
202 |
+
}
|
203 |
+
|
204 |
+
// Recurrence fields
|
205 |
+
$recurrence = $ai1ec_events_helper->parse_recurrence_rules( $event );
|
206 |
+
extract( $recurrence );
|
207 |
+
|
208 |
+
// Time zone
|
209 |
+
$timezone = get_option( 'gmt_offset' );
|
210 |
+
$timezone = sprintf( '(GMT%+d:%02d)', intval( $timezone ), ( abs( $timezone ) * 60 ) % 60 );
|
211 |
+
|
212 |
+
// ===============================
|
213 |
+
// = Display event time and date =
|
214 |
+
// ===============================
|
215 |
+
if( is_null( $until ) ) $until = gmmktime();
|
216 |
+
$repeating_event = is_null( $repeat ) ? false : true;
|
217 |
+
$args = array(
|
218 |
+
'all_day_event' => $all_day_event,
|
219 |
+
'start_timestamp' => $start_timestamp,
|
220 |
+
'end_timestamp' => $end_timestamp,
|
221 |
+
'repeat' => $ai1ec_events_helper->create_repeat_dropdown( $repeat ),
|
222 |
+
'count' => $ai1ec_events_helper->create_count_input( $count ),
|
223 |
+
'end' => $ai1ec_events_helper->create_end_dropdown( $end ),
|
224 |
+
'until' => $ai1ec_events_helper->gmt_to_local( $until ),
|
225 |
+
'repeating_event' => $repeating_event,
|
226 |
+
'timezone' => $timezone,
|
227 |
+
'ending' => $end
|
228 |
+
);
|
229 |
+
$ai1ec_view_helper->display( 'box_time_and_date.php', $args );
|
230 |
+
|
231 |
+
// =================================================
|
232 |
+
// = Display event location details and Google map =
|
233 |
+
// =================================================
|
234 |
+
$args = array(
|
235 |
+
'venue' => $venue,
|
236 |
+
'country' => $country,
|
237 |
+
'address' => $address,
|
238 |
+
'city' => $city,
|
239 |
+
'province' => $province,
|
240 |
+
'postal_code' => $postal_code,
|
241 |
+
'google_map' => $google_map,
|
242 |
+
'show_map' => $show_map,
|
243 |
+
);
|
244 |
+
$ai1ec_view_helper->display( 'box_event_location.php', $args );
|
245 |
+
|
246 |
+
// ======================
|
247 |
+
// = Display event cost =
|
248 |
+
// ======================
|
249 |
+
$args = array(
|
250 |
+
'cost' => $cost
|
251 |
+
);
|
252 |
+
$ai1ec_view_helper->display( 'box_event_cost.php', $args );
|
253 |
+
|
254 |
+
// =========================================
|
255 |
+
// = Display organizer contact information =
|
256 |
+
// =========================================
|
257 |
+
$args = array(
|
258 |
+
'contact_name' => $contact_name,
|
259 |
+
'contact_phone' => $contact_phone,
|
260 |
+
'contact_email' => $contact_email,
|
261 |
+
);
|
262 |
+
$ai1ec_view_helper->display( 'box_event_contact.php', $args );
|
263 |
+
|
264 |
+
if( $ai1ec_settings->show_publish_button ) {
|
265 |
+
$args = array();
|
266 |
+
$post_type = $post->post_type;
|
267 |
+
$post_type_object = get_post_type_object( $post_type );
|
268 |
+
if( current_user_can( $post_type_object->cap->publish_posts ) )
|
269 |
+
$args["button_value"] = is_null( $event ) ? __( 'Publish', AI1EC_PLUGIN_NAME ) : __( 'Update', AI1EC_PLUGIN_NAME );
|
270 |
+
else
|
271 |
+
$args["button_value"] = __( 'Submit for Review', AI1EC_PLUGIN_NAME );
|
272 |
+
|
273 |
+
$ai1ec_view_helper->display( 'box_publish_button.php', $args );
|
274 |
+
}
|
275 |
+
|
276 |
+
/*
|
277 |
+
TODO Display Eventbrite ticketing
|
278 |
+
$ai1ec_view_helper->display( 'box_eventbrite.php' );
|
279 |
+
*/
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* save_post function
|
284 |
+
*
|
285 |
+
* Saves meta post data
|
286 |
+
*
|
287 |
+
* @param int $post_id Post ID
|
288 |
+
*
|
289 |
+
* @return void
|
290 |
+
**/
|
291 |
+
function save_post( $post_id ) {
|
292 |
+
global $wpdb, $ai1ec_events_helper;
|
293 |
+
|
294 |
+
// verify if this is not an auto save routine.
|
295 |
+
if( ! defined( 'DOING_AUTOSAVE' ) && ! DOING_AUTOSAVE ) {
|
296 |
+
|
297 |
+
// verify this came from the our screen and with proper authorization,
|
298 |
+
// because save_post can be triggered at other times
|
299 |
+
if ( !wp_verify_nonce( $_POST[AI1EC_POST_TYPE], 'ai1ec' ) ) {
|
300 |
+
return;
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
// verify that the post_type is that of an event
|
305 |
+
if( $_POST['post_type'] != AI1EC_POST_TYPE ) {
|
306 |
+
return;
|
307 |
+
}
|
308 |
+
|
309 |
+
$all_day = isset( $_POST['ai1ec_all_day_event'] ) ? 1 : 0;
|
310 |
+
$start_time = isset( $_POST['ai1ec_start_time'] ) ? $_POST['ai1ec_start_time'] : '';
|
311 |
+
$end_time = isset( $_POST['ai1ec_end_time'] ) ? $_POST['ai1ec_end_time'] : '';
|
312 |
+
$venue = isset( $_POST['ai1ec_venue'] ) ? stripslashes( $_POST['ai1ec_venue'] ) : '';
|
313 |
+
$address = isset( $_POST['ai1ec_address'] ) ? stripslashes( $_POST['ai1ec_address'] ) : '';
|
314 |
+
$city = isset( $_POST['ai1ec_city'] ) ? stripslashes( $_POST['ai1ec_city'] ) : '';
|
315 |
+
$province = isset( $_POST['ai1ec_province'] ) ? stripslashes( $_POST['ai1ec_province'] ) : '';
|
316 |
+
$postal_code = isset( $_POST['ai1ec_postal_code'] ) ? stripslashes( $_POST['ai1ec_postal_code'] ) : '';
|
317 |
+
$country = isset( $_POST['ai1ec_country'] ) ? stripslashes( $_POST['ai1ec_country'] ) : '';
|
318 |
+
$google_map = isset( $_POST['ai1ec_google_map'] ) ? 1 : 0;
|
319 |
+
$cost = isset( $_POST['ai1ec_cost'] ) ? stripslashes( $_POST['ai1ec_cost'] ) : '';
|
320 |
+
$contact_name = isset( $_POST['ai1ec_contact_name'] ) ? stripslashes( $_POST['ai1ec_contact_name'] ) : '';
|
321 |
+
$contact_phone = isset( $_POST['ai1ec_contact_phone'] ) ? stripslashes( $_POST['ai1ec_contact_phone'] ) : '';
|
322 |
+
$contact_email = isset( $_POST['ai1ec_contact_email'] ) ? stripslashes( $_POST['ai1ec_contact_email'] ) : '';
|
323 |
+
|
324 |
+
$rrule = null;
|
325 |
+
|
326 |
+
if( isset( $_POST['ai1ec_repeat'] ) && ! empty( $_POST['ai1ec_repeat'] ) && $_POST['ai1ec_repeat'] != ' ' ) {
|
327 |
+
// ================================
|
328 |
+
// = Repeating event, build rrule =
|
329 |
+
// ================================
|
330 |
+
$end = (int) $_POST['ai1ec_end'];
|
331 |
+
switch( $end ) :
|
332 |
+
// Never
|
333 |
+
case 0:
|
334 |
+
$end = '';
|
335 |
+
break;
|
336 |
+
// After
|
337 |
+
case 1:
|
338 |
+
$end = ';COUNT=' . (int) $_POST['ai1ec_count'];
|
339 |
+
break;
|
340 |
+
// On date
|
341 |
+
case 2:
|
342 |
+
$until = $_POST['ai1ec_until_time'];
|
343 |
+
$until = $ai1ec_events_helper->local_to_gmt( $until );
|
344 |
+
$until += 24 * 60 * 60; // Add 1 day (intuitively, the last day is included)
|
345 |
+
$until = gmdate( 'Ymd\THis\Z', $until ); // Convert to Zulu time
|
346 |
+
$end = ';UNTIL=' . $until;
|
347 |
+
break;
|
348 |
+
endswitch;
|
349 |
+
|
350 |
+
switch( $_POST['ai1ec_repeat'] ) {
|
351 |
+
// Daily
|
352 |
+
case 'DAILY':
|
353 |
+
$rrule = 'FREQ=DAILY' . $end;
|
354 |
+
break;
|
355 |
+
// Mondays
|
356 |
+
case 'MO':
|
357 |
+
$rrule = 'FREQ=DAILY;BYDAY=MO' . $end;
|
358 |
+
break;
|
359 |
+
// Tuesdays
|
360 |
+
case 'TU':
|
361 |
+
$rrule = 'FREQ=DAILY;BYDAY=TU' . $end;
|
362 |
+
break;
|
363 |
+
// Wednesdays
|
364 |
+
case 'WE':
|
365 |
+
$rrule = 'FREQ=DAILY;BYDAY=WE' . $end;
|
366 |
+
break;
|
367 |
+
// Thursdays
|
368 |
+
case 'TH':
|
369 |
+
$rrule = 'FREQ=DAILY;BYDAY=TH' . $end;
|
370 |
+
break;
|
371 |
+
// Fridays
|
372 |
+
case 'FR':
|
373 |
+
$rrule = 'FREQ=DAILY;BYDAY=FR' . $end;
|
374 |
+
break;
|
375 |
+
// Tuesdays and Thursdays
|
376 |
+
case 'TU+TH':
|
377 |
+
$rrule = 'FREQ=DAILY;BYDAY=TU,TH' . $end;
|
378 |
+
break;
|
379 |
+
// Mondays Wednesdays Fridays
|
380 |
+
case 'MO+WE+FR':
|
381 |
+
$rrule = 'FREQ=DAILY;BYDAY=MO,WE,FR' . $end;
|
382 |
+
break;
|
383 |
+
// Weekends
|
384 |
+
case 'WEEKDAYS':
|
385 |
+
$rrule = 'FREQ=DAILY;BYDAY=MO,TU,WE,TH,FR' . $end;
|
386 |
+
break;
|
387 |
+
// Saturdays
|
388 |
+
case 'SA':
|
389 |
+
$rrule = 'FREQ=DAILY;BYDAY=SA' . $end;
|
390 |
+
break;
|
391 |
+
// Sundays
|
392 |
+
case 'SU':
|
393 |
+
$rrule = 'FREQ=DAILY;BYDAY=SU' . $end;
|
394 |
+
break;
|
395 |
+
// Weekends
|
396 |
+
case 'WEEKENDS':
|
397 |
+
$rrule = 'FREQ=DAILY;BYDAY=SA+SU' . $end;
|
398 |
+
break;
|
399 |
+
// Weekly
|
400 |
+
case 'WEEKLY':
|
401 |
+
$rrule = 'FREQ=WEEKLY' . $end;
|
402 |
+
break;
|
403 |
+
// Monthly
|
404 |
+
case 'MONTHLY':
|
405 |
+
$rrule = 'FREQ=MONTHLY' . $end;
|
406 |
+
break;
|
407 |
+
// Yearly
|
408 |
+
case 'YEARLY':
|
409 |
+
$rrule = 'FREQ=YEARLY' . $end;
|
410 |
+
break;
|
411 |
+
}
|
412 |
+
}
|
413 |
+
|
414 |
+
$is_new = false;
|
415 |
+
$event = null;
|
416 |
+
try {
|
417 |
+
$event = new Ai1ec_Event( $post_id ? $post_id : null );
|
418 |
+
} catch( Ai1ec_Event_Not_Found $e ) {
|
419 |
+
// Post exists, but event data hasn't been saved yet. Create new event
|
420 |
+
// object.
|
421 |
+
$is_new = true;
|
422 |
+
$event = new Ai1ec_Event();
|
423 |
+
$event->post_id = $post_id;
|
424 |
+
}
|
425 |
+
|
426 |
+
$event->start = $ai1ec_events_helper->local_to_gmt( $start_time );
|
427 |
+
$event->end = $ai1ec_events_helper->local_to_gmt( $end_time );
|
428 |
+
$event->allday = $all_day;
|
429 |
+
$event->venue = $venue;
|
430 |
+
$event->address = $address;
|
431 |
+
$event->city = $city;
|
432 |
+
$event->province = $province;
|
433 |
+
$event->postal_code = $postal_code;
|
434 |
+
$event->country = $country;
|
435 |
+
$event->show_map = $google_map;
|
436 |
+
$event->cost = $cost;
|
437 |
+
$event->contact_name = $contact_name;
|
438 |
+
$event->contact_phone = $contact_phone;
|
439 |
+
$event->contact_email = $contact_email;
|
440 |
+
$event->recurrence_rules = $rrule;
|
441 |
+
$event->save( ! $is_new );
|
442 |
+
|
443 |
+
$ai1ec_events_helper->delete_event_cache( $post_id );
|
444 |
+
$ai1ec_events_helper->cache_event( $event );
|
445 |
+
return;
|
446 |
+
}
|
447 |
+
|
448 |
+
/**
|
449 |
+
* post_updated_messages function
|
450 |
+
*
|
451 |
+
* Filter success messages returned by WordPress when an event post is
|
452 |
+
* updated/saved.
|
453 |
+
*/
|
454 |
+
function post_updated_messages( $messages )
|
455 |
+
{
|
456 |
+
global $post, $post_ID;
|
457 |
+
|
458 |
+
$messages[AI1EC_POST_TYPE] = array(
|
459 |
+
0 => '', // Unused. Messages start at index 1.
|
460 |
+
1 => sprintf( __( 'Event updated. <a href="%s">View event</a>', AI1EC_PLUGIN_NAME ), esc_url( get_permalink( $post_ID ) ) ),
|
461 |
+
2 => __( 'Custom field updated.', AI1EC_PLUGIN_NAME ),
|
462 |
+
3 => __( 'Custom field deleted.', AI1EC_PLUGIN_NAME ),
|
463 |
+
4 => __( 'Event updated.', AI1EC_PLUGIN_NAME ),
|
464 |
+
/* translators: %s: date and time of the revision */
|
465 |
+
5 => isset( $_GET['revision'] ) ? sprintf( __( 'Event restored to revision from %s', AI1EC_PLUGIN_NAME ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
|
466 |
+
6 => sprintf( __( 'Event published. <a href="%s">View event</a>', AI1EC_PLUGIN_NAME ), esc_url( get_permalink($post_ID) ) ),
|
467 |
+
7 => __( 'Event saved.' ),
|
468 |
+
8 => sprintf( __( 'Event submitted. <a target="_blank" href="%s">Preview event</a>', AI1EC_PLUGIN_NAME ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ),
|
469 |
+
9 => sprintf( __( 'Event scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview event</a>', AI1EC_PLUGIN_NAME ),
|
470 |
+
// translators: Publish box date format, see http://php.net/date
|
471 |
+
date_i18n( __( 'M j, Y @ G:i', AI1EC_PLUGIN_NAME ), strtotime( $post->post_date ) ), esc_url( get_permalink($post_ID) ) ),
|
472 |
+
10 => sprintf( __( 'Event draft updated. <a target="_blank" href="%s">Preview event</a>', AI1EC_PLUGIN_NAME ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ),
|
473 |
+
);
|
474 |
+
|
475 |
+
return $messages;
|
476 |
+
}
|
477 |
+
|
478 |
+
/**
|
479 |
+
* event_content function
|
480 |
+
*
|
481 |
+
* Filter event post content by inserting relevant details of the event
|
482 |
+
* alongside the regular post content.
|
483 |
+
*
|
484 |
+
* @param string $content Post/Page content
|
485 |
+
*
|
486 |
+
* @return string Post/Page content
|
487 |
+
**/
|
488 |
+
function event_content( $content )
|
489 |
+
{
|
490 |
+
global $ai1ec_events_helper;
|
491 |
+
|
492 |
+
if( get_post_type() == AI1EC_POST_TYPE ) {
|
493 |
+
$event = $ai1ec_events_helper->get_event( get_the_ID() );
|
494 |
+
$content = $this->get_view( $event, $content );
|
495 |
+
}
|
496 |
+
return $content;
|
497 |
+
}
|
498 |
+
|
499 |
+
/**
|
500 |
+
* event_excerpt function
|
501 |
+
*
|
502 |
+
* Overrides what wp_trim_excerpt() returned if the post is an event,
|
503 |
+
* and outputs better rich-text (but not too rich) excerpt instead.
|
504 |
+
*
|
505 |
+
* @return void
|
506 |
+
**/
|
507 |
+
function event_excerpt( $text )
|
508 |
+
{
|
509 |
+
global $ai1ec_view_helper,
|
510 |
+
$ai1ec_events_helper;
|
511 |
+
|
512 |
+
if( get_post_type() != AI1EC_POST_TYPE )
|
513 |
+
return $text;
|
514 |
+
|
515 |
+
$event = new Ai1ec_Event( get_the_ID() );
|
516 |
+
|
517 |
+
ob_start();
|
518 |
+
|
519 |
+
$this->excerpt_view( $event );
|
520 |
+
|
521 |
+
// Re-apply any filters to the post content that normally would have been
|
522 |
+
// applied if it weren't for our interference (below).
|
523 |
+
echo
|
524 |
+
shortcode_unautop( wpautop(
|
525 |
+
$ai1ec_events_helper->trim_excerpt( $event->post->post_content )
|
526 |
+
) );
|
527 |
+
|
528 |
+
$page_content = ob_get_contents();
|
529 |
+
ob_end_clean();
|
530 |
+
|
531 |
+
return $page_content;
|
532 |
+
}
|
533 |
+
|
534 |
+
/**
|
535 |
+
* event_excerpt_noautop function
|
536 |
+
*
|
537 |
+
* Conditionally apply wpautop() filter to content, only if it is not an
|
538 |
+
* event.
|
539 |
+
*
|
540 |
+
* @return void
|
541 |
+
**/
|
542 |
+
function event_excerpt_noautop( $content )
|
543 |
+
{
|
544 |
+
if( get_post_type() != AI1EC_POST_TYPE )
|
545 |
+
return wpautop( $content );
|
546 |
+
return $content;
|
547 |
+
}
|
548 |
+
|
549 |
+
/**
|
550 |
+
* get_view function
|
551 |
+
*
|
552 |
+
* Returns the appropriate output to prepend to an event post, depending on
|
553 |
+
* WP loop context.
|
554 |
+
*
|
555 |
+
* @param Ai1ec_Event $event The event post being displayed
|
556 |
+
* @param string $content The post's original content
|
557 |
+
*
|
558 |
+
* @return string The event data markup to prepend to the post content
|
559 |
+
**/
|
560 |
+
function get_view( &$event, &$content )
|
561 |
+
{
|
562 |
+
global $ai1ec_view_helper;
|
563 |
+
|
564 |
+
ob_start();
|
565 |
+
|
566 |
+
if( is_single() ) {
|
567 |
+
$this->single_view( $event );
|
568 |
+
} else {
|
569 |
+
$this->multi_view( $event );
|
570 |
+
}
|
571 |
+
|
572 |
+
echo $content;
|
573 |
+
|
574 |
+
if( is_single() )
|
575 |
+
$this->single_event_footer( $event );
|
576 |
+
|
577 |
+
$page_content = ob_get_contents();
|
578 |
+
ob_end_clean();
|
579 |
+
|
580 |
+
return $page_content;
|
581 |
+
}
|
582 |
+
|
583 |
+
/**
|
584 |
+
* single_view function
|
585 |
+
*
|
586 |
+
* Outputs event-specific details as HTML to be prepended to post content
|
587 |
+
* when displayed as a single page.
|
588 |
+
*
|
589 |
+
* @param Ai1ec_Event $event The event being displayed
|
590 |
+
*
|
591 |
+
* @return void
|
592 |
+
**/
|
593 |
+
function single_view( &$event )
|
594 |
+
{
|
595 |
+
global $ai1ec_view_helper,
|
596 |
+
$ai1ec_calendar_helper;
|
597 |
+
|
598 |
+
$subscribe_url = AI1EC_EXPORT_URL . "&ai1ec_post_ids=$event->post_id";
|
599 |
+
$subscribe_url = str_replace( 'webcal://', 'http://', $subscribe_url );
|
600 |
+
|
601 |
+
$args = array(
|
602 |
+
'event' => &$event,
|
603 |
+
'recurrence' => $event->recurrence_html,
|
604 |
+
'categories' => $event->categories_html,
|
605 |
+
'tags' => $event->tags_html,
|
606 |
+
'location' => nl2br( $event->location ),
|
607 |
+
'map' => $this->get_map_view( $event ),
|
608 |
+
'contact' => $event->contact_html,
|
609 |
+
'calendar_url' => $ai1ec_calendar_helper->get_calendar_url( $event ),
|
610 |
+
'subscribe_url' => $subscribe_url,
|
611 |
+
'google_url' => 'http://www.google.com/calendar/render?cid=' . urlencode( $subscribe_url ),
|
612 |
+
);
|
613 |
+
$ai1ec_view_helper->display( 'event-single.php', $args );
|
614 |
+
}
|
615 |
+
|
616 |
+
/**
|
617 |
+
* multi_view function
|
618 |
+
*
|
619 |
+
* Outputs event-specific details as HTML to be prepended to post content
|
620 |
+
* when displayed in a loop alongside other posts.
|
621 |
+
*
|
622 |
+
* @param Ai1ec_Event $event The event being displayed
|
623 |
+
*
|
624 |
+
* @return void
|
625 |
+
**/
|
626 |
+
function multi_view( &$event )
|
627 |
+
{
|
628 |
+
global $ai1ec_view_helper,
|
629 |
+
$ai1ec_calendar_helper;
|
630 |
+
|
631 |
+
$location = str_replace( "\n", ', ', rtrim( $event->location ) );
|
632 |
+
|
633 |
+
$args = array(
|
634 |
+
'event' => &$event,
|
635 |
+
'recurrence' => $event->recurrence_html,
|
636 |
+
'categories' => $event->categories_html,
|
637 |
+
'tags' => $event->tags_html,
|
638 |
+
'location' => $location,
|
639 |
+
'contact' => $event->contact_html,
|
640 |
+
'calendar_url' => $ai1ec_calendar_helper->get_calendar_url( $event ),
|
641 |
+
);
|
642 |
+
$ai1ec_view_helper->display( 'event-multi.php', $args );
|
643 |
+
}
|
644 |
+
|
645 |
+
/**
|
646 |
+
* excerpt_view function
|
647 |
+
*
|
648 |
+
* Outputs event-specific details as HTML to be prepended to post content
|
649 |
+
* when displayed in an excerpt format.
|
650 |
+
*
|
651 |
+
* @param Ai1ec_Event $event The event being displayed
|
652 |
+
*
|
653 |
+
* @return void
|
654 |
+
**/
|
655 |
+
function excerpt_view( &$event )
|
656 |
+
{
|
657 |
+
global $ai1ec_view_helper,
|
658 |
+
$ai1ec_calendar_helper;
|
659 |
+
|
660 |
+
$location = str_replace( "\n", ', ', rtrim( $event->location ) );
|
661 |
+
|
662 |
+
$args = array(
|
663 |
+
'event' => &$event,
|
664 |
+
'location' => $location,
|
665 |
+
);
|
666 |
+
$ai1ec_view_helper->display( 'event-excerpt.php', $args );
|
667 |
+
}
|
668 |
+
|
669 |
+
/**
|
670 |
+
* get_map_view function
|
671 |
+
*
|
672 |
+
* Returns HTML markup displaying a Google map of the given event, if the event
|
673 |
+
* has show_map set to true. Returns a zero-length string otherwise.
|
674 |
+
*
|
675 |
+
* @return void
|
676 |
+
**/
|
677 |
+
function get_map_view( &$event )
|
678 |
+
{
|
679 |
+
global $ai1ec_view_helper, $ai1ec_events_helper;
|
680 |
+
|
681 |
+
if( ! $event->show_map )
|
682 |
+
return '';
|
683 |
+
|
684 |
+
$args = array(
|
685 |
+
'address' => $event->address,
|
686 |
+
'gmap_url_link' => $ai1ec_events_helper->get_gmap_url( $event, false ),
|
687 |
+
);
|
688 |
+
return $ai1ec_view_helper->get_view( 'event-map.php', $args );
|
689 |
+
}
|
690 |
+
|
691 |
+
/**
|
692 |
+
* single_event_footer function
|
693 |
+
*
|
694 |
+
* Outputs any markup that should appear below the post's content on the
|
695 |
+
* single post page for this event.
|
696 |
+
*
|
697 |
+
* @return void
|
698 |
+
**/
|
699 |
+
function single_event_footer( &$event )
|
700 |
+
{
|
701 |
+
global $ai1ec_view_helper;
|
702 |
+
|
703 |
+
$args = array(
|
704 |
+
'event' => &$event,
|
705 |
+
);
|
706 |
+
return $ai1ec_view_helper->display( 'event-single-footer.php', $args );
|
707 |
+
}
|
708 |
+
|
709 |
+
/**
|
710 |
+
* events_categories_add_form_fields function
|
711 |
+
*
|
712 |
+
*
|
713 |
+
*
|
714 |
+
* @return void
|
715 |
+
**/
|
716 |
+
function events_categories_add_form_fields() {
|
717 |
+
global $ai1ec_view_helper;
|
718 |
+
|
719 |
+
$args = array();
|
720 |
+
$ai1ec_view_helper->display( 'event_categories-color_picker.php' );
|
721 |
+
}
|
722 |
+
|
723 |
+
/**
|
724 |
+
* events_categories_edit_form_fields function
|
725 |
+
*
|
726 |
+
*
|
727 |
+
*
|
728 |
+
* @return void
|
729 |
+
**/
|
730 |
+
function events_categories_edit_form_fields( $term ) {
|
731 |
+
global $ai1ec_view_helper, $wpdb;
|
732 |
+
|
733 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_category_colors';
|
734 |
+
$color = $wpdb->get_var( "SELECT term_color FROM {$table_name} WHERE term_id = {$term->term_id}" );
|
735 |
+
|
736 |
+
$style = '';
|
737 |
+
$clr = '';
|
738 |
+
|
739 |
+
if( ! is_null( $color ) && ! empty( $color ) ) {
|
740 |
+
$style = 'style="background-color: ' . $color . '"';
|
741 |
+
$clr = $color;
|
742 |
+
}
|
743 |
+
$args = array(
|
744 |
+
'style' => $style,
|
745 |
+
'color' => $clr,
|
746 |
+
'edit' => true,
|
747 |
+
);
|
748 |
+
$ai1ec_view_helper->display( 'event_categories-color_picker.php', $args );
|
749 |
+
}
|
750 |
+
|
751 |
+
/**
|
752 |
+
* edited_events_categories function
|
753 |
+
*
|
754 |
+
*
|
755 |
+
*
|
756 |
+
* @return void
|
757 |
+
**/
|
758 |
+
function created_events_categories( $term_id ) {
|
759 |
+
global $wpdb;
|
760 |
+
$tag_color_value = '';
|
761 |
+
if( isset( $_POST["tag-color-value"] ) && ! empty( $_POST["tag-color-value"] ) ) {
|
762 |
+
$tag_color_value = $_POST["tag-color-value"];
|
763 |
+
}
|
764 |
+
|
765 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_category_colors';
|
766 |
+
$wpdb->insert( $table_name, array( 'term_id' => $term_id, 'term_color' => $tag_color_value ), array( '%d', '%s' ) );
|
767 |
+
}
|
768 |
+
|
769 |
+
function edited_events_categories( $term_id ) {
|
770 |
+
global $wpdb;
|
771 |
+
$tag_color_value = '';
|
772 |
+
if( isset( $_POST["tag-color-value"] ) && ! empty( $_POST["tag-color-value"] ) ) {
|
773 |
+
$tag_color_value = $_POST["tag-color-value"];
|
774 |
+
}
|
775 |
+
|
776 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_category_colors';
|
777 |
+
$term = $wpdb->get_var( "SELECT term_id FROM {$table_name} WHERE term_id = {$term_id}" );
|
778 |
+
|
779 |
+
if( is_null( $term ) ) {
|
780 |
+
// term doesn't exist, create it
|
781 |
+
$wpdb->insert( $table_name, array( 'term_id' => $term_id, 'term_color' => $tag_color_value ), array( '%d', '%s' ) );
|
782 |
+
} else {
|
783 |
+
// term exist, update it
|
784 |
+
$wpdb->update( $table_name, array( 'term_color' => $tag_color_value ), array( 'term_id' => $term_id ), array( '%s' ), array( '%d' ) );
|
785 |
+
}
|
786 |
+
|
787 |
+
|
788 |
+
}
|
789 |
+
}
|
790 |
+
// END class
|
app/controller/class-ai1ec-exporter-controller.php
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-exporter-controller.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Exporter_Controller class
|
11 |
+
*
|
12 |
+
* @package Controllers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Exporter_Controller {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* get_instance function
|
27 |
+
*
|
28 |
+
* Return singleton instance
|
29 |
+
*
|
30 |
+
* @return object
|
31 |
+
**/
|
32 |
+
static function get_instance() {
|
33 |
+
if( self::$_instance === NULL ) {
|
34 |
+
self::$_instance = new self();
|
35 |
+
}
|
36 |
+
|
37 |
+
return self::$_instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructor
|
42 |
+
*
|
43 |
+
* Default constructor
|
44 |
+
**/
|
45 |
+
private function __construct() { }
|
46 |
+
|
47 |
+
/**
|
48 |
+
* export_events function
|
49 |
+
*
|
50 |
+
* Export events
|
51 |
+
*
|
52 |
+
* @return void
|
53 |
+
**/
|
54 |
+
function export_events() {
|
55 |
+
global $ai1ec_events_helper,
|
56 |
+
$ai1ec_exporter_helper;
|
57 |
+
$ai1ec_cat_ids = isset( $_REQUEST['ai1ec_cat_ids'] ) && ! empty( $_REQUEST['ai1ec_cat_ids'] ) ? $_REQUEST['ai1ec_cat_ids'] : false;
|
58 |
+
$ai1ec_tag_ids = isset( $_REQUEST['ai1ec_tag_ids'] ) && ! empty( $_REQUEST['ai1ec_tag_ids'] ) ? $_REQUEST['ai1ec_tag_ids'] : false;
|
59 |
+
$ai1ec_post_ids = isset( $_REQUEST['ai1ec_post_ids'] ) && ! empty( $_REQUEST['ai1ec_post_ids'] ) ? $_REQUEST['ai1ec_post_ids'] : false;
|
60 |
+
$start = false;
|
61 |
+
$end = gmmktime() - 24 * 60 * 60; // Include any events ending today
|
62 |
+
$events = $ai1ec_events_helper->get_matching_events( $start, $end, $ai1ec_tag_ids, $ai1ec_cat_ids, $ai1ec_post_ids );
|
63 |
+
$c = new vcalendar();
|
64 |
+
$c->setProperty( 'calscale', 'GREGORIAN' );
|
65 |
+
$c->setProperty( 'method', 'PUBLISH' );
|
66 |
+
$c->setProperty( 'X-WR-CALNAME', get_bloginfo( 'name' ) );
|
67 |
+
$c->setProperty( 'X-WR-CALDESC', get_bloginfo( 'description' ) );
|
68 |
+
// Timezone setup
|
69 |
+
$tz = get_option( 'timezone_string' );
|
70 |
+
$c->setProperty( 'X-WR-TIMEZONE', $tz );
|
71 |
+
$tz_xprops = array( 'X-LIC-LOCATION' => $tz );
|
72 |
+
iCalUtilityFunctions::createTimezone( $c, $tz, $tz_xprops );
|
73 |
+
|
74 |
+
foreach( $events as $event ) {
|
75 |
+
$ai1ec_exporter_helper->insert_event_in_calendar( $event, $c );
|
76 |
+
}
|
77 |
+
$str = $c->createCalendar();
|
78 |
+
echo $str;
|
79 |
+
exit();
|
80 |
+
}
|
81 |
+
}
|
82 |
+
// END class
|
app/controller/class-ai1ec-importer-controller.php
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-importer-controller.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Importer_Controller class
|
11 |
+
*
|
12 |
+
* @package Controllers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Importer_Controller {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* get_instance function
|
27 |
+
*
|
28 |
+
* Return singleton instance
|
29 |
+
*
|
30 |
+
* @return object
|
31 |
+
**/
|
32 |
+
static function get_instance() {
|
33 |
+
if( self::$_instance === NULL ) {
|
34 |
+
self::$_instance = new self();
|
35 |
+
}
|
36 |
+
|
37 |
+
return self::$_instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructor
|
42 |
+
*
|
43 |
+
* Default constructor
|
44 |
+
**/
|
45 |
+
private function __construct() { }
|
46 |
+
|
47 |
+
/**
|
48 |
+
* cron function
|
49 |
+
*
|
50 |
+
* Import all ICS feeds
|
51 |
+
*
|
52 |
+
* @return void
|
53 |
+
**/
|
54 |
+
function cron()
|
55 |
+
{
|
56 |
+
global $wpdb,
|
57 |
+
$ai1ec_importer_helper,
|
58 |
+
$ai1ec_events_helper;
|
59 |
+
|
60 |
+
// ====================
|
61 |
+
// = Select all feeds =
|
62 |
+
// ====================
|
63 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
64 |
+
$sql = "SELECT * FROM {$table_name}";
|
65 |
+
$feeds = $wpdb->get_results( $sql );
|
66 |
+
|
67 |
+
// ===============================
|
68 |
+
// = go over each iCalendar feed =
|
69 |
+
// ===============================
|
70 |
+
foreach( $feeds as $feed ) {
|
71 |
+
$ai1ec_importer_helper->parse_ics_feed( $feed );
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* register_importer function
|
77 |
+
*
|
78 |
+
* Registers the events calendar importer
|
79 |
+
*
|
80 |
+
* @return void
|
81 |
+
**/
|
82 |
+
function register_importer() {
|
83 |
+
global $wp_importers;
|
84 |
+
|
85 |
+
if( ! isset( $wp_importers['ai1ec_the_events_calendar'] ) ) {
|
86 |
+
$wp_importers['ai1ec_the_events_calendar'] = array(
|
87 |
+
__( 'The Events Calendar → All-in-One Events Calendar', AI1EC_PLUGIN_NAME ),
|
88 |
+
__( 'Imports events created using The Events Calendar plugin into the All-in-One Events Calendar', AI1EC_PLUGIN_NAME ),
|
89 |
+
array( &$this, 'import_the_events_calendar' )
|
90 |
+
);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
* import_the_events_calendar function
|
96 |
+
*
|
97 |
+
* Import events from The Events Calendar into Ai1ec.
|
98 |
+
*
|
99 |
+
* @return void
|
100 |
+
**/
|
101 |
+
function import_the_events_calendar() {
|
102 |
+
global $ai1ec_view_helper,
|
103 |
+
$ai1ec_events_helper;
|
104 |
+
|
105 |
+
$args = array(
|
106 |
+
'post_type' => 'post',
|
107 |
+
'numberposts' => -1,
|
108 |
+
'meta_key' => '_isEvent',
|
109 |
+
'meta_value' => 'yes'
|
110 |
+
);
|
111 |
+
$posts = get_posts( $args );
|
112 |
+
|
113 |
+
$imported_events = 0;
|
114 |
+
foreach( $posts as $post )
|
115 |
+
{
|
116 |
+
$event = new Ai1ec_Event( null );
|
117 |
+
$postmeta = get_post_custom( $post->ID );
|
118 |
+
|
119 |
+
// Need this to offset dates coming from The Events Calendar
|
120 |
+
$gm_diff = mktime( 0 ) - gmmktime( 0 );
|
121 |
+
|
122 |
+
$event->allday = $postmeta['_EventAllDay'][0] == 'yes' || $postmeta['_EventAllDay'][0] == 1;
|
123 |
+
$event->start = strtotime( $postmeta['_EventStartDate'][0] ) - $gm_diff;
|
124 |
+
$event->end = strtotime( $postmeta['_EventEndDate'][0] ) - $gm_diff;
|
125 |
+
// If all-day event, align start/end to start/end of day
|
126 |
+
if( $event->allday ) {
|
127 |
+
$event->start = $ai1ec_events_helper->gmgetdate( $event->start );
|
128 |
+
$event->start = gmmktime( 0, 0, 0, $event->start['mon'], $event->start['mday'], $event->start['year'] );
|
129 |
+
$event->end = $ai1ec_events_helper->gmgetdate( $event->end );
|
130 |
+
$event->end = gmmktime( 0, 0, 0, $event->end['mon'], $event->end['mday'], $event->end['year'] );
|
131 |
+
}
|
132 |
+
// Finally, convert to GMT storage format
|
133 |
+
$event->start = $ai1ec_events_helper->local_to_gmt( $event->start );
|
134 |
+
$event->end = $ai1ec_events_helper->local_to_gmt( $event->end );
|
135 |
+
// Bug in The Events Calendar where some all-day events start and end at the same time
|
136 |
+
if( $event->allday && $event->end - $event->start < ( 24 * 60 * 60 ) )
|
137 |
+
$event->end = $event->start + 24 * 60 * 60;
|
138 |
+
$event->venue = $postmeta['_EventVenue'][0];
|
139 |
+
$event->country = $postmeta['_EventCountry'][0];
|
140 |
+
$event->city = $postmeta['_EventCity'][0];
|
141 |
+
$event->province = $postmeta['_EventState'][0];
|
142 |
+
$event->postal_code = $postmeta['_EventZip'][0];
|
143 |
+
$event->address = array();
|
144 |
+
if( $postmeta['$_EventAddress'] ) $event->address[] = $postmeta['$_EventAddress'];
|
145 |
+
if( $event->city ) $event->address[] = $event->city;
|
146 |
+
if( $event->province ) $event->address[] = $event->province;
|
147 |
+
if( $event->postal_code ) $event->address[] = $event->postal_code;
|
148 |
+
if( $event->country ) $event->address[] = $event->country;
|
149 |
+
$event->address = join( ', ', $event->address );
|
150 |
+
$event->show_map = $postmeta['_EventShowMapLink'][0] == 'true' || $postmeta['_EventShowMap'][0] == 'true';
|
151 |
+
$event->cost = $postmeta['_EventCost'][0];
|
152 |
+
$event->contact_phone = $postmeta['_EventPhone'][0];
|
153 |
+
$event->post = get_object_vars( $post );
|
154 |
+
$event->post["post_type"] = AI1EC_POST_TYPE;
|
155 |
+
unset( $event->post["ID"] );
|
156 |
+
|
157 |
+
// Transfer post categories => event categories, post tags => event tags
|
158 |
+
$terms = wp_get_post_terms( $post->ID, array( 'category', 'post_tag' ) );
|
159 |
+
$event->categories = array();
|
160 |
+
$event->tags = array();
|
161 |
+
foreach( $terms as $term )
|
162 |
+
{
|
163 |
+
switch( $term->taxonomy )
|
164 |
+
{
|
165 |
+
case 'category':
|
166 |
+
// Ignore special "Events" category by The Events Calendar
|
167 |
+
if( $term->name == 'Events' )
|
168 |
+
break;
|
169 |
+
// Need to find out the category ID, if it exists.
|
170 |
+
$event_term = get_term_by( 'name', $term->name, 'events_categories' );
|
171 |
+
// If no category exists, create it.
|
172 |
+
if( $event_term === false )
|
173 |
+
$event_term = (object) wp_insert_term(
|
174 |
+
$term->name,
|
175 |
+
'events_categories',
|
176 |
+
array(
|
177 |
+
'description' => $term->description,
|
178 |
+
'slug' => $term->slug
|
179 |
+
)
|
180 |
+
);
|
181 |
+
$event->categories[] = $event_term->term_id;
|
182 |
+
break;
|
183 |
+
|
184 |
+
case 'post_tag':
|
185 |
+
// For some reason tag-like taxonomies are treated differently; term
|
186 |
+
// IDs cannot be used; instead the actual term name must be appended
|
187 |
+
$event->tags[] = $term->name;
|
188 |
+
break;
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
$post_id = $event->save();
|
193 |
+
$ai1ec_events_helper->cache_event( $event, $post_id );
|
194 |
+
|
195 |
+
$imported_events++;
|
196 |
+
}
|
197 |
+
|
198 |
+
$ai1ec_view_helper->display( "import.php", array( 'imported_events' => $imported_events ) );
|
199 |
+
}
|
200 |
+
}
|
201 |
+
// END class
|
app/controller/class-ai1ec-settings-controller.php
ADDED
@@ -0,0 +1,325 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-settings-controller.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Settings_Controller class
|
11 |
+
*
|
12 |
+
* @package Controllers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Settings_Controller {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* view function
|
49 |
+
*
|
50 |
+
* Display this plugin's settings page in the admin.
|
51 |
+
*
|
52 |
+
* @return void
|
53 |
+
**/
|
54 |
+
function view() {
|
55 |
+
global $ai1ec_view_helper,
|
56 |
+
$ai1ec_settings;
|
57 |
+
|
58 |
+
if( isset( $_REQUEST['ai1ec_save_settings'] ) ) {
|
59 |
+
$this->save();
|
60 |
+
}
|
61 |
+
$args = array(
|
62 |
+
'settings_page' => $ai1ec_settings->settings_page
|
63 |
+
);
|
64 |
+
$ai1ec_view_helper->display( 'settings.php', $args );
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* save function
|
69 |
+
*
|
70 |
+
* Save the submitted settings form.
|
71 |
+
*
|
72 |
+
* @return void
|
73 |
+
**/
|
74 |
+
function save() {
|
75 |
+
global $ai1ec_settings,
|
76 |
+
$ai1ec_view_helper;
|
77 |
+
|
78 |
+
$ai1ec_settings->update( $_REQUEST );
|
79 |
+
$ai1ec_settings->save();
|
80 |
+
|
81 |
+
$args = array(
|
82 |
+
"msg" => __( "Settings Updated.", AI1EC_PLUGIN_NAME )
|
83 |
+
);
|
84 |
+
|
85 |
+
$ai1ec_view_helper->display( "save_successful.php", $args );
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* add_ics_feed function
|
90 |
+
*
|
91 |
+
* Adds submitted ics feed to the database
|
92 |
+
*
|
93 |
+
* @return string JSON output
|
94 |
+
**/
|
95 |
+
function add_ics_feed() {
|
96 |
+
global $ai1ec_view_helper,
|
97 |
+
$wpdb;
|
98 |
+
|
99 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
100 |
+
|
101 |
+
$wpdb->insert(
|
102 |
+
$table_name,
|
103 |
+
array(
|
104 |
+
'feed_url' => $_REQUEST["feed_url"], // convert webcal to http
|
105 |
+
'feed_category' => $_REQUEST["feed_category"],
|
106 |
+
'feed_tags' => $_REQUEST["feed_tags"],
|
107 |
+
),
|
108 |
+
array(
|
109 |
+
'%s',
|
110 |
+
'%d',
|
111 |
+
'%s'
|
112 |
+
)
|
113 |
+
);
|
114 |
+
$feed_id = $wpdb->insert_id;
|
115 |
+
ob_start();
|
116 |
+
$feed_category = get_term( $_REQUEST["feed_category"], 'events_categories' );
|
117 |
+
$args = array(
|
118 |
+
'feed_url' => $_REQUEST["feed_url"],
|
119 |
+
'event_category' => $feed_category->name,
|
120 |
+
'tags' => $_REQUEST["feed_tags"],
|
121 |
+
'feed_id' => $feed_id
|
122 |
+
);
|
123 |
+
// display added feed row
|
124 |
+
$ai1ec_view_helper->display( 'feed_row.php', $args );
|
125 |
+
|
126 |
+
$output = ob_get_contents();
|
127 |
+
ob_end_clean();
|
128 |
+
|
129 |
+
$output = array(
|
130 |
+
"error" => 0,
|
131 |
+
"message" => stripslashes( $output )
|
132 |
+
);
|
133 |
+
|
134 |
+
echo json_encode( $output );
|
135 |
+
exit();
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* flush_ics_feed function
|
140 |
+
*
|
141 |
+
* Deletes all event posts that are from that selected feed
|
142 |
+
*
|
143 |
+
* @return void
|
144 |
+
**/
|
145 |
+
function flush_ics_feed()
|
146 |
+
{
|
147 |
+
global $wpdb,
|
148 |
+
$ai1ec_view_helper;
|
149 |
+
$ics_id = (int) $_REQUEST['ics_id'];
|
150 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
151 |
+
$feed_url = $wpdb->get_var( $wpdb->prepare( "SELECT feed_url FROM $table_name WHERE feed_id = %d", $ics_id ) );
|
152 |
+
if( $feed_url )
|
153 |
+
{
|
154 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
155 |
+
$sql = "SELECT post_id FROM {$table_name} WHERE ical_feed_url = '%s'";
|
156 |
+
$events = $wpdb->get_results( $wpdb->prepare( $sql, $feed_url ) );
|
157 |
+
$total = count( $events );
|
158 |
+
|
159 |
+
foreach( $events as $event ) {
|
160 |
+
// delete post (this will trigger deletion of cached events, and remove the event from events table)
|
161 |
+
wp_delete_post( $event->post_id, 'true' );
|
162 |
+
}
|
163 |
+
|
164 |
+
$output = array(
|
165 |
+
'error' => false,
|
166 |
+
'message' => sprintf( __( 'Flushed %d events', AI1EC_PLUGIN_NAME ), $total ),
|
167 |
+
'count' => $total,
|
168 |
+
);
|
169 |
+
}
|
170 |
+
else
|
171 |
+
{
|
172 |
+
$output = array(
|
173 |
+
'error' => true,
|
174 |
+
'message' => 'Invalid feed'
|
175 |
+
);
|
176 |
+
}
|
177 |
+
|
178 |
+
$ai1ec_view_helper->json_response( $output );
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* update_ics_feed function
|
183 |
+
*
|
184 |
+
* Imports the selected iCalendar feed
|
185 |
+
*
|
186 |
+
* @return void
|
187 |
+
**/
|
188 |
+
function update_ics_feed()
|
189 |
+
{
|
190 |
+
global $wpdb,
|
191 |
+
$ai1ec_view_helper,
|
192 |
+
$ai1ec_importer_helper;
|
193 |
+
|
194 |
+
$feed_id = (int) $_REQUEST['ics_id'];
|
195 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
196 |
+
$feed = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE feed_id = %d", $feed_id ) );
|
197 |
+
|
198 |
+
if( $feed )
|
199 |
+
{
|
200 |
+
$count = $ai1ec_importer_helper->parse_ics_feed( $feed );
|
201 |
+
$output = array(
|
202 |
+
'error' => false,
|
203 |
+
'message' => sprintf( __( 'Imported %d events', AI1EC_PLUGIN_NAME ), $count ),
|
204 |
+
'flush_label' => sprintf( _n( 'Flush 1 event', 'Flush %s events', $count, AI1EC_PLUGIN_NAME ), $count ),
|
205 |
+
'count' => $count,
|
206 |
+
);
|
207 |
+
}
|
208 |
+
else
|
209 |
+
{
|
210 |
+
$output = array(
|
211 |
+
'error' => true,
|
212 |
+
'message' => 'Invalid feed'
|
213 |
+
);
|
214 |
+
}
|
215 |
+
|
216 |
+
$ai1ec_view_helper->json_response( $output );
|
217 |
+
}
|
218 |
+
|
219 |
+
/**
|
220 |
+
* delete_ics_feed function
|
221 |
+
*
|
222 |
+
* Deletes submitted ics feed id from the database
|
223 |
+
*
|
224 |
+
* @return String JSON output
|
225 |
+
**/
|
226 |
+
function delete_ics_feed()
|
227 |
+
{
|
228 |
+
global $wpdb,
|
229 |
+
$ai1ec_view_helper;
|
230 |
+
|
231 |
+
$ics_id = (int) $_REQUEST['ics_id'];
|
232 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
233 |
+
$wpdb->query( $wpdb->prepare( "DELETE FROM {$table_name} WHERE feed_id = %d", $ics_id ) );
|
234 |
+
$output = array(
|
235 |
+
'error' => false,
|
236 |
+
'message' => 'Request successful.'
|
237 |
+
);
|
238 |
+
|
239 |
+
$ai1ec_view_helper->json_response( $output );
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* add_meta_boxes function
|
244 |
+
*
|
245 |
+
*
|
246 |
+
*
|
247 |
+
* @return void
|
248 |
+
**/
|
249 |
+
function add_meta_boxes() {
|
250 |
+
global $ai1ec_settings_helper,
|
251 |
+
$ai1ec_settings;
|
252 |
+
|
253 |
+
/* Add the 'General Settings' meta box. */
|
254 |
+
add_meta_box( 'general-settings',
|
255 |
+
_x( 'General Settings', 'meta box', AI1EC_PLUGIN_NAME ),
|
256 |
+
array( &$ai1ec_settings_helper, 'general_settings_meta_box' ),
|
257 |
+
$ai1ec_settings->settings_page,
|
258 |
+
'left-side',
|
259 |
+
'default' );
|
260 |
+
/* Add the 'The Seed Studio' meta box. */
|
261 |
+
add_meta_box( 'the-seed-studio-settings',
|
262 |
+
_x( 'The Seed Studio Support', 'meta box', AI1EC_PLUGIN_NAME ),
|
263 |
+
array( &$ai1ec_settings_helper, 'the_seed_studio_meta_box' ),
|
264 |
+
$ai1ec_settings->settings_page,
|
265 |
+
'right-side',
|
266 |
+
'default' );
|
267 |
+
/* Add the 'ICS Import Settings' meta box. */
|
268 |
+
add_meta_box( 'ics-import-settings',
|
269 |
+
_x( 'ICS Import Settings', 'meta box', AI1EC_PLUGIN_NAME ),
|
270 |
+
array( &$ai1ec_settings_helper, 'ics_import_settings_meta_box' ),
|
271 |
+
$ai1ec_settings->settings_page,
|
272 |
+
'left-side',
|
273 |
+
'default' );
|
274 |
+
|
275 |
+
}
|
276 |
+
|
277 |
+
/**
|
278 |
+
* admin_print_styles function
|
279 |
+
*
|
280 |
+
*
|
281 |
+
*
|
282 |
+
* @return void
|
283 |
+
**/
|
284 |
+
function admin_print_styles() {
|
285 |
+
global $ai1ec_view_helper;
|
286 |
+
$ai1ec_view_helper->display_css( 'settings.css' );
|
287 |
+
}
|
288 |
+
|
289 |
+
/**
|
290 |
+
* admin_print_scripts function
|
291 |
+
*
|
292 |
+
*
|
293 |
+
*
|
294 |
+
* @return void
|
295 |
+
**/
|
296 |
+
function admin_print_scripts() {
|
297 |
+
global $ai1ec_settings;
|
298 |
+
?>
|
299 |
+
<script type="text/javascript">
|
300 |
+
//<![CDATA[
|
301 |
+
var ai1ec_settings_page = '<?php echo $ai1ec_settings->settings_page; ?>';
|
302 |
+
//]]>
|
303 |
+
</script>
|
304 |
+
<?php
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* admin_enqueue_scripts function
|
309 |
+
*
|
310 |
+
*
|
311 |
+
*
|
312 |
+
* @return void
|
313 |
+
**/
|
314 |
+
function admin_enqueue_scripts( $hook_suffix ) {
|
315 |
+
global $ai1ec_settings;
|
316 |
+
|
317 |
+
if( isset( $ai1ec_settings->settings_page ) && $hook_suffix == $ai1ec_settings->settings_page ) {
|
318 |
+
wp_enqueue_script( 'common' );
|
319 |
+
wp_enqueue_script( 'wp-lists' );
|
320 |
+
wp_enqueue_script( 'postbox' );
|
321 |
+
wp_enqueue_script( 'ai1ec-settings', AI1EC_JS_URL . '/settings.js', array( 'jquery' ) );
|
322 |
+
}
|
323 |
+
}
|
324 |
+
}
|
325 |
+
// END class
|
app/exception/class-ai1ec-event-not-found.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-event-not-found.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Event_Not_Found class
|
11 |
+
*
|
12 |
+
* @package Exceptions
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Event_Not_Found extends Exception {
|
16 |
+
|
17 |
+
}
|
18 |
+
// END class
|
app/exception/class-ai1ec-file-not-found.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-file-not-found.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_File_Not_Found class
|
11 |
+
*
|
12 |
+
* @package Exceptions
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_File_Not_Found extends Exception {
|
16 |
+
|
17 |
+
}
|
18 |
+
// END class
|
app/exception/class-ai1ec-file-not-provided.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-file-not-provided.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_File_Not_Provided class
|
11 |
+
*
|
12 |
+
* @package Exceptions
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_File_Not_Provided extends Exception {
|
16 |
+
|
17 |
+
}
|
18 |
+
// END class
|
app/exception/class-ai1ec-invalid-argument.php
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-invalid-argument.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Invalid_Argument class
|
11 |
+
*
|
12 |
+
* @package Exceptions
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Invalid_Argument extends Exception {
|
16 |
+
|
17 |
+
}
|
18 |
+
// END class
|
app/helper/class-ai1ec-app-helper.php
ADDED
@@ -0,0 +1,636 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-app-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_App_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_App_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* map_meta_cap function
|
49 |
+
*
|
50 |
+
* Assigns proper capability
|
51 |
+
*
|
52 |
+
* @return void
|
53 |
+
**/
|
54 |
+
function map_meta_cap( $caps, $cap, $user_id, $args ) {
|
55 |
+
// If editing, deleting, or reading an event, get the post and post type object.
|
56 |
+
if( 'edit_ai1ec_event' == $cap || 'delete_ai1ec_event' == $cap || 'read_ai1ec_event' == $cap ) {
|
57 |
+
$post = get_post( $args[0] );
|
58 |
+
$post_type = get_post_type_object( $post->post_type );
|
59 |
+
/* Set an empty array for the caps. */
|
60 |
+
$caps = array();
|
61 |
+
}
|
62 |
+
|
63 |
+
/* If editing an event, assign the required capability. */
|
64 |
+
if( 'edit_ai1ec_event' == $cap ) {
|
65 |
+
if( $user_id == $post->post_author )
|
66 |
+
$caps[] = $post_type->cap->edit_posts;
|
67 |
+
else
|
68 |
+
$caps[] = $post_type->cap->edit_others_posts;
|
69 |
+
}
|
70 |
+
|
71 |
+
/* If deleting an event, assign the required capability. */
|
72 |
+
else if( 'delete_ai1ec_event' == $cap ) {
|
73 |
+
if( $user_id == $post->post_author )
|
74 |
+
$caps[] = $post_type->cap->delete_posts;
|
75 |
+
else
|
76 |
+
$caps[] = $post_type->cap->delete_others_posts;
|
77 |
+
}
|
78 |
+
|
79 |
+
/* If reading a private event, assign the required capability. */
|
80 |
+
else if( 'read_ai1ec_event' == $cap ) {
|
81 |
+
if( 'private' != $post->post_status )
|
82 |
+
$caps[] = 'read';
|
83 |
+
elseif ( $user_id == $post->post_author )
|
84 |
+
$caps[] = 'read';
|
85 |
+
else
|
86 |
+
$caps[] = $post_type->cap->read_private_posts;
|
87 |
+
}
|
88 |
+
|
89 |
+
/* Return the capabilities required by the user. */
|
90 |
+
return $caps;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* create_post_type function
|
95 |
+
*
|
96 |
+
* Create event's custom post type
|
97 |
+
* and registers events_categories and events_tags under
|
98 |
+
* event's custom post type taxonomy
|
99 |
+
*
|
100 |
+
* @return void
|
101 |
+
**/
|
102 |
+
function create_post_type() {
|
103 |
+
|
104 |
+
// if the event contributor role is not created, create it
|
105 |
+
if( !get_role( 'ai1ec_event_assistant' ) ) {
|
106 |
+
|
107 |
+
// creating event contributor role with the same capabilities
|
108 |
+
// as subscriber role, later in this file, event contributor role will be extended
|
109 |
+
// to include more capabilities
|
110 |
+
$caps = get_role( 'subscriber' )->capabilities;
|
111 |
+
add_role( 'ai1ec_event_assistant', 'Event Contributor', $caps );
|
112 |
+
|
113 |
+
// add event managing capability to administrator, editor, author
|
114 |
+
foreach( array( 'administrator', 'editor', 'author' ) as $user ) {
|
115 |
+
$role = get_role( $user );
|
116 |
+
// read events
|
117 |
+
$role->add_cap( 'read_ai1ec_event' );
|
118 |
+
// edit events
|
119 |
+
$role->add_cap( 'edit_ai1ec_event' );
|
120 |
+
$role->add_cap( 'edit_ai1ec_events' );
|
121 |
+
$role->add_cap( 'edit_others_ai1ec_events' );
|
122 |
+
$role->add_cap( 'edit_private_ai1ec_events' );
|
123 |
+
$role->add_cap( 'edit_published_ai1ec_events' );
|
124 |
+
// delete events
|
125 |
+
$role->add_cap( 'delete_ai1ec_event' );
|
126 |
+
$role->add_cap( 'delete_ai1ec_events' );
|
127 |
+
$role->add_cap( 'delete_others_ai1ec_events' );
|
128 |
+
$role->add_cap( 'delete_published_ai1ec_events' );
|
129 |
+
$role->add_cap( 'delete_private_ai1ec_events' );
|
130 |
+
// publish events
|
131 |
+
$role->add_cap( 'publish_ai1ec_events' );
|
132 |
+
// read private events
|
133 |
+
$role->add_cap( 'read_private_ai1ec_events' );
|
134 |
+
}
|
135 |
+
|
136 |
+
// add event managing capability to contributors
|
137 |
+
$role = get_role( 'ai1ec_event_assistant' );
|
138 |
+
$role->add_cap( 'edit_ai1ec_events' );
|
139 |
+
$role->add_cap( 'delete_ai1ec_event' );
|
140 |
+
$role->add_cap( 'read' );
|
141 |
+
}
|
142 |
+
// ===============================
|
143 |
+
// = labels for custom post type =
|
144 |
+
// ===============================
|
145 |
+
$labels = array(
|
146 |
+
'name' => _x( 'Events', AI1EC_PLUGIN_NAME ),
|
147 |
+
'singular_name' => _x( 'Event', AI1EC_PLUGIN_NAME ),
|
148 |
+
'add_new' => __( 'Add New', AI1EC_PLUGIN_NAME ),
|
149 |
+
'add_new_item' => __( 'Add New Event', AI1EC_PLUGIN_NAME ),
|
150 |
+
'edit_item' => __( 'Edit Event', AI1EC_PLUGIN_NAME ),
|
151 |
+
'new_item' => __( 'New Event', AI1EC_PLUGIN_NAME ),
|
152 |
+
'view_item' => __( 'View Event', AI1EC_PLUGIN_NAME ),
|
153 |
+
'search_items' => __( 'Search Events', AI1EC_PLUGIN_NAME ),
|
154 |
+
'not_found' => __( 'No Events found', AI1EC_PLUGIN_NAME ),
|
155 |
+
'not_found_in_trash' => __( 'No Events found in Trash', AI1EC_PLUGIN_NAME ),
|
156 |
+
'parent_item_colon' => __( 'Parent Event', AI1EC_PLUGIN_NAME ),
|
157 |
+
'menu_name' => __( 'Events', AI1EC_PLUGIN_NAME ),
|
158 |
+
'all_items' => $this->get_all_items_name()
|
159 |
+
);
|
160 |
+
|
161 |
+
|
162 |
+
// ================================
|
163 |
+
// = support for custom post type =
|
164 |
+
// ================================
|
165 |
+
$supports = array( 'title', 'editor', 'comments' );
|
166 |
+
|
167 |
+
// =============================
|
168 |
+
// = args for custom post type =
|
169 |
+
// =============================
|
170 |
+
$args = array(
|
171 |
+
'labels' => $labels,
|
172 |
+
'public' => true,
|
173 |
+
'publicly_queryable' => true,
|
174 |
+
'show_ui' => true,
|
175 |
+
'show_in_menu' => true,
|
176 |
+
'query_var' => true,
|
177 |
+
'rewrite' => true,
|
178 |
+
'capability_type' => array( 'ai1ec_event', 'ai1ec_events' ),
|
179 |
+
'capabilities' => array(
|
180 |
+
'read_post' => 'read_ai1ec_event',
|
181 |
+
'edit_post' => 'edit_ai1ec_event',
|
182 |
+
'edit_posts' => 'edit_ai1ec_events',
|
183 |
+
'edit_others_posts' => 'edit_others_ai1ec_events',
|
184 |
+
'edit_private_posts' => 'edit_private_ai1ec_events',
|
185 |
+
'edit_published_posts' => 'edit_published_ai1ec_events',
|
186 |
+
'delete_post' => 'delete_ai1ec_event',
|
187 |
+
'delete_posts' => 'delete_ai1ec_events',
|
188 |
+
'delete_others_posts' => 'delete_others_ai1ec_events',
|
189 |
+
'delete_published_posts' => 'delete_published_ai1ec_events',
|
190 |
+
'delete_private_posts' => 'delete_private_ai1ec_events',
|
191 |
+
'publish_posts' => 'publish_ai1ec_events',
|
192 |
+
'read_private_posts' => 'read_private_ai1ec_events' ),
|
193 |
+
'has_archive' => true,
|
194 |
+
'hierarchical' => false,
|
195 |
+
'menu_position' => 5,
|
196 |
+
'supports' => $supports
|
197 |
+
);
|
198 |
+
|
199 |
+
// ========================================
|
200 |
+
// = labels for event categories taxonomy =
|
201 |
+
// ========================================
|
202 |
+
$events_categories_labels = array(
|
203 |
+
'name' => _x( 'Event Categories', AI1EC_PLUGIN_NAME ),
|
204 |
+
'singular_name' => _x( 'Event Category', AI1EC_PLUGIN_NAME )
|
205 |
+
);
|
206 |
+
|
207 |
+
// ==================================
|
208 |
+
// = labels for event tags taxonomy =
|
209 |
+
// ==================================
|
210 |
+
$events_tags_labels = array(
|
211 |
+
'name' => _x( 'Event Tags', AI1EC_PLUGIN_NAME ),
|
212 |
+
'singular_name' => _x( 'Event Tag', AI1EC_PLUGIN_NAME )
|
213 |
+
);
|
214 |
+
|
215 |
+
// ======================================
|
216 |
+
// = args for event categories taxonomy =
|
217 |
+
// ======================================
|
218 |
+
$events_categories_args = array(
|
219 |
+
'labels' => $events_categories_labels,
|
220 |
+
'hierarchical' => true,
|
221 |
+
'rewrite' => array( 'slug' => 'events_categories' ),
|
222 |
+
'capabilities' => array(
|
223 |
+
'manage_terms' => 'manage_categories',
|
224 |
+
'edit_terms' => 'manage_categories',
|
225 |
+
'delete_terms' => 'manage_categories',
|
226 |
+
'assign_terms' => 'edit_ai1ec_events'
|
227 |
+
)
|
228 |
+
);
|
229 |
+
|
230 |
+
// ================================
|
231 |
+
// = args for event tags taxonomy =
|
232 |
+
// ================================
|
233 |
+
$events_tags_args = array(
|
234 |
+
'labels' => $events_tags_labels,
|
235 |
+
'hierarchical' => false,
|
236 |
+
'rewrite' => array( 'slug' => 'events_tags' ),
|
237 |
+
'capabilities' => array(
|
238 |
+
'manage_terms' => 'manage_categories',
|
239 |
+
'edit_terms' => 'manage_categories',
|
240 |
+
'delete_terms' => 'manage_categories',
|
241 |
+
'assign_terms' => 'edit_ai1ec_events'
|
242 |
+
)
|
243 |
+
);
|
244 |
+
|
245 |
+
// ======================================
|
246 |
+
// = register event categories taxonomy =
|
247 |
+
// ======================================
|
248 |
+
register_taxonomy( 'events_categories', array( AI1EC_POST_TYPE ), $events_categories_args );
|
249 |
+
|
250 |
+
// ================================
|
251 |
+
// = register event tags taxonomy =
|
252 |
+
// ================================
|
253 |
+
register_taxonomy( 'events_tags', array( AI1EC_POST_TYPE ), $events_tags_args );
|
254 |
+
|
255 |
+
// ========================================
|
256 |
+
// = register custom post type for events =
|
257 |
+
// ========================================
|
258 |
+
register_post_type( AI1EC_POST_TYPE, $args );
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* taxonomy_filter_restrict_manage_posts function
|
263 |
+
*
|
264 |
+
* Adds filter dropdowns for event categories and event tags
|
265 |
+
*
|
266 |
+
* @return void
|
267 |
+
**/
|
268 |
+
function taxonomy_filter_restrict_manage_posts() {
|
269 |
+
global $typenow;
|
270 |
+
|
271 |
+
// =============================================
|
272 |
+
// = add the dropdowns only on the events page =
|
273 |
+
// =============================================
|
274 |
+
if( $typenow == AI1EC_POST_TYPE ) {
|
275 |
+
$filters = get_object_taxonomies( $typenow );
|
276 |
+
foreach( $filters as $tax_slug ) {
|
277 |
+
$tax_obj = get_taxonomy( $tax_slug );
|
278 |
+
wp_dropdown_categories( array(
|
279 |
+
'show_option_all' => __( 'Show All ' . $tax_obj->label, AI1EC_PLUGIN_NAME ),
|
280 |
+
'taxonomy' => $tax_slug,
|
281 |
+
'name' => $tax_obj->name,
|
282 |
+
'orderby' => 'name',
|
283 |
+
'selected' => $_GET[$tax_slug],
|
284 |
+
'hierarchical' => $tax_obj->hierarchical,
|
285 |
+
'show_count' => false,
|
286 |
+
'hide_empty' => true
|
287 |
+
));
|
288 |
+
}
|
289 |
+
}
|
290 |
+
}
|
291 |
+
|
292 |
+
/**
|
293 |
+
* get_all_items_name function
|
294 |
+
*
|
295 |
+
* If current user can publish events and there
|
296 |
+
* is at least 1 event pending, append the pending
|
297 |
+
* events number to the menu
|
298 |
+
*
|
299 |
+
* @return string
|
300 |
+
**/
|
301 |
+
function get_all_items_name() {
|
302 |
+
|
303 |
+
// if current user can publish events
|
304 |
+
if( current_user_can( 'publish_ai1ec_events' ) ) {
|
305 |
+
// get all pending events
|
306 |
+
$query = new WP_Query( array ( 'post_type' => 'ai1ec_event', 'post_status' => 'pending', 'posts_per_page' => -1, ) );
|
307 |
+
|
308 |
+
// at least 1 pending event?
|
309 |
+
if( $query->post_count > 0 ) {
|
310 |
+
// append the pending events number to the menu
|
311 |
+
return sprintf( __( 'All Events <span class="update-plugins count-%d" title="%d Pending Events"><span class="update-count">%d</span></span>', AI1EC_PLUGIN_NAME ),
|
312 |
+
$query->post_count, $query->post_count, $query->post_count );
|
313 |
+
}
|
314 |
+
}
|
315 |
+
|
316 |
+
// no pending events, or the user doesn't have sufficient capabilities
|
317 |
+
return __( 'All Events', AI1EC_PLUGIN_NAME );
|
318 |
+
}
|
319 |
+
|
320 |
+
/**
|
321 |
+
* taxonomy_filter_post_type_request function
|
322 |
+
*
|
323 |
+
* Adds filtering of events list by event tags and event categories
|
324 |
+
*
|
325 |
+
* @return void
|
326 |
+
**/
|
327 |
+
function taxonomy_filter_post_type_request( $query ) {
|
328 |
+
global $pagenow, $typenow;
|
329 |
+
if( 'edit.php' == $pagenow ) {
|
330 |
+
$filters = get_object_taxonomies( $typenow );
|
331 |
+
foreach( $filters as $tax_slug ) {
|
332 |
+
$var = &$query->query_vars[$tax_slug];
|
333 |
+
if( isset( $var ) ) {
|
334 |
+
$term = null;
|
335 |
+
|
336 |
+
if( is_numeric( $var ) )
|
337 |
+
$term = get_term_by( 'id', $var, $tax_slug );
|
338 |
+
else
|
339 |
+
$term = get_term_by( 'slug', $var, $tax_slug );
|
340 |
+
|
341 |
+
$var = $term->slug;
|
342 |
+
}
|
343 |
+
}
|
344 |
+
}
|
345 |
+
// ===========================
|
346 |
+
// = Order by Event date ASC =
|
347 |
+
// ===========================
|
348 |
+
if( $typenow == 'ai1ec_event' ) {
|
349 |
+
if( ! array_key_exists( 'orderby', $query->query_vars ) ) {
|
350 |
+
$query->query_vars["orderby"] = 'ai1ec_event_date';
|
351 |
+
$query->query_vars["order"] = 'desc';
|
352 |
+
}
|
353 |
+
}
|
354 |
+
|
355 |
+
}
|
356 |
+
|
357 |
+
/**
|
358 |
+
* orderby function
|
359 |
+
*
|
360 |
+
* Orders events by event date
|
361 |
+
*
|
362 |
+
* @param string $orderby Orderby sql
|
363 |
+
* @param object $wp_query
|
364 |
+
*
|
365 |
+
* @return void
|
366 |
+
**/
|
367 |
+
function orderby( $orderby, $wp_query ) {
|
368 |
+
global $typenow, $wpdb, $post;
|
369 |
+
|
370 |
+
if( $typenow == 'ai1ec_event' ) {
|
371 |
+
$wp_query->query = wp_parse_args( $wp_query->query );
|
372 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
373 |
+
if( 'ai1ec_event_date' == @$wp_query->query['orderby'] ) {
|
374 |
+
$orderby = "(SELECT start FROM {$table_name} WHERE post_id = $wpdb->posts.ID) " . $wp_query->get('order');
|
375 |
+
} else if( empty( $wp_query->query['orderby'] ) ) {
|
376 |
+
$orderby = "(SELECT start FROM {$table_name} WHERE post_id = $wpdb->posts.ID) " . 'desc';
|
377 |
+
}
|
378 |
+
}
|
379 |
+
return $orderby;
|
380 |
+
}
|
381 |
+
|
382 |
+
/**
|
383 |
+
* add_meta_boxes function
|
384 |
+
*
|
385 |
+
* Display event meta_box when creating or editing an event
|
386 |
+
*
|
387 |
+
* @return void
|
388 |
+
**/
|
389 |
+
function add_meta_boxes() {
|
390 |
+
global $ai1ec_events_controller;
|
391 |
+
add_meta_box(
|
392 |
+
AI1EC_POST_TYPE,
|
393 |
+
__( 'Event Details', AI1EC_PLUGIN_NAME ),
|
394 |
+
array( &$ai1ec_events_controller, 'meta_box_view' ),
|
395 |
+
AI1EC_POST_TYPE
|
396 |
+
);
|
397 |
+
}
|
398 |
+
|
399 |
+
/**
|
400 |
+
* change_columns function
|
401 |
+
*
|
402 |
+
* Adds Event date/time column to our custom post type
|
403 |
+
* and renames Date column to Post Date
|
404 |
+
*
|
405 |
+
* @param array $columns Existing columns
|
406 |
+
*
|
407 |
+
* @return array Updated columns array
|
408 |
+
**/
|
409 |
+
function change_columns( $columns ) {
|
410 |
+
$columns["date"] = __( 'Post Date', AI1EC_PLUGIN_NAME );
|
411 |
+
$columns["ai1ec_event_date"] = __( 'Event date/time', AI1EC_PLUGIN_NAME );
|
412 |
+
return $columns;
|
413 |
+
}
|
414 |
+
|
415 |
+
/**
|
416 |
+
* custom_columns function
|
417 |
+
*
|
418 |
+
* Adds content for custom columns
|
419 |
+
*
|
420 |
+
* @return void
|
421 |
+
**/
|
422 |
+
function custom_columns( $column, $post_id ) {
|
423 |
+
global $ai1ec_events_helper;
|
424 |
+
switch( $column ) {
|
425 |
+
case 'ai1ec_event_date':
|
426 |
+
$e = new Ai1ec_Event( $post_id );
|
427 |
+
echo $e->short_start_date . ' ' . $e->short_start_time . " - " . $e->short_end_date . ' ' .$e->short_end_time;
|
428 |
+
break;
|
429 |
+
}
|
430 |
+
}
|
431 |
+
|
432 |
+
/**
|
433 |
+
* sortable_columns function
|
434 |
+
*
|
435 |
+
* Enable sorting of columns
|
436 |
+
*
|
437 |
+
* @return void
|
438 |
+
**/
|
439 |
+
function sortable_columns( $columns ) {
|
440 |
+
$columns["ai1ec_event_date"] = 'ai1ec_event_date';
|
441 |
+
return $columns;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* get_param function
|
446 |
+
*
|
447 |
+
* Tries to return the parameter from POST and GET
|
448 |
+
* incase it is missing, default value is returned
|
449 |
+
*
|
450 |
+
* @param string $param Parameter to return
|
451 |
+
* @param mixed $default Default value
|
452 |
+
*
|
453 |
+
* @return mixed
|
454 |
+
**/
|
455 |
+
function get_param( $param, $default='' ) {
|
456 |
+
return isset( $_POST[$param] )
|
457 |
+
? $_POST[$param]
|
458 |
+
: isset( $_GET[$param] )
|
459 |
+
? $_GET[$param]
|
460 |
+
: $default;
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* get_param_delimiter_char function
|
465 |
+
*
|
466 |
+
* Returns the delimiter character in a link
|
467 |
+
*
|
468 |
+
* @param string $link Link to parse
|
469 |
+
*
|
470 |
+
* @return string
|
471 |
+
**/
|
472 |
+
function get_param_delimiter_char( $link ) {
|
473 |
+
return strpos( $link, '?' ) === false ? '?' : '&';
|
474 |
+
}
|
475 |
+
|
476 |
+
/**
|
477 |
+
* inject_categories function
|
478 |
+
*
|
479 |
+
* Displays event categories whenever post categories are requested
|
480 |
+
*
|
481 |
+
* @param array $terms Terms to be returned by get_terms()
|
482 |
+
* @param array $taxonomies Taxonomies requested in get_terms()
|
483 |
+
* @param array $args Args passed to get_terms()
|
484 |
+
*
|
485 |
+
* @return string|array If "category" taxonomy was requested, then returns
|
486 |
+
* $terms with fake category pointing to calendar page
|
487 |
+
* with its children being the event categories
|
488 |
+
**/
|
489 |
+
function inject_categories( $terms, $taxonomies, $args )
|
490 |
+
{
|
491 |
+
global $ai1ec_settings;
|
492 |
+
|
493 |
+
if( in_array( 'category', $taxonomies ) )
|
494 |
+
{
|
495 |
+
// Create fake calendar page category
|
496 |
+
$count_args = $args;
|
497 |
+
$count_args['fields'] = 'count';
|
498 |
+
$count = get_terms( 'events_categories', $count_args );
|
499 |
+
$post = get_post( $ai1ec_settings->calendar_page_id );
|
500 |
+
switch( $args['fields'] )
|
501 |
+
{
|
502 |
+
case 'all':
|
503 |
+
$calendar = (object) array(
|
504 |
+
'term_id' => AI1EC_FAKE_CATEGORY_ID,
|
505 |
+
'name' => $post->post_title,
|
506 |
+
'slug' => $post->post_name,
|
507 |
+
'taxonomy' => 'events_categories',
|
508 |
+
'description' => '',
|
509 |
+
'parent' => 0,
|
510 |
+
'count' => $count,
|
511 |
+
);
|
512 |
+
break;
|
513 |
+
case 'ids':
|
514 |
+
$calendar = 'ai1ec_calendar';
|
515 |
+
break;
|
516 |
+
case 'names':
|
517 |
+
$calendar = $post->post_title;
|
518 |
+
break;
|
519 |
+
}
|
520 |
+
$terms[] = $calendar;
|
521 |
+
|
522 |
+
if( $args['hierarchical'] ) {
|
523 |
+
$children = get_terms( 'events_categories', $args );
|
524 |
+
foreach( $children as &$child ) {
|
525 |
+
if( is_object( $child ) && $child->parent == 0 )
|
526 |
+
$child->parent = AI1EC_FAKE_CATEGORY_ID;
|
527 |
+
$terms[] = $child;
|
528 |
+
}
|
529 |
+
}
|
530 |
+
}
|
531 |
+
|
532 |
+
return $terms;
|
533 |
+
}
|
534 |
+
|
535 |
+
/**
|
536 |
+
* function calendar_term_link
|
537 |
+
*
|
538 |
+
* Corrects the URL for the calendar page when injected into the post
|
539 |
+
* categories.
|
540 |
+
*
|
541 |
+
* @param string $link The normally generated link
|
542 |
+
* @param object $term The term that we're getting the link for
|
543 |
+
* @param string $taxonomy The name of the taxonomy of interest
|
544 |
+
*
|
545 |
+
* @return string The correct link to the calendar page
|
546 |
+
*/
|
547 |
+
function calendar_term_link( $link, $term, $taxonomy )
|
548 |
+
{
|
549 |
+
global $ai1ec_calendar_helper;
|
550 |
+
|
551 |
+
if( $taxonomy == 'events_categories' ) {
|
552 |
+
if( $term->term_id == AI1EC_FAKE_CATEGORY_ID )
|
553 |
+
$link = $ai1ec_calendar_helper->get_calendar_url( null );
|
554 |
+
else
|
555 |
+
$link = $ai1ec_calendar_helper->get_calendar_url( null, array( $term->term_id ) );
|
556 |
+
}
|
557 |
+
|
558 |
+
return $link;
|
559 |
+
}
|
560 |
+
|
561 |
+
/**
|
562 |
+
* function selected_category_link
|
563 |
+
*
|
564 |
+
* Corrects the output of wp_list_categories so that the currently viewed
|
565 |
+
* event category (in calendar view) has the "active" CSS class applied to it.
|
566 |
+
*
|
567 |
+
* @param string $output The normally generated output of wp_list_categories()
|
568 |
+
* @param object $args The args passed to wp_list_categories()
|
569 |
+
*
|
570 |
+
* @return string The corrected output
|
571 |
+
*/
|
572 |
+
function selected_category_link( $output, $args )
|
573 |
+
{
|
574 |
+
global $ai1ec_calendar_controller, $ai1ec_settings;
|
575 |
+
|
576 |
+
// First check if current page is calendar
|
577 |
+
if( is_page( $ai1ec_settings->calendar_page_id ) )
|
578 |
+
{
|
579 |
+
$cat_ids = array_filter( split( ',', $ai1ec_calendar_controller->get_requested_categories() ), 'is_numeric' );
|
580 |
+
if( $cat_ids ) {
|
581 |
+
// Mark each filtered event category link as selected
|
582 |
+
foreach( $cat_ids as $cat_id ) {
|
583 |
+
$output = str_replace(
|
584 |
+
'class="cat-item cat-item-' . $cat_id . '"',
|
585 |
+
'class="cat-item cat-item-' . $cat_id . ' current-cat current_page_item"',
|
586 |
+
$output );
|
587 |
+
}
|
588 |
+
// Mark calendar page link as selected parent
|
589 |
+
$output = str_replace(
|
590 |
+
'class="cat-item cat-item-' . AI1EC_FAKE_CATEGORY_ID . '"',
|
591 |
+
'class="cat-item cat-item-' . AI1EC_FAKE_CATEGORY_ID . ' current-cat-parent"',
|
592 |
+
$output );
|
593 |
+
} else {
|
594 |
+
// No categories filtered, so mark calendar page link as selected
|
595 |
+
$output = str_replace(
|
596 |
+
'class="cat-item cat-item-' . AI1EC_FAKE_CATEGORY_ID . '"',
|
597 |
+
'class="cat-item cat-item-' . AI1EC_FAKE_CATEGORY_ID . ' current-cat current_page_item"',
|
598 |
+
$output );
|
599 |
+
}
|
600 |
+
}
|
601 |
+
|
602 |
+
return $output;
|
603 |
+
}
|
604 |
+
|
605 |
+
/**
|
606 |
+
* admin_notices function
|
607 |
+
*
|
608 |
+
* Notify the user about anything special.
|
609 |
+
*
|
610 |
+
* @return void
|
611 |
+
**/
|
612 |
+
function admin_notices() {
|
613 |
+
global $ai1ec_view_helper,
|
614 |
+
$ai1ec_settings,
|
615 |
+
$plugin_page;
|
616 |
+
|
617 |
+
// If calendar page ID has not been set, and we're not updating the settings
|
618 |
+
// page, the calendar is not properly set up yet
|
619 |
+
if( ! $ai1ec_settings->calendar_page_id && ! isset( $_REQUEST['ai1ec_save_settings'] ) )
|
620 |
+
{
|
621 |
+
$args = array();
|
622 |
+
// If not on the settings page already, direct user there with a message
|
623 |
+
if( $plugin_page == 'all-in-one-events-calendar-settings' ) {
|
624 |
+
$args['msg'] = __( 'To set up the plugin, please select an option in the <strong>Calendar page</strong> dropdown list, then click <strong>Update Settings</strong>.', AI1EC_PLUGIN_NAME );
|
625 |
+
// Else instruct user as to what to do on the settings page
|
626 |
+
} else {
|
627 |
+
$args['msg'] = sprintf(
|
628 |
+
__( 'The plugin is installed, but has not been configured. <a href="%s">Click here to set it up now »</a>', AI1EC_PLUGIN_NAME ),
|
629 |
+
admin_url( 'edit.php?post_type=ai1ec_event&page=all-in-one-events-calendar-settings' )
|
630 |
+
);
|
631 |
+
}
|
632 |
+
$ai1ec_view_helper->display( 'admin_notices.php', $args );
|
633 |
+
}
|
634 |
+
}
|
635 |
+
}
|
636 |
+
// END class
|
app/helper/class-ai1ec-calendar-helper.php
ADDED
@@ -0,0 +1,542 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-calendar-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Calendar_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Calendar_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* get_events_for_month function
|
49 |
+
*
|
50 |
+
* Return an array of all dates for the current month as an associative
|
51 |
+
* array, with each element's value being another array of event objects
|
52 |
+
* representing the events occuring on that date.
|
53 |
+
*
|
54 |
+
* @param int $time the UNIX timestamp of a date within the desired month
|
55 |
+
* @param array $categories the categories to filter events by
|
56 |
+
* @param array $tags the tags to filter events by
|
57 |
+
*
|
58 |
+
* @return array array of arrays as per function description
|
59 |
+
**/
|
60 |
+
function get_events_for_month( $time, $categories = array(), $tags = array() )
|
61 |
+
{
|
62 |
+
global $ai1ec_events_helper;
|
63 |
+
|
64 |
+
$days_events = array();
|
65 |
+
|
66 |
+
$bits = $ai1ec_events_helper->gmgetdate( $time );
|
67 |
+
$last_day = gmdate( 't', $time );
|
68 |
+
|
69 |
+
// ==========================================
|
70 |
+
// = Iterate through each date of the month =
|
71 |
+
// ==========================================
|
72 |
+
for( $day = 1; $day <= $last_day; $day++ )
|
73 |
+
{
|
74 |
+
$start_time = gmmktime( 0, 0, 0, $bits['mon'], $day, $bits['year'] );
|
75 |
+
$end_time = gmmktime( 0, 0, 0, $bits['mon'], $day + 1, $bits['year'] );
|
76 |
+
|
77 |
+
$days_events[$day] = $this->get_events_between(
|
78 |
+
$start_time, $end_time, 'publish', $categories, $tags );
|
79 |
+
}
|
80 |
+
|
81 |
+
return $days_events;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* get_month_cell_array function
|
86 |
+
*
|
87 |
+
* Return an array of weeks, each containing an array of days, each
|
88 |
+
* containing the date for the day ['date'] (if inside the month) and
|
89 |
+
* the events ['events'] (if any) for the day.
|
90 |
+
*
|
91 |
+
* @param int $timestamp UNIX timestamp of the 1st day of the desired
|
92 |
+
* month to display
|
93 |
+
* @param array $days_events list of events for each day of the month in
|
94 |
+
* the format returned by get_events_for_month()
|
95 |
+
*
|
96 |
+
* @return void
|
97 |
+
**/
|
98 |
+
function get_month_cell_array( $timestamp, $days_events )
|
99 |
+
{
|
100 |
+
global $ai1ec_settings, $ai1ec_events_helper;
|
101 |
+
|
102 |
+
// Decompose date into components, used for calculations below
|
103 |
+
$bits = $ai1ec_events_helper->gmgetdate( $timestamp );
|
104 |
+
$today = $ai1ec_events_helper->gmgetdate( $ai1ec_events_helper->gmt_to_local( time() ) ); // Used to flag today's cell
|
105 |
+
|
106 |
+
// Figure out index of first table cell
|
107 |
+
$first_cell_index = gmdate( 'w', $timestamp );
|
108 |
+
// Modify weekday based on start of week setting
|
109 |
+
$first_cell_index = ( 7 + $first_cell_index - $ai1ec_settings->week_start_day ) % 7;
|
110 |
+
|
111 |
+
// Get the last day of the month
|
112 |
+
$last_day = gmdate( 't', $timestamp );
|
113 |
+
$last_timestamp = gmmktime( 0, 0, 0, $bits['mon'], $last_day, $bits['year'] );
|
114 |
+
// Figure out index of last table cell
|
115 |
+
$last_cell_index = gmdate( 'w', $last_timestamp );
|
116 |
+
// Modify weekday based on start of week setting
|
117 |
+
$last_cell_index = ( 7 + $last_cell_index - $ai1ec_settings->week_start_day ) % 7;
|
118 |
+
|
119 |
+
$weeks = array();
|
120 |
+
$week = 0;
|
121 |
+
$weeks[$week] = array();
|
122 |
+
|
123 |
+
// Insert any needed blank cells into first week
|
124 |
+
for( $i = 0; $i < $first_cell_index; $i++ ) {
|
125 |
+
$weeks[$week][] = array( 'date' => null, 'events' => array() );
|
126 |
+
}
|
127 |
+
|
128 |
+
// Insert each month's day and associated events
|
129 |
+
for( $i = 1; $i <= $last_day; $i++ ) {
|
130 |
+
$weeks[$week][] = array(
|
131 |
+
'date' => $i,
|
132 |
+
'today' =>
|
133 |
+
$bits['year'] == $today['year'] &&
|
134 |
+
$bits['mon'] == $today['mon'] &&
|
135 |
+
$i == $today['mday'],
|
136 |
+
'events' => $days_events[$i]
|
137 |
+
);
|
138 |
+
// If reached the end of the week, increment week
|
139 |
+
if( count( $weeks[$week] ) == 7 )
|
140 |
+
$week++;
|
141 |
+
}
|
142 |
+
|
143 |
+
// Insert any needed blank cells into last week
|
144 |
+
for( $i = $last_cell_index + 1; $i < 7; $i++ ) {
|
145 |
+
$weeks[$week][] = array( 'date' => null, 'events' => array() );
|
146 |
+
}
|
147 |
+
|
148 |
+
return $weeks;
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* get_events_between function
|
153 |
+
*
|
154 |
+
* Return all events starting after the given start time and before the
|
155 |
+
* given end time. If there are any all-day events spanning this period,
|
156 |
+
* then return those as well. All-day events are returned first.
|
157 |
+
*
|
158 |
+
* @param int $start_time limit to events starting after this (local) UNIX time
|
159 |
+
* @param int $end_time limit to events starting before this (local) UNIX time
|
160 |
+
* @param string $post_status limit to events matching this post_status
|
161 |
+
* (null for no restriction)
|
162 |
+
*
|
163 |
+
* @return array list of matching event objects
|
164 |
+
**/
|
165 |
+
function get_events_between( $start_time, $end_time, $post_status = 'publish' ) {
|
166 |
+
global $wpdb, $ai1ec_events_helper;
|
167 |
+
|
168 |
+
// Convert timestamps to MySQL format in GMT time
|
169 |
+
$start_time = $ai1ec_events_helper->local_to_gmt( $start_time );
|
170 |
+
$end_time = $ai1ec_events_helper->local_to_gmt( $end_time );
|
171 |
+
|
172 |
+
// Query arguments
|
173 |
+
$args = array(
|
174 |
+
$start_time,
|
175 |
+
$end_time,
|
176 |
+
);
|
177 |
+
if( $post_status != null ) $args[] = $post_status;
|
178 |
+
|
179 |
+
$query = $wpdb->prepare(
|
180 |
+
"SELECT p.*, e.post_id, i.id AS instance_id, " .
|
181 |
+
"UNIX_TIMESTAMP( i.start ) AS start, " .
|
182 |
+
"UNIX_TIMESTAMP( i.end ) AS end, " .
|
183 |
+
// Treat event instances that span 24 hours as all-day
|
184 |
+
"IF( e.allday, e.allday, i.end = DATE_ADD( i.start, INTERVAL 1 DAY ) ) AS allday, " .
|
185 |
+
"e.recurrence_rules, e.exception_rules, e.recurrence_dates, e.exception_dates, " .
|
186 |
+
"e.venue, e.country, e.address, e.city, e.province, e.postal_code, " .
|
187 |
+
"e.show_map, e.contact_name, e.contact_phone, e.contact_email, e.cost, " .
|
188 |
+
"e.ical_feed_url, e.ical_source_url, e.ical_organizer, e.ical_contact, e.ical_uid " .
|
189 |
+
"FROM {$wpdb->prefix}ai1ec_events e " .
|
190 |
+
"INNER JOIN $wpdb->posts p ON p.ID = e.post_id " .
|
191 |
+
"INNER JOIN {$wpdb->prefix}ai1ec_event_instances i ON e.post_id = i.post_id " .
|
192 |
+
"WHERE post_type = '" . AI1EC_POST_TYPE . "' " .
|
193 |
+
"AND i.start >= FROM_UNIXTIME( %d ) " .
|
194 |
+
"AND i.start < FROM_UNIXTIME( %d ) " .
|
195 |
+
( $post_status == null ? '' : "AND post_status = %s " ) .
|
196 |
+
"ORDER BY allday DESC, i.start ASC, post_title ASC",
|
197 |
+
$args );
|
198 |
+
$events = $wpdb->get_results( $query, ARRAY_A );
|
199 |
+
foreach( $events as &$event ) {
|
200 |
+
$event = new Ai1ec_Event( $event );
|
201 |
+
}
|
202 |
+
|
203 |
+
return $events;
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* get_events_relative_to function
|
208 |
+
*
|
209 |
+
* Return all events starting after the given reference time, limiting the
|
210 |
+
* result set to a maximum of $limit items, offset by $page_offset. A
|
211 |
+
* negative $page_offset can be provided, which will return events *before*
|
212 |
+
* the reference time, as expected.
|
213 |
+
*
|
214 |
+
* @param int $time limit to events starting after this (local) UNIX time
|
215 |
+
* @param int $limit return a maximum of this number of items
|
216 |
+
* @param int $page_offset offset the result set by $limit times this number
|
217 |
+
* @param string $post_status limit to events matching this post_status
|
218 |
+
* (null for no restriction)
|
219 |
+
*
|
220 |
+
*
|
221 |
+
* @return array three-element array:
|
222 |
+
* ['events'] an array of matching event objects
|
223 |
+
* ['prev'] true if more previous events
|
224 |
+
* ['next'] true if more next events
|
225 |
+
**/
|
226 |
+
function get_events_relative_to( $time, $limit = 0, $page_offset = 0, $post_status = 'publish' ) {
|
227 |
+
global $wpdb, $ai1ec_events_helper;
|
228 |
+
|
229 |
+
// Figure out what the beginning of the day is to properly query all-day
|
230 |
+
// events; then convert to GMT time
|
231 |
+
$bits = $ai1ec_events_helper->gmgetdate( $time );
|
232 |
+
|
233 |
+
// Convert timestamp to GMT time
|
234 |
+
$time = $ai1ec_events_helper->local_to_gmt( $time );
|
235 |
+
|
236 |
+
// Query arguments
|
237 |
+
$args = array( $time );
|
238 |
+
if( $post_status != null ) $args[] = $post_status;
|
239 |
+
|
240 |
+
if( $page_offset >= 0 )
|
241 |
+
$first_record = $page_offset * $limit;
|
242 |
+
else
|
243 |
+
$first_record = ( -$page_offset - 1 ) * $limit;
|
244 |
+
|
245 |
+
$query = $wpdb->prepare(
|
246 |
+
"SELECT SQL_CALC_FOUND_ROWS p.*, e.post_id, i.id AS instance_id, " .
|
247 |
+
"UNIX_TIMESTAMP( i.start ) AS start, " .
|
248 |
+
"UNIX_TIMESTAMP( i.end ) AS end, " .
|
249 |
+
// Treat event instances that span 24 hours as all-day
|
250 |
+
"IF( e.allday, e.allday, i.end = DATE_ADD( i.start, INTERVAL 1 DAY ) ) AS allday, " .
|
251 |
+
"e.recurrence_rules, e.exception_rules, e.recurrence_dates, e.exception_dates, " .
|
252 |
+
"e.venue, e.country, e.address, e.city, e.province, e.postal_code, " .
|
253 |
+
"e.show_map, e.contact_name, e.contact_phone, e.contact_email, e.cost, " .
|
254 |
+
"e.ical_feed_url, e.ical_source_url, e.ical_organizer, e.ical_contact, e.ical_uid " .
|
255 |
+
"FROM {$wpdb->prefix}ai1ec_events e " .
|
256 |
+
"INNER JOIN $wpdb->posts p ON e.post_id = p.ID " .
|
257 |
+
"INNER JOIN {$wpdb->prefix}ai1ec_event_instances i ON e.post_id = i.post_id " .
|
258 |
+
"WHERE post_type = '" . AI1EC_POST_TYPE . "' " .
|
259 |
+
"AND " .
|
260 |
+
( $page_offset >= 0 ? "i.end >= FROM_UNIXTIME( %d ) "
|
261 |
+
: "i.start < FROM_UNIXTIME( %d ) "
|
262 |
+
) .
|
263 |
+
( $post_status == null ? '' : "AND post_status = %s " ) .
|
264 |
+
// Reverse order when viewing negative pages, to get correct set of
|
265 |
+
// records. Then reverse results later to order them properly.
|
266 |
+
"ORDER BY i.start " . ( $page_offset >= 0 ? 'ASC' : 'DESC' ) .
|
267 |
+
", post_title " . ( $page_offset >= 0 ? 'ASC' : 'DESC' ) .
|
268 |
+
" LIMIT $first_record, $limit",
|
269 |
+
$args );
|
270 |
+
|
271 |
+
$events = $wpdb->get_results( $query, ARRAY_A );
|
272 |
+
|
273 |
+
// Re-order records if in negative page offset
|
274 |
+
if( $page_offset < 0 ) $events = array_reverse( $events );
|
275 |
+
|
276 |
+
foreach( $events as &$event ) {
|
277 |
+
$event = new Ai1ec_Event( $event );
|
278 |
+
}
|
279 |
+
|
280 |
+
// Find out if there are more records in the current nav direction
|
281 |
+
$more = $wpdb->get_var( 'SELECT FOUND_ROWS()' ) > $first_record + $limit;
|
282 |
+
|
283 |
+
// Navigating in the future
|
284 |
+
if( $page_offset > 0 ) {
|
285 |
+
$prev = true;
|
286 |
+
$next = $more;
|
287 |
+
}
|
288 |
+
// Navigating in the past
|
289 |
+
elseif( $page_offset < 0 ) {
|
290 |
+
$prev = $more;
|
291 |
+
$next = true;
|
292 |
+
}
|
293 |
+
// Navigating from the reference time
|
294 |
+
else {
|
295 |
+
$query = $wpdb->prepare(
|
296 |
+
"SELECT COUNT(*) " .
|
297 |
+
"FROM {$wpdb->prefix}ai1ec_events e " .
|
298 |
+
"INNER JOIN {$wpdb->prefix}ai1ec_event_instances i ON e.post_id = i.post_id " .
|
299 |
+
"INNER JOIN $wpdb->posts p ON e.post_id = p.ID " .
|
300 |
+
"WHERE post_type = '" . AI1EC_POST_TYPE . "' " .
|
301 |
+
"AND i.start < FROM_UNIXTIME( %d ) " .
|
302 |
+
( $post_status == null ? '' : "AND post_status = %s " ),
|
303 |
+
$args );
|
304 |
+
$prev = $wpdb->get_var( $query );
|
305 |
+
$next = $more;
|
306 |
+
}
|
307 |
+
return array(
|
308 |
+
'events' => $events,
|
309 |
+
'prev' => $prev,
|
310 |
+
'next' => $next,
|
311 |
+
);
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* get_agenda_date_array function
|
316 |
+
*
|
317 |
+
* Breaks down the given ordered array of event objects into dates, and
|
318 |
+
* outputs an ordered array of two-element associative arrays in the
|
319 |
+
* following format:
|
320 |
+
* key: localized UNIX timestamp of date
|
321 |
+
* value:
|
322 |
+
* ['events'] => two-element associatative array broken down thus:
|
323 |
+
* ['allday'] => all-day events occurring on this day
|
324 |
+
* ['notallday'] => all other events occurring on this day
|
325 |
+
* ['today'] => whether or not this date is today
|
326 |
+
*
|
327 |
+
* @param array $events
|
328 |
+
*
|
329 |
+
* @return array
|
330 |
+
**/
|
331 |
+
function get_agenda_date_array( $events ) {
|
332 |
+
global $ai1ec_events_helper;
|
333 |
+
|
334 |
+
$dates = array();
|
335 |
+
|
336 |
+
// Classify each event into a date/allday category
|
337 |
+
foreach( $events as $event ) {
|
338 |
+
$date = $ai1ec_events_helper->gmt_to_local( $event->start );
|
339 |
+
$date = $ai1ec_events_helper->gmgetdate( $date );
|
340 |
+
$timestamp = gmmktime( 0, 0, 0, $date['mon'], $date['mday'], $date['year'] );
|
341 |
+
$category = $event->allday ? 'allday' : 'notallday';
|
342 |
+
$dates[$timestamp]['events'][$category][] = $event;
|
343 |
+
}
|
344 |
+
|
345 |
+
// Flag today
|
346 |
+
$today = $ai1ec_events_helper->gmt_to_local( time() );
|
347 |
+
$today = $ai1ec_events_helper->gmgetdate( $today );
|
348 |
+
$today = gmmktime( 0, 0, 0, $today['mon'], $today['mday'], $today['year'] );
|
349 |
+
if( isset( $dates[$today] ) )
|
350 |
+
$dates[$today]['today'] = true;
|
351 |
+
|
352 |
+
return $dates;
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* get_calendar_url function
|
357 |
+
*
|
358 |
+
* Returns the URL of the configured calendar page in the default view,
|
359 |
+
* optionally preloaded at the month containing the given event (rather than
|
360 |
+
* today's date), and optionally prefiltered by the given category IDs and/or
|
361 |
+
* tag IDs.
|
362 |
+
*
|
363 |
+
* @param object|null $event The event to focus the calendar on
|
364 |
+
* @param array $cat_ids The category IDs to filter the calendar by
|
365 |
+
* @param array $tag_ids The tag IDs to filter the calendar by
|
366 |
+
*
|
367 |
+
* @return string The URL for this calendar
|
368 |
+
**/
|
369 |
+
function get_calendar_url( $event = null, $cat_ids = array(), $tag_ids = array() ) {
|
370 |
+
global $ai1ec_settings, $ai1ec_events_helper, $ai1ec_app_helper, $wpdb;
|
371 |
+
|
372 |
+
$url = get_permalink( $ai1ec_settings->calendar_page_id );
|
373 |
+
|
374 |
+
if( $event )
|
375 |
+
{
|
376 |
+
$url .= $ai1ec_app_helper->get_param_delimiter_char( $url );
|
377 |
+
|
378 |
+
switch( $ai1ec_settings->default_calendar_view )
|
379 |
+
{
|
380 |
+
case 'month':
|
381 |
+
// Get components of localized timstamps and calculate month offset
|
382 |
+
$today = $ai1ec_events_helper->gmgetdate( $ai1ec_events_helper->gmt_to_local( time() ) );
|
383 |
+
$desired = $ai1ec_events_helper->gmgetdate( $ai1ec_events_helper->gmt_to_local( $event->start ) );
|
384 |
+
$month_offset =
|
385 |
+
( $desired['year'] - $today['year'] ) * 12 +
|
386 |
+
$desired['mon'] - $today['mon'];
|
387 |
+
|
388 |
+
$url .= "ai1ec_month_offset=$month_offset";
|
389 |
+
break;
|
390 |
+
|
391 |
+
case 'agenda':
|
392 |
+
// Find out how many event instances are between today's first
|
393 |
+
// instance and the desired event's instance
|
394 |
+
$now = $ai1ec_events_helper->local_to_gmt( time() );
|
395 |
+
$after_today = $event->end >= $now;
|
396 |
+
$query = $wpdb->prepare(
|
397 |
+
"SELECT COUNT(*) FROM {$wpdb->prefix}ai1ec_events e " .
|
398 |
+
"INNER JOIN $wpdb->posts p ON e.post_id = p.ID " .
|
399 |
+
"INNER JOIN {$wpdb->prefix}ai1ec_event_instances i ON e.post_id = i.post_id " .
|
400 |
+
"WHERE post_type = '" . AI1EC_POST_TYPE . "' " .
|
401 |
+
"AND post_status = 'publish' " .
|
402 |
+
( $after_today
|
403 |
+
? "AND i.end >= FROM_UNIXTIME( %d ) AND i.end < FROM_UNIXTIME( %d ) "
|
404 |
+
: "AND i.start < FROM_UNIXTIME( %d ) AND i.start >= FROM_UNIXTIME( %d ) "
|
405 |
+
) .
|
406 |
+
"ORDER BY i.start ASC",
|
407 |
+
array( $now, $after_today ? $event->end : $event->start ) );
|
408 |
+
$count = $wpdb->get_var( $query );
|
409 |
+
// ( $count - 1 ) below solves boundary case for first event of each agenda page
|
410 |
+
$page_offset = intval( ( $count - 1 ) / $ai1ec_settings->agenda_events_per_page );
|
411 |
+
if( ! $after_today ) $page_offset = -1 - $page_offset;
|
412 |
+
|
413 |
+
$url .= "ai1ec_page_offset=$page_offset";
|
414 |
+
break;
|
415 |
+
}
|
416 |
+
|
417 |
+
$url .= "&ai1ec_active_event=$event->post_id";
|
418 |
+
}
|
419 |
+
|
420 |
+
if( $cat_ids )
|
421 |
+
$url .= $ai1ec_app_helper->get_param_delimiter_char( $url ) .
|
422 |
+
'ai1ec_cat_ids=' . join( ',', $cat_ids );
|
423 |
+
if( $tag_ids )
|
424 |
+
$url .= $ai1ec_app_helper->get_param_delimiter_char( $url ) .
|
425 |
+
'ai1ec_tag_ids=' . join( ',', $tag_ids );
|
426 |
+
|
427 |
+
return $url;
|
428 |
+
}
|
429 |
+
|
430 |
+
/**
|
431 |
+
* get_weekdays function
|
432 |
+
*
|
433 |
+
* Returns a list of abbreviated weekday names starting on the configured
|
434 |
+
* week start day setting.
|
435 |
+
*
|
436 |
+
* @return array
|
437 |
+
**/
|
438 |
+
function get_weekdays() {
|
439 |
+
global $ai1ec_settings;
|
440 |
+
static $weekdays;
|
441 |
+
|
442 |
+
if( ! isset( $weekdays ) )
|
443 |
+
{
|
444 |
+
$time = strtotime( 'next Sunday' );
|
445 |
+
$time = strtotime( "+{$ai1ec_settings->week_start_day} days", $time );
|
446 |
+
|
447 |
+
$weekdays = array();
|
448 |
+
for( $i = 0; $i < 7; $i++ ) {
|
449 |
+
$weekdays[] = strftime( '%a', $time );
|
450 |
+
$time += 60 * 60 * 24; // Add a day
|
451 |
+
}
|
452 |
+
}
|
453 |
+
return $weekdays;
|
454 |
+
}
|
455 |
+
|
456 |
+
/**
|
457 |
+
* get_month_pagination_links function
|
458 |
+
*
|
459 |
+
* Returns an associative array of four links for the month view of the
|
460 |
+
* calendar:
|
461 |
+
* previous year, previous month, next month, and next year, in that order.
|
462 |
+
* Each element's key is an associative array containing the link's ID
|
463 |
+
* ['id'], text ['text'] and value to assign to link's href ['href'].
|
464 |
+
*
|
465 |
+
* @param int $cur_offset month offset of current month, needed for hrefs
|
466 |
+
*
|
467 |
+
* @return array array of link information as described above
|
468 |
+
**/
|
469 |
+
function get_month_pagination_links( $cur_offset ) {
|
470 |
+
global $ai1ec_events_helper;
|
471 |
+
|
472 |
+
$links = array();
|
473 |
+
|
474 |
+
// Base timestamp on offset month
|
475 |
+
$bits = $ai1ec_events_helper->gmgetdate( $ai1ec_events_helper->gmt_to_local( time() ) );
|
476 |
+
$bits['mon'] += $cur_offset;
|
477 |
+
// 'mon' may now be out of range (< 1 or > 12), so recreate $bits to make sane
|
478 |
+
$bits = $ai1ec_events_helper->gmgetdate( gmmktime( 0, 0, 0, $bits['mon'], 1, $bits['year'] ) );
|
479 |
+
|
480 |
+
$links[] = array(
|
481 |
+
'id' => 'ai1ec-prev-year',
|
482 |
+
'text' => '« ' . ( $bits['year'] - 1 ),
|
483 |
+
'href' => '#action=ai1ec_month&ai1ec_month_offset=' . ( $cur_offset - 12 ),
|
484 |
+
);
|
485 |
+
$links[] = array(
|
486 |
+
'id' => 'ai1ec-prev-month',
|
487 |
+
'text' => '‹ ' . gmstrftime( '%B', gmmktime( 0, 0, 0, $bits['mon'] - 1, 1, $bits['year'] ) ),
|
488 |
+
'href' => '#action=ai1ec_month&ai1ec_month_offset=' . ( $cur_offset - 1 ),
|
489 |
+
);
|
490 |
+
$links[] = array(
|
491 |
+
'id' => 'ai1ec-next-month',
|
492 |
+
'text' => gmstrftime( '%B', gmmktime( 0, 0, 0, $bits['mon'] + 1, 1, $bits['year'] ) ) . ' ›',
|
493 |
+
'href' => '#action=ai1ec_month&ai1ec_month_offset=' . ( $cur_offset + 1 ),
|
494 |
+
);
|
495 |
+
$links[] = array(
|
496 |
+
'id' => 'ai1ec-next-year',
|
497 |
+
'text' => ( $bits['year'] + 1 ) . ' »',
|
498 |
+
'href' => '#action=ai1ec_month&ai1ec_month_offset=' . ( $cur_offset + 12 ),
|
499 |
+
);
|
500 |
+
|
501 |
+
return $links;
|
502 |
+
}
|
503 |
+
|
504 |
+
/**
|
505 |
+
* get_agenda_pagination_links function
|
506 |
+
*
|
507 |
+
* Returns an associative array of two links for the agenda view of the
|
508 |
+
* calendar: previous page (if previous events exist), next page (if next
|
509 |
+
* events exist), in that order.
|
510 |
+
* Each element' is an associative array containing the link ID ['id'],
|
511 |
+
* text ['text'] and value to assign to link's href ['href'].
|
512 |
+
*
|
513 |
+
* @param int $cur_offset page offset of agenda view, needed for hrefs
|
514 |
+
* @param int $prev whether there are more events before the current page
|
515 |
+
* @param int $next whether there are more events after the current page
|
516 |
+
*
|
517 |
+
* @return array array of link information as described above
|
518 |
+
**/
|
519 |
+
function get_agenda_pagination_links( $cur_offset, $prev = false, $next = false ) {
|
520 |
+
global $ai1ec_settings;
|
521 |
+
|
522 |
+
$links = array();
|
523 |
+
|
524 |
+
if( $prev ) {
|
525 |
+
$links['prev'] = array(
|
526 |
+
'id' => 'ai1ec-prev-page',
|
527 |
+
'text' => sprintf( __( '« Previous Events', AI1EC_PLUGIN_NAME ), $ai1ec_settings->agenda_events_per_page ),
|
528 |
+
'href' => '#action=ai1ec_agenda&ai1ec_page_offset=' . ( $cur_offset - 1 ),
|
529 |
+
);
|
530 |
+
}
|
531 |
+
if( $next ) {
|
532 |
+
$links['next'] = array(
|
533 |
+
'id' => 'ai1ec-next-page',
|
534 |
+
'text' => sprintf( __( 'Next Events »', AI1EC_PLUGIN_NAME ), $ai1ec_settings->agenda_events_per_page ),
|
535 |
+
'href' => '#action=ai1ec_agenda&ai1ec_page_offset=' . ( $cur_offset + 1 ),
|
536 |
+
);
|
537 |
+
}
|
538 |
+
|
539 |
+
return $links;
|
540 |
+
}
|
541 |
+
}
|
542 |
+
// END class
|
app/helper/class-ai1ec-events-helper.php
ADDED
@@ -0,0 +1,895 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-events-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Events_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Events_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* get_event function
|
49 |
+
*
|
50 |
+
* Fetches the event object with the given post ID. Uses the WP cache to
|
51 |
+
* make this more efficient if possible.
|
52 |
+
*
|
53 |
+
* @param int $post_id The ID of the post associated with the event
|
54 |
+
*
|
55 |
+
* @return Ai1ec_Event The associated event object
|
56 |
+
**/
|
57 |
+
static function get_event( $post_id )
|
58 |
+
{
|
59 |
+
$event = wp_cache_get( $post_id, AI1EC_POST_TYPE );
|
60 |
+
if( $event === false ) {
|
61 |
+
$event = new Ai1ec_Event( $post_id );
|
62 |
+
|
63 |
+
if( ! $event->post_id )
|
64 |
+
throw new Ai1ec_Event_Not_Found( "Event with ID '$post_id' could not be retrieved from the database." );
|
65 |
+
|
66 |
+
// Cache the event data
|
67 |
+
wp_cache_add( $post_id, $event, AI1EC_POST_TYPE );
|
68 |
+
}
|
69 |
+
return $event;
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* get_matching_event function
|
74 |
+
*
|
75 |
+
* Return event ID by iCalendar UID, feed url, start time and whether the
|
76 |
+
* event has recurrence rules (to differentiate between an event with a UID
|
77 |
+
* defining the recurrence pattern, and other events with with the same UID,
|
78 |
+
* which are just RECURRENCE-IDs).
|
79 |
+
*
|
80 |
+
* @param int $uid iCalendar UID property
|
81 |
+
* @param string $feed Feed URL
|
82 |
+
* @param int $start Start timestamp (GMT)
|
83 |
+
* @param bool $has_recurrence Whether the event has recurrence rules
|
84 |
+
* @param int|null $exclude_post_id Do not match against this post ID
|
85 |
+
*
|
86 |
+
* @return object|null Matching event's post ID, or null if no match
|
87 |
+
**/
|
88 |
+
function get_matching_event_id( $uid, $feed, $start, $has_recurrence = false, $exclude_post_id = null ) {
|
89 |
+
global $wpdb;
|
90 |
+
|
91 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
92 |
+
$query = "SELECT post_id FROM {$table_name} " .
|
93 |
+
"WHERE ical_feed_url = %s " .
|
94 |
+
"AND ical_uid = %s " .
|
95 |
+
"AND start = FROM_UNIXTIME( %d ) " .
|
96 |
+
( $has_recurrence ? 'AND NOT ' : 'AND ' ) .
|
97 |
+
"( recurrence_rules IS NULL OR recurrence_rules = '' )";
|
98 |
+
$args = array( $feed, $uid, $start );
|
99 |
+
if( ! is_null( $exclude_post_id ) ) {
|
100 |
+
$query .= 'AND post_id <> %d';
|
101 |
+
$args[] = $exclude_post_id;
|
102 |
+
}
|
103 |
+
|
104 |
+
return $wpdb->get_var( $wpdb->prepare( $query, $args ) );
|
105 |
+
}
|
106 |
+
|
107 |
+
/**
|
108 |
+
* delete_event_cache function
|
109 |
+
*
|
110 |
+
* Delete cache of event
|
111 |
+
*
|
112 |
+
* @param int $pid Event post ID
|
113 |
+
*
|
114 |
+
* @return void
|
115 |
+
**/
|
116 |
+
function delete_event_cache( $pid ) {
|
117 |
+
global $wpdb;
|
118 |
+
|
119 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_instances';
|
120 |
+
$wpdb->query( $wpdb->prepare( "DELETE FROM $table_name WHERE post_id = %d", $pid ) );
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* cache_event function
|
125 |
+
*
|
126 |
+
* Creates a new entry in the cache table for each date that the event appears
|
127 |
+
* (and does not already have an explicit RECURRENCE-ID instance, given its
|
128 |
+
* iCalendar UID).
|
129 |
+
*
|
130 |
+
* @param object $event Event to generate cache table for
|
131 |
+
*
|
132 |
+
* @return void
|
133 |
+
**/
|
134 |
+
function cache_event( &$event ) {
|
135 |
+
global $wpdb;
|
136 |
+
|
137 |
+
// Convert event's timestamps to local for correct calculations of
|
138 |
+
// recurrence.
|
139 |
+
// $gm_diff: Needed with SG_iCal_Freq, which doesn't use gm___ version of
|
140 |
+
// PHP date functions and calculates wrong recurrences sometimes
|
141 |
+
$gm_diff = mktime( 0 ) - gmmktime( 0 );
|
142 |
+
$event->start = $this->gmt_to_local( $event->start ) + $gm_diff;
|
143 |
+
$event->end = $this->gmt_to_local( $event->end ) + $gm_diff;
|
144 |
+
|
145 |
+
$evs = array();
|
146 |
+
$e = array(
|
147 |
+
'post_id' => $event->post_id,
|
148 |
+
'start' => $event->start,
|
149 |
+
'end' => $event->end,
|
150 |
+
);
|
151 |
+
$duration = $event->getDuration();
|
152 |
+
|
153 |
+
// Always cache initial instance
|
154 |
+
$evs[] = $e;
|
155 |
+
|
156 |
+
if( $event->recurrence_rules )
|
157 |
+
{
|
158 |
+
$count = 0;
|
159 |
+
$start = $event->start;
|
160 |
+
$freq = $event->getFrequency();
|
161 |
+
|
162 |
+
$freq->firstOccurrence();
|
163 |
+
while( ( $next = $freq->nextOccurrence( $start ) ) > 0 &&
|
164 |
+
$count < 1000 )
|
165 |
+
{
|
166 |
+
$count++;
|
167 |
+
$start = $next;
|
168 |
+
$e['start'] = $start;
|
169 |
+
$e['end'] = $start + $duration;
|
170 |
+
|
171 |
+
$evs[] = $e;
|
172 |
+
}
|
173 |
+
}
|
174 |
+
|
175 |
+
// Make entries unique (sometimes recurrence generator creates duplicates?)
|
176 |
+
$evs_unique = array();
|
177 |
+
foreach( $evs as $ev ) {
|
178 |
+
$evs_unique[ md5( serialize( $ev ) ) ] = $ev;
|
179 |
+
}
|
180 |
+
|
181 |
+
foreach( $evs_unique as $e )
|
182 |
+
{
|
183 |
+
// Find out if this event instance is already accounted for by an
|
184 |
+
// overriding 'RECURRENCE-ID' of the same iCalendar feed (by comparing the
|
185 |
+
// UID, start date, recurrence). If so, then do not create duplicate
|
186 |
+
// instance of event.
|
187 |
+
$matching_event_id = $event->ical_uid ?
|
188 |
+
$this->get_matching_event_id(
|
189 |
+
$event->ical_uid,
|
190 |
+
$event->ical_feed_url,
|
191 |
+
$start = $this->local_to_gmt( $e['start'] ) - $gm_diff,
|
192 |
+
false, // Only search events that don't define recurrence (i.e. only search for RECURRENCE-ID events)
|
193 |
+
$event->post_id
|
194 |
+
)
|
195 |
+
: null;
|
196 |
+
|
197 |
+
// If no other instance was found
|
198 |
+
if( is_null( $matching_event_id ) )
|
199 |
+
{
|
200 |
+
$start_day = date( 'j', $e['start'] );
|
201 |
+
$end_day = date( 'j', $e['end'] );
|
202 |
+
|
203 |
+
// If event spans days, create instance for each spanning day
|
204 |
+
if( $start_day != $end_day || $e['end'] - $e['start'] > 60 * 60 * 24 )
|
205 |
+
$this->create_cache_table_entries( $e, $gm_diff );
|
206 |
+
// Else cache single instance of event
|
207 |
+
else
|
208 |
+
$this->insert_event_in_cache_table( $e, $gm_diff );
|
209 |
+
}
|
210 |
+
}
|
211 |
+
}
|
212 |
+
|
213 |
+
/**
|
214 |
+
* insert_event_in_cache_table function
|
215 |
+
*
|
216 |
+
* Inserts a new record in the cache table
|
217 |
+
*
|
218 |
+
* @param array $event Event array
|
219 |
+
* @param int $gm_diff Different between local time and gmt time
|
220 |
+
*
|
221 |
+
* @return void
|
222 |
+
**/
|
223 |
+
function insert_event_in_cache_table( $event, $gm_diff ) {
|
224 |
+
global $wpdb;
|
225 |
+
|
226 |
+
// Return the start/end times to GMT zone
|
227 |
+
$event['start'] = $this->local_to_gmt( $event['start'] ) - $gm_diff;
|
228 |
+
$event['end'] = $this->local_to_gmt( $event['end'] ) - $gm_diff;
|
229 |
+
|
230 |
+
$wpdb->query(
|
231 |
+
$wpdb->prepare(
|
232 |
+
"INSERT INTO {$wpdb->prefix}ai1ec_event_instances " .
|
233 |
+
" ( post_id, start, end ) " .
|
234 |
+
"VALUES ( %d, FROM_UNIXTIME( %d ), FROM_UNIXTIME( %d ) )",
|
235 |
+
$event
|
236 |
+
)
|
237 |
+
);
|
238 |
+
}
|
239 |
+
|
240 |
+
/**
|
241 |
+
* create_cache_table_entries function
|
242 |
+
*
|
243 |
+
* Create a new entry for each day that the event spans.
|
244 |
+
*
|
245 |
+
* @param array $e Event array
|
246 |
+
* @param int $gm_diff Different between local time and GMT time
|
247 |
+
*
|
248 |
+
* @return void
|
249 |
+
**/
|
250 |
+
function create_cache_table_entries( $e, $gm_diff )
|
251 |
+
{
|
252 |
+
// Decompose start dates into components
|
253 |
+
$start_bits = getdate( $e['start'] );
|
254 |
+
|
255 |
+
// ============================================
|
256 |
+
// = Calculate the time for event's first day =
|
257 |
+
// ============================================
|
258 |
+
// Start time is event's original start time
|
259 |
+
$event_start = $e['start'];
|
260 |
+
// End time is beginning of next day
|
261 |
+
$event_end = mktime(
|
262 |
+
0, // hour
|
263 |
+
0, // minute
|
264 |
+
0, // second
|
265 |
+
$start_bits['mon'], // month
|
266 |
+
$start_bits['mday'] + 1, // day
|
267 |
+
$start_bits['year'] // year
|
268 |
+
);
|
269 |
+
// Cache first day
|
270 |
+
$this->insert_event_in_cache_table( array( 'post_id' => $e['post_id'], 'start' => $event_start, 'end' => $event_end ), $gm_diff );
|
271 |
+
|
272 |
+
// ====================================================
|
273 |
+
// = Calculate the time for event's intermediate days =
|
274 |
+
// ====================================================
|
275 |
+
// Start time is previous end time
|
276 |
+
$event_start = $event_end;
|
277 |
+
// End time one day ahead
|
278 |
+
$event_end += 60 * 60 * 24;
|
279 |
+
// Cache intermediate days
|
280 |
+
while( $event_end < $e['end'] ) {
|
281 |
+
$this->insert_event_in_cache_table( array( 'post_id' => $e['post_id'], 'start' => $event_start, 'end' => $event_end ), $gm_diff );
|
282 |
+
$event_start = $event_end; // Start time is previous end time
|
283 |
+
$event_end += 24 * 60 * 60; // Increment end time by 1 day
|
284 |
+
}
|
285 |
+
|
286 |
+
// ===========================================
|
287 |
+
// = Calculate the time for event's last day =
|
288 |
+
// ===========================================
|
289 |
+
// Start time is already correct (previous end time)
|
290 |
+
// End time is event end time
|
291 |
+
// Only insert if the last event instance if span is > 0
|
292 |
+
$event_end = $e['end'];
|
293 |
+
if( $event_end > $event_start )
|
294 |
+
// Cache last day
|
295 |
+
$this->insert_event_in_cache_table( array( 'post_id' => $e['post_id'], 'start' => $event_start, 'end' => $event_end ), $gm_diff );
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Returns the various preset recurrence options available (e.g.,
|
300 |
+
* 'DAILY', 'WEEKENDS', etc.).
|
301 |
+
*
|
302 |
+
* @return string An associative array of pattern names to English
|
303 |
+
* equivalents
|
304 |
+
*/
|
305 |
+
function get_repeat_patterns() {
|
306 |
+
static $options = array(
|
307 |
+
' ' => 'No repeat',
|
308 |
+
'DAILY' => 'Daily',
|
309 |
+
'MO' => 'Mondays',
|
310 |
+
'TU' => 'Tuesdays',
|
311 |
+
'WE' => 'Wednesdays',
|
312 |
+
'TH' => 'Thursdays',
|
313 |
+
'FR' => 'Fridays',
|
314 |
+
'SA' => 'Saturdays',
|
315 |
+
'SU' => 'Sundays',
|
316 |
+
'TU+TH' => 'Tuesdays & Thursdays',
|
317 |
+
'MO+WE+FR' => 'Mondays, Wednesdays & Fridays',
|
318 |
+
'WEEKDAYS' => 'Weekdays',
|
319 |
+
'WEEKENDS' => 'Weekends',
|
320 |
+
'WEEKLY' => 'Weekly',
|
321 |
+
'MONTHLY' => 'Monthly',
|
322 |
+
'YEARLY' => 'Yearly',
|
323 |
+
);
|
324 |
+
|
325 |
+
return $options;
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Generates and returns repeat dropdown
|
330 |
+
*
|
331 |
+
* @param Integer|NULL $selected Selected option
|
332 |
+
*
|
333 |
+
* @return String Repeat dropdown
|
334 |
+
*/
|
335 |
+
function create_repeat_dropdown( $selected = null ) {
|
336 |
+
ob_start();
|
337 |
+
|
338 |
+
$options = $this->get_repeat_patterns();
|
339 |
+
|
340 |
+
?>
|
341 |
+
<select name="ai1ec_repeat" id="ai1ec_repeat">
|
342 |
+
<?php foreach( $options as $key => $val ): ?>
|
343 |
+
<option value="<?php echo $key ?>" <?php if( $key === $selected ) echo 'selected="selected"' ?>>
|
344 |
+
<?php _e( $val, AI1EC_PLUGIN_NAME ) ?>
|
345 |
+
</option>
|
346 |
+
<?php endforeach ?>
|
347 |
+
</select>
|
348 |
+
<?php
|
349 |
+
|
350 |
+
$output = ob_get_contents();
|
351 |
+
ob_end_clean();
|
352 |
+
|
353 |
+
return $output;
|
354 |
+
}
|
355 |
+
|
356 |
+
/**
|
357 |
+
* Returns an associative array containing the following information:
|
358 |
+
* string 'repeat' => pattern of repetition ('DAILY', 'WEEKENDS', etc.)
|
359 |
+
* int 'count' => end after 'count' times
|
360 |
+
* int 'until' => repeat until date (as UNIX timestamp)
|
361 |
+
* Elements are null if no such recurrence information is available.
|
362 |
+
*
|
363 |
+
* @param Ai1ec_Event Event object to parse recurrence rules of
|
364 |
+
* @return array Array structured as described above
|
365 |
+
**/
|
366 |
+
function parse_recurrence_rules( &$event )
|
367 |
+
{
|
368 |
+
$repeat = null;
|
369 |
+
$count = null;
|
370 |
+
$until = null;
|
371 |
+
$end = 0;
|
372 |
+
if( ! is_null( $event ) ) {
|
373 |
+
if( strlen( $event->recurrence_rules ) > 0 ) {
|
374 |
+
$line = new SG_iCal_Line( $event->recurrence_rules );
|
375 |
+
$rec = new SG_iCal_Recurrence( $line );
|
376 |
+
switch( $rec->req ) {
|
377 |
+
case 'DAILY':
|
378 |
+
$by_day = $rec->getByDay();
|
379 |
+
if( empty( $by_day ) ) {
|
380 |
+
$repeat = 'DAILY';
|
381 |
+
} elseif( $by_day[0] == 'SA+SU' ) {
|
382 |
+
$repeat = 'WEEKENDS';
|
383 |
+
} elseif( count( $by_day ) == 5 ) {
|
384 |
+
$repeat = 'WEEKDAYS';
|
385 |
+
} else {
|
386 |
+
foreach( $by_day as $d ) {
|
387 |
+
$repeat .= $d . '+';
|
388 |
+
}
|
389 |
+
$repeat = substr( $repeat, 0, -1 );
|
390 |
+
}
|
391 |
+
break;
|
392 |
+
case 'WEEKLY':
|
393 |
+
$repeat = 'WEEKLY';
|
394 |
+
break;
|
395 |
+
case 'MONTHLY':
|
396 |
+
$repeat = 'MONTHLY';
|
397 |
+
break;
|
398 |
+
case 'YEARLY':
|
399 |
+
$repeat = 'YEARLY';
|
400 |
+
break;
|
401 |
+
}
|
402 |
+
$count = $rec->getCount();
|
403 |
+
$until = $rec->getUntil();
|
404 |
+
if( $until ) {
|
405 |
+
$until = strtotime( $rec->getUntil() );
|
406 |
+
$until -= 24 * 60 * 60; // Subtract 1 day (intuitively, last date is included)
|
407 |
+
$end = 2; // set end value
|
408 |
+
} else if( $count )
|
409 |
+
$end = 1; // set end value
|
410 |
+
else
|
411 |
+
$end = 0; // set end value
|
412 |
+
}
|
413 |
+
}
|
414 |
+
return array(
|
415 |
+
'repeat' => $repeat,
|
416 |
+
'count' => $count,
|
417 |
+
'until' => $until,
|
418 |
+
'end' => $end
|
419 |
+
);
|
420 |
+
}
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Generates and returns "End after X times" input
|
424 |
+
*
|
425 |
+
* @param Integer|NULL $count Initial value of range input
|
426 |
+
*
|
427 |
+
* @return String Repeat dropdown
|
428 |
+
*/
|
429 |
+
function create_count_input( $count = 100 ) {
|
430 |
+
ob_start();
|
431 |
+
|
432 |
+
if( ! $count ) $count = 100;
|
433 |
+
?>
|
434 |
+
<input type="range" name="ai1ec_count" id="ai1ec_count" min="1" max="100"
|
435 |
+
<?php if( $count ) echo 'value="' . $count . '"' ?> />
|
436 |
+
<?php _e( 'times', AI1EC_PLUGIN_NAME ) ?>
|
437 |
+
<?php
|
438 |
+
$output = ob_get_contents();
|
439 |
+
ob_end_clean();
|
440 |
+
|
441 |
+
return $output;
|
442 |
+
}
|
443 |
+
|
444 |
+
/**
|
445 |
+
* get_all_matching_posts function
|
446 |
+
*
|
447 |
+
* Gets existing event posts that are between the interval
|
448 |
+
*
|
449 |
+
* @param int $s_time Start time
|
450 |
+
* @param int $e_time End time
|
451 |
+
*
|
452 |
+
* @return Array of matching event posts
|
453 |
+
**/
|
454 |
+
function get_all_matching_posts( $s_time, $e_time ) {
|
455 |
+
global $ai1ec_calendar_helper;
|
456 |
+
return $ai1ec_calendar_helper->get_events_between( $s_time, $e_time );
|
457 |
+
}
|
458 |
+
|
459 |
+
/**
|
460 |
+
* get_matching_events function
|
461 |
+
*
|
462 |
+
* Get events that match with the arguments provided.
|
463 |
+
*
|
464 |
+
* @param int | bool $start Events start before this (GMT) time
|
465 |
+
* @param int | bool $end Events end before this (GMT) time
|
466 |
+
* @param int | array | bool $tags Tag(s) of events
|
467 |
+
* @param int | array | bool $categories Category(ies) of events
|
468 |
+
*
|
469 |
+
* @return array Matching events
|
470 |
+
**/
|
471 |
+
function get_matching_events( $start = false, $end = false, $tags = false, $categories = false, $posts = false ) {
|
472 |
+
$args = array(
|
473 |
+
'post_type' => AI1EC_POST_TYPE,
|
474 |
+
'posts_per_page' => -1
|
475 |
+
);
|
476 |
+
|
477 |
+
if( $categories !== false ) {
|
478 |
+
// add categories
|
479 |
+
if( strstr( $categories, ',' ) !== false ) {
|
480 |
+
$categories = explode( ',', $categories );
|
481 |
+
// prevent sql injection
|
482 |
+
foreach( $categories as $key => $val ) {
|
483 |
+
$categories[$key] = (int) $val;
|
484 |
+
}
|
485 |
+
}
|
486 |
+
$args["tax_query"][] = array(
|
487 |
+
'taxonomy' => 'events_categories',
|
488 |
+
'terms' => $categories,
|
489 |
+
'field' => 'id'
|
490 |
+
);
|
491 |
+
}
|
492 |
+
|
493 |
+
if( $tags !== false ) {
|
494 |
+
// add tags
|
495 |
+
if( strstr( $tags, ',' ) !== false ) {
|
496 |
+
$tags = explode( ',', $tags );
|
497 |
+
// prevent sql injection
|
498 |
+
foreach( $tags as $key => $val ) {
|
499 |
+
$tags[$key] = (int) $val;
|
500 |
+
}
|
501 |
+
}
|
502 |
+
$args["tax_query"][] = array(
|
503 |
+
'taxonomy' => 'events_tags',
|
504 |
+
'terms' => $tags,
|
505 |
+
'field' => 'id'
|
506 |
+
);
|
507 |
+
}
|
508 |
+
|
509 |
+
if( $posts !== false ) {
|
510 |
+
// add posts
|
511 |
+
if( strstr( $posts, ',' ) !== false ) {
|
512 |
+
$posts = explode( ',', $posts );
|
513 |
+
// prevent sql injection
|
514 |
+
foreach( $posts as $key => $val ) {
|
515 |
+
$posts[$key] = (int) $val;
|
516 |
+
}
|
517 |
+
}
|
518 |
+
if( is_array( $posts ) )
|
519 |
+
$args["post__in"] = $posts;
|
520 |
+
else
|
521 |
+
$args["p"] = $posts;
|
522 |
+
}
|
523 |
+
|
524 |
+
$loop = new WP_Query( $args );
|
525 |
+
$events = array();
|
526 |
+
foreach( $loop->posts as $post ) {
|
527 |
+
try{
|
528 |
+
$ev = new Ai1ec_Event( $post->ID );
|
529 |
+
} catch( Ai1ec_Event_Not_Found $n ) {
|
530 |
+
// The event is not found, continue to the next event
|
531 |
+
continue;
|
532 |
+
}
|
533 |
+
// if there are recurrence rules, include the event, else...
|
534 |
+
if( empty( $ev->recurrence_rules ) ) {
|
535 |
+
// if start time is set, and event start time is before the range
|
536 |
+
// it, continue to the next event
|
537 |
+
if( $start !== false && $ev->start < $start )
|
538 |
+
continue;
|
539 |
+
// if end time is set, and event end time is after
|
540 |
+
// it, continue to the next event
|
541 |
+
if( $end !== false && $ev->end < $end )
|
542 |
+
continue;
|
543 |
+
}
|
544 |
+
$events[] = $ev;
|
545 |
+
}
|
546 |
+
|
547 |
+
return $events;
|
548 |
+
}
|
549 |
+
|
550 |
+
/**
|
551 |
+
* fuzzy_string_compare function
|
552 |
+
*
|
553 |
+
* Compares string A to string B using fuzzy comparison algorithm
|
554 |
+
*
|
555 |
+
* @param String $a String to compare
|
556 |
+
* @param String $b String to compare
|
557 |
+
*
|
558 |
+
* @return boolean True if the two strings match, false otherwise
|
559 |
+
**/
|
560 |
+
function fuzzy_string_compare( $a, $b ) {
|
561 |
+
$percent = 0;
|
562 |
+
similar_text( $a, $b, &$percent );
|
563 |
+
return ( $percent > 50 );
|
564 |
+
}
|
565 |
+
|
566 |
+
/**
|
567 |
+
* get_short_time function
|
568 |
+
*
|
569 |
+
* Format a short-form time for use in compressed (e.g. month) views;
|
570 |
+
* this is also converted to the local timezone.
|
571 |
+
*
|
572 |
+
* @param int $timestamp
|
573 |
+
*
|
574 |
+
* @return string
|
575 |
+
**/
|
576 |
+
function get_short_time( $timestamp ) {
|
577 |
+
$timestamp = $this->gmt_to_local( $timestamp );
|
578 |
+
$ampm = gmstrftime( '%p', $timestamp );
|
579 |
+
$ampm = $ampm[0];
|
580 |
+
$ampm = strtolower( $ampm );
|
581 |
+
return gmstrftime( '%l:%M', $timestamp ) . $ampm;
|
582 |
+
}
|
583 |
+
|
584 |
+
/**
|
585 |
+
* get_short_date function
|
586 |
+
*
|
587 |
+
* Format a short-form date for use in compressed (e.g. month) views;
|
588 |
+
* this is also converted to the local timezone.
|
589 |
+
*
|
590 |
+
* @param int $timestamp
|
591 |
+
*
|
592 |
+
* @return string
|
593 |
+
**/
|
594 |
+
function get_short_date( $timestamp ) {
|
595 |
+
$timestamp = $this->gmt_to_local( $timestamp );
|
596 |
+
return gmstrftime( '%b %e', $timestamp );
|
597 |
+
}
|
598 |
+
|
599 |
+
/**
|
600 |
+
* get_medium_time function
|
601 |
+
*
|
602 |
+
* Format a medium-length time for use in other views (e.g., Agenda);
|
603 |
+
* this is also converted to the local timezone.
|
604 |
+
*
|
605 |
+
* @param int $timestamp
|
606 |
+
*
|
607 |
+
* @return string
|
608 |
+
**/
|
609 |
+
function get_medium_time( $timestamp ) {
|
610 |
+
$timestamp = $this->gmt_to_local( $timestamp );
|
611 |
+
$ampm = gmstrftime( '%p', $timestamp );
|
612 |
+
$ampm = strtolower( $ampm );
|
613 |
+
return gmstrftime( '%l:%M', $timestamp ) . $ampm;
|
614 |
+
}
|
615 |
+
|
616 |
+
/**
|
617 |
+
* get_long_time function
|
618 |
+
*
|
619 |
+
* Format a long-length time for use in other views (e.g., single event);
|
620 |
+
* this is also converted to the local timezone.
|
621 |
+
*
|
622 |
+
* @param int $timestamp
|
623 |
+
*
|
624 |
+
* @return string
|
625 |
+
**/
|
626 |
+
function get_long_time( $timestamp ) {
|
627 |
+
$timestamp = $this->gmt_to_local( $timestamp );
|
628 |
+
$ampm = gmstrftime( '%p', $timestamp );
|
629 |
+
$ampm = strtolower( $ampm );
|
630 |
+
return gmstrftime( '%a, %B %e @ %l:%M', $timestamp ) . $ampm;
|
631 |
+
}
|
632 |
+
|
633 |
+
/**
|
634 |
+
* get_long_date function
|
635 |
+
*
|
636 |
+
* Format a long-length date for use in other views (e.g., single event);
|
637 |
+
* this is also converted to the local timezone.
|
638 |
+
*
|
639 |
+
* @param int $timestamp
|
640 |
+
*
|
641 |
+
* @return string
|
642 |
+
**/
|
643 |
+
function get_long_date( $timestamp ) {
|
644 |
+
$timestamp = $this->gmt_to_local( $timestamp );
|
645 |
+
return gmstrftime( '%a, %B %e', $timestamp );
|
646 |
+
}
|
647 |
+
|
648 |
+
/**
|
649 |
+
* gmt_to_local function
|
650 |
+
*
|
651 |
+
* Returns the UNIX timestamp adjusted to the local timezone.
|
652 |
+
*
|
653 |
+
* @param int $timestamp
|
654 |
+
*
|
655 |
+
* @return int
|
656 |
+
**/
|
657 |
+
function gmt_to_local( $timestamp ) {
|
658 |
+
return $timestamp + get_option( 'gmt_offset' ) * 3600;
|
659 |
+
}
|
660 |
+
|
661 |
+
/**
|
662 |
+
* local_to_gmt function
|
663 |
+
*
|
664 |
+
* Returns the UNIX timestamp adjusted from the local timezone to GMT.
|
665 |
+
*
|
666 |
+
* @param int $timestamp
|
667 |
+
*
|
668 |
+
* @return int
|
669 |
+
**/
|
670 |
+
function local_to_gmt( $timestamp ) {
|
671 |
+
return $timestamp - get_option( 'gmt_offset' ) * 3600;
|
672 |
+
}
|
673 |
+
|
674 |
+
/**
|
675 |
+
* A GMT-version of PHP getdate().
|
676 |
+
*
|
677 |
+
* @param int $timestamp UNIX timestamp
|
678 |
+
* @return array Same result as getdate(), but based in GMT time.
|
679 |
+
**/
|
680 |
+
function gmgetdate( $timestamp = null ) {
|
681 |
+
if( ! $timestamp ) $timestamp = time();
|
682 |
+
$bits = explode( ',', gmdate( 's,i,G,j,w,n,Y,z,l,F,U', $timestamp ) );
|
683 |
+
$bits = array_combine(
|
684 |
+
array( 'seconds', 'minutes', 'hours', 'mday', 'wday', 'mon', 'year', 'yday', 'weekday', 'month', 0 ),
|
685 |
+
$bits
|
686 |
+
);
|
687 |
+
return $bits;
|
688 |
+
}
|
689 |
+
|
690 |
+
/**
|
691 |
+
* time_to_gmt function
|
692 |
+
*
|
693 |
+
* Converts time to GMT
|
694 |
+
*
|
695 |
+
* @param int $timestamp
|
696 |
+
*
|
697 |
+
* @return int
|
698 |
+
**/
|
699 |
+
function time_to_gmt( $timestamp ) {
|
700 |
+
return strtotime( gmdate( 'M d Y H:i:s', $timestamp ) );
|
701 |
+
}
|
702 |
+
|
703 |
+
/**
|
704 |
+
* get_gmap_url function
|
705 |
+
*
|
706 |
+
* Returns the URL to the Google Map for the given event object.
|
707 |
+
*
|
708 |
+
* @param Ai1ec_Event $event The event object to display a map for
|
709 |
+
*
|
710 |
+
* @return string
|
711 |
+
**/
|
712 |
+
function get_gmap_url( &$event ) {
|
713 |
+
$location_arg = urlencode( $event->address );
|
714 |
+
return "http://www.google.com/maps?f=q&hl=en&source=embed&q=$location_arg";
|
715 |
+
}
|
716 |
+
|
717 |
+
/**
|
718 |
+
* trim_excerpt function
|
719 |
+
*
|
720 |
+
* Generates an excerpt from the given content string. Adapted from
|
721 |
+
* WordPress's wp_trim_excerpt function that is not useful for applying
|
722 |
+
* to custom content.
|
723 |
+
*
|
724 |
+
* @param string $text The content to trim.
|
725 |
+
*
|
726 |
+
* @return string The excerpt.
|
727 |
+
**/
|
728 |
+
function trim_excerpt( $text )
|
729 |
+
{
|
730 |
+
$raw_excerpt = $text;
|
731 |
+
|
732 |
+
$text = strip_shortcodes( $text );
|
733 |
+
|
734 |
+
$text = str_replace(']]>', ']]>', $text);
|
735 |
+
$text = strip_tags($text);
|
736 |
+
$excerpt_length = apply_filters('excerpt_length', 55);
|
737 |
+
$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
|
738 |
+
$words = preg_split("/[\n\r\t ]+/", $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY);
|
739 |
+
if ( count($words) > $excerpt_length ) {
|
740 |
+
array_pop($words);
|
741 |
+
$text = implode(' ', $words);
|
742 |
+
$text = $text . $excerpt_more;
|
743 |
+
} else {
|
744 |
+
$text = implode(' ', $words);
|
745 |
+
}
|
746 |
+
return apply_filters('wp_trim_excerpt', $text, $raw_excerpt);
|
747 |
+
}
|
748 |
+
|
749 |
+
/**
|
750 |
+
* filter_by_terms function
|
751 |
+
*
|
752 |
+
* Returns a subset of post IDs from the given set of post IDs that have any
|
753 |
+
* of the given taxonomy term IDs. This is actually useful for all posts and
|
754 |
+
* taxonomies in general, not just event posts and event-specific taxonomies.
|
755 |
+
*
|
756 |
+
* @param array|string $post_ids Post IDs as an array of ints or
|
757 |
+
* comma-separated string
|
758 |
+
* @param array|string $term_ids Term IDs as an array of ints or
|
759 |
+
* comma-separated string
|
760 |
+
*
|
761 |
+
* @return array Filtered post IDs as an array of ints
|
762 |
+
**/
|
763 |
+
function filter_by_terms( $post_ids, $term_ids )
|
764 |
+
{
|
765 |
+
global $wpdb;
|
766 |
+
|
767 |
+
// ===============================================
|
768 |
+
// = Sanitize provided IDs against SQL injection =
|
769 |
+
// ===============================================
|
770 |
+
if( ! is_array( $post_ids ) )
|
771 |
+
$post_ids = explode( ',', $post_ids );
|
772 |
+
foreach( $post_ids as &$post_id ) {
|
773 |
+
$post_id = intval( $post_id );
|
774 |
+
}
|
775 |
+
$post_ids = join( ',', $post_ids );
|
776 |
+
|
777 |
+
if( ! is_array( $term_ids ) )
|
778 |
+
$term_ids = explode( ',', $term_ids );
|
779 |
+
foreach( $term_ids as &$term_id ) {
|
780 |
+
$term_id = intval( $term_id );
|
781 |
+
}
|
782 |
+
$term_ids = join( ',', $term_ids );
|
783 |
+
|
784 |
+
$query =
|
785 |
+
"SELECT DISTINCT p.ID " .
|
786 |
+
"FROM $wpdb->posts p " .
|
787 |
+
"INNER JOIN $wpdb->term_relationships tr ON p.ID = tr.object_id " .
|
788 |
+
"INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id " .
|
789 |
+
"WHERE p.ID IN ( " . $post_ids . " ) " .
|
790 |
+
"AND tt.term_id IN ( " . $term_ids . " )";
|
791 |
+
|
792 |
+
return $wpdb->get_col( $query );
|
793 |
+
}
|
794 |
+
|
795 |
+
/**
|
796 |
+
* get_category_color function
|
797 |
+
*
|
798 |
+
*
|
799 |
+
*
|
800 |
+
* @return void
|
801 |
+
**/
|
802 |
+
function get_category_color( $term_id = 0 ) {
|
803 |
+
global $wpdb;
|
804 |
+
|
805 |
+
$term_id = (int) $term_id;
|
806 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_category_colors';
|
807 |
+
$color = $wpdb->get_var( "SELECT term_color FROM {$table_name} WHERE term_id = {$term_id}" );
|
808 |
+
return $color;
|
809 |
+
}
|
810 |
+
|
811 |
+
/**
|
812 |
+
* get_category_color_square function
|
813 |
+
*
|
814 |
+
*
|
815 |
+
*
|
816 |
+
* @return void
|
817 |
+
**/
|
818 |
+
function get_category_color_square( $term_id ) {
|
819 |
+
$color = $this->get_category_color( $term_id );
|
820 |
+
if( ! is_null( $color ) && ! empty( $color ) )
|
821 |
+
return '<div class="ai1ec-category-color" style="background:' . $color . '"></div>';
|
822 |
+
|
823 |
+
return '';
|
824 |
+
}
|
825 |
+
|
826 |
+
/**
|
827 |
+
* get_event_category_color_style function
|
828 |
+
*
|
829 |
+
* Returns the style attribute assigning the category color style to an event.
|
830 |
+
*
|
831 |
+
* @return string
|
832 |
+
**/
|
833 |
+
function get_event_category_color_style( $term_id, $allday = false ) {
|
834 |
+
$color = $this->get_category_color( $term_id );
|
835 |
+
if( ! is_null( $color ) && ! empty( $color ) ) {
|
836 |
+
if( $allday )
|
837 |
+
return ' style="background:' . $color . '"';
|
838 |
+
else
|
839 |
+
return ' style="color:' . $color . ' !important"';
|
840 |
+
}
|
841 |
+
|
842 |
+
return '';
|
843 |
+
}
|
844 |
+
|
845 |
+
/**
|
846 |
+
* get_event_category_colors function
|
847 |
+
*
|
848 |
+
* Returns category color boxes
|
849 |
+
*
|
850 |
+
* @return string
|
851 |
+
**/
|
852 |
+
function get_event_category_colors( $cats ) {
|
853 |
+
$sqrs = '';
|
854 |
+
foreach( $cats as $cat ) :
|
855 |
+
$tmp = $this->get_category_color_square( $cat->term_id );
|
856 |
+
if( ! empty( $tmp ) )
|
857 |
+
$sqrs .= $tmp;
|
858 |
+
endforeach;
|
859 |
+
|
860 |
+
return $sqrs;
|
861 |
+
}
|
862 |
+
|
863 |
+
/**
|
864 |
+
* create_end_dropdown function
|
865 |
+
*
|
866 |
+
*
|
867 |
+
*
|
868 |
+
* @return void
|
869 |
+
**/
|
870 |
+
function create_end_dropdown( $selected = null ) {
|
871 |
+
ob_start();
|
872 |
+
|
873 |
+
$options = array(
|
874 |
+
0 => 'Never',
|
875 |
+
1 => 'After',
|
876 |
+
2 => 'On date'
|
877 |
+
);
|
878 |
+
|
879 |
+
?>
|
880 |
+
<select name="ai1ec_end" id="ai1ec_end">
|
881 |
+
<?php foreach( $options as $key => $val ): ?>
|
882 |
+
<option value="<?php echo $key ?>" <?php if( $key === $selected ) echo 'selected="selected"' ?>>
|
883 |
+
<?php _e( $val, AI1EC_PLUGIN_NAME ) ?>
|
884 |
+
</option>
|
885 |
+
<?php endforeach ?>
|
886 |
+
</select>
|
887 |
+
<?php
|
888 |
+
|
889 |
+
$output = ob_get_contents();
|
890 |
+
ob_end_clean();
|
891 |
+
|
892 |
+
return $output;
|
893 |
+
}
|
894 |
+
}
|
895 |
+
// END class
|
app/helper/class-ai1ec-exporter-helper.php
ADDED
@@ -0,0 +1,130 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-exporter-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Exporter_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Exporter_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* insert_event_in_calendar function
|
49 |
+
*
|
50 |
+
* Add event to the calendar
|
51 |
+
*
|
52 |
+
* @param object $event Event object
|
53 |
+
* @param object $c Calendar object
|
54 |
+
*
|
55 |
+
* @return void
|
56 |
+
**/
|
57 |
+
function insert_event_in_calendar( $event, &$c )
|
58 |
+
{
|
59 |
+
global $ai1ec_events_helper;
|
60 |
+
|
61 |
+
$tz = get_option( 'timezone_string' );
|
62 |
+
|
63 |
+
$e = & $c->newComponent( 'vevent' );
|
64 |
+
$uid = $event->ical_uid ? $event->ical_uid : $event->post->guid;
|
65 |
+
$e->setProperty( 'uid', $uid );
|
66 |
+
$e->setProperty( 'url', get_permalink( $event->post_id ) );
|
67 |
+
$e->setProperty( 'summary', html_entity_decode( $event->post->post_title, ENT_QUOTES ) );
|
68 |
+
$content = apply_filters( 'the_content', $event->post->post_content );
|
69 |
+
$content = str_replace(']]>', ']]>', $content);
|
70 |
+
$e->setProperty( 'description', $content );
|
71 |
+
if( $event->allday ) {
|
72 |
+
$e->setProperty( 'dtstart',
|
73 |
+
gmdate( "Ymd\T", $ai1ec_events_helper->gmt_to_local( $event->start ) ),
|
74 |
+
array( 'VALUE' => 'DATE', 'TZID' => $tz ) );
|
75 |
+
$e->setProperty( 'dtend',
|
76 |
+
gmdate( "Ymd\T", $ai1ec_events_helper->gmt_to_local( $event->end ) ),
|
77 |
+
array( 'VALUE' => 'DATE', 'TZID' => $tz ) );
|
78 |
+
} else {
|
79 |
+
$e->setProperty( 'dtstart',
|
80 |
+
gmdate( "Ymd\THis\Z", $ai1ec_events_helper->gmt_to_local( $event->start ) ),
|
81 |
+
array( 'TZID' => $tz ) );
|
82 |
+
$e->setProperty( 'dtend',
|
83 |
+
gmdate( "Ymd\THis\Z", $ai1ec_events_helper->gmt_to_local( $event->end ) ),
|
84 |
+
array( 'TZID' => $tz ) );
|
85 |
+
}
|
86 |
+
$e->setProperty( 'location', $event->address );
|
87 |
+
|
88 |
+
$contact = ! empty( $event->contact_name ) ? $event->contact_name : '';
|
89 |
+
$contact .= ! empty( $event->contact_phone ) ? " ($event->contact_phone)" : '';
|
90 |
+
$contact .= ! empty( $event->contact_email ) ? " <$event->contact_email>" : '';
|
91 |
+
$e->setProperty( 'contact', $contact );
|
92 |
+
|
93 |
+
$rrule = array();
|
94 |
+
if( ! empty( $event->recurrence_rules ) ) {
|
95 |
+
$rules = array();
|
96 |
+
foreach( explode( ';', $event->recurrence_rules ) AS $v) {
|
97 |
+
list($k, $v) = explode( '=', $v );
|
98 |
+
// If $v is a comma-separated list, turn it into array for iCalcreator
|
99 |
+
switch( $k ) {
|
100 |
+
case 'BYSECOND':
|
101 |
+
case 'BYMINUTE':
|
102 |
+
case 'BYHOUR':
|
103 |
+
case 'BYDAY':
|
104 |
+
case 'BYMONTHDAY':
|
105 |
+
case 'BYYEARDAY':
|
106 |
+
case 'BYWEEKNO':
|
107 |
+
case 'BYMONTH':
|
108 |
+
case 'BYSETPOS':
|
109 |
+
$exploded = explode( ',', $v );
|
110 |
+
break;
|
111 |
+
default:
|
112 |
+
$exploded = $v;
|
113 |
+
break;
|
114 |
+
}
|
115 |
+
// iCalcreator requires a more complex array structure for BYDAY...
|
116 |
+
if( $k == 'BYDAY' ) {
|
117 |
+
$v = array();
|
118 |
+
foreach( $exploded as $day ) {
|
119 |
+
$v[] = array( 'DAY' => $day );
|
120 |
+
}
|
121 |
+
} else {
|
122 |
+
$v = $exploded;
|
123 |
+
}
|
124 |
+
$rrule[ $k ] = $v;
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
if( ! empty( $rrule ) ) $e->setProperty( 'rrule', $rrule );
|
129 |
+
}
|
130 |
+
}
|
app/helper/class-ai1ec-importer-helper.php
ADDED
@@ -0,0 +1,233 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-importer-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Importer_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Importer_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* time_array_to_timestamp function
|
49 |
+
*
|
50 |
+
* Converts time array to time string.
|
51 |
+
* Passed array: Array( 'year', 'month', 'day', ['hour', 'min', 'sec', ['tz']] )
|
52 |
+
* Return int: UNIX timestamp in GMT
|
53 |
+
*
|
54 |
+
* @param array $t Time array
|
55 |
+
* @param string $def_timezone Default time zone in case not defined in $t
|
56 |
+
*
|
57 |
+
* @return int UNIX timestamp
|
58 |
+
**/
|
59 |
+
function time_array_to_timestamp( $t, $def_timezone ) {
|
60 |
+
$ret = $t['year'] . '-' . $t['month'] . '-' . $t['day'];
|
61 |
+
if( isset( $t['hour'] ) )
|
62 |
+
$ret .= ' ' . $t['hour'] . ':' . $t['min'] . ':' . $t['sec'];
|
63 |
+
$timezone = $t['tz'];
|
64 |
+
if( ! $timezone ) $timezone = $def_timezone;
|
65 |
+
if( $timezone )
|
66 |
+
$ret .= ' ' . $timezone;
|
67 |
+
return strtotime( $ret );
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Gets and parses an iCalendar feed into an array of Ai1ec_Event objects
|
72 |
+
*
|
73 |
+
* @param object $feed Row from the ai1ec_event_feeds table
|
74 |
+
*
|
75 |
+
* @return int Number of events imported
|
76 |
+
*/
|
77 |
+
function parse_ics_feed( &$feed )
|
78 |
+
{
|
79 |
+
global $ai1ec_events_helper;
|
80 |
+
|
81 |
+
$count = 0;
|
82 |
+
|
83 |
+
// include ical parser
|
84 |
+
require_once( AI1EC_LIB_PATH . '/iCalcreator.class.php' );
|
85 |
+
|
86 |
+
// set unique id, required if any component UID is missing
|
87 |
+
$config = array( 'unique_id' => 'ai1ec' );
|
88 |
+
|
89 |
+
// create new instance
|
90 |
+
$v = new vcalendar( array(
|
91 |
+
'unique_id' => $feed->feed_url,
|
92 |
+
'url' => str_replace( 'webcal', 'http', $feed->feed_url ),
|
93 |
+
) );
|
94 |
+
|
95 |
+
// actual parse of the feed
|
96 |
+
if( $v->parse() )
|
97 |
+
{
|
98 |
+
$v->sort();
|
99 |
+
// Reverse the sort order, so that RECURRENCE-IDs are listed before the
|
100 |
+
// defining recurrence events, and therefore take precedence during
|
101 |
+
// caching.
|
102 |
+
$v->components = array_reverse( $v->components );
|
103 |
+
|
104 |
+
// TODO: select only VEVENT components that occur after, say, 1 month ago.
|
105 |
+
// Maybe use $v->selectComponents(), which takes into account recurrence
|
106 |
+
|
107 |
+
// Fetch default timezone in case individual properties don't define it
|
108 |
+
$timezone = $v->getProperty( 'X-WR-TIMEZONE' );
|
109 |
+
$timezone = $timezone[1];
|
110 |
+
|
111 |
+
// go over each event
|
112 |
+
while( $e = $v->getComponent( 'vevent' ) )
|
113 |
+
{
|
114 |
+
$start = $e->getProperty( 'dtstart' );
|
115 |
+
$end = $e->getProperty( 'dtend' );
|
116 |
+
|
117 |
+
// Event is all-day if no time components are defined
|
118 |
+
$allday = ! isset( $start['hour'] );
|
119 |
+
|
120 |
+
// convert times to GMT UNIX timestamps
|
121 |
+
$start = $this->time_array_to_timestamp( $start, $timezone );
|
122 |
+
$end = $this->time_array_to_timestamp( $end, $timezone );
|
123 |
+
|
124 |
+
// If all-day, and start and end times are equal, then this event has
|
125 |
+
// invalid end time (happens sometimes with poorly implemented iCalendar
|
126 |
+
// exports, such as in The Event Calendar), so set end time to 1 day
|
127 |
+
// after start time.
|
128 |
+
if( $allday && $start === $end )
|
129 |
+
$end += 24 * 60 * 60;
|
130 |
+
|
131 |
+
// Due to potential time zone differences (WP time zone vs. feed time
|
132 |
+
// zone), must convert all-day event start/end dates to date only (the
|
133 |
+
// *intended* local date, non-GMT-ified)
|
134 |
+
if( $allday ) {
|
135 |
+
$start = $ai1ec_events_helper->gmt_to_local( $start );
|
136 |
+
$start = $ai1ec_events_helper->gmgetdate( $start );
|
137 |
+
$start = gmmktime( 0, 0, 0, $start['mon'], $start['mday'], $start['year'] );
|
138 |
+
$start = $ai1ec_events_helper->local_to_gmt( $start );
|
139 |
+
$end = $ai1ec_events_helper->gmt_to_local( $end );
|
140 |
+
$end = $ai1ec_events_helper->gmgetdate( $end );
|
141 |
+
$end = gmmktime( 0, 0, 0, $end['mon'], $end['mday'], $end['year'] );
|
142 |
+
$end = $ai1ec_events_helper->local_to_gmt( $end );
|
143 |
+
}
|
144 |
+
|
145 |
+
if( $rrule = $e->createRrule() )
|
146 |
+
$rrule = trim( end( split( ':', $rrule ) ) );
|
147 |
+
if( $exrule = $e->createExrule() )
|
148 |
+
$exrule = trim( end( split( ':', $exrule ) ) );
|
149 |
+
if( $rdate = $e->createRdate() )
|
150 |
+
$rdate = trim( end( split( ':', $rdate ) ) );
|
151 |
+
if( $exdate = $e->createExdate() )
|
152 |
+
$exdate = trim( end( split( ':', $exdate ) ) );
|
153 |
+
|
154 |
+
$data = array(
|
155 |
+
'start' => $start,
|
156 |
+
'end' => $end,
|
157 |
+
'allday' => $allday,
|
158 |
+
'recurrence_rules' => $rrule,
|
159 |
+
'exception_rules' => $exrule,
|
160 |
+
'recurrence_dates' => $rdate,
|
161 |
+
'exception_dates' => $exdate,
|
162 |
+
'venue' => $e->getProperty( 'location' ),
|
163 |
+
'ical_feed_url' => $feed->feed_url,
|
164 |
+
'ical_source_url' => $e->getProperty( 'url' ),
|
165 |
+
'ical_organizer' => $e->getProperty( 'organizer' ),
|
166 |
+
'ical_contact' => $e->getProperty( 'contact' ),
|
167 |
+
'ical_uid' => $e->getProperty( 'uid' ),
|
168 |
+
'categories' => $feed->feed_category,
|
169 |
+
'tags' => $feed->feed_tags,
|
170 |
+
'post' => array(
|
171 |
+
'post_status' => 'publish',
|
172 |
+
'post_type' => AI1EC_POST_TYPE,
|
173 |
+
'post_author' => 1,
|
174 |
+
'post_title' => $e->getProperty( 'summary' ),
|
175 |
+
'post_content' => stripslashes( str_replace( '\n', "\n", $e->getProperty( 'description' ) ) ),
|
176 |
+
),
|
177 |
+
);
|
178 |
+
|
179 |
+
$event = new Ai1ec_Event( $data );
|
180 |
+
|
181 |
+
// TODO: when singular events change their times in an ICS feed from one
|
182 |
+
// import to another, the matching_event_id is null, which is wrong. We
|
183 |
+
// want to match that event that previously had a different time.
|
184 |
+
// However, we also want the function to NOT return a matching event in
|
185 |
+
// the case of recurring events, and different events with different
|
186 |
+
// RECURRENCE-IDs... ponder how to solve this.. may require saving the
|
187 |
+
// RECURRENCE-ID as another field in the database.
|
188 |
+
$matching_event_id = $ai1ec_events_helper->get_matching_event_id(
|
189 |
+
$event->ical_uid,
|
190 |
+
$event->ical_feed_url,
|
191 |
+
$event->start,
|
192 |
+
! empty( $event->recurrence_rules )
|
193 |
+
);
|
194 |
+
|
195 |
+
if( is_null( $matching_event_id ) )
|
196 |
+
{
|
197 |
+
// =================================================
|
198 |
+
// = Event was not found, so store it and the post =
|
199 |
+
// =================================================
|
200 |
+
$event->save();
|
201 |
+
}
|
202 |
+
else
|
203 |
+
{
|
204 |
+
// ======================================================
|
205 |
+
// = Event was found, let's store the new event details =
|
206 |
+
// ======================================================
|
207 |
+
|
208 |
+
// Update the post
|
209 |
+
$post = get_post( $matching_event_id );
|
210 |
+
$post->post_title = $event->post->post_title;
|
211 |
+
$post->post_content = $event->post->post_content;
|
212 |
+
wp_update_post( $post );
|
213 |
+
|
214 |
+
// Update the event
|
215 |
+
$event->post_id = $matching_event_id;
|
216 |
+
$event->post = $post;
|
217 |
+
$event->save( true );
|
218 |
+
|
219 |
+
// Delete event's cache
|
220 |
+
$ai1ec_events_helper->delete_event_cache( $matching_event_id );
|
221 |
+
}
|
222 |
+
|
223 |
+
// Regenerate event's cache
|
224 |
+
$ai1ec_events_helper->cache_event( $event );
|
225 |
+
|
226 |
+
$count++;
|
227 |
+
}
|
228 |
+
}
|
229 |
+
|
230 |
+
return $count;
|
231 |
+
}
|
232 |
+
}
|
233 |
+
// END class
|
app/helper/class-ai1ec-settings-helper.php
ADDED
@@ -0,0 +1,329 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-settings-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Settings_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Settings_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* get_instance function
|
27 |
+
*
|
28 |
+
* Return singleton instance
|
29 |
+
*
|
30 |
+
* @return object
|
31 |
+
**/
|
32 |
+
static function get_instance() {
|
33 |
+
if( self::$_instance === NULL ) {
|
34 |
+
self::$_instance = new self();
|
35 |
+
}
|
36 |
+
|
37 |
+
return self::$_instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructor
|
42 |
+
*
|
43 |
+
* Default constructor
|
44 |
+
**/
|
45 |
+
private function __construct() { }
|
46 |
+
|
47 |
+
/**
|
48 |
+
* wp_pages_dropdown function
|
49 |
+
*
|
50 |
+
* Display drop-down list selector of pages, including an "Auto-Create New Page"
|
51 |
+
* option which causes the plugin to generate a new page on user's behalf.
|
52 |
+
*
|
53 |
+
* @param string $field_name
|
54 |
+
* @param int $selected_page_id
|
55 |
+
* @param string $auto_page
|
56 |
+
* @param bool $include_disabled
|
57 |
+
*
|
58 |
+
* @return string
|
59 |
+
**/
|
60 |
+
function wp_pages_dropdown( $field_name, $selected_page_id = 0, $auto_page = '', $include_disabled = false ) {
|
61 |
+
global $wpdb;
|
62 |
+
ob_start();
|
63 |
+
$query = "SELECT
|
64 |
+
*
|
65 |
+
FROM
|
66 |
+
{$wpdb->posts}
|
67 |
+
WHERE
|
68 |
+
post_status = %s
|
69 |
+
AND
|
70 |
+
post_type = %s";
|
71 |
+
|
72 |
+
$query = $wpdb->prepare( $query, 'publish', 'page' );
|
73 |
+
$results = $wpdb->get_results( $query );
|
74 |
+
$pages = array();
|
75 |
+
if( $results ) {
|
76 |
+
$pages = $results;
|
77 |
+
}
|
78 |
+
|
79 |
+
?>
|
80 |
+
<select class="inputwidth" name="<?php echo $field_name; ?>"
|
81 |
+
id="<?php echo $field_name; ?>"
|
82 |
+
class="wafp-dropdown wafp-pages-dropdown">
|
83 |
+
<?php if( ! empty( $auto_page ) ) { ?>
|
84 |
+
<option value="__auto_page:<?php echo $auto_page; ?>">
|
85 |
+
<?php _e( '- Auto-Create New Page -', THE_PLUGIN_NAME ); ?>
|
86 |
+
</option>
|
87 |
+
<?php }
|
88 |
+
foreach( $pages as $page ) {
|
89 |
+
if( $selected_page_id == $page->ID ) {
|
90 |
+
$selected = ' selected="selected"';
|
91 |
+
$selected_title = $page->post_title;
|
92 |
+
} else {
|
93 |
+
$selected = '';
|
94 |
+
}
|
95 |
+
?>
|
96 |
+
<option value="<?php echo $page->ID ?>" <?php echo $selected; ?>>
|
97 |
+
<?php echo $page->post_title ?>
|
98 |
+
</option>
|
99 |
+
<?php } ?>
|
100 |
+
</select>
|
101 |
+
<?php
|
102 |
+
if( is_numeric( $selected_page_id ) && $selected_page_id > 0 ) {
|
103 |
+
$permalink = get_permalink( $selected_page_id );
|
104 |
+
?>
|
105 |
+
<br /><a href="<?php echo $permalink ?>" target="_blank">
|
106 |
+
<?php printf( __( 'View "%s" »', AI1EC_PLUGIN_NAME ), $selected_title ) ?>
|
107 |
+
</a>
|
108 |
+
<?php
|
109 |
+
}
|
110 |
+
return ob_get_clean();
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* get_week_dropdown function
|
115 |
+
*
|
116 |
+
* Creates the dropdown element for selecting start of the week
|
117 |
+
*
|
118 |
+
* @param int $week_start_day Selected start day
|
119 |
+
*
|
120 |
+
* @return String dropdown element
|
121 |
+
**/
|
122 |
+
function get_week_dropdown( $week_start_day ) {
|
123 |
+
global $wp_locale;
|
124 |
+
ob_start();
|
125 |
+
?>
|
126 |
+
<select class="inputwidth" name="week_start_day" id="week_start_day">
|
127 |
+
<?php
|
128 |
+
for( $day_index = 0; $day_index <= 6; $day_index++ ) :
|
129 |
+
$selected = ( $week_start_day == $day_index ) ? 'selected="selected"' : '';
|
130 |
+
echo "\n\t<option value='" . esc_attr($day_index) . "' $selected>" . $wp_locale->get_weekday($day_index) . '</option>';
|
131 |
+
endfor;
|
132 |
+
?>
|
133 |
+
</select>
|
134 |
+
<?php
|
135 |
+
return ob_get_clean();
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* get_view_dropdown function
|
140 |
+
*
|
141 |
+
* @return void
|
142 |
+
**/
|
143 |
+
function get_view_dropdown( $view = null ) {
|
144 |
+
ob_start();
|
145 |
+
?>
|
146 |
+
<select name="default_calendar_view">
|
147 |
+
<option value="month" <?php echo $view == 'month' ? 'selected' : '' ?>>
|
148 |
+
<?php _e( 'Month', AI1EC_PLUGIN_NAME ) ?>
|
149 |
+
</option>
|
150 |
+
<option value="agenda" <?php echo $view == 'agenda' ? 'selected' : '' ?>>
|
151 |
+
<?php _e( 'Agenda', AI1EC_PLUGIN_NAME ) ?>
|
152 |
+
</option>
|
153 |
+
</select>
|
154 |
+
<?php
|
155 |
+
return ob_get_clean();
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* get_cron_freq_dropdown function
|
160 |
+
*
|
161 |
+
* @return void
|
162 |
+
**/
|
163 |
+
function get_cron_freq_dropdown( $cron_freq = null ) {
|
164 |
+
ob_start();
|
165 |
+
?>
|
166 |
+
<select name="cron_freq">
|
167 |
+
<option value="hourly" <?php echo $cron_freq == 'hourly' ? 'selected' : ''; ?>>
|
168 |
+
<?php _e( 'Hourly', AI1EC_PLUGIN_NAME ) ?>
|
169 |
+
</option>
|
170 |
+
<option value="twicedaily" <?php echo $cron_freq == 'twicedaily' ? 'selected' : '' ?>>
|
171 |
+
<?php _e( 'Twice Daily', AI1EC_PLUGIN_NAME ) ?>
|
172 |
+
</option>
|
173 |
+
<option value="daily" <?php echo $cron_freq == 'daily' ? 'selected' : '' ?>>
|
174 |
+
<?php _e( 'Daily', AI1EC_PLUGIN_NAME ) ?>
|
175 |
+
</option>
|
176 |
+
</select>
|
177 |
+
<?php
|
178 |
+
return ob_get_clean();
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* get_feed_rows function
|
183 |
+
*
|
184 |
+
* Creates feed rows to display on settings page
|
185 |
+
*
|
186 |
+
* @return String feed rows
|
187 |
+
**/
|
188 |
+
function get_feed_rows() {
|
189 |
+
global $wpdb,
|
190 |
+
$ai1ec_view_helper;
|
191 |
+
|
192 |
+
// Select all added feeds
|
193 |
+
$table_name = $wpdb->prefix . 'ai1ec_event_feeds';
|
194 |
+
$sql = "SELECT * FROM {$table_name}";
|
195 |
+
$rows = $wpdb->get_results( $sql );
|
196 |
+
|
197 |
+
ob_start();
|
198 |
+
foreach( $rows as $row ) :
|
199 |
+
$feed_category = get_term( $row->feed_category, 'events_categories' );
|
200 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
201 |
+
$sql = "SELECT COUNT(*) FROM {$table_name} WHERE ical_feed_url = '%s'";
|
202 |
+
$events = $wpdb->get_var( $wpdb->prepare( $sql, $row->feed_url ) );
|
203 |
+
$args = array(
|
204 |
+
'feed_url' => $row->feed_url,
|
205 |
+
'event_category' => $feed_category->name,
|
206 |
+
'tags' => stripslashes( $row->feed_tags ),
|
207 |
+
'feed_id' => $row->feed_id,
|
208 |
+
'events' => $events
|
209 |
+
);
|
210 |
+
$ai1ec_view_helper->display( 'feed_row.php', $args );
|
211 |
+
endforeach;
|
212 |
+
|
213 |
+
return ob_get_clean();
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* get_event_categories_select function
|
218 |
+
*
|
219 |
+
* Creates the dropdown element for selecting feed category
|
220 |
+
*
|
221 |
+
* @param int|null $selected The selected category or null
|
222 |
+
*
|
223 |
+
* @return String dropdown element
|
224 |
+
**/
|
225 |
+
function get_event_categories_select( $selected = null) {
|
226 |
+
ob_start();
|
227 |
+
?>
|
228 |
+
<select name="ai1ec_feed_category" id="ai1ec_feed_category">
|
229 |
+
<?php
|
230 |
+
foreach( get_terms( 'events_categories', array( 'hide_empty' => false ) ) as $term ) :
|
231 |
+
?>
|
232 |
+
<option value="<?php echo $term->term_id; ?>" <?php echo ( $selected === $term->id ) ? 'selected' : '' ?>>
|
233 |
+
<?php echo $term->name; ?>
|
234 |
+
</option>
|
235 |
+
<?php
|
236 |
+
endforeach;
|
237 |
+
?>
|
238 |
+
</select>
|
239 |
+
<?php
|
240 |
+
return ob_get_clean();
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* general_settings_meta_box function
|
245 |
+
*
|
246 |
+
*
|
247 |
+
*
|
248 |
+
* @return void
|
249 |
+
**/
|
250 |
+
function general_settings_meta_box( $object, $box ) {
|
251 |
+
global $ai1ec_view_helper,
|
252 |
+
$ai1ec_settings_helper,
|
253 |
+
$ai1ec_settings;
|
254 |
+
|
255 |
+
$calendar_page = $ai1ec_settings_helper->wp_pages_dropdown(
|
256 |
+
'calendar_page_id',
|
257 |
+
$ai1ec_settings->calendar_page_id,
|
258 |
+
__( 'Calendar', AI1EC_PLUGIN_NAME )
|
259 |
+
);
|
260 |
+
$calendar_css_selector = $ai1ec_settings->calendar_css_selector;
|
261 |
+
$week_start_day = $ai1ec_settings_helper->get_week_dropdown( get_option( 'start_of_week' ) );
|
262 |
+
$agenda_events_per_page = $ai1ec_settings->agenda_events_per_page;
|
263 |
+
$include_events_in_rss =
|
264 |
+
'<input type="checkbox" name="include_events_in_rss"
|
265 |
+
id="include_events_in_rss" value="1"'
|
266 |
+
. ( $ai1ec_settings->include_events_in_rss ? ' checked="checked"' : '' )
|
267 |
+
. '/>';
|
268 |
+
$show_publish_button = $ai1ec_settings->show_publish_button ? 'checked=checked' : '';
|
269 |
+
$show_create_event_button = $ai1ec_settings->show_create_event_button ? 'checked=checked' : '';
|
270 |
+
$inject_categories = $ai1ec_settings->inject_categories ? 'checked=checked' : '';
|
271 |
+
$default_calendar_view = $ai1ec_settings_helper->get_view_dropdown( $ai1ec_settings->default_calendar_view );
|
272 |
+
|
273 |
+
$args = array(
|
274 |
+
'calendar_page' => $calendar_page,
|
275 |
+
'default_calendar_view' => $default_calendar_view,
|
276 |
+
'calendar_css_selector' => $calendar_css_selector,
|
277 |
+
'week_start_day' => $week_start_day,
|
278 |
+
'agenda_events_per_page' => $agenda_events_per_page,
|
279 |
+
'show_publish_button' => $show_publish_button,
|
280 |
+
'show_create_event_button' => $show_create_event_button,
|
281 |
+
'inject_categories' => $inject_categories,
|
282 |
+
);
|
283 |
+
$ai1ec_view_helper->display( 'box_general_settings.php', $args );
|
284 |
+
}
|
285 |
+
|
286 |
+
/**
|
287 |
+
* ics_import_settings_meta_box function
|
288 |
+
*
|
289 |
+
*
|
290 |
+
*
|
291 |
+
* @return void
|
292 |
+
**/
|
293 |
+
function ics_import_settings_meta_box( $object, $box ) {
|
294 |
+
global $ai1ec_view_helper,
|
295 |
+
$ai1ec_settings_helper;
|
296 |
+
|
297 |
+
$args = array(
|
298 |
+
'cron_freq' => $ai1ec_settings_helper->get_cron_freq_dropdown( $ai1ec_settings->cron_freq ),
|
299 |
+
'event_categories' => $ai1ec_settings_helper->get_event_categories_select(),
|
300 |
+
'feed_rows' => $ai1ec_settings_helper->get_feed_rows()
|
301 |
+
);
|
302 |
+
$ai1ec_view_helper->display( 'box_ics_import_settings.php', $args );
|
303 |
+
}
|
304 |
+
|
305 |
+
/**
|
306 |
+
* the_seed_studio_meta_box function
|
307 |
+
*
|
308 |
+
*
|
309 |
+
*
|
310 |
+
* @return void
|
311 |
+
**/
|
312 |
+
function the_seed_studio_meta_box( $object, $box ) {
|
313 |
+
global $ai1ec_view_helper;
|
314 |
+
$ai1ec_view_helper->display( 'box_the_seed_studio.php' );
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* add_meta_boxes function
|
319 |
+
*
|
320 |
+
*
|
321 |
+
*
|
322 |
+
* @return void
|
323 |
+
**/
|
324 |
+
function add_meta_boxes(){
|
325 |
+
global $ai1ec_settings;
|
326 |
+
do_action( 'add_meta_boxes', $ai1ec_settings->settings_page );
|
327 |
+
}
|
328 |
+
}
|
329 |
+
// END class
|
app/helper/class-ai1ec-view-helper.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-view-helper.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_View_Helper class
|
11 |
+
*
|
12 |
+
* @package Helpers
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_View_Helper {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Constructor
|
27 |
+
*
|
28 |
+
* Default constructor
|
29 |
+
**/
|
30 |
+
private function __construct() { }
|
31 |
+
|
32 |
+
/**
|
33 |
+
* get_instance function
|
34 |
+
*
|
35 |
+
* Return singleton instance
|
36 |
+
*
|
37 |
+
* @return object
|
38 |
+
**/
|
39 |
+
static function get_instance() {
|
40 |
+
if( self::$_instance === NULL ) {
|
41 |
+
self::$_instance = new self();
|
42 |
+
}
|
43 |
+
|
44 |
+
return self::$_instance;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* display function
|
49 |
+
*
|
50 |
+
* Display the view specified by file $file and passed arguments $args.
|
51 |
+
*
|
52 |
+
* @param string $file
|
53 |
+
* @param array $args
|
54 |
+
*
|
55 |
+
* @return void
|
56 |
+
**/
|
57 |
+
function display( $file = false, $args = array() ) {
|
58 |
+
if( ! $file || empty( $file ) ) {
|
59 |
+
throw new Ai1ec_File_Not_Provided( "You need to specify a view file." );
|
60 |
+
}
|
61 |
+
|
62 |
+
$file = AI1EC_VIEW_PATH . "/" . $file;
|
63 |
+
|
64 |
+
if( ! file_exists( $file ) ) {
|
65 |
+
throw new Ai1ec_File_Not_Found( "The specified view file doesn't exist." );
|
66 |
+
} else {
|
67 |
+
extract( $args );
|
68 |
+
require( $file );
|
69 |
+
}
|
70 |
+
}
|
71 |
+
|
72 |
+
/**
|
73 |
+
* display_css function
|
74 |
+
*
|
75 |
+
* Renders the given stylesheet inline. If stylesheet has already been
|
76 |
+
* displayed once before with the same set of $args, does not display
|
77 |
+
* it again.
|
78 |
+
*
|
79 |
+
* @param string $file
|
80 |
+
* @param array $args
|
81 |
+
*
|
82 |
+
* @return void
|
83 |
+
**/
|
84 |
+
function display_css( $file = false, $args = array() ) {
|
85 |
+
static $displayed = array();
|
86 |
+
static $num = 0;
|
87 |
+
|
88 |
+
if( ! $file || empty( $file ) ) {
|
89 |
+
throw new Ai1ec_File_Not_Provided( 'You need to specify a css file.' );
|
90 |
+
}
|
91 |
+
|
92 |
+
$file = AI1EC_CSS_PATH . "/" . $file;
|
93 |
+
|
94 |
+
if( $displayed[$file] === $args ) // Skip if already displayed
|
95 |
+
return;
|
96 |
+
|
97 |
+
if( ! file_exists( $file ) ) {
|
98 |
+
throw new Ai1ec_File_Not_Found( "The specified css file doesn't exist." );
|
99 |
+
} else {
|
100 |
+
$displayed[$file] = $args; // Flag that we've displayed this file with these args
|
101 |
+
|
102 |
+
extract( $args );
|
103 |
+
echo '<style type="text/css">';
|
104 |
+
require( $file );
|
105 |
+
echo '</style>';
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* display_js function
|
111 |
+
*
|
112 |
+
* Renders the given script inline. If script has already been displayed
|
113 |
+
* once before with the same set of $args, does not display it again.
|
114 |
+
*
|
115 |
+
* @param string $file
|
116 |
+
* @param array $args
|
117 |
+
*
|
118 |
+
* @return void
|
119 |
+
**/
|
120 |
+
function display_js( $file = false, $args = array() ) {
|
121 |
+
static $displayed = array();
|
122 |
+
|
123 |
+
if( ! $file || empty( $file ) ) {
|
124 |
+
throw new Ai1ec_File_Not_Provided( "You need to specify a js file." );
|
125 |
+
}
|
126 |
+
|
127 |
+
$file = AI1EC_JS_PATH . "/" . $file;
|
128 |
+
|
129 |
+
if( $displayed[$file] === $args) // Skip if already displayed
|
130 |
+
return;
|
131 |
+
|
132 |
+
if( ! file_exists( $file ) ) {
|
133 |
+
throw new Ai1ec_File_Not_Found( "The specified js file doesn't exist." );
|
134 |
+
} else {
|
135 |
+
$displayed[$file] = $args; // Flag that we've displayed this file with these args
|
136 |
+
|
137 |
+
extract( $args );
|
138 |
+
echo '<script type="text/javascript" charset="utf-8">';
|
139 |
+
echo '/* <![CDATA[ */';
|
140 |
+
require( $file );
|
141 |
+
echo '/* ]]> */';
|
142 |
+
echo '</script>';
|
143 |
+
}
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* get_view function
|
148 |
+
*
|
149 |
+
* Return the output of a view as a string rather than output to response.
|
150 |
+
*
|
151 |
+
* @param string $file
|
152 |
+
* @param array $args
|
153 |
+
*
|
154 |
+
* @return void
|
155 |
+
**/
|
156 |
+
function get_view( $file = false, $args = array() ) {
|
157 |
+
ob_start();
|
158 |
+
$this->display( $file, $args );
|
159 |
+
return ob_get_clean();
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* json_response function
|
164 |
+
*
|
165 |
+
* Utility for properly outputting JSON data as an AJAX response.
|
166 |
+
*
|
167 |
+
* @param array $data
|
168 |
+
*
|
169 |
+
* @return void
|
170 |
+
**/
|
171 |
+
function json_response( $data ) {
|
172 |
+
header( 'Cache-Control: no-cache, must-revalidate' );
|
173 |
+
header( 'Pragma: no-cache' );
|
174 |
+
header( 'Content-type: application/json' );
|
175 |
+
|
176 |
+
// Output JSON-encoded result and quit
|
177 |
+
echo json_encode( $data );
|
178 |
+
exit;
|
179 |
+
}
|
180 |
+
|
181 |
+
}
|
182 |
+
// END class
|
app/model/class-ai1ec-event.php
ADDED
@@ -0,0 +1,794 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-event.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Event class
|
11 |
+
*
|
12 |
+
* @package Models
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Event {
|
16 |
+
/**
|
17 |
+
* post class variable
|
18 |
+
*
|
19 |
+
* @var object
|
20 |
+
**/
|
21 |
+
var $post;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* post_id class variable
|
25 |
+
*
|
26 |
+
* @var int
|
27 |
+
**/
|
28 |
+
var $post_id;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* instance_id class variable
|
32 |
+
*
|
33 |
+
* Uniquely identifies the recurrence instance of this event object. This
|
34 |
+
* may be null.
|
35 |
+
*
|
36 |
+
* @var int|null
|
37 |
+
**/
|
38 |
+
var $instance_id;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* start class variable
|
42 |
+
*
|
43 |
+
* @var int
|
44 |
+
**/
|
45 |
+
var $start;
|
46 |
+
|
47 |
+
/**
|
48 |
+
* end class variable
|
49 |
+
*
|
50 |
+
* @var int
|
51 |
+
**/
|
52 |
+
var $end;
|
53 |
+
|
54 |
+
/**
|
55 |
+
* allday class variable
|
56 |
+
*
|
57 |
+
* @var int
|
58 |
+
**/
|
59 |
+
var $allday;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* recurrence_rules class variable
|
63 |
+
*
|
64 |
+
* @var string
|
65 |
+
**/
|
66 |
+
var $recurrence_rules;
|
67 |
+
|
68 |
+
/**
|
69 |
+
* exception_rules class variable
|
70 |
+
*
|
71 |
+
* @var string
|
72 |
+
**/
|
73 |
+
var $exception_rules;
|
74 |
+
|
75 |
+
/**
|
76 |
+
* recurrence_dates class variable
|
77 |
+
*
|
78 |
+
* @var string
|
79 |
+
**/
|
80 |
+
var $recurrence_dates;
|
81 |
+
|
82 |
+
/**
|
83 |
+
* exception_dates class variable
|
84 |
+
*
|
85 |
+
* @var string
|
86 |
+
**/
|
87 |
+
var $exception_dates;
|
88 |
+
|
89 |
+
/**
|
90 |
+
* venue class variable
|
91 |
+
*
|
92 |
+
* @var string
|
93 |
+
**/
|
94 |
+
var $venue;
|
95 |
+
|
96 |
+
/**
|
97 |
+
* country class variable
|
98 |
+
*
|
99 |
+
* @var string
|
100 |
+
**/
|
101 |
+
var $country;
|
102 |
+
|
103 |
+
/**
|
104 |
+
* address class variable
|
105 |
+
*
|
106 |
+
* @var string
|
107 |
+
**/
|
108 |
+
var $address;
|
109 |
+
|
110 |
+
/**
|
111 |
+
* city class variable
|
112 |
+
*
|
113 |
+
* @var string
|
114 |
+
**/
|
115 |
+
var $city;
|
116 |
+
|
117 |
+
/**
|
118 |
+
* province class variable
|
119 |
+
*
|
120 |
+
* @var string
|
121 |
+
**/
|
122 |
+
var $province;
|
123 |
+
|
124 |
+
/**
|
125 |
+
* postal_code class variable
|
126 |
+
*
|
127 |
+
* @var int
|
128 |
+
**/
|
129 |
+
var $postal_code;
|
130 |
+
|
131 |
+
/**
|
132 |
+
* show_map class variable
|
133 |
+
*
|
134 |
+
* @var int
|
135 |
+
**/
|
136 |
+
var $show_map;
|
137 |
+
|
138 |
+
/**
|
139 |
+
* contact_name class variable
|
140 |
+
*
|
141 |
+
* @var string
|
142 |
+
**/
|
143 |
+
var $contact_name;
|
144 |
+
|
145 |
+
/**
|
146 |
+
* contact_phone class variable
|
147 |
+
*
|
148 |
+
* @var string
|
149 |
+
**/
|
150 |
+
var $contact_phone;
|
151 |
+
|
152 |
+
/**
|
153 |
+
* contact_email class variable
|
154 |
+
*
|
155 |
+
* @var string
|
156 |
+
**/
|
157 |
+
var $contact_email;
|
158 |
+
|
159 |
+
/**
|
160 |
+
* cost class variable
|
161 |
+
*
|
162 |
+
* @var string
|
163 |
+
**/
|
164 |
+
var $cost;
|
165 |
+
|
166 |
+
// ====================================
|
167 |
+
// = iCalendar feed (.ics) properties =
|
168 |
+
// ====================================
|
169 |
+
/**
|
170 |
+
* ical_feed_url class variable
|
171 |
+
*
|
172 |
+
* @var string
|
173 |
+
**/
|
174 |
+
var $ical_feed_url;
|
175 |
+
|
176 |
+
/**
|
177 |
+
* ical_source_url class variable
|
178 |
+
*
|
179 |
+
* @var string
|
180 |
+
**/
|
181 |
+
var $ical_source_url;
|
182 |
+
|
183 |
+
/**
|
184 |
+
* ical_organizer class variable
|
185 |
+
*
|
186 |
+
* @var string
|
187 |
+
**/
|
188 |
+
var $ical_organizer;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* ical_contact class variable
|
192 |
+
*
|
193 |
+
* @var string
|
194 |
+
**/
|
195 |
+
var $ical_contact;
|
196 |
+
|
197 |
+
/**
|
198 |
+
* ical_uid class variable
|
199 |
+
*
|
200 |
+
* @var string | int
|
201 |
+
**/
|
202 |
+
var $ical_uid;
|
203 |
+
|
204 |
+
// ============
|
205 |
+
// = Taxonomy =
|
206 |
+
// ============
|
207 |
+
/**
|
208 |
+
* tags class variable
|
209 |
+
*
|
210 |
+
* Associated event tag IDs, joined by commas.
|
211 |
+
*
|
212 |
+
* @var string
|
213 |
+
**/
|
214 |
+
var $tags;
|
215 |
+
|
216 |
+
/**
|
217 |
+
* categories class variable
|
218 |
+
*
|
219 |
+
* Associated event category IDs, joined by commas.
|
220 |
+
*
|
221 |
+
* @var string
|
222 |
+
**/
|
223 |
+
var $categories;
|
224 |
+
|
225 |
+
/**
|
226 |
+
* category_colors class variable
|
227 |
+
*
|
228 |
+
* @var string
|
229 |
+
**/
|
230 |
+
private $category_colors;
|
231 |
+
|
232 |
+
/**
|
233 |
+
* color_style class variable
|
234 |
+
*
|
235 |
+
* @var string
|
236 |
+
**/
|
237 |
+
private $color_style;
|
238 |
+
|
239 |
+
/**
|
240 |
+
* tags_html class variable
|
241 |
+
*
|
242 |
+
* A cache variable, used by __get().
|
243 |
+
*
|
244 |
+
* @var string
|
245 |
+
**/
|
246 |
+
private $tags_html;
|
247 |
+
|
248 |
+
/**
|
249 |
+
* categories_html class variable
|
250 |
+
*
|
251 |
+
* A cache variable, used by __get().
|
252 |
+
*
|
253 |
+
* @var string
|
254 |
+
**/
|
255 |
+
private $categories_html;
|
256 |
+
|
257 |
+
/**
|
258 |
+
* __construct function
|
259 |
+
*
|
260 |
+
* Create new event object, using provided data for initialization.
|
261 |
+
*
|
262 |
+
* @param int|array $data Look up post with id $data, or initialize fields
|
263 |
+
* with flat associative array $data containing both
|
264 |
+
* post and event fields returned by join query
|
265 |
+
*
|
266 |
+
* @return void
|
267 |
+
**/
|
268 |
+
function __construct( $data = null ) {
|
269 |
+
global $wpdb;
|
270 |
+
|
271 |
+
if( $data == null )
|
272 |
+
return;
|
273 |
+
|
274 |
+
// ===========
|
275 |
+
// = Post ID =
|
276 |
+
// ===========
|
277 |
+
if( is_numeric( $data ) )
|
278 |
+
{
|
279 |
+
// ============================
|
280 |
+
// = Fetch post from database =
|
281 |
+
// ============================
|
282 |
+
$post = get_post( $data );
|
283 |
+
|
284 |
+
if( ! $post || $post->post_status == 'auto-draft' )
|
285 |
+
throw new Ai1ec_Event_Not_Found( "Post with ID '$data' could not be retrieved from the database." );
|
286 |
+
|
287 |
+
// =============================
|
288 |
+
// = Fetch event from database =
|
289 |
+
// =============================
|
290 |
+
$query = $wpdb->prepare(
|
291 |
+
"SELECT e.post_id, UNIX_TIMESTAMP( e.start ) as start, UNIX_TIMESTAMP( e.end ) as end, e.allday, e.recurrence_rules, e.exception_rules,
|
292 |
+
e.recurrence_dates, e.exception_dates, e.venue, e.country, e.address, e.city, e.province, e.postal_code,
|
293 |
+
e.show_map, e.contact_name, e.contact_phone, e.contact_email, e.cost, e.ical_feed_url, e.ical_source_url,
|
294 |
+
e.ical_organizer, e.ical_contact, e.ical_uid, " .
|
295 |
+
"GROUP_CONCAT( ttc.term_id ) AS categories, " .
|
296 |
+
"GROUP_CONCAT( ttt.term_id ) AS tags " .
|
297 |
+
"FROM {$wpdb->prefix}ai1ec_events e " .
|
298 |
+
"LEFT JOIN $wpdb->term_relationships tr ON post_id = tr.object_id " .
|
299 |
+
"LEFT JOIN $wpdb->term_taxonomy ttc ON tr.term_taxonomy_id = ttc.term_taxonomy_id AND ttc.taxonomy = 'events_categories' " .
|
300 |
+
"LEFT JOIN $wpdb->term_taxonomy ttt ON tr.term_taxonomy_id = ttt.term_taxonomy_id AND ttt.taxonomy = 'events_tags' " .
|
301 |
+
"WHERE post_id = %d",
|
302 |
+
$data );
|
303 |
+
$event = $wpdb->get_row( $query );
|
304 |
+
|
305 |
+
if( $event === null || $event->post_id === null )
|
306 |
+
throw new Ai1ec_Event_Not_Found( "Event with ID '$data' could not be retrieved from the database." );
|
307 |
+
|
308 |
+
// ===========================
|
309 |
+
// = Assign post to property =
|
310 |
+
// ===========================
|
311 |
+
$this->post = $post;
|
312 |
+
|
313 |
+
// ==========================
|
314 |
+
// = Assign values to $this =
|
315 |
+
// ==========================
|
316 |
+
foreach( $this as $property => $value ) {
|
317 |
+
if( $property != 'post' )
|
318 |
+
$this->{$property} = $event->{$property};
|
319 |
+
}
|
320 |
+
}
|
321 |
+
// ===================
|
322 |
+
// = Post/event data =
|
323 |
+
// ===================
|
324 |
+
elseif( is_array( $data ) )
|
325 |
+
{
|
326 |
+
// =======================================================
|
327 |
+
// = Assign each event field the value from the database =
|
328 |
+
// =======================================================
|
329 |
+
foreach( $this as $property => $value ) {
|
330 |
+
if( $property != 'post' && array_key_exists( $property, $data ) ) {
|
331 |
+
$this->{$property} = $data[$property];
|
332 |
+
unset( $data[$property] );
|
333 |
+
}
|
334 |
+
}
|
335 |
+
if( isset( $data['post'] ) ) {
|
336 |
+
$this->post = (object) $data['post'];
|
337 |
+
} else {
|
338 |
+
// ========================================
|
339 |
+
// = Remaining fields are the post fields =
|
340 |
+
// ========================================
|
341 |
+
$this->post = (object) $data;
|
342 |
+
}
|
343 |
+
}
|
344 |
+
else {
|
345 |
+
throw new Ai1ec_Invalid_Argument( "Argument to constructor must be integer, array or null, not '$data'." );
|
346 |
+
}
|
347 |
+
}
|
348 |
+
|
349 |
+
/**
|
350 |
+
* __set function
|
351 |
+
*
|
352 |
+
* Magic set function
|
353 |
+
*
|
354 |
+
* @param string $name Property name
|
355 |
+
* @param mixed $value Property value
|
356 |
+
*
|
357 |
+
* @return void
|
358 |
+
**/
|
359 |
+
public function __set( $name, $value ) {
|
360 |
+
// Not currently used...
|
361 |
+
switch( $name ) {
|
362 |
+
default:
|
363 |
+
$this->{$name} = $value;
|
364 |
+
break;
|
365 |
+
}
|
366 |
+
}
|
367 |
+
|
368 |
+
/**
|
369 |
+
* __get function
|
370 |
+
*
|
371 |
+
* Magic get function
|
372 |
+
* Shortcuts for common formatted versions of event data.
|
373 |
+
*
|
374 |
+
* @param string $name Property name
|
375 |
+
*
|
376 |
+
* @return mixed Property value
|
377 |
+
**/
|
378 |
+
public function __get( $name ) {
|
379 |
+
global $post, $more, $ai1ec_events_helper;
|
380 |
+
|
381 |
+
switch( $name ) {
|
382 |
+
|
383 |
+
case 'uid':
|
384 |
+
return $this->post_id . '@' . bloginfo( 'url' );
|
385 |
+
// ========================
|
386 |
+
// = Get short-form dates =
|
387 |
+
// ========================
|
388 |
+
case 'short_start_time':
|
389 |
+
return $ai1ec_events_helper->get_short_time( $this->start );
|
390 |
+
|
391 |
+
case 'short_end_time':
|
392 |
+
return $ai1ec_events_helper->get_short_time( $this->end );
|
393 |
+
|
394 |
+
case 'short_start_date':
|
395 |
+
return $ai1ec_events_helper->get_short_date( $this->start );
|
396 |
+
|
397 |
+
case 'short_end_date':
|
398 |
+
// Subtract 1 second so that all-day events' end date still
|
399 |
+
// falls within the logical duration of days (since the end date
|
400 |
+
// is always midnight of the following day)
|
401 |
+
return $ai1ec_events_helper->get_short_date( $this->end - 1 );
|
402 |
+
|
403 |
+
// =========================
|
404 |
+
// = Get medium-form dates =
|
405 |
+
// =========================
|
406 |
+
case 'start_time':
|
407 |
+
return $ai1ec_events_helper->get_medium_time( $this->start );
|
408 |
+
|
409 |
+
case 'end_time':
|
410 |
+
return $ai1ec_events_helper->get_medium_time( $this->end );
|
411 |
+
|
412 |
+
// =======================
|
413 |
+
// = Get long-form times =
|
414 |
+
// =======================
|
415 |
+
case 'long_start_time':
|
416 |
+
return $ai1ec_events_helper->get_long_time( $this->start );
|
417 |
+
|
418 |
+
case 'long_end_time':
|
419 |
+
return $ai1ec_events_helper->get_long_time( $this->end );
|
420 |
+
|
421 |
+
// =======================
|
422 |
+
// = Get long-form dates =
|
423 |
+
// =======================
|
424 |
+
case 'long_start_date':
|
425 |
+
return $ai1ec_events_helper->get_long_date( $this->start );
|
426 |
+
|
427 |
+
case 'long_end_date':
|
428 |
+
// Subtract 1 second so that all-day events' end date still
|
429 |
+
// falls within the logical duration of days (since the end date
|
430 |
+
// is always midnight of the following day)
|
431 |
+
return $ai1ec_events_helper->get_long_date( $this->end - 1 );
|
432 |
+
|
433 |
+
case 'timespan_html':
|
434 |
+
$timespan = '';
|
435 |
+
$long_start_date = $this->long_start_date;
|
436 |
+
$long_end_date = $this->long_end_date;
|
437 |
+
|
438 |
+
if( $this->allday ) {
|
439 |
+
$timespan .= $long_start_date;
|
440 |
+
if( $long_end_date != $long_start_date )
|
441 |
+
$timespan .= " – $long_end_date";
|
442 |
+
$timespan = esc_html( $timespan );
|
443 |
+
$timespan .= '<span class="ai1ec-allday-label">';
|
444 |
+
$timespan .= __( ' (all-day)', AI1EC_PLUGIN_NAME );
|
445 |
+
$timespan .= '</span>';
|
446 |
+
} else {
|
447 |
+
if( $long_end_date != $long_start_date )
|
448 |
+
$timespan .= esc_html( $this->long_start_time . ' – ' . $this->long_end_time );
|
449 |
+
elseif( $this->start != $this->end )
|
450 |
+
$timespan .= esc_html( $this->long_start_time . ' - ' . $this->end_time );
|
451 |
+
else
|
452 |
+
$timespan .= esc_html( $this->long_start_time );
|
453 |
+
}
|
454 |
+
return $timespan;
|
455 |
+
|
456 |
+
// =====================================================
|
457 |
+
// = Get the post's excerpt for display in popup view. =
|
458 |
+
// =====================================================
|
459 |
+
case 'post_excerpt':
|
460 |
+
if( ! $this->post->post_excerpt ) {
|
461 |
+
$content = strip_tags( strip_shortcodes( $this->post->post_content ) );
|
462 |
+
$content = preg_replace( '/\s+/', ' ', $content );
|
463 |
+
$words = explode( ' ', $content );
|
464 |
+
if( count( $words ) > 25 )
|
465 |
+
$this->post->post_excerpt = implode( ' ', array_slice( $words, 0, 25 ) ) . ' [...]';
|
466 |
+
else
|
467 |
+
$this->post->post_excerpt = $content;
|
468 |
+
}
|
469 |
+
return $this->post->post_excerpt;
|
470 |
+
|
471 |
+
// ===============================================================
|
472 |
+
// = Return any available location details separated by newlines =
|
473 |
+
// ===============================================================
|
474 |
+
case 'location':
|
475 |
+
$location = '';
|
476 |
+
if( $this->venue ) $location .= "$this->venue\n";
|
477 |
+
if( $this->address ) {
|
478 |
+
$bits = explode( ',', $this->address );
|
479 |
+
$bits = array_map( 'trim', $bits );
|
480 |
+
|
481 |
+
// If more than three comma-separated values, treat first value as
|
482 |
+
// the street address, last value as the country, and everything
|
483 |
+
// in the middle as the city, state, etc.
|
484 |
+
if( count( $bits ) >= 3 ) {
|
485 |
+
// Append the street address
|
486 |
+
$street_address = array_shift( $bits ) . "\n";
|
487 |
+
if( $street_address ) $location .= $street_address;
|
488 |
+
// Save the country for the last line
|
489 |
+
$country = array_pop( $bits );
|
490 |
+
// Append the middle bit(s) (filtering out any zero-length strings)
|
491 |
+
$bits = array_filter( $bits, 'strval' );
|
492 |
+
if( $bits ) $location .= join( ',', $bits ) . "\n";
|
493 |
+
if( $country ) $location .= $country . "\n";
|
494 |
+
} else {
|
495 |
+
// There are two or less comma-separated values, so just append
|
496 |
+
// them each on their own line (filtering out any zero-length strings)
|
497 |
+
$bits = array_filter( $bits, 'strval' );
|
498 |
+
$location .= join( "\n", $bits );
|
499 |
+
}
|
500 |
+
}
|
501 |
+
return $location;
|
502 |
+
|
503 |
+
// ======================
|
504 |
+
// = Categories as HTML =
|
505 |
+
// ======================
|
506 |
+
case 'categories_html':
|
507 |
+
if( $this->categories_html === null ) {
|
508 |
+
$categories = wp_get_post_terms( $this->post_id, 'events_categories' );
|
509 |
+
foreach( $categories as &$category ) {
|
510 |
+
$category =
|
511 |
+
'<a class="ai1ec-category ai1ec-term-id-' . $category->term_id . '" ' .
|
512 |
+
( $category->description ? 'title="' . esc_attr( $category->description ) . '" ' : '' ) .
|
513 |
+
'href="' . get_term_link( $category ) . '">' .
|
514 |
+
$ai1ec_events_helper->get_category_color_square( $category->term_id ) . ' ' . esc_html( $category->name ) . '</a>';
|
515 |
+
}
|
516 |
+
$this->categories_html = join( ' ', $categories );
|
517 |
+
}
|
518 |
+
return $this->categories_html;
|
519 |
+
|
520 |
+
// ================
|
521 |
+
// = Tags as HTML =
|
522 |
+
// ================
|
523 |
+
case 'tags_html':
|
524 |
+
if( $this->tags_html === null ) {
|
525 |
+
$tags = wp_get_post_terms( $this->post_id, 'events_tags' );
|
526 |
+
foreach( $tags as &$tag ) {
|
527 |
+
$tag =
|
528 |
+
'<a class="ai1ec-tag ai1ec-term-id-' . $tag->term_id . '" ' .
|
529 |
+
( $tag->description ? 'title="' . esc_attr( $tag->description ) . '" ' : '' ) .
|
530 |
+
'href="' . get_term_link( $tag ) . '">' .
|
531 |
+
esc_html( $tag->name ) . '</a>';
|
532 |
+
}
|
533 |
+
$this->tags_html = join( ' ', $tags );
|
534 |
+
}
|
535 |
+
return $this->tags_html;
|
536 |
+
|
537 |
+
// ======================================
|
538 |
+
// = Style attribute for event category =
|
539 |
+
// ======================================
|
540 |
+
case 'color_style':
|
541 |
+
if( $this->color_style === null ) {
|
542 |
+
$categories = wp_get_post_terms( $this->post_id, 'events_categories' );
|
543 |
+
$this->color_style = $ai1ec_events_helper->get_event_category_color_style( $categories[0]->term_id, $this->allday );
|
544 |
+
}
|
545 |
+
return $this->color_style;
|
546 |
+
|
547 |
+
// ===============================================
|
548 |
+
// = HTML of category color boxes for this event =
|
549 |
+
// ===============================================
|
550 |
+
case 'category_colors':
|
551 |
+
if( $this->category_colors === null ) {
|
552 |
+
$categories = wp_get_post_terms( $this->post_id, 'events_categories' );
|
553 |
+
$this->category_colors = $ai1ec_events_helper->get_event_category_colors( $categories );
|
554 |
+
}
|
555 |
+
return $this->category_colors;
|
556 |
+
|
557 |
+
// ========================
|
558 |
+
// = Contact info as HTML =
|
559 |
+
// ========================
|
560 |
+
case 'contact_html':
|
561 |
+
$contact = '';
|
562 |
+
if( $this->contact_name )
|
563 |
+
$contact .= '<strong>' . esc_html( $this->contact_name ) . '</strong><br />';
|
564 |
+
if( $this->contact_phone )
|
565 |
+
$contact .= esc_html( $this->contact_phone ) . '<br />';
|
566 |
+
if( $this->contact_email )
|
567 |
+
$contact .= '<a href="mailto:' . esc_attr( $this->contact_email ) . '">' . esc_html( $this->contact_email ) . '</a>';
|
568 |
+
return $contact;
|
569 |
+
|
570 |
+
// ===========================
|
571 |
+
// = Recurrence info as HTML =
|
572 |
+
// ===========================
|
573 |
+
case 'recurrence_html':
|
574 |
+
if( ! $this->recurrence_rules )
|
575 |
+
return null;
|
576 |
+
$rules = $ai1ec_events_helper->parse_recurrence_rules( $this );
|
577 |
+
$patterns = $ai1ec_events_helper->get_repeat_patterns();
|
578 |
+
|
579 |
+
$recurrence_html = '<strong>' . esc_html( $patterns[$rules['repeat']] ) . '</strong>';
|
580 |
+
unset( $rules['repeat'] );
|
581 |
+
|
582 |
+
if( $rules['count'] ) {
|
583 |
+
$rules['count'] = sprintf( _n(
|
584 |
+
'ending after <strong>%d</strong> time',
|
585 |
+
'ending after <strong>%d</strong> times',
|
586 |
+
$rules['count'], AI1EC_PLUGIN_NAME ),
|
587 |
+
$rules['count'] );
|
588 |
+
} else {
|
589 |
+
unset( $rules['count'] );
|
590 |
+
}
|
591 |
+
|
592 |
+
if( $rules['until'] ) {
|
593 |
+
$rules['until'] = sprintf(
|
594 |
+
__( 'until <strong>%s</strong>', AI1EC_PLUGIN_NAME ),
|
595 |
+
esc_html( $ai1ec_events_helper->get_long_date( $rules['until'] ) ) );
|
596 |
+
} else {
|
597 |
+
unset( $rules['until'] );
|
598 |
+
}
|
599 |
+
|
600 |
+
$end = join( __( ' or ', AI1EC_PLUGIN_NAME ), $rules );
|
601 |
+
|
602 |
+
if( $end )
|
603 |
+
$recurrence_html .= ', ' . $end;
|
604 |
+
|
605 |
+
return $recurrence_html;
|
606 |
+
}
|
607 |
+
}
|
608 |
+
|
609 |
+
/**
|
610 |
+
* save function
|
611 |
+
*
|
612 |
+
* Saves the current event data to the database. If $this->post_id exists,
|
613 |
+
* but $update is false, creates a new record in the ai1ec_events table of
|
614 |
+
* this event data, but does not try to create a new post. Else if $update
|
615 |
+
* is true, updates existing event record. If $this->post_id is empty,
|
616 |
+
* creates a new post AND record in the ai1ec_events table for this event.
|
617 |
+
*
|
618 |
+
* @param bool $update Whether to update an existing event or create a
|
619 |
+
* new one
|
620 |
+
* @return int The post_id of the new or existing event.
|
621 |
+
**/
|
622 |
+
function save( $update = false )
|
623 |
+
{
|
624 |
+
global $wpdb,
|
625 |
+
$ai1ec_events_helper;
|
626 |
+
|
627 |
+
// ===========================
|
628 |
+
// = Insert events meta data =
|
629 |
+
// ===========================
|
630 |
+
$columns = array(
|
631 |
+
'post_id' => $this->post_id,
|
632 |
+
'start' => $this->start,
|
633 |
+
'end' => $this->end,
|
634 |
+
'allday' => $this->allday,
|
635 |
+
'recurrence_rules' => $this->recurrence_rules,
|
636 |
+
'exception_rules' => $this->exception_rules,
|
637 |
+
'recurrence_dates' => $this->recurrence_dates,
|
638 |
+
'exception_dates' => $this->exception_dates,
|
639 |
+
'venue' => $this->venue,
|
640 |
+
'country' => $this->country,
|
641 |
+
'address' => $this->address,
|
642 |
+
'city' => $this->city,
|
643 |
+
'province' => $this->province,
|
644 |
+
'postal_code' => $this->postal_code,
|
645 |
+
'show_map' => $this->show_map,
|
646 |
+
'contact_name' => $this->contact_name,
|
647 |
+
'contact_phone' => $this->contact_phone,
|
648 |
+
'contact_email' => $this->contact_email,
|
649 |
+
'cost' => $this->cost,
|
650 |
+
'ical_feed_url' => $this->ical_feed_url,
|
651 |
+
'ical_source_url' => $this->ical_source_url,
|
652 |
+
'ical_uid' => $this->ical_uid,
|
653 |
+
);
|
654 |
+
|
655 |
+
$format = array(
|
656 |
+
'%d',
|
657 |
+
'FROM_UNIXTIME( %d )',
|
658 |
+
'FROM_UNIXTIME( %d )',
|
659 |
+
'%d',
|
660 |
+
'%s',
|
661 |
+
'%s',
|
662 |
+
'%s',
|
663 |
+
'%s',
|
664 |
+
'%s',
|
665 |
+
'%s',
|
666 |
+
'%s',
|
667 |
+
'%s',
|
668 |
+
'%s',
|
669 |
+
'%s',
|
670 |
+
'%d',
|
671 |
+
'%s',
|
672 |
+
'%s',
|
673 |
+
'%s',
|
674 |
+
'%s',
|
675 |
+
'%s',
|
676 |
+
'%s',
|
677 |
+
'%s'
|
678 |
+
);
|
679 |
+
|
680 |
+
$table_name = $wpdb->prefix . 'ai1ec_events';
|
681 |
+
if( $this->post_id )
|
682 |
+
{
|
683 |
+
if( ! $update ) {
|
684 |
+
// =========================
|
685 |
+
// = Insert new event data =
|
686 |
+
// =========================
|
687 |
+
$wpdb->query( $wpdb->prepare(
|
688 |
+
"INSERT INTO $table_name ( " .
|
689 |
+
join( ', ', array_keys( $columns ) ) .
|
690 |
+
" ) VALUES ( " .
|
691 |
+
join( ', ', $format ) .
|
692 |
+
" )",
|
693 |
+
$columns ) );
|
694 |
+
} else {
|
695 |
+
// ==============================
|
696 |
+
// = Update existing event data =
|
697 |
+
// ==============================
|
698 |
+
$where = array( 'post_id' => $this->post_id );
|
699 |
+
$where_escape = array( '%d' );
|
700 |
+
$wpdb->update( $table_name, $columns, $where, $format, $where_escape );
|
701 |
+
}
|
702 |
+
} else {
|
703 |
+
// ===================
|
704 |
+
// = Insert new post =
|
705 |
+
// ===================
|
706 |
+
$this->post_id = wp_insert_post( $this->post );
|
707 |
+
$columns['post_id'] = $this->post_id;
|
708 |
+
wp_set_post_terms( $this->post_id, $this->categories, 'events_categories' );
|
709 |
+
wp_set_post_terms( $this->post_id, $this->tags, 'events_tags' );
|
710 |
+
|
711 |
+
// =========================
|
712 |
+
// = Insert new event data =
|
713 |
+
// =========================
|
714 |
+
$wpdb->query( $wpdb->prepare(
|
715 |
+
"INSERT INTO $table_name ( " .
|
716 |
+
join( ', ', array_keys( $columns ) ) .
|
717 |
+
" ) VALUES ( " .
|
718 |
+
join( ', ', $format ) .
|
719 |
+
" )",
|
720 |
+
$columns ) );
|
721 |
+
}
|
722 |
+
|
723 |
+
return $this->post_id;
|
724 |
+
}
|
725 |
+
|
726 |
+
/**
|
727 |
+
* getProperty function
|
728 |
+
*
|
729 |
+
* Returns $property value
|
730 |
+
*
|
731 |
+
* @param string $property Property name
|
732 |
+
*
|
733 |
+
* @return mixed
|
734 |
+
**/
|
735 |
+
function getProperty( $property ) {
|
736 |
+
return $this->property;
|
737 |
+
}
|
738 |
+
|
739 |
+
/**
|
740 |
+
* isWholeDay function
|
741 |
+
*
|
742 |
+
* Determines if an event is a whole day event
|
743 |
+
*
|
744 |
+
* @return bool
|
745 |
+
**/
|
746 |
+
function isWholeDay() {
|
747 |
+
return ( bool ) $this->allday;
|
748 |
+
}
|
749 |
+
|
750 |
+
/**
|
751 |
+
* getStart function
|
752 |
+
*
|
753 |
+
* Returns the start time of the event
|
754 |
+
*
|
755 |
+
* @return int
|
756 |
+
**/
|
757 |
+
function getStart() {
|
758 |
+
return $this->start;
|
759 |
+
}
|
760 |
+
|
761 |
+
/**
|
762 |
+
* getEnd function
|
763 |
+
*
|
764 |
+
* Returns the end time of the event
|
765 |
+
*
|
766 |
+
* @return int
|
767 |
+
**/
|
768 |
+
function getEnd() {
|
769 |
+
return $this->end;
|
770 |
+
}
|
771 |
+
|
772 |
+
/**
|
773 |
+
* getFrequency function
|
774 |
+
*
|
775 |
+
* Returns the frequency of the event
|
776 |
+
*
|
777 |
+
* @return object
|
778 |
+
**/
|
779 |
+
function getFrequency() {
|
780 |
+
return new SG_iCal_Freq( $this->recurrence_rules, $this->start );
|
781 |
+
}
|
782 |
+
|
783 |
+
/**
|
784 |
+
* getDuration function
|
785 |
+
*
|
786 |
+
* Returns the duration of the event
|
787 |
+
*
|
788 |
+
* @return int
|
789 |
+
**/
|
790 |
+
function getDuration() {
|
791 |
+
return $this->end - $this->start;
|
792 |
+
}
|
793 |
+
}
|
794 |
+
// END class
|
app/model/class-ai1ec-exporter.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-exporter.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Event class
|
11 |
+
*
|
12 |
+
* @package Models
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Exporter {
|
16 |
+
|
17 |
+
function __construct() {
|
18 |
+
|
19 |
+
}
|
20 |
+
|
21 |
+
function export( $events, $format = "ics" ) {
|
22 |
+
|
23 |
+
}
|
24 |
+
|
25 |
+
function export_to_ics() {
|
26 |
+
|
27 |
+
}
|
28 |
+
}
|
29 |
+
// END class
|
app/model/class-ai1ec-importer.php
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-importer.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Importer class
|
11 |
+
*
|
12 |
+
* @package Models
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Importer {
|
16 |
+
var $events;
|
17 |
+
|
18 |
+
function __construct() {
|
19 |
+
|
20 |
+
}
|
21 |
+
|
22 |
+
function parse_rss( $rss_feed ) {
|
23 |
+
|
24 |
+
}
|
25 |
+
|
26 |
+
function parse_file( $file ) {
|
27 |
+
|
28 |
+
}
|
29 |
+
}
|
30 |
+
// END class
|
app/model/class-ai1ec-settings.php
ADDED
@@ -0,0 +1,288 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
//
|
3 |
+
// class-ai1ec-settings.php
|
4 |
+
// all-in-one-events-calendar
|
5 |
+
//
|
6 |
+
// Created by The Seed Studio on 2011-07-13.
|
7 |
+
//
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Ai1ec_Settings class
|
11 |
+
*
|
12 |
+
* @package Models
|
13 |
+
* @author The Seed Studio
|
14 |
+
**/
|
15 |
+
class Ai1ec_Settings {
|
16 |
+
/**
|
17 |
+
* _instance class variable
|
18 |
+
*
|
19 |
+
* Class instance
|
20 |
+
*
|
21 |
+
* @var null | object
|
22 |
+
**/
|
23 |
+
private static $_instance = NULL;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* calendar_page_id class variable
|
27 |
+
*
|
28 |
+
* @var int
|
29 |
+
**/
|
30 |
+
var $calendar_page_id;
|
31 |
+
|
32 |
+
/**
|
33 |
+
* default_calendar_view class variable
|
34 |
+
*
|
35 |
+
* @var string
|
36 |
+
**/
|
37 |
+
var $default_calendar_view;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* week_start_day class variable
|
41 |
+
*
|
42 |
+
* @var int
|
43 |
+
**/
|
44 |
+
var $week_start_day;
|
45 |
+
|
46 |
+
/**
|
47 |
+
* agenda_events_per_page class variable
|
48 |
+
*
|
49 |
+
* @var int
|
50 |
+
**/
|
51 |
+
var $agenda_events_per_page;
|
52 |
+
|
53 |
+
/**
|
54 |
+
* calendar_css_selector class variable
|
55 |
+
*
|
56 |
+
* @var string
|
57 |
+
**/
|
58 |
+
var $calendar_css_selector;
|
59 |
+
|
60 |
+
/**
|
61 |
+
* include_events_in_rss class variable
|
62 |
+
*
|
63 |
+
* @var bool
|
64 |
+
**/
|
65 |
+
var $include_events_in_rss;
|
66 |
+
|
67 |
+
/**
|
68 |
+
* allow_publish_to_facebook class variable
|
69 |
+
*
|
70 |
+
* @var bool
|
71 |
+
**/
|
72 |
+
var $allow_publish_to_facebook;
|
73 |
+
|
74 |
+
/**
|
75 |
+
* facebook_credentials class variable
|
76 |
+
*
|
77 |
+
* @var array
|
78 |
+
**/
|
79 |
+
var $facebook_credentials;
|
80 |
+
|
81 |
+
/**
|
82 |
+
* user_role_can_create_event class variable
|
83 |
+
*
|
84 |
+
* @var bool
|
85 |
+
**/
|
86 |
+
var $user_role_can_create_event;
|
87 |
+
|
88 |
+
/**
|
89 |
+
* cron_freq class variable
|
90 |
+
*
|
91 |
+
* Cron frequency
|
92 |
+
*
|
93 |
+
* @var string
|
94 |
+
**/
|
95 |
+
var $cron_freq;
|
96 |
+
|
97 |
+
/**
|
98 |
+
* show_publish_button class variable
|
99 |
+
*
|
100 |
+
* Display publish button at the bottom of the
|
101 |
+
* submission form
|
102 |
+
*
|
103 |
+
* @var bool
|
104 |
+
**/
|
105 |
+
var $show_publish_button;
|
106 |
+
|
107 |
+
/**
|
108 |
+
* show_create_event_button class variable
|
109 |
+
*
|
110 |
+
* Display "Post Your Event" button on the calendar page for those users with
|
111 |
+
* the privilege.
|
112 |
+
*
|
113 |
+
* @var bool
|
114 |
+
**/
|
115 |
+
var $show_create_event_button;
|
116 |
+
|
117 |
+
/**
|
118 |
+
* inject_categories class variable
|
119 |
+
*
|
120 |
+
* Include Event Categories as part of the output of the wp_list_categories()
|
121 |
+
* template tag.
|
122 |
+
*
|
123 |
+
* @var bool
|
124 |
+
**/
|
125 |
+
var $inject_categories;
|
126 |
+
|
127 |
+
/**
|
128 |
+
* settings_page class variable
|
129 |
+
*
|
130 |
+
* Stores a reference to the settings page added using
|
131 |
+
* add_submenu_page function
|
132 |
+
*
|
133 |
+
* @var object
|
134 |
+
**/
|
135 |
+
var $settings_page;
|
136 |
+
|
137 |
+
/**
|
138 |
+
* __construct function
|
139 |
+
*
|
140 |
+
* Default constructor
|
141 |
+
**/
|
142 |
+
private function __construct() {
|
143 |
+
$this->set_defaults(); // set default settings
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* get_instance function
|
148 |
+
*
|
149 |
+
* Return singleton instance
|
150 |
+
*
|
151 |
+
* @return object
|
152 |
+
**/
|
153 |
+
static function get_instance()
|
154 |
+
{
|
155 |
+
if( self::$_instance === NULL ) {
|
156 |
+
// get the settings from the database
|
157 |
+
self::$_instance = get_option( 'ai1ec_settings' );
|
158 |
+
|
159 |
+
// if there are no settings in the database
|
160 |
+
// save default values for the settings
|
161 |
+
if( ! self::$_instance ) {
|
162 |
+
self::$_instance = new self();
|
163 |
+
delete_option( 'ai1ec_settings' );
|
164 |
+
add_option( 'ai1ec_settings', self::$_instance );
|
165 |
+
} else {
|
166 |
+
self::$_instance->set_defaults(); // set default settings
|
167 |
+
}
|
168 |
+
}
|
169 |
+
|
170 |
+
return self::$_instance;
|
171 |
+
}
|
172 |
+
|
173 |
+
/**
|
174 |
+
* save function
|
175 |
+
*
|
176 |
+
* Save settings to the database.
|
177 |
+
*
|
178 |
+
* @return void
|
179 |
+
**/
|
180 |
+
function save() {
|
181 |
+
update_option( 'ai1ec_settings', $this );
|
182 |
+
update_option( 'start_of_week', $this->week_start_day );
|
183 |
+
update_option( 'ai1ec_cron_version', get_option( 'ai1ec_cron_version' ) + 1 );
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* set_defaults function
|
188 |
+
*
|
189 |
+
* Set default values for settings.
|
190 |
+
*
|
191 |
+
* @return void
|
192 |
+
**/
|
193 |
+
function set_defaults() {
|
194 |
+
$defaults = array(
|
195 |
+
'calendar_page_id' => 0,
|
196 |
+
'default_calendar_view' => 'month',
|
197 |
+
'calendar_css_selector' => '',
|
198 |
+
'week_start_day' => get_option( 'start_of_week' ),
|
199 |
+
'agenda_events_per_page' => get_option( 'posts_per_page' ),
|
200 |
+
'include_events_in_rss' => false,
|
201 |
+
'allow_publish_to_facebook' => false,
|
202 |
+
'facebook_credentials' => null,
|
203 |
+
'user_role_can_create_event' => null,
|
204 |
+
'show_publish_button' => false,
|
205 |
+
'show_create_event_button' => false,
|
206 |
+
'inject_categories' => false,
|
207 |
+
'cron_freq' => 'daily'
|
208 |
+
);
|
209 |
+
|
210 |
+
foreach( $defaults as $key => $default ) {
|
211 |
+
if( ! isset( $this->$key ) )
|
212 |
+
$this->$key = $default;
|
213 |
+
}
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* update function
|
218 |
+
*
|
219 |
+
* Updates field values with corresponding values found in $params
|
220 |
+
* associative array.
|
221 |
+
*
|
222 |
+
* @param array $params
|
223 |
+
*
|
224 |
+
* @return void
|
225 |
+
**/
|
226 |
+
function update( $params ) {
|
227 |
+
$this->update_page( 'calendar_page_id', $params );
|
228 |
+
$this->default_calendar_view = $params['default_calendar_view'];
|
229 |
+
$this->calendar_css_selector = $params['calendar_css_selector'];
|
230 |
+
$this->week_start_day = $params['week_start_day'];
|
231 |
+
$this->agenda_events_per_page = $params['agenda_events_per_page'];
|
232 |
+
$this->agenda_events_per_page = intval( $this->agenda_events_per_page );
|
233 |
+
if( $this->agenda_events_per_page <= 0 )
|
234 |
+
$this->agenda_events_per_page = 1;
|
235 |
+
$this->cron_freq = $params['cron_freq'];
|
236 |
+
$this->show_publish_button = $params['show_publish_button'];
|
237 |
+
$this->show_create_event_button = $params['show_create_event_button'];
|
238 |
+
$this->inject_categories = $params['inject_categories'];
|
239 |
+
$this->include_events_in_rss = $params['include_events_in_rss'];
|
240 |
+
$this->allow_events_posting_facebook = $params['allow_events_posting_facebook'];
|
241 |
+
$this->facebook_credentials = $params['facebook_credentials'];
|
242 |
+
$this->user_role_can_create_event = $params['user_role_can_create_event'];
|
243 |
+
}
|
244 |
+
|
245 |
+
/**
|
246 |
+
* update_page function
|
247 |
+
*
|
248 |
+
* Update page for the calendar with the one specified by the drop-down box.
|
249 |
+
* If the value is not numeric, user chose to auto-create a new page,
|
250 |
+
* therefore do so.
|
251 |
+
*
|
252 |
+
* @param string $field_name
|
253 |
+
* @param array $params
|
254 |
+
*
|
255 |
+
* @return void
|
256 |
+
**/
|
257 |
+
function update_page( $field_name, &$params ) {
|
258 |
+
if( ! is_numeric( $params[$field_name] ) &&
|
259 |
+
preg_match( '#^__auto_page:(.*?)$#', $params[$field_name], $matches ) )
|
260 |
+
{
|
261 |
+
$this->$field_name = $params[$field_name] = $this->auto_add_page( $matches[1] );
|
262 |
+
} else {
|
263 |
+
$this->$field_name = (int) $params[$field_name];
|
264 |
+
}
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* auto_add_page function
|
269 |
+
*
|
270 |
+
* Auto-create a WordPress page with given name for use by this plugin.
|
271 |
+
*
|
272 |
+
* @param string page_name
|
273 |
+
*
|
274 |
+
* @return int the new page's ID.
|
275 |
+
**/
|
276 |
+
function auto_add_page( $page_name ) {
|
277 |
+
return wp_insert_post(
|
278 |
+
array(
|
279 |
+
'post_title' => $page_name,
|
280 |
+
'post_type' => 'page',
|
281 |
+
'post_status' => 'publish',
|
282 |
+
'comment_status' => 'closed'
|
283 |
+
)
|
284 |
+
);
|
285 |
+
}
|
286 |
+
|
287 |
+
}
|
288 |
+
// END class
|
app/view/admin_notices.php
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
1 |
+
<div id="message" class="updated fade">
|
2 |
+
<p><strong><?php _e( 'All-in-One Events Calendar Notice:', AI1EC_PLUGIN_NAME ) ?></strong> <?php echo $msg ?></p>
|
3 |
+
</div>
|
app/view/agenda.php
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h2 class="ai1ec-calendar-title"><?php echo esc_html( $title ) ?></h2>
|
2 |
+
<span class="ai1ec-title-buttons">
|
3 |
+
<?php if( $dates ): ?>
|
4 |
+
<a id="ai1ec-expand-all" class="ai1ec-button">
|
5 |
+
<?php _e( '+ Expand All', AI1EC_JS_URL ) ?>
|
6 |
+
</a><a
|
7 |
+
id="ai1ec-collapse-all" class="ai1ec-button">
|
8 |
+
<?php _e( '− Collapse All', AI1EC_JS_URL ) ?>
|
9 |
+
</a
|
10 |
+
><?php endif ?><a
|
11 |
+
id="ai1ec-today" class="ai1ec-load-view ai1ec-button" href="#action=ai1ec_agenda">
|
12 |
+
<?php _e( 'Today', AI1EC_JS_URL ) ?>
|
13 |
+
</a>
|
14 |
+
</span>
|
15 |
+
<ul class="ai1ec-pagination">
|
16 |
+
<?php foreach( $pagination_links as $link ): ?>
|
17 |
+
<li>
|
18 |
+
<a id="<?php echo $link['id'] ?>" class="ai1ec-load-view ai1ec-button ai1ec-pagination"
|
19 |
+
href="<?php echo esc_attr( $link['href'] ) ?>">
|
20 |
+
<?php echo esc_html( $link['text'] ) ?>
|
21 |
+
</a>
|
22 |
+
</li>
|
23 |
+
<?php endforeach ?>
|
24 |
+
</ul>
|
25 |
+
<ol class="ai1ec-agenda-view">
|
26 |
+
<?php if( ! $dates ): ?>
|
27 |
+
<p class="ai1ec-no-results">
|
28 |
+
<?php _e( 'There are no upcoming events to display at this time.' ) ?>
|
29 |
+
</p>
|
30 |
+
<?php else: ?>
|
31 |
+
<?php foreach( $dates as $timestamp => $date_info ): ?>
|
32 |
+
<li class="ai1ec-date <?php if( $date_info['today'] ) echo 'ai1ec-today' ?>">
|
33 |
+
<h3 class="ai1ec-date-title">
|
34 |
+
<div class="ai1ec-month"><?php echo strftime( '%b', $timestamp ) ?></div>
|
35 |
+
<div class="ai1ec-day"><?php echo strftime( '%e', $timestamp ) ?></div>
|
36 |
+
<div class="ai1ec-weekday"><?php echo strftime( '%a', $timestamp ) ?></div>
|
37 |
+
</h3>
|
38 |
+
<ol class="ai1ec-date-events">
|
39 |
+
<?php foreach( $date_info['events'] as $category ): ?>
|
40 |
+
<?php foreach( $category as $event ): ?>
|
41 |
+
<li class="ai1ec-event
|
42 |
+
ai1ec-event-id-<?php echo $event->post_id ?>
|
43 |
+
ai1ec-event-instance-id-<?php echo $event->instance_id ?>
|
44 |
+
<?php if( $event->allday ) echo 'ai1ec-allday' ?>
|
45 |
+
<?php if( $event->post_id == $active_event ) echo 'ai1ec-active-event' ?>">
|
46 |
+
|
47 |
+
<?php // Insert post ID for use by JavaScript filtering later ?>
|
48 |
+
<input type="hidden" class="ai1ec-post-id" value="<?php echo $event->post_id ?>" />
|
49 |
+
|
50 |
+
<?php // Hidden summary, until clicked ?>
|
51 |
+
<div class="ai1ec-event-summary">
|
52 |
+
<div class="ai1ec-event-click">
|
53 |
+
<div class="ai1ec-event-expand">−</div>
|
54 |
+
<div class="ai1ec-event-title">
|
55 |
+
<?php echo esc_html( $event->post->post_title ) ?>
|
56 |
+
<?php if( $event->allday ): ?>
|
57 |
+
<span class="ai1ec-allday-label"><?php _e( '(all-day)' ) ?></span>
|
58 |
+
<?php endif ?>
|
59 |
+
</div>
|
60 |
+
<div class="ai1ec-event-time">
|
61 |
+
<?php if( $event->allday ): ?>
|
62 |
+
<?php echo esc_html( $event->short_start_date ) ?>
|
63 |
+
<?php if( $event->short_end_date != $event->short_start_date ): ?>
|
64 |
+
– <?php echo esc_html( $event->short_end_date ) ?>
|
65 |
+
<?php endif ?>
|
66 |
+
<?php else: ?>
|
67 |
+
<?php echo esc_html( $event->start_time . ' – ' . $event->end_time ) ?></span>
|
68 |
+
<?php endif ?>
|
69 |
+
</div>
|
70 |
+
</div>
|
71 |
+
<div class="ai1ec-event-description">
|
72 |
+
<div class="ai1ec-event-overlay">
|
73 |
+
<a class="ai1ec-read-more ai1ec-button"
|
74 |
+
href="<?php echo esc_attr( get_permalink( $event->post_id ) ) ?>">
|
75 |
+
<?php _e( 'Read more »', AI1EP_PLUGIN_NAME ) ?>
|
76 |
+
</a>
|
77 |
+
<?php if( $event->categories_html ): ?>
|
78 |
+
<div class="ai1ec-categories">
|
79 |
+
<label class="ai1ec-label"><?php _e( 'Categories:', AI1EC_PLUGIN_NAME ) ?></label>
|
80 |
+
<?php echo $event->categories_html ?>
|
81 |
+
</div>
|
82 |
+
<?php endif ?>
|
83 |
+
<?php if( $event->tags_html ): ?>
|
84 |
+
<div class="ai1ec-tags">
|
85 |
+
<label class="ai1ec-label"><?php _e( 'Tags:', AI1EC_PLUGIN_NAME ) ?></label>
|
86 |
+
<?php echo $event->tags_html ?>
|
87 |
+
</div>
|
88 |
+
<?php endif ?>
|
89 |
+
</div>
|
90 |
+
<?php echo apply_filters( 'the_content', $event->post->post_content ) ?>
|
91 |
+
</div>
|
92 |
+
</div>
|
93 |
+
|
94 |
+
<div class="ai1ec-event-click">
|
95 |
+
<?php if( $event->category_colors ): ?>
|
96 |
+
<div class="ai1ec-category-colors"><?php echo $event->category_colors ?></div>
|
97 |
+
<?php endif ?>
|
98 |
+
<div class="ai1ec-event-expand">+</div>
|
99 |
+
<?php if( ! $event->allday ): ?>
|
100 |
+
<div class="ai1ec-event-time">
|
101 |
+
<?php echo esc_html( $event->start_time ) ?></span>
|
102 |
+
</div>
|
103 |
+
<?php endif ?>
|
104 |
+
<div class="ai1ec-event-title">
|
105 |
+
<?php echo esc_html( $event->post->post_title ) ?>
|
106 |
+
<?php if( $event->allday ): ?>
|
107 |
+
<span class="ai1ec-allday-label"><?php _e( '(all-day)' ) ?></span>
|
108 |
+
<?php endif ?>
|
109 |
+
</div>
|
110 |
+
</div>
|
111 |
+
|
112 |
+
</li>
|
113 |
+
<?php endforeach ?>
|
114 |
+
<?php endforeach ?>
|
115 |
+
</ol>
|
116 |
+
</li>
|
117 |
+
<?php endforeach ?>
|
118 |
+
<?php endif ?>
|
119 |
+
</ol>
|
app/view/box_event_contact.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h4 class="ai1ec-section-title"><?php _e( 'Organizer contact info', 'ai1ec' ); ?></h4>
|
2 |
+
<table class="ai1ec-form">
|
3 |
+
<tbody>
|
4 |
+
<tr>
|
5 |
+
<td class="ai1ec-first">
|
6 |
+
<label for="ai1ec_contact_name">
|
7 |
+
<?php _e( 'Contact name:', 'ai1ec' ); ?>
|
8 |
+
</label>
|
9 |
+
</td>
|
10 |
+
<td>
|
11 |
+
<input type="text" name="ai1ec_contact_name" id="ai1ec_contact_name" value="<?php echo $contact_name; ?>" />
|
12 |
+
</td>
|
13 |
+
</tr>
|
14 |
+
<tr>
|
15 |
+
<td>
|
16 |
+
<label for="ai1ec_contact_phone">
|
17 |
+
<?php _e( 'Phone:', 'ai1ec' ); ?>
|
18 |
+
</label>
|
19 |
+
</td>
|
20 |
+
<td>
|
21 |
+
<input type="text" name="ai1ec_contact_phone" id="ai1ec_contact_phone" value="<?php echo $contact_phone; ?>" />
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
<tr>
|
25 |
+
<td>
|
26 |
+
<label for="ai1ec_contact_email">
|
27 |
+
<?php _e( 'E-mail:', 'ai1ec' ); ?>
|
28 |
+
</label>
|
29 |
+
</td>
|
30 |
+
<td>
|
31 |
+
<input type="text" name="ai1ec_contact_email" id="ai1ec_contact_email" value="<?php echo $contact_email; ?>" />
|
32 |
+
</td>
|
33 |
+
</tr>
|
34 |
+
</tbody>
|
35 |
+
</table>
|
app/view/box_event_cost.php
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h4 class="ai1ec-section-title"><?php _e( 'Event cost', 'ai1ec' ); ?></h4>
|
2 |
+
<table class="ai1ec-form">
|
3 |
+
<tbody>
|
4 |
+
<tr>
|
5 |
+
<td class="ai1ec-first">
|
6 |
+
<label for="ai1ec_cost">
|
7 |
+
<?php _e( 'Cost', 'ai1ec' ); ?>:
|
8 |
+
</label>
|
9 |
+
</td>
|
10 |
+
<td>
|
11 |
+
<input type="text" name="ai1ec_cost" id="ai1ec_cost" value="<?php echo $cost; ?>" />
|
12 |
+
</td>
|
13 |
+
</tr>
|
14 |
+
</tbody>
|
15 |
+
</table>
|
app/view/box_event_location.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h4 class="ai1ec-section-title"><?php _e( 'Event location details', 'ai1ec' ); ?></h4>
|
2 |
+
<table class="ai1ec-form ai1ec-location-form">
|
3 |
+
<tbody>
|
4 |
+
<tr>
|
5 |
+
<td class="ai1ec-first">
|
6 |
+
<label for="ai1ec_venue">
|
7 |
+
<?php _e( 'Venue name:', 'ai1ec' ); ?>
|
8 |
+
</label>
|
9 |
+
</td>
|
10 |
+
<td>
|
11 |
+
<input type="text" name="ai1ec_venue" id="ai1ec_venue" value="<?php echo $venue; ?>" />
|
12 |
+
</td>
|
13 |
+
</tr>
|
14 |
+
<tr>
|
15 |
+
<td>
|
16 |
+
<label for="ai1ec_address">
|
17 |
+
<?php _e( 'Address:', 'ai1ec' ); ?>
|
18 |
+
</label>
|
19 |
+
</td>
|
20 |
+
<td>
|
21 |
+
<input type="text" name="ai1ec_address" id="ai1ec_address" value="<?php echo $address; ?>" />
|
22 |
+
</td>
|
23 |
+
</tr>
|
24 |
+
<tr>
|
25 |
+
<td>
|
26 |
+
<label for="ai1ec_google_map">
|
27 |
+
<?php _e( 'Show Google Map:', 'ai1ec' ); ?>
|
28 |
+
</label>
|
29 |
+
</td>
|
30 |
+
<td>
|
31 |
+
<input type="checkbox" value="1" name="ai1ec_google_map" id="ai1ec_google_map" <?php echo $google_map; ?> />
|
32 |
+
</td>
|
33 |
+
</tr>
|
34 |
+
</tbody>
|
35 |
+
</table>
|
36 |
+
<div class="ai1ec_box_map <?php if( $show_map ) echo 'ai1ec_box_map_visible' ?>">
|
37 |
+
<div id="ai1ec_map_canvas"></div>
|
38 |
+
</div>
|
39 |
+
<input type="hidden" name="ai1ec_city" id="ai1ec_city" value="<?php echo $city; ?>" />
|
40 |
+
<input type="hidden" name="ai1ec_province" id="ai1ec_province" value="<?php echo $province; ?>" />
|
41 |
+
<input type="hidden" name="ai1ec_postal_code" id="ai1ec_postal_code" value="<?php echo $postal_code; ?>" />
|
42 |
+
<input type="hidden" name="ai1ec_country" id="ai1ec_country" value="<?php echo $country; ?>" />
|
app/view/box_eventbrite.php
ADDED
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h4 class="box_h4"><?php _e( 'Eventbrite Ticketing', AI1EC_PLUGIN_NAME ); ?>:</h4>
|
2 |
+
<table>
|
3 |
+
<tbody>
|
4 |
+
<tr>
|
5 |
+
<td>
|
6 |
+
<label>
|
7 |
+
<?php _e( 'Register this event with Eventbrite.com?', AI1EC_PLUGIN_NAME ); ?>
|
8 |
+
</label>
|
9 |
+
</td>
|
10 |
+
<td>
|
11 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_yes" id="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_yes" />
|
12 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_yes"><?php _e( 'Yes', AI1EC_PLUGIN_NAME ); ?></label>
|
13 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_no" id="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_no" />
|
14 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_no"><?php _e( 'No', AI1EC_PLUGIN_NAME ); ?></label>
|
15 |
+
</td>
|
16 |
+
</tr>
|
17 |
+
</tbody>
|
18 |
+
</table>
|
19 |
+
|
20 |
+
<div id="<?php echo AI1EC_PLUGIN_NAME; ?>_eventbrite_body">
|
21 |
+
<h4>
|
22 |
+
<?php _e( 'Set up your first ticket', AI1EC_PLUGIN_NAME ); ?>
|
23 |
+
<small>
|
24 |
+
<?php _e( 'To create multiple tickets per event, submit this form, then follow the link to Eventbrite.', AI1EC_PLUGIN_NAME ); ?>
|
25 |
+
</small>
|
26 |
+
</h4>
|
27 |
+
<table>
|
28 |
+
<tbody>
|
29 |
+
<tr>
|
30 |
+
<td>
|
31 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_name">
|
32 |
+
<?php _e( 'Name', AI1EC_PLUGIN_NAME ); ?>:
|
33 |
+
</label>
|
34 |
+
</td>
|
35 |
+
<td>
|
36 |
+
<input type="text" name="<?php echo AI1EC_PLUGIN_NAME; ?>_name" id="<?php echo AI1EC_PLUGIN_NAME; ?>_name" />
|
37 |
+
</td>
|
38 |
+
</tr>
|
39 |
+
<tr>
|
40 |
+
<td>
|
41 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_description">
|
42 |
+
<?php _e( 'Description', AI1EC_PLUGIN_NAME ); ?>:
|
43 |
+
</label>
|
44 |
+
</td>
|
45 |
+
<td>
|
46 |
+
<textarea name="<?php echo AI1EC_PLUGIN_NAME; ?>_description" id="<?php echo AI1EC_PLUGIN_NAME; ?>_description">
|
47 |
+
</textarea>
|
48 |
+
</td>
|
49 |
+
</tr>
|
50 |
+
<tr>
|
51 |
+
<td>
|
52 |
+
<label>
|
53 |
+
<?php _e( 'Type', AI1EC_PLUGIN_NAME ); ?>:
|
54 |
+
</label>
|
55 |
+
</td>
|
56 |
+
<td>
|
57 |
+
<input type="radio" name="<?php echo AI1EC_PLUGIN_NAME; ?>_type" id="<?php echo AI1EC_PLUGIN_NAME; ?>_type_price" />
|
58 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_type_price"><?php _e( 'Set Price', AI1EC_PLUGIN_NAME ); ?></label>
|
59 |
+
<input type="radio" name="<?php echo AI1EC_PLUGIN_NAME; ?>_type" id="<?php echo AI1EC_PLUGIN_NAME; ?>_type_donation" />
|
60 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_type_donation"><?php _e( 'Donation Based', AI1EC_PLUGIN_NAME ); ?></label>
|
61 |
+
</td>
|
62 |
+
</tr>
|
63 |
+
<tr>
|
64 |
+
<td>
|
65 |
+
</td>
|
66 |
+
<td>
|
67 |
+
<small>
|
68 |
+
<?php _e( "The price for this event's first ticket will be taken from the Cost field above.", AI1EC_PLUGIN_NAME ); ?>
|
69 |
+
</small>
|
70 |
+
</td>
|
71 |
+
</tr>
|
72 |
+
<tr>
|
73 |
+
<td>
|
74 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_quantity">
|
75 |
+
<?php _e( 'Quantity', AI1EC_PLUGIN_NAME ); ?>:
|
76 |
+
</label>
|
77 |
+
</td>
|
78 |
+
<td>
|
79 |
+
<input type="text" name="<?php echo AI1EC_PLUGIN_NAME; ?>_quantity" id="<?php echo AI1EC_PLUGIN_NAME; ?>_quantity" />
|
80 |
+
</td>
|
81 |
+
</tr>
|
82 |
+
<tr>
|
83 |
+
<td>
|
84 |
+
<label>
|
85 |
+
<?php _e( 'Include Fee in Price', AI1EC_PLUGIN_NAME ); ?>:
|
86 |
+
</label>
|
87 |
+
</td>
|
88 |
+
<td>
|
89 |
+
<input type="radio" name="<?php echo AI1EC_PLUGIN_NAME; ?>_fee_in_price" id="<?php echo AI1EC_PLUGIN_NAME; ?>_add_fee" />
|
90 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_add_fee"><?php _e( 'Add Service Fee on top of price', AI1EC_PLUGIN_NAME ); ?></label>
|
91 |
+
<input type="radio" name="<?php echo AI1EC_PLUGIN_NAME; ?>_fee_in_price" id="<?php echo AI1EC_PLUGIN_NAME; ?>_include_fee" />
|
92 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_include_fee"><?php _e( 'Include Service fee in price', AI1EC_PLUGIN_NAME ); ?></label>
|
93 |
+
</td>
|
94 |
+
</tr>
|
95 |
+
<tr>
|
96 |
+
<td>
|
97 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>">
|
98 |
+
<?php _e( 'Payment Options', AI1EC_PLUGIN_NAME ); ?>:
|
99 |
+
</label>
|
100 |
+
</td>
|
101 |
+
<td>
|
102 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_paypal" id="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_paypal" />
|
103 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_paypal"><?php _e( 'Paypal', AI1EC_PLUGIN_NAME ); ?></label>
|
104 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_google" id="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_google" />
|
105 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_google"><?php _e( 'Google Checkout', AI1EC_PLUGIN_NAME ); ?></label>
|
106 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_check" id="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_check" />
|
107 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_check"><?php _e( 'Check', AI1EC_PLUGIN_NAME ); ?></label>
|
108 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_cash" id="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_cash" />
|
109 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_cash"><?php _e( 'Cash', AI1EC_PLUGIN_NAME ); ?></label>
|
110 |
+
<input type="checkbox" name="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_invoice" id="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_invoice" />
|
111 |
+
<label for="<?php echo AI1EC_PLUGIN_NAME; ?>_payment_invoice"><?php _e( 'Send an Invoice', AI1EC_PLUGIN_NAME ); ?></label>
|
112 |
+
</td>
|
113 |
+
</tr>
|
114 |
+
</tbody>
|
115 |
+
</table>
|
116 |
+
</div>
|
app/view/box_general_settings.php
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<label class="textinput" for="calendar_page_id"><?php _e( 'Calendar page:', AI1EC_PLUGIN_NAME ) ?></label>
|
2 |
+
<div class="alignleft"><?php echo $calendar_page ?></div>
|
3 |
+
<br class="clear" />
|
4 |
+
|
5 |
+
<label class="textinput" for="default_calendar_view"><?php _e( 'Default calendar view:', AI1EC_PLUGIN_NAME ) ?></label>
|
6 |
+
<?php echo $default_calendar_view ?>
|
7 |
+
<br class="clear" />
|
8 |
+
|
9 |
+
<label class="textinput" for="calendar_css_selector"><?php _e( 'Contain calendar in this DOM element:', AI1EC_PLUGIN_NAME ) ?></label>
|
10 |
+
<input name="calendar_css_selector" id="calendar_css_selector" type="text" size="20" value="<?php echo esc_attr( $calendar_css_selector ) ?>" />
|
11 |
+
<div class="description"><?php _e( 'Optional. Provide a <a href="http://api.jquery.com/category/selectors/" target="_blank">jQuery selector</a> that evaluates to a single DOM element. Replaces any existing markup found within target. If left empty, calendar is shown in normal page content container.', AI1EC_PLUGIN_NAME ) ?></div>
|
12 |
+
|
13 |
+
<label class="textinput" for="week_start_day"><?php _e( 'Week starts on', AI1EC_PLUGIN_NAME ) ?></label>
|
14 |
+
<?php echo $week_start_day ?>
|
15 |
+
<br class="clear" />
|
16 |
+
|
17 |
+
<label class="textinput" for="agenda_events_per_page"><?php _e( 'Agenda pages show at most', AI1EC_PLUGIN_NAME ) ?></label>
|
18 |
+
<input name="agenda_events_per_page" id="agenda_events_per_page" type="text" size="1" value="<?php echo esc_attr( $agenda_events_per_page ) ?>" /> <?php _e( 'events', AI1EC_PLUGIN_NAME ) ?>
|
19 |
+
<br class="clear" />
|
20 |
+
|
21 |
+
<label for="show_publish_button">
|
22 |
+
<input class="checkbox" name="show_publish_button" id="show_publish_button" type="checkbox" value="1" <?php echo $show_publish_button ?> />
|
23 |
+
<?php _e( 'Display <strong>Publish</strong> at bottom of Edit Event form', AI1EC_PLUGIN_NAME ) ?>
|
24 |
+
</label>
|
25 |
+
<br class="clear" />
|
26 |
+
|
27 |
+
<label for="show_create_event_button">
|
28 |
+
<input class="checkbox" name="show_create_event_button" id="show_create_event_button" type="checkbox" value="1" <?php echo $show_create_event_button ?> />
|
29 |
+
<?php _e( 'Show <strong>Post Your Event</strong> button to privileged users', AI1EC_PLUGIN_NAME ) ?>
|
30 |
+
</label>
|
31 |
+
<br class="clear" />
|
32 |
+
|
33 |
+
<label for="inject_categories">
|
34 |
+
<input class="checkbox" name="inject_categories" id="inject_categories" type="checkbox" value="1" <?php echo $inject_categories ?> />
|
35 |
+
<?php _e( 'Include <strong>event categories</strong> in post category lists', AI1EC_PLUGIN_NAME ) ?>
|
36 |
+
</label>
|
37 |
+
<br class="clear" />
|
app/view/box_ics_import_settings.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<label class="textinput" for="cron_freq">
|
2 |
+
<?php _e( 'Auto-refresh', AI1EC_PLUGIN_NAME ) ?>:
|
3 |
+
</label>
|
4 |
+
<?php echo $cron_freq ?>
|
5 |
+
<br class="clear" />
|
6 |
+
|
7 |
+
<div class="ai1ec-feed-container">
|
8 |
+
<h4 class="ai1ec_feed_h4"><?php _e( 'iCalendar/.ics Feed URL:', AI1EC_PLUGIN_NAME ) ?></h4>
|
9 |
+
<div class="ai1ec-feed-url"><input type="text" name="ai1ec_feed_url" id="ai1ec_feed_url" /></div>
|
10 |
+
<div class="ai1ec-feed-category">
|
11 |
+
<label for="ai1ec_feed_category">
|
12 |
+
<?php _e( 'Event category', AI1EC_PLUGIN_NAME ); ?>:
|
13 |
+
</label>
|
14 |
+
<?php echo $event_categories; ?>
|
15 |
+
</div>
|
16 |
+
<div class="ai1ec-feed-tags">
|
17 |
+
<label for="ai1ec_feed_tags">
|
18 |
+
<?php _e( 'Tag with', AI1EC_PLUGIN_NAME ); ?>:
|
19 |
+
</label>
|
20 |
+
<input type="text" name="ai1ec_feed_tags" id="ai1ec_feed_tags" />
|
21 |
+
</div>
|
22 |
+
<input type="button" id="ai1ec_add_new_ics" class="button" value="<?php _e( '+ Add new subscription', AI1EC_PLUGIN_NAME ) ?>" />
|
23 |
+
</div>
|
24 |
+
|
25 |
+
<?php echo $feed_rows; ?>
|
26 |
+
<br class="clear" />
|
app/view/box_publish_button.php
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<input type="button"
|
2 |
+
name="ai1ec_bottom_publish"
|
3 |
+
id="ai1ec_bottom_publish"
|
4 |
+
class="button-primary ai1ec_bottom_publish"
|
5 |
+
value="<?php echo $button_value ?>" />
|
app/view/box_the_seed_studio.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="ai1ec-plugin-branding">
|
2 |
+
<div class="ai1ec-plugin-logo">
|
3 |
+
<img src="http://yellowseedimages.s3.amazonaws.com/logo-plugin.png" alt="<?php esc_attr_e( 'The Seed Studio', AI1EC_PLUGIN_NAME ) ?>" class="pluginlogo" />
|
4 |
+
</div>
|
5 |
+
<p><?php _e( 'The Seed Studio provides web development and support services for clients and web developers.', AI1EC_PLUGIN_NAME ) ?></p>
|
6 |
+
<div class="ai1ec-follow-fan">
|
7 |
+
<div class="facebook-like-top">
|
8 |
+
<script src="http://connect.facebook.net/en_US/all.js#xfbml=1"></script>
|
9 |
+
<fb:like href="http://www.facebook.com/pages/The-Seed-Agency/66657743707" layout="button_count" show_faces="true" width="110" font="lucida grande"></fb:like>
|
10 |
+
</div>
|
11 |
+
<a href="http://twitter.com/the_seed_studio" class="twitter-follow-button"><?php _e( 'Follow @the_seed_studio', AI1EC_PLUGIN_NAME ) ?></a>
|
12 |
+
<script src="http://platform.twitter.com/widgets.js" type="text/javascript"></script>
|
13 |
+
<div class="clear"></div>
|
14 |
+
</div>
|
15 |
+
<div class="ai1ec-support-button">
|
16 |
+
<a href="http://theseedstudio.com/get-supported/" target="_blank"><?php _e( 'Get Support<span> from one of our experienced pros</span>', AI1EC_PLUGIN_NAME ) ?></a>
|
17 |
+
</div>
|
18 |
+
<h2><?php _e( 'Support', AI1EC_PLUGIN_NAME ) ?></h2>
|
19 |
+
<p>
|
20 |
+
<a href="http://theseedstudio.com/software/all-in-one-events-calendar-wordpress/all-in-one-events-calendar-documentation/" target="_blank"><?php _e( 'View plugin documentation', AI1EC_PLUGIN_NAME ) ?></a>
|
21 |
+
</p>
|
22 |
+
<p>
|
23 |
+
<?php _e( 'You can also hire The Seed for support on a contract or per-hour basis for this plugin, for your website or for any of your Internet marketing needs (we can really help!).', AI1EC_PLUGIN_NAME ) ?>
|
24 |
+
</p>
|
25 |
+
<p>
|
26 |
+
<?php _e( 'Plugin users: The Seed gives support priority to clients. For free support from other WordPress users, visit the plugin\'s forum.', AI1EC_PLUGIN_NAME ) ?>
|
27 |
+
</p>
|
28 |
+
|
29 |
+
<h2><?php _e( 'Vote and Share', AI1EC_PLUGIN_NAME ) ?></h2>
|
30 |
+
|
31 |
+
<p>
|
32 |
+
<?php _e( 'This plugin is offered free to the Wordpress Community under the GPL3 license. All we ask is that you:', AI1EC_PLUGIN_NAME ) ?>
|
33 |
+
<ol>
|
34 |
+
<li><?php _e( '<a href="http://wordpress.org/extend/plugins/all-in-one-event-calendar/" target="_blank">Give it a five-star rating on wordpress.org</a> (if you think it deserves it!)', AI1EC_PLUGIN_NAME ) ?></li>
|
35 |
+
<li><a href="http://theseedstudio.com/software/all-in-one-events-calendar-wordpress/" target="_blank"><?php _e( 'Link to the plugin page on our website', AI1EC_PLUGIN_NAME ) ?></a></li>
|
36 |
+
<li><a href="http://www.facebook.com/theseednet" target="_blank"><?php _e( 'Become a Fan on Facebook', AI1EC_PLUGIN_NAME ) ?></a></li>
|
37 |
+
<li><a href="https://twitter.com/intent/user?screen_name=the_seed_studio" target="_blank"><?php _e( 'Follow us on Twitter', AI1EC_PLUGIN_NAME ) ?></a></li>
|
38 |
+
</ol>
|
39 |
+
</p>
|
40 |
+
</div>
|
41 |
+
<br class="clear" />
|
app/view/box_time_and_date.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php wp_nonce_field( 'ai1ec', AI1EC_POST_TYPE ); ?>
|
2 |
+
<h4 class="ai1ec-section-title"><?php _e( 'Event date and time'); ?></h4>
|
3 |
+
<table class="ai1ec-form">
|
4 |
+
<tbody>
|
5 |
+
<tr>
|
6 |
+
<td class="ai1ec-first">
|
7 |
+
<label for="ai1ec_all_day_event">
|
8 |
+
<?php _e( 'All-day event', 'ai1ec' ); ?>?
|
9 |
+
</label>
|
10 |
+
</td>
|
11 |
+
<td>
|
12 |
+
<input type="checkbox" name="ai1ec_all_day_event" id="ai1ec_all_day_event" <?php echo $all_day_event; ?> />
|
13 |
+
</td>
|
14 |
+
</tr>
|
15 |
+
<tr>
|
16 |
+
<td>
|
17 |
+
<label for="ai1ec_start-date-input">
|
18 |
+
<?php _e( 'Start date / time', 'ai1ec' ); ?>:
|
19 |
+
</label>
|
20 |
+
</td>
|
21 |
+
<td>
|
22 |
+
<input type="text" class="ai1ec-date-input" id="ai1ec_start-date-input" />
|
23 |
+
<input type="text" class="ai1ec-time-input" id="ai1ec_start-time-input" />
|
24 |
+
<small><?php echo $timezone ?></small>
|
25 |
+
<input type="hidden" name="ai1ec_start_time" id="ai1ec_start-time" value="<?php echo $start_timestamp ?>" />
|
26 |
+
</td>
|
27 |
+
</tr>
|
28 |
+
<tr>
|
29 |
+
<td>
|
30 |
+
<label for="ai1ec_end-date-input">
|
31 |
+
<?php _e( 'End date / time', 'ai1ec' ) ?>:
|
32 |
+
</label>
|
33 |
+
</td>
|
34 |
+
<td>
|
35 |
+
<input type="text" class="ai1ec-date-input" id="ai1ec_end-date-input" />
|
36 |
+
<input type="text" class="ai1ec-time-input" id="ai1ec_end-time-input" />
|
37 |
+
<small><?php echo $timezone ?></small>
|
38 |
+
<input type="hidden" name="ai1ec_end_time" id="ai1ec_end-time" value="<?php echo $end_timestamp ?>" />
|
39 |
+
</td>
|
40 |
+
</tr>
|
41 |
+
<tr>
|
42 |
+
<td>
|
43 |
+
<label for="ai1ec_repeat">
|
44 |
+
<?php _e( 'Repeat', 'ai1ec' ) ?>:
|
45 |
+
</label>
|
46 |
+
</td>
|
47 |
+
<td>
|
48 |
+
<?php echo $repeat; ?>
|
49 |
+
</td>
|
50 |
+
</tr>
|
51 |
+
<tr id="ai1ec_end_holder" <?php if( ! $repeating_event ) echo 'class="ai1ec_hidden"' ?>>
|
52 |
+
<td>
|
53 |
+
<label for="ai1ec_end">
|
54 |
+
<?php _e( 'End', 'ai1ec' ) ?>:
|
55 |
+
</label>
|
56 |
+
</td>
|
57 |
+
<td>
|
58 |
+
<?php echo $end ?>
|
59 |
+
</td>
|
60 |
+
</tr>
|
61 |
+
<tr id="ai1ec_count_holder" <?php if( $ending != 1 ) echo 'class="ai1ec_hidden"' ?>>
|
62 |
+
<td>
|
63 |
+
<label for="ai1ec_count">
|
64 |
+
<?php _e( 'Ending after', 'ai1ec' ) ?>:
|
65 |
+
</label>
|
66 |
+
</td>
|
67 |
+
<td>
|
68 |
+
<?php echo $count; ?>
|
69 |
+
</td>
|
70 |
+
</tr>
|
71 |
+
<tr id="ai1ec_until_holder" <?php if( $ending != 2 ) echo 'class="ai1ec_hidden"' ?>>
|
72 |
+
<td>
|
73 |
+
<label for="ai1ec_until-date-input">
|
74 |
+
<?php _e( 'On date', 'ai1ec' ) ?>:
|
75 |
+
</label>
|
76 |
+
</td>
|
77 |
+
<td>
|
78 |
+
<input type="text" class="ai1ec-date-input" id="ai1ec_until-date-input" />
|
79 |
+
<input type="hidden" name="ai1ec_until_time" id="ai1ec_until-time" value="<?php echo !is_null( $until ) && $until > 0 ? $until : '' ?>" />
|
80 |
+
</td>
|
81 |
+
</tr>
|
82 |
+
</tbody>
|
83 |
+
</table>
|
app/view/calendar.php
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<table class="ai1ec-calendar-toolbar">
|
2 |
+
<tbody>
|
3 |
+
<tr>
|
4 |
+
|
5 |
+
<td>
|
6 |
+
<ul class="ai1ec-view-tabs">
|
7 |
+
<li>
|
8 |
+
<a id="ai1ec-view-month" class="ai1ec-load-view ai1ec-button"
|
9 |
+
href="#action=ai1ec_month">
|
10 |
+
<img src="<?php echo AI1EC_IMAGE_URL ?>/month-view.png" alt="<?php _e( 'Month', AI1EC_PLUGIN_NAME ) ?>" />
|
11 |
+
<?php _e( 'Month', AI1EC_PLUGIN_NAME ) ?>
|
12 |
+
</a>
|
13 |
+
</li>
|
14 |
+
<li>
|
15 |
+
<a id="ai1ec-view-agenda" class="ai1ec-load-view ai1ec-button"
|
16 |
+
href="#action=ai1ec_agenda">
|
17 |
+
<img src="<?php echo AI1EC_IMAGE_URL ?>/agenda-view.png" alt="<?php _e( 'Month', AI1EC_PLUGIN_NAME ) ?>" />
|
18 |
+
<?php _e( 'Agenda', AI1EC_PLUGIN_NAME ) ?>
|
19 |
+
</a>
|
20 |
+
</li>
|
21 |
+
</ul>
|
22 |
+
</td>
|
23 |
+
|
24 |
+
<?php if( $create_event_url ): ?>
|
25 |
+
<td>
|
26 |
+
<a class="ai1ec-button" href="<?php echo $create_event_url ?>">
|
27 |
+
<?php _e( '+ Post Your Event', AI1EC_PLUGIN_NAME ) ?>
|
28 |
+
</a>
|
29 |
+
</td>
|
30 |
+
<?php endif ?>
|
31 |
+
|
32 |
+
<?php if( $categories || $tags ): ?>
|
33 |
+
<td>
|
34 |
+
<div class="ai1ec-filters-container">
|
35 |
+
<label class="ai1ec-label">
|
36 |
+
<a class="ai1ec-clear-filters" title="<?php _e( 'Clear Filters', AI1EC_PLUGIN_NAME ) ?>"><?php _e( '✘', AI1EC_PLUGIN_NAME ) ?></a>
|
37 |
+
<?php _e( 'Filter:', AI1EC_PLUGIN_NAME ) ?>
|
38 |
+
</label>
|
39 |
+
|
40 |
+
<?php if( $categories ): ?>
|
41 |
+
<span class="ai1ec-filter-selector-container">
|
42 |
+
<a class="ai1ec-button ai1ec-dropdown"><?php _e( 'Categories ▾', AI1EC_PLUGIN_NAME ) ?></a>
|
43 |
+
<input class="ai1ec-selected-terms"
|
44 |
+
id="ai1ec-selected-categories"
|
45 |
+
type="hidden"
|
46 |
+
value="<?php echo $selected_cat_ids ?>" />
|
47 |
+
<div class="ai1ec-filter-selector ai1ec-category-filter-selector">
|
48 |
+
<ul>
|
49 |
+
<?php foreach( $categories as $cat ): ?>
|
50 |
+
<li class="ai1ec-category"
|
51 |
+
<?php if( $cat->description ) echo 'title="' . esc_attr( $cat->description ) . '"' ?>>
|
52 |
+
<?php echo $cat->color ?>
|
53 |
+
<?php echo esc_html( $cat->name ) ?>
|
54 |
+
<input class="ai1ec-term-ids" name="ai1ec-categories" type="hidden" value="<?php echo $cat->term_id ?>" />
|
55 |
+
</li>
|
56 |
+
<?php endforeach ?>
|
57 |
+
</ul>
|
58 |
+
</div>
|
59 |
+
</span>
|
60 |
+
<?php endif // $categories ?>
|
61 |
+
|
62 |
+
<?php if( $tags ): ?>
|
63 |
+
<span class="ai1ec-filter-selector-container">
|
64 |
+
<a class="ai1ec-button ai1ec-dropdown"><?php _e( 'Tags ▾', AI1EC_PLUGIN_NAME ) ?></a>
|
65 |
+
<input class="ai1ec-selected-terms"
|
66 |
+
id="ai1ec-selected-tags"
|
67 |
+
type="hidden"
|
68 |
+
value="<?php echo $selected_tag_ids ?>" />
|
69 |
+
<div class="ai1ec-filter-selector ai1ec-tag-filter-selector">
|
70 |
+
<ul>
|
71 |
+
<?php foreach( $tags as $tag ): ?>
|
72 |
+
<li class="ai1ec-tag"
|
73 |
+
<?php if( $tag->description ) echo 'title="' . esc_attr( $tag->description ) . '"' ?>
|
74 |
+
style="<?php echo $tag->count > 1 ? 'font-weight: bold;' : 'font-size: 10px !important;' ?>">
|
75 |
+
<?php echo esc_html( $tag->name ) . " ($tag->count)" ?>
|
76 |
+
<input class="ai1ec-term-ids" name="ai1ec-tags" type="hidden" value="<?php echo $tag->term_id ?>" />
|
77 |
+
</li>
|
78 |
+
<?php endforeach ?>
|
79 |
+
</ul>
|
80 |
+
<input class="ai1ec-selected-terms" id="ai1ec-selected-tags" type="hidden" />
|
81 |
+
</div>
|
82 |
+
</span>
|
83 |
+
<?php endif // $tags ?>
|
84 |
+
</div>
|
85 |
+
</td>
|
86 |
+
<?php endif // $categories || $tags ?>
|
87 |
+
</tr>
|
88 |
+
</tbody>
|
89 |
+
</table>
|
90 |
+
|
91 |
+
<div id="ai1ec-calendar-view-container">
|
92 |
+
<div id="ai1ec-calendar-view-loading" class="ai1ec-loading"></div>
|
93 |
+
<div id="ai1ec-calendar-view">
|
94 |
+
<?php echo $view ?>
|
95 |
+
</div>
|
96 |
+
</div>
|
97 |
+
|
98 |
+
<a class="ai1ec-button ai1ec-subscribe"
|
99 |
+
href="<?php echo AI1EC_EXPORT_URL ?>"
|
100 |
+
title="<?php _e( 'Subscribe to this calendar using your favourite calendar program (iCal, Outlook, etc.)', AI1EC_PLUGIN_NAME ) ?>" />
|
101 |
+
<?php _e( '✔ Subscribe', AI1EC_PLUGIN_NAME ) ?>
|
102 |
+
<span class="ai1ec-subscribe-filtered"><?php _e( 'to this filtered calendar', AI1EC_PLUGIN_NAME ) ?></span>
|
103 |
+
</a>
|
104 |
+
<a class="ai1ec-button ai1ec-subscribe-google" target="_blank"
|
105 |
+
href="http://www.google.com/calendar/render?cid=<?php echo urlencode( str_replace( 'webcal://', 'http://', AI1EC_EXPORT_URL ) ) ?>"
|
106 |
+
title="<?php _e( 'Subscribe to this calendar in your Google Calendar', AI1EC_PLUGIN_NAME ) ?>" />
|
107 |
+
<img src="<?php echo AI1EC_IMAGE_URL ?>/google-calendar.png" />
|
108 |
+
<?php _e( 'Subscribe in Google Calendar', AI1EC_PLUGIN_NAME ) ?>
|
109 |
+
</a>
|
app/view/donate_button.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
|
2 |
+
<input type="hidden" name="cmd" value="_s-xclick" />
|
3 |
+
<input type="hidden" name="hosted_button_id" value="9JJMUW48W2ED8" />
|
4 |
+
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
5 |
+
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
6 |
+
</form>
|
app/view/event-excerpt.php
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="ai1ec-excerpt">
|
2 |
+
<a class="ai1ec-button ai1ec-event-link" href="<?php the_permalink() ?>">
|
3 |
+
<?php _e( 'View Event »', AI1EC_PLUGIN_NAME ) ?>
|
4 |
+
</a>
|
5 |
+
<div class="ai1ec-time"><label class="ai1ec-label"><?php _e( 'When:', AI1EC_PLUGIN_NAME ) ?></label> <?php echo $event->timespan_html ?></div>
|
6 |
+
<?php if( $location ): ?>
|
7 |
+
<div class="ai1ec-location"><label class="ai1ec-label"><?php _e( 'Where:', AI1EC_PLUGIN_NAME ) ?></label> <?php echo $location ?></div>
|
8 |
+
<?php endif ?>
|
9 |
+
</div>
|
app/view/event-map.php
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="ai1ec-gmap-container">
|
2 |
+
<div id="ai1ec-gmap-canvas"></div>
|
3 |
+
<input type="hidden" id="ai1ec-gmap-address" value="<?php echo esc_attr( $address ) ?>" />
|
4 |
+
</div>
|
5 |
+
<a class="ai1ec-gmap-link ai1ec-button"
|
6 |
+
href="<?php echo $gmap_url_link ?>" target="_blank">
|
7 |
+
<?php _e( 'View Full-Size Map »', AI1EC_PLUGIN_NAME ) ?>
|
8 |
+
</a>
|
app/view/event-multi.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<table class="ai1ec-event ai1ec-multi-event ai1ec-event-id-<?php echo $event->post_id ?> <?php if( $event->allday ) echo 'ai1ec-allday' ?>">
|
2 |
+
<tbody>
|
3 |
+
<tr>
|
4 |
+
<th scope="row" class="ai1ec-time"><?php _e( 'When:', AI1EC_PLUGIN_NAME ) ?></th>
|
5 |
+
<td class="ai1ec-time">
|
6 |
+
<a class="ai1ec-button ai1ec-calendar-link" href="<?php echo $calendar_url ?>">
|
7 |
+
<?php _e( 'View in Calendar »', AI1EC_PLUGIN_NAME ) ?>
|
8 |
+
</a>
|
9 |
+
<?php echo $event->timespan_html ?>
|
10 |
+
</td>
|
11 |
+
</tr>
|
12 |
+
<?php if( $recurrence ): ?>
|
13 |
+
<tr>
|
14 |
+
<th scope="row" class="ai1ec-recurrence"><?php _e( 'Repeats:', AI1EC_PLUGIN_NAME ) ?></th>
|
15 |
+
<td class="ai1ec-recurrence" colspan="2"><?php echo $recurrence ?></td>
|
16 |
+
</tr>
|
17 |
+
<?php endif ?>
|
18 |
+
<tr>
|
19 |
+
<?php if( $location ): ?>
|
20 |
+
<th scope="row" class="ai1ec-location"><?php _e( 'Where:', AI1EC_PLUGIN_NAME ) ?></th>
|
21 |
+
<td class="ai1ec-location">
|
22 |
+
<?php if( $event->show_map ): ?>
|
23 |
+
<a class="ai1ec-button ai1ec-gmap-link" href="<?php the_permalink() ?>#ai1ec-event">
|
24 |
+
<?php _e( 'View Map »', AI1EC_PLUGIN_NAME ) ?>
|
25 |
+
</a>
|
26 |
+
<?php endif ?>
|
27 |
+
<?php echo $location ?>
|
28 |
+
</td>
|
29 |
+
<?php endif ?>
|
30 |
+
</tr>
|
31 |
+
<tr>
|
32 |
+
<?php if( $event->cost ): ?>
|
33 |
+
<th scope="row" class="ai1ec-cost"><?php _e( 'Cost:', AI1EC_PLUGIN_NAME ) ?></th>
|
34 |
+
<td class="ai1ec-cost"><?php echo esc_html( $event->cost ) ?></td>
|
35 |
+
<?php endif ?>
|
36 |
+
</tr>
|
37 |
+
<tr>
|
38 |
+
<?php if( $contact ): ?>
|
39 |
+
<th scope="row" class="ai1ec-contact"><?php _e( 'Contact:', AI1EC_PLUGIN_NAME ) ?></th>
|
40 |
+
<td class="ai1ec-contact"><?php echo $contact ?></td>
|
41 |
+
<?php endif ?>
|
42 |
+
</tr>
|
43 |
+
<tr>
|
44 |
+
<?php if( $categories ): ?>
|
45 |
+
<th scope="row" class="ai1ec-categories"><?php _e( 'Categories:', AI1EC_PLUGIN_NAME ) ?></th>
|
46 |
+
<td class="ai1ec-categories"><?php echo $categories ?></td>
|
47 |
+
<?php endif ?>
|
48 |
+
</tr>
|
49 |
+
<tr>
|
50 |
+
<?php if( $tags ): ?>
|
51 |
+
<th scope="row" class="ai1ec-tags"><?php _e( 'Tags:', AI1EC_PLUGIN_NAME ) ?></th>
|
52 |
+
<td class="ai1ec-tags"><?php echo $tags ?></td>
|
53 |
+
<?php endif ?>
|
54 |
+
</tr>
|
55 |
+
</tbody>
|
56 |
+
</table>
|
app/view/event-single-footer.php
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="ai1ec-event-footer">
|
2 |
+
<?php if( $event->ical_feed_url ): ?>
|
3 |
+
<p class="ai1ec-source-link">
|
4 |
+
<?php _e( sprintf( 'This post was replicated from another site\'s <a class="ai1ec-ics-icon" href="%s" title="iCalendar feed">calendar feed</a>.',
|
5 |
+
esc_attr( str_replace( 'http://', 'webcal://', $event->ical_feed_url ) ) ), AI1EC_PLUGIN_NAME ) ?>
|
6 |
+
<?php if( $event->ical_source_url ): ?>
|
7 |
+
<a href="<?php echo esc_attr( $event->ical_source_url ) ?>" target="_blank">
|
8 |
+
<?php _e( 'View original post »', AI1EC_PLUGIN_NAME ) ?>
|
9 |
+
</a>
|
10 |
+
<?php endif ?>
|
11 |
+
</p>
|
12 |
+
<?php endif ?>
|
13 |
+
</div>
|
app/view/event-single.php
ADDED
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<a name="ai1ec-event"></a>
|
2 |
+
<table class="ai1ec-full-event ai1ec-single-event ai1ec-event-id-<?php echo $event->post_id ?> <?php if( $event->allday ) echo 'ai1ec-allday' ?>">
|
3 |
+
<tbody>
|
4 |
+
<tr>
|
5 |
+
<th scope="row" class="ai1ec-time"><?php _e( 'When:', AI1EC_PLUGIN_NAME ) ?></th>
|
6 |
+
<td colspan="2" class="ai1ec-time">
|
7 |
+
<a class="ai1ec-button ai1ec-calendar-link" href="<?php echo $calendar_url ?>">
|
8 |
+
<?php _e( 'Back to Calendar »', AI1EC_PLUGIN_NAME ) ?>
|
9 |
+
</a>
|
10 |
+
<?php echo $event->timespan_html ?>
|
11 |
+
</td>
|
12 |
+
</tr>
|
13 |
+
<?php if( $recurrence ): ?>
|
14 |
+
<tr>
|
15 |
+
<th scope="row" class="ai1ec-recurrence"><?php _e( 'Repeats:', AI1EC_PLUGIN_NAME ) ?></th>
|
16 |
+
<td class="ai1ec-recurrence" colspan="2"><?php echo $recurrence ?></td>
|
17 |
+
</tr>
|
18 |
+
<?php endif ?>
|
19 |
+
<tr>
|
20 |
+
<th scope="row" class="ai1ec-location <?php if( ! $location ) echo 'ai1ec-empty' ?>"><?php if( $location ) _e( 'Where:', AI1EC_PLUGIN_NAME ) ?></th>
|
21 |
+
<td class="ai1ec-location <?php if( ! $location ) echo 'ai1ec-empty' ?>"><?php echo $location ?></td>
|
22 |
+
<td rowspan="5" class="ai1ec-map <?php if( $map ) echo 'ai1ec-has-map' ?>">
|
23 |
+
<?php echo $map ?>
|
24 |
+
<a class="ai1ec-button ai1ec-subscribe"
|
25 |
+
href="<?php echo esc_attr( $subscribe_url ) ?>"
|
26 |
+
title="<?php _e( 'Add this event to your favourite calendar program (iCal, Outlook, etc.)', AI1EC_PLUGIN_NAME ) ?>" />
|
27 |
+
<?php _e( '✔ Add to Calendar', AI1EC_PLUGIN_NAME ) ?></a>
|
28 |
+
<a class="ai1ec-button ai1ec-subscribe-google" target="_blank"
|
29 |
+
href="<?php echo esc_attr( $google_url ) ?>"
|
30 |
+
title="<?php _e( 'Add this event to your Google Calendar', AI1EC_PLUGIN_NAME ) ?>" />
|
31 |
+
<img src="<?php echo AI1EC_IMAGE_URL ?>/google-calendar.png" />
|
32 |
+
<?php _e( 'Add to Google Calendar', AI1EC_PLUGIN_NAME ) ?>
|
33 |
+
</a>
|
34 |
+
</td>
|
35 |
+
</tr>
|
36 |
+
<tr>
|
37 |
+
<?php if( $event->cost ): ?>
|
38 |
+
<th scope="row" class="ai1ec-cost"><?php _e( 'Cost:', AI1EC_PLUGIN_NAME ) ?></th>
|
39 |
+
<td class="ai1ec-cost"><?php echo esc_html( $event->cost ) ?></td>
|
40 |
+
<?php endif ?>
|
41 |
+
</tr>
|
42 |
+
<tr>
|
43 |
+
<?php if( $contact ): ?>
|
44 |
+
<th scope="row" class="ai1ec-contact"><?php _e( 'Contact:', AI1EC_PLUGIN_NAME ) ?></th>
|
45 |
+
<td class="ai1ec-contact"><?php echo $contact ?></td>
|
46 |
+
<?php endif ?>
|
47 |
+
</tr>
|
48 |
+
<tr>
|
49 |
+
<?php if( $categories ): ?>
|
50 |
+
<th scope="row" class="ai1ec-categories"><?php _e( 'Categories:', AI1EC_PLUGIN_NAME ) ?></th>
|
51 |
+
<td class="ai1ec-categories"><?php echo $categories ?></td>
|
52 |
+
<?php endif ?>
|
53 |
+
</tr>
|
54 |
+
<tr>
|
55 |
+
<th scope="row" class="ai1ec-tags">
|
56 |
+
<?php if( $tags ): ?>
|
57 |
+
<?php _e( 'Tags:', AI1EC_PLUGIN_NAME ) ?>
|
58 |
+
<?php endif ?>
|
59 |
+
</th>
|
60 |
+
<td class="ai1ec-tags"><?php echo $tags ?></td>
|
61 |
+
</tr>
|
62 |
+
</tbody>
|
63 |
+
</table>
|
app/view/event_categories-color_picker.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if( $edit ) : ?>
|
2 |
+
<tr class="form-field">
|
3 |
+
<th scope="row" valign="top">
|
4 |
+
<label for="tag-color">
|
5 |
+
<?php _e( 'Category Color', AI1EC_PLUGIN_NAME ) ?>
|
6 |
+
</label>
|
7 |
+
</th>
|
8 |
+
<td>
|
9 |
+
<div id="tag-color">
|
10 |
+
<div id="tag-color-background"<?php echo $style ?>></div>
|
11 |
+
</div>
|
12 |
+
<input type="hidden" name="tag-color-value" id="tag-color-value" value="<?php echo $color ?>" />
|
13 |
+
<p class="description"><?php _e( 'Events in this category will be identified by this color', AI1EC_PLUGIN_NAME ) ?>.</p>
|
14 |
+
</td>
|
15 |
+
</tr>
|
16 |
+
<?php else : ?>
|
17 |
+
<div class="form-field">
|
18 |
+
<label for="tag-color">
|
19 |
+
<?php _e( 'Category Color', AI1EC_PLUGIN_NAME ) ?>
|
20 |
+
</label>
|
21 |
+
<div id="tag-color">
|
22 |
+
<div id="tag-color-background"></div>
|
23 |
+
</div>
|
24 |
+
<input type="hidden" name="tag-color-value" id="tag-color-value" value="" />
|
25 |
+
<p><?php _e( 'Events in this category will be identified by this color', AI1EC_PLUGIN_NAME ) ?>.</p>
|
26 |
+
</div>
|
27 |
+
<?php endif; ?>
|
app/view/feed_row.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="ai1ec-feed-container">
|
2 |
+
<h4 class="ai1ec_feed_h4">
|
3 |
+
<?php _e( 'iCalendar/.ics Feed URL:', AI1EC_PLUGIN_NAME ); ?>
|
4 |
+
</h4>
|
5 |
+
<div class="ai1ec-feed-url"><input type="text" class="ai1ec-feed-url" readonly="readonly" value="<?php echo esc_attr( $feed_url ) ?>" /></div>
|
6 |
+
<input type="hidden" name="feed_id" class="ai1ec_feed_id" value="<?php echo $feed_id;?>" />
|
7 |
+
<div class="ai1ec-feed-category">
|
8 |
+
<?php _e( 'Event category:', AI1EC_PLUGIN_NAME ); ?>
|
9 |
+
<strong><?php echo $event_category; ?></strong>
|
10 |
+
</div>
|
11 |
+
<?php if( $tags ): ?>
|
12 |
+
<div class="ai1ec-feed-tags">
|
13 |
+
<?php _e( 'Tag with', AI1EC_PLUGIN_NAME ); ?>:
|
14 |
+
<strong><?php echo $tags; ?></strong>
|
15 |
+
</div>
|
16 |
+
<?php endif ?>
|
17 |
+
<input type="button" class="button ai1ec_delete_ics" value="<?php _e( '× Delete', AI1EC_PLUGIN_NAME ); ?>" />
|
18 |
+
<input type="button" class="button ai1ec_update_ics" value="<?php _e( 'Update', AI1EC_PLUGIN_NAME ); ?>" />
|
19 |
+
<?php if( $events ): ?>
|
20 |
+
<input type="button" class="button ai1ec_flush_ics" value="<?php printf( _n( 'Flush 1 event', 'Flush %s events', $events, AI1EC_PLUGIN_NAME ), $events ) ?>" />
|
21 |
+
<?php endif ?>
|
22 |
+
<img src="images/wpspin_light.gif" class="ajax-loading" alt="" />
|
23 |
+
</div>
|
app/view/import.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap">
|
2 |
+
<table class="form-table">
|
3 |
+
<tbody>
|
4 |
+
<tr valign="top">
|
5 |
+
<th scope="row">
|
6 |
+
<?php _e( 'Successfully imported events:', AI1EC_PLUGIN_NAME ) ?>
|
7 |
+
</th>
|
8 |
+
<td>
|
9 |
+
<?php echo $imported_events ?>
|
10 |
+
</td>
|
11 |
+
</tr>
|
12 |
+
</tbody>
|
13 |
+
</table>
|
14 |
+
</div>
|
app/view/month.php
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<h2 class="ai1ec-calendar-title"><?php echo esc_html( $title ) ?></h2>
|
2 |
+
<span class="ai1ec-title-buttons">
|
3 |
+
<a id="ai1ec-today" class="ai1ec-load-view ai1ec-button" href="#action=ai1ec_month">
|
4 |
+
<?php _e( 'Today', AI1EC_JS_URL ) ?>
|
5 |
+
</a>
|
6 |
+
</span>
|
7 |
+
<ul class="ai1ec-pagination">
|
8 |
+
<?php foreach( $pagination_links as $link ): ?>
|
9 |
+
<li>
|
10 |
+
<a id="<?php echo $link['id'] ?>"
|
11 |
+
class="ai1ec-load-view ai1ec-button"
|
12 |
+
href="<?php echo esc_attr( $link['href'] ) ?>">
|
13 |
+
<?php echo esc_html( $link['text'] ) ?>
|
14 |
+
</a>
|
15 |
+
</li>
|
16 |
+
<?php endforeach ?>
|
17 |
+
</ul>
|
18 |
+
<table class="ai1ec-month-view">
|
19 |
+
<thead>
|
20 |
+
<tr>
|
21 |
+
<?php foreach( $weekdays as $weekday ): ?>
|
22 |
+
<th class="ai1ec-weekday"><?php echo $weekday; ?></th>
|
23 |
+
<?php endforeach // weekday ?>
|
24 |
+
</tr>
|
25 |
+
</thead>
|
26 |
+
<tbody>
|
27 |
+
<?php foreach( $cell_array as $week ): ?>
|
28 |
+
<tr class="ai1ec-week">
|
29 |
+
<?php foreach( $week as $day ): ?>
|
30 |
+
<?php if( $day['date'] ): ?>
|
31 |
+
<td <?php if( $day['today'] ) echo 'class="ai1ec-today"' ?>>
|
32 |
+
<div class="ai1ec-day">
|
33 |
+
<div class="ai1ec-date"><?php echo $day['date'] ?></div>
|
34 |
+
<?php foreach( $day['events'] as $event ): ?>
|
35 |
+
<a href="<?php echo esc_attr( get_permalink( $event->post_id ) ) ?>"
|
36 |
+
class="ai1ec-event-container
|
37 |
+
ai1ec-event-id-<?php echo $event->post_id ?>
|
38 |
+
ai1ec-event-instance-id-<?php echo $event->instance_id ?>
|
39 |
+
<?php if( $event->allday ) echo 'ai1ec-allday' ?>">
|
40 |
+
|
41 |
+
<?php // Insert post ID for use by JavaScript filtering later ?>
|
42 |
+
<input type="hidden" class="ai1ec-post-id" value="<?php echo $event->post_id ?>" />
|
43 |
+
|
44 |
+
<div class="ai1ec-event-popup">
|
45 |
+
<div class="ai1ec-event-summary">
|
46 |
+
<?php if( $event->category_colors ): ?>
|
47 |
+
<div class="ai1ec-category-colors"><?php echo $event->category_colors ?></div>
|
48 |
+
<?php endif ?>
|
49 |
+
<?php if( $event->post_excerpt ): ?>
|
50 |
+
<strong><?php _e( 'Summary:', AI1EC_PLUGIN_NAME ) ?></strong>
|
51 |
+
<p><?php echo esc_html( $event->post_excerpt ) ?></p>
|
52 |
+
<?php endif ?>
|
53 |
+
<div class="ai1ec-read-more"><?php esc_html_e( 'click anywhere for details', AI1EC_PLUGIN_NAME ) ?></div>
|
54 |
+
</div>
|
55 |
+
<div class="ai1ec-event-popup-bg">
|
56 |
+
<?php if( ! $event->allday ): ?>
|
57 |
+
<span class="ai1ec-event-time"><?php echo esc_html( $event->short_start_time ) ?></span>
|
58 |
+
<?php endif ?>
|
59 |
+
<span class="ai1ec-event-title"><?php echo esc_html( mb_strimwidth( $event->post->post_title, 0, 35, '...' ) ) ?></span>
|
60 |
+
<?php if( $event->allday ): ?>
|
61 |
+
<small><?php esc_html_e( '(all-day)', AI1EC_PLUGIN_NAME ) ?></small>
|
62 |
+
<?php endif ?>
|
63 |
+
</div>
|
64 |
+
</div><!-- .event-popup -->
|
65 |
+
|
66 |
+
<div class="ai1ec-event <?php if( $event->post_id == $active_event ) echo 'ai1ec-active-event' ?>" <?php echo $event->color_style; ?>>
|
67 |
+
<?php if( ! $event->allday ): ?>
|
68 |
+
<span class="ai1ec-event-time"><?php echo esc_html( $event->short_start_time ) ?></span>
|
69 |
+
<?php endif ?>
|
70 |
+
<span class="ai1ec-event-title"><?php echo esc_html( $event->post->post_title ) ?></span>
|
71 |
+
</div>
|
72 |
+
|
73 |
+
</a>
|
74 |
+
<?php endforeach // events ?>
|
75 |
+
</div>
|
76 |
+
</td>
|
77 |
+
<?php else: ?>
|
78 |
+
<td class="ai1ec-empty"></td>
|
79 |
+
<?php endif // date ?>
|
80 |
+
<?php endforeach // day ?>
|
81 |
+
</tr>
|
82 |
+
<?php endforeach // week ?>
|
83 |
+
</tbody>
|
84 |
+
</table>
|
app/view/save_successful.php
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="updated">
|
2 |
+
<p>
|
3 |
+
<strong>
|
4 |
+
<?php echo $msg; ?>
|
5 |
+
</strong>
|
6 |
+
</p>
|
7 |
+
</div>
|
app/view/settings.php
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div class="wrap">
|
2 |
+
|
3 |
+
<?php screen_icon(); ?>
|
4 |
+
|
5 |
+
<h2><?php _e( 'All-in-one Event Calendar', AI1EC_PLUGIN_NAME ) ?></h2>
|
6 |
+
|
7 |
+
<div id="poststuff">
|
8 |
+
|
9 |
+
<form method="post" action="">
|
10 |
+
<?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
|
11 |
+
<?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
|
12 |
+
|
13 |
+
<div class="metabox-holder">
|
14 |
+
<div class="post-box-container column-1-ai1ec left-side"><?php do_meta_boxes( $settings_page, 'left-side', null ); ?></div>
|
15 |
+
<div class="post-box-container column-2-ai1ec right-side"><?php do_meta_boxes( $settings_page, 'right-side', null ); ?></div>
|
16 |
+
<div class="post-box-container column-3-ai1ec full"><?php do_meta_boxes( $settings_page, 'full', null ); ?></div>
|
17 |
+
</div>
|
18 |
+
<?php submit_button( esc_attr__( 'Update Settings', AI1EC_PLUGIN_NAME ), 'primary', 'ai1ec_save_settings' ); ?>
|
19 |
+
|
20 |
+
</form>
|
21 |
+
|
22 |
+
</div><!-- #poststuff -->
|
23 |
+
|
24 |
+
</div><!-- .wrap -->
|
app/view/subscription_button.php
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
|
2 |
+
<input type="hidden" name="cmd" value="_s-xclick" />
|
3 |
+
<input type="hidden" name="hosted_button_id" value="RGE42APRSL5UA" />
|
4 |
+
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
5 |
+
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
6 |
+
</form>
|
css/add_new_event.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
#ai1ec_event{overflow:hidden}.ai1ec-form{width:100%;margin-bottom:1em}.ai1ec-form td.ai1ec-first{width:8.5em}.ai1ec-form label{font-size:9pt}.ai1ec-form td{line-height:1.5em}.ai1ec-section-title{text-transform:uppercase;border-bottom:1px solid #eee;padding-bottom:.4em;color:#aaa;clear:both}.ai1ec_hidden{display:none}.ai1ec_week_days_list,.ai1ec_month_days_list,.ai1ec_yearly_months_list{margin:0;padding:0;list-style:none}.ai1ec_week_days_list li,.ai1ec_month_days_list li,.ai1ec_yearly_months_list li{float:left;padding:.3em 0;width:2.2em;border:1px solid #dfdfdf;border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em;margin-right:.2em;background-color:#fff;text-align:center}.ai1ec_yearly_months_list li{width:2.5em!important;padding:.5em 0!important}.ai1ec_week_days_list li:hover,.ai1ec_month_days_list li:hover,.ai1ec_yearly_months_list li:hover{cursor:pointer}.ai1ec_selected{background-color:#e2e2e2!important}.ai1ec-date-input{width:7em}.ai1ec-time-input{width:5.5em}#ai1ec_venue,#ai1ec_address,#ai1ec_cost,#ai1ec_contact_name,#ai1ec_contact_phone,#ai1ec_contact_email{width:100%;max-width:20em}.ai1ec-form.ai1ec-location-form{float:left;width:33em}#side-info-column .ai1ec-form.ai1ec-location-form{float:none;width:100%}.ac_results img{float:left;margin:.2em .7em .2em .2em}.ai1ec_box_map{float:right;margin-bottom:1em;position:absolute;visibility:hidden;border:1px solid #ddd}.ai1ec_box_map.ai1ec_box_map_visible{position:static;visibility:visible}#ai1ec_map_canvas{width:264px;height:15em}.ai1ec_bottom_publish{min-width:80px;text-align:center}.calendricalDatePopup,.calendricalTimePopup{z-index:2}.calendricalDatePopup{background:white;border:solid 1px #999;padding:2px;text-align:center;width:200px}.calendricalDatePopup table{border-collapse:collapse;width:200px}.calendricalDatePopup table .monthCell{padding:2px 0}.calendricalDatePopup table .monthCell a{display:block;float:left;line-height:20px}.calendricalDatePopup table .monthCell .prevMonth,.calendricalDatePopup table .monthCell .nextMonth{width:24px}.calendricalDatePopup table .monthCell .monthName{width:150px}.calendricalDatePopup table a{text-decoration:none!important;padding:0}.calendricalDatePopup table th{text-align:center}.calendricalDatePopup table td{text-align:center;font-size:12px;padding:0;font-family:inherit}.calendricalDatePopup table td a{display:block;color:black;padding:2px 3px}.calendricalDatePopup table td a:hover{background:#ccf;border:0;padding:2px 3px}.calendricalDatePopup table td.today a{background:#f8f8c0}.calendricalDatePopup table td.selected a{background:#ccf}.calendricalDatePopup table td.today_selected a{background:#f8f8c0;border:solid 1px #dd6;padding:1px 2px}.calendricalDatePopup table td.nonMonth a{color:#999}.calendricalTimePopup{background:white;border:solid 1px #999;width:110px;height:130px;overflow:auto}.calendricalTimePopup ul{margin:0!important;padding:0!important}.calendricalTimePopup ul li{list-style:none!important;padding:0!important;margin:0}.calendricalTimePopup ul li a,.calendricalTimePopup ul li a:visited{text-indent:10px;padding:4px;display:block;color:black;text-decoration:none!important}.calendricalTimePopup ul li a:hover,.calendricalTimePopup ul li.selected a{background:#ccf}.calendricalEndTimePopup{width:200px}.ai1ec-slider{background:#eee;height:.4em;position:relative;cursor:pointer;border:1px solid #ccc;width:8.8em;margin:.7em .25em 0 0;float:left;clear:right;border-radius:3px;-moz-border-radius:3px;-webkit-border-radius:3px}.ai1ec-progress{height:.5em;background-color:#c5ff00;display:none}.ai1ec-handle{background:#fff;height:1em;width:1em;top:-0.5em;margin-top:1px;position:absolute;z-index:0;display:block;border:1px solid #ccc;cursor:move;border-radius:.25em;-moz-border-radius:.25em;-webkit-border-radius:.25em;box-shadow:0 2px 5px rgba(0,0,0,0.15);-moz-box-shadow:0 2px 5px rgba(0,0,0,0.15);-webkit-box-shadow:0 2px 5px rgba(0,0,0,0.15)}.ai1ec-range{text-align:center;width:3em;border:1px solid #dfdfdf;background:#fff;border-radius:4px;-moz-border-radius:4px;-webkit-border-radius:4px;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}
|
css/calendar.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.ai1ec-container{font-size:13pt!important}.ai1ec-container small{margin:0!important}.ai1ec-action-month #ai1ec-view-month,.ai1ec-action-agenda #ai1ec-view-agenda{color:#000;background:#ddd;background:-o-linear-gradient(#ccc,#eee);background:-ms-linear-gradient(#ccc,#eee);background:-moz-linear-gradient(#ccc,#eee);background:-webkit-gradient(linear,0% 0,0% 100%,from(#ccc),to(#eee));background:-webkit-linear-gradient(#ccc,#eee)}#ai1ec-calendar-view-container{position:relative;clear:both;margin-bottom:.2em}table.ai1ec-calendar-toolbar{width:100%;border:0!important;margin:0!important}.ai1ec-calendar-toolbar td{text-align:center;width:1em;vertical-align:middle;border:0!important;padding:0!important;white-space:nowrap;background:none!important}.ai1ec-calendar-toolbar td:last-child{text-align:right}.ai1ec-calendar-toolbar td:first-child{text-align:left}.ai1ec-loading{position:absolute;z-index:9;top:0;left:0;width:100%;height:100%;background:#fff url(../img/ajax-loader.gif) no-repeat center center;display:none}ul.ai1ec-view-tabs{margin:0 0 .2em!important;padding:0!important;display:inline-block}.ai1ec-view-tabs li{list-style:none!important;float:left;margin:.1em 0!important;padding:0!important}.ai1ec-view-tabs a{line-height:25px!important;padding:.2em .5em}.ai1ec-view-tabs a img{border:0!important;padding:0!important;margin:0!important;float:none!important;position:static!important;vertical-align:middle;background:none!important}.ai1ec-filters-container{display:inline-block}.ai1ec-filters-container .ai1ec-button{margin:0}.ai1ec-filter-selector-container{position:relative;display:inline-block;text-align:left;white-space:normal}.ai1ec-filter-selector{display:none;position:absolute;z-index:10;right:0;top:100%;overflow:auto;max-width:20em;max-height:30em;background:#fff;border:1px solid #ddd;box-shadow:1px 5px 8px rgba(0,0,0,0.08);-o-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-ms-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-moz-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-webkit-box-shadow:1px 5px 8px rgba(0,0,0,0.08);padding:.1em}.ai1ec-filter-selector ul{margin:0!important;padding:0!important}.ai1ec-filter-selector li{list-style:none}.ai1ec-filter-selector .ai1ec-category,.ai1ec-filter-selector .ai1ec-tag{font-size:8pt!important}.ai1ec-clear-filters{display:none;font-size:11pt!important;font-weight:normal;color:#7a86d9!important;cursor:pointer;text-decoration:none!important}.ai1ec-clear-filters:hover{color:#000!important}h2.ai1ec-calendar-title{float:left;font-size:1.15em!important;line-height:1.3em!important;margin:0 0 .2em!important}.ai1ec-title-buttons{margin:0 .5em}.ai1ec-title-buttons .ai1ec-button{font-size:8pt!important;margin:.3em .1em}.ai1ec-today #ai1ec-today{display:none}ul.ai1ec-pagination{margin:0 0 .3em!important;padding:0!important;float:right}a.ai1ec-pagination{margin:0 0 .3em!important}.ai1ec-pagination li{list-style:none!important;padding:0!important;float:left}.ai1ec-action-month .ai1ec-pagination a{width:7em}.ai1ec-action-agenda a.ai1ec-pagination{float:right;width:9em}#ai1ec-prev-year,#ai1ec-next-year{width:4em}table.ai1ec-month-view{border-collapse:collapse;border:1px solid #ddd!important;margin:0!important;background:#fff;table-layout:fixed;clear:both;width:100%}.ai1ec-month-view td{border:1px solid #ddd!important;vertical-align:top;background:none!important}.ai1ec-month-view td.ai1ec-empty{background:#f8f8f8!important}.ai1ec-month-view th{padding:.2em!important;border-bottom:1px solid #ddd;font:bold 9pt Tahoma,Geneva,sans-serif!important;text-align:center!important;background:#f2f2f2!important;border:none!important;color:#999!important;text-shadow:0 1px 0 #fff;-o-text-shadow:0 1px 0 #fff;-ms-text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff}.ai1ec-month-view td{padding:0!important;text-align:left}.ai1ec-month-view .ai1ec-day{position:relative;min-height:5em}.ai1ec-month-view .ai1ec-today{background:#ffd;background:rgba(255,255,128,0.3)}.ai1ec-month-view .ai1ec-date{text-align:right;font-size:10pt;line-height:12pt;padding:0 .4em;background:#eaf4ff;font:8pt Tahoma,Geneva,sans-serif;color:#666;text-shadow:0 1px 0 #fff;-o-text-shadow:0 1px 0 #fff;-ms-text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff}.ai1ec-month-view a.ai1ec-event-container{position:relative;font:9pt Tahoma,Geneva,sans-serif!important;text-decoration:none!important;display:block;border:none!important}.ai1ec-month-view .ai1ec-event{border-radius:.3em;-o-border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;margin:1px 1px 0 1px;padding:0 0 1px 2px;white-space:nowrap;overflow:hidden;color:#568!important}.ai1ec-month-view .ai1ec-allday .ai1ec-event{background:#568;color:#fff!important}.ai1ec-month-view .ai1ec-category-colors{float:right;font-size:1.2em;margin-top:1px}.ai1ec-month-view .ai1ec-event-popup,.ai1ec-month-view .ai1ec-event-summary{border:2px solid #d4c4b0;box-shadow:1px 5px 8px rgba(0,0,0,0.08);-o-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-ms-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-moz-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-webkit-box-shadow:1px 5px 8px rgba(0,0,0,0.08);background:#fff}.ai1ec-month-view .ai1ec-event-popup{position:absolute;z-index:5;display:none;white-space:nowrap;color:#000!important;top:-4px;left:-2px;min-width:100%;border-radius:0 .3em .3em 0;-o-border-radius:0 .3em .3em 0;-moz-border-radius:0 .3em .3em 0;-webkit-border-radius:0 .3em .3em 0}.ai1ec-month-view .ai1ec-event-popup.ai1ec-shifted-right{border-radius:.3em 0 0 .3em;-o-border-radius:.3em 0 0 .3em;-ms-border-radius:.3em 0 0 .3em;-moz-border-radius:.3em 0 0 .3em;-webkit-border-radius:.3em 0 0 .3em}.ai1ec-month-view .ai1ec-event-popup-bg{position:relative;left:-2px;margin-right:-1px;padding:2px 2px 2px 5px;background:#fff}.ai1ec-month-view .ai1ec-shifted-right .ai1ec-event-popup-bg{left:1px;padding:2px 5px 2px 2px}.ai1ec-month-view .ai1ec-event-summary,.ai1ec-month-view .ai1ec-event-summary p{font-size:.95em!important}.ai1ec-month-view .ai1ec-event-summary p{line-height:1.4em!important}.ai1ec-month-view .ai1ec-event-summary{position:absolute;overflow:hidden;top:-2px;white-space:normal;right:100%;width:13em;padding:2px 4px 3px;border-radius:.3em 0 .3em .3em;-o-border-radius:.3em 0 .3em .3em;-ms-border-radius:.3em 0 .3em .3em;-moz-border-radius:.3em 0 .3em .3em;-webkit-border-radius:.3em 0 .3em .3em;background:linear-gradient(#fff 1.5em,#fdfadc);background:-o-linear-gradient(#fff 1.5em,#fdfadc);background:-ms-linear-gradient(#fff 1.5em,#fdfadc);background:-moz-linear-gradient(#fff 1.5em,#fdfadc);background:-webkit-gradient(linear,0% 1.5em,0% 100%,from(#fff),to(#fdfadc));background:-webkit-linear-gradient(#fff 1.5em,#fdfadc);color:#6d5e4a}.ai1ec-month-view .ai1ec-shifted-right .ai1ec-event-summary{left:100%;border-radius:0 .3em .3em .3em;-o-border-radius:0 .3em .3em .3em;-moz-border-radius:0 .3em .3em .3em;-webkit-border-radius:0 .3em .3em .3em}.ai1ec-month-view .ai1ec-event-summary p{margin:0 0 .3em!important;padding:0!important}.ai1ec-month-view .ai1ec-event-time{font-size:8pt;font-weight:bold}.ai1ec-month-view .ai1ec-read-more{text-align:center;font-size:8pt;color:#aaa;color:rgba(0,0,0,0.4)}ol.ai1ec-agenda-view{clear:both;overflow:hidden;margin:0!important;padding:0!important}.ai1ec-agenda-view .ai1ec-no-results{font-size:10pt!important;font-style:italic}ol.ai1ec-date-events{overflow:hidden;margin:0 .75em 0 0!important;padding:0!important}ol.ai1ec-agenda-view>li,ol.ai1ec-date-events>li{list-style:none!important}.ai1ec-agenda-view .ai1ec-date{overflow:hidden;margin:0!important;padding:0!important;border-top:1px solid #f2f2f2;border-bottom:1px solid #fff;background:#f8f8f8;background:-o-linear-gradient(#f2f2f2 1em,#fff);background:-ms-linear-gradient(#f2f2f2 1em,#fff);background:-moz-linear-gradient(#f2f2f2 1em,#fff);background:-webkit-gradient(linear,0 1em,0 100%,from(#f2f2f2),to(#fff));background:-webkit-linear-gradient(#f2f2f2 1em,#fff)}.ai1ec-agenda-view .ai1ec-date.ai1ec-today{border-top:1px solid #eec;border-bottom:1px solid #fff;background:#ffd;background:-o-linear-gradient(#f8f8ce 1em,#fff);background:-ms-linear-gradient(#f8f8ce 1em,#fff);background:-moz-linear-gradient(#f8f8ce 1em,#fff);background:-webkit-gradient(linear,0 1em,0 100%,from(#f8f8ce),to(#fff));background:-webkit-linear-gradient(#f8f8ce 1em,#fff);background:-o-linear-gradient(#f8f8ce 1em,#fff)}.ai1ec-agenda-view h3.ai1ec-date-title{width:4em;float:left;margin:0 .75em .5em!important;font:10pt/1.1em Tahoma,Geneva,sans-serif!important;color:#444;text-shadow:0 1px 0 #fff;-o-text-shadow:0 1px 0 #fff;-ms-text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff;line-height:1.1em;text-align:center;border:2px solid #7e9dbd;border-radius:0 0 5px 5px;-o-border-radius:0 0 .5em .5em;-moz-border-radius:0 0 .5em .5em;-webkit-border-radius:0 0 .5em .5em;box-shadow:0 2px 2px rgba(0,0,0,0.08);-o-box-shadow:0 2px 2px rgba(0,0,0,0.08);-ms-box-shadow:0 2px 2px rgba(0,0,0,0.08);-moz-box-shadow:0 2px 2px rgba(0,0,0,0.08);-webkit-box-shadow:0 2px 2px rgba(0,0,0,0.08);background:#fff;background:-o-linear-gradient(#fff 1em,#eee);background:-ms-linear-gradient(#fff 1em,#eee);background:-moz-linear-gradient(#fff 1em,#eee);background:-webkit-gradient(linear,0% 1em,0% 100%,from(#fff),to(#eee));background:-webkit-linear-gradient(#fff 1em,#eee)}.ai1ec-agenda-view .ai1ec-month{text-shadow:0 -1px 0 #000;-o-text-shadow:0 -1px 0 #000;-ms-text-shadow:0 -1px 0 #000;-moz-text-shadow:0 -1px 0 #000;-webkit-text-shadow:0 -1px 0 #000;background:#7e9dbd;font-size:.8em!important;padding:.1em;text-transform:uppercase;letter-spacing:.2em;color:#fff}.ai1ec-agenda-view .ai1ec-day{font-size:2.2em!important;padding:.3em 0 .2em!important}.ai1ec-agenda-view .ai1ec-weekday{font-size:.8em!important;line-height:1.5em}.ai1ec-agenda-view .ai1ec-event{position:relative;clear:right;overflow:hidden;font-size:10pt;text-decoration:none;padding:.1em .3em!important;margin:.5em 0!important;background:#fff;border:1px solid #ddd;border-radius:.5em;-o-border-radius:.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em}.ai1ec-agenda-view .ai1ec-event.ai1ec-expanded{border:2px solid #d4c4b0;box-shadow:1px 5px 8px rgba(0,0,0,0.08);-o-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-ms-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-moz-box-shadow:1px 5px 8px rgba(0,0,0,0.08);-webkit-box-shadow:1px 5px 8px rgba(0,0,0,0.08)}.ai1ec-agenda-view .ai1ec-event-click{font-family:Tahoma,Geneva,sans-serif!important;cursor:pointer;line-height:1.3em;color:#568;text-shadow:0 1px 0 #fff;-o-text-shadow:0 1px 0 #fff;-ms-text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff}.ai1ec-agenda-view .ai1ec-event-time{float:left;margin-right:.5em;min-height:1em;font-weight:bold;line-height:1.3em}.ai1ec-agenda-view .ai1ec-event-title{margin:0 0 0 8em;font-size:10pt!important;font-weight:normal}.ai1ec-agenda-view .ai1ec-event.ai1ec-allday{padding:0!important}.ai1ec-agenda-view .ai1ec-allday-label{font-size:8pt!important;color:#b9c0ce;padding-left:.2em}.ai1ec-agenda-view .ai1ec-allday .ai1ec-event-click{color:#fff;background:#568;padding:.1em .4em;border-radius:.3em;-o-border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;text-shadow:none;-o-text-shadow:none;-ms-text-shadow:none;-moz-text-shadow:none;-webkit-text-shadow:none}.ai1ec-agenda-view .ai1ec-allday .ai1ec-event-time{color:#fff}.ai1ec-agenda-view .ai1ec-allday .ai1ec-event-title{margin:0}.ai1ec-agenda-view .ai1ec-event-expand{float:right;margin-left:.5em;visibility:hidden;font-size:9pt!important}.ai1ec-agenda-view .ai1ec-event:hover,.ai1ec-agenda-view .ai1ec-event.ai1ec-expanded:hover{border-color:#aaa}.ai1ec-agenda-view .ai1ec-event:hover .ai1ec-event-click{color:#000}.ai1ec-agenda-view .ai1ec-allday:hover .ai1ec-event-click{color:#fff;background:#3b475f}.ai1ec-agenda-view .ai1ec-event-click:hover>.ai1ec-event-expand{visibility:visible}.ai1ec-agenda-view .ai1ec-category-colors{float:left;font-size:.9em;margin:.2em .2em 0 -0.2em}.ai1ec-agenda-view .ai1ec-category-colors .ai1ec-category-color{border:1px solid rgba(255,255,255,0.7)}.ai1ec-agenda-view .ai1ec-event-summary{display:none}.ai1ec-agenda-view .ai1ec-event-summary .ai1ec-event-title{margin:.1em 0;font-size:11pt!important;line-height:1.1em}.ai1ec-agenda-view .ai1ec-event-summary .ai1ec-event-time{width:auto;float:none;font-size:9pt!important;line-height:1.5em}.ai1ec-agenda-view .ai1ec-event-summary .ai1ec-event-click{border-bottom:1px solid #ddd}.ai1ec-agenda-view .ai1ec-allday .ai1ec-event-summary .ai1ec-event-click{border-bottom:1px solid #ddd;border-radius:.3em .3em 0 0;-o-border-radius:.3em .3em 0 0;-moz-border-radius:.3em .3em 0 0;-webkit-border-radius:.3em .3em 0 0}.ai1ec-agenda-view .ai1ec-categories,.ai1ec-agenda-view .ai1ec-tags{font-size:8pt!important}.ai1ec-agenda-view .ai1ec-event-description{clear:both;overflow:hidden;padding:0 0 3.6em;max-height:20em}.ai1ec-agenda-view .ai1ec-event-description,.ai1ec-agenda-view .ai1ec-event-description p{font-size:9pt!important;line-height:1.5em!important}.ai1ec-agenda-view .ai1ec-event-description p{margin:.5em 0 .75em!important;padding:0!important}.ai1ec-agenda-view .ai1ec-allday .ai1ec-event-description{position:relative;overflow:hidden;padding:0 .4em 3.5em}.ai1ec-agenda-view .ai1ec-event-description .ai1ec-label{font-size:8pt!important;font-weight:normal}.ai1ec-agenda-view .ai1ec-event-overlay{position:absolute;z-index:5;bottom:0;left:0;right:0;padding:.4em .5em .4em .2em;border-radius:0 0 .5em .5em;-o-border-radius:0 0 .5em .5em;-moz-border-radius:0 0 .5em .5em;-webkit-border-radius:0 0 .5em .5em;background:rgba(255,255,255,0.75);background:-o-linear-gradient(rgba(255,255,255,0.75),#fdfadc);background:-ms-linear-gradient(rgba(255,255,255,0.75),#fdfadc);background:-moz-linear-gradient(rgba(255,255,255,0.75),#fdfadc);background:-webkit-gradient(linear,0 0,0 100%,from(rgba(255,255,255,0.75)),to(#fdfadc));background:-webkit-linear-gradient(rgba(255,255,255,0.75),#fdfadc)}.ai1ec-agenda-view .ai1ec-read-more{float:right;margin:.6em 0 .2em}.ai1ec-subscribe{clear:both}.ai1ec-subscribe-filtered{display:none}
|
css/colorpicker.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
#tag-color{width:39px;height:24px;background:url(../img/color-picker.png);cursor:pointer}#tag-color:hover{background-position:0 -24px}#tag-color-background{position:relative;top:3px;left:3px;width:20px;height:18px;background:transparent}ul.colorpicker-list{padding:.1em}.colorpicker-list li{float:left;width:13px;height:13px;margin:1px;cursor:pointer;border-radius:2px;-o-border-radius:2px;-moz-border-radius:2px;-webkit-border-radius:2px}.select-more-colors{width:73px!important;line-height:22px;height:22px!important;border-color:#fff!important;margin:2px 1px 2px 1px!important;text-align:center;font-family:Tahoma,Verdana,Arial,Helvetica;font-size:11px}li.select-more-colors:hover{border-color:#0a246a!important;background:#b6bdd2!important}.color-1{background:#60a!important}.color-2{background:#807!important}.color-3{background:#920!important}.color-4{background:#a60!important}.color-5{background:#990!important}.color-6{background:#080!important}.color-7{background:#077!important}.color-8{background:#00a!important}.color-9{background:#000!important}.color-10{background:#444!important}.color-11{background:#85e!important}.color-12{background:#d5d!important}.color-13{background:#d43!important}.color-14{background:#d90!important}.color-15{background:#bb0!important}.color-16{background:#2b0!important}.color-17{background:#0ba!important}.color-18{background:#26d!important}.color-19{background:#777!important}.color-20{background:#aaa!important}.colorpicker{width:356px;height:176px;overflow:hidden;position:absolute;background:url(../img/colorpicker_background.png);font-family:Arial,Helvetica,sans-serif;display:none;z-index:2}.colorpicker_color{width:150px;height:150px;left:14px;top:13px;position:absolute;background:#f00;overflow:hidden;cursor:crosshair}.colorpicker_color div{position:absolute;top:0;left:0;width:150px;height:150px;background:url(../img/colorpicker_overlay.png)}.colorpicker_color div div{position:absolute;top:0;left:0;width:11px;height:11px;overflow:hidden;background:url(../img/colorpicker_select.gif);margin:-5px 0 0 -5px}.colorpicker_hue{position:absolute;top:13px;left:171px;width:35px;height:150px;cursor:n-resize}.colorpicker_hue div{position:absolute;width:35px;height:9px;overflow:hidden;background:url(../img/colorpicker_indic.gif) left top;margin:-4px 0 0 0;left:0}.colorpicker_new_color{position:absolute;width:60px;height:30px;left:213px;top:13px;background:#f00}.colorpicker_current_color{position:absolute;width:60px;height:30px;left:283px;top:13px;background:#f00}.colorpicker input{background-color:transparent!important;border:1px solid transparent;border-color:transparent!important;border-radius:0!important;box-sizing:content-box!important;position:absolute;font-size:10px;font-family:Arial,Helvetica,sans-serif;color:#898989;top:4px;right:11px;text-align:right;margin:0;padding:0;height:11px}.colorpicker_hex{position:absolute;width:72px;height:22px;background:url(../img/colorpicker_hex.png) top;left:212px;top:142px}.colorpicker_hex input{right:6px}.colorpicker_field{height:22px;width:62px;background-position:top;position:absolute}.colorpicker_field span{position:absolute;width:12px;height:22px;overflow:hidden;top:0;right:0;cursor:n-resize}.colorpicker_rgb_r{background-image:url(../img/colorpicker_rgb_r.png);top:52px;left:212px}.colorpicker_rgb_g{background-image:url(../img/colorpicker_rgb_g.png);top:82px;left:212px}.colorpicker_rgb_b{background-image:url(../img/colorpicker_rgb_b.png);top:112px;left:212px}.colorpicker_hsb_h{background-image:url(../img/colorpicker_hsb_h.png);top:52px;left:282px}.colorpicker_hsb_s{background-image:url(../img/colorpicker_hsb_s.png);top:82px;left:282px}.colorpicker_hsb_b{background-image:url(../img/colorpicker_hsb_b.png);top:112px;left:282px}.colorpicker_submit{position:absolute;width:50px;height:22px;background:url(../img/colorpicker_submit.png) top;left:290px;top:142px;overflow:hidden}.colorpicker_focus{background-position:center}.colorpicker_hex.colorpicker_focus{background-position:bottom}.colorpicker_submit.colorpicker_focus{background-position:bottom}.colorpicker_slider{background-position:bottom}
|
css/event.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
table.ai1ec-full-event{border:none!important;border-collapse:collapse!important;width:100%;margin-bottom:.5em!important}.ai1ec-full-event td{font-size:10pt!important}.ai1ec-full-event th,.ai1ec-full-event td{line-height:14pt!important;padding:.3em .5em!important;border:none!important;vertical-align:top}.ai1ec-multi-event th,.ai1ec-multi-event td{padding:.3em .5em!important}.ai1ec-full-event th.ai1ec-empty,.ai1ec-full-event td.ai1ec-empty{padding:0!important}.ai1ec-full-event th{width:6em;font-size:9pt!important;font-family:sans-serif!important;font-weight:bold;color:#888!important;text-align:right;text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff;background:-moz-linear-gradient(right,#fff,#ececec 1em,#f8f8f8);background:-webkit-gradient(linear,0 0,100% 0,from(#f8f8f8),to(#ececec));background:-webkit-linear-gradient(right,#fff,#ececec 1em,#f8f8f8);background:-o-linear-gradient(right,#fff,#ececec 1em,#f8f8f8)}.ai1ec-full-event .ai1ec-time{line-height:16pt!important;vertical-align:middle}.ai1ec-multi-event .ai1ec-time{line-height:15pt!important}.ai1ec-full-event td.ai1ec-time{font-weight:bold;font-size:11pt!important}.ai1ec-multi-event td.ai1ec-time{font-size:10pt!important}.ai1ec-full-event .ai1ec-allday-label{font-size:10pt!important;color:#bbb;padding-left:.2em}.ai1ec-multi-event .ai1ec-allday-label{font-size:9pt!important}.ai1ec-full-event .ai1ec-calendar-link{float:right;margin:-0.1em 0}.ai1ec-multi-event .ai1ec-calendar-link{font-size:8pt!important}.ai1ec-full-event td.ai1ec-location{min-width:30%}.ai1ec-full-event td.ai1ec-map{text-align:right;vertical-align:bottom}.ai1ec-full-event td.ai1ec-map.ai1ec-has-map{width:55%;text-align:left}.ai1ec-full-event .ai1ec-gmap-container{border:1px solid #ddd;margin-bottom:.3em}.ai1ec-full-event #ai1ec-gmap-canvas{min-width:18em;width:100%;height:12em}.ai1ec-full-event .ai1ec-gmap-link{float:right}.ai1ec-multi-event .ai1ec-gmap-link{font-size:8pt!important;margin:-0.2em 0}.ai1ec-full-event #ai1ec-gmap-canvas input{margin:0!important}.ai1ec-full-event .ai1ec-contact a{white-space:nowrap}.ai1ec-full-event td.ai1ec-tags,.ai1ec-full-event td.ai1ec-categories{padding:.1em .2em!important}.ai1ec-full-event .ai1ec-category{float:left}.ai1ec-multi-event .ai1ec-category{font:8pt Tahoma,Geneva,sans-serif!important}.ai1ec-full-event .ai1ec-tag{font-size:.9em!important}.ai1ec-event-footer{clear:left;font-size:.9em!important;font-style:italic}.ai1ec-ics-icon{background:url(../img/ics-icon.png) no-repeat right;padding-right:15px}.ai1ec-excerpt{margin-bottom:.5em;font-size:10pt!important;line-height:1.6em;overflow:hidden}.ai1ec-excerpt>div{padding-left:7.2em}.ai1ec-excerpt label{padding:0 .6em!important;background:-moz-linear-gradient(right,#fff,#ececec 1em,#f8f8f8);background:-webkit-gradient(linear,0 0,100% 0,from(#f8f8f8),to(#ececec));background:-webkit-linear-gradient(right,#fff,#ececec 1em,#f8f8f8);background:-o-linear-gradient(right,#fff,#ececec 1em,#f8f8f8);text-align:right;text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff;clear:left;float:left;width:6em;margin-left:-7.2em}.ai1ec-excerpt .ai1ec-time{font-weight:bold}.ai1ec-excerpt .ai1ec-event-link{float:right;font-size:8pt!important}.ai1ec-excerpt .ai1ec-allday-label{font-size:9pt!important;color:#bbb;padding-left:.2em}
|
css/general.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
a.ai1ec-button{cursor:pointer;font:10pt/1.1em Tahoma,Geneva,sans-serif!important;text-decoration:none!important;color:#666!important;text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff;padding:.4em .5em;margin:.1em;background:#eee;background:-moz-linear-gradient(#f8f8f8,#ddd);background:-webkit-gradient(linear,0% 0,0% 100%,from(#f8f8f8),to(#ddd));background:-webkit-linear-gradient(#f8f8f8,#ddd);background:-o-linear-gradient(#f8f8f8,#ddd);box-shadow:0 2px 2px rgba(0,0,0,0.08);-moz-box-shadow:0 2px 2px rgba(0,0,0,0.08);-webkit-box-shadow:0 2px 2px rgba(0,0,0,0.08);border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em;text-align:center;border:1px solid #ccc;border-width:1px;display:inline-block;white-space:nowrap}a.ai1ec-button:hover{color:#444!important;background:#ddd;background:-moz-linear-gradient(#eee,#ccc);background:-webkit-gradient(linear,0% 0,0% 100%,from(#eee),to(#ccc));background:-webkit-linear-gradient(#eee,#ccc);background:-o-linear-gradient(#eee,#ccc)}a.ai1ec-button.ai1ec-selected{color:#000!important;border-color:#909ce0;background:#dde6f8;background:-moz-linear-gradient(#edf6ff,#c5d4f3);background:-webkit-gradient(linear,0% 0,0% 100%,from(#edf6ff),to(#c5d4f3));background:-webkit-linear-gradient(#edf6ff,#c5d4f3);background:-o-linear-gradient(#edf6ff,#c5d4f3)}a.ai1ec-button.ai1ec-active{color:#000!important;background:#ddd;background:-moz-linear-gradient(#ccc,#eee);background:-webkit-gradient(linear,0% 0,0% 100%,from(#ccc),to(#eee));background:-webkit-linear-gradient(#ccc,#eee);background:-o-linear-gradient(#ccc,#eee)}a.ai1ec-button.ai1ec-active.ai1ec-selected{background:#dde6f8;background:-moz-linear-gradient(#c5d4f3,#edf6ff);background:-webkit-gradient(linear,0% 0,0% 100%,from(#c5d4f3),to(#edf6ff));background:-webkit-linear-gradient(#c5d4f3,#edf6ff);background:-o-linear-gradient(#c5d4f3,#edf6ff)}li>a.ai1ec-button{display:block;margin:0;border-radius:0;-moz-border-radius:0;-webkit-border-radius:0;border-left-width:0}li:first-child>a.ai1ec-button{border-radius:.4em 0 0 .4em;-moz-border-radius:.4em 0 0 .4em;-webkit-border-radius:.4em 0 0 .4em;border-left-width:1px}li:last-child>a.ai1ec-button{border-radius:0 .4em .4em 0;-moz-border-radius:0 .4em .4em 0;-webkit-border-radius:0 .4em .4em 0}li:first-child:last-child>a.ai1ec-button{border-radius:.4em;-moz-border-radius:.4em;-webkit-border-radius:.4em}label.ai1ec-label{padding:0 .2em;font-family:Tahoma,Geneva,sans-serif!important;font-size:9pt!important;font-weight:bold;color:#888!important}.ai1ec-category{cursor:pointer;font:.9em Tahoma,Geneva,sans-serif!important;border:1px solid #dcdcdc;text-shadow:0 1px 0 #fff;-moz-text-shadow:0 1px 0 #fff;-webkit-text-shadow:0 1px 0 #fff;padding:2pt 3pt!important;margin:.2em!important;text-decoration:none!important;text-transform:uppercase;letter-spacing:1pt;white-space:nowrap;color:#666!important;background:#f0f0f0;border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em}.ai1ec-category:hover{color:#222!important;background:#dcdcdc}.ai1ec-category.ai1ec-selected{background:#c5d4f3;border-color:#7a86d9}.ai1ec-tag{color:#568!important;font-family:Tahoma,Geneva,sans-serif!important;line-height:1.3em!important;cursor:pointer;white-space:nowrap;margin:.1em .2em;padding:.1em .2em;border-radius:.3em;-moz-border-radius:.3em;-webkit-border-radius:.3em;display:inline-block}.ai1ec-tag:hover{color:#000!important;text-decoration:underline}.ai1ec-tag.ai1ec-selected{background:#cddbf5}.ai1ec-category-color{display:inline-block;width:.9em;height:.9em;margin:0 1px;border-radius:.2em;-o-border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em}.ai1ec-subscribe-google img{float:left;margin:-10px .5em -8px 0;padding:0!important;border:none!important;background:none!important}
|
css/jquery.autocomplete.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
.ac_results{padding:0;border:1px solid black;background-color:white;overflow:hidden;z-index:99999}.ac_results ul{width:100%;list-style-position:outside;list-style:none;padding:0;margin:0}.ac_results li{margin:0;padding:2px 5px;cursor:default;display:block;font:menu;font-size:12px;line-height:16px;overflow:hidden}.ac_loading{background:white url('../img/indicator.gif') right center no-repeat}.ac_odd{background-color:#eee}.ac_over{background-color:#0a246a;color:white}
|
css/selector.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
<?php echo $selector ?>{visibility:hidden}
|
css/settings.css
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
#the-seed-studio-settings div.inside{background:#fff;margin:0!important;padding:6px 0 8px}#the-seed-studio-settings a{font-weight:bold}.ai1ec_feed_h4{margin-bottom:5px}.column-1-ai1ec{float:left;width:54%}.column-2-ai1ec{float:right;width:45%}.column-3-ai1ec{float:left;width:100%}.ai1ec-plugin-branding{padding:0 20px 0 20px}.ai1ec-plugin-logo{position:relative;margin-left:-15px}.ai1ec-support-button{float:right;width:280px;text-align:center;margin:1em 0 1em 1em}.ai1ec-support-button a{font-size:24px;color:#fff;text-decoration:none;text-transform:uppercase;text-align:center;display:block;padding:10px 30px 10px 30px;margin:0 auto;border-radius:10px;-o-border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-shadow:-1px -1px 1px rgba(0,0,0,.2);-o-text-shadow:-1px -1px 1px rgba(0,0,0,.2);-moz-text-shadow:-1px -1px 1px rgba(0,0,0,.2);-webkit-text-shadow:-1px -1px 1px rgba(0,0,0,.2);box-shadow:0 .3em .3em rgba(0,0,0,0.2);-o-box-shadow:0 .3em .3em rgba(0,0,0,0.2);-moz-box-shadow:0 .3em .3em rgba(0,0,0,0.2);-webkit-box-shadow:0 .3em .3em rgba(0,0,0,0.2);border:1px solid #fff}.ai1ec-support-button a:link,.ai1ec-support-button a:visited{background:#88b633;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#91bb35',endColorstr='#548a26');background:linear-gradient(#91bb35,#548a26);background:-o-linear-gradient(#91bb35,#548a26);background:-moz-linear-gradient(#91bb35,#548a26);background:-webkit-gradient(linear,left top,left bottom,from(#91bb35),to(#548a26));background:-webkit-linear-gradient(#91bb35,#548a26)}.ai1ec-support-button a:hover{color:#fff;background:#88b633;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d2e7a2',endColorstr='#91bb35');background:linear-gradient(#d2e7a2,#91bb35);background:-o-linear-gradient(#d2e7a2,#91bb35);background:-moz-linear-gradient(#d2e7a2,#91bb35);background:-webkit-gradient(linear,left top,left bottom,from(#d2e7a2),to(#91bb35));background:-webkit-linear-gradient(#d2e7a2,#91bb35)}.ai1ec-support-button a span{display:block;padding-top:2px;font-size:.5em;color:#e5f3ca;text-align:center;text-transform:lowercase}#general-settings{line-height:1.7em}#general-settings div.inside label{float:left;clear:left;margin:.25em 0}#general-settings .checkbox{float:left;margin:.5em .5em 0 0}#general-settings div.description{clear:left;font-size:.95em;line-height:1.5em;margin-bottom:1em}label.textinput{width:230px}.ai1ec-follow-fan{padding:10px 0 10px 0;margin:10px 0 0 0;border-top:1px solid #ccc;border-bottom:1px solid #ccc}.facebook-like-top{float:left}#ai1ec_feed_url,.ai1ec-feed-url{width:100%}.ai1ec-feed-category,.ai1ec-feed-tags{float:left;overflow:hidden;line-height:2em}.ai1ec-feed-category strong,.ai1ec-feed-tags strong{margin:0 1em 0 .2em}#ai1ec_feed_category,#ai1ec_feed_tags{width:15em}#ai1ec_feed_category{margin-right:.5em}.ai1ec-feed-container{background:#eee;border:1px solid #ddd;padding:.3em .5em;border-radius:.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em;overflow:hidden;position:relative;margin:1em 0 0}.ai1ec-feed-container .ajax-loading{clear:left;display:block}.ai1ec_feed_h4{margin:.5em 0}#ai1ec_add_new_ics,.ai1ec_delete_ics{clear:left}#ai1ec_add_new_ics,.ai1ec_delete_ics,.ai1ec_update_ics,.ai1ec_flush_ics{float:right}#ai1ec_save_settings{clear:left;display:block}
|
img/agenda-view.png
ADDED
Binary file
|
img/ajax-loader.gif
ADDED
Binary file
|
img/blank.gif
ADDED
Binary file
|
img/color-picker.png
ADDED
Binary file
|
img/colorpicker_background.png
ADDED
Binary file
|
img/colorpicker_hex.png
ADDED
Binary file
|
img/colorpicker_hsb_b.png
ADDED
Binary file
|
img/colorpicker_hsb_h.png
ADDED
Binary file
|
img/colorpicker_hsb_s.png
ADDED
Binary file
|
img/colorpicker_indic.gif
ADDED
Binary file
|
img/colorpicker_overlay.png
ADDED
Binary file
|
img/colorpicker_rgb_b.png
ADDED
Binary file
|
img/colorpicker_rgb_g.png
ADDED
Binary file
|
img/colorpicker_rgb_r.png
ADDED
Binary file
|
img/colorpicker_select.gif
ADDED
Binary file
|
img/colorpicker_submit.png
ADDED
Binary file
|
img/custom_background.png
ADDED
Binary file
|
img/custom_hex.png
ADDED
Binary file
|
img/custom_hsb_b.png
ADDED
Binary file
|
img/custom_hsb_h.png
ADDED
Binary file
|
img/custom_hsb_s.png
ADDED
Binary file
|
img/custom_indic.gif
ADDED
Binary file
|
img/custom_rgb_b.png
ADDED
Binary file
|
img/custom_rgb_g.png
ADDED
Binary file
|
img/custom_rgb_r.png
ADDED
Binary file
|
img/custom_submit.png
ADDED
Binary file
|
img/google-calendar.png
ADDED
Binary file
|
img/ics-icon.png
ADDED
Binary file
|
img/indicator.gif
ADDED
Binary file
|
img/month-view.png
ADDED
Binary file
|
img/slider.png
ADDED
Binary file
|
js/add_new_event.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
jQuery(function(f){if(f("#ai1ec_event").length){element_selector(".ai1ec_week_days_list > li","ai1ec_selected","ai1ec_weekday_value","#ai1ec_weekly_days");element_selector(".ai1ec_month_days_list > li","ai1ec_selected","ai1ec_monthday_value","#ai1ec_monthly_days");element_selector(".ai1ec_yearly_months_list > li","ai1ec_selected","ai1ec_yearmonth_value","#ai1ec_yearly_months");var a=new Date(ai1ec_add_new_event.now*1000);var g={allday:"#ai1ec_all_day_event",start_date_input:"#ai1ec_start-date-input",start_time_input:"#ai1ec_start-time-input",start_time:"#ai1ec_start-time",end_date_input:"#ai1ec_end-date-input",end_time_input:"#ai1ec_end-time-input",end_time:"#ai1ec_end-time",now:a};f.timespan(g);g={start_date_input:"#ai1ec_until-date-input",start_time:"#ai1ec_until-time",now:a};f.inputdate(g);f("#ai1ec_count").rangeinput({css:{input:"ai1ec-range",slider:"ai1ec-slider",progress:"ai1ec-progress",handle:"ai1ec-handle"}});var k=new google.maps.Geocoder();var j=new google.maps.LatLng(9.965,-83.327);var h={zoom:0,mapTypeId:google.maps.MapTypeId.ROADMAP,center:j};var e=new google.maps.Map(f("#ai1ec_map_canvas").get(0),h);var d=new google.maps.Marker({map:e});function l(w){e.setCenter(w.geometry.location);e.setZoom(15);d.setPosition(w.geometry.location);f("#ai1ec_address").val(w.formatted_address);var v="";var u="";var q="";var o="";var t=0;var p=0;for(var r=0;r<w.address_components.length;r++){switch(w.address_components[r].types[0]){case"street_number":v=w.address_components[r].long_name;break;case"route":u=w.address_components[r].long_name;break;case"locality":q=w.address_components[r].long_name;break;case"administrative_area_level_1":province=w.address_components[r].long_name;break;case"postal_code":t=w.address_components[r].long_name;break;case"country":p=w.address_components[r].long_name;break}}var s=v.length>0?v+" ":"";s+=u.length>0?u:"";t=t!=0?t:"";f("#ai1ec_city").val(q);f("#ai1ec_province").val(province);f("#ai1ec_postal_code").val(t);f("#ai1ec_country").val(p)}f("#ai1ec_address").geo_autocomplete(new google.maps.Geocoder,{selectFirst:false,minChars:3,cacheLength:50,width:300,scroll:true,scrollHeight:330}).result(function(o,p){if(p){l(p)}}).change(function(){if(f(this).val().length>0){var o=f(this).val();k.geocode({address:o},function(q,p){if(p==google.maps.GeocoderStatus.OK){l(q[0])}})}}).change();f("#ai1ec_google_map").click(function(){if(f(this).is(":checked")){f(".ai1ec_box_map").addClass("ai1ec_box_map_visible").hide().slideDown("fast")}else{f(".ai1ec_box_map").slideUp("fast")}});f("#ai1ec_repeat").change(function(){var o=f("#ai1ec_repeat option:selected").val();switch(o){case" ":i();break;default:c();break}});f("#ai1ec_end").change(m);function c(){f("#ai1ec_end_holder").fadeIn();m()}function i(){b();f("#ai1ec_end_holder").fadeOut()}function m(){var o=f("#ai1ec_end option:selected").val();switch(o){case"0":b();break;case"1":if(f("#ai1ec_count_holder").css("display")=="none"){b();f("#ai1ec_count_holder").fadeIn()}break;case"2":if(f("#ai1ec_until_holder").css("display")=="none"){b();f("#ai1ec_until_holder").fadeIn()}break}}function b(){f("#ai1ec_count_holder, #ai1ec_until_holder").hide()}if(f("#ai1ec_bottom_publish").length>0){f("#ai1ec_bottom_publish").click(function(){f("#publish").trigger("click")})}}if(f("#ai1ec_add_new_ics").length){f("#ai1ec_add_new_ics").click(function(){var q=f(this);var o=f("#ai1ec_feed_url");if(!n(o.val())){o.css("border-color","#FF0000").focus()}else{q.attr("disabled",true);o.css("border-color","#DFDFDF");var p={action:"ai1ec_add_ics",feed_url:o.val(),feed_category:f("#ai1ec_feed_category option:selected").val(),feed_tags:f("#ai1ec_feed_tags").val()};f.getJSON(ajaxurl,p,function(r){q.removeAttr("disabled");if(r.error){alert(r.message)}else{o.val("");f("#ai1ec-feeds-after").after(r.message)}})}});f(".ai1ec_delete_ics").live("click",function(){var r=f(this);r.attr("disabled",true);var q=r.closest(".ai1ec-feed-container");var p=r.siblings(".ai1ec_feed_id").val();var o={action:"ai1ec_delete_ics",ics_id:p};f.getJSON(ajaxurl,o,function(s){r.removeAttr("disabled");if(s.error){alert(s.message)}else{q.remove()}})});f(".ai1ec_flush_ics").live("click",function(){var q=f(this);q.attr("disabled",true);var p=q.siblings(".ai1ec_feed_id").val();q.siblings(".ajax-loading").css("visibility","visible");var o={action:"ai1ec_flush_ics",ics_id:p};f.getJSON(ajaxurl,o,function(r){if(r.error){alert(r.message)}else{q.fadeOut()}q.siblings(".ajax-loading").css("visibility","hidden")})});f(".ai1ec_update_ics").live("click",function(){var q=f(this);q.attr("disabled",true);var p=q.siblings(".ai1ec_feed_id").val();q.siblings(".ajax-loading").css("visibility","visible");var o={action:"ai1ec_update_ics",ics_id:p};f.getJSON(ajaxurl,o,function(r){if(r.error){alert(r.message)}else{q.siblings(".ai1ec_flush_ics").remove();if(r.count){q.after('<input type="button" class="button ai1ec_flush_ics" value="'+r.flush_label+'" />')}}q.attr("disabled",false).siblings(".ajax-loading").css("visibility","hidden")})});function n(o){var p=/(http|https|webcal):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;return p.test(o)}}});
|
js/calendar.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
jQuery(document).ready(function(i){if(ai1ec_calendar.selector!=undefined&&ai1ec_calendar.selector!=""&&i(ai1ec_calendar.selector).length==1){var n=i(":header:contains("+ai1ec_calendar.title+"):first");if(!n.length){n=i('<h1 class="page-title"></h1>');n.text(ai1ec_calendar.title)}var c=i("#ai1ec-container").detach().before(n);i(ai1ec_calendar.selector).empty().append(c).hide().css("visibility","visible").fadeIn("fast")}var h="";var l;var f=i("body").attr("class");if(f==undefined){f=""}if(f.match(/\s?\bai1ec-[\w-]+\b/)==null){f+=" "+ai1ec_calendar.body_class;i("body").attr("class",f)}function d(){var q=document.location.hash;var p=convertEntities(ai1ec_calendar.default_hash);if(h!=q&&(q!=""||h!=p)){var r=q;if(!r){r=p}j(r)}}setInterval(d,300);function j(p){i("#ai1ec-calendar-view-loading").fadeTo("fast",0.7,function(){var q=p.substring(1);i.getJSON(ai1ec_calendar.ajaxurl,q,function(t){var s=i("body").attr("class");s=s.replace(/\s?\bai1ec-[\w-]+\b/g,"");s+=" "+t.body_class;i("body").attr("class",s);var u=i("#ai1ec-calendar-view-container");u.height(u.height());var r=i("#ai1ec-calendar-view").html(t.html).height();u.animate({height:r},{complete:function(){u.height("auto")}});i("#ai1ec-calendar-view-loading").fadeOut("fast");o()})});h=p}i("a.ai1ec-load-view").live("click",function(){j(i(this).attr("href"))});function b(){var r=i(this).prev();if(!r.data("ai1ec_offset")){r.css("visibility","hidden").show();var q=i("#ai1ec-calendar-view-container");var u=r.width();var t=r.offset();var s=q.offset();var p=s.left+q.width();if(t.left+u>p){r.offset({left:p-u,top:t.top})}if(i(".ai1ec-event-summary",r).offset().left<s.left){r.addClass("ai1ec-shifted-right")}r.hide().css("visibility","visible");r.data("ai1ec_offset",true)}r.fadeIn(100,function(){if(!i(this).data("ai1ec_mouseinside")){i(this).each(e)}})}function e(){i(this).fadeOut(100,function(){i(this).parent().css({zIndex:"auto"})}).data("ai1ec_mouseinside",false)}i(".ai1ec-month-view .ai1ec-event").live("mouseenter",b);i(".ai1ec-month-view .ai1ec-event-popup").live("mouseleave",e).live("mousemove",function(){i(this).data("ai1ec_mouseinside",true)});if(i(".ai1ec-month-view").length){i(window).blur(function(){i(".ai1ec-event-popup:visible").each(e)})}function m(){i(this).hide().parent().addClass("ai1ec-expanded").end().prev().show().find(".ai1ec-event-description").hide().slideDown("fast")}function g(){i(this).next().slideUp("fast",function(){i(this).parent().parent().removeClass("ai1ec-expanded").end().hide().next().show()})}i(".ai1ec-agenda-view .ai1ec-event > .ai1ec-event-click").live("click",m);i(".ai1ec-agenda-view .ai1ec-event-summary > .ai1ec-event-click").live("click",g);i(".ai1ec-action-agenda #ai1ec-expand-all").live("click",function(){i(".ai1ec-event > .ai1ec-event-click:visible").click()});i(".ai1ec-action-agenda #ai1ec-collapse-all").live("click",function(){i(".ai1ec-event-summary > .ai1ec-event-click:visible").click()});element_selector(".ai1ec-category-filter-selector li","ai1ec-selected","ai1ec-categories","#ai1ec-selected-categories");element_selector(".ai1ec-tag-filter-selector li","ai1ec-selected","ai1ec-tags","#ai1ec-selected-tags");i(".ai1ec-dropdown").click(function(){i(".ai1ec-filter-selector").css("zIndex",10);var p=i(this).siblings(".ai1ec-filter-selector").css("zIndex",11);if(i(this).hasClass("ai1ec-active")){i(this).removeClass("ai1ec-active");p.slideUp(150)}else{i(this).addClass("ai1ec-active");p.slideDown(150)}});function k(){var s=new Array();selected_cats=i(".ai1ec-filters-container .ai1ec-dropdown.ai1ec-selected + #ai1ec-selected-categories").val();if(selected_cats){s.push(selected_cats);selected_cats="&ai1ec_cat_ids="+selected_cats}else{selected_cats=""}selected_tags=i(".ai1ec-filters-container .ai1ec-dropdown.ai1ec-selected + #ai1ec-selected-tags").val();if(selected_tags){s.push(selected_tags);selected_tags="&ai1ec_tag_ids="+selected_tags}else{selected_tags=""}s=s.join();var p;if(s.length){p=convertEntities(ai1ec_calendar.export_url)+selected_cats+selected_tags;i(".ai1ec-subscribe-filtered").fadeIn("fast")}else{p=convertEntities(ai1ec_calendar.export_url);i(".ai1ec-subscribe-filtered").fadeOut("fast")}i(".ai1ec-subscribe").attr("href",p);i(".ai1ec-subscribe-google").attr("href","http://www.google.com/calendar/render?cid="+escape(p.replace("webcal://","http://")));var r={action:"ai1ec_term_filter",ai1ec_post_ids:l,ai1ec_term_ids:s};var q=i("#ai1ec-calendar-view-loading").delay(500).fadeTo("fast",0.7);i.getJSON(ai1ec_calendar.ajaxurl,r,function(u){q.clearQueue().fadeOut("fast");var t=new Array();i.each(u.matching_ids,function(v,w){t.push(".ai1ec-event-id-"+w)});i(t.join()).fadeIn("fast");t=new Array();i.each(u.unmatching_ids,function(v,w){t.push(".ai1ec-event-id-"+w)});i(t.join()).fadeOut("fast")})}function a(){i(".ai1ec-filter-selector-container").each(function(){if(i("li.ai1ec-selected",this).length){i(".ai1ec-dropdown",this).addClass("ai1ec-selected")}else{i(".ai1ec-dropdown",this).removeClass("ai1ec-selected")}});if(i(".ai1ec-filters-container .ai1ec-selected").length){i(".ai1ec-clear-filters").fadeIn("fast")}else{i(".ai1ec-clear-filters").fadeOut("fast")}k()}i(".ai1ec-filter-selector li").click(a);i(".ai1ec-clear-filters").click(function(){i(".ai1ec-filter-selector-container li").removeClass("ai1ec-selected");a()});function o(){l=new Array();i(".ai1ec-post-id").each(function(){l.push(this.value)});l=l.join();if(i(".ai1ec-active-event:first").length){i(".ai1ec-month-view .ai1ec-active-event:first").each(function(){i(this).each(b).prev().data("ai1ec_mouseinside",true)});i(".ai1ec-agenda-view .ai1ec-active-event:first > .ai1ec-event-click").each(m);i.scrollTo(".ai1ec-active-event:first",1000,{offset:{left:0,top:-window.innerHeight/2+100}})}if(i(".ai1ec-dropdown.ai1ec-selected").length){i(".ai1ec-month-view .ai1ec-event-container, .ai1ec-agenda-view .ai1ec-event").hide();k()}}if(i("#ai1ec-selected-categories").val()!=""||i("#ai1ec-selected-tags").val()!=""){a()}o()});
|
js/colorpicker.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(function(b){var a=function(){var S={},c,N=65,t,P='<div class="colorpicker"><div class="colorpicker_color"><div><div></div></div></div><div class="colorpicker_hue"><div></div></div><div class="colorpicker_new_color"></div><div class="colorpicker_current_color"></div><div class="colorpicker_hex"><input type="text" maxlength="6" size="6" /></div><div class="colorpicker_rgb_r colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_g colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_rgb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_h colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_s colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_hsb_b colorpicker_field"><input type="text" maxlength="3" size="3" /><span></span></div><div class="colorpicker_submit"></div></div>',B={eventName:"click",onShow:function(){},onBeforeShow:function(){},onHide:function(){},onChange:function(){},onSubmit:function(){},color:"ff0000",livePreview:true,flat:false},J=function(T,V){var U=j(T);b(V).data("colorpicker").fields.eq(1).val(U.r).end().eq(2).val(U.g).end().eq(3).val(U.b).end()},u=function(T,U){b(U).data("colorpicker").fields.eq(4).val(T.h).end().eq(5).val(T.s).end().eq(6).val(T.b).end()},g=function(T,U){b(U).data("colorpicker").fields.eq(0).val(R(T)).end()},l=function(T,U){b(U).data("colorpicker").selector.css("backgroundColor","#"+R({h:T.h,s:100,b:100}));b(U).data("colorpicker").selectorIndic.css({left:parseInt(150*T.s/100,10),top:parseInt(150*(100-T.b)/100,10)})},G=function(T,U){b(U).data("colorpicker").hue.css("top",parseInt(150-150*T.h/360,10))},h=function(T,U){b(U).data("colorpicker").currentColor.css("backgroundColor","#"+R(T))},E=function(T,U){b(U).data("colorpicker").newColor.css("backgroundColor","#"+R(T))},n=function(T){var V=T.charCode||T.keyCode||-1;if((V>N&&V<=90)||V==32){return false}var U=b(this).parent().parent();if(U.data("colorpicker").livePreview===true){e.apply(this)}},e=function(U){var V=b(this).parent().parent(),T;if(this.parentNode.className.indexOf("_hex")>0){V.data("colorpicker").color=T=m(y(this.value))}else{if(this.parentNode.className.indexOf("_hsb")>0){V.data("colorpicker").color=T=f({h:parseInt(V.data("colorpicker").fields.eq(4).val(),10),s:parseInt(V.data("colorpicker").fields.eq(5).val(),10),b:parseInt(V.data("colorpicker").fields.eq(6).val(),10)})}else{V.data("colorpicker").color=T=i(M({r:parseInt(V.data("colorpicker").fields.eq(1).val(),10),g:parseInt(V.data("colorpicker").fields.eq(2).val(),10),b:parseInt(V.data("colorpicker").fields.eq(3).val(),10)}))}}if(U){J(T,V.get(0));g(T,V.get(0));u(T,V.get(0))}l(T,V.get(0));G(T,V.get(0));E(T,V.get(0));V.data("colorpicker").onChange.apply(V,[T,R(T),j(T)])},o=function(T){var U=b(this).parent().parent();U.data("colorpicker").fields.parent().removeClass("colorpicker_focus")},K=function(){N=this.parentNode.className.indexOf("_hex")>0?70:65;b(this).parent().parent().data("colorpicker").fields.parent().removeClass("colorpicker_focus");b(this).parent().addClass("colorpicker_focus")},I=function(T){var V=b(this).parent().find("input").focus();var U={el:b(this).parent().addClass("colorpicker_slider"),max:this.parentNode.className.indexOf("_hsb_h")>0?360:(this.parentNode.className.indexOf("_hsb")>0?100:255),y:T.pageY,field:V,val:parseInt(V.val(),10),preview:b(this).parent().parent().data("colorpicker").livePreview};b(document).bind("mouseup",U,s);b(document).bind("mousemove",U,L)},L=function(T){T.data.field.val(Math.max(0,Math.min(T.data.max,parseInt(T.data.val+T.pageY-T.data.y,10))));if(T.data.preview){e.apply(T.data.field.get(0),[true])}return false},s=function(T){e.apply(T.data.field.get(0),[true]);T.data.el.removeClass("colorpicker_slider").find("input").focus();b(document).unbind("mouseup",s);b(document).unbind("mousemove",L);return false},w=function(T){var U={cal:b(this).parent(),y:b(this).offset().top};U.preview=U.cal.data("colorpicker").livePreview;b(document).bind("mouseup",U,r);b(document).bind("mousemove",U,k)},k=function(T){e.apply(T.data.cal.data("colorpicker").fields.eq(4).val(parseInt(360*(150-Math.max(0,Math.min(150,(T.pageY-T.data.y))))/150,10)).get(0),[T.data.preview]);return false},r=function(T){J(T.data.cal.data("colorpicker").color,T.data.cal.get(0));g(T.data.cal.data("colorpicker").color,T.data.cal.get(0));b(document).unbind("mouseup",r);b(document).unbind("mousemove",k);return false},x=function(T){var U={cal:b(this).parent(),pos:b(this).offset()};U.preview=U.cal.data("colorpicker").livePreview;b(document).bind("mouseup",U,A);b(document).bind("mousemove",U,q)},q=function(T){e.apply(T.data.cal.data("colorpicker").fields.eq(6).val(parseInt(100*(150-Math.max(0,Math.min(150,(T.pageY-T.data.pos.top))))/150,10)).end().eq(5).val(parseInt(100*(Math.max(0,Math.min(150,(T.pageX-T.data.pos.left))))/150,10)).get(0),[T.data.preview]);return false},A=function(T){J(T.data.cal.data("colorpicker").color,T.data.cal.get(0));g(T.data.cal.data("colorpicker").color,T.data.cal.get(0));b(document).unbind("mouseup",A);b(document).unbind("mousemove",q);return false},v=function(T){b(this).addClass("colorpicker_focus")},Q=function(T){b(this).removeClass("colorpicker_focus")},p=function(U){var V=b(this).parent();var T=V.data("colorpicker").color;V.data("colorpicker").origColor=T;h(T,V.get(0));V.data("colorpicker").onSubmit(T,R(T),j(T),V.data("colorpicker").el)},D=function(U){var Y=b("#"+b(this).data("colorpickerId"));Y.data("colorpicker").onBeforeShow.apply(this,[Y.get(0)]);var Z=b(this).offset();var X=z();var T=b("#tag-color").offset();var W=(T.top)+b("#tag-color").height();var V=(T.left+1);Y.css({left:V+"px",top:W+"px"});if(Y.data("colorpicker").onShow.apply(this,[Y.get(0)])!=false){Y.show()}b(document).bind("mousedown",{cal:Y},O);return false},O=function(T){if(!H(T.data.cal.get(0),T.target,T.data.cal.get(0))){if(T.data.cal.data("colorpicker").onHide.apply(this,[T.data.cal.get(0)])!=false){T.data.cal.hide()}b(document).unbind("mousedown",O)}},H=function(V,U,T){if(V==U){return true}if(V.contains){return V.contains(U)}if(V.compareDocumentPosition){return !!(V.compareDocumentPosition(U)&16)}var W=U.parentNode;while(W&&W!=T){if(W==V){return true}W=W.parentNode}return false},z=function(){var T=document.compatMode=="CSS1Compat";return{l:window.pageXOffset||(T?document.documentElement.scrollLeft:document.body.scrollLeft),t:window.pageYOffset||(T?document.documentElement.scrollTop:document.body.scrollTop),w:window.innerWidth||(T?document.documentElement.clientWidth:document.body.clientWidth),h:window.innerHeight||(T?document.documentElement.clientHeight:document.body.clientHeight)}},f=function(T){return{h:Math.min(360,Math.max(0,T.h)),s:Math.min(100,Math.max(0,T.s)),b:Math.min(100,Math.max(0,T.b))}},M=function(T){return{r:Math.min(255,Math.max(0,T.r)),g:Math.min(255,Math.max(0,T.g)),b:Math.min(255,Math.max(0,T.b))}},y=function(V){var T=6-V.length;if(T>0){var W=[];for(var U=0;U<T;U++){W.push("0")}W.push(V);V=W.join("")}return V},d=function(T){var T=parseInt(((T.indexOf("#")>-1)?T.substring(1):T),16);return{r:T>>16,g:(T&65280)>>8,b:(T&255)}},m=function(T){return i(d(T))},i=function(V){var U={h:0,s:0,b:0};var W=Math.min(V.r,V.g,V.b);var T=Math.max(V.r,V.g,V.b);var X=T-W;U.b=T;if(T!=0){}U.s=T!=0?255*X/T:0;if(U.s!=0){if(V.r==T){U.h=(V.g-V.b)/X}else{if(V.g==T){U.h=2+(V.b-V.r)/X}else{U.h=4+(V.r-V.g)/X}}}else{U.h=-1}U.h*=60;if(U.h<0){U.h+=360}U.s*=100/255;U.b*=100/255;return U},j=function(T){var V={};var Z=Math.round(T.h);var Y=Math.round(T.s*255/100);var U=Math.round(T.b*255/100);if(Y==0){V.r=V.g=V.b=U}else{var aa=U;var X=(255-Y)*U/255;var W=(aa-X)*(Z%60)/60;if(Z==360){Z=0}if(Z<60){V.r=aa;V.b=X;V.g=X+W}else{if(Z<120){V.g=aa;V.b=X;V.r=aa-W}else{if(Z<180){V.g=aa;V.r=X;V.b=X+W}else{if(Z<240){V.b=aa;V.r=X;V.g=aa-W}else{if(Z<300){V.b=aa;V.g=X;V.r=X+W}else{if(Z<360){V.r=aa;V.g=X;V.b=aa-W}else{V.r=0;V.g=0;V.b=0}}}}}}}return{r:Math.round(V.r),g:Math.round(V.g),b:Math.round(V.b)}},C=function(T){var U=[T.r.toString(16),T.g.toString(16),T.b.toString(16)];b.each(U,function(V,W){if(W.length==1){U[V]="0"+W}});return U.join("")},R=function(T){return C(j(T))},F=function(){var U=b(this).parent();var T=U.data("colorpicker").origColor;U.data("colorpicker").color=T;J(T,U.get(0));g(T,U.get(0));u(T,U.get(0));l(T,U.get(0));G(T,U.get(0));E(T,U.get(0))};return{init:function(T){T=b.extend({},B,T||{});if(typeof T.color=="string"){T.color=m(T.color)}else{if(T.color.r!=undefined&&T.color.g!=undefined&&T.color.b!=undefined){T.color=i(T.color)}else{if(T.color.h!=undefined&&T.color.s!=undefined&&T.color.b!=undefined){T.color=f(T.color)}else{return this}}}return this.each(function(){if(!b(this).data("colorpickerId")){var U=b.extend({},T);U.origColor=T.color;var W="collorpicker_"+parseInt(Math.random()*1000);b(this).data("colorpickerId",W);var V=b(P).attr("id",W);if(U.flat){V.appendTo(this).show()}else{V.appendTo(document.body)}U.fields=V.find("input").bind("keyup",n).bind("change",e).bind("blur",o).bind("focus",K);V.find("span").bind("mousedown",I).end().find(">div.colorpicker_current_color").bind("click",F);U.selector=V.find("div.colorpicker_color").bind("mousedown",x);U.selectorIndic=U.selector.find("div div");U.el=this;U.hue=V.find("div.colorpicker_hue div");V.find("div.colorpicker_hue").bind("mousedown",w);U.newColor=V.find("div.colorpicker_new_color");U.currentColor=V.find("div.colorpicker_current_color");V.data("colorpicker",U);V.find("div.colorpicker_submit").bind("mouseenter",v).bind("mouseleave",Q).bind("click",p);J(U.color,V.get(0));u(U.color,V.get(0));g(U.color,V.get(0));G(U.color,V.get(0));l(U.color,V.get(0));h(U.color,V.get(0));E(U.color,V.get(0));if(U.flat){V.css({position:"relative",display:"block"})}else{b(this).bind(U.eventName,D)}}})},showPicker:function(){return this.each(function(){if(b(this).data("colorpickerId")){D.apply(this)}})},hidePicker:function(){return this.each(function(){if(b(this).data("colorpickerId")){b("#"+b(this).data("colorpickerId")).hide()}})},setColor:function(T){if(typeof T=="string"){T=m(T)}else{if(T.r!=undefined&&T.g!=undefined&&T.b!=undefined){T=i(T)}else{if(T.h!=undefined&&T.s!=undefined&&T.b!=undefined){T=f(T)}else{return this}}}return this.each(function(){if(b(this).data("colorpickerId")){var U=b("#"+b(this).data("colorpickerId"));U.data("colorpicker").color=T;U.data("colorpicker").origColor=T;J(T,U.get(0));u(T,U.get(0));g(T,U.get(0));G(T,U.get(0));l(T,U.get(0));h(T,U.get(0));E(T,U.get(0))}})}}}();b.fn.extend({ColorPicker:a.init,ColorPickerHide:a.hidePicker,ColorPickerShow:a.showPicker,ColorPickerSetColor:a.setColor})})(jQuery);jQuery(function(e){e("#tag-color").click(function(){var g=e("#tag-color").offset();var k=g.top+e("#tag-color").height();var j=g.left+1;var i=e("<ul></ul>");var h=e('<li style="color: #60a;" class="color-1"></li><li style="color: #807;" class="color-2"></li><li style="color: #920;" class="color-3"></li><li style="color: #a60;" class="color-4"></li><li style="color: #990;" class="color-5"></li><li style="color: #080;" class="color-6"></li><li style="color: #077;" class="color-7"></li><li style="color: #00a;" class="color-8"></li><li style="color: #000;" class="color-9"></li><li style="color: #444;" class="color-10"></li><li style="color: #85e;" class="color-11"></li><li style="color: #d5d;" class="color-12"></li><li style="color: #d43;" class="color-13"></li><li style="color: #d90;" class="color-14"></li><li style="color: #bb0;" class="color-15"></li><li style="color: #2b0;" class="color-16"></li><li style="color: #0ba;" class="color-17"></li><li style="color: #26d;" class="color-18"></li><li style="color: #777;" class="color-19"></li><li style="color: #aaa;" class="color-20"></li>');var f=e('<li class="select-more-colors">More colors</li>');e(f).ColorPicker({onSubmit:function(l,o,m,n){e("#tag-color-background").css("background-color","#"+o);e("#tag-color-value").val("#"+o);e(n).ColorPickerHide();i.remove()},onBeforeShow:function(){i.hide();e(document).unbind("mousedown",a);var l=e("#tag-color-value").val();l=l.length>0?l:"#ffffff";e(this).ColorPickerSetColor(l)}});h.click(function(){e("#tag-color-background").css("background-color",e(this).css("color"));e("#tag-color-value").val(c(e(this).css("color")));i.remove()});i.append(h).append(f);i.appendTo("body").css({position:"absolute",top:k+"px",left:j+"px",width:"75px",height:"85px","z-index":1,background:"#fff",border:"1px solid #ccc"}).addClass("colorpicker-list");e(document).bind("mousedown",{ls:i},a)});var c=function(f){f=f.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);return"#"+d(f[1])+d(f[2])+d(f[3])};var d=function(f){return("0"+parseInt(f).toString(16)).slice(-2)};var a=function(f){if(!b(f.data.ls.get(0),f.target,f.data.ls.get(0))){e(f.data.ls.get(0)).remove();e(document).unbind("mousedown",a)}};var b=function(h,g,f){if(h==g){return true}if(h.contains){return h.contains(g)}if(h.compareDocumentPosition){return !!(h.compareDocumentPosition(g)&16)}var i=g.parentNode;while(i&&i!=f){if(i==h){return true}i=i.parentNode}return false}});
|
js/element-selector.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
function element_selector(a,c,g,b){var f=jQuery;f(a).click(function(){var h=new Array();if(f(this).hasClass(c)){f(this).removeClass(c)}else{f(this).addClass(c)}f(a+"."+c).each(function(){var i=f(this).find('input[name="'+g+'"]:first').val();h.push(i)});f(b).val(h.join())});var d=f(b).val();if(d!=undefined&&d!=""){var e=d.split(",");f(e).each(function(h,j){e[h]='input[name="'+g+'"][value="'+j+'"]'});e=e.join();f(a).has(e).addClass(c)}};
|
js/event.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
function ai1ec_load_map(){var b={zoom:14,mapTypeId:google.maps.MapTypeId.ROADMAP};var d=new google.maps.Map(document.getElementById("ai1ec-gmap-canvas"),b);var a=new google.maps.Marker({map:d});var c=new google.maps.Geocoder();c.geocode({address:document.getElementById("ai1ec-gmap-address").value,},function(f,e){if(e==google.maps.GeocoderStatus.OK){d.setCenter(f[0].geometry.location);a.setPosition(f[0].geometry.location)}})}var orig_onload=window.onload;window.onload=function(){if(typeof(orig_onload)=="function"){orig_onload()}if(document.getElementById("ai1ec-gmap-canvas")){var a=document.createElement("script");a.type="text/javascript";a.src="http://maps.google.com/maps/api/js?sensor=false&callback=ai1ec_load_map";document.body.appendChild(a)}};
|
js/geo_autocomplete.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(function(a){a.fn.extend({geo_autocomplete:function(c,b){options=a.extend({},a.Autocompleter.defaults,{geocoder:c,mapwidth:100,mapheight:100,maptype:"terrain",mapkey:"ABQIAAAAbnvDoAoYOSW2iqoXiGTpYBT2yXp_ZAY8_ufC3CFXhHIE1NvwkxQNumU68AwGqjbSNF9YO8NokKst8w",mapsensor:false,parse:function(d,f,e){var g=[];if(d&&f&&f=="OK"){a.each(d,function(j,i){if(i.geometry&&i.geometry.viewport){var h=i.formatted_address.split(",");var k=h[0];a.each(h,function(m,l){if(l.toLowerCase().indexOf(e.toLowerCase())!=-1){k=a.trim(l);return false}});g.push({data:i,value:k,result:k})}})}return g},formatItem:function(f,h,e,d){var i="http://maps.google.com/maps/api/staticmap?visible="+f.geometry.viewport.getSouthWest().toUrlValue()+"|"+f.geometry.viewport.getNorthEast().toUrlValue()+"&size="+options.mapwidth+"x"+options.mapheight+"&maptype="+options.maptype+"&key="+options.mapkey+"&sensor="+(options.mapsensor?"true":"false");var g=f.formatted_address.replace(/,/gi,",<br/>");return'<img src="'+i+'" width="'+options.mapwidth+'" height="'+options.mapheight+'" /> '+g+'<br clear="both"/>'}},b);options.highlight=options.highlight||function(d){return d};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new a.Autocompleter(this,options)})}})})(jQuery);
|
js/jquery.autocomplete_geomod.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(function(a){a.fn.extend({autocomplete:function(b,c){var d=typeof b=="string";c=a.extend({},a.Autocompleter.defaults,{url:d?b:null,data:d?null:b,delay:d?a.Autocompleter.defaults.delay:10,max:c&&!c.scroll?10:150},c);c.highlight=c.highlight||function(e){return e};c.formatMatch=c.formatMatch||c.formatItem;return this.each(function(){new a.Autocompleter(this,c)})},result:function(b){return this.bind("result",b)},search:function(b){return this.trigger("search",[b])},flushCache:function(){return this.trigger("flushCache")},setOptions:function(b){return this.trigger("setOptions",[b])},unautocomplete:function(){return this.trigger("unautocomplete")}});a.Autocompleter=function(l,g){var c={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var b=a(l).attr("autocomplete","off").addClass(g.inputClass);var j;var p="";var m=a.Autocompleter.Cache(g);var e=0;var u;var x={mouseDownOnSelect:false};var r=a.Autocompleter.Select(g,l,d,x);var w;a.browser.opera&&a(l.form).bind("submit.autocomplete",function(){if(w){w=false;return false}});b.bind((a.browser.opera?"keypress":"keydown")+".autocomplete",function(y){e=1;u=y.keyCode;switch(y.keyCode){case c.UP:y.preventDefault();if(r.visible()){r.prev()}else{t(0,true)}break;case c.DOWN:y.preventDefault();if(r.visible()){r.next()}else{t(0,true)}break;case c.PAGEUP:y.preventDefault();if(r.visible()){r.pageUp()}else{t(0,true)}break;case c.PAGEDOWN:y.preventDefault();if(r.visible()){r.pageDown()}else{t(0,true)}break;case g.multiple&&a.trim(g.multipleSeparator)==","&&c.COMMA:case c.TAB:case c.RETURN:if(d()){y.preventDefault();w=true;return false}break;case c.ESC:r.hide();break;default:clearTimeout(j);j=setTimeout(t,g.delay);break}}).focus(function(){e++}).blur(function(){e=0;if(!x.mouseDownOnSelect){s()}}).click(function(){if(e++>1&&!r.visible()){t(0,true)}}).bind("search",function(){var y=(arguments.length>1)?arguments[1]:null;function z(D,C){var A;if(C&&C.length){for(var B=0;B<C.length;B++){if(C[B].result.toLowerCase()==D.toLowerCase()){A=C[B];break}}}if(typeof y=="function"){y(A)}else{b.trigger("result",A&&[A.data,A.value])}}a.each(h(b.val()),function(A,B){f(B,z,z)})}).bind("flushCache",function(){m.flush()}).bind("setOptions",function(){a.extend(g,arguments[1]);if("data" in arguments[1]){m.populate()}}).bind("unautocomplete",function(){r.unbind();b.unbind();a(l.form).unbind(".autocomplete")});function d(){var B=r.selected();if(!B){return false}var y=B.result;p=y;if(g.multiple){var E=h(b.val());if(E.length>1){var A=g.multipleSeparator.length;var D=a(l).selection().start;var C,z=0;a.each(E,function(F,G){z+=G.length;if(D<=z){C=F;return false}z+=A});E[C]=y;y=E.join(g.multipleSeparator)}y+=g.multipleSeparator}b.val(y);v();b.trigger("result",[B.data,B.value]);return true}function t(A,z){if(u==c.DEL){r.hide();return}var y=b.val();if(!z&&y==p){return}p=y;y=i(y);if(y.length>=g.minChars){b.addClass(g.loadingClass);if(!g.matchCase){y=y.toLowerCase()}f(y,k,v)}else{n();r.hide()}}function h(y){if(!y){return[""]}if(!g.multiple){return[a.trim(y)]}return a.map(y.split(g.multipleSeparator),function(z){return a.trim(y).length?a.trim(z):null})}function i(y){if(!g.multiple){return y}var A=h(y);if(A.length==1){return A[0]}var z=a(l).selection().start;if(z==y.length){A=h(y)}else{A=h(y.replace(y.substring(z),""))}return A[A.length-1]}function q(y,z){if(g.autoFill&&(i(b.val()).toLowerCase()==y.toLowerCase())&&u!=c.BACKSPACE){b.val(b.val()+z.substring(i(p).length));a(l).selection(p.length,p.length+z.length)}}function s(){clearTimeout(j);j=setTimeout(v,200)}function v(){var y=r.visible();r.hide();clearTimeout(j);n();if(g.mustMatch){b.search(function(z){if(!z){if(g.multiple){var A=h(b.val()).slice(0,-1);b.val(A.join(g.multipleSeparator)+(A.length?g.multipleSeparator:""))}else{b.val("");b.trigger("result",null)}}})}}function k(z,y){if(y&&y.length&&e){n();r.display(y,z);q(z,y[0].value);r.show()}else{v()}}function f(A,C,z){if(!g.matchCase){A=A.toLowerCase()}var B=m.load(A);if(B&&B.length){C(A,B)}else{if(g.geocoder){var y=i(A);g.geocoder.geocode({address:y},function(E,G){var F=g.parse(E,G,y);m.add(A,F);C(A,F)})}else{if((typeof g.url=="string")&&(g.url.length>0)){var D={timestamp:+new Date()};a.each(g.extraParams,function(E,F){D[E]=typeof F=="function"?F():F});a.ajax({mode:"abort",port:"autocomplete"+l.name,dataType:g.dataType,url:g.url,data:a.extend({q:i(A),limit:g.max},D),success:function(F){var E=g.parse&&g.parse(F)||o(F);m.add(A,E);C(A,E)}})}else{r.emptyList();z(A)}}}}function o(B){var y=[];var A=B.split("\n");for(var z=0;z<A.length;z++){var C=a.trim(A[z]);if(C){C=C.split("|");y[y.length]={data:C,value:C[0],result:g.formatResult&&g.formatResult(C,C[0])||C[0]}}}return y}function n(){b.removeClass(g.loadingClass)}};a.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(b){return b[0]},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(c,b){return c.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+b.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>")},scroll:true,scrollHeight:180};a.Autocompleter.Cache=function(c){var f={};var d=0;function h(l,k){if(!c.matchCase){l=l.toLowerCase()}var j=l.indexOf(k);if(c.matchContains=="word"){j=l.toLowerCase().search("\\b"+k.toLowerCase())}if(j==-1){return false}return j==0||c.matchContains}function g(j,i){if(d>c.cacheLength){b()}if(!f[j]){d++}f[j]=i}function e(){if(!c.data){return false}var k={},j=0;if(!c.url){c.cacheLength=1}k[""]=[];for(var m=0,l=c.data.length;m<l;m++){var p=c.data[m];p=(typeof p=="string")?[p]:p;var o=c.formatMatch(p,m+1,c.data.length);if(o===false){continue}var n=o.charAt(0).toLowerCase();if(!k[n]){k[n]=[]}var q={value:o,data:p,result:c.formatResult&&c.formatResult(p)||o};k[n].push(q);if(j++<c.max){k[""].push(q)}}a.each(k,function(r,s){c.cacheLength++;g(r,s)})}setTimeout(e,25);function b(){f={};d=0}return{flush:b,add:g,populate:e,load:function(n){if(!c.cacheLength||!d){return null}if(!c.url&&c.matchContains){var m=[];for(var j in f){if(j.length>0){var o=f[j];a.each(o,function(p,k){if(h(k.value,n)){m.push(k)}})}}return m}else{if(f[n]){return f[n]}else{if(c.matchSubset){for(var l=n.length-1;l>=c.minChars;l--){var o=f[n.substr(0,l)];if(o){var m=[];a.each(o,function(p,k){if(h(k.value,n)){m[m.length]=k}});return m}}}}}return null}}};a.Autocompleter.Select=function(e,j,l,p){var i={ACTIVE:"ac_over"};var k,f=-1,r,m="",s=true,c,o;function n(){if(!s){return}c=a("<div/>").hide().addClass(e.resultsClass).css("position","absolute").appendTo(document.body);o=a("<ul/>").appendTo(c).mouseover(function(t){if(q(t).nodeName&&q(t).nodeName.toUpperCase()=="LI"){f=a("li",o).removeClass(i.ACTIVE).index(q(t));a(q(t)).addClass(i.ACTIVE)}}).click(function(t){a(q(t)).addClass(i.ACTIVE);l();j.focus();return false}).mousedown(function(){p.mouseDownOnSelect=true}).mouseup(function(){p.mouseDownOnSelect=false});if(e.width>0){c.css("width",e.width)}s=false}function q(u){var t=u.target;while(t&&t.tagName!="LI"){t=t.parentNode}if(!t){return[]}return t}function h(t){k.slice(f,f+1).removeClass(i.ACTIVE);g(t);var v=k.slice(f,f+1).addClass(i.ACTIVE);if(e.scroll){var u=0;k.slice(0,f).each(function(){u+=this.offsetHeight});if((u+v[0].offsetHeight-o.scrollTop())>o[0].clientHeight){o.scrollTop(u+v[0].offsetHeight-o.innerHeight())}else{if(u<o.scrollTop()){o.scrollTop(u)}}}}function g(t){f+=t;if(f<0){f=k.size()-1}else{if(f>=k.size()){f=0}}}function b(t){return e.max&&e.max<t?e.max:t}function d(){o.empty();var u=b(r.length);for(var v=0;v<u;v++){if(!r[v]){continue}var w=e.formatItem(r[v].data,v+1,u,r[v].value,m);if(w===false){continue}var t=a("<li/>").html(e.highlight(w,m)).addClass(v%2==0?"ac_even":"ac_odd").appendTo(o)[0];a.data(t,"ac_data",r[v])}k=o.find("li");if(e.selectFirst){k.slice(0,1).addClass(i.ACTIVE);f=0}if(a.fn.bgiframe){o.bgiframe()}}return{display:function(u,t){n();r=u;m=t;d()},next:function(){h(1)},prev:function(){h(-1)},pageUp:function(){if(f!=0&&f-8<0){h(-f)}else{h(-8)}},pageDown:function(){if(f!=k.size()-1&&f+8>k.size()){h(k.size()-1-f)}else{h(8)}},hide:function(){c&&c.hide();k&&k.removeClass(i.ACTIVE);f=-1},visible:function(){return c&&c.is(":visible")},current:function(){return this.visible()&&(k.filter("."+i.ACTIVE)[0]||e.selectFirst&&k[0])},show:function(){var v=a(j).offset();c.css({width:typeof e.width=="string"||e.width>0?e.width:a(j).width(),top:v.top+j.offsetHeight,left:v.left}).show();if(e.scroll){o.scrollTop(0);o.css({maxHeight:e.scrollHeight,overflow:"auto"});if(a.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var t=0;k.each(function(){t+=this.offsetHeight});var u=t>e.scrollHeight;o.css("height",u?e.scrollHeight:t);if(!u){k.width(o.width()-parseInt(k.css("padding-left"))-parseInt(k.css("padding-right")))}}}},selected:function(){var t=k&&k.filter("."+i.ACTIVE).removeClass(i.ACTIVE);return t&&t.length&&a.data(t[0],"ac_data")},emptyList:function(){o&&o.empty()},unbind:function(){c&&c.remove()}}};a.fn.selection=function(i,b){if(i!==undefined){return this.each(function(){if(this.createTextRange){var j=this.createTextRange();if(b===undefined||i==b){j.move("character",i);j.select()}else{j.collapse(true);j.moveStart("character",i);j.moveEnd("character",b);j.select()}}else{if(this.setSelectionRange){this.setSelectionRange(i,b)}else{if(this.selectionStart){this.selectionStart=i;this.selectionEnd=b}}}})}var g=this[0];if(g.createTextRange){var c=document.selection.createRange(),h=g.value,f="<->",d=c.text.length;c.text=f;var e=g.value.indexOf(f);g.value=h;this.selection(e,e+d);return{start:e,end:e+d}}else{if(g.selectionStart!==undefined){return{start:g.selectionStart,end:g.selectionEnd}}}}})(jQuery);
|
js/jquery.calendrical.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
function formatDate(b,c){return(c?((b.getUTCMonth()+1)+"/"+b.getUTCDate()):(b.getUTCDate()+"/"+(b.getUTCMonth()+1)))+"/"+b.getUTCFullYear()}function formatTime(b,g,e){var d=g;if(g<10){d="0"+g}if(e){var c=b;if(c<10){c="0"+b}return c+":"+d}else{var c=b%12;if(c==0){c=12}var f=(b<12)?"am":"pm";return c+":"+d+f}}function parseDate(c,d){c+=" GMT";if(d){return new Date(c)}a=c.split(/[\.\-\/]/);var b=a.shift();var e=a.shift();a.unshift(b);a.unshift(e);return new Date(a.join("/"))}function parseTime(e){var c=c=/(\d+)\s*[:\-\.,]\s*(\d+)\s*(am|pm)?/i.exec(e);if(c&&c.length>=3){var b=Number(c[1]);var d=Number(c[2]);if(b==12&&c[3]){b-=12}if(c[3]&&c[3].toLowerCase()=="pm"){b+=12}return{hour:b,minute:d}}else{return null}}(function(h){var i=["January","February","March","April","May","June","July","August","September","October","November","December"];function e(){var m=new Date();return new Date(m.getFullYear(),m.getMonth(),m.getDate())}function b(n,m){return String(n)==String(m)}function c(m,n){if(m instanceof Date){return c(m.getUTCFullYear(),m.getUTCMonth())}if(n==1){var o=(m%4==0)&&(!(m%100==0)||(m%400==0));return o?29:28}else{if(n==3||n==5||n==8||n==10){return 30}else{return 31}}}function k(m){return new Date(m.getTime()+(1*24*60*60*1000))}function f(m){return new Date(m.getTime()-(1*24*60*60*1000))}function l(m,n){return(n==11)?new Date(m+1,0,1):new Date(m,n+1,1)}function j(n,o,r,m){var q=h("<thead />");var p=h("<tr />").appendTo(q);h("<th />").addClass("monthCell").append(h('<a href="javascript:;">«</a>').addClass("prevMonth").mousedown(function(t){g(n,r==0?(o-1):o,r==0?11:(r-1),m);t.preventDefault()})).appendTo(p);h("<th />").addClass("monthCell").attr("colSpan",5).append(h('<a href="javascript:;">'+i[r]+" "+o+"</a>").addClass("monthName")).appendTo(p);h("<th />").addClass("monthCell").append(h('<a href="javascript:;">»</a>').addClass("nextMonth").mousedown(function(){g(n,r==11?(o+1):o,r==11?0:(r+1),m)})).appendTo(p);var s=h("<tr />").appendTo(q);h.each(String("SMTWTFS").split(""),function(u,t){h("<td />").addClass("dayName").append(t).appendTo(s)});return q}function g(t,x,w,B){B=B||{};var y=B.today?B.today:e();var o=new Date(x,w,1);var u=l(x,w);var m=6-u.getUTCDay();if(m<6){m+=7}for(var s=0;s<m;s++){u=k(u)}var z=h("<table />");j(t,x,w,B).appendTo(z);var r=h("<tbody />").appendTo(z);var A=h("<tr />");var q=o.getUTCDay()+7;for(var s=0;s<q;s++){o=f(o)}while(o<=u){var p=h("<td />").addClass("day").append(h('<a href="javascript:;">'+o.getUTCDate()+"</a>").click((function(){var C=o;return function(){if(B&&B.selectDate){B.selectDate(C)}}}()))).appendTo(A);var v=b(o,y);var n=B.selected&&b(B.selected,o);if(v){p.addClass("today")}if(n){p.addClass("selected")}if(v&&n){p.addClass("today_selected")}if(o.getUTCMonth()!=w){p.addClass("nonMonth")}dow=o.getUTCDay();if(dow==6){r.append(A);A=h("<tr />")}o=k(o)}if(A.children().length){r.append(A)}else{A.remove()}t.empty().append(z)}function d(q,o){var s=o.selection&&parseTime(o.selection);if(s){s.minute=Math.floor(s.minute/15)*15}var r=o.startTime&&(o.startTime.hour*60+o.startTime.minute);var n;var p=h("<ul />");for(var m=0;m<24;m++){for(var t=0;t<60;t+=15){if(r&&r>(m*60+t)){continue}(function(){var v=formatTime(m,t,o.isoTime);var w=v;if(r!=null){var x=(m*60+t)-r;if(x<60){w+=" ("+x+" min)"}else{if(x==60){w+=" (1 hr)"}else{w+=" ("+Math.round(x/60)+" hr "+(x%60)+" min)"}}}var u=h("<li />").append(h('<a href="javascript:;">'+w+"</a>").click(function(){if(o&&o.selectTime){o.selectTime(v)}}).mousemove(function(){h("li.selected",p).removeClass("selected")})).appendTo(p);if(!n&&m==o.defaultHour){n=u}if(s&&s.hour==m&&s.minute==t){u.addClass("selected");n=u}})()}}if(n){setTimeout(function(){q[0].scrollTop=n[0].offsetTop-n.height()*2},0)}q.empty().append(p)}h.fn.calendricalDate=function(m){m=m||{};m.padding=m.padding||4;return this.each(function(){var o=h(this);var p;var n=false;o.bind("focus",function(){if(p){return}var s=o.position();var r=o.css("padding-left");p=h("<div />").addClass("calendricalDatePopup").mouseenter(function(){n=true}).mouseleave(function(){n=false}).mousedown(function(t){t.preventDefault()}).css({position:"absolute",left:s.left,top:s.top+o.height()+m.padding*2});o.after(p);var q=parseDate(o.val(),m.usa);if(!q.getUTCFullYear()){q=m.today?m.today:e()}g(p,q.getUTCFullYear(),q.getUTCMonth(),{today:m.today,selected:q,selectDate:function(t){n=false;o.val(formatDate(t,m.usa));p.remove();p=null;if(m.endDate){var u=parseDate(m.endDate.val(),m.usa);if(u>=q){m.endDate.val(formatDate(new Date(t.getTime()+u.getTime()-q.getTime()),m.usa))}}}})}).blur(function(){if(n){if(p){o.focus()}return}if(!p){return}p.remove();p=null})})};h.fn.calendricalDateRange=function(m){if(this.length>=2){h(this[0]).calendricalDate(h.extend({endDate:h(this[1])},m));h(this[1]).calendricalDate(m)}return this};h.fn.calendricalDateRangeSingle=function(m){if(this.length==1){h(this).calendricalDate(m)}return this};h.fn.calendricalTime=function(m){m=m||{};m.padding=m.padding||4;return this.each(function(){var o=h(this);var p;var n=false;o.bind("focus click",function(){if(p){return}var q=m.startTime;if(q){if(m.startDate&&m.endDate&&!b(parseDate(m.startDate.val()),parseDate(m.endDate.val()))){q=false}}var s=o.position();p=h("<div />").addClass("calendricalTimePopup").mouseenter(function(){n=true}).mouseleave(function(){n=false}).mousedown(function(t){t.preventDefault()}).css({position:"absolute",left:s.left,top:s.top+o.height()+m.padding*2});if(q){p.addClass("calendricalEndTimePopup")}o.after(p);var r={selection:o.val(),selectTime:function(t){n=false;o.val(t);p.remove();p=null},isoTime:m.isoTime||false,defaultHour:(m.defaultHour!=null)?m.defaultHour:8};if(q){r.startTime=parseTime(m.startTime.val())}d(p,r)}).blur(function(){if(n){if(p){o.focus()}return}if(!p){return}p.remove();p=null})})},h.fn.calendricalTimeRange=function(m){if(this.length>=2){h(this[0]).calendricalTime(m);h(this[1]).calendricalTime(h.extend({startTime:h(this[0])},m))}return this};h.fn.calendricalDateTimeRange=function(m){if(this.length>=4){h(this[0]).calendricalDate(h.extend({endDate:h(this[2])},m));h(this[1]).calendricalTime(m);h(this[2]).calendricalDate(m);h(this[3]).calendricalTime(h.extend({startTime:h(this[1]),startDate:h(this[0]),endDate:h(this[2])},m))}return this}})(jQuery);
|
js/jquery.inputdate.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(function(d){function a(g){g.addClass("error").fadeOut("normal",function(){g.val(g.data("timespan.stored")).removeClass("error").fadeIn("fast")})}function e(){d(this).data("timespan.stored",this.value)}function c(h,i,j,g){i.val(i.data("timespan.initial_value"));var k=parseInt(i.val());if(!isNaN(parseInt(k))){k=new Date(parseInt(k)*1000)}else{k=new Date(g)}h.val(formatDate(k,false));h.each(e)}var f={start_date_input:"date-input",start_time:"time",twentyfour_hour:false,now:new Date()};var b={init:function(i){var l=d.extend({},f,i);var j=d(l.start_date_input);var k=d(l.start_time);var h=j;var g=j;g.bind("focus.timespan",e);h.calendricalDate({today:new Date(l.now.getFullYear(),l.now.getMonth(),l.now.getDate())});h.bind("blur.timespan",function(){var m=parseDate(this.value,false);if(isNaN(m)){a(d(this))}else{d(this).data("timespan.stored",this.value);d(this).val(formatDate(m,false))}});j.bind("focus.timespan",function(){var m=parseDate(j.val(),false).getTime()/1000}).bind("blur.timespan",function(){var m=parseDate(j.data("timespan.stored"),false)});j.closest("form").bind("submit.timespan",function(){var m=parseDate(j.val(),false).getTime()/1000;if(isNaN(m)){m=""}k.val(m)});k.data("timespan.initial_value",k.val());c(j,k,l.twentyfour_hour,l.now);return this},reset:function(g){var h=d.extend({},f,g);c(d(h.start_date_input),d(h.start_time),h.twentyfour_hour,h.now);return this},destroy:function(g){g=d.extend({},f,g);d.each(g,function(i,h){d(h).unbind(".timespan")});d(g.start_date_input).closest("form").unbind(".timespan");return this}};d.inputdate=function(g){if(b[g]){return b[g].apply(this,Array.prototype.slice.call(arguments,1))}else{if(typeof g==="object"||!g){return b.init.apply(this,arguments)}else{d.error("Method "+g+" does not exist on jQuery.timespan")}}}})(jQuery);
|
js/jquery.scrollTo-min.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(function(c){var a=c.scrollTo=function(d,f,g){c(window).scrollTo(d,f,g)};a.defaults={axis:"xy",duration:parseFloat(c.fn.jquery)>=1.3?0:1};a.window=function(d){return c(window)._scrollable()};c.fn._scrollable=function(){return this.map(function(){var d=this,f=!d.nodeName||c.inArray(d.nodeName.toLowerCase(),["iframe","#document","html","body"])!=-1;if(!f){return d}var g=(d.contentWindow||d).document||d.ownerDocument||d;return c.browser.safari||g.compatMode=="BackCompat"?g.body:g.documentElement})};c.fn.scrollTo=function(f,e,d){if(typeof e=="object"){d=e;e=0}if(typeof d=="function"){d={onAfter:d}}if(f=="max"){f=9000000000}d=c.extend({},a.defaults,d);e=e||d.speed||d.duration;d.queue=d.queue&&d.axis.length>1;if(d.queue){e/=2}d.offset=b(d.offset);d.over=b(d.over);return this._scrollable().each(function(){var n=this,l=c(n),m=f,j,k={},h=l.is("html,body");switch(typeof m){case"number":case"string":if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(m)){m=b(m);break}m=c(m,this);case"object":if(m.is||m.style){j=(m=c(m)).offset()}}c.each(d.axis.split(""),function(q,r){var t=r=="x"?"Left":"Top",s=t.toLowerCase(),v="scroll"+t,p=n[v],g=a.max(n,r);if(j){k[v]=j[s]+(h?0:p-l.offset()[s]);if(d.margin){k[v]-=parseInt(m.css("margin"+t))||0;k[v]-=parseInt(m.css("border"+t+"Width"))||0}k[v]+=d.offset[s]||0;if(d.over[s]){k[v]+=m[r=="x"?"width":"height"]()*d.over[s]}}else{var u=m[s];k[v]=u.slice&&u.slice(-1)=="%"?parseFloat(u)/100*g:u}if(/^\d+$/.test(k[v])){k[v]=k[v]<=0?0:Math.min(k[v],g)}if(!q&&d.queue){if(p!=k[v]){i(d.onAfterFirst)}delete k[v]}});i(d.onAfter);function i(g){l.animate(k,e,d.easing,g&&function(){g.call(this,f,d)})}}).end()};a.max=function(g,j){var n=j=="x"?"Width":"Height",k="scroll"+n;if(!c(g).is("html,body")){return g[k]-c(g)[n.toLowerCase()]()}var o="client"+n,f=g.ownerDocument.documentElement,d=g.ownerDocument.body;return Math.max(f[k],d[k])-Math.min(f[o],d[o])};function b(d){return typeof d=="object"?d:{top:d,left:d}}})(jQuery);
|
js/jquery.timespan.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
(function(d){function a(g){g.addClass("error").fadeOut("normal",function(){g.val(g.data("timespan.stored")).removeClass("error").fadeIn("fast")})}function e(){d(this).data("timespan.stored",this.value)}function c(l,p,o,j,n,i,q,m,h){o.val(o.data("timespan.initial_value"));i.val(i.data("timespan.initial_value"));q.get(0).checked=q.data("timespan.initial_value");var g=parseInt(o.val());if(!isNaN(parseInt(g))){g=new Date(parseInt(g)*1000);p.val(formatTime(g.getUTCHours(),g.getUTCMinutes(),m))}else{g=new Date(h);p.val(formatTime(g.getUTCHours(),g.getUTCMinutes()-g.getUTCMinutes()%15,m))}l.val(formatDate(g,false));var k=parseInt(i.val());if(!isNaN(parseInt(k))){k=new Date(parseInt(k)*1000);n.val(formatTime(k.getUTCHours(),k.getUTCMinutes(),m))}else{k=new Date(g.getTime()+3600000);n.val(formatTime(k.getUTCHours(),k.getUTCMinutes()-k.getUTCMinutes()%15,m))}if(q.get(0).checked){k.setUTCDate(k.getUTCDate()-1)}j.val(formatDate(k,false));l.each(e);p.each(e);j.each(e);n.each(e);q.trigger("change.timespan")}var f={allday:"#allday",start_date_input:"#start-date-input",start_time_input:"#start-time-input",start_time:"#start-time",end_date_input:"#end-date-input",end_time_input:"#end-time-input",end_time:"#end-time",twentyfour_hour:false,now:new Date(),};var b={init:function(t){var h=d.extend({},f,t);var s=d(h.allday);var k=d(h.start_date_input);var p=d(h.start_time_input);var m=d(h.start_time);var j=d(h.end_date_input);var l=d(h.end_time_input);var g=d(h.end_time);var q=k.add(h.end_date_input);var r=p.add(h.end_time_input);var i=k.add(h.start_time_input).add(h.end_date_input).add(h.end_time_input);i.bind("focus.timespan",e);var n=new Date(h.now.getFullYear(),h.now.getMonth(),h.now.getDate());s.bind("change.timespan",function(){if(this.checked){r.fadeOut();q.calendricalDateRange({today:n})}else{r.fadeIn();i.calendricalDateTimeRange({today:n})}}).get().checked=false;q.bind("blur.timespan",function(){var o=parseDate(this.value,false);if(isNaN(o)){a(d(this))}else{d(this).data("timespan.stored",this.value);d(this).val(formatDate(o,false))}});r.bind("blur.timespan",function(){var o=parseTime(this.value);if(!o){a(d(this))}else{d(this).data("timespan.stored",this.value);d(this).val(formatTime(o.hour,o.minute,false))}});k.add(h.start_time_input).bind("focus.timespan",function(){var o=parseDate(k.val(),false).getTime()/1000;var v=parseTime(p.val());o+=v.hour*3600+v.minute*60;var u=parseDate(j.val(),false).getTime()/1000;var w=parseTime(l.val());u+=w.hour*3600+w.minute*60;k.data("time_diff",u-o)}).bind("blur.timespan",function(){var o=parseDate(k.data("timespan.stored"),false);var u=parseTime(p.data("timespan.stored"));var v=o.getTime()/1000+u.hour*3600+u.minute*60+k.data("time_diff");v=new Date(v*1000);j.val(formatDate(v,false));l.val(formatTime(v.getUTCHours(),v.getUTCMinutes(),false))});k.closest("form").bind("submit.timespan",function(){var o=parseDate(k.val(),false).getTime()/1000;if(!isNaN(o)){if(!s.get(0).checked){var u=parseTime(p.val());if(u){o+=u.hour*3600+u.minute*60}else{o=""}}}else{o=""}m.val(o);var v=parseDate(j.val(),false).getTime()/1000;if(!isNaN(v)){if(s.get(0).checked){v+=24*60*60}else{var u=parseTime(l.val());if(u){v+=u.hour*3600+u.minute*60}else{v=""}}}else{v=""}g.val(v)});m.data("timespan.initial_value",m.val());g.data("timespan.initial_value",g.val());s.data("timespan.initial_value",s.get(0).checked);c(k,p,m,j,l,g,s,h.twentyfour_hour,h.now);return this},reset:function(g){var h=d.extend({},f,g);c(d(h.start_date_input),d(h.start_time_input),d(h.start_time),d(h.end_date_input),d(h.end_time_input),d(h.end_time),d(h.allday),h.twentyfour_hour,h.now);return this},destroy:function(g){g=d.extend({},f,g);d.each(g,function(i,h){d(h).unbind(".timespan")});d(g.start_date_input).closest("form").unbind(".timespan");return this}};d.timespan=function(g){if(b[g]){return b[g].apply(this,Array.prototype.slice.call(arguments,1))}else{if(typeof g==="object"||!g){return b.init.apply(this,arguments)}else{d.error("Method "+g+" does not exist on jQuery.timespan")}}}})(jQuery);
|
js/settings.js
ADDED
@@ -0,0 +1 @@
|
|
|
1 |
+
jQuery(function(a){a(".if-js-closed").removeClass("if-js-closed").addClass("closed");postboxes.add_postbox_toggles(ai1ec_settings_page)});
|
lib/SG_iCal.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
define('SG_ICALREADER_VERSION', '0.7.0');
|
4 |
+
|
5 |
+
/**
|
6 |
+
* A simple iCal parser. Should take care of most stuff for ya
|
7 |
+
* http://github.com/fangel/SG-iCalendar
|
8 |
+
*
|
9 |
+
* Roadmap:
|
10 |
+
* * Finish FREQUENCY-parsing.
|
11 |
+
* * Add API for recurring events
|
12 |
+
*
|
13 |
+
* A simple example:
|
14 |
+
* <?php
|
15 |
+
* $ical = new SG_iCalReader("http://example.com/calendar.ics");
|
16 |
+
* foreach( $ical->getEvents() As $event ) {
|
17 |
+
* // Do stuff with the event $event
|
18 |
+
* }
|
19 |
+
* ?>
|
20 |
+
*
|
21 |
+
* @package SG_iCalReader
|
22 |
+
* @author Morten Fangel (C) 2008
|
23 |
+
* @author xonev (C) 2010
|
24 |
+
* @author Tanguy Pruvot (C) 2010
|
25 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
26 |
+
*/
|
27 |
+
class SG_iCal {
|
28 |
+
|
29 |
+
//objects
|
30 |
+
public $information; //SG_iCal_VCalendar
|
31 |
+
public $timezones; //SG_iCal_VTimeZone
|
32 |
+
|
33 |
+
protected $events; //SG_iCal_VEvent[]
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Constructs a new iCalReader. You can supply the url now, or later using setUrl
|
37 |
+
* @param $url string
|
38 |
+
*/
|
39 |
+
public function __construct($url = false) {
|
40 |
+
$this->setUrl($url);
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Sets (or resets) the url this reader reads from.
|
45 |
+
* @param $url string
|
46 |
+
*/
|
47 |
+
public function setUrl( $url = false ) {
|
48 |
+
if( $url !== false ) {
|
49 |
+
SG_iCal_Parser::Parse($url, $this);
|
50 |
+
}
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Returns the main calendar info. You can then query the returned
|
55 |
+
* object with ie getTitle().
|
56 |
+
* @return SG_iCal_VCalendar
|
57 |
+
*/
|
58 |
+
public function getCalendarInfo() {
|
59 |
+
return $this->information;
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Sets the calendar info for this calendar
|
64 |
+
* @param SG_iCal_VCalendar $info
|
65 |
+
*/
|
66 |
+
public function setCalendarInfo( SG_iCal_VCalendar $info ) {
|
67 |
+
$this->information = $info;
|
68 |
+
}
|
69 |
+
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Returns a given timezone for the calendar. This is mainly used
|
73 |
+
* by VEvents to adjust their date-times if they have specified a
|
74 |
+
* timezone.
|
75 |
+
*
|
76 |
+
* If no timezone is given, all timezones in the calendar is
|
77 |
+
* returned.
|
78 |
+
*
|
79 |
+
* @param $tzid string
|
80 |
+
* @return SG_iCal_VTimeZone
|
81 |
+
*/
|
82 |
+
public function getTimeZoneInfo( $tzid = null ) {
|
83 |
+
if( $tzid == null ) {
|
84 |
+
return $this->timezones;
|
85 |
+
} else {
|
86 |
+
if ( !isset($this->timezones)) {
|
87 |
+
return null;
|
88 |
+
}
|
89 |
+
foreach( $this->timezones AS $tz ) {
|
90 |
+
if( $tz->getTimeZoneId() == $tzid ) {
|
91 |
+
return $tz;
|
92 |
+
}
|
93 |
+
}
|
94 |
+
return null;
|
95 |
+
}
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Adds a new timezone to this calendar
|
100 |
+
* @param SG_iCal_VTimeZone $tz
|
101 |
+
*/
|
102 |
+
public function addTimeZone( SG_iCal_VTimeZone $tz ) {
|
103 |
+
$this->timezones[] = $tz;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Returns the events found
|
108 |
+
* @return array
|
109 |
+
*/
|
110 |
+
public function getEvents() {
|
111 |
+
return $this->events;
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* Adds a event to this calendar
|
116 |
+
* @param SG_iCal_VEvent $event
|
117 |
+
*/
|
118 |
+
public function addEvent( SG_iCal_VEvent $event ) {
|
119 |
+
$this->events[] = $event;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* For legacy reasons, we keep the name SG_iCalReader..
|
125 |
+
*/
|
126 |
+
class SG_iCalReader extends SG_iCal {}
|
lib/blocks/SG_iCal_VCalendar.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The wrapper for the main vcalendar data. Used instead of ArrayObject
|
5 |
+
* so you can easily query for title and description.
|
6 |
+
* Exposes a iterator that will loop though all the data
|
7 |
+
*
|
8 |
+
* @package SG_iCalReader
|
9 |
+
* @author Morten Fangel (C) 2008
|
10 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
11 |
+
*/
|
12 |
+
class SG_iCal_VCalendar implements IteratorAggregate {
|
13 |
+
protected $data;
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Creates a new SG_iCal_VCalendar.
|
17 |
+
*/
|
18 |
+
public function __construct($data) {
|
19 |
+
$this->data = $data;
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Returns the title of the calendar. If no title is known, NULL
|
24 |
+
* will be returned
|
25 |
+
* @return string
|
26 |
+
*/
|
27 |
+
public function getTitle() {
|
28 |
+
if( isset($this->data['x-wr-calname']) ) {
|
29 |
+
return $this->data['x-wr-calname'];
|
30 |
+
} else {
|
31 |
+
return null;
|
32 |
+
}
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Returns the description of the calendar. If no description is
|
37 |
+
* known, NULL will be returned.
|
38 |
+
* @return string
|
39 |
+
*/
|
40 |
+
public function getDescription() {
|
41 |
+
if( isset($this->data['x-wr-caldesc']) ) {
|
42 |
+
return $this->data['x-wr-caldesc'];
|
43 |
+
} else {
|
44 |
+
return null;
|
45 |
+
}
|
46 |
+
}
|
47 |
+
|
48 |
+
public function getTimezone() {
|
49 |
+
if( isset($this->data['x-wr-timezone']) ) {
|
50 |
+
return $this->data['x-wr-timezone'];
|
51 |
+
} else {
|
52 |
+
return null;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* @see IteratorAggregate.getIterator()
|
58 |
+
*/
|
59 |
+
public function getIterator() {
|
60 |
+
return new ArrayIterator($this->data);
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
?>
|
lib/blocks/SG_iCal_VEvent.php
ADDED
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The wrapper for vevents. Will reveal a unified and simple api for
|
5 |
+
* the events, which include always finding a start and end (except
|
6 |
+
* when no end or duration is given) and checking if the event is
|
7 |
+
* blocking or similar.
|
8 |
+
*
|
9 |
+
* Will apply the specified timezone to timestamps if a tzid is
|
10 |
+
* specified
|
11 |
+
*
|
12 |
+
* @package SG_iCalReader
|
13 |
+
* @author Morten Fangel (C) 2008
|
14 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
15 |
+
*/
|
16 |
+
class SG_iCal_VEvent {
|
17 |
+
const DEFAULT_CONFIRMED = true;
|
18 |
+
|
19 |
+
public $uid;
|
20 |
+
|
21 |
+
public $start;
|
22 |
+
public $end;
|
23 |
+
|
24 |
+
public $summary;
|
25 |
+
public $description;
|
26 |
+
public $location;
|
27 |
+
|
28 |
+
public $laststart;
|
29 |
+
public $lastend;
|
30 |
+
|
31 |
+
public $recurrence; //RRULE
|
32 |
+
public $recurex; //EXRULE
|
33 |
+
public $excluded; //EXDATE(s)
|
34 |
+
public $added; //RDATE(s)
|
35 |
+
|
36 |
+
public $freq; //getFrequency() SG_iCal_Freq
|
37 |
+
|
38 |
+
public $data;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructs a new SG_iCal_VEvent. Needs the SG_iCalReader
|
42 |
+
* supplied so it can query for timezones.
|
43 |
+
* @param SG_iCal_Line[] $data
|
44 |
+
* @param SG_iCalReader $ical
|
45 |
+
*/
|
46 |
+
public function __construct($data, SG_iCal $ical) {
|
47 |
+
|
48 |
+
$this->uid = $data['uid']->getData();
|
49 |
+
unset($data['uid']);
|
50 |
+
|
51 |
+
if ( isset($data['rrule']) ) {
|
52 |
+
$this->recurrence = new SG_iCal_Recurrence($data['rrule']);
|
53 |
+
unset($data['rrule']);
|
54 |
+
}
|
55 |
+
|
56 |
+
if ( isset($data['exrule']) ) {
|
57 |
+
$this->recurex = new SG_iCal_Recurrence($data['exrule']);
|
58 |
+
unset($data['exrule']);
|
59 |
+
}
|
60 |
+
|
61 |
+
if( isset($data['dtstart']) ) {
|
62 |
+
$this->start = $this->getTimestamp($data['dtstart'], $ical);
|
63 |
+
unset($data['dtstart']);
|
64 |
+
}
|
65 |
+
|
66 |
+
if( isset($data['dtend']) ) {
|
67 |
+
$this->end = $this->getTimestamp($data['dtend'], $ical);
|
68 |
+
unset($data['dtend']);
|
69 |
+
} elseif( isset($data['duration']) ) {
|
70 |
+
$dur = new SG_iCal_Duration( $data['duration']->getData() );
|
71 |
+
$this->end = $this->start + $dur->getDuration();
|
72 |
+
unset($data['duration']);
|
73 |
+
}
|
74 |
+
|
75 |
+
//google cal set dtend as end of initial event (duration)
|
76 |
+
if ( isset($this->recurrence) ) {
|
77 |
+
//if there is a recurrence rule
|
78 |
+
|
79 |
+
//exclusions
|
80 |
+
if ( isset($data['exdate']) ) {
|
81 |
+
foreach ($data['exdate'] as $exdate) {
|
82 |
+
foreach ($exdate->getDataAsArray() as $ts) {
|
83 |
+
$this->excluded[] = strtotime($ts);
|
84 |
+
}
|
85 |
+
}
|
86 |
+
unset($data['exdate']);
|
87 |
+
}
|
88 |
+
//additions
|
89 |
+
if ( isset($data['rdate']) ) {
|
90 |
+
foreach ($data['rdate'] as $rdate) {
|
91 |
+
foreach ($rdate->getDataAsArray() as $ts) {
|
92 |
+
$this->added[] = strtotime($ts);
|
93 |
+
}
|
94 |
+
}
|
95 |
+
unset($data['rdate']);
|
96 |
+
}
|
97 |
+
|
98 |
+
$until = $this->recurrence->getUntil();
|
99 |
+
$count = $this->recurrence->getCount();
|
100 |
+
//check if there is either 'until' or 'count' set
|
101 |
+
if ( $until ) {
|
102 |
+
//ok..
|
103 |
+
} elseif ($count) {
|
104 |
+
//if count is set, then figure out the last occurrence and set that as the end date
|
105 |
+
$this->getFrequency();
|
106 |
+
$until = $this->freq->lastOccurrence($this->start);
|
107 |
+
} else {
|
108 |
+
//forever... limit to 3 years
|
109 |
+
$this->recurrence->setUntil('+3 years');
|
110 |
+
$until = $this->recurrence->getUntil();
|
111 |
+
}
|
112 |
+
//date_default_timezone_set( xx ) needed ?;
|
113 |
+
$this->laststart = strtotime($until);
|
114 |
+
$this->lastend = $this->laststart + $this->getDuration();
|
115 |
+
}
|
116 |
+
|
117 |
+
$imports = array('summary','description','location');
|
118 |
+
foreach( $imports AS $import ) {
|
119 |
+
if( isset($data[$import]) ) {
|
120 |
+
$this->$import = $data[$import]->getData();
|
121 |
+
unset($data[$import]);
|
122 |
+
}
|
123 |
+
}
|
124 |
+
|
125 |
+
if( isset($this->previous_tz) ) {
|
126 |
+
date_default_timezone_set($this->previous_tz);
|
127 |
+
}
|
128 |
+
|
129 |
+
$this->data = SG_iCal_Line::Remove_Line($data);
|
130 |
+
}
|
131 |
+
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Returns the Event Occurrences Iterator (if recurrence set)
|
135 |
+
* @return SG_iCal_Freq
|
136 |
+
*/
|
137 |
+
public function getFrequency() {
|
138 |
+
if (! isset($this->freq)) {
|
139 |
+
if ( isset($this->recurrence) ) {
|
140 |
+
$this->freq = new SG_iCal_Freq($this->recurrence->rrule, $this->start, $this->excluded, $this->added);
|
141 |
+
}
|
142 |
+
}
|
143 |
+
return $this->freq;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Returns the UID of the event
|
148 |
+
* @return string
|
149 |
+
*/
|
150 |
+
public function getUID() {
|
151 |
+
return $this->uid;
|
152 |
+
}
|
153 |
+
|
154 |
+
/**
|
155 |
+
* Returns the summary (or null if none is given) of the event
|
156 |
+
* @return string
|
157 |
+
*/
|
158 |
+
public function getSummary() {
|
159 |
+
return $this->summary;
|
160 |
+
}
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Returns the description (or null if none is given) of the event
|
164 |
+
* @return string
|
165 |
+
*/
|
166 |
+
public function getDescription() {
|
167 |
+
return $this->description;
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Returns the location (or null if none is given) of the event
|
172 |
+
* @return string
|
173 |
+
*/
|
174 |
+
public function getLocation() {
|
175 |
+
return $this->location;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Returns true if the event is blocking (ie not transparent)
|
180 |
+
* @return bool
|
181 |
+
*/
|
182 |
+
public function isBlocking() {
|
183 |
+
return !(isset($this->data['transp']) && $this->data['transp'] == 'TRANSPARENT');
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* Returns true if the event is confirmed
|
188 |
+
* @return bool
|
189 |
+
*/
|
190 |
+
public function isConfirmed() {
|
191 |
+
if( !isset($this->data['status']) ) {
|
192 |
+
return self::DEFAULT_CONFIRMED;
|
193 |
+
} else {
|
194 |
+
return $this->data['status'] == 'CONFIRMED';
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Returns true if duration is multiple of 86400
|
200 |
+
* @return bool
|
201 |
+
*/
|
202 |
+
public function isWholeDay() {
|
203 |
+
$dur = $this->getDuration();
|
204 |
+
if ($dur > 0 && ($dur % 86400) == 0) {
|
205 |
+
return true;
|
206 |
+
}
|
207 |
+
return false;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Returns the timestamp for the beginning of the event
|
212 |
+
* @return int
|
213 |
+
*/
|
214 |
+
public function getStart() {
|
215 |
+
return $this->start;
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Returns the timestamp for the end of the event
|
220 |
+
* @return int
|
221 |
+
*/
|
222 |
+
public function getEnd() {
|
223 |
+
return $this->end;
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Returns the timestamp for the end of the last event
|
228 |
+
* @return int
|
229 |
+
*/
|
230 |
+
public function getRangeEnd() {
|
231 |
+
return max($this->end,$this->lastend);
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Returns the duration of this event in seconds
|
236 |
+
* @return int
|
237 |
+
*/
|
238 |
+
public function getDuration() {
|
239 |
+
return $this->end - $this->start;
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Returns the given property of the event.
|
244 |
+
* @param string $prop
|
245 |
+
* @return string
|
246 |
+
*/
|
247 |
+
public function getProperty( $prop ) {
|
248 |
+
if( isset($this->$prop) ) {
|
249 |
+
return $this->$prop;
|
250 |
+
} elseif( isset($this->data[$prop]) ) {
|
251 |
+
return $this->data[$prop];
|
252 |
+
} else {
|
253 |
+
return null;
|
254 |
+
}
|
255 |
+
}
|
256 |
+
|
257 |
+
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Set default timezone (temporary) to get timestamps
|
261 |
+
* @return string
|
262 |
+
*/
|
263 |
+
protected function setLineTimeZone(SG_iCal_Line $line) {
|
264 |
+
if( isset($line['tzid']) ) {
|
265 |
+
if (!isset($this->previous_tz)) {
|
266 |
+
$this->previous_tz = @ date_default_timezone_get();
|
267 |
+
}
|
268 |
+
$this->tzid = $line['tzid'];
|
269 |
+
date_default_timezone_set($this->tzid);
|
270 |
+
return true;
|
271 |
+
}
|
272 |
+
return false;
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Calculates the timestamp from a DT line.
|
277 |
+
* @param $line SG_iCal_Line
|
278 |
+
* @return int
|
279 |
+
*/
|
280 |
+
protected function getTimestamp( SG_iCal_Line $line, SG_iCal $ical ) {
|
281 |
+
|
282 |
+
if( isset($line['tzid']) ) {
|
283 |
+
$this->setLineTimeZone($line);
|
284 |
+
//$tz = $ical->getTimeZoneInfo($line['tzid']);
|
285 |
+
//$offset = $tz->getOffset($ts);
|
286 |
+
//$ts = strtotime(date('D, d M Y H:i:s', $ts) . ' ' . $offset);
|
287 |
+
}
|
288 |
+
$ts = strtotime($line->getData());
|
289 |
+
|
290 |
+
return $ts;
|
291 |
+
}
|
292 |
+
}
|
lib/blocks/SG_iCal_VTimeZone.php
ADDED
@@ -0,0 +1,95 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* The wrapper for vtimezones. Stores the timezone-id and the setup for
|
5 |
+
* daylight savings and standard time.
|
6 |
+
*
|
7 |
+
* @package SG_iCalReader
|
8 |
+
* @author Morten Fangel (C) 2008
|
9 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
10 |
+
*/
|
11 |
+
class SG_iCal_VTimeZone {
|
12 |
+
protected $tzid;
|
13 |
+
protected $daylight;
|
14 |
+
protected $standard;
|
15 |
+
protected $cache = array();
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Constructs a new SG_iCal_VTimeZone
|
19 |
+
*/
|
20 |
+
public function __construct( $data ) {
|
21 |
+
require_once dirname(__FILE__).'/../helpers/SG_iCal_Freq.php'; // BUILD: Remove line
|
22 |
+
|
23 |
+
$this->tzid = $data['tzid'];
|
24 |
+
$this->daylight = $data['daylight'];
|
25 |
+
$this->standard = $data['standard'];
|
26 |
+
}
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Returns the timezone-id for this timezone. (Used to
|
30 |
+
* differentiate between different tzs in a calendar)
|
31 |
+
* @return string
|
32 |
+
*/
|
33 |
+
public function getTimeZoneId() {
|
34 |
+
return $this->tzid;
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Returns the given offset in this timezone for the given
|
39 |
+
* timestamp. (eg +0200)
|
40 |
+
* @param int $ts
|
41 |
+
* @return string
|
42 |
+
*/
|
43 |
+
public function getOffset( $ts ) {
|
44 |
+
$act = $this->getActive($ts);
|
45 |
+
return $this->{$act}['tzoffsetto'];
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Returns the timezone name for the given timestamp (eg CEST)
|
50 |
+
* @param int $ts
|
51 |
+
* @return string
|
52 |
+
*/
|
53 |
+
public function getTimeZoneName($ts) {
|
54 |
+
$act = $this->getActive($ts);
|
55 |
+
return $this->{$act}['tzname'];
|
56 |
+
}
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Determines which of the daylight or standard is the active
|
60 |
+
* setting.
|
61 |
+
* The call is cached for a given timestamp, so a call to
|
62 |
+
* getOffset and getTimeZoneName with the same ts won't calculate
|
63 |
+
* the answer twice.
|
64 |
+
* @param int $ts
|
65 |
+
* @return string standard|daylight
|
66 |
+
*/
|
67 |
+
private function getActive( $ts ) {
|
68 |
+
|
69 |
+
if (class_exists('DateTimeZone')) {
|
70 |
+
|
71 |
+
//PHP >= 5.2
|
72 |
+
$tz = new DateTimeZone( $this->tzid );
|
73 |
+
$date = new DateTime("@$ts", $tz);
|
74 |
+
return ($date->format('I') == 1) ? 'daylight' : 'standard';
|
75 |
+
|
76 |
+
} else {
|
77 |
+
|
78 |
+
if( isset($this->cache[$ts]) ) {
|
79 |
+
return $this->cache[$ts];
|
80 |
+
}
|
81 |
+
|
82 |
+
$daylight_freq = new SG_iCal_Freq($this->daylight['rrule'], strtotime($this->daylight['dtstart']));
|
83 |
+
$standard_freq = new SG_iCal_Freq($this->standard['rrule'], strtotime($this->standard['dtstart']));
|
84 |
+
$last_standard = $standard_freq->previousOccurrence($ts);
|
85 |
+
$last_dst = $daylight_freq->previousOccurrence($ts);
|
86 |
+
if( $last_dst > $last_standard ) {
|
87 |
+
$this->cache[$ts] = 'daylight';
|
88 |
+
} else {
|
89 |
+
$this->cache[$ts] = 'standard';
|
90 |
+
}
|
91 |
+
|
92 |
+
return $this->cache[$ts];
|
93 |
+
}
|
94 |
+
}
|
95 |
+
}
|
lib/helpers/SG_iCal_Duration.php
ADDED
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A class for calculating how many seconds a duration-string is
|
5 |
+
*
|
6 |
+
* @package SG_iCalReader
|
7 |
+
* @author Morten Fangel (C) 2008
|
8 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
9 |
+
*/
|
10 |
+
|
11 |
+
class SG_iCal_Duration {
|
12 |
+
protected $dur;
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Constructs a new SG_iCal_Duration from a duration-rule.
|
16 |
+
* The basic build-up of DURATIONs are:
|
17 |
+
* (["+"] / "-") "P" (dur-date / dur-date + "T" + dur-time / dur-time / dur-week)
|
18 |
+
* Is solved via a really fugly reg-exp with way to many ()'s..
|
19 |
+
*
|
20 |
+
* @param $duration string
|
21 |
+
*/
|
22 |
+
public function __construct( $duration ) {
|
23 |
+
|
24 |
+
$ts = 0;
|
25 |
+
|
26 |
+
if (preg_match('/[\\+\\-]{0,1}P((\d+)W)?((\d+)D)?(T)?((\d+)H)?((\d+)M)?((\d+)S)?/', $duration, $matches) === 1) {
|
27 |
+
$results = array(
|
28 |
+
'weeks'=> (int)@ $matches[2],
|
29 |
+
'days'=> (int)@ $matches[4],
|
30 |
+
'hours'=> (int)@ $matches[7],
|
31 |
+
'minutes'=>(int)@ $matches[9],
|
32 |
+
'seconds'=>(int)@ $matches[11]
|
33 |
+
);
|
34 |
+
|
35 |
+
$ts += $results['seconds'];
|
36 |
+
$ts += 60 * $results['minutes'];
|
37 |
+
$ts += 60 * 60 * $results['hours'];
|
38 |
+
$ts += 24 * 60 * 60 * $results['days'];
|
39 |
+
$ts += 7 * 24 * 60 * 60 * $results['weeks'];
|
40 |
+
} else {
|
41 |
+
// Invalid duration!
|
42 |
+
}
|
43 |
+
|
44 |
+
$dir = ($duration{0} == '-') ? -1 : 1;
|
45 |
+
|
46 |
+
$this->dur = $dir * $ts;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Returns the duration in seconds
|
51 |
+
* @return int
|
52 |
+
*/
|
53 |
+
public function getDuration() {
|
54 |
+
return $this->dur;
|
55 |
+
}
|
56 |
+
}
|
lib/helpers/SG_iCal_Factory.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A simple Factory for converting a section/data pair into the
|
5 |
+
* corrosponding block-object. If the section isn't known a simple
|
6 |
+
* ArrayObject is used instead.
|
7 |
+
*
|
8 |
+
* @package SG_iCalReader
|
9 |
+
* @author Morten Fangel (C) 2008
|
10 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
11 |
+
*/
|
12 |
+
class SG_iCal_Factory {
|
13 |
+
/**
|
14 |
+
* Returns a new block-object for the section/data-pair. The list
|
15 |
+
* of returned objects is:
|
16 |
+
*
|
17 |
+
* vcalendar => SG_iCal_VCalendar
|
18 |
+
* vtimezone => SG_iCal_VTimeZone
|
19 |
+
* vevent => SG_iCal_VEvent
|
20 |
+
* * => ArrayObject
|
21 |
+
*
|
22 |
+
* @param $ical SG_iCalReader The reader this section/data-pair belongs to
|
23 |
+
* @param $section string
|
24 |
+
* @param SG_iCal_Line[]
|
25 |
+
*/
|
26 |
+
public static function factory( SG_iCal $ical, $section, $data ) {
|
27 |
+
switch( $section ) {
|
28 |
+
case "vcalendar":
|
29 |
+
require_once dirname(__FILE__).'/../blocks/SG_iCal_VCalendar.php'; // BUILD: Remove line
|
30 |
+
return new SG_iCal_VCalendar(SG_iCal_Line::Remove_Line($data), $ical );
|
31 |
+
case "vtimezone":
|
32 |
+
require_once dirname(__FILE__).'/../blocks/SG_iCal_VTimeZone.php'; // BUILD: Remove line
|
33 |
+
return new SG_iCal_VTimeZone(SG_iCal_Line::Remove_Line($data), $ical );
|
34 |
+
case "vevent":
|
35 |
+
require_once dirname(__FILE__).'/../blocks/SG_iCal_VEvent.php'; // BUILD: Remove line
|
36 |
+
return new SG_iCal_VEvent($data, $ical );
|
37 |
+
|
38 |
+
default:
|
39 |
+
return new ArrayObject(SG_iCal_Line::Remove_Line((array) $data) );
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
lib/helpers/SG_iCal_Freq.php
ADDED
@@ -0,0 +1,554 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A class to store Frequency-rules in. Will allow a easy way to find the
|
5 |
+
* last and next occurrence of the rule.
|
6 |
+
*
|
7 |
+
* No - this is so not pretty. But.. ehh.. You do it better, and I will
|
8 |
+
* gladly accept patches.
|
9 |
+
*
|
10 |
+
* Created by trail-and-error on the examples given in the RFC.
|
11 |
+
*
|
12 |
+
* TODO: Update to a better way of doing calculating the different options.
|
13 |
+
* Instead of only keeping track of the best of the current dates found
|
14 |
+
* it should instead keep a array of all the calculated dates within the
|
15 |
+
* period.
|
16 |
+
* This should fix the issues with multi-rule + multi-rule interference,
|
17 |
+
* and make it possible to implement the SETPOS rule.
|
18 |
+
* By pushing the next period onto the stack as the last option will
|
19 |
+
* (hopefully) remove the need for the awful simpleMode
|
20 |
+
*
|
21 |
+
* @package SG_iCalReader
|
22 |
+
* @author Morten Fangel (C) 2008
|
23 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
24 |
+
*/
|
25 |
+
class SG_iCal_Freq {
|
26 |
+
protected $weekdays = array('MO'=>'monday', 'TU'=>'tuesday', 'WE'=>'wednesday', 'TH'=>'thursday', 'FR'=>'friday', 'SA'=>'saturday', 'SU'=>'sunday');
|
27 |
+
protected $knownRules = array('month', 'weekno', 'day', 'monthday', 'yearday', 'hour', 'minute'); //others : 'setpos', 'second'
|
28 |
+
protected $ruleModifiers = array('wkst');
|
29 |
+
protected $simpleMode = true;
|
30 |
+
|
31 |
+
protected $rules = array('freq'=>'yearly', 'interval'=>1);
|
32 |
+
protected $start = 0;
|
33 |
+
protected $freq = '';
|
34 |
+
|
35 |
+
protected $excluded; //EXDATE
|
36 |
+
protected $added; //RDATE
|
37 |
+
|
38 |
+
protected $cache; // getAllOccurrences()
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructs a new Freqency-rule
|
42 |
+
* @param $rule string
|
43 |
+
* @param $start int Unix-timestamp (important : Need to be the start of Event)
|
44 |
+
* @param $excluded array of int (timestamps), see EXDATE documentation
|
45 |
+
* @param $added array of int (timestamps), see RDATE documentation
|
46 |
+
*/
|
47 |
+
public function __construct( $rule, $start, $excluded=array(), $added=array()) {
|
48 |
+
$this->start = $start;
|
49 |
+
$this->excluded = array();
|
50 |
+
|
51 |
+
$rules = array();
|
52 |
+
foreach( explode(';', $rule) AS $v) {
|
53 |
+
list($k, $v) = explode('=', $v);
|
54 |
+
$this->rules[ strtolower($k) ] = $v;
|
55 |
+
}
|
56 |
+
|
57 |
+
if( isset($this->rules['until']) && is_string($this->rules['until']) ) {
|
58 |
+
$this->rules['until'] = strtotime($this->rules['until']);
|
59 |
+
}
|
60 |
+
$this->freq = strtolower($this->rules['freq']);
|
61 |
+
|
62 |
+
foreach( $this->knownRules AS $rule ) {
|
63 |
+
if( isset($this->rules['by' . $rule]) ) {
|
64 |
+
if( $this->isPrerule($rule, $this->freq) ) {
|
65 |
+
$this->simpleMode = false;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
if(!$this->simpleMode) {
|
71 |
+
if(! (isset($this->rules['byday']) || isset($this->rules['bymonthday']) || isset($this->rules['byyearday']))) {
|
72 |
+
$this->rules['bymonthday'] = date('d', $this->start);
|
73 |
+
}
|
74 |
+
}
|
75 |
+
|
76 |
+
//set until, and cache
|
77 |
+
if( isset($this->rules['count']) ) {
|
78 |
+
|
79 |
+
$cache[$ts] = $ts = $this->start;
|
80 |
+
for($n=1; $n < $this->rules['count']; $n++) {
|
81 |
+
$ts = $this->findNext($ts);
|
82 |
+
$cache[$ts] = $ts;
|
83 |
+
}
|
84 |
+
$this->rules['until'] = $ts;
|
85 |
+
|
86 |
+
//EXDATE
|
87 |
+
if (!empty($excluded)) {
|
88 |
+
foreach($excluded as $ts) {
|
89 |
+
unset($cache[$ts]);
|
90 |
+
}
|
91 |
+
}
|
92 |
+
//RDATE
|
93 |
+
if (!empty($added)) {
|
94 |
+
$cache = $cache + $added;
|
95 |
+
asort($cache);
|
96 |
+
}
|
97 |
+
|
98 |
+
$this->cache = array_values($cache);
|
99 |
+
}
|
100 |
+
|
101 |
+
$this->excluded = $excluded;
|
102 |
+
$this->added = $added;
|
103 |
+
}
|
104 |
+
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Returns all timestamps array(), build the cache if not made before
|
108 |
+
* @return array
|
109 |
+
*/
|
110 |
+
public function getAllOccurrences() {
|
111 |
+
if (empty($this->cache)) {
|
112 |
+
//build cache
|
113 |
+
$next = $this->firstOccurrence();
|
114 |
+
while ($next) {
|
115 |
+
$cache[] = $next;
|
116 |
+
$next = $this->findNext($next);
|
117 |
+
}
|
118 |
+
if (!empty($this->added)) {
|
119 |
+
$cache = $cache + $this->added;
|
120 |
+
asort($cache);
|
121 |
+
}
|
122 |
+
$this->cache = $cache;
|
123 |
+
}
|
124 |
+
return $this->cache;
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Returns the previous (most recent) occurrence of the rule from the
|
129 |
+
* given offset
|
130 |
+
* @param int $offset
|
131 |
+
* @return int
|
132 |
+
*/
|
133 |
+
public function previousOccurrence( $offset ) {
|
134 |
+
if (!empty($this->cache)) {
|
135 |
+
$t2=$this->start;
|
136 |
+
foreach($this->cache as $ts) {
|
137 |
+
if ($ts >= $offset)
|
138 |
+
return $t2;
|
139 |
+
$t2 = $ts;
|
140 |
+
}
|
141 |
+
} else {
|
142 |
+
$ts = $this->start;
|
143 |
+
while( ($t2 = $this->findNext($ts)) < $offset) {
|
144 |
+
if( $t2 == false ){
|
145 |
+
break;
|
146 |
+
}
|
147 |
+
$ts = $t2;
|
148 |
+
}
|
149 |
+
}
|
150 |
+
return $ts;
|
151 |
+
}
|
152 |
+
|
153 |
+
/**
|
154 |
+
* Returns the next occurrence of this rule after the given offset
|
155 |
+
* @param int $offset
|
156 |
+
* @return int
|
157 |
+
*/
|
158 |
+
public function nextOccurrence( $offset ) {
|
159 |
+
if ($offset < $this->start)
|
160 |
+
return $this->firstOccurrence();
|
161 |
+
return $this->findNext($offset);
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Finds the first occurrence of the rule.
|
166 |
+
* @return int timestamp
|
167 |
+
*/
|
168 |
+
public function firstOccurrence() {
|
169 |
+
$t = $this->start;
|
170 |
+
if ( is_array( $this->excluded ) && in_array($t, $this->excluded))
|
171 |
+
$t = $this->findNext($t);
|
172 |
+
return $t;
|
173 |
+
}
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Finds the absolute last occurrence of the rule from the given offset.
|
177 |
+
* Builds also the cache, if not set before...
|
178 |
+
* @return int timestamp
|
179 |
+
*/
|
180 |
+
public function lastOccurrence() {
|
181 |
+
//build cache if not done
|
182 |
+
$this->getAllOccurrences();
|
183 |
+
//return last timestamp in cache
|
184 |
+
return end($this->cache);
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Calculates the next time after the given offset that the rule
|
189 |
+
* will apply.
|
190 |
+
*
|
191 |
+
* The approach to finding the next is as follows:
|
192 |
+
* First we establish a timeframe to find timestamps in. This is
|
193 |
+
* between $offset and the end of the period that $offset is in.
|
194 |
+
*
|
195 |
+
* We then loop though all the rules (that is a Prerule in the
|
196 |
+
* current freq.), and finds the smallest timestamp inside the
|
197 |
+
* timeframe.
|
198 |
+
*
|
199 |
+
* If we find something, we check if the date is a valid recurrence
|
200 |
+
* (with validDate). If it is, we return it. Otherwise we try to
|
201 |
+
* find a new date inside the same timeframe (but using the new-
|
202 |
+
* found date as offset)
|
203 |
+
*
|
204 |
+
* If no new timestamps were found in the period, we try in the
|
205 |
+
* next period
|
206 |
+
*
|
207 |
+
* @param int $offset
|
208 |
+
* @return int
|
209 |
+
*/
|
210 |
+
public function findNext($offset) {
|
211 |
+
if (!empty($this->cache)) {
|
212 |
+
foreach($this->cache as $ts) {
|
213 |
+
if ($ts > $offset)
|
214 |
+
return $ts;
|
215 |
+
}
|
216 |
+
}
|
217 |
+
|
218 |
+
$debug = false;
|
219 |
+
|
220 |
+
//make sure the offset is valid
|
221 |
+
if( $offset === false || (isset($this->rules['until']) && $offset > $this->rules['until']) ) {
|
222 |
+
if($debug) echo 'STOP: ' . date('r', $offset) . "\n";
|
223 |
+
return false;
|
224 |
+
}
|
225 |
+
|
226 |
+
$found = true;
|
227 |
+
|
228 |
+
//set the timestamp of the offset (ignoring hours and minutes unless we want them to be
|
229 |
+
//part of the calculations.
|
230 |
+
if($debug) echo 'O: ' . date('r', $offset) . "\n";
|
231 |
+
$hour = (in_array($this->freq, array('hourly','minutely')) && $offset > $this->start) ? date('H', $offset) : date('H', $this->start);
|
232 |
+
$minute = (($this->freq == 'minutely' || isset($this->rules['byminute'])) && $offset > $this->start) ? date('i', $offset) : date('i', $this->start);
|
233 |
+
$t = mktime($hour, $minute, date('s', $this->start), date('m', $offset), date('d', $offset), date('Y',$offset));
|
234 |
+
if($debug) echo 'START: ' . date('r', $t) . "\n";
|
235 |
+
|
236 |
+
if( $this->simpleMode ) {
|
237 |
+
if( $offset < $t ) {
|
238 |
+
$ts = $t;
|
239 |
+
if ($ts && in_array($ts, $this->excluded))
|
240 |
+
$ts = $this->findNext($ts);
|
241 |
+
} else {
|
242 |
+
$ts = $this->findStartingPoint( $t, $this->rules['interval'], false );
|
243 |
+
if( !$this->validDate( $ts ) ) {
|
244 |
+
$ts = $this->findNext($ts);
|
245 |
+
}
|
246 |
+
}
|
247 |
+
return $ts;
|
248 |
+
}
|
249 |
+
|
250 |
+
$eop = $this->findEndOfPeriod($offset);
|
251 |
+
if($debug) echo 'EOP: ' . date('r', $eop) . "\n";
|
252 |
+
|
253 |
+
foreach( $this->knownRules AS $rule ) {
|
254 |
+
if( $found && isset($this->rules['by' . $rule]) ) {
|
255 |
+
if( $this->isPrerule($rule, $this->freq) ) {
|
256 |
+
$subrules = explode(',', $this->rules['by' . $rule]);
|
257 |
+
$_t = null;
|
258 |
+
foreach( $subrules AS $subrule ) {
|
259 |
+
$imm = call_user_func_array(array($this, 'ruleBy' . $rule), array($subrule, $t));
|
260 |
+
if( $imm === false ) {
|
261 |
+
break;
|
262 |
+
}
|
263 |
+
if($debug) echo strtoupper($rule) . ': ' . date('r', $imm) . ' A: ' . ((int) ($imm > $offset && $imm < $eop)) . "\n";
|
264 |
+
if( $imm > $offset && $imm < $eop && ($_t == null || $imm < $_t) ) {
|
265 |
+
$_t = $imm;
|
266 |
+
}
|
267 |
+
}
|
268 |
+
if( $_t !== null ) {
|
269 |
+
$t = $_t;
|
270 |
+
} else {
|
271 |
+
$found = $this->validDate($t);
|
272 |
+
}
|
273 |
+
}
|
274 |
+
}
|
275 |
+
}
|
276 |
+
|
277 |
+
if( $offset < $this->start && $this->start < $t ) {
|
278 |
+
$ts = $this->start;
|
279 |
+
} else if( $found && ($t != $offset)) {
|
280 |
+
if( $this->validDate( $t ) ) {
|
281 |
+
if($debug) echo 'OK' . "\n";
|
282 |
+
$ts = $t;
|
283 |
+
} else {
|
284 |
+
if($debug) echo 'Invalid' . "\n";
|
285 |
+
$ts = $this->findNext($t);
|
286 |
+
}
|
287 |
+
} else {
|
288 |
+
if($debug) echo 'Not found' . "\n";
|
289 |
+
$ts = $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) );
|
290 |
+
}
|
291 |
+
if ( is_array( $this->excluded ) && $ts && in_array($ts, $this->excluded))
|
292 |
+
return $this->findNext($ts);
|
293 |
+
|
294 |
+
return $ts;
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Finds the starting point for the next rule. It goes $interval
|
299 |
+
* 'freq' forward in time since the given offset
|
300 |
+
* @param int $offset
|
301 |
+
* @param int $interval
|
302 |
+
* @param boolean $truncate
|
303 |
+
* @return int
|
304 |
+
*/
|
305 |
+
private function findStartingPoint( $offset, $interval, $truncate = true ) {
|
306 |
+
$_freq = ($this->freq == 'daily') ? 'day__' : $this->freq;
|
307 |
+
$t = '+' . $interval . ' ' . substr($_freq,0,-2) . 's';
|
308 |
+
if( $_freq == 'monthly' && $truncate ) {
|
309 |
+
if( $interval > 1) {
|
310 |
+
$offset = strtotime('+' . ($interval - 1) . ' months ', $offset);
|
311 |
+
}
|
312 |
+
$t = '+' . (date('t', $offset) - date('d', $offset) + 1) . ' days';
|
313 |
+
}
|
314 |
+
|
315 |
+
$sp = strtotime($t, $offset);
|
316 |
+
|
317 |
+
if( $truncate ) {
|
318 |
+
$sp = $this->truncateToPeriod($sp, $this->freq);
|
319 |
+
}
|
320 |
+
|
321 |
+
return $sp;
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Finds the earliest timestamp posible outside this perioid
|
326 |
+
* @param int $offset
|
327 |
+
* @return int
|
328 |
+
*/
|
329 |
+
public function findEndOfPeriod($offset) {
|
330 |
+
return $this->findStartingPoint($offset, 1);
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Resets the timestamp to the beginning of the
|
335 |
+
* period specified by freq
|
336 |
+
*
|
337 |
+
* Yes - the fall-through is on purpose!
|
338 |
+
*
|
339 |
+
* @param int $time
|
340 |
+
* @param int $freq
|
341 |
+
* @return int
|
342 |
+
*/
|
343 |
+
private function truncateToPeriod( $time, $freq ) {
|
344 |
+
$date = getdate($time);
|
345 |
+
switch( $freq ) {
|
346 |
+
case "yearly":
|
347 |
+
$date['mon'] = 1;
|
348 |
+
case "monthly":
|
349 |
+
$date['mday'] = 1;
|
350 |
+
case "daily":
|
351 |
+
$date['hours'] = 0;
|
352 |
+
case 'hourly':
|
353 |
+
$date['minutes'] = 0;
|
354 |
+
case "minutely":
|
355 |
+
$date['seconds'] = 0;
|
356 |
+
break;
|
357 |
+
case "weekly":
|
358 |
+
if( date('N', $time) == 1) {
|
359 |
+
$date['hours'] = 0;
|
360 |
+
$date['minutes'] = 0;
|
361 |
+
$date['seconds'] = 0;
|
362 |
+
} else {
|
363 |
+
$date = getdate(strtotime("last monday 0:00", $time));
|
364 |
+
}
|
365 |
+
break;
|
366 |
+
}
|
367 |
+
$d = mktime($date['hours'], $date['minutes'], $date['seconds'], $date['mon'], $date['mday'], $date['year']);
|
368 |
+
return $d;
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Applies the BYDAY rule to the given timestamp
|
373 |
+
* @param string $rule
|
374 |
+
* @param int $t
|
375 |
+
* @return int
|
376 |
+
*/
|
377 |
+
private function ruleByday($rule, $t) {
|
378 |
+
$dir = ($rule{0} == '-') ? -1 : 1;
|
379 |
+
$dir_t = ($dir == 1) ? 'next' : 'last';
|
380 |
+
|
381 |
+
|
382 |
+
$d = $this->weekdays[substr($rule,-2)];
|
383 |
+
$s = $dir_t . ' ' . $d . ' ' . date('H:i:s',$t);
|
384 |
+
|
385 |
+
if( $rule == substr($rule, -2) ) {
|
386 |
+
if( date('l', $t) == ucfirst($d) ) {
|
387 |
+
$s = 'today ' . date('H:i:s',$t);
|
388 |
+
}
|
389 |
+
|
390 |
+
$_t = strtotime($s, $t);
|
391 |
+
|
392 |
+
if( $_t == $t && in_array($this->freq, array('monthly', 'yearly')) ) {
|
393 |
+
// Yes. This is not a great idea.. but hey, it works.. for now
|
394 |
+
$s = 'next ' . $d . ' ' . date('H:i:s',$t);
|
395 |
+
$_t = strtotime($s, $_t);
|
396 |
+
}
|
397 |
+
|
398 |
+
return $_t;
|
399 |
+
} else {
|
400 |
+
$_f = $this->freq;
|
401 |
+
if( isset($this->rules['bymonth']) && $this->freq == 'yearly' ) {
|
402 |
+
$this->freq = 'monthly';
|
403 |
+
}
|
404 |
+
if( $dir == -1 ) {
|
405 |
+
$_t = $this->findEndOfPeriod($t);
|
406 |
+
} else {
|
407 |
+
$_t = $this->truncateToPeriod($t, $this->freq);
|
408 |
+
}
|
409 |
+
$this->freq = $_f;
|
410 |
+
|
411 |
+
$c = preg_replace('/[^0-9]/','',$rule);
|
412 |
+
$c = ($c == '') ? 1 : $c;
|
413 |
+
|
414 |
+
$n = $_t;
|
415 |
+
while($c > 0 ) {
|
416 |
+
if( $dir == 1 && $c == 1 && date('l', $t) == ucfirst($d) ) {
|
417 |
+
$s = 'today ' . date('H:i:s',$t);
|
418 |
+
}
|
419 |
+
$n = strtotime($s, $n);
|
420 |
+
$c--;
|
421 |
+
}
|
422 |
+
|
423 |
+
return $n;
|
424 |
+
}
|
425 |
+
}
|
426 |
+
|
427 |
+
private function ruleBymonth($rule, $t) {
|
428 |
+
$_t = mktime(date('H',$t), date('i',$t), date('s',$t), $rule, date('d', $t), date('Y', $t));
|
429 |
+
if( $t == $_t && isset($this->rules['byday']) ) {
|
430 |
+
// TODO: this should check if one of the by*day's exists, and have a multi-day value
|
431 |
+
return false;
|
432 |
+
} else {
|
433 |
+
return $_t;
|
434 |
+
}
|
435 |
+
}
|
436 |
+
|
437 |
+
private function ruleBymonthday($rule, $t) {
|
438 |
+
if( $rule < 0 ) {
|
439 |
+
$rule = date('t', $t) + $rule + 1;
|
440 |
+
}
|
441 |
+
return mktime(date('H',$t), date('i',$t), date('s',$t), date('m', $t), $rule, date('Y', $t));
|
442 |
+
}
|
443 |
+
|
444 |
+
private function ruleByyearday($rule, $t) {
|
445 |
+
if( $rule < 0 ) {
|
446 |
+
$_t = $this->findEndOfPeriod();
|
447 |
+
$d = '-';
|
448 |
+
} else {
|
449 |
+
$_t = $this->truncateToPeriod($t, $this->freq);
|
450 |
+
$d = '+';
|
451 |
+
}
|
452 |
+
$s = $d . abs($rule -1) . ' days ' . date('H:i:s',$t);
|
453 |
+
return strtotime($s, $_t);
|
454 |
+
}
|
455 |
+
|
456 |
+
private function ruleByweekno($rule, $t) {
|
457 |
+
if( $rule < 0 ) {
|
458 |
+
$_t = $this->findEndOfPeriod();
|
459 |
+
$d = '-';
|
460 |
+
} else {
|
461 |
+
$_t = $this->truncateToPeriod($t, $this->freq);
|
462 |
+
$d = '+';
|
463 |
+
}
|
464 |
+
|
465 |
+
$sub = (date('W', $_t) == 1) ? 2 : 1;
|
466 |
+
$s = $d . abs($rule - $sub) . ' weeks ' . date('H:i:s',$t);
|
467 |
+
$_t = strtotime($s, $_t);
|
468 |
+
|
469 |
+
return $_t;
|
470 |
+
}
|
471 |
+
|
472 |
+
private function ruleByhour($rule, $t) {
|
473 |
+
$_t = mktime($rule, date('i',$t), date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
474 |
+
return $_t;
|
475 |
+
}
|
476 |
+
|
477 |
+
private function ruleByminute($rule, $t) {
|
478 |
+
$_t = mktime(date('h',$t), $rule, date('s',$t), date('m',$t), date('d', $t), date('Y', $t));
|
479 |
+
return $_t;
|
480 |
+
}
|
481 |
+
|
482 |
+
private function validDate( $t ) {
|
483 |
+
if( isset($this->rules['until']) && $t > $this->rules['until'] ) {
|
484 |
+
return false;
|
485 |
+
}
|
486 |
+
|
487 |
+
if ( is_array( $this->excluded ) && in_array($t, $this->excluded)) {
|
488 |
+
return false;
|
489 |
+
}
|
490 |
+
|
491 |
+
if( isset($this->rules['bymonth']) ) {
|
492 |
+
$months = explode(',', $this->rules['bymonth']);
|
493 |
+
if( !in_array(date('m', $t), $months)) {
|
494 |
+
return false;
|
495 |
+
}
|
496 |
+
}
|
497 |
+
if( isset($this->rules['byday']) ) {
|
498 |
+
$days = explode(',', $this->rules['byday']);
|
499 |
+
foreach( $days As $i => $k ) {
|
500 |
+
$days[$i] = $this->weekdays[ preg_replace('/[^A-Z]/', '', $k)];
|
501 |
+
}
|
502 |
+
if( !in_array(strtolower(date('l', $t)), $days)) {
|
503 |
+
return false;
|
504 |
+
}
|
505 |
+
}
|
506 |
+
if( isset($this->rules['byweekno']) ) {
|
507 |
+
$weeks = explode(',', $this->rules['byweekno']);
|
508 |
+
if( !in_array(date('W', $t), $weeks)) {
|
509 |
+
return false;
|
510 |
+
}
|
511 |
+
}
|
512 |
+
if( isset($this->rules['bymonthday'])) {
|
513 |
+
$weekdays = explode(',', $this->rules['bymonthday']);
|
514 |
+
foreach( $weekdays As $i => $k ) {
|
515 |
+
if( $k < 0 ) {
|
516 |
+
$weekdays[$i] = date('t', $t) + $k + 1;
|
517 |
+
}
|
518 |
+
}
|
519 |
+
if( !in_array(date('d', $t), $weekdays)) {
|
520 |
+
return false;
|
521 |
+
}
|
522 |
+
}
|
523 |
+
if( isset($this->rules['byhour']) ) {
|
524 |
+
$hours = explode(',', $this->rules['byhour']);
|
525 |
+
if( !in_array(date('H', $t), $hours)) {
|
526 |
+
return false;
|
527 |
+
}
|
528 |
+
}
|
529 |
+
|
530 |
+
return true;
|
531 |
+
}
|
532 |
+
|
533 |
+
private function isPrerule($rule, $freq) {
|
534 |
+
if( $rule == 'year')
|
535 |
+
return false;
|
536 |
+
if( $rule == 'month' && $freq == 'yearly')
|
537 |
+
return true;
|
538 |
+
if( $rule == 'monthday' && in_array($freq, array('yearly', 'monthly')) && !isset($this->rules['byday']))
|
539 |
+
return true;
|
540 |
+
// TODO: is it faster to do monthday first, and ignore day if monthday exists? - prolly by a factor of 4..
|
541 |
+
if( $rule == 'yearday' && $freq == 'yearly' )
|
542 |
+
return true;
|
543 |
+
if( $rule == 'weekno' && $freq == 'yearly' )
|
544 |
+
return true;
|
545 |
+
if( $rule == 'day' && in_array($freq, array('yearly', 'monthly', 'weekly')))
|
546 |
+
return true;
|
547 |
+
if( $rule == 'hour' && in_array($freq, array('yearly', 'monthly', 'weekly', 'daily')))
|
548 |
+
return true;
|
549 |
+
if( $rule == 'minute' )
|
550 |
+
return true;
|
551 |
+
|
552 |
+
return false;
|
553 |
+
}
|
554 |
+
}
|
lib/helpers/SG_iCal_Line.php
ADDED
@@ -0,0 +1,165 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A class for storing a single (complete) line of the iCal file.
|
5 |
+
* Will find the line-type, the arguments and the data of the file and
|
6 |
+
* store them.
|
7 |
+
*
|
8 |
+
* The line-type can be found by querying getIdent(), data via either
|
9 |
+
* getData() or typecasting to a string.
|
10 |
+
* Params can be access via the ArrayAccess. A iterator is also avilable
|
11 |
+
* to iterator over the params.
|
12 |
+
*
|
13 |
+
* @package SG_iCalReader
|
14 |
+
* @author Morten Fangel (C) 2008
|
15 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
16 |
+
*/
|
17 |
+
class SG_iCal_Line implements ArrayAccess, Countable, IteratorAggregate {
|
18 |
+
protected $ident;
|
19 |
+
protected $data;
|
20 |
+
protected $params = array();
|
21 |
+
|
22 |
+
protected $replacements = array('from'=>array('\\,', '\\n', '\\;', '\\:', '\\"'), 'to'=>array(',', "\n", ';', ':', '"'));
|
23 |
+
|
24 |
+
/**
|
25 |
+
* Constructs a new line.
|
26 |
+
*/
|
27 |
+
public function __construct( $line ) {
|
28 |
+
$split = strpos($line, ':');
|
29 |
+
$idents = explode(';', substr($line, 0, $split));
|
30 |
+
$ident = strtolower(array_shift($idents));
|
31 |
+
|
32 |
+
$data = trim(substr($line, $split+1));
|
33 |
+
$data = str_replace($this->replacements['from'], $this->replacements['to'], $data);
|
34 |
+
|
35 |
+
$params = array();
|
36 |
+
foreach( $idents AS $v) {
|
37 |
+
list($k, $v) = explode('=', $v);
|
38 |
+
$params[ strtolower($k) ] = $v;
|
39 |
+
}
|
40 |
+
|
41 |
+
$this->ident = $ident;
|
42 |
+
$this->params = $params;
|
43 |
+
$this->data = $data;
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Is this line the begining of a new block?
|
48 |
+
* @return bool
|
49 |
+
*/
|
50 |
+
public function isBegin() {
|
51 |
+
return $this->ident == 'begin';
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Is this line the end of a block?
|
56 |
+
* @return bool
|
57 |
+
*/
|
58 |
+
public function isEnd() {
|
59 |
+
return $this->ident == 'end';
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Returns the line-type (ident) of the line
|
64 |
+
* @return string
|
65 |
+
*/
|
66 |
+
public function getIdent() {
|
67 |
+
return $this->ident;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Returns the content of the line
|
72 |
+
* @return string
|
73 |
+
*/
|
74 |
+
public function getData() {
|
75 |
+
return $this->data;
|
76 |
+
}
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Returns the content of the line
|
80 |
+
* @return string
|
81 |
+
*/
|
82 |
+
public function getDataAsArray() {
|
83 |
+
if (strpos($this->data,",") !== false) {
|
84 |
+
return explode(",",$this->data);
|
85 |
+
}
|
86 |
+
else
|
87 |
+
return array($this->data);
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* A static helper to get a array of SG_iCal_Line's, and calls
|
92 |
+
* getData() on each of them to lay the data "bare"..
|
93 |
+
*
|
94 |
+
* @param SG_iCal_Line[]
|
95 |
+
* @return array
|
96 |
+
*/
|
97 |
+
public static function Remove_Line($arr) {
|
98 |
+
$rtn = array();
|
99 |
+
foreach( $arr AS $k => $v ) {
|
100 |
+
if(is_array($v)) {
|
101 |
+
$rtn[$k] = self::Remove_Line($v);
|
102 |
+
} elseif( $v instanceof SG_iCal_Line ) {
|
103 |
+
$rtn[$k] = $v->getData();
|
104 |
+
} else {
|
105 |
+
$rtn[$k] = $v;
|
106 |
+
}
|
107 |
+
}
|
108 |
+
return $rtn;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* @see ArrayAccess.offsetExists
|
113 |
+
*/
|
114 |
+
public function offsetExists( $param ) {
|
115 |
+
return isset($this->params[ strtolower($param) ]);
|
116 |
+
}
|
117 |
+
|
118 |
+
/**
|
119 |
+
* @see ArrayAccess.offsetGet
|
120 |
+
*/
|
121 |
+
public function offsetGet( $param ) {
|
122 |
+
$index = strtolower($param);
|
123 |
+
if (isset($this->params[ $index ])) {
|
124 |
+
return $this->params[ $index ];
|
125 |
+
}
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Disabled ArrayAccess requirement
|
130 |
+
* @see ArrayAccess.offsetSet
|
131 |
+
*/
|
132 |
+
public function offsetSet( $param, $val ) {
|
133 |
+
return false;
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Disabled ArrayAccess requirement
|
138 |
+
* @see ArrayAccess.offsetUnset
|
139 |
+
*/
|
140 |
+
public function offsetUnset( $param ) {
|
141 |
+
return false;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* toString method.
|
146 |
+
* @see getData()
|
147 |
+
*/
|
148 |
+
public function __toString() {
|
149 |
+
return $this->getData();
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* @see Countable.count
|
154 |
+
*/
|
155 |
+
public function count() {
|
156 |
+
return count($this->params);
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* @see IteratorAggregate.getIterator
|
161 |
+
*/
|
162 |
+
public function getIterator() {
|
163 |
+
return new ArrayIterator($this->params);
|
164 |
+
}
|
165 |
+
}
|
lib/helpers/SG_iCal_Parser.php
ADDED
@@ -0,0 +1,197 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
class SG_iCal_Parser {
|
4 |
+
/**
|
5 |
+
* Fetches $url and passes it on to be parsed
|
6 |
+
* @param string $url
|
7 |
+
* @param SG_iCal $ical
|
8 |
+
*/
|
9 |
+
public static function Parse( $url, SG_iCal $ical ) {
|
10 |
+
$content = self::Fetch( $url );
|
11 |
+
$content = self::UnfoldLines($content);
|
12 |
+
self::_Parse( $content, $ical );
|
13 |
+
}
|
14 |
+
|
15 |
+
/**
|
16 |
+
* Passes a text string on to be parsed
|
17 |
+
* @param string $content
|
18 |
+
* @param SG_iCal $ical
|
19 |
+
*/
|
20 |
+
public static function ParseString($content, SG_iCal $ical ) {
|
21 |
+
$content = self::UnfoldLines($content);
|
22 |
+
self::_Parse( $content, $ical );
|
23 |
+
}
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Fetches a resource and tries to make sure it's UTF8
|
27 |
+
* encoded
|
28 |
+
* @return string
|
29 |
+
*/
|
30 |
+
protected static function Fetch( $resource ) {
|
31 |
+
$is_utf8 = true;
|
32 |
+
|
33 |
+
if( is_file( $resource ) ) {
|
34 |
+
// The resource is a local file
|
35 |
+
$content = file_get_contents($resource);
|
36 |
+
|
37 |
+
if( ! self::_ValidUtf8( $content ) ) {
|
38 |
+
// The file doesn't appear to be UTF8
|
39 |
+
$is_utf8 = false;
|
40 |
+
}
|
41 |
+
} else {
|
42 |
+
// The resource isn't local, so it's assumed to
|
43 |
+
// be a URL
|
44 |
+
$c = curl_init();
|
45 |
+
curl_setopt($c, CURLOPT_URL, $resource);
|
46 |
+
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
|
47 |
+
curl_setopt($c, CURLOPT_USERAGENT, 'PHP/'.PHP_VERSION);
|
48 |
+
curl_setopt($c, CURLOPT_ENCODING, '');
|
49 |
+
if( strstr( $resource, 'https' ) !== FALSE ) {
|
50 |
+
curl_setopt($c, CURLOPT_SSLVERSION, 3);
|
51 |
+
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
|
52 |
+
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
|
53 |
+
}
|
54 |
+
curl_setopt($c, CURLOPT_COOKIESESSION, true);
|
55 |
+
curl_setopt($c, CURLOPT_HEADER, true);
|
56 |
+
if( !ini_get('safe_mode') ){
|
57 |
+
curl_setopt($c, CURLOPT_FOLLOWLOCATION, true);
|
58 |
+
}
|
59 |
+
$content = curl_exec($c);
|
60 |
+
$ct = curl_getinfo($c, CURLINFO_CONTENT_TYPE);
|
61 |
+
$enc = preg_replace('/^.*charset=([-a-zA-Z0-9]+).*$/', '$1', $ct);
|
62 |
+
if( ! self::_ValidUtf8( $content ) ) {
|
63 |
+
// The data isn't utf-8
|
64 |
+
$is_utf8 = false;
|
65 |
+
}
|
66 |
+
}
|
67 |
+
|
68 |
+
if( !$is_utf8 ) {
|
69 |
+
$content = utf8_encode($content);
|
70 |
+
}
|
71 |
+
|
72 |
+
return $content;
|
73 |
+
}
|
74 |
+
|
75 |
+
/**
|
76 |
+
* Takes the string $content, and creates a array of iCal lines.
|
77 |
+
* This includes unfolding multi-line entries into a single line.
|
78 |
+
* @param $content string
|
79 |
+
*/
|
80 |
+
protected static function UnfoldLines($content) {
|
81 |
+
$data = array();
|
82 |
+
$content = explode("\n", $content);
|
83 |
+
for( $i=0; $i < count($content); $i++) {
|
84 |
+
$line = rtrim($content[$i]);
|
85 |
+
while( isset($content[$i+1]) && strlen($content[$i+1]) > 0 && ($content[$i+1]{0} == ' ' || $content[$i+1]{0} == "\t" )) {
|
86 |
+
$line .= rtrim(substr($content[++$i],1));
|
87 |
+
}
|
88 |
+
$data[] = $line;
|
89 |
+
}
|
90 |
+
return $data;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Parses the feed found in content and calls storeSection to store
|
95 |
+
* parsed data
|
96 |
+
* @param string $content
|
97 |
+
* @param SG_iCal $ical
|
98 |
+
*/
|
99 |
+
private static function _Parse( $content, SG_iCal $ical ) {
|
100 |
+
$main_sections = array('vevent', 'vjournal', 'vtodo', 'vtimezone', 'vcalendar');
|
101 |
+
$array_idents = array('exdate','rdate');
|
102 |
+
$sections = array();
|
103 |
+
$section = '';
|
104 |
+
$current_data = array();
|
105 |
+
foreach( $content AS $line ) {
|
106 |
+
$line = new SG_iCal_Line($line);
|
107 |
+
if( $line->isBegin() ) {
|
108 |
+
// New block of data, $section = new block
|
109 |
+
$section = strtolower($line->getData());
|
110 |
+
$sections[] = strtolower($line->getData());
|
111 |
+
} elseif( $line->isEnd() ) {
|
112 |
+
// End of block of data ($removed = just ended block, $section = new top-block)
|
113 |
+
$removed = array_pop($sections);
|
114 |
+
$section = end($sections);
|
115 |
+
|
116 |
+
if( array_search($removed, $main_sections) !== false ) {
|
117 |
+
self::StoreSection( $removed, $current_data[$removed], $ical);
|
118 |
+
$current_data[$removed] = array();
|
119 |
+
}
|
120 |
+
} else {
|
121 |
+
// Data line
|
122 |
+
foreach( $main_sections AS $s ) {
|
123 |
+
// Loops though the main sections
|
124 |
+
if( array_search($s, $sections) !== false ) {
|
125 |
+
// This section is in the main section
|
126 |
+
if( $section == $s ) {
|
127 |
+
// It _is_ the main section else
|
128 |
+
if (in_array($line->getIdent(), $array_idents))
|
129 |
+
//exdate could appears more that once
|
130 |
+
$current_data[$s][$line->getIdent()][] = $line;
|
131 |
+
else {
|
132 |
+
$current_data[$s][$line->getIdent()] = $line;
|
133 |
+
}
|
134 |
+
} else {
|
135 |
+
// Sub section
|
136 |
+
$current_data[$s][$section][$line->getIdent()] = $line;
|
137 |
+
}
|
138 |
+
break;
|
139 |
+
}
|
140 |
+
}
|
141 |
+
}
|
142 |
+
}
|
143 |
+
$current_data = array();
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Stores the data in provided SG_iCal object
|
148 |
+
* @param string $section eg 'vcalender', 'vevent' etc
|
149 |
+
* @param string $data
|
150 |
+
* @param SG_iCal $ical
|
151 |
+
*/
|
152 |
+
protected static function storeSection( $section, $data, SG_iCal $ical ) {
|
153 |
+
$data = SG_iCal_Factory::Factory($ical, $section, $data);
|
154 |
+
switch( $section ) {
|
155 |
+
case 'vcalendar':
|
156 |
+
return $ical->setCalendarInfo( $data );
|
157 |
+
case 'vevent':
|
158 |
+
return $ical->addEvent( $data );
|
159 |
+
case 'vjournal':
|
160 |
+
case 'vtodo':
|
161 |
+
return true; // TODO: Implement
|
162 |
+
case 'vtimezone':
|
163 |
+
return $ical->addTimeZone( $data );
|
164 |
+
}
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* This functions does some regexp checking to see if the value is
|
169 |
+
* valid UTF-8.
|
170 |
+
*
|
171 |
+
* The function is from the book "Building Scalable Web Sites" by
|
172 |
+
* Cal Henderson.
|
173 |
+
*
|
174 |
+
* @param string $data
|
175 |
+
* @return bool
|
176 |
+
*/
|
177 |
+
private static function _ValidUtf8( $data ) {
|
178 |
+
$rx = '[\xC0-\xDF]([^\x80-\xBF]|$)';
|
179 |
+
$rx .= '|[\xE0-\xEF].{0,1}([^\x80-\xBF]|$)';
|
180 |
+
$rx .= '|[\xF0-\xF7].{0,2}([^\x80-\xBF]|$)';
|
181 |
+
$rx .= '|[\xF8-\xFB].{0,3}([^\x80-\xBF]|$)';
|
182 |
+
$rx .= '|[\xFC-\xFD].{0,4}([^\x80-\xBF]|$)';
|
183 |
+
$rx .= '|[\xFE-\xFE].{0,5}([^\x80-\xBF]|$)';
|
184 |
+
$rx .= '|[\x00-\x7F][\x80-\xBF]';
|
185 |
+
$rx .= '|[\xC0-\xDF].[\x80-\xBF]';
|
186 |
+
$rx .= '|[\xE0-\xEF]..[\x80-\xBF]';
|
187 |
+
$rx .= '|[\xF0-\xF7]...[\x80-\xBF]';
|
188 |
+
$rx .= '|[\xF8-\xFB]....[\x80-\xBF]';
|
189 |
+
$rx .= '|[\xFC-\xFD].....[\x80-\xBF]';
|
190 |
+
$rx .= '|[\xFE-\xFE]......[\x80-\xBF]';
|
191 |
+
$rx .= '|^[\x80-\xBF]';
|
192 |
+
|
193 |
+
return ( ! (bool) preg_match('!'.$rx.'!', $data) );
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
|
lib/helpers/SG_iCal_Query.php
ADDED
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A collection of functions to query the events in a calendar.
|
5 |
+
*
|
6 |
+
* @package SG_iCalReader
|
7 |
+
* @author Morten Fangel (C) 2008
|
8 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
9 |
+
*/
|
10 |
+
class SG_iCal_Query {
|
11 |
+
/**
|
12 |
+
* Returns all events from the calendar between two timestamps
|
13 |
+
*
|
14 |
+
* Note that the events returned needs only slightly overlap.
|
15 |
+
*
|
16 |
+
* @param SG_iCalReader|array $ical The calendar to query
|
17 |
+
* @param int $start
|
18 |
+
* @param int $end
|
19 |
+
* @return SG_iCal_VEvent[]
|
20 |
+
*/
|
21 |
+
public static function Between( $ical, $start, $end ) {
|
22 |
+
if( $ical instanceof SG_iCalReader ) {
|
23 |
+
$ical = $ical->getEvents();
|
24 |
+
}
|
25 |
+
if( !is_array($ical) ) {
|
26 |
+
throw new Exception('SG_iCal_Query::Between called with invalid input!');
|
27 |
+
}
|
28 |
+
|
29 |
+
$rtn = array();
|
30 |
+
foreach( $ical AS $e ) {
|
31 |
+
if( ($start <= $e->getStart() && $e->getStart() < $end)
|
32 |
+
|| ($start < $e->getRangeEnd() && $e->getRangeEnd() <= $end) ) {
|
33 |
+
$rtn[] = $e;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
return $rtn;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Returns all events from the calendar after a given timestamp
|
41 |
+
*
|
42 |
+
* @param SG_iCalReader|array $ical The calendar to query
|
43 |
+
* @param int $start
|
44 |
+
* @return SG_iCal_VEvent[]
|
45 |
+
*/
|
46 |
+
public static function After( $ical, $start ) {
|
47 |
+
if( $ical instanceof SG_iCalReader ) {
|
48 |
+
$ical = $ical->getEvents();
|
49 |
+
}
|
50 |
+
if( !is_array($ical) ) {
|
51 |
+
throw new Exception('SG_iCal_Query::After called with invalid input!');
|
52 |
+
}
|
53 |
+
|
54 |
+
$rtn = array();
|
55 |
+
foreach( $ical AS $e ) {
|
56 |
+
if($e->getStart() >= $start || $e->getRangeEnd() >= $start) {
|
57 |
+
$rtn[] = $e;
|
58 |
+
}
|
59 |
+
}
|
60 |
+
return $rtn;
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Sorts the events from the calendar after the specified column.
|
65 |
+
* Column can be all valid entires that getProperty can return.
|
66 |
+
* So stuff like uid, start, end, summary etc.
|
67 |
+
* @param SG_iCalReader|array $ical The calendar to query
|
68 |
+
* @param string $column
|
69 |
+
* @return SG_iCal_VEvent[]
|
70 |
+
*/
|
71 |
+
public static function Sort( $ical, $column ) {
|
72 |
+
if( $ical instanceof SG_iCalReader ) {
|
73 |
+
$ical = $ical->getEvents();
|
74 |
+
}
|
75 |
+
if( !is_array($ical) ) {
|
76 |
+
throw new Exception('SG_iCal_Query::Sort called with invalid input!');
|
77 |
+
}
|
78 |
+
|
79 |
+
$cmp = create_function('$a, $b', 'return strcmp($a->getProperty("' . $column . '"), $b->getProperty("' . $column . '"));');
|
80 |
+
usort($ical, $cmp);
|
81 |
+
return $ical;
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
lib/helpers/SG_iCal_Recurrence.php
ADDED
@@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php // BUILD: Remove line
|
2 |
+
|
3 |
+
/**
|
4 |
+
* A wrapper for recurrence rules in iCalendar. Parses the given line and puts the
|
5 |
+
* recurrence rules in the correct field of this object.
|
6 |
+
*
|
7 |
+
* See http://tools.ietf.org/html/rfc2445 for more information. Page 39 and onward contains more
|
8 |
+
* information on the recurrence rules themselves. Page 116 and onward contains
|
9 |
+
* some great examples which were often used for testing.
|
10 |
+
*
|
11 |
+
* @package SG_iCalReader
|
12 |
+
* @author Steven Oxley
|
13 |
+
* @license http://creativecommons.org/licenses/by-sa/2.5/dk/deed.en_GB CC-BY-SA-DK
|
14 |
+
*/
|
15 |
+
class SG_iCal_Recurrence {
|
16 |
+
|
17 |
+
public $rrule;
|
18 |
+
|
19 |
+
protected $freq;
|
20 |
+
|
21 |
+
protected $until;
|
22 |
+
protected $count;
|
23 |
+
|
24 |
+
protected $interval;
|
25 |
+
protected $bysecond;
|
26 |
+
protected $byminute;
|
27 |
+
protected $byhour;
|
28 |
+
protected $byday;
|
29 |
+
protected $bymonthday;
|
30 |
+
protected $byyearday;
|
31 |
+
protected $byyearno;
|
32 |
+
protected $bymonth;
|
33 |
+
protected $bysetpos;
|
34 |
+
|
35 |
+
protected $wkst;
|
36 |
+
|
37 |
+
/**
|
38 |
+
* A list of the properties that can have comma-separated lists for values.
|
39 |
+
* @var array
|
40 |
+
*/
|
41 |
+
protected $listProperties = array(
|
42 |
+
'bysecond', 'byminute', 'byhour', 'byday', 'bymonthday',
|
43 |
+
'byyearday', 'byyearno', 'bymonth', 'bysetpos'
|
44 |
+
);
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Creates an recurrence object with a passed in line. Parses the line.
|
48 |
+
* @param object $line an SG_iCal_Line object which will be parsed to get the
|
49 |
+
* desired information.
|
50 |
+
*/
|
51 |
+
public function __construct(SG_iCal_Line $line) {
|
52 |
+
$this->parseLine($line->getData());
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* Parses an 'RRULE' line and sets the member variables of this object.
|
57 |
+
* Expects a string that looks like this: 'FREQ=WEEKLY;INTERVAL=2;BYDAY=SU,TU,WE'
|
58 |
+
* @param string $line the line to be parsed
|
59 |
+
*/
|
60 |
+
protected function parseLine($line) {
|
61 |
+
$this->rrule = $line;
|
62 |
+
|
63 |
+
//split up the properties
|
64 |
+
$recurProperties = explode(';', $line);
|
65 |
+
$recur = array();
|
66 |
+
|
67 |
+
//loop through the properties in the line and set their associated
|
68 |
+
//member variables
|
69 |
+
foreach ($recurProperties as $property) {
|
70 |
+
$nameAndValue = explode('=', $property);
|
71 |
+
|
72 |
+
//need the lower-case name for setting the member variable
|
73 |
+
$propertyName = strtolower($nameAndValue[0]);
|
74 |
+
$propertyValue = $nameAndValue[1];
|
75 |
+
|
76 |
+
//split up the list of values into an array (if it's a list)
|
77 |
+
if (in_array($propertyName, $this->listProperties)) {
|
78 |
+
$propertyValue = explode(',', $propertyValue);
|
79 |
+
}
|
80 |
+
$this->$propertyName = $propertyValue;
|
81 |
+
}
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Set the $until member
|
86 |
+
* @param mixed timestamp (int) / Valid DateTime format (string)
|
87 |
+
*/
|
88 |
+
public function setUntil($ts) {
|
89 |
+
if ( is_int($ts) )
|
90 |
+
$dt = new DateTime('@'.$ts);
|
91 |
+
else
|
92 |
+
$dt = new DateTime($ts);
|
93 |
+
$this->until = $dt->format('Ymd\THisO');
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Retrieves the desired member variable and returns it (if it's set)
|
98 |
+
* @param string $member name of the member variable
|
99 |
+
* @return mixed the variable value (if set), false otherwise
|
100 |
+
*/
|
101 |
+
protected function getMember($member)
|
102 |
+
{
|
103 |
+
if (isset($this->$member)) {
|
104 |
+
return $this->$member;
|
105 |
+
}
|
106 |
+
return false;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Returns the frequency - corresponds to FREQ in RFC 2445.
|
111 |
+
* @return mixed string if the member has been set, false otherwise
|
112 |
+
*/
|
113 |
+
public function getFreq() {
|
114 |
+
return $this->getMember('freq');
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Returns when the event will go until - corresponds to UNTIL in RFC 2445.
|
119 |
+
* @return mixed string if the member has been set, false otherwise
|
120 |
+
*/
|
121 |
+
public function getUntil() {
|
122 |
+
return $this->getMember('until');
|
123 |
+
}
|
124 |
+
|
125 |
+
/**
|
126 |
+
* Returns the count of the times the event will occur (should only appear if 'until'
|
127 |
+
* does not appear) - corresponds to COUNT in RFC 2445.
|
128 |
+
* @return mixed string if the member has been set, false otherwise
|
129 |
+
*/
|
130 |
+
public function getCount() {
|
131 |
+
return $this->getMember('count');
|
132 |
+
}
|
133 |
+
|
134 |
+
/**
|
135 |
+
* Returns the interval - corresponds to INTERVAL in RFC 2445.
|
136 |
+
* @return mixed string if the member has been set, false otherwise
|
137 |
+
*/
|
138 |
+
public function getInterval() {
|
139 |
+
return $this->getMember('interval');
|
140 |
+
}
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Returns the bysecond part of the event - corresponds to BYSECOND in RFC 2445.
|
144 |
+
* @return mixed string if the member has been set, false otherwise
|
145 |
+
*/
|
146 |
+
public function getBySecond() {
|
147 |
+
return $this->getMember('bysecond');
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Returns the byminute information for the event - corresponds to BYMINUTE in RFC 2445.
|
152 |
+
* @return mixed string if the member has been set, false otherwise
|
153 |
+
*/
|
154 |
+
public function getByMinute() {
|
155 |
+
return $this->getMember('byminute');
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Corresponds to BYHOUR in RFC 2445.
|
160 |
+
* @return mixed string if the member has been set, false otherwise
|
161 |
+
*/
|
162 |
+
public function getByHour() {
|
163 |
+
return $this->getMember('byhour');
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
*Corresponds to BYDAY in RFC 2445.
|
168 |
+
* @return mixed string if the member has been set, false otherwise
|
169 |
+
*/
|
170 |
+
public function getByDay() {
|
171 |
+
return $this->getMember('byday');
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Corresponds to BYMONTHDAY in RFC 2445.
|
176 |
+
* @return mixed string if the member has been set, false otherwise
|
177 |
+
*/
|
178 |
+
public function getByMonthDay() {
|
179 |
+
return $this->getMember('bymonthday');
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Corresponds to BYYEARDAY in RFC 2445.
|
184 |
+
* @return mixed string if the member has been set, false otherwise
|
185 |
+
*/
|
186 |
+
public function getByYearDay() {
|
187 |
+
return $this->getMember('byyearday');
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Corresponds to BYYEARNO in RFC 2445.
|
192 |
+
* @return mixed string if the member has been set, false otherwise
|
193 |
+
*/
|
194 |
+
public function getByYearNo() {
|
195 |
+
return $this->getMember('byyearno');
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Corresponds to BYMONTH in RFC 2445.
|
200 |
+
* @return mixed string if the member has been set, false otherwise
|
201 |
+
*/
|
202 |
+
public function getByMonth() {
|
203 |
+
return $this->getMember('bymonth');
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Corresponds to BYSETPOS in RFC 2445.
|
208 |
+
* @return mixed string if the member has been set, false otherwise
|
209 |
+
*/
|
210 |
+
public function getBySetPos() {
|
211 |
+
return $this->getMember('bysetpos');
|
212 |
+
}
|
213 |
+
|
214 |
+
/**
|
215 |
+
* Corresponds to WKST in RFC 2445.
|
216 |
+
* @return mixed string if the member has been set, false otherwise
|
217 |
+
*/
|
218 |
+
public function getWkst() {
|
219 |
+
return $this->getMember('wkst');
|
220 |
+
}
|
221 |
+
}
|
lib/iCalUtilityFunctions.class.php
ADDED
@@ -0,0 +1,1505 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* iCalcreator class v2.10
|
4 |
+
* copyright (c) 2007-2011 Kjell-Inge Gustafsson kigkonsult
|
5 |
+
* www.kigkonsult.se/iCalcreator/index.php
|
6 |
+
* ical@kigkonsult.se
|
7 |
+
*
|
8 |
+
* This library is free software; you can redistribute it and/or
|
9 |
+
* modify it under the terms of the GNU Lesser General Public
|
10 |
+
* License as published by the Free Software Foundation; either
|
11 |
+
* version 2.1 of the License, or (at your option) any later version.
|
12 |
+
*
|
13 |
+
* This library is distributed in the hope that it will be useful,
|
14 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
16 |
+
* Lesser General Public License for more details.
|
17 |
+
*
|
18 |
+
* You should have received a copy of the GNU Lesser General Public
|
19 |
+
* License along with this library; if not, write to the Free Software
|
20 |
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
21 |
+
*/
|
22 |
+
/**
|
23 |
+
* moving all utility (static) functions to a utility class
|
24 |
+
*
|
25 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
26 |
+
* @since 2.6.22 - 2010-09-25
|
27 |
+
*
|
28 |
+
*/
|
29 |
+
class iCalUtilityFunctions {
|
30 |
+
// Store the single instance of iCalUtilityFunctions
|
31 |
+
private static $m_pInstance;
|
32 |
+
|
33 |
+
// Private constructor to limit object instantiation to within the class
|
34 |
+
private function __construct() {
|
35 |
+
$m_pInstance = FALSE;
|
36 |
+
}
|
37 |
+
|
38 |
+
// Getter method for creating/returning the single instance of this class
|
39 |
+
public static function getInstance() {
|
40 |
+
if (!self::$m_pInstance)
|
41 |
+
self::$m_pInstance = new iCalUtilityFunctions();
|
42 |
+
|
43 |
+
return self::$m_pInstance;
|
44 |
+
}
|
45 |
+
/**
|
46 |
+
* check a date(-time) for an opt. timezone and if it is a DATE-TIME or DATE
|
47 |
+
*
|
48 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
49 |
+
* @since 2.4.16 - 2008-10-25
|
50 |
+
* @param array $date, date to check
|
51 |
+
* @param int $parno, no of date parts (i.e. year, month.. .)
|
52 |
+
* @return array $params, property parameters
|
53 |
+
*/
|
54 |
+
public static function _chkdatecfg( $theDate, & $parno, & $params ) {
|
55 |
+
if( isset( $params['TZID'] ))
|
56 |
+
$parno = 6;
|
57 |
+
elseif( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] ))
|
58 |
+
$parno = 3;
|
59 |
+
else {
|
60 |
+
if( isset( $params['VALUE'] ) && ( 'PERIOD' == $params['VALUE'] ))
|
61 |
+
$parno = 7;
|
62 |
+
if( is_array( $theDate )) {
|
63 |
+
if( isset( $theDate['timestamp'] ))
|
64 |
+
$tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : null;
|
65 |
+
else
|
66 |
+
$tzid = ( isset( $theDate['tz'] )) ? $theDate['tz'] : ( 7 == count( $theDate )) ? end( $theDate ) : null;
|
67 |
+
if( !empty( $tzid )) {
|
68 |
+
$parno = 7;
|
69 |
+
if( !iCalUtilityFunctions::_isOffset( $tzid ))
|
70 |
+
$params['TZID'] = $tzid; // save only timezone
|
71 |
+
}
|
72 |
+
elseif( !$parno && ( 3 == count( $theDate )) &&
|
73 |
+
( isset( $params['VALUE'] ) && ( 'DATE' == $params['VALUE'] )))
|
74 |
+
$parno = 3;
|
75 |
+
else
|
76 |
+
$parno = 6;
|
77 |
+
}
|
78 |
+
else { // string
|
79 |
+
$date = trim( $theDate );
|
80 |
+
if( 'Z' == substr( $date, -1 ))
|
81 |
+
$parno = 7; // UTC DATE-TIME
|
82 |
+
elseif((( 8 == strlen( $date ) && ctype_digit( $date )) || ( 11 >= strlen( $date ))) &&
|
83 |
+
( !isset( $params['VALUE'] ) || !in_array( $params['VALUE'], array( 'DATE-TIME', 'PERIOD' ))))
|
84 |
+
$parno = 3; // DATE
|
85 |
+
$date = iCalUtilityFunctions::_date_time_string( $date, $parno );
|
86 |
+
if( !empty( $date['tz'] )) {
|
87 |
+
$parno = 7;
|
88 |
+
if( !iCalUtilityFunctions::_isOffset( $date['tz'] ))
|
89 |
+
$params['TZID'] = $date['tz']; // save only timezone
|
90 |
+
}
|
91 |
+
elseif( empty( $parno ))
|
92 |
+
$parno = 6;
|
93 |
+
}
|
94 |
+
if( isset( $params['TZID'] ))
|
95 |
+
$parno = 6;
|
96 |
+
}
|
97 |
+
}
|
98 |
+
/**
|
99 |
+
* create (very simple) timezone and standard/daylight components
|
100 |
+
*
|
101 |
+
* Result when 'Europe/Stockholm' is used as timezone:
|
102 |
+
*
|
103 |
+
* BEGIN:VTIMEZONE
|
104 |
+
* TZID:Europe/Stockholm
|
105 |
+
* BEGIN:STANDARD
|
106 |
+
* DTSTART:20101031T020000
|
107 |
+
* TZOFFSETFROM:+0200
|
108 |
+
* TZOFFSETTO:+0100
|
109 |
+
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
|
110 |
+
* TZNAME:CET
|
111 |
+
* END:STANDARD
|
112 |
+
* BEGIN:DAYLIGHT
|
113 |
+
* DTSTART:20100328T030000
|
114 |
+
* TZOFFSETFROM:+0100
|
115 |
+
* TZOFFSETTO:+0200
|
116 |
+
* RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
|
117 |
+
* TZNAME:CEST
|
118 |
+
* END:DAYLIGHT
|
119 |
+
* END:VTIMEZONE
|
120 |
+
*
|
121 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
122 |
+
* @since 2.9.2 - 2011-05-30
|
123 |
+
* @param object $calendar, reference to an iCalcreator calendar instance
|
124 |
+
* @param string $timezone, a PHP5 (DateTimeZone) valid timezone
|
125 |
+
* @param array $xProp, *[x-propName => x-propValue], optional
|
126 |
+
* @return bool
|
127 |
+
*/
|
128 |
+
public static function createTimezone( & $calendar, $timezone, $xProp=array() ) {
|
129 |
+
if( !class_exists( 'DateTimeZone' ))
|
130 |
+
return FALSE;
|
131 |
+
if( empty( $timezone ))
|
132 |
+
return FALSE;
|
133 |
+
try {
|
134 |
+
$dtz = new DateTimeZone( $timezone );
|
135 |
+
$transitions = $dtz->getTransitions();
|
136 |
+
$stdDTSTART = $stdTZOFFSETTO = $stdTZOFFSETFROM = $stdTZNAME = $dlghtDTSTART = $dlghtTZOFFSETTO = $dlghtTZOFFSETFROM = $dlghtTZNAME = FALSE;
|
137 |
+
foreach( $transitions as $trans ) {
|
138 |
+
if( substr( $trans['time'], 0, 4 ) > ( date( 'Y' ) - 1 ))
|
139 |
+
break;
|
140 |
+
if( $trans['isdst'] !== TRUE ) {
|
141 |
+
$stdDTSTART = $trans['time'];
|
142 |
+
$stdTZOFFSETTO = $dlghtTZOFFSETFROM = iCalUtilityFunctions::offsetSec2His( $trans['offset'] );
|
143 |
+
$stdTZNAME = $trans['abbr'];
|
144 |
+
}
|
145 |
+
else {
|
146 |
+
$dlghtDTSTART = $trans['time'];
|
147 |
+
$dlghtTZOFFSETTO = $stdTZOFFSETFROM = iCalUtilityFunctions::offsetSec2His( $trans['offset'] );
|
148 |
+
$dlghtTZNAME = $trans['abbr'];
|
149 |
+
}
|
150 |
+
}
|
151 |
+
if( $stdDTSTART && $stdTZOFFSETTO && $stdTZOFFSETFROM && $stdTZNAME && $dlghtDTSTART && $dlghtTZOFFSETTO && $dlghtTZOFFSETFROM && $dlghtTZNAME ) {
|
152 |
+
$tz = & $calendar->newComponent( 'vtimezone' );
|
153 |
+
$tz->setproperty( 'tzid', $timezone );
|
154 |
+
if( !empty( $xProp )) {
|
155 |
+
foreach( $xProp as $xPropName => $xPropValue )
|
156 |
+
if( 'x-' == strtolower( substr( $xPropName, 0, 2 )))
|
157 |
+
$tz->setproperty( $xPropName, $xPropValue );
|
158 |
+
}
|
159 |
+
$std = & $tz->newComponent( 'standard' );
|
160 |
+
$std->setProperty( 'dtstart', $stdDTSTART );
|
161 |
+
$std->setProperty( 'tzname', $stdTZNAME );
|
162 |
+
$std->setProperty( 'tzoffsetto', $stdTZOFFSETTO );
|
163 |
+
$std->setProperty( 'tzoffsetfrom', $stdTZOFFSETFROM );
|
164 |
+
$std->setProperty( 'RRULE', array( 'FREQ' => 'YEARLY', 'BYDAY' => array( '-1', 'DAY' => 'SU' ), 'BYMONTH' => 10 ));
|
165 |
+
$dlght = & $tz->newComponent( 'daylight' );
|
166 |
+
$dlght->setProperty( 'dtstart', $dlghtDTSTART );
|
167 |
+
$dlght->setProperty( 'tzname', $dlghtTZNAME );
|
168 |
+
$dlght->setProperty( 'tzoffsetto', $dlghtTZOFFSETTO );
|
169 |
+
$dlght->setProperty( 'tzoffsetfrom', $dlghtTZOFFSETFROM );
|
170 |
+
$dlght->setProperty( 'RRULE', array( 'FREQ' => 'YEARLY', 'BYDAY' => array( '-1', 'DAY' => 'SU' ), 'BYMONTH' => 3 ));
|
171 |
+
}
|
172 |
+
}
|
173 |
+
catch( Exception $e ) {
|
174 |
+
return FALSE;
|
175 |
+
}
|
176 |
+
return TRUE;
|
177 |
+
}
|
178 |
+
/**
|
179 |
+
* convert date/datetime to timestamp
|
180 |
+
*
|
181 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
182 |
+
* @since 2.4.8 - 2008-10-30
|
183 |
+
* @param array $datetime datetime/(date)
|
184 |
+
* @param string $tz timezone
|
185 |
+
* @return timestamp
|
186 |
+
*/
|
187 |
+
public static function _date2timestamp( $datetime, $tz=null ) {
|
188 |
+
$output = null;
|
189 |
+
if( !isset( $datetime['hour'] )) $datetime['hour'] = '0';
|
190 |
+
if( !isset( $datetime['min'] )) $datetime['min'] = '0';
|
191 |
+
if( !isset( $datetime['sec'] )) $datetime['sec'] = '0';
|
192 |
+
foreach( $datetime as $dkey => $dvalue ) {
|
193 |
+
if( 'tz' != $dkey )
|
194 |
+
$datetime[$dkey] = (integer) $dvalue;
|
195 |
+
}
|
196 |
+
if( $tz )
|
197 |
+
$datetime['tz'] = $tz;
|
198 |
+
$offset = ( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) ? iCalUtilityFunctions::_tz2offset( $datetime['tz'] ) : 0;
|
199 |
+
$output = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year'] );
|
200 |
+
return $output;
|
201 |
+
}
|
202 |
+
/**
|
203 |
+
* ensures internal date-time/date format for input date-time/date in array format
|
204 |
+
*
|
205 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
206 |
+
* @since 0.3.0 - 2006-08-15
|
207 |
+
* @param array $datetime
|
208 |
+
* @param int $parno optional, default FALSE
|
209 |
+
* @return array
|
210 |
+
*/
|
211 |
+
public static function _date_time_array( $datetime, $parno=FALSE ) {
|
212 |
+
$output = array();
|
213 |
+
foreach( $datetime as $dateKey => $datePart ) {
|
214 |
+
switch ( $dateKey ) {
|
215 |
+
case '0': case 'year': $output['year'] = $datePart; break;
|
216 |
+
case '1': case 'month': $output['month'] = $datePart; break;
|
217 |
+
case '2': case 'day': $output['day'] = $datePart; break;
|
218 |
+
}
|
219 |
+
if( 3 != $parno ) {
|
220 |
+
switch ( $dateKey ) {
|
221 |
+
case '0':
|
222 |
+
case '1':
|
223 |
+
case '2': break;
|
224 |
+
case '3': case 'hour': $output['hour'] = $datePart; break;
|
225 |
+
case '4': case 'min' : $output['min'] = $datePart; break;
|
226 |
+
case '5': case 'sec' : $output['sec'] = $datePart; break;
|
227 |
+
case '6': case 'tz' : $output['tz'] = $datePart; break;
|
228 |
+
}
|
229 |
+
}
|
230 |
+
}
|
231 |
+
if( 3 != $parno ) {
|
232 |
+
if( !isset( $output['hour'] ))
|
233 |
+
$output['hour'] = 0;
|
234 |
+
if( !isset( $output['min'] ))
|
235 |
+
$output['min'] = 0;
|
236 |
+
if( !isset( $output['sec'] ))
|
237 |
+
$output['sec'] = 0;
|
238 |
+
}
|
239 |
+
return $output;
|
240 |
+
}
|
241 |
+
/**
|
242 |
+
* ensures internal date-time/date format for input date-time/date in string fromat
|
243 |
+
*
|
244 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
245 |
+
* @since 2.6.35 - 2010-12-03
|
246 |
+
* @param array $datetime
|
247 |
+
* @param int $parno optional, default FALSE
|
248 |
+
* @return array
|
249 |
+
*/
|
250 |
+
public static function _date_time_string( $datetime, $parno=FALSE ) {
|
251 |
+
$datetime = (string) trim( $datetime );
|
252 |
+
$tz = null;
|
253 |
+
$len = strlen( $datetime ) - 1;
|
254 |
+
if( 'Z' == substr( $datetime, -1 )) {
|
255 |
+
$tz = 'Z';
|
256 |
+
$datetime = trim( substr( $datetime, 0, $len ));
|
257 |
+
}
|
258 |
+
elseif( ( ctype_digit( substr( $datetime, -2, 2 ))) && // time or date
|
259 |
+
( '-' == substr( $datetime, -3, 1 )) ||
|
260 |
+
( ':' == substr( $datetime, -3, 1 )) ||
|
261 |
+
( '.' == substr( $datetime, -3, 1 ))) {
|
262 |
+
$continue = TRUE;
|
263 |
+
}
|
264 |
+
elseif( ( ctype_digit( substr( $datetime, -4, 4 ))) && // 4 pos offset
|
265 |
+
( ' +' == substr( $datetime, -6, 2 )) ||
|
266 |
+
( ' -' == substr( $datetime, -6, 2 ))) {
|
267 |
+
$tz = substr( $datetime, -5, 5 );
|
268 |
+
$datetime = substr( $datetime, 0, ($len - 5));
|
269 |
+
}
|
270 |
+
elseif( ( ctype_digit( substr( $datetime, -6, 6 ))) && // 6 pos offset
|
271 |
+
( ' +' == substr( $datetime, -8, 2 )) ||
|
272 |
+
( ' -' == substr( $datetime, -8, 2 ))) {
|
273 |
+
$tz = substr( $datetime, -7, 7 );
|
274 |
+
$datetime = substr( $datetime, 0, ($len - 7));
|
275 |
+
}
|
276 |
+
elseif( ( 6 < $len ) && ( ctype_digit( substr( $datetime, -6, 6 )))) {
|
277 |
+
$continue = TRUE;
|
278 |
+
}
|
279 |
+
elseif( 'T' == substr( $datetime, -7, 1 )) {
|
280 |
+
$continue = TRUE;
|
281 |
+
}
|
282 |
+
else {
|
283 |
+
$cx = $tx = 0; // 19970415T133000 US-Eastern
|
284 |
+
for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
|
285 |
+
$char = substr( $datetime, $cx, 1 );
|
286 |
+
if(( ' ' == $char) || ctype_digit( $char))
|
287 |
+
break; // if exists, tz ends here.. . ?
|
288 |
+
else
|
289 |
+
$tx--; // tz length counter
|
290 |
+
}
|
291 |
+
if( 0 > $tx ) {
|
292 |
+
$tz = substr( $datetime, $tx );
|
293 |
+
$datetime = trim( substr( $datetime, 0, $len + $tx + 1 ));
|
294 |
+
}
|
295 |
+
}
|
296 |
+
if( 0 < substr_count( $datetime, '-' )) {
|
297 |
+
$datetime = str_replace( '-', '/', $datetime );
|
298 |
+
}
|
299 |
+
elseif( ctype_digit( substr( $datetime, 0, 8 )) &&
|
300 |
+
( 'T' == substr( $datetime, 8, 1 )) &&
|
301 |
+
ctype_digit( substr( $datetime, 9, 6 ))) {
|
302 |
+
$datetime = substr( $datetime, 4, 2 )
|
303 |
+
.'/'.substr( $datetime, 6, 2 )
|
304 |
+
.'/'.substr( $datetime, 0, 4 )
|
305 |
+
.' '.substr( $datetime, 9, 2 )
|
306 |
+
.':'.substr( $datetime, 11, 2 )
|
307 |
+
.':'.substr( $datetime, 13);
|
308 |
+
}
|
309 |
+
$datestring = date( 'Y-m-d H:i:s', strtotime( $datetime ));
|
310 |
+
$tz = trim( $tz );
|
311 |
+
$output = array();
|
312 |
+
$output['year'] = substr( $datestring, 0, 4 );
|
313 |
+
$output['month'] = substr( $datestring, 5, 2 );
|
314 |
+
$output['day'] = substr( $datestring, 8, 2 );
|
315 |
+
if(( 6 == $parno ) || ( 7 == $parno ) || ( !$parno && ( 'Z' == $tz ))) {
|
316 |
+
$output['hour'] = substr( $datestring, 11, 2 );
|
317 |
+
$output['min'] = substr( $datestring, 14, 2 );
|
318 |
+
$output['sec'] = substr( $datestring, 17, 2 );
|
319 |
+
if( !empty( $tz ))
|
320 |
+
$output['tz'] = $tz;
|
321 |
+
}
|
322 |
+
elseif( 3 != $parno ) {
|
323 |
+
if(( '00' < substr( $datestring, 11, 2 )) ||
|
324 |
+
( '00' < substr( $datestring, 14, 2 )) ||
|
325 |
+
( '00' < substr( $datestring, 17, 2 ))) {
|
326 |
+
$output['hour'] = substr( $datestring, 11, 2 );
|
327 |
+
$output['min'] = substr( $datestring, 14, 2 );
|
328 |
+
$output['sec'] = substr( $datestring, 17, 2 );
|
329 |
+
}
|
330 |
+
if( !empty( $tz ))
|
331 |
+
$output['tz'] = $tz;
|
332 |
+
}
|
333 |
+
return $output;
|
334 |
+
}
|
335 |
+
/**
|
336 |
+
* convert local startdate/enddate (Ymd[His]) to duration array
|
337 |
+
*
|
338 |
+
* uses this component dates if missing input dates
|
339 |
+
*
|
340 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
341 |
+
* @since 2.6.11 - 2010-10-21
|
342 |
+
* @param array $startdate
|
343 |
+
* @param array $duration
|
344 |
+
* @return array duration
|
345 |
+
*/
|
346 |
+
function _date2duration( $startdate, $enddate ) {
|
347 |
+
$startWdate = mktime( 0, 0, 0, $startdate['month'], $startdate['day'], $startdate['year'] );
|
348 |
+
$endWdate = mktime( 0, 0, 0, $enddate['month'], $enddate['day'], $enddate['year'] );
|
349 |
+
$wduration = $endWdate - $startWdate;
|
350 |
+
$dur = array();
|
351 |
+
$dur['week'] = (int) floor( $wduration / ( 7 * 24 * 60 * 60 ));
|
352 |
+
$wduration = $wduration % ( 7 * 24 * 60 * 60 );
|
353 |
+
$dur['day'] = (int) floor( $wduration / ( 24 * 60 * 60 ));
|
354 |
+
$wduration = $wduration % ( 24 * 60 * 60 );
|
355 |
+
$dur['hour'] = (int) floor( $wduration / ( 60 * 60 ));
|
356 |
+
$wduration = $wduration % ( 60 * 60 );
|
357 |
+
$dur['min'] = (int) floor( $wduration / ( 60 ));
|
358 |
+
$dur['sec'] = (int) $wduration % ( 60 );
|
359 |
+
return $dur;
|
360 |
+
}
|
361 |
+
/**
|
362 |
+
* ensures internal duration format for input in array format
|
363 |
+
*
|
364 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
365 |
+
* @since 2.1.1 - 2007-06-24
|
366 |
+
* @param array $duration
|
367 |
+
* @return array
|
368 |
+
*/
|
369 |
+
public static function _duration_array( $duration ) {
|
370 |
+
$output = array();
|
371 |
+
if( is_array( $duration ) &&
|
372 |
+
( 1 == count( $duration )) &&
|
373 |
+
isset( $duration['sec'] ) &&
|
374 |
+
( 60 < $duration['sec'] )) {
|
375 |
+
$durseconds = $duration['sec'];
|
376 |
+
$output['week'] = floor( $durseconds / ( 60 * 60 * 24 * 7 ));
|
377 |
+
$durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
|
378 |
+
$output['day'] = floor( $durseconds / ( 60 * 60 * 24 ));
|
379 |
+
$durseconds = $durseconds % ( 60 * 60 * 24 );
|
380 |
+
$output['hour'] = floor( $durseconds / ( 60 * 60 ));
|
381 |
+
$durseconds = $durseconds % ( 60 * 60 );
|
382 |
+
$output['min'] = floor( $durseconds / ( 60 ));
|
383 |
+
$output['sec'] = ( $durseconds % ( 60 ));
|
384 |
+
}
|
385 |
+
else {
|
386 |
+
foreach( $duration as $durKey => $durValue ) {
|
387 |
+
if( empty( $durValue )) continue;
|
388 |
+
switch ( $durKey ) {
|
389 |
+
case '0': case 'week': $output['week'] = $durValue; break;
|
390 |
+
case '1': case 'day': $output['day'] = $durValue; break;
|
391 |
+
case '2': case 'hour': $output['hour'] = $durValue; break;
|
392 |
+
case '3': case 'min': $output['min'] = $durValue; break;
|
393 |
+
case '4': case 'sec': $output['sec'] = $durValue; break;
|
394 |
+
}
|
395 |
+
}
|
396 |
+
}
|
397 |
+
if( isset( $output['week'] ) && ( 0 < $output['week'] )) {
|
398 |
+
unset( $output['day'], $output['hour'], $output['min'], $output['sec'] );
|
399 |
+
return $output;
|
400 |
+
}
|
401 |
+
unset( $output['week'] );
|
402 |
+
if( empty( $output['day'] ))
|
403 |
+
unset( $output['day'] );
|
404 |
+
if ( isset( $output['hour'] ) || isset( $output['min'] ) || isset( $output['sec'] )) {
|
405 |
+
if( !isset( $output['hour'] )) $output['hour'] = 0;
|
406 |
+
if( !isset( $output['min'] )) $output['min'] = 0;
|
407 |
+
if( !isset( $output['sec'] )) $output['sec'] = 0;
|
408 |
+
if(( 0 == $output['hour'] ) && ( 0 == $output['min'] ) && ( 0 == $output['sec'] ))
|
409 |
+
unset( $output['hour'], $output['min'], $output['sec'] );
|
410 |
+
}
|
411 |
+
return $output;
|
412 |
+
}
|
413 |
+
/**
|
414 |
+
* ensures internal duration format for input in string format
|
415 |
+
*
|
416 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
417 |
+
* @since 2.0.5 - 2007-03-14
|
418 |
+
* @param string $duration
|
419 |
+
* @return array
|
420 |
+
*/
|
421 |
+
public static function _duration_string( $duration ) {
|
422 |
+
$duration = (string) trim( $duration );
|
423 |
+
while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
|
424 |
+
if( 0 < strlen( $duration ))
|
425 |
+
$duration = substr( $duration, 1 );
|
426 |
+
else
|
427 |
+
return false; // no leading P !?!?
|
428 |
+
}
|
429 |
+
$duration = substr( $duration, 1 ); // skip P
|
430 |
+
$duration = str_replace ( 't', 'T', $duration );
|
431 |
+
$duration = str_replace ( 'T', '', $duration );
|
432 |
+
$output = array();
|
433 |
+
$val = null;
|
434 |
+
for( $ix=0; $ix < strlen( $duration ); $ix++ ) {
|
435 |
+
switch( strtoupper( substr( $duration, $ix, 1 ))) {
|
436 |
+
case 'W':
|
437 |
+
$output['week'] = $val;
|
438 |
+
$val = null;
|
439 |
+
break;
|
440 |
+
case 'D':
|
441 |
+
$output['day'] = $val;
|
442 |
+
$val = null;
|
443 |
+
break;
|
444 |
+
case 'H':
|
445 |
+
$output['hour'] = $val;
|
446 |
+
$val = null;
|
447 |
+
break;
|
448 |
+
case 'M':
|
449 |
+
$output['min'] = $val;
|
450 |
+
$val = null;
|
451 |
+
break;
|
452 |
+
case 'S':
|
453 |
+
$output['sec'] = $val;
|
454 |
+
$val = null;
|
455 |
+
break;
|
456 |
+
default:
|
457 |
+
if( !ctype_digit( substr( $duration, $ix, 1 )))
|
458 |
+
return false; // unknown duration control character !?!?
|
459 |
+
else
|
460 |
+
$val .= substr( $duration, $ix, 1 );
|
461 |
+
}
|
462 |
+
}
|
463 |
+
return iCalUtilityFunctions::_duration_array( $output );
|
464 |
+
}
|
465 |
+
/**
|
466 |
+
* convert duration to date in array format
|
467 |
+
*
|
468 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
469 |
+
* @since 2.8.7 - 2011-03-03
|
470 |
+
* @param array $startdate
|
471 |
+
* @param array $duration
|
472 |
+
* @return array, date format
|
473 |
+
*/
|
474 |
+
function _duration2date( $startdate=null, $duration=null ) {
|
475 |
+
if( empty( $startdate )) return FALSE;
|
476 |
+
if( empty( $duration )) return FALSE;
|
477 |
+
$dateOnly = ( isset( $startdate['hour'] ) || isset( $startdate['min'] ) || isset( $startdate['sec'] )) ? FALSE : TRUE;
|
478 |
+
$startdate['hour'] = ( isset( $startdate['hour'] )) ? $startdate['hour'] : 0;
|
479 |
+
$startdate['min'] = ( isset( $startdate['min'] )) ? $startdate['min'] : 0;
|
480 |
+
$startdate['sec'] = ( isset( $startdate['sec'] )) ? $startdate['sec'] : 0;
|
481 |
+
$dtend = 0;
|
482 |
+
if( isset( $duration['week'] ))
|
483 |
+
$dtend += ( $duration['week'] * 7 * 24 * 60 * 60 );
|
484 |
+
if( isset( $duration['day'] ))
|
485 |
+
$dtend += ( $duration['day'] * 24 * 60 * 60 );
|
486 |
+
if( isset( $duration['hour'] ))
|
487 |
+
$dtend += ( $duration['hour'] * 60 *60 );
|
488 |
+
if( isset( $duration['min'] ))
|
489 |
+
$dtend += ( $duration['min'] * 60 );
|
490 |
+
if( isset( $duration['sec'] ))
|
491 |
+
$dtend += $duration['sec'];
|
492 |
+
$dtend = mktime( $startdate['hour'], $startdate['min'], ( $startdate['sec'] + $dtend ), $startdate['month'], $startdate['day'], $startdate['year'] );
|
493 |
+
$dtend2 = array();
|
494 |
+
$dtend2['year'] = date('Y', $dtend );
|
495 |
+
$dtend2['month'] = date('m', $dtend );
|
496 |
+
$dtend2['day'] = date('d', $dtend );
|
497 |
+
$dtend2['hour'] = date('H', $dtend );
|
498 |
+
$dtend2['min'] = date('i', $dtend );
|
499 |
+
$dtend2['sec'] = date('s', $dtend );
|
500 |
+
if( isset( $startdate['tz'] ))
|
501 |
+
$dtend2['tz'] = $startdate['tz'];
|
502 |
+
if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
|
503 |
+
unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
|
504 |
+
return $dtend2;
|
505 |
+
}
|
506 |
+
/**
|
507 |
+
* if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue
|
508 |
+
*
|
509 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
510 |
+
* @since 2.4.16 - 2008-11-08
|
511 |
+
* @param array $array
|
512 |
+
* @param string $expkey, expected key
|
513 |
+
* @param string $expval, expected value
|
514 |
+
* @param int $hitVal optional, return value if found
|
515 |
+
* @param int $elseVal optional, return value if not found
|
516 |
+
* @param int $preSet optional, return value if already preset
|
517 |
+
* @return int
|
518 |
+
*/
|
519 |
+
public static function _existRem( &$array, $expkey, $expval=FALSE, $hitVal=null, $elseVal=null, $preSet=null ) {
|
520 |
+
if( $preSet )
|
521 |
+
return $preSet;
|
522 |
+
if( !is_array( $array ) || ( 0 == count( $array )))
|
523 |
+
return $elseVal;
|
524 |
+
foreach( $array as $key => $value ) {
|
525 |
+
if( strtoupper( $expkey ) == strtoupper( $key )) {
|
526 |
+
if( !$expval || ( strtoupper( $expval ) == strtoupper( $array[$key] ))) {
|
527 |
+
unset( $array[$key] );
|
528 |
+
return $hitVal;
|
529 |
+
}
|
530 |
+
}
|
531 |
+
}
|
532 |
+
return $elseVal;
|
533 |
+
}
|
534 |
+
/**
|
535 |
+
* creates formatted output for calendar component property data value type date/date-time
|
536 |
+
*
|
537 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
538 |
+
* @since 2.4.8 - 2008-10-30
|
539 |
+
* @param array $datetime
|
540 |
+
* @param int $parno, optional, default 6
|
541 |
+
* @return string
|
542 |
+
*/
|
543 |
+
public static function _format_date_time( $datetime, $parno=6 ) {
|
544 |
+
if( !isset( $datetime['year'] ) &&
|
545 |
+
!isset( $datetime['month'] ) &&
|
546 |
+
!isset( $datetime['day'] ) &&
|
547 |
+
!isset( $datetime['hour'] ) &&
|
548 |
+
!isset( $datetime['min'] ) &&
|
549 |
+
!isset( $datetime['sec'] ))
|
550 |
+
return ;
|
551 |
+
$output = null;
|
552 |
+
// if( !isset( $datetime['day'] )) { $o=''; foreach($datetime as $k=>$v) {if(is_array($v)) $v=implode('-',$v);$o.=" $k=>$v";} echo " day SAKNAS : $o <br />\n"; }
|
553 |
+
foreach( $datetime as $dkey => & $dvalue )
|
554 |
+
if( 'tz' != $dkey ) $dvalue = (integer) $dvalue;
|
555 |
+
$output = date('Ymd', mktime( 0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year']));
|
556 |
+
if( isset( $datetime['hour'] ) ||
|
557 |
+
isset( $datetime['min'] ) ||
|
558 |
+
isset( $datetime['sec'] ) ||
|
559 |
+
isset( $datetime['tz'] )) {
|
560 |
+
if( isset( $datetime['tz'] ) &&
|
561 |
+
!isset( $datetime['hour'] ))
|
562 |
+
$datetime['hour'] = 0;
|
563 |
+
if( isset( $datetime['hour'] ) &&
|
564 |
+
!isset( $datetime['min'] ))
|
565 |
+
$datetime['min'] = 0;
|
566 |
+
if( isset( $datetime['hour'] ) &&
|
567 |
+
isset( $datetime['min'] ) &&
|
568 |
+
!isset( $datetime['sec'] ))
|
569 |
+
$datetime['sec'] = 0;
|
570 |
+
$date = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']);
|
571 |
+
$output .= date('\THis', $date );
|
572 |
+
if( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) {
|
573 |
+
$datetime['tz'] = trim( $datetime['tz'] );
|
574 |
+
if( 'Z' == $datetime['tz'] )
|
575 |
+
$output .= 'Z';
|
576 |
+
$offset = iCalUtilityFunctions::_tz2offset( $datetime['tz'] );
|
577 |
+
if( 0 != $offset ) {
|
578 |
+
$date = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']);
|
579 |
+
$output = date( 'Ymd\THis\Z', $date );
|
580 |
+
}
|
581 |
+
}
|
582 |
+
elseif( 7 == $parno )
|
583 |
+
$output .= 'Z';
|
584 |
+
}
|
585 |
+
return $output;
|
586 |
+
}
|
587 |
+
/**
|
588 |
+
* creates formatted output for calendar component property data value type duration
|
589 |
+
*
|
590 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
591 |
+
* @since 2.9.9 - 2011-06-17
|
592 |
+
* @param array $duration ( week, day, hour, min, sec )
|
593 |
+
* @return string
|
594 |
+
*/
|
595 |
+
public static function _format_duration( $duration ) {
|
596 |
+
if( isset( $duration['week'] ) ||
|
597 |
+
isset( $duration['day'] ) ||
|
598 |
+
isset( $duration['hour'] ) ||
|
599 |
+
isset( $duration['min'] ) ||
|
600 |
+
isset( $duration['sec'] ))
|
601 |
+
$ok = TRUE;
|
602 |
+
else
|
603 |
+
return;
|
604 |
+
if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
|
605 |
+
return 'P'.$duration['week'].'W';
|
606 |
+
$output = 'P';
|
607 |
+
if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
|
608 |
+
$output .= $duration['day'].'D';
|
609 |
+
if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
|
610 |
+
( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
|
611 |
+
( isset( $duration['sec']) && ( 0 < $duration['sec'] )))
|
612 |
+
$output .= 'T';
|
613 |
+
$output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '';
|
614 |
+
$output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '';
|
615 |
+
$output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '';
|
616 |
+
if( 'P' == $output )
|
617 |
+
$output = 'PT0S';
|
618 |
+
return $output;
|
619 |
+
}
|
620 |
+
/**
|
621 |
+
* checks if input array contains a date
|
622 |
+
*
|
623 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
624 |
+
* @since 2.4.16 - 2008-10-25
|
625 |
+
* @param array $input
|
626 |
+
* @return bool
|
627 |
+
*/
|
628 |
+
public static function _isArrayDate( $input ) {
|
629 |
+
if( isset( $input['week'] ) || ( !in_array( count( $input ), array( 3, 6, 7 ))))
|
630 |
+
return FALSE;
|
631 |
+
if( 7 == count( $input ))
|
632 |
+
return TRUE;
|
633 |
+
if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
|
634 |
+
return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
|
635 |
+
if( isset( $input['day'] ) || isset( $input['hour'] ) || isset( $input['min'] ) || isset( $input['sec'] ))
|
636 |
+
return FALSE;
|
637 |
+
if( in_array( 0, $input ))
|
638 |
+
return FALSE;
|
639 |
+
if(( 1970 > $input[0] ) || ( 12 < $input[1] ) || ( 31 < $input[2] ))
|
640 |
+
return FALSE;
|
641 |
+
if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
|
642 |
+
checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
|
643 |
+
return TRUE;
|
644 |
+
$input = iCalUtilityFunctions::_date_time_string( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
|
645 |
+
if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
|
646 |
+
return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
|
647 |
+
return FALSE;
|
648 |
+
}
|
649 |
+
/**
|
650 |
+
* checks if input array contains a timestamp date
|
651 |
+
*
|
652 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
653 |
+
* @since 2.4.16 - 2008-10-18
|
654 |
+
* @param array $input
|
655 |
+
* @return bool
|
656 |
+
*/
|
657 |
+
public static function _isArrayTimestampDate( $input ) {
|
658 |
+
return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
|
659 |
+
}
|
660 |
+
/**
|
661 |
+
* controll if input string contains trailing UTC offset
|
662 |
+
*
|
663 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
664 |
+
* @since 2.4.16 - 2008-10-19
|
665 |
+
* @param string $input
|
666 |
+
* @return bool
|
667 |
+
*/
|
668 |
+
public static function _isOffset( $input ) {
|
669 |
+
$input = trim( (string) $input );
|
670 |
+
if( 'Z' == substr( $input, -1 ))
|
671 |
+
return TRUE;
|
672 |
+
elseif(( 5 <= strlen( $input )) &&
|
673 |
+
( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
|
674 |
+
( '0000' < substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
|
675 |
+
return TRUE;
|
676 |
+
elseif(( 7 <= strlen( $input )) &&
|
677 |
+
( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
|
678 |
+
( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
|
679 |
+
return TRUE;
|
680 |
+
return FALSE;
|
681 |
+
|
682 |
+
}
|
683 |
+
/**
|
684 |
+
* transform offset in seconds to [-/+]hhmm[ss]
|
685 |
+
*
|
686 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
687 |
+
* @since 2011-05-02
|
688 |
+
* @param string $seconds
|
689 |
+
* @return string
|
690 |
+
*/
|
691 |
+
public static function offsetSec2His( $seconds ) {
|
692 |
+
if( '-' == substr( $seconds, 0, 1 )) {
|
693 |
+
$prefix = '-';
|
694 |
+
$seconds = substr( $seconds, 1 );
|
695 |
+
}
|
696 |
+
elseif( '+' == substr( $seconds, 0, 1 )) {
|
697 |
+
$prefix = '+';
|
698 |
+
$seconds = substr( $seconds, 1 );
|
699 |
+
}
|
700 |
+
else
|
701 |
+
$prefix = '+';
|
702 |
+
$output = '';
|
703 |
+
$hour = (int) floor( $seconds / 3600 );
|
704 |
+
if( 10 > $hour )
|
705 |
+
$hour = '0'.$hour;
|
706 |
+
$seconds = $seconds % 3600;
|
707 |
+
$min = (int) floor( $seconds / 60 );
|
708 |
+
if( 10 > $min )
|
709 |
+
$min = '0'.$min;
|
710 |
+
$output = $hour.$min;
|
711 |
+
$seconds = $seconds % 60;
|
712 |
+
if( 0 < $seconds) {
|
713 |
+
if( 9 < $seconds)
|
714 |
+
$output .= $seconds;
|
715 |
+
else
|
716 |
+
$output .= '0'.$seconds;
|
717 |
+
}
|
718 |
+
return $prefix.$output;
|
719 |
+
}
|
720 |
+
/**
|
721 |
+
* remakes a recur pattern to an array of dates
|
722 |
+
*
|
723 |
+
* if missing, UNTIL is set 1 year from startdate (emergency break)
|
724 |
+
*
|
725 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
726 |
+
* @since 2.9.10 - 2011-07-07
|
727 |
+
* @param array $result, array to update, array([timestamp] => timestamp)
|
728 |
+
* @param array $recur, pattern for recurrency (only value part, params ignored)
|
729 |
+
* @param array $wdate, component start date
|
730 |
+
* @param array $startdate, start date
|
731 |
+
* @param array $enddate, optional
|
732 |
+
* @return array of recurrence (start-)dates as index
|
733 |
+
* @todo BYHOUR, BYMINUTE, BYSECOND, ev. BYSETPOS due to ambiguity, WEEKLY at year end/start
|
734 |
+
*/
|
735 |
+
public static function _recur2date( & $result, $recur, $wdate, $startdate, $enddate=FALSE ) {
|
736 |
+
foreach( $wdate as $k => $v ) if( ctype_digit( $v )) $wdate[$k] = (int) $v;
|
737 |
+
$wdateStart = $wdate;
|
738 |
+
$wdatets = iCalUtilityFunctions::_date2timestamp( $wdate );
|
739 |
+
$startdatets = iCalUtilityFunctions::_date2timestamp( $startdate );
|
740 |
+
if( !$enddate ) {
|
741 |
+
$enddate = $startdate;
|
742 |
+
$enddate['year'] += 1;
|
743 |
+
}
|
744 |
+
// echo "recur __in_ comp start ".implode('-',$wdate)." period start ".implode('-',$startdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test###
|
745 |
+
$endDatets = iCalUtilityFunctions::_date2timestamp( $enddate ); // fix break
|
746 |
+
if( !isset( $recur['COUNT'] ) && !isset( $recur['UNTIL'] ))
|
747 |
+
$recur['UNTIL'] = $enddate; // create break
|
748 |
+
if( isset( $recur['UNTIL'] )) {
|
749 |
+
$tdatets = iCalUtilityFunctions::_date2timestamp( $recur['UNTIL'] );
|
750 |
+
if( $endDatets > $tdatets ) {
|
751 |
+
$endDatets = $tdatets; // emergency break
|
752 |
+
$enddate = iCalUtilityFunctions::_timestamp2date( $endDatets, 6 );
|
753 |
+
}
|
754 |
+
else
|
755 |
+
$recur['UNTIL'] = iCalUtilityFunctions::_timestamp2date( $endDatets, 6 );
|
756 |
+
}
|
757 |
+
if( $wdatets > $endDatets ) {
|
758 |
+
// echo "recur out of date ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
|
759 |
+
return array(); // nothing to do.. .
|
760 |
+
}
|
761 |
+
if( !isset( $recur['FREQ'] )) // "MUST be specified.. ."
|
762 |
+
$recur['FREQ'] = 'DAILY'; // ??
|
763 |
+
$wkst = ( isset( $recur['WKST'] ) && ( 'SU' == $recur['WKST'] )) ? 24*60*60 : 0; // ??
|
764 |
+
$weekStart = (int) date( 'W', ( $wdatets + $wkst ));
|
765 |
+
if( !isset( $recur['INTERVAL'] ))
|
766 |
+
$recur['INTERVAL'] = 1;
|
767 |
+
$countcnt = ( !isset( $recur['BYSETPOS'] )) ? 1 : 0; // DTSTART counts as the first occurrence
|
768 |
+
/* find out how to step up dates and set index for interval count */
|
769 |
+
$step = array();
|
770 |
+
if( 'YEARLY' == $recur['FREQ'] )
|
771 |
+
$step['year'] = 1;
|
772 |
+
elseif( 'MONTHLY' == $recur['FREQ'] )
|
773 |
+
$step['month'] = 1;
|
774 |
+
elseif( 'WEEKLY' == $recur['FREQ'] )
|
775 |
+
$step['day'] = 7;
|
776 |
+
else
|
777 |
+
$step['day'] = 1;
|
778 |
+
if( isset( $step['year'] ) && isset( $recur['BYMONTH'] ))
|
779 |
+
$step = array( 'month' => 1 );
|
780 |
+
if( empty( $step ) && isset( $recur['BYWEEKNO'] )) // ??
|
781 |
+
$step = array( 'day' => 7 );
|
782 |
+
if( isset( $recur['BYYEARDAY'] ) || isset( $recur['BYMONTHDAY'] ) || isset( $recur['BYDAY'] ))
|
783 |
+
$step = array( 'day' => 1 );
|
784 |
+
$intervalarr = array();
|
785 |
+
if( 1 < $recur['INTERVAL'] ) {
|
786 |
+
$intervalix = iCalUtilityFunctions::_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
|
787 |
+
$intervalarr = array( $intervalix => 0 );
|
788 |
+
}
|
789 |
+
if( isset( $recur['BYSETPOS'] )) { // save start date + weekno
|
790 |
+
$bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array();
|
791 |
+
// echo "bysetposXold_start=$bysetposYold $bysetposMold $bysetposDold<br />\n"; // test ###
|
792 |
+
if( is_array( $recur['BYSETPOS'] )) {
|
793 |
+
foreach( $recur['BYSETPOS'] as $bix => $bval )
|
794 |
+
$recur['BYSETPOS'][$bix] = (int) $bval;
|
795 |
+
}
|
796 |
+
else
|
797 |
+
$recur['BYSETPOS'] = array( (int) $recur['BYSETPOS'] );
|
798 |
+
if( 'YEARLY' == $recur['FREQ'] ) {
|
799 |
+
$wdate['month'] = $wdate['day'] = 1; // start from beginning of year
|
800 |
+
$wdatets = iCalUtilityFunctions::_date2timestamp( $wdate );
|
801 |
+
iCalUtilityFunctions::_stepdate( $enddate, $endDatets, array( 'year' => 1 )); // make sure to count whole last year
|
802 |
+
}
|
803 |
+
elseif( 'MONTHLY' == $recur['FREQ'] ) {
|
804 |
+
$wdate['day'] = 1; // start from beginning of month
|
805 |
+
$wdatets = iCalUtilityFunctions::_date2timestamp( $wdate );
|
806 |
+
iCalUtilityFunctions::_stepdate( $enddate, $endDatets, array( 'month' => 1 )); // make sure to count whole last month
|
807 |
+
}
|
808 |
+
else
|
809 |
+
iCalUtilityFunctions::_stepdate( $enddate, $endDatets, $step); // make sure to count whole last period
|
810 |
+
// echo "BYSETPOS endDat++ =".implode('-',$enddate).' step='.var_export($step,TRUE)."<br />\n";//test###
|
811 |
+
$bysetposWold = (int) date( 'W', ( $wdatets + $wkst ));
|
812 |
+
$bysetposYold = $wdate['year'];
|
813 |
+
$bysetposMold = $wdate['month'];
|
814 |
+
$bysetposDold = $wdate['day'];
|
815 |
+
}
|
816 |
+
else
|
817 |
+
iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step);
|
818 |
+
$year_old = null;
|
819 |
+
$daynames = array( 'SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA' );
|
820 |
+
/* MAIN LOOP */
|
821 |
+
// echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test
|
822 |
+
while( TRUE ) {
|
823 |
+
if( isset( $endDatets ) && ( $wdatets > $endDatets ))
|
824 |
+
break;
|
825 |
+
if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
|
826 |
+
break;
|
827 |
+
if( $year_old != $wdate['year'] ) {
|
828 |
+
$year_old = $wdate['year'];
|
829 |
+
$daycnts = array();
|
830 |
+
$yeardays = $weekno = 0;
|
831 |
+
$yeardaycnt = array();
|
832 |
+
for( $m = 1; $m <= 12; $m++ ) { // count up and update up-counters
|
833 |
+
$daycnts[$m] = array();
|
834 |
+
$weekdaycnt = array();
|
835 |
+
foreach( $daynames as $dn )
|
836 |
+
$yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
|
837 |
+
$mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
|
838 |
+
for( $d = 1; $d <= $mcnt; $d++ ) {
|
839 |
+
$daycnts[$m][$d] = array();
|
840 |
+
if( isset( $recur['BYYEARDAY'] )) {
|
841 |
+
$yeardays++;
|
842 |
+
$daycnts[$m][$d]['yearcnt_up'] = $yeardays;
|
843 |
+
}
|
844 |
+
if( isset( $recur['BYDAY'] )) {
|
845 |
+
$day = date( 'w', mktime( 0, 0, 0, $m, $d, $wdate['year'] ));
|
846 |
+
$day = $daynames[$day];
|
847 |
+
$daycnts[$m][$d]['DAY'] = $day;
|
848 |
+
$weekdaycnt[$day]++;
|
849 |
+
$daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day];
|
850 |
+
$yeardaycnt[$day]++;
|
851 |
+
$daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day];
|
852 |
+
}
|
853 |
+
if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
|
854 |
+
$daycnts[$m][$d]['weekno_up'] =(int)date('W',mktime(0,0,$wkst,$m,$d,$wdate['year']));
|
855 |
+
}
|
856 |
+
}
|
857 |
+
$daycnt = 0;
|
858 |
+
$yeardaycnt = array();
|
859 |
+
if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' )) {
|
860 |
+
$weekno = null;
|
861 |
+
for( $d=31; $d > 25; $d-- ) { // get last weekno for year
|
862 |
+
if( !$weekno )
|
863 |
+
$weekno = $daycnts[12][$d]['weekno_up'];
|
864 |
+
elseif( $weekno < $daycnts[12][$d]['weekno_up'] ) {
|
865 |
+
$weekno = $daycnts[12][$d]['weekno_up'];
|
866 |
+
break;
|
867 |
+
}
|
868 |
+
}
|
869 |
+
}
|
870 |
+
for( $m = 12; $m > 0; $m-- ) { // count down and update down-counters
|
871 |
+
$weekdaycnt = array();
|
872 |
+
foreach( $daynames as $dn )
|
873 |
+
$yeardaycnt[$dn] = $weekdaycnt[$dn] = 0;
|
874 |
+
$monthcnt = 0;
|
875 |
+
$mcnt = date( 't', mktime( 0, 0, 0, $m, 1, $wdate['year'] ));
|
876 |
+
for( $d = $mcnt; $d > 0; $d-- ) {
|
877 |
+
if( isset( $recur['BYYEARDAY'] )) {
|
878 |
+
$daycnt -= 1;
|
879 |
+
$daycnts[$m][$d]['yearcnt_down'] = $daycnt;
|
880 |
+
}
|
881 |
+
if( isset( $recur['BYMONTHDAY'] )) {
|
882 |
+
$monthcnt -= 1;
|
883 |
+
$daycnts[$m][$d]['monthcnt_down'] = $monthcnt;
|
884 |
+
}
|
885 |
+
if( isset( $recur['BYDAY'] )) {
|
886 |
+
$day = $daycnts[$m][$d]['DAY'];
|
887 |
+
$weekdaycnt[$day] -= 1;
|
888 |
+
$daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day];
|
889 |
+
$yeardaycnt[$day] -= 1;
|
890 |
+
$daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day];
|
891 |
+
}
|
892 |
+
if( isset( $recur['BYWEEKNO'] ) || ( $recur['FREQ'] == 'WEEKLY' ))
|
893 |
+
$daycnts[$m][$d]['weekno_down'] = ($daycnts[$m][$d]['weekno_up'] - $weekno - 1);
|
894 |
+
}
|
895 |
+
}
|
896 |
+
}
|
897 |
+
/* check interval */
|
898 |
+
if( 1 < $recur['INTERVAL'] ) {
|
899 |
+
/* create interval index */
|
900 |
+
$intervalix = iCalUtilityFunctions::_recurIntervalIx( $recur['FREQ'], $wdate, $wkst );
|
901 |
+
/* check interval */
|
902 |
+
$currentKey = array_keys( $intervalarr );
|
903 |
+
$currentKey = end( $currentKey ); // get last index
|
904 |
+
if( $currentKey != $intervalix )
|
905 |
+
$intervalarr = array( $intervalix => ( $intervalarr[$currentKey] + 1 ));
|
906 |
+
if(( $recur['INTERVAL'] != $intervalarr[$intervalix] ) &&
|
907 |
+
( 0 != $intervalarr[$intervalix] )) {
|
908 |
+
/* step up date */
|
909 |
+
// echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
|
910 |
+
iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step);
|
911 |
+
continue;
|
912 |
+
}
|
913 |
+
else // continue within the selected interval
|
914 |
+
$intervalarr[$intervalix] = 0;
|
915 |
+
// echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test
|
916 |
+
}
|
917 |
+
$updateOK = TRUE;
|
918 |
+
if( $updateOK && isset( $recur['BYMONTH'] ))
|
919 |
+
$updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYMONTH']
|
920 |
+
, $wdate['month']
|
921 |
+
,($wdate['month'] - 13));
|
922 |
+
if( $updateOK && isset( $recur['BYWEEKNO'] ))
|
923 |
+
$updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYWEEKNO']
|
924 |
+
, $daycnts[$wdate['month']][$wdate['day']]['weekno_up']
|
925 |
+
, $daycnts[$wdate['month']][$wdate['day']]['weekno_down'] );
|
926 |
+
if( $updateOK && isset( $recur['BYYEARDAY'] ))
|
927 |
+
$updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYYEARDAY']
|
928 |
+
, $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up']
|
929 |
+
, $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down'] );
|
930 |
+
if( $updateOK && isset( $recur['BYMONTHDAY'] ))
|
931 |
+
$updateOK = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYMONTHDAY']
|
932 |
+
, $wdate['day']
|
933 |
+
, $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down'] );
|
934 |
+
// echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test###
|
935 |
+
if( $updateOK && isset( $recur['BYDAY'] )) {
|
936 |
+
$updateOK = FALSE;
|
937 |
+
$m = $wdate['month'];
|
938 |
+
$d = $wdate['day'];
|
939 |
+
if( isset( $recur['BYDAY']['DAY'] )) { // single day, opt with year/month day order no
|
940 |
+
$daynoexists = $daynosw = $daynamesw = FALSE;
|
941 |
+
if( $recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY'] )
|
942 |
+
$daynamesw = TRUE;
|
943 |
+
if( isset( $recur['BYDAY'][0] )) {
|
944 |
+
$daynoexists = TRUE;
|
945 |
+
if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) || isset( $recur['BYMONTH'] ))
|
946 |
+
$daynosw = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYDAY'][0]
|
947 |
+
, $daycnts[$m][$d]['monthdayno_up']
|
948 |
+
, $daycnts[$m][$d]['monthdayno_down'] );
|
949 |
+
elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
|
950 |
+
$daynosw = iCalUtilityFunctions::_recurBYcntcheck( $recur['BYDAY'][0]
|
951 |
+
, $daycnts[$m][$d]['yeardayno_up']
|
952 |
+
, $daycnts[$m][$d]['yeardayno_down'] );
|
953 |
+
}
|
954 |
+
if(( $daynoexists && $daynosw && $daynamesw ) ||
|
955 |
+
( !$daynoexists && !$daynosw && $daynamesw )) {
|
956 |
+
$updateOK = TRUE;
|
957 |
+
}
|
958 |
+
// echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
|
959 |
+
}
|
960 |
+
else {
|
961 |
+
foreach( $recur['BYDAY'] as $bydayvalue ) {
|
962 |
+
$daynoexists = $daynosw = $daynamesw = FALSE;
|
963 |
+
if( isset( $bydayvalue['DAY'] ) &&
|
964 |
+
( $bydayvalue['DAY'] == $daycnts[$m][$d]['DAY'] ))
|
965 |
+
$daynamesw = TRUE;
|
966 |
+
if( isset( $bydayvalue[0] )) {
|
967 |
+
$daynoexists = TRUE;
|
968 |
+
if(( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'MONTHLY' )) ||
|
969 |
+
isset( $recur['BYMONTH'] ))
|
970 |
+
$daynosw = iCalUtilityFunctions::_recurBYcntcheck( $bydayvalue['0']
|
971 |
+
, $daycnts[$m][$d]['monthdayno_up']
|
972 |
+
, $daycnts[$m][$d]['monthdayno_down'] );
|
973 |
+
elseif( isset( $recur['FREQ'] ) && ( $recur['FREQ'] == 'YEARLY' ))
|
974 |
+
$daynosw = iCalUtilityFunctions::_recurBYcntcheck( $bydayvalue['0']
|
975 |
+
, $daycnts[$m][$d]['yeardayno_up']
|
976 |
+
, $daycnts[$m][$d]['yeardayno_down'] );
|
977 |
+
}
|
978 |
+
// echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ###
|
979 |
+
if(( $daynoexists && $daynosw && $daynamesw ) ||
|
980 |
+
( !$daynoexists && !$daynosw && $daynamesw )) {
|
981 |
+
$updateOK = TRUE;
|
982 |
+
break;
|
983 |
+
}
|
984 |
+
}
|
985 |
+
}
|
986 |
+
}
|
987 |
+
// echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ###
|
988 |
+
/* check BYSETPOS */
|
989 |
+
if( $updateOK ) {
|
990 |
+
if( isset( $recur['BYSETPOS'] ) &&
|
991 |
+
( in_array( $recur['FREQ'], array( 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY' )))) {
|
992 |
+
if( isset( $recur['WEEKLY'] )) {
|
993 |
+
if( $bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] )
|
994 |
+
$bysetposw1[] = $wdatets;
|
995 |
+
else
|
996 |
+
$bysetposw2[] = $wdatets;
|
997 |
+
}
|
998 |
+
else {
|
999 |
+
if(( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
|
1000 |
+
( $bysetposYold == $wdate['year'] )) ||
|
1001 |
+
( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] ) &&
|
1002 |
+
(( $bysetposYold == $wdate['year'] ) &&
|
1003 |
+
( $bysetposMold == $wdate['month'] ))) ||
|
1004 |
+
( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) &&
|
1005 |
+
(( $bysetposYold == $wdate['year'] ) &&
|
1006 |
+
( $bysetposMold == $wdate['month']) &&
|
1007 |
+
( $bysetposDold == $wdate['day'] )))) {
|
1008 |
+
// echo "bysetposymd1[]=".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
|
1009 |
+
$bysetposymd1[] = $wdatets;
|
1010 |
+
}
|
1011 |
+
else {
|
1012 |
+
// echo "bysetposymd2[]=".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
|
1013 |
+
$bysetposymd2[] = $wdatets;
|
1014 |
+
}
|
1015 |
+
}
|
1016 |
+
}
|
1017 |
+
else {
|
1018 |
+
/* update result array if BYSETPOS is set */
|
1019 |
+
$countcnt++;
|
1020 |
+
if( $startdatets <= $wdatets ) { // only output within period
|
1021 |
+
$result[$wdatets] = TRUE;
|
1022 |
+
// echo "recur ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test
|
1023 |
+
}
|
1024 |
+
// echo "recur undate ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$wdatets),6))." okdatstart ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$startdatets),6))."<br />\n";//test
|
1025 |
+
$updateOK = FALSE;
|
1026 |
+
}
|
1027 |
+
}
|
1028 |
+
/* step up date */
|
1029 |
+
iCalUtilityFunctions::_stepdate( $wdate, $wdatets, $step);
|
1030 |
+
/* check if BYSETPOS is set for updating result array */
|
1031 |
+
if( $updateOK && isset( $recur['BYSETPOS'] )) {
|
1032 |
+
$bysetpos = FALSE;
|
1033 |
+
if( isset( $recur['FREQ'] ) && ( 'YEARLY' == $recur['FREQ'] ) &&
|
1034 |
+
( $bysetposYold != $wdate['year'] )) {
|
1035 |
+
$bysetpos = TRUE;
|
1036 |
+
$bysetposYold = $wdate['year'];
|
1037 |
+
}
|
1038 |
+
elseif( isset( $recur['FREQ'] ) && ( 'MONTHLY' == $recur['FREQ'] &&
|
1039 |
+
(( $bysetposYold != $wdate['year'] ) || ( $bysetposMold != $wdate['month'] )))) {
|
1040 |
+
$bysetpos = TRUE;
|
1041 |
+
$bysetposYold = $wdate['year'];
|
1042 |
+
$bysetposMold = $wdate['month'];
|
1043 |
+
}
|
1044 |
+
elseif( isset( $recur['FREQ'] ) && ( 'WEEKLY' == $recur['FREQ'] )) {
|
1045 |
+
$weekno = (int) date( 'W', mktime( 0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year']));
|
1046 |
+
if( $bysetposWold != $weekno ) {
|
1047 |
+
$bysetposWold = $weekno;
|
1048 |
+
$bysetpos = TRUE;
|
1049 |
+
}
|
1050 |
+
}
|
1051 |
+
elseif( isset( $recur['FREQ'] ) && ( 'DAILY' == $recur['FREQ'] ) &&
|
1052 |
+
(( $bysetposYold != $wdate['year'] ) ||
|
1053 |
+
( $bysetposMold != $wdate['month'] ) ||
|
1054 |
+
( $bysetposDold != $wdate['day'] ))) {
|
1055 |
+
$bysetpos = TRUE;
|
1056 |
+
$bysetposYold = $wdate['year'];
|
1057 |
+
$bysetposMold = $wdate['month'];
|
1058 |
+
$bysetposDold = $wdate['day'];
|
1059 |
+
}
|
1060 |
+
if( $bysetpos ) {
|
1061 |
+
if( isset( $recur['BYWEEKNO'] )) {
|
1062 |
+
$bysetposarr1 = & $bysetposw1;
|
1063 |
+
$bysetposarr2 = & $bysetposw2;
|
1064 |
+
}
|
1065 |
+
else {
|
1066 |
+
$bysetposarr1 = & $bysetposymd1;
|
1067 |
+
$bysetposarr2 = & $bysetposymd2;
|
1068 |
+
}
|
1069 |
+
// echo 'test före out startYMD (weekno)='.$wdateStart['year'].':'.$wdateStart['month'].':'.$wdateStart['day']." ($weekStart) "; // test ###
|
1070 |
+
foreach( $recur['BYSETPOS'] as $ix ) {
|
1071 |
+
if( 0 > $ix ) // both positive and negative BYSETPOS allowed
|
1072 |
+
$ix = ( count( $bysetposarr1 ) + $ix + 1);
|
1073 |
+
$ix--;
|
1074 |
+
if( isset( $bysetposarr1[$ix] )) {
|
1075 |
+
if( $startdatets <= $bysetposarr1[$ix] ) { // only output within period
|
1076 |
+
// $testdate = iCalUtilityFunctions::_timestamp2date( $bysetposarr1[$ix], 6 ); // test ###
|
1077 |
+
// $testweekno = (int) date( 'W', mktime( 0, 0, $wkst, $testdate['month'], $testdate['day'], $testdate['year'] )); // test ###
|
1078 |
+
// echo " testYMD (weekno)=".$testdate['year'].':'.$testdate['month'].':'.$testdate['day']." ($testweekno)"; // test ###
|
1079 |
+
$result[$bysetposarr1[$ix]] = TRUE;
|
1080 |
+
// echo " recur ".implode('-',iCalUtilityFunctions::_date_time_string(date('Y-m-d H:i:s',$bysetposarr1[$ix]),6)); // test ###
|
1081 |
+
}
|
1082 |
+
$countcnt++;
|
1083 |
+
}
|
1084 |
+
if( isset( $recur['COUNT'] ) && ( $countcnt >= $recur['COUNT'] ))
|
1085 |
+
break;
|
1086 |
+
}
|
1087 |
+
// echo "<br />\n"; // test ###
|
1088 |
+
$bysetposarr1 = $bysetposarr2;
|
1089 |
+
$bysetposarr2 = array();
|
1090 |
+
}
|
1091 |
+
}
|
1092 |
+
}
|
1093 |
+
}
|
1094 |
+
public static function _recurBYcntcheck( $BYvalue, $upValue, $downValue ) {
|
1095 |
+
if( is_array( $BYvalue ) &&
|
1096 |
+
( in_array( $upValue, $BYvalue ) || in_array( $downValue, $BYvalue )))
|
1097 |
+
return TRUE;
|
1098 |
+
elseif(( $BYvalue == $upValue ) || ( $BYvalue == $downValue ))
|
1099 |
+
return TRUE;
|
1100 |
+
else
|
1101 |
+
return FALSE;
|
1102 |
+
}
|
1103 |
+
public static function _recurIntervalIx( $freq, $date, $wkst ) {
|
1104 |
+
/* create interval index */
|
1105 |
+
switch( $freq ) {
|
1106 |
+
case 'YEARLY':
|
1107 |
+
$intervalix = $date['year'];
|
1108 |
+
break;
|
1109 |
+
case 'MONTHLY':
|
1110 |
+
$intervalix = $date['year'].'-'.$date['month'];
|
1111 |
+
break;
|
1112 |
+
case 'WEEKLY':
|
1113 |
+
$wdatets = iCalUtilityFunctions::_date2timestamp( $date );
|
1114 |
+
$intervalix = (int) date( 'W', ( $wdatets + $wkst ));
|
1115 |
+
break;
|
1116 |
+
case 'DAILY':
|
1117 |
+
default:
|
1118 |
+
$intervalix = $date['year'].'-'.$date['month'].'-'.$date['day'];
|
1119 |
+
break;
|
1120 |
+
}
|
1121 |
+
return $intervalix;
|
1122 |
+
}
|
1123 |
+
/**
|
1124 |
+
* convert input format for exrule and rrule to internal format
|
1125 |
+
*
|
1126 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1127 |
+
* @since 2.9.10 - 2011-07-07
|
1128 |
+
* @param array $rexrule
|
1129 |
+
* @return array
|
1130 |
+
*/
|
1131 |
+
public static function _setRexrule( $rexrule ) {
|
1132 |
+
$input = array();
|
1133 |
+
if( empty( $rexrule ))
|
1134 |
+
return $input;
|
1135 |
+
foreach( $rexrule as $rexrulelabel => $rexrulevalue ) {
|
1136 |
+
$rexrulelabel = strtoupper( $rexrulelabel );
|
1137 |
+
if( 'UNTIL' != $rexrulelabel )
|
1138 |
+
$input[$rexrulelabel] = $rexrulevalue;
|
1139 |
+
else {
|
1140 |
+
if( iCalUtilityFunctions::_isArrayTimestampDate( $rexrulevalue )) // timestamp date
|
1141 |
+
$input[$rexrulelabel] = iCalUtilityFunctions::_timestamp2date( $rexrulevalue, 6 );
|
1142 |
+
elseif( iCalUtilityFunctions::_isArrayDate( $rexrulevalue )) // date-time
|
1143 |
+
$input[$rexrulelabel] = iCalUtilityFunctions::_date_time_array( $rexrulevalue, 6 );
|
1144 |
+
elseif( 8 <= strlen( trim( $rexrulevalue ))) // ex. 2006-08-03 10:12:18
|
1145 |
+
$input[$rexrulelabel] = iCalUtilityFunctions::_date_time_string( $rexrulevalue );
|
1146 |
+
if(( 3 < count( $input[$rexrulelabel] )) && !isset( $input[$rexrulelabel]['tz'] ))
|
1147 |
+
$input[$rexrulelabel]['tz'] = 'Z';
|
1148 |
+
}
|
1149 |
+
}
|
1150 |
+
/* set recurrence rule specification in rfc2445 order */
|
1151 |
+
$input2 = array();
|
1152 |
+
if( isset( $input['FREQ'] ))
|
1153 |
+
$input2['FREQ'] = $input['FREQ'];
|
1154 |
+
if( isset( $input['UNTIL'] ))
|
1155 |
+
$input2['UNTIL'] = $input['UNTIL'];
|
1156 |
+
elseif( isset( $input['COUNT'] ))
|
1157 |
+
$input2['COUNT'] = $input['COUNT'];
|
1158 |
+
if( isset( $input['INTERVAL'] ))
|
1159 |
+
$input2['INTERVAL'] = $input['INTERVAL'];
|
1160 |
+
if( isset( $input['BYSECOND'] ))
|
1161 |
+
$input2['BYSECOND'] = $input['BYSECOND'];
|
1162 |
+
if( isset( $input['BYMINUTE'] ))
|
1163 |
+
$input2['BYMINUTE'] = $input['BYMINUTE'];
|
1164 |
+
if( isset( $input['BYHOUR'] ))
|
1165 |
+
$input2['BYHOUR'] = $input['BYHOUR'];
|
1166 |
+
if( isset( $input['BYDAY'] )) {
|
1167 |
+
if( !is_array( $input['BYDAY'] )) // ensure upper case.. .
|
1168 |
+
$input2['BYDAY'] = strtoupper( $input['BYDAY'] );
|
1169 |
+
else {
|
1170 |
+
foreach( $input['BYDAY'] as $BYDAYx => $BYDAYv ) {
|
1171 |
+
if( 'DAY' == strtoupper( $BYDAYx ))
|
1172 |
+
$input2['BYDAY']['DAY'] = strtoupper( $BYDAYv );
|
1173 |
+
elseif( !is_array( $BYDAYv )) {
|
1174 |
+
$input2['BYDAY'][$BYDAYx] = $BYDAYv;
|
1175 |
+
}
|
1176 |
+
else {
|
1177 |
+
foreach( $BYDAYv as $BYDAYx2 => $BYDAYv2 ) {
|
1178 |
+
if( 'DAY' == strtoupper( $BYDAYx2 ))
|
1179 |
+
$input2['BYDAY'][$BYDAYx]['DAY'] = strtoupper( $BYDAYv2 );
|
1180 |
+
else
|
1181 |
+
$input2['BYDAY'][$BYDAYx][$BYDAYx2] = $BYDAYv2;
|
1182 |
+
}
|
1183 |
+
}
|
1184 |
+
}
|
1185 |
+
}
|
1186 |
+
}
|
1187 |
+
if( isset( $input['BYMONTHDAY'] ))
|
1188 |
+
$input2['BYMONTHDAY'] = $input['BYMONTHDAY'];
|
1189 |
+
if( isset( $input['BYYEARDAY'] ))
|
1190 |
+
$input2['BYYEARDAY'] = $input['BYYEARDAY'];
|
1191 |
+
if( isset( $input['BYWEEKNO'] ))
|
1192 |
+
$input2['BYWEEKNO'] = $input['BYWEEKNO'];
|
1193 |
+
if( isset( $input['BYMONTH'] ))
|
1194 |
+
$input2['BYMONTH'] = $input['BYMONTH'];
|
1195 |
+
if( isset( $input['BYSETPOS'] ))
|
1196 |
+
$input2['BYSETPOS'] = $input['BYSETPOS'];
|
1197 |
+
if( isset( $input['WKST'] ))
|
1198 |
+
$input2['WKST'] = $input['WKST'];
|
1199 |
+
return $input2;
|
1200 |
+
}
|
1201 |
+
/**
|
1202 |
+
* convert format for input date to internal date with parameters
|
1203 |
+
*
|
1204 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1205 |
+
* @since 2.9.6 - 2011-05-14
|
1206 |
+
* @param mixed $year
|
1207 |
+
* @param mixed $month optional
|
1208 |
+
* @param int $day optional
|
1209 |
+
* @param int $hour optional
|
1210 |
+
* @param int $min optional
|
1211 |
+
* @param int $sec optional
|
1212 |
+
* @param string $tz optional
|
1213 |
+
* @param array $params optional
|
1214 |
+
* @param string $caller optional
|
1215 |
+
* @param string $objName optional
|
1216 |
+
* @param string $tzid optional
|
1217 |
+
* @return array
|
1218 |
+
*/
|
1219 |
+
public static function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null, $objName=null, $tzid=FALSE ) {
|
1220 |
+
$input = $parno = null;
|
1221 |
+
$localtime = (( 'dtstart' == $caller ) && in_array( $objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
|
1222 |
+
if( iCalUtilityFunctions::_isArrayDate( $year )) {
|
1223 |
+
if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
|
1224 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
|
1225 |
+
if( isset( $input['params']['TZID'] )) {
|
1226 |
+
$input['params']['VALUE'] = 'DATE-TIME';
|
1227 |
+
unset( $year['tz'] );
|
1228 |
+
}
|
1229 |
+
$hitval = (( !empty( $year['tz'] ) || !empty( $year[6] ))) ? 7 : 6;
|
1230 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
|
1231 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $year ), $parno );
|
1232 |
+
$input['value'] = iCalUtilityFunctions::_date_time_array( $year, $parno );
|
1233 |
+
}
|
1234 |
+
elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
|
1235 |
+
if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
|
1236 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
|
1237 |
+
if( isset( $input['params']['TZID'] )) {
|
1238 |
+
$input['params']['VALUE'] = 'DATE-TIME';
|
1239 |
+
unset( $year['tz'] );
|
1240 |
+
}
|
1241 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
|
1242 |
+
$hitval = ( isset( $year['tz'] )) ? 7 : 6;
|
1243 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
|
1244 |
+
$input['value'] = iCalUtilityFunctions::_timestamp2date( $year, $parno );
|
1245 |
+
}
|
1246 |
+
elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
|
1247 |
+
if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
|
1248 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
|
1249 |
+
if( isset( $input['params']['TZID'] )) {
|
1250 |
+
$input['params']['VALUE'] = 'DATE-TIME';
|
1251 |
+
$parno = 6;
|
1252 |
+
}
|
1253 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
|
1254 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
|
1255 |
+
$input['value'] = iCalUtilityFunctions::_date_time_string( $year, $parno );
|
1256 |
+
}
|
1257 |
+
else {
|
1258 |
+
if( is_array( $params )) {
|
1259 |
+
if( $localtime ) unset ( $params['VALUE'], $params['TZID'] );
|
1260 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
|
1261 |
+
}
|
1262 |
+
elseif( is_array( $tz )) {
|
1263 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
|
1264 |
+
$tz = FALSE;
|
1265 |
+
}
|
1266 |
+
elseif( is_array( $hour )) {
|
1267 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
|
1268 |
+
$hour = $min = $sec = $tz = FALSE;
|
1269 |
+
}
|
1270 |
+
if( isset( $input['params']['TZID'] )) {
|
1271 |
+
$tz = null;
|
1272 |
+
$input['params']['VALUE'] = 'DATE-TIME';
|
1273 |
+
}
|
1274 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE', 3 );
|
1275 |
+
$hitval = ( !empty( $tz )) ? 7 : 6;
|
1276 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
|
1277 |
+
$input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
|
1278 |
+
if( 3 != $parno ) {
|
1279 |
+
$input['value']['hour'] = ( $hour ) ? $hour : '0';
|
1280 |
+
$input['value']['min'] = ( $min ) ? $min : '0';
|
1281 |
+
$input['value']['sec'] = ( $sec ) ? $sec : '0';
|
1282 |
+
if( !empty( $tz ))
|
1283 |
+
$input['value']['tz'] = $tz;
|
1284 |
+
}
|
1285 |
+
}
|
1286 |
+
if( 3 == $parno ) {
|
1287 |
+
$input['params']['VALUE'] = 'DATE';
|
1288 |
+
unset( $input['value']['tz'] );
|
1289 |
+
unset( $input['params']['TZID'] );
|
1290 |
+
}
|
1291 |
+
elseif( isset( $input['params']['TZID'] ))
|
1292 |
+
unset( $input['value']['tz'] );
|
1293 |
+
if( $localtime )
|
1294 |
+
unset( $input['value']['tz'], $input['params']['TZID'] );
|
1295 |
+
elseif(( !isset( $input['params']['VALUE'] ) || ( $input['params']['VALUE'] != 'DATE' )) && !isset( $input['params']['TZID'] ) && $tzid )
|
1296 |
+
$input['params']['TZID'] = $tzid;
|
1297 |
+
if( isset( $input['value']['tz'] ))
|
1298 |
+
$input['value']['tz'] = (string) $input['value']['tz'];
|
1299 |
+
if( !empty( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) &&
|
1300 |
+
( !iCalUtilityFunctions::_isOffset( $input['value']['tz'] )))
|
1301 |
+
$input['params']['TZID'] = $input['value']['tz'];
|
1302 |
+
return $input;
|
1303 |
+
}
|
1304 |
+
/**
|
1305 |
+
* convert format for input date (UTC) to internal date with parameters
|
1306 |
+
*
|
1307 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1308 |
+
* @since 2.4.17 - 2008-10-31
|
1309 |
+
* @param mixed $year
|
1310 |
+
* @param mixed $month optional
|
1311 |
+
* @param int $day optional
|
1312 |
+
* @param int $hour optional
|
1313 |
+
* @param int $min optional
|
1314 |
+
* @param int $sec optional
|
1315 |
+
* @param array $params optional
|
1316 |
+
* @return array
|
1317 |
+
*/
|
1318 |
+
public static function _setDate2( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
|
1319 |
+
$input = null;
|
1320 |
+
if( iCalUtilityFunctions::_isArrayDate( $year )) {
|
1321 |
+
$input['value'] = iCalUtilityFunctions::_date_time_array( $year, 7 );
|
1322 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
|
1323 |
+
}
|
1324 |
+
elseif( iCalUtilityFunctions::_isArrayTimestampDate( $year )) {
|
1325 |
+
$input['value'] = iCalUtilityFunctions::_timestamp2date( $year, 7 );
|
1326 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
|
1327 |
+
}
|
1328 |
+
elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
|
1329 |
+
$input['value'] = iCalUtilityFunctions::_date_time_string( $year, 7 );
|
1330 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
|
1331 |
+
}
|
1332 |
+
else {
|
1333 |
+
$input['value'] = array( 'year' => $year
|
1334 |
+
, 'month' => $month
|
1335 |
+
, 'day' => $day
|
1336 |
+
, 'hour' => $hour
|
1337 |
+
, 'min' => $min
|
1338 |
+
, 'sec' => $sec );
|
1339 |
+
$input['params'] = iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
|
1340 |
+
}
|
1341 |
+
$parno = iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
|
1342 |
+
if( !isset( $input['value']['hour'] ))
|
1343 |
+
$input['value']['hour'] = 0;
|
1344 |
+
if( !isset( $input['value']['min'] ))
|
1345 |
+
$input['value']['min'] = 0;
|
1346 |
+
if( !isset( $input['value']['sec'] ))
|
1347 |
+
$input['value']['sec'] = 0;
|
1348 |
+
if( !isset( $input['value']['tz'] ) || !iCalUtilityFunctions::_isOffset( $input['value']['tz'] ))
|
1349 |
+
$input['value']['tz'] = 'Z';
|
1350 |
+
return $input;
|
1351 |
+
}
|
1352 |
+
/**
|
1353 |
+
* check index and set (an indexed) content in multiple value array
|
1354 |
+
*
|
1355 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1356 |
+
* @since 2.6.12 - 2011-01-03
|
1357 |
+
* @param array $valArr
|
1358 |
+
* @param mixed $value
|
1359 |
+
* @param array $params
|
1360 |
+
* @param array $defaults
|
1361 |
+
* @param int $index
|
1362 |
+
* @return void
|
1363 |
+
*/
|
1364 |
+
public static function _setMval( & $valArr, $value, $params=FALSE, $defaults=FALSE, $index=FALSE ) {
|
1365 |
+
if( !is_array( $valArr )) $valArr = array();
|
1366 |
+
if( $index )
|
1367 |
+
$index = $index - 1;
|
1368 |
+
elseif( 0 < count( $valArr )) {
|
1369 |
+
$keys = array_keys( $valArr );
|
1370 |
+
$index = end( $keys ) + 1;
|
1371 |
+
}
|
1372 |
+
else
|
1373 |
+
$index = 0;
|
1374 |
+
$valArr[$index] = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params, $defaults ));
|
1375 |
+
ksort( $valArr );
|
1376 |
+
}
|
1377 |
+
/**
|
1378 |
+
* set input (formatted) parameters- component property attributes
|
1379 |
+
*
|
1380 |
+
* default parameters can be set, if missing
|
1381 |
+
*
|
1382 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1383 |
+
* @since 1.x.x - 2007-05-01
|
1384 |
+
* @param array $params
|
1385 |
+
* @param array $defaults
|
1386 |
+
* @return array
|
1387 |
+
*/
|
1388 |
+
public static function _setParams( $params, $defaults=FALSE ) {
|
1389 |
+
if( !is_array( $params))
|
1390 |
+
$params = array();
|
1391 |
+
$input = array();
|
1392 |
+
foreach( $params as $paramKey => $paramValue ) {
|
1393 |
+
if( is_array( $paramValue )) {
|
1394 |
+
foreach( $paramValue as $pkey => $pValue ) {
|
1395 |
+
if(( '"' == substr( $pValue, 0, 1 )) && ( '"' == substr( $pValue, -1 )))
|
1396 |
+
$paramValue[$pkey] = substr( $pValue, 1, ( strlen( $pValue ) - 2 ));
|
1397 |
+
}
|
1398 |
+
}
|
1399 |
+
elseif(( '"' == substr( $paramValue, 0, 1 )) && ( '"' == substr( $paramValue, -1 )))
|
1400 |
+
$paramValue = substr( $paramValue, 1, ( strlen( $paramValue ) - 2 ));
|
1401 |
+
if( 'VALUE' == strtoupper( $paramKey ))
|
1402 |
+
$input['VALUE'] = strtoupper( $paramValue );
|
1403 |
+
else
|
1404 |
+
$input[strtoupper( $paramKey )] = $paramValue;
|
1405 |
+
}
|
1406 |
+
if( is_array( $defaults )) {
|
1407 |
+
foreach( $defaults as $paramKey => $paramValue ) {
|
1408 |
+
if( !isset( $input[$paramKey] ))
|
1409 |
+
$input[$paramKey] = $paramValue;
|
1410 |
+
}
|
1411 |
+
}
|
1412 |
+
return (0 < count( $input )) ? $input : null;
|
1413 |
+
}
|
1414 |
+
/**
|
1415 |
+
* step date, return updated date, array and timpstamp
|
1416 |
+
*
|
1417 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1418 |
+
* @since 2.4.16 - 2008-10-18
|
1419 |
+
* @param array $date, date to step
|
1420 |
+
* @param int $timestamp
|
1421 |
+
* @param array $step, default array( 'day' => 1 )
|
1422 |
+
* @return void
|
1423 |
+
*/
|
1424 |
+
public static function _stepdate( &$date, &$timestamp, $step=array( 'day' => 1 )) {
|
1425 |
+
foreach( $step as $stepix => $stepvalue )
|
1426 |
+
$date[$stepix] += $stepvalue;
|
1427 |
+
$timestamp = iCalUtilityFunctions::_date2timestamp( $date );
|
1428 |
+
$date = iCalUtilityFunctions::_timestamp2date( $timestamp, 6 );
|
1429 |
+
foreach( $date as $k => $v ) {
|
1430 |
+
if( ctype_digit( $v ))
|
1431 |
+
$date[$k] = (int) $v;
|
1432 |
+
}
|
1433 |
+
}
|
1434 |
+
/**
|
1435 |
+
* convert timestamp to date array
|
1436 |
+
*
|
1437 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1438 |
+
* @since 2.4.16 - 2008-11-01
|
1439 |
+
* @param mixed $timestamp
|
1440 |
+
* @param int $parno
|
1441 |
+
* @return array
|
1442 |
+
*/
|
1443 |
+
public static function _timestamp2date( $timestamp, $parno=6 ) {
|
1444 |
+
if( is_array( $timestamp )) {
|
1445 |
+
if(( 7 == $parno ) && !empty( $timestamp['tz'] ))
|
1446 |
+
$tz = $timestamp['tz'];
|
1447 |
+
$timestamp = $timestamp['timestamp'];
|
1448 |
+
}
|
1449 |
+
$output = array( 'year' => date( 'Y', $timestamp )
|
1450 |
+
, 'month' => date( 'm', $timestamp )
|
1451 |
+
, 'day' => date( 'd', $timestamp ));
|
1452 |
+
if( 3 != $parno ) {
|
1453 |
+
$output['hour'] = date( 'H', $timestamp );
|
1454 |
+
$output['min'] = date( 'i', $timestamp );
|
1455 |
+
$output['sec'] = date( 's', $timestamp );
|
1456 |
+
if( isset( $tz ))
|
1457 |
+
$output['tz'] = $tz;
|
1458 |
+
}
|
1459 |
+
return $output;
|
1460 |
+
}
|
1461 |
+
/**
|
1462 |
+
* convert timestamp to duration in array format
|
1463 |
+
*
|
1464 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1465 |
+
* @since 2.6.23 - 2010-10-23
|
1466 |
+
* @param int $timestamp
|
1467 |
+
* @return array, duration format
|
1468 |
+
*/
|
1469 |
+
function _timestamp2duration( $timestamp ) {
|
1470 |
+
$dur = array();
|
1471 |
+
$dur['week'] = (int) floor( $timestamp / ( 7 * 24 * 60 * 60 ));
|
1472 |
+
$timestamp = $timestamp % ( 7 * 24 * 60 * 60 );
|
1473 |
+
$dur['day'] = (int) floor( $timestamp / ( 24 * 60 * 60 ));
|
1474 |
+
$timestamp = $timestamp % ( 24 * 60 * 60 );
|
1475 |
+
$dur['hour'] = (int) floor( $timestamp / ( 60 * 60 ));
|
1476 |
+
$timestamp = $timestamp % ( 60 * 60 );
|
1477 |
+
$dur['min'] = (int) floor( $timestamp / ( 60 ));
|
1478 |
+
$dur['sec'] = (int) $timestamp % ( 60 );
|
1479 |
+
return $dur;
|
1480 |
+
}
|
1481 |
+
/**
|
1482 |
+
* convert (numeric) local time offset to seconds correcting localtime to GMT
|
1483 |
+
*
|
1484 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1485 |
+
* @since 2.4.16 - 2008-10-19
|
1486 |
+
* @param string $offset
|
1487 |
+
* @return integer
|
1488 |
+
*/
|
1489 |
+
public static function _tz2offset( $tz ) {
|
1490 |
+
$tz = trim( (string) $tz );
|
1491 |
+
$offset = 0;
|
1492 |
+
if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
|
1493 |
+
(( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
|
1494 |
+
(( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
|
1495 |
+
(( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
|
1496 |
+
return $offset;
|
1497 |
+
$hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
|
1498 |
+
$min2sec = (int) substr( $tz, 3, 2 ) * 60;
|
1499 |
+
$sec = ( 7 == strlen( $tz )) ? (int) substr( $tz, -2 ) : '00';
|
1500 |
+
$offset = $hours2sec + $min2sec + $sec;
|
1501 |
+
$offset = ('-' == substr( $tz, 0, 1 )) ? $offset : -1 * $offset;
|
1502 |
+
return $offset;
|
1503 |
+
}
|
1504 |
+
}
|
1505 |
+
?>
|
lib/iCalcreator.class.php
ADDED
@@ -0,0 +1,6897 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*********************************************************************************/
|
3 |
+
/**
|
4 |
+
* iCalcreator class v2.10
|
5 |
+
* copyright (c) 2007-2011 Kjell-Inge Gustafsson kigkonsult
|
6 |
+
* www.kigkonsult.se/iCalcreator/index.php
|
7 |
+
* ical@kigkonsult.se
|
8 |
+
*
|
9 |
+
* Description:
|
10 |
+
* This file is a PHP implementation of RFC 2445.
|
11 |
+
*
|
12 |
+
* This library is free software; you can redistribute it and/or
|
13 |
+
* modify it under the terms of the GNU Lesser General Public
|
14 |
+
* License as published by the Free Software Foundation; either
|
15 |
+
* version 2.1 of the License, or (at your option) any later version.
|
16 |
+
*
|
17 |
+
* This library is distributed in the hope that it will be useful,
|
18 |
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19 |
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
20 |
+
* Lesser General Public License for more details.
|
21 |
+
*
|
22 |
+
* You should have received a copy of the GNU Lesser General Public
|
23 |
+
* License along with this library; if not, write to the Free Software
|
24 |
+
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
25 |
+
*/
|
26 |
+
/*********************************************************************************/
|
27 |
+
/*********************************************************************************/
|
28 |
+
/* A little setup */
|
29 |
+
/*********************************************************************************/
|
30 |
+
/* your local language code */
|
31 |
+
// define( 'ICAL_LANG', 'sv' );
|
32 |
+
// alt. autosetting
|
33 |
+
/*
|
34 |
+
$langstr = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
|
35 |
+
$pos = strpos( $langstr, ';' );
|
36 |
+
if ($pos !== false) {
|
37 |
+
$langstr = substr( $langstr, 0, $pos );
|
38 |
+
$pos = strpos( $langstr, ',' );
|
39 |
+
if ($pos !== false) {
|
40 |
+
$pos = strpos( $langstr, ',' );
|
41 |
+
$langstr = substr( $langstr, 0, $pos );
|
42 |
+
}
|
43 |
+
define( 'ICAL_LANG', $langstr );
|
44 |
+
}
|
45 |
+
*/
|
46 |
+
/*********************************************************************************/
|
47 |
+
/* only for phpversion 5.1 and later, */
|
48 |
+
/* date management, default timezone setting */
|
49 |
+
/* since 2.6.36 - 2010-12-31 */
|
50 |
+
if( substr( phpversion(), 0, 3) >= '5.1' )
|
51 |
+
// && ( 'UTC' == date_default_timezone_get()))
|
52 |
+
date_default_timezone_set( 'Europe/Stockholm' );
|
53 |
+
/*********************************************************************************/
|
54 |
+
/* since 2.6.22 - 2010-09-25, do NOT remove!! */
|
55 |
+
require_once ( 'iCalUtilityFunctions.class.php' );
|
56 |
+
/*********************************************************************************/
|
57 |
+
/* version, do NOT remove!! */
|
58 |
+
define( 'ICALCREATOR_VERSION', 'iCalcreator 2.10' );
|
59 |
+
/*********************************************************************************/
|
60 |
+
/*********************************************************************************/
|
61 |
+
/**
|
62 |
+
* vcalendar class
|
63 |
+
*
|
64 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
65 |
+
* @since 2.9.6 - 2011-05-14
|
66 |
+
*/
|
67 |
+
class vcalendar {
|
68 |
+
// calendar property variables
|
69 |
+
var $calscale;
|
70 |
+
var $method;
|
71 |
+
var $prodid;
|
72 |
+
var $version;
|
73 |
+
var $xprop;
|
74 |
+
// container for calendar components
|
75 |
+
var $components;
|
76 |
+
// component config variables
|
77 |
+
var $allowEmpty;
|
78 |
+
var $unique_id;
|
79 |
+
var $language;
|
80 |
+
var $directory;
|
81 |
+
var $filename;
|
82 |
+
var $url;
|
83 |
+
var $delimiter;
|
84 |
+
var $nl;
|
85 |
+
var $format;
|
86 |
+
var $dtzid;
|
87 |
+
// component internal variables
|
88 |
+
var $attributeDelimiter;
|
89 |
+
var $valueInit;
|
90 |
+
// component xCal declaration container
|
91 |
+
var $xcaldecl;
|
92 |
+
/**
|
93 |
+
* constructor for calendar object
|
94 |
+
*
|
95 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
96 |
+
* @since 2.9.6 - 2011-05-14
|
97 |
+
* @param array $config
|
98 |
+
* @return void
|
99 |
+
*/
|
100 |
+
function vcalendar ( $config = array()) {
|
101 |
+
$this->_makeVersion();
|
102 |
+
$this->calscale = null;
|
103 |
+
$this->method = null;
|
104 |
+
$this->_makeUnique_id();
|
105 |
+
$this->prodid = null;
|
106 |
+
$this->xprop = array();
|
107 |
+
$this->language = null;
|
108 |
+
$this->directory = null;
|
109 |
+
$this->filename = null;
|
110 |
+
$this->url = null;
|
111 |
+
$this->dtzid = null;
|
112 |
+
/**
|
113 |
+
* language = <Text identifying a language, as defined in [RFC 1766]>
|
114 |
+
*/
|
115 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
116 |
+
$config['language'] = ICAL_LANG;
|
117 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
118 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
119 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
120 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
121 |
+
$this->setConfig( $config );
|
122 |
+
|
123 |
+
$this->xcaldecl = array();
|
124 |
+
$this->components = array();
|
125 |
+
}
|
126 |
+
/*********************************************************************************/
|
127 |
+
/**
|
128 |
+
* Property Name: CALSCALE
|
129 |
+
*/
|
130 |
+
/**
|
131 |
+
* creates formatted output for calendar property calscale
|
132 |
+
*
|
133 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
134 |
+
* @since 2.4.8 - 2008-10-21
|
135 |
+
* @return string
|
136 |
+
*/
|
137 |
+
function createCalscale() {
|
138 |
+
if( empty( $this->calscale )) return FALSE;
|
139 |
+
switch( $this->format ) {
|
140 |
+
case 'xcal':
|
141 |
+
return ' calscale="'.$this->calscale.'"'.$this->nl;
|
142 |
+
break;
|
143 |
+
default:
|
144 |
+
return 'CALSCALE:'.$this->calscale.$this->nl;
|
145 |
+
break;
|
146 |
+
}
|
147 |
+
}
|
148 |
+
/**
|
149 |
+
* set calendar property calscale
|
150 |
+
*
|
151 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
152 |
+
* @since 2.4.8 - 2008-10-21
|
153 |
+
* @param string $value
|
154 |
+
* @return void
|
155 |
+
*/
|
156 |
+
function setCalscale( $value ) {
|
157 |
+
if( empty( $value )) return FALSE;
|
158 |
+
$this->calscale = $value;
|
159 |
+
}
|
160 |
+
/*********************************************************************************/
|
161 |
+
/**
|
162 |
+
* Property Name: METHOD
|
163 |
+
*/
|
164 |
+
/**
|
165 |
+
* creates formatted output for calendar property method
|
166 |
+
*
|
167 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
168 |
+
* @since 0.9.7 - 2006-11-20
|
169 |
+
* @return string
|
170 |
+
*/
|
171 |
+
function createMethod() {
|
172 |
+
if( empty( $this->method )) return FALSE;
|
173 |
+
switch( $this->format ) {
|
174 |
+
case 'xcal':
|
175 |
+
return ' method="'.$this->method.'"'.$this->nl;
|
176 |
+
break;
|
177 |
+
default:
|
178 |
+
return 'METHOD:'.$this->method.$this->nl;
|
179 |
+
break;
|
180 |
+
}
|
181 |
+
}
|
182 |
+
/**
|
183 |
+
* set calendar property method
|
184 |
+
*
|
185 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
186 |
+
* @since 2.4.8 - 2008-20-23
|
187 |
+
* @param string $value
|
188 |
+
* @return bool
|
189 |
+
*/
|
190 |
+
function setMethod( $value ) {
|
191 |
+
if( empty( $value )) return FALSE;
|
192 |
+
$this->method = $value;
|
193 |
+
return TRUE;
|
194 |
+
}
|
195 |
+
/*********************************************************************************/
|
196 |
+
/**
|
197 |
+
* Property Name: PRODID
|
198 |
+
*
|
199 |
+
* The identifier is RECOMMENDED to be the identical syntax to the
|
200 |
+
* [RFC 822] addr-spec. A good method to assure uniqueness is to put the
|
201 |
+
* domain name or a domain literal IP address of the host on which.. .
|
202 |
+
*/
|
203 |
+
/**
|
204 |
+
* creates formatted output for calendar property prodid
|
205 |
+
*
|
206 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
207 |
+
* @since 0.9.7 - 2006-11-20
|
208 |
+
* @return string
|
209 |
+
*/
|
210 |
+
function createProdid() {
|
211 |
+
if( !isset( $this->prodid ))
|
212 |
+
$this->_makeProdid();
|
213 |
+
switch( $this->format ) {
|
214 |
+
case 'xcal':
|
215 |
+
return ' prodid="'.$this->prodid.'"'.$this->nl;
|
216 |
+
break;
|
217 |
+
default:
|
218 |
+
return 'PRODID:'.$this->prodid.$this->nl;
|
219 |
+
break;
|
220 |
+
}
|
221 |
+
}
|
222 |
+
/**
|
223 |
+
* make default value for calendar prodid
|
224 |
+
*
|
225 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
226 |
+
* @since 2.6.8 - 2009-12-30
|
227 |
+
* @return void
|
228 |
+
*/
|
229 |
+
function _makeProdid() {
|
230 |
+
$this->prodid = '-//'.$this->unique_id.'//NONSGML kigkonsult.se '.ICALCREATOR_VERSION.'//'.strtoupper( $this->language );
|
231 |
+
}
|
232 |
+
/**
|
233 |
+
* Conformance: The property MUST be specified once in an iCalendar object.
|
234 |
+
* Description: The vendor of the implementation SHOULD assure that this
|
235 |
+
* is a globally unique identifier; using some technique such as an FPI
|
236 |
+
* value, as defined in [ISO 9070].
|
237 |
+
*/
|
238 |
+
/**
|
239 |
+
* make default unique_id for calendar prodid
|
240 |
+
*
|
241 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
242 |
+
* @since 0.3.0 - 2006-08-10
|
243 |
+
* @return void
|
244 |
+
*/
|
245 |
+
function _makeUnique_id() {
|
246 |
+
$this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
|
247 |
+
}
|
248 |
+
/*********************************************************************************/
|
249 |
+
/**
|
250 |
+
* Property Name: VERSION
|
251 |
+
*
|
252 |
+
* Description: A value of "2.0" corresponds to this memo.
|
253 |
+
*/
|
254 |
+
/**
|
255 |
+
* creates formatted output for calendar property version
|
256 |
+
|
257 |
+
*
|
258 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
259 |
+
* @since 0.9.7 - 2006-11-20
|
260 |
+
* @return string
|
261 |
+
*/
|
262 |
+
function createVersion() {
|
263 |
+
if( empty( $this->version ))
|
264 |
+
$this->_makeVersion();
|
265 |
+
switch( $this->format ) {
|
266 |
+
case 'xcal':
|
267 |
+
return ' version="'.$this->version.'"'.$this->nl;
|
268 |
+
break;
|
269 |
+
default:
|
270 |
+
return 'VERSION:'.$this->version.$this->nl;
|
271 |
+
break;
|
272 |
+
}
|
273 |
+
}
|
274 |
+
/**
|
275 |
+
* set default calendar version
|
276 |
+
*
|
277 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
278 |
+
* @since 0.3.0 - 2006-08-10
|
279 |
+
* @return void
|
280 |
+
*/
|
281 |
+
function _makeVersion() {
|
282 |
+
$this->version = '2.0';
|
283 |
+
}
|
284 |
+
/**
|
285 |
+
* set calendar version
|
286 |
+
*
|
287 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
288 |
+
* @since 2.4.8 - 2008-10-23
|
289 |
+
* @param string $value
|
290 |
+
* @return void
|
291 |
+
*/
|
292 |
+
function setVersion( $value ) {
|
293 |
+
if( empty( $value )) return FALSE;
|
294 |
+
$this->version = $value;
|
295 |
+
return TRUE;
|
296 |
+
}
|
297 |
+
/*********************************************************************************/
|
298 |
+
/**
|
299 |
+
* Property Name: x-prop
|
300 |
+
*/
|
301 |
+
/**
|
302 |
+
* creates formatted output for calendar property x-prop, iCal format only
|
303 |
+
*
|
304 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
305 |
+
* @since 2.9.3 - 2011-05-14
|
306 |
+
* @return string
|
307 |
+
*/
|
308 |
+
function createXprop() {
|
309 |
+
if( 'xcal' == $this->format )
|
310 |
+
return false;
|
311 |
+
if( empty( $this->xprop ) || !is_array( $this->xprop )) return FALSE;
|
312 |
+
$output = null;
|
313 |
+
$toolbox = new calendarComponent();
|
314 |
+
$toolbox->setConfig( $this->getConfig());
|
315 |
+
foreach( $this->xprop as $label => $xpropPart ) {
|
316 |
+
if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) {
|
317 |
+
$output .= $toolbox->_createElement( $label );
|
318 |
+
continue;
|
319 |
+
}
|
320 |
+
$attributes = $toolbox->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
|
321 |
+
if( is_array( $xpropPart['value'] )) {
|
322 |
+
foreach( $xpropPart['value'] as $pix => $theXpart )
|
323 |
+
$xpropPart['value'][$pix] = $toolbox->_strrep( $theXpart );
|
324 |
+
$xpropPart['value'] = implode( ',', $xpropPart['value'] );
|
325 |
+
}
|
326 |
+
else
|
327 |
+
$xpropPart['value'] = $toolbox->_strrep( $xpropPart['value'] );
|
328 |
+
$output .= $toolbox->_createElement( $label, $attributes, $xpropPart['value'] );
|
329 |
+
}
|
330 |
+
return $output;
|
331 |
+
}
|
332 |
+
/**
|
333 |
+
* set calendar property x-prop
|
334 |
+
*
|
335 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
336 |
+
* @since 2.9.3 - 2011-05-14
|
337 |
+
* @param string $label
|
338 |
+
* @param string $value
|
339 |
+
* @param array $params optional
|
340 |
+
* @return bool
|
341 |
+
*/
|
342 |
+
function setXprop( $label, $value, $params=FALSE ) {
|
343 |
+
if( empty( $label )) return FALSE;
|
344 |
+
if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
345 |
+
$xprop = array( 'value' => $value );
|
346 |
+
$xprop['params'] = iCalUtilityFunctions::_setParams( $params );
|
347 |
+
if( !is_array( $this->xprop )) $this->xprop = array();
|
348 |
+
$this->xprop[strtoupper( $label )] = $xprop;
|
349 |
+
return TRUE;
|
350 |
+
}
|
351 |
+
/*********************************************************************************/
|
352 |
+
/**
|
353 |
+
* delete calendar property value
|
354 |
+
*
|
355 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
356 |
+
* @since 2.8.8 - 2011-03-15
|
357 |
+
* @param mixed $propName, bool FALSE => X-property
|
358 |
+
* @param int $propix, optional, if specific property is wanted in case of multiply occurences
|
359 |
+
* @return bool, if successfull delete
|
360 |
+
*/
|
361 |
+
function deleteProperty( $propName=FALSE, $propix=FALSE ) {
|
362 |
+
$propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
|
363 |
+
if( !$propix )
|
364 |
+
$propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1;
|
365 |
+
$this->propdelix[$propName] = --$propix;
|
366 |
+
$return = FALSE;
|
367 |
+
switch( $propName ) {
|
368 |
+
case 'CALSCALE':
|
369 |
+
if( isset( $this->calscale )) {
|
370 |
+
$this->calscale = null;
|
371 |
+
$return = TRUE;
|
372 |
+
}
|
373 |
+
break;
|
374 |
+
case 'METHOD':
|
375 |
+
if( isset( $this->method )) {
|
376 |
+
$this->method = null;
|
377 |
+
$return = TRUE;
|
378 |
+
}
|
379 |
+
break;
|
380 |
+
default:
|
381 |
+
$reduced = array();
|
382 |
+
if( $propName != 'X-PROP' ) {
|
383 |
+
if( !isset( $this->xprop[$propName] )) { unset( $this->propdelix[$propName] ); return FALSE; }
|
384 |
+
foreach( $this->xprop as $k => $a ) {
|
385 |
+
if(( $k != $propName ) && !empty( $a ))
|
386 |
+
$reduced[$k] = $a;
|
387 |
+
}
|
388 |
+
}
|
389 |
+
else {
|
390 |
+
if( count( $this->xprop ) <= $propix ) return FALSE;
|
391 |
+
$xpropno = 0;
|
392 |
+
foreach( $this->xprop as $xpropkey => $xpropvalue ) {
|
393 |
+
if( $propix != $xpropno )
|
394 |
+
$reduced[$xpropkey] = $xpropvalue;
|
395 |
+
$xpropno++;
|
396 |
+
}
|
397 |
+
}
|
398 |
+
$this->xprop = $reduced;
|
399 |
+
if( empty( $this->xprop )) {
|
400 |
+
unset( $this->propdelix[$propName] );
|
401 |
+
return FALSE;
|
402 |
+
}
|
403 |
+
return TRUE;
|
404 |
+
}
|
405 |
+
return $return;
|
406 |
+
}
|
407 |
+
/**
|
408 |
+
* get calendar property value/params
|
409 |
+
*
|
410 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
411 |
+
* @since 2.8.8 - 2011-04-16
|
412 |
+
* @param string $propName, optional
|
413 |
+
* @param int $propix, optional, if specific property is wanted in case of multiply occurences
|
414 |
+
* @param bool $inclParam=FALSE
|
415 |
+
* @return mixed
|
416 |
+
*/
|
417 |
+
function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) {
|
418 |
+
$propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
|
419 |
+
if( 'X-PROP' == $propName ) {
|
420 |
+
if( !$propix )
|
421 |
+
$propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
|
422 |
+
$this->propix[$propName] = --$propix;
|
423 |
+
}
|
424 |
+
switch( $propName ) {
|
425 |
+
case 'ATTENDEE':
|
426 |
+
case 'CATEGORIES':
|
427 |
+
case 'DTSTART':
|
428 |
+
case 'LOCATION':
|
429 |
+
case 'ORGANIZER':
|
430 |
+
case 'PRIORITY':
|
431 |
+
case 'RESOURCES':
|
432 |
+
case 'STATUS':
|
433 |
+
case 'SUMMARY':
|
434 |
+
case 'RECURRENCE-ID-UID':
|
435 |
+
case 'R-UID':
|
436 |
+
case 'UID':
|
437 |
+
$output = array();
|
438 |
+
foreach ( $this->components as $cix => $component) {
|
439 |
+
if( !in_array( $component->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy' )))
|
440 |
+
continue;
|
441 |
+
if(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) {
|
442 |
+
$component->_getProperties( $propName, $output );
|
443 |
+
continue;
|
444 |
+
}
|
445 |
+
elseif(( 3 < strlen( $propName )) && ( 'UID' == substr( $propName, -3 ))) {
|
446 |
+
if( FALSE !== ( $content = $component->getProperty( 'RECURRENCE-ID' )))
|
447 |
+
$content = $component->getProperty( 'UID' );
|
448 |
+
}
|
449 |
+
elseif( FALSE === ( $content = $component->getProperty( $propName )))
|
450 |
+
continue;
|
451 |
+
if( FALSE === $content )
|
452 |
+
continue;
|
453 |
+
elseif( is_array( $content )) {
|
454 |
+
if( isset( $content['year'] )) {
|
455 |
+
$key = sprintf( '%04d%02d%02d', $content['year'], $content['month'], $content['day'] );
|
456 |
+
if( !isset( $output[$key] ))
|
457 |
+
$output[$key] = 1;
|
458 |
+
else
|
459 |
+
$output[$key] += 1;
|
460 |
+
}
|
461 |
+
else {
|
462 |
+
foreach( $content as $partValue => $partCount ) {
|
463 |
+
if( !isset( $output[$partValue] ))
|
464 |
+
$output[$partValue] = $partCount;
|
465 |
+
else
|
466 |
+
$output[$partValue] += $partCount;
|
467 |
+
}
|
468 |
+
}
|
469 |
+
} // end elseif( is_array( $content )) {
|
470 |
+
elseif( !isset( $output[$content] ))
|
471 |
+
$output[$content] = 1;
|
472 |
+
else
|
473 |
+
$output[$content] += 1;
|
474 |
+
} // end foreach ( $this->components as $cix => $component)
|
475 |
+
if( !empty( $output ))
|
476 |
+
ksort( $output );
|
477 |
+
return $output;
|
478 |
+
break;
|
479 |
+
|
480 |
+
case 'CALSCALE':
|
481 |
+
return ( !empty( $this->calscale )) ? $this->calscale : FALSE;
|
482 |
+
break;
|
483 |
+
case 'METHOD':
|
484 |
+
return ( !empty( $this->method )) ? $this->method : FALSE;
|
485 |
+
break;
|
486 |
+
case 'PRODID':
|
487 |
+
if( empty( $this->prodid ))
|
488 |
+
$this->_makeProdid();
|
489 |
+
return $this->prodid;
|
490 |
+
break;
|
491 |
+
case 'VERSION':
|
492 |
+
return ( !empty( $this->version )) ? $this->version : FALSE;
|
493 |
+
break;
|
494 |
+
default:
|
495 |
+
if( $propName != 'X-PROP' ) {
|
496 |
+
if( !isset( $this->xprop[$propName] )) return FALSE;
|
497 |
+
return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
|
498 |
+
: array( $propName, $this->xprop[$propName]['value'] );
|
499 |
+
}
|
500 |
+
else {
|
501 |
+
if( empty( $this->xprop )) return FALSE;
|
502 |
+
$xpropno = 0;
|
503 |
+
foreach( $this->xprop as $xpropkey => $xpropvalue ) {
|
504 |
+
if( $propix == $xpropno )
|
505 |
+
return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
|
506 |
+
: array( $xpropkey, $this->xprop[$xpropkey]['value'] );
|
507 |
+
else
|
508 |
+
$xpropno++;
|
509 |
+
}
|
510 |
+
unset( $this->propix[$propName] );
|
511 |
+
return FALSE; // not found ??
|
512 |
+
}
|
513 |
+
}
|
514 |
+
return FALSE;
|
515 |
+
}
|
516 |
+
/**
|
517 |
+
* general vcalendar property setting
|
518 |
+
*
|
519 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
520 |
+
* @since 2.2.13 - 2007-11-04
|
521 |
+
* @param mixed $args variable number of function arguments,
|
522 |
+
* first argument is ALWAYS component name,
|
523 |
+
* second ALWAYS component value!
|
524 |
+
* @return bool
|
525 |
+
*/
|
526 |
+
function setProperty () {
|
527 |
+
$numargs = func_num_args();
|
528 |
+
if( 1 > $numargs )
|
529 |
+
return FALSE;
|
530 |
+
$arglist = func_get_args();
|
531 |
+
$arglist[0] = strtoupper( $arglist[0] );
|
532 |
+
switch( $arglist[0] ) {
|
533 |
+
case 'CALSCALE':
|
534 |
+
return $this->setCalscale( $arglist[1] );
|
535 |
+
case 'METHOD':
|
536 |
+
return $this->setMethod( $arglist[1] );
|
537 |
+
case 'VERSION':
|
538 |
+
return $this->setVersion( $arglist[1] );
|
539 |
+
default:
|
540 |
+
if( !isset( $arglist[1] )) $arglist[1] = null;
|
541 |
+
if( !isset( $arglist[2] )) $arglist[2] = null;
|
542 |
+
return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
|
543 |
+
}
|
544 |
+
return FALSE;
|
545 |
+
}
|
546 |
+
/*********************************************************************************/
|
547 |
+
/**
|
548 |
+
* get vcalendar config values or * calendar components
|
549 |
+
*
|
550 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
551 |
+
* @since 2.9.6 - 2011-05-14
|
552 |
+
* @param mixed $config
|
553 |
+
* @return value
|
554 |
+
*/
|
555 |
+
function getConfig( $config = FALSE ) {
|
556 |
+
if( !$config ) {
|
557 |
+
$return = array();
|
558 |
+
$return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' );
|
559 |
+
$return['DELIMITER'] = $this->getConfig( 'DELIMITER' );
|
560 |
+
$return['DIRECTORY'] = $this->getConfig( 'DIRECTORY' );
|
561 |
+
$return['FILENAME'] = $this->getConfig( 'FILENAME' );
|
562 |
+
$return['DIRFILE'] = $this->getConfig( 'DIRFILE' );
|
563 |
+
$return['FILESIZE'] = $this->getConfig( 'FILESIZE' );
|
564 |
+
$return['FORMAT'] = $this->getConfig( 'FORMAT' );
|
565 |
+
if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' )))
|
566 |
+
$return['LANGUAGE'] = $lang;
|
567 |
+
$return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' );
|
568 |
+
$return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' );
|
569 |
+
if( FALSE !== ( $url = $this->getConfig( 'URL' )))
|
570 |
+
$return['URL'] = $url;
|
571 |
+
$return['TZID'] = $this->getConfig( 'TZID' );
|
572 |
+
return $return;
|
573 |
+
}
|
574 |
+
switch( strtoupper( $config )) {
|
575 |
+
case 'ALLOWEMPTY':
|
576 |
+
return $this->allowEmpty;
|
577 |
+
break;
|
578 |
+
case 'COMPSINFO':
|
579 |
+
unset( $this->compix );
|
580 |
+
$info = array();
|
581 |
+
foreach( $this->components as $cix => $component ) {
|
582 |
+
if( empty( $component )) continue;
|
583 |
+
$info[$cix]['ordno'] = $cix + 1;
|
584 |
+
$info[$cix]['type'] = $component->objName;
|
585 |
+
$info[$cix]['uid'] = $component->getProperty( 'uid' );
|
586 |
+
$info[$cix]['props'] = $component->getConfig( 'propinfo' );
|
587 |
+
$info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
|
588 |
+
}
|
589 |
+
return $info;
|
590 |
+
break;
|
591 |
+
case 'DELIMITER':
|
592 |
+
return $this->delimiter;
|
593 |
+
break;
|
594 |
+
case 'DIRECTORY':
|
595 |
+
if( empty( $this->directory ))
|
596 |
+
$this->directory = '.';
|
597 |
+
return $this->directory;
|
598 |
+
break;
|
599 |
+
case 'DIRFILE':
|
600 |
+
return $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$this->getConfig( 'filename' );
|
601 |
+
break;
|
602 |
+
case 'FILEINFO':
|
603 |
+
return array( $this->getConfig( 'directory' )
|
604 |
+
, $this->getConfig( 'filename' )
|
605 |
+
, $this->getConfig( 'filesize' ));
|
606 |
+
break;
|
607 |
+
case 'FILENAME':
|
608 |
+
if( empty( $this->filename )) {
|
609 |
+
if( 'xcal' == $this->format )
|
610 |
+
$this->filename = date( 'YmdHis' ).'.xml'; // recommended xcs.. .
|
611 |
+
else
|
612 |
+
$this->filename = date( 'YmdHis' ).'.ics';
|
613 |
+
}
|
614 |
+
return $this->filename;
|
615 |
+
break;
|
616 |
+
case 'FILESIZE':
|
617 |
+
$size = 0;
|
618 |
+
if( empty( $this->url )) {
|
619 |
+
$dirfile = $this->getConfig( 'dirfile' );
|
620 |
+
if( !is_file( $dirfile ) || ( FALSE === ( $size = filesize( $dirfile ))))
|
621 |
+
$size = 0;
|
622 |
+
clearstatcache();
|
623 |
+
}
|
624 |
+
return $size;
|
625 |
+
break;
|
626 |
+
case 'FORMAT':
|
627 |
+
return ( $this->format == 'xcal' ) ? 'xCal' : 'iCal';
|
628 |
+
break;
|
629 |
+
case 'LANGUAGE':
|
630 |
+
/* get language for calendar component as defined in [RFC 1766] */
|
631 |
+
return $this->language;
|
632 |
+
break;
|
633 |
+
case 'NL':
|
634 |
+
case 'NEWLINECHAR':
|
635 |
+
return $this->nl;
|
636 |
+
break;
|
637 |
+
case 'TZID':
|
638 |
+
return $this->dtzid;
|
639 |
+
break;
|
640 |
+
case 'UNIQUE_ID':
|
641 |
+
return $this->unique_id;
|
642 |
+
break;
|
643 |
+
case 'URL':
|
644 |
+
if( !empty( $this->url ))
|
645 |
+
return $this->url;
|
646 |
+
else
|
647 |
+
return FALSE;
|
648 |
+
break;
|
649 |
+
}
|
650 |
+
}
|
651 |
+
/**
|
652 |
+
* general vcalendar config setting
|
653 |
+
*
|
654 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
655 |
+
* @since 2.9.6 - 2011-05-14
|
656 |
+
* @param mixed $config
|
657 |
+
* @param string $value
|
658 |
+
* @return void
|
659 |
+
*/
|
660 |
+
function setConfig( $config, $value = FALSE) {
|
661 |
+
if( is_array( $config )) {
|
662 |
+
foreach( $config as $cKey => $cValue ) {
|
663 |
+
if( FALSE === $this->setConfig( $cKey, $cValue ))
|
664 |
+
return FALSE;
|
665 |
+
}
|
666 |
+
return TRUE;
|
667 |
+
}
|
668 |
+
$res = FALSE;
|
669 |
+
switch( strtoupper( $config )) {
|
670 |
+
case 'ALLOWEMPTY':
|
671 |
+
$this->allowEmpty = $value;
|
672 |
+
$subcfg = array( 'ALLOWEMPTY' => $value );
|
673 |
+
$res = TRUE;
|
674 |
+
break;
|
675 |
+
case 'DELIMITER':
|
676 |
+
$this->delimiter = $value;
|
677 |
+
return TRUE;
|
678 |
+
break;
|
679 |
+
case 'DIRECTORY':
|
680 |
+
$value = trim( $value );
|
681 |
+
$del = $this->getConfig('delimiter');
|
682 |
+
if( $del == substr( $value, ( 0 - strlen( $del ))))
|
683 |
+
$value = substr( $value, 0, ( strlen( $value ) - strlen( $del )));
|
684 |
+
if( is_dir( $value )) {
|
685 |
+
/* local directory */
|
686 |
+
clearstatcache();
|
687 |
+
$this->directory = $value;
|
688 |
+
$this->url = null;
|
689 |
+
return TRUE;
|
690 |
+
}
|
691 |
+
else
|
692 |
+
return FALSE;
|
693 |
+
break;
|
694 |
+
case 'FILENAME':
|
695 |
+
$value = trim( $value );
|
696 |
+
if( !empty( $this->url )) {
|
697 |
+
/* remote directory+file -> URL */
|
698 |
+
$this->filename = $value;
|
699 |
+
return TRUE;
|
700 |
+
}
|
701 |
+
$dirfile = $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$value;
|
702 |
+
if( file_exists( $dirfile )) {
|
703 |
+
/* local file exists */
|
704 |
+
if( is_readable( $dirfile ) || is_writable( $dirfile )) {
|
705 |
+
clearstatcache();
|
706 |
+
$this->filename = $value;
|
707 |
+
return TRUE;
|
708 |
+
}
|
709 |
+
else
|
710 |
+
return FALSE;
|
711 |
+
}
|
712 |
+
elseif( is_readable($this->getConfig( 'directory' ) ) || is_writable( $this->getConfig( 'directory' ) )) {
|
713 |
+
/* read- or writable directory */
|
714 |
+
$this->filename = $value;
|
715 |
+
return TRUE;
|
716 |
+
}
|
717 |
+
else
|
718 |
+
return FALSE;
|
719 |
+
break;
|
720 |
+
case 'FORMAT':
|
721 |
+
$value = trim( strtolower( $value ));
|
722 |
+
if( 'xcal' == $value ) {
|
723 |
+
$this->format = 'xcal';
|
724 |
+
$this->attributeDelimiter = $this->nl;
|
725 |
+
$this->valueInit = null;
|
726 |
+
}
|
727 |
+
else {
|
728 |
+
$this->format = null;
|
729 |
+
$this->attributeDelimiter = ';';
|
730 |
+
$this->valueInit = ':';
|
731 |
+
}
|
732 |
+
$subcfg = array( 'FORMAT' => $value );
|
733 |
+
$res = TRUE;
|
734 |
+
break;
|
735 |
+
case 'LANGUAGE':
|
736 |
+
// set language for calendar component as defined in [RFC 1766]
|
737 |
+
$value = trim( $value );
|
738 |
+
$this->language = $value;
|
739 |
+
$subcfg = array( 'LANGUAGE' => $value );
|
740 |
+
$res = TRUE;
|
741 |
+
break;
|
742 |
+
case 'NL':
|
743 |
+
case 'NEWLINECHAR':
|
744 |
+
$this->nl = $value;
|
745 |
+
$subcfg = array( 'NL' => $value );
|
746 |
+
$res = TRUE;
|
747 |
+
break;
|
748 |
+
case 'TZID':
|
749 |
+
$this->dtzid = $value;
|
750 |
+
$subcfg = array( 'TZID' => $value );
|
751 |
+
$res = TRUE;
|
752 |
+
break;
|
753 |
+
case 'UNIQUE_ID':
|
754 |
+
$value = trim( $value );
|
755 |
+
$this->unique_id = $value;
|
756 |
+
$subcfg = array( 'UNIQUE_ID' => $value );
|
757 |
+
$res = TRUE;
|
758 |
+
break;
|
759 |
+
case 'URL':
|
760 |
+
/* remote file - URL */
|
761 |
+
$value = trim( $value );
|
762 |
+
$value = str_replace( 'HTTP://', 'http://', $value );
|
763 |
+
$value = str_replace( 'WEBCAL://', 'http://', $value );
|
764 |
+
$value = str_replace( 'webcal://', 'http://', $value );
|
765 |
+
$this->url = $value;
|
766 |
+
$this->directory = null;
|
767 |
+
$parts = pathinfo( $value );
|
768 |
+
return $this->setConfig( 'filename', $parts['basename'] );
|
769 |
+
break;
|
770 |
+
default: // any unvalid config key.. .
|
771 |
+
return TRUE;
|
772 |
+
}
|
773 |
+
if( !$res ) return FALSE;
|
774 |
+
if( isset( $subcfg ) && !empty( $this->components )) {
|
775 |
+
foreach( $subcfg as $cfgkey => $cfgvalue ) {
|
776 |
+
foreach( $this->components as $cix => $component ) {
|
777 |
+
$res = $component->setConfig( $cfgkey, $cfgvalue, TRUE );
|
778 |
+
if( !$res )
|
779 |
+
break 2;
|
780 |
+
$this->components[$cix] = $component->copy(); // PHP4 compliant
|
781 |
+
}
|
782 |
+
}
|
783 |
+
}
|
784 |
+
return $res;
|
785 |
+
}
|
786 |
+
/*********************************************************************************/
|
787 |
+
/**
|
788 |
+
* add calendar component to container
|
789 |
+
*
|
790 |
+
* alias to setComponent
|
791 |
+
*
|
792 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
793 |
+
* @since 1.x.x - 2007-04-24
|
794 |
+
* @param object $component calendar component
|
795 |
+
* @return void
|
796 |
+
*/
|
797 |
+
function addComponent( $component ) {
|
798 |
+
$this->setComponent( $component );
|
799 |
+
}
|
800 |
+
/**
|
801 |
+
* delete calendar component from container
|
802 |
+
*
|
803 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
804 |
+
* @since 2.8.8 - 2011-03-15
|
805 |
+
* @param mixed $arg1 ordno / component type / component uid
|
806 |
+
* @param mixed $arg2 optional, ordno if arg1 = component type
|
807 |
+
* @return void
|
808 |
+
*/
|
809 |
+
function deleteComponent( $arg1, $arg2=FALSE ) {
|
810 |
+
$argType = $index = null;
|
811 |
+
if ( ctype_digit( (string) $arg1 )) {
|
812 |
+
$argType = 'INDEX';
|
813 |
+
$index = (int) $arg1 - 1;
|
814 |
+
}
|
815 |
+
elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
|
816 |
+
$argType = strtolower( $arg1 );
|
817 |
+
$index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
|
818 |
+
}
|
819 |
+
$cix1dC = 0;
|
820 |
+
foreach ( $this->components as $cix => $component) {
|
821 |
+
if( empty( $component )) continue;
|
822 |
+
if(( 'INDEX' == $argType ) && ( $index == $cix )) {
|
823 |
+
unset( $this->components[$cix] );
|
824 |
+
return TRUE;
|
825 |
+
}
|
826 |
+
elseif( $argType == $component->objName ) {
|
827 |
+
if( $index == $cix1dC ) {
|
828 |
+
unset( $this->components[$cix] );
|
829 |
+
return TRUE;
|
830 |
+
}
|
831 |
+
$cix1dC++;
|
832 |
+
}
|
833 |
+
elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
|
834 |
+
unset( $this->components[$cix] );
|
835 |
+
return TRUE;
|
836 |
+
}
|
837 |
+
}
|
838 |
+
return FALSE;
|
839 |
+
}
|
840 |
+
/**
|
841 |
+
* get calendar component from container
|
842 |
+
*
|
843 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
844 |
+
* @since 2.9.1 - 2011-04-16
|
845 |
+
* @param mixed $arg1 optional, ordno/component type/ component uid
|
846 |
+
* @param mixed $arg2 optional, ordno if arg1 = component type
|
847 |
+
* @return object
|
848 |
+
*/
|
849 |
+
function getComponent( $arg1=FALSE, $arg2=FALSE ) {
|
850 |
+
$index = $argType = null;
|
851 |
+
if ( !$arg1 ) { // first or next in component chain
|
852 |
+
$argType = 'INDEX';
|
853 |
+
$index = $this->compix['INDEX'] = ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
|
854 |
+
}
|
855 |
+
elseif ( ctype_digit( (string) $arg1 )) { // specific component in chain
|
856 |
+
$argType = 'INDEX';
|
857 |
+
$index = (int) $arg1;
|
858 |
+
unset( $this->compix );
|
859 |
+
}
|
860 |
+
elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
|
861 |
+
$arg2 = implode( '-', array_keys( $arg1 ));
|
862 |
+
$index = $this->compix[$arg2] = ( isset( $this->compix[$arg2] )) ? $this->compix[$arg2] + 1 : 1;
|
863 |
+
$dateProps = array( 'DTSTART', 'DTEND', 'DUE', 'CREATED', 'COMPLETED', 'DTSTAMP', 'LAST-MODIFIED', 'RECURRENCE-ID' );
|
864 |
+
$otherProps = array( 'ATTENDEE', 'CATEGORIES', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RESOURCES', 'STATUS', 'SUMMARY', 'UID' );
|
865 |
+
}
|
866 |
+
elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { // object class name
|
867 |
+
unset( $this->compix['INDEX'] );
|
868 |
+
$argType = strtolower( $arg1 );
|
869 |
+
if( !$arg2 )
|
870 |
+
$index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
|
871 |
+
elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 ))
|
872 |
+
$index = (int) $arg2;
|
873 |
+
}
|
874 |
+
elseif(( strlen( $arg1 ) > strlen( 'vfreebusy' )) && ( FALSE !== strpos( $arg1, '@' ))) { // UID as 1st argument
|
875 |
+
if( !$arg2 )
|
876 |
+
$index = $this->compix[$arg1] = ( isset( $this->compix[$arg1] )) ? $this->compix[$arg1] + 1 : 1;
|
877 |
+
elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 ))
|
878 |
+
$index = (int) $arg2;
|
879 |
+
}
|
880 |
+
if( isset( $index ))
|
881 |
+
$index -= 1;
|
882 |
+
$ckeys = array_keys( $this->components );
|
883 |
+
if( !empty( $index) && ( $index > end( $ckeys )))
|
884 |
+
return FALSE;
|
885 |
+
$cix1gC = 0;
|
886 |
+
foreach ( $this->components as $cix => $component) {
|
887 |
+
if( empty( $component )) continue;
|
888 |
+
if(( 'INDEX' == $argType ) && ( $index == $cix ))
|
889 |
+
return $component->copy();
|
890 |
+
elseif( $argType == $component->objName ) {
|
891 |
+
if( $index == $cix1gC )
|
892 |
+
return $component->copy();
|
893 |
+
$cix1gC++;
|
894 |
+
}
|
895 |
+
elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
|
896 |
+
$hit = FALSE;
|
897 |
+
foreach( $arg1 as $pName => $pValue ) {
|
898 |
+
$pName = strtoupper( $pName );
|
899 |
+
if( !in_array( $pName, $dateProps ) && !in_array( $pName, $otherProps ))
|
900 |
+
continue;
|
901 |
+
if(( 'ATTENDEE' == $pName ) || ( 'CATEGORIES' == $pName ) || ( 'RESOURCES' == $pName )) { // multiple ocurrence may occur
|
902 |
+
$propValues = array();
|
903 |
+
$component->_getProperties( $pName, $propValues );
|
904 |
+
$propValues = array_keys( $propValues );
|
905 |
+
$hit = ( in_array( $pValue, $propValues )) ? TRUE : FALSE;
|
906 |
+
continue;
|
907 |
+
} // end if(( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) { // multiple ocurrence may occur
|
908 |
+
if( FALSE === ( $value = $component->getProperty( $pName ))) { // single ocurrency
|
909 |
+
$hit = FALSE; // missing property
|
910 |
+
continue;
|
911 |
+
}
|
912 |
+
if( 'SUMMARY' == $pName ) { // exists within (any case)
|
913 |
+
$hit = ( FALSE !== stripos( $d, $pValue )) ? TRUE : FALSE;
|
914 |
+
continue;
|
915 |
+
}
|
916 |
+
if( in_array( strtoupper( $pName ), $dateProps )) {
|
917 |
+
$valuedate = sprintf( '%04d%02d%02d', $value['year'], $value['month'], $value['day'] );
|
918 |
+
if( 8 < strlen( $pValue )) {
|
919 |
+
if( isset( $value['hour'] )) {
|
920 |
+
if( 'T' == substr( $pValue, 8, 1 ))
|
921 |
+
$pValue = str_replace( 'T', '', $pValue );
|
922 |
+
$valuedate .= sprintf( '%02d%02d%02d', $value['hour'], $value['min'], $value['sec'] );
|
923 |
+
}
|
924 |
+
else
|
925 |
+
$pValue = substr( $pValue, 0, 8 );
|
926 |
+
}
|
927 |
+
$hit = ( $pValue == $valuedate ) ? TRUE : FALSE;
|
928 |
+
continue;
|
929 |
+
}
|
930 |
+
elseif( !is_array( $value ))
|
931 |
+
$value = array( $value );
|
932 |
+
foreach( $value as $part ) {
|
933 |
+
$part = ( FALSE !== strpos( $part, ',' )) ? explode( ',', $part ) : array( $part );
|
934 |
+
foreach( $part as $subPart ) {
|
935 |
+
if( $pValue == $subPart ) {
|
936 |
+
$hit = TRUE;
|
937 |
+
continue 2;
|
938 |
+
}
|
939 |
+
}
|
940 |
+
}
|
941 |
+
$hit = FALSE; // no hit in property
|
942 |
+
} // end foreach( $arg1 as $pName => $pValue )
|
943 |
+
if( $hit ) {
|
944 |
+
if( $index == $cix1gC )
|
945 |
+
return $component->copy();
|
946 |
+
$cix1gC++;
|
947 |
+
}
|
948 |
+
} // end elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
|
949 |
+
elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { // UID
|
950 |
+
if( $index == $cix1gC )
|
951 |
+
return $component->copy();
|
952 |
+
$cix1gC++;
|
953 |
+
}
|
954 |
+
} // end foreach ( $this->components.. .
|
955 |
+
/* not found.. . */
|
956 |
+
unset( $this->compix );
|
957 |
+
return FALSE;
|
958 |
+
}
|
959 |
+
/**
|
960 |
+
* create new calendar component, already included within calendar
|
961 |
+
*
|
962 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
963 |
+
* @since 2.6.33 - 2011-01-03
|
964 |
+
* @param string $compType component type
|
965 |
+
* @return object (reference)
|
966 |
+
*/
|
967 |
+
function & newComponent( $compType ) {
|
968 |
+
$config = $this->getConfig();
|
969 |
+
$keys = array_keys( $this->components );
|
970 |
+
$ix = end( $keys) + 1;
|
971 |
+
switch( strtoupper( $compType )) {
|
972 |
+
case 'EVENT':
|
973 |
+
case 'VEVENT':
|
974 |
+
$this->components[$ix] = new vevent( $config );
|
975 |
+
break;
|
976 |
+
case 'TODO':
|
977 |
+
case 'VTODO':
|
978 |
+
$this->components[$ix] = new vtodo( $config );
|
979 |
+
break;
|
980 |
+
case 'JOURNAL':
|
981 |
+
case 'VJOURNAL':
|
982 |
+
$this->components[$ix] = new vjournal( $config );
|
983 |
+
break;
|
984 |
+
case 'FREEBUSY':
|
985 |
+
case 'VFREEBUSY':
|
986 |
+
$this->components[$ix] = new vfreebusy( $config );
|
987 |
+
break;
|
988 |
+
case 'TIMEZONE':
|
989 |
+
case 'VTIMEZONE':
|
990 |
+
array_unshift( $this->components, new vtimezone( $config ));
|
991 |
+
$ix = 0;
|
992 |
+
break;
|
993 |
+
default:
|
994 |
+
return FALSE;
|
995 |
+
}
|
996 |
+
return $this->components[$ix];
|
997 |
+
}
|
998 |
+
/**
|
999 |
+
* select components from calendar on date or selectOption basis
|
1000 |
+
*
|
1001 |
+
* Ensure DTSTART is set for every component.
|
1002 |
+
* No date controls occurs.
|
1003 |
+
*
|
1004 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1005 |
+
* @since 2.9.7 - 2011-06-04
|
1006 |
+
* @param mixed $startY optional, start Year, default current Year ALT. array selecOptions
|
1007 |
+
* @param int $startM optional, start Month, default current Month
|
1008 |
+
* @param int $startD optional, start Day, default current Day
|
1009 |
+
* @param int $endY optional, end Year, default $startY
|
1010 |
+
* @param int $endY optional, end Month, default $startM
|
1011 |
+
* @param int $endY optional, end Day, default $startD
|
1012 |
+
* @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s)
|
1013 |
+
* @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][]
|
1014 |
+
* TRUE => output : array[] (ignores split)
|
1015 |
+
* @param bool $any optional, TRUE (default) - select component that take place within period
|
1016 |
+
* FALSE - only components that starts within period
|
1017 |
+
* @param bool $split optional, TRUE (default) - one component copy every day it take place during the
|
1018 |
+
* period (implies flat=FALSE)
|
1019 |
+
* FALSE - one occurance of component only in output array
|
1020 |
+
* @return array or FALSE
|
1021 |
+
*/
|
1022 |
+
function selectComponents( $startY=FALSE, $startM=FALSE, $startD=FALSE, $endY=FALSE, $endM=FALSE, $endD=FALSE, $cType=FALSE, $flat=FALSE, $any=TRUE, $split=TRUE ) {
|
1023 |
+
/* check if empty calendar */
|
1024 |
+
if( 0 >= count( $this->components )) return FALSE;
|
1025 |
+
if( is_array( $startY ))
|
1026 |
+
return $this->selectComponents2( $startY );
|
1027 |
+
/* check default dates */
|
1028 |
+
if( !$startY ) $startY = date( 'Y' );
|
1029 |
+
if( !$startM ) $startM = date( 'm' );
|
1030 |
+
if( !$startD ) $startD = date( 'd' );
|
1031 |
+
$startDate = mktime( 0, 0, 0, $startM, $startD, $startY );
|
1032 |
+
if( !$endY ) $endY = $startY;
|
1033 |
+
if( !$endM ) $endM = $startM;
|
1034 |
+
if( !$endD ) $endD = $startD;
|
1035 |
+
$endDate = mktime( 23, 59, 59, $endM, $endD, $endY );
|
1036 |
+
//echo 'selectComp arg='.date( 'Y-m-d H:i:s', $startDate).' -- '.date( 'Y-m-d H:i:s', $endDate)."<br />\n"; $tcnt = 0;// test ###
|
1037 |
+
/* check component types */
|
1038 |
+
$validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy' );
|
1039 |
+
if( is_array( $cType )) {
|
1040 |
+
foreach( $cType as $cix => $theType ) {
|
1041 |
+
$cType[$cix] = $theType = strtolower( $theType );
|
1042 |
+
if( !in_array( $theType, $validTypes ))
|
1043 |
+
$cType[$cix] = 'vevent';
|
1044 |
+
}
|
1045 |
+
$cType = array_unique( $cType );
|
1046 |
+
}
|
1047 |
+
elseif( !empty( $cType )) {
|
1048 |
+
$cType = strtolower( $cType );
|
1049 |
+
if( !in_array( $cType, $validTypes ))
|
1050 |
+
$cType = array( 'vevent' );
|
1051 |
+
else
|
1052 |
+
$cType = array( $cType );
|
1053 |
+
}
|
1054 |
+
else
|
1055 |
+
$cType = $validTypes;
|
1056 |
+
if( 0 >= count( $cType ))
|
1057 |
+
$cType = $validTypes;
|
1058 |
+
if(( TRUE === $flat ) && ( TRUE === $split )) // invalid combination
|
1059 |
+
$split = FALSE;
|
1060 |
+
/* iterate components */
|
1061 |
+
$result = array();
|
1062 |
+
foreach ( $this->components as $cix => $component ) {
|
1063 |
+
if( empty( $component )) continue;
|
1064 |
+
unset( $start );
|
1065 |
+
/* deselect unvalid type components */
|
1066 |
+
if( !in_array( $component->objName, $cType )) continue;
|
1067 |
+
$start = $component->getProperty( 'dtstart' );
|
1068 |
+
/* select due when dtstart is missing */
|
1069 |
+
if( empty( $start ) && ( $component->objName == 'vtodo' ) && ( FALSE === ( $start = $component->getProperty( 'due' ))))
|
1070 |
+
continue;
|
1071 |
+
$dtendExist = $dueExist = $durationExist = $endAllDayEvent = FALSE;
|
1072 |
+
unset( $end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $workstart, $workend, $endDateFormat ); // clean up
|
1073 |
+
$startWdate = iCalUtilityFunctions::_date2timestamp( $start );
|
1074 |
+
$startDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
|
1075 |
+
/* get end date from dtend/due/duration properties */
|
1076 |
+
$end = $component->getProperty( 'dtend' );
|
1077 |
+
if( !empty( $end )) {
|
1078 |
+
$dtendExist = TRUE;
|
1079 |
+
$endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
|
1080 |
+
}
|
1081 |
+
if( empty( $end ) && ( $component->objName == 'vtodo' )) {
|
1082 |
+
$end = $component->getProperty( 'due' );
|
1083 |
+
if( !empty( $end )) {
|
1084 |
+
$dueExist = TRUE;
|
1085 |
+
$endDateFormat = ( isset( $end['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
|
1086 |
+
}
|
1087 |
+
}
|
1088 |
+
if( !empty( $end ) && !isset( $end['hour'] )) {
|
1089 |
+
/* a DTEND without time part regards an event that ends the day before,
|
1090 |
+
for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */
|
1091 |
+
$endAllDayEvent = TRUE;
|
1092 |
+
$endWdate = mktime( 23, 59, 59, $end['month'], ($end['day'] - 1), $end['year'] );
|
1093 |
+
$end['year'] = date( 'Y', $endWdate );
|
1094 |
+
$end['month'] = date( 'm', $endWdate );
|
1095 |
+
$end['day'] = date( 'd', $endWdate );
|
1096 |
+
$end['hour'] = 23;
|
1097 |
+
$end['min'] = $end['sec'] = 59;
|
1098 |
+
}
|
1099 |
+
if( empty( $end )) {
|
1100 |
+
$end = $component->getProperty( 'duration', FALSE, FALSE, TRUE );// in dtend (array) format
|
1101 |
+
if( !empty( $end ))
|
1102 |
+
$durationExist = TRUE;
|
1103 |
+
$endDateFormat = ( isset( $start['hour'] )) ? 'Y-m-d H:i:s' : 'Y-m-d';
|
1104 |
+
// if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
|
1105 |
+
}
|
1106 |
+
if( empty( $end )) { // assume one day duration if missing end date
|
1107 |
+
$end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
|
1108 |
+
}
|
1109 |
+
// if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
|
1110 |
+
$endWdate = iCalUtilityFunctions::_date2timestamp( $end );
|
1111 |
+
if( $endWdate < $startWdate ) { // MUST be after start date!!
|
1112 |
+
$end = array( 'year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59 );
|
1113 |
+
$endWdate = iCalUtilityFunctions::_date2timestamp( $end );
|
1114 |
+
}
|
1115 |
+
$rdurWsecs = $endWdate - $startWdate; // compute component duration in seconds
|
1116 |
+
/* make a list of optional exclude dates for component occurence from exrule and exdate */
|
1117 |
+
$exdatelist = array();
|
1118 |
+
$workstart = iCalUtilityFunctions::_timestamp2date(( $startDate - $rdurWsecs ), 6);
|
1119 |
+
$workend = iCalUtilityFunctions::_timestamp2date(( $endDate + $rdurWsecs ), 6);
|
1120 |
+
while( FALSE !== ( $exrule = $component->getProperty( 'exrule' ))) // check exrule
|
1121 |
+
iCalUtilityFunctions::_recur2date( $exdatelist, $exrule, $start, $workstart, $workend );
|
1122 |
+
while( FALSE !== ( $exdate = $component->getProperty( 'exdate' ))) { // check exdate
|
1123 |
+
foreach( $exdate as $theExdate ) {
|
1124 |
+
$exWdate = iCalUtilityFunctions::_date2timestamp( $theExdate );
|
1125 |
+
$exWdate = mktime( 0, 0, 0, date( 'm', $exWdate ), date( 'd', $exWdate ), date( 'Y', $exWdate ) ); // on a day-basis !!!
|
1126 |
+
if((( $startDate - $rdurWsecs ) <= $exWdate ) && ( $endDate >= $exWdate ))
|
1127 |
+
$exdatelist[$exWdate] = TRUE;
|
1128 |
+
}
|
1129 |
+
}
|
1130 |
+
/* if 'any' components, check repeating components, removing all excluding dates */
|
1131 |
+
if( TRUE === $any ) {
|
1132 |
+
/* make a list of optional repeating dates for component occurence, rrule, rdate */
|
1133 |
+
$recurlist = array();
|
1134 |
+
while( FALSE !== ( $rrule = $component->getProperty( 'rrule' ))) // check rrule
|
1135 |
+
iCalUtilityFunctions::_recur2date( $recurlist, $rrule, $start, $workstart, $workend );
|
1136 |
+
foreach( $recurlist as $recurkey => $recurvalue ) // key=match date as timestamp
|
1137 |
+
$recurlist[$recurkey] = $rdurWsecs; // add duration in seconds
|
1138 |
+
while( FALSE !== ( $rdate = $component->getProperty( 'rdate' ))) { // check rdate
|
1139 |
+
foreach( $rdate as $theRdate ) {
|
1140 |
+
if( is_array( $theRdate ) && ( 2 == count( $theRdate )) && // all days within PERIOD
|
1141 |
+
array_key_exists( '0', $theRdate ) && array_key_exists( '1', $theRdate )) {
|
1142 |
+
$rstart = iCalUtilityFunctions::_date2timestamp( $theRdate[0] );
|
1143 |
+
if(( $rstart < ( $startDate - $rdurWsecs )) || ( $rstart > $endDate ))
|
1144 |
+
continue;
|
1145 |
+
if( isset( $theRdate[1]['year'] )) // date-date period
|
1146 |
+
$rend = iCalUtilityFunctions::_date2timestamp( $theRdate[1] );
|
1147 |
+
else { // date-duration period
|
1148 |
+
$rend = iCalUtilityFunctions::_duration2date( $theRdate[0], $theRdate[1] );
|
1149 |
+
$rend = iCalUtilityFunctions::_date2timestamp( $rend );
|
1150 |
+
}
|
1151 |
+
while( $rstart < $rend ) {
|
1152 |
+
$recurlist[$rstart] = $rdurWsecs; // set start date for recurrence instance + rdate duration in seconds
|
1153 |
+
$rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day
|
1154 |
+
}
|
1155 |
+
} // PERIOD end
|
1156 |
+
else { // single date
|
1157 |
+
$theRdate = iCalUtilityFunctions::_date2timestamp( $theRdate );
|
1158 |
+
if((( $startDate - $rdurWsecs ) <= $theRdate ) && ( $endDate >= $theRdate ))
|
1159 |
+
$recurlist[$theRdate] = $rdurWsecs; // set start date for recurrence instance + event duration in seconds
|
1160 |
+
}
|
1161 |
+
}
|
1162 |
+
}
|
1163 |
+
if( 0 < count( $recurlist )) {
|
1164 |
+
ksort( $recurlist );
|
1165 |
+
$xRecurrence = 1;
|
1166 |
+
foreach( $recurlist as $recurkey => $durvalue ) {
|
1167 |
+
// echo "recurKey=".date( 'Y-m-d H:i:s', $recurkey ).' dur='.iCalUtilityFunctions::offsetSec2His( $durvalue )."<br />\n"; // test ###;
|
1168 |
+
if((( $startDate - $rdurWsecs ) > $recurkey ) || ( $endDate < $recurkey )) // not within period
|
1169 |
+
continue;
|
1170 |
+
$checkDate = mktime( 0, 0, 0, date( 'm', $recurkey ), date( 'd', $recurkey ), date( 'Y', $recurkey ) ); // on a day-basis !!!
|
1171 |
+
if( isset( $exdatelist[$checkDate] )) // check excluded dates
|
1172 |
+
continue;
|
1173 |
+
if( $startWdate >= $recurkey ) // exclude component start date
|
1174 |
+
continue;
|
1175 |
+
$component2 = $component->copy();
|
1176 |
+
$rstart = $recurkey;
|
1177 |
+
$rend = $recurkey + $durvalue;
|
1178 |
+
/* add repeating components within valid dates to output array, only start date set */
|
1179 |
+
if( $flat ) {
|
1180 |
+
$datestring = date( $startDateFormat, $recurkey );
|
1181 |
+
if( isset( $start['tz'] ))
|
1182 |
+
$datestring .= ' '.$start['tz'];
|
1183 |
+
// echo "X-CURRENT-DTSTART 0 =$datestring tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
|
1184 |
+
$component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
|
1185 |
+
if( $dtendExist || $dueExist || $durationExist ) {
|
1186 |
+
$datestring = date( $endDateFormat, $recurkey + $durvalue ); // fixa korrekt sluttid
|
1187 |
+
if( isset( $end['tz'] ))
|
1188 |
+
$datestring .= ' '.$end['tz'];
|
1189 |
+
$propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
|
1190 |
+
$component2->setProperty( $propName, $datestring );
|
1191 |
+
} // end if( $dtendExist || $dueExist || $durationExist )
|
1192 |
+
$component2->setProperty( 'X-RECURRENCE', ++$xRecurrence );
|
1193 |
+
$result[$component2->getProperty( 'UID' )] = $component2->copy(); // copy to output
|
1194 |
+
}
|
1195 |
+
/* add repeating components within valid dates to output array, one each day */
|
1196 |
+
elseif( $split ) {
|
1197 |
+
if( $rend > $endDate )
|
1198 |
+
$rend = $endDate;
|
1199 |
+
$startYMD = date( 'Ymd', $rstart );
|
1200 |
+
$endYMD = date( 'Ymd', $rend );
|
1201 |
+
// echo "splitStart=".date( 'Y-m-d H:i:s', $rstart ).' end='.date( 'Y-m-d H:i:s', $rend )."<br />\n"; // test ###;
|
1202 |
+
while( $rstart <= $rend ) { // iterate.. .
|
1203 |
+
$checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
|
1204 |
+
if( isset( $exdatelist[$checkDate] )) // exclude any recurrence START date, found in exdatelist
|
1205 |
+
break;
|
1206 |
+
// echo "checking date after startdate=".date( 'Y-m-d H:i:s', $rstart ).' mot '.date( 'Y-m-d H:i:s', $startDate )."<br />"; // test ###;
|
1207 |
+
if( $rstart >= $startDate ) { // date after dtstart
|
1208 |
+
if( date( 'Ymd', $rstart ) > $startYMD ) // date after dtstart
|
1209 |
+
$datestring = date( $startDateFormat, $checkDate );
|
1210 |
+
else
|
1211 |
+
$datestring = date( $startDateFormat, $rstart );
|
1212 |
+
if( isset( $start['tz'] ))
|
1213 |
+
$datestring .= ' '.$start['tz'];
|
1214 |
+
//echo "X-CURRENT-DTSTART 1 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
|
1215 |
+
$component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
|
1216 |
+
if( $dtendExist || $dueExist || $durationExist ) {
|
1217 |
+
if( date( 'Ymd', $rstart ) < $endYMD ) // not the last day
|
1218 |
+
$tend = mktime( 23, 59, 59, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ));
|
1219 |
+
else
|
1220 |
+
$tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
|
1221 |
+
$datestring = date( $endDateFormat, $tend );
|
1222 |
+
if( isset( $end['tz'] ))
|
1223 |
+
$datestring .= ' '.$end['tz'];
|
1224 |
+
$propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
|
1225 |
+
$component2->setProperty( $propName, $datestring );
|
1226 |
+
} // end if( $dtendExist || $dueExist || $durationExist )
|
1227 |
+
$component2->setProperty( 'X-RECURRENCE', $xRecurrence );
|
1228 |
+
$wd = getdate( $rstart );
|
1229 |
+
$result[$wd['year']][$wd['mon']][$wd['mday']][$component2->getProperty( 'UID' )] = $component2->copy(); // copy to output
|
1230 |
+
} // end if( $checkDate > $startYMD ) { // date after dtstart
|
1231 |
+
$rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day
|
1232 |
+
} // end while( $rstart <= $rend )
|
1233 |
+
$xRecurrence += 1;
|
1234 |
+
} // end elseif( $split )
|
1235 |
+
elseif( $rstart >= $startDate ) { // date within period //* flat=FALSE && split=FALSE *//
|
1236 |
+
$checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
|
1237 |
+
if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist
|
1238 |
+
$xRecurrence += 1;
|
1239 |
+
$datestring = date( $startDateFormat, $rstart );
|
1240 |
+
if( isset( $start['tz'] ))
|
1241 |
+
$datestring .= ' '.$start['tz'];
|
1242 |
+
//echo "X-CURRENT-DTSTART 2 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
|
1243 |
+
$component2->setProperty( 'X-CURRENT-DTSTART', $datestring );
|
1244 |
+
if( $dtendExist || $dueExist || $durationExist ) {
|
1245 |
+
$rstart += $rdurWsecs;
|
1246 |
+
if( date( 'Ymd', $rstart ) < date( 'Ymd', $endWdate ))
|
1247 |
+
$tend = mktime( 23, 59, 59, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ));
|
1248 |
+
else
|
1249 |
+
$tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
|
1250 |
+
$datestring = date( $endDateFormat, $tend );
|
1251 |
+
if( isset( $end['tz'] ))
|
1252 |
+
$datestring .= ' '.$end['tz'];
|
1253 |
+
$propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
|
1254 |
+
$component2->setProperty( $propName, $datestring );
|
1255 |
+
} // end if( $dtendExist || $dueExist || $durationExist )
|
1256 |
+
$component2->setProperty( 'X-RECURRENCE', $xRecurrence );
|
1257 |
+
$wd = getdate( $rstart );
|
1258 |
+
$result[$wd['year']][$wd['mon']][$wd['mday']][$component2->getProperty( 'UID' )] = $component2->copy(); // copy to output
|
1259 |
+
} // end if( !isset( $exdatelist[$checkDate] ))
|
1260 |
+
} // end elseif( $rstart >= $startDate )
|
1261 |
+
} // end foreach( $recurlist as $recurkey => $durvalue )
|
1262 |
+
} // end if( 0 < count( $recurlist ))
|
1263 |
+
/* deselect components with startdate/enddate not within period */
|
1264 |
+
if(( $endWdate < $startDate ) || ( $startWdate > $endDate ))
|
1265 |
+
continue;
|
1266 |
+
} // end if( TRUE === $any )
|
1267 |
+
/* deselect components with startdate not within period */
|
1268 |
+
elseif(( $startWdate < $startDate ) || ( $startWdate > $endDate ))
|
1269 |
+
continue;
|
1270 |
+
/* add the selected component (WITHIN valid dates) to output array */
|
1271 |
+
if( $flat )
|
1272 |
+
$result[$component->getProperty( 'UID' )] = $component->copy(); // copy to output;
|
1273 |
+
elseif( $split ) { // split the original component
|
1274 |
+
if( $endWdate > $endDate )
|
1275 |
+
$endWdate = $endDate; // use period end date
|
1276 |
+
$rstart = $startWdate;
|
1277 |
+
if( $rstart < $startDate )
|
1278 |
+
$rstart = $startDate; // use period start date
|
1279 |
+
$checkDate = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
|
1280 |
+
if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist
|
1281 |
+
foreach( array( 'X-CURRENT-DTSTART','X-CURRENT-DTEND','X-CURRENT-DUE','X-RECURRENCE' ) as $propName )
|
1282 |
+
$component->deleteProperty( $propName ); // remove any x-props, if set
|
1283 |
+
while( $rstart <= $endWdate ) { // iterate
|
1284 |
+
if( $rstart > $startWdate ) { // if NOT startdate, set X-properties
|
1285 |
+
$datestring = date( $startDateFormat, mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart )));
|
1286 |
+
if( isset( $start['tz'] ))
|
1287 |
+
$datestring .= ' '.$start['tz'];
|
1288 |
+
// echo "X-CURRENT-DTSTART 3 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component->setProperty( 'X-CNT', $tcnt ); // test ###
|
1289 |
+
$component->setProperty( 'X-CURRENT-DTSTART', $datestring );
|
1290 |
+
if( $dtendExist || $dueExist || $durationExist ) {
|
1291 |
+
if( date( 'Ymd', $rstart ) < date( 'Ymd', $endWdate ))
|
1292 |
+
$tend = mktime( 0, 0, 0, date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ));
|
1293 |
+
else
|
1294 |
+
$tend = mktime( date( 'H', $endWdate ), date( 'i', $endWdate ), date( 's', $endWdate ), date( 'm', $rstart ), date( 'd', $rstart ), date( 'Y', $rstart ) ); // on a day-basis !!!
|
1295 |
+
$datestring = date( $endDateFormat, $tend );
|
1296 |
+
if( isset( $end['tz'] ))
|
1297 |
+
$datestring .= ' '.$end['tz'];
|
1298 |
+
$propName = ( !$dueExist ) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
|
1299 |
+
$component->setProperty( $propName, $datestring );
|
1300 |
+
} // end if( $dtendExist || $dueExist || $durationExist )
|
1301 |
+
} // end if( $rstart > $startWdate )
|
1302 |
+
$wd = getdate( $rstart );
|
1303 |
+
$result[$wd['year']][$wd['mon']][$wd['mday']][$component->getProperty( 'UID' )] = $component->copy(); // copy to output
|
1304 |
+
$rstart = mktime( date( 'H', $rstart ), date( 'i', $rstart ), date( 's', $rstart ), date( 'm', $rstart ), date( 'd', $rstart ) + 1, date( 'Y', $rstart ) ); // step one day
|
1305 |
+
} // end while( $rstart <= $endWdate )
|
1306 |
+
} // end if( !isset( $exdatelist[$checkDate] ))
|
1307 |
+
} // end if( $split ) - else use component date
|
1308 |
+
elseif( $startWdate >= $startDate ) { // within period
|
1309 |
+
$checkDate = mktime( 0, 0, 0, date( 'm', $startWdate ), date( 'd', $startWdate ), date( 'Y', $startWdate ) ); // on a day-basis !!!
|
1310 |
+
if( !isset( $exdatelist[$checkDate] )) { // exclude any recurrence START date, found in exdatelist
|
1311 |
+
foreach( array( 'X-CURRENT-DTSTART','X-CURRENT-DTEND','X-CURRENT-DUE','X-RECURRENCE' ) as $propName )
|
1312 |
+
$component->deleteProperty( $propName ); // remove any x-props, if set
|
1313 |
+
$wd = getdate( $startWdate );
|
1314 |
+
$result[$wd['year']][$wd['mon']][$wd['mday']][$component->getProperty( 'UID' )] = $component->copy(); // copy to output
|
1315 |
+
}
|
1316 |
+
}
|
1317 |
+
} // end foreach ( $this->components as $cix => $component )
|
1318 |
+
if( 0 >= count( $result )) return FALSE;
|
1319 |
+
elseif( !$flat ) {
|
1320 |
+
foreach( $result as $y => $yeararr ) {
|
1321 |
+
foreach( $yeararr as $m => $montharr ) {
|
1322 |
+
foreach( $montharr as $d => $dayarr )
|
1323 |
+
$result[$y][$m][$d] = array_values( $dayarr ); // skip tricky UID-index
|
1324 |
+
ksort( $result[$y][$m] );
|
1325 |
+
}
|
1326 |
+
ksort( $result[$y] );
|
1327 |
+
}
|
1328 |
+
ksort( $result );
|
1329 |
+
} // end elseif( !$flat )
|
1330 |
+
return $result;
|
1331 |
+
}
|
1332 |
+
/**
|
1333 |
+
* select components from calendar on based on Categories, Location, Resources and/or Summary
|
1334 |
+
*
|
1335 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1336 |
+
* @since 2.8.8 - 2011-05-03
|
1337 |
+
* @param array $selectOptions, (string) key => (mixed) value, (key=propertyName)
|
1338 |
+
* @return array
|
1339 |
+
*/
|
1340 |
+
function selectComponents2( $selectOptions ) {
|
1341 |
+
$output = array();
|
1342 |
+
$allowedProperties = array( 'ATTENDEE', 'CATEGORIES', 'LOCATION', 'ORGANIZER', 'RESOURCES', 'PRIORITY', 'STATUS', 'SUMMARY', 'UID' );
|
1343 |
+
foreach( $this->components as $cix => $component3 ) {
|
1344 |
+
if( !in_array( $component3->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy' )))
|
1345 |
+
continue;
|
1346 |
+
$uid = $component3->getProperty( 'UID' );
|
1347 |
+
foreach( $selectOptions as $propName => $pvalue ) {
|
1348 |
+
$propName = strtoupper( $propName );
|
1349 |
+
if( !in_array( $propName, $allowedProperties ))
|
1350 |
+
continue;
|
1351 |
+
if( !is_array( $pvalue ))
|
1352 |
+
$pvalue = array( $pvalue );
|
1353 |
+
if(( 'UID' == $propName ) && in_array( $uid, $pvalue )) {
|
1354 |
+
$output[] = $component3->copy();
|
1355 |
+
continue;
|
1356 |
+
}
|
1357 |
+
elseif(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) {
|
1358 |
+
$propValues = array();
|
1359 |
+
$component3->_getProperties( $propName, $propValues );
|
1360 |
+
$propValues = array_keys( $propValues );
|
1361 |
+
foreach( $pvalue as $theValue ) {
|
1362 |
+
if( in_array( $theValue, $propValues ) && !isset( $output[$uid] )) {
|
1363 |
+
$output[$uid] = $component3->copy();
|
1364 |
+
break;
|
1365 |
+
}
|
1366 |
+
}
|
1367 |
+
continue;
|
1368 |
+
} // end elseif(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName ))
|
1369 |
+
elseif( FALSE === ( $d = $component3->getProperty( $propName ))) // single ocurrence
|
1370 |
+
continue;
|
1371 |
+
if( is_array( $d )) {
|
1372 |
+
foreach( $d as $part ) {
|
1373 |
+
if( in_array( $part, $pvalue ) && !isset( $output[$uid] ))
|
1374 |
+
$output[$uid] = $component3->copy();
|
1375 |
+
}
|
1376 |
+
}
|
1377 |
+
elseif(( 'SUMMARY' == $propName ) && !isset( $output[$uid] )) {
|
1378 |
+
foreach( $pvalue as $pval ) {
|
1379 |
+
if( FALSE !== stripos( $d, $pval )) {
|
1380 |
+
$output[$uid] = $component3->copy();
|
1381 |
+
break;
|
1382 |
+
}
|
1383 |
+
}
|
1384 |
+
}
|
1385 |
+
elseif( in_array( $d, $pvalue ) && !isset( $output[$uid] ))
|
1386 |
+
$output[$uid] = $component3->copy();
|
1387 |
+
} // end foreach( $selectOptions as $propName => $pvalue ) {
|
1388 |
+
} // end foreach( $this->components as $cix => $component3 ) {
|
1389 |
+
if( !empty( $output )) {
|
1390 |
+
ksort( $output );
|
1391 |
+
$output = array_values( $output );
|
1392 |
+
}
|
1393 |
+
return $output;
|
1394 |
+
}
|
1395 |
+
/**
|
1396 |
+
* add calendar component to container
|
1397 |
+
*
|
1398 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1399 |
+
* @since 2.8.8 - 2011-03-15
|
1400 |
+
* @param object $component calendar component
|
1401 |
+
* @param mixed $arg1 optional, ordno/component type/ component uid
|
1402 |
+
* @param mixed $arg2 optional, ordno if arg1 = component type
|
1403 |
+
* @return void
|
1404 |
+
*/
|
1405 |
+
function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
|
1406 |
+
$component->setConfig( $this->getConfig(), FALSE, TRUE );
|
1407 |
+
if( !in_array( $component->objName, array( 'valarm', 'vtimezone' ))) {
|
1408 |
+
/* make sure dtstamp and uid is set */
|
1409 |
+
$dummy1 = $component->getProperty( 'dtstamp' );
|
1410 |
+
$dummy2 = $component->getProperty( 'uid' );
|
1411 |
+
}
|
1412 |
+
if( !$arg1 ) { // plain insert, last in chain
|
1413 |
+
$this->components[] = $component->copy();
|
1414 |
+
return TRUE;
|
1415 |
+
}
|
1416 |
+
$argType = $index = null;
|
1417 |
+
if ( ctype_digit( (string) $arg1 )) { // index insert/replace
|
1418 |
+
$argType = 'INDEX';
|
1419 |
+
$index = (int) $arg1 - 1;
|
1420 |
+
}
|
1421 |
+
elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) {
|
1422 |
+
$argType = strtolower( $arg1 );
|
1423 |
+
$index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
|
1424 |
+
}
|
1425 |
+
// else if arg1 is set, arg1 must be an UID
|
1426 |
+
$cix1sC = 0;
|
1427 |
+
foreach ( $this->components as $cix => $component2) {
|
1428 |
+
if( empty( $component2 )) continue;
|
1429 |
+
if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace
|
1430 |
+
$this->components[$cix] = $component->copy();
|
1431 |
+
return TRUE;
|
1432 |
+
}
|
1433 |
+
elseif( $argType == $component2->objName ) { // component Type index insert/replace
|
1434 |
+
if( $index == $cix1sC ) {
|
1435 |
+
$this->components[$cix] = $component->copy();
|
1436 |
+
return TRUE;
|
1437 |
+
}
|
1438 |
+
$cix1sC++;
|
1439 |
+
}
|
1440 |
+
elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace
|
1441 |
+
$this->components[$cix] = $component->copy();
|
1442 |
+
return TRUE;
|
1443 |
+
}
|
1444 |
+
}
|
1445 |
+
/* arg1=index and not found.. . insert at index .. .*/
|
1446 |
+
if( 'INDEX' == $argType ) {
|
1447 |
+
$this->components[$index] = $component->copy();
|
1448 |
+
ksort( $this->components, SORT_NUMERIC );
|
1449 |
+
}
|
1450 |
+
else /* not found.. . insert last in chain anyway .. .*/
|
1451 |
+
$this->components[] = $component->copy();
|
1452 |
+
return TRUE;
|
1453 |
+
}
|
1454 |
+
/**
|
1455 |
+
* sort iCal compoments
|
1456 |
+
*
|
1457 |
+
* ascending sort on properties (if exist) x-current-dtstart, dtstart,
|
1458 |
+
* x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid
|
1459 |
+
* if no arguments, otherwise sorting on argument CATEGORIES, LOCATION, SUMMARY or RESOURCES
|
1460 |
+
*
|
1461 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1462 |
+
* @since 2.8.4 - 2011-06-02
|
1463 |
+
* @param string $sortArg, optional
|
1464 |
+
* @return void
|
1465 |
+
*
|
1466 |
+
*/
|
1467 |
+
function sort( $sortArg=FALSE ) {
|
1468 |
+
if( is_array( $this->components )) {
|
1469 |
+
if( $sortArg ) {
|
1470 |
+
$sortArg = strtoupper( $sortArg );
|
1471 |
+
if( !in_array( $sortArg, array( 'ATTENDEE', 'CATEGORIES', 'DTSTAMP', 'LOCATION', 'ORGANIZER', 'RESOURCES', 'PRIORITY', 'STATUS', 'SUMMARY' )))
|
1472 |
+
$sortArg = FALSE;
|
1473 |
+
}
|
1474 |
+
/* set sort parameters for each component */
|
1475 |
+
foreach( $this->components as $cix => & $c ) {
|
1476 |
+
$c->srtk = array( '0', '0', '0', '0' );
|
1477 |
+
if( 'vtimezone' == $c->objName ) {
|
1478 |
+
if( FALSE === ( $c->srtk[0] = $c->getProperty( 'tzid' )))
|
1479 |
+
$c->srtk[0] = 0;
|
1480 |
+
continue;
|
1481 |
+
}
|
1482 |
+
elseif( $sortArg ) {
|
1483 |
+
if(( 'ATTENDEE' == $sortArg ) || ( 'CATEGORIES' == $sortArg ) || ( 'RESOURCES' == $sortArg )) {
|
1484 |
+
$propValues = array();
|
1485 |
+
$c->_getProperties( $sortArg, $propValues );
|
1486 |
+
$c->srtk[0] = reset( array_keys( $propValues ));
|
1487 |
+
}
|
1488 |
+
elseif( FALSE !== ( $d = $c->getProperty( $sortArg )))
|
1489 |
+
$c->srtk[0] = $d;
|
1490 |
+
continue;
|
1491 |
+
}
|
1492 |
+
if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTSTART' )))
|
1493 |
+
$c->srtk[0] = iCalUtilityFunctions::_date_time_string( $d[1] );
|
1494 |
+
elseif( FALSE === ( $c->srtk[0] = $c->getProperty( 'dtstart' )))
|
1495 |
+
$c->srtk[1] = 0; // sortkey 0 : dtstart
|
1496 |
+
if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DTEND' )))
|
1497 |
+
$c->srtk[1] = iCalUtilityFunctions::_date_time_string( $d[1] ); // sortkey 1 : dtend/due(/dtstart+duration)
|
1498 |
+
elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'dtend' ))) {
|
1499 |
+
if( FALSE !== ( $d = $c->getProperty( 'X-CURRENT-DUE' )))
|
1500 |
+
$c->srtk[1] = iCalUtilityFunctions::_date_time_string( $d[1] );
|
1501 |
+
elseif( FALSE === ( $c->srtk[1] = $c->getProperty( 'due' )))
|
1502 |
+
if( FALSE === ( $c->srtk[1] = $c->getProperty( 'duration', FALSE, FALSE, TRUE )))
|
1503 |
+
$c->srtk[1] = 0;
|
1504 |
+
}
|
1505 |
+
if( FALSE === ( $c->srtk[2] = $c->getProperty( 'created' ))) // sortkey 2 : created/dtstamp
|
1506 |
+
if( FALSE === ( $c->srtk[2] = $c->getProperty( 'dtstamp' )))
|
1507 |
+
$c->srtk[2] = 0;
|
1508 |
+
if( FALSE === ( $c->srtk[3] = $c->getProperty( 'uid' ))) // sortkey 3 : uid
|
1509 |
+
$c->srtk[3] = 0;
|
1510 |
+
} // end foreach( $this->components as & $c
|
1511 |
+
/* sort */
|
1512 |
+
usort( $this->components, array( $this, '_cmpfcn' ));
|
1513 |
+
}
|
1514 |
+
}
|
1515 |
+
function _cmpfcn( $a, $b ) {
|
1516 |
+
if( empty( $a )) return -1;
|
1517 |
+
if( empty( $b )) return 1;
|
1518 |
+
if( 'vtimezone' == $a->objName ) {
|
1519 |
+
if( 'vtimezone' != $b->objName ) return -1;
|
1520 |
+
elseif( $a->srtk[0] <= $b->srtk[0] ) return -1;
|
1521 |
+
else return 1;
|
1522 |
+
}
|
1523 |
+
elseif( 'vtimezone' == $b->objName ) return 1;
|
1524 |
+
$sortkeys = array( 'year', 'month', 'day', 'hour', 'min', 'sec' );
|
1525 |
+
for( $k = 0; $k < 4 ; $k++ ) {
|
1526 |
+
if( empty( $a->srtk[$k] )) return -1;
|
1527 |
+
elseif( empty( $b->srtk[$k] )) return 1;
|
1528 |
+
if( is_array( $a->srtk[$k] )) {
|
1529 |
+
if( is_array( $b->srtk[$k] )) {
|
1530 |
+
foreach( $sortkeys as $key ) {
|
1531 |
+
if ( empty( $a->srtk[$k][$key] )) return -1;
|
1532 |
+
elseif( empty( $b->srtk[$k][$key] )) return 1;
|
1533 |
+
if ( $a->srtk[$k][$key] == $b->srtk[$k][$key])
|
1534 |
+
continue;
|
1535 |
+
if (( (int) $a->srtk[$k][$key] ) < ((int) $b->srtk[$k][$key] ))
|
1536 |
+
return -1;
|
1537 |
+
elseif(( (int) $a->srtk[$k][$key] ) > ((int) $b->srtk[$k][$key] ))
|
1538 |
+
return 1;
|
1539 |
+
}
|
1540 |
+
}
|
1541 |
+
else return -1;
|
1542 |
+
}
|
1543 |
+
elseif( is_array( $b->srtk[$k] )) return 1;
|
1544 |
+
elseif( $a->srtk[$k] < $b->srtk[$k] ) return -1;
|
1545 |
+
elseif( $a->srtk[$k] > $b->srtk[$k] ) return 1;
|
1546 |
+
}
|
1547 |
+
return 0;
|
1548 |
+
}
|
1549 |
+
/**
|
1550 |
+
* parse iCal text/file into vcalendar, components, properties and parameters
|
1551 |
+
*
|
1552 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1553 |
+
* @since 2.8.2 - 2011-05-21
|
1554 |
+
* @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
|
1555 |
+
* @return bool FALSE if error occurs during parsing
|
1556 |
+
*
|
1557 |
+
*/
|
1558 |
+
function parse( $unparsedtext=FALSE ) {
|
1559 |
+
$nl = $this->getConfig( 'nl' );
|
1560 |
+
if(( FALSE === $unparsedtext ) || empty( $unparsedtext )) {
|
1561 |
+
/* directory+filename is set previously via setConfig directory+filename or url */
|
1562 |
+
if( FALSE === ( $filename = $this->getConfig( 'url' )))
|
1563 |
+
$filename = $this->getConfig( 'dirfile' );
|
1564 |
+
/* READ FILE */
|
1565 |
+
if( FALSE === ( $rows = file_get_contents( $filename )))
|
1566 |
+
return FALSE; /* err 1 */
|
1567 |
+
}
|
1568 |
+
elseif( is_array( $unparsedtext ))
|
1569 |
+
$rows = implode( '\n'.$nl, $unparsedtext );
|
1570 |
+
else
|
1571 |
+
$rows = & $unparsedtext;
|
1572 |
+
/* identify BEGIN:VCALENDAR, MUST be first row */
|
1573 |
+
if( 'BEGIN:VCALENDAR' != strtoupper( substr( $rows, 0, 15 )))
|
1574 |
+
return FALSE; /* err 8 */
|
1575 |
+
/* fix line folding */
|
1576 |
+
$eolchars = array( "\r\n", "\n\r", "\n", "\r" ); // check all line endings
|
1577 |
+
$EOLmark = FALSE;
|
1578 |
+
foreach( $eolchars as $eolchar ) {
|
1579 |
+
if( !$EOLmark && ( FALSE !== strpos( $rows, $eolchar ))) {
|
1580 |
+
$rows = str_replace( $eolchar." ", '', $rows );
|
1581 |
+
$rows = str_replace( $eolchar."\t", '', $rows );
|
1582 |
+
if( $eolchar != $nl )
|
1583 |
+
$rows = str_replace( $eolchar, $nl, $rows );
|
1584 |
+
$EOLmark = TRUE;
|
1585 |
+
}
|
1586 |
+
}
|
1587 |
+
$tmp = explode( $nl, $rows );
|
1588 |
+
$rows = array();
|
1589 |
+
foreach( $tmp as $tmpr )
|
1590 |
+
if( !empty( $tmpr ))
|
1591 |
+
$rows[] = $tmpr;
|
1592 |
+
/* skip trailing empty lines */
|
1593 |
+
$lix = count( $rows ) - 1;
|
1594 |
+
while( empty( $rows[$lix] ) && ( 0 < $lix ))
|
1595 |
+
$lix -= 1;
|
1596 |
+
/* identify ending END:VCALENDAR row, MUST be last row */
|
1597 |
+
if( 'END:VCALENDAR' != strtoupper( substr( $rows[$lix], 0, 13 )))
|
1598 |
+
return FALSE; /* err 9 */
|
1599 |
+
if( 3 > count( $rows ))
|
1600 |
+
return FALSE; /* err 10 */
|
1601 |
+
$comp = & $this;
|
1602 |
+
$calsync = 0;
|
1603 |
+
/* identify components and update unparsed data within component */
|
1604 |
+
$config = $this->getConfig();
|
1605 |
+
foreach( $rows as $line ) {
|
1606 |
+
if( '' == trim( $line ))
|
1607 |
+
continue;
|
1608 |
+
if( 'BEGIN:VCALENDAR' == strtoupper( substr( $line, 0, 15 ))) {
|
1609 |
+
$calsync++;
|
1610 |
+
continue;
|
1611 |
+
}
|
1612 |
+
elseif( 'END:VCALENDAR' == strtoupper( substr( $line, 0, 13 ))) {
|
1613 |
+
$calsync--;
|
1614 |
+
break;
|
1615 |
+
}
|
1616 |
+
elseif( 1 != $calsync )
|
1617 |
+
return FALSE; /* err 20 */
|
1618 |
+
elseif( in_array( strtoupper( substr( $line, 0, 6 )), array( 'END:VE', 'END:VF', 'END:VJ', 'END:VT' ))) {
|
1619 |
+
$this->components[] = $comp->copy();
|
1620 |
+
continue;
|
1621 |
+
}
|
1622 |
+
|
1623 |
+
if( 'BEGIN:VEVENT' == strtoupper( substr( $line, 0, 12 )))
|
1624 |
+
$comp = new vevent( $config );
|
1625 |
+
elseif( 'BEGIN:VFREEBUSY' == strtoupper( substr( $line, 0, 15 )))
|
1626 |
+
$comp = new vfreebusy( $config );
|
1627 |
+
elseif( 'BEGIN:VJOURNAL' == strtoupper( substr( $line, 0, 14 )))
|
1628 |
+
$comp = new vjournal( $config );
|
1629 |
+
elseif( 'BEGIN:VTODO' == strtoupper( substr( $line, 0, 11 )))
|
1630 |
+
$comp = new vtodo( $config );
|
1631 |
+
elseif( 'BEGIN:VTIMEZONE' == strtoupper( substr( $line, 0, 15 )))
|
1632 |
+
$comp = new vtimezone( $config );
|
1633 |
+
else /* update component with unparsed data */
|
1634 |
+
$comp->unparsed[] = $line;
|
1635 |
+
} // end - foreach( rows.. .
|
1636 |
+
unset( $config );
|
1637 |
+
/* parse data for calendar (this) object */
|
1638 |
+
if( isset( $this->unparsed ) && is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) {
|
1639 |
+
/* concatenate property values spread over several lines */
|
1640 |
+
$lastix = -1;
|
1641 |
+
$propnames = array( 'calscale','method','prodid','version','x-' );
|
1642 |
+
$proprows = array();
|
1643 |
+
foreach( $this->unparsed as $line ) {
|
1644 |
+
if( '' == trim( $line ))
|
1645 |
+
continue;
|
1646 |
+
$newProp = FALSE;
|
1647 |
+
foreach ( $propnames as $propname ) {
|
1648 |
+
if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
|
1649 |
+
$newProp = TRUE;
|
1650 |
+
break;
|
1651 |
+
}
|
1652 |
+
}
|
1653 |
+
if( $newProp ) {
|
1654 |
+
$newProp = FALSE;
|
1655 |
+
$lastix++;
|
1656 |
+
$proprows[$lastix] = $line;
|
1657 |
+
}
|
1658 |
+
else
|
1659 |
+
$proprows[$lastix] .= '!"#¤%&/()=?'.$line;
|
1660 |
+
}
|
1661 |
+
foreach( $proprows as $line ) {
|
1662 |
+
$line = str_replace( '!"#¤%&/()=? ', '', $line );
|
1663 |
+
$line = str_replace( '!"#¤%&/()=?', '', $line );
|
1664 |
+
if( '\n' == substr( $line, -2 ))
|
1665 |
+
$line = substr( $line, 0, strlen( $line ) - 2 );
|
1666 |
+
/* get property name */
|
1667 |
+
$cix = $propname = null;
|
1668 |
+
for( $cix=0, $clen = strlen( $line ); $cix < $clen; $cix++ ) {
|
1669 |
+
if( in_array( $line[$cix], array( ':', ';' )))
|
1670 |
+
break;
|
1671 |
+
else
|
1672 |
+
$propname .= $line[$cix];
|
1673 |
+
}
|
1674 |
+
/* ignore version/prodid properties */
|
1675 |
+
if( in_array( strtoupper( $propname ), array( 'VERSION', 'PRODID' )))
|
1676 |
+
continue;
|
1677 |
+
$line = substr( $line, $cix);
|
1678 |
+
/* separate attributes from value */
|
1679 |
+
$attr = array();
|
1680 |
+
$attrix = -1;
|
1681 |
+
$strlen = strlen( $line );
|
1682 |
+
for( $cix=0; $cix < $strlen; $cix++ ) {
|
1683 |
+
if(( ':' == $line[$cix] ) &&
|
1684 |
+
( '://' != substr( $line, $cix, 3 )) &&
|
1685 |
+
( !in_array( strtolower( substr( $line, $cix - 3, 4 )), array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ))) &&
|
1686 |
+
( !in_array( strtolower( substr( $line, $cix - 4, 5 )), array( 'crid:', 'news:', 'pres:' ))) &&
|
1687 |
+
( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
|
1688 |
+
$attrEnd = TRUE;
|
1689 |
+
if(( $cix < ( $strlen - 4 )) &&
|
1690 |
+
ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
|
1691 |
+
for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
|
1692 |
+
if( '://' == substr( $line, $c2ix - 2, 3 )) {
|
1693 |
+
$attrEnd = FALSE;
|
1694 |
+
break; // an URI with a portnr!!
|
1695 |
+
}
|
1696 |
+
}
|
1697 |
+
}
|
1698 |
+
if( $attrEnd) {
|
1699 |
+
$line = substr( $line, $cix + 1 );
|
1700 |
+
break;
|
1701 |
+
}
|
1702 |
+
}
|
1703 |
+
if( ';' == $line[$cix] )
|
1704 |
+
$attr[++$attrix] = null;
|
1705 |
+
else
|
1706 |
+
$attr[$attrix] .= $line[$cix];
|
1707 |
+
}
|
1708 |
+
|
1709 |
+
/* make attributes in array format */
|
1710 |
+
$propattr = array();
|
1711 |
+
foreach( $attr as $attribute ) {
|
1712 |
+
$attrsplit = explode( '=', $attribute, 2 );
|
1713 |
+
if( 1 < count( $attrsplit ))
|
1714 |
+
$propattr[$attrsplit[0]] = $attrsplit[1];
|
1715 |
+
else
|
1716 |
+
$propattr[] = $attribute;
|
1717 |
+
}
|
1718 |
+
/* update Property */
|
1719 |
+
if( FALSE !== strpos( $line, ',' )) {
|
1720 |
+
$content = explode( ',', $line );
|
1721 |
+
$clen = count( $content );
|
1722 |
+
for( $cix = 0; $cix < $clen; $cix++ ) {
|
1723 |
+
if( "\\" == substr( $content[$cix], -1 )) {
|
1724 |
+
$content[$cix] .= ','.$content[$cix + 1];
|
1725 |
+
unset( $content[$cix + 1] );
|
1726 |
+
$cix++;
|
1727 |
+
}
|
1728 |
+
}
|
1729 |
+
if( 1 < count( $content )) {
|
1730 |
+
foreach( $content as $cix => $contentPart )
|
1731 |
+
$content[$cix] = calendarComponent::_strunrep( $contentPart );
|
1732 |
+
$this->setProperty( $propname, $content, $propattr );
|
1733 |
+
continue;
|
1734 |
+
}
|
1735 |
+
else
|
1736 |
+
$line = reset( $content );
|
1737 |
+
$line = calendarComponent::_strunrep( $line );
|
1738 |
+
}
|
1739 |
+
$this->setProperty( $propname, trim( $line ), $propattr );
|
1740 |
+
} // end - foreach( $this->unparsed.. .
|
1741 |
+
} // end - if( is_array( $this->unparsed.. .
|
1742 |
+
unset( $unparsedtext, $rows, $this->unparsed, $proprows );
|
1743 |
+
/* parse Components */
|
1744 |
+
if( is_array( $this->components ) && ( 0 < count( $this->components ))) {
|
1745 |
+
$ckeys = array_keys( $this->components );
|
1746 |
+
foreach( $ckeys as $ckey ) {
|
1747 |
+
if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) {
|
1748 |
+
$this->components[$ckey]->parse();
|
1749 |
+
}
|
1750 |
+
}
|
1751 |
+
}
|
1752 |
+
else
|
1753 |
+
return FALSE; /* err 91 or something.. . */
|
1754 |
+
return TRUE;
|
1755 |
+
}
|
1756 |
+
/*********************************************************************************/
|
1757 |
+
/**
|
1758 |
+
* creates formatted output for calendar object instance
|
1759 |
+
*
|
1760 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1761 |
+
* @since 2.8.1 - 2011-03-12
|
1762 |
+
* @return string
|
1763 |
+
*/
|
1764 |
+
function createCalendar() {
|
1765 |
+
$calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null;
|
1766 |
+
switch( $this->format ) {
|
1767 |
+
case 'xcal':
|
1768 |
+
$calendarInit1 = '<?xml version="1.0" encoding="UTF-8"?>'.$this->nl.
|
1769 |
+
'<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"'.$this->nl.
|
1770 |
+
'"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"';
|
1771 |
+
$calendarInit2 = '>'.$this->nl;
|
1772 |
+
$calendarStart = '<vcalendar';
|
1773 |
+
break;
|
1774 |
+
default:
|
1775 |
+
$calendarStart = 'BEGIN:VCALENDAR'.$this->nl;
|
1776 |
+
break;
|
1777 |
+
}
|
1778 |
+
$calendarStart .= $this->createVersion();
|
1779 |
+
$calendarStart .= $this->createProdid();
|
1780 |
+
$calendarStart .= $this->createCalscale();
|
1781 |
+
$calendarStart .= $this->createMethod();
|
1782 |
+
switch( $this->format ) {
|
1783 |
+
case 'xcal':
|
1784 |
+
$nlstrlen = strlen( $this->nl );
|
1785 |
+
if( $this->nl == substr( $calendarStart, ( 0 - $nlstrlen )))
|
1786 |
+
$calendarStart = substr( $calendarStart, 0, ( strlen( $calendarStart ) - $nlstrlen ));
|
1787 |
+
$calendarStart .= '>'.$this->nl;
|
1788 |
+
break;
|
1789 |
+
default:
|
1790 |
+
break;
|
1791 |
+
}
|
1792 |
+
$calendar .= $this->createXprop();
|
1793 |
+
foreach( $this->components as $component ) {
|
1794 |
+
if( empty( $component )) continue;
|
1795 |
+
$component->setConfig( $this->getConfig(), FALSE, TRUE );
|
1796 |
+
$calendar .= $component->createComponent( $this->xcaldecl );
|
1797 |
+
}
|
1798 |
+
if(( 0 < count( $this->xcaldecl )) && ( 'xcal' == $this->format )) { // xCal only
|
1799 |
+
$calendarInit1 .= $this->nl.'['.$this->nl;
|
1800 |
+
$old_xcaldecl = array();
|
1801 |
+
foreach( $this->xcaldecl as $declix => $declPart ) {
|
1802 |
+
if(( 0 < count( $old_xcaldecl)) &&
|
1803 |
+
( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) &&
|
1804 |
+
( in_array( $declPart['external'], $old_xcaldecl['external'] )))
|
1805 |
+
continue; // no duplicate uri and ext. references
|
1806 |
+
$calendarxCaldecl .= '<!';
|
1807 |
+
foreach( $declPart as $declKey => $declValue ) {
|
1808 |
+
switch( $declKey ) { // index
|
1809 |
+
case 'xmldecl': // no 1
|
1810 |
+
$calendarxCaldecl .= $declValue.' ';
|
1811 |
+
break;
|
1812 |
+
case 'uri': // no 2
|
1813 |
+
$calendarxCaldecl .= $declValue.' ';
|
1814 |
+
$old_xcaldecl['uri'][] = $declValue;
|
1815 |
+
break;
|
1816 |
+
case 'ref': // no 3
|
1817 |
+
$calendarxCaldecl .= $declValue.' ';
|
1818 |
+
break;
|
1819 |
+
case 'external': // no 4
|
1820 |
+
$calendarxCaldecl .= '"'.$declValue.'" ';
|
1821 |
+
$old_xcaldecl['external'][] = $declValue;
|
1822 |
+
break;
|
1823 |
+
case 'type': // no 5
|
1824 |
+
$calendarxCaldecl .= $declValue.' ';
|
1825 |
+
break;
|
1826 |
+
case 'type2': // no 6
|
1827 |
+
$calendarxCaldecl .= $declValue;
|
1828 |
+
break;
|
1829 |
+
}
|
1830 |
+
}
|
1831 |
+
$calendarxCaldecl .= '>'.$this->nl;
|
1832 |
+
}
|
1833 |
+
$calendarInit2 = ']'.$calendarInit2;
|
1834 |
+
}
|
1835 |
+
switch( $this->format ) {
|
1836 |
+
case 'xcal':
|
1837 |
+
$calendar .= '</vcalendar>'.$this->nl;
|
1838 |
+
break;
|
1839 |
+
default:
|
1840 |
+
$calendar .= 'END:VCALENDAR'.$this->nl;
|
1841 |
+
break;
|
1842 |
+
}
|
1843 |
+
return $calendarInit1.$calendarxCaldecl.$calendarInit2.$calendarStart.$calendar;
|
1844 |
+
}
|
1845 |
+
/**
|
1846 |
+
* a HTTP redirect header is sent with created, updated and/or parsed calendar
|
1847 |
+
*
|
1848 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1849 |
+
* @since 2.9.12 - 2011-07-13
|
1850 |
+
* @param bool $utf8Encode
|
1851 |
+
* @param bool $gzip
|
1852 |
+
* @return redirect
|
1853 |
+
*/
|
1854 |
+
function returnCalendar( $utf8Encode=FALSE, $gzip=FALSE ) {
|
1855 |
+
$filename = $this->getConfig( 'filename' );
|
1856 |
+
$output = $this->createCalendar();
|
1857 |
+
if( $utf8Encode )
|
1858 |
+
$output = utf8_encode( $output );
|
1859 |
+
if( $gzip ) {
|
1860 |
+
$output = gzencode( $output, 9 );
|
1861 |
+
header( 'Content-Encoding: gzip');
|
1862 |
+
header( 'Vary: *');
|
1863 |
+
}
|
1864 |
+
$filesize = strlen( $output );
|
1865 |
+
if( 'xcal' == $this->format )
|
1866 |
+
header( 'Content-Type: application/calendar+xml; charset=utf-8' );
|
1867 |
+
else
|
1868 |
+
header( 'Content-Type: text/calendar; charset=utf-8' );
|
1869 |
+
header( 'Content-Length: '.$filesize );
|
1870 |
+
header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
|
1871 |
+
header( 'Cache-Control: max-age=10' );
|
1872 |
+
echo $output;
|
1873 |
+
die();
|
1874 |
+
}
|
1875 |
+
/**
|
1876 |
+
* save content in a file
|
1877 |
+
*
|
1878 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1879 |
+
* @since 2.2.12 - 2007-12-30
|
1880 |
+
* @param string $directory optional
|
1881 |
+
* @param string $filename optional
|
1882 |
+
* @param string $delimiter optional
|
1883 |
+
* @return bool
|
1884 |
+
*/
|
1885 |
+
function saveCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE ) {
|
1886 |
+
if( $directory )
|
1887 |
+
$this->setConfig( 'directory', $directory );
|
1888 |
+
if( $filename )
|
1889 |
+
$this->setConfig( 'filename', $filename );
|
1890 |
+
if( $delimiter && ($delimiter != DIRECTORY_SEPARATOR ))
|
1891 |
+
$this->setConfig( 'delimiter', $delimiter );
|
1892 |
+
if( FALSE === ( $dirfile = $this->getConfig( 'url' )))
|
1893 |
+
$dirfile = $this->getConfig( 'dirfile' );
|
1894 |
+
$iCalFile = @fopen( $dirfile, 'w' );
|
1895 |
+
if( $iCalFile ) {
|
1896 |
+
if( FALSE === fwrite( $iCalFile, $this->createCalendar() ))
|
1897 |
+
return FALSE;
|
1898 |
+
fclose( $iCalFile );
|
1899 |
+
return TRUE;
|
1900 |
+
}
|
1901 |
+
else
|
1902 |
+
return FALSE;
|
1903 |
+
}
|
1904 |
+
/**
|
1905 |
+
* if recent version of calendar file exists (default one hour), an HTTP redirect header is sent
|
1906 |
+
* else FALSE is returned
|
1907 |
+
*
|
1908 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1909 |
+
* @since 2.2.12 - 2007-10-28
|
1910 |
+
* @param string $directory optional alt. int timeout
|
1911 |
+
* @param string $filename optional
|
1912 |
+
* @param string $delimiter optional
|
1913 |
+
* @param int timeout optional, default 3600 sec
|
1914 |
+
* @return redirect/FALSE
|
1915 |
+
*/
|
1916 |
+
function useCachedCalendar( $directory=FALSE, $filename=FALSE, $delimiter=FALSE, $timeout=3600) {
|
1917 |
+
if ( $directory && ctype_digit( (string) $directory ) && !$filename ) {
|
1918 |
+
$timeout = (int) $directory;
|
1919 |
+
$directory = FALSE;
|
1920 |
+
}
|
1921 |
+
if( $directory )
|
1922 |
+
$this->setConfig( 'directory', $directory );
|
1923 |
+
if( $filename )
|
1924 |
+
$this->setConfig( 'filename', $filename );
|
1925 |
+
if( $delimiter && ( $delimiter != DIRECTORY_SEPARATOR ))
|
1926 |
+
$this->setConfig( 'delimiter', $delimiter );
|
1927 |
+
$filesize = $this->getConfig( 'filesize' );
|
1928 |
+
if( 0 >= $filesize )
|
1929 |
+
return FALSE;
|
1930 |
+
$dirfile = $this->getConfig( 'dirfile' );
|
1931 |
+
if( time() - filemtime( $dirfile ) < $timeout) {
|
1932 |
+
clearstatcache();
|
1933 |
+
$dirfile = $this->getConfig( 'dirfile' );
|
1934 |
+
$filename = $this->getConfig( 'filename' );
|
1935 |
+
// if( headers_sent( $filename, $linenum ))
|
1936 |
+
// die( "Headers already sent in $filename on line $linenum\n" );
|
1937 |
+
if( 'xcal' == $this->format )
|
1938 |
+
header( 'Content-Type: application/calendar+xml; charset=utf-8' );
|
1939 |
+
else
|
1940 |
+
header( 'Content-Type: text/calendar; charset=utf-8' );
|
1941 |
+
header( 'Content-Length: '.$filesize );
|
1942 |
+
header( 'Content-Disposition: attachment; filename="'.$filename.'"' );
|
1943 |
+
header( 'Cache-Control: max-age=10' );
|
1944 |
+
$fp = @fopen( $dirfile, 'r' );
|
1945 |
+
if( $fp ) {
|
1946 |
+
fpassthru( $fp );
|
1947 |
+
fclose( $fp );
|
1948 |
+
}
|
1949 |
+
die();
|
1950 |
+
}
|
1951 |
+
else
|
1952 |
+
return FALSE;
|
1953 |
+
}
|
1954 |
+
}
|
1955 |
+
/*********************************************************************************/
|
1956 |
+
/*********************************************************************************/
|
1957 |
+
/**
|
1958 |
+
* abstract class for calendar components
|
1959 |
+
*
|
1960 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1961 |
+
* @since 2.9.6 - 2011-05-14
|
1962 |
+
*/
|
1963 |
+
class calendarComponent {
|
1964 |
+
// component property variables
|
1965 |
+
var $uid;
|
1966 |
+
var $dtstamp;
|
1967 |
+
|
1968 |
+
// component config variables
|
1969 |
+
var $allowEmpty;
|
1970 |
+
var $language;
|
1971 |
+
var $nl;
|
1972 |
+
var $unique_id;
|
1973 |
+
var $format;
|
1974 |
+
var $objName; // created automatically at instance creation
|
1975 |
+
var $dtzid; // default (local) timezone
|
1976 |
+
// component internal variables
|
1977 |
+
var $componentStart1;
|
1978 |
+
var $componentStart2;
|
1979 |
+
var $componentEnd1;
|
1980 |
+
var $componentEnd2;
|
1981 |
+
var $elementStart1;
|
1982 |
+
var $elementStart2;
|
1983 |
+
var $elementEnd1;
|
1984 |
+
var $elementEnd2;
|
1985 |
+
var $intAttrDelimiter;
|
1986 |
+
var $attributeDelimiter;
|
1987 |
+
var $valueInit;
|
1988 |
+
// component xCal declaration container
|
1989 |
+
var $xcaldecl;
|
1990 |
+
/**
|
1991 |
+
* constructor for calendar component object
|
1992 |
+
*
|
1993 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1994 |
+
* @since 2.9.6 - 2011-05-17
|
1995 |
+
*/
|
1996 |
+
function calendarComponent() {
|
1997 |
+
$this->objName = ( isset( $this->timezonetype )) ?
|
1998 |
+
strtolower( $this->timezonetype ) : get_class ( $this );
|
1999 |
+
$this->uid = array();
|
2000 |
+
$this->dtstamp = array();
|
2001 |
+
|
2002 |
+
$this->language = null;
|
2003 |
+
$this->nl = null;
|
2004 |
+
$this->unique_id = null;
|
2005 |
+
$this->format = null;
|
2006 |
+
$this->dtzid = null;
|
2007 |
+
$this->allowEmpty = TRUE;
|
2008 |
+
$this->xcaldecl = array();
|
2009 |
+
|
2010 |
+
$this->_createFormat();
|
2011 |
+
$this->_makeDtstamp();
|
2012 |
+
}
|
2013 |
+
/*********************************************************************************/
|
2014 |
+
/**
|
2015 |
+
* Property Name: ACTION
|
2016 |
+
*/
|
2017 |
+
/**
|
2018 |
+
* creates formatted output for calendar component property action
|
2019 |
+
*
|
2020 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2021 |
+
* @since 2.4.8 - 2008-10-22
|
2022 |
+
* @return string
|
2023 |
+
*/
|
2024 |
+
function createAction() {
|
2025 |
+
if( empty( $this->action )) return FALSE;
|
2026 |
+
if( empty( $this->action['value'] ))
|
2027 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE;
|
2028 |
+
$attributes = $this->_createParams( $this->action['params'] );
|
2029 |
+
return $this->_createElement( 'ACTION', $attributes, $this->action['value'] );
|
2030 |
+
}
|
2031 |
+
/**
|
2032 |
+
* set calendar component property action
|
2033 |
+
*
|
2034 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2035 |
+
* @since 2.4.8 - 2008-11-04
|
2036 |
+
* @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
|
2037 |
+
* @param mixed $params
|
2038 |
+
* @return bool
|
2039 |
+
*/
|
2040 |
+
function setAction( $value, $params=FALSE ) {
|
2041 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2042 |
+
$this->action = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2043 |
+
return TRUE;
|
2044 |
+
}
|
2045 |
+
/*********************************************************************************/
|
2046 |
+
/**
|
2047 |
+
* Property Name: ATTACH
|
2048 |
+
*/
|
2049 |
+
/**
|
2050 |
+
* creates formatted output for calendar component property attach
|
2051 |
+
*
|
2052 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2053 |
+
* @since 0.9.7 - 2006-11-23
|
2054 |
+
* @return string
|
2055 |
+
*/
|
2056 |
+
function createAttach() {
|
2057 |
+
if( empty( $this->attach )) return FALSE;
|
2058 |
+
$output = null;
|
2059 |
+
foreach( $this->attach as $attachPart ) {
|
2060 |
+
if(! empty( $attachPart['value'] )) {
|
2061 |
+
$attributes = $this->_createParams( $attachPart['params'] );
|
2062 |
+
$output .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] );
|
2063 |
+
}
|
2064 |
+
elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' );
|
2065 |
+
}
|
2066 |
+
return $output;
|
2067 |
+
}
|
2068 |
+
/**
|
2069 |
+
* set calendar component property attach
|
2070 |
+
*
|
2071 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2072 |
+
* @since 2.5.1 - 2008-11-06
|
2073 |
+
* @param string $value
|
2074 |
+
* @param array $params, optional
|
2075 |
+
* @param integer $index, optional
|
2076 |
+
* @return bool
|
2077 |
+
*/
|
2078 |
+
function setAttach( $value, $params=FALSE, $index=FALSE ) {
|
2079 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2080 |
+
iCalUtilityFunctions::_setMval( $this->attach, $value, $params, FALSE, $index );
|
2081 |
+
return TRUE;
|
2082 |
+
}
|
2083 |
+
/*********************************************************************************/
|
2084 |
+
/**
|
2085 |
+
* Property Name: ATTENDEE
|
2086 |
+
*/
|
2087 |
+
/**
|
2088 |
+
* creates formatted output for calendar component property attendee
|
2089 |
+
*
|
2090 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2091 |
+
* @since 2.9.8 - 2011-05-30
|
2092 |
+
* @return string
|
2093 |
+
*/
|
2094 |
+
function createAttendee() {
|
2095 |
+
if( empty( $this->attendee )) return FALSE;
|
2096 |
+
$output = null;
|
2097 |
+
foreach( $this->attendee as $attendeePart ) { // start foreach 1
|
2098 |
+
if( empty( $attendeePart['value'] )) {
|
2099 |
+
if( $this->getConfig( 'allowEmpty' ))
|
2100 |
+
$output .= $this->_createElement( 'ATTENDEE' );
|
2101 |
+
continue;
|
2102 |
+
}
|
2103 |
+
$attendee1 = $attendee2 = null;
|
2104 |
+
foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2
|
2105 |
+
if( 'value' == $paramlabel )
|
2106 |
+
$attendee2 .= $paramvalue;
|
2107 |
+
elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
|
2108 |
+
// set attenddee parameters in rfc2445 order
|
2109 |
+
if( isset( $paramvalue['CUTYPE'] ))
|
2110 |
+
$attendee1 .= $this->intAttrDelimiter.'CUTYPE='.$paramvalue['CUTYPE'];
|
2111 |
+
if( isset( $paramvalue['MEMBER'] )) {
|
2112 |
+
$attendee1 .= $this->intAttrDelimiter.'MEMBER=';
|
2113 |
+
foreach( $paramvalue['MEMBER'] as $cix => $opv )
|
2114 |
+
$attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
|
2115 |
+
}
|
2116 |
+
if( isset( $paramvalue['ROLE'] ))
|
2117 |
+
$attendee1 .= $this->intAttrDelimiter.'ROLE='.$paramvalue['ROLE'];
|
2118 |
+
if( isset( $paramvalue['PARTSTAT'] ))
|
2119 |
+
$attendee1 .= $this->intAttrDelimiter.'PARTSTAT='.$paramvalue['PARTSTAT'];
|
2120 |
+
if( isset( $paramvalue['RSVP'] ))
|
2121 |
+
$attendee1 .= $this->intAttrDelimiter.'RSVP='.$paramvalue['RSVP'];
|
2122 |
+
if( isset( $paramvalue['DELEGATED-TO'] )) {
|
2123 |
+
$attendee1 .= $this->intAttrDelimiter.'DELEGATED-TO=';
|
2124 |
+
foreach( $paramvalue['DELEGATED-TO'] as $cix => $opv )
|
2125 |
+
$attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
|
2126 |
+
}
|
2127 |
+
if( isset( $paramvalue['DELEGATED-FROM'] )) {
|
2128 |
+
$attendee1 .= $this->intAttrDelimiter.'DELEGATED-FROM=';
|
2129 |
+
foreach( $paramvalue['DELEGATED-FROM'] as $cix => $opv )
|
2130 |
+
$attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
|
2131 |
+
}
|
2132 |
+
if( isset( $paramvalue['SENT-BY'] ))
|
2133 |
+
$attendee1 .= $this->intAttrDelimiter.'SENT-BY="'.$paramvalue['SENT-BY'].'"';
|
2134 |
+
if( isset( $paramvalue['CN'] ))
|
2135 |
+
$attendee1 .= $this->intAttrDelimiter.'CN="'.$paramvalue['CN'].'"';
|
2136 |
+
if( isset( $paramvalue['DIR'] ))
|
2137 |
+
$attendee1 .= $this->intAttrDelimiter.'DIR="'.$paramvalue['DIR'].'"';
|
2138 |
+
if( isset( $paramvalue['LANGUAGE'] ))
|
2139 |
+
$attendee1 .= $this->intAttrDelimiter.'LANGUAGE='.$paramvalue['LANGUAGE'];
|
2140 |
+
$xparams = array();
|
2141 |
+
foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
|
2142 |
+
if( ctype_digit( (string) $optparamlabel )) {
|
2143 |
+
$xparams[] = $optparamvalue;
|
2144 |
+
continue;
|
2145 |
+
}
|
2146 |
+
if( !in_array( $optparamlabel, array( 'CUTYPE', 'MEMBER', 'ROLE', 'PARTSTAT', 'RSVP', 'DELEGATED-TO', 'DELEGATED-FROM', 'SENT-BY', 'CN', 'DIR', 'LANGUAGE' )))
|
2147 |
+
$xparams[$optparamlabel] = $optparamvalue;
|
2148 |
+
} // end foreach 3
|
2149 |
+
ksort( $xparams, SORT_STRING );
|
2150 |
+
foreach( $xparams as $paramKey => $paramValue ) {
|
2151 |
+
if( ctype_digit( (string) $paramKey ))
|
2152 |
+
$attendee1 .= $this->intAttrDelimiter.$paramValue;
|
2153 |
+
else
|
2154 |
+
$attendee1 .= $this->intAttrDelimiter."$paramKey=$paramValue";
|
2155 |
+
} // end foreach 3
|
2156 |
+
} // end elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue )))
|
2157 |
+
} // end foreach 2
|
2158 |
+
$output .= $this->_createElement( 'ATTENDEE', $attendee1, $attendee2 );
|
2159 |
+
} // end foreach 1
|
2160 |
+
return $output;
|
2161 |
+
}
|
2162 |
+
/**
|
2163 |
+
* set calendar component property attach
|
2164 |
+
*
|
2165 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2166 |
+
* @since 2.6.34 - 2010-12-18
|
2167 |
+
* @param string $value
|
2168 |
+
* @param array $params, optional
|
2169 |
+
* @param integer $index, optional
|
2170 |
+
* @return bool
|
2171 |
+
*/
|
2172 |
+
function setAttendee( $value, $params=FALSE, $index=FALSE ) {
|
2173 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2174 |
+
// ftp://, http://, mailto:, file://, gopher://, news:, nntp://, telnet://, wais://, prospero:// may exist.. . also in params
|
2175 |
+
if( FALSE !== ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
|
2176 |
+
$value = strtoupper( substr( $value, 0, $pos )).substr( $value, $pos );
|
2177 |
+
elseif( !empty( $value ))
|
2178 |
+
$value = 'MAILTO:'.$value;
|
2179 |
+
$params2 = array();
|
2180 |
+
if( is_array($params )) {
|
2181 |
+
$optarrays = array();
|
2182 |
+
foreach( $params as $optparamlabel => $optparamvalue ) {
|
2183 |
+
$optparamlabel = strtoupper( $optparamlabel );
|
2184 |
+
switch( $optparamlabel ) {
|
2185 |
+
case 'MEMBER':
|
2186 |
+
case 'DELEGATED-TO':
|
2187 |
+
case 'DELEGATED-FROM':
|
2188 |
+
if( !is_array( $optparamvalue ))
|
2189 |
+
$optparamvalue = array( $optparamvalue );
|
2190 |
+
foreach( $optparamvalue as $part ) {
|
2191 |
+
$part = trim( $part );
|
2192 |
+
if(( '"' == substr( $part, 0, 1 )) &&
|
2193 |
+
( '"' == substr( $part, -1 )))
|
2194 |
+
$part = substr( $part, 1, ( strlen( $part ) - 2 ));
|
2195 |
+
if( 'mailto:' != strtolower( substr( $part, 0, 7 )))
|
2196 |
+
$part = "MAILTO:$part";
|
2197 |
+
else
|
2198 |
+
$part = 'MAILTO:'.substr( $part, 7 );
|
2199 |
+
$optarrays[$optparamlabel][] = $part;
|
2200 |
+
}
|
2201 |
+
break;
|
2202 |
+
default:
|
2203 |
+
if(( '"' == substr( $optparamvalue, 0, 1 )) &&
|
2204 |
+
( '"' == substr( $optparamvalue, -1 )))
|
2205 |
+
$optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
|
2206 |
+
if( 'SENT-BY' == $optparamlabel ) {
|
2207 |
+
if( 'mailto:' != strtolower( substr( $optparamvalue, 0, 7 )))
|
2208 |
+
$optparamvalue = "MAILTO:$optparamvalue";
|
2209 |
+
else
|
2210 |
+
$optparamvalue = 'MAILTO:'.substr( $optparamvalue, 7 );
|
2211 |
+
}
|
2212 |
+
$params2[$optparamlabel] = $optparamvalue;
|
2213 |
+
break;
|
2214 |
+
} // end switch( $optparamlabel.. .
|
2215 |
+
} // end foreach( $optparam.. .
|
2216 |
+
foreach( $optarrays as $optparamlabel => $optparams )
|
2217 |
+
$params2[$optparamlabel] = $optparams;
|
2218 |
+
}
|
2219 |
+
// remove defaults
|
2220 |
+
iCalUtilityFunctions::_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' );
|
2221 |
+
iCalUtilityFunctions::_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
|
2222 |
+
iCalUtilityFunctions::_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' );
|
2223 |
+
iCalUtilityFunctions::_existRem( $params2, 'RSVP', 'FALSE' );
|
2224 |
+
// check language setting
|
2225 |
+
if( isset( $params2['CN' ] )) {
|
2226 |
+
$lang = $this->getConfig( 'language' );
|
2227 |
+
if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
|
2228 |
+
$params2['LANGUAGE' ] = $lang;
|
2229 |
+
}
|
2230 |
+
iCalUtilityFunctions::_setMval( $this->attendee, $value, $params2, FALSE, $index );
|
2231 |
+
return TRUE;
|
2232 |
+
}
|
2233 |
+
/*********************************************************************************/
|
2234 |
+
/**
|
2235 |
+
* Property Name: CATEGORIES
|
2236 |
+
*/
|
2237 |
+
/**
|
2238 |
+
* creates formatted output for calendar component property categories
|
2239 |
+
*
|
2240 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2241 |
+
* @since 2.4.8 - 2008-10-22
|
2242 |
+
* @return string
|
2243 |
+
*/
|
2244 |
+
function createCategories() {
|
2245 |
+
if( empty( $this->categories )) return FALSE;
|
2246 |
+
$output = null;
|
2247 |
+
foreach( $this->categories as $category ) {
|
2248 |
+
if( empty( $category['value'] )) {
|
2249 |
+
if ( $this->getConfig( 'allowEmpty' ))
|
2250 |
+
$output .= $this->_createElement( 'CATEGORIES' );
|
2251 |
+
continue;
|
2252 |
+
}
|
2253 |
+
$attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' ));
|
2254 |
+
if( is_array( $category['value'] )) {
|
2255 |
+
foreach( $category['value'] as $cix => $categoryPart )
|
2256 |
+
$category['value'][$cix] = $this->_strrep( $categoryPart );
|
2257 |
+
$content = implode( ',', $category['value'] );
|
2258 |
+
}
|
2259 |
+
else
|
2260 |
+
$content = $this->_strrep( $category['value'] );
|
2261 |
+
$output .= $this->_createElement( 'CATEGORIES', $attributes, $content );
|
2262 |
+
}
|
2263 |
+
return $output;
|
2264 |
+
}
|
2265 |
+
/**
|
2266 |
+
* set calendar component property categories
|
2267 |
+
*
|
2268 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2269 |
+
* @since 2.5.1 - 2008-11-06
|
2270 |
+
* @param mixed $value
|
2271 |
+
* @param array $params, optional
|
2272 |
+
* @param integer $index, optional
|
2273 |
+
* @return bool
|
2274 |
+
*/
|
2275 |
+
function setCategories( $value, $params=FALSE, $index=FALSE ) {
|
2276 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2277 |
+
iCalUtilityFunctions::_setMval( $this->categories, $value, $params, FALSE, $index );
|
2278 |
+
return TRUE;
|
2279 |
+
}
|
2280 |
+
/*********************************************************************************/
|
2281 |
+
/**
|
2282 |
+
* Property Name: CLASS
|
2283 |
+
*/
|
2284 |
+
/**
|
2285 |
+
* creates formatted output for calendar component property class
|
2286 |
+
*
|
2287 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2288 |
+
* @since 0.9.7 - 2006-11-20
|
2289 |
+
* @return string
|
2290 |
+
*/
|
2291 |
+
function createClass() {
|
2292 |
+
if( empty( $this->class )) return FALSE;
|
2293 |
+
if( empty( $this->class['value'] ))
|
2294 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE;
|
2295 |
+
$attributes = $this->_createParams( $this->class['params'] );
|
2296 |
+
return $this->_createElement( 'CLASS', $attributes, $this->class['value'] );
|
2297 |
+
}
|
2298 |
+
/**
|
2299 |
+
* set calendar component property class
|
2300 |
+
*
|
2301 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2302 |
+
* @since 2.4.8 - 2008-11-04
|
2303 |
+
* @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
|
2304 |
+
* @param array $params optional
|
2305 |
+
* @return bool
|
2306 |
+
*/
|
2307 |
+
function setClass( $value, $params=FALSE ) {
|
2308 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2309 |
+
$this->class = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2310 |
+
return TRUE;
|
2311 |
+
}
|
2312 |
+
/*********************************************************************************/
|
2313 |
+
/**
|
2314 |
+
* Property Name: COMMENT
|
2315 |
+
*/
|
2316 |
+
/**
|
2317 |
+
* creates formatted output for calendar component property comment
|
2318 |
+
*
|
2319 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2320 |
+
* @since 2.4.8 - 2008-10-22
|
2321 |
+
* @return string
|
2322 |
+
*/
|
2323 |
+
function createComment() {
|
2324 |
+
if( empty( $this->comment )) return FALSE;
|
2325 |
+
$output = null;
|
2326 |
+
foreach( $this->comment as $commentPart ) {
|
2327 |
+
if( empty( $commentPart['value'] )) {
|
2328 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
|
2329 |
+
continue;
|
2330 |
+
}
|
2331 |
+
$attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
|
2332 |
+
$content = $this->_strrep( $commentPart['value'] );
|
2333 |
+
$output .= $this->_createElement( 'COMMENT', $attributes, $content );
|
2334 |
+
}
|
2335 |
+
return $output;
|
2336 |
+
}
|
2337 |
+
/**
|
2338 |
+
* set calendar component property comment
|
2339 |
+
*
|
2340 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2341 |
+
* @since 2.5.1 - 2008-11-06
|
2342 |
+
* @param string $value
|
2343 |
+
* @param array $params, optional
|
2344 |
+
* @param integer $index, optional
|
2345 |
+
* @return bool
|
2346 |
+
*/
|
2347 |
+
function setComment( $value, $params=FALSE, $index=FALSE ) {
|
2348 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2349 |
+
iCalUtilityFunctions::_setMval( $this->comment, $value, $params, FALSE, $index );
|
2350 |
+
return TRUE;
|
2351 |
+
}
|
2352 |
+
/*********************************************************************************/
|
2353 |
+
/**
|
2354 |
+
* Property Name: COMPLETED
|
2355 |
+
*/
|
2356 |
+
/**
|
2357 |
+
* creates formatted output for calendar component property completed
|
2358 |
+
*
|
2359 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2360 |
+
* @since 2.4.8 - 2008-10-22
|
2361 |
+
* @return string
|
2362 |
+
*/
|
2363 |
+
function createCompleted( ) {
|
2364 |
+
if( empty( $this->completed )) return FALSE;
|
2365 |
+
if( !isset( $this->completed['value']['year'] ) &&
|
2366 |
+
!isset( $this->completed['value']['month'] ) &&
|
2367 |
+
!isset( $this->completed['value']['day'] ) &&
|
2368 |
+
!isset( $this->completed['value']['hour'] ) &&
|
2369 |
+
!isset( $this->completed['value']['min'] ) &&
|
2370 |
+
!isset( $this->completed['value']['sec'] ))
|
2371 |
+
if( $this->getConfig( 'allowEmpty' ))
|
2372 |
+
return $this->_createElement( 'COMPLETED' );
|
2373 |
+
else return FALSE;
|
2374 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->completed['value'], 7 );
|
2375 |
+
$attributes = $this->_createParams( $this->completed['params'] );
|
2376 |
+
return $this->_createElement( 'COMPLETED', $attributes, $formatted );
|
2377 |
+
}
|
2378 |
+
/**
|
2379 |
+
* set calendar component property completed
|
2380 |
+
*
|
2381 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2382 |
+
* @since 2.4.8 - 2008-10-23
|
2383 |
+
* @param mixed $year
|
2384 |
+
* @param mixed $month optional
|
2385 |
+
* @param int $day optional
|
2386 |
+
* @param int $hour optional
|
2387 |
+
* @param int $min optional
|
2388 |
+
* @param int $sec optional
|
2389 |
+
* @param array $params optional
|
2390 |
+
* @return bool
|
2391 |
+
*/
|
2392 |
+
function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
|
2393 |
+
if( empty( $year )) {
|
2394 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
2395 |
+
$this->completed = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2396 |
+
return TRUE;
|
2397 |
+
}
|
2398 |
+
else
|
2399 |
+
return FALSE;
|
2400 |
+
}
|
2401 |
+
$this->completed = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
|
2402 |
+
return TRUE;
|
2403 |
+
}
|
2404 |
+
/*********************************************************************************/
|
2405 |
+
/**
|
2406 |
+
* Property Name: CONTACT
|
2407 |
+
*/
|
2408 |
+
/**
|
2409 |
+
* creates formatted output for calendar component property contact
|
2410 |
+
*
|
2411 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2412 |
+
* @since 2.4.8 - 2008-10-23
|
2413 |
+
* @return string
|
2414 |
+
*/
|
2415 |
+
function createContact() {
|
2416 |
+
if( empty( $this->contact )) return FALSE;
|
2417 |
+
$output = null;
|
2418 |
+
foreach( $this->contact as $contact ) {
|
2419 |
+
if( !empty( $contact['value'] )) {
|
2420 |
+
$attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
|
2421 |
+
$content = $this->_strrep( $contact['value'] );
|
2422 |
+
$output .= $this->_createElement( 'CONTACT', $attributes, $content );
|
2423 |
+
}
|
2424 |
+
elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
|
2425 |
+
}
|
2426 |
+
return $output;
|
2427 |
+
}
|
2428 |
+
/**
|
2429 |
+
* set calendar component property contact
|
2430 |
+
*
|
2431 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2432 |
+
* @since 2.5.1 - 2008-11-05
|
2433 |
+
* @param string $value
|
2434 |
+
* @param array $params, optional
|
2435 |
+
* @param integer $index, optional
|
2436 |
+
* @return bool
|
2437 |
+
*/
|
2438 |
+
function setContact( $value, $params=FALSE, $index=FALSE ) {
|
2439 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
2440 |
+
iCalUtilityFunctions::_setMval( $this->contact, $value, $params, FALSE, $index );
|
2441 |
+
return TRUE;
|
2442 |
+
}
|
2443 |
+
/*********************************************************************************/
|
2444 |
+
/**
|
2445 |
+
* Property Name: CREATED
|
2446 |
+
*/
|
2447 |
+
/**
|
2448 |
+
* creates formatted output for calendar component property created
|
2449 |
+
*
|
2450 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2451 |
+
* @since 2.4.8 - 2008-10-21
|
2452 |
+
* @return string
|
2453 |
+
*/
|
2454 |
+
function createCreated() {
|
2455 |
+
if( empty( $this->created )) return FALSE;
|
2456 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->created['value'], 7 );
|
2457 |
+
$attributes = $this->_createParams( $this->created['params'] );
|
2458 |
+
return $this->_createElement( 'CREATED', $attributes, $formatted );
|
2459 |
+
}
|
2460 |
+
/**
|
2461 |
+
* set calendar component property created
|
2462 |
+
*
|
2463 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2464 |
+
* @since 2.4.8 - 2008-10-23
|
2465 |
+
* @param mixed $year optional
|
2466 |
+
* @param mixed $month optional
|
2467 |
+
* @param int $day optional
|
2468 |
+
* @param int $hour optional
|
2469 |
+
* @param int $min optional
|
2470 |
+
* @param int $sec optional
|
2471 |
+
* @param mixed $params optional
|
2472 |
+
* @return bool
|
2473 |
+
*/
|
2474 |
+
function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
|
2475 |
+
if( !isset( $year )) {
|
2476 |
+
$year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
|
2477 |
+
}
|
2478 |
+
$this->created = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
|
2479 |
+
return TRUE;
|
2480 |
+
}
|
2481 |
+
/*********************************************************************************/
|
2482 |
+
/**
|
2483 |
+
* Property Name: DESCRIPTION
|
2484 |
+
*/
|
2485 |
+
/**
|
2486 |
+
* creates formatted output for calendar component property description
|
2487 |
+
*
|
2488 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2489 |
+
* @since 2.4.8 - 2008-10-22
|
2490 |
+
* @return string
|
2491 |
+
*/
|
2492 |
+
function createDescription() {
|
2493 |
+
if( empty( $this->description )) return FALSE;
|
2494 |
+
$output = null;
|
2495 |
+
foreach( $this->description as $description ) {
|
2496 |
+
if( !empty( $description['value'] )) {
|
2497 |
+
$attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
|
2498 |
+
$content = $this->_strrep( $description['value'] );
|
2499 |
+
$output .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
|
2500 |
+
}
|
2501 |
+
elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
|
2502 |
+
}
|
2503 |
+
return $output;
|
2504 |
+
}
|
2505 |
+
/**
|
2506 |
+
* set calendar component property description
|
2507 |
+
*
|
2508 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2509 |
+
* @since 2.6.24 - 2010-11-06
|
2510 |
+
* @param string $value
|
2511 |
+
* @param array $params, optional
|
2512 |
+
* @param integer $index, optional
|
2513 |
+
* @return bool
|
2514 |
+
*/
|
2515 |
+
function setDescription( $value, $params=FALSE, $index=FALSE ) {
|
2516 |
+
if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; }
|
2517 |
+
if( 'vjournal' != $this->objName )
|
2518 |
+
$index = 1;
|
2519 |
+
iCalUtilityFunctions::_setMval( $this->description, $value, $params, FALSE, $index );
|
2520 |
+
return TRUE;
|
2521 |
+
}
|
2522 |
+
/*********************************************************************************/
|
2523 |
+
/**
|
2524 |
+
* Property Name: DTEND
|
2525 |
+
*/
|
2526 |
+
/**
|
2527 |
+
* creates formatted output for calendar component property dtend
|
2528 |
+
*
|
2529 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2530 |
+
* @since 2.9.6 - 2011-05-14
|
2531 |
+
* @return string
|
2532 |
+
*/
|
2533 |
+
function createDtend() {
|
2534 |
+
if( empty( $this->dtend )) return FALSE;
|
2535 |
+
if( !isset( $this->dtend['value']['year'] ) &&
|
2536 |
+
!isset( $this->dtend['value']['month'] ) &&
|
2537 |
+
!isset( $this->dtend['value']['day'] ) &&
|
2538 |
+
!isset( $this->dtend['value']['hour'] ) &&
|
2539 |
+
!isset( $this->dtend['value']['min'] ) &&
|
2540 |
+
!isset( $this->dtend['value']['sec'] ))
|
2541 |
+
if( $this->getConfig( 'allowEmpty' ))
|
2542 |
+
return $this->_createElement( 'DTEND' );
|
2543 |
+
else return FALSE;
|
2544 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->dtend['value'] );
|
2545 |
+
if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
|
2546 |
+
( !isset( $this->dtend['params']['VALUE'] ) || ( $this->dtend['params']['VALUE'] != 'DATE' )) &&
|
2547 |
+
!isset( $this->dtend['params']['TZID'] ))
|
2548 |
+
$this->dtend['params']['TZID'] = $tzid;
|
2549 |
+
$attributes = $this->_createParams( $this->dtend['params'] );
|
2550 |
+
return $this->_createElement( 'DTEND', $attributes, $formatted );
|
2551 |
+
}
|
2552 |
+
/**
|
2553 |
+
* set calendar component property dtend
|
2554 |
+
*
|
2555 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2556 |
+
* @since 2.9.6 - 2011-05-14
|
2557 |
+
* @param mixed $year
|
2558 |
+
* @param mixed $month optional
|
2559 |
+
* @param int $day optional
|
2560 |
+
* @param int $hour optional
|
2561 |
+
* @param int $min optional
|
2562 |
+
* @param int $sec optional
|
2563 |
+
* @param string $tz optional
|
2564 |
+
* @param array params optional
|
2565 |
+
* @return bool
|
2566 |
+
*/
|
2567 |
+
function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
|
2568 |
+
if( empty( $year )) {
|
2569 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
2570 |
+
$this->dtend = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2571 |
+
return TRUE;
|
2572 |
+
}
|
2573 |
+
else
|
2574 |
+
return FALSE;
|
2575 |
+
}
|
2576 |
+
$this->dtend = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
|
2577 |
+
return TRUE;
|
2578 |
+
}
|
2579 |
+
/*********************************************************************************/
|
2580 |
+
/**
|
2581 |
+
* Property Name: DTSTAMP
|
2582 |
+
*/
|
2583 |
+
/**
|
2584 |
+
* creates formatted output for calendar component property dtstamp
|
2585 |
+
*
|
2586 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2587 |
+
* @since 2.4.4 - 2008-03-07
|
2588 |
+
* @return string
|
2589 |
+
*/
|
2590 |
+
function createDtstamp() {
|
2591 |
+
if( !isset( $this->dtstamp['value']['year'] ) &&
|
2592 |
+
!isset( $this->dtstamp['value']['month'] ) &&
|
2593 |
+
!isset( $this->dtstamp['value']['day'] ) &&
|
2594 |
+
!isset( $this->dtstamp['value']['hour'] ) &&
|
2595 |
+
!isset( $this->dtstamp['value']['min'] ) &&
|
2596 |
+
!isset( $this->dtstamp['value']['sec'] ))
|
2597 |
+
$this->_makeDtstamp();
|
2598 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->dtstamp['value'], 7 );
|
2599 |
+
$attributes = $this->_createParams( $this->dtstamp['params'] );
|
2600 |
+
return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
|
2601 |
+
}
|
2602 |
+
/**
|
2603 |
+
* computes datestamp for calendar component object instance dtstamp
|
2604 |
+
*
|
2605 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2606 |
+
* @since 2.6.25 - 2010-11-09
|
2607 |
+
* @return void
|
2608 |
+
*/
|
2609 |
+
function _makeDtstamp() {
|
2610 |
+
$d = mktime( date('H'), date('m'), (date('s') - date( 'Z' )), date('m'), date('d'), date('Y'));
|
2611 |
+
$this->dtstamp['value'] = array( 'year' => date( 'Y', $d )
|
2612 |
+
, 'month' => date( 'm', $d )
|
2613 |
+
, 'day' => date( 'd', $d )
|
2614 |
+
, 'hour' => date( 'H', $d )
|
2615 |
+
, 'min' => date( 'i', $d )
|
2616 |
+
, 'sec' => date( 's', $d ));
|
2617 |
+
$this->dtstamp['params'] = null;
|
2618 |
+
}
|
2619 |
+
/**
|
2620 |
+
* set calendar component property dtstamp
|
2621 |
+
*
|
2622 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2623 |
+
* @since 2.4.8 - 2008-10-23
|
2624 |
+
* @param mixed $year
|
2625 |
+
* @param mixed $month optional
|
2626 |
+
* @param int $day optional
|
2627 |
+
* @param int $hour optional
|
2628 |
+
* @param int $min optional
|
2629 |
+
* @param int $sec optional
|
2630 |
+
* @param array $params optional
|
2631 |
+
* @return TRUE
|
2632 |
+
*/
|
2633 |
+
function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
|
2634 |
+
if( empty( $year ))
|
2635 |
+
$this->_makeDtstamp();
|
2636 |
+
else
|
2637 |
+
$this->dtstamp = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
|
2638 |
+
return TRUE;
|
2639 |
+
}
|
2640 |
+
/*********************************************************************************/
|
2641 |
+
/**
|
2642 |
+
* Property Name: DTSTART
|
2643 |
+
*/
|
2644 |
+
/**
|
2645 |
+
* creates formatted output for calendar component property dtstart
|
2646 |
+
*
|
2647 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2648 |
+
* @since 2.9.6 - 2011-05-15
|
2649 |
+
* @return string
|
2650 |
+
*/
|
2651 |
+
function createDtstart() {
|
2652 |
+
if( empty( $this->dtstart )) return FALSE;
|
2653 |
+
if( !isset( $this->dtstart['value']['year'] ) &&
|
2654 |
+
!isset( $this->dtstart['value']['month'] ) &&
|
2655 |
+
!isset( $this->dtstart['value']['day'] ) &&
|
2656 |
+
!isset( $this->dtstart['value']['hour'] ) &&
|
2657 |
+
!isset( $this->dtstart['value']['min'] ) &&
|
2658 |
+
!isset( $this->dtstart['value']['sec'] )) {
|
2659 |
+
if( $this->getConfig( 'allowEmpty' ))
|
2660 |
+
return $this->_createElement( 'DTSTART' );
|
2661 |
+
else return FALSE;
|
2662 |
+
}
|
2663 |
+
if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
|
2664 |
+
unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
|
2665 |
+
elseif(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
|
2666 |
+
( !isset( $this->dtstart['params']['VALUE'] ) || ( $this->dtstart['params']['VALUE'] != 'DATE' )) &&
|
2667 |
+
!isset( $this->dtstart['params']['TZID'] ))
|
2668 |
+
$this->dtstart['params']['TZID'] = $tzid;
|
2669 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->dtstart['value'] );
|
2670 |
+
$attributes = $this->_createParams( $this->dtstart['params'] );
|
2671 |
+
return $this->_createElement( 'DTSTART', $attributes, $formatted );
|
2672 |
+
}
|
2673 |
+
/**
|
2674 |
+
* set calendar component property dtstart
|
2675 |
+
*
|
2676 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2677 |
+
* @since 2.6.22 - 2010-09-22
|
2678 |
+
* @param mixed $year
|
2679 |
+
* @param mixed $month optional
|
2680 |
+
* @param int $day optional
|
2681 |
+
* @param int $hour optional
|
2682 |
+
* @param int $min optional
|
2683 |
+
* @param int $sec optional
|
2684 |
+
* @param string $tz optional
|
2685 |
+
* @param array $params optional
|
2686 |
+
* @return bool
|
2687 |
+
*/
|
2688 |
+
function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
|
2689 |
+
if( empty( $year )) {
|
2690 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
2691 |
+
$this->dtstart = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2692 |
+
return TRUE;
|
2693 |
+
}
|
2694 |
+
else
|
2695 |
+
return FALSE;
|
2696 |
+
}
|
2697 |
+
$this->dtstart = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart', $this->objName, $this->getConfig( 'TZID' ));
|
2698 |
+
return TRUE;
|
2699 |
+
}
|
2700 |
+
/*********************************************************************************/
|
2701 |
+
/**
|
2702 |
+
* Property Name: DUE
|
2703 |
+
*/
|
2704 |
+
/**
|
2705 |
+
* creates formatted output for calendar component property due
|
2706 |
+
*
|
2707 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2708 |
+
* @since 2.4.8 - 2008-10-22
|
2709 |
+
* @return string
|
2710 |
+
*/
|
2711 |
+
function createDue() {
|
2712 |
+
if( empty( $this->due )) return FALSE;
|
2713 |
+
if( !isset( $this->due['value']['year'] ) &&
|
2714 |
+
!isset( $this->due['value']['month'] ) &&
|
2715 |
+
!isset( $this->due['value']['day'] ) &&
|
2716 |
+
!isset( $this->due['value']['hour'] ) &&
|
2717 |
+
!isset( $this->due['value']['min'] ) &&
|
2718 |
+
!isset( $this->due['value']['sec'] )) {
|
2719 |
+
if( $this->getConfig( 'allowEmpty' ))
|
2720 |
+
return $this->_createElement( 'DUE' );
|
2721 |
+
else
|
2722 |
+
return FALSE;
|
2723 |
+
}
|
2724 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->due['value'] );
|
2725 |
+
if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
|
2726 |
+
( !isset( $this->due['params']['VALUE'] ) || ( $this->due['params']['VALUE'] != 'DATE' )) &&
|
2727 |
+
!isset( $this->due['params']['TZID'] ))
|
2728 |
+
$this->due['params']['TZID'] = $tzid;
|
2729 |
+
$attributes = $this->_createParams( $this->due['params'] );
|
2730 |
+
return $this->_createElement( 'DUE', $attributes, $formatted );
|
2731 |
+
}
|
2732 |
+
/**
|
2733 |
+
* set calendar component property due
|
2734 |
+
*
|
2735 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2736 |
+
* @since 2.4.8 - 2008-11-04
|
2737 |
+
* @param mixed $year
|
2738 |
+
* @param mixed $month optional
|
2739 |
+
* @param int $day optional
|
2740 |
+
* @param int $hour optional
|
2741 |
+
* @param int $min optional
|
2742 |
+
* @param int $sec optional
|
2743 |
+
* @param array $params optional
|
2744 |
+
* @return bool
|
2745 |
+
*/
|
2746 |
+
function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
|
2747 |
+
if( empty( $year )) {
|
2748 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
2749 |
+
$this->due = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2750 |
+
return TRUE;
|
2751 |
+
}
|
2752 |
+
else
|
2753 |
+
return FALSE;
|
2754 |
+
}
|
2755 |
+
$this->due = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
|
2756 |
+
return TRUE;
|
2757 |
+
}
|
2758 |
+
/*********************************************************************************/
|
2759 |
+
/**
|
2760 |
+
* Property Name: DURATION
|
2761 |
+
*/
|
2762 |
+
/**
|
2763 |
+
* creates formatted output for calendar component property duration
|
2764 |
+
*
|
2765 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2766 |
+
* @since 2.4.8 - 2008-10-21
|
2767 |
+
* @return string
|
2768 |
+
*/
|
2769 |
+
function createDuration() {
|
2770 |
+
if( empty( $this->duration )) return FALSE;
|
2771 |
+
if( !isset( $this->duration['value']['week'] ) &&
|
2772 |
+
!isset( $this->duration['value']['day'] ) &&
|
2773 |
+
!isset( $this->duration['value']['hour'] ) &&
|
2774 |
+
!isset( $this->duration['value']['min'] ) &&
|
2775 |
+
!isset( $this->duration['value']['sec'] ))
|
2776 |
+
if( $this->getConfig( 'allowEmpty' ))
|
2777 |
+
return $this->_createElement( 'DURATION', array(), null );
|
2778 |
+
else return FALSE;
|
2779 |
+
$attributes = $this->_createParams( $this->duration['params'] );
|
2780 |
+
return $this->_createElement( 'DURATION', $attributes, iCalUtilityFunctions::_format_duration( $this->duration['value'] ));
|
2781 |
+
}
|
2782 |
+
/**
|
2783 |
+
* set calendar component property duration
|
2784 |
+
*
|
2785 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2786 |
+
* @since 2.4.8 - 2008-11-04
|
2787 |
+
* @param mixed $week
|
2788 |
+
* @param mixed $day optional
|
2789 |
+
* @param int $hour optional
|
2790 |
+
* @param int $min optional
|
2791 |
+
* @param int $sec optional
|
2792 |
+
* @param array $params optional
|
2793 |
+
* @return bool
|
2794 |
+
*/
|
2795 |
+
function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
|
2796 |
+
if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
|
2797 |
+
if( is_array( $week ) && ( 1 <= count( $week )))
|
2798 |
+
$this->duration = array( 'value' => iCalUtilityFunctions::_duration_array( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
|
2799 |
+
elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
|
2800 |
+
$week = trim( $week );
|
2801 |
+
if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
|
2802 |
+
$week = substr( $week, 1 );
|
2803 |
+
$this->duration = array( 'value' => iCalUtilityFunctions::_duration_string( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
|
2804 |
+
}
|
2805 |
+
elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
|
2806 |
+
return FALSE;
|
2807 |
+
else
|
2808 |
+
$this->duration = array( 'value' => iCalUtilityFunctions::_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => iCalUtilityFunctions::_setParams( $params ));
|
2809 |
+
return TRUE;
|
2810 |
+
}
|
2811 |
+
/*********************************************************************************/
|
2812 |
+
/**
|
2813 |
+
* Property Name: EXDATE
|
2814 |
+
*/
|
2815 |
+
/**
|
2816 |
+
* creates formatted output for calendar component property exdate
|
2817 |
+
*
|
2818 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2819 |
+
* @since 2.4.8 - 2008-10-22
|
2820 |
+
* @return string
|
2821 |
+
*/
|
2822 |
+
function createExdate() {
|
2823 |
+
if( empty( $this->exdate )) return FALSE;
|
2824 |
+
$output = null;
|
2825 |
+
foreach( $this->exdate as $ex => $theExdate ) {
|
2826 |
+
if( empty( $theExdate['value'] )) {
|
2827 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'EXDATE' );
|
2828 |
+
continue;
|
2829 |
+
}
|
2830 |
+
$content = $attributes = null;
|
2831 |
+
foreach( $theExdate['value'] as $eix => $exdatePart ) {
|
2832 |
+
$parno = count( $exdatePart );
|
2833 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $exdatePart, $parno );
|
2834 |
+
if( isset( $theExdate['params']['TZID'] ))
|
2835 |
+
$formatted = str_replace( 'Z', '', $formatted);
|
2836 |
+
if( 0 < $eix ) {
|
2837 |
+
if( isset( $theExdate['value'][0]['tz'] )) {
|
2838 |
+
if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) ||
|
2839 |
+
( 'Z' == $theExdate['value'][0]['tz'] )) {
|
2840 |
+
if( 'Z' != substr( $formatted, -1 ))
|
2841 |
+
$formatted .= 'Z';
|
2842 |
+
}
|
2843 |
+
else
|
2844 |
+
$formatted = str_replace( 'Z', '', $formatted );
|
2845 |
+
}
|
2846 |
+
else
|
2847 |
+
$formatted = str_replace( 'Z', '', $formatted );
|
2848 |
+
}
|
2849 |
+
$content .= ( 0 < $eix ) ? ','.$formatted : $formatted;
|
2850 |
+
}
|
2851 |
+
$attributes .= $this->_createParams( $theExdate['params'] );
|
2852 |
+
$output .= $this->_createElement( 'EXDATE', $attributes, $content );
|
2853 |
+
}
|
2854 |
+
return $output;
|
2855 |
+
}
|
2856 |
+
/**
|
2857 |
+
* set calendar component property exdate
|
2858 |
+
*
|
2859 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2860 |
+
* @since 2.5.1 - 2008-11-05
|
2861 |
+
* @param array exdates
|
2862 |
+
* @param array $params, optional
|
2863 |
+
* @param integer $index, optional
|
2864 |
+
* @return bool
|
2865 |
+
*/
|
2866 |
+
function setExdate( $exdates, $params=FALSE, $index=FALSE ) {
|
2867 |
+
if( empty( $exdates )) {
|
2868 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
2869 |
+
iCalUtilityFunctions::_setMval( $this->exdate, null, $params, FALSE, $index );
|
2870 |
+
return TRUE;
|
2871 |
+
}
|
2872 |
+
else
|
2873 |
+
return FALSE;
|
2874 |
+
}
|
2875 |
+
$input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
|
2876 |
+
/* ev. check 1:st date and save ev. timezone **/
|
2877 |
+
iCalUtilityFunctions::_chkdatecfg( reset( $exdates ), $parno, $input['params'] );
|
2878 |
+
iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
|
2879 |
+
foreach( $exdates as $eix => $theExdate ) {
|
2880 |
+
if( iCalUtilityFunctions::_isArrayTimestampDate( $theExdate ))
|
2881 |
+
$exdatea = iCalUtilityFunctions::_timestamp2date( $theExdate, $parno );
|
2882 |
+
elseif( is_array( $theExdate ))
|
2883 |
+
$exdatea = iCalUtilityFunctions::_date_time_array( $theExdate, $parno );
|
2884 |
+
elseif( 8 <= strlen( trim( $theExdate ))) // ex. 2006-08-03 10:12:18
|
2885 |
+
$exdatea = iCalUtilityFunctions::_date_time_string( $theExdate, $parno );
|
2886 |
+
if( 3 == $parno )
|
2887 |
+
unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] );
|
2888 |
+
elseif( isset( $exdatea['tz'] ))
|
2889 |
+
$exdatea['tz'] = (string) $exdatea['tz'];
|
2890 |
+
if( isset( $input['params']['TZID'] ) ||
|
2891 |
+
( isset( $exdatea['tz'] ) && !iCalUtilityFunctions::_isOffset( $exdatea['tz'] )) ||
|
2892 |
+
( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
|
2893 |
+
( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
|
2894 |
+
unset( $exdatea['tz'] );
|
2895 |
+
$input['value'][] = $exdatea;
|
2896 |
+
}
|
2897 |
+
if( 0 >= count( $input['value'] ))
|
2898 |
+
return FALSE;
|
2899 |
+
if( 3 == $parno ) {
|
2900 |
+
$input['params']['VALUE'] = 'DATE';
|
2901 |
+
unset( $input['params']['TZID'] );
|
2902 |
+
}
|
2903 |
+
iCalUtilityFunctions::_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index );
|
2904 |
+
return TRUE;
|
2905 |
+
}
|
2906 |
+
/*********************************************************************************/
|
2907 |
+
/**
|
2908 |
+
* Property Name: EXRULE
|
2909 |
+
*/
|
2910 |
+
/**
|
2911 |
+
* creates formatted output for calendar component property exrule
|
2912 |
+
*
|
2913 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2914 |
+
* @since 2.4.8 - 2008-10-22
|
2915 |
+
* @return string
|
2916 |
+
*/
|
2917 |
+
function createExrule() {
|
2918 |
+
if( empty( $this->exrule )) return FALSE;
|
2919 |
+
return $this->_format_recur( 'EXRULE', $this->exrule );
|
2920 |
+
}
|
2921 |
+
/**
|
2922 |
+
* set calendar component property exdate
|
2923 |
+
*
|
2924 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2925 |
+
* @since 2.5.1 - 2008-11-05
|
2926 |
+
* @param array $exruleset
|
2927 |
+
* @param array $params, optional
|
2928 |
+
* @param integer $index, optional
|
2929 |
+
* @return bool
|
2930 |
+
*/
|
2931 |
+
function setExrule( $exruleset, $params=FALSE, $index=FALSE ) {
|
2932 |
+
if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = null; else return FALSE;
|
2933 |
+
iCalUtilityFunctions::_setMval( $this->exrule, iCalUtilityFunctions::_setRexrule( $exruleset ), $params, FALSE, $index );
|
2934 |
+
return TRUE;
|
2935 |
+
}
|
2936 |
+
/*********************************************************************************/
|
2937 |
+
/**
|
2938 |
+
* Property Name: FREEBUSY
|
2939 |
+
*/
|
2940 |
+
/**
|
2941 |
+
* creates formatted output for calendar component property freebusy
|
2942 |
+
*
|
2943 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2944 |
+
* @since 2.4.8 - 2008-10-22
|
2945 |
+
* @return string
|
2946 |
+
*/
|
2947 |
+
function createFreebusy() {
|
2948 |
+
if( empty( $this->freebusy )) return FALSE;
|
2949 |
+
$output = null;
|
2950 |
+
foreach( $this->freebusy as $freebusyPart ) {
|
2951 |
+
if( empty( $freebusyPart['value'] )) {
|
2952 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' );
|
2953 |
+
continue;
|
2954 |
+
}
|
2955 |
+
$attributes = $content = null;
|
2956 |
+
if( isset( $freebusyPart['value']['fbtype'] )) {
|
2957 |
+
$attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype'];
|
2958 |
+
unset( $freebusyPart['value']['fbtype'] );
|
2959 |
+
$freebusyPart['value'] = array_values( $freebusyPart['value'] );
|
2960 |
+
}
|
2961 |
+
else
|
2962 |
+
$attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY';
|
2963 |
+
$attributes .= $this->_createParams( $freebusyPart['params'] );
|
2964 |
+
$fno = 1;
|
2965 |
+
$cnt = count( $freebusyPart['value']);
|
2966 |
+
foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
|
2967 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $freebusyPeriod[0] );
|
2968 |
+
$content .= $formatted;
|
2969 |
+
$content .= '/';
|
2970 |
+
$cnt2 = count( $freebusyPeriod[1]);
|
2971 |
+
if( array_key_exists( 'year', $freebusyPeriod[1] )) // date-time
|
2972 |
+
$cnt2 = 7;
|
2973 |
+
elseif( array_key_exists( 'week', $freebusyPeriod[1] )) // duration
|
2974 |
+
$cnt2 = 5;
|
2975 |
+
if(( 7 == $cnt2 ) && // period= -> date-time
|
2976 |
+
isset( $freebusyPeriod[1]['year'] ) &&
|
2977 |
+
isset( $freebusyPeriod[1]['month'] ) &&
|
2978 |
+
isset( $freebusyPeriod[1]['day'] )) {
|
2979 |
+
$content .= iCalUtilityFunctions::_format_date_time( $freebusyPeriod[1] );
|
2980 |
+
}
|
2981 |
+
else { // period= -> dur-time
|
2982 |
+
$content .= iCalUtilityFunctions::_format_duration( $freebusyPeriod[1] );
|
2983 |
+
}
|
2984 |
+
if( $fno < $cnt )
|
2985 |
+
$content .= ',';
|
2986 |
+
$fno++;
|
2987 |
+
}
|
2988 |
+
$output .= $this->_createElement( 'FREEBUSY', $attributes, $content );
|
2989 |
+
}
|
2990 |
+
return $output;
|
2991 |
+
}
|
2992 |
+
/**
|
2993 |
+
* set calendar component property freebusy
|
2994 |
+
*
|
2995 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2996 |
+
* @since 2.8.10 - 2011-03-24
|
2997 |
+
* @param string $fbType
|
2998 |
+
* @param array $fbValues
|
2999 |
+
* @param array $params, optional
|
3000 |
+
* @param integer $index, optional
|
3001 |
+
* @return bool
|
3002 |
+
*/
|
3003 |
+
function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) {
|
3004 |
+
if( empty( $fbValues )) {
|
3005 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
3006 |
+
iCalUtilityFunctions::_setMval( $this->freebusy, null, $params, FALSE, $index );
|
3007 |
+
return TRUE;
|
3008 |
+
}
|
3009 |
+
else
|
3010 |
+
return FALSE;
|
3011 |
+
}
|
3012 |
+
$fbType = strtoupper( $fbType );
|
3013 |
+
if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) &&
|
3014 |
+
( 'X-' != substr( $fbType, 0, 2 )))
|
3015 |
+
$fbType = 'BUSY';
|
3016 |
+
$input = array( 'fbtype' => $fbType );
|
3017 |
+
foreach( $fbValues as $fbPeriod ) { // periods => period
|
3018 |
+
if( empty( $fbPeriod ))
|
3019 |
+
continue;
|
3020 |
+
$freebusyPeriod = array();
|
3021 |
+
foreach( $fbPeriod as $fbMember ) { // pairs => singlepart
|
3022 |
+
$freebusyPairMember = array();
|
3023 |
+
if( is_array( $fbMember )) {
|
3024 |
+
if( iCalUtilityFunctions::_isArrayDate( $fbMember )) { // date-time value
|
3025 |
+
$freebusyPairMember = iCalUtilityFunctions::_date_time_array( $fbMember, 7 );
|
3026 |
+
$freebusyPairMember['tz'] = 'Z';
|
3027 |
+
}
|
3028 |
+
elseif( iCalUtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value
|
3029 |
+
$freebusyPairMember = iCalUtilityFunctions::_timestamp2date( $fbMember['timestamp'], 7 );
|
3030 |
+
$freebusyPairMember['tz'] = 'Z';
|
3031 |
+
}
|
3032 |
+
else { // array format duration
|
3033 |
+
$freebusyPairMember = iCalUtilityFunctions::_duration_array( $fbMember );
|
3034 |
+
}
|
3035 |
+
}
|
3036 |
+
elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
|
3037 |
+
( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
|
3038 |
+
if( 'P' != $fbMember{0} )
|
3039 |
+
$fbmember = substr( $fbMember, 1 );
|
3040 |
+
$freebusyPairMember = iCalUtilityFunctions::_duration_string( $fbMember );
|
3041 |
+
}
|
3042 |
+
elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
|
3043 |
+
$freebusyPairMember = iCalUtilityFunctions::_date_time_string( $fbMember, 7 );
|
3044 |
+
$freebusyPairMember['tz'] = 'Z';
|
3045 |
+
}
|
3046 |
+
$freebusyPeriod[] = $freebusyPairMember;
|
3047 |
+
}
|
3048 |
+
$input[] = $freebusyPeriod;
|
3049 |
+
}
|
3050 |
+
iCalUtilityFunctions::_setMval( $this->freebusy, $input, $params, FALSE, $index );
|
3051 |
+
return TRUE;
|
3052 |
+
}
|
3053 |
+
/*********************************************************************************/
|
3054 |
+
/**
|
3055 |
+
* Property Name: GEO
|
3056 |
+
*/
|
3057 |
+
/**
|
3058 |
+
* creates formatted output for calendar component property geo
|
3059 |
+
*
|
3060 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3061 |
+
* @since 2.4.8 - 2008-10-21
|
3062 |
+
* @return string
|
3063 |
+
*/
|
3064 |
+
function createGeo() {
|
3065 |
+
if( empty( $this->geo )) return FALSE;
|
3066 |
+
if( empty( $this->geo['value'] ))
|
3067 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE;
|
3068 |
+
$attributes = $this->_createParams( $this->geo['params'] );
|
3069 |
+
$content = null;
|
3070 |
+
$content .= number_format( (float) $this->geo['value']['latitude'], 6, '.', '');
|
3071 |
+
$content .= ';';
|
3072 |
+
$content .= number_format( (float) $this->geo['value']['longitude'], 6, '.', '');
|
3073 |
+
return $this->_createElement( 'GEO', $attributes, $content );
|
3074 |
+
}
|
3075 |
+
/**
|
3076 |
+
* set calendar component property geo
|
3077 |
+
*
|
3078 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3079 |
+
* @since 2.4.8 - 2008-11-04
|
3080 |
+
* @param float $latitude
|
3081 |
+
* @param float $longitude
|
3082 |
+
* @param array $params optional
|
3083 |
+
* @return bool
|
3084 |
+
*/
|
3085 |
+
function setGeo( $latitude, $longitude, $params=FALSE ) {
|
3086 |
+
if( !empty( $latitude ) && !empty( $longitude )) {
|
3087 |
+
if( !is_array( $this->geo )) $this->geo = array();
|
3088 |
+
$this->geo['value']['latitude'] = $latitude;
|
3089 |
+
$this->geo['value']['longitude'] = $longitude;
|
3090 |
+
$this->geo['params'] = iCalUtilityFunctions::_setParams( $params );
|
3091 |
+
}
|
3092 |
+
elseif( $this->getConfig( 'allowEmpty' ))
|
3093 |
+
$this->geo = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ) );
|
3094 |
+
else
|
3095 |
+
return FALSE;
|
3096 |
+
return TRUE;
|
3097 |
+
}
|
3098 |
+
/*********************************************************************************/
|
3099 |
+
/**
|
3100 |
+
* Property Name: LAST-MODIFIED
|
3101 |
+
*/
|
3102 |
+
/**
|
3103 |
+
* creates formatted output for calendar component property last-modified
|
3104 |
+
*
|
3105 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3106 |
+
* @since 2.4.8 - 2008-10-21
|
3107 |
+
* @return string
|
3108 |
+
*/
|
3109 |
+
function createLastModified() {
|
3110 |
+
if( empty( $this->lastmodified )) return FALSE;
|
3111 |
+
$attributes = $this->_createParams( $this->lastmodified['params'] );
|
3112 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->lastmodified['value'], 7 );
|
3113 |
+
return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
|
3114 |
+
}
|
3115 |
+
/**
|
3116 |
+
* set calendar component property completed
|
3117 |
+
*
|
3118 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3119 |
+
* @since 2.4.8 - 2008-10-23
|
3120 |
+
* @param mixed $year optional
|
3121 |
+
* @param mixed $month optional
|
3122 |
+
* @param int $day optional
|
3123 |
+
* @param int $hour optional
|
3124 |
+
* @param int $min optional
|
3125 |
+
* @param int $sec optional
|
3126 |
+
* @param array $params optional
|
3127 |
+
* @return boll
|
3128 |
+
*/
|
3129 |
+
function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
|
3130 |
+
if( empty( $year ))
|
3131 |
+
$year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
|
3132 |
+
$this->lastmodified = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
|
3133 |
+
return TRUE;
|
3134 |
+
}
|
3135 |
+
/*********************************************************************************/
|
3136 |
+
/**
|
3137 |
+
* Property Name: LOCATION
|
3138 |
+
*/
|
3139 |
+
/**
|
3140 |
+
* creates formatted output for calendar component property location
|
3141 |
+
*
|
3142 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3143 |
+
* @since 2.4.8 - 2008-10-22
|
3144 |
+
* @return string
|
3145 |
+
*/
|
3146 |
+
function createLocation() {
|
3147 |
+
if( empty( $this->location )) return FALSE;
|
3148 |
+
if( empty( $this->location['value'] ))
|
3149 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
|
3150 |
+
$attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
|
3151 |
+
$content = $this->_strrep( $this->location['value'] );
|
3152 |
+
return $this->_createElement( 'LOCATION', $attributes, $content );
|
3153 |
+
}
|
3154 |
+
/**
|
3155 |
+
* set calendar component property location
|
3156 |
+
'
|
3157 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3158 |
+
* @since 2.4.8 - 2008-11-04
|
3159 |
+
* @param string $value
|
3160 |
+
* @param array params optional
|
3161 |
+
* @return bool
|
3162 |
+
*/
|
3163 |
+
function setLocation( $value, $params=FALSE ) {
|
3164 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3165 |
+
$this->location = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3166 |
+
return TRUE;
|
3167 |
+
}
|
3168 |
+
/*********************************************************************************/
|
3169 |
+
/**
|
3170 |
+
* Property Name: ORGANIZER
|
3171 |
+
*/
|
3172 |
+
/**
|
3173 |
+
* creates formatted output for calendar component property organizer
|
3174 |
+
*
|
3175 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3176 |
+
* @since 2.6.33 - 2010-12-17
|
3177 |
+
* @return string
|
3178 |
+
*/
|
3179 |
+
function createOrganizer() {
|
3180 |
+
if( empty( $this->organizer )) return FALSE;
|
3181 |
+
if( empty( $this->organizer['value'] ))
|
3182 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
|
3183 |
+
$attributes = $this->_createParams( $this->organizer['params']
|
3184 |
+
, array( 'CN', 'DIR', 'SENT-BY', 'LANGUAGE' ));
|
3185 |
+
return $this->_createElement( 'ORGANIZER', $attributes, $this->organizer['value'] );
|
3186 |
+
}
|
3187 |
+
/**
|
3188 |
+
* set calendar component property organizer
|
3189 |
+
*
|
3190 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3191 |
+
* @since 2.6.27 - 2010-11-29
|
3192 |
+
* @param string $value
|
3193 |
+
* @param array params optional
|
3194 |
+
* @return bool
|
3195 |
+
*/
|
3196 |
+
function setOrganizer( $value, $params=FALSE ) {
|
3197 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3198 |
+
if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
|
3199 |
+
$value = 'MAILTO:'.$value;
|
3200 |
+
else
|
3201 |
+
$value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos );
|
3202 |
+
$value = str_replace( 'mailto:', 'MAILTO:', $value );
|
3203 |
+
$this->organizer = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3204 |
+
if( isset( $this->organizer['params']['SENT-BY'] )){
|
3205 |
+
if( 'mailto:' !== strtolower( substr( $this->organizer['params']['SENT-BY'], 0, 7 )))
|
3206 |
+
$this->organizer['params']['SENT-BY'] = 'MAILTO:'.$this->organizer['params']['SENT-BY'];
|
3207 |
+
else
|
3208 |
+
$this->organizer['params']['SENT-BY'] = 'MAILTO:'.substr( $this->organizer['params']['SENT-BY'], 7 );
|
3209 |
+
}
|
3210 |
+
return TRUE;
|
3211 |
+
}
|
3212 |
+
/*********************************************************************************/
|
3213 |
+
/**
|
3214 |
+
* Property Name: PERCENT-COMPLETE
|
3215 |
+
*/
|
3216 |
+
/**
|
3217 |
+
* creates formatted output for calendar component property percent-complete
|
3218 |
+
*
|
3219 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3220 |
+
* @since 2.9.3 - 2011-05-14
|
3221 |
+
* @return string
|
3222 |
+
*/
|
3223 |
+
function createPercentComplete() {
|
3224 |
+
if( !isset($this->percentcomplete) || ( empty( $this->percentcomplete ) && !is_numeric( $this->percentcomplete ))) return FALSE;
|
3225 |
+
if( !isset( $this->percentcomplete['value'] ) || ( empty( $this->percentcomplete['value'] ) && !is_numeric( $this->percentcomplete['value'] )))
|
3226 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE;
|
3227 |
+
$attributes = $this->_createParams( $this->percentcomplete['params'] );
|
3228 |
+
return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] );
|
3229 |
+
}
|
3230 |
+
/**
|
3231 |
+
* set calendar component property percent-complete
|
3232 |
+
*
|
3233 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3234 |
+
* @since 2.9.3 - 2011-05-14
|
3235 |
+
* @param int $value
|
3236 |
+
* @param array $params optional
|
3237 |
+
* @return bool
|
3238 |
+
*/
|
3239 |
+
function setPercentComplete( $value, $params=FALSE ) {
|
3240 |
+
if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3241 |
+
$this->percentcomplete = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3242 |
+
return TRUE;
|
3243 |
+
}
|
3244 |
+
/*********************************************************************************/
|
3245 |
+
/**
|
3246 |
+
* Property Name: PRIORITY
|
3247 |
+
*/
|
3248 |
+
/**
|
3249 |
+
* creates formatted output for calendar component property priority
|
3250 |
+
*
|
3251 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3252 |
+
* @since 2.9.3 - 2011-05-14
|
3253 |
+
* @return string
|
3254 |
+
*/
|
3255 |
+
function createPriority() {
|
3256 |
+
if( !isset($this->priority) || ( empty( $this->priority ) && !is_numeric( $this->priority ))) return FALSE;
|
3257 |
+
if( !isset( $this->priority['value'] ) || ( empty( $this->priority['value'] ) && !is_numeric( $this->priority['value'] )))
|
3258 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
|
3259 |
+
$attributes = $this->_createParams( $this->priority['params'] );
|
3260 |
+
return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
|
3261 |
+
}
|
3262 |
+
/**
|
3263 |
+
* set calendar component property priority
|
3264 |
+
*
|
3265 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3266 |
+
* @since 2.9.3 - 2011-05-14
|
3267 |
+
* @param int $value
|
3268 |
+
* @param array $params optional
|
3269 |
+
* @return bool
|
3270 |
+
*/
|
3271 |
+
function setPriority( $value, $params=FALSE ) {
|
3272 |
+
if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3273 |
+
$this->priority = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3274 |
+
return TRUE;
|
3275 |
+
}
|
3276 |
+
/*********************************************************************************/
|
3277 |
+
/**
|
3278 |
+
* Property Name: RDATE
|
3279 |
+
*/
|
3280 |
+
/**
|
3281 |
+
* creates formatted output for calendar component property rdate
|
3282 |
+
*
|
3283 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3284 |
+
* @since 2.4.16 - 2008-10-26
|
3285 |
+
* @return string
|
3286 |
+
*/
|
3287 |
+
function createRdate() {
|
3288 |
+
if( empty( $this->rdate )) return FALSE;
|
3289 |
+
$utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
|
3290 |
+
$output = null;
|
3291 |
+
if( $utctime )
|
3292 |
+
unset( $this->rdate['params']['TZID'] );
|
3293 |
+
foreach( $this->rdate as $theRdate ) {
|
3294 |
+
if( empty( $theRdate['value'] )) {
|
3295 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
|
3296 |
+
continue;
|
3297 |
+
}
|
3298 |
+
if( $utctime )
|
3299 |
+
unset( $theRdate['params']['TZID'] );
|
3300 |
+
$attributes = $this->_createParams( $theRdate['params'] );
|
3301 |
+
$cnt = count( $theRdate['value'] );
|
3302 |
+
$content = null;
|
3303 |
+
$rno = 1;
|
3304 |
+
foreach( $theRdate['value'] as $rpix => $rdatePart ) {
|
3305 |
+
$contentPart = null;
|
3306 |
+
if( is_array( $rdatePart ) &&
|
3307 |
+
isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
|
3308 |
+
if( $utctime )
|
3309 |
+
unset( $rdatePart[0]['tz'] );
|
3310 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $rdatePart[0]); // PERIOD part 1
|
3311 |
+
if( $utctime || !empty( $theRdate['params']['TZID'] ))
|
3312 |
+
$formatted = str_replace( 'Z', '', $formatted);
|
3313 |
+
if( 0 < $rpix ) {
|
3314 |
+
if( !empty( $rdatePart[0]['tz'] ) && iCalUtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
|
3315 |
+
if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
|
3316 |
+
}
|
3317 |
+
else
|
3318 |
+
$formatted = str_replace( 'Z', '', $formatted );
|
3319 |
+
}
|
3320 |
+
$contentPart .= $formatted;
|
3321 |
+
$contentPart .= '/';
|
3322 |
+
$cnt2 = count( $rdatePart[1]);
|
3323 |
+
if( array_key_exists( 'year', $rdatePart[1] )) {
|
3324 |
+
if( array_key_exists( 'hour', $rdatePart[1] ))
|
3325 |
+
$cnt2 = 7; // date-time
|
3326 |
+
else
|
3327 |
+
$cnt2 = 3; // date
|
3328 |
+
}
|
3329 |
+
elseif( array_key_exists( 'week', $rdatePart[1] )) // duration
|
3330 |
+
$cnt2 = 5;
|
3331 |
+
if(( 7 == $cnt2 ) && // period= -> date-time
|
3332 |
+
isset( $rdatePart[1]['year'] ) &&
|
3333 |
+
isset( $rdatePart[1]['month'] ) &&
|
3334 |
+
isset( $rdatePart[1]['day'] )) {
|
3335 |
+
if( $utctime )
|
3336 |
+
unset( $rdatePart[1]['tz'] );
|
3337 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $rdatePart[1] ); // PERIOD part 2
|
3338 |
+
if( $utctime || !empty( $theRdate['params']['TZID'] ))
|
3339 |
+
$formatted = str_replace( 'Z', '', $formatted);
|
3340 |
+
if( !empty( $rdatePart[0]['tz'] ) && iCalUtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
|
3341 |
+
if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
|
3342 |
+
}
|
3343 |
+
else
|
3344 |
+
$formatted = str_replace( 'Z', '', $formatted );
|
3345 |
+
$contentPart .= $formatted;
|
3346 |
+
}
|
3347 |
+
else { // period= -> dur-time
|
3348 |
+
$contentPart .= iCalUtilityFunctions::_format_duration( $rdatePart[1] );
|
3349 |
+
}
|
3350 |
+
} // PERIOD end
|
3351 |
+
else { // SINGLE date start
|
3352 |
+
if( $utctime )
|
3353 |
+
unset( $rdatePart['tz'] );
|
3354 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $rdatePart);
|
3355 |
+
if( $utctime || !empty( $theRdate['params']['TZID'] ))
|
3356 |
+
$formatted = str_replace( 'Z', '', $formatted);
|
3357 |
+
if( !$utctime && ( 0 < $rpix )) {
|
3358 |
+
if( !empty( $theRdate['value'][0]['tz'] ) && iCalUtilityFunctions::_isOffset( $theRdate['value'][0]['tz'] )) {
|
3359 |
+
if( 'Z' != substr( $formatted, -1 ))
|
3360 |
+
$formatted .= 'Z';
|
3361 |
+
}
|
3362 |
+
else
|
3363 |
+
$formatted = str_replace( 'Z', '', $formatted );
|
3364 |
+
}
|
3365 |
+
$contentPart .= $formatted;
|
3366 |
+
}
|
3367 |
+
$content .= $contentPart;
|
3368 |
+
if( $rno < $cnt )
|
3369 |
+
$content .= ',';
|
3370 |
+
$rno++;
|
3371 |
+
}
|
3372 |
+
$output .= $this->_createElement( 'RDATE', $attributes, $content );
|
3373 |
+
}
|
3374 |
+
return $output;
|
3375 |
+
}
|
3376 |
+
/**
|
3377 |
+
* set calendar component property rdate
|
3378 |
+
*
|
3379 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3380 |
+
* @since 2.5.1 - 2008-11-07
|
3381 |
+
* @param array $rdates
|
3382 |
+
* @param array $params, optional
|
3383 |
+
* @param integer $index, optional
|
3384 |
+
* @return bool
|
3385 |
+
*/
|
3386 |
+
function setRdate( $rdates, $params=FALSE, $index=FALSE ) {
|
3387 |
+
if( empty( $rdates )) {
|
3388 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
3389 |
+
iCalUtilityFunctions::_setMval( $this->rdate, null, $params, FALSE, $index );
|
3390 |
+
return TRUE;
|
3391 |
+
}
|
3392 |
+
else
|
3393 |
+
return FALSE;
|
3394 |
+
}
|
3395 |
+
$input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
|
3396 |
+
if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) {
|
3397 |
+
unset( $input['params']['TZID'] );
|
3398 |
+
$input['params']['VALUE'] = 'DATE-TIME';
|
3399 |
+
}
|
3400 |
+
/* check if PERIOD, if not set */
|
3401 |
+
if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) &&
|
3402 |
+
isset( $rdates[0] ) && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) &&
|
3403 |
+
isset( $rdates[0][0] ) && isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) &&
|
3404 |
+
(( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) ||
|
3405 |
+
iCalUtilityFunctions::_isArrayDate( $rdates[0][0] ))) ||
|
3406 |
+
( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] ))))) &&
|
3407 |
+
( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] ))))))
|
3408 |
+
$input['params']['VALUE'] = 'PERIOD';
|
3409 |
+
/* check 1:st date, upd. $parno (opt) and save ev. timezone **/
|
3410 |
+
$date = reset( $rdates );
|
3411 |
+
if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD
|
3412 |
+
$date = reset( $date );
|
3413 |
+
iCalUtilityFunctions::_chkdatecfg( $date, $parno, $input['params'] );
|
3414 |
+
if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
|
3415 |
+
unset( $input['params']['TZID'] );
|
3416 |
+
iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default
|
3417 |
+
foreach( $rdates as $rpix => $theRdate ) {
|
3418 |
+
$inputa = null;
|
3419 |
+
if( is_array( $theRdate )) {
|
3420 |
+
if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD
|
3421 |
+
foreach( $theRdate as $rix => $rPeriod ) {
|
3422 |
+
if( is_array( $rPeriod )) {
|
3423 |
+
if( iCalUtilityFunctions::_isArrayTimestampDate( $rPeriod )) // timestamp
|
3424 |
+
$inputab = ( isset( $rPeriod['tz'] )) ? iCalUtilityFunctions::_timestamp2date( $rPeriod, $parno ) : iCalUtilityFunctions::_timestamp2date( $rPeriod, 6 );
|
3425 |
+
elseif( iCalUtilityFunctions::_isArrayDate( $rPeriod ))
|
3426 |
+
$inputab = ( 3 < count ( $rPeriod )) ? iCalUtilityFunctions::_date_time_array( $rPeriod, $parno ) : iCalUtilityFunctions::_date_time_array( $rPeriod, 6 );
|
3427 |
+
elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) // text-date
|
3428 |
+
$inputab = iCalUtilityFunctions::_date_time_string( reset( $rPeriod ), $parno );
|
3429 |
+
else // array format duration
|
3430 |
+
$inputab = iCalUtilityFunctions::_duration_array( $rPeriod );
|
3431 |
+
}
|
3432 |
+
elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
|
3433 |
+
( in_array( $rPeriod[0], array( 'P', '+', '-' )))) {
|
3434 |
+
if( 'P' != $rPeriod[0] )
|
3435 |
+
$rPeriod = substr( $rPeriod, 1 );
|
3436 |
+
$inputab = iCalUtilityFunctions::_duration_string( $rPeriod );
|
3437 |
+
}
|
3438 |
+
elseif( 8 <= strlen( trim( $rPeriod ))) // text date ex. 2006-08-03 10:12:18
|
3439 |
+
$inputab = iCalUtilityFunctions::_date_time_string( $rPeriod, $parno );
|
3440 |
+
if( isset( $input['params']['TZID'] ) ||
|
3441 |
+
( isset( $inputab['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputab['tz'] )) ||
|
3442 |
+
( isset( $inputa[0] ) && ( !isset( $inputa[0]['tz'] ))) ||
|
3443 |
+
( isset( $inputa[0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputa[0]['tz'] )))
|
3444 |
+
unset( $inputab['tz'] );
|
3445 |
+
$inputa[] = $inputab;
|
3446 |
+
}
|
3447 |
+
} // PERIOD end
|
3448 |
+
elseif ( iCalUtilityFunctions::_isArrayTimestampDate( $theRdate )) // timestamp
|
3449 |
+
$inputa = iCalUtilityFunctions::_timestamp2date( $theRdate, $parno );
|
3450 |
+
else // date[-time]
|
3451 |
+
$inputa = iCalUtilityFunctions::_date_time_array( $theRdate, $parno );
|
3452 |
+
}
|
3453 |
+
elseif( 8 <= strlen( trim( $theRdate ))) // text date ex. 2006-08-03 10:12:18
|
3454 |
+
$inputa = iCalUtilityFunctions::_date_time_string( $theRdate, $parno );
|
3455 |
+
if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
|
3456 |
+
if( 3 == $parno )
|
3457 |
+
unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
|
3458 |
+
elseif( isset( $inputa['tz'] ))
|
3459 |
+
$inputa['tz'] = (string) $inputa['tz'];
|
3460 |
+
if( isset( $input['params']['TZID'] ) ||
|
3461 |
+
( isset( $inputa['tz'] ) && !iCalUtilityFunctions::_isOffset( $inputa['tz'] )) ||
|
3462 |
+
( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
|
3463 |
+
( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
|
3464 |
+
unset( $inputa['tz'] );
|
3465 |
+
}
|
3466 |
+
$input['value'][] = $inputa;
|
3467 |
+
}
|
3468 |
+
if( 3 == $parno ) {
|
3469 |
+
$input['params']['VALUE'] = 'DATE';
|
3470 |
+
unset( $input['params']['TZID'] );
|
3471 |
+
}
|
3472 |
+
iCalUtilityFunctions::_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index );
|
3473 |
+
return TRUE;
|
3474 |
+
}
|
3475 |
+
/*********************************************************************************/
|
3476 |
+
/**
|
3477 |
+
* Property Name: RECURRENCE-ID
|
3478 |
+
*/
|
3479 |
+
/**
|
3480 |
+
* creates formatted output for calendar component property recurrence-id
|
3481 |
+
*
|
3482 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3483 |
+
* @since 2.9.6 - 2011-05-15
|
3484 |
+
* @return string
|
3485 |
+
*/
|
3486 |
+
function createRecurrenceid() {
|
3487 |
+
if( empty( $this->recurrenceid )) return FALSE;
|
3488 |
+
if( empty( $this->recurrenceid['value'] ))
|
3489 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
|
3490 |
+
$formatted = iCalUtilityFunctions::_format_date_time( $this->recurrenceid['value'] );
|
3491 |
+
if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
|
3492 |
+
( !isset( $this->recurrenceid['params']['VALUE'] ) || ( $this->recurrenceid['params']['VALUE'] != 'DATE' )) &&
|
3493 |
+
!isset( $this->recurrenceid['params']['TZID'] ))
|
3494 |
+
$this->recurrenceid['params']['TZID'] = $tzid;
|
3495 |
+
$attributes = $this->_createParams( $this->recurrenceid['params'] );
|
3496 |
+
return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
|
3497 |
+
}
|
3498 |
+
/**
|
3499 |
+
* set calendar component property recurrence-id
|
3500 |
+
*
|
3501 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3502 |
+
* @since 2.9.6 - 2011-05-15
|
3503 |
+
* @param mixed $year
|
3504 |
+
* @param mixed $month optional
|
3505 |
+
* @param int $day optional
|
3506 |
+
* @param int $hour optional
|
3507 |
+
* @param int $min optional
|
3508 |
+
* @param int $sec optional
|
3509 |
+
* @param array $params optional
|
3510 |
+
* @return bool
|
3511 |
+
*/
|
3512 |
+
function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
|
3513 |
+
if( empty( $year )) {
|
3514 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
3515 |
+
$this->recurrenceid = array( 'value' => null, 'params' => null );
|
3516 |
+
return TRUE;
|
3517 |
+
}
|
3518 |
+
else
|
3519 |
+
return FALSE;
|
3520 |
+
}
|
3521 |
+
$this->recurrenceid = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
|
3522 |
+
return TRUE;
|
3523 |
+
}
|
3524 |
+
/*********************************************************************************/
|
3525 |
+
/**
|
3526 |
+
* Property Name: RELATED-TO
|
3527 |
+
*/
|
3528 |
+
/**
|
3529 |
+
* creates formatted output for calendar component property related-to
|
3530 |
+
*
|
3531 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3532 |
+
* @since 2.4.8 - 2008-10-23
|
3533 |
+
* @return string
|
3534 |
+
*/
|
3535 |
+
function createRelatedTo() {
|
3536 |
+
if( empty( $this->relatedto )) return FALSE;
|
3537 |
+
$output = null;
|
3538 |
+
foreach( $this->relatedto as $relation ) {
|
3539 |
+
if( empty( $relation['value'] )) {
|
3540 |
+
if( $this->getConfig( 'allowEmpty' )) $output.= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ));
|
3541 |
+
continue;
|
3542 |
+
}
|
3543 |
+
$attributes = $this->_createParams( $relation['params'] );
|
3544 |
+
$content = ( 'xcal' != $this->format ) ? '<' : '';
|
3545 |
+
$content .= $this->_strrep( $relation['value'] );
|
3546 |
+
$content .= ( 'xcal' != $this->format ) ? '>' : '';
|
3547 |
+
$output .= $this->_createElement( 'RELATED-TO', $attributes, $content );
|
3548 |
+
}
|
3549 |
+
return $output;
|
3550 |
+
}
|
3551 |
+
/**
|
3552 |
+
* set calendar component property related-to
|
3553 |
+
*
|
3554 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3555 |
+
* @since 2.5.1 - 2008-11-07
|
3556 |
+
* @param float $relid
|
3557 |
+
* @param array $params, optional
|
3558 |
+
* @param index $index, optional
|
3559 |
+
* @return bool
|
3560 |
+
*/
|
3561 |
+
function setRelatedTo( $value, $params=FALSE, $index=FALSE ) {
|
3562 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3563 |
+
if(( '<' == substr( $value, 0, 1 )) && ( '>' == substr( $value, -1 )))
|
3564 |
+
$value = substr( $value, 1, ( strlen( $value ) - 2 ));
|
3565 |
+
iCalUtilityFunctions::_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default
|
3566 |
+
iCalUtilityFunctions::_setMval( $this->relatedto, $value, $params, FALSE, $index );
|
3567 |
+
return TRUE;
|
3568 |
+
}
|
3569 |
+
/*********************************************************************************/
|
3570 |
+
/**
|
3571 |
+
* Property Name: REPEAT
|
3572 |
+
*/
|
3573 |
+
/**
|
3574 |
+
* creates formatted output for calendar component property repeat
|
3575 |
+
*
|
3576 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3577 |
+
* @since 2.9.3 - 2011-05-14
|
3578 |
+
* @return string
|
3579 |
+
*/
|
3580 |
+
function createRepeat() {
|
3581 |
+
if( !isset( $this->repeat ) || ( empty( $this->repeat ) && !is_numeric( $this->repeat ))) return FALSE;
|
3582 |
+
if( !isset( $this->repeat['value']) || ( empty( $this->repeat['value'] ) && !is_numeric( $this->repeat['value'] )))
|
3583 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE;
|
3584 |
+
$attributes = $this->_createParams( $this->repeat['params'] );
|
3585 |
+
return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] );
|
3586 |
+
}
|
3587 |
+
/**
|
3588 |
+
* set calendar component property transp
|
3589 |
+
*
|
3590 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3591 |
+
* @since 2.9.3 - 2011-05-14
|
3592 |
+
* @param string $value
|
3593 |
+
* @param array $params optional
|
3594 |
+
* @return void
|
3595 |
+
*/
|
3596 |
+
function setRepeat( $value, $params=FALSE ) {
|
3597 |
+
if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3598 |
+
$this->repeat = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3599 |
+
return TRUE;
|
3600 |
+
}
|
3601 |
+
/*********************************************************************************/
|
3602 |
+
/**
|
3603 |
+
* Property Name: REQUEST-STATUS
|
3604 |
+
*/
|
3605 |
+
/**
|
3606 |
+
* creates formatted output for calendar component property request-status
|
3607 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3608 |
+
* @since 2.4.8 - 2008-10-23
|
3609 |
+
* @return string
|
3610 |
+
*/
|
3611 |
+
function createRequestStatus() {
|
3612 |
+
if( empty( $this->requeststatus )) return FALSE;
|
3613 |
+
$output = null;
|
3614 |
+
foreach( $this->requeststatus as $rstat ) {
|
3615 |
+
if( empty( $rstat['value']['statcode'] )) {
|
3616 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' );
|
3617 |
+
continue;
|
3618 |
+
}
|
3619 |
+
$attributes = $this->_createParams( $rstat['params'], array( 'LANGUAGE' ));
|
3620 |
+
$content = number_format( (float) $rstat['value']['statcode'], 2, '.', '');
|
3621 |
+
$content .= ';'.$this->_strrep( $rstat['value']['text'] );
|
3622 |
+
if( isset( $rstat['value']['extdata'] ))
|
3623 |
+
$content .= ';'.$this->_strrep( $rstat['value']['extdata'] );
|
3624 |
+
$output .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content );
|
3625 |
+
}
|
3626 |
+
return $output;
|
3627 |
+
}
|
3628 |
+
/**
|
3629 |
+
* set calendar component property request-status
|
3630 |
+
*
|
3631 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3632 |
+
* @since 2.5.1 - 2008-11-05
|
3633 |
+
* @param float $statcode
|
3634 |
+
* @param string $text
|
3635 |
+
* @param string $extdata, optional
|
3636 |
+
* @param array $params, optional
|
3637 |
+
* @param integer $index, optional
|
3638 |
+
* @return bool
|
3639 |
+
*/
|
3640 |
+
function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) {
|
3641 |
+
if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = null; else return FALSE;
|
3642 |
+
$input = array( 'statcode' => $statcode, 'text' => $text );
|
3643 |
+
if( $extdata )
|
3644 |
+
$input['extdata'] = $extdata;
|
3645 |
+
iCalUtilityFunctions::_setMval( $this->requeststatus, $input, $params, FALSE, $index );
|
3646 |
+
return TRUE;
|
3647 |
+
}
|
3648 |
+
/*********************************************************************************/
|
3649 |
+
/**
|
3650 |
+
* Property Name: RESOURCES
|
3651 |
+
*/
|
3652 |
+
/**
|
3653 |
+
* creates formatted output for calendar component property resources
|
3654 |
+
*
|
3655 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3656 |
+
* @since 2.4.8 - 2008-10-23
|
3657 |
+
* @return string
|
3658 |
+
*/
|
3659 |
+
function createResources() {
|
3660 |
+
if( empty( $this->resources )) return FALSE;
|
3661 |
+
$output = null;
|
3662 |
+
foreach( $this->resources as $resource ) {
|
3663 |
+
if( empty( $resource['value'] )) {
|
3664 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
|
3665 |
+
continue;
|
3666 |
+
}
|
3667 |
+
$attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
|
3668 |
+
if( is_array( $resource['value'] )) {
|
3669 |
+
foreach( $resource['value'] as $rix => $resourcePart )
|
3670 |
+
$resource['value'][$rix] = $this->_strrep( $resourcePart );
|
3671 |
+
$content = implode( ',', $resource['value'] );
|
3672 |
+
}
|
3673 |
+
else
|
3674 |
+
$content = $this->_strrep( $resource['value'] );
|
3675 |
+
$output .= $this->_createElement( 'RESOURCES', $attributes, $content );
|
3676 |
+
}
|
3677 |
+
return $output;
|
3678 |
+
}
|
3679 |
+
/**
|
3680 |
+
* set calendar component property recources
|
3681 |
+
*
|
3682 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3683 |
+
* @since 2.5.1 - 2008-11-05
|
3684 |
+
* @param mixed $value
|
3685 |
+
* @param array $params, optional
|
3686 |
+
* @param integer $index, optional
|
3687 |
+
* @return bool
|
3688 |
+
*/
|
3689 |
+
function setResources( $value, $params=FALSE, $index=FALSE ) {
|
3690 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3691 |
+
iCalUtilityFunctions::_setMval( $this->resources, $value, $params, FALSE, $index );
|
3692 |
+
return TRUE;
|
3693 |
+
}
|
3694 |
+
/*********************************************************************************/
|
3695 |
+
/**
|
3696 |
+
* Property Name: RRULE
|
3697 |
+
*/
|
3698 |
+
/**
|
3699 |
+
* creates formatted output for calendar component property rrule
|
3700 |
+
*
|
3701 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3702 |
+
* @since 2.4.8 - 2008-10-21
|
3703 |
+
* @return string
|
3704 |
+
*/
|
3705 |
+
function createRrule() {
|
3706 |
+
if( empty( $this->rrule )) return FALSE;
|
3707 |
+
return $this->_format_recur( 'RRULE', $this->rrule );
|
3708 |
+
}
|
3709 |
+
/**
|
3710 |
+
* set calendar component property rrule
|
3711 |
+
*
|
3712 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3713 |
+
* @since 2.5.1 - 2008-11-05
|
3714 |
+
* @param array $rruleset
|
3715 |
+
* @param array $params, optional
|
3716 |
+
* @param integer $index, optional
|
3717 |
+
* @return void
|
3718 |
+
*/
|
3719 |
+
function setRrule( $rruleset, $params=FALSE, $index=FALSE ) {
|
3720 |
+
if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = null; else return FALSE;
|
3721 |
+
iCalUtilityFunctions::_setMval( $this->rrule, iCalUtilityFunctions::_setRexrule( $rruleset ), $params, FALSE, $index );
|
3722 |
+
return TRUE;
|
3723 |
+
}
|
3724 |
+
/*********************************************************************************/
|
3725 |
+
/**
|
3726 |
+
* Property Name: SEQUENCE
|
3727 |
+
*/
|
3728 |
+
/**
|
3729 |
+
* creates formatted output for calendar component property sequence
|
3730 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3731 |
+
* @since 2.9.3 - 2011-05-14
|
3732 |
+
* @return string
|
3733 |
+
*/
|
3734 |
+
function createSequence() {
|
3735 |
+
if( !isset( $this->sequence ) || ( empty( $this->sequence ) && !is_numeric( $this->sequence ))) return FALSE;
|
3736 |
+
if(( !isset($this->sequence['value'] ) || ( empty( $this->sequence['value'] ) && !is_numeric( $this->sequence['value'] ))) &&
|
3737 |
+
( '0' != $this->sequence['value'] ))
|
3738 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
|
3739 |
+
$attributes = $this->_createParams( $this->sequence['params'] );
|
3740 |
+
return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
|
3741 |
+
}
|
3742 |
+
/**
|
3743 |
+
* set calendar component property sequence
|
3744 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3745 |
+
* @since 2.9.3 - 2011-05-14
|
3746 |
+
* @param int $value optional
|
3747 |
+
* @param array $params optional
|
3748 |
+
* @return bool
|
3749 |
+
*/
|
3750 |
+
function setSequence( $value=FALSE, $params=FALSE ) {
|
3751 |
+
if(( empty( $value ) && !is_numeric( $value )) && ( '0' != $value ))
|
3752 |
+
$value = ( isset( $this->sequence['value'] ) && ( 0 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : 1;
|
3753 |
+
$this->sequence = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3754 |
+
return TRUE;
|
3755 |
+
}
|
3756 |
+
/*********************************************************************************/
|
3757 |
+
/**
|
3758 |
+
* Property Name: STATUS
|
3759 |
+
*/
|
3760 |
+
/**
|
3761 |
+
* creates formatted output for calendar component property status
|
3762 |
+
*
|
3763 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3764 |
+
* @since 2.4.8 - 2008-10-21
|
3765 |
+
* @return string
|
3766 |
+
*/
|
3767 |
+
function createStatus() {
|
3768 |
+
if( empty( $this->status )) return FALSE;
|
3769 |
+
if( empty( $this->status['value'] ))
|
3770 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
|
3771 |
+
$attributes = $this->_createParams( $this->status['params'] );
|
3772 |
+
return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
|
3773 |
+
}
|
3774 |
+
/**
|
3775 |
+
* set calendar component property status
|
3776 |
+
*
|
3777 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3778 |
+
* @since 2.4.8 - 2008-11-04
|
3779 |
+
* @param string $value
|
3780 |
+
* @param array $params optional
|
3781 |
+
* @return bool
|
3782 |
+
*/
|
3783 |
+
function setStatus( $value, $params=FALSE ) {
|
3784 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3785 |
+
$this->status = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3786 |
+
return TRUE;
|
3787 |
+
}
|
3788 |
+
/*********************************************************************************/
|
3789 |
+
/**
|
3790 |
+
* Property Name: SUMMARY
|
3791 |
+
*/
|
3792 |
+
/**
|
3793 |
+
* creates formatted output for calendar component property summary
|
3794 |
+
*
|
3795 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3796 |
+
* @since 2.4.8 - 2008-10-21
|
3797 |
+
* @return string
|
3798 |
+
*/
|
3799 |
+
function createSummary() {
|
3800 |
+
if( empty( $this->summary )) return FALSE;
|
3801 |
+
if( empty( $this->summary['value'] ))
|
3802 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
|
3803 |
+
$attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
|
3804 |
+
$content = $this->_strrep( $this->summary['value'] );
|
3805 |
+
return $this->_createElement( 'SUMMARY', $attributes, $content );
|
3806 |
+
}
|
3807 |
+
/**
|
3808 |
+
* set calendar component property summary
|
3809 |
+
*
|
3810 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3811 |
+
* @since 2.4.8 - 2008-11-04
|
3812 |
+
* @param string $value
|
3813 |
+
* @param string $params optional
|
3814 |
+
* @return bool
|
3815 |
+
*/
|
3816 |
+
function setSummary( $value, $params=FALSE ) {
|
3817 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3818 |
+
$this->summary = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3819 |
+
return TRUE;
|
3820 |
+
}
|
3821 |
+
/*********************************************************************************/
|
3822 |
+
/**
|
3823 |
+
* Property Name: TRANSP
|
3824 |
+
*/
|
3825 |
+
/**
|
3826 |
+
* creates formatted output for calendar component property transp
|
3827 |
+
*
|
3828 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3829 |
+
* @since 2.4.8 - 2008-10-21
|
3830 |
+
* @return string
|
3831 |
+
*/
|
3832 |
+
function createTransp() {
|
3833 |
+
if( empty( $this->transp )) return FALSE;
|
3834 |
+
if( empty( $this->transp['value'] ))
|
3835 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE;
|
3836 |
+
$attributes = $this->_createParams( $this->transp['params'] );
|
3837 |
+
return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] );
|
3838 |
+
}
|
3839 |
+
/**
|
3840 |
+
* set calendar component property transp
|
3841 |
+
*
|
3842 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3843 |
+
* @since 2.4.8 - 2008-11-04
|
3844 |
+
* @param string $value
|
3845 |
+
* @param string $params optional
|
3846 |
+
* @return bool
|
3847 |
+
*/
|
3848 |
+
function setTransp( $value, $params=FALSE ) {
|
3849 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
3850 |
+
$this->transp = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
3851 |
+
return TRUE;
|
3852 |
+
}
|
3853 |
+
/*********************************************************************************/
|
3854 |
+
/**
|
3855 |
+
* Property Name: TRIGGER
|
3856 |
+
*/
|
3857 |
+
/**
|
3858 |
+
* creates formatted output for calendar component property trigger
|
3859 |
+
*
|
3860 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3861 |
+
* @since 2.4.16 - 2008-10-21
|
3862 |
+
* @return string
|
3863 |
+
*/
|
3864 |
+
function createTrigger() {
|
3865 |
+
if( empty( $this->trigger )) return FALSE;
|
3866 |
+
if( empty( $this->trigger['value'] ))
|
3867 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE;
|
3868 |
+
$content = $attributes = null;
|
3869 |
+
if( isset( $this->trigger['value']['year'] ) &&
|
3870 |
+
isset( $this->trigger['value']['month'] ) &&
|
3871 |
+
isset( $this->trigger['value']['day'] ))
|
3872 |
+
$content .= iCalUtilityFunctions::_format_date_time( $this->trigger['value'] );
|
3873 |
+
else {
|
3874 |
+
if( TRUE !== $this->trigger['value']['relatedStart'] )
|
3875 |
+
$attributes .= $this->intAttrDelimiter.'RELATED=END';
|
3876 |
+
if( $this->trigger['value']['before'] )
|
3877 |
+
$content .= '-';
|
3878 |
+
$content .= iCalUtilityFunctions::_format_duration( $this->trigger['value'] );
|
3879 |
+
}
|
3880 |
+
$attributes .= $this->_createParams( $this->trigger['params'] );
|
3881 |
+
return $this->_createElement( 'TRIGGER', $attributes, $content );
|
3882 |
+
}
|
3883 |
+
/**
|
3884 |
+
* set calendar component property trigger
|
3885 |
+
*
|
3886 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
3887 |
+
* @since 2.9.9 - 2011-06-17
|
3888 |
+
* @param mixed $year
|
3889 |
+
* @param mixed $month optional
|
3890 |
+
* @param int $day optional
|
3891 |
+
* @param int $week optional
|
3892 |
+
* @param int $hour optional
|
3893 |
+
* @param int $min optional
|
3894 |
+
* @param int $sec optional
|
3895 |
+
* @param bool $relatedStart optional
|
3896 |
+
* @param bool $before optional
|
3897 |
+
* @param array $params optional
|
3898 |
+
* @return bool
|
3899 |
+
*/
|
3900 |
+
function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) {
|
3901 |
+
if( empty( $year ) && empty( $month ) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec ))
|
3902 |
+
if( $this->getConfig( 'allowEmpty' )) {
|
3903 |
+
$this->trigger = array( 'value' => null, 'params' => iCalUtilityFunctions::_setParams( $params ) );
|
3904 |
+
return TRUE;
|
3905 |
+
}
|
3906 |
+
else
|
3907 |
+
return FALSE;
|
3908 |
+
if( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp
|
3909 |
+
$params = iCalUtilityFunctions::_setParams( $month );
|
3910 |
+
$date = iCalUtilityFunctions::_timestamp2date( $year, 7 );
|
3911 |
+
foreach( $date as $k => $v )
|
3912 |
+
$$k = $v;
|
3913 |
+
}
|
3914 |
+
elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) {
|
3915 |
+
$params = iCalUtilityFunctions::_setParams( $month );
|
3916 |
+
if(!(array_key_exists( 'year', $year ) && // exclude date-time
|
3917 |
+
array_key_exists( 'month', $year ) &&
|
3918 |
+
array_key_exists( 'day', $year ))) { // when this must be a duration
|
3919 |
+
if( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] )))
|
3920 |
+
$relatedStart = FALSE;
|
3921 |
+
else
|
3922 |
+
$relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE;
|
3923 |
+
$before = ( array_key_exists( 'before', $year ) && ( TRUE !== $year['before'] )) ? FALSE : TRUE;
|
3924 |
+
}
|
3925 |
+
$SSYY = ( array_key_exists( 'year', $year )) ? $year['year'] : null;
|
3926 |
+
$month = ( array_key_exists( 'month', $year )) ? $year['month'] : null;
|
3927 |
+
$day = ( array_key_exists( 'day', $year )) ? $year['day'] : null;
|
3928 |
+
$week = ( array_key_exists( 'week', $year )) ? $year['week'] : null;
|
3929 |
+
$hour = ( array_key_exists( 'hour', $year )) ? $year['hour'] : 0; //null;
|
3930 |
+
$min = ( array_key_exists( 'min', $year )) ? $year['min'] : 0; //null;
|
3931 |
+
$sec = ( array_key_exists( 'sec', $year )) ? $year['sec'] : 0; //null;
|
3932 |
+
$year = $SSYY;
|
3933 |
+
}
|
3934 |
+
elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) { // duration or date in a string
|
3935 |
+
$params = iCalUtilityFunctions::_setParams( $month );
|
3936 |
+
if( in_array( $year[0], array( 'P', '+', '-' ))) { // duration
|
3937 |
+
$relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] ))) ? FALSE : TRUE;
|
3938 |
+
$before = ( '-' == $year[0] ) ? TRUE : FALSE;
|
3939 |
+
if( 'P' != $year[0] )
|
3940 |
+
$year = substr( $year, 1 );
|
3941 |
+
$date = iCalUtilityFunctions::_duration_string( $year);
|
3942 |
+
}
|
3943 |
+
else // date
|
3944 |
+
$date = iCalUtilityFunctions::_date_time_string( $year, 7 );
|
3945 |
+
unset( $year, $month, $day );
|
3946 |
+
if( empty( $date ))
|
3947 |
+
$sec = 0;
|
3948 |
+
else
|
3949 |
+
foreach( $date as $k => $v )
|
3950 |
+
$$k = $v;
|
3951 |
+
}
|
3952 |
+
else // single values in function input parameters
|
3953 |
+
$params = iCalUtilityFunctions::_setParams( $params );
|
3954 |
+
if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date
|
3955 |
+
$params['VALUE'] = 'DATE-TIME';
|
3956 |
+
$hour = ( $hour ) ? $hour : 0;
|
3957 |
+
$min = ( $min ) ? $min : 0;
|
3958 |
+
$sec = ( $sec ) ? $sec : 0;
|
3959 |
+
$this->trigger = array( 'params' => $params );
|
3960 |
+
$this->trigger['value'] = array( 'year' => $year
|
3961 |
+
, 'month' => $month
|
3962 |
+
, 'day' => $day
|
3963 |
+
, 'hour' => $hour
|
3964 |
+
, 'min' => $min
|
3965 |
+
, 'sec' => $sec
|
3966 |
+
, 'tz' => 'Z' );
|
3967 |
+
return TRUE;
|
3968 |
+
}
|
3969 |
+
elseif(( empty( $year ) && empty( $month )) && // duration
|
3970 |
+
(( !empty( $week ) || ( 0 == $week )) ||
|
3971 |
+
( !empty( $day ) || ( 0 == $day )) ||
|
3972 |
+
( !empty( $hour ) || ( 0 == $hour )) ||
|
3973 |
+
( !empty( $min ) || ( 0 == $min )) ||
|
3974 |
+
( !empty( $sec ) || ( 0 == $sec )))) {
|
3975 |
+
unset( $params['RELATED'] ); // set at output creation (END only)
|
3976 |
+
unset( $params['VALUE'] ); // 'DURATION' default
|
3977 |
+
$this->trigger = array( 'params' => $params );
|
3978 |
+
$this->trigger['value'] = array();
|
3979 |
+
if( !empty( $week )) $this->trigger['value']['week'] = $week;
|
3980 |
+
if( !empty( $day )) $this->trigger['value']['day'] = $day;
|
3981 |
+
if( !empty( $hour )) $this->trigger['value']['hour'] = $hour;
|
3982 |
+
if( !empty( $min )) $this->trigger['value']['min'] = $min;
|
3983 |
+
if( !empty( $sec )) $this->trigger['value']['sec'] = $sec;
|
3984 |
+
if( empty( $this->trigger['value'] )) {
|
3985 |
+
$this->trigger['value']['sec'] = 0;
|
3986 |
+
$before = FALSE;
|
3987 |
+
}
|
3988 |
+
$relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE;
|
3989 |
+
$before = ( FALSE !== $before ) ? TRUE : FALSE;
|
3990 |
+
$this->trigger['value']['relatedStart'] = $relatedStart;
|
3991 |
+
$this->trigger['value']['before'] = $before;
|
3992 |
+
return TRUE;
|
3993 |
+
}
|
3994 |
+
return FALSE;
|
3995 |
+
}
|
3996 |
+
/*********************************************************************************/
|
3997 |
+
/**
|
3998 |
+
* Property Name: TZID
|
3999 |
+
*/
|
4000 |
+
/**
|
4001 |
+
* creates formatted output for calendar component property tzid
|
4002 |
+
*
|
4003 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4004 |
+
* @since 2.4.8 - 2008-10-21
|
4005 |
+
* @return string
|
4006 |
+
*/
|
4007 |
+
function createTzid() {
|
4008 |
+
if( empty( $this->tzid )) return FALSE;
|
4009 |
+
if( empty( $this->tzid['value'] ))
|
4010 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
|
4011 |
+
$attributes = $this->_createParams( $this->tzid['params'] );
|
4012 |
+
return $this->_createElement( 'TZID', $attributes, $this->_strrep( $this->tzid['value'] ));
|
4013 |
+
}
|
4014 |
+
/**
|
4015 |
+
* set calendar component property tzid
|
4016 |
+
*
|
4017 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4018 |
+
* @since 2.4.8 - 2008-11-04
|
4019 |
+
* @param string $value
|
4020 |
+
* @param array $params optional
|
4021 |
+
* @return bool
|
4022 |
+
*/
|
4023 |
+
function setTzid( $value, $params=FALSE ) {
|
4024 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4025 |
+
$this->tzid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
4026 |
+
return TRUE;
|
4027 |
+
}
|
4028 |
+
/*********************************************************************************/
|
4029 |
+
/**
|
4030 |
+
* .. .
|
4031 |
+
* Property Name: TZNAME
|
4032 |
+
*/
|
4033 |
+
/**
|
4034 |
+
* creates formatted output for calendar component property tzname
|
4035 |
+
*
|
4036 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4037 |
+
* @since 2.4.8 - 2008-10-21
|
4038 |
+
* @return string
|
4039 |
+
*/
|
4040 |
+
function createTzname() {
|
4041 |
+
if( empty( $this->tzname )) return FALSE;
|
4042 |
+
$output = null;
|
4043 |
+
foreach( $this->tzname as $theName ) {
|
4044 |
+
if( !empty( $theName['value'] )) {
|
4045 |
+
$attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
|
4046 |
+
$output .= $this->_createElement( 'TZNAME', $attributes, $this->_strrep( $theName['value'] ));
|
4047 |
+
}
|
4048 |
+
elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
|
4049 |
+
}
|
4050 |
+
return $output;
|
4051 |
+
}
|
4052 |
+
/**
|
4053 |
+
* set calendar component property tzname
|
4054 |
+
*
|
4055 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4056 |
+
* @since 2.5.1 - 2008-11-05
|
4057 |
+
* @param string $value
|
4058 |
+
* @param string $params, optional
|
4059 |
+
* @param integer $index, optional
|
4060 |
+
* @return bool
|
4061 |
+
*/
|
4062 |
+
function setTzname( $value, $params=FALSE, $index=FALSE ) {
|
4063 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4064 |
+
iCalUtilityFunctions::_setMval( $this->tzname, $value, $params, FALSE, $index );
|
4065 |
+
return TRUE;
|
4066 |
+
}
|
4067 |
+
/*********************************************************************************/
|
4068 |
+
/**
|
4069 |
+
* Property Name: TZOFFSETFROM
|
4070 |
+
*/
|
4071 |
+
/**
|
4072 |
+
* creates formatted output for calendar component property tzoffsetfrom
|
4073 |
+
*
|
4074 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4075 |
+
* @since 2.4.8 - 2008-10-21
|
4076 |
+
* @return string
|
4077 |
+
*/
|
4078 |
+
function createTzoffsetfrom() {
|
4079 |
+
if( empty( $this->tzoffsetfrom )) return FALSE;
|
4080 |
+
if( empty( $this->tzoffsetfrom['value'] ))
|
4081 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
|
4082 |
+
$attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
|
4083 |
+
return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
|
4084 |
+
}
|
4085 |
+
/**
|
4086 |
+
* set calendar component property tzoffsetfrom
|
4087 |
+
*
|
4088 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4089 |
+
* @since 2.4.8 - 2008-11-04
|
4090 |
+
* @param string $value
|
4091 |
+
* @param string $params optional
|
4092 |
+
* @return bool
|
4093 |
+
*/
|
4094 |
+
function setTzoffsetfrom( $value, $params=FALSE ) {
|
4095 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4096 |
+
$this->tzoffsetfrom = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
4097 |
+
return TRUE;
|
4098 |
+
}
|
4099 |
+
/*********************************************************************************/
|
4100 |
+
/**
|
4101 |
+
* Property Name: TZOFFSETTO
|
4102 |
+
*/
|
4103 |
+
/**
|
4104 |
+
* creates formatted output for calendar component property tzoffsetto
|
4105 |
+
*
|
4106 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4107 |
+
* @since 2.4.8 - 2008-10-21
|
4108 |
+
* @return string
|
4109 |
+
*/
|
4110 |
+
function createTzoffsetto() {
|
4111 |
+
if( empty( $this->tzoffsetto )) return FALSE;
|
4112 |
+
if( empty( $this->tzoffsetto['value'] ))
|
4113 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
|
4114 |
+
$attributes = $this->_createParams( $this->tzoffsetto['params'] );
|
4115 |
+
return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
|
4116 |
+
}
|
4117 |
+
/**
|
4118 |
+
* set calendar component property tzoffsetto
|
4119 |
+
*
|
4120 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4121 |
+
* @since 2.4.8 - 2008-11-04
|
4122 |
+
* @param string $value
|
4123 |
+
* @param string $params optional
|
4124 |
+
* @return bool
|
4125 |
+
*/
|
4126 |
+
function setTzoffsetto( $value, $params=FALSE ) {
|
4127 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4128 |
+
$this->tzoffsetto = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
4129 |
+
return TRUE;
|
4130 |
+
}
|
4131 |
+
/*********************************************************************************/
|
4132 |
+
/**
|
4133 |
+
* Property Name: TZURL
|
4134 |
+
*/
|
4135 |
+
/**
|
4136 |
+
* creates formatted output for calendar component property tzurl
|
4137 |
+
*
|
4138 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4139 |
+
* @since 2.4.8 - 2008-10-21
|
4140 |
+
* @return string
|
4141 |
+
*/
|
4142 |
+
function createTzurl() {
|
4143 |
+
if( empty( $this->tzurl )) return FALSE;
|
4144 |
+
if( empty( $this->tzurl['value'] ))
|
4145 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
|
4146 |
+
$attributes = $this->_createParams( $this->tzurl['params'] );
|
4147 |
+
return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
|
4148 |
+
}
|
4149 |
+
/**
|
4150 |
+
* set calendar component property tzurl
|
4151 |
+
*
|
4152 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4153 |
+
* @since 2.4.8 - 2008-11-04
|
4154 |
+
* @param string $value
|
4155 |
+
* @param string $params optional
|
4156 |
+
* @return boll
|
4157 |
+
*/
|
4158 |
+
function setTzurl( $value, $params=FALSE ) {
|
4159 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4160 |
+
$this->tzurl = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
4161 |
+
return TRUE;
|
4162 |
+
}
|
4163 |
+
/*********************************************************************************/
|
4164 |
+
/**
|
4165 |
+
* Property Name: UID
|
4166 |
+
*/
|
4167 |
+
/**
|
4168 |
+
* creates formatted output for calendar component property uid
|
4169 |
+
*
|
4170 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4171 |
+
* @since 0.9.7 - 2006-11-20
|
4172 |
+
* @return string
|
4173 |
+
*/
|
4174 |
+
function createUid() {
|
4175 |
+
if( 0 >= count( $this->uid ))
|
4176 |
+
$this->_makeuid();
|
4177 |
+
$attributes = $this->_createParams( $this->uid['params'] );
|
4178 |
+
return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
|
4179 |
+
}
|
4180 |
+
/**
|
4181 |
+
* create an unique id for this calendar component object instance
|
4182 |
+
*
|
4183 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4184 |
+
* @since 2.2.7 - 2007-09-04
|
4185 |
+
* @return void
|
4186 |
+
*/
|
4187 |
+
function _makeUid() {
|
4188 |
+
$date = date('Ymd\THisT');
|
4189 |
+
$unique = substr(microtime(), 2, 4);
|
4190 |
+
$base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
|
4191 |
+
$start = 0;
|
4192 |
+
$end = strlen( $base ) - 1;
|
4193 |
+
$length = 6;
|
4194 |
+
$str = null;
|
4195 |
+
for( $p = 0; $p < $length; $p++ )
|
4196 |
+
$unique .= $base{mt_rand( $start, $end )};
|
4197 |
+
$this->uid = array( 'params' => null );
|
4198 |
+
$this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
|
4199 |
+
}
|
4200 |
+
/**
|
4201 |
+
* set calendar component property uid
|
4202 |
+
*
|
4203 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4204 |
+
* @since 2.4.8 - 2008-11-04
|
4205 |
+
* @param string $value
|
4206 |
+
* @param string $params optional
|
4207 |
+
* @return bool
|
4208 |
+
*/
|
4209 |
+
function setUid( $value, $params=FALSE ) {
|
4210 |
+
if( empty( $value )) return FALSE; // no allowEmpty check here !!!!
|
4211 |
+
$this->uid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
4212 |
+
return TRUE;
|
4213 |
+
}
|
4214 |
+
/*********************************************************************************/
|
4215 |
+
/**
|
4216 |
+
* Property Name: URL
|
4217 |
+
*/
|
4218 |
+
/**
|
4219 |
+
* creates formatted output for calendar component property url
|
4220 |
+
*
|
4221 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4222 |
+
* @since 2.4.8 - 2008-10-21
|
4223 |
+
* @return string
|
4224 |
+
*/
|
4225 |
+
function createUrl() {
|
4226 |
+
if( empty( $this->url )) return FALSE;
|
4227 |
+
if( empty( $this->url['value'] ))
|
4228 |
+
return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
|
4229 |
+
$attributes = $this->_createParams( $this->url['params'] );
|
4230 |
+
return $this->_createElement( 'URL', $attributes, $this->url['value'] );
|
4231 |
+
}
|
4232 |
+
/**
|
4233 |
+
* set calendar component property url
|
4234 |
+
*
|
4235 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4236 |
+
* @since 2.4.8 - 2008-11-04
|
4237 |
+
* @param string $value
|
4238 |
+
* @param string $params optional
|
4239 |
+
* @return bool
|
4240 |
+
*/
|
4241 |
+
function setUrl( $value, $params=FALSE ) {
|
4242 |
+
if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4243 |
+
$this->url = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
|
4244 |
+
return TRUE;
|
4245 |
+
}
|
4246 |
+
/*********************************************************************************/
|
4247 |
+
/**
|
4248 |
+
* Property Name: x-prop
|
4249 |
+
*/
|
4250 |
+
/**
|
4251 |
+
* creates formatted output for calendar component property x-prop
|
4252 |
+
*
|
4253 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4254 |
+
* @since 2.9.3 - 2011-05-14
|
4255 |
+
* @return string
|
4256 |
+
*/
|
4257 |
+
function createXprop() {
|
4258 |
+
if( empty( $this->xprop )) return FALSE;
|
4259 |
+
$output = null;
|
4260 |
+
foreach( $this->xprop as $label => $xpropPart ) {
|
4261 |
+
if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) {
|
4262 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label );
|
4263 |
+
continue;
|
4264 |
+
}
|
4265 |
+
$attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
|
4266 |
+
if( is_array( $xpropPart['value'] )) {
|
4267 |
+
foreach( $xpropPart['value'] as $pix => $theXpart )
|
4268 |
+
$xpropPart['value'][$pix] = $this->_strrep( $theXpart );
|
4269 |
+
$xpropPart['value'] = implode( ',', $xpropPart['value'] );
|
4270 |
+
}
|
4271 |
+
else
|
4272 |
+
$xpropPart['value'] = $this->_strrep( $xpropPart['value'] );
|
4273 |
+
$output .= $this->_createElement( $label, $attributes, $xpropPart['value'] );
|
4274 |
+
}
|
4275 |
+
return $output;
|
4276 |
+
}
|
4277 |
+
/**
|
4278 |
+
* set calendar component property x-prop
|
4279 |
+
*
|
4280 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4281 |
+
* @since 2.9.3 - 2011-05-14
|
4282 |
+
* @param string $label
|
4283 |
+
* @param mixed $value
|
4284 |
+
* @param array $params optional
|
4285 |
+
* @return bool
|
4286 |
+
*/
|
4287 |
+
function setXprop( $label, $value, $params=FALSE ) {
|
4288 |
+
if( empty( $label )) return;
|
4289 |
+
if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
|
4290 |
+
$xprop = array( 'value' => $value );
|
4291 |
+
$xprop['params'] = iCalUtilityFunctions::_setParams( $params );
|
4292 |
+
if( !is_array( $this->xprop )) $this->xprop = array();
|
4293 |
+
$this->xprop[strtoupper( $label )] = $xprop;
|
4294 |
+
return TRUE;
|
4295 |
+
}
|
4296 |
+
/*********************************************************************************/
|
4297 |
+
/*********************************************************************************/
|
4298 |
+
/**
|
4299 |
+
* create element format parts
|
4300 |
+
*
|
4301 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4302 |
+
* @since 2.0.6 - 2006-06-20
|
4303 |
+
* @return string
|
4304 |
+
*/
|
4305 |
+
function _createFormat() {
|
4306 |
+
$objectname = null;
|
4307 |
+
switch( $this->format ) {
|
4308 |
+
case 'xcal':
|
4309 |
+
$objectname = ( isset( $this->timezonetype )) ?
|
4310 |
+
strtolower( $this->timezonetype ) : strtolower( $this->objName );
|
4311 |
+
$this->componentStart1 = $this->elementStart1 = '<';
|
4312 |
+
$this->componentStart2 = $this->elementStart2 = '>';
|
4313 |
+
$this->componentEnd1 = $this->elementEnd1 = '</';
|
4314 |
+
$this->componentEnd2 = $this->elementEnd2 = '>'.$this->nl;
|
4315 |
+
$this->intAttrDelimiter = '<!-- -->';
|
4316 |
+
$this->attributeDelimiter = $this->nl;
|
4317 |
+
$this->valueInit = null;
|
4318 |
+
break;
|
4319 |
+
default:
|
4320 |
+
$objectname = ( isset( $this->timezonetype )) ?
|
4321 |
+
strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
|
4322 |
+
$this->componentStart1 = 'BEGIN:';
|
4323 |
+
$this->componentStart2 = null;
|
4324 |
+
$this->componentEnd1 = 'END:';
|
4325 |
+
$this->componentEnd2 = $this->nl;
|
4326 |
+
$this->elementStart1 = null;
|
4327 |
+
$this->elementStart2 = null;
|
4328 |
+
$this->elementEnd1 = null;
|
4329 |
+
$this->elementEnd2 = $this->nl;
|
4330 |
+
$this->intAttrDelimiter = '<!-- -->';
|
4331 |
+
$this->attributeDelimiter = ';';
|
4332 |
+
$this->valueInit = ':';
|
4333 |
+
break;
|
4334 |
+
}
|
4335 |
+
return $objectname;
|
4336 |
+
}
|
4337 |
+
/**
|
4338 |
+
* creates formatted output for calendar component property
|
4339 |
+
*
|
4340 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4341 |
+
* @since 2.6.22 - 2010-12-06
|
4342 |
+
* @param string $label property name
|
4343 |
+
* @param string $attributes property attributes
|
4344 |
+
* @param string $content property content (optional)
|
4345 |
+
* @return string
|
4346 |
+
*/
|
4347 |
+
function _createElement( $label, $attributes=null, $content=FALSE ) {
|
4348 |
+
switch( $this->format ) {
|
4349 |
+
case 'xcal':
|
4350 |
+
$label = strtolower( $label );
|
4351 |
+
break;
|
4352 |
+
default:
|
4353 |
+
$label = strtoupper( $label );
|
4354 |
+
break;
|
4355 |
+
}
|
4356 |
+
$output = $this->elementStart1.$label;
|
4357 |
+
$categoriesAttrLang = null;
|
4358 |
+
$attachInlineBinary = FALSE;
|
4359 |
+
$attachfmttype = null;
|
4360 |
+
if( !empty( $attributes )) {
|
4361 |
+
$attributes = trim( $attributes );
|
4362 |
+
if ( 'xcal' == $this->format) {
|
4363 |
+
$attributes2 = explode( $this->intAttrDelimiter, $attributes );
|
4364 |
+
$attributes = null;
|
4365 |
+
foreach( $attributes2 as $attribute ) {
|
4366 |
+
$attrKVarr = explode( '=', $attribute );
|
4367 |
+
if( empty( $attrKVarr[0] ))
|
4368 |
+
continue;
|
4369 |
+
if( !isset( $attrKVarr[1] )) {
|
4370 |
+
$attrValue = $attrKVarr[0];
|
4371 |
+
$attrKey = null;
|
4372 |
+
}
|
4373 |
+
elseif( 2 == count( $attrKVarr)) {
|
4374 |
+
$attrKey = strtolower( $attrKVarr[0] );
|
4375 |
+
$attrValue = $attrKVarr[1];
|
4376 |
+
}
|
4377 |
+
else {
|
4378 |
+
$attrKey = strtolower( $attrKVarr[0] );
|
4379 |
+
unset( $attrKVarr[0] );
|
4380 |
+
$attrValue = implode( '=', $attrKVarr );
|
4381 |
+
}
|
4382 |
+
if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) {
|
4383 |
+
$attachInlineBinary = TRUE;
|
4384 |
+
if( 'fmttype' == $attrKey )
|
4385 |
+
$attachfmttype = $attrKey.'='.$attrValue;
|
4386 |
+
continue;
|
4387 |
+
}
|
4388 |
+
elseif(( 'categories' == $label ) && ( 'language' == $attrKey ))
|
4389 |
+
$categoriesAttrLang = $attrKey.'='.$attrValue;
|
4390 |
+
else {
|
4391 |
+
$attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
|
4392 |
+
$attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null;
|
4393 |
+
if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) {
|
4394 |
+
$attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 ));
|
4395 |
+
$attrValue = str_replace( '"', '', $attrValue );
|
4396 |
+
}
|
4397 |
+
$attributes .= '"'.htmlspecialchars( $attrValue ).'"';
|
4398 |
+
}
|
4399 |
+
}
|
4400 |
+
}
|
4401 |
+
else {
|
4402 |
+
$attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
|
4403 |
+
}
|
4404 |
+
}
|
4405 |
+
if(((( 'attach' == $label ) && !$attachInlineBinary ) ||
|
4406 |
+
( in_array( $label, array( 'tzurl', 'url' )))) && ( 'xcal' == $this->format)) {
|
4407 |
+
$pos = strrpos($content, "/");
|
4408 |
+
$docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content;
|
4409 |
+
$this->xcaldecl[] = array( 'xmldecl' => 'ENTITY'
|
4410 |
+
, 'uri' => $docname
|
4411 |
+
, 'ref' => 'SYSTEM'
|
4412 |
+
, 'external' => $content
|
4413 |
+
, 'type' => 'NDATA'
|
4414 |
+
, 'type2' => 'BINERY' );
|
4415 |
+
$attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
|
4416 |
+
$attributes .= 'uri="'.$docname.'"';
|
4417 |
+
$content = null;
|
4418 |
+
if( 'attach' == $label ) {
|
4419 |
+
$attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes );
|
4420 |
+
$content = $this->_createElement( 'extref', $attributes, null );
|
4421 |
+
$attributes = null;
|
4422 |
+
}
|
4423 |
+
}
|
4424 |
+
elseif(( 'attach' == $label ) && $attachInlineBinary && ( 'xcal' == $this->format)) {
|
4425 |
+
$content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute
|
4426 |
+
}
|
4427 |
+
$output .= $attributes;
|
4428 |
+
if( !$content && ( '0' != $content )) {
|
4429 |
+
switch( $this->format ) {
|
4430 |
+
case 'xcal':
|
4431 |
+
$output .= ' /';
|
4432 |
+
$output .= $this->elementStart2;
|
4433 |
+
return $output;
|
4434 |
+
break;
|
4435 |
+
default:
|
4436 |
+
$output .= $this->elementStart2.$this->valueInit;
|
4437 |
+
return $this->_size75( $output );
|
4438 |
+
break;
|
4439 |
+
}
|
4440 |
+
}
|
4441 |
+
$output .= $this->elementStart2;
|
4442 |
+
$output .= $this->valueInit.$content;
|
4443 |
+
switch( $this->format ) {
|
4444 |
+
case 'xcal':
|
4445 |
+
return $output.$this->elementEnd1.$label.$this->elementEnd2;
|
4446 |
+
break;
|
4447 |
+
default:
|
4448 |
+
return $this->_size75( $output );
|
4449 |
+
break;
|
4450 |
+
}
|
4451 |
+
}
|
4452 |
+
/**
|
4453 |
+
* creates formatted output for calendar component property parameters
|
4454 |
+
*
|
4455 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4456 |
+
* @since 2.6.33 - 2010-12-18
|
4457 |
+
* @param array $params optional
|
4458 |
+
* @param array $ctrKeys optional
|
4459 |
+
* @return string
|
4460 |
+
*/
|
4461 |
+
function _createParams( $params=array(), $ctrKeys=array() ) {
|
4462 |
+
if( !is_array( $params ) || empty( $params ))
|
4463 |
+
$params = array();
|
4464 |
+
$attrLANG = $attr1 = $attr2 = $lang = null;
|
4465 |
+
$CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ;
|
4466 |
+
$LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ;
|
4467 |
+
$CNattrExist = $LANGattrExist = FALSE;
|
4468 |
+
$xparams = array();
|
4469 |
+
foreach( $params as $paramKey => $paramValue ) {
|
4470 |
+
if( ctype_digit( (string) $paramKey )) {
|
4471 |
+
$xparams[] = $paramValue;
|
4472 |
+
continue;
|
4473 |
+
}
|
4474 |
+
$paramKey = strtoupper( $paramKey );
|
4475 |
+
if( !in_array( $paramKey, array( 'ALTREP', 'CN', 'DIR', 'ENCODING', 'FMTTYPE', 'LANGUAGE', 'RANGE', 'RELTYPE', 'SENT-BY', 'TZID', 'VALUE' )))
|
4476 |
+
$xparams[$paramKey] = $paramValue;
|
4477 |
+
else
|
4478 |
+
$params[$paramKey] = $paramValue;
|
4479 |
+
}
|
4480 |
+
ksort( $xparams, SORT_STRING );
|
4481 |
+
foreach( $xparams as $paramKey => $paramValue ) {
|
4482 |
+
if( ctype_digit( (string) $paramKey ))
|
4483 |
+
$attr2 .= $this->intAttrDelimiter.$paramValue;
|
4484 |
+
else
|
4485 |
+
$attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue";
|
4486 |
+
}
|
4487 |
+
if( isset( $params['FMTTYPE'] ) && !in_array( 'FMTTYPE', $ctrKeys )) {
|
4488 |
+
$attr1 .= $this->intAttrDelimiter.'FMTTYPE='.$params['FMTTYPE'].$attr2;
|
4489 |
+
$attr2 = null;
|
4490 |
+
}
|
4491 |
+
if( isset( $params['ENCODING'] ) && !in_array( 'ENCODING', $ctrKeys )) {
|
4492 |
+
if( !empty( $attr2 )) {
|
4493 |
+
$attr1 .= $attr2;
|
4494 |
+
$attr2 = null;
|
4495 |
+
}
|
4496 |
+
$attr1 .= $this->intAttrDelimiter.'ENCODING='.$params['ENCODING'];
|
4497 |
+
}
|
4498 |
+
if( isset( $params['VALUE'] ) && !in_array( 'VALUE', $ctrKeys ))
|
4499 |
+
$attr1 .= $this->intAttrDelimiter.'VALUE='.$params['VALUE'];
|
4500 |
+
if( isset( $params['TZID'] ) && !in_array( 'TZID', $ctrKeys ))
|
4501 |
+
$attr1 .= $this->intAttrDelimiter.'TZID='.$params['TZID'];
|
4502 |
+
if( isset( $params['RANGE'] ) && !in_array( 'RANGE', $ctrKeys ))
|
4503 |
+
$attr1 .= $this->intAttrDelimiter.'RANGE='.$params['RANGE'];
|
4504 |
+
if( isset( $params['RELTYPE'] ) && !in_array( 'RELTYPE', $ctrKeys ))
|
4505 |
+
$attr1 .= $this->intAttrDelimiter.'RELTYPE='.$params['RELTYPE'];
|
4506 |
+
if( isset( $params['CN'] ) && $CNattrKey ) {
|
4507 |
+
$attr1 = $this->intAttrDelimiter.'CN="'.$params['CN'].'"';
|
4508 |
+
$CNattrExist = TRUE;
|
4509 |
+
}
|
4510 |
+
if( isset( $params['DIR'] ) && in_array( 'DIR', $ctrKeys ))
|
4511 |
+
$attr1 .= $this->intAttrDelimiter.'DIR="'.$params['DIR'].'"';
|
4512 |
+
if( isset( $params['SENT-BY'] ) && in_array( 'SENT-BY', $ctrKeys ))
|
4513 |
+
$attr1 .= $this->intAttrDelimiter.'SENT-BY="'.$params['SENT-BY'].'"';
|
4514 |
+
if( isset( $params['ALTREP'] ) && in_array( 'ALTREP', $ctrKeys ))
|
4515 |
+
$attr1 .= $this->intAttrDelimiter.'ALTREP="'.$params['ALTREP'].'"';
|
4516 |
+
if( isset( $params['LANGUAGE'] ) && $LANGattrKey ) {
|
4517 |
+
$attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$params['LANGUAGE'];
|
4518 |
+
$LANGattrExist = TRUE;
|
4519 |
+
}
|
4520 |
+
if( !$LANGattrExist ) {
|
4521 |
+
$lang = $this->getConfig( 'language' );
|
4522 |
+
if(( $CNattrExist || $LANGattrKey ) && $lang )
|
4523 |
+
$attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang;
|
4524 |
+
}
|
4525 |
+
return $attr1.$attrLANG.$attr2;
|
4526 |
+
}
|
4527 |
+
/**
|
4528 |
+
* creates formatted output for calendar component property data value type recur
|
4529 |
+
*
|
4530 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4531 |
+
* @since 2.4.8 - 2008-10-22
|
4532 |
+
* @param array $recurlabel
|
4533 |
+
* @param array $recurdata
|
4534 |
+
* @return string
|
4535 |
+
*/
|
4536 |
+
function _format_recur( $recurlabel, $recurdata ) {
|
4537 |
+
$output = null;
|
4538 |
+
foreach( $recurdata as $therule ) {
|
4539 |
+
if( empty( $therule['value'] )) {
|
4540 |
+
if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel );
|
4541 |
+
continue;
|
4542 |
+
}
|
4543 |
+
$attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null;
|
4544 |
+
$content1 = $content2 = null;
|
4545 |
+
foreach( $therule['value'] as $rulelabel => $rulevalue ) {
|
4546 |
+
switch( $rulelabel ) {
|
4547 |
+
case 'FREQ': {
|
4548 |
+
$content1 .= "FREQ=$rulevalue";
|
4549 |
+
break;
|
4550 |
+
}
|
4551 |
+
case 'UNTIL': {
|
4552 |
+
$content2 .= ";UNTIL=";
|
4553 |
+
$content2 .= iCalUtilityFunctions::_format_date_time( $rulevalue );
|
4554 |
+
break;
|
4555 |
+
}
|
4556 |
+
case 'COUNT':
|
4557 |
+
case 'INTERVAL':
|
4558 |
+
case 'WKST': {
|
4559 |
+
$content2 .= ";$rulelabel=$rulevalue";
|
4560 |
+
break;
|
4561 |
+
}
|
4562 |
+
case 'BYSECOND':
|
4563 |
+
case 'BYMINUTE':
|
4564 |
+
case 'BYHOUR':
|
4565 |
+
case 'BYMONTHDAY':
|
4566 |
+
case 'BYYEARDAY':
|
4567 |
+
case 'BYWEEKNO':
|
4568 |
+
case 'BYMONTH':
|
4569 |
+
case 'BYSETPOS': {
|
4570 |
+
$content2 .= ";$rulelabel=";
|
4571 |
+
if( is_array( $rulevalue )) {
|
4572 |
+
foreach( $rulevalue as $vix => $valuePart ) {
|
4573 |
+
$content2 .= ( $vix ) ? ',' : null;
|
4574 |
+
$content2 .= $valuePart;
|
4575 |
+
}
|
4576 |
+
}
|
4577 |
+
else
|
4578 |
+
$content2 .= $rulevalue;
|
4579 |
+
break;
|
4580 |
+
}
|
4581 |
+
case 'BYDAY': {
|
4582 |
+
$content2 .= ";$rulelabel=";
|
4583 |
+
$bydaycnt = 0;
|
4584 |
+
foreach( $rulevalue as $vix => $valuePart ) {
|
4585 |
+
$content21 = $content22 = null;
|
4586 |
+
if( is_array( $valuePart )) {
|
4587 |
+
$content2 .= ( $bydaycnt ) ? ',' : null;
|
4588 |
+
foreach( $valuePart as $vix2 => $valuePart2 ) {
|
4589 |
+
if( 'DAY' != strtoupper( $vix2 ))
|
4590 |
+
$content21 .= $valuePart2;
|
4591 |
+
else
|
4592 |
+
$content22 .= $valuePart2;
|
4593 |
+
}
|
4594 |
+
$content2 .= $content21.$content22;
|
4595 |
+
$bydaycnt++;
|
4596 |
+
}
|
4597 |
+
else {
|
4598 |
+
$content2 .= ( $bydaycnt ) ? ',' : null;
|
4599 |
+
if( 'DAY' != strtoupper( $vix ))
|
4600 |
+
$content21 .= $valuePart;
|
4601 |
+
else {
|
4602 |
+
$content22 .= $valuePart;
|
4603 |
+
$bydaycnt++;
|
4604 |
+
}
|
4605 |
+
$content2 .= $content21.$content22;
|
4606 |
+
}
|
4607 |
+
}
|
4608 |
+
break;
|
4609 |
+
}
|
4610 |
+
default: {
|
4611 |
+
$content2 .= ";$rulelabel=$rulevalue";
|
4612 |
+
break;
|
4613 |
+
}
|
4614 |
+
}
|
4615 |
+
}
|
4616 |
+
$output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 );
|
4617 |
+
}
|
4618 |
+
return $output;
|
4619 |
+
}
|
4620 |
+
/**
|
4621 |
+
* check if property not exists within component
|
4622 |
+
*
|
4623 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4624 |
+
* @since 2.5.1 - 2008-10-15
|
4625 |
+
* @param string $propName
|
4626 |
+
* @return bool
|
4627 |
+
*/
|
4628 |
+
function _notExistProp( $propName ) {
|
4629 |
+
if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
|
4630 |
+
$propName = strtolower( $propName );
|
4631 |
+
if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; }
|
4632 |
+
elseif( 'percent-complete' == $propName ) { if( !isset( $this->percentcomplete )) return TRUE; }
|
4633 |
+
elseif( 'recurrence-id' == $propName ) { if( !isset( $this->recurrenceid )) return TRUE; }
|
4634 |
+
elseif( 'related-to' == $propName ) { if( !isset( $this->relatedto )) return TRUE; }
|
4635 |
+
elseif( 'request-status' == $propName ) { if( !isset( $this->requeststatus )) return TRUE; }
|
4636 |
+
elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE;
|
4637 |
+
return FALSE;
|
4638 |
+
}
|
4639 |
+
/*********************************************************************************/
|
4640 |
+
/*********************************************************************************/
|
4641 |
+
/**
|
4642 |
+
* get general component config variables or info about subcomponents
|
4643 |
+
*
|
4644 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4645 |
+
* @since 2.9.6 - 2011-05-14
|
4646 |
+
* @param mixed $config
|
4647 |
+
* @return value
|
4648 |
+
*/
|
4649 |
+
function getConfig( $config = FALSE) {
|
4650 |
+
if( !$config ) {
|
4651 |
+
$return = array();
|
4652 |
+
$return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' );
|
4653 |
+
$return['FORMAT'] = $this->getConfig( 'FORMAT' );
|
4654 |
+
if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' )))
|
4655 |
+
$return['LANGUAGE'] = $lang;
|
4656 |
+
$return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' );
|
4657 |
+
$return['TZTD'] = $this->getConfig( 'TZID' );
|
4658 |
+
$return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' );
|
4659 |
+
return $return;
|
4660 |
+
}
|
4661 |
+
switch( strtoupper( $config )) {
|
4662 |
+
case 'ALLOWEMPTY':
|
4663 |
+
return $this->allowEmpty;
|
4664 |
+
break;
|
4665 |
+
case 'COMPSINFO':
|
4666 |
+
unset( $this->compix );
|
4667 |
+
$info = array();
|
4668 |
+
if( isset( $this->components )) {
|
4669 |
+
foreach( $this->components as $cix => $component ) {
|
4670 |
+
if( empty( $component )) continue;
|
4671 |
+
$info[$cix]['ordno'] = $cix + 1;
|
4672 |
+
$info[$cix]['type'] = $component->objName;
|
4673 |
+
$info[$cix]['uid'] = $component->getProperty( 'uid' );
|
4674 |
+
$info[$cix]['props'] = $component->getConfig( 'propinfo' );
|
4675 |
+
$info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
|
4676 |
+
}
|
4677 |
+
}
|
4678 |
+
return $info;
|
4679 |
+
break;
|
4680 |
+
case 'FORMAT':
|
4681 |
+
return $this->format;
|
4682 |
+
break;
|
4683 |
+
case 'LANGUAGE':
|
4684 |
+
// get language for calendar component as defined in [RFC 1766]
|
4685 |
+
return $this->language;
|
4686 |
+
break;
|
4687 |
+
case 'NL':
|
4688 |
+
case 'NEWLINECHAR':
|
4689 |
+
return $this->nl;
|
4690 |
+
break;
|
4691 |
+
case 'PROPINFO':
|
4692 |
+
$output = array();
|
4693 |
+
if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
|
4694 |
+
if( empty( $this->uid['value'] )) $this->_makeuid();
|
4695 |
+
$output['UID'] = 1;
|
4696 |
+
}
|
4697 |
+
if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
|
4698 |
+
if( !empty( $this->summary )) $output['SUMMARY'] = 1;
|
4699 |
+
if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
|
4700 |
+
if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
|
4701 |
+
if( !empty( $this->dtend )) $output['DTEND'] = 1;
|
4702 |
+
if( !empty( $this->due )) $output['DUE'] = 1;
|
4703 |
+
if( !empty( $this->duration )) $output['DURATION'] = 1;
|
4704 |
+
if( !empty( $this->rrule )) $output['RRULE'] = count( $this->rrule );
|
4705 |
+
if( !empty( $this->rdate )) $output['RDATE'] = count( $this->rdate );
|
4706 |
+
if( !empty( $this->exdate )) $output['EXDATE'] = count( $this->exdate );
|
4707 |
+
if( !empty( $this->exrule )) $output['EXRULE'] = count( $this->exrule );
|
4708 |
+
if( !empty( $this->action )) $output['ACTION'] = 1;
|
4709 |
+
if( !empty( $this->attach )) $output['ATTACH'] = count( $this->attach );
|
4710 |
+
if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee );
|
4711 |
+
if( !empty( $this->categories )) $output['CATEGORIES'] = count( $this->categories );
|
4712 |
+
if( !empty( $this->class )) $output['CLASS'] = 1;
|
4713 |
+
if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment );
|
4714 |
+
if( !empty( $this->completed )) $output['COMPLETED'] = 1;
|
4715 |
+
if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact );
|
4716 |
+
if( !empty( $this->created )) $output['CREATED'] = 1;
|
4717 |
+
if( !empty( $this->freebusy )) $output['FREEBUSY'] = count( $this->freebusy );
|
4718 |
+
if( !empty( $this->geo )) $output['GEO'] = 1;
|
4719 |
+
if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1;
|
4720 |
+
if( !empty( $this->location )) $output['LOCATION'] = 1;
|
4721 |
+
if( !empty( $this->organizer )) $output['ORGANIZER'] = 1;
|
4722 |
+
if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1;
|
4723 |
+
if( !empty( $this->priority )) $output['PRIORITY'] = 1;
|
4724 |
+
if( !empty( $this->recurrenceid )) $output['RECURRENCE-ID'] = 1;
|
4725 |
+
if( !empty( $this->relatedto )) $output['RELATED-TO'] = count( $this->relatedto );
|
4726 |
+
if( !empty( $this->repeat )) $output['REPEAT'] = 1;
|
4727 |
+
if( !empty( $this->requeststatus )) $output['REQUEST-STATUS'] = count( $this->requeststatus );
|
4728 |
+
if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources );
|
4729 |
+
if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
|
4730 |
+
if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
|
4731 |
+
if( !empty( $this->status )) $output['STATUS'] = 1;
|
4732 |
+
if( !empty( $this->transp )) $output['TRANSP'] = 1;
|
4733 |
+
if( !empty( $this->trigger )) $output['TRIGGER'] = 1;
|
4734 |
+
if( !empty( $this->tzid )) $output['TZID'] = 1;
|
4735 |
+
if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname );
|
4736 |
+
if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETFROM'] = 1;
|
4737 |
+
if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1;
|
4738 |
+
if( !empty( $this->tzurl )) $output['TZURL'] = 1;
|
4739 |
+
if( !empty( $this->url )) $output['URL'] = 1;
|
4740 |
+
if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
|
4741 |
+
return $output;
|
4742 |
+
break;
|
4743 |
+
case 'TZID':
|
4744 |
+
return $this->dtzid;
|
4745 |
+
break;
|
4746 |
+
case 'UNIQUE_ID':
|
4747 |
+
if( empty( $this->unique_id ))
|
4748 |
+
$this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
|
4749 |
+
return $this->unique_id;
|
4750 |
+
break;
|
4751 |
+
}
|
4752 |
+
}
|
4753 |
+
/**
|
4754 |
+
* general component config setting
|
4755 |
+
*
|
4756 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4757 |
+
* @since 2.9.6 - 2011-05-14
|
4758 |
+
* @param mixed $config
|
4759 |
+
* @param string $value
|
4760 |
+
* @param bool $softUpdate
|
4761 |
+
* @return void
|
4762 |
+
*/
|
4763 |
+
function setConfig( $config, $value = FALSE, $softUpdate = FALSE ) {
|
4764 |
+
if( is_array( $config )) {
|
4765 |
+
foreach( $config as $cKey => $cValue ) {
|
4766 |
+
if( FALSE === $this->setConfig( $cKey, $cValue, $softUpdate ))
|
4767 |
+
return FALSE;
|
4768 |
+
}
|
4769 |
+
return TRUE;
|
4770 |
+
}
|
4771 |
+
$res = FALSE;
|
4772 |
+
switch( strtoupper( $config )) {
|
4773 |
+
case 'ALLOWEMPTY':
|
4774 |
+
$this->allowEmpty = $value;
|
4775 |
+
$subcfg = array( 'ALLOWEMPTY' => $value );
|
4776 |
+
$res = TRUE;
|
4777 |
+
break;
|
4778 |
+
case 'FORMAT':
|
4779 |
+
$value = trim( strtolower( $value ));
|
4780 |
+
$this->format = $value;
|
4781 |
+
$this->_createFormat();
|
4782 |
+
$subcfg = array( 'FORMAT' => $value );
|
4783 |
+
$res = TRUE;
|
4784 |
+
break;
|
4785 |
+
case 'LANGUAGE':
|
4786 |
+
// set language for calendar component as defined in [RFC 1766]
|
4787 |
+
$value = trim( $value );
|
4788 |
+
if( empty( $this->language ) || !$softUpdate )
|
4789 |
+
$this->language = $value;
|
4790 |
+
$subcfg = array( 'LANGUAGE' => $value );
|
4791 |
+
$res = TRUE;
|
4792 |
+
break;
|
4793 |
+
case 'NL':
|
4794 |
+
case 'NEWLINECHAR':
|
4795 |
+
$this->nl = $value;
|
4796 |
+
$subcfg = array( 'NL' => $value );
|
4797 |
+
$res = TRUE;
|
4798 |
+
break;
|
4799 |
+
case 'TZID':
|
4800 |
+
$this->dtzid = $value;
|
4801 |
+
$subcfg = array( 'TZID' => $value );
|
4802 |
+
$res = TRUE;
|
4803 |
+
break;
|
4804 |
+
case 'UNIQUE_ID':
|
4805 |
+
$value = trim( $value );
|
4806 |
+
$this->unique_id = $value;
|
4807 |
+
$subcfg = array( 'UNIQUE_ID' => $value );
|
4808 |
+
$res = TRUE;
|
4809 |
+
break;
|
4810 |
+
default: // any unvalid config key.. .
|
4811 |
+
return TRUE;
|
4812 |
+
}
|
4813 |
+
if( !$res ) return FALSE;
|
4814 |
+
if( isset( $subcfg ) && !empty( $this->components )) {
|
4815 |
+
foreach( $subcfg as $cfgkey => $cfgvalue ) {
|
4816 |
+
foreach( $this->components as $cix => $component ) {
|
4817 |
+
$res = $component->setConfig( $cfgkey, $cfgvalue, $softUpdate );
|
4818 |
+
if( !$res )
|
4819 |
+
break 2;
|
4820 |
+
$this->components[$cix] = $component->copy(); // PHP4 compliant
|
4821 |
+
}
|
4822 |
+
}
|
4823 |
+
}
|
4824 |
+
return $res;
|
4825 |
+
}
|
4826 |
+
/*********************************************************************************/
|
4827 |
+
/**
|
4828 |
+
* delete component property value
|
4829 |
+
*
|
4830 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
4831 |
+
* @since 2.8.8 - 2011-03-15
|
4832 |
+
* @param mixed $propName, bool FALSE => X-property
|
4833 |
+
* @param int $propix, optional, if specific property is wanted in case of multiply occurences
|
4834 |
+
* @return bool, if successfull delete TRUE
|
4835 |
+
*/
|
4836 |
+
function deleteProperty( $propName=FALSE, $propix=FALSE ) {
|
4837 |
+
if( $this->_notExistProp( $propName )) return FALSE;
|
4838 |
+
$propName = strtoupper( $propName );
|
4839 |
+
if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
|
4840 |
+
'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
|
4841 |
+
if( !$propix )
|
4842 |
+
$propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1;
|
4843 |
+
$this->propdelix[$propName] = --$propix;
|
4844 |
+
}
|
4845 |
+
$return = FALSE;
|
4846 |
+
switch( $propName ) {
|
4847 |
+
case 'ACTION':
|
4848 |
+
if( !empty( $this->action )) {
|
4849 |
+
$this->action = '';
|
4850 |
+
$return = TRUE;
|
4851 |
+
}
|
4852 |
+
break;
|
4853 |
+
case 'ATTACH':
|
4854 |
+
return $this->deletePropertyM( $this->attach, $this->propdelix[$propName] );
|
4855 |
+
break;
|
4856 |
+
case 'ATTENDEE':
|
4857 |
+
return $this->deletePropertyM( $this->attendee, $this->propdelix[$propName] );
|
4858 |
+
break;
|
4859 |
+
case 'CATEGORIES':
|
4860 |
+
return $this->deletePropertyM( $this->categories, $this->propdelix[$propName] );
|
4861 |
+
break;
|
4862 |
+
case 'CLASS':
|
4863 |
+
if( !empty( $this->class )) {
|
4864 |
+
$this->class = '';
|
4865 |
+
$return = TRUE;
|
4866 |
+
}
|
4867 |
+
break;
|
4868 |
+
case 'COMMENT':
|
4869 |
+
return $this->deletePropertyM( $this->comment, $this->propdelix[$propName] );
|
4870 |
+
break;
|
4871 |
+
case 'COMPLETED':
|
4872 |
+
if( !empty( $this->completed )) {
|
4873 |
+
$this->completed = '';
|
4874 |
+
$return = TRUE;
|
4875 |
+
}
|
4876 |
+
break;
|
4877 |
+
case 'CONTACT':
|
4878 |
+
return $this->deletePropertyM( $this->contact, $this->propdelix[$propName] );
|
4879 |
+
break;
|
4880 |
+
case 'CREATED':
|
4881 |
+
if( !empty( $this->created )) {
|
4882 |
+
$this->created = '';
|
4883 |
+
$return = TRUE;
|
4884 |
+
}
|
4885 |
+
break;
|
4886 |
+
case 'DESCRIPTION':
|
4887 |
+
return $this->deletePropertyM( $this->description, $this->propdelix[$propName] );
|
4888 |
+
break;
|
4889 |
+
case 'DTEND':
|
4890 |
+
if( !empty( $this->dtend )) {
|
4891 |
+
$this->dtend = '';
|
4892 |
+
$return = TRUE;
|
4893 |
+
}
|
4894 |
+
break;
|
4895 |
+
case 'DTSTAMP':
|
4896 |
+
if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
|
4897 |
+
return FALSE;
|
4898 |
+
if( !empty( $this->dtstamp )) {
|
4899 |
+
$this->dtstamp = '';
|
4900 |
+
$return = TRUE;
|
4901 |
+
}
|
4902 |
+
break;
|
4903 |
+
case 'DTSTART':
|
4904 |
+
if( !empty( $this->dtstart )) {
|
4905 |
+
$this->dtstart = '';
|
4906 |
+
$return = TRUE;
|
4907 |
+
}
|
4908 |
+
break;
|
4909 |
+
case 'DUE':
|
4910 |
+
if( !empty( $this->due )) {
|
4911 |
+
$this->due = '';
|
4912 |
+
$return = TRUE;
|
4913 |
+
}
|
4914 |
+
break;
|
4915 |
+
case 'DURATION':
|
4916 |
+
if( !empty( $this->duration )) {
|
4917 |
+
$this->duration = '';
|
4918 |
+
$return = TRUE;
|
4919 |
+
}
|
4920 |
+
break;
|
4921 |
+
case 'EXDATE':
|
4922 |
+
return $this->deletePropertyM( $this->exdate, $this->propdelix[$propName] );
|
4923 |
+
break;
|
4924 |
+
case 'EXRULE':
|
4925 |
+
return $this->deletePropertyM( $this->exrule, $this->propdelix[$propName] );
|
4926 |
+
break;
|
4927 |
+
case 'FREEBUSY':
|
4928 |
+
return $this->deletePropertyM( $this->freebusy, $this->propdelix[$propName] );
|
4929 |
+
break;
|
4930 |
+
case 'GEO':
|
4931 |
+
if( !empty( $this->geo )) {
|
4932 |
+
$this->geo = '';
|
4933 |
+
$return = TRUE;
|
4934 |
+
}
|
4935 |
+
break;
|
4936 |
+
case 'LAST-MODIFIED':
|
4937 |
+
if( !empty( $this->lastmodified )) {
|
4938 |
+
$this->lastmodified = '';
|
4939 |
+
$return = TRUE;
|
4940 |
+
}
|
4941 |
+
break;
|
4942 |
+
case 'LOCATION':
|
4943 |
+
if( !empty( $this->location )) {
|
4944 |
+
$this->location = '';
|
4945 |
+
$return = TRUE;
|
4946 |
+
}
|
4947 |
+
break;
|
4948 |
+
case 'ORGANIZER':
|
4949 |
+
if( !empty( $this->organizer )) {
|
4950 |
+
$this->organizer = '';
|
4951 |
+
$return = TRUE;
|
4952 |
+
}
|
4953 |
+
break;
|
4954 |
+
case 'PERCENT-COMPLETE':
|
4955 |
+
if( !empty( $this->percentcomplete )) {
|
4956 |
+
$this->percentcomplete = '';
|
4957 |
+
$return = TRUE;
|
4958 |
+
}
|
4959 |
+
break;
|
4960 |
+
case 'PRIORITY':
|
4961 |
+
if( !empty( $this->priority )) {
|
4962 |
+
$this->priority = '';
|
4963 |
+
$return = TRUE;
|
4964 |
+
}
|
4965 |
+
break;
|
4966 |
+
case 'RDATE':
|
4967 |
+
return $this->deletePropertyM( $this->rdate, $this->propdelix[$propName] );
|
4968 |
+
break;
|
4969 |
+
case 'RECURRENCE-ID':
|
4970 |
+
if( !empty( $this->recurrenceid )) {
|
4971 |
+
$this->recurrenceid = '';
|
4972 |
+
$return = TRUE;
|
4973 |
+
}
|
4974 |
+
break;
|
4975 |
+
case 'RELATED-TO':
|
4976 |
+
return $this->deletePropertyM( $this->relatedto, $this->propdelix[$propName] );
|
4977 |
+
break;
|
4978 |
+
case 'REPEAT':
|
4979 |
+
if( !empty( $this->repeat )) {
|
4980 |
+
$this->repeat = '';
|
4981 |
+
$return = TRUE;
|
4982 |
+
}
|
4983 |
+
break;
|
4984 |
+
case 'REQUEST-STATUS':
|
4985 |
+
return $this->deletePropertyM( $this->requeststatus, $this->propdelix[$propName] );
|
4986 |
+
break;
|
4987 |
+
case 'RESOURCES':
|
4988 |
+
return $this->deletePropertyM( $this->resources, $this->propdelix[$propName] );
|
4989 |
+
break;
|
4990 |
+
case 'RRULE':
|
4991 |
+
return $this->deletePropertyM( $this->rrule, $this->propdelix[$propName] );
|
4992 |
+
break;
|
4993 |
+
case 'SEQUENCE':
|
4994 |
+
if( !empty( $this->sequence )) {
|
4995 |
+
$this->sequence = '';
|
4996 |
+
$return = TRUE;
|
4997 |
+
}
|
4998 |
+
break;
|
4999 |
+
case 'STATUS':
|
5000 |
+
if( !empty( $this->status )) {
|
5001 |
+
$this->status = '';
|
5002 |
+
$return = TRUE;
|
5003 |
+
}
|
5004 |
+
break;
|
5005 |
+
case 'SUMMARY':
|
5006 |
+
if( !empty( $this->summary )) {
|
5007 |
+
$this->summary = '';
|
5008 |
+
$return = TRUE;
|
5009 |
+
}
|
5010 |
+
break;
|
5011 |
+
case 'TRANSP':
|
5012 |
+
if( !empty( $this->transp )) {
|
5013 |
+
$this->transp = '';
|
5014 |
+
$return = TRUE;
|
5015 |
+
}
|
5016 |
+
break;
|
5017 |
+
case 'TRIGGER':
|
5018 |
+
if( !empty( $this->trigger )) {
|
5019 |
+
$this->trigger = '';
|
5020 |
+
$return = TRUE;
|
5021 |
+
}
|
5022 |
+
break;
|
5023 |
+
case 'TZID':
|
5024 |
+
if( !empty( $this->tzid )) {
|
5025 |
+
$this->tzid = '';
|
5026 |
+
$return = TRUE;
|
5027 |
+
}
|
5028 |
+
break;
|
5029 |
+
case 'TZNAME':
|
5030 |
+
return $this->deletePropertyM( $this->tzname, $this->propdelix[$propName] );
|
5031 |
+
break;
|
5032 |
+
case 'TZOFFSETFROM':
|
5033 |
+
if( !empty( $this->tzoffsetfrom )) {
|
5034 |
+
$this->tzoffsetfrom = '';
|
5035 |
+
$return = TRUE;
|
5036 |
+
}
|
5037 |
+
break;
|
5038 |
+
case 'TZOFFSETTO':
|
5039 |
+
if( !empty( $this->tzoffsetto )) {
|
5040 |
+
$this->tzoffsetto = '';
|
5041 |
+
$return = TRUE;
|
5042 |
+
}
|
5043 |
+
break;
|
5044 |
+
case 'TZURL':
|
5045 |
+
if( !empty( $this->tzurl )) {
|
5046 |
+
$this->tzurl = '';
|
5047 |
+
$return = TRUE;
|
5048 |
+
}
|
5049 |
+
break;
|
5050 |
+
case 'UID':
|
5051 |
+
if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
|
5052 |
+
return FALSE;
|
5053 |
+
if( !empty( $this->uid )) {
|
5054 |
+
$this->uid = '';
|
5055 |
+
$return = TRUE;
|
5056 |
+
}
|
5057 |
+
break;
|
5058 |
+
case 'URL':
|
5059 |
+
if( !empty( $this->url )) {
|
5060 |
+
$this->url = '';
|
5061 |
+
$return = TRUE;
|
5062 |
+
}
|
5063 |
+
break;
|
5064 |
+
default:
|
5065 |
+
$reduced = '';
|
5066 |
+
if( $propName != 'X-PROP' ) {
|
5067 |
+
if( !isset( $this->xprop[$propName] )) return FALSE;
|
5068 |
+
foreach( $this->xprop as $k => $a ) {
|
5069 |
+
if(( $k != $propName ) && !empty( $a ))
|
5070 |
+
$reduced[$k] = $a;
|
5071 |
+
}
|
5072 |
+
}
|
5073 |
+
else {
|
5074 |
+
if( count( $this->xprop ) <= $propix ) { unset( $this->propdelix[$propName] ); return FALSE; }
|
5075 |
+
$xpropno = 0;
|
5076 |
+
foreach( $this->xprop as $xpropkey => $xpropvalue ) {
|
5077 |
+
if( $propix != $xpropno )
|
5078 |
+
$reduced[$xpropkey] = $xpropvalue;
|
5079 |
+
$xpropno++;
|
5080 |
+
}
|
5081 |
+
}
|
5082 |
+
$this->xprop = $reduced;
|
5083 |
+
if( empty( $this->xprop )) {
|
5084 |
+
unset( $this->propdelix[$propName] );
|
5085 |
+
return FALSE;
|
5086 |
+
}
|
5087 |
+
return TRUE;
|
5088 |
+
}
|
5089 |
+
return $return;
|
5090 |
+
}
|
5091 |
+
/*********************************************************************************/
|
5092 |
+
/**
|
5093 |
+
* delete component property value, fixing components with multiple occurencies
|
5094 |
+
*
|
5095 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5096 |
+
* @since 2.8.8 - 2011-03-15
|
5097 |
+
* @param array $multiprop, reference to a component property
|
5098 |
+
* @param int $propix, reference to removal counter
|
5099 |
+
* @return bool TRUE
|
5100 |
+
*/
|
5101 |
+
function deletePropertyM( & $multiprop, & $propix ) {
|
5102 |
+
if( isset( $multiprop[$propix] ))
|
5103 |
+
unset( $multiprop[$propix] );
|
5104 |
+
if( empty( $multiprop )) {
|
5105 |
+
$multiprop = '';
|
5106 |
+
unset( $propix );
|
5107 |
+
return FALSE;
|
5108 |
+
}
|
5109 |
+
else
|
5110 |
+
return TRUE;
|
5111 |
+
}
|
5112 |
+
/**
|
5113 |
+
* get component property value/params
|
5114 |
+
*
|
5115 |
+
* if property has multiply values, consequtive function calls are needed
|
5116 |
+
*
|
5117 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5118 |
+
* @since 2.9.3 - 2011-05-18
|
5119 |
+
* @param string $propName, optional
|
5120 |
+
* @param int @propix, optional, if specific property is wanted in case of multiply occurences
|
5121 |
+
* @param bool $inclParam=FALSE
|
5122 |
+
* @param bool $specform=FALSE
|
5123 |
+
* @return mixed
|
5124 |
+
*/
|
5125 |
+
function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
|
5126 |
+
if( $this->_notExistProp( $propName )) return FALSE;
|
5127 |
+
$propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
|
5128 |
+
if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
|
5129 |
+
'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
|
5130 |
+
if( !$propix )
|
5131 |
+
$propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
|
5132 |
+
$this->propix[$propName] = --$propix;
|
5133 |
+
}
|
5134 |
+
switch( $propName ) {
|
5135 |
+
case 'ACTION':
|
5136 |
+
if( !empty( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value'];
|
5137 |
+
break;
|
5138 |
+
case 'ATTACH':
|
5139 |
+
while( is_array( $this->attach ) && !isset( $this->attach[$propix] ) && ( 0 < count( $this->attach )) && ( $propix < end( array_keys( $this->attach ))))
|
5140 |
+
$propix++;
|
5141 |
+
if( !isset( $this->attach[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5142 |
+
return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value'];
|
5143 |
+
break;
|
5144 |
+
case 'ATTENDEE':
|
5145 |
+
while( is_array( $this->attendee ) && !isset( $this->attendee[$propix] ) && ( 0 < count( $this->attendee )) && ( $propix < end( array_keys( $this->attendee ))))
|
5146 |
+
$propix++;
|
5147 |
+
if( !isset( $this->attendee[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5148 |
+
return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
|
5149 |
+
break;
|
5150 |
+
case 'CATEGORIES':
|
5151 |
+
while( is_array( $this->categories ) && !isset( $this->categories[$propix] ) && ( 0 < count( $this->categories )) && ( $propix < end( array_keys( $this->categories ))))
|
5152 |
+
$propix++;
|
5153 |
+
if( !isset( $this->categories[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5154 |
+
return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value'];
|
5155 |
+
break;
|
5156 |
+
case 'CLASS':
|
5157 |
+
if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
|
5158 |
+
break;
|
5159 |
+
case 'COMMENT':
|
5160 |
+
while( is_array( $this->comment ) && !isset( $this->comment[$propix] ) && ( 0 < count( $this->comment )) && ( $propix < end( array_keys( $this->comment ))))
|
5161 |
+
$propix++;
|
5162 |
+
if( !isset( $this->comment[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5163 |
+
return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
|
5164 |
+
break;
|
5165 |
+
case 'COMPLETED':
|
5166 |
+
if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
|
5167 |
+
break;
|
5168 |
+
case 'CONTACT':
|
5169 |
+
while( is_array( $this->contact ) && !isset( $this->contact[$propix] ) && ( 0 < count( $this->contact )) && ( $propix < end( array_keys( $this->contact ))))
|
5170 |
+
$propix++;
|
5171 |
+
if( !isset( $this->contact[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5172 |
+
return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
|
5173 |
+
break;
|
5174 |
+
case 'CREATED':
|
5175 |
+
if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
|
5176 |
+
break;
|
5177 |
+
case 'DESCRIPTION':
|
5178 |
+
while( is_array( $this->description ) && !isset( $this->description[$propix] ) && ( 0 < count( $this->description )) && ( $propix < end( array_keys( $this->description ))))
|
5179 |
+
$propix++;
|
5180 |
+
if( !isset( $this->description[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5181 |
+
return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
|
5182 |
+
break;
|
5183 |
+
case 'DTEND':
|
5184 |
+
if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
|
5185 |
+
break;
|
5186 |
+
case 'DTSTAMP':
|
5187 |
+
if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
|
5188 |
+
return;
|
5189 |
+
if( !isset( $this->dtstamp['value'] ))
|
5190 |
+
$this->_makeDtstamp();
|
5191 |
+
return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
|
5192 |
+
break;
|
5193 |
+
case 'DTSTART':
|
5194 |
+
if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
|
5195 |
+
break;
|
5196 |
+
case 'DUE':
|
5197 |
+
if( !empty( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value'];
|
5198 |
+
break;
|
5199 |
+
case 'DURATION':
|
5200 |
+
if( !isset( $this->duration['value'] )) return FALSE;
|
5201 |
+
$value = ( $specform && isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) ? iCalUtilityFunctions::_duration2date( $this->dtstart['value'], $this->duration['value'] ) : $this->duration['value'];
|
5202 |
+
return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
|
5203 |
+
break;
|
5204 |
+
case 'EXDATE':
|
5205 |
+
while( is_array( $this->exdate ) && !isset( $this->exdate[$propix] ) && ( 0 < count( $this->exdate )) && ( $propix < end( array_keys( $this->exdate ))))
|
5206 |
+
$propix++;
|
5207 |
+
if( !isset( $this->exdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5208 |
+
return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
|
5209 |
+
break;
|
5210 |
+
case 'EXRULE':
|
5211 |
+
while( is_array( $this->exrule ) && !isset( $this->exrule[$propix] ) && ( 0 < count( $this->exrule )) && ( $propix < end( array_keys( $this->exrule ))))
|
5212 |
+
$propix++;
|
5213 |
+
if( !isset( $this->exrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5214 |
+
return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
|
5215 |
+
break;
|
5216 |
+
case 'FREEBUSY':
|
5217 |
+
while( is_array( $this->freebusy ) && !isset( $this->freebusy[$propix] ) && ( 0 < count( $this->freebusy )) && ( $propix < end( array_keys( $this->freebusy ))))
|
5218 |
+
$propix++;
|
5219 |
+
if( !isset( $this->freebusy[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5220 |
+
return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
|
5221 |
+
break;
|
5222 |
+
case 'GEO':
|
5223 |
+
if( !empty( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value'];
|
5224 |
+
break;
|
5225 |
+
case 'LAST-MODIFIED':
|
5226 |
+
if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
|
5227 |
+
break;
|
5228 |
+
case 'LOCATION':
|
5229 |
+
if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
|
5230 |
+
break;
|
5231 |
+
case 'ORGANIZER':
|
5232 |
+
if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
|
5233 |
+
break;
|
5234 |
+
case 'PERCENT-COMPLETE':
|
5235 |
+
if( !empty( $this->percentcomplete['value'] ) || ( isset( $this->percentcomplete['value'] ) && ( '0' == $this->percentcomplete['value'] ))) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value'];
|
5236 |
+
break;
|
5237 |
+
case 'PRIORITY':
|
5238 |
+
if( !empty( $this->priority['value'] ) || ( isset( $this->priority['value'] ) && ('0' == $this->priority['value'] ))) return ( $inclParam ) ? $this->priority : $this->priority['value'];
|
5239 |
+
break;
|
5240 |
+
case 'RDATE':
|
5241 |
+
while( is_array( $this->rdate ) && !isset( $this->rdate[$propix] ) && ( 0 < count( $this->rdate )) && ( $propix < end( array_keys( $this->rdate ))))
|
5242 |
+
$propix++;
|
5243 |
+
if( !isset( $this->rdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5244 |
+
return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
|
5245 |
+
break;
|
5246 |
+
case 'RECURRENCE-ID':
|
5247 |
+
if( !empty( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value'];
|
5248 |
+
break;
|
5249 |
+
case 'RELATED-TO':
|
5250 |
+
while( is_array( $this->relatedto ) && !isset( $this->relatedto[$propix] ) && ( 0 < count( $this->relatedto )) && ( $propix < end( array_keys( $this->relatedto ))))
|
5251 |
+
$propix++;
|
5252 |
+
if( !isset( $this->relatedto[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5253 |
+
return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
|
5254 |
+
break;
|
5255 |
+
case 'REPEAT':
|
5256 |
+
if( !empty( $this->repeat['value'] ) || ( isset( $this->repeat['value'] ) && ( '0' == $this->repeat['value'] ))) return ( $inclParam ) ? $this->repeat : $this->repeat['value'];
|
5257 |
+
break;
|
5258 |
+
case 'REQUEST-STATUS':
|
5259 |
+
while( is_array( $this->requeststatus ) && !isset( $this->requeststatus[$propix] ) && ( 0 < count( $this->requeststatus )) && ( $propix < end( array_keys( $this->requeststatus ))))
|
5260 |
+
$propix++;
|
5261 |
+
if( !isset( $this->requeststatus[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5262 |
+
return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
|
5263 |
+
break;
|
5264 |
+
case 'RESOURCES':
|
5265 |
+
while( is_array( $this->resources ) && !isset( $this->resources[$propix] ) && ( 0 < count( $this->resources )) && ( $propix < end( array_keys( $this->resources ))))
|
5266 |
+
$propix++;
|
5267 |
+
if( !isset( $this->resources[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5268 |
+
return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
|
5269 |
+
break;
|
5270 |
+
case 'RRULE':
|
5271 |
+
while( is_array( $this->rrule ) && !isset( $this->rrule[$propix] ) && ( 0 < count( $this->rrule )) && ( $propix < end( array_keys( $this->rrule ))))
|
5272 |
+
$propix++;
|
5273 |
+
if( !isset( $this->rrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5274 |
+
return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
|
5275 |
+
break;
|
5276 |
+
case 'SEQUENCE':
|
5277 |
+
if( isset( $this->sequence['value'] ) && ( isset( $this->sequence['value'] ) && ( '0' <= $this->sequence['value'] ))) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
|
5278 |
+
break;
|
5279 |
+
case 'STATUS':
|
5280 |
+
if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
|
5281 |
+
break;
|
5282 |
+
case 'SUMMARY':
|
5283 |
+
if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
|
5284 |
+
break;
|
5285 |
+
case 'TRANSP':
|
5286 |
+
if( !empty( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value'];
|
5287 |
+
break;
|
5288 |
+
case 'TRIGGER':
|
5289 |
+
if( !empty( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value'];
|
5290 |
+
break;
|
5291 |
+
case 'TZID':
|
5292 |
+
if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
|
5293 |
+
break;
|
5294 |
+
case 'TZNAME':
|
5295 |
+
while( is_array( $this->tzname ) && !isset( $this->tzname[$propix] ) && ( 0 < count( $this->tzname )) && ( $propix < end( array_keys( $this->tzname ))))
|
5296 |
+
$propix++;
|
5297 |
+
if( !isset( $this->tzname[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
|
5298 |
+
return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
|
5299 |
+
break;
|
5300 |
+
case 'TZOFFSETFROM':
|
5301 |
+
if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
|
5302 |
+
break;
|
5303 |
+
case 'TZOFFSETTO':
|
5304 |
+
if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
|
5305 |
+
break;
|
5306 |
+
case 'TZURL':
|
5307 |
+
if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
|
5308 |
+
break;
|
5309 |
+
case 'UID':
|
5310 |
+
if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
|
5311 |
+
return FALSE;
|
5312 |
+
if( empty( $this->uid['value'] ))
|
5313 |
+
$this->_makeuid();
|
5314 |
+
return ( $inclParam ) ? $this->uid : $this->uid['value'];
|
5315 |
+
break;
|
5316 |
+
case 'URL':
|
5317 |
+
if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
|
5318 |
+
break;
|
5319 |
+
default:
|
5320 |
+
if( $propName != 'X-PROP' ) {
|
5321 |
+
if( !isset( $this->xprop[$propName] )) return FALSE;
|
5322 |
+
return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
|
5323 |
+
: array( $propName, $this->xprop[$propName]['value'] );
|
5324 |
+
}
|
5325 |
+
else {
|
5326 |
+
if( empty( $this->xprop )) return FALSE;
|
5327 |
+
$xpropno = 0;
|
5328 |
+
foreach( $this->xprop as $xpropkey => $xpropvalue ) {
|
5329 |
+
if( $propix == $xpropno )
|
5330 |
+
return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
|
5331 |
+
: array( $xpropkey, $this->xprop[$xpropkey]['value'] );
|
5332 |
+
else
|
5333 |
+
$xpropno++;
|
5334 |
+
}
|
5335 |
+
return FALSE; // not found ??
|
5336 |
+
}
|
5337 |
+
}
|
5338 |
+
return FALSE;
|
5339 |
+
}
|
5340 |
+
/**
|
5341 |
+
* returns calendar property unique values for 'CATEGORIES', 'RESOURCES' or 'ATTENDEE' and each number of ocurrence
|
5342 |
+
*
|
5343 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5344 |
+
* @since 2.8.8 - 2011-04-13
|
5345 |
+
* @param string $propName
|
5346 |
+
* @param array $output, incremented result array
|
5347 |
+
*/
|
5348 |
+
function _getProperties( $propName, & $output ) {
|
5349 |
+
if( !in_array( strtoupper( $propName ), array( 'ATTENDEE', 'CATEGORIES', 'RESOURCES' )))
|
5350 |
+
return output;
|
5351 |
+
while( FALSE !== ( $content = $this->getProperty( $propName ))) {
|
5352 |
+
if( is_array( $content )) {
|
5353 |
+
foreach( $content as $part ) {
|
5354 |
+
if( FALSE !== strpos( $part, ',' )) {
|
5355 |
+
$part = explode( ',', $part );
|
5356 |
+
foreach( $part as $thePart ) {
|
5357 |
+
$thePart = trim( $thePart );
|
5358 |
+
if( !empty( $thePart )) {
|
5359 |
+
if( !isset( $output[$thePart] ))
|
5360 |
+
$output[$thePart] = 1;
|
5361 |
+
else
|
5362 |
+
$output[$thePart] += 1;
|
5363 |
+
}
|
5364 |
+
}
|
5365 |
+
}
|
5366 |
+
else {
|
5367 |
+
$part = trim( $part );
|
5368 |
+
if( !isset( $output[$part] ))
|
5369 |
+
$output[$part] = 1;
|
5370 |
+
else
|
5371 |
+
$output[$part] += 1;
|
5372 |
+
}
|
5373 |
+
}
|
5374 |
+
}
|
5375 |
+
elseif( FALSE !== strpos( $content, ',' )) {
|
5376 |
+
$content = explode( ',', $content );
|
5377 |
+
foreach( $content as $thePart ) {
|
5378 |
+
$thePart = trim( $thePart );
|
5379 |
+
if( !empty( $thePart )) {
|
5380 |
+
if( !isset( $output[$thePart] ))
|
5381 |
+
$output[$thePart] = 1;
|
5382 |
+
else
|
5383 |
+
$output[$thePart] += 1;
|
5384 |
+
}
|
5385 |
+
}
|
5386 |
+
}
|
5387 |
+
else {
|
5388 |
+
$content = trim( $content );
|
5389 |
+
if( !empty( $content )) {
|
5390 |
+
if( !isset( $output[$content] ))
|
5391 |
+
$output[$content] = 1;
|
5392 |
+
else
|
5393 |
+
$output[$content] += 1;
|
5394 |
+
}
|
5395 |
+
}
|
5396 |
+
}
|
5397 |
+
ksort( $output );
|
5398 |
+
return $output;
|
5399 |
+
}
|
5400 |
+
/**
|
5401 |
+
* general component property setting
|
5402 |
+
*
|
5403 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5404 |
+
* @since 2.5.1 - 2008-11-05
|
5405 |
+
* @param mixed $args variable number of function arguments,
|
5406 |
+
* first argument is ALWAYS component name,
|
5407 |
+
* second ALWAYS component value!
|
5408 |
+
* @return void
|
5409 |
+
*/
|
5410 |
+
function setProperty() {
|
5411 |
+
$numargs = func_num_args();
|
5412 |
+
if( 1 > $numargs ) return FALSE;
|
5413 |
+
$arglist = func_get_args();
|
5414 |
+
if( $this->_notExistProp( $arglist[0] )) return FALSE;
|
5415 |
+
if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
|
5416 |
+
return FALSE;
|
5417 |
+
$arglist[0] = strtoupper( $arglist[0] );
|
5418 |
+
for( $argix=$numargs; $argix < 12; $argix++ ) {
|
5419 |
+
if( !isset( $arglist[$argix] ))
|
5420 |
+
$arglist[$argix] = null;
|
5421 |
+
}
|
5422 |
+
switch( $arglist[0] ) {
|
5423 |
+
case 'ACTION':
|
5424 |
+
return $this->setAction( $arglist[1], $arglist[2] );
|
5425 |
+
case 'ATTACH':
|
5426 |
+
return $this->setAttach( $arglist[1], $arglist[2], $arglist[3] );
|
5427 |
+
case 'ATTENDEE':
|
5428 |
+
return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
|
5429 |
+
case 'CATEGORIES':
|
5430 |
+
return $this->setCategories( $arglist[1], $arglist[2], $arglist[3] );
|
5431 |
+
case 'CLASS':
|
5432 |
+
return $this->setClass( $arglist[1], $arglist[2] );
|
5433 |
+
case 'COMMENT':
|
5434 |
+
return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
|
5435 |
+
case 'COMPLETED':
|
5436 |
+
return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
|
5437 |
+
case 'CONTACT':
|
5438 |
+
return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
|
5439 |
+
case 'CREATED':
|
5440 |
+
return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
|
5441 |
+
case 'DESCRIPTION':
|
5442 |
+
return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
|
5443 |
+
case 'DTEND':
|
5444 |
+
return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
|
5445 |
+
case 'DTSTAMP':
|
5446 |
+
return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
|
5447 |
+
case 'DTSTART':
|
5448 |
+
return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
|
5449 |
+
case 'DUE':
|
5450 |
+
return $this->setDue( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
|
5451 |
+
case 'DURATION':
|
5452 |
+
return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
|
5453 |
+
case 'EXDATE':
|
5454 |
+
return $this->setExdate( $arglist[1], $arglist[2], $arglist[3] );
|
5455 |
+
case 'EXRULE':
|
5456 |
+
return $this->setExrule( $arglist[1], $arglist[2], $arglist[3] );
|
5457 |
+
case 'FREEBUSY':
|
5458 |
+
return $this->setFreebusy( $arglist[1], $arglist[2], $arglist[3], $arglist[4] );
|
5459 |
+
case 'GEO':
|
5460 |
+
return $this->setGeo( $arglist[1], $arglist[2], $arglist[3] );
|
5461 |
+
case 'LAST-MODIFIED':
|
5462 |
+
return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
|
5463 |
+
case 'LOCATION':
|
5464 |
+
return $this->setLocation( $arglist[1], $arglist[2] );
|
5465 |
+
case 'ORGANIZER':
|
5466 |
+
return $this->setOrganizer( $arglist[1], $arglist[2] );
|
5467 |
+
case 'PERCENT-COMPLETE':
|
5468 |
+
return $this->setPercentComplete( $arglist[1], $arglist[2] );
|
5469 |
+
case 'PRIORITY':
|
5470 |
+
return $this->setPriority( $arglist[1], $arglist[2] );
|
5471 |
+
case 'RDATE':
|
5472 |
+
return $this->setRdate( $arglist[1], $arglist[2], $arglist[3] );
|
5473 |
+
case 'RECURRENCE-ID':
|
5474 |
+
return $this->setRecurrenceid( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
|
5475 |
+
case 'RELATED-TO':
|
5476 |
+
return $this->setRelatedTo( $arglist[1], $arglist[2], $arglist[3] );
|
5477 |
+
case 'REPEAT':
|
5478 |
+
return $this->setRepeat( $arglist[1], $arglist[2] );
|
5479 |
+
case 'REQUEST-STATUS':
|
5480 |
+
return $this->setRequestStatus( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] );
|
5481 |
+
case 'RESOURCES':
|
5482 |
+
return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
|
5483 |
+
case 'RRULE':
|
5484 |
+
return $this->setRrule( $arglist[1], $arglist[2], $arglist[3] );
|
5485 |
+
case 'SEQUENCE':
|
5486 |
+
return $this->setSequence( $arglist[1], $arglist[2] );
|
5487 |
+
case 'STATUS':
|
5488 |
+
return $this->setStatus( $arglist[1], $arglist[2] );
|
5489 |
+
case 'SUMMARY':
|
5490 |
+
return $this->setSummary( $arglist[1], $arglist[2] );
|
5491 |
+
case 'TRANSP':
|
5492 |
+
return $this->setTransp( $arglist[1], $arglist[2] );
|
5493 |
+
case 'TRIGGER':
|
5494 |
+
return $this->setTrigger( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8], $arglist[9], $arglist[10], $arglist[11] );
|
5495 |
+
case 'TZID':
|
5496 |
+
return $this->setTzid( $arglist[1], $arglist[2] );
|
5497 |
+
case 'TZNAME':
|
5498 |
+
return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
|
5499 |
+
case 'TZOFFSETFROM':
|
5500 |
+
return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
|
5501 |
+
case 'TZOFFSETTO':
|
5502 |
+
return $this->setTzoffsetto( $arglist[1], $arglist[2] );
|
5503 |
+
case 'TZURL':
|
5504 |
+
return $this->setTzurl( $arglist[1], $arglist[2] );
|
5505 |
+
case 'UID':
|
5506 |
+
return $this->setUid( $arglist[1], $arglist[2] );
|
5507 |
+
case 'URL':
|
5508 |
+
return $this->setUrl( $arglist[1], $arglist[2] );
|
5509 |
+
default:
|
5510 |
+
return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
|
5511 |
+
}
|
5512 |
+
return FALSE;
|
5513 |
+
}
|
5514 |
+
/*********************************************************************************/
|
5515 |
+
/**
|
5516 |
+
* parse component unparsed data into properties
|
5517 |
+
*
|
5518 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5519 |
+
* @since 2.8.2 - 2011-05-21
|
5520 |
+
* @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings
|
5521 |
+
* @return bool FALSE if error occurs during parsing
|
5522 |
+
*
|
5523 |
+
*/
|
5524 |
+
function parse( $unparsedtext=null ) {
|
5525 |
+
if( !empty( $unparsedtext )) {
|
5526 |
+
$nl = $this->getConfig( 'nl' );
|
5527 |
+
if( is_array( $unparsedtext ))
|
5528 |
+
$unparsedtext = implode( '\n'.$nl, $unparsedtext );
|
5529 |
+
/* fix line folding */
|
5530 |
+
$eolchars = array( "\r\n", "\n\r", "\n", "\r" ); // check all line endings
|
5531 |
+
$EOLmark = FALSE;
|
5532 |
+
foreach( $eolchars as $eolchar ) {
|
5533 |
+
if( !$EOLmark && ( FALSE !== strpos( $unparsedtext, $eolchar ))) {
|
5534 |
+
$unparsedtext = str_replace( $eolchar." ", '', $unparsedtext );
|
5535 |
+
$unparsedtext = str_replace( $eolchar."\t", '', $unparsedtext );
|
5536 |
+
if( $eolchar != $nl )
|
5537 |
+
$unparsedtext = str_replace( $eolchar, $nl, $unparsedtext );
|
5538 |
+
$EOLmark = TRUE;
|
5539 |
+
}
|
5540 |
+
}
|
5541 |
+
$tmp = explode( $nl, $unparsedtext );
|
5542 |
+
$unparsedtext = array();
|
5543 |
+
foreach( $tmp as $tmpr )
|
5544 |
+
if( !empty( $tmpr ))
|
5545 |
+
$unparsedtext[] = $tmpr;
|
5546 |
+
}
|
5547 |
+
elseif( !isset( $this->unparsed ))
|
5548 |
+
$unparsedtext = array();
|
5549 |
+
else
|
5550 |
+
$unparsedtext = $this->unparsed;
|
5551 |
+
$this->unparsed = array();
|
5552 |
+
$comp = & $this;
|
5553 |
+
$config = $this->getConfig();
|
5554 |
+
foreach ( $unparsedtext as $line ) {
|
5555 |
+
// echo $comp->objName.": $line<br />"; // test ###
|
5556 |
+
if( in_array( strtoupper( substr( $line, 0, 6 )), array( 'END:VA', 'END:ST', 'END:DA' )))
|
5557 |
+
$this->components[] = $comp->copy();
|
5558 |
+
elseif( 'END:' == strtoupper( substr( $line, 0, 4 )))
|
5559 |
+
break;
|
5560 |
+
elseif( 'BEGIN:VALARM' == strtoupper( substr( $line, 0, 12 )))
|
5561 |
+
$comp = new valarm( $config);
|
5562 |
+
elseif( 'BEGIN:STANDARD' == strtoupper( substr( $line, 0, 14 )))
|
5563 |
+
$comp = new vtimezone( 'standard', $config );
|
5564 |
+
elseif( 'BEGIN:DAYLIGHT' == strtoupper( substr( $line, 0, 14 )))
|
5565 |
+
$comp = new vtimezone( 'daylight', $config );
|
5566 |
+
elseif( 'BEGIN:' == strtoupper( substr( $line, 0, 6 )))
|
5567 |
+
continue;
|
5568 |
+
else {
|
5569 |
+
$comp->unparsed[] = $line;
|
5570 |
+
// echo $comp->objName.": $line<br />\n"; // test ###
|
5571 |
+
}
|
5572 |
+
}
|
5573 |
+
unset( $config );
|
5574 |
+
// echo $this->objName.'<br />'.var_export( $this->unparsed, TRUE )."<br />\n"; // test ###
|
5575 |
+
/* concatenate property values spread over several lines */
|
5576 |
+
$lastix = -1;
|
5577 |
+
$propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed'
|
5578 |
+
, 'contact', 'class', 'created', 'description', 'dtend', 'dtstart'
|
5579 |
+
, 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo'
|
5580 |
+
, 'last-modified', 'location', 'organizer', 'percent-complete'
|
5581 |
+
, 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat'
|
5582 |
+
, 'request-status', 'resources', 'rrule', 'sequence', 'status'
|
5583 |
+
, 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
|
5584 |
+
, 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
|
5585 |
+
$proprows = array();
|
5586 |
+
foreach( $this->unparsed as $line ) {
|
5587 |
+
$newProp = FALSE;
|
5588 |
+
foreach ( $propnames as $propname ) {
|
5589 |
+
if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
|
5590 |
+
$newProp = TRUE;
|
5591 |
+
break;
|
5592 |
+
}
|
5593 |
+
}
|
5594 |
+
if( $newProp ) {
|
5595 |
+
if( -1 < $lastix )
|
5596 |
+
$proprows[$lastix] = $proprows[$lastix];
|
5597 |
+
$newProp = FALSE;
|
5598 |
+
$lastix++;
|
5599 |
+
$proprows[$lastix] = $line;
|
5600 |
+
}
|
5601 |
+
else
|
5602 |
+
$proprows[$lastix] .= '!"#¤%&/()=?'.$line;
|
5603 |
+
}
|
5604 |
+
/* parse each property 'line' */
|
5605 |
+
foreach( $proprows as $line ) {
|
5606 |
+
$line = str_replace( '!"#¤%&/()=? ', '', $line );
|
5607 |
+
$line = str_replace( '!"#¤%&/()=?', '', $line );
|
5608 |
+
if( '\n' == substr( $line, -2 ))
|
5609 |
+
$line = substr( $line, 0, strlen( $line ) - 2 );
|
5610 |
+
/* get propname, (problem with x-properties, otherwise in previous loop) */
|
5611 |
+
$cix = $propname = null;
|
5612 |
+
for( $cix=0, $clen = strlen( $line ); $cix < $clen; $cix++ ) {
|
5613 |
+
if( in_array( $line[$cix], array( ':', ';' )))
|
5614 |
+
break;
|
5615 |
+
else {
|
5616 |
+
$propname .= $line[$cix];
|
5617 |
+
}
|
5618 |
+
}
|
5619 |
+
if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) {
|
5620 |
+
$propname2 = $propname;
|
5621 |
+
$propname = 'X-';
|
5622 |
+
}
|
5623 |
+
/* rest of the line is opt.params and value */
|
5624 |
+
$line = substr( $line, $cix );
|
5625 |
+
/* separate attributes from value */
|
5626 |
+
$attr = array();
|
5627 |
+
$attrix = -1;
|
5628 |
+
$clen = strlen( $line );
|
5629 |
+
for( $cix=0; $cix < $clen; $cix++ ) {
|
5630 |
+
if(( ':' == $line[$cix] ) &&
|
5631 |
+
( '://' != substr( $line, $cix, 3 )) &&
|
5632 |
+
( !in_array( strtolower( substr( $line, $cix - 3, 4 )), array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ))) &&
|
5633 |
+
( !in_array( strtolower( substr( $line, $cix - 4, 5 )), array( 'crid:', 'news:', 'pres:' ))) &&
|
5634 |
+
( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
|
5635 |
+
$attrEnd = TRUE;
|
5636 |
+
if(( $cix < ( $clen - 4 )) &&
|
5637 |
+
ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
|
5638 |
+
for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
|
5639 |
+
if( '://' == substr( $line, $c2ix - 2, 3 )) {
|
5640 |
+
$attrEnd = FALSE;
|
5641 |
+
break; // an URI with a portnr!!
|
5642 |
+
}
|
5643 |
+
}
|
5644 |
+
}
|
5645 |
+
if( $attrEnd) {
|
5646 |
+
$line = substr( $line, $cix + 1 );
|
5647 |
+
break;
|
5648 |
+
}
|
5649 |
+
}
|
5650 |
+
if( ';' == $line[$cix] )
|
5651 |
+
$attr[++$attrix] = null;
|
5652 |
+
else
|
5653 |
+
$attr[$attrix] .= $line[$cix];
|
5654 |
+
}
|
5655 |
+
/* make attributes in array format */
|
5656 |
+
$propattr = array();
|
5657 |
+
foreach( $attr as $attribute ) {
|
5658 |
+
$attrsplit = explode( '=', $attribute, 2 );
|
5659 |
+
if( 1 < count( $attrsplit ))
|
5660 |
+
$propattr[$attrsplit[0]] = $attrsplit[1];
|
5661 |
+
else
|
5662 |
+
$propattr[] = $attribute;
|
5663 |
+
}
|
5664 |
+
/* call setProperty( $propname.. . */
|
5665 |
+
switch( strtoupper( $propname )) {
|
5666 |
+
case 'ATTENDEE':
|
5667 |
+
foreach( $propattr as $pix => $attr ) {
|
5668 |
+
$attr2 = explode( ',', $attr );
|
5669 |
+
if( 1 < count( $attr2 ))
|
5670 |
+
$propattr[$pix] = $attr2;
|
5671 |
+
}
|
5672 |
+
$this->setProperty( $propname, $line, $propattr );
|
5673 |
+
break;
|
5674 |
+
case 'CATEGORIES':
|
5675 |
+
case 'RESOURCES':
|
5676 |
+
if( FALSE !== strpos( $line, ',' )) {
|
5677 |
+
$content = explode( ',', $line );
|
5678 |
+
$clen = count( $content );
|
5679 |
+
for( $cix = 0; $cix < $clen; $cix++ ) {
|
5680 |
+
if( "\\" == substr($content[$cix], -1)) {
|
5681 |
+
$content[$cix] .= ','.$content[$cix + 1];
|
5682 |
+
unset($content[$cix + 1]);
|
5683 |
+
$cix++;
|
5684 |
+
}
|
5685 |
+
}
|
5686 |
+
if( 1 < count( $content )) {
|
5687 |
+
$content = array_values( $content );
|
5688 |
+
foreach( $content as $cix => $contentPart )
|
5689 |
+
$content[$cix] = calendarComponent::_strunrep( $contentPart );
|
5690 |
+
$this->setProperty( $propname, $content, $propattr );
|
5691 |
+
break;
|
5692 |
+
}
|
5693 |
+
else
|
5694 |
+
$line = reset( $content );
|
5695 |
+
}
|
5696 |
+
case 'X-':
|
5697 |
+
$propname = ( isset( $propname2 )) ? $propname2 : $propname;
|
5698 |
+
case 'COMMENT':
|
5699 |
+
case 'CONTACT':
|
5700 |
+
case 'DESCRIPTION':
|
5701 |
+
case 'LOCATION':
|
5702 |
+
case 'SUMMARY':
|
5703 |
+
if( empty( $line ))
|
5704 |
+
$propattr = null;
|
5705 |
+
$this->setProperty( $propname, calendarComponent::_strunrep( $line ), $propattr );
|
5706 |
+
unset( $propname2 );
|
5707 |
+
break;
|
5708 |
+
case 'REQUEST-STATUS':
|
5709 |
+
$values = explode( ';', $line, 3 );
|
5710 |
+
$values[1] = ( !isset( $values[1] )) ? null : calendarComponent::_strunrep( $values[1] );
|
5711 |
+
$values[2] = ( !isset( $values[2] )) ? null : calendarComponent::_strunrep( $values[2] );
|
5712 |
+
$this->setProperty( $propname
|
5713 |
+
, $values[0] // statcode
|
5714 |
+
, $values[1] // statdesc
|
5715 |
+
, $values[2] // extdata
|
5716 |
+
, $propattr );
|
5717 |
+
break;
|
5718 |
+
case 'FREEBUSY':
|
5719 |
+
$fbtype = ( isset( $propattr['FBTYPE'] )) ? $propattr['FBTYPE'] : ''; // force setting default, if missing
|
5720 |
+
unset( $propattr['FBTYPE'] );
|
5721 |
+
$values = explode( ',', $line );
|
5722 |
+
foreach( $values as $vix => $value ) {
|
5723 |
+
$value2 = explode( '/', $value );
|
5724 |
+
if( 1 < count( $value2 ))
|
5725 |
+
$values[$vix] = $value2;
|
5726 |
+
}
|
5727 |
+
$this->setProperty( $propname, $fbtype, $values, $propattr );
|
5728 |
+
break;
|
5729 |
+
case 'GEO':
|
5730 |
+
$value = explode( ';', $line, 2 );
|
5731 |
+
if( 2 > count( $value ))
|
5732 |
+
$value[1] = null;
|
5733 |
+
$this->setProperty( $propname, $value[0], $value[1], $propattr );
|
5734 |
+
break;
|
5735 |
+
case 'EXDATE':
|
5736 |
+
$values = ( !empty( $line )) ? explode( ',', $line ) : null;
|
5737 |
+
$this->setProperty( $propname, $values, $propattr );
|
5738 |
+
break;
|
5739 |
+
case 'RDATE':
|
5740 |
+
if( empty( $line )) {
|
5741 |
+
$this->setProperty( $propname, $line, $propattr );
|
5742 |
+
break;
|
5743 |
+
}
|
5744 |
+
$values = explode( ',', $line );
|
5745 |
+
foreach( $values as $vix => $value ) {
|
5746 |
+
$value2 = explode( '/', $value );
|
5747 |
+
if( 1 < count( $value2 ))
|
5748 |
+
$values[$vix] = $value2;
|
5749 |
+
}
|
5750 |
+
$this->setProperty( $propname, $values, $propattr );
|
5751 |
+
break;
|
5752 |
+
case 'EXRULE':
|
5753 |
+
case 'RRULE':
|
5754 |
+
$values = explode( ';', $line );
|
5755 |
+
$recur = array();
|
5756 |
+
foreach( $values as $value2 ) {
|
5757 |
+
if( empty( $value2 ))
|
5758 |
+
continue; // ;-char in ending position ???
|
5759 |
+
$value3 = explode( '=', $value2, 2 );
|
5760 |
+
$rulelabel = strtoupper( $value3[0] );
|
5761 |
+
switch( $rulelabel ) {
|
5762 |
+
case 'BYDAY': {
|
5763 |
+
$value4 = explode( ',', $value3[1] );
|
5764 |
+
if( 1 < count( $value4 )) {
|
5765 |
+
foreach( $value4 as $v5ix => $value5 ) {
|
5766 |
+
$value6 = array();
|
5767 |
+
$dayno = $dayname = null;
|
5768 |
+
$value5 = trim( (string) $value5 );
|
5769 |
+
if(( ctype_alpha( substr( $value5, -1 ))) &&
|
5770 |
+
( ctype_alpha( substr( $value5, -2, 1 )))) {
|
5771 |
+
$dayname = substr( $value5, -2, 2 );
|
5772 |
+
if( 2 < strlen( $value5 ))
|
5773 |
+
$dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
|
5774 |
+
}
|
5775 |
+
if( $dayno )
|
5776 |
+
$value6[] = $dayno;
|
5777 |
+
if( $dayname )
|
5778 |
+
$value6['DAY'] = $dayname;
|
5779 |
+
$value4[$v5ix] = $value6;
|
5780 |
+
}
|
5781 |
+
}
|
5782 |
+
else {
|
5783 |
+
$value4 = array();
|
5784 |
+
$dayno = $dayname = null;
|
5785 |
+
$value5 = trim( (string) $value3[1] );
|
5786 |
+
if(( ctype_alpha( substr( $value5, -1 ))) &&
|
5787 |
+
( ctype_alpha( substr( $value5, -2, 1 )))) {
|
5788 |
+
$dayname = substr( $value5, -2, 2 );
|
5789 |
+
if( 2 < strlen( $value5 ))
|
5790 |
+
$dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
|
5791 |
+
}
|
5792 |
+
if( $dayno )
|
5793 |
+
$value4[] = $dayno;
|
5794 |
+
if( $dayname )
|
5795 |
+
$value4['DAY'] = $dayname;
|
5796 |
+
}
|
5797 |
+
$recur[$rulelabel] = $value4;
|
5798 |
+
break;
|
5799 |
+
}
|
5800 |
+
default: {
|
5801 |
+
$value4 = explode( ',', $value3[1] );
|
5802 |
+
if( 1 < count( $value4 ))
|
5803 |
+
$value3[1] = $value4;
|
5804 |
+
$recur[$rulelabel] = $value3[1];
|
5805 |
+
break;
|
5806 |
+
}
|
5807 |
+
} // end - switch $rulelabel
|
5808 |
+
} // end - foreach( $values.. .
|
5809 |
+
$this->setProperty( $propname, $recur, $propattr );
|
5810 |
+
break;
|
5811 |
+
case 'ACTION':
|
5812 |
+
case 'CLASSIFICATION':
|
5813 |
+
case 'STATUS':
|
5814 |
+
case 'TRANSP':
|
5815 |
+
case 'UID':
|
5816 |
+
case 'TZID':
|
5817 |
+
case 'RELATED-TO':
|
5818 |
+
case 'TZNAME':
|
5819 |
+
$line = calendarComponent::_strunrep( $line );
|
5820 |
+
default:
|
5821 |
+
$this->setProperty( $propname, $line, $propattr );
|
5822 |
+
break;
|
5823 |
+
} // end switch( $propname.. .
|
5824 |
+
} // end - foreach( $proprows.. .
|
5825 |
+
unset( $unparsedtext, $this->unparsed, $proprows );
|
5826 |
+
if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) {
|
5827 |
+
$ckeys = array_keys( $this->components );
|
5828 |
+
foreach( $ckeys as $ckey ) {
|
5829 |
+
if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) {
|
5830 |
+
$this->components[$ckey]->parse();
|
5831 |
+
}
|
5832 |
+
}
|
5833 |
+
}
|
5834 |
+
return TRUE;
|
5835 |
+
}
|
5836 |
+
/*********************************************************************************/
|
5837 |
+
/*********************************************************************************/
|
5838 |
+
/**
|
5839 |
+
* return a copy of this component
|
5840 |
+
*
|
5841 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5842 |
+
* @since 2.8.8 - 2011-03-15
|
5843 |
+
* @return object
|
5844 |
+
*/
|
5845 |
+
function copy() {
|
5846 |
+
$serialized_contents = serialize( $this );
|
5847 |
+
$copy = unserialize( $serialized_contents );
|
5848 |
+
return $copy;
|
5849 |
+
}
|
5850 |
+
/*********************************************************************************/
|
5851 |
+
/*********************************************************************************/
|
5852 |
+
/**
|
5853 |
+
* delete calendar subcomponent from component container
|
5854 |
+
*
|
5855 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5856 |
+
* @since 2.8.8 - 2011-03-15
|
5857 |
+
* @param mixed $arg1 ordno / component type / component uid
|
5858 |
+
* @param mixed $arg2 optional, ordno if arg1 = component type
|
5859 |
+
* @return void
|
5860 |
+
*/
|
5861 |
+
function deleteComponent( $arg1, $arg2=FALSE ) {
|
5862 |
+
if( !isset( $this->components )) return FALSE;
|
5863 |
+
$argType = $index = null;
|
5864 |
+
if ( ctype_digit( (string) $arg1 )) {
|
5865 |
+
$argType = 'INDEX';
|
5866 |
+
$index = (int) $arg1 - 1;
|
5867 |
+
}
|
5868 |
+
elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
|
5869 |
+
$argType = strtolower( $arg1 );
|
5870 |
+
$index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
|
5871 |
+
}
|
5872 |
+
$cix2dC = 0;
|
5873 |
+
foreach ( $this->components as $cix => $component) {
|
5874 |
+
if( empty( $component )) continue;
|
5875 |
+
if(( 'INDEX' == $argType ) && ( $index == $cix )) {
|
5876 |
+
unset( $this->components[$cix] );
|
5877 |
+
return TRUE;
|
5878 |
+
}
|
5879 |
+
elseif( $argType == $component->objName ) {
|
5880 |
+
if( $index == $cix2dC ) {
|
5881 |
+
unset( $this->components[$cix] );
|
5882 |
+
return TRUE;
|
5883 |
+
}
|
5884 |
+
$cix2dC++;
|
5885 |
+
}
|
5886 |
+
elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
|
5887 |
+
unset( $this->components[$cix] );
|
5888 |
+
return TRUE;
|
5889 |
+
}
|
5890 |
+
}
|
5891 |
+
return FALSE;
|
5892 |
+
}
|
5893 |
+
/**
|
5894 |
+
* get calendar component subcomponent from component container
|
5895 |
+
*
|
5896 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5897 |
+
* @since 2.8.8 - 2011-03-15
|
5898 |
+
* @param mixed $arg1 optional, ordno/component type/ component uid
|
5899 |
+
* @param mixed $arg2 optional, ordno if arg1 = component type
|
5900 |
+
* @return object
|
5901 |
+
*/
|
5902 |
+
function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
|
5903 |
+
if( !isset( $this->components )) return FALSE;
|
5904 |
+
$index = $argType = null;
|
5905 |
+
if ( !$arg1 ) {
|
5906 |
+
$argType = 'INDEX';
|
5907 |
+
$index = $this->compix['INDEX'] =
|
5908 |
+
( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
|
5909 |
+
}
|
5910 |
+
elseif ( ctype_digit( (string) $arg1 )) {
|
5911 |
+
$argType = 'INDEX';
|
5912 |
+
$index = (int) $arg1;
|
5913 |
+
unset( $this->compix );
|
5914 |
+
}
|
5915 |
+
elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
|
5916 |
+
unset( $this->compix['INDEX'] );
|
5917 |
+
$argType = strtolower( $arg1 );
|
5918 |
+
if( !$arg2 )
|
5919 |
+
$index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
|
5920 |
+
else
|
5921 |
+
$index = (int) $arg2;
|
5922 |
+
}
|
5923 |
+
$index -= 1;
|
5924 |
+
$ckeys = array_keys( $this->components );
|
5925 |
+
if( !empty( $index) && ( $index > end( $ckeys )))
|
5926 |
+
return FALSE;
|
5927 |
+
$cix2gC = 0;
|
5928 |
+
foreach( $this->components as $cix => $component ) {
|
5929 |
+
if( empty( $component )) continue;
|
5930 |
+
if(( 'INDEX' == $argType ) && ( $index == $cix ))
|
5931 |
+
return $component->copy();
|
5932 |
+
elseif( $argType == $component->objName ) {
|
5933 |
+
if( $index == $cix2gC )
|
5934 |
+
return $component->copy();
|
5935 |
+
$cix2gC++;
|
5936 |
+
}
|
5937 |
+
elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' )))
|
5938 |
+
return $component->copy();
|
5939 |
+
}
|
5940 |
+
/* not found.. . */
|
5941 |
+
unset( $this->compix );
|
5942 |
+
return false;
|
5943 |
+
}
|
5944 |
+
/**
|
5945 |
+
* add calendar component as subcomponent to container for subcomponents
|
5946 |
+
*
|
5947 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5948 |
+
* @since 1.x.x - 2007-04-24
|
5949 |
+
* @param object $component calendar component
|
5950 |
+
* @return void
|
5951 |
+
*/
|
5952 |
+
function addSubComponent ( $component ) {
|
5953 |
+
$this->setComponent( $component );
|
5954 |
+
}
|
5955 |
+
/**
|
5956 |
+
* create new calendar component subcomponent, already included within component
|
5957 |
+
*
|
5958 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5959 |
+
* @since 2.6.33 - 2011-01-03
|
5960 |
+
* @param string $compType subcomponent type
|
5961 |
+
* @return object (reference)
|
5962 |
+
*/
|
5963 |
+
function & newComponent( $compType ) {
|
5964 |
+
$config = $this->getConfig();
|
5965 |
+
$keys = array_keys( $this->components );
|
5966 |
+
$ix = end( $keys) + 1;
|
5967 |
+
switch( strtoupper( $compType )) {
|
5968 |
+
case 'ALARM':
|
5969 |
+
case 'VALARM':
|
5970 |
+
$this->components[$ix] = new valarm( $config );
|
5971 |
+
break;
|
5972 |
+
case 'STANDARD':
|
5973 |
+
array_unshift( $this->components, new vtimezone( 'STANDARD', $config ));
|
5974 |
+
$ix = 0;
|
5975 |
+
break;
|
5976 |
+
case 'DAYLIGHT':
|
5977 |
+
$this->components[$ix] = new vtimezone( 'DAYLIGHT', $config );
|
5978 |
+
break;
|
5979 |
+
default:
|
5980 |
+
return FALSE;
|
5981 |
+
}
|
5982 |
+
return $this->components[$ix];
|
5983 |
+
}
|
5984 |
+
/**
|
5985 |
+
* add calendar component as subcomponent to container for subcomponents
|
5986 |
+
*
|
5987 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
5988 |
+
* @since 2.8.8 - 2011-03-15
|
5989 |
+
* @param object $component calendar component
|
5990 |
+
* @param mixed $arg1 optional, ordno/component type/ component uid
|
5991 |
+
* @param mixed $arg2 optional, ordno if arg1 = component type
|
5992 |
+
* @return bool
|
5993 |
+
*/
|
5994 |
+
function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
|
5995 |
+
if( !isset( $this->components )) return FALSE;
|
5996 |
+
$component->setConfig( $this->getConfig(), FALSE, TRUE );
|
5997 |
+
if( !in_array( $component->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
|
5998 |
+
/* make sure dtstamp and uid is set */
|
5999 |
+
$dummy = $component->getProperty( 'dtstamp' );
|
6000 |
+
$dummy = $component->getProperty( 'uid' );
|
6001 |
+
}
|
6002 |
+
if( !$arg1 ) { // plain insert, last in chain
|
6003 |
+
$this->components[] = $component->copy();
|
6004 |
+
return TRUE;
|
6005 |
+
}
|
6006 |
+
$argType = $index = null;
|
6007 |
+
if ( ctype_digit( (string) $arg1 )) { // index insert/replace
|
6008 |
+
$argType = 'INDEX';
|
6009 |
+
$index = (int) $arg1 - 1;
|
6010 |
+
}
|
6011 |
+
elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) {
|
6012 |
+
$argType = strtolower( $arg1 );
|
6013 |
+
$index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
|
6014 |
+
}
|
6015 |
+
// else if arg1 is set, arg1 must be an UID
|
6016 |
+
$cix2sC = 0;
|
6017 |
+
foreach ( $this->components as $cix => $component2 ) {
|
6018 |
+
if( empty( $component2 )) continue;
|
6019 |
+
if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace
|
6020 |
+
$this->components[$cix] = $component->copy();
|
6021 |
+
return TRUE;
|
6022 |
+
}
|
6023 |
+
elseif( $argType == $component2->objName ) { // component Type index insert/replace
|
6024 |
+
if( $index == $cix2sC ) {
|
6025 |
+
$this->components[$cix] = $component->copy();
|
6026 |
+
return TRUE;
|
6027 |
+
}
|
6028 |
+
$cix2sC++;
|
6029 |
+
}
|
6030 |
+
elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace
|
6031 |
+
$this->components[$cix] = $component->copy();
|
6032 |
+
return TRUE;
|
6033 |
+
}
|
6034 |
+
}
|
6035 |
+
/* arg1=index and not found.. . insert at index .. .*/
|
6036 |
+
if( 'INDEX' == $argType ) {
|
6037 |
+
$this->components[$index] = $component->copy();
|
6038 |
+
ksort( $this->components, SORT_NUMERIC );
|
6039 |
+
}
|
6040 |
+
else /* not found.. . insert last in chain anyway .. .*/
|
6041 |
+
$this->components[] = $component->copy();
|
6042 |
+
return TRUE;
|
6043 |
+
}
|
6044 |
+
/**
|
6045 |
+
* creates formatted output for subcomponents
|
6046 |
+
*
|
6047 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6048 |
+
* @since 2.6.27 - 2010-12-12
|
6049 |
+
* @return string
|
6050 |
+
*/
|
6051 |
+
function createSubComponent() {
|
6052 |
+
$output = null;
|
6053 |
+
foreach( $this->components as $component ) {
|
6054 |
+
if( empty( $component )) continue;
|
6055 |
+
$component->setConfig( $this->getConfig(), FALSE, TRUE );
|
6056 |
+
$output .= $component->createComponent( $this->xcaldecl );
|
6057 |
+
}
|
6058 |
+
return $output;
|
6059 |
+
}
|
6060 |
+
/********************************************************************************/
|
6061 |
+
/**
|
6062 |
+
* break lines at pos 75
|
6063 |
+
*
|
6064 |
+
* Lines of text SHOULD NOT be longer than 75 octets, excluding the line
|
6065 |
+
* break. Long content lines SHOULD be split into a multiple line
|
6066 |
+
* representations using a line "folding" technique. That is, a long
|
6067 |
+
* line can be split between any two characters by inserting a CRLF
|
6068 |
+
* immediately followed by a single linear white space character (i.e.,
|
6069 |
+
* SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
|
6070 |
+
* of CRLF followed immediately by a single linear white space character
|
6071 |
+
* is ignored (i.e., removed) when processing the content type.
|
6072 |
+
*
|
6073 |
+
* Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
|
6074 |
+
* the reserved expression "\n" in the arg $string could be broken up by the
|
6075 |
+
* folding of lines, causing ambiguity in the return string.
|
6076 |
+
* Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
|
6077 |
+
*
|
6078 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6079 |
+
* @since 2.6.13 - 2010-12-06
|
6080 |
+
* @param string $value
|
6081 |
+
* @return string
|
6082 |
+
*/
|
6083 |
+
function _size75( $string ) {
|
6084 |
+
$tmp = $string;
|
6085 |
+
$string = null;
|
6086 |
+
/* if PHP is config with mb_string.. . */
|
6087 |
+
if( defined( MB_OVERLOAD_STRING )) {
|
6088 |
+
$strlen = mb_strlen( $tmp );
|
6089 |
+
while( $strlen > 75 ) {
|
6090 |
+
$breakAtChar = 75;
|
6091 |
+
if( substr( $tmp, ( $breakAtChar - 1 ), strlen( '\n' )) == '\n' )
|
6092 |
+
$breakAtChar = $breakAtChar - 1;
|
6093 |
+
$string .= mb_substr( $tmp, 0, $breakAtChar );
|
6094 |
+
if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
|
6095 |
+
$string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' )));
|
6096 |
+
if( $this->nl != mb_substr( $string, ( 0 - strlen( $this->nl ))))
|
6097 |
+
$string .= $this->nl;
|
6098 |
+
$tmp = ' '.mb_substr( $tmp, $breakAtChar );
|
6099 |
+
$strlen = mb_strlen( $tmp );
|
6100 |
+
} // end while
|
6101 |
+
if( 0 < $strlen ) {
|
6102 |
+
$string .= $tmp; // the rest
|
6103 |
+
if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
|
6104 |
+
$string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' )));
|
6105 |
+
if( $this->nl != mb_substr( $string, ( 0 - strlen( $this->nl ))))
|
6106 |
+
$string .= $this->nl;
|
6107 |
+
}
|
6108 |
+
return $string;
|
6109 |
+
}
|
6110 |
+
/* if PHP is not config with mb_string.. . */
|
6111 |
+
$eolcharlen = strlen( '\n' );
|
6112 |
+
while( TRUE ) {
|
6113 |
+
$bytecnt = strlen( $tmp );
|
6114 |
+
$charCnt = $ix = 0;
|
6115 |
+
for( $ix = 0; $ix < $bytecnt; $ix++ ) {
|
6116 |
+
if(( 73 < $charCnt ) && ( '\n' == substr( $tmp, $ix, $eolcharlen ))) {
|
6117 |
+
$ix += $eolcharlen;
|
6118 |
+
break; // break when '\n' and eol
|
6119 |
+
}
|
6120 |
+
elseif( 74 < $charCnt )
|
6121 |
+
break; // always break for-loop here
|
6122 |
+
else {
|
6123 |
+
$byte = ord( $tmp[$ix] );
|
6124 |
+
if ($byte <= 127) { // add a one byte character
|
6125 |
+
$string .= substr( $tmp, $ix, 1 );
|
6126 |
+
$charCnt += 1;
|
6127 |
+
}
|
6128 |
+
else if ($byte >= 194 && $byte <= 223) { // start byte in two byte character
|
6129 |
+
$string .= substr( $tmp, $ix, 2 ); // add a two bytes character
|
6130 |
+
$charCnt += 1;
|
6131 |
+
}
|
6132 |
+
else if ($byte >= 224 && $byte <= 239) { // start byte in three bytes character
|
6133 |
+
$string .= substr( $tmp, $ix, 3 ); // add a three bytes character
|
6134 |
+
$charCnt += 1;
|
6135 |
+
}
|
6136 |
+
else if ($byte >= 240 && $byte <= 244) { // start byte in four bytes character
|
6137 |
+
$string .= substr( $tmp, $ix, 4 ); // add a four bytes character
|
6138 |
+
$charCnt += 1;
|
6139 |
+
}
|
6140 |
+
}
|
6141 |
+
} // end for
|
6142 |
+
if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
|
6143 |
+
$string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' )));
|
6144 |
+
if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
|
6145 |
+
$string .= $this->nl;
|
6146 |
+
$tmp = substr( $tmp, $ix );
|
6147 |
+
if( empty( $tmp ))
|
6148 |
+
break; // while-loop breakes here
|
6149 |
+
else
|
6150 |
+
$tmp = ' '.$tmp;
|
6151 |
+
} // end while
|
6152 |
+
if( !empty( $tmp )) {
|
6153 |
+
if( '\n' == substr( $string, ( 0 - strlen( '\n' ))))
|
6154 |
+
$string = substr( $string, 0, ( strlen( $string ) - strlen( '\n' ))).$this->nl;
|
6155 |
+
if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
|
6156 |
+
$string .= $this->nl;
|
6157 |
+
}
|
6158 |
+
return $string;
|
6159 |
+
}
|
6160 |
+
/**
|
6161 |
+
* special characters management output
|
6162 |
+
*
|
6163 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6164 |
+
* @since 2.6.15 - 2010-09-24
|
6165 |
+
* @param string $string
|
6166 |
+
* @return string
|
6167 |
+
*/
|
6168 |
+
function _strrep( $string ) {
|
6169 |
+
switch( $this->format ) {
|
6170 |
+
case 'xcal':
|
6171 |
+
$string = str_replace( '\n', $this->nl, $string);
|
6172 |
+
$string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
|
6173 |
+
break;
|
6174 |
+
default:
|
6175 |
+
$pos = 0;
|
6176 |
+
$specChars = array( 'n', 'N', 'r', ',', ';' );
|
6177 |
+
while( $pos <= strlen( $string )) {
|
6178 |
+
$pos = strpos( $string, "\\", $pos );
|
6179 |
+
if( FALSE === $pos )
|
6180 |
+
break;
|
6181 |
+
if( !in_array( substr( $string, $pos, 1 ), $specChars )) {
|
6182 |
+
$string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
|
6183 |
+
$pos += 1;
|
6184 |
+
}
|
6185 |
+
$pos += 1;
|
6186 |
+
}
|
6187 |
+
if( FALSE !== strpos( $string, '"' ))
|
6188 |
+
$string = str_replace('"', "'", $string);
|
6189 |
+
if( FALSE !== strpos( $string, ',' ))
|
6190 |
+
$string = str_replace(',', '\,', $string);
|
6191 |
+
if( FALSE !== strpos( $string, ';' ))
|
6192 |
+
$string = str_replace(';', '\;', $string);
|
6193 |
+
|
6194 |
+
if( FALSE !== strpos( $string, "\r\n" ))
|
6195 |
+
$string = str_replace( "\r\n", '\n', $string);
|
6196 |
+
elseif( FALSE !== strpos( $string, "\r" ))
|
6197 |
+
$string = str_replace( "\r", '\n', $string);
|
6198 |
+
|
6199 |
+
elseif( FALSE !== strpos( $string, "\n" ))
|
6200 |
+
$string = str_replace( "\n", '\n', $string);
|
6201 |
+
|
6202 |
+
if( FALSE !== strpos( $string, '\N' ))
|
6203 |
+
$string = str_replace( '\N', '\n', $string);
|
6204 |
+
// if( FALSE !== strpos( $string, $this->nl ))
|
6205 |
+
$string = str_replace( $this->nl, '\n', $string);
|
6206 |
+
break;
|
6207 |
+
}
|
6208 |
+
return $string;
|
6209 |
+
}
|
6210 |
+
/**
|
6211 |
+
* special characters management input (from iCal file)
|
6212 |
+
*
|
6213 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6214 |
+
* @since 2.6.22 - 2010-10-17
|
6215 |
+
* @param string $string
|
6216 |
+
* @return string
|
6217 |
+
*/
|
6218 |
+
static function _strunrep( $string ) {
|
6219 |
+
$string = str_replace( '\\\\', '\\', $string);
|
6220 |
+
$string = str_replace( '\,', ',', $string);
|
6221 |
+
$string = str_replace( '\;', ';', $string);
|
6222 |
+
// $string = str_replace( '\n', $this->nl, $string); // ??
|
6223 |
+
return $string;
|
6224 |
+
}
|
6225 |
+
}
|
6226 |
+
/*********************************************************************************/
|
6227 |
+
/*********************************************************************************/
|
6228 |
+
/**
|
6229 |
+
* class for calendar component VEVENT
|
6230 |
+
*
|
6231 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6232 |
+
* @since 2.5.1 - 2008-10-12
|
6233 |
+
*/
|
6234 |
+
class vevent extends calendarComponent {
|
6235 |
+
var $attach;
|
6236 |
+
var $attendee;
|
6237 |
+
var $categories;
|
6238 |
+
var $comment;
|
6239 |
+
var $contact;
|
6240 |
+
var $class;
|
6241 |
+
var $created;
|
6242 |
+
var $description;
|
6243 |
+
var $dtend;
|
6244 |
+
var $dtstart;
|
6245 |
+
var $duration;
|
6246 |
+
var $exdate;
|
6247 |
+
var $exrule;
|
6248 |
+
var $geo;
|
6249 |
+
var $lastmodified;
|
6250 |
+
var $location;
|
6251 |
+
var $organizer;
|
6252 |
+
var $priority;
|
6253 |
+
var $rdate;
|
6254 |
+
var $recurrenceid;
|
6255 |
+
var $relatedto;
|
6256 |
+
var $requeststatus;
|
6257 |
+
var $resources;
|
6258 |
+
var $rrule;
|
6259 |
+
var $sequence;
|
6260 |
+
var $status;
|
6261 |
+
var $summary;
|
6262 |
+
var $transp;
|
6263 |
+
var $url;
|
6264 |
+
var $xprop;
|
6265 |
+
// component subcomponents container
|
6266 |
+
var $components;
|
6267 |
+
/**
|
6268 |
+
* constructor for calendar component VEVENT object
|
6269 |
+
*
|
6270 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6271 |
+
* @since 2.8.2 - 2011-05-01
|
6272 |
+
* @param array $config
|
6273 |
+
* @return void
|
6274 |
+
*/
|
6275 |
+
function vevent( $config = array()) {
|
6276 |
+
$this->calendarComponent();
|
6277 |
+
|
6278 |
+
$this->attach = '';
|
6279 |
+
$this->attendee = '';
|
6280 |
+
$this->categories = '';
|
6281 |
+
$this->class = '';
|
6282 |
+
$this->comment = '';
|
6283 |
+
$this->contact = '';
|
6284 |
+
$this->created = '';
|
6285 |
+
$this->description = '';
|
6286 |
+
$this->dtstart = '';
|
6287 |
+
$this->dtend = '';
|
6288 |
+
$this->duration = '';
|
6289 |
+
$this->exdate = '';
|
6290 |
+
$this->exrule = '';
|
6291 |
+
$this->geo = '';
|
6292 |
+
$this->lastmodified = '';
|
6293 |
+
$this->location = '';
|
6294 |
+
$this->organizer = '';
|
6295 |
+
$this->priority = '';
|
6296 |
+
$this->rdate = '';
|
6297 |
+
$this->recurrenceid = '';
|
6298 |
+
$this->relatedto = '';
|
6299 |
+
$this->requeststatus = '';
|
6300 |
+
$this->resources = '';
|
6301 |
+
$this->rrule = '';
|
6302 |
+
$this->sequence = '';
|
6303 |
+
$this->status = '';
|
6304 |
+
$this->summary = '';
|
6305 |
+
$this->transp = '';
|
6306 |
+
$this->url = '';
|
6307 |
+
$this->xprop = '';
|
6308 |
+
|
6309 |
+
$this->components = array();
|
6310 |
+
|
6311 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
6312 |
+
$config['language'] = ICAL_LANG;
|
6313 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
6314 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
6315 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
6316 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
6317 |
+
$this->setConfig( $config );
|
6318 |
+
|
6319 |
+
}
|
6320 |
+
/**
|
6321 |
+
* create formatted output for calendar component VEVENT object instance
|
6322 |
+
*
|
6323 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6324 |
+
* @since 2.5.1 - 2008-11-07
|
6325 |
+
* @param array $xcaldecl
|
6326 |
+
* @return string
|
6327 |
+
*/
|
6328 |
+
function createComponent( &$xcaldecl ) {
|
6329 |
+
$objectname = $this->_createFormat();
|
6330 |
+
$component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
|
6331 |
+
$component .= $this->createUid();
|
6332 |
+
$component .= $this->createDtstamp();
|
6333 |
+
$component .= $this->createAttach();
|
6334 |
+
$component .= $this->createAttendee();
|
6335 |
+
$component .= $this->createCategories();
|
6336 |
+
$component .= $this->createComment();
|
6337 |
+
$component .= $this->createContact();
|
6338 |
+
$component .= $this->createClass();
|
6339 |
+
$component .= $this->createCreated();
|
6340 |
+
$component .= $this->createDescription();
|
6341 |
+
$component .= $this->createDtstart();
|
6342 |
+
$component .= $this->createDtend();
|
6343 |
+
$component .= $this->createDuration();
|
6344 |
+
$component .= $this->createExdate();
|
6345 |
+
$component .= $this->createExrule();
|
6346 |
+
$component .= $this->createGeo();
|
6347 |
+
$component .= $this->createLastModified();
|
6348 |
+
$component .= $this->createLocation();
|
6349 |
+
$component .= $this->createOrganizer();
|
6350 |
+
$component .= $this->createPriority();
|
6351 |
+
$component .= $this->createRdate();
|
6352 |
+
$component .= $this->createRrule();
|
6353 |
+
$component .= $this->createRelatedTo();
|
6354 |
+
$component .= $this->createRequestStatus();
|
6355 |
+
$component .= $this->createRecurrenceid();
|
6356 |
+
$component .= $this->createResources();
|
6357 |
+
$component .= $this->createSequence();
|
6358 |
+
$component .= $this->createStatus();
|
6359 |
+
$component .= $this->createSummary();
|
6360 |
+
$component .= $this->createTransp();
|
6361 |
+
$component .= $this->createUrl();
|
6362 |
+
$component .= $this->createXprop();
|
6363 |
+
$component .= $this->createSubComponent();
|
6364 |
+
$component .= $this->componentEnd1.$objectname.$this->componentEnd2;
|
6365 |
+
if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
|
6366 |
+
foreach( $this->xcaldecl as $localxcaldecl )
|
6367 |
+
$xcaldecl[] = $localxcaldecl;
|
6368 |
+
}
|
6369 |
+
return $component;
|
6370 |
+
}
|
6371 |
+
}
|
6372 |
+
/*********************************************************************************/
|
6373 |
+
/*********************************************************************************/
|
6374 |
+
/**
|
6375 |
+
* class for calendar component VTODO
|
6376 |
+
*
|
6377 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6378 |
+
* @since 2.5.1 - 2008-10-12
|
6379 |
+
*/
|
6380 |
+
class vtodo extends calendarComponent {
|
6381 |
+
var $attach;
|
6382 |
+
var $attendee;
|
6383 |
+
var $categories;
|
6384 |
+
var $comment;
|
6385 |
+
var $completed;
|
6386 |
+
var $contact;
|
6387 |
+
var $class;
|
6388 |
+
var $created;
|
6389 |
+
var $description;
|
6390 |
+
var $dtstart;
|
6391 |
+
var $due;
|
6392 |
+
var $duration;
|
6393 |
+
var $exdate;
|
6394 |
+
var $exrule;
|
6395 |
+
var $geo;
|
6396 |
+
var $lastmodified;
|
6397 |
+
var $location;
|
6398 |
+
var $organizer;
|
6399 |
+
var $percentcomplete;
|
6400 |
+
var $priority;
|
6401 |
+
var $rdate;
|
6402 |
+
var $recurrenceid;
|
6403 |
+
var $relatedto;
|
6404 |
+
var $requeststatus;
|
6405 |
+
var $resources;
|
6406 |
+
var $rrule;
|
6407 |
+
var $sequence;
|
6408 |
+
var $status;
|
6409 |
+
var $summary;
|
6410 |
+
var $url;
|
6411 |
+
var $xprop;
|
6412 |
+
// component subcomponents container
|
6413 |
+
var $components;
|
6414 |
+
/**
|
6415 |
+
* constructor for calendar component VTODO object
|
6416 |
+
*
|
6417 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6418 |
+
* @since 2.8.2 - 2011-05-01
|
6419 |
+
* @param array $config
|
6420 |
+
* @return void
|
6421 |
+
*/
|
6422 |
+
function vtodo( $config = array()) {
|
6423 |
+
$this->calendarComponent();
|
6424 |
+
|
6425 |
+
$this->attach = '';
|
6426 |
+
$this->attendee = '';
|
6427 |
+
$this->categories = '';
|
6428 |
+
$this->class = '';
|
6429 |
+
$this->comment = '';
|
6430 |
+
$this->completed = '';
|
6431 |
+
$this->contact = '';
|
6432 |
+
$this->created = '';
|
6433 |
+
$this->description = '';
|
6434 |
+
$this->dtstart = '';
|
6435 |
+
$this->due = '';
|
6436 |
+
$this->duration = '';
|
6437 |
+
$this->exdate = '';
|
6438 |
+
$this->exrule = '';
|
6439 |
+
$this->geo = '';
|
6440 |
+
$this->lastmodified = '';
|
6441 |
+
$this->location = '';
|
6442 |
+
$this->organizer = '';
|
6443 |
+
$this->percentcomplete = '';
|
6444 |
+
$this->priority = '';
|
6445 |
+
$this->rdate = '';
|
6446 |
+
$this->recurrenceid = '';
|
6447 |
+
$this->relatedto = '';
|
6448 |
+
$this->requeststatus = '';
|
6449 |
+
$this->resources = '';
|
6450 |
+
$this->rrule = '';
|
6451 |
+
$this->sequence = '';
|
6452 |
+
$this->status = '';
|
6453 |
+
$this->summary = '';
|
6454 |
+
$this->url = '';
|
6455 |
+
$this->xprop = '';
|
6456 |
+
|
6457 |
+
$this->components = array();
|
6458 |
+
|
6459 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
6460 |
+
$config['language'] = ICAL_LANG;
|
6461 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
6462 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
6463 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
6464 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
6465 |
+
$this->setConfig( $config );
|
6466 |
+
|
6467 |
+
}
|
6468 |
+
/**
|
6469 |
+
* create formatted output for calendar component VTODO object instance
|
6470 |
+
*
|
6471 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6472 |
+
* @since 2.5.1 - 2008-11-07
|
6473 |
+
* @param array $xcaldecl
|
6474 |
+
* @return string
|
6475 |
+
*/
|
6476 |
+
function createComponent( &$xcaldecl ) {
|
6477 |
+
$objectname = $this->_createFormat();
|
6478 |
+
$component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
|
6479 |
+
$component .= $this->createUid();
|
6480 |
+
$component .= $this->createDtstamp();
|
6481 |
+
$component .= $this->createAttach();
|
6482 |
+
$component .= $this->createAttendee();
|
6483 |
+
$component .= $this->createCategories();
|
6484 |
+
$component .= $this->createClass();
|
6485 |
+
$component .= $this->createComment();
|
6486 |
+
$component .= $this->createCompleted();
|
6487 |
+
$component .= $this->createContact();
|
6488 |
+
$component .= $this->createCreated();
|
6489 |
+
$component .= $this->createDescription();
|
6490 |
+
$component .= $this->createDtstart();
|
6491 |
+
$component .= $this->createDue();
|
6492 |
+
$component .= $this->createDuration();
|
6493 |
+
$component .= $this->createExdate();
|
6494 |
+
$component .= $this->createExrule();
|
6495 |
+
$component .= $this->createGeo();
|
6496 |
+
$component .= $this->createLastModified();
|
6497 |
+
$component .= $this->createLocation();
|
6498 |
+
$component .= $this->createOrganizer();
|
6499 |
+
$component .= $this->createPercentComplete();
|
6500 |
+
$component .= $this->createPriority();
|
6501 |
+
$component .= $this->createRdate();
|
6502 |
+
$component .= $this->createRelatedTo();
|
6503 |
+
$component .= $this->createRequestStatus();
|
6504 |
+
$component .= $this->createRecurrenceid();
|
6505 |
+
$component .= $this->createResources();
|
6506 |
+
$component .= $this->createRrule();
|
6507 |
+
$component .= $this->createSequence();
|
6508 |
+
$component .= $this->createStatus();
|
6509 |
+
$component .= $this->createSummary();
|
6510 |
+
$component .= $this->createUrl();
|
6511 |
+
$component .= $this->createXprop();
|
6512 |
+
$component .= $this->createSubComponent();
|
6513 |
+
$component .= $this->componentEnd1.$objectname.$this->componentEnd2;
|
6514 |
+
if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
|
6515 |
+
foreach( $this->xcaldecl as $localxcaldecl )
|
6516 |
+
$xcaldecl[] = $localxcaldecl;
|
6517 |
+
}
|
6518 |
+
return $component;
|
6519 |
+
}
|
6520 |
+
}
|
6521 |
+
/*********************************************************************************/
|
6522 |
+
/*********************************************************************************/
|
6523 |
+
/**
|
6524 |
+
* class for calendar component VJOURNAL
|
6525 |
+
*
|
6526 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6527 |
+
* @since 2.5.1 - 2008-10-12
|
6528 |
+
*/
|
6529 |
+
class vjournal extends calendarComponent {
|
6530 |
+
var $attach;
|
6531 |
+
var $attendee;
|
6532 |
+
var $categories;
|
6533 |
+
var $comment;
|
6534 |
+
var $contact;
|
6535 |
+
var $class;
|
6536 |
+
var $created;
|
6537 |
+
var $description;
|
6538 |
+
var $dtstart;
|
6539 |
+
var $exdate;
|
6540 |
+
var $exrule;
|
6541 |
+
var $lastmodified;
|
6542 |
+
var $organizer;
|
6543 |
+
var $rdate;
|
6544 |
+
var $recurrenceid;
|
6545 |
+
var $relatedto;
|
6546 |
+
var $requeststatus;
|
6547 |
+
var $rrule;
|
6548 |
+
var $sequence;
|
6549 |
+
var $status;
|
6550 |
+
var $summary;
|
6551 |
+
var $url;
|
6552 |
+
var $xprop;
|
6553 |
+
/**
|
6554 |
+
* constructor for calendar component VJOURNAL object
|
6555 |
+
*
|
6556 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6557 |
+
* @since 2.8.2 - 2011-05-01
|
6558 |
+
* @param array $config
|
6559 |
+
* @return void
|
6560 |
+
*/
|
6561 |
+
function vjournal( $config = array()) {
|
6562 |
+
$this->calendarComponent();
|
6563 |
+
|
6564 |
+
$this->attach = '';
|
6565 |
+
$this->attendee = '';
|
6566 |
+
$this->categories = '';
|
6567 |
+
$this->class = '';
|
6568 |
+
$this->comment = '';
|
6569 |
+
$this->contact = '';
|
6570 |
+
$this->created = '';
|
6571 |
+
$this->description = '';
|
6572 |
+
$this->dtstart = '';
|
6573 |
+
$this->exdate = '';
|
6574 |
+
$this->exrule = '';
|
6575 |
+
$this->lastmodified = '';
|
6576 |
+
$this->organizer = '';
|
6577 |
+
$this->rdate = '';
|
6578 |
+
$this->recurrenceid = '';
|
6579 |
+
$this->relatedto = '';
|
6580 |
+
$this->requeststatus = '';
|
6581 |
+
$this->rrule = '';
|
6582 |
+
$this->sequence = '';
|
6583 |
+
$this->status = '';
|
6584 |
+
$this->summary = '';
|
6585 |
+
$this->url = '';
|
6586 |
+
$this->xprop = '';
|
6587 |
+
|
6588 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
6589 |
+
$config['language'] = ICAL_LANG;
|
6590 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
6591 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
6592 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
6593 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
6594 |
+
$this->setConfig( $config );
|
6595 |
+
|
6596 |
+
}
|
6597 |
+
/**
|
6598 |
+
* create formatted output for calendar component VJOURNAL object instance
|
6599 |
+
*
|
6600 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6601 |
+
* @since 2.5.1 - 2008-10-12
|
6602 |
+
* @param array $xcaldecl
|
6603 |
+
* @return string
|
6604 |
+
*/
|
6605 |
+
function createComponent( &$xcaldecl ) {
|
6606 |
+
$objectname = $this->_createFormat();
|
6607 |
+
$component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
|
6608 |
+
$component .= $this->createUid();
|
6609 |
+
$component .= $this->createDtstamp();
|
6610 |
+
$component .= $this->createAttach();
|
6611 |
+
$component .= $this->createAttendee();
|
6612 |
+
$component .= $this->createCategories();
|
6613 |
+
$component .= $this->createClass();
|
6614 |
+
$component .= $this->createComment();
|
6615 |
+
$component .= $this->createContact();
|
6616 |
+
$component .= $this->createCreated();
|
6617 |
+
$component .= $this->createDescription();
|
6618 |
+
$component .= $this->createDtstart();
|
6619 |
+
$component .= $this->createExdate();
|
6620 |
+
$component .= $this->createExrule();
|
6621 |
+
$component .= $this->createLastModified();
|
6622 |
+
$component .= $this->createOrganizer();
|
6623 |
+
$component .= $this->createRdate();
|
6624 |
+
$component .= $this->createRequestStatus();
|
6625 |
+
$component .= $this->createRecurrenceid();
|
6626 |
+
$component .= $this->createRelatedTo();
|
6627 |
+
$component .= $this->createRrule();
|
6628 |
+
$component .= $this->createSequence();
|
6629 |
+
$component .= $this->createStatus();
|
6630 |
+
$component .= $this->createSummary();
|
6631 |
+
$component .= $this->createUrl();
|
6632 |
+
$component .= $this->createXprop();
|
6633 |
+
$component .= $this->componentEnd1.$objectname.$this->componentEnd2;
|
6634 |
+
if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
|
6635 |
+
foreach( $this->xcaldecl as $localxcaldecl )
|
6636 |
+
$xcaldecl[] = $localxcaldecl;
|
6637 |
+
}
|
6638 |
+
return $component;
|
6639 |
+
}
|
6640 |
+
}
|
6641 |
+
/*********************************************************************************/
|
6642 |
+
/*********************************************************************************/
|
6643 |
+
/**
|
6644 |
+
* class for calendar component VFREEBUSY
|
6645 |
+
*
|
6646 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6647 |
+
* @since 2.5.1 - 2008-10-12
|
6648 |
+
*/
|
6649 |
+
class vfreebusy extends calendarComponent {
|
6650 |
+
var $attendee;
|
6651 |
+
var $comment;
|
6652 |
+
var $contact;
|
6653 |
+
var $dtend;
|
6654 |
+
var $dtstart;
|
6655 |
+
var $duration;
|
6656 |
+
var $freebusy;
|
6657 |
+
var $organizer;
|
6658 |
+
var $requeststatus;
|
6659 |
+
var $url;
|
6660 |
+
var $xprop;
|
6661 |
+
// component subcomponents container
|
6662 |
+
var $components;
|
6663 |
+
/**
|
6664 |
+
* constructor for calendar component VFREEBUSY object
|
6665 |
+
*
|
6666 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6667 |
+
* @since 2.8.2 - 2011-05-01
|
6668 |
+
* @param array $config
|
6669 |
+
* @return void
|
6670 |
+
*/
|
6671 |
+
function vfreebusy( $config = array()) {
|
6672 |
+
$this->calendarComponent();
|
6673 |
+
|
6674 |
+
$this->attendee = '';
|
6675 |
+
$this->comment = '';
|
6676 |
+
$this->contact = '';
|
6677 |
+
$this->dtend = '';
|
6678 |
+
$this->dtstart = '';
|
6679 |
+
$this->duration = '';
|
6680 |
+
$this->freebusy = '';
|
6681 |
+
$this->organizer = '';
|
6682 |
+
$this->requeststatus = '';
|
6683 |
+
$this->url = '';
|
6684 |
+
$this->xprop = '';
|
6685 |
+
|
6686 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
6687 |
+
$config['language'] = ICAL_LANG;
|
6688 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
6689 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
6690 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
6691 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
6692 |
+
$this->setConfig( $config );
|
6693 |
+
|
6694 |
+
}
|
6695 |
+
/**
|
6696 |
+
* create formatted output for calendar component VFREEBUSY object instance
|
6697 |
+
*
|
6698 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6699 |
+
* @since 2.3.1 - 2007-11-19
|
6700 |
+
* @param array $xcaldecl
|
6701 |
+
* @return string
|
6702 |
+
*/
|
6703 |
+
function createComponent( &$xcaldecl ) {
|
6704 |
+
$objectname = $this->_createFormat();
|
6705 |
+
$component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
|
6706 |
+
$component .= $this->createUid();
|
6707 |
+
$component .= $this->createDtstamp();
|
6708 |
+
$component .= $this->createAttendee();
|
6709 |
+
$component .= $this->createComment();
|
6710 |
+
$component .= $this->createContact();
|
6711 |
+
$component .= $this->createDtstart();
|
6712 |
+
$component .= $this->createDtend();
|
6713 |
+
$component .= $this->createDuration();
|
6714 |
+
$component .= $this->createFreebusy();
|
6715 |
+
$component .= $this->createOrganizer();
|
6716 |
+
$component .= $this->createRequestStatus();
|
6717 |
+
$component .= $this->createUrl();
|
6718 |
+
$component .= $this->createXprop();
|
6719 |
+
$component .= $this->componentEnd1.$objectname.$this->componentEnd2;
|
6720 |
+
if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
|
6721 |
+
foreach( $this->xcaldecl as $localxcaldecl )
|
6722 |
+
$xcaldecl[] = $localxcaldecl;
|
6723 |
+
}
|
6724 |
+
return $component;
|
6725 |
+
}
|
6726 |
+
}
|
6727 |
+
/*********************************************************************************/
|
6728 |
+
/*********************************************************************************/
|
6729 |
+
/**
|
6730 |
+
* class for calendar component VALARM
|
6731 |
+
*
|
6732 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6733 |
+
* @since 2.5.1 - 2008-10-12
|
6734 |
+
*/
|
6735 |
+
class valarm extends calendarComponent {
|
6736 |
+
var $action;
|
6737 |
+
var $attach;
|
6738 |
+
var $attendee;
|
6739 |
+
var $description;
|
6740 |
+
var $duration;
|
6741 |
+
var $repeat;
|
6742 |
+
var $summary;
|
6743 |
+
var $trigger;
|
6744 |
+
var $xprop;
|
6745 |
+
/**
|
6746 |
+
* constructor for calendar component VALARM object
|
6747 |
+
*
|
6748 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6749 |
+
* @since 2.8.2 - 2011-05-01
|
6750 |
+
* @param array $config
|
6751 |
+
* @return void
|
6752 |
+
*/
|
6753 |
+
function valarm( $config = array()) {
|
6754 |
+
$this->calendarComponent();
|
6755 |
+
|
6756 |
+
$this->action = '';
|
6757 |
+
$this->attach = '';
|
6758 |
+
$this->attendee = '';
|
6759 |
+
$this->description = '';
|
6760 |
+
$this->duration = '';
|
6761 |
+
$this->repeat = '';
|
6762 |
+
$this->summary = '';
|
6763 |
+
$this->trigger = '';
|
6764 |
+
$this->xprop = '';
|
6765 |
+
|
6766 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
6767 |
+
$config['language'] = ICAL_LANG;
|
6768 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
6769 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
6770 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
6771 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
6772 |
+
$this->setConfig( $config );
|
6773 |
+
|
6774 |
+
}
|
6775 |
+
/**
|
6776 |
+
* create formatted output for calendar component VALARM object instance
|
6777 |
+
*
|
6778 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6779 |
+
* @since 2.5.1 - 2008-10-22
|
6780 |
+
* @param array $xcaldecl
|
6781 |
+
* @return string
|
6782 |
+
*/
|
6783 |
+
function createComponent( &$xcaldecl ) {
|
6784 |
+
$objectname = $this->_createFormat();
|
6785 |
+
$component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
|
6786 |
+
$component .= $this->createAction();
|
6787 |
+
$component .= $this->createAttach();
|
6788 |
+
$component .= $this->createAttendee();
|
6789 |
+
$component .= $this->createDescription();
|
6790 |
+
$component .= $this->createDuration();
|
6791 |
+
$component .= $this->createRepeat();
|
6792 |
+
$component .= $this->createSummary();
|
6793 |
+
$component .= $this->createTrigger();
|
6794 |
+
$component .= $this->createXprop();
|
6795 |
+
$component .= $this->componentEnd1.$objectname.$this->componentEnd2;
|
6796 |
+
return $component;
|
6797 |
+
}
|
6798 |
+
}
|
6799 |
+
/**********************************************************************************
|
6800 |
+
/*********************************************************************************/
|
6801 |
+
/**
|
6802 |
+
* class for calendar component VTIMEZONE
|
6803 |
+
*
|
6804 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6805 |
+
* @since 2.5.1 - 2008-10-12
|
6806 |
+
*/
|
6807 |
+
class vtimezone extends calendarComponent {
|
6808 |
+
var $timezonetype;
|
6809 |
+
|
6810 |
+
var $comment;
|
6811 |
+
var $dtstart;
|
6812 |
+
var $lastmodified;
|
6813 |
+
var $rdate;
|
6814 |
+
var $rrule;
|
6815 |
+
var $tzid;
|
6816 |
+
var $tzname;
|
6817 |
+
var $tzoffsetfrom;
|
6818 |
+
var $tzoffsetto;
|
6819 |
+
var $tzurl;
|
6820 |
+
var $xprop;
|
6821 |
+
// component subcomponents container
|
6822 |
+
var $components;
|
6823 |
+
/**
|
6824 |
+
* constructor for calendar component VTIMEZONE object
|
6825 |
+
*
|
6826 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6827 |
+
* @since 2.8.2 - 2011-05-01
|
6828 |
+
* @param mixed $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
|
6829 |
+
* @param array $config
|
6830 |
+
* @return void
|
6831 |
+
*/
|
6832 |
+
function vtimezone( $timezonetype=FALSE, $config = array()) {
|
6833 |
+
if( is_array( $timezonetype )) {
|
6834 |
+
$config = $timezonetype;
|
6835 |
+
$timezonetype = FALSE;
|
6836 |
+
}
|
6837 |
+
if( !$timezonetype )
|
6838 |
+
$this->timezonetype = 'VTIMEZONE';
|
6839 |
+
else
|
6840 |
+
$this->timezonetype = strtoupper( $timezonetype );
|
6841 |
+
$this->calendarComponent();
|
6842 |
+
|
6843 |
+
$this->comment = '';
|
6844 |
+
$this->dtstart = '';
|
6845 |
+
$this->lastmodified = '';
|
6846 |
+
$this->rdate = '';
|
6847 |
+
$this->rrule = '';
|
6848 |
+
$this->tzid = '';
|
6849 |
+
$this->tzname = '';
|
6850 |
+
$this->tzoffsetfrom = '';
|
6851 |
+
$this->tzoffsetto = '';
|
6852 |
+
$this->tzurl = '';
|
6853 |
+
$this->xprop = '';
|
6854 |
+
|
6855 |
+
$this->components = array();
|
6856 |
+
|
6857 |
+
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] ))
|
6858 |
+
$config['language'] = ICAL_LANG;
|
6859 |
+
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE;
|
6860 |
+
if( !isset( $config['nl'] )) $config['nl'] = "\r\n";
|
6861 |
+
if( !isset( $config['format'] )) $config['format'] = 'iCal';
|
6862 |
+
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR;
|
6863 |
+
$this->setConfig( $config );
|
6864 |
+
|
6865 |
+
}
|
6866 |
+
/**
|
6867 |
+
* create formatted output for calendar component VTIMEZONE object instance
|
6868 |
+
*
|
6869 |
+
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
6870 |
+
* @since 2.5.1 - 2008-10-25
|
6871 |
+
* @param array $xcaldecl
|
6872 |
+
* @return string
|
6873 |
+
*/
|
6874 |
+
function createComponent( &$xcaldecl ) {
|
6875 |
+
$objectname = $this->_createFormat();
|
6876 |
+
$component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
|
6877 |
+
$component .= $this->createTzid();
|
6878 |
+
$component .= $this->createLastModified();
|
6879 |
+
$component .= $this->createTzurl();
|
6880 |
+
$component .= $this->createDtstart();
|
6881 |
+
$component .= $this->createTzoffsetfrom();
|
6882 |
+
$component .= $this->createTzoffsetto();
|
6883 |
+
$component .= $this->createComment();
|
6884 |
+
$component .= $this->createRdate();
|
6885 |
+
$component .= $this->createRrule();
|
6886 |
+
$component .= $this->createTzname();
|
6887 |
+
$component .= $this->createXprop();
|
6888 |
+
$component .= $this->createSubComponent();
|
6889 |
+
$component .= $this->componentEnd1.$objectname.$this->componentEnd2;
|
6890 |
+
if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
|
6891 |
+
foreach( $this->xcaldecl as $localxcaldecl )
|
6892 |
+
$xcaldecl[] = $localxcaldecl;
|
6893 |
+
}
|
6894 |
+
return $component;
|
6895 |
+
}
|
6896 |
+
}
|
6897 |
+
?>
|
lib/lgpl.txt
ADDED
@@ -0,0 +1,504 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
GNU LESSER GENERAL PUBLIC LICENSE
|
2 |
+
Version 2.1, February 1999
|
3 |
+
|
4 |
+
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
|
5 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
6 |
+
Everyone is permitted to copy and distribute verbatim copies
|
7 |
+
of this license document, but changing it is not allowed.
|
8 |
+
|
9 |
+
[This is the first released version of the Lesser GPL. It also counts
|
10 |
+
as the successor of the GNU Library Public License, version 2, hence
|
11 |
+
the version number 2.1.]
|
12 |
+
|
13 |
+
Preamble
|
14 |
+
|
15 |
+
The licenses for most software are designed to take away your
|
16 |
+
freedom to share and change it. By contrast, the GNU General Public
|
17 |
+
Licenses are intended to guarantee your freedom to share and change
|
18 |
+
free software--to make sure the software is free for all its users.
|
19 |
+
|
20 |
+
This license, the Lesser General Public License, applies to some
|
21 |
+
specially designated software packages--typically libraries--of the
|
22 |
+
Free Software Foundation and other authors who decide to use it. You
|
23 |
+
can use it too, but we suggest you first think carefully about whether
|
24 |
+
this license or the ordinary General Public License is the better
|
25 |
+
strategy to use in any particular case, based on the explanations below.
|
26 |
+
|
27 |
+
When we speak of free software, we are referring to freedom of use,
|
28 |
+
not price. Our General Public Licenses are designed to make sure that
|
29 |
+
you have the freedom to distribute copies of free software (and charge
|
30 |
+
for this service if you wish); that you receive source code or can get
|
31 |
+
it if you want it; that you can change the software and use pieces of
|
32 |
+
it in new free programs; and that you are informed that you can do
|
33 |
+
these things.
|
34 |
+
|
35 |
+
To protect your rights, we need to make restrictions that forbid
|
36 |
+
distributors to deny you these rights or to ask you to surrender these
|
37 |
+
rights. These restrictions translate to certain responsibilities for
|
38 |
+
you if you distribute copies of the library or if you modify it.
|
39 |
+
|
40 |
+
For example, if you distribute copies of the library, whether gratis
|
41 |
+
or for a fee, you must give the recipients all the rights that we gave
|
42 |
+
you. You must make sure that they, too, receive or can get the source
|
43 |
+
code. If you link other code with the library, you must provide
|
44 |
+
complete object files to the recipients, so that they can relink them
|
45 |
+
with the library after making changes to the library and recompiling
|
46 |
+
it. And you must show them these terms so they know their rights.
|
47 |
+
|
48 |
+
We protect your rights with a two-step method: (1) we copyright the
|
49 |
+
library, and (2) we offer you this license, which gives you legal
|
50 |
+
permission to copy, distribute and/or modify the library.
|
51 |
+
|
52 |
+
To protect each distributor, we want to make it very clear that
|
53 |
+
there is no warranty for the free library. Also, if the library is
|
54 |
+
modified by someone else and passed on, the recipients should know
|
55 |
+
that what they have is not the original version, so that the original
|
56 |
+
author's reputation will not be affected by problems that might be
|
57 |
+
introduced by others.
|
58 |
+
|
59 |
+
Finally, software patents pose a constant threat to the existence of
|
60 |
+
any free program. We wish to make sure that a company cannot
|
61 |
+
effectively restrict the users of a free program by obtaining a
|
62 |
+
restrictive license from a patent holder. Therefore, we insist that
|
63 |
+
any patent license obtained for a version of the library must be
|
64 |
+
consistent with the full freedom of use specified in this license.
|
65 |
+
|
66 |
+
Most GNU software, including some libraries, is covered by the
|
67 |
+
ordinary GNU General Public License. This license, the GNU Lesser
|
68 |
+
General Public License, applies to certain designated libraries, and
|
69 |
+
is quite different from the ordinary General Public License. We use
|
70 |
+
this license for certain libraries in order to permit linking those
|
71 |
+
libraries into non-free programs.
|
72 |
+
|
73 |
+
When a program is linked with a library, whether statically or using
|
74 |
+
a shared library, the combination of the two is legally speaking a
|
75 |
+
combined work, a derivative of the original library. The ordinary
|
76 |
+
General Public License therefore permits such linking only if the
|
77 |
+
entire combination fits its criteria of freedom. The Lesser General
|
78 |
+
Public License permits more lax criteria for linking other code with
|
79 |
+
the library.
|
80 |
+
|
81 |
+
We call this license the "Lesser" General Public License because it
|
82 |
+
does Less to protect the user's freedom than the ordinary General
|
83 |
+
Public License. It also provides other free software developers Less
|
84 |
+
of an advantage over competing non-free programs. These disadvantages
|
85 |
+
are the reason we use the ordinary General Public License for many
|
86 |
+
libraries. However, the Lesser license provides advantages in certain
|
87 |
+
special circumstances.
|
88 |
+
|
89 |
+
For example, on rare occasions, there may be a special need to
|
90 |
+
encourage the widest possible use of a certain library, so that it becomes
|
91 |
+
a de-facto standard. To achieve this, non-free programs must be
|
92 |
+
allowed to use the library. A more frequent case is that a free
|
93 |
+
library does the same job as widely used non-free libraries. In this
|
94 |
+
case, there is little to gain by limiting the free library to free
|
95 |
+
software only, so we use the Lesser General Public License.
|
96 |
+
|
97 |
+
In other cases, permission to use a particular library in non-free
|
98 |
+
programs enables a greater number of people to use a large body of
|
99 |
+
free software. For example, permission to use the GNU C Library in
|
100 |
+
non-free programs enables many more people to use the whole GNU
|
101 |
+
operating system, as well as its variant, the GNU/Linux operating
|
102 |
+
system.
|
103 |
+
|
104 |
+
Although the Lesser General Public License is Less protective of the
|
105 |
+
users' freedom, it does ensure that the user of a program that is
|
106 |
+
linked with the Library has the freedom and the wherewithal to run
|
107 |
+
that program using a modified version of the Library.
|
108 |
+
|
109 |
+
The precise terms and conditions for copying, distribution and
|
110 |
+
modification follow. Pay close attention to the difference between a
|
111 |
+
"work based on the library" and a "work that uses the library". The
|
112 |
+
former contains code derived from the library, whereas the latter must
|
113 |
+
be combined with the library in order to run.
|
114 |
+
|
115 |
+
GNU LESSER GENERAL PUBLIC LICENSE
|
116 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
117 |
+
|
118 |
+
0. This License Agreement applies to any software library or other
|
119 |
+
program which contains a notice placed by the copyright holder or
|
120 |
+
other authorized party saying it may be distributed under the terms of
|
121 |
+
this Lesser General Public License (also called "this License").
|
122 |
+
Each licensee is addressed as "you".
|
123 |
+
|
124 |
+
A "library" means a collection of software functions and/or data
|
125 |
+
prepared so as to be conveniently linked with application programs
|
126 |
+
(which use some of those functions and data) to form executables.
|
127 |
+
|
128 |
+
The "Library", below, refers to any such software library or work
|
129 |
+
which has been distributed under these terms. A "work based on the
|
130 |
+
Library" means either the Library or any derivative work under
|
131 |
+
copyright law: that is to say, a work containing the Library or a
|
132 |
+
portion of it, either verbatim or with modifications and/or translated
|
133 |
+
straightforwardly into another language. (Hereinafter, translation is
|
134 |
+
included without limitation in the term "modification".)
|
135 |
+
|
136 |
+
"Source code" for a work means the preferred form of the work for
|
137 |
+
making modifications to it. For a library, complete source code means
|
138 |
+
all the source code for all modules it contains, plus any associated
|
139 |
+
interface definition files, plus the scripts used to control compilation
|
140 |
+
and installation of the library.
|
141 |
+
|
142 |
+
Activities other than copying, distribution and modification are not
|
143 |
+
covered by this License; they are outside its scope. The act of
|
144 |
+
running a program using the Library is not restricted, and output from
|
145 |
+
such a program is covered only if its contents constitute a work based
|
146 |
+
on the Library (independent of the use of the Library in a tool for
|
147 |
+
writing it). Whether that is true depends on what the Library does
|
148 |
+
and what the program that uses the Library does.
|
149 |
+
|
150 |
+
1. You may copy and distribute verbatim copies of the Library's
|
151 |
+
complete source code as you receive it, in any medium, provided that
|
152 |
+
you conspicuously and appropriately publish on each copy an
|
153 |
+
appropriate copyright notice and disclaimer of warranty; keep intact
|
154 |
+
all the notices that refer to this License and to the absence of any
|
155 |
+
warranty; and distribute a copy of this License along with the
|
156 |
+
Library.
|
157 |
+
|
158 |
+
You may charge a fee for the physical act of transferring a copy,
|
159 |
+
and you may at your option offer warranty protection in exchange for a
|
160 |
+
fee.
|
161 |
+
|
162 |
+
2. You may modify your copy or copies of the Library or any portion
|
163 |
+
of it, thus forming a work based on the Library, and copy and
|
164 |
+
distribute such modifications or work under the terms of Section 1
|
165 |
+
above, provided that you also meet all of these conditions:
|
166 |
+
|
167 |
+
a) The modified work must itself be a software library.
|
168 |
+
|
169 |
+
b) You must cause the files modified to carry prominent notices
|
170 |
+
stating that you changed the files and the date of any change.
|
171 |
+
|
172 |
+
c) You must cause the whole of the work to be licensed at no
|
173 |
+
charge to all third parties under the terms of this License.
|
174 |
+
|
175 |
+
d) If a facility in the modified Library refers to a function or a
|
176 |
+
table of data to be supplied by an application program that uses
|
177 |
+
the facility, other than as an argument passed when the facility
|
178 |
+
is invoked, then you must make a good faith effort to ensure that,
|
179 |
+
in the event an application does not supply such function or
|
180 |
+
table, the facility still operates, and performs whatever part of
|
181 |
+
its purpose remains meaningful.
|
182 |
+
|
183 |
+
(For example, a function in a library to compute square roots has
|
184 |
+
a purpose that is entirely well-defined independent of the
|
185 |
+
application. Therefore, Subsection 2d requires that any
|
186 |
+
application-supplied function or table used by this function must
|
187 |
+
be optional: if the application does not supply it, the square
|
188 |
+
root function must still compute square roots.)
|
189 |
+
|
190 |
+
These requirements apply to the modified work as a whole. If
|
191 |
+
identifiable sections of that work are not derived from the Library,
|
192 |
+
and can be reasonably considered independent and separate works in
|
193 |
+
themselves, then this License, and its terms, do not apply to those
|
194 |
+
sections when you distribute them as separate works. But when you
|
195 |
+
distribute the same sections as part of a whole which is a work based
|
196 |
+
on the Library, the distribution of the whole must be on the terms of
|
197 |
+
this License, whose permissions for other licensees extend to the
|
198 |
+
entire whole, and thus to each and every part regardless of who wrote
|
199 |
+
it.
|
200 |
+
|
201 |
+
Thus, it is not the intent of this section to claim rights or contest
|
202 |
+
your rights to work written entirely by you; rather, the intent is to
|
203 |
+
exercise the right to control the distribution of derivative or
|
204 |
+
collective works based on the Library.
|
205 |
+
|
206 |
+
In addition, mere aggregation of another work not based on the Library
|
207 |
+
with the Library (or with a work based on the Library) on a volume of
|
208 |
+
a storage or distribution medium does not bring the other work under
|
209 |
+
the scope of this License.
|
210 |
+
|
211 |
+
3. You may opt to apply the terms of the ordinary GNU General Public
|
212 |
+
License instead of this License to a given copy of the Library. To do
|
213 |
+
this, you must alter all the notices that refer to this License, so
|
214 |
+
that they refer to the ordinary GNU General Public License, version 2,
|
215 |
+
instead of to this License. (If a newer version than version 2 of the
|
216 |
+
ordinary GNU General Public License has appeared, then you can specify
|
217 |
+
that version instead if you wish.) Do not make any other change in
|
218 |
+
these notices.
|
219 |
+
|
220 |
+
Once this change is made in a given copy, it is irreversible for
|
221 |
+
that copy, so the ordinary GNU General Public License applies to all
|
222 |
+
subsequent copies and derivative works made from that copy.
|
223 |
+
|
224 |
+
This option is useful when you wish to copy part of the code of
|
225 |
+
the Library into a program that is not a library.
|
226 |
+
|
227 |
+
4. You may copy and distribute the Library (or a portion or
|
228 |
+
derivative of it, under Section 2) in object code or executable form
|
229 |
+
under the terms of Sections 1 and 2 above provided that you accompany
|
230 |
+
it with the complete corresponding machine-readable source code, which
|
231 |
+
must be distributed under the terms of Sections 1 and 2 above on a
|
232 |
+
medium customarily used for software interchange.
|
233 |
+
|
234 |
+
If distribution of object code is made by offering access to copy
|
235 |
+
from a designated place, then offering equivalent access to copy the
|
236 |
+
source code from the same place satisfies the requirement to
|
237 |
+
distribute the source code, even though third parties are not
|
238 |
+
compelled to copy the source along with the object code.
|
239 |
+
|
240 |
+
5. A program that contains no derivative of any portion of the
|
241 |
+
Library, but is designed to work with the Library by being compiled or
|
242 |
+
linked with it, is called a "work that uses the Library". Such a
|
243 |
+
work, in isolation, is not a derivative work of the Library, and
|
244 |
+
therefore falls outside the scope of this License.
|
245 |
+
|
246 |
+
However, linking a "work that uses the Library" with the Library
|
247 |
+
creates an executable that is a derivative of the Library (because it
|
248 |
+
contains portions of the Library), rather than a "work that uses the
|
249 |
+
library". The executable is therefore covered by this License.
|
250 |
+
Section 6 states terms for distribution of such executables.
|
251 |
+
|
252 |
+
When a "work that uses the Library" uses material from a header file
|
253 |
+
that is part of the Library, the object code for the work may be a
|
254 |
+
derivative work of the Library even though the source code is not.
|
255 |
+
Whether this is true is especially significant if the work can be
|
256 |
+
linked without the Library, or if the work is itself a library. The
|
257 |
+
threshold for this to be true is not precisely defined by law.
|
258 |
+
|
259 |
+
If such an object file uses only numerical parameters, data
|
260 |
+
structure layouts and accessors, and small macros and small inline
|
261 |
+
functions (ten lines or less in length), then the use of the object
|
262 |
+
file is unrestricted, regardless of whether it is legally a derivative
|
263 |
+
work. (Executables containing this object code plus portions of the
|
264 |
+
Library will still fall under Section 6.)
|
265 |
+
|
266 |
+
Otherwise, if the work is a derivative of the Library, you may
|
267 |
+
distribute the object code for the work under the terms of Section 6.
|
268 |
+
Any executables containing that work also fall under Section 6,
|
269 |
+
whether or not they are linked directly with the Library itself.
|
270 |
+
|
271 |
+
6. As an exception to the Sections above, you may also combine or
|
272 |
+
link a "work that uses the Library" with the Library to produce a
|
273 |
+
work containing portions of the Library, and distribute that work
|
274 |
+
under terms of your choice, provided that the terms permit
|
275 |
+
modification of the work for the customer's own use and reverse
|
276 |
+
engineering for debugging such modifications.
|
277 |
+
|
278 |
+
You must give prominent notice with each copy of the work that the
|
279 |
+
Library is used in it and that the Library and its use are covered by
|
280 |
+
this License. You must supply a copy of this License. If the work
|
281 |
+
during execution displays copyright notices, you must include the
|
282 |
+
copyright notice for the Library among them, as well as a reference
|
283 |
+
directing the user to the copy of this License. Also, you must do one
|
284 |
+
of these things:
|
285 |
+
|
286 |
+
a) Accompany the work with the complete corresponding
|
287 |
+
machine-readable source code for the Library including whatever
|
288 |
+
changes were used in the work (which must be distributed under
|
289 |
+
Sections 1 and 2 above); and, if the work is an executable linked
|
290 |
+
with the Library, with the complete machine-readable "work that
|
291 |
+
uses the Library", as object code and/or source code, so that the
|
292 |
+
user can modify the Library and then relink to produce a modified
|
293 |
+
executable containing the modified Library. (It is understood
|
294 |
+
that the user who changes the contents of definitions files in the
|
295 |
+
Library will not necessarily be able to recompile the application
|
296 |
+
to use the modified definitions.)
|
297 |
+
|
298 |
+
b) Use a suitable shared library mechanism for linking with the
|
299 |
+
Library. A suitable mechanism is one that (1) uses at run time a
|
300 |
+
copy of the library already present on the user's computer system,
|
301 |
+
rather than copying library functions into the executable, and (2)
|
302 |
+
will operate properly with a modified version of the library, if
|
303 |
+
the user installs one, as long as the modified version is
|
304 |
+
interface-compatible with the version that the work was made with.
|
305 |
+
|
306 |
+
c) Accompany the work with a written offer, valid for at
|
307 |
+
least three years, to give the same user the materials
|
308 |
+
specified in Subsection 6a, above, for a charge no more
|
309 |
+
than the cost of performing this distribution.
|
310 |
+
|
311 |
+
d) If distribution of the work is made by offering access to copy
|
312 |
+
from a designated place, offer equivalent access to copy the above
|
313 |
+
specified materials from the same place.
|
314 |
+
|
315 |
+
e) Verify that the user has already received a copy of these
|
316 |
+
materials or that you have already sent this user a copy.
|
317 |
+
|
318 |
+
For an executable, the required form of the "work that uses the
|
319 |
+
Library" must include any data and utility programs needed for
|
320 |
+
reproducing the executable from it. However, as a special exception,
|
321 |
+
the materials to be distributed need not include anything that is
|
322 |
+
normally distributed (in either source or binary form) with the major
|
323 |
+
components (compiler, kernel, and so on) of the operating system on
|
324 |
+
which the executable runs, unless that component itself accompanies
|
325 |
+
the executable.
|
326 |
+
|
327 |
+
It may happen that this requirement contradicts the license
|
328 |
+
restrictions of other proprietary libraries that do not normally
|
329 |
+
accompany the operating system. Such a contradiction means you cannot
|
330 |
+
use both them and the Library together in an executable that you
|
331 |
+
distribute.
|
332 |
+
|
333 |
+
7. You may place library facilities that are a work based on the
|
334 |
+
Library side-by-side in a single library together with other library
|
335 |
+
facilities not covered by this License, and distribute such a combined
|
336 |
+
library, provided that the separate distribution of the work based on
|
337 |
+
the Library and of the other library facilities is otherwise
|
338 |
+
permitted, and provided that you do these two things:
|
339 |
+
|
340 |
+
a) Accompany the combined library with a copy of the same work
|
341 |
+
based on the Library, uncombined with any other library
|
342 |
+
facilities. This must be distributed under the terms of the
|
343 |
+
Sections above.
|
344 |
+
|
345 |
+
b) Give prominent notice with the combined library of the fact
|
346 |
+
that part of it is a work based on the Library, and explaining
|
347 |
+
where to find the accompanying uncombined form of the same work.
|
348 |
+
|
349 |
+
8. You may not copy, modify, sublicense, link with, or distribute
|
350 |
+
the Library except as expressly provided under this License. Any
|
351 |
+
attempt otherwise to copy, modify, sublicense, link with, or
|
352 |
+
distribute the Library is void, and will automatically terminate your
|
353 |
+
rights under this License. However, parties who have received copies,
|
354 |
+
or rights, from you under this License will not have their licenses
|
355 |
+
terminated so long as such parties remain in full compliance.
|
356 |
+
|
357 |
+
9. You are not required to accept this License, since you have not
|
358 |
+
signed it. However, nothing else grants you permission to modify or
|
359 |
+
distribute the Library or its derivative works. These actions are
|
360 |
+
prohibited by law if you do not accept this License. Therefore, by
|
361 |
+
modifying or distributing the Library (or any work based on the
|
362 |
+
Library), you indicate your acceptance of this License to do so, and
|
363 |
+
all its terms and conditions for copying, distributing or modifying
|
364 |
+
the Library or works based on it.
|
365 |
+
|
366 |
+
10. Each time you redistribute the Library (or any work based on the
|
367 |
+
Library), the recipient automatically receives a license from the
|
368 |
+
original licensor to copy, distribute, link with or modify the Library
|
369 |
+
subject to these terms and conditions. You may not impose any further
|
370 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
371 |
+
You are not responsible for enforcing compliance by third parties with
|
372 |
+
this License.
|
373 |
+
|
374 |
+
11. If, as a consequence of a court judgment or allegation of patent
|
375 |
+
infringement or for any other reason (not limited to patent issues),
|
376 |
+
conditions are imposed on you (whether by court order, agreement or
|
377 |
+
otherwise) that contradict the conditions of this License, they do not
|
378 |
+
excuse you from the conditions of this License. If you cannot
|
379 |
+
distribute so as to satisfy simultaneously your obligations under this
|
380 |
+
License and any other pertinent obligations, then as a consequence you
|
381 |
+
may not distribute the Library at all. For example, if a patent
|
382 |
+
license would not permit royalty-free redistribution of the Library by
|
383 |
+
all those who receive copies directly or indirectly through you, then
|
384 |
+
the only way you could satisfy both it and this License would be to
|
385 |
+
refrain entirely from distribution of the Library.
|
386 |
+
|
387 |
+
If any portion of this section is held invalid or unenforceable under any
|
388 |
+
particular circumstance, the balance of the section is intended to apply,
|
389 |
+
and the section as a whole is intended to apply in other circumstances.
|
390 |
+
|
391 |
+
It is not the purpose of this section to induce you to infringe any
|
392 |
+
patents or other property right claims or to contest validity of any
|
393 |
+
such claims; this section has the sole purpose of protecting the
|
394 |
+
integrity of the free software distribution system which is
|
395 |
+
implemented by public license practices. Many people have made
|
396 |
+
generous contributions to the wide range of software distributed
|
397 |
+
through that system in reliance on consistent application of that
|
398 |
+
system; it is up to the author/donor to decide if he or she is willing
|
399 |
+
to distribute software through any other system and a licensee cannot
|
400 |
+
impose that choice.
|
401 |
+
|
402 |
+
This section is intended to make thoroughly clear what is believed to
|
403 |
+
be a consequence of the rest of this License.
|
404 |
+
|
405 |
+
12. If the distribution and/or use of the Library is restricted in
|
406 |
+
certain countries either by patents or by copyrighted interfaces, the
|
407 |
+
original copyright holder who places the Library under this License may add
|
408 |
+
an explicit geographical distribution limitation excluding those countries,
|
409 |
+
so that distribution is permitted only in or among countries not thus
|
410 |
+
excluded. In such case, this License incorporates the limitation as if
|
411 |
+
written in the body of this License.
|
412 |
+
|
413 |
+
13. The Free Software Foundation may publish revised and/or new
|
414 |
+
versions of the Lesser General Public License from time to time.
|
415 |
+
Such new versions will be similar in spirit to the present version,
|
416 |
+
but may differ in detail to address new problems or concerns.
|
417 |
+
|
418 |
+
Each version is given a distinguishing version number. If the Library
|
419 |
+
specifies a version number of this License which applies to it and
|
420 |
+
"any later version", you have the option of following the terms and
|
421 |
+
conditions either of that version or of any later version published by
|
422 |
+
the Free Software Foundation. If the Library does not specify a
|
423 |
+
license version number, you may choose any version ever published by
|
424 |
+
the Free Software Foundation.
|
425 |
+
|
426 |
+
14. If you wish to incorporate parts of the Library into other free
|
427 |
+
programs whose distribution conditions are incompatible with these,
|
428 |
+
write to the author to ask for permission. For software which is
|
429 |
+
copyrighted by the Free Software Foundation, write to the Free
|
430 |
+
Software Foundation; we sometimes make exceptions for this. Our
|
431 |
+
decision will be guided by the two goals of preserving the free status
|
432 |
+
of all derivatives of our free software and of promoting the sharing
|
433 |
+
and reuse of software generally.
|
434 |
+
|
435 |
+
NO WARRANTY
|
436 |
+
|
437 |
+
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
438 |
+
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
439 |
+
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
440 |
+
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
441 |
+
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
442 |
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
443 |
+
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
444 |
+
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
445 |
+
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
446 |
+
|
447 |
+
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
448 |
+
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
449 |
+
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
450 |
+
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
451 |
+
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
452 |
+
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
453 |
+
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
454 |
+
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
455 |
+
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
456 |
+
DAMAGES.
|
457 |
+
|
458 |
+
END OF TERMS AND CONDITIONS
|
459 |
+
|
460 |
+
How to Apply These Terms to Your New Libraries
|
461 |
+
|
462 |
+
If you develop a new library, and you want it to be of the greatest
|
463 |
+
possible use to the public, we recommend making it free software that
|
464 |
+
everyone can redistribute and change. You can do so by permitting
|
465 |
+
redistribution under these terms (or, alternatively, under the terms of the
|
466 |
+
ordinary General Public License).
|
467 |
+
|
468 |
+
To apply these terms, attach the following notices to the library. It is
|
469 |
+
safest to attach them to the start of each source file to most effectively
|
470 |
+
convey the exclusion of warranty; and each file should have at least the
|
471 |
+
"copyright" line and a pointer to where the full notice is found.
|
472 |
+
|
473 |
+
<one line to give the library's name and a brief idea of what it does.>
|
474 |
+
Copyright (C) <year> <name of author>
|
475 |
+
|
476 |
+
This library is free software; you can redistribute it and/or
|
477 |
+
modify it under the terms of the GNU Lesser General Public
|
478 |
+
License as published by the Free Software Foundation; either
|
479 |
+
version 2.1 of the License, or (at your option) any later version.
|
480 |
+
|
481 |
+
This library is distributed in the hope that it will be useful,
|
482 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
483 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
484 |
+
Lesser General Public License for more details.
|
485 |
+
|
486 |
+
You should have received a copy of the GNU Lesser General Public
|
487 |
+
License along with this library; if not, write to the Free Software
|
488 |
+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
489 |
+
|
490 |
+
Also add information on how to contact you by electronic and paper mail.
|
491 |
+
|
492 |
+
You should also get your employer (if you work as a programmer) or your
|
493 |
+
school, if any, to sign a "copyright disclaimer" for the library, if
|
494 |
+
necessary. Here is a sample; alter the names:
|
495 |
+
|
496 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
497 |
+
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
498 |
+
|
499 |
+
<signature of Ty Coon>, 1 April 1990
|
500 |
+
Ty Coon, President of Vice
|
501 |
+
|
502 |
+
That's all there is to it!
|
503 |
+
|
504 |
+
|
readme.txt
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== All-in-One Events Calendar ===
|
2 |
+
Contributors: theseed, hubrik, vtowel, yani.iliev
|
3 |
+
Donate link: http://theseedstudio.com/software/all-in-one-events-calendar-wordpress/
|
4 |
+
Tags: calendar, event, events, ics, ics calendar, ical-feed, ics feed, wordpress ics importer, wordpress ical importer, upcoming events, todo, notes, journal, freebusy, availability, web calendar, web events, webcal, google calendar, ical, iCalendar, all-in-one, ai1ec, google calendar sync, ical sync, events sync, holiday calendar, calendar 2011, events 2011
|
5 |
+
Requires at least: 3.1.3
|
6 |
+
Tested up to: 3.2.1
|
7 |
+
Stable tag: 1.0
|
8 |
+
|
9 |
+
An events calendar system with month and agenda calendar views, color-coded categories, recurring events, and import/export of iCalendar (.ics) feeds.
|
10 |
+
|
11 |
+
== Description ==
|
12 |
+
|
13 |
+
Welcome to the All-in-One Events Calendar Plugin, a new way to list your events in WordPress and easily share them with the rest of the world.
|
14 |
+
|
15 |
+
Our new calendar system combines a clean visual design, solid architectural patterns and rigorous testing with a powerful set of features to create the most advanced calendar system available for WordPress and one of the most powerful website calendar systems in the world. Best of all: it’s completely free.
|
16 |
+
|
17 |
+
= Calendar Features For Users =
|
18 |
+
|
19 |
+
This plugin has many features we hope will prove useful to users, including:
|
20 |
+
|
21 |
+
* Recurring* events
|
22 |
+
* Filtering by event category or tag
|
23 |
+
* Easy sharing with Google Calendar, Apple iCal, MS Outlook and any other system that accepts iCalendar (.ics) feeds
|
24 |
+
* Embedded Google Maps
|
25 |
+
* Color-coded events based on category
|
26 |
+
* Event-registration ready
|
27 |
+
* Month and agenda views
|
28 |
+
* Links to filtered calendar views
|
29 |
+
|
30 |
+
(* Limited recurrence patterns available in first release. Full support to come in the next release.)
|
31 |
+
|
32 |
+
= Features for Website and Blog Owners =
|
33 |
+
|
34 |
+
* Import other calendars automatically to display in your calendar
|
35 |
+
* Categorize and tag imported calendar feeds automatically
|
36 |
+
* Events from [The Events Calendar](http://wordpress.org/extend/plugins/the-events-calendar/) plugin can also be easily imported
|
37 |
+
|
38 |
+
Importing and exporting iCalendar (.ics) feeds is one of the strongest features of the All-in-One Events Calendar system. Enter an event on one site and you can have it appear automatically in another website's calendar. You can even send events from a specific category or tag (or combination of categories and tags).
|
39 |
+
|
40 |
+
Why is this cool? It allows event creators to create one event and have it displayed on a few or thousands of calendars with no extra work. And it also allows calendar owners to populate their calendar from other calendar feeds without having to go through the hassle of creating new events. For example, a soccer league can send its game schedule to a community sports calendar, which, in turn, can send only featured games (from all the sports leagues it aggragates) to a community calendar, which features sports as just one category.
|
41 |
+
|
42 |
+
= Additional Features =
|
43 |
+
|
44 |
+
The All-in-One Events Calendar Plugin also has a few features that will prove useful for website and blog owners:
|
45 |
+
|
46 |
+
* Each event is SEO-optimized
|
47 |
+
* Each event links to the original calendar
|
48 |
+
* Your calendar can be embedded into a WordPress page without needing to create template files or modify the theme
|
49 |
+
|
50 |
+
[Check out the demo »](http://thenelsonpost.ca/calendar/)
|
51 |
+
|
52 |
+
== Installation ==
|
53 |
+
|
54 |
+
1. Upload `all-in-one-events-calendar` to the `/wp-content/plugins/` directory.
|
55 |
+
1. Activate the plugin through the **Plugins** menu item in the WordPress Dashboard.
|
56 |
+
1. Once the plugin is activated, follow the instructions in the notice to configure it.
|
57 |
+
|
58 |
+
== Screenshots ==
|
59 |
+
|
60 |
+
1. Add new event - part 1
|
61 |
+
2. Add new event - part 2
|
62 |
+
3. Event categories
|
63 |
+
4. Event categories with color picker
|
64 |
+
5. Front-end: Month view of calendar
|
65 |
+
6. Front-end: Month view of calendar with mouse cursor hovering over event
|
66 |
+
7. Front-end: Month view of calendar with active category filter
|
67 |
+
8. Front-end: Month view of calendar with active tag filter
|
68 |
+
9. Front-end: Agenda view of calendar
|
69 |
+
10. Settings page
|
screenshot-1.png
ADDED
Binary file
|
screenshot-10.png
ADDED
Binary file
|
screenshot-2.png
ADDED
Binary file
|
screenshot-3.png
ADDED
Binary file
|
screenshot-4.png
ADDED
Binary file
|
screenshot-5.png
ADDED
Binary file
|
screenshot-6.png
ADDED
Binary file
|
screenshot-7.png
ADDED
Binary file
|
screenshot-8.png
ADDED
Binary file
|
screenshot-9.png
ADDED
Binary file
|