1/** 2 * A copy of wp.Uploader class 3 * @type @exp;window@pro;mpp 4 */ 5/* global wp, pluploadL10n, plupload, _wpPluploadSettings, mpp, _mppData, _mppUploadSettings, Backbone, jQuery, console, _ */ 6 7window.mpp = window.mpp || {}; 8 9(function (exports, $) { 10 var Uploader; 11 12 if (typeof _mppUploadSettings === 'undefined') { 13 return; 14 } 15 16 /** 17 * An object that helps create a WordPress uploader using plupload. 18 * 19 * @param options - object - The options passed to the new plupload instance. 20 * Accepts the following parameters: 21 * - container - The id of uploader container. 22 * - browser - The id of button to trigger the file select. 23 * - dropzone - The id of file drop target. 24 * - plupload - An object of parameters to pass to the plupload instance. 25 * - params - An object of parameters to pass to $_POST when uploading the file. 26 * Extends this.plupload.multipart_params under the hood. 27 * 28 * @param attributes - object - Attributes and methods for this specific instance. 29 */ 30 Uploader = function (options) { 31 var self = this, 32 elements = { 33 container: 'container', 34 browser: 'browse_button', 35 dropzone: 'drop_element' 36 }, 37 key, error; 38 39 this.supports = { 40 upload: Uploader.browser.supported 41 }; 42 43 this.supported = this.supports.upload; 44 45 if (!this.supported) { 46 return; 47 } 48 49 // Use deep extend to ensure that multipart_params and other objects are cloned. 50 this.plupload = $.extend(true, {multipart_params: {}}, Uploader.defaults); 51 this.container = document.body; // Set default container. 52 53 // Extend the instance with options 54 // 55 // Use deep extend to allow options.plupload to override individual 56 // default plupload keys. 57 $.extend(true, this, options); 58 59 // Proxy all methods so this always refers to the current instance. 60 for (key in this) { 61 if ($.isFunction(this[key])) { 62 this[key] = $.proxy(this[key], this); 63 } 64 } 65 66 // Ensure all elements are jQuery elements and have id attributes 67 // Then set the proper plupload arguments to the ids. 68 for (key in elements) { 69 if (!this[key]) { 70 continue; 71 } 72 73 this[key] = $(this[key]).first(); 74 //should we allow multiple drop zone? then we will need to remove first() from above 75 if (!this[key].length) { 76 delete this[key]; 77 continue; 78 } 79 80 if (!this[key].prop('id')) { 81 this[key].prop('id', '__mpp-uploader-id-' + Uploader.uuid++);//If there is no id, generate one for the element 82 } 83 this.plupload[elements[key]] = this[key].prop('id'); 84 } 85 86 // If the uploader has neither a browse button nor a dropzone, bail. 87 if (!( this.browser && this.browser.length ) && !( this.dropzone && this.dropzone.length )) { 88 return; 89 } 90 91 this.uploader = new plupload.Uploader(this.plupload); 92 delete this.plupload; 93 94 // Set default params and remove this.params alias. 95 this.param(this.params || {}); 96 delete this.params; 97 98 error = function (message, data, file) { 99 console.log("MPP Error: " + message); 100 if (file.attachment) { 101 file.attachment.destroy(); 102 } 103 104 Uploader.errors.unshift({ 105 message: message || pluploadL10n.default_error, 106 data: data, 107 file: file 108 }); 109 110 self.error(message, data, file); 111 $(document).trigger( 'mpp:uploader:error', [self, message, data, file] ); 112 }; 113 114 this.uploader.init(); 115 116 this.supports.dragdrop = this.uploader.features.dragdrop && !Uploader.browser.mobile; 117 118 // Generate drag/drop helper classes. 119 (function (dropzone, supported) { 120 var timer, active; 121 122 if (!dropzone) { 123 return; 124 } 125 126 dropzone.toggleClass('supports-drag-drop', !!supported); 127 128 if (!supported) { 129 return dropzone.unbind('.mpp-uploader'); 130 } 131 132 // 'dragenter' doesn't fire correctly, 133 // simulate it with a limited 'dragover' 134 dropzone.bind('dragover.mpp-uploader', function () { 135 if (timer) { 136 clearTimeout(timer); 137 } 138 139 if (active) { 140 return; 141 } 142 143 dropzone.trigger('dropzone:enter').addClass('drag-over'); 144 active = true; 145 }); 146 147 dropzone.bind('dragleave.mpp-uploader, drop.mpp-uploader', function () { 148 // Using an instant timer prevents the drag-over class from 149 // being quickly removed and re-added when elements inside the 150 // dropzone are repositioned. 151 // 152 // See http://core.trac.wordpress.org/ticket/21705 153 timer = setTimeout(function () { 154 active = false;
155 dropzone.trigger('dropzone:leave').removeClass('drag-over'); 156 }, 0); 157 }); 158 }(this.dropzone, this.supports.dragdrop)); 159 160 if (this.browser) { 161 this.browser.on('mouseenter', this.refresh); 162 } else { 163 this.uploader.disableBrowse(true); 164 // If HTML5 mode, hide the auto-created file container. 165 $('#' + this.uploader.id + '_html5_container').hide(); 166 } 167 168 this.uploader.bind('FilesAdded', function (up, files) { 169 _.each(files, function (file) { 170 var attributes, image; 171 172 // Ignore failed uploads. 173 if (plupload.FAILED === file.status) { 174 return; 175 } 176 177 var original_file = file; 178 // Generate attributes for a new `Attachment` model. 179 attributes = _.extend({ 180 file: file, 181 uploading: true, 182 date: new Date(), 183 filename: file.name, 184 menuOrder: 0, 185 uploadedTo: wp.media.model.settings.post.id 186 }, _.pick(file, 'loaded', 'size', 'percent')); 187 188 // Handle early mime type scanning for images. 189 image = /(?:jpe?g|png|gif)$/i.exec(file.name); 190 191 // Did we find an image? 192 if (image) { 193 attributes.type = 'image'; 194 195 // `jpeg`, `png` and `gif` are valid subtypes. 196 // `jpg` is not, so map it to `jpeg`. 197 attributes.subtype = ( 'jpg' === image[0] ) ? 'jpeg' : image[0]; 198 } 199 200 // Create the `Attachment`. 201 file.attachment = wp.media.model.Attachment.create(attributes); 202 203 Uploader.queue.add(file.attachment); 204 205 self.added(original_file); 206 $(document).trigger( 'mpp:uploader:file.added', [self, file] ); 207 }); 208 // trigger files enqueued. 209 self.allFilesAdded(up); 210 $(document).trigger( 'mpp:uploader:files.added', [self, up] ); 211 up.refresh(); 212 up.start(); 213 }); 214 215 this.uploader.bind('UploadProgress', function (up, file) { 216 217 file.attachment.set(_.pick(file, 'loaded', 'percent')); 218 self.progress(file.attachment); 219 $(document).trigger( 'mpp:uploader:upload.progress', [self, file.attachment] ); 220 }); 221 222 this.uploader.bind('FileUploaded', function (up, file, response) { 223 var complete; 224 //var attachment; 225 try { 226 response = JSON.parse(response.response); 227 228 } catch (e) { 229 return error(pluploadL10n.default_error, e, file); 230 } 231 //console.log(); 232 if (!_.isObject(response)) { 233 return error(pluploadL10n.default_error, null, file); 234 } else if (_.isUndefined(response.success) || !response.success) { 235 return error(response.data.message, response.data.message, file); 236 } 237 238 _.each(['loaded', 'size', 'percent'], function (key) {//'file', 239 file.attachment.unset(key); 240 }); 241 242 file.attachment.set(_.extend(response.data, {uploading: false})); 243 //wp.media.model.Attachment.get( response.data.id, file.attachment ); 244 245 complete = Uploader.queue.all(function (attachment) { 246 return !attachment.get('uploading'); 247 }); 248 249 if (complete) { 250 Uploader.queue.reset(); 251 } 252 //console.log(file); 253 self.success(file.attachment); 254 $(document).trigger( 'mpp:uploader:upload.success', [self, file.attachment] ); 255 }); 256 257 //should we use this here? or just Uploaded and check our collection? 258 //when all files in the current queue is uploaded 259 this.uploader.bind('UploadComplete', function (up, files) { 260 261 self.complete(up, files); 262 $(document).trigger( 'mpp:uploader:upload.complete', [self, up, files] ); 263 }); 264 265 this.uploader.bind('BeforeUpload', function (up, file) { 266 267 if (self.isRestricted(up, file)) { 268 up.stop(); 269 return; 270 } 271 $(document).trigger( 'mpp:uploader:before.upload', [self, up, file] ); 272 }); 273 274 this.uploader.bind('Error', function (up, pluploadError) { 275 var message = pluploadL10n.default_error, 276 key; 277 278 // Check for plupload errors. 279 for (key in Uploader.errorMap) { 280 if (pluploadError.code === plupload[key]) { 281 message = Uploader.errorMap[key]; 282 if (_.isFunction(message)) { 283 message = message(pluploadError.file, pluploadError); 284 } 285 break; 286 } 287 } 288 289 error(message, pluploadError, pluploadError.file); 290 up.refresh(); 291 }); 292 293 this.init(); 294 }; 295 296 // Adds the 'defaults' and 'browser' properties. 297 $.extend(Uploader, _mppUploadSettings); 298 299 Uploader.uuid = 0; 300 301 Uploader.errorMap = { 302 'FAILED': pluploadL10n.upload_failed, 303 'FILE_EXTENSION_ERROR': pluploadL10n.invalid_filetype, 304 'IMAGE_FORMAT_ERROR': pluploadL10n.not_an_image, 305 'IMAGE_MEMORY_ERROR': pluploadL10n.image_memory_exceeded, 306 'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded, 307 'GENERIC_ERROR': pluploadL10n.upload_failed, 308 'IO_ERROR': pluploadL10n.io_error, 309 'HTTP_ERROR': pluploadL10n.http_error, 310 'SECURITY_ERROR': pluploadL10n.security_error, 311 312 'FILE_SIZE_ERROR': function (file) { 313 return pluploadL10n.file_exceeds_size_limit.replace('%s', file.name); 314 } 315 }; 316 317 $.extend(Uploader.prototype, { 318 feedback: '#mpp-upload-feedback-activity', 319 media_list: '#mpp-uploaded-media-list-activity',//where we will list the media 320 uploading_media_list: _.template("<li id='<%= id %>'><span class='mpp-attached-file-name'><%= name %></span>(<span class='mpp-attached-file-size'><%= size %></spa>)<span class='mpp-remove-file-attachment'>x</span> <b></b></li>"), 321 uploaded_media_list: _.template("<li class='mpp-uploaded-media-item' id='mpp-uploaded-media-item-<%= id %>' data-media-id='<%= id %>'><img src='<%= url %>' /><a href='#' class='mpp-delete-uploaded-media-item'>x</a></li>"), 322 323 /** 324 * Acts as a shortcut to extending the uploader's multipart_params object. 325 * 326 * param( key ) 327 * Returns the value of the key. 328 * 329 * param( key, value ) 330 * Sets the value of a key. 331 * 332 * param( map ) 333 * Sets values for a map of data. 334 */ 335 param: function (key, value) { 336 if (arguments.length === 1 && typeof key === 'string') { 337 return this.uploader.settings.multipart_params[key]; 338 } 339 340 if (arguments.length > 1) { 341 this.uploader.settings.multipart_params[key] = value; 342 } else { 343 $.extend(this.uploader.settings.multipart_params, key); 344 } 345 }, 346 347 348 success: function (file) { 349 350 var sizes = file.get('sizes'); 351 var original_url = file.get('url'); 352 var id = file.get('id'); 353 var file_obj = file.get('file'); 354 var thumbnail = ''; 355 if (sizes !== undefined) { 356 thumbnail = sizes.thumbnail; 357 } else if (file.get('thumb')) { 358 thumbnail = file.get('thumb'); 359 } 360 361 var html = ''; 362 html = this.uploaded_media_list({id: id, url: thumbnail.url}); 363 364 $(this.feedback).find('li#' + file_obj.id).remove(); 365 //if a place is given to append the media 366 if (this.media_list) { 367 $('ul', this.media_list).append(html); 368 } 369 370 //console.log( thumbnail); 371 372 // console.log( sizes); 373 //console.log('Url:'+original_url ); 374 //console.log('ID:'+ id); 375 }, 376 error: function (reason, data, file) { 377 //When type is not matched for selected files in the file browser 378 //this error will request our awesome site owner friend to choose the file types from given extensions 379 if (data && data.code == '-601' && mpp.notify != undefined && _mppData.current_type) { 380 mpp.notify(_mppData.type_errors[_mppData.current_type], 'error'); 381 return; 382 } 383 384 //this is used when a file upload fails for some reason 385 //we love helpful people and we are trying to be helpful here to 386 if (this.feedback && jq('ul li#' + file.id, this.feedback).get(0)) { 387 jq('ul li#' + file.id, this.feedback).addClass('mpp-upload-fail').find('b').html('<span>' + reason + "</span>"); 388 } else { 389 mpp.notify(reason, 'error'); 390 } 391 }, 392 //when file/files are selected for uploading 393 added: function (file) { 394 //file = file.file; 395 //console.log(files); 396 var html = ''; 397 398 html = this.uploading_media_list({id: file.id, name: file.name, size: plupload.formatSize(file.size)});// '<li id="' + file.id + '">' + file.name + ' (' + plupload.formatSize(file.size) + ') <b></b></li>'; 399 400 if (this.feedback) { 401 $('ul', this.feedback).append(html);//append to the list 402 ////start the load now 403 } 404 405 if (this.onAddFile) { 406 this.onAddFile(file); 407 } 408 //$( '.mpp-uploading', this.feedback ).show();//addClass( 'uploading' ); 409 }, 410 allFilesAdded: function (up) { 411 // called when all files are added to the queue. For individual, please see added. 412 }, 413 progress: function (file) { 414 415 if (!filename, this.feedback) { 416 return; 417 } 418 419 var filename, percent; 420 421 filename = file.get('file').id; 422 //console.log( filename); 423 percent = file.get('percent'); 424 // console.log('ul li#'+filename); 425 $('ul li#' + filename, this.feedback).find('b').html('<span>' + percent + "%</span>"); 426 427 //$( '#liveblog-messages' ).html( "Uploading: " + filename + ' ' + percent + '%' ); 428 }, 429 430 complete: function () { 431 //disable loader 432 //hide the loader 433 if (!this.media_list) { 434 return; 435 } 436 //show loader 437 jq('.mpp-loader', this.media_list).hide(); 438 }, 439 removeFileFeedback: function (file) { 440 if (file.id === undefined) { 441 return; 442 } 443 444 if (this.feedback) { 445 jQuery(this.feedback).find('ul li#' + file.id).remove(); 446 } 447 448 }, 449 clear_media_list: function () { 450 451 jq('ul', this.media_list).empty(); 452 jq('ul', this.media_list).append(jq('#mpp-loader-wrapper').clone()); 453 }, 454 clear_feedback: function () { 455 jq('ul', this.feedback).empty(); 456 }, 457 458 hide_dropzone: function () { 459 jq(this.dropzone).hide(); 460 }, 461 hide_ui: function () { 462 463 this.clear_media_list(); 464 this.clear_feedback(); 465 this.hide_dropzone(); 466 }, 467 onAddFile: function (file) { 468 if (!this.media_list) { 469 return; 470 } 471 //show loader 472 jq('.mpp-loader', this.media_list).show(); 473 }, 474 init: function () { 475 //add loader to the feedback list 476 if (!this.feedback) { 477 return; 478 } 479 480 this.clear_media_list(); 481 //jq('ul', this.media_list).append( jq( '#mpp-loader-wrapper')); 482 483 }, 484 refresh: function () { 485 var node, attached, container, id; 486 487 if (this.browser) { 488 node = this.browser[0]; 489 490 // Check if the browser node is in the DOM. 491 while (node) { 492 if (node === document.body) { 493 attached = true; 494 break; 495 } 496 node = node.parentNode; 497 } 498 499 // If the browser node is not attached to the DOM, use a 500 // temporary container to house it, as the browser button 501 // shims require the button to exist in the DOM at all times. 502 if (!attached) { 503 id = 'mpp-uploader-browser-' + this.uploader.id; 504 505 container = $('#' + id); 506 if (!container.length) {
507 container = $('<div class="mpp-uploader-browser" />').css({ 508 position: 'fixed', 509 top: '-1000px', 510 left: '-1000px', 511 height: 0, 512 width: 0 513 }).attr('id', 'mpp-uploader-browser-' + this.uploader.id).appendTo('body'); 514 } 515 516 container.append(this.browser); 517 } 518 } 519 520 this.uploader.refresh(); 521 }, 522 isRestricted: function (up, file) { 523 return false; 524 } 525 }); 526 527 Uploader.queue = new wp.media.model.Attachments([], {query: false}); 528 Uploader.errors = new Backbone.Collection(); 529 530 exports.Uploader = Uploader; 531})(mpp, jQuery); 532 533 534/** If the jQuery Cookie plugin is not included, include it*/ 535var jq = jQuery; 536if (jq.cookie === undefined) { 537 /* jQuery Cookie plugin */ 538 jQuery.cookie = function (name, value, options) { 539 if (typeof value !== 'undefined') { 540 options = options || {}; 541 if (value === null) { 542 value = ''; 543 options.expires = -1; 544 } 545 var expires = ''; 546 if (options.expires && (typeof options.expires === 'number' || options.expires.toUTCString)) { 547 var date; 548 if (typeof options.expires === 'number') { 549 date = new Date(); 550 date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); 551 } else { 552 date = options.expires; 553 } 554 expires = '; expires=' + date.toUTCString(); 555 } 556 var path = options.path ? '; path=' + (options.path) : ''; 557 var domain = options.domain ? '; domain=' + (options.domain) : ''; 558 var secure = options.secure ? '; secure' : ''; 559 document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join(''); 560 } else { 561 var cookieValue = null; 562 if (document.cookie && document.cookie != '') { 563 var cookies = document.cookie.split(';'); 564 for (var i = 0; i < cookies.length; i++) { 565 var cookie = jQuery.trim(cookies[i]); 566 if (cookie.substring(0, name.length + 1) == (name + '=')) { 567 cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); 568 break; 569 } 570 } 571 } 572 return cookieValue; 573 } 574 }; 575 576} 577 578 579function mpp_setup_uploader_file_types(mpp_uploader, type) { 580 581 if (!_mppData || !_mppData.types) { 582 return; 583 } 584 585 if (type === undefined && _mppData.current_type !== undefined) { 586 type = _mppData.current_type; 587 } 588 //if type is still not defined, go back 589 if (type === undefined) { 590 return; 591 } 592 //console.log(mpp_uploader); 593 var settings = mpp_uploader.uploader.getOption('filters'); 594 595 settings.mime_types = [_mppData.types[type]]; 596 597 mpp_uploader.uploader.setOption('filters', settings); 598 599 if (mpp_uploader.dropzone) { 600 jQuery(mpp_uploader.dropzone).find('.mpp-uploader-allowed-file-type-info').html(_mppData.allowed_type_messages[type]); 601 jQuery(mpp_uploader.dropzone).find('.mpp-uploader-allowed-max-file-size-info').html(_mppData.max_allowed_file_size); 602 } 603} 604 605/** 606 * 607 * @returns {Object}Get media attached to the activity form 608 */ 609function mpp_get_attached_media() { 610 611 return jQuery('body').data('mpp-attached-media'); 612} 613 614/** 615 * Add a media to attachment list 616 * 617 * @param int media_id 618 * @returns {undefined} 619 */ 620function mpp_add_attached_media(media_id) { 621 622 var $body = jQuery('body'); 623 var attached_media = $body.data('mpp-attached-media'); 624 625 if (!attached_media) { 626 attached_media = []; 627 } else { 628 attached_media = attached_media.split(','); 629 } 630 631 attached_media.push(media_id); 632 633 attached_media = attached_media.join(','); 634 635 $body.data('mpp-attached-media', attached_media); 636 637} 638 639/** 640 * Remove an attached media id from dom 641 * 642 * @param int media_id 643 * @returns {Boolean} 644 */ 645function mpp_remove_attached_media(media_id) { 646 647 var $body = jQuery('body'); 648 var attached_media = $body.data('mpp-attached-media'); 649 650 if (!attached_media) { 651 return false;
652 } else { 653 attached_media = attached_media.split(','); 654 attached_media = _.without(attached_media, '' + media_id); 655 attached_media = attached_media.join(','); 656 } 657 658 $body.data('mpp-attached-media', attached_media); 659} 660 661function mpp_reset_attached_media() { 662 jQuery('body').data('mpp-attached-media', ''); 663}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.