/** * plupload.browserplus.js * * Copyright 2009, Moxiecode Systems AB * Released under GPL License. * * License: http://www.plupload.com/license * Contributing: http://www.plupload.com/contributing */ // JSLint defined globals /*global plupload:false, BrowserPlus:false, window:false */ (function(plupload) { /** * Yahoo BrowserPlus implementation. This runtime supports these features: dragdrop, jpgresize, pngresize. * * @static * @class plupload.runtimes.BrowserPlus * @extends plupload.Runtime */ plupload.runtimes.BrowserPlus = plupload.addRuntime("browserplus", { /** * Returns a list of supported features for the runtime. * * @return {Object} Name/value object with supported features. */ getFeatures : function() { return { dragdrop : true, jpgresize : true, pngresize : true, chunks : true, progress: true, multipart: true }; }, /** * Initializes the browserplus runtime. * * @method init * @param {plupload.Uploader} uploader Uploader instance that needs to be initialized. * @param {function} callback Callback to execute when the runtime initializes or fails to initialize. If it succeeds an object with a parameter name success will be set to true. */ init : function(uploader, callback) { var browserPlus = window.BrowserPlus, browserPlusFiles = {}, settings = uploader.settings, resize = settings.resize; function addSelectedFiles(native_files) { var files, i, selectedFiles = [], file, id; // Add the native files and setup plupload files for (i = 0; i < native_files.length; i++) { file = native_files[i]; id = plupload.guid(); browserPlusFiles[id] = file; selectedFiles.push(new plupload.File(id, file.name, file.size)); } // Any files selected fire event if (i) { uploader.trigger("FilesAdded", selectedFiles); } } // Setup event listeners if browserplus was initialized function setup() { // Add drop handler uploader.bind("PostInit", function() { var dropTargetElm, dropElmId = settings.drop_element, dropTargetId = uploader.id + '_droptarget', dropElm = document.getElementById(dropElmId), lastState; // Enable/disable drop support for the drop target // this is needed to resolve IE bubbeling issues and make it possible to drag/drop // files into gears runtimes on the same page function addDropHandler(id, end_callback) { // Add drop target and listener browserPlus.DragAndDrop.AddDropTarget({id : id}, function(res) { browserPlus.DragAndDrop.AttachCallbacks({ id : id, hover : function(res) { if (!res && end_callback) { end_callback(); } }, drop : function(res) { if (end_callback) { end_callback(); } addSelectedFiles(res); } }, function() { }); }); } function hide() { document.getElementById(dropTargetId).style.top = '-1000px'; } if (dropElm) { // Since IE has issues with bubbeling when it comes to the drop of files // we need to do this hack where we show a drop target div element while dropping if (document.attachEvent && (/MSIE/gi).test(navigator.userAgent)) { // Create drop target dropTargetElm = document.createElement('div'); dropTargetElm.setAttribute('id', dropTargetId); plupload.extend(dropTargetElm.style, { position : 'absolute', top : '-1000px', background : 'red', filter : 'alpha(opacity=0)', opacity : 0 }); document.body.appendChild(dropTargetElm); plupload.addEvent(dropElm, 'dragenter', function(e) { var dropElm, dropElmPos; dropElm = document.getElementById(dropElmId); dropElmPos = plupload.getPos(dropElm); plupload.extend(document.getElementById(dropTargetId).style, { top : dropElmPos.y + 'px', left : dropElmPos.x + 'px', width : dropElm.offsetWidth + 'px', height : dropElm.offsetHeight + 'px' }); }); addDropHandler(dropTargetId, hide); } else { addDropHandler(dropElmId); } } plupload.addEvent(document.getElementById(settings.browse_button), 'click', function(e) { var mimeTypes = [], i, a, filters = settings.filters, ext; e.preventDefault(); // Convert extensions to mimetypes for (i = 0; i < filters.length; i++) { ext = filters[i].extensions.split(','); for (a = 0; a < ext.length; a++) { mimeTypes.push(plupload.mimeTypes[ext[a]]); } } browserPlus.FileBrowse.OpenBrowseDialog({ mimeTypes : mimeTypes }, function(res) { if (res.success) { addSelectedFiles(res.value); } }); }); // Prevent IE leaks dropElm = dropTargetElm = null; }); uploader.bind("UploadFile", function(up, file) { var nativeFile = browserPlusFiles[file.id], reqParams = {}, chunkSize = up.settings.chunk_size, loadProgress, chunkStack = []; function uploadFile(chunk, chunks) { var chunkFile; // Stop upload if file is maked as failed if (file.status == plupload.FAILED) { return; } reqParams.name = file.target_name || file.name; // Only send chunk parameters if chunk size is defined if (chunkSize) { reqParams.chunk = "" + chunk; reqParams.chunks = "" + chunks; } chunkFile = chunkStack.shift(); browserPlus.Uploader.upload({ url : up.settings.url, files : {file : chunkFile}, cookies : document.cookies, postvars : plupload.extend(reqParams, up.settings.multipart_params), progressCallback : function(res) { var i, loaded = 0; // since more than 1 chunk can be sent at a time, keep track of how many bytes // of each chunk was sent loadProgress[chunk] = parseInt(res.filePercent * chunkFile.size / 100, 10); for (i = 0; i < loadProgress.length; i++) { loaded += loadProgress[i]; } file.loaded = loaded; up.trigger('UploadProgress', file); } }, function(res) { var httpStatus, chunkArgs; if (res.success) { httpStatus = res.value.statusCode; if (chunkSize) { up.trigger('ChunkUploaded', file, { chunk : chunk, chunks : chunks, response : res.value.body, status : httpStatus }); } if (chunkStack.length > 0) { // More chunks to be uploaded uploadFile(++chunk, chunks); } else { file.status = plupload.DONE; up.trigger('FileUploaded', file, { response : res.value.body, status : httpStatus }); // Is error status if (httpStatus >= 400) { up.trigger('Error', { code : plupload.HTTP_ERROR, message : plupload.translate('HTTP Error.'), file : file, status : httpStatus }); } } } else { up.trigger('Error', { code : plupload.GENERIC_ERROR, message : plupload.translate('Generic Error.'), file : file, details : res.error }); } }); } function chunkAndUploadFile(native_file) { file.size = native_file.size; if (chunkSize) { browserPlus.FileAccess.chunk({file : native_file, chunkSize : chunkSize}, function(cr) { if (cr.success) { var chunks = cr.value, len = chunks.length; loadProgress = Array(len); for (var i = 0; i < len; i++) { loadProgress[i] = 0; chunkStack.push(chunks[i]); } uploadFile(0, len); } }); } else { loadProgress = Array(1); chunkStack.push(native_file); uploadFile(0, 1); } } // Resize image if it's a supported format and resize is enabled if (resize && /\.(png|jpg|jpeg)$/i.test(file.name)) { BrowserPlus.ImageAlter.transform({ file : nativeFile, quality : resize.quality || 90, actions : [{ scale : { maxwidth : resize.width, maxheight : resize.height } }] }, function(res) { if (res.success) { chunkAndUploadFile(res.value.file); } }); } else { chunkAndUploadFile(nativeFile); } }); callback({success : true}); } // Check for browserplus object if (browserPlus) { browserPlus.init(function(res) { var services = [ {service: "Uploader", version: "3"}, {service: "DragAndDrop", version: "1"}, {service: "FileBrowse", version: "1"}, {service: "FileAccess", version: "2"} ]; if (resize) { services.push({service : 'ImageAlter', version : "4"}); } if (res.success) { browserPlus.require({ services : services }, function(sres) { if (sres.success) { setup(); } else { callback(); } }); } else { callback(); } }); } else { callback(); } } }); })(plupload);