[ Index ] |
PHP Cross Reference of BuddyPress |
[Summary view] [Print] [Text view]
1 /* global bp, BP_Uploader, _, Backbone */ 2 3 window.bp = window.bp || {}; 4 5 ( function( exports, $ ) { 6 7 // Bail if not set. 8 if ( typeof BP_Uploader === 'undefined' ) { 9 return; 10 } 11 12 bp.Models = bp.Models || {}; 13 bp.Collections = bp.Collections || {}; 14 bp.Views = bp.Views || {}; 15 16 bp.Avatar = { 17 start: function() { 18 var self = this; 19 20 /** 21 * Remove the bp-legacy UI 22 * 23 * bp.Avatar successfully loaded, we can now 24 * safely remove the Legacy UI. 25 */ 26 this.removeLegacyUI(); 27 28 // Init some vars. 29 this.views = new Backbone.Collection(); 30 this.jcropapi = {}; 31 this.warning = null; 32 33 // Set up nav. 34 this.setupNav(); 35 36 // Avatars are uploaded files. 37 this.avatars = bp.Uploader.filesUploaded; 38 39 // The Avatar Attachment object. 40 this.Attachment = new Backbone.Model(); 41 42 // Wait till the queue is reset. 43 bp.Uploader.filesQueue.on( 'reset', this.cropView, this ); 44 45 /** 46 * In Administration screens we're using Thickbox 47 * We need to make sure to reset the views if it's closed or opened 48 */ 49 $( 'body.wp-admin' ).on( 'tb_unload', '#TB_window', function() { 50 self.resetViews(); 51 } ); 52 53 $( 'body.wp-admin' ).on( 'click', '.bp-members-avatar-user-edit', function() { 54 self.resetViews(); 55 } ); 56 }, 57 58 removeLegacyUI: function() { 59 // User. 60 if ( $( '#avatar-upload-form' ).length ) { 61 $( '#avatar-upload' ).remove(); 62 $( '#avatar-upload-form p' ).remove(); 63 64 // Group Manage. 65 } else if ( $( '#group-settings-form' ).length ) { 66 $( '#group-settings-form p' ).each( function( i ) { 67 if ( 0 !== i ) { 68 $( this ).remove(); 69 } 70 } ); 71 72 if ( $( '#delete-group-avatar-button' ).length ) { 73 $( '#delete-group-avatar-button' ).remove(); 74 } 75 76 // Group Create. 77 } else if ( $( '#group-create-body' ).length ) { 78 $( '.main-column p #file' ).remove(); 79 $( '.main-column p #upload' ).remove(); 80 81 // Member Admin. 82 } else if ( $( '#bp_members_user_admin_avatar a.bp-members-avatar-user-admin' ).length ) { 83 $( '#bp_members_user_admin_avatar a.bp-members-avatar-user-admin' ).remove(); 84 } 85 }, 86 87 setView: function( view ) { 88 // Clear views. 89 if ( ! _.isUndefined( this.views.models ) ) { 90 _.each( this.views.models, function( model ) { 91 model.get( 'view' ).remove(); 92 }, this ); 93 } 94 95 // Reset Views. 96 this.views.reset(); 97 98 // Reset Avatars (file uploaded). 99 if ( ! _.isUndefined( this.avatars ) ) { 100 this.avatars.reset(); 101 } 102 103 // Reset the Jcrop API. 104 if ( ! _.isEmpty( this.jcropapi ) ) { 105 this.jcropapi.destroy(); 106 this.jcropapi = {}; 107 } 108 109 // Load the required view. 110 switch ( view ) { 111 case 'upload': 112 this.uploaderView(); 113 break; 114 115 case 'delete': 116 this.deleteView(); 117 break; 118 } 119 }, 120 121 resetViews: function() { 122 // Reset to the uploader view. 123 this.nav.trigger( 'bp-avatar-view:changed', 'upload' ); 124 125 // Reset to the uploader nav. 126 _.each( this.navItems.models, function( model ) { 127 if ( model.id === 'upload' ) { 128 model.set( { active: 1 } ); 129 } else { 130 model.set( { active: 0 } ); 131 } 132 } ); 133 }, 134 135 setupNav: function() { 136 var self = this, 137 initView, activeView; 138 139 this.navItems = new Backbone.Collection(); 140 141 _.each( BP_Uploader.settings.nav, function( item, index ) { 142 if ( ! _.isObject( item ) ) { 143 return; 144 } 145 146 // Reset active View. 147 activeView = 0; 148 149 if ( 0 === index ) { 150 initView = item.id; 151 activeView = 1; 152 } 153 154 self.navItems.add( { 155 id : item.id, 156 name : item.caption, 157 href : '#', 158 active : activeView, 159 hide : _.isUndefined( item.hide ) ? 0 : item.hide 160 } ); 161 } ); 162 163 this.nav = new bp.Views.Nav( { collection: this.navItems } ); 164 this.nav.inject( '.bp-avatar-nav' ); 165 166 // Activate the initial view (uploader). 167 this.setView( initView ); 168 169 // Listen to nav changes (it's like a do_action!). 170 this.nav.on( 'bp-avatar-view:changed', _.bind( this.setView, this ) ); 171 }, 172 173 uploaderView: function() { 174 // Listen to the Queued uploads. 175 bp.Uploader.filesQueue.on( 'add', this.uploadProgress, this ); 176 177 // Create the BuddyPress Uploader. 178 var uploader = new bp.Views.Uploader(); 179 180 // Add it to views. 181 this.views.add( { id: 'upload', view: uploader } ); 182 183 // Display it. 184 uploader.inject( '.bp-avatar' ); 185 }, 186 187 uploadProgress: function() { 188 // Create the Uploader status view. 189 var avatarStatus = new bp.Views.uploaderStatus( { collection: bp.Uploader.filesQueue } ); 190 191 if ( ! _.isUndefined( this.views.get( 'status' ) ) ) { 192 this.views.set( { id: 'status', view: avatarStatus } ); 193 } else { 194 this.views.add( { id: 'status', view: avatarStatus } ); 195 } 196 197 // Display it. 198 avatarStatus.inject( '.bp-avatar-status' ); 199 }, 200 201 cropView: function() { 202 var status; 203 204 // Bail there was an error during the Upload. 205 if ( _.isEmpty( this.avatars.models ) ) { 206 return; 207 } 208 209 // Make sure to remove the uploads status. 210 if ( ! _.isUndefined( this.views.get( 'status' ) ) ) { 211 status = this.views.get( 'status' ); 212 status.get( 'view' ).remove(); 213 this.views.remove( { id: 'status', view: status } ); 214 } 215 216 // Create the Avatars view. 217 var avatar = new bp.Views.Avatars( { collection: this.avatars } ); 218 this.views.add( { id: 'crop', view: avatar } ); 219 220 avatar.inject( '.bp-avatar' ); 221 }, 222 223 setAvatar: function( avatar ) { 224 var self = this, 225 crop; 226 227 // Remove the crop view. 228 if ( ! _.isUndefined( this.views.get( 'crop' ) ) ) { 229 // Remove the JCrop API. 230 if ( ! _.isEmpty( this.jcropapi ) ) { 231 this.jcropapi.destroy(); 232 this.jcropapi = {}; 233 } 234 crop = this.views.get( 'crop' ); 235 crop.get( 'view' ).remove(); 236 this.views.remove( { id: 'crop', view: crop } ); 237 } 238 239 // Set the avatar ! 240 bp.ajax.post( 'bp_avatar_set', { 241 json: true, 242 original_file: avatar.get( 'url' ), 243 crop_w: avatar.get( 'w' ), 244 crop_h: avatar.get( 'h' ), 245 crop_x: avatar.get( 'x' ), 246 crop_y: avatar.get( 'y' ), 247 item_id: avatar.get( 'item_id' ), 248 object: avatar.get( 'object' ), 249 type: _.isUndefined( avatar.get( 'type' ) ) ? 'crop' : avatar.get( 'type' ), 250 nonce: avatar.get( 'nonces' ).set 251 } ).done( function( response ) { 252 var avatarStatus = new bp.Views.AvatarStatus( { 253 value : BP_Uploader.strings.feedback_messages[ response.feedback_code ], 254 type : 'success' 255 } ); 256 257 self.views.add( { 258 id : 'status', 259 view : avatarStatus 260 } ); 261 262 avatarStatus.inject( '.bp-avatar-status' ); 263 264 // Update each avatars of the page. 265 $( '.' + avatar.get( 'object' ) + '-' + response.item_id + '-avatar' ).each( function() { 266 $(this).prop( 'src', response.avatar ); 267 } ); 268 269 // Inject the Delete nav. 270 bp.Avatar.navItems.get( 'delete' ).set( { hide: 0 } ); 271 272 /** 273 * Set the Attachment object 274 * 275 * You can run extra actions once the avatar is set using: 276 * bp.Avatar.Attachment.on( 'change:url', function( data ) { your code } ); 277 * 278 * In this case data.attributes will include the url to the newly 279 * uploaded avatar, the object and the item_id concerned. 280 */ 281 self.Attachment.set( _.extend( 282 _.pick( avatar.attributes, ['object', 'item_id'] ), 283 { url: response.avatar, action: 'uploaded' } 284 ) ); 285 286 } ).fail( function( response ) { 287 var feedback = BP_Uploader.strings.default_error; 288 if ( ! _.isUndefined( response ) ) { 289 feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ]; 290 } 291 292 var avatarStatus = new bp.Views.AvatarStatus( { 293 value : feedback, 294 type : 'error' 295 } ); 296 297 self.views.add( { 298 id : 'status', 299 view : avatarStatus 300 } ); 301 302 avatarStatus.inject( '.bp-avatar-status' ); 303 } ); 304 }, 305 306 deleteView:function() { 307 // Create the delete model. 308 var delete_model = new Backbone.Model( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, 309 'object', 310 'item_id', 311 'nonces' 312 ) ); 313 314 // Create the delete view. 315 var deleteView = new bp.Views.DeleteAvatar( { model: delete_model } ); 316 317 // Add it to views. 318 this.views.add( { id: 'delete', view: deleteView } ); 319 320 // Display it. 321 deleteView.inject( '.bp-avatar' ); 322 }, 323 324 deleteAvatar: function( model ) { 325 var self = this, 326 deleteView; 327 328 // Remove the delete view. 329 if ( ! _.isUndefined( this.views.get( 'delete' ) ) ) { 330 deleteView = this.views.get( 'delete' ); 331 deleteView.get( 'view' ).remove(); 332 this.views.remove( { id: 'delete', view: deleteView } ); 333 } 334 335 // Remove the avatar ! 336 bp.ajax.post( 'bp_avatar_delete', { 337 json: true, 338 item_id: model.get( 'item_id' ), 339 object: model.get( 'object' ), 340 nonce: model.get( 'nonces' ).remove 341 } ).done( function( response ) { 342 var avatarStatus = new bp.Views.AvatarStatus( { 343 value : BP_Uploader.strings.feedback_messages[ response.feedback_code ], 344 type : 'success' 345 } ); 346 347 self.views.add( { 348 id : 'status', 349 view : avatarStatus 350 } ); 351 352 avatarStatus.inject( '.bp-avatar-status' ); 353 354 // Update each avatars of the page. 355 $( '.' + model.get( 'object' ) + '-' + response.item_id + '-avatar').each( function() { 356 $( this ).prop( 'src', response.avatar ); 357 } ); 358 359 // Remove the Delete nav. 360 bp.Avatar.navItems.get( 'delete' ).set( { active: 0, hide: 1 } ); 361 362 /** 363 * Reset the Attachment object. 364 * 365 * You can run extra actions once the avatar is set using: 366 * bp.Avatar.Attachment.on( 'change:url', function( data ) { your code } ); 367 * 368 * In this case data.attributes will include the url to the gravatar, 369 * the object and the item_id concerned. 370 */ 371 self.Attachment.set( _.extend( 372 _.pick( model.attributes, ['object', 'item_id'] ), 373 { url: response.avatar, action: 'deleted' } 374 ) ); 375 376 } ).fail( function( response ) { 377 var feedback = BP_Uploader.strings.default_error; 378 if ( ! _.isUndefined( response ) ) { 379 feedback = BP_Uploader.strings.feedback_messages[ response.feedback_code ]; 380 } 381 382 var avatarStatus = new bp.Views.AvatarStatus( { 383 value : feedback, 384 type : 'error' 385 } ); 386 387 self.views.add( { 388 id : 'status', 389 view : avatarStatus 390 } ); 391 392 avatarStatus.inject( '.bp-avatar-status' ); 393 } ); 394 }, 395 396 removeWarning: function() { 397 if ( ! _.isNull( this.warning ) ) { 398 this.warning.remove(); 399 } 400 }, 401 402 displayWarning: function( message ) { 403 this.removeWarning(); 404 405 this.warning = new bp.Views.uploaderWarning( { 406 value: message 407 } ); 408 409 this.warning.inject( '.bp-avatar-status' ); 410 } 411 }; 412 413 // Main Nav view. 414 bp.Views.Nav = bp.View.extend( { 415 tagName: 'ul', 416 className: 'avatar-nav-items', 417 418 events: { 419 'click .bp-avatar-nav-item' : 'toggleView' 420 }, 421 422 initialize: function() { 423 var hasAvatar = _.findWhere( this.collection.models, { id: 'delete' } ); 424 425 // Display a message to inform about the delete tab. 426 if ( 1 !== hasAvatar.get( 'hide' ) ) { 427 bp.Avatar.displayWarning( BP_Uploader.strings.has_avatar_warning ); 428 } 429 430 _.each( this.collection.models, this.addNavItem, this ); 431 this.collection.on( 'change:hide', this.showHideNavItem, this ); 432 }, 433 434 addNavItem: function( item ) { 435 /** 436 * The delete nav is not added if no avatar 437 * is set for the object. 438 */ 439 if ( 1 === item.get( 'hide' ) ) { 440 return; 441 } 442 443 this.views.add( new bp.Views.NavItem( { model: item } ) ); 444 }, 445 446 showHideNavItem: function( item ) { 447 var isRendered = null; 448 449 /** 450 * Loop in views to show/hide the nav item 451 * BuddyPress is only using this for the delete nav 452 */ 453 _.each( this.views._views[''], function( view ) { 454 if ( 1 === view.model.get( 'hide' ) ) { 455 view.remove(); 456 } 457 458 // Check to see if the nav is not already rendered. 459 if ( item.get( 'id' ) === view.model.get( 'id' ) ) { 460 isRendered = true; 461 } 462 } ); 463 464 // Add the Delete nav if not rendered. 465 if ( ! _.isBoolean( isRendered ) ) { 466 this.addNavItem( item ); 467 } 468 }, 469 470 toggleView: function( event ) { 471 event.preventDefault(); 472 473 // First make sure to remove all warnings. 474 bp.Avatar.removeWarning(); 475 476 var active = $( event.target ).data( 'nav' ); 477 478 _.each( this.collection.models, function( model ) { 479 if ( model.id === active ) { 480 model.set( { active: 1 } ); 481 this.trigger( 'bp-avatar-view:changed', model.id ); 482 } else { 483 model.set( { active: 0 } ); 484 } 485 }, this ); 486 } 487 } ); 488 489 // Nav item view. 490 bp.Views.NavItem = bp.View.extend( { 491 tagName: 'li', 492 className: 'avatar-nav-item', 493 template: bp.template( 'bp-avatar-nav' ), 494 495 initialize: function() { 496 if ( 1 === this.model.get( 'active' ) ) { 497 this.el.className += ' current'; 498 } 499 this.el.id += 'bp-avatar-' + this.model.get( 'id' ); 500 501 this.model.on( 'change:active', this.setCurrentNav, this ); 502 }, 503 504 setCurrentNav: function( model ) { 505 if ( 1 === model.get( 'active' ) ) { 506 this.$el.addClass( 'current' ); 507 } else { 508 this.$el.removeClass( 'current' ); 509 } 510 } 511 } ); 512 513 // Avatars view. 514 bp.Views.Avatars = bp.View.extend( { 515 className: 'items', 516 517 initialize: function() { 518 _.each( this.collection.models, this.addItemView, this ); 519 }, 520 521 addItemView: function( item ) { 522 // Defaults to 150. 523 var full_d = { full_h: 150, full_w: 150 }; 524 525 // Make sure to take in account bp_core_avatar_full_height or bp_core_avatar_full_width php filters. 526 if ( ! _.isUndefined( BP_Uploader.settings.crop.full_h ) && ! _.isUndefined( BP_Uploader.settings.crop.full_w ) ) { 527 full_d.full_h = BP_Uploader.settings.crop.full_h; 528 full_d.full_w = BP_Uploader.settings.crop.full_w; 529 } 530 531 // Set the avatar model. 532 item.set( _.extend( _.pick( BP_Uploader.settings.defaults.multipart_params.bp_params, 533 'object', 534 'item_id', 535 'nonces' 536 ), full_d ) ); 537 538 // Add the view. 539 this.views.add( new bp.Views.Avatar( { model: item } ) ); 540 } 541 } ); 542 543 // Avatar view. 544 bp.Views.Avatar = bp.View.extend( { 545 className: 'item', 546 template: bp.template( 'bp-avatar-item' ), 547 548 events: { 549 'click .avatar-crop-submit': 'cropAvatar' 550 }, 551 552 initialize: function() { 553 _.defaults( this.options, { 554 full_h: BP_Uploader.settings.crop.full_h, 555 full_w: BP_Uploader.settings.crop.full_w, 556 aspectRatio : 1 557 } ); 558 559 // Display a warning if the image is smaller than minimum advised. 560 if ( false !== this.model.get( 'feedback' ) ) { 561 bp.Avatar.displayWarning( this.model.get( 'feedback' ) ); 562 } 563 564 this.on( 'ready', this.initCropper ); 565 }, 566 567 initCropper: function() { 568 var self = this, 569 tocrop = this.$el.find( '#avatar-to-crop img' ), 570 availableWidth = this.$el.width(), 571 selection = {}, crop_top, crop_bottom, crop_left, crop_right, nh, nw; 572 573 if ( ! _.isUndefined( this.options.full_h ) && ! _.isUndefined( this.options.full_w ) ) { 574 this.options.aspectRatio = this.options.full_w / this.options.full_h; 575 } 576 577 selection.w = this.model.get( 'width' ); 578 selection.h = this.model.get( 'height' ); 579 580 /** 581 * Make sure the crop preview is at the right of the avatar 582 * if the available width allowes it. 583 */ 584 if ( this.options.full_w + selection.w + 20 < availableWidth ) { 585 $( '#avatar-to-crop' ).addClass( 'adjust' ); 586 this.$el.find( '.avatar-crop-management' ).addClass( 'adjust' ); 587 } 588 589 if ( selection.h <= selection.w ) { 590 crop_top = Math.round( selection.h / 4 ); 591 nh = nw = Math.round( selection.h / 2 ); 592 crop_bottom = nh + crop_top; 593 crop_left = ( selection.w - nw ) / 2; 594 crop_right = nw + crop_left; 595 } else { 596 crop_left = Math.round( selection.w / 4 ); 597 nh = nw = Math.round( selection.w / 2 ); 598 crop_right = nw + crop_left; 599 crop_top = ( selection.h - nh ) / 2; 600 crop_bottom = nh + crop_top; 601 } 602 603 // Add the cropping interface. 604 tocrop.Jcrop( { 605 onChange: _.bind( self.showPreview, self ), 606 onSelect: _.bind( self.showPreview, self ), 607 aspectRatio: self.options.aspectRatio, 608 setSelect: [ crop_left, crop_top, crop_right, crop_bottom ] 609 }, function() { 610 // Get the Jcrop API. 611 bp.Avatar.jcropapi = this; 612 } ); 613 }, 614 615 cropAvatar: function( event ) { 616 event.preventDefault(); 617 618 bp.Avatar.setAvatar( this.model ); 619 }, 620 621 showPreview: function( coords ) { 622 if ( ! coords.w || ! coords.h ) { 623 return; 624 } 625 626 if ( parseInt( coords.w, 10 ) > 0 ) { 627 var fw = this.options.full_w; 628 var fh = this.options.full_h; 629 var rx = fw / coords.w; 630 var ry = fh / coords.h; 631 632 // Update the model. 633 this.model.set( { x: coords.x, y: coords.y, w: coords.w, h: coords.h } ); 634 635 $( '#avatar-crop-preview' ).css( { 636 maxWidth:'none', 637 width: Math.round( rx * this.model.get( 'width' ) )+ 'px', 638 height: Math.round( ry * this.model.get( 'height' ) )+ 'px', 639 marginLeft: '-' + Math.round( rx * this.model.get( 'x' ) ) + 'px', 640 marginTop: '-' + Math.round( ry * this.model.get( 'y' ) ) + 'px' 641 } ); 642 } 643 } 644 } ); 645 646 // BuddyPress Avatar Feedback view. 647 bp.Views.AvatarStatus = bp.View.extend( { 648 tagName: 'p', 649 className: 'updated', 650 id: 'bp-avatar-feedback', 651 652 initialize: function() { 653 this.el.className += ' ' + this.options.type; 654 this.value = this.options.value; 655 }, 656 657 render: function() { 658 this.$el.html( this.value ); 659 return this; 660 } 661 } ); 662 663 // BuddyPress Avatar Delete view 664 bp.Views.DeleteAvatar = bp.View.extend( { 665 tagName: 'div', 666 id: 'bp-delete-avatar-container', 667 template: bp.template( 'bp-avatar-delete' ), 668 669 events: { 670 'click #bp-delete-avatar': 'deleteAvatar' 671 }, 672 673 deleteAvatar: function( event ) { 674 event.preventDefault(); 675 676 bp.Avatar.deleteAvatar( this.model ); 677 } 678 } ); 679 680 bp.Avatar.start(); 681 682 })( bp, jQuery );
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Sun Feb 28 01:01:34 2021 | Cross-referenced by PHPXref 0.7.1 |