1. 程式人生 > >webuploader 手機端上傳圖片預設開啟相機 改為選擇相簿

webuploader 手機端上傳圖片預設開啟相機 改為選擇相簿

解決辦法

1.高版本的webuploader.js會出現這種情況,改為低版本webuploader.js可以解決這個問題
2.隱藏這行capture=camera,用編輯器開啟webupload.js 4926 行

以下是低版本的webuploader.js,複製儲存為webuploader.js,覆蓋原js即可

/*! WebUploader 0.1.5 */


/**
 * @fileOverview 讓內部各個部件的程式碼可以用[amd](https://github.com/amdjs/amdjs-api/wiki/AMD)模組定義方式組織起來。
 *
 * AMD API 內部的簡單不完全實現,請忽略。只有當WebUploader被合併成一個檔案的時候才會引入。
 */
(function( root, factory ) { var modules = {}, // 內部require, 簡單不完全實現。 // https://github.com/amdjs/amdjs-api/wiki/require _require = function( deps, callback ) { var args, len, i; // 如果deps不是陣列,則直接返回指定module if ( typeof deps === 'string' ) { return
getModule( deps ); } else { args = []; for( len = deps.length, i = 0; i < len; i++ ) { args.push( getModule( deps[ i ] ) ); } return callback.apply( null, args ); } }, // 內部define,暫時不支援不指定id.
_define = function( id, deps, factory ) { if ( arguments.length === 2 ) { factory = deps; deps = null; } _require( deps || [], function() { setModule( id, factory, arguments ); }); }, // 設定module, 相容CommonJs寫法。 setModule = function( id, factory, args ) { var module = { exports: factory }, returned; if ( typeof factory === 'function' ) { args.length || (args = [ _require, module.exports, module ]); returned = factory.apply( null, args ); returned !== undefined && (module.exports = returned); } modules[ id ] = module.exports; }, // 根據id獲取module getModule = function( id ) { var module = modules[ id ] || root[ id ]; if ( !module ) { throw new Error( '`' + id + '` is undefined' ); } return module; }, // 將所有modules,將路徑ids裝換成物件。 exportsTo = function( obj ) { var key, host, parts, part, last, ucFirst; // make the first character upper case. ucFirst = function( str ) { return str && (str.charAt( 0 ).toUpperCase() + str.substr( 1 )); }; for ( key in modules ) { host = obj; if ( !modules.hasOwnProperty( key ) ) { continue; } parts = key.split('/'); last = ucFirst( parts.pop() ); while( (part = ucFirst( parts.shift() )) ) { host[ part ] = host[ part ] || {}; host = host[ part ]; } host[ last ] = modules[ key ]; } return obj; }, makeExport = function( dollar ) { root.__dollar = dollar; // exports every module. return exportsTo( factory( root, _define, _require ) ); }, origin; if ( typeof module === 'object' && typeof module.exports === 'object' ) { // For CommonJS and CommonJS-like environments where a proper window is present, module.exports = makeExport(); } else if ( typeof define === 'function' && define.amd ) { // Allow using this built library as an AMD module // in another project. That other project will only // see this AMD call, not the internal modules in // the closure below. define([ 'jquery' ], makeExport ); } else { // Browser globals case. Just assign the // result to a property on the global. origin = root.WebUploader; root.WebUploader = makeExport(); root.WebUploader.noConflict = function() { root.WebUploader = origin; }; } })( window, function( window, define, require ) { /** * @fileOverview jQuery or Zepto */ define('dollar-third',[],function() { var $ = window.__dollar || window.jQuery || window.Zepto; if ( !$ ) { throw new Error('jQuery or Zepto not found!'); } return $; }); /** * @fileOverview Dom 操作相關 */ define('dollar',[ 'dollar-third' ], function( _ ) { return _; }); /** * @fileOverview 使用jQuery的Promise */ define('promise-third',[ 'dollar' ], function( $ ) { return { Deferred: $.Deferred, when: $.when, isPromise: function( anything ) { return anything && typeof anything.then === 'function'; } }; }); /** * @fileOverview Promise/A+ */ define('promise',[ 'promise-third' ], function( _ ) { return _; }); /** * @fileOverview 基礎類方法。 */ /** * Web Uploader內部類的詳細說明,以下提及的功能類,都可以在`WebUploader`這個變數中訪問到。 * * As you know, Web Uploader的每個檔案都是用過[AMD](https://github.com/amdjs/amdjs-api/wiki/AMD)規範中的`define`組織起來的, 每個Module都會有個module id. * 預設module id為該檔案的路徑,而此路徑將會轉化成名字空間存放在WebUploader中。如: * * * module `base`:WebUploader.Base * * module `file`: WebUploader.File * * module `lib/dnd`: WebUploader.Lib.Dnd * * module `runtime/html5/dnd`: WebUploader.Runtime.Html5.Dnd * * * 以下文件中對類的使用可能省略掉了`WebUploader`字首。 * @module WebUploader * @title WebUploader API文件 */ define('base',[ 'dollar', 'promise' ], function( $, promise ) { var noop = function() {}, call = Function.call; // http://jsperf.com/uncurrythis // 反科裡化 function uncurryThis( fn ) { return function() { return call.apply( fn, arguments ); }; } function bindFn( fn, context ) { return function() { return fn.apply( context, arguments ); }; } function createObject( proto ) { var f; if ( Object.create ) { return Object.create( proto ); } else { f = function() {}; f.prototype = proto; return new f(); } } /** * 基礎類,提供一些簡單常用的方法。 * @class Base */ return { /** * @property {String} version 當前版本號。 */ version: '0.1.5', /** * @property {jQuery|Zepto} $ 引用依賴的jQuery或者Zepto物件。 */ $: $, Deferred: promise.Deferred, isPromise: promise.isPromise, when: promise.when, /** * @description 簡單的瀏覽器檢查結果。 * * * `webkit` webkit版本號,如果瀏覽器為非webkit核心,此屬性為`undefined`。 * * `chrome` chrome瀏覽器版本號,如果瀏覽器為chrome,此屬性為`undefined`。 * * `ie` ie瀏覽器版本號,如果瀏覽器為非ie,此屬性為`undefined`。**暫不支援ie10+** * * `firefox` firefox瀏覽器版本號,如果瀏覽器為非firefox,此屬性為`undefined`。 * * `safari` safari瀏覽器版本號,如果瀏覽器為非safari,此屬性為`undefined`。 * * `opera` opera瀏覽器版本號,如果瀏覽器為非opera,此屬性為`undefined`。 * * @property {Object} [browser] */ browser: (function( ua ) { var ret = {}, webkit = ua.match( /WebKit\/([\d.]+)/ ), chrome = ua.match( /Chrome\/([\d.]+)/ ) || ua.match( /CriOS\/([\d.]+)/ ), ie = ua.match( /MSIE\s([\d\.]+)/ ) || ua.match( /(?:trident)(?:.*rv:([\w.]+))?/i ), firefox = ua.match( /Firefox\/([\d.]+)/ ), safari = ua.match( /Safari\/([\d.]+)/ ), opera = ua.match( /OPR\/([\d.]+)/ ); webkit && (ret.webkit = parseFloat( webkit[ 1 ] )); chrome && (ret.chrome = parseFloat( chrome[ 1 ] )); ie && (ret.ie = parseFloat( ie[ 1 ] )); firefox && (ret.firefox = parseFloat( firefox[ 1 ] )); safari && (ret.safari = parseFloat( safari[ 1 ] )); opera && (ret.opera = parseFloat( opera[ 1 ] )); return ret; })( navigator.userAgent ), /** * @description 作業系統檢查結果。 * * * `android` 如果在android瀏覽器環境下,此值為對應的android版本號,否則為`undefined`。 * * `ios` 如果在ios瀏覽器環境下,此值為對應的ios版本號,否則為`undefined`。 * @property {Object} [os] */ os: (function( ua ) { var ret = {}, // osx = !!ua.match( /\(Macintosh\; Intel / ), android = ua.match( /(?:Android);?[\s\/]+([\d.]+)?/ ), ios = ua.match( /(?:iPad|iPod|iPhone).*OS\s([\d_]+)/ ); // osx && (ret.osx = true); android && (ret.android = parseFloat( android[ 1 ] )); ios && (ret.ios = parseFloat( ios[ 1 ].replace( /_/g, '.' ) )); return ret; })( navigator.userAgent ), /** * 實現類與類之間的繼承。 * @method inherits * @grammar Base.inherits( super ) => child * @grammar Base.inherits( super, protos ) => child * @grammar Base.inherits( super, protos, statics ) => child * @param {Class} super 父類 * @param {Object | Function} [protos] 子類或者物件。如果物件中包含constructor,子類將是用此屬性值。 * @param {Function} [protos.constructor] 子類構造器,不指定的話將建立個臨時的直接執行父類構造器的方法。 * @param {Object} [statics] 靜態屬性或方法。 * @return {Class} 返回子類。 * @example * function Person() { * console.log( 'Super' ); * } * Person.prototype.hello = function() { * console.log( 'hello' ); * }; * * var Manager = Base.inherits( Person, { * world: function() { * console.log( 'World' ); * } * }); * * // 因為沒有指定構造器,父類的構造器將會執行。 * var instance = new Manager(); // => Super * * // 繼承子父類的方法 * instance.hello(); // => hello * instance.world(); // => World * * // 子類的__super__屬性指向父類 * console.log( Manager.__super__ === Person ); // => true */ inherits: function( Super, protos, staticProtos ) { var child; if ( typeof protos === 'function' ) { child = protos; protos = null; } else if ( protos && protos.hasOwnProperty('constructor') ) { child = protos.constructor; } else { child = function() { return Super.apply( this, arguments ); }; } // 複製靜態方法 $.extend( true, child, Super, staticProtos || {} ); /* jshint camelcase: false */ // 讓子類的__super__屬性指向父類。 child.__super__ = Super.prototype; // 構建原型,新增原型方法或屬性。 // 暫時用Object.create實現。 child.prototype = createObject( Super.prototype ); protos && $.extend( true, child.prototype, protos ); return child; }, /** * 一個不做任何事情的方法。可以用來賦值給預設的callback. * @method noop */ noop: noop, /** * 返回一個新的方法,此方法將已指定的`context`來執行。 * @grammar Base.bindFn( fn, context ) => Function * @method bindFn * @example * var doSomething = function() { * console.log( this.name ); * }, * obj = { * name: 'Object Name' * }, * aliasFn = Base.bind( doSomething, obj ); * * aliasFn(); // => Object Name * */ bindFn: bindFn, /** * 引用Console.log如果存在的話,否則引用一個[空函式noop](#WebUploader:Base.noop)。 * @grammar Base.log( args... ) => undefined * @method log */ log: (function() { if ( window.console ) { return bindFn( console.log, console ); } return noop; })(), nextTick: (function() { return function( cb ) { setTimeout( cb, 1 ); }; // @bug 當瀏覽器不在當前視窗時就停了。 // var next = window.requestAnimationFrame || // window.webkitRequestAnimationFrame || // window.mozRequestAnimationFrame || // function( cb ) { // window.setTimeout( cb, 1000 / 60 ); // }; // // fix: Uncaught TypeError: Illegal invocation // return bindFn( next, window ); })(), /** * 被[uncurrythis](http://www.2ality.com/2011/11/uncurrying-this.html)的陣列slice方法。 * 將用來將非陣列物件轉化成陣列物件。 * @grammar Base.slice( target, start[, end] ) => Array * @method slice * @example * function doSomthing() { * var args = Base.slice( arguments, 1 ); * console.log( args ); * } * * doSomthing( 'ignored', 'arg2', 'arg3' ); // => Array ["arg2", "arg3"] */ slice: uncurryThis( [].slice ), /** * 生成唯一的ID * @method guid * @grammar Base.guid() => String * @grammar Base.guid( prefx ) => String */ guid: (function() { var counter = 0; return function( prefix ) { var guid = (+new Date()).toString( 32 ), i = 0; for ( ; i < 5; i++ ) { guid += Math.floor( Math.random() * 65535 ).toString( 32 ); } return (prefix || 'wu_') + guid + (counter++).toString( 32 ); }; })(), /** * 格式化檔案大小, 輸出成帶單位的字串 * @method formatSize * @grammar Base.formatSize( size ) => String * @grammar Base.formatSize( size, pointLength ) => String * @grammar Base.formatSize( size, pointLength, units ) => String * @param {Number} size 檔案大小 * @param {Number} [pointLength=2] 精確到的小數點數。 * @param {Array} [units=[ 'B', 'K', 'M', 'G', 'TB' ]] 單位陣列。從位元組,到千位元組,一直往上指定。如果單位數組裡面只指定了到了K(千位元組),同時檔案大小大於M, 此方法的輸出將還是顯示成多少K. * @example * console.log( Base.formatSize( 100 ) ); // => 100B * console.log( Base.formatSize( 1024 ) ); // => 1.00K * console.log( Base.formatSize( 1024, 0 ) ); // => 1K * console.log( Base.formatSize( 1024 * 1024 ) ); // => 1.00M * console.log( Base.formatSize( 1024 * 1024 * 1024 ) ); // => 1.00G * console.log( Base.formatSize( 1024 * 1024 * 1024, 0, ['B', 'KB', 'MB'] ) ); // => 1024MB */ formatSize: function( size, pointLength, units ) { var unit; units = units || [ 'B', 'K', 'M', 'G', 'TB' ]; while ( (unit = units.shift()) && size > 1024 ) { size = size / 1024; } return (unit === 'B' ? size : size.toFixed( pointLength || 2 )) + unit; } }; }); /** * 事件處理類,可以獨立使用,也可以擴充套件給物件使用。 * @fileOverview Mediator */ define('mediator',[ 'base' ], function( Base ) { var $ = Base.$, slice = [].slice, separator = /\s+/, protos; // 根據條件過濾出事件handlers. function findHandlers( arr, name, callback, context ) { return $.grep( arr, function( handler ) { return handler && (!name || handler.e === name) && (!callback || handler.cb === callback || handler.cb._cb === callback) && (!context || handler.ctx === context); }); } function eachEvent( events, callback, iterator ) { // 不支援物件,只支援多個event用空格隔開 $.each( (events || '').split( separator ), function( _, key ) { iterator( key, callback ); }); } function triggerHanders( events, args ) { var stoped = false, i = -1, len = events.length, handler; while ( ++i < len ) { handler = events[ i ]; if ( handler.cb.apply( handler.ctx2, args ) === false ) { stoped = true; break; } } return !stoped; } protos = { /** * 繫結事件。 * * `callback`方法在執行時,arguments將會來源於trigger的時候攜帶的引數。如 * ```javascript * var obj = {}; * * // 使得obj有事件行為 * Mediator.installTo( obj ); * * obj.on( 'testa', function( arg1, arg2 ) { * console.log( arg1, arg2 ); // => 'arg1', 'arg2' * }); * * obj.trigger( 'testa', 'arg1', 'arg2' ); * ``` * * 如果`callback`中,某一個方法`return false`了,則後續的其他`callback`都不會被執行到。 * 切會影響到`trigger`方法的返回值,為`false`。 * * `on`還可以用來新增一個特殊事件`all`, 這樣所有的事件觸發都會響應到。同時此類`callback`中的arguments有一個不同處, * 就是第一個引數為`type`,記錄當前是什麼事件在觸發。此類`callback`的優先順序比腳低,會再正常`callback`執行完後觸發。 * ```javascript * obj.on( 'all', function( type, arg1, arg2 ) { * console.log( type, arg1, arg2 ); // => 'testa', 'arg1', 'arg2' * }); * ``` * * @method on * @grammar on( name, callback[, context] ) => self * @param {String} name 事件名,支援多個事件用空格隔開 * @param {Function} callback 事件處理器 * @param {Object} [context] 事件處理器的上下文。 * @return {self} 返回自身,方便鏈式 * @chainable * @class Mediator */ on: function( name, callback, context ) { var me = this, set; if ( !callback ) { return this; } set = this._events || (this._events = []); eachEvent( name, callback, function( name, callback ) { var handler = { e: name }; handler.cb = callback; handler.ctx = context; handler.ctx2 = context || me; handler.id = set.length; set.push( handler ); }); return this; }, /** * 繫結事件,且當handler執行完後,自動解除繫結。 * @method once * @grammar once( name, callback[, context] ) => self * @param {String} name 事件名 * @param {Function} callback 事件處理器 * @param {Object} [context] 事件處理器的上下文。 * @return {self} 返回自身,方便鏈式 * @chainable */ once: function( name, callback, context ) { var me = this; if ( !callback ) { return me; } eachEvent( name, callback, function( name, callback ) { var once = function() { me.off( name, once ); return callback.apply( context || me, arguments ); }; once._cb = callback; me.on( name, once, context ); }); return me; }, /** * 解除事件繫結 * @method off * @grammar off( [name[, callback[, context] ] ] ) => self * @param {String} [name] 事件名 * @param {Function} [callback] 事件處理器 * @param {Object} [context] 事件處理器的上下文。 * @return {self} 返回自身,方便鏈式 * @chainable */ off: function( name, cb, ctx ) { var events = this._events; if ( !events ) { return this; } if ( !name && !cb && !ctx ) { this._events = []; return this; } eachEvent( name, cb, function( name, cb ) { $.each( findHandlers( events, name, cb, ctx ), function() { delete events[ this.id ]; }); }); return this; }, /** * 觸發事件 * @method trigger * @grammar trigger( name[, args...] ) => self * @param {String} type 事件名 * @param {*} [...] 任意引數 * @return {Boolean} 如果handler中return false了,則返回false, 否則返回true */ trigger: function( type ) { var args, events, allEvents; if ( !this._events || !type ) { return this; } args = slice.call( arguments, 1 ); events = findHandlers( this._events, type ); allEvents = findHandlers( this._events, 'all' ); return triggerHanders( events, args ) && triggerHanders( allEvents, arguments ); } }; /** * 中介者,它本身是個單例,但可以通過[installTo](#WebUploader:Mediator:installTo)方法,使任何物件具備事件行為。 * 主要目的是負責模組與模組之間的合作,降低耦合度。 * * @class Mediator */ return $.extend({ /** * 可以通過這個介面,使任何物件具備事件功能。 * @method installTo * @param {Object} obj 需要具備事件行為的物件。 * @return {Object} 返回obj. */ installTo: function( obj ) { return $.extend( obj, protos ); } }, protos ); }); /** * @fileOverview Uploader上傳類 */ define('uploader',[ 'base', 'mediator' ], function( Base, Mediator ) { var $ = Base.$; /** * 上傳入口類。 * @class Uploader * @constructor * @grammar new Uploader( opts ) => Uploader * @example * var uploader = WebUploader.Uploader({ * swf: 'path_of_swf/Uploader.swf', * * // 開起分片上傳。 * chunked: true * }); */ function Uploader( opts ) { this.options = $.extend( true, {}, Uploader.options, opts ); this._init( this.options ); } // default Options // widgets中有相應擴充套件 Uploader.options = {}; Mediator.installTo( Uploader.prototype ); // 批量新增純命令式方法。 $.each({ upload: 'start-upload', stop: 'stop-upload', getFile: 'get-file', getFiles: 'get-files', addFile: 'add-file', addFiles: 'add-file', sort: 'sort-files', removeFile: 'remove-file', cancelFile: 'cancel-file', skipFile: 'skip-file', retry: 'retry', isInProgress: 'is-in-progress', makeThumb: 'make-thumb', md5File: 'md5-file', getDimension: 'get-dimension', addButton: 'add-btn', predictRuntimeType: 'predict-runtime-type', refresh: 'refresh', disable: 'disable', enable: 'enable', reset: 'reset' }, function( fn, command ) { Uploader.prototype[ fn ] = function() { return this.request( command, arguments ); }; }); $.extend( Uploader.prototype, { state: 'pending', _init: function( opts ) { var me = this; me.request( 'init', opts, function() { me.state = 'ready'; me.trigger('ready'); }); }, /** * 獲取或者設定Uploader配置項。 * @method option * @grammar option( key ) => * * @grammar option( key, val ) => self * @example * * // 初始狀態圖片上傳前不會壓縮 * var uploader = new WebUploader.Uploader({ * compress: null; * }); * * // 修改後圖片上傳前,嘗試將圖片壓縮到1600 * 1600 * uploader.option( 'compress', { * width: 1600, * height: 1600 * }); */ option: function( key, val ) { var opts = this.options; // setter if ( arguments.length > 1 ) { if ( $.isPlainObject( val ) && $.isPlainObject( opts[ key ] ) ) { $.extend( opts[ key ], val ); } else { opts[ key ] = val; } } else { // getter return key ? opts[ key ] : opts; } }, /** * 獲取檔案統計資訊。返回一個包含一下資訊的物件。 * * `successNum` 上傳成功的檔案數 * * `progressNum` 上傳中的檔案數 * * `cancelNum` 被刪除的檔案數 * * `invalidNum` 無效的檔案數 * * `uploadFailNum` 上傳失敗的檔案數 * * `queueNum` 還在佇列中的檔案數 * * `interruptNum` 被暫停的檔案數 * @method getStats * @grammar getStats() => Object */ getStats: function() { // return this._mgr.getStats.apply( this._mgr, arguments ); var stats = this.request('get-stats'); return stats ? { successNum: stats.numOfSuccess, progressNum: stats.numOfProgress, // who care? // queueFailNum: 0, cancelNum: stats.numOfCancel, invalidNum: stats.numOfInvalid, uploadFailNum: stats.numOfUploadFailed, queueNum: stats.numOfQueue, interruptNum: stats.numofInterrupt } : {}; }, // 需要重寫此方法來來支援opts.onEvent和instance.onEvent的處理器 trigger: function( type/*, args...*/ ) { var args = [].slice.call( arguments, 1 ), opts = this.options, name = 'on' + type.substring( 0, 1 ).toUpperCase() + type.substring( 1 ); if ( // 呼叫通過on方法註冊的handler. Mediator.trigger.apply( this, arguments ) === false || // 呼叫opts.onEvent $.isFunction( opts[ name ] ) && opts[ name ].apply( this, args ) === false || // 呼叫this.onEvent $.isFunction( this[ name ] ) && this[ name ].apply( this, args ) === false || // 廣播所有uploader的事件。 Mediator.trigger.apply( Mediator, [ this, type ].concat( args ) ) === false ) { return false; } return true; }, /** * 銷燬 webuploader 例項 * @method destroy * @grammar destroy() => undefined */ destroy: function() { this.request( 'destroy', arguments ); this.off(); }, // widgets/widget.js將補充此方法的詳細文件。 request: Base.noop }); /** * 建立Uploader例項,等同於new Uploader( opts ); * @method create * @class Base * @static * @grammar Base.create( opts ) => Uploader */ Base.create = Uploader.create = function( opts ) { return new Uploader( opts ); }; // 暴露Uploader,可以通過它來擴充套件業務邏輯。 Base.Uploader = Uploader; return Uploader; }); /** * @fileOverview Runtime管理器,負責Runtime的選擇, 連線 */ define('runtime/runtime',[ 'base', 'mediator' ], function( Base, Mediator ) { var $ = Base.$, factories = {}, // 獲取物件的第一個key getFirstKey = function( obj ) { for ( var key in obj ) { if ( obj.hasOwnProperty( key ) ) { return key; } } return null; }; // 介面類。 function Runtime( options ) { this.options = $.extend({ container: document.body }, options ); this.uid = Base.guid('rt_'); } $.extend( Runtime.prototype, { getContainer: function() { var opts = this.options, parent, container; if ( this._container ) { return this._container; } parent = $( opts.container || document.body ); container = $( document.createElement('div') ); container.attr( 'id', 'rt_' + this.uid ); container.css({ position: 'absolute', top: '0px', left: '0px', width: '1px', height: '1px', overflow: 'hidden' }); parent.append( container ); parent.addClass('webuploader-container'); this._container = container; this._parent = parent; return container; }, init: Base.noop, exec: Base.noop, destroy: function() { this._container && this._container.remove(); this._parent && this._parent.removeClass('webuploader-container'); this.off(); } }); Runtime.orders = 'html5,flash'; /** * 新增Runtime實現。 * @param {String} type 型別 * @param {Runtime} factory 具體Runtime實現。 */ Runtime.addRuntime = function( type, factory ) { factories[ type ] = factory; }; Runtime.hasRuntime = function( type ) { return !!(type ? factories[ type ] : getFirstKey( factories )); }; Runtime.create = function( opts, orders ) { var type, runtime; orders = orders || Runtime.orders; $.each( orders.split( /\s*,\s*/g ), function() { if ( factories[ this ] ) { type = this; return false; } }); type = type || getFirstKey( factories ); if ( !type ) { throw new Error('Runtime Error'); } runtime = new factories[ type ]( opts ); return runtime; }; Mediator.installTo( Runtime.prototype ); return Runtime; }); /** * @fileOverview Runtime管理器,負責Runtime的選擇, 連線 */ define('runtime/client',[ 'base', 'mediator', 'runtime/runtime' ], function( Base, Mediator, Runtime ) { var cache; cache = (function() { var obj = {}; return { add: function( runtime ) { obj[ runtime.uid ] = runtime; }, get: function( ruid, standalone ) { var i; if ( ruid ) { return obj[ ruid ]; } for ( i in obj ) { // 有些型別不能重用,比如filepicker. if ( standalone && obj[ i ].__standalone ) { continue; } return obj[ i ]; } return null; }, remove: function( runtime ) { delete obj[ runtime.uid ]; } }; })(); function RuntimeClient( component, standalone ) { var deferred = Base.Deferred(), runtime; this.uid = Base.guid('client_'); // 允許runtime沒有初始化之前,註冊一些方法在初始化後執行。 this.runtimeReady = function( cb ) { return deferred.done( cb ); }; this.connectRuntime = function( opts, cb ) { // already connected. if ( runtime ) { throw new Error('already connected!'); } deferred.done( cb ); if ( typeof opts === 'string' && cache.get( opts ) ) { runtime = cache.get( opts ); } // 像filePicker只能獨立存在,不能公用。 runtime = runtime || cache.get( null, standalone ); // 需要建立 if ( !runtime ) { runtime = Runtime.create( opts, opts.runtimeOrder ); runtime.__promise = deferred.promise(); runtime.once( 'ready', deferred.resolve ); runtime.init(); cache.add( runtime ); runtime.__client = 1; } else { // 來自cache Base.$.extend( runtime.options, opts ); runtime.__promise.then( deferred.resolve ); runtime.__client++; } standalone && (runtime.__standalone = standalone); return runtime; }; this.getRuntime = function() { return runtime; }; this.disconnectRuntime = function() { if ( !runtime ) { return; } runtime.__client--; if ( runtime.__client <= 0 ) { cache.remove( runtime ); delete runtime.__promise; runtime.destroy(); } runtime = null; }; this.exec = function() { if ( !runtime ) { return; } var args = Base.slice( arguments ); component && args.unshift( component ); return runtime.exec.apply( this, args ); }; this.getRuid = function() { return runtime && runtime.uid; }; this.destroy = (function( destroy ) { return function() { destroy && destroy.apply( this, arguments ); this.trigger('destroy'); this.off(); this.exec('destroy'); this.disconnectRuntime(); }; })( this.destroy ); } Mediator.installTo( RuntimeClient.prototype ); return RuntimeClient; }); /** * @fileOverview 錯誤資訊 */ define('lib/dnd',[ 'base', 'mediator', 'runtime/client' ], function( Base, Mediator, RuntimeClent ) { var $ = Base.$; function DragAndDrop( opts ) { opts = this.options = $.extend({}, DragAndDrop.options, opts ); opts.container = $( opts.container ); if ( !opts.container.length ) { return; } RuntimeClent.call( this, 'DragAndDrop' ); } DragAndDrop.options = { accept: null, disableGlobalDnd: false }; Base.inherits( RuntimeClent, { constructor: DragAndDrop, init: function() { var me = this; me.connectRuntime( me.options, function() { me.exec('init'); me.trigger('ready'); }); } }); Mediator.installTo( DragAndDrop.prototype ); return DragAndDrop; }); /** * @fileOverview 元件基類。 */ define('widgets/widget',[ 'base', 'uploader' ], function( Base, Uploader ) { var $ = Base.$, _init = Uploader.prototype._init, _destroy = Uploader.prototype.destroy, IGNORE = {}, widgetClass = []; function isArrayLike( obj ) { if ( !obj ) { return false; } var length = obj.length, type = $.type( obj ); if ( obj.nodeType === 1 && length ) { return true; } return type === 'array' || type !== 'function' && type !== 'string' && (length === 0 || typeof length === 'number' && length > 0 && (length - 1) in obj); } function Widget( uploader ) { this.owner = uploader; this.options = uploader.options; } $.extend( Widget.prototype, { init: Base.noop, // 類Backbone的事件監聽宣告,監聽uploader例項上的事件 // widget直接無法監聽事件,事件只能通過uploader來傳遞 invoke: function( apiName, args ) { /* { 'make-thumb': 'makeThumb' } */ var map = this.responseMap; // 如果無API響應宣告則忽略 if ( !map || !(apiName in map) || !(map[ apiName ] in this) || !$.isFunction( this[ map[ apiName ] ] ) ) { return