Révision 204e4d33
Ajouté par Assos Assos il y a presque 9 ans
drupal7/sites/all/modules/date_ical/README.txt | ||
---|---|---|
16 | 16 |
- The Feeds module is optional. It's needed only if you you wish to import iCal |
17 | 17 |
feeds from other sites. |
18 | 18 |
|
19 |
To install the iCalcreator library, download the project's v2.20.2 zip file:
|
|
20 |
https://github.com/iCalcreator/iCalcreator/archive/e3dbec2cb3bb91a8bde989e467567ae8831a4026.zip
|
|
21 |
Extract it, and copy iCalcreator.class.php to a folder in your Drupal site
|
|
22 |
named sites/all/libraries/iCalcreator (you'll need to create that folder).
|
|
19 |
To install the iCalcreator library, download the latest release from ths url:
|
|
20 |
https://github.com/iCalcreator/iCalcreator/archive/master.zip
|
|
21 |
Extract it, and copy the contents to a folder in your Drupal site named
|
|
22 |
sites/all/libraries/iCalcreator (you'll need to create that folder). |
|
23 | 23 |
|
24 | 24 |
Or, if you have drush, you can install iCalcreator by running this command from |
25 | 25 |
your site's root directory: |
... | ... | |
67 | 67 |
as the event date for the iCal feed. Make sure that you choose a field that |
68 | 68 |
is a part of every entity that your View displays. Otherwise, the entities |
69 | 69 |
which don't have that field will be left out of the iCal feed. |
70 |
9. You may optionally choose a field that will be used to populate the
|
|
70 |
9. You may optionally choose a field that will be used to populate the |
|
71 | 71 |
Location property of events in your iCal feed. This field can be a text |
72 | 72 |
field, a Node Reference field, an Addressfield, or a Location field. |
73 | 73 |
10. Give the Feed a path like 'calendar/%/export.ics', including a '/%/' for |
... | ... | |
243 | 243 |
timezone names to real timezone IDs, is from Version24 of the Unicode CLDR: |
244 | 244 |
http://cldr.unicode.org/. |
245 | 245 |
|
246 |
The author of iCalcreator made backwards incompatible changes to the library |
|
247 |
in the v2.22 release. Thus Date iCal does not currently support any version of |
|
248 |
iCalcreator after v2.20.2. |
|
246 |
For some time, Date iCal did not support the 2.22+ of the iCalcreator library. |
|
247 |
This has been corrected, and any version should now function normally. |
drupal7/sites/all/modules/date_ical/date_ical.api.php | ||
---|---|---|
15 | 15 |
* hook exists to allow users to alter the original HTML to ensure that it |
16 | 16 |
* gets converted into pretty plaintext. |
17 | 17 |
* |
18 |
* ONLY <p> tags will be converted to newlines by the plaintext conversion.
|
|
18 |
* <p>, <h*>, and <div> tags are changed to newlines by the plaintext converter.
|
|
19 | 19 |
* |
20 | 20 |
* @param array $text_fields |
21 | 21 |
* A reference to an associative array with the following keys and values: |
... | ... | |
80 | 80 |
$event['comment'] = check_plain($comment['value']); |
81 | 81 |
} |
82 | 82 |
} |
83 |
|
|
83 |
|
|
84 | 84 |
// Example: Retrieving information from additional fields in the View (using |
85 | 85 |
// the Fields plugin). |
86 | 86 |
$event['comment'] = $view->style_plugin->get_field($context['row_index'], 'field_comment'); |
drupal7/sites/all/modules/date_ical/date_ical.info | ||
---|---|---|
21 | 21 |
; Includes for iCal feed import using Feeds |
22 | 22 |
files[] = includes/DateiCalFeedsParser.inc |
23 | 23 |
|
24 |
; Information added by Drupal.org packaging script on 2015-07-20
|
|
25 |
version = "7.x-3.5"
|
|
24 |
; Information added by Drupal.org packaging script on 2015-11-16
|
|
25 |
version = "7.x-3.6"
|
|
26 | 26 |
core = "7.x" |
27 | 27 |
project = "date_ical" |
28 |
datestamp = "1437419644"
|
|
28 |
datestamp = "1447703054"
|
|
29 | 29 |
|
drupal7/sites/all/modules/date_ical/date_ical.install | ||
---|---|---|
9 | 9 |
*/ |
10 | 10 |
function date_ical_requirements($phase) { |
11 | 11 |
$requirements = array(); |
12 |
|
|
12 |
|
|
13 | 13 |
// Ensure translations don't break at install time. |
14 | 14 |
$t = get_t(); |
15 |
|
|
15 |
|
|
16 | 16 |
if ($phase == 'runtime') { |
17 | 17 |
if (!function_exists('libraries_detect')) { |
18 | 18 |
$requirements['date_ical'] = array( |
... | ... | |
26 | 26 |
// Return immediately, since we can't even attempt to determine if iCalcreator is installed. |
27 | 27 |
return $requirements; |
28 | 28 |
} |
29 |
|
|
29 |
|
|
30 | 30 |
$library = libraries_detect('iCalcreator'); |
31 | 31 |
if ($library && !empty($library['installed'])) { |
32 | 32 |
$requirements['date_ical'] = array( |
... | ... | |
46 | 46 |
); |
47 | 47 |
} |
48 | 48 |
} |
49 |
|
|
49 |
|
|
50 | 50 |
return $requirements; |
51 | 51 |
} |
52 | 52 |
|
... | ... | |
73 | 73 |
// Drupal attempts to instantiate the old feeds plugin classes. |
74 | 74 |
registry_rebuild(); |
75 | 75 |
cache_clear_all('plugins:feeds:plugins', 'cache'); |
76 |
|
|
76 |
|
|
77 | 77 |
// Update all the importers which used DateIcalIcalcreatorParser to use |
78 | 78 |
// DateiCalFeedsParser instead. |
79 | 79 |
$importer_data = ctools_export_load_object('feeds_importer', 'all'); |
... | ... | |
81 | 81 |
$importer = feeds_importer($key); |
82 | 82 |
$importer_config = $importer->getConfig(); |
83 | 83 |
$needs_update = ($importer_config['parser']['plugin_key'] == 'DateIcalIcalcreatorParser'); |
84 |
|
|
84 |
|
|
85 | 85 |
$processor = $importer->processor; |
86 | 86 |
$processor_config = $processor->getconfig(); |
87 | 87 |
// Also update importers which use the new parser, but have un-capitalized |
... | ... | |
91 | 91 |
&& !empty($processor_config['mappings'][0]['source'])) { |
92 | 92 |
$needs_update = (strtoupper($processor_config['mappings'][0]['source']) != $processor_config['mappings'][0]['source']); |
93 | 93 |
} |
94 |
|
|
94 |
|
|
95 | 95 |
if ($needs_update) { |
96 | 96 |
$importer->setPlugin('DateiCalFeedsParser'); |
97 |
|
|
97 |
|
|
98 | 98 |
// Source keys are now capitalized, so we need to update the mappings. |
99 | 99 |
foreach ($processor_config['mappings'] as &$mapping) { |
100 | 100 |
$mapping['source'] = strtoupper($mapping['source']); |
101 | 101 |
} |
102 | 102 |
$processor->setConfig($processor_config); |
103 |
|
|
103 |
|
|
104 | 104 |
$importer->save(); |
105 |
|
|
105 |
|
|
106 | 106 |
// When this importer object got created, a warning was issued about its |
107 | 107 |
// parser plugin being missing. We corrected that warning above, so we |
108 | 108 |
// should clear it out to avoid potential confusion. |
drupal7/sites/all/modules/date_ical/date_ical.make | ||
---|---|---|
2 | 2 |
api = 2 |
3 | 3 |
|
4 | 4 |
libraries[iCalcreator][download][type] = "get" |
5 |
libraries[iCalcreator][download][url] = "https://github.com/iCalcreator/iCalcreator/archive/e3dbec2cb3bb91a8bde989e467567ae8831a4026.zip"
|
|
5 |
libraries[iCalcreator][download][url] = "https://github.com/iCalcreator/iCalcreator/archive/master.zip"
|
|
6 | 6 |
libraries[iCalcreator][directory_name] = "iCalcreator" |
7 | 7 |
libraries[iCalcreator][destination] = "libraries" |
drupal7/sites/all/modules/date_ical/date_ical.module | ||
---|---|---|
9 | 9 |
* The version number of the current release. This is inserted into the PRODID |
10 | 10 |
* value of the iCal feeds created by Date iCal, for debugging purposes. |
11 | 11 |
*/ |
12 |
define('DATE_ICAL_VERSION', '3.5');
|
|
12 |
define('DATE_ICAL_VERSION', '3.6');
|
|
13 | 13 |
|
14 | 14 |
/** |
15 | 15 |
* Exception class for generic exceptions thrown by this module. |
... | ... | |
121 | 121 |
$variables['page'] = TRUE; |
122 | 122 |
$variables['title_prefix'] = ''; |
123 | 123 |
$variables['title_suffix'] = ''; |
124 |
|
|
124 |
|
|
125 | 125 |
// We don't want to see the author information in our feed. |
126 | 126 |
$variables['display_submitted'] = FALSE; |
127 |
|
|
127 |
|
|
128 | 128 |
// Comments and links don't belong in an iCal feed. |
129 | 129 |
if (isset($variables['content']['comments'])) { |
130 | 130 |
unset($variables['content']['comments']); |
... | ... | |
165 | 165 |
'name' => 'iCalcreator', |
166 | 166 |
'vendor url' => 'http://github.com/iCalcreator/iCalcreator', |
167 | 167 |
'download url' => 'http://github.com/iCalcreator/iCalcreator', |
168 |
'version arguments' => array( |
|
169 |
'file' => 'iCalcreator.class.php', |
|
170 |
'pattern' => "/define.*?ICALCREATOR_VERSION.*?([\d\.]+)/", |
|
171 |
'lines' => 100, |
|
172 |
), |
|
173 |
'files' => array( |
|
174 |
'php' => array('iCalcreator.class.php'), |
|
168 |
'version callback' => '_date_ical_detect_icalcreator_version', |
|
169 |
'versions' => array( |
|
170 |
'2.20' => array( |
|
171 |
'files' => array( |
|
172 |
'php' => array('iCalcreator.class.php'), |
|
173 |
), |
|
174 |
), |
|
175 |
'2.22+' => array( |
|
176 |
'files' => array( |
|
177 |
'php' => array('iCalcreator.php'), |
|
178 |
), |
|
179 |
), |
|
175 | 180 |
), |
176 | 181 |
); |
177 |
|
|
182 |
|
|
178 | 183 |
return $libraries; |
179 | 184 |
} |
180 | 185 |
|
... | ... | |
231 | 236 |
// HTML tags may get converted to < and such by the View code, so we need |
232 | 237 |
// to convert them back to HTML so we can remove them with strip_tags(). |
233 | 238 |
$text = decode_entities($text); |
234 |
|
|
239 |
|
|
235 | 240 |
// Convert <p> tags to double newlines. |
236 | 241 |
$text = trim(preg_replace("/<p.*?>/i", "\n\n", $text)); |
237 | 242 |
// Separate heading tags from the text around them in both directions. |
238 | 243 |
$text = trim(preg_replace("/<\\?h\d.*?>/i", "\n\n", $text)); |
239 | 244 |
// Add a newline for each <div>. |
240 | 245 |
$text = trim(preg_replace("/<div.*?>/i", "\n", $text)); |
241 |
|
|
246 |
|
|
242 | 247 |
// Strip the remaining HTML. |
243 | 248 |
$text = strip_tags($text); |
244 | 249 |
// Remove newlines added at the beginning. |
... | ... | |
278 | 283 |
array('RRULE', 'RDATE', 'EXRULE', 'EXDATE'), |
279 | 284 |
explode('|', $repeat_rule) |
280 | 285 |
); |
281 |
|
|
286 |
|
|
282 | 287 |
module_load_include('inc', 'date_ical', 'date_ical.utils'); |
283 | 288 |
// This "loop" is really just to make sure we get the right array keys. It |
284 | 289 |
// souldn't ever execute more than once. |
... | ... | |
296 | 301 |
function date_ical_get_location_fields($base = 'node', $reset = FALSE) { |
297 | 302 |
static $fields = array(); |
298 | 303 |
$empty = array('name' => array(), 'alias' => array()); |
299 |
|
|
304 |
|
|
300 | 305 |
if (empty($fields[$base]) || $reset) { |
301 | 306 |
$cid = 'date_ical_location_fields_' . $base; |
302 | 307 |
if (!$reset && $cached = cache_get($cid, 'cache_views')) { |
... | ... | |
326 | 331 |
if (empty($base)) { |
327 | 332 |
$base = 'node'; |
328 | 333 |
} |
329 |
|
|
334 |
|
|
330 | 335 |
$cid = 'date_ical_location_fields_' . $base; |
331 | 336 |
cache_clear_all($cid, 'cache_views'); |
332 |
|
|
337 |
|
|
333 | 338 |
// Iterate over all the fields that Views knows about. |
334 | 339 |
$all_fields = date_views_views_fetch_fields($base, 'field'); |
335 | 340 |
$fields = array(); |
... | ... | |
338 | 343 |
$tmp = explode('.', $name); |
339 | 344 |
$field_name = $tmp[1]; |
340 | 345 |
$table_name = $tmp[0]; |
341 |
|
|
346 |
|
|
342 | 347 |
// Skip unsupported field types and fields that weren't defined through |
343 | 348 |
// the Field module. |
344 | 349 |
$info = field_info_field($field_name); |
... | ... | |
353 | 358 |
if (!$info || !in_array($info['type'], $supported_location_fields)) { |
354 | 359 |
continue; |
355 | 360 |
} |
356 |
|
|
361 |
|
|
357 | 362 |
// Build an array of the field info that we'll need. |
358 | 363 |
$alias = str_replace('.', '_', $alias); |
359 | 364 |
$fields['name'][$name] = array( |
... | ... | |
362 | 367 |
'field_name' => $field_name, |
363 | 368 |
'type' => $info['type'], |
364 | 369 |
); |
365 |
|
|
370 |
|
|
366 | 371 |
// These are here only to make this $field array conform to the same format |
367 | 372 |
// as the one returned by _date_views_fields(). They're probably not needed, |
368 | 373 |
// but I thought that consistency would be a good idea. |
369 | 374 |
$fields['name'][$name]['real_field_name'] = $field_name; |
370 | 375 |
$fields['alias'][$alias] = $fields['name'][$name]; |
371 | 376 |
} |
372 |
|
|
377 |
|
|
373 | 378 |
cache_set($cid, $fields, 'cache_views'); |
374 | 379 |
return $fields; |
375 | 380 |
} |
... | ... | |
492 | 497 |
} |
493 | 498 |
return $new_rrule; |
494 | 499 |
} |
500 |
|
|
501 |
function _date_ical_detect_icalcreator_version() { |
|
502 |
$path = libraries_get_path('iCalcreator'); |
|
503 |
if (file_exists(DRUPAL_ROOT . "/$path/iCalcreator.class.php")) { |
|
504 |
return '2.20'; |
|
505 |
} |
|
506 |
else if (file_exists(DRUPAL_ROOT . "/$path//iCalcreator.php")) { |
|
507 |
return '2.22+'; |
|
508 |
} |
|
509 |
else { |
|
510 |
return FALSE; |
|
511 |
} |
|
512 |
} |
drupal7/sites/all/modules/date_ical/date_ical.utils.inc | ||
---|---|---|
14 | 14 |
function _date_ical_get_repeat_dates($field_name, $repeat_data, $item, $source) { |
15 | 15 |
module_load_include('inc', 'date_api', 'date_api_ical'); |
16 | 16 |
$field_info = field_info_field($field_name); |
17 |
|
|
17 |
|
|
18 | 18 |
$rrule_values = _date_ical_parse_repeat_rule($repeat_data['RRULE']); |
19 | 19 |
//$exrule_values = _date_ical_parse_repeat_rule($repeat_data['EXRULE']); |
20 | 20 |
$rdates = _date_ical_parse_repeat_dates($repeat_data['RDATE']); |
21 | 21 |
$exdates = _date_ical_parse_repeat_dates($repeat_data['EXDATE']); |
22 |
|
|
22 |
|
|
23 | 23 |
// By the time we get here, the start and end dates have been |
24 | 24 |
// adjusted back to UTC, but we want localtime dates to do |
25 | 25 |
// things like '+1 Tuesday', so adjust back to localtime. |
... | ... | |
40 | 40 |
} |
41 | 41 |
$duration = $start->difference($end); |
42 | 42 |
$start_datetime = date_format($start, DATE_FORMAT_DATETIME); |
43 |
|
|
43 |
|
|
44 | 44 |
if (!empty($rrule_values['UNTIL']['datetime'])) { |
45 | 45 |
// The spec says that UNTIL must be in UTC, but not all feed creators |
46 | 46 |
// follow that rule. If the user specified that he wanted to overcome this |
... | ... | |
50 | 50 |
// Change the parsed UNTIL from UTC to $timezone, so that the |
51 | 51 |
// date_ical_date() won't convert it. |
52 | 52 |
$rrule_values['UNTIL']['tz'] = $timezone; |
53 |
|
|
53 |
|
|
54 | 54 |
// Convert the unparsed UNTIL to UTC, since the Date code will use it. |
55 | 55 |
// It may currently have a Z on it, but only because iCalcreator blindly |
56 | 56 |
// adds one to DATETIME-type UNTILs if it's not there. |
... | ... | |
81 | 81 |
// No UNTIL and no COUNT? This is an illegal RRULE. |
82 | 82 |
return array(); |
83 | 83 |
} |
84 |
|
|
84 |
|
|
85 | 85 |
// Convert the EXDATE and RDATE values to datetime strings. |
86 | 86 |
// Even though exdates and rdates can be specified to the second, Date |
87 | 87 |
// Repeat's code checks them by comparing them to the date value only. |
... | ... | |
95 | 95 |
$date = date_ical_date($rdate, $timezone); |
96 | 96 |
$additions[] = date_format($date, 'Y-m-d'); |
97 | 97 |
} |
98 |
|
|
98 |
|
|
99 | 99 |
// TODO: EXRULEs. |
100 |
|
|
100 |
|
|
101 | 101 |
$date_repeat_compatible_rrule = "{$repeat_data['RRULE']}\n{$repeat_data['RDATE']}\n{$repeat_data['EXDATE']}"; |
102 | 102 |
$calculated_dates = date_repeat_calc($date_repeat_compatible_rrule, $start_datetime, $final_repeat_datetime, $exceptions, $timezone, $additions); |
103 | 103 |
$repeat_dates = array(); |
... | ... | |
131 | 131 |
*/ |
132 | 132 |
function _date_ical_parse_repeat_rule($repeat_rule_string) { |
133 | 133 |
module_load_include('inc', 'date_api', 'date_api_ical'); |
134 |
|
|
134 |
|
|
135 | 135 |
$repeat_rule_string = preg_replace('/(R|EX)RULE.*:/', '', $repeat_rule_string); |
136 | 136 |
$items = array('DATA' => $repeat_rule_string); |
137 | 137 |
foreach (explode(';', $repeat_rule_string) as $recur_val) { |
... | ... | |
140 | 140 |
if (empty($key) || empty($value)) { |
141 | 141 |
continue; |
142 | 142 |
} |
143 |
|
|
143 |
|
|
144 | 144 |
// The following keys never have multiple values. |
145 | 145 |
if (in_array($key, array('UNTIL', 'FREQ', 'INTERVAL', 'COUNT', 'WKST'))) { |
146 | 146 |
if ($key == 'UNTIL') { |
... | ... | |
152 | 152 |
// The rest can be multi-value csv strings. |
153 | 153 |
$value = explode(',', $value); |
154 | 154 |
} |
155 |
|
|
155 |
|
|
156 | 156 |
$items[$key] = $value; |
157 | 157 |
} |
158 | 158 |
return $items; |
... | ... | |
171 | 171 |
*/ |
172 | 172 |
function _date_ical_parse_repeat_dates($repeat_date_string) { |
173 | 173 |
module_load_include('inc', 'date_api', 'date_api_ical'); |
174 |
|
|
174 |
|
|
175 | 175 |
$properties = explode("\n", str_replace("\r\n", "\n", $repeat_date_string)); |
176 | 176 |
$parsed_dates = array(); |
177 |
|
|
177 |
|
|
178 | 178 |
foreach ($properties as $property) { |
179 | 179 |
$matches = array(); |
180 | 180 |
if (preg_match('/(R|EX)DATE([^:]*):(.*)/', $property, $matches)) { |
drupal7/sites/all/modules/date_ical/includes/DateiCalFeedsParser.inc | ||
---|---|---|
5 | 5 |
*/ |
6 | 6 |
|
7 | 7 |
class DateiCalFeedsParser extends FeedsParser { |
8 |
|
|
8 |
|
|
9 | 9 |
/** |
10 | 10 |
* Implements FeedsParser::getMappingSources(). |
11 | 11 |
*/ |
12 | 12 |
public function getMappingSources() { |
13 | 13 |
return parent::getMappingSources() + self::getiCalMappingSources(); |
14 | 14 |
} |
15 |
|
|
15 |
|
|
16 | 16 |
/** |
17 | 17 |
* Implements FeedsParser::parse(). |
18 | 18 |
*/ |
... | ... | |
22 | 22 |
throw new DateIcalException(t('Unable to load the iCalcreator library. Please ensure that it is properly installed.')); |
23 | 23 |
} |
24 | 24 |
$state = $source->state(FEEDS_PARSE); |
25 |
|
|
25 |
|
|
26 | 26 |
// Read the iCal feed into memory. |
27 | 27 |
$ical_feed_contents = $fetcher_result->getRaw(); |
28 |
|
|
28 |
|
|
29 | 29 |
// Parse the feed into an iCalcreator vcalendar object. |
30 | 30 |
$calendar = new vcalendar(); |
31 | 31 |
if ($calendar->parse($ical_feed_contents) === FALSE) { |
... | ... | |
33 | 33 |
$url = $source->config[$plugin]['source']; |
34 | 34 |
throw new DateIcalException(t('Parsing the data from %url failed. Please ensure that this URL leads to a valid iCal feed.', array('%url' => $url))); |
35 | 35 |
} |
36 |
|
|
36 |
|
|
37 | 37 |
// Total hack to get around iCalcreator's mistreatment of UID "0". |
38 | 38 |
if (empty($calendar->components[0]->uid) || empty($calendar->components[0]->uid['value'])) { |
39 | 39 |
$calendar->components[0]->uid = array('value' => 'zero', 'params' => NULL); |
40 | 40 |
} |
41 |
|
|
41 |
|
|
42 | 42 |
// Allow modules to alter the vcalendar object before we interpret it. |
43 | 43 |
$context = array( |
44 | 44 |
'source' => $source, |
45 | 45 |
'fetcher_result' => $fetcher_result, |
46 | 46 |
); |
47 | 47 |
drupal_alter('date_ical_import_vcalendar', $calendar, $context); |
48 |
|
|
48 |
|
|
49 | 49 |
// We've got a vcalendar object created from the feed data. Now we need to |
50 | 50 |
// convert that vcalendar into an array of Feeds-compatible data arrays. |
51 | 51 |
// ParserVcalendar->parse() does that. |
52 | 52 |
require_once DRUPAL_ROOT . '/' . drupal_get_path('module', 'date_ical') . '/libraries/ParserVcalendar.inc'; |
53 | 53 |
$parser = new ParserVcalendar($calendar, $source, $fetcher_result, $source->getConfigFor($this)); |
54 |
|
|
54 |
|
|
55 | 55 |
// Using the stored progress pointer (or 0 if it's not set), |
56 | 56 |
// determine which section of the feed to parse, then parse it. |
57 | 57 |
$offset = isset($state->pointer) ? $state->pointer : 0; |
58 | 58 |
$limit = $source->importer->getLimit(); |
59 | 59 |
$rows = $parser->parse($offset, $limit); |
60 |
|
|
60 |
|
|
61 | 61 |
// Report progress. |
62 | 62 |
$state->total = $parser->getTotalComponents(); |
63 | 63 |
// We need to add 1 to the index of the last parsed componenent so that |
64 | 64 |
// the subsequent batch starts on the first unparsed component. |
65 | 65 |
$state->pointer = $parser->getLastComponentParsed() + 1; |
66 | 66 |
$state->progress($state->total, $state->pointer); |
67 |
|
|
67 |
|
|
68 | 68 |
return new FeedsParserResult($rows); |
69 | 69 |
} |
70 |
|
|
70 |
|
|
71 | 71 |
/** |
72 | 72 |
* Defines the default configuration settings for an actual import. |
73 | 73 |
*/ |
... | ... | |
78 | 78 |
'skip_days' => $this->config['skip_days'], |
79 | 79 |
); |
80 | 80 |
} |
81 |
|
|
81 |
|
|
82 | 82 |
/** |
83 | 83 |
* Defines the default settings shown on the configuration form. |
84 | 84 |
*/ |
... | ... | |
90 | 90 |
'skip_days' => NULL, |
91 | 91 |
); |
92 | 92 |
} |
93 |
|
|
93 |
|
|
94 | 94 |
/** |
95 | 95 |
* Builds the configuration form. |
96 | 96 |
*/ |
... | ... | |
133 | 133 |
); |
134 | 134 |
return $form; |
135 | 135 |
} |
136 |
|
|
136 |
|
|
137 | 137 |
/** |
138 | 138 |
* Validation handler for configForm. |
139 | 139 |
*/ |
... | ... | |
145 | 145 |
$source_config['skip_days'] = NULL; |
146 | 146 |
} |
147 | 147 |
} |
148 |
|
|
148 |
|
|
149 | 149 |
/** |
150 | 150 |
* Creates the list of mapping sources offered by DateiCalFeedsParser. |
151 | 151 |
*/ |
... | ... | |
210 | 210 |
'description' => t('The CATEGORIES property. Catagories that describe the event, which can be imported into taxonomy terms.'), |
211 | 211 |
'date_ical_parse_handler' => 'parseMultivalueProperty', |
212 | 212 |
); |
213 |
|
|
213 |
|
|
214 | 214 |
// Allow other modules to add custom source fields. |
215 | 215 |
drupal_alter('date_ical_mapping_sources', $sources); |
216 |
|
|
216 |
|
|
217 | 217 |
return $sources; |
218 | 218 |
} |
219 | 219 |
} |
drupal7/sites/all/modules/date_ical/includes/date_ical.views.inc | ||
---|---|---|
10 | 10 |
*/ |
11 | 11 |
function date_ical_views_plugins() { |
12 | 12 |
$includes_path = drupal_get_path('module', 'date_ical') . '/includes'; |
13 |
|
|
13 |
|
|
14 | 14 |
$data = array( |
15 | 15 |
'module' => 'date_ical', |
16 | 16 |
'style' => array( |
... | ... | |
48 | 48 |
), |
49 | 49 |
), |
50 | 50 |
); |
51 |
|
|
51 |
|
|
52 | 52 |
return $data; |
53 | 53 |
} |
drupal7/sites/all/modules/date_ical/includes/date_ical_plugin_row_ical_entity.inc | ||
---|---|---|
9 | 9 |
* A Views plugin which builds an iCal VEVENT from a single node. |
10 | 10 |
*/ |
11 | 11 |
class date_ical_plugin_row_ical_entity extends views_plugin_row { |
12 |
|
|
12 |
|
|
13 | 13 |
// Basic properties that let the row style follow relationships. |
14 | 14 |
protected $base_table = 'node'; |
15 | 15 |
protected $base_field = 'nid'; |
16 |
|
|
16 |
|
|
17 | 17 |
// Stores the nodes loaded with pre_render. |
18 | 18 |
protected $entities = array(); |
19 |
|
|
19 |
|
|
20 | 20 |
/** |
21 | 21 |
* Initialize the row plugin. |
22 | 22 |
*/ |
... | ... | |
25 | 25 |
$this->base_table = $view->base_table; |
26 | 26 |
$this->base_field = $view->base_field; |
27 | 27 |
} |
28 |
|
|
28 |
|
|
29 | 29 |
/** |
30 | 30 |
* Set up the options for the row plugin. |
31 | 31 |
*/ |
... | ... | |
36 | 36 |
$options['location_field'] = array('default' => array()); |
37 | 37 |
return $options; |
38 | 38 |
} |
39 |
|
|
39 |
|
|
40 | 40 |
/** |
41 | 41 |
* Build the form for setting the row plugin's options. |
42 | 42 |
*/ |
43 | 43 |
public function options_form(&$form, &$form_state) { |
44 | 44 |
parent::options_form($form, $form_state); |
45 |
|
|
45 |
|
|
46 | 46 |
// Build the select dropdown for the Date field that the user wants to use |
47 | 47 |
// to populate the date properties in VEVENTs. |
48 | 48 |
$data = date_views_fields($this->base_table); |
... | ... | |
71 | 71 |
<br>To change the iCal view mode, configure it on the 'Manage Display' page for each Content Type. |
72 | 72 |
Please note that all HTML will be stripped from the output, to comply with iCal standards."), |
73 | 73 |
); |
74 |
|
|
74 |
|
|
75 | 75 |
// Build the select dropdown for the text/node_reference field that the user |
76 | 76 |
// wants to use to (optionally) populate the SUMMARY. |
77 | 77 |
$summary_fields = date_ical_get_summary_fields($this->base_table); |
... | ... | |
88 | 88 |
Choose which text, taxonomy term reference or Node Reference field you would like to be output as the SUMMARY. |
89 | 89 |
If using a Node Reference, the Title of the referenced node will be used.'), |
90 | 90 |
); |
91 |
|
|
91 |
|
|
92 | 92 |
// Build the select dropdown for the text/node_reference field that the user |
93 | 93 |
// wants to use to (optionally) populate the LOCATION. |
94 | 94 |
$location_fields = date_ical_get_location_fields($this->base_table); |
... | ... | |
106 | 106 |
If using a Node Reference, the Title of the referenced node will be used.'), |
107 | 107 |
); |
108 | 108 |
} |
109 |
|
|
109 |
|
|
110 | 110 |
/** |
111 | 111 |
* Preload the list of entities which will appear in the view. |
112 | 112 |
* |
... | ... | |
123 | 123 |
foreach ($values as $row) { |
124 | 124 |
// Use the $id as the key so we create only value per entity. |
125 | 125 |
$id = $row->{$this->field_alias}; |
126 |
|
|
126 |
|
|
127 | 127 |
// Node revisions need special loading. |
128 | 128 |
if ($this->view->base_table == 'node_revision') { |
129 | 129 |
$this->entities[$id] = node_load(NULL, $id); |
... | ... | |
134 | 134 |
$ids[$id] = $id; |
135 | 135 |
} |
136 | 136 |
} |
137 |
|
|
137 |
|
|
138 | 138 |
$base_tables = date_views_base_tables(); |
139 | 139 |
$this->entity_type = $base_tables[$this->view->base_table]; |
140 | 140 |
if (!empty($ids)) { |
141 | 141 |
$this->entities = entity_load($this->entity_type, $ids); |
142 | 142 |
} |
143 |
|
|
143 |
|
|
144 | 144 |
// Get the language for this view. |
145 | 145 |
$this->language = $this->display->handler->get_option('field_language'); |
146 | 146 |
$substitutions = views_views_query_substitutions($this->view); |
... | ... | |
148 | 148 |
$this->language = $substitutions[$this->language]; |
149 | 149 |
} |
150 | 150 |
} |
151 |
|
|
151 |
|
|
152 | 152 |
/** |
153 | 153 |
* Renders the entities returned by the view into event arrays. |
154 | 154 |
*/ |
... | ... | |
157 | 157 |
if (!is_numeric($id)) { |
158 | 158 |
return NULL; |
159 | 159 |
} |
160 |
|
|
160 |
|
|
161 | 161 |
// Load the specified entity: |
162 | 162 |
$entity = $this->entities[$id]; |
163 | 163 |
if (empty($entity)) { |
164 | 164 |
// This can happen when an RRULE is involved. |
165 | 165 |
return NULL; |
166 | 166 |
} |
167 |
|
|
167 |
|
|
168 | 168 |
$date_fields = date_views_fields($this->base_table); |
169 | 169 |
$date_info = $date_fields['name'][$this->options['date_field']]; |
170 | 170 |
$field_name = str_replace(array('_value', '_value2'), '', $date_info['real_field_name']); |
171 | 171 |
$delta_field = $date_info['delta_field']; |
172 | 172 |
$is_field = $date_info['is_field']; |
173 |
|
|
173 |
|
|
174 | 174 |
// Sometimes the timestamp is actually the revision timestamp. |
175 | 175 |
if ($this->view->base_table == 'node_revision' && $field_name == 'timestamp') { |
176 | 176 |
$field_name = 'revision_timestamp'; |
177 | 177 |
} |
178 |
|
|
178 |
|
|
179 | 179 |
if (!isset($entity->$field_name)) { |
180 | 180 |
// This entity doesn't have the date property that the user configured |
181 | 181 |
// our view to use. We can't do anything with it. |
182 | 182 |
return NULL; |
183 | 183 |
} |
184 | 184 |
$date_field = $entity->$field_name; |
185 |
|
|
185 |
|
|
186 | 186 |
// Pull the date value from the specified field of the entity. |
187 | 187 |
$entity->date_id = array(); |
188 | 188 |
$start = NULL; |
... | ... | |
199 | 199 |
global $base_url; |
200 | 200 |
$domain = preg_replace('#^https?://#', '', $base_url); |
201 | 201 |
$entity->date_id[] = "calendar.$id.$field_name.$delta@$domain"; |
202 |
|
|
202 |
|
|
203 | 203 |
if (!empty($date_field['value'])) { |
204 | 204 |
$start = new DateObject($date_field['value'], $date_field['timezone_db']); |
205 | 205 |
if (!empty($date_field['value2'])) { |
... | ... | |
214 | 214 |
$start = new DateObject($date_field, $date_field['timezone_db']); |
215 | 215 |
$end = new DateObject($date_field, $date_field['timezone_db']); |
216 | 216 |
} |
217 |
|
|
217 |
|
|
218 | 218 |
// Set the item date to the proper display timezone. |
219 | 219 |
$start->setTimezone(new DateTimeZone($date_field['timezone'])); |
220 | 220 |
$end->setTimezone(new DateTimeZone($date_field['timezone'])); |
221 |
|
|
221 |
|
|
222 | 222 |
// Check if the start and end dates indicate that this is an All Day event. |
223 | 223 |
$all_day = date_is_all_day( |
224 | 224 |
date_format($start, DATE_FORMAT_DATETIME), |
225 | 225 |
date_format($end, DATE_FORMAT_DATETIME), |
226 | 226 |
date_granularity_precision($date_info['granularity']) |
227 | 227 |
); |
228 |
|
|
228 |
|
|
229 | 229 |
if ($all_day) { |
230 | 230 |
// According to RFC 2445 (clarified in RFC 5545) the DTEND value is |
231 | 231 |
// non-inclusive. When dealing with All Day values, they're DATEs rather |
232 | 232 |
// than DATETIMEs, so we need to add a day to conform to RFC. |
233 | 233 |
$end->modify("+1 day"); |
234 | 234 |
} |
235 |
|
|
235 |
|
|
236 | 236 |
// If the user specified a LOCATION field, pull that data from the entity. |
237 | 237 |
$location = ''; |
238 | 238 |
if (!empty($this->options['location_field']) && $this->options['location_field'] != 'none') { |
239 | 239 |
$location_fields = date_ical_get_location_fields($this->base_table); |
240 | 240 |
$location_info = $location_fields['name'][$this->options['location_field']]; |
241 | 241 |
$location_field_name = $location_info['real_field_name']; |
242 |
|
|
242 |
|
|
243 | 243 |
// Only attempt this is the entity actually has this field. |
244 | 244 |
$items = field_get_items($this->entity_type, $entity, $location_field_name); |
245 | 245 |
if ($items) { |
... | ... | |
253 | 253 |
} |
254 | 254 |
elseif ($location_info['type'] == 'addressfield') { |
255 | 255 |
$locations = array(); |
256 |
// Get full country name |
|
257 |
if (!empty($location_field['country'])) { |
|
258 |
require_once DRUPAL_ROOT . '/includes/locale.inc'; |
|
259 |
$countries = country_get_list(); |
|
260 |
$location_field['country'] = $countries[$location_field['country']]; |
|
261 |
} |
|
256 | 262 |
foreach ($location_field as $key => $loc) { |
257 | 263 |
if ($loc && !in_array($key, array('first_name', 'last_name'))) { |
258 | 264 |
$locations[] = $loc; |
... | ... | |
283 | 289 |
} |
284 | 290 |
} |
285 | 291 |
} |
286 |
|
|
292 |
|
|
287 | 293 |
// Create the rendered event using the display settings from the |
288 | 294 |
// iCal view mode. |
289 | 295 |
$rendered_array = entity_view($this->entity_type, array($entity), 'ical', $this->language, TRUE); |
... | ... | |
333 | 339 |
'language' => $this->language, |
334 | 340 |
); |
335 | 341 |
drupal_alter('date_ical_export_html', $data, $this->view, $context); |
336 |
|
|
342 |
|
|
337 | 343 |
$event = array(); |
338 | 344 |
$event['summary'] = date_ical_sanitize_text($data['summary']); |
339 | 345 |
$event['description'] = date_ical_sanitize_text($data['description']); |
... | ... | |
343 | 349 |
$uri = entity_uri($this->entity_type, $entity); |
344 | 350 |
$uri['options']['absolute'] = TRUE; |
345 | 351 |
$event['url'] = url($uri['path'], $uri['options']); |
346 |
$event['rrule'] = $is_field && array_key_exists('rrule', $date_field) ? $date_field['rrule'] : ''; |
|
352 |
if ($is_field && !empty($date_field['rrule'])) { |
|
353 |
$event['rrule'] = $date_field['rrule']; |
|
354 |
} |
|
347 | 355 |
if ($location) { |
348 | 356 |
$event['location'] = date_ical_sanitize_text($location); |
349 | 357 |
} |
350 |
|
|
358 |
|
|
351 | 359 |
// For this event's UID, use either the date_id generated by the Date |
352 | 360 |
// module, or the event page's URL if the date_id isn't available. |
353 | 361 |
$event['uid'] = !empty($entity->date_id) ? $entity->date_id[0] : $event['url']; |
354 |
|
|
362 |
|
|
355 | 363 |
// If we are using a repeat rule (and not just multi-day events) we |
356 | 364 |
// remove the item from the entities list so that its VEVENT won't be |
357 | 365 |
// re-created. |
358 |
if ($event['rrule']) {
|
|
366 |
if (!empty($event['rrule'])) {
|
|
359 | 367 |
$this->entities[$id] = NULL; |
360 | 368 |
} |
361 |
|
|
369 |
|
|
362 | 370 |
// According to the iCal standard, CREATED and LAST-MODIFIED must be UTC. |
363 | 371 |
// Fortunately, Drupal stores timestamps in the DB as UTC, so we just need |
364 | 372 |
// to tell DateObject to treat the timestamp as UTC from the start. |
... | ... | |
374 | 382 |
// If changed is unset, but created is, use that for last-modified. |
375 | 383 |
$event['last-modified'] = new DateObject($entity->created, 'UTC'); |
376 | 384 |
} |
377 |
|
|
385 |
|
|
378 | 386 |
// Allow other modules to alter the structured event object, before it gets |
379 | 387 |
// passed to the style plugin to be converted into an iCalcreator vevent. |
380 | 388 |
drupal_alter('date_ical_export_raw_event', $event, $this->view, $context); |
381 |
|
|
389 |
|
|
382 | 390 |
return $event; |
383 | 391 |
} |
384 | 392 |
} |
drupal7/sites/all/modules/date_ical/includes/date_ical_plugin_row_ical_fields.inc | ||
---|---|---|
9 | 9 |
* A Views plugin which builds an iCal VEVENT from a views row with Fields. |
10 | 10 |
*/ |
11 | 11 |
class date_ical_plugin_row_ical_fields extends views_plugin_row { |
12 |
|
|
12 |
|
|
13 | 13 |
/** |
14 | 14 |
* Set up the options for the row plugin. |
15 | 15 |
*/ |
... | ... | |
22 | 22 |
$options['additional_settings']['skip_blank_dates'] = array('default' => FALSE); |
23 | 23 |
return $options; |
24 | 24 |
} |
25 |
|
|
25 |
|
|
26 | 26 |
/** |
27 | 27 |
* Build the form for setting the row plugin's options. |
28 | 28 |
*/ |
... | ... | |
32 | 32 |
$date_field_labels = $this->get_date_field_candidates($all_field_labels); |
33 | 33 |
$date_field_label_options = array_merge(array('first_available' => t('First populated Date field')), $date_field_labels); |
34 | 34 |
$text_field_label_options = array_merge(array('' => t('- None -')), $all_field_labels); |
35 |
|
|
35 |
|
|
36 | 36 |
$form['instructions'] = array( |
37 | 37 |
// The surrounding <div> ensures that the settings dialog expands. |
38 | 38 |
'#prefix' => '<div style="font-size: 90%">', |
... | ... | |
88 | 88 |
'#default_value' => $this->options['additional_settings']['skip_blank_dates'], |
89 | 89 |
); |
90 | 90 |
} |
91 |
|
|
91 |
|
|
92 | 92 |
/** |
93 | 93 |
* Set up the environment for the render() function. |
94 | 94 |
*/ |
... | ... | |
101 | 101 |
} |
102 | 102 |
$this->repeated_dates = array(); |
103 | 103 |
} |
104 |
|
|
104 |
|
|
105 | 105 |
/** |
106 | 106 |
* Returns an Event array row in the query with index: $row->index. |
107 | 107 |
*/ |
108 | 108 |
public function render($row) { |
109 | 109 |
$date_field_name = $this->options['date_field']; |
110 |
|
|
110 |
|
|
111 | 111 |
// If this view is set to use the first populated date field, check each |
112 | 112 |
// field in the row to find the first non-NULL Date field. |
113 | 113 |
if ($date_field_name == 'first_available') { |
... | ... | |
123 | 123 |
} |
124 | 124 |
} |
125 | 125 |
} |
126 |
|
|
126 |
|
|
127 | 127 |
// Fetch the event's date information. |
128 | 128 |
try { |
129 | 129 |
if ($date_field_name == 'first_available') { |
... | ... | |
147 | 147 |
throw $e; |
148 | 148 |
} |
149 | 149 |
} |
150 |
|
|
150 |
|
|
151 | 151 |
// Create the event by starting with the date array from this row. |
152 | 152 |
$event = $date; |
153 |
|
|
153 |
|
|
154 | 154 |
$entity = $row->_field_data[$this->view->base_field]['entity']; |
155 | 155 |
$entity_type = $row->_field_data[$this->view->base_field]['entity_type']; |
156 | 156 |
// Add the CREATED, LAST-MODIFIED, and URL components based on the entity. |
... | ... | |
170 | 170 |
$uri = entity_uri($entity_type, $entity); |
171 | 171 |
$uri['options']['absolute'] = TRUE; |
172 | 172 |
$event['url'] = url($uri['path'], $uri['options']); |
173 |
|
|
173 |
|
|
174 | 174 |
// Generate a unique ID for this event by emulating the way the Date module |
175 | 175 |
// creates a Date ID. |
176 | 176 |
if (isset($row->{"field_data_{$date_field_name}_delta"})) { |
... | ... | |
193 | 193 |
global $base_url; |
194 | 194 |
$domain = preg_replace('#^https?://#', '', $base_url); |
195 | 195 |
$event['uid'] = "calendar.$entity_id.$date_field_name.$date_field_delta@$domain"; |
196 |
|
|
196 |
|
|
197 | 197 |
// Because of the way that Date implements repeating dates, we're going to |
198 | 198 |
// be given a separate view result for each repeat. We only want to |
199 | 199 |
// render a VEVENT (with an RRULE) for the first instance of that date, so |
... | ... | |
208 | 208 |
return FALSE; |
209 | 209 |
} |
210 | 210 |
} |
211 |
|
|
211 |
|
|
212 | 212 |
// Retrieve the rendered text fields. |
213 | 213 |
$text_fields['summary'] = $this->get_field($row->index, $this->options['title_field']); |
214 | 214 |
$text_fields['description'] = $this->get_field($row->index, $this->options['description_field']); |
215 | 215 |
$text_fields['location'] = $this->get_field($row->index, $this->options['location_field']); |
216 |
|
|
216 |
|
|
217 | 217 |
// Allow other modules to alter the rendered text fields before they get |
218 | 218 |
// sanitized for iCal-compliance. This is most useful for fields of type |
219 | 219 |
// "Content: Rendered Node", which are likely to have complex HTML. |
... | ... | |
224 | 224 |
'options' => $this->options, |
225 | 225 |
); |
226 | 226 |
drupal_alter('date_ical_export_html', $text_fields, $this->view, $context); |
227 |
|
|
227 |
|
|
228 | 228 |
// Sanitize the text fields for iCal compliance, and add them to the event. |
229 | 229 |
$event['summary'] = date_ical_sanitize_text($text_fields['summary']); |
230 | 230 |
$event['location'] = date_ical_sanitize_text($text_fields['location']); |
231 | 231 |
$event['description'] = date_ical_sanitize_text($text_fields['description']); |
232 |
|
|
232 |
|
|
233 | 233 |
// Allow other modules to alter the event object before it gets passed to |
234 | 234 |
// the style plugin to be converted into an iCal VEVENT. |
235 | 235 |
drupal_alter('date_ical_export_raw_event', $event, $this->view, $context); |
236 |
|
|
236 |
|
|
237 | 237 |
return $event; |
238 | 238 |
} |
239 | 239 |
|
... | ... | |
254 | 254 |
$rrule = NULL; |
255 | 255 |
$delta = 0; |
256 | 256 |
$is_date_field = FALSE; |
257 |
|
|
257 |
|
|
258 | 258 |
// Fetch the date field value. |
259 | 259 |
$date_field_value = $this->view->style_plugin->get_field_value($row->index, $date_field_name); |
260 |
|
|
260 |
|
|
261 | 261 |
// Handle date fields. |
262 | 262 |
if (isset($date_field_value[$delta]) && is_array($date_field_value[$delta])) { |
263 | 263 |
$is_date_field = TRUE; |
264 | 264 |
$date_field = $date_field_value[$delta]; |
265 |
|
|
265 |
|
|
266 | 266 |
$start = new DateObject($date_field['value'], $date_field['timezone_db']); |
267 | 267 |
if (!empty($date_field['value2'])) { |
268 | 268 |
$end = new DateObject($date_field['value2'], $date_field['timezone_db']); |
... | ... | |
270 | 270 |
else { |
271 | 271 |
$end = clone $start; |
272 | 272 |
} |
273 |
|
|
273 |
|
|
274 | 274 |
if (isset($date_field['rrule'])) { |
275 | 275 |
$rrule = $date_field['rrule']; |
276 | 276 |
} |
... | ... | |
285 | 285 |
$title = strip_tags($this->view->style_plugin->get_field($row->index, $this->options['title_field'])); |
286 | 286 |
throw new BlankDateFieldException(t("The row %title has a blank date. An iCal entry cannot be created for it.", array('%title' => $title))); |
287 | 287 |
} |
288 |
|
|
288 |
|
|
289 | 289 |
// Set the display timezone to whichever tz is stored for this field. |
290 | 290 |
// If there isn't a stored TZ, use the site default. |
291 | 291 |
$timezone = isset($date_field['timezone']) ? $date_field['timezone'] : date_default_timezone(FALSE); |
292 | 292 |
$dtz = new DateTimeZone($timezone); |
293 | 293 |
$start->setTimezone($dtz); |
294 | 294 |
$end->setTimezone($dtz); |
295 |
|
|
295 |
|
|
296 | 296 |
$granularity = 'second'; |
297 | 297 |
if ($is_date_field) { |
298 | 298 |
$granularity_settings = $this->view->field[$date_field_name]->field_info['settings']['granularity']; |
299 | 299 |
$granularity = date_granularity_precision($granularity_settings); |
300 | 300 |
} |
301 |
|
|
301 |
|
|
302 | 302 |
// Check if the start and end dates indicate that this is an All Day event. |
303 | 303 |
$all_day = date_is_all_day( |
304 | 304 |
date_format($start, DATE_FORMAT_DATETIME), |
305 | 305 |
date_format($end, DATE_FORMAT_DATETIME), |
306 | 306 |
$granularity |
307 | 307 |
); |
308 |
|
|
308 |
|
|
309 | 309 |
if ($all_day) { |
310 | 310 |
// According to RFC 2445 (clarified in RFC 5545) the DTEND value is |
311 | 311 |
// non-inclusive. When dealing with All Day values, they are DATEs rather |
312 | 312 |
// than DATETIMEs, so we need to add a day to conform to RFC. |
313 | 313 |
$end->modify("+1 day"); |
314 | 314 |
} |
315 |
|
|
315 |
|
|
316 | 316 |
$date = array( |
317 | 317 |
'start' => $start, |
318 | 318 |
'end' => $end, |
319 | 319 |
'all_day' => $all_day, |
320 | 320 |
'rrule' => $rrule, |
321 | 321 |
); |
322 |
|
|
322 |
|
|
323 | 323 |
return $date; |
324 | 324 |
} |
325 | 325 |
|
... | ... | |
339 | 339 |
$field_candidates = array(); |
340 | 340 |
// These are Date, Date (ISO format), and Date (Unix timestamp). |
341 | 341 |
$date_fields = array('datetime', 'date', 'datestamp'); |
342 |
|
|
342 |
|
|
343 | 343 |
foreach ($view_fields as $alias => $label) { |
344 | 344 |
$handler_class = get_class($handlers[$alias]); |
345 | 345 |
if ($handler_class == 'views_handler_field_date' |
drupal7/sites/all/modules/date_ical/includes/date_ical_plugin_style_ical_feed.inc | ||
---|---|---|
8 | 8 |
* Defines a Views style plugin that renders iCal feeds. |
9 | 9 |
*/ |
10 | 10 |
class date_ical_plugin_style_ical_feed extends views_plugin_style { |
11 |
|
|
11 |
|
|
12 | 12 |
/** |
13 | 13 |
* Internal helper function. |
14 | 14 |
*/ |
15 | 15 |
protected function _get_option($option_name) { |
16 | 16 |
return isset($this->options[$option_name]) ? $this->options[$option_name] : ''; |
17 | 17 |
} |
18 |
|
|
18 |
|
|
19 | 19 |
/** |
20 | 20 |
* Sets up the iCal feed icon on calendar pages. |
21 | 21 |
*/ |
... | ... | |
26 | 26 |
$url_options['query'] = $input; |
27 | 27 |
} |
28 | 28 |
$url_options['absolute'] = TRUE; |
29 |
|
|
29 |
|
|
30 | 30 |
$url = url($this->view->get_url(NULL, $path), $url_options); |
31 | 31 |
// If the user didn't disable the option, change the scheme to webcal:// |
32 | 32 |
// so calendar clients can automatically subscribe via the iCal link. |
33 | 33 |
if (!$this->_get_option('disable_webcal')) { |
34 | 34 |
$url = str_replace(array('http://', 'https://'), 'webcal://', $url); |
35 | 35 |
} |
36 |
|
|
36 |
|
|
37 | 37 |
// Render the feed icon and header tag (except during a View Preview). |
38 | 38 |
if (empty($this->view->live_preview)) { |
39 | 39 |
$tooltip = t('Add to My Calendar'); |
... | ... | |
57 | 57 |
)); |
58 | 58 |
} |
59 | 59 |
} |
60 |
|
|
60 |
|
|
61 | 61 |
/** |
62 | 62 |
* Set up the options for the style plugin. |
63 | 63 |
*/ |
64 | 64 |
public function option_definition() { |
65 | 65 |
$false_bool = array('default' => FALSE, 'bool' => TRUE); |
66 |
|
|
66 |
|
|
67 | 67 |
$options = parent::option_definition(); |
68 | 68 |
$options['cal_name'] = array('default' => array()); |
69 | 69 |
$options['no_calname'] = $false_bool; |
... | ... | |
72 | 72 |
$options['unescape_punctuation'] = $false_bool; |
73 | 73 |
return $options; |
74 | 74 |
} |
75 |
|
|
75 |
|
|
76 | 76 |
/** |
77 | 77 |
* Build the form for setting the style plugin's options. |
78 | 78 |
*/ |
... | ... | |
120 | 120 |
Enable this option to have Date iCal unescape these characters before it exports the iCal feed.'), |
121 | 121 |
); |
122 | 122 |
} |
123 |
|
|
123 |
|
|
124 | 124 |
/** |
125 | 125 |
* Render the event arrays returned by the row plugin into a VCALENDAR. |
126 | 126 |
*/ |
... | ... | |
148 | 148 |
} |
149 | 149 |
} |
150 | 150 |
unset($this->view->row_index); |
151 |
|
|
151 |
|
|
152 | 152 |
// Try to load the iCalcreator library. |
153 | 153 |
$library = libraries_load('iCalcreator'); |
154 | 154 |
if (!$library['loaded']) { |
... | ... | |
160 | 160 |
$config = array('unique_id' => 'Date iCal v' . DATE_ICAL_VERSION); |
161 | 161 |
$vcalendar = new vcalendar($config); |
162 | 162 |
$vcalendar->setMethod('PUBLISH'); |
163 |
|
|
163 |
|
|
164 | 164 |
// Only include the X-WR-CALNAME property if the user didn't enable |
165 | 165 |
// the "Exclude Calendar Name" option. |
166 | 166 |
if (!$this->_get_option('no_calname')) { |
... | ... | |
175 | 175 |
$vcalendar->setProperty('X-WR-CALNAME', $cal_name, array('VALUE' => 'TEXT')); |
176 | 176 |
} |
177 | 177 |
} |
178 |
|
|
178 |
|
|
179 | 179 |
// Now add the VEVENTs. |
180 | 180 |
$timezones = array(); |
181 | 181 |
foreach ($events as $event) { |
... | ... | |
185 | 185 |
// When this happens, just skip it. |
186 | 186 |
continue; |
187 | 187 |
} |
188 |
|
|
188 |
|
|
189 | 189 |
$vevent = $vcalendar->newComponent('vevent'); |
190 | 190 |
$vevent->setUid($event['uid']); |
191 | 191 |
$vevent->setSummary($event['summary']); |
192 |
|
|
192 |
|
|
193 | 193 |
// Get the start date as an array. |
194 | 194 |
$start = $event['start']->toArray(); |
195 | 195 |
$start_timezone = $event['start']->getTimezone()->getName(); |
196 | 196 |
$timezones[$start_timezone] = $start_timezone; |
197 |
|
|
197 |
|
|
198 | 198 |
if ($event['all_day']) { |
199 | 199 |
// All Day events need to be DATEs, rather than DATE-TIMEs. |
200 | 200 |
$vevent->setDtstart($start['year'], $start['month'], $start['day'], |
... | ... | |
211 | 211 |
$start_timezone |
212 | 212 |
); |
213 | 213 |
} |
214 |
|
|
214 |
|
|
215 | 215 |
// Add the Timezone info to the start date, for use later. |
216 | 216 |
$start['tz'] = $event['start']->getTimezone(); |
217 |
|
|
217 |
|
|
218 | 218 |
// Only add the end date if there is one. |
219 | 219 |
if (!empty($event['end'])) { |
220 | 220 |
$end = $event['end']->toArray(); |
221 | 221 |
$end_timezone = $event['end']->getTimezone()->getName(); |
222 | 222 |
$timezones[$end_timezone] = $end_timezone; |
223 |
|
|
223 |
|
|
224 | 224 |
if ($event['all_day']) { |
225 | 225 |
$vevent->setDtend($end['year'], $end['month'], $end['day'], |
226 | 226 |
FALSE, FALSE, FALSE, FALSE, array('VALUE' => 'DATE')); |
... | ... | |
238 | 238 |
} |
239 | 239 |
$end['tz'] = $event['end']->getTimezone(); |
240 | 240 |
} |
241 |
|
|
241 |
|
|
242 | 242 |
// Handle repeating dates from the date_repeat module. |
243 | 243 |
if (!empty($event['rrule']) && module_exists('date_repeat')) { |
244 | 244 |
// Split the rrule into an RRULE and any additions and exceptions. |
245 | 245 |
module_load_include('inc', 'date_api', 'date_api_ical'); |
246 | 246 |
module_load_include('inc', 'date_repeat', 'date_repeat_calc'); |
247 | 247 |
list($rrule, $exceptions, $additions) = date_repeat_split_rrule($event['rrule']); |
248 |
|
|
248 |
|
|
249 | 249 |
// Add the RRULE itself. We need to massage the data a bit, since |
250 | 250 |
// iCalcreator expects RRULEs to be in a different format than how |
251 | 251 |
// Date API gives them to us. |
252 | 252 |
$vevent->setRrule(_date_ical_convert_rrule_for_icalcreator($rrule)); |
253 |
|
|
253 |
|
|
254 | 254 |
// Convert any exceptions to EXDATE properties. |
255 | 255 |
if (!empty($exceptions)) { |
256 | 256 |
$exdates = array(); |
257 | 257 |
foreach ($exceptions as $exception) { |
258 | 258 |
$except = date_ical_date($exception, 'UTC'); |
259 |
date_timezone_set($except, $start['tz']);
|
|
259 |
$except->setTimezone($start['tz']);
|
|
260 | 260 |
$exception_array = $except->toArray(); |
261 | 261 |
$exdates[] = array( |
262 | 262 |
'year' => $exception_array['year'], |
... | ... | |
278 | 278 |
$vevent->setExdate(array($exdate)); |
279 | 279 |
} |
280 | 280 |
} |
281 |
|
|
281 |
|
|
282 | 282 |
// Convert any additions to RDATE properties. |
283 | 283 |
if (!empty($additions)) { |
284 | 284 |
$rdates = array(); |
285 | 285 |
foreach ($additions as $addition) { |
286 | 286 |
$add = date_ical_date($addition, 'UTC'); |
287 |
date_timezone_set($add, $start['tz']);
|
|
287 |
$add->setTimezone($start['tz']);
|
|
288 | 288 |
$addition_array = $add->toArray(); |
289 |
|
|
289 |
|
|
290 | 290 |
$rdate = array( |
291 | 291 |
'year' => $addition_array['year'], |
292 | 292 |
'month' => $addition_array['month'], |
293 | 293 |
'day' => $addition_array['day'], |
294 | 294 |
// If the user's copy of Date has support for time in RDATEs, |
295 | 295 |
// use that. Otherwise use the time from the start date. |
296 |
'hour' => isset($addition_array['hour']) ? $addition_array['hour'] : $start['hour'],
|
|
297 |
'min' => isset($addition_array['minute']) ? $addition_array['minute'] : $start['minute'],
|
|
298 |
'second' => isset($addition_array['second']) ? $addition_array['second'] : $start['second'],
|
|
296 |
'hour' => !empty($addition_array['hour']) ? $addition_array['hour'] : $start['hour'],
|
|
297 |
'min' => !empty($addition_array['minute']) ? $addition_array['minute'] : $start['minute'],
|
|
298 |
'second' => !empty($addition_array['second']) ? $addition_array['second'] : $start['second'],
|
|
299 | 299 |
'tz' => $start['tz']->getName(), |
300 | 300 |
); |
301 |
|
|
301 |
|
|
302 | 302 |
// If an end date was was calculated above, use that too. |
303 | 303 |
// iCalcreator expects RDATEs that have end dates to be |
304 | 304 |
// specified as array($start_rdate, $end_rdate). |
... | ... | |
310 | 310 |
'day' => $addition_array['day'], |
311 | 311 |
// If the user's copy of Date has support for time in RDATEs, |
312 | 312 |
// use that. Otherwise use the time from the end date. |
313 |
'hour' => isset($addition_array['hour']) ? $addition_array['hour'] : $end['hour'],
|
|
314 |
'min' => isset($addition_array['minute']) ? $addition_array['minute'] : $end['minute'],
|
|
315 |
'second' => isset($addition_array['second']) ? $addition_array['second'] : $end['second'],
|
|
313 |
'hour' => !empty($addition_array['hour']) ? $addition_array['hour'] : $end['hour'],
|
|
314 |
'min' => !empty($addition_array['minute']) ? $addition_array['minute'] : $end['minute'],
|
|
315 |
'second' => !empty($addition_array['second']) ? $addition_array['second'] : $end['second'],
|
|
316 | 316 |
'tz' => $end['tz']->getName(), |
317 | 317 |
); |
318 | 318 |
$rdate = $rdate_with_end; |
319 | 319 |
} |
320 |
|
|
320 |
|
|
321 | 321 |
$rdates[] = $rdate; |
322 | 322 |
} |
323 | 323 |
// Add each addition as a separate RDATE property. |
... | ... | |
362 | 362 |
$created['timezone'] |
363 | 363 |
); |
364 | 364 |
} |
365 |
|
|
365 |
|
|
366 | 366 |
// Allow other modules to alter the vevent before it's exported. |
367 | 367 |
drupal_alter('date_ical_export_vevent', $vevent, $this->view, $event); |
368 | 368 |
} |
369 |
|
|
369 |
|
|
370 | 370 |
// Now add to the calendar all the timezones used by the events. |
371 | 371 |
foreach ($timezones as $timezone) { |
372 | 372 |
if (strtoupper($timezone) != 'UTC') { |
373 | 373 |
iCalUtilityFunctions::createTimezone($vcalendar, $timezone); |
374 | 374 |
} |
375 | 375 |
} |
376 |
|
|
376 |
|
|
377 | 377 |
// Allow other modules to alter the vcalendar before it's exported. |
378 | 378 |
drupal_alter('date_ical_export_vcalendar', $vcalendar, $this->view); |
379 |
|
|
379 |
|
|
380 | 380 |
$output = $vcalendar->createCalendar(); |
381 | 381 |
// iCalcreator escapes all commas and semicolons in string values, as the |
382 | 382 |
// spec demands. However, some calendar clients are buggy and fail to |
... | ... | |
388 | 388 |
$output = str_replace('\,', ',', $output); |
389 | 389 |
$output = str_replace('\;', ';', $output); |
390 | 390 |
} |
391 |
|
|
391 |
|
|
392 | 392 |
// In order to respect the Exclude DTSTAMP option, we unfortunately have |
393 | 393 |
// to parse out the DTSTAMP properties after they get rendered. Simply |
394 | 394 |
// using deleteProperty('DTSTAMP') doesn't work, because iCalcreator |
... | ... | |
405 | 405 |
$output = implode("\r\n", $filtered_lines); |
406 | 406 |
} |
407 | 407 |
} |
408 |
|
|
408 |
|
|
409 | 409 |
// These steps shouldn't be run during Preview on the View page. |
410 | 410 |
if (empty($this->view->live_preview)) { |
411 | 411 |
// Prevent devel module from appending queries to ical export. |
412 | 412 |
$GLOBALS['devel_shutdown'] = FALSE; |
413 |
|
|
413 |
|
|
414 | 414 |
drupal_add_http_header('Content-Type', 'text/calendar; charset=UTF-8'); |
415 | 415 |
drupal_add_http_header('Cache-Control', 'no-cache, must-revalidate'); |
416 | 416 |
drupal_add_http_header('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT'); |
417 |
|
|
417 |
|
|
418 | 418 |
// For sites with Clean URLs disabled, the Display's "path" value ends |
419 | 419 |
// up only in the query args, meaning the filename won't be set properly |
420 | 420 |
// when users download the feed. So we need to manually instruct browsers |
... | ... | |
425 | 425 |
drupal_add_http_header('Content-Disposition', "attachment; filename=\"$filename\""); |
426 | 426 |
} |
427 | 427 |
} |
428 |
|
|
428 |
|
|
429 | 429 |
// Allow other modules to alter the rendered calendar. |
430 | 430 |
drupal_alter('date_ical_export_post_render', $output, $this->view); |
431 |
|
|
431 |
|
|
432 | 432 |
return $output; |
433 | 433 |
} |
434 | 434 |
} |
drupal7/sites/all/modules/date_ical/libraries/ParserVcalendar.inc | ||
---|---|---|
15 | 15 |
protected $config; |
16 | 16 |
protected $timezones = array(); |
17 | 17 |
protected $xtimezone; |
18 |
|
|
18 |
|
|
19 | 19 |
/** |
20 | 20 |
* The parsed data for the component that's currently being processed. |
21 | 21 |
* |
... | ... | |
26 | 26 |
* @var array |
27 | 27 |
*/ |
28 | 28 |
protected $parsed_data = array(); |
29 |
|
|
29 |
|
|
30 | 30 |
/** |
31 | 31 |
* Variables used for batch processing. |
32 | 32 |
*/ |
33 | 33 |
protected $totalComponents = 0; |
34 | 34 |
protected $lastComponentParsed = 0; |
35 |
|
|
35 |
|
|
36 | 36 |
/** |
37 | 37 |
* This is the list of iCal properties which are allowed to have more than |
38 | 38 |
* one entry in a single VEVENT. If we ever support parsing more than just |
... | ... | |
43 | 43 |
'EXDATE', 'EXRULE', 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', |
44 | 44 |
'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' |
45 | 45 |
); |
46 |
|
|
46 |
|
|
47 | 47 |
/** |
48 | 48 |
* Constructor. |
49 | 49 |
*/ |
... | ... | |
54 | 54 |
$this->fetcherResult = $fetcher_result; |
55 | 55 |
$this->config = $config; |
56 | 56 |
} |
57 |
|
|
57 |
|
|
58 | 58 |
/** |
59 | 59 |
* Parses the vcalendar object into an array of event data arrays. |
60 | 60 |
* |
... | ... | |
90 | 90 |
while ($component = $this->calendar->getComponent('VTIMEZONE')) { |
91 | 91 |
$this->timezones[] = $component; |
92 | 92 |
} |
93 |
|
|
93 |
|
|
94 | 94 |
// This context array is used by date_ical_import_component_alter() and |
95 | 95 |
// date_ical_import_parsed_data_alter(). |
96 | 96 |
$context2 = array( |
... | ... | |
98 | 98 |
'source' => $this->source, |
99 | 99 |
'fetcher_result' => $this->fetcherResult, |
100 | 100 |
); |
101 |
|
|
101 |
|
|
102 | 102 |
// Collect each component, so we can batch them properly in the next loop. |
103 | 103 |
$raw_components = array(); |
104 | 104 |
$types = array('VEVENT', 'VTODO', 'VJOURNAL', 'VFREEBUSY', 'VALARM'); |
... | ... | |
110 | 110 |
$raw_components[] = $vcalendar_component; |
111 | 111 |
} |
112 | 112 |
} |
113 |
|
|
113 |
|
|
114 | 114 |
// Store this for use by DateiCalFeedsParser's batch processing code. |
115 | 115 |
$this->totalComponents = count($raw_components); |
116 |
|
|
116 |
|
|
117 | 117 |
// Parse each raw component in the current batch into a Feeds-compatible |
118 | 118 |
// event data array. |
119 | 119 |
$events = array(); |
... | ... | |
152 | 152 |
if ($handler) { |
153 | 153 |
$this->parsed_data[$property_key] = $this->$handler($property_key, $raw_component); |
154 | 154 |
} |
155 |
|
|
155 |
|
|
156 | 156 |
if ($property_key == 'geofield' && !empty($this->parsed_data['geofield'])) { |
157 | 157 |
// To make our data readable by geofield_feeds_combined_source(), we |
158 | 158 |
// need to put it into the format output by Simplepie 1.3. |
... | ... | |
160 | 160 |
$this->parsed_data['location_longitude'] = array($this->parsed_data['geofield']['lon']); |
161 | 161 |
} |
162 | 162 |
} |
163 |
|
|
163 |
|
|
164 | 164 |
// Allow modules to alter the final parsed data before we send it to the |
165 | 165 |
// Feeds processor. |
166 | 166 |
drupal_alter('date_ical_import_post_parse', $this->parsed_data, $context2); |
167 |
|
|
167 |
|
|
168 | 168 |
// Skip this event if it's earlier than the user's specified skip time. |
169 | 169 |
if (!$this->_skip_current_event()) { |
170 | 170 |
$events[] = $this->parsed_data; |
... | ... | |
174 | 174 |
// through the full collection of components. |
175 | 175 |
$this->lastComponentParsed = $ndx; |
176 | 176 |
} |
177 |
|
|
177 |
|
|
178 | 178 |
return $events; |
179 | 179 |
} |
180 |
|
|
180 |
|
|
181 | 181 |
/** |
182 | 182 |
* Getter for the protected totalComponents property. |
183 | 183 |
*/ |
184 | 184 |
public function getTotalComponents() { |
185 | 185 |
return $this->totalComponents; |
186 | 186 |
} |
187 |
|
|
187 |
|
|
188 | 188 |
/** |
189 | 189 |
* Getter for the protected lastComponentParsed property. |
190 | 190 |
*/ |
191 | 191 |
public function getLastComponentParsed() { |
192 | 192 |
return $this->lastComponentParsed; |
193 | 193 |
} |
194 |
|
|
194 |
|
|
195 | 195 |
/** |
196 | 196 |
* Handler that parses GEO fields. |
197 | 197 |
* |
... | ... | |
206 | 206 |
} |
207 | 207 |
return $geo; |
208 | 208 |
} |
209 |
|
|
209 |
|
|
210 | 210 |
/** |
211 | 211 |
* Handler that parses text fields. |
212 | 212 |
* |
... | ... | |
223 | 223 |
if (in_array($property_key, $this->multi_entry_properties)) { |
224 | 224 |
unset($vcalendar_component->propix[$property_key]); |
225 | 225 |
} |
226 |
|
|
226 |
|
|
227 | 227 |
if ($text === FALSE) { |
228 | 228 |
if ($property_key != 'SUMMARY') { |
229 | 229 |
return NULL; |
Formats disponibles : Unified diff
Weekly update of contrib modules