jquery_update.module 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. <?php
  2. /**
  3. * @file
  4. * Updates Drupal to use the latest version of jQuery.
  5. */
  6. /**
  7. * Implements hook_help().
  8. */
  9. function jquery_update_help($path, $arg) {
  10. switch ($path) {
  11. // Help for another path in the block module.
  12. case 'admin/config/development/jquery_update':
  13. return '<p>' . t('Configure how <a href="@jquery">jQuery</a> behaves on the site. Select which jQuery version, the compression level and whether or not to use a CDN.', array(
  14. '@jquery' => 'http://jquery.com',
  15. )) . '</p>';
  16. }
  17. }
  18. /**
  19. * Implements hook_library().
  20. */
  21. function jquery_update_library() {
  22. // Register libraries available in the external directory.
  23. $path = drupal_get_path('module', 'jquery_update') . '/ui/external';
  24. $libraries['qunit'] = array(
  25. 'title' => 'QUnit',
  26. 'js' => array(
  27. $path . '/qunit.js' => array(
  28. 'group' => JS_LIBRARY,
  29. 'weight' => 2,
  30. ),
  31. ),
  32. 'css' => array(
  33. $path . '/qunit.css' => array(),
  34. ),
  35. 'version' => '1.11.0',
  36. );
  37. $libraries['jquery_update.ajax.fix'] = array(
  38. 'title' => 'jQuery Update Version Fix',
  39. 'js' => array(
  40. drupal_get_path('module', 'jquery_update') . '/js/jquery_update.js' => array(
  41. 'group' => JS_LIBRARY,
  42. 'weight' => 3,
  43. ),
  44. ),
  45. 'version' => '0.0.1',
  46. );
  47. $libraries['jquery.metadata'] = array(
  48. 'title' => 'QUnit',
  49. 'js' => array(
  50. $path . '/jquery.metadata.js' => array(
  51. 'group' => JS_LIBRARY,
  52. 'weight' => 2,
  53. ),
  54. ),
  55. 'version' => '4187',
  56. );
  57. $libraries['jquery.bgiframe'] = array(
  58. 'title' => 'bgiframe',
  59. 'website' => 'http://docs.jquery.com/Plugins/bgiframe',
  60. 'js' => array(
  61. $path . '/jquery.bgiframe.js' => array(
  62. 'group' => JS_LIBRARY,
  63. 'weight' => 2,
  64. ),
  65. ),
  66. 'version' => '2.1.2',
  67. );
  68. return $libraries;
  69. }
  70. /**
  71. * Implements hook_library_alter().
  72. */
  73. function jquery_update_library_alter(&$javascript, $module) {
  74. $path = drupal_get_path('module', 'jquery_update');
  75. $version = variable_get('jquery_update_jquery_version', '1.10');
  76. // Modified System Library.
  77. if ($module === 'system') {
  78. // Make sure we inject either the minified or uncompressed version as desired.
  79. $min = variable_get('jquery_update_compression_type', 'min') == 'none' ? '' : '.min';
  80. $cdn = variable_get('jquery_update_jquery_cdn', 'none');
  81. // Replace jQuery with the alternative version.
  82. $admin_version = variable_get('jquery_update_jquery_admin_version', '');
  83. if (!empty($admin_version) && path_is_admin(current_path())) {
  84. if (version_compare($version, $admin_version, '!=')) {
  85. $version = $admin_version;
  86. }
  87. }
  88. // If the ajax version is set then that one always win.
  89. if (!empty($_POST['ajax_page_state']['jquery_version'])) {
  90. $ajax_version = $_POST['ajax_page_state']['jquery_version'];
  91. if (in_array($ajax_version, array('default', '1.5', '1.6', '1.7', '1.8', '1.9', '1.10'))) {
  92. $version = $ajax_version;
  93. }
  94. }
  95. // Always add a new jquery_version array to ajaxPageState.
  96. // This is what we used to determine which version to use
  97. // for any ajax callback.
  98. $javascript['drupal.ajax']['js'][] = array(
  99. 'data' => array('ajaxPageState' => array('jquery_version' => $version)),
  100. 'type' => 'setting',
  101. );
  102. $javascript['drupal.ajax']['dependencies'][] = array('jquery_update', 'jquery_update.ajax.fix');
  103. // Don't replace anything if Drupal provided jQuery should be used
  104. if ('default' == $version) {
  105. return;
  106. }
  107. jquery_update_jquery_replace($javascript, $cdn, $path, $min, $version);
  108. // Replace jQuery UI with CDN or local files. If from a CDN include all of
  109. // jQuery UI.
  110. if (version_compare($version, '1.6', '>=')) {
  111. jquery_update_jqueryui_replace($javascript, $cdn, $path, $min);
  112. }
  113. // Replace the jQuery Cookie plugin.
  114. $javascript['cookie']['js']['misc/jquery.cookie.js']['data'] = $path . '/replace/ui/external/jquery.cookie.js';
  115. // Noting the version based on git commit as no version number is available.
  116. $javascript['cookie']['version'] = '67fb34f6a866c40d0570';
  117. // Replace jQuery Form plugin.
  118. $javascript['jquery.form']['js']['misc/jquery.form.js']['data'] = $path . '/replace/misc/jquery.form' . $min . '.js';
  119. $javascript['jquery.form']['version'] = '2.69';
  120. // Replace files for Jquery 1.9 and up
  121. if (version_compare($version, '1.9', '>=')) {
  122. $javascript['jquery.bbq']['js']['misc/jquery.ba-bbq.js']['data'] = $path . '/replace/misc/1.9/jquery.ba-bbq' . $min . '.js';
  123. }
  124. }
  125. if ($module == 'overlay') {
  126. if (version_compare($version, '1.9', '>=')) {
  127. $javascript['parent']['js']['modules/overlay/overlay-parent.js']['data'] = $path . '/replace/misc/1.9/overlay-parent.js';
  128. }
  129. }
  130. }
  131. /**
  132. * Implements hook_menu().
  133. */
  134. function jquery_update_menu() {
  135. $items['admin/config/development/jquery_update'] = array(
  136. 'title' => 'jQuery update',
  137. 'description' => 'Configure settings related to the jQuery upgrade, the library path and compression.',
  138. 'page callback' => 'drupal_get_form',
  139. 'page arguments' => array('jquery_update_settings_form'),
  140. 'access arguments' => array('administer site configuration'),
  141. );
  142. return $items;
  143. }
  144. /**
  145. * Admin settings menu callback.
  146. *
  147. * @see jquery_update_menu()
  148. */
  149. function jquery_update_settings_form() {
  150. $form['version_options'] = array(
  151. '#type' => 'fieldset',
  152. '#title' => t('Version options'),
  153. );
  154. $form['version_options']['jquery_update_jquery_version'] = array(
  155. '#type' => 'select',
  156. '#title' => t('Default jQuery Version'),
  157. '#options' => array(
  158. 'default' => t('Default (provided by Drupal)'),
  159. '1.5' => '1.5',
  160. '1.7' => '1.7',
  161. '1.8' => '1.8',
  162. '1.9' => '1.9',
  163. '1.10' => '1.10',
  164. ),
  165. '#default_value' => variable_get('jquery_update_jquery_version', '1.10'),
  166. '#description' => t('Select which jQuery version to use by default.'),
  167. );
  168. $form['version_options']['jquery_update_jquery_admin_version'] = array(
  169. '#type' => 'select',
  170. '#title' => t('Alternate jQuery version for administrative pages'),
  171. '#options' => array(
  172. '' => t('Default jQuery Version'),
  173. 'default' => t('Default (provided by Drupal)'),
  174. '1.5' => '1.5',
  175. '1.7' => '1.7',
  176. '1.8' => '1.8',
  177. '1.10' => '1.10',
  178. ),
  179. '#default_value' => variable_get('jquery_update_jquery_admin_version', ''),
  180. '#description' => t('Optionally select a different version of jQuery to use on administrative pages.'),
  181. );
  182. $form['jquery_update_compression_type'] = array(
  183. '#type' => 'radios',
  184. '#title' => t('jQuery compression level'),
  185. '#options' => array(
  186. 'min' => t('Production (minified)'),
  187. 'none' => t('Development (uncompressed)'),
  188. ),
  189. // Do not show this field if jQuery version is default
  190. '#states' => array(
  191. 'invisible' => array(
  192. ':input[name=jquery_update_jquery_version]' => array('value' => "default"),
  193. ),
  194. ),
  195. '#default_value' => variable_get('jquery_update_compression_type', 'min'),
  196. );
  197. $form['jquery_update_jquery_cdn'] = array(
  198. '#type' => 'select',
  199. '#title' => t('jQuery and jQuery UI CDN'),
  200. '#options' => array(
  201. 'none' => t('None'),
  202. 'google' => t('Google'),
  203. 'microsoft' => t('Microsoft'),
  204. 'jquery' => t('jQuery'),
  205. ),
  206. // Do not show this field if jQuery version is default
  207. '#states' => array(
  208. 'invisible' => array(
  209. ':input[name=jquery_update_jquery_version]' => array('value' => "default"),
  210. ),
  211. ),
  212. '#default_value' => variable_get('jquery_update_jquery_cdn', 'none'),
  213. '#description' => t('Use jQuery and jQuery UI from a CDN. If the CDN is not available the local version of jQuery and jQuery UI will be used.'),
  214. );
  215. return system_settings_form($form);
  216. }
  217. /**
  218. * Update jQuery to the CDN or local path.
  219. *
  220. * @param array $javascript
  221. * The library definition array as seen in hook_library_alter().
  222. * @param string $cdn
  223. * The name of the CDN option to use. Possible options are:
  224. * - none
  225. * - google
  226. * - microsoft
  227. * @param string $path
  228. * The path to the module where replacements can be found.
  229. * @param string $min
  230. * The '.min' to include in the file name if we are requesting a minified
  231. * version.
  232. * @param string $version
  233. * The version of jQuery to use.
  234. */
  235. function jquery_update_jquery_replace(&$javascript, $cdn, $path, $min, $version) {
  236. // Make sure to use the latest version in given branch.
  237. $trueversion = NULL;
  238. switch ($version) {
  239. case '1.5':
  240. $trueversion = '1.5.2';
  241. break;
  242. case '1.7':
  243. $trueversion = '1.7.2';
  244. break;
  245. case '1.8':
  246. $trueversion = '1.8.3';
  247. break;
  248. case '1.9':
  249. $trueversion = '1.9.1';
  250. break;
  251. case '1.10':
  252. $trueversion = '1.10.2';
  253. break;
  254. }
  255. $javascript['jquery']['version'] = $trueversion;
  256. // Check for CDN support.
  257. switch ($cdn) {
  258. case 'google':
  259. $javascript['jquery']['js']['misc/jquery.js']['data'] = '//ajax.googleapis.com/ajax/libs/jquery/' . $trueversion . '/jquery' . $min . '.js';
  260. $javascript['jquery']['js']['misc/jquery.js']['type'] = 'external';
  261. jquery_update_jquery_backup($javascript, $path, $min, $version);
  262. break;
  263. case 'microsoft':
  264. $javascript['jquery']['js']['misc/jquery.js']['data'] = '//ajax.aspnetcdn.com/ajax/jQuery/jquery-' . $trueversion . $min . '.js';
  265. $javascript['jquery']['js']['misc/jquery.js']['type'] = 'external';
  266. jquery_update_jquery_backup($javascript, $path, $min, $version);
  267. break;
  268. case 'jquery':
  269. $javascript['jquery']['js']['misc/jquery.js']['data'] = '//code.jquery.com/jquery-' . $trueversion . $min . '.js';
  270. $javascript['jquery']['js']['misc/jquery.js']['type'] = 'external';
  271. jquery_update_jquery_backup($javascript, $path, $min, $version);
  272. break;
  273. case 'none':
  274. default:
  275. $javascript['jquery']['js']['misc/jquery.js']['data'] = $path . '/replace/jquery/' . $version . '/jquery' . $min . '.js';
  276. break;
  277. }
  278. }
  279. /**
  280. * Add the local fallback in case jQuery from the CDN is unavailable.
  281. *
  282. * @param array $javascript
  283. * The $libraries array as seen in hook_library_alter()
  284. * @param string $path
  285. * The path to the module where replacements can be found.
  286. * @param string $min
  287. * The '.min' to include in the file name if we are requesting a minified
  288. * version.
  289. * @param string $version
  290. * The verison of jQuery to use.
  291. */
  292. function jquery_update_jquery_backup(&$javascript, $path, $min, $version) {
  293. $javascript['jquery']['js'][] = array(
  294. 'data' => 'window.jQuery || document.write("<script src=\'' . base_path() . $path . '/replace/jquery/' . $version . '/jquery' . $min . '.js\'>\x3C/script>")',
  295. 'type' => 'inline',
  296. 'group' => JS_LIBRARY,
  297. 'weight' => -19.999999999,
  298. );
  299. }
  300. /**
  301. * Update jQuery UI to the CDN or local path.
  302. *
  303. * @param array $javascript
  304. * The library definition array as seen in hook_library_alter().
  305. * @param string $cdn
  306. * The name of the CDN option to use. Possible options are:
  307. * - none
  308. * - google
  309. * - microsoft
  310. * @param string $path
  311. * The path to the module where replacements can be found.
  312. * @param string $min
  313. * The '.min' to include in the file name if we are requesting a minified
  314. * version.
  315. */
  316. function jquery_update_jqueryui_replace(&$javascript, $cdn, $path, $min) {
  317. // Add new components
  318. $javascript['ui.menu'] = array(
  319. 'title' => 'jQuery UI: Menu',
  320. 'website' => 'http://jqueryui.com/demos/menu/',
  321. 'version' => '1.10.2',
  322. 'js' => array('misc/ui/jquery.ui.menu.min.js' => array()),
  323. 'css' => array('misc/ui/jquery.ui.menu.css' => array()),
  324. 'dependencies' => array(array('system', 'ui.widget'), array('system', 'ui.position')),
  325. );
  326. $javascript['ui.spinner'] = array(
  327. 'title' => 'jQuery UI: Spinner',
  328. 'website' => 'http://jqueryui.com/demos/spinner/',
  329. 'version' => '1.10.2',
  330. 'js' => array('misc/ui/jquery.ui.spinner.min.js' => array()),
  331. 'css' => array('misc/ui/jquery.ui.spinner.css' => array()),
  332. 'dependencies' => array(array('system', 'ui.widget'), array('system', 'ui.button')),
  333. );
  334. $javascript['ui.tooltip'] = array(
  335. 'title' => 'jQuery UI: Spinner',
  336. 'website' => 'http://jqueryui.com/demos/tooltip/',
  337. 'version' => '1.10.2',
  338. 'js' => array('misc/ui/jquery.ui.tooltip.min.js' => array()),
  339. 'css' => array('misc/ui/jquery.ui.tooltip.css' => array()),
  340. 'dependencies' => array(array('system', 'ui.widget'), array('system', 'ui.position')),
  341. );
  342. // fix dependencies
  343. $javascript['ui.autocomplete']['dependencies'][] = array('system', 'ui.menu');
  344. // Replace all CSS files.
  345. $names = drupal_map_assoc(array(
  346. 'ui.accordion', 'ui.autocomplete', 'ui.button', 'ui.datepicker', 'ui.dialog',
  347. 'ui.progressbar', 'ui.resizable', 'ui.selectable', 'ui.slider', 'ui.tabs',
  348. 'ui.menu', 'ui.spinner', 'ui.tooltip',
  349. ));
  350. $names['ui'] = 'ui.core';
  351. $csspath = $path . '/replace/ui/themes/base/' . (($min == '.min') ? 'minified/' : '');
  352. foreach ($names as $name => $file) {
  353. $javascript[$name]['css']["misc/ui/jquery.$file.css"]['data'] = $csspath . 'jquery.' . $file . $min . '.css';
  354. }
  355. // Make sure ui.theme is replaced as well.
  356. $javascript['ui']['css']['misc/ui/jquery.ui.theme.css']['data'] = $csspath . 'jquery.ui.theme' . $min . '.css';
  357. // Replace jQuery UI's JavaScript, beginning by defining the mapping.
  358. $names = drupal_map_assoc(array(
  359. 'ui.accordion', 'ui.autocomplete', 'ui.button', 'ui.datepicker', 'ui.dialog', 'ui.draggable',
  360. 'ui.droppable', 'ui.mouse', 'ui.position', 'ui.progressbar', 'ui.resizable', 'ui.selectable',
  361. 'ui.slider', 'ui.sortable', 'ui.tabs', 'ui.widget', 'ui.spinner', 'ui.menu', 'ui.tooltip',
  362. ));
  363. $names['ui'] = 'ui.core';
  364. $names['effects'] = array('effects.core', 'ui.effect'); // map[library_hook] = array(core_fn, updated_fn)
  365. $names = jquery_update_make_library_hook_to_file_name_segment_map_for_effects($names);
  366. switch ($cdn) {
  367. case 'google':
  368. $cdn = '//ajax.googleapis.com/ajax/libs/jqueryui/1.10.2/jquery-ui' . $min . '.js';
  369. jquery_update_jqueryui_cdn($cdn, $javascript, $path, $min, $names);
  370. jquery_update_jqueryui_backup($javascript, $path, $min);
  371. break;
  372. case 'microsoft':
  373. $cdn = '//ajax.aspnetcdn.com/ajax/jquery.ui/1.10.2/jquery-ui' . $min . '.js';
  374. jquery_update_jqueryui_cdn($cdn, $javascript, $path, $min, $names);
  375. jquery_update_jqueryui_backup($javascript, $path, $min);
  376. break;
  377. case 'jquery':
  378. $cdn = '//code.jquery.com/ui/1.10.2/jquery-ui' . $min . '.js';
  379. jquery_update_jqueryui_cdn($cdn, $javascript, $path, $min, $names);
  380. jquery_update_jqueryui_backup($javascript, $path, $min);
  381. break;
  382. case 'none':
  383. jquery_update_jqueryui_local($javascript, $path, $min, $names);
  384. break;
  385. }
  386. }
  387. /**
  388. * Create a mapping from system.module library hooks to file name segments.
  389. *
  390. * @param array $map Optional. If given, append to it.
  391. * @return array The keys are library hooks and the values are each arrays of
  392. * 2 file name segments as values. The first file name segment can be used to
  393. * reach Drupal core's jQuery UI effect files, and the second file name segment
  394. * can be used to construct a path to the equivalent replacement
  395. * jQuery UI effect file provided by jquery_update.module.
  396. */
  397. function jquery_update_make_library_hook_to_file_name_segment_map_for_effects($map = array()) {
  398. $effect_names = array(
  399. 'blind', 'bounce', 'clip', 'drop', 'explode', 'fade', 'fold',
  400. 'highlight', 'pulsate', 'scale', 'shake', 'slide', 'transfer',
  401. );
  402. foreach ($effect_names as $effect_name) {
  403. $library_hook = 'effects.' . $effect_name;
  404. $file_name_segment_core = $library_hook; // Yes, for the effect files, this is indeed identical.
  405. $file_name_segment_updated = 'ui.effect-' . $effect_name;
  406. $map[$library_hook] = array($file_name_segment_core, $file_name_segment_updated);
  407. }
  408. return $map;
  409. }
  410. /**
  411. * Add the local fallback in case jQuery UI from the CDN is unavailable.
  412. *
  413. * @param array $javascript
  414. * The $libraries array as seen in hook_library_alter()
  415. * @param string $path
  416. * The path to the module where replacements can be found.
  417. * @param string $min
  418. * The '.min' to include in the file name if we are requesting a minified
  419. * version.
  420. */
  421. function jquery_update_jqueryui_backup(&$javascript, $path, $min) {
  422. $js_path = ($min == '.min') ? '/replace/ui/ui/minified/jquery-ui.min.js' : '/replace/ui/ui/jquery-ui.js';
  423. $javascript['ui']['js'][] = array(
  424. 'data' => 'window.jQuery.ui || document.write("<script src=\'' . base_path() . $path . $js_path . '\'>\x3C/script>")',
  425. 'type' => 'inline',
  426. 'group' => JS_LIBRARY,
  427. 'weight' => -10.999999999,
  428. );
  429. }
  430. /**
  431. * Handle when jQuery UI is updated to the cdn version.
  432. *
  433. * @param string $cdn
  434. * The name of the CDN option to use. Possible options are:
  435. * - none
  436. * - google
  437. * - microsoft
  438. * @param array $javascript
  439. * The $libraries array as seen in hook_library_alter()
  440. * @param string $path
  441. * The path to the module where replacements can be found.
  442. * @param string $min
  443. * The '.min' to include in the file name if we are requesting a minified
  444. * version.
  445. * * @param array $names
  446. * An array mapping jquery ui parts to their file names.
  447. */
  448. function jquery_update_jqueryui_cdn($cdn, &$javascript, $path, $min, $names) {
  449. // Construct the jQuery UI path and replace the JavaScript.
  450. $jspath = $path . '/replace/ui/ui/' . ($min == '.min' ? 'minified/' : '');
  451. foreach ($names as $name => $file) {
  452. list($file_core, $file_updated) = is_array($file) ? $file : array($file, $file);
  453. $corefile = 'misc/ui/jquery.' . $file_core . '.min.js';
  454. // Remove the core files.
  455. unset($javascript[$name]['js'][$corefile]);
  456. $javascript[$name]['version'] = '1.10.2';
  457. }
  458. // UI is used by all of UI. Add the js cdn here.
  459. $javascript['ui']['js'][$cdn] = array(
  460. 'data' => $cdn,
  461. 'type' => 'external',
  462. 'group' => JS_LIBRARY,
  463. 'weight' => -11,
  464. );
  465. // The cdn puts jQuery UI core and the jQuery UI Effects library in the same
  466. // file, but the latter can normally be used without the former. So we need
  467. // to add a dependency to guarantee that code which uses the Effects library
  468. // has the file loaded regardless of whether they are also using jQuery UI
  469. // core.
  470. $javascript['effects']['dependencies'][] = array('system', 'ui');
  471. }
  472. /**
  473. * Handle when jQuery UI is updated to the local version.
  474. *
  475. * @param array $javascript
  476. * The $libraries array as seen in hook_library_alter()
  477. * @param string $path
  478. * The path to the module where replacements can be found.
  479. * @param string $min
  480. * The '.min' to include in the file name if we are requesting a minified
  481. * version.
  482. * @param array $names
  483. * An array mapping jquery ui parts to their file names.
  484. */
  485. function jquery_update_jqueryui_local(&$javascript, $path, $min, $names) {
  486. // Construct the jQuery UI path and replace the JavaScript.
  487. $jspath = $path . '/replace/ui/ui/' . ($min == '.min' ? 'minified/' : '');
  488. foreach ($names as $name => $file) {
  489. list($file_core, $file_updated) = is_array($file) ? $file : array($file, $file);
  490. $corefile = 'misc/ui/jquery.' . $file_core . '.min.js';
  491. $javascript[$name]['js'][$corefile]['data'] = $jspath . 'jquery.' . $file_updated . $min . '.js';
  492. $javascript[$name]['version'] = '1.10.2';
  493. }
  494. }