Fixed issue #1521240 by MJCO: Added Move from 'Fields' module group to 'Share/Sharing'.
[project/addthis.git] / classes / AddThis.php
1 <?php
2 /**
3 * @file
4 * An AddThis-class.
5 */
6
7 class AddThis {
8
9 const BLOCK_NAME = 'addthis_block';
10 const DEFAULT_CUSTOM_CONFIGURATION_CODE = 'var addthis_config = {}';
11 const DEFAULT_FORMATTER = 'addthis_default_formatter';
12 const DEFAULT_NUMBER_OF_PREFERRED_SERVICES = 4;
13 const FIELD_TYPE = 'addthis';
14 const MODULE_NAME = 'addthis';
15 const PERMISSION_ADMINISTER_ADDTHIS = 'administer addthis';
16 const PERMISSION_ADMINISTER_ADVANCED_ADDTHIS = 'administer advanced addthis';
17 const STYLE_KEY = 'addthis_style';
18 const WIDGET_TYPE = 'addthis_button_widget';
19
20 // AddThis attribute and parameter names (as defined in AddThis APIs)
21 const PROFILE_ID_QUERY_PARAMETER = 'pubid';
22 const TITLE_ATTRIBUTE = 'addthis:title';
23 const URL_ATTRIBUTE = 'addthis:url';
24
25 // Persistent variable keys
26 const ADDRESSBOOK_ENABLED_KEY = 'addthis_addressbook_enabled';
27 const BLOCK_WIDGET_TYPE_KEY = 'addthis_block_widget_type';
28 const BOOKMARK_URL_KEY = 'addthis_bookmark_url';
29 const CLICKBACK_TRACKING_ENABLED_KEY = 'addthis_clickback_tracking_enabled';
30 const CLICK_TO_OPEN_COMPACT_MENU_ENABLED_KEY = 'addthis_click_to_open_compact_menu_enabled';
31 const CO_BRAND_KEY = 'addthis_co_brand';
32 const COMPLIANT_508_KEY = 'addthis_508_compliant';
33 const CUSTOM_CONFIGURATION_CODE_ENABLED_KEY = 'addthis_custom_configuration_code_enabled';
34 const CUSTOM_CONFIGURATION_CODE_KEY = 'addthis_custom_configuration_code';
35 const ENABLED_SERVICES_KEY = 'addthis_enabled_services';
36 const GOOGLE_ANALYTICS_TRACKING_ENABLED_KEY = 'addthis_google_analytics_tracking_enabled';
37 const GOOGLE_ANALYTICS_SOCIAL_TRACKING_ENABLED_KEY = 'addthis_google_analytics_social_tracking_enabled';
38 const FACEBOOK_LIKE_COUNT_SUPPORT_ENABLED = 'addthis_facebook_like_count_support_enabled';
39 const OPEN_WINDOWS_ENABLED_KEY = 'addthis_open_windows_enabled';
40 const PROFILE_ID_KEY = 'addthis_profile_id';
41 const SERVICES_CSS_URL_KEY = 'addthis_services_css_url';
42 const SERVICES_JSON_URL_KEY = 'addthis_services_json_url';
43 const STANDARD_CSS_ENABLED_KEY = 'addthis_standard_css_enabled';
44 const UI_DELAY_KEY = 'addthis_ui_delay';
45 const UI_HEADER_BACKGROUND_COLOR_KEY = 'addthis_ui_header_background_color';
46 const UI_HEADER_COLOR_KEY = 'addthis_ui_header_color';
47 const WIDGET_JS_URL_KEY = 'addthis_widget_js_url';
48 const WIDGET_JS_ASYNC = 'addthis_widget_async';
49
50 // Twitter
51 const TWITTER_VIA_KEY = 'addthis_twitter_via';
52 const TWITTER_VIA_DEFAULT = 'AddThis';
53 const TWITTER_TEMPLATE_KEY = 'addthis_twitter_template';
54 const TWITTER_TEMPLATE_DEFAULT = '{{title}} {{url}} via @AddThis';
55
56 // External resources
57 const DEFAULT_BOOKMARK_URL = 'http://www.addthis.com/bookmark.php?v=250';
58 const DEFAULT_SERVICES_CSS_URL = 'http://cache.addthiscdn.com/icons/v1/sprites/services.css';
59 const DEFAULT_SERVICES_JSON_URL = 'http://cache.addthiscdn.com/services/v1/sharing.en.json';
60 const DEFAULT_WIDGET_JS_URL = 'http://s7.addthis.com/js/250/addthis_widget.js';
61 const DEFAULT_WIDGET_JS_ASYNC = TRUE;
62
63 // Internal resources
64 const ADMIN_CSS_FILE = 'addthis.admin.css';
65 const ADMIN_INCLUDE_FILE = 'includes/addthis.admin.inc';
66
67 // Widget types
68 const WIDGET_TYPE_DISABLED = 'addthis_disabled';
69
70 // Styles
71 const CSS_32x32 = 'addthis_32x32_style';
72 const CSS_16x16 = 'addthis_16x16_style';
73
74 private static $instance;
75
76 /* @var AddThisJson */
77 private $json;
78
79 /**
80 * @return AddThis
81 */
82 public static function getInstance() {
83 module_load_include('php', 'addthis', 'classes/AddThisJson');
84 if (!isset(self::$instance)) {
85 $addThis = new AddThis();
86 $addThis->setJson(new AddThisJson());
87 self::$instance = $addThis;
88 }
89 return self::$instance;
90 }
91
92 public function setJson(AddThisJson $json) {
93 $this->json = $json;
94 }
95
96 public function getDefaultFormatterTypes() {
97 return array(
98 self::WIDGET_TYPE_DISABLED => t('Disabled'),
99 );
100 }
101
102 public function getDisplayTypes() {
103 $displays = array();
104 foreach ($display_impl = _addthis_field_info_formatter_field_type() as $key => $display) {
105 $displays[$key] = t(check_plain($display['label']));
106 }
107 return $displays;
108 }
109
110 /*
111 * Get markup for a given display type.
112 *
113 * When $options does not contain #entity, link to the current URL.
114 * When $options does not contain #display, use default settings.
115 */
116 public function getDisplayMarkup($display, $options = array()) {
117 if (empty($display)) {
118 return array();
119 }
120
121 $formatters = _addthis_field_info_formatter_field_type();
122
123 if (!array_key_exists($display, $formatters)) {
124 return array();
125 }
126
127 // The display type exists. Now get it and get the markup.
128 $display_information = $formatters[$display];
129
130 // Theme function might only give a display name and
131 // render on default implementation.
132 if (!isset($options['#display']) ||
133 (isset($options['#display']['type']) && $options['#display']['type'] != $display)) {
134
135 $options['#display'] = isset($options['#display']) ? $options['#display'] : array();
136 $options['#display'] = array_merge($options['#display'], $display_information);
137 $options['#display']['type'] = $display;
138
139 }
140
141 // When #entity and #entity_type exist, use the entity's URL.
142 if (isset($options['#entity']) && isset($options['#entity_type'])) {
143 $uri = entity_uri($options['#entity_type'], $options['#entity']);
144 $uri['options'] += array(
145 'absolute' => TRUE,
146 );
147
148 // @todo Add a hook to alter the uri also based on fields from the
149 // entity (such as custom share link). Pass $options and $uri. Return
150 // a uri object to which we can reset it. Maybe use the alter structure.
151
152 $options['#url'] = url($uri['path'], $uri['options']);
153 }
154 // @todo Hash the options array and cache the markup.
155 // This will save all the extra calls to modules and alters.
156
157 // Allow other modules to alter markup options.
158 drupal_alter('addthis_markup_options', $options);
159
160 $markup = array(
161 '#display' => $options['#display'],
162 );
163 // Get all hook implementation to verify later if we can call it.
164 $addthis_display_markup_implementations = module_implements('addthis_display_markup');
165
166 // Look for a targeted implementation to call.
167 // This should be the default implementation that is called.
168 if (function_exists($display_information['module'] . '_addthis_display_markup__' . $display)) {
169 $markup += call_user_func_array($display_information['module'] . '_addthis_display_markup__' . $display, array($options));
170 }
171 elseif (in_array($display_information['module'], $addthis_display_markup_implementations)) {
172 $markup += module_invoke($display_information['module'], 'addthis_display_markup', $display, $options);
173 }
174 // Allow other modules to alter markup.
175 drupal_alter('addthis_markup', $markup);
176 return $markup;
177 }
178
179 public function getServices() {
180 $rows = array();
181 $services = $this->json->decode($this->getServicesJsonUrl());
182 if (empty($services)) {
183 drupal_set_message(t('AddThis services could not be loaded from @service_url', array('@service_url', $this->getServicesJsonUrl())), 'warning');
184 }
185 else {
186 foreach ($services['data'] as $service) {
187 $serviceCode = check_plain($service['code']);
188 $serviceName = check_plain($service['name']);
189 $rows[$serviceCode] = '<span class="addthis_service_icon icon_' . $serviceCode . '"></span> ' . $serviceName;
190 }
191 }
192 return $rows;
193 }
194
195 public function addWidgetJs() {
196 $async_parameter = self::isWidgetJsAsync() ? '?async=1' : '';
197 $url = self::getWidgetUrl() . $async_parameter;
198 if (self::isWidgetJsAsync()) {
199 drupal_add_js(
200 array(
201 'addthis' => array(
202 'widget_url' => $url,
203 ),
204 ),
205 'setting'
206 );
207 }
208 else {
209 // Add AddThis.com resources
210 drupal_add_js(
211 $url,
212 array(
213 'type' => 'external',
214 'group' => JS_LIBRARY,
215 'every_page' => TRUE,
216 'weight' => 9,
217 )
218 );
219 }
220 // Add local internal behaviours
221 if (self::isWidgetJsAsync()) {
222 drupal_add_js(
223 drupal_get_path('module', 'addthis') . '/addthis.js',
224 array(
225 'group' => JS_DEFAULT,
226 'weight' => 10,
227 'every_page' => TRUE,
228 'preprocess' => TRUE,
229 )
230 );
231 }
232 }
233
234 public function addConfigurationOptionsJs() {
235 if ($this->isCustomConfigurationCodeEnabled()) {
236 $configurationOptionsJavascript = $this->getCustomConfigurationCode();
237 }
238 else {
239 $enabledServices = $this->getServiceNamesAsCommaSeparatedString() . 'more';
240
241 global $language;
242 $configuration = array(
243 'services_compact' => $enabledServices,
244 'data_track_clickback' => $this->isClickbackTrackingEnabled(),
245 'ui_508_compliant' => $this->get508Compliant(),
246 'ui_click' => $this->isClickToOpenCompactMenuEnabled(),
247 'ui_cobrand' => $this->getCoBrand(),
248 'ui_delay' => $this->getUiDelay(),
249 'ui_header_background' => $this->getUiHeaderBackgroundColor(),
250 'ui_header_color' => $this->getUiHeaderColor(),
251 'ui_open_windows' => $this->isOpenWindowsEnabled(),
252 'ui_use_css' => $this->isStandardCssEnabled(),
253 'ui_use_addressbook' => $this->isAddressbookEnabled(),
254 'ui_language' => $language->language,
255 );
256 if (module_exists('googleanalytics')) {
257 if ($this->isGoogleAnalyticsTrackingEnabled()) {
258 $configuration['data_ga_property'] = variable_get('googleanalytics_account', '');
259 $configuration['data_ga_social'] = $this->isGoogleAnalyticsSocialTrackingEnabled();
260 }
261 }
262 $configuration['templates']['twitter'] = $this->getTwitterTemplate();
263 drupal_alter('addthis_configuration', $configuration);
264
265 $templates = array('templates' => $configuration['templates']);
266 unset($configuration['templates']);
267 $configurationOptionsJavascript = 'var addthis_config = ' . drupal_json_encode($configuration) . "\n";
268 $configurationOptionsJavascript .= 'var addthis_share = ' . drupal_json_encode($templates);
269 }
270 drupal_add_js(
271 $configurationOptionsJavascript,
272 array(
273 'type' => 'inline',
274 'scope' => 'footer',
275 'every_page' => TRUE,
276 )
277 );
278 }
279
280 public function getAddThisAttributesMarkup($options) {
281 if (isset($options)) {
282 $attributes = array();
283
284 if (isset($options['#entity'])) {
285 $attributes += $this->getAttributeTitle($options['#entity']);
286 }
287 $attributes += $this->getAttributeUrl($options);
288
289 return $attributes;
290 }
291 return array();
292 }
293
294 public function getBlockDisplayType() {
295 return variable_get(self::BLOCK_WIDGET_TYPE_KEY, self::WIDGET_TYPE_DISABLED);
296 }
297
298 public function getProfileId() {
299 return check_plain(variable_get(AddThis::PROFILE_ID_KEY));
300 }
301
302 public function getServicesCssUrl() {
303 return check_url(variable_get(AddThis::SERVICES_CSS_URL_KEY, self::DEFAULT_SERVICES_CSS_URL));
304 }
305
306 public function getServicesJsonUrl() {
307 return check_url(variable_get(AddThis::SERVICES_JSON_URL_KEY, self::DEFAULT_SERVICES_JSON_URL));
308 }
309
310 public function getEnabledServices() {
311 return variable_get(self::ENABLED_SERVICES_KEY, array());
312 }
313
314 public function isWidgetJsAsync() {
315 return variable_get(self::WIDGET_JS_ASYNC, self::DEFAULT_WIDGET_JS_ASYNC);
316 }
317
318 public function isClickToOpenCompactMenuEnabled() {
319 return (boolean) variable_get(self::CLICK_TO_OPEN_COMPACT_MENU_ENABLED_KEY, FALSE);
320 }
321
322 public function isOpenWindowsEnabled() {
323 return (boolean) variable_get(self::OPEN_WINDOWS_ENABLED_KEY, FALSE);
324 }
325
326 public function getUiDelay() {
327 return (int) check_plain(variable_get(self::UI_DELAY_KEY));
328 }
329
330 public function getUiHeaderColor() {
331 return check_plain(variable_get(self::UI_HEADER_COLOR_KEY));
332 }
333
334 public function getUiHeaderBackgroundColor() {
335 return check_plain(variable_get(self::UI_HEADER_BACKGROUND_COLOR_KEY));
336 }
337
338 public function isStandardCssEnabled() {
339 return (boolean) variable_get(self::STANDARD_CSS_ENABLED_KEY, TRUE);
340 }
341
342 public function getCustomConfigurationCode() {
343 return variable_get(self::CUSTOM_CONFIGURATION_CODE_KEY, self::DEFAULT_CUSTOM_CONFIGURATION_CODE);
344 }
345
346 public function isCustomConfigurationCodeEnabled() {
347 return (boolean) variable_get(self::CUSTOM_CONFIGURATION_CODE_ENABLED_KEY, FALSE);
348 }
349
350 public function getBaseWidgetJsUrl() {
351 return check_url(variable_get(self::WIDGET_JS_URL_KEY, self::DEFAULT_WIDGET_JS_URL));
352 }
353
354 public function getBaseBookmarkUrl() {
355 return check_url(variable_get(self::BOOKMARK_URL_KEY, self::DEFAULT_BOOKMARK_URL));
356 }
357
358 public function getCoBrand() {
359 return variable_get(self::CO_BRAND_KEY, '');
360 }
361
362 public function get508Compliant() {
363 return (boolean) variable_get(self::COMPLIANT_508_KEY, FALSE);
364 }
365
366 public function getTwitterVia() {
367 return variable_get(self::TWITTER_VIA_KEY, self::TWITTER_VIA_DEFAULT);
368 }
369
370 public function getTwitterTemplate() {
371 return variable_get(self::TWITTER_TEMPLATE_KEY, self::TWITTER_TEMPLATE_DEFAULT);
372 }
373
374 public function isClickbackTrackingEnabled() {
375 return (boolean) variable_get(self::CLICKBACK_TRACKING_ENABLED_KEY, FALSE);
376 }
377
378 public function isAddressbookEnabled() {
379 return (boolean) variable_get(self::ADDRESSBOOK_ENABLED_KEY, FALSE);
380 }
381
382 public function isGoogleAnalyticsTrackingEnabled() {
383 return (boolean) variable_get(self::GOOGLE_ANALYTICS_TRACKING_ENABLED_KEY, FALSE);
384 }
385
386 public function isGoogleAnalyticsSocialTrackingEnabled() {
387 return (boolean) variable_get(self::GOOGLE_ANALYTICS_SOCIAL_TRACKING_ENABLED_KEY, FALSE);
388 }
389
390 public function isFacebookLikeCountSupportEnabled() {
391 return (boolean) variable_get(self::FACEBOOK_LIKE_COUNT_SUPPORT_ENABLED, TRUE);
392 }
393
394 public function addStylesheets() {
395 drupal_add_css($this->getServicesCssUrl(), 'external');
396 drupal_add_css($this->getAdminCssFilePath(), 'file');
397 }
398
399 public function getFullBookmarkUrl() {
400 return $this->getBaseBookmarkUrl() . $this->getProfileIdQueryParameterPrefixedWithAmp();
401 }
402
403 private function getAttributeTitle($entity) {
404 if (isset($entity->title)) {
405 return array(
406 self::TITLE_ATTRIBUTE => (check_plain($entity->title) . ' - ' . variable_get('site_name')),
407 );
408 }
409 return array();
410 }
411
412 private function getAttributeUrl($options) {
413 if (isset($options['#url'])) {
414 return array(
415 self::URL_ATTRIBUTE => $options['#url'],
416 );
417 }
418 return array();
419 }
420
421 private function getServiceNamesAsCommaSeparatedString() {
422 $enabledServiceNames = array_values($this->getEnabledServices());
423 $enabledServicesAsCommaSeparatedString = '';
424 foreach ($enabledServiceNames as $enabledServiceName) {
425 if ($enabledServiceName != '0') {
426 $enabledServicesAsCommaSeparatedString .= $enabledServiceName . ',';
427 }
428 }
429 return $enabledServicesAsCommaSeparatedString;
430 }
431
432 private function getAdminCssFilePath() {
433 return drupal_get_path('module', self::MODULE_NAME) . '/' . self::ADMIN_CSS_FILE;
434 }
435
436 private function getProfileIdQueryParameter($prefix) {
437 $profileId = $this->getProfileId();
438 return !empty($profileId) ? $prefix . self::PROFILE_ID_QUERY_PARAMETER . '=' . $profileId : '';
439 }
440
441 private function getProfileIdQueryParameterPrefixedWithAmp() {
442 return $this->getProfileIdQueryParameter('&');
443 }
444
445 private function getProfileIdQueryParameterPrefixedWithHash() {
446 return $this->getProfileIdQueryParameter('#');
447 }
448
449 private function getWidgetUrl() {
450 return check_url($this->validateSecureUrl($this->getBaseWidgetJsUrl()) . $this->getProfileIdQueryParameterPrefixedWithHash());
451 }
452
453 private function validateSecureUrl($url) {
454 global $base_root;
455 if (strpos($base_root, 'https://') !== FALSE) {
456 $url = (strpos($url, 'http://') === 0 ? 'https://' . substr($url, 7) : $url);
457 }
458 return $url;
459 }
460 }