Ticket #6290: 6290.01.patch
File 6290.01.patch, 76.0 KB (added by , 10 years ago) |
---|
-
src/bp-core/bp-core-attachments.php
diff --git src/bp-core/bp-core-attachments.php src/bp-core/bp-core-attachments.php index e69de29..2a71148 100644
1 <?php 2 /** 3 * BuddyPress Attachments functions. 4 * 5 * @package BuddyPress 6 * @subpackage Attachments 7 */ 8 9 // Exit if accessed directly 10 defined( 'ABSPATH' ) || exit; 11 12 /** 13 * Returns the directory containing the javascrit templates needed for the Uploader 14 * 15 * @since BuddyPress (2.3.0) 16 * 17 * @return string the directory containing the javascrit templates 18 */ 19 function bp_attachments_templates() { 20 return apply_filters( 'bp_attachments_templates', trailingslashit( buddypress()->themes_dir ) . 'bp-attachments' ); 21 } 22 23 /** 24 * Registers the Attachments templates in BuddyPress templates stack 25 * 26 * @since BuddyPress (2.3.0) 27 */ 28 function bp_attachements_register_templates() { 29 bp_register_template_stack( 'bp_attachments_templates' ); 30 } 31 add_action( 'bp_register_theme_directory', 'bp_attachements_register_templates' ); 32 33 /** 34 * Get the BuddyPress Plupload settings 35 * 36 * @since BuddyPress (2.3.0) 37 * 38 * @uses apply_filters() call 'bp_attachments_get_plupload_default_settings' to override the settings 39 * @return array list of BuddyPress Plupload settings 40 */ 41 function bp_attachments_get_plupload_default_settings() { 42 43 $max_upload_size = wp_max_upload_size(); 44 45 if ( ! $max_upload_size ) { 46 $max_upload_size = 0; 47 } 48 49 $defaults = array( 50 'runtimes' => 'html5,flash,silverlight,html4', 51 'file_data_name' => 'file', 52 'multipart_params' => array( 53 'action' => 'bp_upload_attachment', 54 '_wpnonce' => wp_create_nonce( 'bp-uploader' ), 55 ), 56 'url' => admin_url( 'admin-ajax.php', 'relative' ), 57 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ), 58 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ), 59 'filters' => array( 60 'max_file_size' => $max_upload_size . 'b', 61 ), 62 'multipart' => true, 63 'urlstream_upload' => true, 64 ); 65 66 // WordPress is not allowing multi selection for iOs 7 device.. See #29602. 67 if ( wp_is_mobile() && strpos( $_SERVER['HTTP_USER_AGENT'], 'OS 7_' ) !== false && 68 strpos( $_SERVER['HTTP_USER_AGENT'], 'like Mac OS X' ) !== false ) { 69 70 $defaults['multi_selection'] = false; 71 } 72 73 $settings = array( 74 'defaults' => $defaults, 75 'browser' => array( 76 'mobile' => wp_is_mobile(), 77 'supported' => _device_can_upload(), 78 ), 79 'limitExceeded' => is_multisite() && ! is_upload_space_available(), 80 ); 81 82 /** 83 * Filter the BuddyPress Plupload default settings. 84 * 85 * @since 2.3.0 86 * 87 * @param array $params Default Plupload parameters array. 88 */ 89 return apply_filters( 'bp_attachments_get_plupload_default_settings', $settings ); 90 } 91 92 /** 93 * Builds localization data for the BuddyPress Uploader scripts 94 * 95 * Gets WordPress Plupload data to avoid translating the same strings 96 * twice. 97 * 98 * @since BuddyPress (2.3.0) 99 * 100 * @global $wp_scripts 101 * @return array Plupload default localization data 102 */ 103 function bp_attachments_get_plupload_l10n() { 104 global $wp_scripts; 105 106 $attachments_l10n = array(); 107 $wp_plupload_l10n = $wp_scripts->get_data( 'wp-plupload', 'data' ); 108 109 preg_match( '/\{(.*?)\}/', $wp_plupload_l10n, $matches ); 110 111 if ( ! empty( $matches[0] ) ) { 112 $attachments_l10n['strings'] = json_decode( $matches[0], true ); 113 } 114 115 $attachments_l10n['settings'] = bp_attachments_get_plupload_default_settings(); 116 117 // In case the multisection is off, include a specific error string 118 if ( empty( $attachments_l10n['settings']['defaults']['multi_selection'] ) ) { 119 $attachments_l10n['strings']['unique_file_warning'] = __( 'Make sure to upload a unique file', 'buddypress' ); 120 } 121 122 return $attachments_l10n; 123 } 124 125 /** 126 * Enqueues the script needed for the Uploader UI 127 * 128 * @see BP_Attachment::script_data() && BP_Attachment_Avatar::script_data() for examples showing how 129 * to set specific script data 130 * 131 * @since BuddyPress (2.3.0) 132 * 133 * @param string $class name of the class extending BP_Attachment (eg: BP_Attachment_Avatar) 134 */ 135 function bp_attachments_enqueue_scripts( $class = '' ) { 136 // Enqueue me just once per page, please. 137 if ( did_action( 'bp_attachments_enqueue_scripts' ) ) { 138 return; 139 } 140 141 if ( empty( $class ) || ! class_exists( $class ) ) { 142 return new WP_Error( 'missing_parameter' ); 143 } 144 145 // Get an instance of the class and get the script data 146 $attachment = new $class; 147 $script_data = $attachment->script_data(); 148 149 $args = bp_parse_args( $script_data, array( 150 'action' => '', 151 'file_data_name' => '', 152 'max_file_size' => 0, 153 'browse_button' => 'bp-browse-button', 154 'container' => 'bp-upload-ui', 155 'drop_element' => 'drag-drop-area', 156 'bp_params' => array(), 157 'extra_css' => array(), 158 'extra_js' => array(), 159 ), 'attachments_enqueue_scripts' ); 160 161 if ( empty( $args['action'] ) || empty( $args['file_data_name'] ) ) { 162 return new WP_Error( 'missing_parameter' ); 163 } 164 165 // Get the BuddyPress uploader default settings 166 $attachments_l10n = bp_attachments_get_plupload_l10n(); 167 $defaults = $attachments_l10n['settings']['defaults']; 168 169 // Set the upload action 170 $defaults['multipart_params']['action'] = $args['action']; 171 172 // Set BuddyPress upload parameters if provided 173 if ( ! empty( $args['bp_params'] ) ) { 174 $defaults['multipart_params']['bp_params'] = $args['bp_params']; 175 } 176 177 // Merge other arguments 178 $ui_args = array_intersect_key( $args, array( 179 'file_data_name' => true, 180 'browse_button' => true, 181 'container' => true, 182 'drop_element' => true, 183 ) ); 184 185 $defaults = array_merge( $defaults, $ui_args ); 186 187 if ( ! empty( $args['max_file_size'] ) ) { 188 $defaults['filters']['max_file_size'] = $args['max_file_size'] . 'b'; 189 } 190 191 // Specific to BuddyPress Avatars 192 if ( 'bp_avatar_upload' == $defaults['multipart_params']['action'] ) { 193 194 // Include the cropping informations for avatars 195 $attachments_l10n['settings']['crop'] = array( 196 'full_h' => bp_core_avatar_full_height(), 197 'full_w' => bp_core_avatar_full_width(), 198 ); 199 200 // Avatar only need 1 file and 1 only! 201 $defaults['multi_selection'] = false; 202 203 // Init the Avatar nav 204 $avatar_nav = array( 'upload' => array( 'id' => 'upload', 'caption' => __( 'Upload', 'buddypress' ), 'order' => 0 ) ); 205 206 // Use this filter to disable the Webcam Avatar feature 207 if ( false !== apply_filters( 'bp_attachment_avatar_use_webcam', true ) && 'user' == $defaults['multipart_params']['bp_params']['object'] ) { 208 $avatar_nav['camera'] = array( 'id' => 'camera', 'caption' => __( 'Camera', 'buddypress' ), 'order' => 10 ); 209 210 // Set warning messages 211 $attachments_l10n['strings']['camera_warnings'] = array( 212 'requesting' => __( 'Requesting video stream, please authorize this website to access to your camera.', 'buddypress'), 213 'loading' => __( 'Please wait for the video to load.', 'buddypress' ), 214 'loaded' => __( 'Video stream loaded. You can use the capture button to display the avatar preview.', 'buddypress' ), 215 'noaccess' => __( 'You denied this website to access to your camera. Please use the upload form.', 'buddypress' ), 216 'errormsg' => __( 'Your browser is not supported. Please use the upload form.', 'buddypress' ), 217 'videoerror' => __( 'Video error. Please use the upload form.', 'buddypress' ), 218 'ready' => __( 'Avatar ready, use the save button to validate.', 'buddypress' ), 219 'nocapture' => __( 'No avatar was captured, please use the capture button first.', 'buddypress' ), 220 ); 221 } 222 223 if ( ! empty( $defaults['multipart_params']['bp_params']['has_avatar'] ) ) { 224 $avatar_nav['delete'] = array( 'id' => 'delete', 'caption' => __( 'Delete', 'buddypress' ), 'order' => 100 ); 225 } 226 227 $attachments_l10n['settings']['nav'] = bp_sort_by_key( apply_filters( 'bp_attachments_avatar_nav', $avatar_nav ), 'order', 'num' ); 228 } 229 230 // Set Plupload settings 231 $attachments_l10n['settings']['defaults'] = $defaults; 232 233 /** 234 * Enqueue some extra styles if required 235 * 236 * Extra styles need to be registered. 237 */ 238 if ( ! empty( $args['extra_css'] ) ) { 239 foreach ( (array) $args['extra_css'] as $css ) { 240 if ( empty( $css ) ) { 241 continue; 242 } 243 244 wp_enqueue_style( $css ); 245 } 246 } 247 248 wp_enqueue_script ( 'bp-plupload' ); 249 wp_localize_script( 'bp-plupload', 'BP_Uploader', $attachments_l10n ); 250 251 /** 252 * Enqueue some extra scripts if required 253 * 254 * Extra scripts need to be registered. 255 */ 256 if ( ! empty( $args['extra_js'] ) ) { 257 foreach ( (array) $args['extra_js'] as $js ) { 258 if ( empty( $js ) ) { 259 continue; 260 } 261 262 wp_enqueue_script( $js ); 263 } 264 } 265 266 /** 267 * Fires at the conclusion of bp_attachments_enqueue_scripts() 268 * to avoid the scripts to be loaded more than once. 269 * 270 * @since BuddyPress 2.3.0 271 */ 272 do_action( 'bp_attachments_enqueue_scripts' ); 273 } -
src/bp-core/bp-core-avatars.php
diff --git src/bp-core/bp-core-avatars.php src/bp-core/bp-core-avatars.php index 44fe3c3..127e650 100644
function bp_core_delete_existing_avatar( $args = '' ) { 553 553 } 554 554 555 555 /** 556 * Ajax delete an avatar for a given object and item id 557 * 558 * @since BuddyPress (2.3.0) 559 * 560 * @uses bp_core_delete_existing_avatar() 561 * @return string a json object containing success data if the avatar was deleted 562 * error message otherwise 563 */ 564 function bp_core_avatar_ajax_delete() { 565 // Bail if not a POST action 566 if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { 567 wp_send_json_error(); 568 } 569 570 $avatar_data = $_POST; 571 572 if ( empty( $avatar_data['object'] ) || empty( $avatar_data['item_id'] ) ) { 573 wp_send_json_error(); 574 } 575 576 $nonce = 'bp_delete_avatar_link'; 577 if ( 'group' == $avatar_data['object'] ) { 578 $nonce = 'bp_group_avatar_delete'; 579 } 580 581 // Check the nonce 582 check_admin_referer( $nonce, 'nonce' ); 583 584 // Capability check 585 if ( ! bp_is_item_admin() && ! bp_current_user_can( 'bp_moderate' ) ) { 586 wp_send_json_error(); 587 } 588 589 // Set feedback part 590 if ( 'user' == $avatar_data['object'] ) { 591 $message_part = _x( 'Your profile photo', 'user object avatar photo', 'buddypress' ); 592 593 // Defaults to object-avatars dir 594 } else { 595 $message_part = sprintf( _x( 'The %s profile photo', 'generic object avatar photo', 'buddypress' ), $avatar_data['object'] ); 596 } 597 598 // Handle delete 599 if ( bp_core_delete_existing_avatar( array( 'item_id' => $avatar_data['item_id'], 'object' => $avatar_data['object'] ) ) ) { 600 $return = array( 601 'avatar' => bp_core_fetch_avatar( array( 602 'object' => $avatar_data['object'], 603 'item_id' => $avatar_data['item_id'], 604 'html' => false, 605 'type' => 'full', 606 ) ), 607 'message' => sprintf( _x( '%s was deleted successfully!', 'avatar deleted feedback', 'buddypress' ), $message_part ), 608 'item_id' => $avatar_data['item_id'], 609 ); 610 611 wp_send_json_success( $return ); 612 } else { 613 wp_send_json_error( array( 614 'message' => sprintf( _x( 'There was a problem deleting %s. Please try again.', 'buddypress' ), strtolower( $message_part ) ) 615 ) ); 616 } 617 } 618 add_action( 'wp_ajax_bp_avatar_delete', 'bp_core_avatar_ajax_delete' ); 619 620 /** 556 621 * Handle avatar uploading. 557 622 * 558 623 * The functions starts off by checking that the file has been uploaded … … function bp_core_avatar_handle_upload( $file, $upload_dir_filter ) { 625 690 } 626 691 627 692 /** 693 * Ajax upload an avatar 694 * 695 * @since BuddyPress (2.3.0) 696 * 697 * @uses bp_core_avatar_handle_upload() 698 * @uses apply_filters() call 'bp_core_avatar_ajax_upload_params' if you need to ajax set 699 * avatars for another component (eg: blavatar) 700 * @return string a json object containing success data if the upload succeeded 701 * error message otherwise 702 */ 703 function bp_core_avatar_ajax_upload() { 704 // Bail if not a POST action 705 if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { 706 wp_send_json_error(); 707 } 708 709 // Check the nonce 710 check_admin_referer( 'bp-uploader' ); 711 712 // Capability check 713 if ( ! bp_is_item_admin() && ! bp_current_user_can( 'bp_moderate' ) && ! bp_is_group_create() ) { 714 wp_send_json_error(); 715 } 716 717 // Init the BuddyPress parameters 718 $bp_params = array(); 719 720 // We need it to carry on 721 if ( ! empty( $_POST['bp_params' ] ) ) { 722 $bp_params = $_POST['bp_params' ]; 723 } else { 724 wp_send_json_error(); 725 } 726 727 // We need the object to set the uploads dir filter 728 if ( empty( $bp_params['object'] ) ) { 729 wp_send_json_error(); 730 } 731 732 $bp = buddypress(); 733 $bp_params['upload_dir_filter'] = ''; 734 $needs_reset = array(); 735 736 if ( 'user' == $bp_params['object'] && bp_is_active( 'xprofile' ) ) { 737 $bp_params['upload_dir_filter'] = 'xprofile_avatar_upload_dir'; 738 739 if ( ! bp_displayed_user_id() && ! empty( $bp_params['item_id'] ) ) { 740 $needs_reset = array( 'key' => 'displayed_user', 'value' => $bp->displayed_user ); 741 $bp->displayed_user->id = $bp_params['item_id']; 742 } 743 } else if ( 'group' == $bp_params['object'] && bp_is_active( 'groups' ) ) { 744 $bp_params['upload_dir_filter'] = 'groups_avatar_upload_dir'; 745 746 if ( ! bp_get_current_group_id() && ! empty( $bp_params['item_id'] ) ) { 747 $needs_reset = array( 'component' => 'groups', 'key' => 'current_group', 'value' => $bp->groups->current_group ); 748 $bp->groups->current_group = groups_get_group( array( 749 'group_id' => $bp_params['item_id'], 750 'populate_extras' => false, 751 ) ); 752 } 753 } else { 754 /** 755 * Filter here to deal with other components 756 * 757 * @since BuddyPress (2.3.0) 758 * 759 * @var array $bp_params the BuddyPress Ajax parameters 760 */ 761 $bp_params = apply_filters( 'bp_core_avatar_ajax_upload_params', $bp_params ); 762 } 763 764 if ( ! isset( $bp->avatar_admin ) ) { 765 $bp->avatar_admin = new stdClass(); 766 } 767 768 // Upload the avatar 769 $avatar = bp_core_avatar_handle_upload( $_FILES, $bp_params['upload_dir_filter'] ); 770 771 // Reset objects 772 if ( ! empty( $needs_reset ) ) { 773 if ( ! empty( $needs_reset['component'] ) ) { 774 $bp->{$needs_reset['component']}->{$needs_reset['key']} = $needs_reset['value']; 775 } else { 776 $bp->{$needs_reset['key']} = $needs_reset['value']; 777 } 778 } 779 780 // Intercept the template message and remove it 781 if ( empty( $avatar ) ) { 782 $message = $bp->template_message; 783 784 // Remove template message. 785 if ( isset( $_COOKIE['bp-message'] ) ) { 786 @setcookie( 'bp-message', false, time() - 1000, COOKIEPATH ); 787 } 788 789 if ( isset( $_COOKIE['bp-message-type'] ) ) { 790 @setcookie( 'bp-message-type', false, time() - 1000, COOKIEPATH ); 791 } 792 793 wp_send_json_error(array( 794 'type' => 'upload_error', 795 'message' => $message, 796 ) ); 797 } 798 799 if ( empty( $bp->avatar_admin->image->file ) ) { 800 wp_send_json_error(); 801 } 802 803 $uploaded_image = @getimagesize( $bp->avatar_admin->image->file ); 804 805 // Set the name of the file 806 $name = $_FILES['file']['name']; 807 $name_parts = pathinfo( $name ); 808 $name = trim( substr( $name, 0, - ( 1 + strlen( $name_parts['extension'] ) ) ) ); 809 810 if ( 'user' == $bp_params['object'] ) { 811 do_action( 'xprofile_avatar_uploaded' ); 812 } 813 814 // Finally return the avatar to the editor 815 wp_send_json_success( array( 816 'name' => $name, 817 'url' => $bp->avatar_admin->image->url, 818 'width' => $uploaded_image[0], 819 'height' => $uploaded_image[1], 820 ) ); 821 } 822 add_action( 'wp_ajax_bp_avatar_upload', 'bp_core_avatar_ajax_upload' ); 823 824 /** 825 * Handle avatar webcam capture. 826 * 827 * @since BuddyPress (2.3.0) 828 * 829 * @param string $data base64 encoded image. 830 * @param int $item_id. 831 * @return bool True on success, false on failure. 832 */ 833 function bp_core_avatar_handle_capture( $data = '', $item_id = 0 ) { 834 if ( empty( $data ) || empty( $item_id ) ) { 835 return false; 836 } 837 838 $avatar_dir = bp_core_avatar_upload_path() . '/avatars'; 839 840 // It's not a regular upload, we may need to create this folder 841 if ( ! file_exists( $avatar_dir ) ) { 842 if ( ! wp_mkdir_p( $avatar_dir ) ) { 843 return false; 844 } 845 } 846 847 $avatar_folder_dir = apply_filters( 'bp_core_avatar_folder_dir', $avatar_dir . '/' . $item_id, $item_id, 'user', 'avatars' ); 848 849 // It's not a regular upload, we may need to create this folder 850 if( ! file_exists( $avatar_folder_dir ) ) { 851 if ( ! wp_mkdir_p( $avatar_folder_dir ) ) { 852 return false; 853 } 854 } 855 856 $original_file = $avatar_folder_dir . '/webcam-capture-' . $item_id . '.png'; 857 858 if ( file_put_contents( $original_file, $data ) ) { 859 $avatar_to_crop = str_replace( bp_core_avatar_upload_path(), '', $original_file ); 860 861 // Crop to default values 862 $crop_args = array( 'item_id' => $item_id, 'original_file' => $avatar_to_crop, 'crop_x' => 0, 'crop_y' => 0 ); 863 864 do_action( 'xprofile_avatar_uploaded' ); 865 866 return bp_core_avatar_handle_crop( $crop_args ); 867 } else { 868 return false; 869 } 870 } 871 872 /** 628 873 * Crop an uploaded avatar. 629 874 * 630 875 * $args has the following parameters: … … function bp_core_avatar_handle_crop( $args = '' ) { 689 934 } 690 935 691 936 /** 937 * Ajax set an avatar for a given object and item id 938 * 939 * @since BuddyPress (2.3.0) 940 * 941 * @uses bp_core_avatar_handle_capture() 942 * @uses bp_core_avatar_handle_crop() 943 * @return string a json object containing success data if the crop/capture succeeded 944 * error message otherwise 945 */ 946 function bp_core_avatar_ajax_set() { 947 // Bail if not a POST action 948 if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { 949 wp_send_json_error(); 950 } 951 952 // Check the nonce 953 check_admin_referer( 'bp_avatar_cropstore', 'nonce' ); 954 955 // Capability check 956 if ( ! bp_is_item_admin() && ! bp_current_user_can( 'bp_moderate' ) && ! bp_is_group_create() ) { 957 wp_send_json_error(); 958 } 959 960 $avatar_data = wp_parse_args( $_POST, array( 961 'crop_w' => bp_core_avatar_full_width(), 962 'crop_h' => bp_core_avatar_full_height(), 963 'crop_x' => 0, 964 'crop_y' => 0 965 ) ); 966 967 if ( empty( $avatar_data['object'] ) || empty( $avatar_data['item_id'] ) || empty( $avatar_data['original_file'] ) ) { 968 wp_send_json_error(); 969 } 970 971 if ( ! empty( $avatar_data['type'] ) && 'camera' == $avatar_data['type'] && 'user' == $avatar_data['object'] ) { 972 $webcam_avatar = false; 973 974 if ( ! empty( $avatar_data['original_file'] ) ) { 975 $webcam_avatar = str_replace( array( 'data:image/png;base64,', ' ' ), array( '', '+' ), $avatar_data['original_file'] ); 976 $webcam_avatar = base64_decode( $webcam_avatar ); 977 } 978 979 if ( ! bp_core_avatar_handle_capture( $webcam_avatar, $avatar_data['item_id'] ) ) { 980 wp_send_json_error( array( 981 'message' => __( 'There was a problem cropping your profile photo.', 'buddypress' ) 982 ) ); 983 984 } else { 985 $return = array( 986 'avatar' => bp_core_fetch_avatar( array( 987 'object' => $avatar_data['object'], 988 'item_id' => $avatar_data['item_id'], 989 'html' => false, 990 'type' => 'full', 991 ) ), 992 'message' => __( 'Your new profile photo was uploaded successfully.', 'buddypress' ), 993 'item_id' => $avatar_data['item_id'], 994 ); 995 996 do_action( 'xprofile_screen_change_avatar' ); 997 998 wp_send_json_success( $return ); 999 } 1000 1001 return; 1002 } 1003 1004 $original_file = str_replace( bp_core_avatar_url(), '', $avatar_data['original_file'] ); 1005 1006 // Set avatars dir & feedback part 1007 if ( 'user' == $avatar_data['object'] ) { 1008 $avatar_dir = 'avatars'; 1009 $message_part = _x( 'Your profile photo', 'user object avatar photo', 'buddypress' ); 1010 1011 // Defaults to object-avatars dir 1012 } else { 1013 $avatar_dir = sanitize_key( $avatar_data['object'] ) . '-avatars'; 1014 $message_part = sprintf( _x( 'The %s profile photo', 'generic object avatar photo', 'buddypress' ), $avatar_data['object'] ); 1015 } 1016 1017 // Crop args 1018 $r = array( 1019 'item_id' => $avatar_data['item_id'], 1020 'object' => $avatar_data['object'], 1021 'avatar_dir' => $avatar_dir, 1022 'original_file' => $original_file, 1023 'crop_w' => $avatar_data['crop_w'], 1024 'crop_h' => $avatar_data['crop_h'], 1025 'crop_x' => $avatar_data['crop_x'], 1026 'crop_y' => $avatar_data['crop_y'] 1027 ); 1028 1029 // Handle crop 1030 if ( bp_core_avatar_handle_crop( $r ) ) { 1031 $return = array( 1032 'avatar' => bp_core_fetch_avatar( array( 1033 'object' => $avatar_data['object'], 1034 'item_id' => $avatar_data['item_id'], 1035 'html' => false, 1036 'type' => 'full', 1037 ) ), 1038 'message' => sprintf( _x( '%s was uploaded successfully.', 'avatar crop success feedback', 'buddypress' ), $message_part ), 1039 'item_id' => $avatar_data['item_id'], 1040 ); 1041 1042 if ( 'user' == $avatar_data['object'] ) { 1043 do_action( 'xprofile_screen_change_avatar' ); 1044 } 1045 1046 wp_send_json_success( $return ); 1047 } else { 1048 wp_send_json_error( array( 1049 'message' => sprintf( _x( 'There was a problem cropping %s.', 'avatar crop error feedback', 'buddypress' ), strtolower( $message_part ) ) 1050 ) ); 1051 } 1052 } 1053 add_action( 'wp_ajax_bp_avatar_set', 'bp_core_avatar_ajax_set' ); 1054 1055 /** 692 1056 * Replace default WordPress avatars with BP avatars, if available. 693 1057 * 694 1058 * Filters 'get_avatar'. … … function bp_core_avatar_reset_query( $posts_query = null ) { 1098 1462 } 1099 1463 } 1100 1464 add_action( 'bp_parse_query', 'bp_core_avatar_reset_query', 10, 1 ); 1465 1466 /** 1467 * Checks whether Avatar UI should be loaded 1468 * 1469 * @since BuddyPress (2.3.0) 1470 * 1471 * @uses bp_is_user_change_avatar() 1472 * @uses bp_get_avatar_admin_step() 1473 * @uses bp_is_active() 1474 * @uses bp_is_group_create() 1475 * @uses bp_is_group_creation_step() 1476 * @uses bp_is_group_admin_page() 1477 * @uses bp_is_group_admin_screen() 1478 * @return bool True if Avatar UI should load, false otherwise 1479 */ 1480 function bp_core_avatar_is_front_edit_avatar() { 1481 $retval = false; 1482 1483 if ( bp_is_user_change_avatar() && 'crop-image' != bp_get_avatar_admin_step() ) { 1484 $retval = true; 1485 } 1486 1487 if ( bp_is_active( 'groups' ) ) { 1488 // Group creation 1489 if ( bp_is_group_create() && bp_is_group_creation_step( 'group-avatar' ) && 'crop-image' != bp_get_avatar_admin_step() ) { 1490 $retval = true; 1491 1492 // Group Manage 1493 } else if ( bp_is_group_admin_page() && bp_is_group_admin_screen( 'group-avatar' ) && 'crop-image' != bp_get_avatar_admin_step() ) { 1494 $retval = true; 1495 } 1496 } 1497 1498 /** 1499 * Use this filter if you need to : 1500 * - Load the avatar UI for a component that is !groups or !user (return true regarding your conditions) 1501 * - Completely disable the avatar UI introduced in 2.3 (eg: __return_false()) 1502 * 1503 * @since BuddyPress (2.3.0) 1504 * 1505 * @var bool whether to load the Avatar UI 1506 */ 1507 return apply_filters( 'bp_core_avatar_is_front_edit_avatar', $retval ); 1508 } 1509 1510 /** 1511 * Template function to load the Avatar UI javascript templates 1512 * 1513 * @since BuddyPress (2.3.0) 1514 * 1515 * @uses bp_core_avatar_is_front_edit_avatar() to check whether javascript templates should be loaded 1516 * @uses bp_get_template_part() to load the template part 1517 */ 1518 function bp_core_avatar_get_template_part() { 1519 if ( ! bp_core_avatar_is_front_edit_avatar() ) { 1520 return; 1521 } 1522 1523 bp_get_template_part( 'avatars/index' ); 1524 } 1525 1526 /** 1527 * Trick to check if the theme's BuddyPress templates are up to date 1528 * 1529 * If the "avatar templates" are not including the new template tag, this will 1530 * help users to get the avatar UI and inform the most curious that their 1531 * templates are out of date. 1532 * 1533 * @since BuddyPress (2.3.0) 1534 * 1535 * @uses bp_core_avatar_is_front_edit_avatar() to check whether javascript templates should be loaded 1536 * @uses did_action() to check if the javascript template was loaded 1537 * @uses bp_get_template_part() to load the template part 1538 */ 1539 function bp_core_avatar_template_check() { 1540 if ( ! bp_core_avatar_is_front_edit_avatar() ) { 1541 return; 1542 } 1543 1544 if ( ! did_action( 'bp_attachments_avatar_check_template' ) ) { 1545 _doing_it_wrong( 'Theme Compatibility', __( "The templates of your theme should be updated", 'buddypress' ), '2.3' ); 1546 bp_get_template_part( 'avatars/index' ); 1547 } 1548 } -
src/bp-core/bp-core-cssjs.php
diff --git src/bp-core/bp-core-cssjs.php src/bp-core/bp-core-cssjs.php index b25eb2b..a480000 100644
function bp_core_register_common_scripts() { 28 28 $scripts = apply_filters( 'bp_core_register_common_scripts', array( 29 29 30 30 // Legacy 31 'bp-confirm' => array( 'file' => "{$url}confirm{$min}.js", 'dependencies' => array( 'jquery' ) ),32 'bp-widget-members' => array( 'file' => "{$url}widget-members{$min}.js", 'dependencies' => array( 'jquery' ) ),33 'bp-jquery-query' => array( 'file' => "{$url}jquery-query{$min}.js", 'dependencies' => array( 'jquery' ) ),34 'bp-jquery-cookie' => array( 'file' => "{$url}jquery-cookie{$min}.js", 'dependencies' => array( 'jquery' ) ),35 'bp-jquery-scroll-to' => array( 'file' => "{$url}jquery-scroll-to{$min}.js", 'dependencies' => array( 'jquery' ) ),31 'bp-confirm' => array( 'file' => "{$url}confirm{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ), 32 'bp-widget-members' => array( 'file' => "{$url}widget-members{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ), 33 'bp-jquery-query' => array( 'file' => "{$url}jquery-query{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ), 34 'bp-jquery-cookie' => array( 'file' => "{$url}jquery-cookie{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ), 35 'bp-jquery-scroll-to' => array( 'file' => "{$url}jquery-scroll-to{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ), 36 36 37 37 // 2.1 38 'jquery-caret' => array( 'file' => "{$url}jquery.caret{$min}.js", 'dependencies' => array( 'jquery' ) ), 39 'jquery-atwho' => array( 'file' => "{$url}jquery.atwho{$min}.js", 'dependencies' => array( 'jquery', 'jquery-caret' ) ), 38 'jquery-caret' => array( 'file' => "{$url}jquery.caret{$min}.js", 'dependencies' => array( 'jquery' ), 'footer' => false ), 39 'jquery-atwho' => array( 'file' => "{$url}jquery.atwho{$min}.js", 'dependencies' => array( 'jquery', 'jquery-caret' ), 'footer' => false ), 40 41 // 2.3 42 'bp-plupload' => array( 'file' => "{$url}bp-plupload{$min}.js", 'dependencies' => array( 'plupload', 'jquery', 'json2', 'wp-backbone' ), 'footer' => true ), 43 'bp-avatar' => array( 'file' => "{$url}avatar{$min}.js", 'dependencies' => array( 'imgareaselect' ), 'footer' => true ), 44 'bp-webcam' => array( 'file' => "{$url}webcam{$min}.js", 'dependencies' => array( 'bp-avatar' ), 'footer' => true ), 45 40 46 ) ); 41 47 42 48 $version = bp_get_version(); 43 49 foreach ( $scripts as $id => $script ) { 44 wp_register_script( $id, $script['file'], $script['dependencies'], $version );50 wp_register_script( $id, $script['file'], $script['dependencies'], $version, $script['footer'] ); 45 51 } 46 52 } 47 53 add_action( 'bp_enqueue_scripts', 'bp_core_register_common_scripts', 1 ); … … function bp_core_register_common_styles() { 76 82 'bp-admin-bar' => array( 77 83 'file' => $admin_bar_file, 78 84 'dependencies' => array( 'admin-bar' ) 79 ) 85 ), 86 'bp-avatar' => array( 87 'file' => "{$url}avatar{$min}.css", 88 'dependencies' => array( 'imgareaselect' ) 89 ), 80 90 ) ); 81 91 82 92 foreach ( $styles as $id => $style ) { … … add_action( 'bp_enqueue_scripts', 'bp_core_confirmation_js' ); 110 120 add_action( 'admin_enqueue_scripts', 'bp_core_confirmation_js' ); 111 121 112 122 /** 123 * Enqueues the css and js required by the Avatar UI 124 * 125 * @since BuddyPress (2.3.0) 126 * 127 * @uses bp_core_avatar_is_front_edit_avatar() to check if the Avatar scripts should be loaded 128 * @uses bp_attachments_enqueue_scripts() to enqueue the css and js required by the Avatar UI 129 * @uses add_action() to eventually load the javascript template files if templates are outdated 130 */ 131 function bp_core_avatar_scripts() { 132 if ( ! bp_core_avatar_is_front_edit_avatar() ) { 133 return false; 134 } 135 136 // Enqueue the Attachments scripts for the Avatar UI 137 bp_attachments_enqueue_scripts( 'BP_Attachment_Avatar' ); 138 139 // Add Some actions for Theme backcompat 140 add_action( 'bp_after_profile_avatar_upload_content', 'bp_core_avatar_template_check' ); 141 add_action( 'bp_after_group_admin_content', 'bp_core_avatar_template_check' ); 142 add_action( 'bp_after_group_avatar_creation_step', 'bp_core_avatar_template_check' ); 143 } 144 add_action( 'bp_enqueue_scripts', 'bp_core_avatar_scripts' ); 145 146 /** 113 147 * Enqueues jCrop library and hooks BP's custom cropper JS. 114 148 */ 115 149 function bp_core_add_jquery_cropper() { -
src/bp-core/classes/class-bp-attachment-avatar.php
diff --git src/bp-core/classes/class-bp-attachment-avatar.php src/bp-core/classes/class-bp-attachment-avatar.php index 8940954..5627f14 100644
class BP_Attachment_Avatar extends BP_Attachment { 252 252 // Return the full and thumb cropped avatars 253 253 return $avatar_types; 254 254 } 255 256 /** 257 * Build script datas for the Uploader UI 258 * 259 * @since BuddyPress (2.3.0) 260 * 261 * @uses BP_Attachment::script_data() 262 */ 263 public function script_data() { 264 // Get default script data 265 $script_data = parent::script_data(); 266 267 // Defaults to Avatar Backbone script 268 $js_scripts = array( 'bp-avatar' ); 269 270 if ( bp_is_user() ) { 271 // Use this filter to disable the Webcam Avatar feature 272 if ( false !== apply_filters( 'bp_attachment_avatar_use_webcam', true ) ) { 273 $js_scripts = array( 'bp-webcam' ); 274 } 275 276 $script_data['bp_params'] = array( 277 'object' => 'user', 278 'item_id' => bp_displayed_user_id(), 279 'has_avatar' => bp_get_user_has_avatar(), 280 'nonces' => array( 281 'set' => wp_create_nonce( 'bp_avatar_cropstore' ), 282 'delete' => wp_create_nonce( 'bp_delete_avatar_link' ), 283 ), 284 ); 285 } else if ( bp_is_group() ) { 286 $script_data['bp_params'] = array( 287 'object' => 'group', 288 'item_id' => bp_get_current_group_id(), 289 'has_avatar' => bp_get_group_has_avatar(), 290 'nonces' => array( 291 'set' => wp_create_nonce( 'bp_avatar_cropstore' ), 292 'delete' => wp_create_nonce( 'bp_group_avatar_delete' ), 293 ), 294 ); 295 } else { 296 // Blavatar ? 297 $script_data['bp_params'] = apply_filters( 'bp_attachment_avatar_params', array() ); 298 } 299 300 // Include the specific css 301 $script_data['extra_css'] = array( 'bp-avatar' ); 302 303 // Include the specific css 304 $script_data['extra_js'] = $js_scripts; 305 306 return $script_data; 307 } 255 308 } -
src/bp-core/classes/class-bp-attachment.php
diff --git src/bp-core/classes/class-bp-attachment.php src/bp-core/classes/class-bp-attachment.php index 337c27f..951d646 100644
class BP_Attachment { 505 505 // Finally crop the image 506 506 return wp_crop_image( $r['original_file'], (int) $r['crop_x'], (int) $r['crop_y'], (int) $r['crop_w'], (int) $r['crop_h'], (int) $r['dst_w'], (int) $r['dst_h'], $r['src_abs'], $r['dst_file'] ); 507 507 } 508 509 /** 510 * Build script datas for the Uploader UI 511 * 512 * @since BuddyPress (2.3.0) 513 * 514 * Override this method from your child class to build the script datas 515 */ 516 public function script_data() { 517 $script_data = array( 518 'action' => $this->action, 519 'file_data_name' => $this->file_input, 520 'max_file_size' => $this->original_max_filesize, 521 ); 522 523 return $script_data; 524 } 508 525 } -
src/bp-core/css/avatar.css
diff --git src/bp-core/css/avatar.css src/bp-core/css/avatar.css index e69de29..216da00 100644
1 div.bp-avatar-status { 2 clear:both; 3 margin:1em 0; 4 } 5 6 div.bp-avatar-status p.updated { 7 display: block; 8 padding: 10px 15px; 9 } 10 11 div.bp-avatar-status p.success { 12 background-color: #efc; 13 border: 1px solid #591; 14 color: #250; 15 } 16 17 div.bp-avatar-status p.error { 18 background-color: #fdc; 19 border: 1px solid #a00; 20 color: #800; 21 } 22 23 .progress { 24 float: right; 25 height: 22px; 26 margin: 6px 10px 0 0; 27 width: 200px; 28 line-height: 2em; 29 padding: 0; 30 overflow: hidden; 31 margin-bottom: 2px; 32 border: 1px solid #d1d1d1; 33 background: none; 34 } 35 36 .bar { 37 z-index: 9; 38 width: 0; 39 height: 100%; 40 background-color: #c3ff88; 41 } 42 43 .bp-uploader-progress div.error { 44 font-size: 90%; 45 display: block; 46 padding: 10px 15px; 47 background-color: #fdc; 48 border: 1px solid #a00; 49 color: #800; 50 } 51 52 #bp-uploader-warning, #bp-webcam-message p.warning { 53 margin:1em 0; 54 font-size: 90%; 55 display: block; 56 padding: 10px 15px; 57 background-color: #ffec8b; 58 border: 1px solid #fc0; 59 color: #440; 60 } 61 62 div.bp-avatar-nav { 63 clear:both; 64 background: transparent; 65 margin: 10px 0 10px; 66 overflow: hidden; 67 } 68 69 .avatar-nav-items { 70 margin: 0; 71 padding: 0; 72 } 73 74 #buddypress .avatar-nav-items li.avatar-nav-item { 75 float: left; 76 margin: 0; 77 list-style: none; 78 } 79 80 .avatar-nav-items li a { 81 display: block; 82 padding: 5px 10px; 83 text-decoration: none; 84 } 85 86 .avatar-nav-items li.current a { 87 background-color: #eee; 88 color: #555; 89 opacity: .8; 90 font-weight: bold; 91 } 92 93 #drag-drop-area { 94 border: 4px dashed #bbb; 95 height: 200px; 96 } 97 98 .drag-drop.drag-over #drag-drop-area { 99 border-color: #83b4d8; 100 } 101 102 .drag-drop .drag-drop-inside { 103 margin: 70px auto 0; 104 width: 250px; 105 } 106 107 .drag-drop .drag-drop-inside p, .drag-drop-inside p.drag-drop-buttons { 108 display: block; 109 } 110 111 .drag-drop .drag-drop-inside p { 112 text-align: center; 113 color: #aaa; 114 font-size: 110%; 115 margin: 5px 0; 116 } 117 118 #avatar-to-crop { 119 float: left; 120 margin: 0 20px 20px 0; 121 text-align: left; 122 } 123 #avatar-crop-pane { 124 width: 150px; 125 height: 150px; 126 overflow: hidden; 127 } 128 129 #avatar-crop-actions { 130 margin: 20px 0; 131 } 132 133 #avatar-to-crop img, 134 #avatar-crop-pane img, 135 #avatar-upload-form img, 136 #create-group-form img, 137 #group-settings-form img { 138 border: none !important; 139 max-width: none !important; 140 } 141 142 #bp-webcam-avatar video { 143 float:left; 144 width:450px; 145 } 146 147 #bp-webcam-avatar #avatar-crop-pane { 148 border: 2px dashed #bbb; 149 } -
src/bp-core/js/avatar.js
diff --git src/bp-core/js/avatar.js src/bp-core/js/avatar.js index e69de29..70a6dba 100644
1 window.bp = window.bp || {}; 2 3 ( function( exports, $ ) { 4 5 // Bail if not set 6 if ( typeof BP_Uploader === 'undefined' ) { 7 return; 8 } 9 10 bp.Models = bp.Models || {}; 11 bp.Collections = bp.Collections || {}; 12 bp.Views = bp.Views || {}; 13 14 bp.Avatar = { 15 start: function() { 16 /** 17 * Remove the bp-legacy UI 18 * 19 * If for some reason javascript is disabled 20 * or broken, this is a way to keep the legacy UI 21 * as nothing will happen.. 22 */ 23 // User 24 if ( $( '#avatar-upload-form' ).length ) { 25 $( '#avatar-upload' ).remove(); 26 $( '#avatar-upload-form p' ).remove(); 27 28 // Group Manage 29 } else if ( $( '#group-settings-form' ).length ) { 30 $( '#group-settings-form p' ).each( function( i ) { 31 if ( 0 !== i ) { 32 $( this ).remove(); 33 } 34 } ); 35 36 if ( $( '#delete-group-avatar-button' ).length ) { 37 $( '#delete-group-avatar-button' ).remove(); 38 } 39 40 // Group Create 41 } else if ( $( '#group-create-body' ).length ) { 42 $( '.main-column p #file' ).remove(); 43 $( '.main-column p #upload' ).remove(); 44 } 45 46 // Init some vars 47 this.views = new Backbone.Collection(); 48 this.activeView = 'upload'; 49 this.iasapi = {}; 50 51 // Set up nav 52 this.setupNav(); 53 54 // Create the uploader view by default 55 this.uploaderView(); 56 57 // Avatars are uploaded files 58 this.avatars = bp.Uploader.filesUploaded; 59 this.avatars.on( 'add', this.cropView, this ); 60 }, 61 62 setView: function( view ) { 63 // Clear views 64 if ( ! _.isUndefined( this.views.models ) ) { 65 _.each( this.views.models, function( model ) { 66 model.get( 'view' ).remove(); 67 }, this ); 68 } 69 70 // Reset objects 71 this.views.reset(); 72 this.avatars.reset(); 73 74 if ( ! _.isEmpty( this.iasapi ) ) { 75 this.iasapi.remove(); 76 this.iasapi = {}; 77 } 78 79 // Load the required view 80 switch ( view ) { 81 case 'upload': 82 this.uploaderView(); 83 break; 84 85 case 'delete': 86 this.deleteView(); 87 break; 88 } 89 }, 90 91 setupNav: function() { 92 var nav = new Backbone.Collection(), 93 self = this; 94 95 _.each( BP_Uploader.settings.nav, function( item ) { 96 if ( ! _.isObject( item ) ) { 97 return; 98 } 99 100 nav.add( { 101 id: item.id, 102 name: item.caption, 103 href: '#', 104 active: ( self.activeView == item.id ) ? 1 : 0, 105 } ); 106 } ); 107 108 this.nav = new bp.Views.Nav( { collection: nav } ); 109 this.nav.inject( '.bp-avatar-nav' ); 110 111 // Listen to nav changes (it's like a do_action!) 112 this.nav.on( 'bp-avatar-view:changed', _.bind( this.setView, this ) ); 113 }, 114 115 uploaderView: function() { 116 // Listen to the Queued uploads 117 bp.Uploader.filesQueue.on( 'add', this.uploadProgress, this ); 118 119 // Create the BuddyPress Uploader 120 uploader = new bp.Views.Uploader(); 121 122 // Add it to views 123 this.views.add( { id: 'upload', view: uploader } ); 124 125 // Display it 126 uploader.inject( '.bp-avatar' ); 127 }, 128 129 uploadProgress: function( model ) { 130 // Create the Uploader status view 131 avatarStatus = new bp.Views.uploaderStatus( { collection: bp.Uploader.filesQueue } ); 132 133 if ( ! _.isUndefined( this.views.get( 'status' ) ) ) { 134 this.views.set( { id: 'status', view: avatarStatus } ); 135 } else { 136 this.views.add( { id: 'status', view: avatarStatus } ); 137 } 138 139 // Display it 140 avatarStatus.inject( '.bp-avatar-status' ); 141 }, 142 143 cropView: function() { 144 var status; 145 146 // Make sure to remove the uploads status 147 if ( ! _.isUndefined( this.views.get( 'status' ) ) ) { 148 status = this.views.get( 'status' ); 149 status.get( 'view' ).remove(); 150 this.views.remove( { id: 'status', view: status } ); 151 } 152 153 // Create the Avatars view 154 avatar = new bp.Views.Avatars( { collection: this.avatars } ); 155 this.views.add( { id: 'crop', view: avatar } ); 156 157 avatar.inject( '.bp-avatar' ); 158 }, 159 160 setAvatar: function( avatar ) { 161 var self = this, 162 crop; 163 164 // Remove the crop view 165 if ( ! _.isUndefined( this.views.get( 'crop' ) ) ) { 166 // Remove the imgAreaSelect API 167 if ( ! _.isEmpty( this.iasapi ) ) { 168 this.iasapi.remove(); 169 this.iasapi = {}; 170 } 171 crop = this.views.get( 'crop' ); 172 crop.get( 'view' ).remove(); 173 this.views.remove( { id: 'crop', view: crop } ); 174 } 175 176 // Set the avatar ! 177 bp.ajax.post( 'bp_avatar_set', { 178 json: true, 179 original_file: avatar.get( 'url' ), 180 crop_w: avatar.get( 'w' ), 181 crop_h: avatar.get( 'h' ), 182 crop_x: avatar.get( 'x' ), 183 crop_y: avatar.get( 'y' ), 184 item_id: avatar.get( 'item_id' ), 185 object: avatar.get( 'object' ), 186 type: _.isUndefined( avatar.get( 'type' ) ) ? 'crop' : avatar.get( 'type' ), 187 nonce: avatar.get( 'nonces' ).set, 188 } ).done( function( response ) { 189 avatarStatus = new bp.Views.AvatarStatus( { 190 value : response.message, 191 type : 'success', 192 } ); 193 194 self.views.add( { 195 id : 'status', 196 view : avatarStatus 197 } ); 198 199 avatarStatus.inject( '.bp-avatar-status' ); 200 201 // Update each avatars of the page 202 $( '.' + avatar.get( 'object' ) + '-' + response.item_id + '-avatar' ).each( function() { 203 $(this).prop( 'src', response.avatar ); 204 } ); 205 } ).fail( function( response ) { 206 avatarStatus = new bp.Views.AvatarStatus( { 207 value : response.message, 208 type : 'error', 209 } ); 210 211 self.views.add( { 212 id : 'status', 213 view : avatarStatus 214 } ); 215 216 avatarStatus.inject( '.bp-avatar-status' ); 217 } ); 218 }, 219 220 deleteView:function() { 221 // Create the delete model 222 delete_model = new Backbone.Model( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, 223 'object', 224 'item_id', 225 'nonces' 226 ) ); 227 228 // Create the delete view 229 deleteView = new bp.Views.DeleteAvatar( { model: delete_model } ); 230 231 // Add it to views 232 this.views.add( { id: 'delete', view: deleteView } ); 233 234 // Display it 235 deleteView.inject( '.bp-avatar' ); 236 }, 237 238 deleteAvatar: function( model ) { 239 var self = this, 240 deleteView; 241 242 // Remove the delete view 243 if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) { 244 deleteView = this.views.get( 'delete' ); 245 deleteView.get( 'view' ).remove(); 246 this.views.remove( { id: 'delete', view: deleteView } ); 247 } 248 249 // Remove the avatar ! 250 bp.ajax.post( 'bp_avatar_delete', { 251 json: true, 252 item_id: model.get( 'item_id' ), 253 object: model.get( 'object' ), 254 nonce: model.get( 'nonces' ).delete, 255 } ).done( function( response ) { 256 avatarStatus = new bp.Views.AvatarStatus( { 257 value : response.message, 258 type : 'success', 259 } ); 260 261 self.views.add( { 262 id : 'status', 263 view : avatarStatus 264 } ); 265 266 avatarStatus.inject( '.bp-avatar-status' ); 267 268 // Update each avatars of the page 269 $( '.' + model.get( 'object' ) + '-' + response.item_id + '-avatar').each( function() { 270 $(this).prop( 'src', response.avatar ); 271 } ); 272 273 /** 274 * Remove the delete tab 275 * @todo this should be more dynamic using model.set() 276 * - create the delete tab when new avatar is set 277 * - remove the delete tab when avatar is deleted. 278 * 279 * For now, let's just remove the nav 280 */ 281 $( '#bp-avatar-delete' ).remove(); 282 283 } ).fail( function( response ) { 284 avatarStatus = new bp.Views.AvatarStatus( { 285 value : response.message, 286 type : 'error', 287 } ); 288 289 self.views.add( { 290 id : 'status', 291 view : avatarStatus 292 } ); 293 294 avatarStatus.inject( '.bp-avatar-status' ); 295 } ); 296 } 297 }; 298 299 // Main Nav view 300 bp.Views.Nav = bp.View.extend( { 301 tagName: 'ul', 302 className: 'avatar-nav-items', 303 304 events: { 305 'click .bp-avatar-nav-item' : 'toggleView', 306 }, 307 308 initialize: function() { 309 _.each( this.collection.models, this.addNavItem, this ); 310 }, 311 312 addNavItem: function( item ) { 313 this.views.add( new bp.Views.NavItem( { model: item } ) ); 314 }, 315 316 toggleView: function( event ) { 317 event.preventDefault(); 318 319 var active = $( event.target ).data( 'nav' ); 320 321 _.each( this.collection.models, function( model ) { 322 if ( model.id == active ) { 323 model.set( { active: 1 } ); 324 this.trigger( 'bp-avatar-view:changed', model.id ) 325 } else { 326 model.set( { active: 0 } ); 327 } 328 }, this ); 329 }, 330 } ); 331 332 // Nav item view 333 bp.Views.NavItem = bp.View.extend( { 334 tagName: 'li', 335 className: 'avatar-nav-item', 336 template: bp.template( 'bp-avatar-nav' ), 337 338 initialize: function() { 339 if ( 1 == this.model.get( 'active' ) ) { 340 this.el.className += ' current'; 341 } 342 this.el.id += 'bp-avatar-' + this.model.get( 'id' ); 343 344 this.model.on( 'change:active', this.setCurrentNav, this ); 345 }, 346 347 setCurrentNav: function( model ) { 348 if ( 1 == model.get( 'active' ) ) { 349 this.$el.addClass( 'current' ); 350 } else { 351 this.$el.removeClass( 'current' ); 352 } 353 }, 354 } ); 355 356 // Avatars view 357 bp.Views.Avatars = bp.View.extend( { 358 className: "items", 359 360 initialize: function() { 361 _.each( this.collection.models, this.addItemView, this ); 362 }, 363 364 addItemView: function( item ) { 365 item.set( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, 366 'object', 367 'item_id', 368 'nonces' 369 ) ); 370 this.views.add( new bp.Views.Avatar( { model: item } ) ); 371 } 372 } ); 373 374 // Avatar view 375 bp.Views.Avatar = bp.View.extend( { 376 className: "item", 377 template: bp.template( 'bp-avatar-item' ), 378 379 events: { 380 'click .avatar-crop-submit': 'cropAvatar', 381 }, 382 383 initialize: function() { 384 _.defaults( this.options, { 385 full_h: BP_Uploader.settings.crop.full_h, 386 full_w: BP_Uploader.settings.crop.full_w, 387 aspectRatio : '150:150' 388 } ); 389 390 this.on( 'ready', this.initCropper ); 391 }, 392 393 initCropper: function() { 394 var self = this, 395 tocrop = this.$el.find( '#avatar-to-crop img' ), 396 selection = {}; 397 398 if ( ! _.isUndefined( this.options.full_h ) && ! _.isUndefined( this.options.full_w ) ) { 399 this.options.aspectRatio = this.options.full_h + ':' + this.options.full_w; 400 } 401 402 selection.w = this.model.get( 'width' ); 403 selection.h = this.model.get( 'height' ); 404 405 if ( selection.h <= selection.w ) { 406 crop_top = Math.round( selection.h / 4 ); 407 nh = nw = Math.round( selection.h / 2 ); 408 crop_bottom = nh + crop_top; 409 crop_left = ( selection.w - nw ) / 2; 410 crop_right = nw + crop_left; 411 } else { 412 crop_left = Math.round( selection.w / 4 ); 413 nh = nw = Math.round( selection.w / 2 ); 414 crop_right = nw + crop_left; 415 crop_top = ( selection.h - nh ) / 2;; 416 crop_bottom = nh + crop_top; 417 } 418 419 /** 420 * Add the cropping interface 421 * We're not specifying the parent option of the imgAreaSelect API 422 * as it can be problematic with some themes (eg: twentyfifteen) 423 */ 424 bp.Avatar.iasapi = tocrop.imgAreaSelect( { 425 instance: true, 426 aspectRatio: self.options.aspectRatio, 427 handles:true, 428 x1: crop_left, 429 y1: crop_top, 430 x2: crop_right, 431 y2: crop_bottom, 432 onInit: function () { 433 self.model.set( { x: crop_left, y: crop_top, w: nw, h: nh } ); 434 self.showPreview( self.model, self.options ); 435 }, 436 onSelectChange: function( img, c ) { 437 self.model.set( { x: c.x1, y: c.y1, w: c.width, h: c.height } ); 438 self.showPreview( self.model, self.options ); 439 } 440 } ); 441 }, 442 443 cropAvatar: function( event ) { 444 event.preventDefault(); 445 446 bp.Avatar.setAvatar( this.model ); 447 }, 448 449 showPreview: function( model, options ) { 450 if ( ! model.get( 'w' ) || ! model.get( 'h' ) ) { 451 return; 452 } 453 454 if ( parseInt( model.get( 'w' ) ) > 0 ) { 455 var fw = options.full_w; 456 var fh = options.full_h; 457 var rx = fw / model.get( 'w' ); 458 var ry = fh / model.get( 'h' ); 459 460 $( '#avatar-crop-preview' ).css( { 461 maxWidth:'none', 462 width: Math.round( rx * model.get( 'width' ) )+ 'px', 463 height: Math.round( ry * model.get( 'height' ) )+ 'px', 464 marginLeft: '-' + Math.round( rx * model.get( 'x' ) ) + 'px', 465 marginTop: '-' + Math.round( ry * model.get( 'y' ) ) + 'px' 466 } ); 467 } 468 }, 469 470 } ); 471 472 // BuddyPress Avatar Feedback view 473 bp.Views.AvatarStatus = bp.View.extend( { 474 tagName: 'p', 475 className: 'updated', 476 id: 'bp-avatar-feedback', 477 478 initialize: function() { 479 this.el.className += ' ' + this.options.type; 480 this.value = this.options.value; 481 }, 482 483 render: function() { 484 this.$el.html( this.value ); 485 return this; 486 } 487 } ); 488 489 // BuddyPress Avatar Delete view 490 bp.Views.DeleteAvatar = bp.View.extend( { 491 tagName: 'div', 492 id: 'bp-delete-avatar', 493 template: bp.template( 'bp-avatar-delete' ), 494 495 events: { 496 'click #bp-delete-avatar': 'deleteAvatar', 497 }, 498 499 deleteAvatar: function( event ) { 500 event.preventDefault(); 501 502 bp.Avatar.deleteAvatar( this.model ); 503 } 504 } ); 505 506 bp.Avatar.start(); 507 508 })( bp, jQuery ); -
src/bp-core/js/bp-plupload.js
diff --git src/bp-core/js/bp-plupload.js src/bp-core/js/bp-plupload.js index e69de29..07f0959 100644
1 window.wp = window.wp || {}; 2 window.bp = window.bp || window.wp; 3 4 ( function( exports, $ ) { 5 6 // Bail if not set 7 if ( typeof BP_Uploader === 'undefined' ) { 8 return; 9 } 10 11 bp.Models = bp.Models || {}; 12 bp.Collections = bp.Collections || {}; 13 bp.Views = bp.Views || {}; 14 bp.Uploader = {}; 15 16 /** 17 * BuddyPress Uploader. 18 * 19 * This is an adapted version of wp.Uploader 20 */ 21 bp.Uploader.uploader = function() { 22 var self = this; 23 this.params = BP_Uploader.settings; 24 this.strings = BP_Uploader.strings; 25 26 this.uploader = new plupload.Uploader( this.params.defaults ); 27 multipart_origin = this.uploader.settings.multipart_params; 28 29 /** 30 * After the Uploader has been initialized, initialize some behaviors for the dropzone. 31 * 32 * @event Init 33 * @param {plupload.Uploader} uploader Uploader instance. 34 */ 35 this.uploader.bind( 'Init', function( uplaoder ) { 36 var container = $( '#' + self.params.defaults.container ), 37 drop_element = $( '#' + self.params.defaults.drop_element ); 38 39 if ( uplaoder.features.dragdrop && ! $( document.body ).hasClass( 'mobile' ) ) { 40 container.addClass( 'drag-drop' ); 41 drop_element.bind( 'dragover.wp-uploader', function() { 42 container.addClass( 'drag-over' ); 43 } ).bind( 'dragleave.wp-uploader, drop.wp-uploader', function() { 44 container.removeClass( 'drag-over' ); 45 } ); 46 } else { 47 container.removeClass( 'drag-drop' ); 48 drop_element.unbind( '.wp-uploader' ); 49 } 50 51 if ( uplaoder.runtime == 'html4' ) { 52 $('.upload-flash-bypass').hide(); 53 } 54 55 } ); 56 57 // Init BuddyPress Uploader 58 this.uploader.init(); 59 60 /** 61 * Feedback callback. 62 * 63 * Add a new message to the errors collection, so it's possible 64 * to give some feedback to the user 65 * 66 * @param {string} message 67 * @param {object} data 68 * @param {plupload.File} file File that was uploaded. 69 */ 70 feedback = function( message, data, file ) { 71 if ( ! _.isNull( file ) && file.item ) { 72 file.item.clear(); 73 } 74 75 bp.Uploader.filesError.unshift( { 76 message: message, 77 data: data, 78 file: file 79 } ); 80 }; 81 82 /** 83 * After files were filtered and added to the queue, create a model for each. 84 * 85 * @event FilesAdded 86 * @param {plupload.Uploader} uploader Uploader instance. 87 * @param {Array} files Array of file objects that were added to queue by the user. 88 */ 89 this.uploader.bind( 'FilesAdded', function( uploader, files ) { 90 hundredmb = 100 * 1024 * 1024, max = parseInt( uploader.settings.max_file_size, 10 ); 91 92 /** 93 * In case the multiple selection is false (eg: avatar) stop the process and send 94 * and event containing a warning 95 */ 96 if ( ! uploader.settings.multi_selection && files.length > 1 ) { 97 for ( i in files ) { 98 uploader.removeFile( files[i] ); 99 } 100 101 $(self).trigger( 'bp-uploader-warning', self.strings.unique_file_warning ); 102 return; 103 } 104 105 _.each( files, function( file ) { 106 var attributes; 107 108 // Ignore failed uploads. 109 if ( plupload.FAILED === file.status ) { 110 return; 111 } 112 113 if ( max > hundredmb && file.size > hundredmb && up.runtime != 'html5' ) { 114 _this.uploadSizeError( uploader, file, true ); 115 } else { 116 attributes = _.extend( { 117 id: file.id, 118 file: file, 119 uploading: true, 120 date: new Date(), 121 filename: file.name, 122 }, _.pick( file, 'loaded', 'size', 'percent' ) ); 123 124 file.item = new bp.Models.File( attributes ); 125 bp.Uploader.filesQueue.add( file.item ); 126 } 127 128 } ); 129 130 uploader.refresh(); 131 uploader.start(); 132 } ); 133 134 /** 135 * Update each file item on progress 136 * 137 * @event UploadProgress 138 * @param {plupload.Uploader} uploader Uploader instance. 139 * @param {Object} file 140 */ 141 this.uploader.bind( 'UploadProgress', function( uploader, file ) { 142 file.item.set( _.pick( file, 'loaded', 'percent' ) ); 143 } ); 144 145 /** 146 * After a file is successfully uploaded, update its model. 147 * 148 * @event FileUploaded 149 * @param {plupload.Uploader} uploader Uploader instance. 150 * @param {plupload.File} file File that was uploaded. 151 * @param {Object} response Object with response properties. 152 * @return {mixed} 153 */ 154 this.uploader.bind( 'FileUploaded', function( uploader, file, response ) { 155 var complete, 156 message = self.strings.default_error; 157 158 try { 159 response = JSON.parse( response.response ); 160 } catch ( e ) { 161 return feedback( message, e, file ); 162 } 163 164 if ( ! _.isObject( response ) || _.isUndefined( response.success ) ) { 165 return feedback( message, null, file ); 166 } else if ( ! response.success ) { 167 if ( response.data && response.data.message ) { 168 message = response.data.message; 169 } 170 171 return feedback( message, response.data, file ); 172 } 173 174 _.each(['file','loaded','size','percent'], function( key ) { 175 file.item.unset( key ); 176 }); 177 178 file.item.set( _.extend( response.data, { uploading: false } ) ); 179 180 // Add the file to the Uploaded ones 181 item = new bp.Models.File( response.data ) 182 bp.Uploader.filesUploaded.add( item ); 183 } ); 184 185 /** 186 * Trigger an event to inform a new upload is being processed 187 * 188 * Mainly used to remove an eventual warning 189 * 190 * @event BeforeUpload 191 * @param {plupload.Uploader} uploader Uploader instance. 192 * @param {Array} files Array of file objects that were added to queue by the user. 193 */ 194 this.uploader.bind( 'BeforeUpload', function( uploader, files ) { 195 $(self).trigger( 'bp-uploader-new-upload' ); 196 } ); 197 198 /** 199 * Reset the filesQueue once the upload is complete 200 * 201 * @event BeforeUpload 202 * @param {plupload.Uploader} uploader Uploader instance. 203 * @param {Array} files Array of file objects that were added to queue by the user. 204 */ 205 this.uploader.bind( 'UploadComplete', function( uploader, files ) { 206 bp.Uploader.filesQueue.reset(); 207 } ); 208 209 /** 210 * Map Plupload errors & Create a warning when plupload failed 211 * 212 * @event Error 213 * @param {plupload.Uploader} uploader Uploader instance. 214 * @param {Object} pluploadError Plupload error 215 */ 216 this.uploader.bind( 'Error', function( uploader, pluploadError ) { 217 var message = self.strings.default_error, 218 key, 219 errors = { 220 'FAILED': self.strings.upload_failed, 221 'FILE_EXTENSION_ERROR': self.strings.invalid_filetype, 222 'IMAGE_FORMAT_ERROR': self.strings.not_an_image, 223 'IMAGE_MEMORY_ERROR': self.strings.image_memory_exceeded, 224 'IMAGE_DIMENSIONS_ERROR': self.strings.image_dimensions_exceeded, 225 'GENERIC_ERROR': self.strings.upload_failed, 226 'IO_ERROR': self.strings.io_error, 227 'HTTP_ERROR': self.strings.http_error, 228 'SECURITY_ERROR': self.strings.security_error, 229 'FILE_SIZE_ERROR': self.strings.file_exceeds_size_limit.replace( '%s' , pluploadError.file.name ) 230 }; 231 232 // Check for plupload errors. 233 for ( key in errors ) { 234 if ( pluploadError.code === plupload[ key ] ) { 235 message = errors[ key ]; 236 break; 237 } 238 } 239 240 $(self).trigger( 'bp-uploader-warning', message ); 241 uploader.refresh(); 242 } ); 243 } 244 245 // Create a very generic Model for files 246 bp.Models.File = Backbone.Model.extend( { 247 file: {}, 248 } ); 249 250 // Add Collections to store queue, uploaded files and errors 251 $.extend( bp.Uploader, { 252 filesQueue : new Backbone.Collection(), 253 filesUploaded : new Backbone.Collection(), 254 filesError : new Backbone.Collection() 255 } ); 256 257 // Extend wp.Backbone.View with .prepare() and .inject() 258 bp.View = bp.Backbone.View.extend( { 259 inject: function( selector ) { 260 this.render(); 261 $(selector).html( this.el ); 262 this.views.ready(); 263 }, 264 265 prepare: function() { 266 if ( ! _.isUndefined( this.model ) && _.isFunction( this.model.toJSON ) ) { 267 return this.model.toJSON(); 268 } else { 269 return {}; 270 } 271 } 272 } ); 273 274 // BuddyPress Uploader main view 275 bp.Views.Uploader = bp.View.extend( { 276 className: "bp-uploader-window", 277 template: bp.template( "upload-window" ), 278 279 defaults: _.pick( BP_Uploader.settings.defaults, 'container', 'drop_element', 'browse_button' ), 280 281 initialize: function() { 282 this.warning = null; 283 this.model = new Backbone.Model( this.defaults ); 284 this.on( 'ready', this.initUploader ); 285 }, 286 287 initUploader: function() { 288 this.uploader = new bp.Uploader.uploader(); 289 $( this.uploader ).on( 'bp-uploader-warning', _.bind( this.setWarning, this ) ); 290 $( this.uploader ).on( 'bp-uploader-new-upload', _.bind( this.resetWarning, this ) ); 291 }, 292 293 setWarning: function( event, message ) { 294 if ( _.isUndefined( message ) ) { 295 return; 296 } 297 298 this.warning = new bp.Views.uploaderWarning( { 299 value: message 300 } ).render(); 301 302 this.$el.after( this.warning.el ); 303 }, 304 305 resetWarning: function( event ) { 306 if ( _.isNull( this.warning ) ) { 307 return; 308 } 309 310 this.warning.remove(); 311 this.warning = null; 312 } 313 } ); 314 315 // BuddyPress Uploader warning view 316 bp.Views.uploaderWarning = bp.View.extend( { 317 tagName: 'p', 318 className: 'warning', 319 id: 'bp-uploader-warning', 320 321 initialize: function() { 322 this.value = this.options.value; 323 }, 324 325 render: function() { 326 this.$el.html( this.value ); 327 return this; 328 } 329 } ); 330 331 // BuddyPress Uploader Files view 332 bp.Views.uploaderStatus = bp.View.extend( { 333 className: "files", 334 335 initialize: function() { 336 _.each( this.collection.models, this.addFile, this ); 337 this.collection.on( 'change:percent', this.progress, this ); 338 bp.Uploader.filesError.on( 'add', this.feedback, this ); 339 }, 340 341 addFile: function( file ) { 342 this.views.add( new bp.Views.uploaderProgress( { model: file } ) ); 343 }, 344 345 progress:function( model ) { 346 if ( ! _.isUndefined( model.get( 'percent' ) ) ) { 347 $( '#' + model.get('id') + ' .progress .bar' ).css( 'width', model.get('percent') + '%' ); 348 } 349 }, 350 351 feedback: function( model ) { 352 if ( ! _.isUndefined( model.get( 'message' ) ) && ! _.isUndefined( model.get( 'file' ) ) ) { 353 $( '#' + model.get( 'file' ).id ).html( model.get( 'message' ) ).addClass( 'error' ); 354 } 355 } 356 } ); 357 358 // BuddyPress Uploader File progress view 359 bp.Views.uploaderProgress = bp.View.extend( { 360 className: "bp-uploader-progress", 361 template: bp.template( "progress-window" ), 362 } ); 363 364 })( bp, jQuery ); -
src/bp-core/js/webcam.js
diff --git src/bp-core/js/webcam.js src/bp-core/js/webcam.js index e69de29..c744191 100644
1 window.bp = window.bp || {}; 2 3 ( function( exports, $ ) { 4 5 // Bail if not set 6 if ( typeof BP_Uploader === 'undefined' ) { 7 return; 8 } 9 10 bp.Models = bp.Models || {}; 11 bp.Collections = bp.Collections || {}; 12 bp.Views = bp.Views || {}; 13 14 bp.WebCam = { 15 start: function() { 16 this.params = { 17 video: null, 18 videoStream: null, 19 capture_enable: false, 20 capture: null, 21 canvas: null, 22 warning: null, 23 } 24 25 bp.Avatar.nav.on( 'bp-avatar-view:changed', _.bind( this.setView, this ) ); 26 }, 27 28 setView: function( view ) { 29 if ( 'camera' != view ) { 30 // Stop the camera if needed 31 if ( ! _.isNull( this.params.video ) ) { 32 this.stop(); 33 34 // Remove all warnings as we're changing the view 35 this.removeWarning(); 36 } 37 38 // Stop as this is not Camera area 39 return; 40 } 41 42 // Create the WebCam view 43 cameraView = new bp.Views.WebCamAvatar( { model: new Backbone.Model( { user_media: false } ) } ); 44 45 // Add it to views 46 bp.Avatar.views.add( { id: 'camera', view: cameraView } ); 47 48 // Display it 49 cameraView.inject( '.bp-avatar' ); 50 }, 51 52 removeView: function() { 53 var camera; 54 55 if ( ! _.isUndefined( bp.Avatar.views.get( 'camera' ) ) ) { 56 camera = bp.Avatar.views.get( 'camera' ); 57 camera.get( 'view' ).remove(); 58 bp.Avatar.views.remove( { id: 'camera', view: camera } ); 59 } 60 }, 61 62 gotStream: function( stream ) { 63 var video = bp.WebCam.params.video; 64 bp.WebCam.params.videoStream = stream; 65 66 // User Feedback 67 bp.WebCam.displayWarning( 'loaded' ); 68 69 video.onerror = function () { 70 // User Feedback 71 bp.WebCam.displayWarning( 'videoerror' ); 72 73 if ( video ) { 74 bp.WebCam.stop(); 75 } 76 }; 77 78 stream.onended = bp.WebCam.noStream(); 79 80 if ( video.mozSrcObject !== undefined ) { 81 video.mozSrcObject = stream; 82 video.play(); 83 } else if ( navigator.mozGetUserMedia ) { 84 video.src = stream; 85 video.play(); 86 } else if ( window.URL ) { 87 video.src = window.URL.createObjectURL( stream ); 88 } else { 89 video.src = stream; 90 } 91 92 bp.WebCam.params.capture_enable = true; 93 }, 94 95 stop: function() { 96 bp.WebCam.params.capture_enable = false; 97 if ( bp.WebCam.params.videoStream ) { 98 if ( bp.WebCam.params.videoStream.stop ) { 99 bp.WebCam.params.videoStream.stop(); 100 } else if ( bp.WebCam.params.videoStream.msStop ) { 101 bp.WebCam.params.videoStream.msStop(); 102 } 103 bp.WebCam.params.videoStream.onended = null; 104 bp.WebCam.params.videoStream = null; 105 } 106 if ( bp.WebCam.params.video ) { 107 bp.WebCam.params.video.onerror = null; 108 bp.WebCam.params.video.pause(); 109 if ( bp.WebCam.params.video.mozSrcObject ) { 110 bp.WebCam.params.video.mozSrcObject = null; 111 } 112 bp.WebCam.params.video.src = ""; 113 } 114 }, 115 116 noStream: function() { 117 if ( _.isNull( bp.WebCam.params.videoStream ) ) { 118 // User Feedback 119 bp.WebCam.displayWarning( 'noaccess' ); 120 121 bp.WebCam.removeView(); 122 } 123 }, 124 125 setAvatar: function( avatar ) { 126 if ( ! avatar.get( 'url' ) ) { 127 bp.WebCam.displayWarning( 'nocapture' ); 128 } 129 130 // Remove the view 131 bp.WebCam.removeView(); 132 133 bp.Avatar.setAvatar( avatar ); 134 }, 135 136 removeWarning: function() { 137 if ( ! _.isNull( this.params.warning ) ) { 138 this.params.warning.remove(); 139 } 140 }, 141 142 displayWarning: function( code ) { 143 this.removeWarning(); 144 145 this.params.warning = new bp.Views.uploaderWarning( { 146 value: BP_Uploader.strings.camera_warnings[code] 147 } ); 148 149 this.params.warning.inject( '.bp-avatar-status' ); 150 }, 151 }; 152 153 // BuddyPress WebCam view 154 bp.Views.WebCamAvatar = bp.View.extend( { 155 tagName: 'div', 156 id: 'bp-webcam-avatar', 157 template: bp.template( 'bp-avatar-webcam' ), 158 159 events: { 160 'click .avatar-webcam-capture': 'captureStream', 161 'click .avatar-webcam-save': 'saveCapture', 162 }, 163 164 initialize: function() { 165 var params; 166 167 if ( navigator.getUserMedia 168 || navigator.oGetUserMedia 169 || navigator.mozGetUserMedia 170 || navigator.webkitGetUserMedia 171 || navigator.msGetUserMedia ) { 172 173 // We need to add some cropping stuff to use bp.Avatar.setAvatar() 174 params = _.extend( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, 175 'object', 176 'item_id', 177 'nonces' 178 ), { 179 user_media: true, 180 w: BP_Uploader.settings.crop.full_w, 181 h: BP_Uploader.settings.crop.full_h, 182 x: 0, 183 y: 0, 184 type: 'camera', 185 } 186 ); 187 188 this.model.set( params ); 189 } 190 191 this.on( 'ready', this.useStream, this ); 192 }, 193 194 useStream:function() { 195 // No support for user media... Stop! 196 if ( ! this.model.get( 'user_media' ) ) { 197 return; 198 } 199 200 this.options.video = new bp.Views.WebCamVideo(); 201 this.options.canvas = new bp.Views.WebCamCanvas(); 202 203 this.$el.find( '#avatar-to-crop' ).append( this.options.video.el ); 204 this.$el.find( '#avatar-crop-pane' ).append( this.options.canvas.el ); 205 206 bp.WebCam.params.video = this.options.video.el; 207 bp.WebCam.params.canvas = this.options.canvas.el; 208 209 // User Feedback 210 bp.WebCam.displayWarning( 'requesting' ); 211 212 if ( navigator.getUserMedia ) { 213 navigator.getUserMedia( {video:true}, bp.WebCam.gotStream, bp.WebCams.noStream ); 214 } else if ( navigator.oGetUserMedia ) { 215 navigator.oGetUserMedia( {video:true}, bp.WebCam.gotStream, bp.WebCam.noStream ); 216 } else if ( navigator.mozGetUserMedia ) { 217 navigator.mozGetUserMedia( {video:true}, bp.WebCam.gotStream, bp.WebCam.noStream ); 218 } else if ( navigator.webkitGetUserMedia ) { 219 navigator.webkitGetUserMedia( {video:true}, bp.WebCam.gotStream, bp.WebCam.noStream ); 220 } else if (navigator.msGetUserMedia) { 221 navigator.msGetUserMedia( {video:true, audio:false}, bp.WebCams.gotStream, bp.WebCam.noStream ); 222 } else { 223 // User Feedback 224 bp.WebCam.displayWarning( 'errormsg' ); 225 } 226 }, 227 228 captureStream: function( event ) { 229 event.preventDefault(); 230 231 if ( ! bp.WebCam.params.capture_enable ) { 232 // User Feedback 233 bp.WebCam.displayWarning( 'loading' ); 234 return; 235 } 236 237 this.options.canvas.el.getContext( '2d' ).drawImage( this.options.video.el, 80, 0, 480, 480, 0, 0, this.model.get( 'w' ), this.model.get( 'h' ) ); 238 bp.WebCam.params.capture = this.options.canvas.el.toDataURL( "image/png" ); 239 this.model.set( 'url', bp.WebCam.params.capture ); 240 241 // User Feedback 242 bp.WebCam.displayWarning( 'ready' ); 243 }, 244 245 saveCapture: function( event ) { 246 event.preventDefault(); 247 248 if ( ! bp.WebCam.params.capture ) { 249 // User Feedback 250 bp.WebCam.displayWarning( 'nocapture' ); 251 return; 252 } 253 254 bp.WebCam.stop(); 255 bp.WebCam.setAvatar( this.model ); 256 }, 257 } ); 258 259 // BuddyPress Video stream view 260 bp.Views.WebCamVideo = bp.View.extend( { 261 tagName: 'video', 262 id: 'bp-webcam-video', 263 attributes: { 264 autoplay: 'autoplay', 265 } 266 } ); 267 268 // BuddyPress Canvas (capture) view 269 bp.Views.WebCamCanvas = bp.View.extend( { 270 tagName: 'canvas', 271 id: 'bp-webcam-canvas', 272 } ); 273 274 bp.WebCam.start(); 275 276 })( bp, jQuery ); -
src/bp-loader.php
diff --git src/bp-loader.php src/bp-loader.php index 4ee261c..94df639 100644
class BuddyPress { 430 430 require( $this->plugin_dir . 'bp-core/bp-core-theme-compatibility.php' ); 431 431 432 432 // Require all of the BuddyPress core libraries 433 require( $this->plugin_dir . 'bp-core/bp-core-dependency.php' ); 434 require( $this->plugin_dir . 'bp-core/bp-core-actions.php' ); 435 require( $this->plugin_dir . 'bp-core/bp-core-caps.php' ); 436 require( $this->plugin_dir . 'bp-core/bp-core-cache.php' ); 437 require( $this->plugin_dir . 'bp-core/bp-core-cssjs.php' ); 438 require( $this->plugin_dir . 'bp-core/bp-core-update.php' ); 439 require( $this->plugin_dir . 'bp-core/bp-core-options.php' ); 440 require( $this->plugin_dir . 'bp-core/bp-core-classes.php' ); 441 require( $this->plugin_dir . 'bp-core/bp-core-taxonomy.php' ); 442 require( $this->plugin_dir . 'bp-core/bp-core-filters.php' ); 443 require( $this->plugin_dir . 'bp-core/bp-core-avatars.php' ); 444 require( $this->plugin_dir . 'bp-core/bp-core-widgets.php' ); 445 require( $this->plugin_dir . 'bp-core/bp-core-template.php' ); 446 require( $this->plugin_dir . 'bp-core/bp-core-adminbar.php' ); 447 require( $this->plugin_dir . 'bp-core/bp-core-buddybar.php' ); 448 require( $this->plugin_dir . 'bp-core/bp-core-catchuri.php' ); 449 require( $this->plugin_dir . 'bp-core/bp-core-component.php' ); 450 require( $this->plugin_dir . 'bp-core/bp-core-functions.php' ); 451 require( $this->plugin_dir . 'bp-core/bp-core-moderation.php' ); 452 require( $this->plugin_dir . 'bp-core/bp-core-loader.php' ); 433 require( $this->plugin_dir . 'bp-core/bp-core-dependency.php' ); 434 require( $this->plugin_dir . 'bp-core/bp-core-actions.php' ); 435 require( $this->plugin_dir . 'bp-core/bp-core-caps.php' ); 436 require( $this->plugin_dir . 'bp-core/bp-core-cache.php' ); 437 require( $this->plugin_dir . 'bp-core/bp-core-cssjs.php' ); 438 require( $this->plugin_dir . 'bp-core/bp-core-update.php' ); 439 require( $this->plugin_dir . 'bp-core/bp-core-options.php' ); 440 require( $this->plugin_dir . 'bp-core/bp-core-classes.php' ); 441 require( $this->plugin_dir . 'bp-core/bp-core-taxonomy.php' ); 442 require( $this->plugin_dir . 'bp-core/bp-core-filters.php' ); 443 require( $this->plugin_dir . 'bp-core/bp-core-attachments.php' ); 444 require( $this->plugin_dir . 'bp-core/bp-core-avatars.php' ); 445 require( $this->plugin_dir . 'bp-core/bp-core-widgets.php' ); 446 require( $this->plugin_dir . 'bp-core/bp-core-template.php' ); 447 require( $this->plugin_dir . 'bp-core/bp-core-adminbar.php' ); 448 require( $this->plugin_dir . 'bp-core/bp-core-buddybar.php' ); 449 require( $this->plugin_dir . 'bp-core/bp-core-catchuri.php' ); 450 require( $this->plugin_dir . 'bp-core/bp-core-component.php' ); 451 require( $this->plugin_dir . 'bp-core/bp-core-functions.php' ); 452 require( $this->plugin_dir . 'bp-core/bp-core-moderation.php' ); 453 require( $this->plugin_dir . 'bp-core/bp-core-loader.php' ); 453 454 454 455 // Skip or load deprecated content 455 456 if ( false !== $this->load_deprecated ) { -
src/bp-templates/bp-attachments/avatars/camera.php
diff --git src/bp-templates/bp-attachments/avatars/camera.php src/bp-templates/bp-attachments/avatars/camera.php index e69de29..79659c6 100644
1 <?php 2 /** 3 * BuddyPress Avatars camera template 4 * 5 * This template is used to create the camera Backbone views 6 * 7 * @since 2.3 8 * 9 * @package BuddyPress 10 * @subpackage bp-attachments 11 */ 12 ?> 13 <script id="tmpl-bp-avatar-webcam" type="text/html"> 14 <# if ( ! data.user_media ) { #> 15 <div id="bp-webcam-message"> 16 <p class="warning"><?php esc_html_e( 'Your browser does not support the camera feature', 'buddypress' );?></p> 17 </div> 18 <# } else { #> 19 <div id="avatar-to-crop"></div> 20 <div id="avatar-crop-pane" class="avatar"></div> 21 <div id="avatar-crop-actions"> 22 <a class="button avatar-webcam-capture" href="#"><?php esc_html_e( 'Capture', 'buddypress' );?></a> 23 <a class="button avatar-webcam-save hide" href="#"><?php esc_html_e( 'Save', 'buddypress' );?></a> 24 </div> 25 <# } #> 26 </script> -
src/bp-templates/bp-attachments/avatars/crop.php
diff --git src/bp-templates/bp-attachments/avatars/crop.php src/bp-templates/bp-attachments/avatars/crop.php index e69de29..3f573c3 100644
1 <?php 2 /** 3 * BuddyPress Avatars crop template 4 * 5 * This template is used to create the crop Backbone views 6 * 7 * @since 2.3 8 * 9 * @package BuddyPress 10 * @subpackage bp-attachments 11 */ 12 ?> 13 <script id="tmpl-bp-avatar-item" type="text/html"> 14 <div id="avatar-to-crop"> 15 <img src="{{data.url}}"/> 16 </div> 17 <div id="avatar-crop-pane" class="avatar"> 18 <img src="{{data.url}}" id="avatar-crop-preview"/> 19 </div> 20 <div id="avatar-crop-actions"> 21 <a class="button avatar-crop-submit" href="#"><?php esc_html_e( 'Crop Image', 'buddypress' ); ?></a> 22 </div> 23 </script> -
src/bp-templates/bp-attachments/avatars/index.php
diff --git src/bp-templates/bp-attachments/avatars/index.php src/bp-templates/bp-attachments/avatars/index.php index e69de29..bf63ae9 100644
1 <?php 2 /** 3 * BuddyPress Avatars main template 4 * 5 * This template is used to inject the BuddyPress Backbone views 6 * dealing with avatars. 7 * It's also used to create the common Backbone views 8 * 9 * @since 2.3 10 * 11 * @package BuddyPress 12 * @subpackage bp-attachments 13 */ 14 15 16 /** 17 * This action is for internal use, please do not use it 18 */ 19 do_action( 'bp_attachments_avatar_check_template' ); 20 ?> 21 <div class="bp-avatar-nav"></div> 22 <div class="bp-avatar"></div> 23 <div class="bp-avatar-status"></div> 24 25 <script type="text/html" id="tmpl-bp-avatar-nav"> 26 <a href="{{data.href}}" class="bp-avatar-nav-item" data-nav="{{data.id}}">{{data.name}}</a> 27 </script> 28 29 <?php bp_get_template_part( 'uploader' ); ?> 30 31 <?php bp_get_template_part( 'avatars/crop' ); ?> 32 33 <?php bp_get_template_part( 'avatars/camera' ); ?> 34 35 <script id="tmpl-bp-avatar-delete" type="text/html"> 36 <# if ( 'user' == data.object ) { #> 37 <p><?php _e( "If you'd like to delete your current profile photo but not upload a new one, please use the delete profile photo button.", 'buddypress' ); ?></p> 38 <p><a class="button edit" id="bp-delete-avatar" href="#" title="<?php esc_attr_e( 'Delete Profile Photo', 'buddypress' ); ?>"><?php esc_html_e( 'Delete My Profile Photo', 'buddypress' ); ?></a></p> 39 <# } else if ( 'group' == data.object ) { #> 40 <p><?php _e( "If you'd like to remove the existing group profile photo but not upload a new one, please use the delete group profile photo button.", 'buddypress' ); ?></p> 41 <p><a class="button edit" id="bp-delete-avatar" href="#" title="<?php esc_attr_e( 'Delete Group Profile Photo', 'buddypress' ); ?>"><?php esc_html_e( 'Delete Group Profile Photo', 'buddypress' ); ?></a></p> 42 <# } else { #> 43 <?php do_action( 'bp_attachments_avatar_delete_template' ); ?> 44 <# } #> 45 </script> 46 47 <?php do_action( 'bp_attachments_avatar_main_template' ); ?> -
src/bp-templates/bp-attachments/uploader.php
diff --git src/bp-templates/bp-attachments/uploader.php src/bp-templates/bp-attachments/uploader.php index e69de29..4c2b15b 100644
1 <?php 2 /** 3 * BuddyPress Uploader templates 4 * 5 * This template is used to create the BuddyPress Uploader Backbone views 6 * 7 * @since 2.3 8 * 9 * @package BuddyPress 10 * @subpackage bp-attachments 11 */ 12 ?> 13 <script type="text/html" id="tmpl-upload-window"> 14 <?php if ( ! _device_can_upload() ) : ?> 15 <h3 class="upload-instructions"><?php esc_html_e( 'The web browser on your device cannot be used to upload files.', 'buddypress' ); ?></h3> 16 <?php elseif ( is_multisite() && ! is_upload_space_available() ) : ?> 17 <h3 class="upload-instructions"><?php esc_html_e( 'Upload Limit Exceeded' ); ?></h3> 18 <?php else : ?> 19 <div id="{{data.container}}"> 20 <div id="{{data.drop_element}}"> 21 <div class="drag-drop-inside"> 22 <p class="drag-drop-info"><?php esc_html_e( 'Drop your file here', 'buddypress' ); ?></p> 23 <p><?php _ex( 'or', 'Uploader: Drop your file here - or - Select your File', 'buddypress' ); ?></p> 24 <p class="drag-drop-buttons"><input id="{{data.browse_button}}" type="button" value="<?php esc_attr_e( 'Select your File', 'buddypress' ); ?>" class="button" /></p> 25 </div> 26 </div> 27 </div> 28 <?php endif; ?> 29 </script> 30 31 <script type="text/html" id="tmpl-progress-window"> 32 <div id="{{data.id}}"> 33 <div class="progress"> 34 <div class="bar"></div> 35 </div> 36 <div class="filename">{{data.filename}}</div> 37 </div> 38 </script> -
src/bp-templates/bp-legacy/buddypress/groups/create.php
diff --git src/bp-templates/bp-legacy/buddypress/groups/create.php src/bp-templates/bp-legacy/buddypress/groups/create.php index 5741f10..f9cc672 100644
60 60 61 61 62 62 <label> 63 <input type="radio" name="group-status" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> /> 63 <input type="radio" name="group-status" value="private"<?php if ( 'private' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> /> 64 64 <strong><?php _e( 'This is a private group', 'buddypress' ); ?></strong> 65 65 </label> 66 66 <ul> … … 71 71 72 72 73 73 <label> 74 <input type="radio" name="group-status" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> /> 74 <input type="radio" name="group-status" value="hidden"<?php if ( 'hidden' == bp_get_new_group_status() ) { ?> checked="checked"<?php } ?> /> 75 75 <strong><?php _e('This is a hidden group', 'buddypress' ); ?></strong> 76 76 </label> 77 77 <ul> … … 153 153 <p><?php _e( 'To skip the group profile photo upload process, hit the "Next Step" button.', 'buddypress' ); ?></p> 154 154 </div><!-- .main-column --> 155 155 156 <?php 157 /** 158 * Load the Avatar UI templates 159 * 160 * @since BuddyPress (2.3.0) 161 */ 162 bp_core_avatar_get_template_part(); ?> 163 156 164 <?php endif; ?> 157 165 158 166 <?php if ( 'crop-image' == bp_get_avatar_admin_step() ) : ?> … … 306 314 307 315 </div> 308 316 309 <?php do_action( 'bp_after_create_group_page' ); ?> 310 No newline at end of file 317 <?php do_action( 'bp_after_create_group_page' ); ?> -
src/bp-templates/bp-legacy/buddypress/groups/single/admin.php
diff --git src/bp-templates/bp-legacy/buddypress/groups/single/admin.php src/bp-templates/bp-legacy/buddypress/groups/single/admin.php index a5811ff..1655959 100644
140 140 141 141 <?php endif; ?> 142 142 143 <?php 144 /** 145 * Load the Avatar UI templates 146 * 147 * @since BuddyPress (2.3.0) 148 */ 149 bp_core_avatar_get_template_part(); ?> 150 143 151 <?php wp_nonce_field( 'bp_avatar_upload' ); ?> 144 152 145 153 <?php endif; ?> -
src/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php
diff --git src/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php src/bp-templates/bp-legacy/buddypress/members/single/profile/change-avatar.php index f2a3060..32cb0ba 100644
50 50 51 51 </form> 52 52 53 <?php 54 /** 55 * Load the Avatar UI templates 56 * 57 * @since BuddyPress (2.3.0) 58 */ 59 bp_core_avatar_get_template_part(); ?> 60 53 61 <?php else : ?> 54 62 55 63 <p><?php _e( 'Your profile photo will be used on your profile and throughout the site. To change your profile photo, please create an account with <a href="http://gravatar.com">Gravatar</a> using the same email address as you used to register with this site.', 'buddypress' ); ?></p>