/bp-core/bp-core-cssjs.php

  1. <?php 
  2. /** 
  3. * Core component CSS & JS. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage Core 
  7. * @since 1.0.0 
  8. */ 
  9.  
  10. // Exit if accessed directly. 
  11. defined( 'ABSPATH' ) || exit; 
  12.  
  13. /** 
  14. * Register scripts commonly used by BuddyPress. 
  15. * 
  16. * @since 2.1.0 
  17. */ 
  18. function bp_core_register_common_scripts() { 
  19. $min = bp_core_get_minified_asset_suffix(); 
  20. $url = buddypress()->plugin_url . 'bp-core/js/'; 
  21.  
  22. /** 
  23. * Moment.js locale. 
  24. * 
  25. * Try to map current WordPress locale to a moment.js locale file for loading. 
  26. * 
  27. * eg. French (France) locale for WP is fr_FR. Here, we try to find fr-fr.js 
  28. * (this file doesn't exist). 
  29. */ 
  30. $locale = sanitize_file_name( strtolower( get_locale() ) ); 
  31. $locale = str_replace( '_', '-', $locale ); 
  32. if ( file_exists( buddypress()->core->path . "bp-core/js/vendor/moment-js/locale/{$locale}{$min}.js" ) ) { 
  33. $moment_locale_url = $url . "vendor/moment-js/locale/{$locale}{$min}.js"; 
  34.  
  35. /** 
  36. * Try to find the short-form locale. 
  37. * 
  38. * eg. French (France) locale for WP is fr_FR. Here, we try to find fr.js 
  39. * (this exists). 
  40. */ 
  41. } else { 
  42. $locale = substr( $locale, 0, strpos( $locale, '-' ) ); 
  43. if ( file_exists( buddypress()->core->path . "bp-core/js/vendor/moment-js/locale/{$locale}{$min}.js" ) ) { 
  44. $moment_locale_url = $url . "vendor/moment-js/locale/{$locale}{$min}.js"; 
  45.  
  46. // Set up default scripts to register. 
  47. $scripts = array( 
  48. // Legacy. 
  49. 'bp-confirm' => array( 'file' => "{$url}confirm{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),  
  50. 'bp-widget-members' => array( 'file' => "{$url}widget-members{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),  
  51. 'bp-jquery-query' => array( 'file' => "{$url}jquery-query{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),  
  52. 'bp-jquery-cookie' => array( 'file' => "{$url}vendor/jquery-cookie{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),  
  53. 'bp-jquery-scroll-to' => array( 'file' => "{$url}vendor/jquery-scroll-to{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ),  
  54.  
  55. // Version 2.1. 
  56. 'jquery-caret' => array( 'file' => "{$url}vendor/jquery.caret{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => true ),  
  57. 'jquery-atwho' => array( 'file' => "{$url}vendor/jquery.atwho{$min}.js", 'dependencies' => array( 'jquery', 'jquery-caret' ), 'footer' => true ),  
  58.  
  59. // Version 2.3. 
  60. 'bp-plupload' => array( 'file' => "{$url}bp-plupload{$min}.js", 'dependencies' => array( 'plupload', 'jquery', 'json2', 'wp-backbone' ), 'footer' => true ),  
  61. 'bp-avatar' => array( 'file' => "{$url}avatar{$min}.js", 'dependencies' => array( 'jcrop' ), 'footer' => true ),  
  62. 'bp-webcam' => array( 'file' => "{$url}webcam{$min}.js", 'dependencies' => array( 'bp-avatar' ), 'footer' => true ),  
  63.  
  64. // Version 2.4. 
  65. 'bp-cover-image' => array( 'file' => "{$url}cover-image{$min}.js", 'dependencies' => array(), 'footer' => true ),  
  66.  
  67. // Version 2.7. 
  68. 'bp-moment' => array( 'file' => "{$url}vendor/moment-js/moment{$min}.js", 'dependencies' => array(), 'footer' => true ),  
  69. 'bp-livestamp' => array( 'file' => "{$url}vendor/livestamp{$min}.js", 'dependencies' => array( 'jquery', 'bp-moment' ), 'footer' => true ),  
  70. ); 
  71.  
  72. // Version 2.7 - Add Moment.js locale to our $scripts array if we found one. 
  73. if ( isset( $moment_locale_url ) ) { 
  74. $scripts['bp-moment-locale'] = array( 'file' => esc_url( $moment_locale_url ), 'dependencies' => array( 'bp-moment' ), 'footer' => true ); 
  75.  
  76. /** 
  77. * Filters the BuddyPress Core javascript files to register. 
  78. * 
  79. * Default handles include 'bp-confirm', 'bp-widget-members',  
  80. * 'bp-jquery-query', 'bp-jquery-cookie', and 'bp-jquery-scroll-to'. 
  81. * 
  82. * @since 2.1.0 'jquery-caret', 'jquery-atwho' added. 
  83. * @since 2.3.0 'bp-plupload', 'bp-avatar', 'bp-webcam' added. 
  84. * @since 2.4.0 'bp-cover-image' added. 
  85. * @since 2.7.0 'bp-moment', 'bp-livestamp' added. 
  86. * 'bp-moment-locale' is added conditionally if a moment.js locale file is found. 
  87. * 
  88. * @param array $value Array of javascript file information to register. 
  89. */ 
  90. $scripts = apply_filters( 'bp_core_register_common_scripts', $scripts ); 
  91.  
  92.  
  93. $version = bp_get_version(); 
  94. foreach ( $scripts as $id => $script ) { 
  95. wp_register_script( $id, $script['file'], $script['dependencies'], $version, $script['footer'] ); 
  96. add_action( 'bp_enqueue_scripts', 'bp_core_register_common_scripts', 1 ); 
  97. add_action( 'bp_admin_enqueue_scripts', 'bp_core_register_common_scripts', 1 ); 
  98.  
  99. /** 
  100. * Register styles commonly used by BuddyPress. 
  101. * 
  102. * @since 2.1.0 
  103. */ 
  104. function bp_core_register_common_styles() { 
  105. $min = bp_core_get_minified_asset_suffix(); 
  106. $url = buddypress()->plugin_url . 'bp-core/css/'; 
  107.  
  108. /** 
  109. * Filters the URL for the Admin Bar stylesheet. 
  110. * 
  111. * @since 1.1.0 
  112. * 
  113. * @param string $value URL for the Admin Bar stylesheet. 
  114. */ 
  115. $admin_bar_file = apply_filters( 'bp_core_admin_bar_css', "{$url}admin-bar{$min}.css" ); 
  116.  
  117. /** 
  118. * Filters the BuddyPress Core stylesheet files to register. 
  119. * 
  120. * @since 2.1.0 
  121. * 
  122. * @param array $value Array of stylesheet file information to register. 
  123. */ 
  124. $styles = apply_filters( 'bp_core_register_common_styles', array( 
  125. 'bp-admin-bar' => array( 
  126. 'file' => $admin_bar_file,  
  127. 'dependencies' => array( 'admin-bar' ) 
  128. ),  
  129. 'bp-avatar' => array( 
  130. 'file' => "{$url}avatar{$min}.css",  
  131. 'dependencies' => array( 'jcrop' ) 
  132. ),  
  133. ) ); 
  134.  
  135. foreach ( $styles as $id => $style ) { 
  136. wp_register_style( $id, $style['file'], $style['dependencies'], bp_get_version() ); 
  137.  
  138. wp_style_add_data( $id, 'rtl', true ); 
  139. if ( $min ) { 
  140. wp_style_add_data( $id, 'suffix', $min ); 
  141. add_action( 'bp_enqueue_scripts', 'bp_core_register_common_styles', 1 ); 
  142. add_action( 'bp_admin_enqueue_scripts', 'bp_core_register_common_styles', 1 ); 
  143.  
  144. /** 
  145. * Load the JS for "Are you sure?" confirm links. 
  146. * 
  147. * @since 1.1.0 
  148. */ 
  149. function bp_core_confirmation_js() { 
  150. if ( is_multisite() && ! bp_is_root_blog() ) { 
  151. return false; 
  152.  
  153. wp_enqueue_script( 'bp-confirm' ); 
  154.  
  155. wp_localize_script( 'bp-confirm', 'BP_Confirm', array( 
  156. 'are_you_sure' => __( 'Are you sure?', 'buddypress' ),  
  157. ) ); 
  158.  
  159. add_action( 'bp_enqueue_scripts', 'bp_core_confirmation_js' ); 
  160. add_action( 'bp_admin_enqueue_scripts', 'bp_core_confirmation_js' ); 
  161.  
  162. /** 
  163. * Enqueues the css and js required by the Avatar UI. 
  164. * 
  165. * @since 2.3.0 
  166. */ 
  167. function bp_core_avatar_scripts() { 
  168. if ( ! bp_avatar_is_front_edit() ) { 
  169. return false; 
  170.  
  171. // Enqueue the Attachments scripts for the Avatar UI. 
  172. bp_attachments_enqueue_scripts( 'BP_Attachment_Avatar' ); 
  173.  
  174. // Add Some actions for Theme backcompat. 
  175. add_action( 'bp_after_profile_avatar_upload_content', 'bp_avatar_template_check' ); 
  176. add_action( 'bp_after_group_admin_content', 'bp_avatar_template_check' ); 
  177. add_action( 'bp_after_group_avatar_creation_step', 'bp_avatar_template_check' ); 
  178. add_action( 'bp_enqueue_scripts', 'bp_core_avatar_scripts' ); 
  179.  
  180. /** 
  181. * Enqueues the css and js required by the Cover Image UI. 
  182. * 
  183. * @since 2.4.0 
  184. */ 
  185. function bp_core_cover_image_scripts() { 
  186. if ( ! bp_attachments_cover_image_is_edit() ) { 
  187. return false; 
  188.  
  189. // Enqueue the Attachments scripts for the Cover Image UI. 
  190. bp_attachments_enqueue_scripts( 'BP_Attachment_Cover_Image' ); 
  191. add_action( 'bp_enqueue_scripts', 'bp_core_cover_image_scripts' ); 
  192.  
  193. /** 
  194. * Enqueues jCrop library and hooks BP's custom cropper JS. 
  195. * 
  196. * @since 1.1.0 
  197. */ 
  198. function bp_core_add_jquery_cropper() { 
  199. wp_enqueue_style( 'jcrop' ); 
  200. wp_enqueue_script( 'jcrop', array( 'jquery' ) ); 
  201. add_action( 'wp_head', 'bp_core_add_cropper_inline_js' ); 
  202. add_action( 'wp_head', 'bp_core_add_cropper_inline_css' ); 
  203.  
  204. /** 
  205. * Output the inline JS needed for the cropper to work on a per-page basis. 
  206. * 
  207. * @since 1.1.0 
  208. */ 
  209. function bp_core_add_cropper_inline_js() { 
  210.  
  211. /** 
  212. * Filters the return value of getimagesize to determine if an image was uploaded. 
  213. * 
  214. * @since 1.1.0 
  215. * 
  216. * @param array $value Array of data found by getimagesize. 
  217. */ 
  218. $image = apply_filters( 'bp_inline_cropper_image', getimagesize( bp_core_avatar_upload_path() . buddypress()->avatar_admin->image->dir ) ); 
  219. if ( empty( $image ) ) { 
  220. return; 
  221.  
  222. // Get avatar full width and height. 
  223. $full_height = bp_core_avatar_full_height(); 
  224. $full_width = bp_core_avatar_full_width(); 
  225.  
  226. // Calculate Aspect Ratio. 
  227. if ( !empty( $full_height ) && ( $full_width != $full_height ) ) { 
  228. $aspect_ratio = $full_width / $full_height; 
  229. } else { 
  230. $aspect_ratio = 1; 
  231.  
  232. // Default cropper coordinates. 
  233. // Smaller than full-width: cropper defaults to entire image. 
  234. if ( $image[0] < $full_width ) { 
  235. $crop_left = 0; 
  236. $crop_right = $image[0]; 
  237.  
  238. // Less than 2x full-width: cropper defaults to full-width. 
  239. } elseif ( $image[0] < ( $full_width * 2 ) ) { 
  240. $padding_w = round( ( $image[0] - $full_width ) / 2 ); 
  241. $crop_left = $padding_w; 
  242. $crop_right = $image[0] - $padding_w; 
  243.  
  244. // Larger than 2x full-width: cropper defaults to 1/2 image width. 
  245. } else { 
  246. $crop_left = round( $image[0] / 4 ); 
  247. $crop_right = $image[0] - $crop_left; 
  248.  
  249. // Smaller than full-height: cropper defaults to entire image. 
  250. if ( $image[1] < $full_height ) { 
  251. $crop_top = 0; 
  252. $crop_bottom = $image[1]; 
  253.  
  254. // Less than double full-height: cropper defaults to full-height. 
  255. } elseif ( $image[1] < ( $full_height * 2 ) ) { 
  256. $padding_h = round( ( $image[1] - $full_height ) / 2 ); 
  257. $crop_top = $padding_h; 
  258. $crop_bottom = $image[1] - $padding_h; 
  259.  
  260. // Larger than 2x full-height: cropper defaults to 1/2 image height. 
  261. } else { 
  262. $crop_top = round( $image[1] / 4 ); 
  263. $crop_bottom = $image[1] - $crop_top; 
  264.  
  265. ?> 
  266.  
  267. <script type="text/javascript"> 
  268. jQuery(window).load( function() { 
  269. jQuery('#avatar-to-crop').Jcrop({ 
  270. onChange: showPreview,  
  271. onSelect: updateCoords,  
  272. aspectRatio: <?php echo (int) $aspect_ratio; ?>,  
  273. setSelect: [ <?php echo (int) $crop_left; ?>, <?php echo (int) $crop_top; ?>, <?php echo (int) $crop_right; ?>, <?php echo (int) $crop_bottom; ?> ] 
  274. }); 
  275. }); 
  276.  
  277. function updateCoords(c) { 
  278. jQuery('#x').val(c.x); 
  279. jQuery('#y').val(c.y); 
  280. jQuery('#w').val(c.w); 
  281. jQuery('#h').val(c.h); 
  282.  
  283. function showPreview(coords) { 
  284. if ( parseInt(coords.w) > 0 ) { 
  285. var fw = <?php echo (int) $full_width; ?>; 
  286. var fh = <?php echo (int) $full_height; ?>; 
  287. var rx = fw / coords.w; 
  288. var ry = fh / coords.h; 
  289.  
  290. jQuery( '#avatar-crop-preview' ).css({ 
  291. width: Math.round(rx * <?php echo (int) $image[0]; ?>) + 'px',  
  292. height: Math.round(ry * <?php echo (int) $image[1]; ?>) + 'px',  
  293. marginLeft: '-' + Math.round(rx * coords.x) + 'px',  
  294. marginTop: '-' + Math.round(ry * coords.y) + 'px' 
  295. }); 
  296. </script> 
  297.  
  298. <?php 
  299.  
  300. /** 
  301. * Output the inline CSS for the BP image cropper. 
  302. * 
  303. * @since 1.1.0 
  304. */ 
  305. function bp_core_add_cropper_inline_css() { 
  306. ?> 
  307.  
  308. <style type="text/css"> 
  309. .jcrop-holder { float: left; margin: 0 20px 20px 0; text-align: left; } 
  310. #avatar-crop-pane { width: <?php echo bp_core_avatar_full_width() ?>px; height: <?php echo bp_core_avatar_full_height() ?>px; overflow: hidden; } 
  311. #avatar-crop-submit { margin: 20px 0; } 
  312. .jcrop-holder img,  
  313. #avatar-crop-pane img,  
  314. #avatar-upload-form img,  
  315. #create-group-form img,  
  316. #group-settings-form img { border: none !important; max-width: none !important; } 
  317. </style> 
  318.  
  319. <?php 
  320.  
  321. /** 
  322. * Define the 'ajaxurl' JS variable, used by themes as an AJAX endpoint. 
  323. * 
  324. * @since 1.1.0 
  325. */ 
  326. function bp_core_add_ajax_url_js() { 
  327. ?> 
  328.  
  329. <script type="text/javascript">var ajaxurl = '<?php echo bp_core_ajax_url(); ?>';</script> 
  330.  
  331. <?php 
  332. add_action( 'wp_head', 'bp_core_add_ajax_url_js' ); 
  333.  
  334. /** 
  335. * Get the proper value for BP's ajaxurl. 
  336. * 
  337. * Designed to be sensitive to FORCE_SSL_ADMIN and non-standard multisite 
  338. * configurations. 
  339. * 
  340. * @since 1.7.0 
  341. * 
  342. * @return string AJAX endpoint URL. 
  343. */ 
  344. function bp_core_ajax_url() { 
  345.  
  346. /** 
  347. * Filters the proper value for BuddyPress' ajaxurl. 
  348. * 
  349. * @since 1.7.0 
  350. * 
  351. * @param string $value Proper ajaxurl value for BuddyPress. 
  352. */ 
  353. return apply_filters( 'bp_core_ajax_url', admin_url( 'admin-ajax.php', is_ssl() ? 'admin' : 'http' ) ); 
  354.  
  355. /** 
  356. * Get the JavaScript dependencies for buddypress.js. 
  357. * 
  358. * @since 2.0.0 
  359. * 
  360. * @return array The JavaScript dependencies. 
  361. */ 
  362. function bp_core_get_js_dependencies() { 
  363.  
  364. /** 
  365. * Filters the javascript dependencies for buddypress.js. 
  366. * 
  367. * @since 2.0.0 
  368. * 
  369. * @param array $value Array of javascript dependencies for buddypress.js. 
  370. */ 
  371. return apply_filters( 'bp_core_get_js_dependencies', array( 
  372. 'jquery',  
  373. 'bp-confirm',  
  374. 'bp-widget-members',  
  375. 'bp-jquery-query',  
  376. 'bp-jquery-cookie',  
  377. 'bp-jquery-scroll-to' 
  378. ) ); 
  379.  
  380. /** 
  381. * Add inline css to display the component's single item cover image. 
  382. * 
  383. * @since 2.4.0 
  384. * 
  385. * @param bool $return True to get the inline css. 
  386. * @return string|array the inline css or an associative array containing 
  387. * the css rules and the style handle 
  388. */ 
  389. function bp_add_cover_image_inline_css( $return = false ) { 
  390. $bp = buddypress(); 
  391.  
  392. // Find the component of the current item. 
  393. if ( bp_is_user() ) { 
  394.  
  395. // User is not allowed to upload cover images 
  396. // no need to carry on. 
  397. if ( bp_disable_cover_image_uploads() ) { 
  398. return; 
  399.  
  400. $cover_image_object = array( 
  401. 'component' => 'xprofile',  
  402. 'object' => $bp->displayed_user 
  403. ); 
  404. } elseif ( bp_is_group() ) { 
  405.  
  406. // Users are not allowed to upload cover images for their groups 
  407. // no need to carry on. 
  408. if ( bp_disable_group_cover_image_uploads() ) { 
  409. return; 
  410.  
  411. $cover_image_object = array( 
  412. 'component' =>'groups',  
  413. 'object' => $bp->groups->current_group 
  414. ); 
  415. } else { 
  416. $cover_image_object = apply_filters( 'bp_current_cover_image_object_inline_css', array() ); 
  417.  
  418. // Bail if no component were found. 
  419. if ( empty( $cover_image_object['component'] ) || empty( $cover_image_object['object'] ) || ! bp_is_active( $cover_image_object['component'], 'cover_image' ) ) { 
  420. return; 
  421.  
  422. // Get the settings of the cover image feature for the current component. 
  423. $params = bp_attachments_get_cover_image_settings( $cover_image_object['component'] ); 
  424.  
  425. // Bail if no params. 
  426. if ( empty( $params ) ) { 
  427. return; 
  428.  
  429. // Try to call the callback. 
  430. if ( is_callable( $params['callback'] ) ) { 
  431.  
  432. $object_dir = $cover_image_object['component']; 
  433.  
  434. if ( 'xprofile' === $object_dir ) { 
  435. $object_dir = 'members'; 
  436.  
  437. $cover_image = bp_attachments_get_attachment( 'url', array( 
  438. 'object_dir' => $object_dir,  
  439. 'item_id' => $cover_image_object['object']->id,  
  440. ) ); 
  441.  
  442. if ( empty( $cover_image ) ) { 
  443. if ( ! empty( $params['default_cover'] ) ) { 
  444. $cover_image = $params['default_cover']; 
  445.  
  446. $inline_css = call_user_func_array( $params['callback'], array( array( 
  447. 'cover_image' => esc_url_raw( $cover_image ),  
  448. 'component' => sanitize_key( $cover_image_object['component'] ),  
  449. 'object_id' => (int) $cover_image_object['object']->id,  
  450. 'width' => (int) $params['width'],  
  451. 'height' => (int) $params['height'],  
  452. ) ) ); 
  453.  
  454. // Finally add the inline css to the handle. 
  455. if ( ! empty( $inline_css ) ) { 
  456.  
  457. // Used to get the css when Ajax setting the cover image. 
  458. if ( true === $return ) { 
  459. return array( 
  460. 'css_rules' => '<style type="text/css">' . "\n" . $inline_css . "\n" . '</style>',  
  461. 'handle' => $params['theme_handle'],  
  462. ); 
  463.  
  464. wp_add_inline_style( $params['theme_handle'], $inline_css ); 
  465. } else { 
  466. return false; 
  467. add_action( 'bp_enqueue_scripts', 'bp_add_cover_image_inline_css', 11 ); 
  468.  
  469. /** 
  470. * Enqueues livestamp.js on BuddyPress pages. 
  471. * 
  472. * @since 2.7.0 
  473. */ 
  474. function bp_core_add_livestamp() { 
  475. if ( ! is_buddypress() ) { 
  476. return; 
  477.  
  478. bp_core_enqueue_livestamp(); 
  479. add_action( 'bp_enqueue_scripts', 'bp_core_add_livestamp' ); 
  480.  
  481. /** 
  482. * Enqueue and localize livestamp.js script. 
  483. * 
  484. * @since 2.7.0 
  485. */ 
  486. function bp_core_enqueue_livestamp() { 
  487. // If bp-livestamp isn't enqueued, do it now. 
  488. if ( wp_script_is( 'bp-livestamp' ) ) { 
  489. return; 
  490.  
  491. /** 
  492. * Only enqueue Moment.js locale if we registered it in 
  493. * bp_core_register_common_scripts(). 
  494. */ 
  495. if ( wp_script_is( 'bp-moment-locale', 'registered' ) ) { 
  496. wp_enqueue_script( 'bp-moment-locale' ); 
  497.  
  498. if ( function_exists( 'wp_add_inline_script' ) ) { 
  499. wp_add_inline_script ( 'bp-livestamp', bp_core_moment_js_config() ); 
  500. } else { 
  501. add_action( 'wp_footer', '_bp_core_moment_js_config_footer', 20 ); 
  502.  
  503. wp_enqueue_script( 'bp-livestamp' ); 
  504.  
  505. /** 
  506. * Return moment.js config. 
  507. * 
  508. * @since 2.7.0 
  509. * 
  510. * @return string 
  511. */ 
  512. function bp_core_moment_js_config() { 
  513. // Grab the locale from the enqueued JS. 
  514. $moment_locale = wp_scripts()->query( 'bp-moment-locale' ); 
  515. $moment_locale = substr( $moment_locale->src, strpos( $moment_locale->src, '/moment-js/locale/' ) + 18 ); 
  516. $moment_locale = str_replace( '.js', '', $moment_locale ); 
  517.  
  518. $inline_js = <<<EOD 
  519. jQuery(function() { 
  520. moment.locale( '{$moment_locale}' ); 
  521. }); 
  522. EOD; 
  523.  
  524. return $inline_js; 
  525.  
  526. /** 
  527. * Print moment.js config in page footer. 
  528. * 
  529. * Will be removed once we set our minimum version of WP 4.5. 
  530. * 
  531. * @since 2.7.0 
  532. * 
  533. * @access private 
  534. */ 
  535. function _bp_core_moment_js_config_footer() { 
  536. if ( ! wp_script_is( 'bp-moment-locale' ) ) { 
  537. return; 
  538.  
  539. printf( '<script>%s</script>', bp_core_moment_js_config() ); 
.