/*! * jQuery JavaScript Library v1.9.1 * http://jquery.com/ * * Includes Sizzle.js * http://sizzlejs.com/ * * Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors * Released under the MIT license * http://jquery.org/license * * Date: 2013-2-4 */ (function( window, undefined ) { // Can't do this because several apps including ASP.NET trace // the stack via arguments.caller.callee and Firefox dies if // you try to trace through "use strict" call chains. (#13335) // Support: Firefox 18+ //"use strict"; var // The deferred used on DOM ready readyList, // A central reference to the root jQuery(document) rootjQuery, // Support: IE<9 // For `typeof node.method` instead of `node.method !== undefined` core_strundefined = typeof undefined, // Use the correct document accordingly with window argument (sandbox) document = window.document, location = window.location, // Map over jQuery in case of overwrite _jQuery = window.jQuery, // Map over the $ in case of overwrite _$ = window.$, // [[Class]] -> type pairs class2type = {}, // List of deleted data cache ids, so we can reuse them core_deletedIds = [], core_version = "1.9.1", // Save a reference to some core methods core_concat = core_deletedIds.concat, core_push = core_deletedIds.push, core_slice = core_deletedIds.slice, core_indexOf = core_deletedIds.indexOf, core_toString = class2type.toString, core_hasOwn = class2type.hasOwnProperty, core_trim = core_version.trim, // Define a local copy of jQuery jQuery = function( selector, context ) { // The jQuery object is actually just the init constructor 'enhanced' return new jQuery.fn.init( selector, context, rootjQuery ); }, // Used for matching numbers core_pnum = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, // Used for splitting on whitespace core_rnotwhite = /\S+/g, // Make sure we trim BOM and NBSP (here's looking at you, Safari 5.0 and IE) rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, // A simple way to check for HTML strings // Prioritize #id over <tag> to avoid XSS via location.hash (#9521) // Strict HTML recognition (#11290: must start with <) rquickExpr = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, // Match a standalone tag rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, // JSON RegExp rvalidchars = /^[\],:{}\s]*$/, rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g, rvalidescape = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, rvalidtokens = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, // Matches dashed string for camelizing rmsPrefix = /^-ms-/, rdashAlpha = /-([\da-z])/gi, // Used by jQuery.camelCase as callback to replace() fcamelCase = function( all, letter ) { return letter.toUpperCase(); }, // The ready event handler completed = function( event ) { // readyState === "complete" is good enough for us to call the dom ready in oldIE if ( document.addEventListener || event.type === "load" || document.readyState === "complete" ) { detach(); jQuery.ready(); } }, // Clean-up method for dom ready events detach = function() { if ( document.addEventListener ) { document.removeEventListener( "DOMContentLoaded", completed, false ); window.removeEventListener( "load", completed, false ); } else { document.detachEvent( "onreadystatechange", completed ); window.detachEvent( "onload", completed ); } }; jQuery.fn = jQuery.prototype = { // The current version of jQuery being used jquery: core_version, constructor: jQuery, init: function( selector, context, rootjQuery ) { var match, elem; // HANDLE: $(""), $(null), $(undefined), $(false) if ( !selector ) { return this; } // Handle HTML strings if ( typeof selector === "string" ) { if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) { // Assume that strings that start and end with <> are HTML and skip the regex check match = [ null, selector, null ]; } else { match = rquickExpr.exec( selector ); } // Match html or make sure no context is specified for #id if ( match && (match[1] || !context) ) { // HANDLE: $(html) -> $(array) if ( match[1] ) { context = context instanceof jQuery ? context[0] : context; // scripts is true for back-compat jQuery.merge( this, jQuery.parseHTML( match[1], context && context.nodeType ? context.ownerDocument || context : document, true ) ); // HANDLE: $(html, props) if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) { for ( match in context ) { // Properties of context are called as methods if possible if ( jQuery.isFunction( this[ match ] ) ) { this[ match ]( context[ match ] ); // ...and otherwise set as attributes } else { this.attr( match, context[ match ] ); } } } return this; // HANDLE: $(#id) } else { elem = document.getElementById( match[2] ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE and Opera return items // by name instead of ID if ( elem.id !== match[2] ) { return rootjQuery.find( selector ); } // Otherwise, we inject the element directly into the jQuery object this.length = 1; this[0] = elem; } this.context = document; this.selector = selector; return this; } // HANDLE: $(expr, $(...)) } else if ( !context || context.jquery ) { return ( context || rootjQuery ).find( selector ); // HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return this.constructor( context ).find( selector ); } // HANDLE: $(DOMElement) } else if ( selector.nodeType ) { this.context = this[0] = selector; this.length = 1; return this; // HANDLE: $(function) // Shortcut for document ready } else if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); } if ( selector.selector !== undefined ) { this.selector = selector.selector; this.context = selector.context; } return jQuery.makeArray( selector, this ); }, // Start with an empty selector selector: "", // The default length of a jQuery object is 0 length: 0, // The number of elements contained in the matched element set size: function() { return this.length; }, toArray: function() { return core_slice.call( this ); }, // Get the Nth element in the matched element set OR // Get the whole matched element set as a clean array get: function( num ) { return num == null ? // Return a 'clean' array this.toArray() : // Return just the object ( num < 0 ? this[ this.length + num ] : this[ num ] ); }, // Take an array of elements and push it onto the stack // (returning the new matched element set) pushStack: function( elems ) { // Build a new jQuery matched element set var ret = jQuery.merge( this.constructor(), elems ); // Add the old object onto the stack (as a reference) ret.prevObject = this; ret.context = this.context; // Return the newly-formed element set return ret; }, // Execute a callback for every element in the matched set. // (You can seed the arguments with an array of args, but this is // only used internally.) each: function( callback, args ) { return jQuery.each( this, callback, args ); }, ready: function( fn ) { // Add the callback jQuery.ready.promise().done( fn ); return this; }, slice: function() { return this.pushStack( core_slice.apply( this, arguments ) ); }, first: function() { return this.eq( 0 ); }, last: function() { return this.eq( -1 ); }, eq: function( i ) { var len = this.length, j = +i + ( i < 0 ? len : 0 ); return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] ); }, map: function( callback ) { return this.pushStack( jQuery.map(this, function( elem, i ) { return callback.call( elem, i, elem ); })); }, end: function() { return this.prevObject || this.constructor(null); }, // For internal use only. // Behaves like an Array's method, not like a jQuery method. push: core_push, sort: [].sort, splice: [].splice }; // Give the init function the jQuery prototype for later instantiation jQuery.fn.init.prototype = jQuery.fn; jQuery.extend = jQuery.fn.extend = function() { var src, copyIsArray, copy, name, options, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target; target = arguments[1] || {}; // skip the boolean and the target i = 2; } // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; } // extend jQuery itself if only one argument is passed if ( length === i ) { target = this; --i; } for ( ; i < length; i++ ) { // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // Extend the base object for ( name in options ) { src = target[ name ]; copy = options[ name ]; // Prevent never-ending loop if ( target === copy ) { continue; } // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { if ( copyIsArray ) { copyIsArray = false; clone = src && jQuery.isArray(src) ? src : []; } else { clone = src && jQuery.isPlainObject(src) ? src : {}; } // Never move original objects, clone them target[ name ] = jQuery.extend( deep, clone, copy ); // Don't bring in undefined values } else if ( copy !== undefined ) { target[ name ] = copy; } } } } // Return the modified object return target; }; jQuery.extend({ noConflict: function( deep ) { if ( window.$ === jQuery ) { window.$ = _$; } if ( deep && window.jQuery === jQuery ) { window.jQuery = _jQuery; } return jQuery; }, // Is the DOM ready to be used? Set to true once it occurs. isReady: false, // A counter to track how many items to wait for before // the ready event fires. See #6781 readyWait: 1, // Hold (or release) the ready event holdReady: function( hold ) { if ( hold ) { jQuery.readyWait++; } else { jQuery.ready( true ); } }, // Handle when the DOM is ready ready: function( wait ) { // Abort if there are pending holds or we're already ready if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { return; } // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). if ( !document.body ) { return setTimeout( jQuery.ready ); } // Remember that the DOM is ready jQuery.isReady = true; // If a normal DOM Ready event fired, decrement, and wait if need be if ( wait !== true && --jQuery.readyWait > 0 ) { return; } // If there are functions bound, to execute readyList.resolveWith( document, [ jQuery ] ); // Trigger any bound ready events if ( jQuery.fn.trigger ) { jQuery( document ).trigger("ready").off("ready"); } }, // See test/unit/core.js for details concerning isFunction. // Since version 1.3, DOM methods and functions like alert // aren't supported. They return false on IE (#2968). isFunction: function( obj ) { return jQuery.type(obj) === "function"; }, isArray: Array.isArray || function( obj ) { return jQuery.type(obj) === "array"; }, isWindow: function( obj ) { return obj != null && obj == obj.window; }, isNumeric: function( obj ) { return !isNaN( parseFloat(obj) ) && isFinite( obj ); }, type: function( obj ) { if ( obj == null ) { return String( obj ); } return typeof obj === "object" || typeof obj === "function" ? class2type[ core_toString.call(obj) ] || "object" : typeof obj; }, isPlainObject: function( obj ) { // Must be an Object. // Because of IE, we also have to check the presence of the constructor property. // Make sure that DOM nodes and window objects don't pass through, as well if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { return false; } try { // Not own constructor property must be Object if ( obj.constructor && !core_hasOwn.call(obj, "constructor") && !core_hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) { return false; } } catch ( e ) { // IE8,9 Will throw exceptions on certain host objects #9897 return false; } // Own properties are enumerated firstly, so to speed up, // if last one is own, then all properties are own. var key; for ( key in obj ) {} return key === undefined || core_hasOwn.call( obj, key ); }, isEmptyObject: function( obj ) { var name; for ( name in obj ) { return false; } return true; }, error: function( msg ) { throw new Error( msg ); }, // data: string of html // context (optional): If specified, the fragment will be created in this context, defaults to document // keepScripts (optional): If true, will include scripts passed in the html string parseHTML: function( data, context, keepScripts ) { if ( !data || typeof data !== "string" ) { return null; } if ( typeof context === "boolean" ) { keepScripts = context; context = false; } context = context || document; var parsed = rsingleTag.exec( data ), scripts = !keepScripts && []; // Single tag if ( parsed ) { return [ context.createElement( parsed[1] ) ]; } parsed = jQuery.buildFragment( [ data ], context, scripts ); if ( scripts ) { jQuery( scripts ).remove(); } return jQuery.merge( [], parsed.childNodes ); }, parseJSON: function( data ) { // Attempt to parse using the native JSON parser first if ( window.JSON && window.JSON.parse ) { return window.JSON.parse( data ); } if ( data === null ) { return data; } if ( typeof data === "string" ) { // Make sure leading/trailing whitespace is removed (IE can't handle it) data = jQuery.trim( data ); if ( data ) { // Make sure the incoming data is actual JSON // Logic borrowed from http://json.org/json2.js if ( rvalidchars.test( data.replace( rvalidescape, "@" ) .replace( rvalidtokens, "]" ) .replace( rvalidbraces, "")) ) { return ( new Function( "return " + data ) )(); } } } jQuery.error( "Invalid JSON: " + data ); }, // Cross-browser xml parsing parseXML: function( data ) { var xml, tmp; if ( !data || typeof data !== "string" ) { return null; } try { if ( window.DOMParser ) { // Standard tmp = new DOMParser(); xml = tmp.parseFromString( data , "text/xml" ); } else { // IE xml = new ActiveXObject( "Microsoft.XMLDOM" ); xml.async = "false"; xml.loadXML( data ); } } catch( e ) { xml = undefined; } if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) { jQuery.error( "Invalid XML: " + data ); } return xml; }, noop: function() {}, // Evaluates a script in a global context // Workarounds based on findings by Jim Driscoll // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context globalEval: function( data ) { if ( data && jQuery.trim( data ) ) { // We use execScript on Internet Explorer // We use an anonymous function so that context is window // rather than jQuery in Firefox ( window.execScript || function( data ) { window[ "eval" ].call( window, data ); } )( data ); } }, // Convert dashed to camelCase; used by the css and data modules // Microsoft forgot to hump their vendor prefix (#9572) camelCase: function( string ) { return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); }, nodeName: function( elem, name ) { return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); }, // args is for internal usage only each: function( obj, callback, args ) { var value, i = 0, length = obj.length, isArray = isArraylike( obj ); if ( args ) { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.apply( obj[ i ], args ); if ( value === false ) { break; } } } // A special, fast, case for the most common use of each } else { if ( isArray ) { for ( ; i < length; i++ ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } else { for ( i in obj ) { value = callback.call( obj[ i ], i, obj[ i ] ); if ( value === false ) { break; } } } } return obj; }, // Use native String.trim function wherever possible trim: core_trim && !core_trim.call("\uFEFF\xA0") ? function( text ) { return text == null ? "" : core_trim.call( text ); } : // Otherwise use our own trimming functionality function( text ) { return text == null ? "" : ( text + "" ).replace( rtrim, "" ); }, // results is for internal usage only makeArray: function( arr, results ) { var ret = results || []; if ( arr != null ) { if ( isArraylike( Object(arr) ) ) { jQuery.merge( ret, typeof arr === "string" ? [ arr ] : arr ); } else { core_push.call( ret, arr ); } } return ret; }, inArray: function( elem, arr, i ) { var len; if ( arr ) { if ( core_indexOf ) { return core_indexOf.call( arr, elem, i ); } len = arr.length; i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; for ( ; i < len; i++ ) { // Skip accessing in sparse arrays if ( i in arr && arr[ i ] === elem ) { return i; } } } return -1; }, merge: function( first, second ) { var l = second.length, i = first.length, j = 0; if ( typeof l === "number" ) { for ( ; j < l; j++ ) { first[ i++ ] = second[ j ]; } } else { while ( second[j] !== undefined ) { first[ i++ ] = second[ j++ ]; } } first.length = i; return first; }, grep: function( elems, callback, inv ) { var retVal, ret = [], i = 0, length = elems.length; inv = !!inv; // Go through the array, only saving the items // that pass the validator function for ( ; i < length; i++ ) { retVal = !!callback( elems[ i ], i ); if ( inv !== retVal ) { ret.push( elems[ i ] ); } } return ret; }, // arg is for internal usage only map: function( elems, callback, arg ) { var value, i = 0, length = elems.length, isArray = isArraylike( elems ), ret = []; // Go through the array, translating each of the items to their if ( isArray ) { for ( ; i < length; i++ ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } // Go through every key on the object, } else { for ( i in elems ) { value = callback( elems[ i ], i, arg ); if ( value != null ) { ret[ ret.length ] = value; } } } // Flatten any nested arrays return core_concat.apply( [], ret ); }, // A global GUID counter for objects guid: 1, // Bind a function to a context, optionally partially applying any // arguments. proxy: function( fn, context ) { var args, proxy, tmp; if ( typeof context === "string" ) { tmp = fn[ context ]; context = fn; fn = tmp; } // Quick check to determine if target is callable, in the spec // this throws a TypeError, but we will just return undefined. if ( !jQuery.isFunction( fn ) ) { return undefined; } // Simulated bind args = core_slice.call( arguments, 2 ); proxy = function() { return fn.apply( context || this, args.concat( core_slice.call( arguments ) ) ); }; // Set the guid of unique handler to the same of original handler, so it can be removed proxy.guid = fn.guid = fn.guid || jQuery.guid++; return proxy; }, // Multifunctional method to get and set values of a collection // The value/s can optionally be executed if it's a function access: function( elems, fn, key, value, chainable, emptyGet, raw ) { var i = 0, length = elems.length, bulk = key == null; // Sets many values if ( jQuery.type( key ) === "object" ) { chainable = true; for ( i in key ) { jQuery.access( elems, fn, i, key[i], true, emptyGet, raw ); } // Sets one value } else if ( value !== undefined ) { chainable = true; if ( !jQuery.isFunction( value ) ) { raw = true; } if ( bulk ) { // Bulk operations run against the entire set if ( raw ) { fn.call( elems, value ); fn = null; // ...except when executing function values } else { bulk = fn; fn = function( elem, key, value ) { return bulk.call( jQuery( elem ), value ); }; } } if ( fn ) { for ( ; i < length; i++ ) { fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) ); } } } return chainable ? elems : // Gets bulk ? fn.call( elems ) : length ? fn( elems[0], key ) : emptyGet; }, now: function() { return ( new Date() ).getTime(); } }); jQuery.ready.promise = function( obj ) { if ( !readyList ) { readyList = jQuery.Deferred(); // Catch cases where $(document).ready() is called after the browser event has already occurred. // we once tried to use readyState "interactive" here, but it caused issues like the one // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15 if ( document.readyState === "complete" ) { // Handle it asynchronously to allow scripts the opportunity to delay ready setTimeout( jQuery.ready ); // Standards-based browsers support DOMContentLoaded } else if ( document.addEventListener ) { // Use the handy event callback document.addEventListener( "DOMContentLoaded", completed, false ); // A fallback to window.onload, that will always work window.addEventListener( "load", completed, false ); // If IE event model is used } else { // Ensure firing before onload, maybe late but safe also for iframes document.attachEvent( "onreadystatechange", completed ); // A fallback to window.onload, that will always work window.attachEvent( "onload", completed ); // If IE and not a frame // continually check to see if the document is ready var top = false; try { top = window.frameElement == null && document.documentElement; } catch(e) {} if ( top && top.doScroll ) { (function doScrollCheck() { if ( !jQuery.isReady ) { try { // Use the trick by Diego Perini // http://javascript.nwbox.com/IEContentLoaded/ top.doScroll("left"); } catch(e) { return setTimeout( doScrollCheck, 50 ); } // detach all dom ready events detach(); // and execute any waiting functions jQuery.ready(); } })(); } } } return readyList.promise( obj ); }; // Populate the class2type map jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); function isArraylike( obj ) { var length = obj.length, type = jQuery.type( obj ); if ( jQuery.isWindow( obj ) ) { return false; } if ( obj.nodeType === 1 && length ) { return true; } return type === "array" || type !== "function" && ( length === 0 || typeof length === "number" && length > 0 && ( length - 1 ) in obj ); } // All jQuery objects should point back to these rootjQuery = jQuery(document); // String to Object options format cache var optionsCache = {}; // Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) { var object = optionsCache[ options ] = {}; jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; }); return object; } /* * Create a callback list using the following parameters: * * options: an optional list of space-separated options that will change how * the callback list behaves or a more traditional option object * * By default a callback list will act like an event callback list and can be * "fired" multiple times. * * Possible options: * * once: will ensure the callback list can only be fired once (like a Deferred) * * memory: will keep track of previous values and will call any callback added * after the list has been fired right away with the latest "memorized" * values (like a Deferred) * * unique: will ensure a callback can only be added once (no duplicate in the list) * * stopOnFalse: interrupt callings when a callback returns false * */ jQuery.Callbacks = function( options ) { // Convert options from String-formatted to Object-formatted if needed // (we check in cache first) options = typeof options === "string" ? ( optionsCache[ options ] || createOptions( options ) ) : jQuery.extend( {}, options ); var // Flag to know if list is currently firing firing, // Last fire value (for non-forgettable lists) memory, // Flag to know if list was already fired fired, // End of the loop when firing firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // First callback to fire (used internally by add and fireWith) firingStart, // Actual callback list list = [], // Stack of fire calls for repeatable lists stack = !options.once && [], // Fire callbacks fire = function( data ) { memory = options.memory && data; fired = true; firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; firing = true; for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) { memory = false; // To prevent further calls using add break; } } firing = false; if ( list ) { if ( stack ) { if ( stack.length ) { fire( stack.shift() ); } } else if ( memory ) { list = []; } else { self.disable(); } } }, // Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { if ( list ) { // First, we save the current length var start = list.length; (function add( args ) { jQuery.each( args, function( _, arg ) { var type = jQuery.type( arg ); if ( type === "function" ) { if ( !options.unique || !self.has( arg ) ) { list.push( arg ); } } else if ( arg && arg.length && type !== "string" ) { // Inspect recursively add( arg ); } }); })( arguments ); // Do we need to add the callbacks to the // current firing batch? if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away } else if ( memory ) { firingStart = start; fire( memory ); } } return this; }, // Remove a callback from the list remove: function() { if ( list ) { jQuery.each( arguments, function( _, arg ) { var index; while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { list.splice( index, 1 ); // Handle firing indexes if ( firing ) { if ( index <= firingLength ) { firingLength--; } if ( index <= firingIndex ) { firingIndex--; } } } }); } return this; }, // Check if a given callback is in the list. // If no argument is given, return whether or not list has callbacks attached. has: function( fn ) { return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length ); }, // Remove all callbacks from the list empty: function() { list = []; return this; }, // Have the list do nothing anymore disable: function() { list = stack = memory = undefined; return this; }, // Is it disabled? disabled: function() { return !list; }, // Lock the list in its current state lock: function() { stack = undefined; if ( !memory ) { self.disable(); } return this; }, // Is it locked? locked: function() { return !stack; }, // Call all callbacks with the given context and arguments fireWith: function( context, args ) { args = args || []; args = [ context, args.slice ? args.slice() : args ]; if ( list && ( !fired || stack ) ) { if ( firing ) { stack.push( args ); } else { fire( args ); } } return this; }, // Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; }; jQuery.extend({ Deferred: function( func ) { var tuples = [ // action, add listener, listener list, final state [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ], [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ], [ "notify", "progress", jQuery.Callbacks("memory") ] ], state = "pending", promise = { state: function() { return state; }, always: function() { deferred.done( arguments ).fail( arguments ); return this; }, then: function( /* fnDone, fnFail, fnProgress */ ) { var fns = arguments; return jQuery.Deferred(function( newDefer ) { jQuery.each( tuples, function( i, tuple ) { var action = tuple[ 0 ], fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; // deferred[ done | fail | progress ] for forwarding actions to newDefer deferred[ tuple[1] ](function() { var returned = fn && fn.apply( this, arguments ); if ( returned && jQuery.isFunction( returned.promise ) ) { returned.promise() .done( newDefer.resolve ) .fail( newDefer.reject ) .progress( newDefer.notify ); } else { newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments ); } }); }); fns = null; }).promise(); }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { var list = tuple[ 2 ], stateString = tuple[ 3 ]; // promise[ done | fail | progress ] = list.add promise[ tuple[1] ] = list.add; // Handle state if ( stateString ) { list.add(function() { // state = [ resolved | rejected ] state = stateString; // [ reject_list | resolve_list ].disable; progress_list.lock }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); } // deferred[ resolve | reject | notify ] deferred[ tuple[0] ] = function() { deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments ); return this; }; deferred[ tuple[0] + "With" ] = list.fireWith; }); // Make the deferred a promise promise.promise( deferred ); // Call given func if any if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; }, // Deferred helper when: function( subordinate /* , ..., subordinateN */ ) { var i = 0, resolveValues = core_slice.call( arguments ), length = resolveValues.length, // the count of uncompleted subordinates remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, // the master Deferred. If resolveValues consist of only a single Deferred, just use that. deferred = remaining === 1 ? subordinate : jQuery.Deferred(), // Update function for both resolve and progress values updateFunc = function( i, contexts, values ) { return function( value ) { contexts[ i ] = this; values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value; if( values === progressValues ) { deferred.notifyWith( contexts, values ); } else if ( !( --remaining ) ) { deferred.resolveWith( contexts, values ); } }; }, progressValues, progressContexts, resolveContexts; // add listeners to Deferred subordinates; treat others as resolved if ( length > 1 ) { progressValues = new Array( length ); progressContexts = new Array( length ); resolveContexts = new Array( length ); for ( ; i < length; i++ ) { if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { resolveValues[ i ].promise() .done( updateFunc( i, resolveContexts, resolveValues ) ) .fail( deferred.reject ) .progress( updateFunc( i, progressContexts, progressValues ) ); } else { --remaining; } } } // if we're not waiting on anything, resolve the master if ( !remaining ) { deferred.resolveWith( resolveContexts, resolveValues ); } return deferred.promise(); } }); jQuery.support = (function() { var support, all, a, input, select, fragment, opt, eventName, isSupported, i, div = document.createElement("div"); // Setup div.setAttribute( "className", "t" ); div.innerHTML = " <link/><table></table><a href='/a'>a</a><input type='checkbox'/>"; // Support tests won't run in some limited or non-browser environments all = div.getElementsByTagName("*"); a = div.getElementsByTagName("a")[ 0 ]; if ( !all || !a || !all.length ) { return {}; } // First batch of tests select = document.createElement("select"); opt = select.appendChild( document.createElement("option") ); input = div.getElementsByTagName("input")[ 0 ]; a.style.cssText = "top:1px;float:left;opacity:.5"; support = { // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7) getSetAttribute: div.className !== "t", // IE strips leading whitespace when .innerHTML is used leadingWhitespace: div.firstChild.nodeType === 3, // Make sure that tbody elements aren't automatically inserted // IE will insert them into empty tables tbody: !div.getElementsByTagName("tbody").length, // Make sure that link elements get serialized correctly by innerHTML // This requires a wrapper element in IE htmlSerialize: !!div.getElementsByTagName("link").length, // Get the style information from getAttribute // (IE uses .cssText instead) style: /top/.test( a.getAttribute("style") ), // Make sure that URLs aren't manipulated // (IE normalizes it by default) hrefNormalized: a.getAttribute("href") === "/a", // Make sure that element opacity exists // (IE uses filter instead) // Use a regex to work around a WebKit issue. See #5145 opacity: /^0.5/.test( a.style.opacity ), // Verify style float existence // (IE uses styleFloat instead of cssFloat) cssFloat: !!a.style.cssFloat, // Check the default checkbox/radio value ("" on WebKit; "on" elsewhere) checkOn: !!input.value, // Make sure that a selected-by-default option has a working selected property. // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) optSelected: opt.selected, // Tests for enctype support on a form (#6743) enctype: !!document.createElement("form").enctype, // Makes sure cloning an html5 element does not cause problems // Where outerHTML is undefined, this still works html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>", // jQuery.support.boxModel DEPRECATED in 1.8 since we don't support Quirks Mode boxModel: document.compatMode === "CSS1Compat", // Will be defined later deleteExpando: true, noCloneEvent: true, inlineBlockNeedsLayout: false, shrinkWrapBlocks: false, reliableMarginRight: true, boxSizingReliable: true, pixelPosition: false }; // Make sure checked status is properly cloned input.checked = true; support.noCloneChecked = input.cloneNode( true ).checked; // Make sure that the options inside disabled selects aren't marked as disabled // (WebKit marks them as disabled) select.disabled = true; support.optDisabled = !opt.disabled; // Support: IE<9 try { delete div.test; } catch( e ) { support.deleteExpando = false; } // Check if we can trust getAttribute("value") input = document.createElement("input"); input.setAttribute( "value", "" ); support.input = input.getAttribute( "value" ) === ""; // Check if an input maintains its value after becoming a radio input.value = "t"; input.setAttribute( "type", "radio" ); support.radioValue = input.value === "t"; // #11217 - WebKit loses check when the name is after the checked attribute input.setAttribute( "checked", "t" ); input.setAttribute( "name", "t" ); fragment = document.createDocumentFragment(); fragment.appendChild( input ); // Check if a disconnected checkbox will retain its checked // value of true after appended to the DOM (IE6/7) support.appendChecked = input.checked; // WebKit doesn't clone checked state correctly in fragments support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked; // Support: IE<9 // Opera does not clone events (and typeof div.attachEvent === undefined). // IE9-10 clones events bound via attachEvent, but they don't trigger with .click() if ( div.attachEvent ) { div.attachEvent( "onclick", function() { support.noCloneEvent = false; }); div.cloneNode( true ).click(); } // Support: IE<9 (lack submit/change bubble), Firefox 17+ (lack focusin event) // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP), test/csp.php for ( i in { submit: true, change: true, focusin: true }) { div.setAttribute( eventName = "on" + i, "t" ); support[ i + "Bubbles" ] = eventName in window || div.attributes[ eventName ].expando === false; } div.style.backgroundClip = "content-box"; div.cloneNode( true ).style.backgroundClip = ""; support.clearCloneStyle = div.style.backgroundClip === "content-box"; // Run tests that need a body at doc ready jQuery(function() { var container, marginDiv, tds, divReset = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", body = document.getElementsByTagName("body")[0]; if ( !body ) { // Return for frameset docs that don't have a body return; } container = document.createElement("div"); container.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px"; body.appendChild( container ).appendChild( div ); // Support: IE8 // Check if table cells still have offsetWidth/Height when they are set // to display:none and there are still other visible table cells in a // table row; if so, offsetWidth/Height are not reliable for use when // determining if an element has been hidden directly using // display:none (it is still safe to use offsets if a parent element is // hidden; don safety goggles and see bug #4512 for more information). div.innerHTML = "<table><tr><td></td><td>t</td></tr></table>"; tds = div.getElementsByTagName("td"); tds[ 0 ].style.cssText = "padding:0;margin:0;border:0;display:none"; isSupported = ( tds[ 0 ].offsetHeight === 0 ); tds[ 0 ].style.display = ""; tds[ 1 ].style.display = "none"; // Support: IE8 // Check if empty table cells still have offsetWidth/Height support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 ); // Check box-sizing and margin behavior div.innerHTML = ""; div.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;"; support.boxSizing = ( div.offsetWidth === 4 ); support.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== 1 ); // Use window.getComputedStyle because jsdom on node.js will break without it. if ( window.getComputedStyle ) { support.pixelPosition = ( window.getComputedStyle( div, null ) || {} ).top !== "1%"; support.boxSizingReliable = ( window.getComputedStyle( div, null ) || { width: "4px" } ).width === "4px"; // Check if div with explicit width and no margin-right incorrectly // gets computed margin-right based on width of container. (#3333) // Fails in WebKit before Feb 2011 nightlies // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right marginDiv = div.appendChild( document.createElement("div") ); marginDiv.style.cssText = div.style.cssText = divReset; marginDiv.style.marginRight = marginDiv.style.width = "0"; div.style.width = "1px"; support.reliableMarginRight = !parseFloat( ( window.getComputedStyle( marginDiv, null ) || {} ).marginRight ); } if ( typeof div.style.zoom !== core_strundefined ) { // Support: IE<8 // Check if natively block-level elements act like inline-block // elements when setting their display to 'inline' and giving // them layout div.innerHTML = ""; div.style.cssText = divReset + "width:1px;padding:1px;display:inline;zoom:1"; support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 ); // Support: IE6 // Check if elements with layout shrink-wrap their children div.style.display = "block"; div.innerHTML = "<div></div>"; div.firstChild.style.width = "5px"; support.shrinkWrapBlocks = ( div.offsetWidth !== 3 ); if ( support.inlineBlockNeedsLayout ) { // Prevent IE 6 from affecting layout for positioned elements #11048 // Prevent IE from shrinking the body in IE 7 mode #12869 // Support: IE<8 body.style.zoom = 1; } } body.removeChild( container ); // Null elements to avoid leaks in IE container = div = tds = marginDiv = null; }); // Null elements to avoid leaks in IE all = select = fragment = opt = a = input = null; return support; })(); var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, rmultiDash = /([A-Z])/g; function internalData( elem, name, data, pvt /* Internal Use Only */ ){ if ( !jQuery.acceptData( elem ) ) { return; } var thisCache, ret, internalKey = jQuery.expando, getByName = typeof name === "string", // We have to handle DOM nodes and JS objects differently because IE6-7 // can't GC object references properly across the DOM-JS boundary isNode = elem.nodeType, // Only DOM nodes need the global jQuery cache; JS object data is // attached directly to the object so GC can occur automatically cache = isNode ? jQuery.cache : elem, // Only defining an ID for JS objects if its cache already exists allows // the code to shortcut on the same path as a DOM node with no cache id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; // Avoid doing any more work than we need to when trying to get data on an // object that has no data at all if ( (!id || !cache[id] || (!pvt && !cache[id].data)) && getByName && data === undefined ) { return; } if ( !id ) { // Only DOM nodes need a new unique ID for each element since their data // ends up in the global cache if ( isNode ) { elem[ internalKey ] = id = core_deletedIds.pop() || jQuery.guid++; } else { id = internalKey; } } if ( !cache[ id ] ) { cache[ id ] = {}; // Avoids exposing jQuery metadata on plain JS objects when the object // is serialized using JSON.stringify if ( !isNode ) { cache[ id ].toJSON = jQuery.noop; } } // An object can be passed to jQuery.data instead of a key/value pair; this gets // shallow copied over onto the existing cache if ( typeof name === "object" || typeof name === "function" ) { if ( pvt ) { cache[ id ] = jQuery.extend( cache[ id ], name ); } else { cache[ id ].data = jQuery.extend( cache[ id ].data, name ); } } thisCache = cache[ id ]; // jQuery data() is stored in a separate object inside the object's internal data // cache in order to avoid key collisions between internal data and user-defined // data. if ( !pvt ) { if ( !thisCache.data ) { thisCache.data = {}; } thisCache = thisCache.data; } if ( data !== undefined ) { thisCache[ jQuery.camelCase( name ) ] = data; } // Check for both converted-to-camel and non-converted data property names // If a data property was specified if ( getByName ) { // First Try to find as-is property data ret = thisCache[ name ]; // Test for null|undefined property data if ( ret == null ) { // Try to find the camelCased property ret = thisCache[ jQuery.camelCase( name ) ]; } } else { ret = thisCache; } return ret; } function internalRemoveData( elem, name, pvt ) { if ( !jQuery.acceptData( elem ) ) { return; } var i, l, thisCache, isNode = elem.nodeType, // See jQuery.data for more information cache = isNode ? jQuery.cache : elem, id = isNode ? elem[ jQuery.expando ] : jQuery.expando; // If there is already no cache entry for this object, there is no // purpose in continuing if ( !cache[ id ] ) { return; } if ( name ) { thisCache = pvt ? cache[ id ] : cache[ id ].data; if ( thisCache ) { // Support array or space separated string names for data keys if ( !jQuery.isArray( name ) ) { // try the string as a key before any manipulation if ( name in thisCache ) { name = [ name ]; } else { // split the camel cased version by spaces unless a key with the spaces exists name = jQuery.camelCase( name ); if ( name in thisCache ) { name = [ name ]; } else { name = name.split(" "); } } } else { // If "name" is an array of keys... // When data is initially created, via ("key", "val") signature, // keys will be converted to camelCase. // Since there is no way to tell _how_ a key was added, remove // both plain key and camelCase key. #12786 // This will only penalize the array argument path. name = name.concat( jQuery.map( name, jQuery.camelCase ) ); } for ( i = 0, l = name.length; i < l; i++ ) { delete thisCache[ name[i] ]; } // If there is no data left in the cache, we want to continue // and let the cache object itself get destroyed if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) { return; } } } // See jQuery.data for more information if ( !pvt ) { delete cache[ id ].data; // Don't destroy the parent cache unless the internal data object // had been the only thing left in it if ( !isEmptyDataObject( cache[ id ] ) ) { return; } } // Destroy the cache if ( isNode ) { jQuery.cleanData( [ elem ], true ); // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) } else if ( jQuery.support.deleteExpando || cache != cache.window ) { delete cache[ id ]; // When all else fails, null } else { cache[ id ] = null; } } jQuery.extend({ cache: {}, // Unique for each copy of jQuery on the page // Non-digits removed to match rinlinejQuery expando: "jQuery" + ( core_version + Math.random() ).replace( /\D/g, "" ), // The following elements throw uncatchable exceptions if you // attempt to add expando properties to them. noData: { "embed": true, // Ban all objects except for Flash (which handle expandos) "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000", "applet": true }, hasData: function( elem ) { elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ]; return !!elem && !isEmptyDataObject( elem ); }, data: function( elem, name, data ) { return internalData( elem, name, data ); }, removeData: function( elem, name ) { return internalRemoveData( elem, name ); }, // For internal use only. _data: function( elem, name, data ) { return internalData( elem, name, data, true ); }, _removeData: function( elem, name ) { return internalRemoveData( elem, name, true ); }, // A method for determining if a DOM node can handle the data expando acceptData: function( elem ) { // Do not set data on non-element because it will not be cleared (#8335). if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) { return false; } var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ]; // nodes accept data unless otherwise specified; rejection can be conditional return !noData || noData !== true && elem.getAttribute("classid") === noData; } }); jQuery.fn.extend({ data: function( key, value ) { var attrs, name, elem = this[0], i = 0, data = null; // Gets all values if ( key === undefined ) { if ( this.length ) { data = jQuery.data( elem ); if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { attrs = elem.attributes; for ( ; i < attrs.length; i++ ) { name = attrs[i].name; if ( !name.indexOf( "data-" ) ) { name = jQuery.camelCase( name.slice(5) ); dataAttr( elem, name, data[ name ] ); } } jQuery._data( elem, "parsedAttrs", true ); } } return data; } // Sets multiple values if ( typeof key === "object" ) { return this.each(function() { jQuery.data( this, key ); }); } return jQuery.access( this, function( value ) { if ( value === undefined ) { // Try to fetch any internally stored data first return elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : null; } this.each(function() { jQuery.data( this, key, value ); }); }, null, value, arguments.length > 1, null, true ); }, removeData: function( key ) { return this.each(function() { jQuery.removeData( this, key ); }); } }); function dataAttr( elem, key, data ) { // If nothing was found internally, try to fetch any // data from the HTML5 data-* attribute if ( data === undefined && elem.nodeType === 1 ) { var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); data = elem.getAttribute( name ); if ( typeof data === "string" ) { try { data = data === "true" ? true : data === "false" ? false : data === "null" ? null : // Only convert to a number if it doesn't change the string +data + "" === data ? +data : rbrace.test( data ) ? jQuery.parseJSON( data ) : data; } catch( e ) {} // Make sure we set the data so it isn't changed later jQuery.data( elem, key, data ); } else { data = undefined; } } return data; } // checks a cache object for emptiness function isEmptyDataObject( obj ) { var name; for ( name in obj ) { // if the public data object is empty, the private is still empty if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) { continue; } if ( name !== "toJSON" ) { return false; } } return true; } jQuery.extend({ queue: function( elem, type, data ) { var queue; if ( elem ) { type = ( type || "fx" ) + "queue"; queue = jQuery._data( elem, type ); // Speed up dequeue by getting out quickly if this is just a lookup if ( data ) { if ( !queue || jQuery.isArray(data) ) { queue = jQuery._data( elem, type, jQuery.makeArray(data) ); } else { queue.push( data ); } } return queue || []; } }, dequeue: function( elem, type ) { type = type || "fx"; var queue = jQuery.queue( elem, type ), startLength = queue.length, fn = queue.shift(), hooks = jQuery._queueHooks( elem, type ), next = function() { jQuery.dequeue( elem, type ); }; // If the fx queue is dequeued, always remove the progress sentinel if ( fn === "inprogress" ) { fn = queue.shift(); startLength--; } hooks.cur = fn; if ( fn ) { // Add a progress sentinel to prevent the fx queue from being // automatically dequeued if ( type === "fx" ) { queue.unshift( "inprogress" ); } // clear up the last queue stop function delete hooks.stop; fn.call( elem, next, hooks ); } if ( !startLength && hooks ) { hooks.empty.fire(); } }, // not intended for public consumption - generates a queueHooks object, or returns the current one _queueHooks: function( elem, type ) { var key = type + "queueHooks"; return jQuery._data( elem, key ) || jQuery._data( elem, key, { empty: jQuery.Callbacks("once memory").add(function() { jQuery._removeData( elem, type + "queue" ); jQuery._removeData( elem, key ); }) }); } }); jQuery.fn.extend({ queue: function( type, data ) { var setter = 2; if ( typeof type !== "string" ) { data = type; type = "fx"; setter--; } if ( arguments.length < setter ) { return jQuery.queue( this[0], type ); } return data === undefined ? this : this.each(function() { var queue = jQuery.queue( this, type, data ); // ensure a hooks for this queue jQuery._queueHooks( this, type ); if ( type === "fx" && queue[0] !== "inprogress" ) { jQuery.dequeue( this, type ); } }); }, dequeue: function( type ) { return this.each(function() { jQuery.dequeue( this, type ); }); }, // Based off of the plugin by Clint Helfers, with permission. // http://blindsignals.com/index.php/2009/07/jquery-delay/ delay: function( time, type ) { time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; type = type || "fx"; return this.queue( type, function( next, hooks ) { var timeout = setTimeout( next, time ); hooks.stop = function() { clearTimeout( timeout ); }; }); }, clearQueue: function( type ) { return this.queue( type || "fx", [] ); }, // Get a promise resolved when queues of a certain type // are emptied (fx is the type by default) promise: function( type, obj ) { var tmp, count = 1, defer = jQuery.Deferred(), elements = this, i = this.length, resolve = function() { if ( !( --count ) ) { defer.resolveWith( elements, [ elements ] ); } }; if ( typeof type !== "string" ) { obj = type; type = undefined; } type = type || "fx"; while( i-- ) { tmp = jQuery._data( elements[ i ], type + "queueHooks" ); if ( tmp && tmp.empty ) { count++; tmp.empty.add( resolve ); } } resolve(); return defer.promise( obj ); } }); var nodeHook, boolHook, rclass = /[\t\r\n]/g, rreturn = /\r/g, rfocusable = /^(?:input|select|textarea|button|object)$/i, rclickable = /^(?:a|area)$/i, rboolean = /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, ruseDefault = /^(?:checked|selected)$/i, getSetAttribute = jQuery.support.getSetAttribute, getSetInput = jQuery.support.input; jQuery.fn.extend({ attr: function( name, value ) { return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 ); }, removeAttr: function( name ) { return this.each(function() { jQuery.removeAttr( this, name ); }); }, prop: function( name, value ) { return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 ); }, removeProp: function( name ) { name = jQuery.propFix[ name ] || name; return this.each(function() { // try/catch handles cases where IE balks (such as removing a property on window) try { this[ name ] = undefined; delete this[ name ]; } catch( e ) {} }); }, addClass: function( value ) { var classes, elem, cur, clazz, j, i = 0, len = this.length, proceed = typeof value === "string" && value; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).addClass( value.call( this, j, this.className ) ); }); } if ( proceed ) { // The disjunction here is for better compressibility (see removeClass) classes = ( value || "" ).match( core_rnotwhite ) || []; for ( ; i < len; i++ ) { elem = this[ i ]; cur = elem.nodeType === 1 && ( elem.className ? ( " " + elem.className + " " ).replace( rclass, " " ) : " " ); if ( cur ) { j = 0; while ( (clazz = classes[j++]) ) { if ( cur.indexOf( " " + clazz + " " ) < 0 ) { cur += clazz + " "; } } elem.className = jQuery.trim( cur ); } } } return this; }, removeClass: function( value ) { var classes, elem, cur, clazz, j, i = 0, len = this.length, proceed = arguments.length === 0 || typeof value === "string" && value; if ( jQuery.isFunction( value ) ) { return this.each(function( j ) { jQuery( this ).removeClass( value.call( this, j, this.className ) ); }); } if ( proceed ) { classes = ( value || "" ).match( core_rnotwhite ) || []; for ( ; i < len; i++ ) { elem = this[ i ]; // This expression is here for better compressibility (see addClass) cur = elem.nodeType === 1 && ( elem.className ? ( " " + elem.className + " " ).replace( rclass, " " ) : "" ); if ( cur ) { j = 0; while ( (clazz = classes[j++]) ) { // Remove *all* instances while ( cur.indexOf( " " + clazz + " " ) >= 0 ) { cur = cur.replace( " " + clazz + " ", " " ); } } elem.className = value ? jQuery.trim( cur ) : ""; } } } return this; }, toggleClass: function( value, stateVal ) { var type = typeof value, isBool = typeof stateVal === "boolean"; if ( jQuery.isFunction( value ) ) { return this.each(function( i ) { jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal ); }); } return this.each(function() { if ( type === "string" ) { // toggle individual class names var className, i = 0, self = jQuery( this ), state = stateVal, classNames = value.match( core_rnotwhite ) || []; while ( (className = classNames[ i++ ]) ) { // check each className given, space separated list state = isBool ? state : !self.hasClass( className ); self[ state ? "addClass" : "removeClass" ]( className ); } // Toggle whole class name } else if ( type === core_strundefined || type === "boolean" ) { if ( this.className ) { // store className if set jQuery._data( this, "__className__", this.className ); } // If the element has a class name or if we're passed "false", // then remove the whole classname (if there was one, the above saved it). // Otherwise bring back whatever was previously saved (if anything), // falling back to the empty string if nothing was stored. this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || ""; } }); }, hasClass: function( selector ) { var className = " " + selector + " ", i = 0, l = this.length; for ( ; i < l; i++ ) { if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) { return true; } } return false; }, val: function( value ) { var ret, hooks, isFunction, elem = this[0]; if ( !arguments.length ) { if ( elem ) { hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ]; if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) { return ret; } ret = elem.value; return typeof ret === "string" ? // handle most common string cases ret.replace(rreturn, "") : // handle cases where value is null/undef or number ret == null ? "" : ret; } return; } isFunction = jQuery.isFunction( value ); return this.each(function( i ) { var val, self = jQuery(this); if ( this.nodeType !== 1 ) { return; } if ( isFunction ) { val = value.call( this, i, self.val() ); } else { val = value; } // Treat null/undefined as ""; convert numbers to string if ( val == null ) { val = ""; } else if ( typeof val === "number" ) { val += ""; } else if ( jQuery.isArray( val ) ) { val = jQuery.map(val, function ( value ) { return value == null ? "" : value + ""; }); } hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; // If set returns undefined, fall back to normal setting if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) { this.value = val; } }); } }); jQuery.extend({ valHooks: { option: { get: function( elem ) { // attributes.value is undefined in Blackberry 4.7 but // uses .value. See #6932 var val = elem.attributes.value; return !val || val.specified ? elem.value : elem.text; } }, select: { get: function( elem ) { var value, option, options = elem.options, index = elem.selectedIndex, one = elem.type === "select-one" || index < 0, values = one ? null : [], max = one ? index + 1 : options.length, i = index < 0 ? max : one ? index : 0; // Loop through all the selected options for ( ; i < max; i++ ) { option = options[ i ]; // oldIE doesn't update selected after form reset (#2551) if ( ( option.selected || i === index ) && // Don't return options that are disabled or in a disabled optgroup ( jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null ) && ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) { // Get the specific value for the option value = jQuery( option ).val(); // We don't need an array for one selects if ( one ) { return value; } // Multi-Selects return an array values.push( value ); } } return values; }, set: function( elem, value ) { var values = jQuery.makeArray( value ); jQuery(elem).find("option").each(function() { this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; }); if ( !values.length ) { elem.selectedIndex = -1; } return values; } } }, attr: function( elem, name, value ) { var hooks, notxml, ret, nType = elem.nodeType; // don't get/set attributes on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } // Fallback to prop when attributes are not supported if ( typeof elem.getAttribute === core_strundefined ) { return jQuery.prop( elem, name, value ); } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); // All attributes are lowercase // Grab necessary hook if one is defined if ( notxml ) { name = name.toLowerCase(); hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook ); } if ( value !== undefined ) { if ( value === null ) { jQuery.removeAttr( elem, name ); } else if ( hooks && notxml && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { elem.setAttribute( name, value + "" ); return value; } } else if ( hooks && notxml && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { // In IE9+, Flash objects don't have .getAttribute (#12945) // Support: IE9+ if ( typeof elem.getAttribute !== core_strundefined ) { ret = elem.getAttribute( name ); } // Non-existent attributes return null, we normalize to undefined return ret == null ? undefined : ret; } }, removeAttr: function( elem, value ) { var name, propName, i = 0, attrNames = value && value.match( core_rnotwhite ); if ( attrNames && elem.nodeType === 1 ) { while ( (name = attrNames[i++]) ) { propName = jQuery.propFix[ name ] || name; // Boolean attributes get special treatment (#10870) if ( rboolean.test( name ) ) { // Set corresponding property to false for boolean attributes // Also clear defaultChecked/defaultSelected (if appropriate) for IE<8 if ( !getSetAttribute && ruseDefault.test( name ) ) { elem[ jQuery.camelCase( "default-" + name ) ] = elem[ propName ] = false; } else { elem[ propName ] = false; } // See #9699 for explanation of this approach (setting first, then removal) } else { jQuery.attr( elem, name, "" ); } elem.removeAttribute( getSetAttribute ? name : propName ); } } }, attrHooks: { type: { set: function( elem, value ) { if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) { // Setting the type on a radio button after the value resets the value in IE6-9 // Reset value to default in case type is set after value during creation var val = elem.value; elem.setAttribute( "type", value ); if ( val ) { elem.value = val; } return value; } } } }, propFix: { tabindex: "tabIndex", readonly: "readOnly", "for": "htmlFor", "class": "className", maxlength: "maxLength", cellspacing: "cellSpacing", cellpadding: "cellPadding", rowspan: "rowSpan", colspan: "colSpan", usemap: "useMap", frameborder: "frameBorder", contenteditable: "contentEditable" }, prop: function( elem, name, value ) { var ret, hooks, notxml, nType = elem.nodeType; // don't get/set properties on text, comment and attribute nodes if ( !elem || nType === 3 || nType === 8 || nType === 2 ) { return; } notxml = nType !== 1 || !jQuery.isXMLDoc( elem ); if ( notxml ) { // Fix name and attach hooks name = jQuery.propFix[ name ] || name; hooks = jQuery.propHooks[ name ]; } if ( value !== undefined ) { if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) { return ret; } else { return ( elem[ name ] = value ); } } else { if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) { return ret; } else { return elem[ name ]; } } }, propHooks: { tabIndex: { get: function( elem ) { // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ var attributeNode = elem.getAttributeNode("tabindex"); return attributeNode && attributeNode.specified ? parseInt( attributeNode.value, 10 ) : rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? 0 : undefined; } } } }); // Hook for boolean attributes boolHook = { get: function( elem, name ) { var // Use .prop to determine if this attribute is understood as boolean prop = jQuery.prop( elem, name ), // Fetch it accordingly attr = typeof prop === "boolean" && elem.getAttribute( name ), detail = typeof prop === "boolean" ? getSetInput && getSetAttribute ? attr != null : // oldIE fabricates an empty string for missing boolean attributes // and conflates checked/selected into attroperties ruseDefault.test( name ) ? elem[ jQuery.camelCase( "default-" + name ) ] : !!attr : // fetch an attribute node for properties not recognized as boolean elem.getAttributeNode( name ); return detail && detail.value !== false ? name.toLowerCase() : undefined; }, set: function( elem, value, name ) { if ( value === false ) { // Remove boolean attributes when set to false jQuery.removeAttr( elem, name ); } else if ( getSetInput && getSetAttribute || !ruseDefault.test( name ) ) { // IE<8 needs the *property* name elem.setAttribute( !getSetAttribute && jQuery.propFix[ name ] || name, name ); // Use defaultChecked and defaultSelected for oldIE } else { elem[ jQuery.camelCase( "default-" + name ) ] = elem[ name ] = true; } return name; } }; // fix oldIE value attroperty if ( !getSetInput || !getSetAttribute ) { jQuery.attrHooks.value = { get: function( elem, name ) { var ret = elem.getAttributeNode( name ); return jQuery.nodeName( elem, "input" ) ? // Ignore the value *property* by using defaultValue elem.defaultValue : ret && ret.specified ? ret.value : undefined; }, set: function( elem, value, name ) { if ( jQuery.nodeName( elem, "input" ) ) { // Does not return so that setAttribute is also used elem.defaultValue = value; } else { // Use nodeHook if defined (#1954); otherwise setAttribute is fine return nodeHook && nodeHook.set( elem, value, name ); } } }; } // IE6/7 do not support getting/setting some attributes with get/setAttribute if ( !getSetAttribute ) { // Use this for any attribute in IE6/7 // This fixes almost every IE6/7 issue nodeHook = jQuery.valHooks.button = { get: function( elem, name ) { var ret = elem.getAttributeNode( name ); return ret && ( name === "id" || name === "name" || name === "coords" ? ret.value !== "" : ret.specified ) ? ret.value : undefined; }, set: function( elem, value, name ) { // Set the existing or create a new attribute node var ret = elem.getAttributeNode( name ); if ( !ret ) { elem.setAttributeNode( (ret = elem.ownerDocument.createAttribute( name )) ); } ret.value = value += ""; // Break association with cloned elements by also using setAttribute (#9646) return name === "value" || value === elem.getAttribute( name ) ? value : undefined; } }; // Set contenteditable to false on removals(#10429) // Setting to empty string throws an error as an invalid value jQuery.attrHooks.contenteditable = { get: nodeHook.get, set: function( elem, value, name ) { nodeHook.set( elem, value === "" ? false : value, name ); } }; // Set width and height to auto instead of 0 on empty string( Bug #8150 ) // This is for removals jQuery.each([ "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { set: function( elem, value ) { if ( value === "" ) { elem.setAttribute( name, "auto" ); return value; } } }); }); } // Some attributes require a special call on IE // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx if ( !jQuery.support.hrefNormalized ) { jQuery.each([ "href", "src", "width", "height" ], function( i, name ) { jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], { get: function( elem ) { var ret = elem.getAttribute( name, 2 ); return ret == null ? undefined : ret; } }); }); // href/src property should get the full normalized URL (#10299/#12915) jQuery.each([ "href", "src" ], function( i, name ) { jQuery.propHooks[ name ] = { get: function( elem ) { return elem.getAttribute( name, 4 ); } }; }); } if ( !jQuery.support.style ) { jQuery.attrHooks.style = { get: function( elem ) { // Return undefined in the case of empty string // Note: IE uppercases css property names, but if we were to .toLowerCase() // .cssText, that would destroy case senstitivity in URL's, like in "background" return elem.style.cssText || undefined; }, set: function( elem, value ) { return ( elem.style.cssText = value + "" ); } }; } // Safari mis-reports the default selected property of an option // Accessing the parent's selectedIndex property fixes it if ( !jQuery.support.optSelected ) { jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, { get: function( elem ) { var parent = elem.parentNode; if ( parent ) { parent.selectedIndex; // Make sure that it also works with optgroups, see #5701 if ( parent.parentNode ) { parent.parentNode.selectedIndex; } } return null; } }); } // IE6/7 call enctype encoding if ( !jQuery.support.enctype ) { jQuery.propFix.enctype = "encoding"; } // Radios and checkboxes getter/setter if ( !jQuery.support.checkOn ) { jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = { get: function( elem ) { // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified return elem.getAttribute("value") === null ? "on" : elem.value; } }; }); } jQuery.each([ "radio", "checkbox" ], function() { jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], { set: function( elem, value ) { if ( jQuery.isArray( value ) ) { return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 ); } } }); }); var rformElems = /^(?:input|select|textarea)$/i, rkeyEvent = /^key/, rmouseEvent = /^(?:mouse|contextmenu)|click/, rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, rtypenamespace = /^([^.]*)(?:\.(.+)|)$/; function returnTrue() { return true; } function returnFalse() { return false; } /* * Helper functions for managing events -- not part of the public interface. * Props to Dean Edwards' addEvent library for many of the ideas. */ jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) { var tmp, events, t, handleObjIn, special, eventHandle, handleObj, handlers, type, namespaces, origType, elemData = jQuery._data( elem ); // Don't attach events to noData or text/comment nodes (but allow plain objects) if ( !elemData ) { return; } // Caller can pass in an object of custom data in lieu of the handler if ( handler.handler ) { handleObjIn = handler; handler = handleObjIn.handler; selector = handleObjIn.selector; } // Make sure that the handler has a unique ID, used to find/remove it later if ( !handler.guid ) { handler.guid = jQuery.guid++; } // Init the element's event structure and main handler, if this is the first if ( !(events = elemData.events) ) { events = elemData.events = {}; } if ( !(eventHandle = elemData.handle) ) { eventHandle = elemData.handle = function( e ) { // Discard the second event of a jQuery.event.trigger() and // when an event is called after a page has unloaded return typeof jQuery !== core_strundefined && (!e || jQuery.event.triggered !== e.type) ? jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : undefined; }; // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events eventHandle.elem = elem; } // Handle multiple events separated by a space // jQuery(...).bind("mouseover mouseout", fn); types = ( types || "" ).match( core_rnotwhite ) || [""]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // If event changes its type, use the special event handlers for the changed type special = jQuery.event.special[ type ] || {}; // If selector defined, determine special event api type, otherwise given type type = ( selector ? special.delegateType : special.bindType ) || type; // Update special based on newly reset type special = jQuery.event.special[ type ] || {}; // handleObj is passed to all event handlers handleObj = jQuery.extend({ type: type, origType: origType, data: data, handler: handler, guid: handler.guid, selector: selector, needsContext: selector && jQuery.expr.match.needsContext.test( selector ), namespace: namespaces.join(".") }, handleObjIn ); // Init the event handler queue if we're the first if ( !(handlers = events[ type ]) ) { handlers = events[ type ] = []; handlers.delegateCount = 0; // Only use addEventListener/attachEvent if the special events handler returns false if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { // Bind the global event handler to the element if ( elem.addEventListener ) { elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) { elem.attachEvent( "on" + type, eventHandle ); } } } if ( special.add ) { special.add.call( elem, handleObj ); if ( !handleObj.handler.guid ) { handleObj.handler.guid = handler.guid; } } // Add to the element's handler list, delegates in front if ( selector ) { handlers.splice( handlers.delegateCount++, 0, handleObj ); } else { handlers.push( handleObj ); } // Keep track of which events have ever been used, for event optimization jQuery.event.global[ type ] = true; } // Nullify elem to prevent memory leaks in IE elem = null; }, // Detach an event or set of events from an element remove: function( elem, types, handler, selector, mappedTypes ) { var j, handleObj, tmp, origCount, t, events, special, handlers, type, namespaces, origType, elemData = jQuery.hasData( elem ) && jQuery._data( elem ); if ( !elemData || !(events = elemData.events) ) { return; } // Once for each type.namespace in types; type may be omitted types = ( types || "" ).match( core_rnotwhite ) || [""]; t = types.length; while ( t-- ) { tmp = rtypenamespace.exec( types[t] ) || []; type = origType = tmp[1]; namespaces = ( tmp[2] || "" ).split( "." ).sort(); // Unbind all events (on this namespace, if provided) for the element if ( !type ) { for ( type in events ) { jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); } continue; } special = jQuery.event.special[ type ] || {}; type = ( selector ? special.delegateType : special.bindType ) || type; handlers = events[ type ] || []; tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ); // Remove matching events origCount = j = handlers.length; while ( j-- ) { handleObj = handlers[ j ]; if ( ( mappedTypes || origType === handleObj.origType ) && ( !handler || handler.guid === handleObj.guid ) && ( !tmp || tmp.test( handleObj.namespace ) ) && ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) { handlers.splice( j, 1 ); if ( handleObj.selector ) { handlers.delegateCount--; } if ( special.remove ) { special.remove.call( elem, handleObj ); } } } // Remove generic event handler if we removed something and no more handlers exist // (avoids potential for endless recursion during removal of special event handlers) if ( origCount && !handlers.length ) { if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) { jQuery.removeEvent( elem, type, elemData.handle ); } delete events[ type ]; } } // Remove the expando if it's no longer used if ( jQuery.isEmptyObject( events ) ) { delete elemData.handle; // removeData also checks for emptiness and clears the expando if empty // so use it instead of delete jQuery._removeData( elem, "events" ); } }, trigger: function( event, data, elem, onlyHandlers ) { var handle, ontype, cur, bubbleType, special, tmp, i, eventPath = [ elem || document ], type = core_hasOwn.call( event, "type" ) ? event.type : event, namespaces = core_hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : []; cur = tmp = elem = elem || document; // Don't do events on text and comment nodes if ( elem.nodeType === 3 || elem.nodeType === 8 ) { return; } // focus/blur morphs to focusin/out; ensure we're not firing them right now if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { return; } if ( type.indexOf(".") >= 0 ) { // Namespaced trigger; create a regexp to match event type in handle() namespaces = type.split("."); type = namespaces.shift(); namespaces.sort(); } ontype = type.indexOf(":") < 0 && "on" + type; // Caller can pass in a jQuery.Event object, Object, or just an event type string event = event[ jQuery.expando ] ? event : new jQuery.Event( type, typeof event === "object" && event ); event.isTrigger = true; event.namespace = namespaces.join("."); event.namespace_re = event.namespace ? new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) : null; // Clean up the event in case it is being reused event.result = undefined; if ( !event.target ) { event.target = elem; } // Clone any incoming data and prepend the event, creating the handler arg list data = data == null ? [ event ] : jQuery.makeArray( data, [ event ] ); // Allow special events to draw outside the lines special = jQuery.event.special[ type ] || {}; if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { return; } // Determine event propagation path in advance, per W3C events spec (#9951) // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { bubbleType = special.delegateType || type; if ( !rfocusMorph.test( bubbleType + type ) ) { cur = cur.parentNode; } for ( ; cur; cur = cur.parentNode ) { eventPath.push( cur ); tmp = cur; } // Only add window if we got to document (e.g., not plain obj or detached DOM) if ( tmp === (elem.ownerDocument || document) ) { eventPath.push( tmp.defaultView || tmp.parentWindow || window ); } } // Fire handlers on the event path i = 0; while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) { event.type = i > 1 ? bubbleType : special.bindType || type; // jQuery handler handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" ); if ( handle ) { handle.apply( cur, data ); } // Native handler handle = ontype && cur[ ontype ]; if ( handle && jQuery.acceptData( cur ) && handle.apply && handle.apply( cur, data ) === false ) { event.preventDefault(); } } event.type = type; // If nobody prevented the default action, do it now if ( !onlyHandlers && !event.isDefaultPrevented() ) { if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) && !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) { // Call a native DOM method on the target with the same name name as the event. // Can't use an .isFunction() check here because IE6/7 fails that test. // Don't do default actions on window, that's where global variables be (#6170) if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { // Don't re-trigger an onFOO event when we call its FOO() method tmp = elem[ ontype ]; if ( tmp ) { elem[ ontype ] = null; } // Prevent re-triggering of the same event, since we already bubbled it above jQuery.event.triggered = type; try { elem[ type ](); } catch ( e ) { // IE<9 dies on focus/blur to hidden element (#1486,#12518) // only reproducible on winXP IE8 native, not IE9 in IE8 mode } jQuery.event.triggered = undefined; if ( tmp ) { elem[ ontype ] = tmp; } } } } return event.result; }, dispatch: function( event ) { // Make a writable jQuery.Event from the native event object event = jQuery.event.fix( event ); var i, ret, handleObj, matched, j, handlerQueue = [], args = core_slice.call( arguments ), handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], special = jQuery.event.special[ event.type ] || {}; // Use the fix-ed jQuery.Event rather than the (read-only) native event args[0] = event; event.delegateTarget = this; // Call the preDispatch hook for the mapped type, and let it bail if desired if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { return; } // Determine handlers handlerQueue = jQuery.event.handlers.call( this, event, handlers ); // Run delegates first; they may want to stop propagation beneath us i = 0; while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) { event.currentTarget = matched.elem; j = 0; while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) { // Triggered event must either 1) have no namespace, or // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace). if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) { event.handleObj = handleObj; event.data = handleObj.data; var obj = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ); if(obj.apply){ ret = obj.apply( matched.elem, args ); } if ( ret !== undefined ) { if ( (event.result = ret) === false ) { event.preventDefault(); event.stopPropagation(); } } } } } // Call the postDispatch hook for the mapped type if ( special.postDispatch ) { special.postDispatch.call( this, event ); } return event.result; }, handlers: function( event, handlers ) { var sel, handleObj, matches, i, handlerQueue = [], delegateCount = handlers.delegateCount, cur = event.target; // Find delegate handlers // Black-hole SVG <use> instance trees (#13180) // Avoid non-left-click bubbling in Firefox (#3861) if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) { for ( ; cur != this; cur = cur.parentNode || this ) { // Don't check non-elements (#13208) // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) if ( cur.nodeType === 1 && (cur.disabled !== true || event.type !== "click") ) { matches = []; for ( i = 0; i < delegateCount; i++ ) { handleObj = handlers[ i ]; // Don't conflict with Object.prototype properties (#13203) sel = handleObj.selector + " "; if ( matches[ sel ] === undefined ) { matches[ sel ] = handleObj.needsContext ? jQuery( sel, this ).index( cur ) >= 0 : jQuery.find( sel, this, null, [ cur ] ).length; } if ( matches[ sel ] ) { matches.push( handleObj ); } } if ( matches.length ) { handlerQueue.push({ elem: cur, handlers: matches }); } } } } // Add the remaining (directly-bound) handlers if ( delegateCount < handlers.length ) { handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) }); } return handlerQueue; }, fix: function( event ) { if ( event[ jQuery.expando ] ) { return event; } // Create a writable copy of the event object and normalize some properties var i, prop, copy, type = event.type, originalEvent = event, fixHook = this.fixHooks[ type ]; if ( !fixHook ) { this.fixHooks[ type ] = fixHook = rmouseEvent.test( type ) ? this.mouseHooks : rkeyEvent.test( type ) ? this.keyHooks : {}; } copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; event = new jQuery.Event( originalEvent ); i = copy.length; while ( i-- ) { prop = copy[ i ]; event[ prop ] = originalEvent[ prop ]; } // Support: IE<9 // Fix target property (#1925) if ( !event.target ) { event.target = originalEvent.srcElement || document; } // Support: Chrome 23+, Safari? // Target should not be a text node (#504, #13143) if ( event.target.nodeType === 3 ) { event.target = event.target.parentNode; } // Support: IE<9 // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) event.metaKey = !!event.metaKey; return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; }, // Includes some event props shared by KeyEvent and MouseEvent props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "), fixHooks: {}, keyHooks: { props: "char charCode key keyCode".split(" "), filter: function( event, original ) { // Add which for key events if ( event.which == null ) { event.which = original.charCode != null ? original.charCode : original.keyCode; } return event; } }, mouseHooks: { props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "), filter: function( event, original ) { var body, eventDoc, doc, button = original.button, fromElement = original.fromElement; // Calculate pageX/Y if missing and clientX/Y available if ( event.pageX == null && original.clientX != null ) { eventDoc = event.target.ownerDocument || document; doc = eventDoc.documentElement; body = eventDoc.body; event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 ); } // Add relatedTarget, if necessary if ( !event.relatedTarget && fromElement ) { event.relatedTarget = fromElement === event.target ? original.toElement : fromElement; } // Add which for click: 1 === left; 2 === middle; 3 === right // Note: button is not normalized, so don't use it if ( !event.which && button !== undefined ) { event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); } return event; } }, special: { load: { // Prevent triggered image.load events from bubbling to window.load noBubble: true }, click: { // For checkbox, fire native event so checked state will be right trigger: function() { if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { this.click(); return false; } } }, focus: { // Fire native event if possible so blur/focus sequence is correct trigger: function() { if ( this !== document.activeElement && this.focus ) { try { this.focus(); return false; } catch ( e ) { // Support: IE<9 // If we error on focus to hidden element (#1486, #12518), // let .trigger() run the handlers } } }, delegateType: "focusin" }, blur: { trigger: function() { if ( this === document.activeElement && this.blur ) { this.blur(); return false; } }, delegateType: "focusout" }, beforeunload: { postDispatch: function( event ) { // Even when returnValue equals to undefined Firefox will still show alert if ( event.result !== undefined ) { event.originalEvent.returnValue = event.result; } } } }, simulate: function( type, elem, event, bubble ) { // Piggyback on a donor event to simulate a different one. // Fake originalEvent to avoid donor's stopPropagation, but if the // simulated event prevents default then we do the same on the donor. var e = jQuery.extend( new jQuery.Event(), event, { type: type, isSimulated: true, originalEvent: {} } ); if ( bubble ) { jQuery.event.trigger( e, null, elem ); } else { jQuery.event.dispatch.call( elem, e ); } if ( e.isDefaultPrevented() ) { event.preventDefault(); } } }; jQuery.removeEvent = document.removeEventListener ? function( elem, type, handle ) { if ( elem.removeEventListener ) { elem.removeEventListener( type, handle, false ); } } : function( elem, type, handle ) { var name = "on" + type; if ( elem.detachEvent ) { // #8545, #7054, preventing memory leaks for custom events in IE6-8 // detachEvent needed property on element, by name of that event, to properly expose it to GC if ( typeof elem[ name ] === core_strundefined ) { elem[ name ] = null; } elem.detachEvent( name, handle ); } }; jQuery.Event = function( src, props ) { // Allow instantiation without the 'new' keyword if ( !(this instanceof jQuery.Event) ) { return new jQuery.Event( src, props ); } // Event object if ( src && src.type ) { this.originalEvent = src; this.type = src.type; // Events bubbling up the document may have been marked as prevented // by a handler lower down the tree; reflect the correct value. this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false || src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse; // Event type } else { this.type = src; } // Put explicitly provided properties onto the event object if ( props ) { jQuery.extend( this, props ); } // Create a timestamp if incoming event doesn't have one this.timeStamp = src && src.timeStamp || jQuery.now(); // Mark it as fixed this[ jQuery.expando ] = true; }; // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html jQuery.Event.prototype = { isDefaultPrevented: returnFalse, isPropagationStopped: returnFalse, isImmediatePropagationStopped: returnFalse, preventDefault: function() { var e = this.originalEvent; this.isDefaultPrevented = returnTrue; if ( !e ) { return; } // If preventDefault exists, run it on the original event if ( e.preventDefault ) { e.preventDefault(); // Support: IE // Otherwise set the returnValue property of the original event to false } else { e.returnValue = false; } }, stopPropagation: function() { var e = this.originalEvent; this.isPropagationStopped = returnTrue; if ( !e ) { return; } // If stopPropagation exists, run it on the original event if ( e.stopPropagation ) { e.stopPropagation(); } // Support: IE // Set the cancelBubble property of the original event to true e.cancelBubble = true; }, stopImmediatePropagation: function() { this.isImmediatePropagationStopped = returnTrue; this.stopPropagation(); } }; // Create mouseenter/leave events using mouseover/out and event-time checks jQuery.each({ mouseenter: "mouseover", mouseleave: "mouseout" }, function( orig, fix ) { jQuery.event.special[ orig ] = { delegateType: fix, bindType: fix, handle: function( event ) { var ret, target = this, related = event.relatedTarget, handleObj = event.handleObj; // For mousenter/leave call the handler if related is outside the target. // NB: No relatedTarget if the mouse left/entered the browser window if ( !related || (related !== target && !jQuery.contains( target, related )) ) { event.type = handleObj.origType; ret = handleObj.handler.apply( this, arguments ); event.type = fix; } return ret; } }; }); // IE submit delegation if ( !jQuery.support.submitBubbles ) { jQuery.event.special.submit = { setup: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Lazy-add a submit handler when a descendant form may potentially be submitted jQuery.event.add( this, "click._submit keypress._submit", function( e ) { // Node name check avoids a VML-related crash in IE (#9807) var elem = e.target, form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined; if ( form && !jQuery._data( form, "submitBubbles" ) ) { jQuery.event.add( form, "submit._submit", function( event ) { event._submit_bubble = true; }); jQuery._data( form, "submitBubbles", true ); } }); // return undefined since we don't need an event listener }, postDispatch: function( event ) { // If form was submitted by the user, bubble the event up the tree if ( event._submit_bubble ) { delete event._submit_bubble; if ( this.parentNode && !event.isTrigger ) { jQuery.event.simulate( "submit", this.parentNode, event, true ); } } }, teardown: function() { // Only need this for delegated form submit events if ( jQuery.nodeName( this, "form" ) ) { return false; } // Remove delegated handlers; cleanData eventually reaps submit handlers attached above jQuery.event.remove( this, "._submit" ); } }; } // IE change delegation and checkbox/radio fix if ( !jQuery.support.changeBubbles ) { jQuery.event.special.change = { setup: function() { if ( rformElems.test( this.nodeName ) ) { // IE doesn't fire change on a check/radio until blur; trigger it on click // after a propertychange. Eat the blur-change in special.change.handle. // This still fires onchange a second time for check/radio after blur. if ( this.type === "checkbox" || this.type === "radio" ) { jQuery.event.add( this, "propertychange._change", function( event ) { if ( event.originalEvent.propertyName === "checked" ) { this._just_changed = true; } }); jQuery.event.add( this, "click._change", function( event ) { if ( this._just_changed && !event.isTrigger ) { this._just_changed = false; } // Allow triggered, simulated change events (#11500) jQuery.event.simulate( "change", this, event, true ); }); } return false; } // Delegated event; lazy-add a change handler on descendant inputs jQuery.event.add( this, "beforeactivate._change", function( e ) { var elem = e.target; if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "changeBubbles" ) ) { jQuery.event.add( elem, "change._change", function( event ) { if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { jQuery.event.simulate( "change", this.parentNode, event, true ); } }); jQuery._data( elem, "changeBubbles", true ); } }); }, handle: function( event ) { var elem = event.target; // Swallow native change events from checkbox/radio, we already triggered them above if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) { return event.handleObj.handler.apply( this, arguments ); } }, teardown: function() { jQuery.event.remove( this, "._change" ); return !rformElems.test( this.nodeName ); } }; } // Create "bubbling" focus and blur events if ( !jQuery.support.focusinBubbles ) { jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { // Attach a single capturing handler while someone wants focusin/focusout var attaches = 0, handler = function( event ) { jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true ); }; jQuery.event.special[ fix ] = { setup: function() { if ( attaches++ === 0 ) { document.addEventListener( orig, handler, true ); } }, teardown: function() { if ( --attaches === 0 ) { document.removeEventListener( orig, handler, true ); } } }; }); } jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var type, origFn; // Types can be a map of types/handlers if ( typeof types === "object" ) { // ( types-Object, selector, data ) if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } for ( type in types ) { this.on( type, selector, data, types[ type ], one ); } return this; } if ( data == null && fn == null ) { // ( types, fn ) fn = selector; data = selector = undefined; } else if ( fn == null ) { if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn ) fn = data; data = selector; selector = undefined; } } if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } if ( one === 1 ) { origFn = fn; fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } return this.each( function() { jQuery.event.add( this, types, fn, data, selector ); }); }, one: function( types, selector, data, fn ) { return this.on( types, selector, data, fn, 1 ); }, off: function( types, selector, fn ) { var handleObj, type; if ( types && types.preventDefault && types.handleObj ) { // ( event ) dispatched jQuery.Event handleObj = types.handleObj; jQuery( types.delegateTarget ).off( handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType, handleObj.selector, handleObj.handler ); return this; } if ( typeof types === "object" ) { // ( types-object [, selector] ) for ( type in types ) { this.off( type, selector, types[ type ] ); } return this; } if ( selector === false || typeof selector === "function" ) { // ( types [, fn] ) fn = selector; selector = undefined; } if ( fn === false ) { fn = returnFalse; } return this.each(function() { jQuery.event.remove( this, types, fn, selector ); }); }, bind: function( types, data, fn ) { return this.on( types, null, data, fn ); }, unbind: function( types, fn ) { return this.off( types, null, fn ); }, delegate: function( selector, types, data, fn ) { return this.on( types, selector, data, fn ); }, undelegate: function( selector, types, fn ) { // ( namespace ) or ( selector, types [, fn] ) return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn ); }, trigger: function( type, data ) { return this.each(function() { jQuery.event.trigger( type, data, this ); }); }, triggerHandler: function( type, data ) { var elem = this[0]; if ( elem ) { return jQuery.event.trigger( type, data, elem, true ); } } }); /*! * Sizzle CSS Selector Engine * Copyright 2012 jQuery Foundation and other contributors * Released under the MIT license * http://sizzlejs.com/ */ (function( window, undefined ) { var i, cachedruns, Expr, getText, isXML, compile, hasDuplicate, outermostContext, // Local document vars setDocument, document, docElem, documentIsXML, rbuggyQSA, rbuggyMatches, matches, contains, sortOrder, // Instance-specific data expando = "sizzle" + -(new Date()), preferredDoc = window.document, support = {}, dirruns = 0, done = 0, classCache = createCache(), tokenCache = createCache(), compilerCache = createCache(), // General-purpose constants strundefined = typeof undefined, MAX_NEGATIVE = 1 << 31, // Array methods arr = [], pop = arr.pop, push = arr.push, slice = arr.slice, // Use a stripped-down indexOf if we can't use a native one indexOf = arr.indexOf || function( elem ) { var i = 0, len = this.length; for ( ; i < len; i++ ) { if ( this[i] === elem ) { return i; } } return -1; }, // Regular expressions // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace whitespace = "[\\x20\\t\\r\\n\\f]", // http://www.w3.org/TR/css3-syntax/#characters characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", // Loosely modeled on CSS identifier characters // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier identifier = characterEncoding.replace( "w", "w#" ), // Acceptable operators http://www.w3.org/TR/selectors/#attribute-selectors operators = "([*^$|!~]?=)", attributes = "\\[" + whitespace + "*(" + characterEncoding + ")" + whitespace + "*(?:" + operators + whitespace + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + identifier + ")|)|)" + whitespace + "*\\]", // Prefer arguments quoted, // then not containing pseudos/brackets, // then attribute selectors/non-parenthetical expressions, // then anything else // These preferences are here to reduce the number of selectors // needing tokenize in the PSEUDO preFilter pseudos = ":(" + characterEncoding + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + attributes.replace( 3, 8 ) + ")*)|.*)\\)|)", // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), rcombinators = new RegExp( "^" + whitespace + "*([\\x20\\t\\r\\n\\f>+~])" + whitespace + "*" ), rpseudo = new RegExp( pseudos ), ridentifier = new RegExp( "^" + identifier + "$" ), matchExpr = { "ID": new RegExp( "^#(" + characterEncoding + ")" ), "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ), "NAME": new RegExp( "^\\[name=['\"]?(" + characterEncoding + ")['\"]?\\]" ), "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ), "ATTR": new RegExp( "^" + attributes ), "PSEUDO": new RegExp( "^" + pseudos ), "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), // For use in libraries implementing .is() // We use this for POS matching in `select` "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) }, rsibling = /[\x20\t\r\n\f]*[+~]/, rnative = /^[^{]+\{\s*\[native code/, // Easily-parseable/retrievable ID or TAG or CLASS selectors rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, rinputs = /^(?:input|select|textarea|button)$/i, rheader = /^h\d$/i, rescape = /'|\\/g, rattributeQuotes = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters runescape = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, funescape = function( _, escaped ) { var high = "0x" + escaped - 0x10000; // NaN means non-codepoint return high !== high ? escaped : // BMP codepoint high < 0 ? String.fromCharCode( high + 0x10000 ) : // Supplemental Plane codepoint (surrogate pair) String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); }; // Use a stripped-down slice if we can't use a native one try { slice.call( preferredDoc.documentElement.childNodes, 0 )[0].nodeType; } catch ( e ) { slice = function( i ) { var elem, results = []; while ( (elem = this[i++]) ) { results.push( elem ); } return results; }; } /** * For feature detection * @param {Function} fn The function to test for native support */ function isNative( fn ) { return rnative.test( fn + "" ); } /** * Create key-value caches of limited size * @returns {Function(string, Object)} Returns the Object data after storing it on itself with * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) * deleting the oldest entry */ function createCache() { var cache, keys = []; return (cache = function( key, value ) { // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) if ( keys.push( key += " " ) > Expr.cacheLength ) { // Only keep the most recent entries delete cache[ keys.shift() ]; } return (cache[ key ] = value); }); } /** * Mark a function for special use by Sizzle * @param {Function} fn The function to mark */ function markFunction( fn ) { fn[ expando ] = true; return fn; } /** * Support testing using an element * @param {Function} fn Passed the created div and expects a boolean result */ function assert( fn ) { var div = document.createElement("div"); try { return fn( div ); } catch (e) { return false; } finally { // release memory in IE div = null; } } function Sizzle( selector, context, results, seed ) { var match, elem, m, nodeType, // QSA vars i, groups, old, nid, newContext, newSelector; if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { setDocument( context ); } context = context || document; results = results || []; if ( !selector || typeof selector !== "string" ) { return results; } if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) { return []; } if ( !documentIsXML && !seed ) { // Shortcuts if ( (match = rquickExpr.exec( selector )) ) { // Speed-up: Sizzle("#ID") if ( (m = match[1]) ) { if ( nodeType === 9 ) { elem = context.getElementById( m ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 if ( elem && elem.parentNode ) { // Handle the case where IE, Opera, and Webkit return items // by name instead of ID if ( elem.id === m ) { results.push( elem ); return results; } } else { return results; } } else { // Context is not a document if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) && contains( context, elem ) && elem.id === m ) { results.push( elem ); return results; } } // Speed-up: Sizzle("TAG") } else if ( match[2] ) { push.apply( results, slice.call(context.getElementsByTagName( selector ), 0) ); return results; // Speed-up: Sizzle(".CLASS") } else if ( (m = match[3]) && support.getByClassName && context.getElementsByClassName ) { push.apply( results, slice.call(context.getElementsByClassName( m ), 0) ); return results; } } // QSA path if ( support.qsa && !rbuggyQSA.test(selector) ) { old = true; nid = expando; newContext = context; newSelector = nodeType === 9 && selector; // qSA works strangely on Element-rooted queries // We can work around this by specifying an extra ID on the root // and working up from there (Thanks to Andrew Dupont for the technique) // IE 8 doesn't work on object elements if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) { groups = tokenize( selector ); if ( (old = context.getAttribute("id")) ) { nid = old.replace( rescape, "\\$&" ); } else { context.setAttribute( "id", nid ); } nid = "[id='" + nid + "'] "; i = groups.length; while ( i-- ) { groups[i] = nid + toSelector( groups[i] ); } newContext = rsibling.test( selector ) && context.parentNode || context; newSelector = groups.join(","); } if ( newSelector ) { try { push.apply( results, slice.call( newContext.querySelectorAll( newSelector ), 0 ) ); return results; } catch(qsaError) { } finally { if ( !old ) { context.removeAttribute("id"); } } } } } // All others return select( selector.replace( rtrim, "$1" ), context, results, seed ); } /** * Detect xml * @param {Element|Object} elem An element or a document */ isXML = Sizzle.isXML = function( elem ) { // documentElement is verified for cases where it doesn't yet exist // (such as loading iframes in IE - #4833) var documentElement = elem && (elem.ownerDocument || elem).documentElement; return documentElement ? documentElement.nodeName !== "HTML" : false; }; /** * Sets document-related variables once based on the current document * @param {Element|Object} [doc] An element or document object to use to set the document * @returns {Object} Returns the current document */ setDocument = Sizzle.setDocument = function( node ) { var doc = node ? node.ownerDocument || node : preferredDoc; // If no document and documentElement is available, return if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { return document; } // Set our document document = doc; docElem = doc.documentElement; // Support tests documentIsXML = isXML( doc ); // Check if getElementsByTagName("*") returns only elements support.tagNameNoComments = assert(function( div ) { div.appendChild( doc.createComment("") ); return !div.getElementsByTagName("*").length; }); // Check if attributes should be retrieved by attribute nodes support.attributes = assert(function( div ) { div.innerHTML = "<select></select>"; var type = typeof div.lastChild.getAttribute("multiple"); // IE8 returns a string for some attributes even when not present return type !== "boolean" && type !== "string"; }); // Check if getElementsByClassName can be trusted support.getByClassName = assert(function( div ) { // Opera can't find a second classname (in 9.6) div.innerHTML = "<div class='hidden e'></div><div class='hidden'></div>"; if ( !div.getElementsByClassName || !div.getElementsByClassName("e").length ) { return false; } // Safari 3.2 caches class attributes and doesn't catch changes div.lastChild.className = "e"; return div.getElementsByClassName("e").length === 2; }); // Check if getElementById returns elements by name // Check if getElementsByName privileges form controls or returns elements by ID support.getByName = assert(function( div ) { // Inject content div.id = expando + 0; div.innerHTML = "<a name='" + expando + "'></a><div name='" + expando + "'></div>"; docElem.insertBefore( div, docElem.firstChild ); // Test var pass = doc.getElementsByName && // buggy browsers will return fewer than the correct 2 doc.getElementsByName( expando ).length === 2 + // buggy browsers will return more than the correct 0 doc.getElementsByName( expando + 0 ).length; support.getIdNotName = !doc.getElementById( expando ); // Cleanup docElem.removeChild( div ); return pass; }); // IE6/7 return modified attributes Expr.attrHandle = assert(function( div ) { div.innerHTML = "<a href='#'></a>"; return div.firstChild && typeof div.firstChild.getAttribute !== strundefined && div.firstChild.getAttribute("href") === "#"; }) ? {} : { "href": function( elem ) { return elem.getAttribute( "href", 2 ); }, "type": function( elem ) { return elem.getAttribute("type"); } }; // ID find and filter if ( support.getIdNotName ) { Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== strundefined && !documentIsXML ) { var m = context.getElementById( id ); // Check parentNode to catch when Blackberry 4.6 returns // nodes that are no longer in the document #6963 return m && m.parentNode ? [m] : []; } }; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { return elem.getAttribute("id") === attrId; }; }; } else { Expr.find["ID"] = function( id, context ) { if ( typeof context.getElementById !== strundefined && !documentIsXML ) { var m = context.getElementById( id ); return m ? m.id === id || typeof m.getAttributeNode !== strundefined && m.getAttributeNode("id").value === id ? [m] : undefined : []; } }; Expr.filter["ID"] = function( id ) { var attrId = id.replace( runescape, funescape ); return function( elem ) { var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id"); return node && node.value === attrId; }; }; } // Tag Expr.find["TAG"] = support.tagNameNoComments ? function( tag, context ) { if ( typeof context.getElementsByTagName !== strundefined ) { return context.getElementsByTagName( tag ); } } : function( tag, context ) { var elem, tmp = [], i = 0, results = context.getElementsByTagName( tag ); // Filter out possible comments if ( tag === "*" ) { while ( (elem = results[i++]) ) { if ( elem.nodeType === 1 ) { tmp.push( elem ); } } return tmp; } return results; }; // Name Expr.find["NAME"] = support.getByName && function( tag, context ) { if ( typeof context.getElementsByName !== strundefined ) { return context.getElementsByName( name ); } }; // Class Expr.find["CLASS"] = support.getByClassName && function( className, context ) { if ( typeof context.getElementsByClassName !== strundefined && !documentIsXML ) { return context.getElementsByClassName( className ); } }; // QSA and matchesSelector support // matchesSelector(:active) reports false when true (IE9/Opera 11.5) rbuggyMatches = []; // qSa(:focus) reports false when true (Chrome 21), // no need to also add to buggyMatches since matches checks buggyQSA // A support test would require too much code (would include document ready) rbuggyQSA = [ ":focus" ]; if ( (support.qsa = isNative(doc.querySelectorAll)) ) { // Build QSA regex // Regex strategy adopted from Diego Perini assert(function( div ) { // Select is set to empty string on purpose // This is to test IE's treatment of not explictly // setting a boolean content attribute, // since its presence should be enough // http://bugs.jquery.com/ticket/12359 div.innerHTML = "<select><option selected=''></option></select>"; // IE8 - Some boolean attributes are not treated correctly if ( !div.querySelectorAll("[selected]").length ) { rbuggyQSA.push( "\\[" + whitespace + "*(?:checked|disabled|ismap|multiple|readonly|selected|value)" ); } // Webkit/Opera - :checked should return selected option elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":checked").length ) { rbuggyQSA.push(":checked"); } }); assert(function( div ) { // Opera 10-12/IE8 - ^= $= *= and empty values // Should not select anything div.innerHTML = "<input type='hidden' i=''/>"; if ( div.querySelectorAll("[i^='']").length ) { rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:\"\"|'')" ); } // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) // IE8 throws error here and will not see later tests if ( !div.querySelectorAll(":enabled").length ) { rbuggyQSA.push( ":enabled", ":disabled" ); } // Opera 10-11 does not throw on post-comma invalid pseudos div.querySelectorAll("*,:x"); rbuggyQSA.push(",.*:"); }); } if ( (support.matchesSelector = isNative( (matches = docElem.matchesSelector || docElem.mozMatchesSelector || docElem.webkitMatchesSelector || docElem.oMatchesSelector || docElem.msMatchesSelector) )) ) { assert(function( div ) { // Check to see if it's possible to do matchesSelector // on a disconnected node (IE 9) support.disconnectedMatch = matches.call( div, "div" ); // This should fail with an exception // Gecko does not error, returns false instead matches.call( div, "[s!='']:x" ); rbuggyMatches.push( "!=", pseudos ); }); } rbuggyQSA = new RegExp( rbuggyQSA.join("|") ); rbuggyMatches = new RegExp( rbuggyMatches.join("|") ); // Element contains another // Purposefully does not implement inclusive descendent // As in, an element does not contain itself contains = isNative(docElem.contains) || docElem.compareDocumentPosition ? function( a, b ) { var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode; return a === bup || !!( bup && bup.nodeType === 1 && ( adown.contains ? adown.contains( bup ) : a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 )); } : function( a, b ) { if ( b ) { while ( (b = b.parentNode) ) { if ( b === a ) { return true; } } } return false; }; // Document order sorting sortOrder = docElem.compareDocumentPosition ? function( a, b ) { var compare; if ( a === b ) { hasDuplicate = true; return 0; } if ( (compare = b.compareDocumentPosition && a.compareDocumentPosition && a.compareDocumentPosition( b )) ) { if ( compare & 1 || a.parentNode && a.parentNode.nodeType === 11 ) { if ( a === doc || contains( preferredDoc, a ) ) { return -1; } if ( b === doc || contains( preferredDoc, b ) ) { return 1; } return 0; } return compare & 4 ? -1 : 1; } return a.compareDocumentPosition ? -1 : 1; } : function( a, b ) { var cur, i = 0, aup = a.parentNode, bup = b.parentNode, ap = [ a ], bp = [ b ]; // Exit early if the nodes are identical if ( a === b ) { hasDuplicate = true; return 0; // Parentless nodes are either documents or disconnected } else if ( !aup || !bup ) { return a === doc ? -1 : b === doc ? 1 : aup ? -1 : bup ? 1 : 0; // If the nodes are siblings, we can do a quick check } else if ( aup === bup ) { return siblingCheck( a, b ); } // Otherwise we need full lists of their ancestors for comparison cur = a; while ( (cur = cur.parentNode) ) { ap.unshift( cur ); } cur = b; while ( (cur = cur.parentNode) ) { bp.unshift( cur ); } // Walk down the tree looking for a discrepancy while ( ap[i] === bp[i] ) { i++; } return i ? // Do a sibling check if the nodes have a common ancestor siblingCheck( ap[i], bp[i] ) : // Otherwise nodes in our document sort first ap[i] === preferredDoc ? -1 : bp[i] === preferredDoc ? 1 : 0; }; // Always assume the presence of duplicates if sort doesn't // pass them to our comparison function (as in Google Chrome). hasDuplicate = false; [0, 0].sort( sortOrder ); support.detectDuplicates = hasDuplicate; return document; }; Sizzle.matches = function( expr, elements ) { return Sizzle( expr, null, null, elements ); }; Sizzle.matchesSelector = function( elem, expr ) { // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } // Make sure that attribute selectors are quoted expr = expr.replace( rattributeQuotes, "='$1']" ); // rbuggyQSA always contains :focus, so no need for an existence check if ( support.matchesSelector && !documentIsXML && (!rbuggyMatches || !rbuggyMatches.test(expr)) && !rbuggyQSA.test(expr) ) { try { var ret = matches.call( elem, expr ); // IE 9's matchesSelector returns false on disconnected nodes if ( ret || support.disconnectedMatch || // As well, disconnected nodes are said to be in a document // fragment in IE 9 elem.document && elem.document.nodeType !== 11 ) { return ret; } } catch(e) {} } return Sizzle( expr, document, null, [elem] ).length > 0; }; Sizzle.contains = function( context, elem ) { // Set document vars if needed if ( ( context.ownerDocument || context ) !== document ) { setDocument( context ); } return contains( context, elem ); }; Sizzle.attr = function( elem, name ) { var val; // Set document vars if needed if ( ( elem.ownerDocument || elem ) !== document ) { setDocument( elem ); } if ( !documentIsXML ) { name = name.toLowerCase(); } if ( (val = Expr.attrHandle[ name ]) ) { return val( elem ); } if ( documentIsXML || support.attributes ) { return elem.getAttribute( name ); } return ( (val = elem.getAttributeNode( name )) || elem.getAttribute( name ) ) && elem[ name ] === true ? name : val && val.specified ? val.value : null; }; Sizzle.error = function( msg ) { throw new Error( "Syntax error, unrecognized expression: " + msg ); }; // Document sorting and removing duplicates Sizzle.uniqueSort = function( results ) { var elem, duplicates = [], i = 1, j = 0; // Unless we *know* we can detect duplicates, assume their presence hasDuplicate = !support.detectDuplicates; results.sort( sortOrder ); if ( hasDuplicate ) { for ( ; (elem = results[i]); i++ ) { if ( elem === results[ i - 1 ] ) { j = duplicates.push( i ); } } while ( j-- ) { results.splice( duplicates[ j ], 1 ); } } return results; }; function siblingCheck( a, b ) { var cur = b && a, diff = cur && ( ~b.sourceIndex || MAX_NEGATIVE ) - ( ~a.sourceIndex || MAX_NEGATIVE ); // Use IE sourceIndex if available on both nodes if ( diff ) { return diff; } // Check if b follows a if ( cur ) { while ( (cur = cur.nextSibling) ) { if ( cur === b ) { return -1; } } } return a ? 1 : -1; } // Returns a function to use in pseudos for input types function createInputPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === type; }; } // Returns a function to use in pseudos for buttons function createButtonPseudo( type ) { return function( elem ) { var name = elem.nodeName.toLowerCase(); return (name === "input" || name === "button") && elem.type === type; }; } // Returns a function to use in pseudos for positionals function createPositionalPseudo( fn ) { return markFunction(function( argument ) { argument = +argument; return markFunction(function( seed, matches ) { var j, matchIndexes = fn( [], seed.length, argument ), i = matchIndexes.length; // Match elements found at the specified indexes while ( i-- ) { if ( seed[ (j = matchIndexes[i]) ] ) { seed[j] = !(matches[j] = seed[j]); } } }); }); } /** * Utility function for retrieving the text value of an array of DOM nodes * @param {Array|Element} elem */ getText = Sizzle.getText = function( elem ) { var node, ret = "", i = 0, nodeType = elem.nodeType; if ( !nodeType ) { // If no nodeType, this is expected to be an array for ( ; (node = elem[i]); i++ ) { // Do not traverse comment nodes ret += getText( node ); } } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { // Use textContent for elements // innerText usage removed for consistency of new lines (see #11153) if ( typeof elem.textContent === "string" ) { return elem.textContent; } else { // Traverse its children for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { ret += getText( elem ); } } } else if ( nodeType === 3 || nodeType === 4 ) { return elem.nodeValue; } // Do not include comment or processing instruction nodes return ret; }; Expr = Sizzle.selectors = { // Can be adjusted by the user cacheLength: 50, createPseudo: markFunction, match: matchExpr, find: {}, relative: { ">": { dir: "parentNode", first: true }, " ": { dir: "parentNode" }, "+": { dir: "previousSibling", first: true }, "~": { dir: "previousSibling" } }, preFilter: { "ATTR": function( match ) { match[1] = match[1].replace( runescape, funescape ); // Move the given value to match[3] whether quoted or unquoted match[3] = ( match[4] || match[5] || "" ).replace( runescape, funescape ); if ( match[2] === "~=" ) { match[3] = " " + match[3] + " "; } return match.slice( 0, 4 ); }, "CHILD": function( match ) { /* matches from matchExpr["CHILD"] 1 type (only|nth|...) 2 what (child|of-type) 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) 4 xn-component of xn+y argument ([+-]?\d*n|) 5 sign of xn-component 6 x of xn-component 7 sign of y-component 8 y of y-component */ match[1] = match[1].toLowerCase(); if ( match[1].slice( 0, 3 ) === "nth" ) { // nth-* requires argument if ( !match[3] ) { Sizzle.error( match[0] ); } // numeric x and y parameters for Expr.filter.CHILD // remember that false/true cast respectively to 0/1 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); // other types prohibit arguments } else if ( match[3] ) { Sizzle.error( match[0] ); } return match; }, "PSEUDO": function( match ) { var excess, unquoted = !match[5] && match[2]; if ( matchExpr["CHILD"].test( match[0] ) ) { return null; } // Accept quoted arguments as-is if ( match[4] ) { match[2] = match[4]; // Strip excess characters from unquoted arguments } else if ( unquoted && rpseudo.test( unquoted ) && // Get excess from tokenize (recursively) (excess = tokenize( unquoted, true )) && // advance to the next closing parenthesis (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { // excess is a negative index match[0] = match[0].slice( 0, excess ); match[2] = unquoted.slice( 0, excess ); } // Return only captures needed by the pseudo filter method (type and argument) return match.slice( 0, 3 ); } }, filter: { "TAG": function( nodeName ) { if ( nodeName === "*" ) { return function() { return true; }; } nodeName = nodeName.replace( runescape, funescape ).toLowerCase(); return function( elem ) { return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; }; }, "CLASS": function( className ) { var pattern = classCache[ className + " " ]; return pattern || (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && classCache( className, function( elem ) { return pattern.test( elem.className || (typeof elem.getAttribute !== strundefined && elem.getAttribute("class")) || "" ); }); }, "ATTR": function( name, operator, check ) { return function( elem ) { var result = Sizzle.attr( elem, name ); if ( result == null ) { return operator === "!="; } if ( !operator ) { return true; } result += ""; return operator === "=" ? result === check : operator === "!=" ? result !== check : operator === "^=" ? check && result.indexOf( check ) === 0 : operator === "*=" ? check && result.indexOf( check ) > -1 : operator === "$=" ? check && result.slice( -check.length ) === check : operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 : operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : false; }; }, "CHILD": function( type, what, argument, first, last ) { var simple = type.slice( 0, 3 ) !== "nth", forward = type.slice( -4 ) !== "last", ofType = what === "of-type"; return first === 1 && last === 0 ? // Shortcut for :nth-*(n) function( elem ) { return !!elem.parentNode; } : function( elem, context, xml ) { var cache, outerCache, node, diff, nodeIndex, start, dir = simple !== forward ? "nextSibling" : "previousSibling", parent = elem.parentNode, name = ofType && elem.nodeName.toLowerCase(), useCache = !xml && !ofType; if ( parent ) { // :(first|last|only)-(child|of-type) if ( simple ) { while ( dir ) { node = elem; while ( (node = node[ dir ]) ) { if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) { return false; } } // Reverse direction for :only-* (if we haven't yet done so) start = dir = type === "only" && !start && "nextSibling"; } return true; } start = [ forward ? parent.firstChild : parent.lastChild ]; // non-xml :nth-child(...) stores cache data on `parent` if ( forward && useCache ) { // Seek `elem` from a previously-cached index outerCache = parent[ expando ] || (parent[ expando ] = {}); cache = outerCache[ type ] || []; nodeIndex = cache[0] === dirruns && cache[1]; diff = cache[0] === dirruns && cache[2]; node = nodeIndex && parent.childNodes[ nodeIndex ]; while ( (node = ++nodeIndex && node && node[ dir ] || // Fallback to seeking `elem` from the start (diff = nodeIndex = 0) || start.pop()) ) { // When found, cache indexes on `parent` and break if ( node.nodeType === 1 && ++diff && node === elem ) { outerCache[ type ] = [ dirruns, nodeIndex, diff ]; break; } } // Use previously-cached element index if available } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) { diff = cache[1]; // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...) } else { // Use the same loop as above to seek `elem` from the start while ( (node = ++nodeIndex && node && node[ dir ] || (diff = nodeIndex = 0) || start.pop()) ) { if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) { // Cache the index of each encountered element if ( useCache ) { (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ]; } if ( node === elem ) { break; } } } } // Incorporate the offset, then check against cycle size diff -= last; return diff === first || ( diff % first === 0 && diff / first >= 0 ); } }; }, "PSEUDO": function( pseudo, argument ) { // pseudo-class names are case-insensitive // http://www.w3.org/TR/selectors/#pseudo-classes // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters // Remember that setFilters inherits from pseudos var args, fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || Sizzle.error( "unsupported pseudo: " + pseudo ); // The user may use createPseudo to indicate that // arguments are needed to create the filter function // just as Sizzle does if ( fn[ expando ] ) { return fn( argument ); } // But maintain support for old signatures if ( fn.length > 1 ) { args = [ pseudo, pseudo, "", argument ]; return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? markFunction(function( seed, matches ) { var idx, matched = fn( seed, argument ), i = matched.length; while ( i-- ) { idx = indexOf.call( seed, matched[i] ); seed[ idx ] = !( matches[ idx ] = matched[i] ); } }) : function( elem ) { return fn( elem, 0, args ); }; } return fn; } }, pseudos: { // Potentially complex pseudos "not": markFunction(function( selector ) { // Trim the selector passed to compile // to avoid treating leading and trailing // spaces as combinators var input = [], results = [], matcher = compile( selector.replace( rtrim, "$1" ) ); return matcher[ expando ] ? markFunction(function( seed, matches, context, xml ) { var elem, unmatched = matcher( seed, null, xml, [] ), i = seed.length; // Match elements unmatched by `matcher` while ( i-- ) { if ( (elem = unmatched[i]) ) { seed[i] = !(matches[i] = elem); } } }) : function( elem, context, xml ) { input[0] = elem; matcher( input, null, xml, results ); return !results.pop(); }; }), "has": markFunction(function( selector ) { return function( elem ) { return Sizzle( selector, elem ).length > 0; }; }), "contains": markFunction(function( text ) { return function( elem ) { return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; }; }), // "Whether an element is represented by a :lang() selector // is based solely on the element's language value // being equal to the identifier C, // or beginning with the identifier C immediately followed by "-". // The matching of C against the element's language value is performed case-insensitively. // The identifier C does not have to be a valid language name." // http://www.w3.org/TR/selectors/#lang-pseudo "lang": markFunction( function( lang ) { // lang value must be a valid identifider if ( !ridentifier.test(lang || "") ) { Sizzle.error( "unsupported lang: " + lang ); } lang = lang.replace( runescape, funescape ).toLowerCase(); return function( elem ) { var elemLang; do { if ( (elemLang = documentIsXML ? elem.getAttribute("xml:lang") || elem.getAttribute("lang") : elem.lang) ) { elemLang = elemLang.toLowerCase(); return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; } } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); return false; }; }), // Miscellaneous "target": function( elem ) { var hash = window.location && window.location.hash; return hash && hash.slice( 1 ) === elem.id; }, "root": function( elem ) { return elem === docElem; }, "focus": function( elem ) { return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); }, // Boolean properties "enabled": function( elem ) { return elem.disabled === false; }, "disabled": function( elem ) { return elem.disabled === true; }, "checked": function( elem ) { // In CSS3, :checked should return both checked and selected elements // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked var nodeName = elem.nodeName.toLowerCase(); return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); }, "selected": function( elem ) { // Accessing this property makes selected-by-default // options in Safari work properly if ( elem.parentNode ) { elem.parentNode.selectedIndex; } return elem.selected === true; }, // Contents "empty": function( elem ) { // http://www.w3.org/TR/selectors/#empty-pseudo // :empty is only affected by element nodes and content nodes(including text(3), cdata(4)), // not comment, processing instructions, or others // Thanks to Diego Perini for the nodeName shortcut // Greater than "@" means alpha characters (specifically not starting with "#" or "?") for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { if ( elem.nodeName > "@" || elem.nodeType === 3 || elem.nodeType === 4 ) { return false; } } return true; }, "parent": function( elem ) { return !Expr.pseudos["empty"]( elem ); }, // Element/input types "header": function( elem ) { return rheader.test( elem.nodeName ); }, "input": function( elem ) { return rinputs.test( elem.nodeName ); }, "button": function( elem ) { var name = elem.nodeName.toLowerCase(); return name === "input" && elem.type === "button" || name === "button"; }, "text": function( elem ) { var attr; // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) // use getAttribute instead to test this case return elem.nodeName.toLowerCase() === "input" && elem.type === "text" && ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === elem.type ); }, // Position-in-collection "first": createPositionalPseudo(function() { return [ 0 ]; }), "last": createPositionalPseudo(function( matchIndexes, length ) { return [ length - 1 ]; }), "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { return [ argument < 0 ? argument + length : argument ]; }), "even": createPositionalPseudo(function( matchIndexes, length ) { var i = 0; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "odd": createPositionalPseudo(function( matchIndexes, length ) { var i = 1; for ( ; i < length; i += 2 ) { matchIndexes.push( i ); } return matchIndexes; }), "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; --i >= 0; ) { matchIndexes.push( i ); } return matchIndexes; }), "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { var i = argument < 0 ? argument + length : argument; for ( ; ++i < length; ) { matchIndexes.push( i ); } return matchIndexes; }) } }; // Add button/input type pseudos for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { Expr.pseudos[ i ] = createInputPseudo( i ); } for ( i in { submit: true, reset: true } ) { Expr.pseudos[ i ] = createButtonPseudo( i ); } function tokenize( selector, parseOnly ) { var matched, match, tokens, type, soFar, groups, preFilters, cached = tokenCache[ selector + " " ]; if ( cached ) { return parseOnly ? 0 : cached.slice( 0 ); } soFar = selector; groups = []; preFilters = Expr.preFilter; while ( soFar ) { // Comma and first run if ( !matched || (match = rcomma.exec( soFar )) ) { if ( match ) { // Don't consume trailing commas as valid soFar = soFar.slice( match[0].length ) || soFar; } groups.push( tokens = [] ); } matched = false; // Combinators if ( (match = rcombinators.exec( soFar )) ) { matched = match.shift(); tokens.push( { value: matched, // Cast descendant combinators to space type: match[0].replace( rtrim, " " ) } ); soFar = soFar.slice( matched.length ); } // Filters for ( type in Expr.filter ) { if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || (match = preFilters[ type ]( match ))) ) { matched = match.shift(); tokens.push( { value: matched, type: type, matches: match } ); soFar = soFar.slice( matched.length ); } } if ( !matched ) { break; } } // Return the length of the invalid excess // if we're just parsing // Otherwise, throw an error or return tokens return parseOnly ? soFar.length : soFar ? Sizzle.error( selector ) : // Cache the tokens tokenCache( selector, groups ).slice( 0 ); } function toSelector( tokens ) { var i = 0, len = tokens.length, selector = ""; for ( ; i < len; i++ ) { selector += tokens[i].value; } return selector; } function addCombinator( matcher, combinator, base ) { var dir = combinator.dir, checkNonElements = base && dir === "parentNode", doneName = done++; return combinator.first ? // Check against closest ancestor/preceding element function( elem, context, xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { return matcher( elem, context, xml ); } } } : // Check against all ancestor/preceding elements function( elem, context, xml ) { var data, cache, outerCache, dirkey = dirruns + " " + doneName; // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching if ( xml ) { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { if ( matcher( elem, context, xml ) ) { return true; } } } } else { while ( (elem = elem[ dir ]) ) { if ( elem.nodeType === 1 || checkNonElements ) { outerCache = elem[ expando ] || (elem[ expando ] = {}); if ( (cache = outerCache[ dir ]) && cache[0] === dirkey ) { if ( (data = cache[1]) === true || data === cachedruns ) { return data === true; } } else { cache = outerCache[ dir ] = [ dirkey ]; cache[1] = matcher( elem, context, xml ) || cachedruns; if ( cache[1] === true ) { return true; } } } } } }; } function elementMatcher( matchers ) { return matchers.length > 1 ? function( elem, context, xml ) { var i = matchers.length; while ( i-- ) { if ( !matchers[i]( elem, context, xml ) ) { return false; } } return true; } : matchers[0]; } function condense( unmatched, map, filter, context, xml ) { var elem, newUnmatched = [], i = 0, len = unmatched.length, mapped = map != null; for ( ; i < len; i++ ) { if ( (elem = unmatched[i]) ) { if ( !filter || filter( elem, context, xml ) ) { newUnmatched.push( elem ); if ( mapped ) { map.push( i ); } } } } return newUnmatched; } function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { if ( postFilter && !postFilter[ expando ] ) { postFilter = setMatcher( postFilter ); } if ( postFinder && !postFinder[ expando ] ) { postFinder = setMatcher( postFinder, postSelector ); } return markFunction(function( seed, results, context, xml ) { var temp, i, elem, preMap = [], postMap = [], preexisting = results.length, // Get initial elements from seed or context elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), // Prefilter to get matcher input, preserving a map for seed-results synchronization matcherIn = preFilter && ( seed || !selector ) ? condense( elems, preMap, preFilter, context, xml ) : elems, matcherOut = matcher ? // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, postFinder || ( seed ? preFilter : preexisting || postFilter ) ? // ...intermediate processing is necessary [] : // ...otherwise use results directly results : matcherIn; // Find primary matches if ( matcher ) { matcher( matcherIn, matcherOut, context, xml ); } // Apply postFilter if ( postFilter ) { temp = condense( matcherOut, postMap ); postFilter( temp, [], context, xml ); // Un-match failing elements by moving them back to matcherIn i = temp.length; while ( i-- ) { if ( (elem = temp[i]) ) { matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); } } } if ( seed ) { if ( postFinder || preFilter ) { if ( postFinder ) { // Get the final matcherOut by condensing this intermediate into postFinder contexts temp = []; i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) ) { // Restore matcherIn since elem is not yet a final match temp.push( (matcherIn[i] = elem) ); } } postFinder( null, (matcherOut = []), temp, xml ); } // Move matched elements from seed to results to keep them synchronized i = matcherOut.length; while ( i-- ) { if ( (elem = matcherOut[i]) && (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) { seed[temp] = !(results[temp] = elem); } } } // Add elements to results, through postFinder if defined } else { matcherOut = condense( matcherOut === results ? matcherOut.splice( preexisting, matcherOut.length ) : matcherOut ); if ( postFinder ) { postFinder( null, results, matcherOut, xml ); } else { push.apply( results, matcherOut ); } } }); } function matcherFromTokens( tokens ) { var checkContext, matcher, j, len = tokens.length, leadingRelative = Expr.relative[ tokens[0].type ], implicitRelative = leadingRelative || Expr.relative[" "], i = leadingRelative ? 1 : 0, // The foundational matcher ensures that elements are reachable from top-level context(s) matchContext = addCombinator( function( elem ) { return elem === checkContext; }, implicitRelative, true ), matchAnyContext = addCombinator( function( elem ) { return indexOf.call( checkContext, elem ) > -1; }, implicitRelative, true ), matchers = [ function( elem, context, xml ) { return ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( (checkContext = context).nodeType ? matchContext( elem, context, xml ) : matchAnyContext( elem, context, xml ) ); } ]; for ( ; i < len; i++ ) { if ( (matcher = Expr.relative[ tokens[i].type ]) ) { matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; } else { matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); // Return special upon seeing a positional matcher if ( matcher[ expando ] ) { // Find the next relative operator (if any) for proper handling j = ++i; for ( ; j < len; j++ ) { if ( Expr.relative[ tokens[j].type ] ) { break; } } return setMatcher( i > 1 && elementMatcher( matchers ), i > 1 && toSelector( tokens.slice( 0, i - 1 ) ).replace( rtrim, "$1" ), matcher, i < j && matcherFromTokens( tokens.slice( i, j ) ), j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), j < len && toSelector( tokens ) ); } matchers.push( matcher ); } } return elementMatcher( matchers ); } function matcherFromGroupMatchers( elementMatchers, setMatchers ) { // A counter to specify which element is currently being matched var matcherCachedRuns = 0, bySet = setMatchers.length > 0, byElement = elementMatchers.length > 0, superMatcher = function( seed, context, xml, results, expandContext ) { var elem, j, matcher, setMatched = [], matchedCount = 0, i = "0", unmatched = seed && [], outermost = expandContext != null, contextBackup = outermostContext, // We must always have either seed elements or context elems = seed || byElement && Expr.find["TAG"]( "*", expandContext && context.parentNode || context ), // Use integer dirruns iff this is the outermost matcher dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1); if ( outermost ) { outermostContext = context !== document && context; cachedruns = matcherCachedRuns; } // Add elements passing elementMatchers directly to results // Keep `i` a string if there are no elements so `matchedCount` will be "00" below for ( ; (elem = elems[i]) != null; i++ ) { if ( byElement && elem ) { j = 0; while ( (matcher = elementMatchers[j++]) ) { if ( matcher( elem, context, xml ) ) { results.push( elem ); break; } } if ( outermost ) { dirruns = dirrunsUnique; cachedruns = ++matcherCachedRuns; } } // Track unmatched elements for set filters if ( bySet ) { // They will have gone through all possible matchers if ( (elem = !matcher && elem) ) { matchedCount--; } // Lengthen the array for every element, matched or not if ( seed ) { unmatched.push( elem ); } } } // Apply set filters to unmatched elements matchedCount += i; if ( bySet && i !== matchedCount ) { j = 0; while ( (matcher = setMatchers[j++]) ) { matcher( unmatched, setMatched, context, xml ); } if ( seed ) { // Reintegrate element matches to eliminate the need for sorting if ( matchedCount > 0 ) { while ( i-- ) { if ( !(unmatched[i] || setMatched[i]) ) { setMatched[i] = pop.call( results ); } } } // Discard index placeholder values to get only actual matches setMatched = condense( setMatched ); } // Add matches to results push.apply( results, setMatched ); // Seedless set matches succeeding multiple successful matchers stipulate sorting if ( outermost && !seed && setMatched.length > 0 && ( matchedCount + setMatchers.length ) > 1 ) { Sizzle.uniqueSort( results ); } } // Override manipulation of globals by nested matchers if ( outermost ) { dirruns = dirrunsUnique; outermostContext = contextBackup; } return unmatched; }; return bySet ? markFunction( superMatcher ) : superMatcher; } compile = Sizzle.compile = function( selector, group /* Internal Use Only */ ) { var i, setMatchers = [], elementMatchers = [], cached = compilerCache[ selector + " " ]; if ( !cached ) { // Generate a function of recursive functions that can be used to check each element if ( !group ) { group = tokenize( selector ); } i = group.length; while ( i-- ) { cached = matcherFromTokens( group[i] ); if ( cached[ expando ] ) { setMatchers.push( cached ); } else { elementMatchers.push( cached ); } } // Cache the compiled function cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); } return cached; }; function multipleContexts( selector, contexts, results ) { var i = 0, len = contexts.length; for ( ; i < len; i++ ) { Sizzle( selector, contexts[i], results ); } return results; } function select( selector, context, results, seed ) { var i, tokens, token, type, find, match = tokenize( selector ); if ( !seed ) { // Try to minimize operations if there is only one group if ( match.length === 1 ) { // Take a shortcut and set the context if the root selector is an ID tokens = match[0] = match[0].slice( 0 ); if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && context.nodeType === 9 && !documentIsXML && Expr.relative[ tokens[1].type ] ) { context = Expr.find["ID"]( token.matches[0].replace( runescape, funescape ), context )[0]; if ( !context ) { return results; } selector = selector.slice( tokens.shift().value.length ); } // Fetch a seed set for right-to-left matching i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; while ( i-- ) { token = tokens[i]; // Abort if we hit a combinator if ( Expr.relative[ (type = token.type) ] ) { break; } if ( (find = Expr.find[ type ]) ) { // Search, expanding context for leading sibling combinators if ( (seed = find( token.matches[0].replace( runescape, funescape ), rsibling.test( tokens[0].type ) && context.parentNode || context )) ) { // If seed is empty or no tokens remain, we can return early tokens.splice( i, 1 ); selector = seed.length && toSelector( tokens ); if ( !selector ) { push.apply( results, slice.call( seed, 0 ) ); return results; } break; } } } } } // Compile and execute a filtering function // Provide `match` to avoid retokenization if we modified the selector above compile( selector, match )( seed, context, documentIsXML, results, rsibling.test( selector ) ); return results; } // Deprecated Expr.pseudos["nth"] = Expr.pseudos["eq"]; // Easy API for creating new setFilters function setFilters() {} Expr.filters = setFilters.prototype = Expr.pseudos; Expr.setFilters = new setFilters(); // Initialize with the default document setDocument(); // Override sizzle attribute retrieval Sizzle.attr = jQuery.attr; jQuery.find = Sizzle; jQuery.expr = Sizzle.selectors; jQuery.expr[":"] = jQuery.expr.pseudos; jQuery.unique = Sizzle.uniqueSort; jQuery.text = Sizzle.getText; jQuery.isXMLDoc = Sizzle.isXML; jQuery.contains = Sizzle.contains; })( window ); var runtil = /Until$/, rparentsprev = /^(?:parents|prev(?:Until|All))/, isSimple = /^.[^:#\[\.,]*$/, rneedsContext = jQuery.expr.match.needsContext, // methods guaranteed to produce a unique set when starting from a unique set guaranteedUnique = { children: true, contents: true, next: true, prev: true }; jQuery.fn.extend({ find: function( selector ) { var i, ret, self, len = this.length; if ( typeof selector !== "string" ) { self = this; return this.pushStack( jQuery( selector ).filter(function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( self[ i ], this ) ) { return true; } } }) ); } ret = []; for ( i = 0; i < len; i++ ) { jQuery.find( selector, this[ i ], ret ); } // Needed because $( selector, context ) becomes $( context ).find( selector ) ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); ret.selector = ( this.selector ? this.selector + " " : "" ) + selector; return ret; }, has: function( target ) { var i, targets = jQuery( target, this ), len = targets.length; return this.filter(function() { for ( i = 0; i < len; i++ ) { if ( jQuery.contains( this, targets[i] ) ) { return true; } } }); }, not: function( selector ) { return this.pushStack( winnow(this, selector, false) ); }, filter: function( selector ) { return this.pushStack( winnow(this, selector, true) ); }, is: function( selector ) { return !!selector && ( typeof selector === "string" ? // If this is a positional/relative selector, check membership in the returned set // so $("p:first").is("p:last") won't return true for a doc with two "p". rneedsContext.test( selector ) ? jQuery( selector, this.context ).index( this[0] ) >= 0 : jQuery.filter( selector, this ).length > 0 : this.filter( selector ).length > 0 ); }, closest: function( selectors, context ) { var cur, i = 0, l = this.length, ret = [], pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? jQuery( selectors, context || this.context ) : 0; for ( ; i < l; i++ ) { cur = this[i]; while ( cur && cur.ownerDocument && cur !== context && cur.nodeType !== 11 ) { if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) { ret.push( cur ); break; } cur = cur.parentNode; } } return this.pushStack( ret.length > 1 ? jQuery.unique( ret ) : ret ); }, // Determine the position of an element within // the matched set of elements index: function( elem ) { // No argument, return index in parent if ( !elem ) { return ( this[0] && this[0].parentNode ) ? this.first().prevAll().length : -1; } // index in selector if ( typeof elem === "string" ) { return jQuery.inArray( this[0], jQuery( elem ) ); } // Locate the position of the desired element return jQuery.inArray( // If it receives a jQuery object, the first element is used elem.jquery ? elem[0] : elem, this ); }, add: function( selector, context ) { var set = typeof selector === "string" ? jQuery( selector, context ) : jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ), all = jQuery.merge( this.get(), set ); return this.pushStack( jQuery.unique(all) ); }, addBack: function( selector ) { return this.add( selector == null ? this.prevObject : this.prevObject.filter(selector) ); } }); jQuery.fn.andSelf = jQuery.fn.addBack; function sibling( cur, dir ) { do { cur = cur[ dir ]; } while ( cur && cur.nodeType !== 1 ); return cur; } jQuery.each({ parent: function( elem ) { var parent = elem.parentNode; return parent && parent.nodeType !== 11 ? parent : null; }, parents: function( elem ) { return jQuery.dir( elem, "parentNode" ); }, parentsUntil: function( elem, i, until ) { return jQuery.dir( elem, "parentNode", until ); }, next: function( elem ) { return sibling( elem, "nextSibling" ); }, prev: function( elem ) { return sibling( elem, "previousSibling" ); }, nextAll: function( elem ) { return jQuery.dir( elem, "nextSibling" ); }, prevAll: function( elem ) { return jQuery.dir( elem, "previousSibling" ); }, nextUntil: function( elem, i, until ) { return jQuery.dir( elem, "nextSibling", until ); }, prevUntil: function( elem, i, until ) { return jQuery.dir( elem, "previousSibling", until ); }, siblings: function( elem ) { return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem ); }, children: function( elem ) { return jQuery.sibling( elem.firstChild ); }, contents: function( elem ) { return jQuery.nodeName( elem, "iframe" ) ? elem.contentDocument || elem.contentWindow.document : jQuery.merge( [], elem.childNodes ); } }, function( name, fn ) { jQuery.fn[ name ] = function( until, selector ) { var ret = jQuery.map( this, fn, until ); if ( !runtil.test( name ) ) { selector = until; } if ( selector && typeof selector === "string" ) { ret = jQuery.filter( selector, ret ); } ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret; if ( this.length > 1 && rparentsprev.test( name ) ) { ret = ret.reverse(); } return this.pushStack( ret ); }; }); jQuery.extend({ filter: function( expr, elems, not ) { if ( not ) { expr = ":not(" + expr + ")"; } return elems.length === 1 ? jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] : jQuery.find.matches(expr, elems); }, dir: function( elem, dir, until ) { var matched = [], cur = elem[ dir ]; while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { if ( cur.nodeType === 1 ) { matched.push( cur ); } cur = cur[dir]; } return matched; }, sibling: function( n, elem ) { var r = []; for ( ; n; n = n.nextSibling ) { if ( n.nodeType === 1 && n !== elem ) { r.push( n ); } } return r; } }); // Implement the identical functionality for filter and not function winnow( elements, qualifier, keep ) { // Can't pass null or undefined to indexOf in Firefox 4 // Set to 0 to skip string check qualifier = qualifier || 0; if ( jQuery.isFunction( qualifier ) ) { return jQuery.grep(elements, function( elem, i ) { var retVal = !!qualifier.call( elem, i, elem ); return retVal === keep; }); } else if ( qualifier.nodeType ) { return jQuery.grep(elements, function( elem ) { return ( elem === qualifier ) === keep; }); } else if ( typeof qualifier === "string" ) { var filtered = jQuery.grep(elements, function( elem ) { return elem.nodeType === 1; }); if ( isSimple.test( qualifier ) ) { return jQuery.filter(qualifier, filtered, !keep); } else { qualifier = jQuery.filter( qualifier, filtered ); } } return jQuery.grep(elements, function( elem ) { return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep; }); } function createSafeFragment( document ) { var list = nodeNames.split( "|" ), safeFrag = document.createDocumentFragment(); if ( safeFrag.createElement ) { while ( list.length ) { safeFrag.createElement( list.pop() ); } } return safeFrag; } var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" + "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"), rleadingWhitespace = /^\s+/, rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, rtagName = /<([\w:]+)/, rtbody = /<tbody/i, rhtml = /<|&#?\w+;/, rnoInnerhtml = /<(?:script|style|link)/i, manipulation_rcheckableType = /^(?:checkbox|radio)$/i, // checked="checked" or checked rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i, rscriptType = /^$|\/(?:java|ecma)script/i, rscriptTypeMasked = /^true\/(.*)/, rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, // We have to close these tags to support XHTML (#13200) wrapMap = { option: [ 1, "<select multiple='multiple'>", "</select>" ], legend: [ 1, "<fieldset>", "</fieldset>" ], area: [ 1, "<map>", "</map>" ], param: [ 1, "<object>", "</object>" ], thead: [ 1, "<table>", "</table>" ], tr: [ 2, "<table><tbody>", "</tbody></table>" ], col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ], td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ], // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, // unless wrapped in a div with non-breaking characters in front of it. _default: jQuery.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ] }, safeFragment = createSafeFragment( document ), fragmentDiv = safeFragment.appendChild( document.createElement("div") ); wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; jQuery.fn.extend({ text: function( value ) { return jQuery.access( this, function( value ) { return value === undefined ? jQuery.text( this ) : this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) ); }, null, value, arguments.length ); }, wrapAll: function( html ) { if ( jQuery.isFunction( html ) ) { return this.each(function(i) { jQuery(this).wrapAll( html.call(this, i) ); }); } if ( this[0] ) { // The elements to wrap the target around var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true); if ( this[0].parentNode ) { wrap.insertBefore( this[0] ); } wrap.map(function() { var elem = this; while ( elem.firstChild && elem.firstChild.nodeType === 1 ) { elem = elem.firstChild; } return elem; }).append( this ); } return this; }, wrapInner: function( html ) { if ( jQuery.isFunction( html ) ) { return this.each(function(i) { jQuery(this).wrapInner( html.call(this, i) ); }); } return this.each(function() { var self = jQuery( this ), contents = self.contents(); if ( contents.length ) { contents.wrapAll( html ); } else { self.append( html ); } }); }, wrap: function( html ) { var isFunction = jQuery.isFunction( html ); return this.each(function(i) { jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html ); }); }, unwrap: function() { return this.parent().each(function() { if ( !jQuery.nodeName( this, "body" ) ) { jQuery( this ).replaceWith( this.childNodes ); } }).end(); }, append: function() { return this.domManip(arguments, true, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.appendChild( elem ); } }); }, prepend: function() { return this.domManip(arguments, true, function( elem ) { if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { this.insertBefore( elem, this.firstChild ); } }); }, before: function() { return this.domManip( arguments, false, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this ); } }); }, after: function() { return this.domManip( arguments, false, function( elem ) { if ( this.parentNode ) { this.parentNode.insertBefore( elem, this.nextSibling ); } }); }, // keepData is for internal use only--do not document remove: function( selector, keepData ) { var elem, i = 0; for ( ; (elem = this[i]) != null; i++ ) { if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) { if ( !keepData && elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem ) ); } if ( elem.parentNode ) { if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) { setGlobalEval( getAll( elem, "script" ) ); } elem.parentNode.removeChild( elem ); } } } return this; }, empty: function() { var elem, i = 0; for ( ; (elem = this[i]) != null; i++ ) { // Remove element nodes and prevent memory leaks if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); } // Remove any remaining nodes while ( elem.firstChild ) { elem.removeChild( elem.firstChild ); } // If this is a select, ensure that it displays empty (#12336) // Support: IE<9 if ( elem.options && jQuery.nodeName( elem, "select" ) ) { elem.options.length = 0; } } return this; }, clone: function( dataAndEvents, deepDataAndEvents ) { dataAndEvents = dataAndEvents == null ? false : dataAndEvents; deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; return this.map( function () { return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); }); }, html: function( value ) { return jQuery.access( this, function( value ) { var elem = this[0] || {}, i = 0, l = this.length; if ( value === undefined ) { return elem.nodeType === 1 ? elem.innerHTML.replace( rinlinejQuery, "" ) : undefined; } // See if we can take a shortcut and just use innerHTML if ( typeof value === "string" && !rnoInnerhtml.test( value ) && ( jQuery.support.htmlSerialize || !rnoshimcache.test( value ) ) && ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) { value = value.replace( rxhtmlTag, "<$1></$2>" ); try { for (; i < l; i++ ) { // Remove element nodes and prevent memory leaks elem = this[i] || {}; if ( elem.nodeType === 1 ) { jQuery.cleanData( getAll( elem, false ) ); elem.innerHTML = value; } } elem = 0; // If using innerHTML throws an exception, use the fallback method } catch(e) {} } if ( elem ) { this.empty().append( value ); } }, null, value, arguments.length ); }, replaceWith: function( value ) { var isFunc = jQuery.isFunction( value ); // Make sure that the elements are removed from the DOM before they are inserted // this can help fix replacing a parent with child elements if ( !isFunc && typeof value !== "string" ) { value = jQuery( value ).not( this ).detach(); } return this.domManip( [ value ], true, function( elem ) { var next = this.nextSibling, parent = this.parentNode; if ( parent ) { jQuery( this ).remove(); parent.insertBefore( elem, next ); } }); }, detach: function( selector ) { return this.remove( selector, true ); }, domManip: function( args, table, callback ) { // Flatten any nested arrays args = core_concat.apply( [], args ); var first, node, hasScripts, scripts, doc, fragment, i = 0, l = this.length, set = this, iNoClone = l - 1, value = args[0], isFunction = jQuery.isFunction( value ); // We can't cloneNode fragments that contain checked, in WebKit if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) { return this.each(function( index ) { var self = set.eq( index ); if ( isFunction ) { args[0] = value.call( this, index, table ? self.html() : undefined ); } self.domManip( args, table, callback ); }); } if ( l ) { fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this ); first = fragment.firstChild; if ( fragment.childNodes.length === 1 ) { fragment = first; } if ( first ) { table = table && jQuery.nodeName( first, "tr" ); scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); hasScripts = scripts.length; // Use the original fragment for the last item instead of the first because it can end up // being emptied incorrectly in certain situations (#8070). for ( ; i < l; i++ ) { node = fragment; if ( i !== iNoClone ) { node = jQuery.clone( node, true, true ); // Keep references to cloned scripts for later restoration if ( hasScripts ) { jQuery.merge( scripts, getAll( node, "script" ) ); } } callback.call( table && jQuery.nodeName( this[i], "table" ) ? findOrAppend( this[i], "tbody" ) : this[i], node, i ); } if ( hasScripts ) { doc = scripts[ scripts.length - 1 ].ownerDocument; // Reenable scripts jQuery.map( scripts, restoreScript ); // Evaluate executable scripts on first document insertion for ( i = 0; i < hasScripts; i++ ) { node = scripts[ i ]; if ( rscriptType.test( node.type || "" ) && !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) { if ( node.src ) { // Hope ajax is available... jQuery.ajax({ url: node.src, type: "GET", dataType: "script", async: false, global: false, "throws": true }); } else { jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) ); } } } } // Fix #11809: Avoid leaking memory fragment = first = null; } } return this; } }); function findOrAppend( elem, tag ) { return elem.getElementsByTagName( tag )[0] || elem.appendChild( elem.ownerDocument.createElement( tag ) ); } // Replace/restore the type attribute of script elements for safe DOM manipulation function disableScript( elem ) { var attr = elem.getAttributeNode("type"); elem.type = ( attr && attr.specified ) + "/" + elem.type; return elem; } function restoreScript( elem ) { var match = rscriptTypeMasked.exec( elem.type ); if ( match ) { elem.type = match[1]; } else { elem.removeAttribute("type"); } return elem; } // Mark scripts as having already been evaluated function setGlobalEval( elems, refElements ) { var elem, i = 0; for ( ; (elem = elems[i]) != null; i++ ) { jQuery._data( elem, "globalEval", !refElements || jQuery._data( refElements[i], "globalEval" ) ); } } function cloneCopyEvent( src, dest ) { if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { return; } var type, i, l, oldData = jQuery._data( src ), curData = jQuery._data( dest, oldData ), events = oldData.events; if ( events ) { delete curData.handle; curData.events = {}; for ( type in events ) { for ( i = 0, l = events[ type ].length; i < l; i++ ) { jQuery.event.add( dest, type, events[ type ][ i ] ); } } } // make the cloned public data object a copy from the original if ( curData.data ) { curData.data = jQuery.extend( {}, curData.data ); } } function fixCloneNodeIssues( src, dest ) { var nodeName, e, data; // We do not need to do anything for non-Elements if ( dest.nodeType !== 1 ) { return; } nodeName = dest.nodeName.toLowerCase(); // IE6-8 copies events bound via attachEvent when using cloneNode. if ( !jQuery.support.noCloneEvent && dest[ jQuery.expando ] ) { data = jQuery._data( dest ); for ( e in data.events ) { jQuery.removeEvent( dest, e, data.handle ); } // Event data gets referenced instead of copied if the expando gets copied too dest.removeAttribute( jQuery.expando ); } // IE blanks contents when cloning scripts, and tries to evaluate newly-set text if ( nodeName === "script" && dest.text !== src.text ) { disableScript( dest ).text = src.text; restoreScript( dest ); // IE6-10 improperly clones children of object elements using classid. // IE10 throws NoModificationAllowedError if parent is null, #12132. } else if ( nodeName === "object" ) { if ( dest.parentNode ) { dest.outerHTML = src.outerHTML; } // This path appears unavoidable for IE9. When cloning an object // element in IE9, the outerHTML strategy above is not sufficient. // If the src has innerHTML and the destination does not, // copy the src.innerHTML into the dest.innerHTML. #10324 if ( jQuery.support.html5Clone && ( src.innerHTML && !jQuery.trim(dest.innerHTML) ) ) { dest.innerHTML = src.innerHTML; } } else if ( nodeName === "input" && manipulation_rcheckableType.test( src.type ) ) { // IE6-8 fails to persist the checked state of a cloned checkbox // or radio button. Worse, IE6-7 fail to give the cloned element // a checked appearance if the defaultChecked value isn't also set dest.defaultChecked = dest.checked = src.checked; // IE6-7 get confused and end up setting the value of a cloned // checkbox/radio button to an empty string instead of "on" if ( dest.value !== src.value ) { dest.value = src.value; } // IE6-8 fails to return the selected option to the default selected // state when cloning options } else if ( nodeName === "option" ) { dest.defaultSelected = dest.selected = src.defaultSelected; // IE6-8 fails to set the defaultValue to the correct value when // cloning other types of input fields } else if ( nodeName === "input" || nodeName === "textarea" ) { dest.defaultValue = src.defaultValue; } } jQuery.each({ appendTo: "append", prependTo: "prepend", insertBefore: "before", insertAfter: "after", replaceAll: "replaceWith" }, function( name, original ) { jQuery.fn[ name ] = function( selector ) { var elems, i = 0, ret = [], insert = jQuery( selector ), last = insert.length - 1; for ( ; i <= last; i++ ) { elems = i === last ? this : this.clone(true); jQuery( insert[i] )[ original ]( elems ); // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() core_push.apply( ret, elems.get() ); } return this.pushStack( ret ); }; }); function getAll( context, tag ) { var elems, elem, i = 0, found = typeof context.getElementsByTagName !== core_strundefined ? context.getElementsByTagName( tag || "*" ) : typeof context.querySelectorAll !== core_strundefined ? context.querySelectorAll( tag || "*" ) : undefined; if ( !found ) { for ( found = [], elems = context.childNodes || context; (elem = elems[i]) != null; i++ ) { if ( !tag || jQuery.nodeName( elem, tag ) ) { found.push( elem ); } else { jQuery.merge( found, getAll( elem, tag ) ); } } } return tag === undefined || tag && jQuery.nodeName( context, tag ) ? jQuery.merge( [ context ], found ) : found; } // Used in buildFragment, fixes the defaultChecked property function fixDefaultChecked( elem ) { if ( manipulation_rcheckableType.test( elem.type ) ) { elem.defaultChecked = elem.checked; } } jQuery.extend({ clone: function( elem, dataAndEvents, deepDataAndEvents ) { var destElements, node, clone, i, srcElements, inPage = jQuery.contains( elem.ownerDocument, elem ); if ( jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { clone = elem.cloneNode( true ); // IE<=8 does not properly clone detached, unknown element nodes } else { fragmentDiv.innerHTML = elem.outerHTML; fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); } if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) && (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) { // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 destElements = getAll( clone ); srcElements = getAll( elem ); // Fix all IE cloning issues for ( i = 0; (node = srcElements[i]) != null; ++i ) { // Ensure that the destination node is not null; Fixes #9587 if ( destElements[i] ) { fixCloneNodeIssues( node, destElements[i] ); } } } // Copy the events from the original to the clone if ( dataAndEvents ) { if ( deepDataAndEvents ) { srcElements = srcElements || getAll( elem ); destElements = destElements || getAll( clone ); for ( i = 0; (node = srcElements[i]) != null; i++ ) { cloneCopyEvent( node, destElements[i] ); } } else { cloneCopyEvent( elem, clone ); } } // Preserve script evaluation history destElements = getAll( clone, "script" ); if ( destElements.length > 0 ) { setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); } destElements = srcElements = node = null; // Return the cloned set return clone; }, buildFragment: function( elems, context, scripts, selection ) { var j, elem, contains, tmp, tag, tbody, wrap, l = elems.length, // Ensure a safe fragment safe = createSafeFragment( context ), nodes = [], i = 0; for ( ; i < l; i++ ) { elem = elems[ i ]; if ( elem || elem === 0 ) { // Add nodes directly if ( jQuery.type( elem ) === "object" ) { jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); // Convert non-html into a text node } else if ( !rhtml.test( elem ) ) { nodes.push( context.createTextNode( elem ) ); // Convert html into DOM nodes } else { tmp = tmp || safe.appendChild( context.createElement("div") ); // Deserialize a standard representation tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(); wrap = wrapMap[ tag ] || wrapMap._default; tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2]; // Descend through wrappers to the right content j = wrap[0]; while ( j-- ) { tmp = tmp.lastChild; } // Manually add leading whitespace removed by IE if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { nodes.push( context.createTextNode( rleadingWhitespace.exec( elem )[0] ) ); } // Remove IE's autoinserted <tbody> from table fragments if ( !jQuery.support.tbody ) { // String was a <table>, *may* have spurious <tbody> elem = tag === "table" && !rtbody.test( elem ) ? tmp.firstChild : // String was a bare <thead> or <tfoot> wrap[1] === "<table>" && !rtbody.test( elem ) ? tmp : 0; j = elem && elem.childNodes.length; while ( j-- ) { if ( jQuery.nodeName( (tbody = elem.childNodes[j]), "tbody" ) && !tbody.childNodes.length ) { elem.removeChild( tbody ); } } } jQuery.merge( nodes, tmp.childNodes ); // Fix #12392 for WebKit and IE > 9 tmp.textContent = ""; // Fix #12392 for oldIE while ( tmp.firstChild ) { tmp.removeChild( tmp.firstChild ); } // Remember the top-level container for proper cleanup tmp = safe.lastChild; } } } // Fix #11356: Clear elements from fragment if ( tmp ) { safe.removeChild( tmp ); } // Reset defaultChecked for any radios and checkboxes // about to be appended to the DOM in IE 6/7 (#8060) if ( !jQuery.support.appendChecked ) { jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); } i = 0; while ( (elem = nodes[ i++ ]) ) { // #4087 - If origin and destination elements are the same, and this is // that element, do not do anything if ( selection && jQuery.inArray( elem, selection ) !== -1 ) { continue; } contains = jQuery.contains( elem.ownerDocument, elem ); // Append to fragment tmp = getAll( safe.appendChild( elem ), "script" ); // Preserve script evaluation history if ( contains ) { setGlobalEval( tmp ); } // Capture executables if ( scripts ) { j = 0; while ( (elem = tmp[ j++ ]) ) { if ( rscriptType.test( elem.type || "" ) ) { scripts.push( elem ); } } } } tmp = null; return safe; }, cleanData: function( elems, /* internal */ acceptData ) { var elem, type, id, data, i = 0, internalKey = jQuery.expando, cache = jQuery.cache, deleteExpando = jQuery.support.deleteExpando, special = jQuery.event.special; for ( ; (elem = elems[i]) != null; i++ ) { if ( acceptData || jQuery.acceptData( elem ) ) { id = elem[ internalKey ]; data = id && cache[ id ]; if ( data ) { if ( data.events ) { for ( type in data.events ) { if ( special[ type ] ) { jQuery.event.remove( elem, type ); // This is a shortcut to avoid jQuery.event.remove's overhead } else { jQuery.removeEvent( elem, type, data.handle ); } } } // Remove cache only if it was not already removed by jQuery.event.remove if ( cache[ id ] ) { delete cache[ id ]; // IE does not allow us to delete expando properties from nodes, // nor does it have a removeAttribute function on Document nodes; // we must handle all of these cases if ( deleteExpando ) { delete elem[ internalKey ]; } else if ( typeof elem.removeAttribute !== core_strundefined ) { elem.removeAttribute( internalKey ); } else { elem[ internalKey ] = null; } core_deletedIds.push( id ); } } } } } }); var iframe, getStyles, curCSS, ralpha = /alpha\([^)]*\)/i, ropacity = /opacity\s*=\s*([^)]*)/, rposition = /^(top|right|bottom|left)$/, // swappable if display is none or starts with table except "table", "table-cell", or "table-caption" // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display rdisplayswap = /^(none|table(?!-c[ea]).+)/, rmargin = /^margin/, rnumsplit = new RegExp( "^(" + core_pnum + ")(.*)$", "i" ), rnumnonpx = new RegExp( "^(" + core_pnum + ")(?!px)[a-z%]+$", "i" ), rrelNum = new RegExp( "^([+-])=(" + core_pnum + ")", "i" ), elemdisplay = { BODY: "block" }, cssShow = { position: "absolute", visibility: "hidden", display: "block" }, cssNormalTransform = { letterSpacing: 0, fontWeight: 400 }, cssExpand = [ "Top", "Right", "Bottom", "Left" ], cssPrefixes = [ "Webkit", "O", "Moz", "ms" ]; // return a css property mapped to a potentially vendor prefixed property function vendorPropName( style, name ) { // shortcut for names that are not vendor prefixed if ( name in style ) { return name; } // check for vendor prefixed names var capName = name.charAt(0).toUpperCase() + name.slice(1), origName = name, i = cssPrefixes.length; while ( i-- ) { name = cssPrefixes[ i ] + capName; if ( name in style ) { return name; } } return origName; } function isHidden( elem, el ) { // isHidden might be called from jQuery#filter function; // in that case, element will be second argument elem = el || elem; return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem ); } function showHide( elements, show ) { var display, elem, hidden, values = [], index = 0, length = elements.length; for ( ; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) { continue; } values[ index ] = jQuery._data( elem, "olddisplay" ); display = elem.style.display; if ( show ) { // Reset the inline display of this element to learn if it is // being hidden by cascaded rules or not if ( !values[ index ] && display === "none" ) { elem.style.display = ""; } // Set elements which have been overridden with display: none // in a stylesheet to whatever the default browser style is // for such an element if ( elem.style.display === "" && isHidden( elem ) ) { values[ index ] = jQuery._data( elem, "olddisplay", css_defaultDisplay(elem.nodeName) ); } } else { if ( !values[ index ] ) { hidden = isHidden( elem ); if ( display && display !== "none" || !hidden ) { jQuery._data( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) ); } } } } // Set the display of most of the elements in a second loop // to avoid the constant reflow for ( index = 0; index < length; index++ ) { elem = elements[ index ]; if ( !elem.style ) { continue; } if ( !show || elem.style.display === "none" || elem.style.display === "" ) { elem.style.display = show ? values[ index ] || "" : "none"; } } return elements; } jQuery.fn.extend({ css: function( name, value ) { return jQuery.access( this, function( elem, name, value ) { var len, styles, map = {}, i = 0; if ( jQuery.isArray( name ) ) { styles = getStyles( elem ); len = name.length; for ( ; i < len; i++ ) { map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); } return map; } return value !== undefined ? jQuery.style( elem, name, value ) : jQuery.css( elem, name ); }, name, value, arguments.length > 1 ); }, show: function() { return showHide( this, true ); }, hide: function() { return showHide( this ); }, toggle: function( state ) { var bool = typeof state === "boolean"; return this.each(function() { if ( bool ? state : isHidden( this ) ) { jQuery( this ).show(); } else { jQuery( this ).hide(); } }); } }); jQuery.extend({ // Add in style property hooks for overriding the default // behavior of getting and setting a style property cssHooks: { opacity: { get: function( elem, computed ) { if ( computed ) { // We should always get a number back from opacity var ret = curCSS( elem, "opacity" ); return ret === "" ? "1" : ret; } } } }, // Exclude the following css properties to add px cssNumber: { "columnCount": true, "fillOpacity": true, "fontWeight": true, "lineHeight": true, "opacity": true, "orphans": true, "widows": true, "zIndex": true, "zoom": true }, // Add in properties whose names you wish to fix before // setting or getting the value cssProps: { // normalize float css property "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat" }, // Get and set the style property on a DOM Node style: function( elem, name, value, extra ) { // Don't set styles on text and comment nodes if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { return; } // Make sure that we're working with the right name var ret, type, hooks, origName = jQuery.camelCase( name ), style = elem.style; name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) ); // gets hook for the prefixed version // followed by the unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // Check if we're setting a value if ( value !== undefined ) { type = typeof value; // convert relative number strings (+= or -=) to relative numbers. #7345 if ( type === "string" && (ret = rrelNum.exec( value )) ) { value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) ); // Fixes bug #9237 type = "number"; } // Make sure that NaN and null values aren't set. See: #7116 if ( value == null || type === "number" && isNaN( value ) ) { return; } // If a number was passed in, add 'px' to the (except for certain CSS properties) if ( type === "number" && !jQuery.cssNumber[ origName ] ) { value += "px"; } // Fixes #8908, it can be done more correctly by specifing setters in cssHooks, // but it would mean to define eight (for every problematic property) identical functions if ( !jQuery.support.clearCloneStyle && value === "" && name.indexOf("background") === 0 ) { style[ name ] = "inherit"; } // If a hook was provided, use that value, otherwise just set the specified value if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) { // Wrapped to prevent IE from throwing errors when 'invalid' values are provided // Fixes bug #5509 try { style[ name ] = value; } catch(e) {} } } else { // If a hook was provided get the non-computed value from there if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) { return ret; } // Otherwise just get the value from the style object return style[ name ]; } }, css: function( elem, name, extra, styles ) { var num, val, hooks, origName = jQuery.camelCase( name ); // Make sure that we're working with the right name name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) ); // gets hook for the prefixed version // followed by the unprefixed version hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; // If a hook was provided get the computed value from there if ( hooks && "get" in hooks ) { val = hooks.get( elem, true, extra ); } // Otherwise, if a way to get the computed value exists, use that if ( val === undefined ) { val = curCSS( elem, name, styles ); } //convert "normal" to computed value if ( val === "normal" && name in cssNormalTransform ) { val = cssNormalTransform[ name ]; } // Return, converting to number if forced or a qualifier was provided and val looks numeric if ( extra === "" || extra ) { num = parseFloat( val ); return extra === true || jQuery.isNumeric( num ) ? num || 0 : val; } return val; }, // A method for quickly swapping in/out CSS properties to get correct calculations swap: function( elem, options, callback, args ) { var ret, name, old = {}; // Remember the old values, and insert the new ones for ( name in options ) { old[ name ] = elem.style[ name ]; elem.style[ name ] = options[ name ]; } ret = callback.apply( elem, args || [] ); // Revert the old values for ( name in options ) { elem.style[ name ] = old[ name ]; } return ret; } }); // NOTE: we've included the "window" in window.getComputedStyle // because jsdom on node.js will break without it. if ( window.getComputedStyle ) { getStyles = function( elem ) { return window.getComputedStyle( elem, null ); }; curCSS = function( elem, name, _computed ) { var width, minWidth, maxWidth, computed = _computed || getStyles( elem ), // getPropertyValue is only needed for .css('filter') in IE9, see #12537 ret = computed ? computed.getPropertyValue( name ) || computed[ name ] : undefined, style = elem.style; if ( computed ) { if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { ret = jQuery.style( elem, name ); } // A tribute to the "awesome hack by Dean Edwards" // Chrome < 17 and Safari 5.0 uses "computed value" instead of "used value" for margin-right // Safari 5.1.7 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) { // Remember the original values width = style.width; minWidth = style.minWidth; maxWidth = style.maxWidth; // Put in the new values to get a computed value out style.minWidth = style.maxWidth = style.width = ret; ret = computed.width; // Revert the changed values style.width = width; style.minWidth = minWidth; style.maxWidth = maxWidth; } } return ret; }; } else if ( document.documentElement.currentStyle ) { getStyles = function( elem ) { return elem.currentStyle; }; curCSS = function( elem, name, _computed ) { var left, rs, rsLeft, computed = _computed || getStyles( elem ), ret = computed ? computed[ name ] : undefined, style = elem.style; // Avoid setting ret to empty string here // so we don't default to auto if ( ret == null && style && style[ name ] ) { ret = style[ name ]; } // From the awesome hack by Dean Edwards // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 // If we're not dealing with a regular pixel number // but a number that has a weird ending, we need to convert it to pixels // but not position css attributes, as those are proportional to the parent element instead // and we can't measure the parent instead because it might trigger a "stacking dolls" problem if ( rnumnonpx.test( ret ) && !rposition.test( name ) ) { // Remember the original values left = style.left; rs = elem.runtimeStyle; rsLeft = rs && rs.left; // Put in the new values to get a computed value out if ( rsLeft ) { rs.left = elem.currentStyle.left; } style.left = name === "fontSize" ? "1em" : ret; ret = style.pixelLeft + "px"; // Revert the changed values style.left = left; if ( rsLeft ) { rs.left = rsLeft; } } return ret === "" ? "auto" : ret; }; } function setPositiveNumber( elem, value, subtract ) { var matches = rnumsplit.exec( value ); return matches ? // Guard against undefined "subtract", e.g., when used as in cssHooks Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) : value; } function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { var i = extra === ( isBorderBox ? "border" : "content" ) ? // If we already have the right measurement, avoid augmentation 4 : // Otherwise initialize for horizontal or vertical properties name === "width" ? 1 : 0, val = 0; for ( ; i < 4; i += 2 ) { // both box models exclude margin, so add it if we want it if ( extra === "margin" ) { val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); } if ( isBorderBox ) { // border-box includes padding, so remove it if we want content if ( extra === "content" ) { val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); } // at this point, extra isn't border nor margin, so remove border if ( extra !== "margin" ) { val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } else { // at this point, extra isn't content, so add padding val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); // at this point, extra isn't content nor padding, so add border if ( extra !== "padding" ) { val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); } } } return val; } function getWidthOrHeight( elem, name, extra ) { // Start with offset property, which is equivalent to the border-box value var valueIsBorderBox = true, val = name === "width" ? elem.offsetWidth : elem.offsetHeight, styles = getStyles( elem ), isBorderBox = jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; // some non-html elements return undefined for offsetWidth, so check for null/undefined // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285 // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668 if ( val <= 0 || val == null ) { // Fall back to computed then uncomputed css if necessary val = curCSS( elem, name, styles ); if ( val < 0 || val == null ) { val = elem.style[ name ]; } // Computed unit is not pixels. Stop here and return. if ( rnumnonpx.test(val) ) { return val; } // we need the check for style in case a browser which returns unreliable values // for getComputedStyle silently falls back to the reliable elem.style valueIsBorderBox = isBorderBox && ( jQuery.support.boxSizingReliable || val === elem.style[ name ] ); // Normalize "", auto, and prepare for extra val = parseFloat( val ) || 0; } // use the active box-sizing model to add/subtract irrelevant styles return ( val + augmentWidthOrHeight( elem, name, extra || ( isBorderBox ? "border" : "content" ), valueIsBorderBox, styles ) ) + "px"; } // Try to determine the default display value of an element function css_defaultDisplay( nodeName ) { var doc = document, display = elemdisplay[ nodeName ]; if ( !display ) { display = actualDisplay( nodeName, doc ); // If the simple way fails, read from inside an iframe if ( display === "none" || !display ) { // Use the already-created iframe if possible iframe = ( iframe || jQuery("<iframe frameborder='0' width='0' height='0'/>") .css( "cssText", "display:block !important" ) ).appendTo( doc.documentElement ); // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse doc = ( iframe[0].contentWindow || iframe[0].contentDocument ).document; doc.write("<!doctype html><html><body>"); doc.close(); display = actualDisplay( nodeName, doc ); iframe.detach(); } // Store the correct default display elemdisplay[ nodeName ] = display; } return display; } // Called ONLY from within css_defaultDisplay function actualDisplay( name, doc ) { var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), display = jQuery.css( elem[0], "display" ); elem.remove(); return display; } jQuery.each([ "height", "width" ], function( i, name ) { jQuery.cssHooks[ name ] = { get: function( elem, computed, extra ) { if ( computed ) { // certain elements can have dimension info if we invisibly show them // however, it must have a current display style that would benefit from this return elem.offsetWidth === 0 && rdisplayswap.test( jQuery.css( elem, "display" ) ) ? jQuery.swap( elem, cssShow, function() { return getWidthOrHeight( elem, name, extra ); }) : getWidthOrHeight( elem, name, extra ); } }, set: function( elem, value, extra ) { var styles = extra && getStyles( elem ); return setPositiveNumber( elem, value, extra ? augmentWidthOrHeight( elem, name, extra, jQuery.support.boxSizing && jQuery.css( elem, "boxSizing", false, styles ) === "border-box", styles ) : 0 ); } }; }); if ( !jQuery.support.opacity ) { jQuery.cssHooks.opacity = { get: function( elem, computed ) { // IE uses filters for opacity return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ? ( 0.01 * parseFloat( RegExp.$1 ) ) + "" : computed ? "1" : ""; }, set: function( elem, value ) { var style = elem.style, currentStyle = elem.currentStyle, opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "", filter = currentStyle && currentStyle.filter || style.filter || ""; // IE has trouble with opacity if it does not have layout // Force it by setting the zoom level style.zoom = 1; // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652 // if value === "", then remove inline opacity #12685 if ( ( value >= 1 || value === "" ) && jQuery.trim( filter.replace( ralpha, "" ) ) === "" && style.removeAttribute ) { // Setting style.filter to null, "" & " " still leave "filter:" in the cssText // if "filter:" is present at all, clearType is disabled, we want to avoid this // style.removeAttribute is IE Only, but so apparently is this code path... style.removeAttribute( "filter" ); // if there is no filter style applied in a css rule or unset inline opacity, we are done if ( value === "" || currentStyle && !currentStyle.filter ) { return; } } // otherwise, set new filter values style.filter = ralpha.test( filter ) ? filter.replace( ralpha, opacity ) : filter + " " + opacity; } }; } // These hooks cannot be added until DOM ready because the support test // for it is not run until after DOM ready jQuery(function() { if ( !jQuery.support.reliableMarginRight ) { jQuery.cssHooks.marginRight = { get: function( elem, computed ) { if ( computed ) { // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right // Work around by temporarily setting element display to inline-block return jQuery.swap( elem, { "display": "inline-block" }, curCSS, [ elem, "marginRight" ] ); } } }; } // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084 // getComputedStyle returns percent when specified for top/left/bottom/right // rather than make the css module depend on the offset module, we just check for it here if ( !jQuery.support.pixelPosition && jQuery.fn.position ) { jQuery.each( [ "top", "left" ], function( i, prop ) { jQuery.cssHooks[ prop ] = { get: function( elem, computed ) { if ( computed ) { computed = curCSS( elem, prop ); // if curCSS returns percentage, fallback to offset return rnumnonpx.test( computed ) ? jQuery( elem ).position()[ prop ] + "px" : computed; } } }; }); } }); if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.hidden = function( elem ) { // Support: Opera <= 12.12 // Opera reports offsetWidths and offsetHeights less than zero on some elements return elem.offsetWidth <= 0 && elem.offsetHeight <= 0 || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none"); }; jQuery.expr.filters.visible = function( elem ) { return !jQuery.expr.filters.hidden( elem ); }; } // These hooks are used by animate to expand properties jQuery.each({ margin: "", padding: "", border: "Width" }, function( prefix, suffix ) { jQuery.cssHooks[ prefix + suffix ] = { expand: function( value ) { var i = 0, expanded = {}, // assumes a single number if not a string parts = typeof value === "string" ? value.split(" ") : [ value ]; for ( ; i < 4; i++ ) { expanded[ prefix + cssExpand[ i ] + suffix ] = parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; } return expanded; } }; if ( !rmargin.test( prefix ) ) { jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; } }); var r20 = /%20/g, rbracket = /\[\]$/, rCRLF = /\r?\n/g, rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, rsubmittable = /^(?:input|select|textarea|keygen)/i; jQuery.fn.extend({ serialize: function() { return jQuery.param( this.serializeArray() ); }, serializeArray: function() { return this.map(function(){ // Can add propHook for "elements" to filter or add form elements var elements = jQuery.prop( this, "elements" ); return elements ? jQuery.makeArray( elements ) : this; }) .filter(function(){ var type = this.type; // Use .is(":disabled") so that fieldset[disabled] works return this.name && !jQuery( this ).is( ":disabled" ) && rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && ( this.checked || !manipulation_rcheckableType.test( type ) ); }) .map(function( i, elem ){ var val = jQuery( this ).val(); return val == null ? null : jQuery.isArray( val ) ? jQuery.map( val, function( val ){ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; }) : { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; }).get(); } }); //Serialize an array of form elements or a set of //key/values into a query string jQuery.param = function( a, traditional ) { var prefix, s = [], add = function( key, value ) { // If value is a function, invoke it and return its value value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value ); s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value ); }; // Set traditional to true for jQuery <= 1.3.2 behavior. if ( traditional === undefined ) { traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional; } // If an array was passed in, assume that it is an array of form elements. if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { // Serialize the form elements jQuery.each( a, function() { add( this.name, this.value ); }); } else { // If traditional, encode the "old" way (the way 1.3.2 or older // did it), otherwise encode params recursively. for ( prefix in a ) { buildParams( prefix, a[ prefix ], traditional, add ); } } // Return the resulting serialization return s.join( "&" ).replace( r20, "+" ); }; function buildParams( prefix, obj, traditional, add ) { var name; if ( jQuery.isArray( obj ) ) { // Serialize array item. jQuery.each( obj, function( i, v ) { if ( traditional || rbracket.test( prefix ) ) { // Treat each array item as a scalar. add( prefix, v ); } else { // Item is non-scalar (array or object), encode its numeric index. buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add ); } }); } else if ( !traditional && jQuery.type( obj ) === "object" ) { // Serialize object item. for ( name in obj ) { buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); } } else { // Serialize scalar item. add( prefix, obj ); } } jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding jQuery.fn[ name ] = function( data, fn ) { return arguments.length > 0 ? this.on( name, null, data, fn ) : this.trigger( name ); }; }); jQuery.fn.hover = function( fnOver, fnOut ) { return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); }; var // Document location ajaxLocParts, ajaxLocation, ajax_nonce = jQuery.now(), ajax_rquery = /\?/, rhash = /#.*$/, rts = /([?&])_=[^&]*/, rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL // #7653, #8125, #8152: local protocol detection rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, rnoContent = /^(?:GET|HEAD)$/, rprotocol = /^\/\//, rurl = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, // Keep a copy of the old load method _load = jQuery.fn.load, /* Prefilters * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) * 2) These are called: * - BEFORE asking for a transport * - AFTER param serialization (s.data is a string if s.processData is true) * 3) key is the dataType * 4) the catchall symbol "*" can be used * 5) execution will start with transport dataType and THEN continue down to "*" if needed */ prefilters = {}, /* Transports bindings * 1) key is the dataType * 2) the catchall symbol "*" can be used * 3) selection will start with transport dataType and THEN go to "*" if needed */ transports = {}, // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression allTypes = "*/".concat("*"); // #8138, IE may throw an exception when accessing // a field from window.location if document.domain has been set try { ajaxLocation = location.href; } catch( e ) { // Use the href attribute of an A element // since IE will modify it given document.location ajaxLocation = document.createElement( "a" ); ajaxLocation.href = ""; ajaxLocation = ajaxLocation.href; } // Segment location into parts ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || []; // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport function addToPrefiltersOrTransports( structure ) { // dataTypeExpression is optional and defaults to "*" return function( dataTypeExpression, func ) { if ( typeof dataTypeExpression !== "string" ) { func = dataTypeExpression; dataTypeExpression = "*"; } var dataType, i = 0, dataTypes = dataTypeExpression.toLowerCase().match( core_rnotwhite ) || []; if ( jQuery.isFunction( func ) ) { // For each dataType in the dataTypeExpression while ( (dataType = dataTypes[i++]) ) { // Prepend if requested if ( dataType[0] === "+" ) { dataType = dataType.slice( 1 ) || "*"; (structure[ dataType ] = structure[ dataType ] || []).unshift( func ); // Otherwise append } else { (structure[ dataType ] = structure[ dataType ] || []).push( func ); } } } }; } // Base inspection function for prefilters and transports function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { var inspected = {}, seekingTransport = ( structure === transports ); function inspect( dataType ) { var selected; inspected[ dataType ] = true; jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); if( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) { options.dataTypes.unshift( dataTypeOrTransport ); inspect( dataTypeOrTransport ); return false; } else if ( seekingTransport ) { return !( selected = dataTypeOrTransport ); } }); return selected; } return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); } // A special extend for ajax options // that takes "flat" options (not to be deep extended) // Fixes #9887 function ajaxExtend( target, src ) { var deep, key, flatOptions = jQuery.ajaxSettings.flatOptions || {}; for ( key in src ) { if ( src[ key ] !== undefined ) { ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ]; } } if ( deep ) { jQuery.extend( true, target, deep ); } return target; } jQuery.fn.load = function( url, params, callback ) { if ( typeof url !== "string" && _load ) { return _load.apply( this, arguments ); } var selector, response, type, self = this, off = url.indexOf(" "); if ( off >= 0 ) { selector = url.slice( off, url.length ); url = url.slice( 0, off ); } // If it's a function if ( jQuery.isFunction( params ) ) { // We assume that it's the callback callback = params; params = undefined; // Otherwise, build a param string } else if ( params && typeof params === "object" ) { type = "POST"; } // If we have elements to modify, make the request if ( self.length > 0 ) { jQuery.ajax({ url: url, // if "type" variable is undefined, then "GET" method will be used type: type, dataType: "html", data: params }).done(function( responseText ) { // Save response for use in complete callback response = arguments; self.html( selector ? // If a selector was specified, locate the right elements in a dummy div // Exclude scripts to avoid IE 'Permission Denied' errors jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) : // Otherwise use the full result responseText ); }).complete( callback && function( jqXHR, status ) { self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] ); }); } return this; }; // Attach a bunch of functions for handling common AJAX events jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ){ jQuery.fn[ type ] = function( fn ){ return this.on( type, fn ); }; }); jQuery.each( [ "get", "post" ], function( i, method ) { jQuery[ method ] = function( url, data, callback, type ) { // shift arguments if data argument was omitted if ( jQuery.isFunction( data ) ) { type = type || callback; callback = data; data = undefined; } return jQuery.ajax({ url: url, type: method, dataType: type, data: data, success: callback }); }; }); jQuery.extend({ // Counter for holding the number of active queries active: 0, // Last-Modified header cache for next request lastModified: {}, etag: {}, ajaxSettings: { url: ajaxLocation, type: "GET", isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ), global: true, processData: true, async: true, contentType: "application/x-www-form-urlencoded; charset=UTF-8", /* timeout: 0, data: null, dataType: null, username: null, password: null, cache: null, throws: false, traditional: false, headers: {}, */ accepts: { "*": allTypes, text: "text/plain", html: "text/html", xml: "application/xml, text/xml", json: "application/json, text/javascript" }, contents: { xml: /xml/, html: /html/, json: /json/ }, responseFields: { xml: "responseXML", text: "responseText" }, // Data converters // Keys separate source (or catchall "*") and destination types with a single space converters: { // Convert anything to text "* text": window.String, // Text to html (true = no transformation) "text html": true, // Evaluate text as a json expression "text json": jQuery.parseJSON, // Parse text as xml "text xml": jQuery.parseXML }, // For options that shouldn't be deep extended: // you can add your own custom options here if // and when you create one that shouldn't be // deep extended (see ajaxExtend) flatOptions: { url: true, context: true } }, // Creates a full fledged settings object into target // with both ajaxSettings and settings fields. // If target is omitted, writes into ajaxSettings. ajaxSetup: function( target, settings ) { return settings ? // Building a settings object ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : // Extending ajaxSettings ajaxExtend( jQuery.ajaxSettings, target ); }, ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), ajaxTransport: addToPrefiltersOrTransports( transports ), // Main method ajax: function( url, options ) { // If url is an object, simulate pre-1.5 signature if ( typeof url === "object" ) { options = url; url = undefined; } // Force options to be an object options = options || {}; var // Cross-domain detection vars parts, // Loop variable i, // URL without anti-cache param cacheURL, // Response headers as string responseHeadersString, // timeout handle timeoutTimer, // To know if global events are to be dispatched fireGlobals, transport, // Response headers responseHeaders, // Create the final options object s = jQuery.ajaxSetup( {}, options ), // Callbacks context callbackContext = s.context || s, // Context for global events is callbackContext if it is a DOM node or jQuery collection globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ? jQuery( callbackContext ) : jQuery.event, // Deferreds deferred = jQuery.Deferred(), completeDeferred = jQuery.Callbacks("once memory"), // Status-dependent callbacks statusCode = s.statusCode || {}, // Headers (they are sent all at once) requestHeaders = {}, requestHeadersNames = {}, // The jqXHR state state = 0, // Default abort message strAbort = "canceled", // Fake xhr jqXHR = { readyState: 0, // Builds headers hashtable if needed getResponseHeader: function( key ) { var match; if ( state === 2 ) { if ( !responseHeaders ) { responseHeaders = {}; while ( (match = rheaders.exec( responseHeadersString )) ) { responseHeaders[ match[1].toLowerCase() ] = match[ 2 ]; } } match = responseHeaders[ key.toLowerCase() ]; } return match == null ? null : match; }, // Raw string getAllResponseHeaders: function() { return state === 2 ? responseHeadersString : null; }, // Caches the header setRequestHeader: function( name, value ) { var lname = name.toLowerCase(); if ( !state ) { name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name; requestHeaders[ name ] = value; } return this; }, // Overrides response content-type header overrideMimeType: function( type ) { if ( !state ) { s.mimeType = type; } return this; }, // Status-dependent callbacks statusCode: function( map ) { var code; if ( map ) { if ( state < 2 ) { for ( code in map ) { // Lazy-add the new callback in a way that preserves old ones statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; } } else { // Execute the appropriate callbacks jqXHR.always( map[ jqXHR.status ] ); } } return this; }, // Cancel the request abort: function( statusText ) { var finalText = statusText || strAbort; if ( transport ) { transport.abort( finalText ); } done( 0, finalText ); return this; } }; // Attach deferreds deferred.promise( jqXHR ).complete = completeDeferred.add; jqXHR.success = jqXHR.done; jqXHR.error = jqXHR.fail; // Remove hash character (#7531: and string promotion) // Add protocol if not provided (#5866: IE7 issue with protocol-less urls) // Handle falsy url in the settings object (#10093: consistency with old signature) // We also use the url parameter if available s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" ); // Alias method option to type as per ticket #12004 s.type = options.method || options.type || s.method || s.type; // Extract dataTypes list s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( core_rnotwhite ) || [""]; // A cross-domain request is in order when we have a protocol:host:port mismatch if ( s.crossDomain == null ) { parts = rurl.exec( s.url.toLowerCase() ); s.crossDomain = !!( parts && ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] || ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) != ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) ) ); } // Convert data if not already a string if ( s.data && s.processData && typeof s.data !== "string" ) { s.data = jQuery.param( s.data, s.traditional ); } // Apply prefilters inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); // If request was aborted inside a prefilter, stop there if ( state === 2 ) { return jqXHR; } // We can fire global events as of now if asked to fireGlobals = s.global; // Watch for a new set of requests if ( fireGlobals && jQuery.active++ === 0 ) { jQuery.event.trigger("ajaxStart"); } // Uppercase the type s.type = s.type.toUpperCase(); // Determine if request has content s.hasContent = !rnoContent.test( s.type ); // Save the URL in case we're toying with the If-Modified-Since // and/or If-None-Match header later on cacheURL = s.url; // More options handling for requests with no content if ( !s.hasContent ) { // If data is available, append data to url if ( s.data ) { cacheURL = ( s.url += ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + s.data ); // #9682: remove data so that it's not used in an eventual retry delete s.data; } // Add anti-cache in url if needed if ( s.cache === false ) { s.url = rts.test( cacheURL ) ? // If there is already a '_' parameter, set its value cacheURL.replace( rts, "$1_=" + ajax_nonce++ ) : // Otherwise add one to the end cacheURL + ( ajax_rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ajax_nonce++; } } // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { if ( jQuery.lastModified[ cacheURL ] ) { jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); } if ( jQuery.etag[ cacheURL ] ) { jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); } } // Set the correct header, if data is being sent if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { jqXHR.setRequestHeader( "Content-Type", s.contentType ); } // Set the Accepts header for the server, depending on the dataType jqXHR.setRequestHeader( "Accept", s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ? s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : s.accepts[ "*" ] ); // Check for headers option for ( i in s.headers ) { jqXHR.setRequestHeader( i, s.headers[ i ] ); } // Allow custom headers/mimetypes and early abort if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) { // Abort if not done already and return return jqXHR.abort(); } // aborting is no longer a cancellation strAbort = "abort"; // Install callbacks on deferreds for ( i in { success: 1, error: 1, complete: 1 } ) { jqXHR[ i ]( s[ i ] ); } // Get transport transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); // If no transport, we auto-abort if ( !transport ) { done( -1, "No Transport" ); } else { jqXHR.readyState = 1; // Send global event if ( fireGlobals ) { globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); } // Timeout if ( s.async && s.timeout > 0 ) { timeoutTimer = setTimeout(function() { jqXHR.abort("timeout"); }, s.timeout ); } try { state = 1; transport.send( requestHeaders, done ); } catch ( e ) { // Propagate exception as error if not done if ( state < 2 ) { done( -1, e ); // Simply rethrow otherwise } else { throw e; } } } // Callback for when everything is done function done( status, nativeStatusText, responses, headers ) { var isSuccess, success, error, response, modified, statusText = nativeStatusText; // Called once if ( state === 2 ) { return; } // State is "done" now state = 2; // Clear timeout if it exists if ( timeoutTimer ) { clearTimeout( timeoutTimer ); } // Dereference transport for early garbage collection // (no matter how long the jqXHR object will be used) transport = undefined; // Cache response headers responseHeadersString = headers || ""; // Set readyState jqXHR.readyState = status > 0 ? 4 : 0; // Get response data if ( responses ) { response = ajaxHandleResponses( s, jqXHR, responses ); } // If successful, handle type chaining if ( status >= 200 && status < 300 || status === 304 ) { // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. if ( s.ifModified ) { modified = jqXHR.getResponseHeader("Last-Modified"); if ( modified ) { jQuery.lastModified[ cacheURL ] = modified; } modified = jqXHR.getResponseHeader("etag"); if ( modified ) { jQuery.etag[ cacheURL ] = modified; } } // if no content if ( status === 204 ) { isSuccess = true; statusText = "nocontent"; // if not modified } else if ( status === 304 ) { isSuccess = true; statusText = "notmodified"; // If we have data, let's convert it } else { isSuccess = ajaxConvert( s, response ); statusText = isSuccess.state; success = isSuccess.data; error = isSuccess.error; isSuccess = !error; } } else { // We extract error from statusText // then normalize statusText and status for non-aborts error = statusText; if ( status || !statusText ) { statusText = "error"; if ( status < 0 ) { status = 0; } } } // Set data for the fake xhr object jqXHR.status = status; jqXHR.statusText = ( nativeStatusText || statusText ) + ""; // Success/Error if ( isSuccess ) { deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); } else { deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); } // Status-dependent callbacks jqXHR.statusCode( statusCode ); statusCode = undefined; if ( fireGlobals ) { globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", [ jqXHR, s, isSuccess ? success : error ] ); } // Complete completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); if ( fireGlobals ) { globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); // Handle the global AJAX counter if ( !( --jQuery.active ) ) { jQuery.event.trigger("ajaxStop"); } } } return jqXHR; }, getScript: function( url, callback ) { return jQuery.get( url, undefined, callback, "script" ); }, getJSON: function( url, data, callback ) { return jQuery.get( url, data, callback, "json" ); } }); /* Handles responses to an ajax request: * - sets all responseXXX fields accordingly * - finds the right dataType (mediates between content-type and expected dataType) * - returns the corresponding response */ function ajaxHandleResponses( s, jqXHR, responses ) { var firstDataType, ct, finalDataType, type, contents = s.contents, dataTypes = s.dataTypes, responseFields = s.responseFields; // Fill responseXXX fields for ( type in responseFields ) { if ( type in responses ) { jqXHR[ responseFields[type] ] = responses[ type ]; } } // Remove auto dataType and get content-type in the process while( dataTypes[ 0 ] === "*" ) { dataTypes.shift(); if ( ct === undefined ) { ct = s.mimeType || jqXHR.getResponseHeader("Content-Type"); } } // Check if we're dealing with a known content-type if ( ct ) { for ( type in contents ) { if ( contents[ type ] && contents[ type ].test( ct ) ) { dataTypes.unshift( type ); break; } } } // Check to see if we have a response for the expected dataType if ( dataTypes[ 0 ] in responses ) { finalDataType = dataTypes[ 0 ]; } else { // Try convertible dataTypes for ( type in responses ) { if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) { finalDataType = type; break; } if ( !firstDataType ) { firstDataType = type; } } // Or just use first one finalDataType = finalDataType || firstDataType; } // If we found a dataType // We add the dataType to the list if needed // and return the corresponding response if ( finalDataType ) { if ( finalDataType !== dataTypes[ 0 ] ) { dataTypes.unshift( finalDataType ); } return responses[ finalDataType ]; } } // Chain conversions given the request and the original response function ajaxConvert( s, response ) { var conv2, current, conv, tmp, converters = {}, i = 0, // Work with a copy of dataTypes in case we need to modify it for conversion dataTypes = s.dataTypes.slice(), prev = dataTypes[ 0 ]; // Apply the dataFilter if provided if ( s.dataFilter ) { response = s.dataFilter( response, s.dataType ); } // Create converters map with lowercased keys if ( dataTypes[ 1 ] ) { for ( conv in s.converters ) { converters[ conv.toLowerCase() ] = s.converters[ conv ]; } } // Convert to each sequential dataType, tolerating list modification for ( ; (current = dataTypes[++i]); ) { // There's only work to do if current dataType is non-auto if ( current !== "*" ) { // Convert response if prev dataType is non-auto and differs from current if ( prev !== "*" && prev !== current ) { // Seek a direct converter conv = converters[ prev + " " + current ] || converters[ "* " + current ]; // If none found, seek a pair if ( !conv ) { for ( conv2 in converters ) { // If conv2 outputs current tmp = conv2.split(" "); if ( tmp[ 1 ] === current ) { // If prev can be converted to accepted input conv = converters[ prev + " " + tmp[ 0 ] ] || converters[ "* " + tmp[ 0 ] ]; if ( conv ) { // Condense equivalence converters if ( conv === true ) { conv = converters[ conv2 ]; // Otherwise, insert the intermediate dataType } else if ( converters[ conv2 ] !== true ) { current = tmp[ 0 ]; dataTypes.splice( i--, 0, current ); } break; } } } } // Apply converter (if not an equivalence) if ( conv !== true ) { // Unless errors are allowed to bubble, catch and return them if ( conv && s["throws"] ) { response = conv( response ); } else { try { response = conv( response ); } catch ( e ) { return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current }; } } } } // Update prev for next iteration prev = current; } } return { state: "success", data: response }; } // Install script dataType jQuery.ajaxSetup({ accepts: { script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript" }, contents: { script: /(?:java|ecma)script/ }, converters: { "text script": function( text ) { jQuery.globalEval( text ); return text; } } }); // Handle cache's special case and global jQuery.ajaxPrefilter( "script", function( s ) { if ( s.cache === undefined ) { s.cache = false; } if ( s.crossDomain ) { s.type = "GET"; s.global = false; } }); // Bind script tag hack transport jQuery.ajaxTransport( "script", function(s) { // This transport only deals with cross domain requests if ( s.crossDomain ) { var script, head = document.head || jQuery("head")[0] || document.documentElement; return { send: function( _, callback ) { script = document.createElement("script"); script.async = true; if ( s.scriptCharset ) { script.charset = s.scriptCharset; } script.src = s.url; // Attach handlers for all browsers script.onload = script.onreadystatechange = function( _, isAbort ) { if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) { // Handle memory leak in IE script.onload = script.onreadystatechange = null; // Remove the script if ( script.parentNode ) { script.parentNode.removeChild( script ); } // Dereference the script script = null; // Callback if not abort if ( !isAbort ) { callback( 200, "success" ); } } }; // Circumvent IE6 bugs with base elements (#2709 and #4378) by prepending // Use native DOM manipulation to avoid our domManip AJAX trickery head.insertBefore( script, head.firstChild ); }, abort: function() { if ( script ) { script.onload( undefined, true ); } } }; } }); var oldCallbacks = [], rjsonp = /(=)\?(?=&|$)|\?\?/; // Default jsonp settings jQuery.ajaxSetup({ jsonp: "callback", jsonpCallback: function() { var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( ajax_nonce++ ) ); this[ callback ] = true; return callback; } }); // Detect, normalize options and install callbacks for jsonp requests jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) { var callbackName, overwritten, responseContainer, jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ? "url" : typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data" ); // Handle iff the expected data type is "jsonp" or we have a parameter to set if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) { // Get callback name, remembering preexisting value associated with it callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback; // Insert callback into url or form data if ( jsonProp ) { s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName ); } else if ( s.jsonp !== false ) { s.url += ( ajax_rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName; } // Use data converter to retrieve json after script execution s.converters["script json"] = function() { if ( !responseContainer ) { jQuery.error( callbackName + " was not called" ); } return responseContainer[ 0 ]; }; // force json dataType s.dataTypes[ 0 ] = "json"; // Install callback overwritten = window[ callbackName ]; window[ callbackName ] = function() { responseContainer = arguments; }; // Clean-up function (fires after converters) jqXHR.always(function() { // Restore preexisting value window[ callbackName ] = overwritten; // Save back as free if ( s[ callbackName ] ) { // make sure that re-using the options doesn't screw things around s.jsonpCallback = originalSettings.jsonpCallback; // save the callback name for future use oldCallbacks.push( callbackName ); } // Call if it was a function and we have a response if ( responseContainer && jQuery.isFunction( overwritten ) ) { overwritten( responseContainer[ 0 ] ); } responseContainer = overwritten = undefined; }); // Delegate to script return "script"; } }); var xhrCallbacks, xhrSupported, xhrId = 0, // #5280: Internet Explorer will keep connections alive if we don't abort on unload xhrOnUnloadAbort = window.ActiveXObject && function() { // Abort all pending requests var key; for ( key in xhrCallbacks ) { xhrCallbacks[ key ]( undefined, true ); } }; // Functions to create xhrs function createStandardXHR() { try { return new window.XMLHttpRequest(); } catch( e ) {} } function createActiveXHR() { try { return new window.ActiveXObject("Microsoft.XMLHTTP"); } catch( e ) {} } // Create the request object // (This is still attached to ajaxSettings for backward compatibility) jQuery.ajaxSettings.xhr = window.ActiveXObject ? /* Microsoft failed to properly * implement the XMLHttpRequest in IE7 (can't request local files), * so we use the ActiveXObject when it is available * Additionally XMLHttpRequest can be disabled in IE7/IE8 so * we need a fallback. */ function() { return !this.isLocal && createStandardXHR() || createActiveXHR(); } : // For all other browsers, use the standard XMLHttpRequest object createStandardXHR; // Determine support properties xhrSupported = jQuery.ajaxSettings.xhr(); jQuery.support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); xhrSupported = jQuery.support.ajax = !!xhrSupported; // Create transport if the browser can provide an xhr if ( xhrSupported ) { jQuery.ajaxTransport(function( s ) { // Cross domain only allowed if supported through XMLHttpRequest if ( !s.crossDomain || jQuery.support.cors ) { var callback; return { send: function( headers, complete ) { // Get a new xhr var handle, i, xhr = s.xhr(); // Open the socket // Passing null username, generates a login popup on Opera (#2865) if ( s.username ) { xhr.open( s.type, s.url, s.async, s.username, s.password ); } else { xhr.open( s.type, s.url, s.async ); } // Apply custom fields if provided if ( s.xhrFields ) { for ( i in s.xhrFields ) { xhr[ i ] = s.xhrFields[ i ]; } } // Override mime type if needed if ( s.mimeType && xhr.overrideMimeType ) { xhr.overrideMimeType( s.mimeType ); } // X-Requested-With header // For cross-domain requests, seeing as conditions for a preflight are // akin to a jigsaw puzzle, we simply never set it to be sure. // (it can always be set on a per-request basis or even using ajaxSetup) // For same-domain requests, won't change header if already provided. if ( !s.crossDomain && !headers["X-Requested-With"] ) { headers["X-Requested-With"] = "XMLHttpRequest"; } // Need an extra try/catch for cross domain requests in Firefox 3 try { for ( i in headers ) { xhr.setRequestHeader( i, headers[ i ] ); } } catch( err ) {} // Do send the request // This may raise an exception which is actually // handled in jQuery.ajax (so no try/catch here) xhr.send( ( s.hasContent && s.data ) || null ); // Listener callback = function( _, isAbort ) { var status, responseHeaders, statusText, responses; // Firefox throws exceptions when accessing properties // of an xhr when a network error occurred // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE) try { // Was never called and is aborted or complete if ( callback && ( isAbort || xhr.readyState === 4 ) ) { // Only called once callback = undefined; // Do not keep as active anymore if ( handle ) { xhr.onreadystatechange = jQuery.noop; if ( xhrOnUnloadAbort ) { delete xhrCallbacks[ handle ]; } } // If it's an abort if ( isAbort ) { // Abort it manually if needed if ( xhr.readyState !== 4 ) { xhr.abort(); } } else { responses = {}; status = xhr.status; responseHeaders = xhr.getAllResponseHeaders(); // When requesting binary data, IE6-9 will throw an exception // on any attempt to access responseText (#11426) if ( typeof xhr.responseText === "string" ) { responses.text = xhr.responseText; } // Firefox throws an exception when accessing // statusText for faulty cross-domain requests try { statusText = xhr.statusText; } catch( e ) { // We normalize with Webkit giving an empty statusText statusText = ""; } // Filter status for non standard behaviors // If the request is local and we have data: assume a success // (success with no data won't get notified, that's the best we // can do given current implementations) if ( !status && s.isLocal && !s.crossDomain ) { status = responses.text ? 200 : 404; // IE - #1450: sometimes returns 1223 when it should be 204 } else if ( status === 1223 ) { status = 204; } } } } catch( firefoxAccessException ) { if ( !isAbort ) { complete( -1, firefoxAccessException ); } } // Call complete if needed if ( responses ) { complete( status, statusText, responses, responseHeaders ); } }; if ( !s.async ) { // if we're in sync mode we fire the callback callback(); } else if ( xhr.readyState === 4 ) { // (IE6 & IE7) if it's in cache and has been // retrieved directly we need to fire the callback setTimeout( callback ); } else { handle = ++xhrId; if ( xhrOnUnloadAbort ) { // Create the active xhrs callbacks list if needed // and attach the unload handler if ( !xhrCallbacks ) { xhrCallbacks = {}; jQuery( window ).unload( xhrOnUnloadAbort ); } // Add to list of active xhrs callbacks xhrCallbacks[ handle ] = callback; } xhr.onreadystatechange = callback; } }, abort: function() { if ( callback ) { callback( undefined, true ); } } }; } }); } var fxNow, timerId, rfxtypes = /^(?:toggle|show|hide)$/, rfxnum = new RegExp( "^(?:([+-])=|)(" + core_pnum + ")([a-z%]*)$", "i" ), rrun = /queueHooks$/, animationPrefilters = [ defaultPrefilter ], tweeners = { "*": [function( prop, value ) { var end, unit, tween = this.createTween( prop, value ), parts = rfxnum.exec( value ), target = tween.cur(), start = +target || 0, scale = 1, maxIterations = 20; if ( parts ) { end = +parts[2]; unit = parts[3] || ( jQuery.cssNumber[ prop ] ? "" : "px" ); // We need to compute starting value if ( unit !== "px" && start ) { // Iteratively approximate from a nonzero starting point // Prefer the current property, because this process will be trivial if it uses the same units // Fallback to end or a simple constant start = jQuery.css( tween.elem, prop, true ) || end || 1; do { // If previous iteration zeroed out, double until we get *something* // Use a string for doubling factor so we don't accidentally see scale as unchanged below scale = scale || ".5"; // Adjust and apply start = start / scale; jQuery.style( tween.elem, prop, start + unit ); // Update scale, tolerating zero or NaN from tween.cur() // And breaking the loop if scale is unchanged or perfect, or if we've just had enough } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations ); } tween.unit = unit; tween.start = start; // If a +=/-= token was provided, we're doing a relative animation tween.end = parts[1] ? start + ( parts[1] + 1 ) * end : end; } return tween; }] }; // Animations created synchronously will run synchronously function createFxNow() { setTimeout(function() { fxNow = undefined; }); return ( fxNow = jQuery.now() ); } function createTweens( animation, props ) { jQuery.each( props, function( prop, value ) { var collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ), index = 0, length = collection.length; for ( ; index < length; index++ ) { if ( collection[ index ].call( animation, prop, value ) ) { // we're done with this property return; } } }); } function Animation( elem, properties, options ) { var result, stopped, index = 0, length = animationPrefilters.length, deferred = jQuery.Deferred().always( function() { // don't match elem in the :animated selector delete tick.elem; }), tick = function() { if ( stopped ) { return false; } var currentTime = fxNow || createFxNow(), remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497) temp = remaining / animation.duration || 0, percent = 1 - temp, index = 0, length = animation.tweens.length; for ( ; index < length ; index++ ) { animation.tweens[ index ].run( percent ); } deferred.notifyWith( elem, [ animation, percent, remaining ]); if ( percent < 1 && length ) { return remaining; } else { deferred.resolveWith( elem, [ animation ] ); return false; } }, animation = deferred.promise({ elem: elem, props: jQuery.extend( {}, properties ), opts: jQuery.extend( true, { specialEasing: {} }, options ), originalProperties: properties, originalOptions: options, startTime: fxNow || createFxNow(), duration: options.duration, tweens: [], createTween: function( prop, end ) { var tween = jQuery.Tween( elem, animation.opts, prop, end, animation.opts.specialEasing[ prop ] || animation.opts.easing ); animation.tweens.push( tween ); return tween; }, stop: function( gotoEnd ) { var index = 0, // if we are going to the end, we want to run all the tweens // otherwise we skip this part length = gotoEnd ? animation.tweens.length : 0; if ( stopped ) { return this; } stopped = true; for ( ; index < length ; index++ ) { animation.tweens[ index ].run( 1 ); } // resolve when we played the last frame // otherwise, reject if ( gotoEnd ) { deferred.resolveWith( elem, [ animation, gotoEnd ] ); } else { deferred.rejectWith( elem, [ animation, gotoEnd ] ); } return this; } }), props = animation.props; propFilter( props, animation.opts.specialEasing ); for ( ; index < length ; index++ ) { result = animationPrefilters[ index ].call( animation, elem, props, animation.opts ); if ( result ) { return result; } } createTweens( animation, props ); if ( jQuery.isFunction( animation.opts.start ) ) { animation.opts.start.call( elem, animation ); } jQuery.fx.timer( jQuery.extend( tick, { elem: elem, anim: animation, queue: animation.opts.queue }) ); // attach callbacks from options return animation.progress( animation.opts.progress ) .done( animation.opts.done, animation.opts.complete ) .fail( animation.opts.fail ) .always( animation.opts.always ); } function propFilter( props, specialEasing ) { var value, name, index, easing, hooks; // camelCase, specialEasing and expand cssHook pass for ( index in props ) { name = jQuery.camelCase( index ); easing = specialEasing[ name ]; value = props[ index ]; if ( jQuery.isArray( value ) ) { easing = value[ 1 ]; value = props[ index ] = value[ 0 ]; } if ( index !== name ) { props[ name ] = value; delete props[ index ]; } hooks = jQuery.cssHooks[ name ]; if ( hooks && "expand" in hooks ) { value = hooks.expand( value ); delete props[ name ]; // not quite $.extend, this wont overwrite keys already present. // also - reusing 'index' from above because we have the correct "name" for ( index in value ) { if ( !( index in props ) ) { props[ index ] = value[ index ]; specialEasing[ index ] = easing; } } } else { specialEasing[ name ] = easing; } } } jQuery.Animation = jQuery.extend( Animation, { tweener: function( props, callback ) { if ( jQuery.isFunction( props ) ) { callback = props; props = [ "*" ]; } else { props = props.split(" "); } var prop, index = 0, length = props.length; for ( ; index < length ; index++ ) { prop = props[ index ]; tweeners[ prop ] = tweeners[ prop ] || []; tweeners[ prop ].unshift( callback ); } }, prefilter: function( callback, prepend ) { if ( prepend ) { animationPrefilters.unshift( callback ); } else { animationPrefilters.push( callback ); } } }); function defaultPrefilter( elem, props, opts ) { /*jshint validthis:true */ var prop, index, length, value, dataShow, toggle, tween, hooks, oldfire, anim = this, style = elem.style, orig = {}, handled = [], hidden = elem.nodeType && isHidden( elem ); // handle queue: false promises if ( !opts.queue ) { hooks = jQuery._queueHooks( elem, "fx" ); if ( hooks.unqueued == null ) { hooks.unqueued = 0; oldfire = hooks.empty.fire; hooks.empty.fire = function() { if ( !hooks.unqueued ) { oldfire(); } }; } hooks.unqueued++; anim.always(function() { // doing this makes sure that the complete handler will be called // before this completes anim.always(function() { hooks.unqueued--; if ( !jQuery.queue( elem, "fx" ).length ) { hooks.empty.fire(); } }); }); } // height/width overflow pass if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) { // Make sure that nothing sneaks out // Record all 3 overflow attributes because IE does not // change the overflow attribute when overflowX and // overflowY are set to the same value opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; // Set display property to inline-block for height/width // animations on inline elements that are having width/height animated if ( jQuery.css( elem, "display" ) === "inline" && jQuery.css( elem, "float" ) === "none" ) { // inline-level elements accept inline-block; // block-level elements need to be inline with layout if ( !jQuery.support.inlineBlockNeedsLayout || css_defaultDisplay( elem.nodeName ) === "inline" ) { style.display = "inline-block"; } else { style.zoom = 1; } } } if ( opts.overflow ) { style.overflow = "hidden"; if ( !jQuery.support.shrinkWrapBlocks ) { anim.always(function() { style.overflow = opts.overflow[ 0 ]; style.overflowX = opts.overflow[ 1 ]; style.overflowY = opts.overflow[ 2 ]; }); } } // show/hide pass for ( index in props ) { value = props[ index ]; if ( rfxtypes.exec( value ) ) { delete props[ index ]; toggle = toggle || value === "toggle"; if ( value === ( hidden ? "hide" : "show" ) ) { continue; } handled.push( index ); } } length = handled.length; if ( length ) { dataShow = jQuery._data( elem, "fxshow" ) || jQuery._data( elem, "fxshow", {} ); if ( "hidden" in dataShow ) { hidden = dataShow.hidden; } // store state if its toggle - enables .stop().toggle() to "reverse" if ( toggle ) { dataShow.hidden = !hidden; } if ( hidden ) { jQuery( elem ).show(); } else { anim.done(function() { jQuery( elem ).hide(); }); } anim.done(function() { var prop; jQuery._removeData( elem, "fxshow" ); for ( prop in orig ) { jQuery.style( elem, prop, orig[ prop ] ); } }); for ( index = 0 ; index < length ; index++ ) { prop = handled[ index ]; tween = anim.createTween( prop, hidden ? dataShow[ prop ] : 0 ); orig[ prop ] = dataShow[ prop ] || jQuery.style( elem, prop ); if ( !( prop in dataShow ) ) { dataShow[ prop ] = tween.start; if ( hidden ) { tween.end = tween.start; tween.start = prop === "width" || prop === "height" ? 1 : 0; } } } } } function Tween( elem, options, prop, end, easing ) { return new Tween.prototype.init( elem, options, prop, end, easing ); } jQuery.Tween = Tween; Tween.prototype = { constructor: Tween, init: function( elem, options, prop, end, easing, unit ) { this.elem = elem; this.prop = prop; this.easing = easing || "swing"; this.options = options; this.start = this.now = this.cur(); this.end = end; this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); }, cur: function() { var hooks = Tween.propHooks[ this.prop ]; return hooks && hooks.get ? hooks.get( this ) : Tween.propHooks._default.get( this ); }, run: function( percent ) { var eased, hooks = Tween.propHooks[ this.prop ]; if ( this.options.duration ) { this.pos = eased = jQuery.easing[ this.easing ]( percent, this.options.duration * percent, 0, 1, this.options.duration ); } else { this.pos = eased = percent; } this.now = ( this.end - this.start ) * eased + this.start; if ( this.options.step ) { this.options.step.call( this.elem, this.now, this ); } if ( hooks && hooks.set ) { hooks.set( this ); } else { Tween.propHooks._default.set( this ); } return this; } }; Tween.prototype.init.prototype = Tween.prototype; Tween.propHooks = { _default: { get: function( tween ) { var result; if ( tween.elem[ tween.prop ] != null && (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) { return tween.elem[ tween.prop ]; } // passing an empty string as a 3rd parameter to .css will automatically // attempt a parseFloat and fallback to a string if the parse fails // so, simple values such as "10px" are parsed to Float. // complex values such as "rotate(1rad)" are returned as is. result = jQuery.css( tween.elem, tween.prop, "" ); // Empty strings, null, undefined and "auto" are converted to 0. return !result || result === "auto" ? 0 : result; }, set: function( tween ) { // use step hook for back compat - use cssHook if its there - use .style if its // available and use plain properties where available if ( jQuery.fx.step[ tween.prop ] ) { jQuery.fx.step[ tween.prop ]( tween ); } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) { jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); } else { tween.elem[ tween.prop ] = tween.now; } } } }; // Remove in 2.0 - this supports IE8's panic based approach // to setting things on disconnected nodes Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { set: function( tween ) { if ( tween.elem.nodeType && tween.elem.parentNode ) { tween.elem[ tween.prop ] = tween.now; } } }; jQuery.each([ "toggle", "show", "hide" ], function( i, name ) { var cssFn = jQuery.fn[ name ]; jQuery.fn[ name ] = function( speed, easing, callback ) { return speed == null || typeof speed === "boolean" ? cssFn.apply( this, arguments ) : this.animate( genFx( name, true ), speed, easing, callback ); }; }); jQuery.fn.extend({ fadeTo: function( speed, to, easing, callback ) { // show any hidden elements after setting opacity to 0 return this.filter( isHidden ).css( "opacity", 0 ).show() // animate to the value specified .end().animate({ opacity: to }, speed, easing, callback ); }, animate: function( prop, speed, easing, callback ) { var empty = jQuery.isEmptyObject( prop ), optall = jQuery.speed( speed, easing, callback ), doAnimation = function() { // Operate on a copy of prop so per-property easing won't be lost var anim = Animation( this, jQuery.extend( {}, prop ), optall ); doAnimation.finish = function() { anim.stop( true ); }; // Empty animations, or finishing resolves immediately if ( empty || jQuery._data( this, "finish" ) ) { anim.stop( true ); } }; doAnimation.finish = doAnimation; return empty || optall.queue === false ? this.each( doAnimation ) : this.queue( optall.queue, doAnimation ); }, stop: function( type, clearQueue, gotoEnd ) { var stopQueue = function( hooks ) { var stop = hooks.stop; delete hooks.stop; stop( gotoEnd ); }; if ( typeof type !== "string" ) { gotoEnd = clearQueue; clearQueue = type; type = undefined; } if ( clearQueue && type !== false ) { this.queue( type || "fx", [] ); } return this.each(function() { var dequeue = true, index = type != null && type + "queueHooks", timers = jQuery.timers, data = jQuery._data( this ); if ( index ) { if ( data[ index ] && data[ index ].stop ) { stopQueue( data[ index ] ); } } else { for ( index in data ) { if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { stopQueue( data[ index ] ); } } } for ( index = timers.length; index--; ) { if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) { timers[ index ].anim.stop( gotoEnd ); dequeue = false; timers.splice( index, 1 ); } } // start the next in the queue if the last step wasn't forced // timers currently will call their complete callbacks, which will dequeue // but only if they were gotoEnd if ( dequeue || !gotoEnd ) { jQuery.dequeue( this, type ); } }); }, finish: function( type ) { if ( type !== false ) { type = type || "fx"; } return this.each(function() { var index, data = jQuery._data( this ), queue = data[ type + "queue" ], hooks = data[ type + "queueHooks" ], timers = jQuery.timers, length = queue ? queue.length : 0; // enable finishing flag on private data data.finish = true; // empty the queue first jQuery.queue( this, type, [] ); if ( hooks && hooks.cur && hooks.cur.finish ) { hooks.cur.finish.call( this ); } // look for any active animations, and finish them for ( index = timers.length; index--; ) { if ( timers[ index ].elem === this && timers[ index ].queue === type ) { timers[ index ].anim.stop( true ); timers.splice( index, 1 ); } } // look for any animations in the old queue and finish them for ( index = 0; index < length; index++ ) { if ( queue[ index ] && queue[ index ].finish ) { queue[ index ].finish.call( this ); } } // turn off finishing flag delete data.finish; }); } }); // Generate parameters to create a standard animation function genFx( type, includeWidth ) { var which, attrs = { height: type }, i = 0; // if we include width, step value is 1 to do all cssExpand values, // if we don't include width, step value is 2 to skip over Left and Right includeWidth = includeWidth? 1 : 0; for( ; i < 4 ; i += 2 - includeWidth ) { which = cssExpand[ i ]; attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; } if ( includeWidth ) { attrs.opacity = attrs.width = type; } return attrs; } // Generate shortcuts for custom animations jQuery.each({ slideDown: genFx("show"), slideUp: genFx("hide"), slideToggle: genFx("toggle"), fadeIn: { opacity: "show" }, fadeOut: { opacity: "hide" }, fadeToggle: { opacity: "toggle" } }, function( name, props ) { jQuery.fn[ name ] = function( speed, easing, callback ) { return this.animate( props, speed, easing, callback ); }; }); jQuery.speed = function( speed, easing, fn ) { var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { complete: fn || !fn && easing || jQuery.isFunction( speed ) && speed, duration: speed, easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing }; opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration : opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default; // normalize opt.queue - true/undefined/null -> "fx" if ( opt.queue == null || opt.queue === true ) { opt.queue = "fx"; } // Queueing opt.old = opt.complete; opt.complete = function() { if ( jQuery.isFunction( opt.old ) ) { opt.old.call( this ); } if ( opt.queue ) { jQuery.dequeue( this, opt.queue ); } }; return opt; }; jQuery.easing = { linear: function( p ) { return p; }, swing: function( p ) { return 0.5 - Math.cos( p*Math.PI ) / 2; } }; jQuery.timers = []; jQuery.fx = Tween.prototype.init; jQuery.fx.tick = function() { var timer, timers = jQuery.timers, i = 0; fxNow = jQuery.now(); for ( ; i < timers.length; i++ ) { timer = timers[ i ]; // Checks the timer has not already been removed if ( !timer() && timers[ i ] === timer ) { timers.splice( i--, 1 ); } } if ( !timers.length ) { jQuery.fx.stop(); } fxNow = undefined; }; jQuery.fx.timer = function( timer ) { if ( timer() && jQuery.timers.push( timer ) ) { jQuery.fx.start(); } }; jQuery.fx.interval = 13; jQuery.fx.start = function() { if ( !timerId ) { timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval ); } }; jQuery.fx.stop = function() { clearInterval( timerId ); timerId = null; }; jQuery.fx.speeds = { slow: 600, fast: 200, // Default speed _default: 400 }; // Back Compat <1.8 extension point jQuery.fx.step = {}; if ( jQuery.expr && jQuery.expr.filters ) { jQuery.expr.filters.animated = function( elem ) { return jQuery.grep(jQuery.timers, function( fn ) { return elem === fn.elem; }).length; }; } jQuery.fn.offset = function( options ) { if ( arguments.length ) { return options === undefined ? this : this.each(function( i ) { jQuery.offset.setOffset( this, options, i ); }); } var docElem, win, box = { top: 0, left: 0 }, elem = this[ 0 ], doc = elem && elem.ownerDocument; if ( !doc ) { return; } docElem = doc.documentElement; // Make sure it's not a disconnected DOM node if ( !jQuery.contains( docElem, elem ) ) { return box; } // If we don't have gBCR, just use 0,0 rather than error // BlackBerry 5, iOS 3 (original iPhone) if ( typeof elem.getBoundingClientRect !== core_strundefined ) { box = elem.getBoundingClientRect(); } win = getWindow( doc ); return { top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ), left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 ) }; }; jQuery.offset = { setOffset: function( elem, options, i ) { var position = jQuery.css( elem, "position" ); // set position first, in-case top/left are set even on static elem if ( position === "static" ) { elem.style.position = "relative"; } var curElem = jQuery( elem ), curOffset = curElem.offset(), curCSSTop = jQuery.css( elem, "top" ), curCSSLeft = jQuery.css( elem, "left" ), calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1, props = {}, curPosition = {}, curTop, curLeft; // need to be able to calculate position if either top or left is auto and position is either absolute or fixed if ( calculatePosition ) { curPosition = curElem.position(); curTop = curPosition.top; curLeft = curPosition.left; } else { curTop = parseFloat( curCSSTop ) || 0; curLeft = parseFloat( curCSSLeft ) || 0; } if ( jQuery.isFunction( options ) ) { options = options.call( elem, i, curOffset ); } if ( options.top != null ) { props.top = ( options.top - curOffset.top ) + curTop; } if ( options.left != null ) { props.left = ( options.left - curOffset.left ) + curLeft; } if ( "using" in options ) { options.using.call( elem, props ); } else { curElem.css( props ); } } }; jQuery.fn.extend({ position: function() { if ( !this[ 0 ] ) { return; } var offsetParent, offset, parentOffset = { top: 0, left: 0 }, elem = this[ 0 ]; // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is it's only offset parent if ( jQuery.css( elem, "position" ) === "fixed" ) { // we assume that getBoundingClientRect is available when computed position is fixed offset = elem.getBoundingClientRect(); } else { // Get *real* offsetParent offsetParent = this.offsetParent(); // Get correct offsets offset = this.offset(); if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) { parentOffset = offsetParent.offset(); } // Add offsetParent borders parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ); parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true ); } // Subtract parent offsets and element margins // note: when an element has margin: auto the offsetLeft and marginLeft // are the same in Safari causing offset.left to incorrectly be 0 return { top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ), left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true) }; }, offsetParent: function() { return this.map(function() { var offsetParent = this.offsetParent || document.documentElement; while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position") === "static" ) ) { offsetParent = offsetParent.offsetParent; } return offsetParent || document.documentElement; }); } }); // Create scrollLeft and scrollTop methods jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) { var top = /Y/.test( prop ); jQuery.fn[ method ] = function( val ) { return jQuery.access( this, function( elem, method, val ) { var win = getWindow( elem ); if ( val === undefined ) { return win ? (prop in win) ? win[ prop ] : win.document.documentElement[ method ] : elem[ method ]; } if ( win ) { win.scrollTo( !top ? val : jQuery( win ).scrollLeft(), top ? val : jQuery( win ).scrollTop() ); } else { elem[ method ] = val; } }, method, val, arguments.length, null ); }; }); function getWindow( elem ) { return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 ? elem.defaultView || elem.parentWindow : false; } // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods jQuery.each( { Height: "height", Width: "width" }, function( name, type ) { jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) { // margin is only for outerHeight, outerWidth jQuery.fn[ funcName ] = function( margin, value ) { var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ), extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" ); return jQuery.access( this, function( elem, type, value ) { var doc; if ( jQuery.isWindow( elem ) ) { // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there // isn't a whole lot we can do. See pull request at this URL for discussion: // https://github.com/jquery/jquery/pull/764 return elem.document.documentElement[ "client" + name ]; } // Get document width or height if ( elem.nodeType === 9 ) { doc = elem.documentElement; // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it. return Math.max( elem.body[ "scroll" + name ], doc[ "scroll" + name ], elem.body[ "offset" + name ], doc[ "offset" + name ], doc[ "client" + name ] ); } return value === undefined ? // Get width or height on the element, requesting but not forcing parseFloat jQuery.css( elem, type, extra ) : // Set width or height on the element jQuery.style( elem, type, value, extra ); }, type, chainable ? margin : undefined, chainable, null ); }; }); }); // Limit scope pollution from any deprecated API // (function() { // })(); // Expose jQuery to the global object window.jQuery = window.$ = jQuery; // Expose jQuery as an AMD module, but only for AMD loaders that // understand the issues with loading multiple versions of jQuery // in a page that all might call define(). The loader will indicate // they have special allowances for multiple jQuery versions by // specifying define.amd.jQuery = true. Register as a named module, // since jQuery can be concatenated with other files that may use define, // but not use a proper concatenation script that understands anonymous // AMD modules. A named AMD is safest and most robust way to register. // Lowercase jquery is used because AMD module names are derived from // file names, and jQuery is normally delivered in a lowercase file name. // Do this after creating the global so that if an AMD module wants to call // noConflict to hide this version of jQuery, it will work. if ( typeof define === "function" && define.amd && define.amd.jQuery ) { define( "jquery", [], function () { return jQuery; } ); } })( window );// Underscore.js 1.8.2 // http://underscorejs.org // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors // Underscore may be freely distributed under the MIT license. (function() { // Baseline setup // -------------- // Establish the root object, `window` in the browser, or `exports` on the server. var root = this; // Save the previous value of the `_` variable. var previousUnderscore = root._; // Save bytes in the minified (but not gzipped) version: var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; // Create quick reference variables for speed access to core prototypes. var push = ArrayProto.push, slice = ArrayProto.slice, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; // All **ECMAScript 5** native function implementations that we hope to use // are declared here. var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind, nativeCreate = Object.create; // Naked function reference for surrogate-prototype-swapping. var Ctor = function(){}; // Create a safe reference to the Underscore object for use below. var _ = function(obj) { if (obj instanceof _) return obj; if (!(this instanceof _)) return new _(obj); this._wrapped = obj; }; // Export the Underscore object for **Node.js**, with // backwards-compatibility for the old `require()` API. If we're in // the browser, add `_` as a global object. if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = _; } exports._ = _; } else { root._ = _; } // Current version. _.VERSION = '1.8.2'; // Internal function that returns an efficient (for current engines) version // of the passed-in callback, to be repeatedly applied in other Underscore // functions. var optimizeCb = function(func, context, argCount) { if (context === void 0) return func; switch (argCount == null ? 3 : argCount) { case 1: return function(value) { return func.call(context, value); }; case 2: return function(value, other) { return func.call(context, value, other); }; case 3: return function(value, index, collection) { return func.call(context, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { return func.call(context, accumulator, value, index, collection); }; } return function() { return func.apply(context, arguments); }; }; // A mostly-internal function to generate callbacks that can be applied // to each element in a collection, returning the desired result 鈥? either // identity, an arbitrary callback, a property matcher, or a property accessor. var cb = function(value, context, argCount) { if (value == null) return _.identity; if (_.isFunction(value)) return optimizeCb(value, context, argCount); if (_.isObject(value)) return _.matcher(value); return _.property(value); }; _.iteratee = function(value, context) { return cb(value, context, Infinity); }; // An internal function for creating assigner functions. var createAssigner = function(keysFunc, undefinedOnly) { return function(obj) { var length = arguments.length; if (length < 2 || obj == null) return obj; for (var index = 1; index < length; index++) { var source = arguments[index], keys = keysFunc(source), l = keys.length; for (var i = 0; i < l; i++) { var key = keys[i]; if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key]; } } return obj; }; }; // An internal function for creating a new object that inherits from another. var baseCreate = function(prototype) { if (!_.isObject(prototype)) return {}; if (nativeCreate) return nativeCreate(prototype); Ctor.prototype = prototype; var result = new Ctor; Ctor.prototype = null; return result; }; // Helper for collection methods to determine whether a collection // should be iterated as an array or as an object // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var isArrayLike = function(collection) { var length = collection != null && collection.length; return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX; }; // Collection Functions // -------------------- // The cornerstone, an `each` implementation, aka `forEach`. // Handles raw objects in addition to array-likes. Treats all // sparse array-likes as if they were dense. _.each = _.forEach = function(obj, iteratee, context) { iteratee = optimizeCb(iteratee, context); var i, length; if (isArrayLike(obj)) { for (i = 0, length = obj.length; i < length; i++) { iteratee(obj[i], i, obj); } } else { var keys = _.keys(obj); for (i = 0, length = keys.length; i < length; i++) { iteratee(obj[keys[i]], keys[i], obj); } } return obj; }; // Return the results of applying the iteratee to each element. _.map = _.collect = function(obj, iteratee, context) { iteratee = cb(iteratee, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, results = Array(length); for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; results[index] = iteratee(obj[currentKey], currentKey, obj); } return results; }; // Create a reducing function iterating left or right. function createReduce(dir) { // Optimized iterator function as using arguments.length // in the main function will deoptimize the, see #1991. function iterator(obj, iteratee, memo, keys, index, length) { for (; index >= 0 && index < length; index += dir) { var currentKey = keys ? keys[index] : index; memo = iteratee(memo, obj[currentKey], currentKey, obj); } return memo; } return function(obj, iteratee, memo, context) { iteratee = optimizeCb(iteratee, context, 4); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length, index = dir > 0 ? 0 : length - 1; // Determine the initial value if none is provided. if (arguments.length < 3) { memo = obj[keys ? keys[index] : index]; index += dir; } return iterator(obj, iteratee, memo, keys, index, length); }; } // **Reduce** builds up a single result from a list of values, aka `inject`, // or `foldl`. _.reduce = _.foldl = _.inject = createReduce(1); // The right-associative version of reduce, also known as `foldr`. _.reduceRight = _.foldr = createReduce(-1); // Return the first value which passes a truth test. Aliased as `detect`. _.find = _.detect = function(obj, predicate, context) { var key; if (isArrayLike(obj)) { key = _.findIndex(obj, predicate, context); } else { key = _.findKey(obj, predicate, context); } if (key !== void 0 && key !== -1) return obj[key]; }; // Return all the elements that pass a truth test. // Aliased as `select`. _.filter = _.select = function(obj, predicate, context) { var results = []; predicate = cb(predicate, context); _.each(obj, function(value, index, list) { if (predicate(value, index, list)) results.push(value); }); return results; }; // Return all the elements for which a truth test fails. _.reject = function(obj, predicate, context) { return _.filter(obj, _.negate(cb(predicate)), context); }; // Determine whether all of the elements match a truth test. // Aliased as `all`. _.every = _.all = function(obj, predicate, context) { predicate = cb(predicate, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length; for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; if (!predicate(obj[currentKey], currentKey, obj)) return false; } return true; }; // Determine if at least one element in the object matches a truth test. // Aliased as `any`. _.some = _.any = function(obj, predicate, context) { predicate = cb(predicate, context); var keys = !isArrayLike(obj) && _.keys(obj), length = (keys || obj).length; for (var index = 0; index < length; index++) { var currentKey = keys ? keys[index] : index; if (predicate(obj[currentKey], currentKey, obj)) return true; } return false; }; // Determine if the array or object contains a given value (using `===`). // Aliased as `includes` and `include`. _.contains = _.includes = _.include = function(obj, target, fromIndex) { if (!isArrayLike(obj)) obj = _.values(obj); return _.indexOf(obj, target, typeof fromIndex == 'number' && fromIndex) >= 0; }; // Invoke a method (with arguments) on every item in a collection. _.invoke = function(obj, method) { var args = slice.call(arguments, 2); var isFunc = _.isFunction(method); return _.map(obj, function(value) { var func = isFunc ? method : value[method]; return func == null ? func : func.apply(value, args); }); }; // Convenience version of a common use case of `map`: fetching a property. _.pluck = function(obj, key) { return _.map(obj, _.property(key)); }; // Convenience version of a common use case of `filter`: selecting only objects // containing specific `key:value` pairs. _.where = function(obj, attrs) { return _.filter(obj, _.matcher(attrs)); }; // Convenience version of a common use case of `find`: getting the first object // containing specific `key:value` pairs. _.findWhere = function(obj, attrs) { return _.find(obj, _.matcher(attrs)); }; // Return the maximum element (or element-based computation). _.max = function(obj, iteratee, context) { var result = -Infinity, lastComputed = -Infinity, value, computed; if (iteratee == null && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for (var i = 0, length = obj.length; i < length; i++) { value = obj[i]; if (value > result) { result = value; } } } else { iteratee = cb(iteratee, context); _.each(obj, function(value, index, list) { computed = iteratee(value, index, list); if (computed > lastComputed || computed === -Infinity && result === -Infinity) { result = value; lastComputed = computed; } }); } return result; }; // Return the minimum element (or element-based computation). _.min = function(obj, iteratee, context) { var result = Infinity, lastComputed = Infinity, value, computed; if (iteratee == null && obj != null) { obj = isArrayLike(obj) ? obj : _.values(obj); for (var i = 0, length = obj.length; i < length; i++) { value = obj[i]; if (value < result) { result = value; } } } else { iteratee = cb(iteratee, context); _.each(obj, function(value, index, list) { computed = iteratee(value, index, list); if (computed < lastComputed || computed === Infinity && result === Infinity) { result = value; lastComputed = computed; } }); } return result; }; // Shuffle a collection, using the modern version of the // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher鈥揧ates_shuffle). _.shuffle = function(obj) { var set = isArrayLike(obj) ? obj : _.values(obj); var length = set.length; var shuffled = Array(length); for (var index = 0, rand; index < length; index++) { rand = _.random(0, index); if (rand !== index) shuffled[index] = shuffled[rand]; shuffled[rand] = set[index]; } return shuffled; }; // Sample **n** random values from a collection. // If **n** is not specified, returns a single random element. // The internal `guard` argument allows it to work with `map`. _.sample = function(obj, n, guard) { if (n == null || guard) { if (!isArrayLike(obj)) obj = _.values(obj); return obj[_.random(obj.length - 1)]; } return _.shuffle(obj).slice(0, Math.max(0, n)); }; // Sort the object's values by a criterion produced by an iteratee. _.sortBy = function(obj, iteratee, context) { iteratee = cb(iteratee, context); return _.pluck(_.map(obj, function(value, index, list) { return { value: value, index: index, criteria: iteratee(value, index, list) }; }).sort(function(left, right) { var a = left.criteria; var b = right.criteria; if (a !== b) { if (a > b || a === void 0) return 1; if (a < b || b === void 0) return -1; } return left.index - right.index; }), 'value'); }; // An internal function used for aggregate "group by" operations. var group = function(behavior) { return function(obj, iteratee, context) { var result = {}; iteratee = cb(iteratee, context); _.each(obj, function(value, index) { var key = iteratee(value, index, obj); behavior(result, value, key); }); return result; }; }; // Groups the object's values by a criterion. Pass either a string attribute // to group by, or a function that returns the criterion. _.groupBy = group(function(result, value, key) { if (_.has(result, key)) result[key].push(value); else result[key] = [value]; }); // Indexes the object's values by a criterion, similar to `groupBy`, but for // when you know that your index values will be unique. _.indexBy = group(function(result, value, key) { result[key] = value; }); // Counts instances of an object that group by a certain criterion. Pass // either a string attribute to count by, or a function that returns the // criterion. _.countBy = group(function(result, value, key) { if (_.has(result, key)) result[key]++; else result[key] = 1; }); // Safely create a real, live array from anything iterable. _.toArray = function(obj) { if (!obj) return []; if (_.isArray(obj)) return slice.call(obj); if (isArrayLike(obj)) return _.map(obj, _.identity); return _.values(obj); }; // Return the number of elements in an object. _.size = function(obj) { if (obj == null) return 0; return isArrayLike(obj) ? obj.length : _.keys(obj).length; }; // Split a collection into two arrays: one whose elements all satisfy the given // predicate, and one whose elements all do not satisfy the predicate. _.partition = function(obj, predicate, context) { predicate = cb(predicate, context); var pass = [], fail = []; _.each(obj, function(value, key, obj) { (predicate(value, key, obj) ? pass : fail).push(value); }); return [pass, fail]; }; // Array Functions // --------------- // Get the first element of an array. Passing **n** will return the first N // values in the array. Aliased as `head` and `take`. The **guard** check // allows it to work with `_.map`. _.first = _.head = _.take = function(array, n, guard) { if (array == null) return void 0; if (n == null || guard) return array[0]; return _.initial(array, array.length - n); }; // Returns everything but the last entry of the array. Especially useful on // the arguments object. Passing **n** will return all the values in // the array, excluding the last N. _.initial = function(array, n, guard) { return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n))); }; // Get the last element of an array. Passing **n** will return the last N // values in the array. _.last = function(array, n, guard) { if (array == null) return void 0; if (n == null || guard) return array[array.length - 1]; return _.rest(array, Math.max(0, array.length - n)); }; // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. // Especially useful on the arguments object. Passing an **n** will return // the rest N values in the array. _.rest = _.tail = _.drop = function(array, n, guard) { return slice.call(array, n == null || guard ? 1 : n); }; // Trim out all falsy values from an array. _.compact = function(array) { return _.filter(array, _.identity); }; // Internal implementation of a recursive `flatten` function. var flatten = function(input, shallow, strict, startIndex) { var output = [], idx = 0; for (var i = startIndex || 0, length = input && input.length; i < length; i++) { var value = input[i]; if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) { //flatten current level of array or arguments object if (!shallow) value = flatten(value, shallow, strict); var j = 0, len = value.length; output.length += len; while (j < len) { output[idx++] = value[j++]; } } else if (!strict) { output[idx++] = value; } } return output; }; // Flatten out an array, either recursively (by default), or just one level. _.flatten = function(array, shallow) { return flatten(array, shallow, false); }; // Return a version of the array that does not contain the specified value(s). _.without = function(array) { return _.difference(array, slice.call(arguments, 1)); }; // Produce a duplicate-free version of the array. If the array has already // been sorted, you have the option of using a faster algorithm. // Aliased as `unique`. _.uniq = _.unique = function(array, isSorted, iteratee, context) { if (array == null) return []; if (!_.isBoolean(isSorted)) { context = iteratee; iteratee = isSorted; isSorted = false; } if (iteratee != null) iteratee = cb(iteratee, context); var result = []; var seen = []; for (var i = 0, length = array.length; i < length; i++) { var value = array[i], computed = iteratee ? iteratee(value, i, array) : value; if (isSorted) { if (!i || seen !== computed) result.push(value); seen = computed; } else if (iteratee) { if (!_.contains(seen, computed)) { seen.push(computed); result.push(value); } } else if (!_.contains(result, value)) { result.push(value); } } return result; }; // Produce an array that contains the union: each distinct element from all of // the passed-in arrays. _.union = function() { return _.uniq(flatten(arguments, true, true)); }; // Produce an array that contains every item shared between all the // passed-in arrays. _.intersection = function(array) { if (array == null) return []; var result = []; var argsLength = arguments.length; for (var i = 0, length = array.length; i < length; i++) { var item = array[i]; if (_.contains(result, item)) continue; for (var j = 1; j < argsLength; j++) { if (!_.contains(arguments[j], item)) break; } if (j === argsLength) result.push(item); } return result; }; // Take the difference between one array and a number of other arrays. // Only the elements present in just the first array will remain. _.difference = function(array) { var rest = flatten(arguments, true, true, 1); return _.filter(array, function(value){ return !_.contains(rest, value); }); }; // Zip together multiple lists into a single array -- elements that share // an index go together. _.zip = function() { return _.unzip(arguments); }; // Complement of _.zip. Unzip accepts an array of arrays and groups // each array's elements on shared indices _.unzip = function(array) { var length = array && _.max(array, 'length').length || 0; var result = Array(length); for (var index = 0; index < length; index++) { result[index] = _.pluck(array, index); } return result; }; // Converts lists into objects. Pass either a single array of `[key, value]` // pairs, or two parallel arrays of the same length -- one of keys, and one of // the corresponding values. _.object = function(list, values) { var result = {}; for (var i = 0, length = list && list.length; i < length; i++) { if (values) { result[list[i]] = values[i]; } else { result[list[i][0]] = list[i][1]; } } return result; }; // Return the position of the first occurrence of an item in an array, // or -1 if the item is not included in the array. // If the array is large and already in sort order, pass `true` // for **isSorted** to use binary search. _.indexOf = function(array, item, isSorted) { var i = 0, length = array && array.length; if (typeof isSorted == 'number') { i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted; } else if (isSorted && length) { i = _.sortedIndex(array, item); return array[i] === item ? i : -1; } if (item !== item) { return _.findIndex(slice.call(array, i), _.isNaN); } for (; i < length; i++) if (array[i] === item) return i; return -1; }; _.lastIndexOf = function(array, item, from) { var idx = array ? array.length : 0; if (typeof from == 'number') { idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1); } if (item !== item) { return _.findLastIndex(slice.call(array, 0, idx), _.isNaN); } while (--idx >= 0) if (array[idx] === item) return idx; return -1; }; // Generator function to create the findIndex and findLastIndex functions function createIndexFinder(dir) { return function(array, predicate, context) { predicate = cb(predicate, context); var length = array != null && array.length; var index = dir > 0 ? 0 : length - 1; for (; index >= 0 && index < length; index += dir) { if (predicate(array[index], index, array)) return index; } return -1; }; } // Returns the first index on an array-like that passes a predicate test _.findIndex = createIndexFinder(1); _.findLastIndex = createIndexFinder(-1); // Use a comparator function to figure out the smallest index at which // an object should be inserted so as to maintain order. Uses binary search. _.sortedIndex = function(array, obj, iteratee, context) { iteratee = cb(iteratee, context, 1); var value = iteratee(obj); var low = 0, high = array.length; while (low < high) { var mid = Math.floor((low + high) / 2); if (iteratee(array[mid]) < value) low = mid + 1; else high = mid; } return low; }; // Generate an integer Array containing an arithmetic progression. A port of // the native Python `range()` function. See // [the Python documentation](http://docs.python.org/library/functions.html#range). _.range = function(start, stop, step) { if (arguments.length <= 1) { stop = start || 0; start = 0; } step = step || 1; var length = Math.max(Math.ceil((stop - start) / step), 0); var range = Array(length); for (var idx = 0; idx < length; idx++, start += step) { range[idx] = start; } return range; }; // Function (ahem) Functions // ------------------ // Determines whether to execute a function as a constructor // or a normal function with the provided arguments var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); var self = baseCreate(sourceFunc.prototype); var result = sourceFunc.apply(self, args); if (_.isObject(result)) return result; return self; }; // Create a function bound to a given object (assigning `this`, and arguments, // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if // available. _.bind = function(func, context) { if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function'); var args = slice.call(arguments, 2); var bound = function() { return executeBound(func, bound, context, this, args.concat(slice.call(arguments))); }; return bound; }; // Partially apply a function by creating a version that has had some of its // arguments pre-filled, without changing its dynamic `this` context. _ acts // as a placeholder, allowing any combination of arguments to be pre-filled. _.partial = function(func) { var boundArgs = slice.call(arguments, 1); var bound = function() { var position = 0, length = boundArgs.length; var args = Array(length); for (var i = 0; i < length; i++) { args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i]; } while (position < arguments.length) args.push(arguments[position++]); return executeBound(func, bound, this, this, args); }; return bound; }; // Bind a number of an object's methods to that object. Remaining arguments // are the method names to be bound. Useful for ensuring that all callbacks // defined on an object belong to it. _.bindAll = function(obj) { var i, length = arguments.length, key; if (length <= 1) throw new Error('bindAll must be passed function names'); for (i = 1; i < length; i++) { key = arguments[i]; obj[key] = _.bind(obj[key], obj); } return obj; }; // Memoize an expensive function by storing its results. _.memoize = function(func, hasher) { var memoize = function(key) { var cache = memoize.cache; var address = '' + (hasher ? hasher.apply(this, arguments) : key); if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); return cache[address]; }; memoize.cache = {}; return memoize; }; // Delays a function for the given number of milliseconds, and then calls // it with the arguments supplied. _.delay = function(func, wait) { var args = slice.call(arguments, 2); return setTimeout(function(){ return func.apply(null, args); }, wait); }; // Defers a function, scheduling it to run after the current call stack has // cleared. _.defer = _.partial(_.delay, _, 1); // Returns a function, that, when invoked, will only be triggered at most once // during a given window of time. Normally, the throttled function will run // as much as it can, without ever going more than once per `wait` duration; // but if you'd like to disable the execution on the leading edge, pass // `{leading: false}`. To disable execution on the trailing edge, ditto. _.throttle = function(func, wait, options) { var context, args, result; var timeout = null; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; return function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; }; // Returns a function, that, as long as it continues to be invoked, will not // be triggered. The function will be called after it stops being called for // N milliseconds. If `immediate` is passed, trigger the function on the // leading edge, instead of the trailing. _.debounce = function(func, wait, immediate) { var timeout, args, context, timestamp, result; var later = function() { var last = _.now() - timestamp; if (last < wait && last >= 0) { timeout = setTimeout(later, wait - last); } else { timeout = null; if (!immediate) { result = func.apply(context, args); if (!timeout) context = args = null; } } }; return function() { context = this; args = arguments; timestamp = _.now(); var callNow = immediate && !timeout; if (!timeout) timeout = setTimeout(later, wait); if (callNow) { result = func.apply(context, args); context = args = null; } return result; }; }; // Returns the first function passed as an argument to the second, // allowing you to adjust arguments, run code before and after, and // conditionally execute the original function. _.wrap = function(func, wrapper) { return _.partial(wrapper, func); }; // Returns a negated version of the passed-in predicate. _.negate = function(predicate) { return function() { return !predicate.apply(this, arguments); }; }; // Returns a function that is the composition of a list of functions, each // consuming the return value of the function that follows. _.compose = function() { var args = arguments; var start = args.length - 1; return function() { var i = start; var result = args[start].apply(this, arguments); while (i--) result = args[i].call(this, result); return result; }; }; // Returns a function that will only be executed on and after the Nth call. _.after = function(times, func) { return function() { if (--times < 1) { return func.apply(this, arguments); } }; }; // Returns a function that will only be executed up to (but not including) the Nth call. _.before = function(times, func) { var memo; return function() { if (--times > 0) { memo = func.apply(this, arguments); } if (times <= 1) func = null; return memo; }; }; // Returns a function that will be executed at most one time, no matter how // often you call it. Useful for lazy initialization. _.once = _.partial(_.before, 2); // Object Functions // ---------------- // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed. var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString'); var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString', 'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString']; function collectNonEnumProps(obj, keys) { var nonEnumIdx = nonEnumerableProps.length; var constructor = obj.constructor; var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto; // Constructor is a special case. var prop = 'constructor'; if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop); while (nonEnumIdx--) { prop = nonEnumerableProps[nonEnumIdx]; if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) { keys.push(prop); } } } // Retrieve the names of an object's own properties. // Delegates to **ECMAScript 5**'s native `Object.keys` _.keys = function(obj) { if (!_.isObject(obj)) return []; if (nativeKeys) return nativeKeys(obj); var keys = []; for (var key in obj) if (_.has(obj, key)) keys.push(key); // Ahem, IE < 9. if (hasEnumBug) collectNonEnumProps(obj, keys); return keys; }; // Retrieve all the property names of an object. _.allKeys = function(obj) { if (!_.isObject(obj)) return []; var keys = []; for (var key in obj) keys.push(key); // Ahem, IE < 9. if (hasEnumBug) collectNonEnumProps(obj, keys); return keys; }; // Retrieve the values of an object's properties. _.values = function(obj) { var keys = _.keys(obj); var length = keys.length; var values = Array(length); for (var i = 0; i < length; i++) { values[i] = obj[keys[i]]; } return values; }; // Returns the results of applying the iteratee to each element of the object // In contrast to _.map it returns an object _.mapObject = function(obj, iteratee, context) { iteratee = cb(iteratee, context); var keys = _.keys(obj), length = keys.length, results = {}, currentKey; for (var index = 0; index < length; index++) { currentKey = keys[index]; results[currentKey] = iteratee(obj[currentKey], currentKey, obj); } return results; }; // Convert an object into a list of `[key, value]` pairs. _.pairs = function(obj) { var keys = _.keys(obj); var length = keys.length; var pairs = Array(length); for (var i = 0; i < length; i++) { pairs[i] = [keys[i], obj[keys[i]]]; } return pairs; }; // Invert the keys and values of an object. The values must be serializable. _.invert = function(obj) { var result = {}; var keys = _.keys(obj); for (var i = 0, length = keys.length; i < length; i++) { result[obj[keys[i]]] = keys[i]; } return result; }; // Return a sorted list of the function names available on the object. // Aliased as `methods` _.functions = _.methods = function(obj) { var names = []; for (var key in obj) { if (_.isFunction(obj[key])) names.push(key); } return names.sort(); }; // Extend a given object with all the properties in passed-in object(s). _.extend = createAssigner(_.allKeys); // Assigns a given object with all the own properties in the passed-in object(s) // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) _.extendOwn = _.assign = createAssigner(_.keys); // Returns the first key on an object that passes a predicate test _.findKey = function(obj, predicate, context) { predicate = cb(predicate, context); var keys = _.keys(obj), key; for (var i = 0, length = keys.length; i < length; i++) { key = keys[i]; if (predicate(obj[key], key, obj)) return key; } }; // Return a copy of the object only containing the whitelisted properties. _.pick = function(object, oiteratee, context) { var result = {}, obj = object, iteratee, keys; if (obj == null) return result; if (_.isFunction(oiteratee)) { keys = _.allKeys(obj); iteratee = optimizeCb(oiteratee, context); } else { keys = flatten(arguments, false, false, 1); iteratee = function(value, key, obj) { return key in obj; }; obj = Object(obj); } for (var i = 0, length = keys.length; i < length; i++) { var key = keys[i]; var value = obj[key]; if (iteratee(value, key, obj)) result[key] = value; } return result; }; // Return a copy of the object without the blacklisted properties. _.omit = function(obj, iteratee, context) { if (_.isFunction(iteratee)) { iteratee = _.negate(iteratee); } else { var keys = _.map(flatten(arguments, false, false, 1), String); iteratee = function(value, key) { return !_.contains(keys, key); }; } return _.pick(obj, iteratee, context); }; // Fill in a given object with default properties. _.defaults = createAssigner(_.allKeys, true); // Creates an object that inherits from the given prototype object. // If additional properties are provided then they will be added to the // created object. _.create = function(prototype, props) { var result = baseCreate(prototype); if (props) _.extendOwn(result, props); return result; }; // Create a (shallow-cloned) duplicate of an object. _.clone = function(obj) { if (!_.isObject(obj)) return obj; return _.isArray(obj) ? obj.slice() : _.extend({}, obj); }; // Invokes interceptor with the obj, and then returns obj. // The primary purpose of this method is to "tap into" a method chain, in // order to perform operations on intermediate results within the chain. _.tap = function(obj, interceptor) { interceptor(obj); return obj; }; // Returns whether an object has a given set of `key:value` pairs. _.isMatch = function(object, attrs) { var keys = _.keys(attrs), length = keys.length; if (object == null) return !length; var obj = Object(object); for (var i = 0; i < length; i++) { var key = keys[i]; if (attrs[key] !== obj[key] || !(key in obj)) return false; } return true; }; // Internal recursive comparison function for `isEqual`. var eq = function(a, b, aStack, bStack) { // Identical objects are equal. `0 === -0`, but they aren't identical. // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal). if (a === b) return a !== 0 || 1 / a === 1 / b; // A strict comparison is necessary because `null == undefined`. if (a == null || b == null) return a === b; // Unwrap any wrapped objects. if (a instanceof _) a = a._wrapped; if (b instanceof _) b = b._wrapped; // Compare `[[Class]]` names. var className = toString.call(a); if (className !== toString.call(b)) return false; switch (className) { // Strings, numbers, regular expressions, dates, and booleans are compared by value. case '[object RegExp]': // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') case '[object String]': // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is // equivalent to `new String("5")`. return '' + a === '' + b; case '[object Number]': // `NaN`s are equivalent, but non-reflexive. // Object(NaN) is equivalent to NaN if (+a !== +a) return +b !== +b; // An `egal` comparison is performed for other numeric values. return +a === 0 ? 1 / +a === 1 / b : +a === +b; case '[object Date]': case '[object Boolean]': // Coerce dates and booleans to numeric primitive values. Dates are compared by their // millisecond representations. Note that invalid dates with millisecond representations // of `NaN` are not equivalent. return +a === +b; } var areArrays = className === '[object Array]'; if (!areArrays) { if (typeof a != 'object' || typeof b != 'object') return false; // Objects with different constructors are not equivalent, but `Object`s or `Array`s // from different frames are. var aCtor = a.constructor, bCtor = b.constructor; if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor && _.isFunction(bCtor) && bCtor instanceof bCtor) && ('constructor' in a && 'constructor' in b)) { return false; } } // Assume equality for cyclic structures. The algorithm for detecting cyclic // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. // Initializing stack of traversed objects. // It's done here since we only need them for objects and arrays comparison. aStack = aStack || []; bStack = bStack || []; var length = aStack.length; while (length--) { // Linear search. Performance is inversely proportional to the number of // unique nested structures. if (aStack[length] === a) return bStack[length] === b; } // Add the first object to the stack of traversed objects. aStack.push(a); bStack.push(b); // Recursively compare objects and arrays. if (areArrays) { // Compare array lengths to determine if a deep comparison is necessary. length = a.length; if (length !== b.length) return false; // Deep compare the contents, ignoring non-numeric properties. while (length--) { if (!eq(a[length], b[length], aStack, bStack)) return false; } } else { // Deep compare objects. var keys = _.keys(a), key; length = keys.length; // Ensure that both objects contain the same number of properties before comparing deep equality. if (_.keys(b).length !== length) return false; while (length--) { // Deep compare each member key = keys[length]; if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; } } // Remove the first object from the stack of traversed objects. aStack.pop(); bStack.pop(); return true; }; // Perform a deep comparison to check if two objects are equal. _.isEqual = function(a, b) { return eq(a, b); }; // Is a given array, string, or object empty? // An "empty" object has no enumerable own-properties. _.isEmpty = function(obj) { if (obj == null) return true; if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0; return _.keys(obj).length === 0; }; // Is a given value a DOM element? _.isElement = function(obj) { return !!(obj && obj.nodeType === 1); }; // Is a given value an array? // Delegates to ECMA5's native Array.isArray _.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; }; // Is a given variable an object? _.isObject = function(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !!obj; }; // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError. _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) { _['is' + name] = function(obj) { return toString.call(obj) === '[object ' + name + ']'; }; }); // Define a fallback version of the method in browsers (ahem, IE < 9), where // there isn't any inspectable "Arguments" type. if (!_.isArguments(arguments)) { _.isArguments = function(obj) { return _.has(obj, 'callee'); }; } // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8, // IE 11 (#1621), and in Safari 8 (#1929). if (typeof /./ != 'function' && typeof Int8Array != 'object') { _.isFunction = function(obj) { return typeof obj == 'function' || false; }; } // Is a given object a finite number? _.isFinite = function(obj) { return isFinite(obj) && !isNaN(parseFloat(obj)); }; // Is the given value `NaN`? (NaN is the only number which does not equal itself). _.isNaN = function(obj) { return _.isNumber(obj) && obj !== +obj; }; // Is a given value a boolean? _.isBoolean = function(obj) { return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; }; // Is a given value equal to null? _.isNull = function(obj) { return obj === null; }; // Is a given variable undefined? _.isUndefined = function(obj) { return obj === void 0; }; // Shortcut function for checking if an object has a given property directly // on itself (in other words, not on a prototype). _.has = function(obj, key) { return obj != null && hasOwnProperty.call(obj, key); }; // Utility Functions // ----------------- // Run Underscore.js in *noConflict* mode, returning the `_` variable to its // previous owner. Returns a reference to the Underscore object. _.noConflict = function() { root._ = previousUnderscore; return this; }; // Keep the identity function around for default iteratees. _.identity = function(value) { return value; }; // Predicate-generating functions. Often useful outside of Underscore. _.constant = function(value) { return function() { return value; }; }; _.noop = function(){}; _.property = function(key) { return function(obj) { return obj == null ? void 0 : obj[key]; }; }; // Generates a function for a given object that returns a given property. _.propertyOf = function(obj) { return obj == null ? function(){} : function(key) { return obj[key]; }; }; // Returns a predicate for checking whether an object has a given set of // `key:value` pairs. _.matcher = _.matches = function(attrs) { attrs = _.extendOwn({}, attrs); return function(obj) { return _.isMatch(obj, attrs); }; }; // Run a function **n** times. _.times = function(n, iteratee, context) { var accum = Array(Math.max(0, n)); iteratee = optimizeCb(iteratee, context, 1); for (var i = 0; i < n; i++) accum[i] = iteratee(i); return accum; }; // Return a random integer between min and max (inclusive). _.random = function(min, max) { if (max == null) { max = min; min = 0; } return min + Math.floor(Math.random() * (max - min + 1)); }; // A (possibly faster) way to get the current timestamp as an integer. _.now = Date.now || function() { return new Date().getTime(); }; // List of HTML entities for escaping. var escapeMap = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', '`': '`' }; var unescapeMap = _.invert(escapeMap); // Functions for escaping and unescaping strings to/from HTML interpolation. var createEscaper = function(map) { var escaper = function(match) { return map[match]; }; // Regexes for identifying a key that needs to be escaped var source = '(?:' + _.keys(map).join('|') + ')'; var testRegexp = RegExp(source); var replaceRegexp = RegExp(source, 'g'); return function(string) { string = string == null ? '' : '' + string; return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string; }; }; _.escape = createEscaper(escapeMap); _.unescape = createEscaper(unescapeMap); // If the value of the named `property` is a function then invoke it with the // `object` as context; otherwise, return it. _.result = function(object, property, fallback) { var value = object == null ? void 0 : object[property]; if (value === void 0) { value = fallback; } return _.isFunction(value) ? value.call(object) : value; }; // Generate a unique integer id (unique within the entire client session). // Useful for temporary DOM ids. var idCounter = 0; _.uniqueId = function(prefix) { var id = ++idCounter + ''; return prefix ? prefix + id : id; }; // By default, Underscore uses ERB-style template delimiters, change the // following template settings to use alternative delimiters. _.templateSettings = { evaluate : /<%([\s\S]+?)%>/g, interpolate : /<%=([\s\S]+?)%>/g, escape : /<%-([\s\S]+?)%>/g }; // When customizing `templateSettings`, if you don't want to define an // interpolation, evaluation or escaping regex, we need one that is // guaranteed not to match. var noMatch = /(.)^/; // Certain characters need to be escaped so that they can be put into a // string literal. var escapes = { "'": "'", '\\': '\\', '\r': 'r', '\n': 'n', '\u2028': 'u2028', '\u2029': 'u2029' }; var escaper = /\\|'|\r|\n|\u2028|\u2029/g; var escapeChar = function(match) { return '\\' + escapes[match]; }; // JavaScript micro-templating, similar to John Resig's implementation. // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. // NB: `oldSettings` only exists for backwards compatibility. _.template = function(text, settings, oldSettings) { if (!settings && oldSettings) settings = oldSettings; settings = _.defaults({}, settings, _.templateSettings); // Combine delimiters into one regular expression via alternation. var matcher = RegExp([ (settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source ].join('|') + '|$', 'g'); // Compile the template source, escaping string literals appropriately. var index = 0; var source = "__p+='"; text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset).replace(escaper, escapeChar); index = offset + match.length; if (escape) { source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; } else if (interpolate) { source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; } else if (evaluate) { source += "';\n" + evaluate + "\n__p+='"; } // Adobe VMs need the match returned to produce the correct offest. return match; }); source += "';\n"; // If a variable is not specified, place data values in local scope. if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; source = "var __t,__p='',__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,'');};\n" + source + 'return __p;\n'; try { var render = new Function(settings.variable || 'obj', '_', source); } catch (e) { e.source = source; throw e; } var template = function(data) { return render.call(this, data, _); }; // Provide the compiled source as a convenience for precompilation. var argument = settings.variable || 'obj'; template.source = 'function(' + argument + '){\n' + source + '}'; return template; }; // Add a "chain" function. Start chaining a wrapped Underscore object. _.chain = function(obj) { var instance = _(obj); instance._chain = true; return instance; }; // OOP // --------------- // If Underscore is called as a function, it returns a wrapped object that // can be used OO-style. This wrapper holds altered versions of all the // underscore functions. Wrapped objects may be chained. // Helper function to continue chaining intermediate results. var result = function(instance, obj) { return instance._chain ? _(obj).chain() : obj; }; // Add your own custom functions to the Underscore object. _.mixin = function(obj) { _.each(_.functions(obj), function(name) { var func = _[name] = obj[name]; _.prototype[name] = function() { var args = [this._wrapped]; push.apply(args, arguments); return result(this, func.apply(_, args)); }; }); }; // Add all of the Underscore functions to the wrapper object. _.mixin(_); // Add all mutator Array functions to the wrapper. _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { var obj = this._wrapped; method.apply(obj, arguments); if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0]; return result(this, obj); }; }); // Add all accessor Array functions to the wrapper. _.each(['concat', 'join', 'slice'], function(name) { var method = ArrayProto[name]; _.prototype[name] = function() { return result(this, method.apply(this._wrapped, arguments)); }; }); // Extracts the result from a wrapped and chained object. _.prototype.value = function() { return this._wrapped; }; // Provide unwrapping proxy for some methods used in engine operations // such as arithmetic and JSON stringification. _.prototype.valueOf = _.prototype.toJSON = _.prototype.value; _.prototype.toString = function() { return '' + this._wrapped; }; // AMD registration happens at the end for compatibility with AMD loaders // that may not enforce next-turn semantics on modules. Even though general // practice for AMD registration is to be anonymous, underscore registers // as a named module because, like jQuery, it is a base library that is // popular enough to be bundled in a third party lib, but not be part of // an AMD load request. Those cases could generate an error when an // anonymous define() is called outside of a loader request. if (typeof define === 'function' && define.amd) { define('underscore', [], function() { return _; }); } }.call(this));/** * Created by richie on 15/7/8. */ /** * 初始化BI对象 */ if (window.BI == null) { window.BI = {}; }/** * MVC工厂 * guy * @class BI.Factory */ BI.Factory = { parsePath: function parsePath (path) { var segments = path.split('.'); return function (obj) { for (var i = 0; i < segments.length; i++) { if (!obj) { return; } obj = obj[segments[i]]; } return obj; } }, createView : function(url, viewFunc, mData, vData, context){ var modelFunc = viewFunc.replace(/View/, "Model"); modelFunc = this.parsePath(modelFunc)(window); if(!_.isFunction(modelFunc)){ modelFunc = BI.Model; } // try { var model = new (modelFunc)(_.extend({}, mData, { parent: context && context.model, rootURL: url }), {silent: true}); // } catch (e) { // // } // try { var view = new (eval(viewFunc))(_.extend({}, vData, { model: model, parent: context, rootURL: url })); // } catch (e) { // // } return view; } };(function (root, factory) { root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); }(this, function (root, BI, _, $) { var previousBI = root.BI; // Create local references to array methods we'll want to use later. var array = []; var slice = array.slice; // Current version of the library. Keep in sync with `package.json`. BI.VERSION = '1.0.0'; // For BI's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns // the `$` variable. BI.$ = $; // Runs BI.js in *noConflict* mode, returning the `BI` variable // to its previous owner. Returns a reference to this BI object. BI.noConflict = function () { root.BI = previousBI; return this; }; // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option // will fake `"PATCH"`, `"PUT"` and `"DELETE"` requests via the `_method` parameter and // set a `X-Http-Method-Override` header. BI.emulateHTTP = true; // Turn on `emulateJSON` to support legacy servers that can't deal with direct // `application/json` requests ... this will encode the body as // `application/x-www-form-urlencoded` instead and will send the model in a // form param named `model`. BI.emulateJSON = true; // BI.Events // --------------- // A module that can be mixed in to *any object* in order to provide it with // custom events. You may bind with `on` or remove with `off` callback // functions to an event; `trigger`-ing an event fires all callbacks in // succession. // // var object = {}; // _.extend(object, BI.Events); // object.on('expand', function(){ alert('expanded'); }); // object.trigger('expand'); // var Events = BI.Events = { // Bind an event to a `callback` function. Passing `"all"` will bind // the callback to all events fired. on: function (name, callback, context) { if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; this._events || (this._events = {}); var events = this._events[name] || (this._events[name] = []); events.push({callback: callback, context: context, ctx: context || this}); return this; }, // Bind an event to only be triggered a single time. After the first time // the callback is invoked, it will be removed. once: function (name, callback, context) { if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; var once = _.once(function () { self.off(name, once); callback.apply(this, arguments); }); once._callback = callback; return this.on(name, once, context); }, // Remove one or many callbacks. If `context` is null, removes all // callbacks with that function. If `callback` is null, removes all // callbacks for the event. If `name` is null, removes all bound // callbacks for all events. off: function (name, callback, context) { if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; // Remove all callbacks for all events. if (!name && !callback && !context) { this._events = void 0; return this; } var names = name ? [name] : _.keys(this._events); for (var i = 0, length = names.length; i < length; i++) { name = names[i]; // Bail out if there are no events stored. var events = this._events[name]; if (!events) continue; // Remove all callbacks for this event. if (!callback && !context) { delete this._events[name]; continue; } // Find any remaining events. var remaining = []; for (var j = 0, k = events.length; j < k; j++) { var event = events[j]; if ( callback && callback !== event.callback && callback !== event.callback._callback || context && context !== event.context ) { remaining.push(event); } } // Replace events if there are any remaining. Otherwise, clean up. if (remaining.length) { this._events[name] = remaining; } else { delete this._events[name]; } } return this; }, un: function () { this.off.apply(this, arguments); }, // Trigger one or many events, firing all bound callbacks. Callbacks are // passed the same arguments as `trigger` is, apart from the event name // (unless you're listening on `"all"`, which will cause your callback to // receive the true name of the event as the first argument). trigger: function (name) { if (!this._events) return this; var args = slice.call(arguments, 1); if (!eventsApi(this, 'trigger', name, args)) return this; var events = this._events[name]; var allEvents = this._events.all; if (events) triggerEvents(events, args); if (allEvents) triggerEvents(allEvents, arguments); return this; }, fireEvent: function () { this.trigger.apply(this, arguments); }, // Inversion-of-control versions of `on` and `once`. Tell *this* object to // listen to an event in another object ... keeping track of what it's // listening to. listenTo: function (obj, name, callback) { var listeningTo = this._listeningTo || (this._listeningTo = {}); var id = obj._listenId || (obj._listenId = _.uniqueId('l')); listeningTo[id] = obj; if (!callback && typeof name === 'object') callback = this; obj.on(name, callback, this); return this; }, listenToOnce: function (obj, name, callback) { if (typeof name === 'object') { for (var event in name) this.listenToOnce(obj, event, name[event]); return this; } if (eventSplitter.test(name)) { var names = name.split(eventSplitter); for (var i = 0, length = names.length; i < length; i++) { this.listenToOnce(obj, names[i], callback); } return this; } if (!callback) return this; var once = _.once(function () { this.stopListening(obj, name, once); callback.apply(this, arguments); }); once._callback = callback; return this.listenTo(obj, name, once); }, // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. stopListening: function (obj, name, callback) { var listeningTo = this._listeningTo; if (!listeningTo) return this; var remove = !name && !callback; if (!callback && typeof name === 'object') callback = this; if (obj) (listeningTo = {})[obj._listenId] = obj; for (var id in listeningTo) { obj = listeningTo[id]; obj.off(name, callback, this); if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id]; } return this; } }; // Regular expression used to split event strings. var eventSplitter = /\s+/; // Implement fancy features of the Events API such as multiple event // names `"change blur"` and jQuery-style event maps `{change: action}` // in terms of the existing API. var eventsApi = function (obj, action, name, rest) { if (!name) return true; // Handle event maps. if (typeof name === 'object') { for (var key in name) { obj[action].apply(obj, [key, name[key]].concat(rest)); } return false; } // Handle space separated event names. if (eventSplitter.test(name)) { var names = name.split(eventSplitter); for (var i = 0, length = names.length; i < length; i++) { obj[action].apply(obj, [names[i]].concat(rest)); } return false; } return true; }; // A difficult-to-believe, but optimized internal dispatch function for // triggering events. Tries to keep the usual cases speedy (most internal // BI events have 3 arguments). var triggerEvents = function (events, args) { var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; switch (args.length) { case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return; } }; // Aliases for backwards compatibility. Events.bind = Events.on; Events.unbind = Events.off; // Allow the `BI` object to serve as a global event bus, for folks who // want global "pubsub" in a convenient place. _.extend(BI, Events); // BI.M // -------------- // BI **Models** are the basic data object in the framework -- // frequently representing a row in a table in a database on your server. // A discrete chunk of data and a bunch of useful, related methods for // performing computations and transformations on that data. // Create a new model with the specified attributes. A client id (`cid`) // is automatically generated and assigned for you. var M = BI.M = function (attributes, options) { var attrs = attributes || {}; options = options || {}; this.cid = _.uniqueId('c'); this.attributes = {}; if (options.collection) this.collection = options.collection; if (options.parse) attrs = this.parse(attrs, options) || {}; this.options = attrs = _.defaults({}, attrs, _.result(this, '_defaultConfig')); _.extend(this, _.pick(this.options, modelOptions)); this.set(attrs, options); this.changed = {}; this._init.apply(this, arguments); }; var modelOptions = ['rootURL', 'parent', 'data', 'id']; // Attach all inheritable methods to the M prototype. _.extend(M.prototype, Events, { // A hash of attributes whose current and previous value differ. changed: null, // The value returned during the last failed validation. validationError: null, // The default name for the JSON `id` attribute is `"id"`. MongoDB and // CouchDB users may want to set this to `"_id"`. idAttribute: 'ID', _defaultConfig: function () { return {} }, // _init is an empty function by default. Override it with your own // initialization logic. _init: function () { }, // Return a copy of the model's `attributes` object. toJSON: function (options) { return _.clone(this.attributes); }, // Proxy `BI.sync` by default -- but override this if you need // custom syncing semantics for *this* particular model. sync: function () { return BI.sync.apply(this, arguments); }, // Get the value of an attribute. get: function (attr) { return this.attributes[attr]; }, // Get the HTML-escaped value of an attribute. escape: function (attr) { return _.escape(this.get(attr)); }, // Returns `true` if the attribute contains a value that is not null // or undefined. has: function (attr) { return _.has(this.attributes, attr); }, // Special-cased proxy to underscore's `_.matches` method. matches: function (attrs) { var keys = _.keys(attrs), length = keys.length; var obj = Object(this.attributes); for (var i = 0; i < length; i++) { var key = keys[i]; if (!_.isEqual(attrs[key], obj[key]) || !(key in obj)) return false; } return true; }, // Set a hash of model attributes on the object, firing `"change"`. This is // the core primitive operation of a model, updating the data and notifying // anyone who needs to know about the change in state. The heart of the beast. set: function (key, val, options) { var attr, attrs, unset, changes, silent, changing, changed, prev, current; if (key == null) return this; // Handle both `"key", value` and `{key: value}` -style arguments. if (typeof key === 'object') { attrs = key; options = val; } else { (attrs = {})[key] = val; } options || (options = {}); // Run validation. if (!this._validate(attrs, options)) return false; // Extract attributes and options. unset = options.unset; silent = options.silent; changes = []; changing = this._changing; this._changing = true; if (!changing) { this._previousAttributes = _.clone(this.attributes); this.changed = {}; } current = this.attributes, prev = this._previousAttributes; // Check for changes of `id`. if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; // For each `set` attribute, update or delete the current value. for (attr in attrs) { val = attrs[attr]; if (!_.isEqual(current[attr], val)) changes.push(attr); if (!_.isEqual(prev[attr], val)) { this.changed[attr] = val; } else { delete this.changed[attr]; } unset ? delete current[attr] : current[attr] = val; } // Trigger all relevant attribute changes. if (!silent) { if (changes.length) this._pending = options; for (var i = 0, length = changes.length; i < length; i++) { this.trigger('change:' + changes[i], this, current[changes[i]], options); } } // You might be wondering why there's a `while` loop here. Changes can // be recursively nested within `"change"` events. if (changing) return this; changed = BI.clone(this.changed); if (!silent) { while (this._pending) { options = this._pending; this._pending = false; this.trigger('change', changed, prev, this, options); } } this._pending = false; this._changing = false; if (!silent && changes.length) this.trigger("changed", changed, prev, this, options); return this; }, // Remove an attribute from the model, firing `"change"`. `unset` is a noop // if the attribute doesn't exist. unset: function (attr, options) { return this.set(attr, void 0, _.extend({}, options, {unset: true})); }, // Clear all attributes on the model, firing `"change"`. clear: function (options) { var attrs = {}; for (var key in this.attributes) attrs[key] = void 0; return this.set(attrs, _.extend({}, options, {unset: true})); }, // Determine if the model has changed since the last `"change"` event. // If you specify an attribute name, determine if that attribute has changed. hasChanged: function (attr) { if (attr == null) return !_.isEmpty(this.changed); return _.has(this.changed, attr); }, // Return an object containing all the attributes that have changed, or // false if there are no changed attributes. Useful for determining what // parts of a view need to be updated and/or what attributes need to be // persisted to the server. Unset attributes will be set to undefined. // You can also pass an attributes object to diff against the model, // determining if there *would be* a change. changedAttributes: function (diff) { if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; var val, changed = false; var old = this._changing ? this._previousAttributes : this.attributes; for (var attr in diff) { if (_.isEqual(old[attr], (val = diff[attr]))) continue; (changed || (changed = {}))[attr] = val; } return changed; }, // Get the previous value of an attribute, recorded at the time the last // `"change"` event was fired. previous: function (attr) { if (attr == null || !this._previousAttributes) return null; return this._previousAttributes[attr]; }, // Get all of the attributes of the model at the time of the previous // `"change"` event. previousAttributes: function () { return _.clone(this._previousAttributes); }, // Fetch the model from the server. If the server's representation of the // model differs from its current attributes, they will be overridden, // triggering a `"change"` event. fetch: function (options) { options = options ? _.clone(options) : {}; if (options.parse === void 0) options.parse = true; var model = this; var success = options.success; options.success = function (resp) { if (!options.noset) { if (!model.set(model.parse(resp, options), options)) return false; } if (success) success(resp, model, options); model.trigger('sync', resp, model, options).trigger('read', resp, model, options); }; wrapError(this, options); return this.sync('read', this, options); }, // Set a hash of model attributes, and sync the model to the server. // If the server returns an attributes hash that differs, the model's // state will be `set` again. save: function (key, val, options) { var attrs, method, xhr, attributes = this.attributes; // Handle both `"key", value` and `{key: value}` -style arguments. if (key == null || typeof key === 'object') { attrs = key; options = val; } else { (attrs = {})[key] = val; } options = _.extend({validate: true}, options); // If we're not waiting and attributes exist, save acts as // `set(attr).save(null, opts)` with validation. Otherwise, check if // the model will be valid when the attributes, if any, are set. if (attrs && !options.wait) { if (!this.set(attrs, options)) return false; } else { if (!this._validate(attrs, options)) return false; } // Set temporary attributes if `{wait: true}`. if (attrs && options.wait) { this.attributes = _.extend({}, attributes, attrs); } // After a successful server-side save, the client is (optionally) // updated with the server-side state. if (options.parse === void 0) options.parse = true; var model = this; var success = options.success; options.success = function (resp) { // Ensure attributes are restored during synchronous saves. model.attributes = attributes; var serverAttrs = model.parse(resp, options); if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); if (_.isObject(serverAttrs) && !options.noset && !model.set(serverAttrs, options)) { return false; } if (success) success(resp, model, options); model.trigger('sync', resp, model, options) .trigger((options.patch ? 'patch' : 'update'), resp, model, options); }; wrapError(this, options); method = /**this.isNew() ? 'create' :**/ (options.patch ? 'patch' : 'update'); if (method === 'patch' && !options.attrs) options.attrs = attrs; xhr = this.sync(method, this, options); // Restore attributes. if (attrs && options.wait) this.attributes = attributes; return xhr; }, // Destroy this model on the server if it was already persisted. // Optimistically removes the model from its collection, if it has one. // If `wait: true` is passed, waits for the server to respond before removal. destroy: function (options) { options = options ? _.clone(options) : {}; var model = this; var success = options.success; var destroy = function () { model.stopListening(); model.trigger('destroy', model.collection, model, options); }; options.success = function (resp) { if (options.wait || model.isNew()) destroy(); if (success) success(resp, model, options); if (!model.isNew()) model.trigger('sync', resp, model, options).trigger('delete', resp, model, options); }; if (this.isNew()) { options.success(); return false; } wrapError(this, options); var xhr = this.sync('delete', this, options); if (!options.wait) destroy(); return xhr; }, // Default URL for the model's representation on the server -- if you're // using BI's restful methods, override this to change the endpoint // that will be called. url: function () { var base = _.result(this.collection, 'url'); if (this.isNew()) return base; return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id); }, // **parse** converts a response into the hash of attributes to be `set` on // the model. The default implementation is just to pass the response along. parse: function (resp, options) { return resp; }, // Create a new model with identical attributes to this one. clone: function () { return new this.constructor(this.attributes); }, // A model is new if it has never been saved to the server, and lacks an id. isNew: function () { return !this.has(this.idAttribute); }, // Check if the model is currently in a valid state. isValid: function (options) { return this._validate({}, _.extend(options || {}, {validate: true})); }, // Run validation against the next complete set of model attributes, // returning `true` if all is well. Otherwise, fire an `"invalid"` event. _validate: function (attrs, options) { if (!options.validate || !this.validate) return true; attrs = _.extend({}, this.attributes, attrs); var error = this.validationError = this.validate(attrs, options) || null; if (!error) return true; this.trigger('invalid', error, this, _.extend(options, {validationError: error})); return false; } }); // Underscore methods that we want to implement on the M. var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit', 'chain', 'isEmpty']; // Mix in each Underscore method as a proxy to `M#attributes`. _.each(modelMethods, function (method) { if (!_[method]) return; M.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.attributes); return _[method].apply(_, args); }; }); // BI.Collection // ------------------- // If models tend to represent a single row of data, a BI Collection is // more analogous to a table full of data ... or a small slice or page of that // table, or a collection of rows that belong together for a particular reason // -- all of the messages in this particular folder, all of the documents // belonging to this particular author, and so on. Collections maintain // indexes of their models, both in order, and for lookup by `id`. // Create a new **Collection**, perhaps to contain a specific type of `model`. // If a `comparator` is specified, the Collection will maintain // its models in sort order, as they're added and removed. var Collection = BI.Collection = function (models, options) { this.options = options = options || {}; if (options.model) this.model = options.model; if (options.comparator !== void 0) this.comparator = options.comparator; this._reset(); this._init.apply(this, arguments); if (models) this.reset(models, _.extend({silent: true}, options)); }; // Default options for `Collection#set`. var setOptions = {add: true, remove: true, merge: true}; var addOptions = {add: true, remove: false}; // Define the Collection's inheritable methods. _.extend(Collection.prototype, Events, { // The default model for a collection is just a **BI.M**. // This should be overridden in most cases. model: M, // _init is an empty function by default. Override it with your own // initialization logic. _init: function () { }, // The JSON representation of a Collection is an array of the // models' attributes. toJSON: function (options) { return this.map(function (model) { return model.toJSON(options); }); }, // Proxy `BI.sync` by default. sync: function () { return BI.sync.apply(this, arguments); }, // Add a model, or list of models to the set. add: function (models, options) { return this.set(models, _.extend({merge: false}, options, addOptions)); }, // Remove a model, or a list of models from the set. remove: function (models, options) { var singular = !_.isArray(models); models = singular ? [models] : _.clone(models); options || (options = {}); for (var i = 0, length = models.length; i < length; i++) { var model = models[i] = this.get(models[i]); if (!model) continue; var id = this.modelId(model.attributes); if (id != null) delete this._byId[id]; delete this._byId[model.cid]; var index = this.indexOf(model); this.models.splice(index, 1); this.length--; if (!options.silent) { options.index = index; model.trigger('remove', model, this, options); } this._removeReference(model, options); } return singular ? models[0] : models; }, // Update a collection by `set`-ing a new list of models, adding new ones, // removing models that are no longer present, and merging models that // already exist in the collection, as necessary. Similar to **M#set**, // the core operation for updating the data contained by the collection. set: function (models, options) { options = _.defaults({}, options, setOptions); if (options.parse) models = this.parse(models, options); var singular = !_.isArray(models); models = singular ? (models ? [models] : []) : models.slice(); var id, model, attrs, existing, sort; var at = options.at; if (at != null) at = +at; if (at < 0) at += this.length + 1; var sortable = this.comparator && (at == null) && options.sort !== false; var sortAttr = _.isString(this.comparator) ? this.comparator : null; var toAdd = [], toRemove = [], modelMap = {}; var add = options.add, merge = options.merge, remove = options.remove; var order = !sortable && add && remove ? [] : false; var orderChanged = false; // Turn bare objects into model references, and prevent invalid models // from being added. for (var i = 0, length = models.length; i < length; i++) { attrs = models[i]; // If a duplicate is found, prevent it from being added and // optionally merge it into the existing model. if (existing = this.get(attrs)) { if (remove) modelMap[existing.cid] = true; if (merge && attrs !== existing) { attrs = this._isModel(attrs) ? attrs.attributes : attrs; if (options.parse) attrs = existing.parse(attrs, options); existing.set(attrs, options); if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; } models[i] = existing; // If this is a new, valid model, push it to the `toAdd` list. } else if (add) { model = models[i] = this._prepareModel(attrs, options); if (!model) continue; toAdd.push(model); this._addReference(model, options); } // Do not add multiple models with the same `id`. model = existing || model; if (!model) continue; id = this.modelId(model.attributes); if (order && (model.isNew() || !modelMap[id])) { order.push(model); // Check to see if this is actually a new model at this index. orderChanged = orderChanged || !this.models[i] || model.cid !== this.models[i].cid; } modelMap[id] = true; } // Remove nonexistent models if appropriate. if (remove) { for (var i = 0, length = this.length; i < length; i++) { if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); } if (toRemove.length) this.remove(toRemove, options); } // See if sorting is needed, update `length` and splice in new models. if (toAdd.length || orderChanged) { if (sortable) sort = true; this.length += toAdd.length; if (at != null) { for (var i = 0, length = toAdd.length; i < length; i++) { this.models.splice(at + i, 0, toAdd[i]); } } else { if (order) this.models.length = 0; var orderedModels = order || toAdd; for (var i = 0, length = orderedModels.length; i < length; i++) { this.models.push(orderedModels[i]); } } } // Silently sort the collection if appropriate. if (sort) this.sort({silent: true}); // Unless silenced, it's time to fire all appropriate add/sort events. if (!options.silent) { var addOpts = at != null ? _.clone(options) : options; for (var i = 0, length = toAdd.length; i < length; i++) { if (at != null) addOpts.index = at + i; (model = toAdd[i]).trigger('add', model, this, addOpts); } if (sort || orderChanged) this.trigger('sort', this, options); } // Return the added (or merged) model (or models). return singular ? models[0] : models; }, // When you have more items than you want to add or remove individually, // you can reset the entire set with a new list of models, without firing // any granular `add` or `remove` events. Fires `reset` when finished. // Useful for bulk operations and optimizations. reset: function (models, options) { options = options ? _.clone(options) : {}; for (var i = 0, length = this.models.length; i < length; i++) { this._removeReference(this.models[i], options); } options.previousModels = this.models; this._reset(); models = this.add(models, _.extend({silent: true}, options)); if (!options.silent) this.trigger('reset', this, options); return models; }, // Add a model to the end of the collection. push: function (model, options) { return this.add(model, _.extend({at: this.length}, options)); }, // Remove a model from the end of the collection. pop: function (options) { var model = this.at(this.length - 1); this.remove(model, options); return model; }, // Add a model to the beginning of the collection. unshift: function (model, options) { return this.add(model, _.extend({at: 0}, options)); }, // Remove a model from the beginning of the collection. shift: function (options) { var model = this.at(0); this.remove(model, options); return model; }, // Slice out a sub-array of models from the collection. slice: function () { return slice.apply(this.models, arguments); }, // Get a model from the set by id. get: function (obj) { if (obj == null) return void 0; var id = this.modelId(this._isModel(obj) ? obj.attributes : obj); return this._byId[obj] || this._byId[id] || this._byId[obj.cid]; }, // Get the model at the given index. at: function (index) { if (index < 0) index += this.length; return this.models[index]; }, // Return models with matching attributes. Useful for simple cases of // `filter`. where: function (attrs, first) { var matches = _.matches(attrs); return this[first ? 'find' : 'filter'](function (model) { return matches(model.attributes); }); }, // Return the first model with matching attributes. Useful for simple cases // of `find`. findWhere: function (attrs) { return this.where(attrs, true); }, // Force the collection to re-sort itself. You don't need to call this under // normal circumstances, as the set will maintain sort order as each item // is added. sort: function (options) { if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); options || (options = {}); // Run sort based on type of `comparator`. if (_.isString(this.comparator) || this.comparator.length === 1) { this.models = this.sortBy(this.comparator, this); } else { this.models.sort(_.bind(this.comparator, this)); } if (!options.silent) this.trigger('sort', this, options); return this; }, // Pluck an attribute from each model in the collection. pluck: function (attr) { return _.invoke(this.models, 'get', attr); }, // Fetch the default set of models for this collection, resetting the // collection when they arrive. If `reset: true` is passed, the response // data will be passed through the `reset` method instead of `set`. fetch: function (options) { options = options ? _.clone(options) : {}; if (options.parse === void 0) options.parse = true; var success = options.success; var collection = this; options.success = function (resp) { var method = options.reset ? 'reset' : 'set'; collection[method](resp, options); if (success) success(collection, resp, options); collection.trigger('sync', collection, resp, options); }; wrapError(this, options); return this.sync('read', this, options); }, // Create a new instance of a model in this collection. Add the model to the // collection immediately, unless `wait: true` is passed, in which case we // wait for the server to agree. create: function (model, options) { options = options ? _.clone(options) : {}; if (!(model = this._prepareModel(model, options))) return false; if (!options.wait) this.add(model, options); var collection = this; var success = options.success; options.success = function (model, resp) { if (options.wait) collection.add(model, options); if (success) success(model, resp, options); }; model.save(null, options); return model; }, // **parse** converts a response into a list of models to be added to the // collection. The default implementation is just to pass it through. parse: function (resp, options) { return resp; }, // Create a new collection with an identical list of models as this one. clone: function () { return new this.constructor(this.models, { model: this.model, comparator: this.comparator }); }, // Define how to uniquely identify models in the collection. modelId: function (attrs) { return attrs[this.model.prototype.idAttribute || 'id']; }, // Private method to reset all internal state. Called when the collection // is first _initd or reset. _reset: function () { this.length = 0; this.models = []; this._byId = {}; }, // Prepare a hash of attributes (or other model) to be added to this // collection. _prepareModel: function (attrs, options) { if (this._isModel(attrs)) { if (!attrs.collection) attrs.collection = this; return attrs; } options = options ? _.clone(options) : {}; options.collection = this; var model = new this.model(attrs, options); if (!model.validationError) return model; this.trigger('invalid', this, model.validationError, options); return false; }, // Method for checking whether an object should be considered a model for // the purposes of adding to the collection. _isModel: function (model) { return model instanceof M; }, // Internal method to create a model's ties to a collection. _addReference: function (model, options) { this._byId[model.cid] = model; var id = this.modelId(model.attributes); if (id != null) this._byId[id] = model; model.on('all', this._onModelEvent, this); }, // Internal method to sever a model's ties to a collection. _removeReference: function (model, options) { if (this === model.collection) delete model.collection; model.off('all', this._onModelEvent, this); }, // Internal method called every time a model in the set fires an event. // Sets need to update their indexes when models change ids. All other // events simply proxy through. "add" and "remove" events that originate // in other collections are ignored. _onModelEvent: function (event, model, collection, options) { if ((event === 'add' || event === 'remove') && collection !== this) return; if (event === 'destroy') this.remove(model, options); if (event === 'change') { var prevId = this.modelId(model.previousAttributes()); var id = this.modelId(model.attributes); if (prevId !== id) { if (prevId != null) delete this._byId[prevId]; if (id != null) this._byId[id] = model; } } this.trigger.apply(this, arguments); } }); // Underscore methods that we want to implement on the Collection. // 90% of the core usefulness of BI Collections is actually implemented // right here: var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', 'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle', 'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition']; // Mix in each Underscore method as a proxy to `Collection#models`. _.each(methods, function (method) { if (!_[method]) return; Collection.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.models); return _[method].apply(_, args); }; }); // Underscore methods that take a property name as an argument. var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; // Use attributes instead of properties. _.each(attributeMethods, function (method) { if (!_[method]) return; Collection.prototype[method] = function (value, context) { var iterator = _.isFunction(value) ? value : function (model) { return model.get(value); }; return _[method](this.models, iterator, context); }; }); // BI.V // ------------- // BI Views are almost more convention than they are actual code. A V // is simply a JavaScript object that represents a logical chunk of UI in the // DOM. This might be a single item, an entire list, a sidebar or panel, or // even the surrounding frame which wraps your whole app. Defining a chunk of // UI as a **V** allows you to define your DOM events declaratively, without // having to worry about render order ... and makes it easy for the view to // react to specific changes in the state of your models. // Creating a BI.V creates its initial element outside of the DOM, // if an existing element is not provided... var V = BI.V = function (options) { this.cid = _.uniqueId('view'); options = options || {}; this.options = _.defaults(options, _.result(this, '_defaultConfig')); _.extend(this, _.pick(this.options, viewOptions)); this._ensureElement(); this._init.apply(this, arguments); }; // Cached regex to split keys for `delegate`. var delegateEventSplitter = /^(\S+)\s*(.*)$/; // List of view options to be merged as properties. var viewOptions = ['rootURL', 'model', 'parent', 'collection', 'element', 'id', 'attributes', 'baseCls', 'tagName', 'events']; // Set up all inheritable **BI.V** properties and methods. _.extend(V.prototype, Events, { // The default `tagName` of a V's element is `"div"`. tagName: 'div', // jQuery delegate for element lookup, scoped to DOM elements within the // current view. This should be preferred to global lookups where possible. $: function (selector) { return this.$el.find(selector); }, _defaultConfig: function () { return {} }, // _init is an empty function by default. Override it with your own // initialization logic. _init: function () { }, //容器,默认放在this.element上 _vessel: function () { return this }, // **render** is the core function that your view should override, in order // to populate its element (`this.el`), with the appropriate HTML. The // convention is for **render** to always return `this`. render: function (vessel) { return this; }, // Remove this view by taking the element out of the DOM, and removing any // applicable BI.Events listeners. remove: function () { this._removeElement(); this.stopListening(); return this; }, // Remove this view's element from the document and all event listeners // attached to it. Exposed for subclasses using an alternative DOM // manipulation API. _removeElement: function () { this.$el.remove(); if ($.browser.msie === true) { this.el.outerHTML = ''; } }, // Change the view's element (`this.el` property) and re-delegate the // view's events on the new element. setElement: function (element) { this.undelegateEvents(); this._setElement(element); this.vessel = this._vessel(); this.render(this.vessel); this.delegateEvents(); return this; }, setVisible: function (visible) { this.options.invisible = !visible; if (visible) { this.element.css("display", ""); } else { this.element.css("display", "none"); } }, isVisible: function () { return !this.options.invisible; }, visible: function () { this.setVisible(true); }, invisible: function () { this.setVisible(false); }, // Creates the `this.el` and `this.$el` references for this view using the // given `el`. `el` can be a CSS selector or an HTML string, a jQuery // context or an element. Subclasses can override this to utilize an // alternative DOM manipulation API and are only required to set the // `this.el` property. _setElement: function (el) { this.$el = el instanceof BI.$ ? el : BI.$(el); this.element = this.$el; this.el = this.$el[0]; }, // Set callbacks, where `this.events` is a hash of // // *{"event selector": "callback"}* // // { // 'mousedown .title': 'edit', // 'click .button': 'save', // 'click .open': function(e) { ... } // } // // pairs. Callbacks will be bound to the view, with `this` set properly. // Uses event delegation for efficiency. // Omitting the selector binds the event to `this.el`. delegateEvents: function (events) { if (!(events || (events = _.result(this, 'events')))) return this; this.undelegateEvents(); for (var key in events) { var method = events[key]; if (!_.isFunction(method)) method = this[events[key]]; if (!method) continue; var match = key.match(delegateEventSplitter); this.delegate(match[1], match[2], _.bind(method, this)); } return this; }, // Add a single event listener to the view's element (or a child element // using `selector`). This only works for delegate-able events: not `focus`, // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer. delegate: function (eventName, selector, listener) { this.vessel.element.on(eventName + '.delegateEvents' + this.cid, selector, listener); }, // Clears all callbacks previously bound to the view by `delegateEvents`. // You usually don't need to use this, but may wish to if you have multiple // BI views attached to the same DOM element. undelegateEvents: function () { if (this.vessel) this.vessel.element.off('.delegateEvents' + this.cid); return this; }, // A finer-grained `undelegateEvents` for removing a single delegated event. // `selector` and `listener` are both optional. undelegate: function (eventName, selector, listener) { this.vessel.element.off(eventName + '.delegateEvents' + this.cid, selector, listener); }, // Produces a DOM element to be assigned to your view. Exposed for // subclasses using an alternative DOM manipulation API. _createElement: function (tagName) { return document.createElement(tagName); }, // Ensure that the V has a DOM element to render into. // If `this.el` is a string, pass it through `$()`, take the first // matching element, and re-assign it to `el`. Otherwise, create // an element from the `id`, `className` and `tagName` properties. _ensureElement: function () { var attrs = _.extend({}, _.result(this, 'attributes')); if (this.baseCls) attrs['class'] = _.result(this, 'baseCls'); if (!this.element) { this.setElement(this._createElement(_.result(this, 'tagName'))); } else { this.setElement(_.result(this, 'element')); } this._setAttributes(attrs); }, // Set attributes from a hash on this view's element. Exposed for // subclasses using an alternative DOM manipulation API. _setAttributes: function (attributes) { this.$el.attr(attributes); } }); // BI.sync // ------------- // Override this function to change the manner in which BI persists // models to the server. You will be passed the type of request, and the // model in question. By default, makes a RESTful Ajax request // to the model's `url()`. Some possible customizations could be: // // * Use `setTimeout` to batch rapid-fire updates into a single request. // * Send up the models as XML instead of JSON. // * Persist models via WebSockets instead of Ajax. // // Turn on `BI.emulateHTTP` in order to send `PUT` and `DELETE` requests // as `POST`, with a `_method` parameter containing the true HTTP method, // as well as all requests with the body as `application/x-www-form-urlencoded` // instead of `application/json` with the model in a param named `model`. // Useful when interfacing with server-side languages like **PHP** that make // it difficult to read the body of `PUT` requests. BI.sync = function (method, model, options) { var type = methodMap[method]; // Default options, unless specified. _.defaults(options || (options = {}), { emulateHTTP: BI.emulateHTTP, emulateJSON: BI.emulateJSON }); // Default JSON-request options. var params = {type: type, dataType: 'json'}; // Ensure that we have a URL. if (!options.url) { params.url = _.result(model, method + "URL") || _.result(model, 'url'); if (!params.url) { return; } } // Ensure that we have the appropriate request data. if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { params.contentType = 'application/json'; params.data = _.extend({id: model.id}, model.toJSON(options), options.attrs); } // For older servers, emulate JSON by encoding the request into an HTML-form. if (options.emulateJSON) { params.contentType = 'application/x-www-form-urlencoded'; params.data = options.data ? options.data : params.data; } // For older servers, emulate HTTP by mimicking the HTTP method with `_method` // And an `X-HTTP-Method-Override` header. if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { params.type = 'POST'; if (options.emulateJSON) params.data._method = type; var beforeSend = options.beforeSend; options.beforeSend = function (xhr) { xhr.setRequestHeader('X-HTTP-Method-Override', type); if (beforeSend) return beforeSend.apply(this, arguments); }; } // Don't process data on a non-GET request. if (params.type !== 'GET' && !options.emulateJSON) { params.processData = false; } // Pass along `textStatus` and `errorThrown` from jQuery. var error = options.error; options.error = function (xhr, textStatus, errorThrown) { options.textStatus = textStatus; options.errorThrown = errorThrown; if (error) error.apply(this, arguments); }; // Make the request, allowing the user to override any Ajax options. var xhr = options.xhr = BI.ajax(_.extend(params, options)); model.trigger('request', xhr, model, options); return xhr; }; // Map from CRUD to HTTP for our default `BI.sync` implementation. var methodMap = { 'create': 'POST', 'update': 'PUT', 'patch': 'PATCH', 'delete': 'DELETE', 'read': 'GET' }; // Set the default implementation of `BI.ajax` to proxy through to `$`. // Override this if you'd like to use a different library. BI.ajax = $.ajax; // BI.Router // --------------- // Routers map faux-URLs to actions, and fire events when routes are // matched. Creating a new one sets its `routes` hash, if not set statically. var Router = BI.Router = function (options) { options || (options = {}); if (options.routes) this.routes = options.routes; this._bindRoutes(); this._init.apply(this, arguments); }; // Cached regular expressions for matching named param parts and splatted // parts of route strings. var optionalParam = /\((.*?)\)/g; var namedParam = /(\(\?)?:\w+/g; var splatParam = /\*\w+/g; var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; // Set up all inheritable **BI.Router** properties and methods. _.extend(Router.prototype, Events, { // _init is an empty function by default. Override it with your own // initialization logic. _init: function () { }, // Manually bind a single named route to a callback. For example: // // this.route('search/:query/p:num', 'search', function(query, num) { // ... // }); // route: function (route, name, callback) { if (!_.isRegExp(route)) route = this._routeToRegExp(route); if (_.isFunction(name)) { callback = name; name = ''; } if (!callback) callback = this[name]; var router = this; BI.history.route(route, function (fragment) { var args = router._extractParameters(route, fragment); if (router.execute(callback, args, name) !== false) { router.trigger.apply(router, ['route:' + name].concat(args)); router.trigger('route', name, args); BI.history.trigger('route', router, name, args); } }); return this; }, // Execute a route handler with the provided parameters. This is an // excellent place to do pre-route setup or post-route cleanup. execute: function (callback, args, name) { if (callback) callback.apply(this, args); }, // Simple proxy to `BI.history` to save a fragment into the history. navigate: function (fragment, options) { BI.history.navigate(fragment, options); return this; }, // Bind all defined routes to `BI.history`. We have to reverse the // order of the routes here to support behavior where the most general // routes can be defined at the bottom of the route map. _bindRoutes: function () { if (!this.routes) return; this.routes = _.result(this, 'routes'); var route, routes = _.keys(this.routes); while ((route = routes.pop()) != null) { this.route(route, this.routes[route]); } }, // Convert a route string into a regular expression, suitable for matching // against the current location hash. _routeToRegExp: function (route) { route = route.replace(escapeRegExp, '\\$&') .replace(optionalParam, '(?:$1)?') .replace(namedParam, function (match, optional) { return optional ? match : '([^/?]+)'; }) .replace(splatParam, '([^?]*?)'); return new RegExp('^' + route + '(?:\\?([\\s\\S]*))?$'); }, // Given a route, and a URL fragment that it matches, return the array of // extracted decoded parameters. Empty or unmatched parameters will be // treated as `null` to normalize cross-browser behavior. _extractParameters: function (route, fragment) { var params = route.exec(fragment).slice(1); return _.map(params, function (param, i) { // Don't decode the search params. if (i === params.length - 1) return param || null; return param ? decodeURIComponent(param) : null; }); } }); // BI.History // ---------------- // Handles cross-browser history management, based on either // [pushState](http://diveintohtml5.info/history.html) and real URLs, or // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) // and URL fragments. If the browser supports neither (old IE, natch), // falls back to polling. var History = BI.History = function () { this.handlers = []; _.bindAll(this, 'checkUrl'); // Ensure that `History` can be used outside of the browser. if (typeof window !== 'undefined') { this.location = window.location; this.history = window.history; } }; // Cached regex for stripping a leading hash/slash and trailing space. var routeStripper = /^[#\/]|\s+$/g; // Cached regex for stripping leading and trailing slashes. var rootStripper = /^\/+|\/+$/g; // Cached regex for stripping urls of hash. var pathStripper = /#.*$/; // Has the history handling already been started? History.started = false; // Set up all inheritable **BI.History** properties and methods. _.extend(History.prototype, Events, { // The default interval to poll for hash changes, if necessary, is // twenty times a second. interval: 50, // Are we at the app root? atRoot: function () { var path = this.location.pathname.replace(/[^\/]$/, '$&/'); return path === this.root && !this.getSearch(); }, // In IE6, the hash fragment and search params are incorrect if the // fragment contains `?`. getSearch: function () { var match = this.location.href.replace(/#.*/, '').match(/\?.+/); return match ? match[0] : ''; }, // Gets the true hash value. Cannot use location.hash directly due to bug // in Firefox where location.hash will always be decoded. getHash: function (window) { var match = (window || this).location.href.match(/#(.*)$/); return match ? match[1] : ''; }, // Get the pathname and search params, without the root. getPath: function () { var path = decodeURI(this.location.pathname + this.getSearch()); var root = this.root.slice(0, -1); if (!path.indexOf(root)) path = path.slice(root.length); return path.charAt(0) === '/' ? path.slice(1) : path; }, // Get the cross-browser normalized URL fragment from the path or hash. getFragment: function (fragment) { if (fragment == null) { if (this._hasPushState || !this._wantsHashChange) { fragment = this.getPath(); } else { fragment = this.getHash(); } } return fragment.replace(routeStripper, ''); }, // Start the hash change handling, returning `true` if the current URL matches // an existing route, and `false` otherwise. start: function (options) { if (History.started) throw new Error('BI.history has already been started'); History.started = true; // Figure out the initial configuration. Do we need an iframe? // Is pushState desired ... is it available? this.options = _.extend({root: '/'}, this.options, options); this.root = this.options.root; this._wantsHashChange = this.options.hashChange !== false; this._hasHashChange = 'onhashchange' in window; this._wantsPushState = !!this.options.pushState; this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); this.fragment = this.getFragment(); // Normalize root to always include a leading and trailing slash. this.root = ('/' + this.root + '/').replace(rootStripper, '/'); // Transition from hashChange to pushState or vice versa if both are // requested. if (this._wantsHashChange && this._wantsPushState) { // If we've started off with a route from a `pushState`-enabled // browser, but we're currently in a browser that doesn't support it... if (!this._hasPushState && !this.atRoot()) { var root = this.root.slice(0, -1) || '/'; this.location.replace(root + '#' + this.getPath()); // Return immediately as browser will do redirect to new url return true; // Or if we've started out with a hash-based route, but we're currently // in a browser where it could be `pushState`-based instead... } else if (this._hasPushState && this.atRoot()) { this.navigate(this.getHash(), {replace: true}); } } // Proxy an iframe to handle location events if the browser doesn't // support the `hashchange` event, HTML5 history, or the user wants // `hashChange` but not `pushState`. if (!this._hasHashChange && this._wantsHashChange && (!this._wantsPushState || !this._hasPushState)) { var iframe = document.createElement('iframe'); iframe.src = 'javascript:0'; iframe.style.display = 'none'; iframe.tabIndex = -1; var body = document.body; // Using `appendChild` will throw on IE < 9 if the document is not ready. this.iframe = body.insertBefore(iframe, body.firstChild).contentWindow; this.iframe.document.open().close(); this.iframe.location.hash = '#' + this.fragment; } // Add a cross-platform `addEventListener` shim for older browsers. var addEventListener = window.addEventListener || function (eventName, listener) { return attachEvent('on' + eventName, listener); }; // Depending on whether we're using pushState or hashes, and whether // 'onhashchange' is supported, determine how we check the URL state. if (this._hasPushState) { addEventListener('popstate', this.checkUrl, false); } else if (this._wantsHashChange && this._hasHashChange && !this.iframe) { addEventListener('hashchange', this.checkUrl, false); } else if (this._wantsHashChange) { this._checkUrlInterval = setInterval(this.checkUrl, this.interval); } if (!this.options.silent) return this.loadUrl(); }, // Disable BI.history, perhaps temporarily. Not useful in a real app, // but possibly useful for unit testing Routers. stop: function () { // Add a cross-platform `removeEventListener` shim for older browsers. var removeEventListener = window.removeEventListener || function (eventName, listener) { return detachEvent('on' + eventName, listener); }; // Remove window listeners. if (this._hasPushState) { removeEventListener('popstate', this.checkUrl, false); } else if (this._wantsHashChange && this._hasHashChange && !this.iframe) { removeEventListener('hashchange', this.checkUrl, false); } // Clean up the iframe if necessary. if (this.iframe) { document.body.removeChild(this.iframe.frameElement); this.iframe = null; } // Some environments will throw when clearing an undefined interval. if (this._checkUrlInterval) clearInterval(this._checkUrlInterval); History.started = false; }, // Add a route to be tested when the fragment changes. Routes added later // may override previous routes. route: function (route, callback) { this.handlers.unshift({route: route, callback: callback}); }, // Checks the current URL to see if it has changed, and if it has, // calls `loadUrl`, normalizing across the hidden iframe. checkUrl: function (e) { var current = this.getFragment(); // If the user pressed the back button, the iframe's hash will have // changed and we should use that for comparison. if (current === this.fragment && this.iframe) { current = this.getHash(this.iframe); } if (current === this.fragment) return false; if (this.iframe) this.navigate(current); this.loadUrl(); }, // Attempt to load the current URL fragment. If a route succeeds with a // match, returns `true`. If no defined routes matches the fragment, // returns `false`. loadUrl: function (fragment) { fragment = this.fragment = this.getFragment(fragment); return _.any(this.handlers, function (handler) { if (handler.route.test(fragment)) { handler.callback(fragment); return true; } }); }, // Save a fragment into the hash history, or replace the URL state if the // 'replace' option is passed. You are responsible for properly URL-encoding // the fragment in advance. // // The options object can contain `trigger: true` if you wish to have the // route callback be fired (not usually desirable), or `replace: true`, if // you wish to modify the current URL without adding an entry to the history. navigate: function (fragment, options) { if (!History.started) return false; if (!options || options === true) options = {trigger: !!options}; // Normalize the fragment. fragment = this.getFragment(fragment || ''); // Don't include a trailing slash on the root. var root = this.root; if (fragment === '' || fragment.charAt(0) === '?') { root = root.slice(0, -1) || '/'; } var url = root + fragment; // Strip the hash and decode for matching. fragment = decodeURI(fragment.replace(pathStripper, '')); if (this.fragment === fragment) return; this.fragment = fragment; // If pushState is available, we use it to set the fragment as a real URL. if (this._hasPushState) { this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url); // If hash changes haven't been explicitly disabled, update the hash // fragment to store history. } else if (this._wantsHashChange) { this._updateHash(this.location, fragment, options.replace); if (this.iframe && (fragment !== this.getHash(this.iframe))) { // Opening and closing the iframe tricks IE7 and earlier to push a // history entry on hash-tag change. When replace is true, we don't // want this. if (!options.replace) this.iframe.document.open().close(); this._updateHash(this.iframe.location, fragment, options.replace); } // If you've told us that you explicitly don't want fallback hashchange- // based history, then `navigate` becomes a page refresh. } else { return this.location.assign(url); } if (options.trigger) return this.loadUrl(fragment); }, // Update the hash location, either replacing the current entry, or adding // a new one to the browser history. _updateHash: function (location, fragment, replace) { if (replace) { var href = location.href.replace(/(javascript:|#).*$/, ''); location.replace(href + '#' + fragment); } else { // Some browsers require that `hash` contains a leading #. location.hash = '#' + fragment; } } }); // Create the default BI.history. BI.history = new History; // Helpers // ------- // Helper function to correctly set up the prototype chain, for subclasses. // Similar to `goog.inherits`, but uses a hash of prototype properties and // class properties to be extended. var extend = function (protoProps, staticProps) { var parent = this; var child; // The constructor function for the new subclass is either defined by you // (the "constructor" property in your `extend` definition), or defaulted // by us to simply call the parent's constructor. if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { child = function () { return parent.apply(this, arguments); }; } // Add static properties to the constructor function, if supplied. _.extend(child, parent, staticProps); // Set the prototype chain to inherit from `parent`, without calling // `parent`'s constructor function. var Surrogate = function () { this.constructor = child; }; Surrogate.prototype = parent.prototype; child.prototype = new Surrogate; // Add prototype properties (instance properties) to the subclass, // if supplied. if (protoProps) _.extend(child.prototype, protoProps); // Set a convenience property in case the parent's prototype is needed // later. child.__super__ = parent.prototype; return child; }; // Set up inheritance for the model, collection, router, view and history. M.extend = Collection.extend = Router.extend = V.extend = History.extend = extend; // Throw an error when a URL is needed, and none is supplied. var urlError = function () { throw new Error('A "url" property or function must be specified'); }; // Wrap an optional error callback with a fallback error event. var wrapError = function (model, options) { var error = options.error; options.error = function (resp) { if (error) error(model, resp, options); model.trigger('error', model, resp, options); }; }; return BI; }));/** * MVC路由 * @class BI.WRouter * @extends BI.Router * @type {*|void|Object} */ BI.WRouter = BI.Router.extend({ add: function(route, callback){ this.handlers || (this.handlers=[]); this.handlers.unshift({route: route, callback: callback}) }, route: function(route, name, callback) { if (!_.isRegExp(route)) route = this._routeToRegExp(route); if (_.isFunction(name)) { callback = name; name = ''; } if (!callback) callback = this[name]; var self = this; this.add(route, function(fragment) { var args = self._extractParameters(route, fragment); var result = self.execute(callback, args, name) if (result !== false) { self.trigger.apply(self, ['route:' + name].concat(args)); self.trigger('route', name, args); } return result; }); return this; }, execute: function(callback, args, name) { if (callback) return callback.apply(this, args); return name; }, get: function(fragment){ var result = null; _.any(this.handlers, function(handler) { if (handler.route.test(fragment)) { result = handler.callback(fragment); return true; } }); return result; } });/** * 基本函数 * Create By GUY 2014\11\17 * */ if (!window.BI) { window.BI = {}; } ; !(function ($, undefined) { var traverse = function (func, context) { return function (value, key, obj) { return func.call(context, key, value, obj); } }; var _apply = function (name) { return function () { return _[name].apply(_, arguments); } }; var _applyFunc = function (name) { return function () { var args = Array.prototype.slice.call(arguments, 0); args[1] = _.isFunction(args[1]) ? traverse(args[1], args[2]) : args[1]; return _[name].apply(_, args); } }; //Utility _.extend(BI, { i18nText: function (key) { var localeText = (BI.i18n && BI.i18n[key]) || ""; if (!localeText) { localeText = key; } var len = arguments.length; if (len > 1) { for (var i = 1; i < len; i++) { var key = "{R" + i + "}"; localeText = localeText.replaceAll(key, arguments[i] + ""); } } return localeText; }, assert: function (v, is) { if (this.isFunction(is)) { if (!is(v)) { throw new Error(v + " error"); } else { return true; } } if (!this.isArray(is)) { is = [is]; } if (!this.deepContains(is, v)) { throw new Error(v + " error"); } }, warn: function (message) { console.warn(message) }, UUID: function () { var f = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; var str = ""; for (var i = 0; i < 16; i++) { var r = parseInt(f.length * Math.random(), 10); str += f[r]; } return str; }, isWidget: function (widget) { return widget instanceof BI.Widget || (BI.View && widget instanceof BI.View); }, createWidgets: function (items, options) { if (!BI.isArray(items)) { throw new Error("cannot create Widgets") } return BI.map(BI.flatten(items), function (i, item) { return BI.createWidget(item, BI.deepClone(options)); }); }, createItems: function (data, innerAttr, outerAttr) { innerAttr = BI.isArray(innerAttr) ? innerAttr : BI.makeArray(BI.flatten(data).length, innerAttr); outerAttr = BI.isArray(outerAttr) ? outerAttr : BI.makeArray(BI.flatten(data).length, outerAttr); return BI.map(data, function (i, item) { if (BI.isArray(item)) { return BI.createItems(item, innerAttr, outerAttr); } if (item instanceof BI.Widget) { return BI.extend({}, innerAttr.shift(), outerAttr.shift(), { type: null, el: item }); } if (innerAttr[0] instanceof BI.Widget) { outerAttr.shift(); return BI.extend({}, item, { el: innerAttr.shift() }) } if (item.el instanceof BI.Widget || (BI.View && item.el instanceof BI.View)) { innerAttr.shift(); return BI.extend({}, outerAttr.shift(), {type: null}, item); } if (item.el) { return BI.extend({}, outerAttr.shift(), item, { el: BI.extend({}, innerAttr.shift(), item.el) }) } return BI.extend({}, outerAttr.shift(), { el: BI.extend({}, innerAttr.shift(), item) }) }) }, //用容器包装items packageItems: function (items, layouts) { for (var i = layouts.length - 1; i >= 0; i--) { items = BI.map(items, function (k, it) { return BI.extend({}, layouts[i], { items: [ BI.extend({}, layouts[i].el, { el: it }) ] }) }) } return items; }, formatEL: function (obj) { if (obj && !obj.type && obj.el) { return obj; } return { el: obj }; }, //剥开EL stripEL: function (obj) { return obj.type && obj || obj.el || obj; }, trans2Element: function (widgets) { return BI.map(widgets, function (i, wi) { return wi.element; }); } }); //集合相关方法 _.each(["where", "findWhere", "contains", "invoke", "pluck", "shuffle", "sample", "toArray", "size"], function (name) { BI[name] = _apply(name) }); _.each(["each", "map", "reduce", "reduceRight", "find", "filter", "reject", "every", "all", "some", "any", "max", "min", "sortBy", "groupBy", "indexBy", "countBy", "partition"], function (name) { BI[name] = _applyFunc(name) }); _.extend(BI, { clamp: function (value, minValue, maxValue) { if (value < minValue) { value = minValue; } if (value > maxValue) { value = maxValue; } return value; }, //数数 count: function (from, to, predicate) { var t; if (predicate) { for (t = from; t < to; t++) { predicate(t); } } return to - from; }, //倒数 inverse: function (from, to, predicate) { return BI.count(to, from, predicate); }, firstKey: function (obj) { var res = undefined; BI.any(obj, function (key, value) { res = key; return true; }); return res; }, lastKey: function (obj) { var res = undefined; BI.each(obj, function (key, value) { res = key; return true; }); return res; }, firstObject: function (obj) { var res = undefined; BI.any(obj, function (key, value) { res = value; return true; }); return res; }, lastObject: function (obj) { var res = undefined; BI.each(obj, function (key, value) { res = value; return true; }); return res; }, concat: function (obj1, obj2) { if (BI.isKey(obj1)) { return obj1 + "" + obj2; } if (BI.isArray(obj1)) { return obj1.concat(obj2); } if (BI.isObject(obj1)) { return _.extend({}, obj1, obj2); } }, backEach: function (obj, predicate, context) { predicate = BI.iteratee(predicate, context); for (var index = obj.length - 1; index >= 0; index--) { predicate(index, obj[index], obj); } return false; }, backAny: function (obj, predicate, context) { predicate = BI.iteratee(predicate, context); for (var index = obj.length - 1; index >= 0; index--) { if (predicate(index, obj[index], obj)) { return true; } } return false; }, backEvery: function (obj, predicate, context) { predicate = BI.iteratee(predicate, context); for (var index = obj.length - 1; index >= 0; index--) { if (!predicate(index, obj[index], obj)) { return false; } } return true; }, backFindKey: function (obj, predicate, context) { predicate = BI.iteratee(predicate, context); var keys = _.keys(obj), key; for (var i = keys.length - 1; i >= 0; i--) { key = keys[i]; if (predicate(obj[key], key, obj)) { return key; } } }, backFind: function (obj, predicate, context) { var key; if (BI.isArray(obj)) { key = BI.findLastIndex(obj, predicate, context); } else { key = BI.backFindKey(obj, predicate, context); } if (key !== void 0 && key !== -1) { return obj[key]; } }, remove: function (obj, target, context) { var isFunction = BI.isFunction(target); target = isFunction || BI.isArray(target) ? target : [target]; var i; if (BI.isArray(obj)) { for (i = 0; i < obj.length; i++) { if ((isFunction && target.apply(context, [i, obj[i]]) === true) || (!isFunction && target.contains(obj[i]))) { obj.splice(i--, 1); } } } else { BI.each(obj, function (i, v) { if ((isFunction && target.apply(context, [i, obj[i]]) === true) || (!isFunction && target.contains(obj[i]))) { delete obj[i]; } }); } }, removeAt: function (obj, index) { index = BI.isArray(index) ? index : [index]; var isArray = BI.isArray(obj), i; for (i = 0; i < index.length; i++) { if (isArray) { obj[index[i]] = "$deleteIndex"; } else { delete obj[index[i]]; } } if (isArray) { BI.remove(obj, "$deleteIndex"); } }, string2Array: function (str) { return str.split('&-&'); }, array2String: function (array) { return array.join("&-&"); }, abc2Int: function (str) { var idx = 0, start = 'A', str = str.toUpperCase(); for (var i = 0, len = str.length; i < len; ++i) { idx = str.charAt(i).charCodeAt(0) - start.charCodeAt(0) + 26 * idx + 1; if (idx > (2147483646 - str.charAt(i).charCodeAt(0) + start.charCodeAt(0)) / 26) { return 0; } } return idx; }, int2Abc: function (num) { var DIGITS = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']; var idx = num, str = ""; if (num === 0) { return ""; } while (idx !== 0) { var t = idx % 26; if (t === 0) { t = 26; } str = DIGITS[t - 1] + str; idx = (idx - t) / 26; } return str; } }); //数组相关的方法 _.each(["first", "initial", "last", "rest", "compact", "flatten", "without", "union", "intersection", "difference", "zip", "unzip", "object", "indexOf", "lastIndexOf", "sortedIndex", "range"], function (name) { BI[name] = _apply(name) }); _.each(["findIndex", "findLastIndex"], function (name) { BI[name] = _applyFunc(name) }); _.extend(BI, { //构建一个长度为length的数组 makeArray: function (length, value) { var res = []; for (var i = 0; i < length; i++) { if (BI.isNull(value)) { res.push(i); } else { res.push(BI.deepClone(value)); } } return res; }, makeObject: function (array, value) { var map = {}; for (var i = 0; i < array.length; i++) { if (BI.isNull(value)) { map[array[i]] = array[i]; } else { map[array[i]] = BI.deepClone(value); } } return map; }, makeArrayByArray: function (array, value) { var res = []; if (!array) { return res; } for (var i = 0, len = array.length; i < len; i++) { if (BI.isArray(array[i])) { res.push(arguments.callee(array[i], value)); } else { res.push(BI.deepClone(value)); } } return res; }, uniq: function (array, isSorted, iteratee, context) { if (array == null) { return []; } if (!_.isBoolean(isSorted)) { context = iteratee; iteratee = isSorted; isSorted = false; } iteratee && (iteratee = traverse(iteratee, context)); return _.uniq.call(_, array, isSorted, iteratee, context); } }); //对象相关方法 _.each(["keys", "allKeys", "values", "pairs", "invert", "create", "functions", "extend", "extendOwn", "defaults", "clone", "property", "propertyOf", "matcher", "isEqual", "isMatch", "isEmpty", "isElement", "isNumber", "isString", "isArray", "isObject", "isArguments", "isFunction", "isFinite", "isBoolean", "isDate", "isRegExp", "isError", "isNaN", "isUndefined"], function (name) { BI[name] = _apply(name) }); _.each(["mapObject", "findKey", "pick", "omit", "tap"], function (name) { BI[name] = _applyFunc(name) }); _.extend(BI, { inherit: function (sb, sp, overrides) { if (typeof sp == 'object') { overrides = sp; sp = sb; sb = function () { sp.apply(this, arguments); }; } var F = function () { }, spp = sp.prototype; F.prototype = spp; sb.prototype = new F(); sb.superclass = spp; _.extend(sb.prototype, overrides, { superclass: sp }); return sb; }, has: function (obj, keys) { if (BI.isArray(keys)) { if (keys.length === 0) { return false; } return BI.every(keys, function (i, key) { return _.has(obj, key); }); } return _.has.apply(_, arguments); }, //数字和字符串可以作为key isKey: function (key) { return BI.isNumber(key) || (BI.isString(key) && key.length > 0); }, //忽略大小写的等于 isCapitalEqual: function (a, b) { a = BI.isNull(a) ? a : ("" + a).toLowerCase(); b = BI.isNull(b) ? b : ("" + b).toLowerCase(); return BI.isEqual(a, b); }, isWidthOrHeight: function (w) { if (typeof w == 'number') { return w >= 0; } else if (typeof w == 'string') { return /^\d{1,3}%$/.exec(w) || w == 'auto' || /^\d+px$/.exec(w); } }, isNotNull: function (obj) { return !BI.isNull(obj); }, isNull: function (obj) { return typeof obj === "undefined" || obj === null; }, isPlainObject: function () { return $.isPlainObject.apply($, arguments); }, isEmptyArray: function (arr) { return BI.isArray(arr) && BI.isEmpty(arr); }, isNotEmptyArray: function (arr) { return BI.isArray(arr) && !BI.isEmpty(arr); }, isEmptyObject: function (obj) { return BI.isEqual(obj, {}); }, isNotEmptyObject: function (obj) { return BI.isPlainObject(obj) && !BI.isEmptyObject(obj); }, isEmptyString: function (obj) { return BI.isString(obj) && obj.length === 0; }, isNotEmptyString: function (obj) { return BI.isString(obj) && !BI.isEmptyString(obj); }, isWindow: function () { return $.isWindow.apply($, arguments); } }); //deep方法 _.extend(BI, { /** *完全克隆�?个js对象 * @param obj * @returns {*} */ deepClone: function (obj) { if (obj === null || obj === undefined) { return obj; } var type = Object.prototype.toString.call(obj); // Date if (type === '[object Date]') { return new Date(obj.getTime()); } var i, clone, key; // Array if (type === '[object Array]') { i = obj.length; clone = []; while (i--) { clone[i] = BI.deepClone(obj[i]); } } // Object else if (type === '[object Object]' && obj.constructor === Object) { clone = {}; for (var i in obj) { if (_.has(obj, i)) { clone[i] = BI.deepClone(obj[i]); } } } return clone || obj; }, isDeepMatch: function (object, attrs) { var keys = BI.keys(attrs), length = keys.length; if (object == null) { return !length; } var obj = Object(object); for (var i = 0; i < length; i++) { var key = keys[i]; if (!BI.isEqual(attrs[key], obj[key]) || !(key in obj)) { return false; } } return true; }, deepContains: function (obj, copy) { if (BI.isObject(copy)) { return BI.any(obj, function (i, v) { if (BI.isEqual(v, copy)) { return true; } }) } return BI.contains(obj, copy); }, deepIndexOf: function (obj, target) { for (var i = 0; i < obj.length; i++) { if (BI.isEqual(target, obj[i])) { return i; } } return -1; }, deepRemove: function (obj, target) { var done = false; var i; if (BI.isArray(obj)) { for (i = 0; i < obj.length; i++) { if (BI.isEqual(target, obj[i])) { obj.splice(i--, 1); done = true; } } } else { BI.each(obj, function (i, v) { if (BI.isEqual(target, obj[i])) { delete obj[i]; done = true; } }); } return done; }, deepWithout: function (obj, target) { if (BI.isArray(obj)) { var result = []; for (var i = 0; i < obj.length; i++) { if (!BI.isEqual(target, obj[i])) { result.push(obj[i]); } } return result; } else { var result = {}; BI.each(obj, function (i, v) { if (!BI.isEqual(target, obj[i])) { result[i] = v; } }); return result; } }, deepUnique: function (array) { var result = []; BI.each(array, function (i, item) { if (!BI.deepContains(result, item)) { result.push(item); } }); return result; }, //比较两个对象得出不一样的key值 deepDiff: function (object, other) { object || (object = {}); other || (other = {}); var result = []; var used = []; for (var b in object) { if (this.has(object, b)) { if (!this.isEqual(object[b], other[b])) { result.push(b); } used.push(b); } } for (var b in other) { if (this.has(other, b) && !used.contains(b)) { result.push(b); } } return result; } }); //通用方法 _.each(["uniqueId", "result", "chain", "iteratee", "escape", "unescape"], function (name) { BI[name] = function () { return _[name].apply(_, arguments); } }); //事件相关方法 _.each(["bind", "once", "partial", "debounce", "throttle", "delay", "defer", "wrap"], function (name) { BI[name] = function () { return _[name].apply(_, arguments); } }); _.extend(BI, { nextTick: (function () { var callbacks = []; var pending = false; var timerFunc; function nextTickHandler() { pending = false; var copies = callbacks.slice(0); callbacks = []; for (var i = 0; i < copies.length; i++) { copies[i](); } } if (typeof Promise !== 'undefined') { var p = Promise.resolve(); timerFunc = function () { p.then(nextTickHandler); } } else /* istanbul ignore if */ if (typeof MutationObserver !== 'undefined') { var counter = 1; var observer = new MutationObserver(nextTickHandler); var textNode = document.createTextNode(counter + ""); observer.observe(textNode, { characterData: true }); timerFunc = function () { counter = (counter + 1) % 2; textNode.data = counter + ""; } } else { timerFunc = function () { setTimeout(nextTickHandler, 0) } } return function queueNextTick(cb) { var _resolve; var args = [].slice.call(arguments, 1); callbacks.push(function () { if (cb) { cb.apply(null, args); } if (_resolve) { _resolve.apply(null, args); } }); if (!pending) { pending = true; timerFunc(); } if (!cb && typeof Promise !== 'undefined') { return new Promise(function (resolve) { _resolve = resolve }) } } })() }); //数字相关方法 _.each(["random"], function (name) { BI[name] = _apply(name) }); _.extend(BI, { getTime: function () { if (window.performance && window.performance.now) { return window.performance.now(); } else { if (window.performance && window.performance.webkitNow) { return window.performance.webkitNow(); } else { if (Date.now) { return Date.now(); } else { return new Date().getTime(); } } } }, parseInt: function (number) { var radix = 10; if (/^0x/g.test(number)) { radix = 16; } try { return parseInt(number, radix); } catch (e) { throw new Error(number + "parse int error"); return NaN; } }, parseSafeInt: function (value) { var MAX_SAFE_INTEGER = 9007199254740991; return value ? this.clamp(this.parseInt(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER) : (value === 0 ? value : 0); }, parseFloat: function (number) { try { return parseFloat(number); } catch (e) { throw new Error(number + "parse float error"); return NaN; } }, isNaturalNumber: function (number) { if (/^\d+$/.test(number)) { return true; } return false; }, isPositiveInteger: function (number) { if (/^\+?[1-9][0-9]*$/.test(number)) { return true; } return false; }, isNegativeInteger: function (number) { if (/^\-[1-9][0-9]*$/.test(number)) { return true; } return false; }, isInteger: function (number) { if (/^\-?\d+$/.test(number)) { return true; } return false; }, isNumeric: function (number) { return $.isNumeric(number); }, isFloat: function (number) { if (/^([+-]?)\\d*\\.\\d+$/.test(number)) { return true; } return false; }, isOdd: function (number) { if (!BI.isInteger(number)) { return false; } return number & 1 === 1; }, isEven: function (number) { if (!BI.isInteger(number)) { return false; } return number & 1 === 0; }, sum: function (array, iteratee, context) { var sum = 0; BI.each(array, function (i, item) { if (iteratee) { sum += Number(iteratee.apply(context, [i, item])); } else { sum += Number(item); } }); return sum; }, average: function (array, iteratee, context) { var sum = BI.sum(array, iteratee, context); return sum / array.length; } }); //字符串相关方法 _.extend(BI, { trim: function () { return $.trim.apply($, arguments); }, toUpperCase: function (string) { return (string + "").toLocaleUpperCase(); }, toLowerCase: function (string) { return (string + "").toLocaleLowerCase(); }, isEndWithBlank: function (string) { return /(\s|\u00A0)$/.test(string); }, isLiteral: function (exp) { var literalValueRE = /^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/ return literalValueRE.test(exp) }, stripQuotes: function (str) { var a = str.charCodeAt(0) var b = str.charCodeAt(str.length - 1) return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str }, //background-color => backgroundColor camelize: function (str) { return str.replace(/-(.)/g, function (_, character) { return character.toUpperCase(); }); }, //backgroundColor => background-color hyphenate: function (str) { return str.replace(/([A-Z])/g, '-$1').toLowerCase(); }, isNotEmptyString: function (str) { return BI.isString(str) && !BI.isEmpty(str); }, isEmptyString: function (str) { return BI.isString(str) && BI.isEmpty(str); }, /** * 对字符串进行加密 {@link #decrypt} * @static * @param str 原始字符�? * @param keyt 密钥 * @returns {String} 加密后的字符�? */ encrypt: function (str, keyt) { if (str == "") { return ""; } str = escape(str); if (!keyt || keyt == "") { keyt = "655"; } keyt = escape(keyt); if (keyt == null || keyt.length <= 0) { alert("Please enter a password with which to encrypt the message."); return null; } var prand = ""; for (var i = 0; i < keyt.length; i++) { prand += keyt.charCodeAt(i).toString(); } var sPos = Math.floor(prand.length / 5); var mult = parseInt(prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4) + prand.charAt(sPos * 5)); var incr = Math.ceil(keyt.length / 2); var modu = Math.pow(2, 31) - 1; if (mult < 2) { alert("Algorithm cannot find a suitable hash. Please choose a different password. \nPossible considerations are to choose a more complex or longer password."); return null; } // var salt = Math.round(Math.random() * 1000000000) % 100000000; var salt = 101; prand += salt; while (prand.length > 10) { prand = (parseInt(prand.substring(0, 10)) + parseInt(prand.substring(10, prand.length), 10)).toString(); } prand = (mult * prand + incr) % modu; var enc_chr = ""; var enc_str = ""; for (var i = 0; i < str.length; i++) { enc_chr = parseInt(str.charCodeAt(i) ^ Math.floor((prand / modu) * 255)); if (enc_chr < 16) { enc_str += "0" + enc_chr.toString(16); } else { enc_str += enc_chr.toString(16); } prand = (mult * prand + incr) % modu; } salt = salt.toString(16); while (salt.length < 8) { salt = "0" + salt; } enc_str += salt; return enc_str; }, /** * 对加密后的字符串解密 {@link #encrypt} * @static * @param str 加密过的字符�? * @param keyt 密钥 * @returns {String} 解密后的字符�? */ decrypt: function (str, keyt) { if (str == "") { return ""; } if (!keyt || keyt == "") { keyt = "655"; } keyt = escape(keyt); if (str == null || str.length < 8) { return; } if (keyt == null || keyt.length <= 0) { return; } var prand = ""; for (var i = 0; i < keyt.length; i++) { prand += keyt.charCodeAt(i).toString(); } var sPos = Math.floor(prand.length / 5); var tempmult = prand.charAt(sPos) + prand.charAt(sPos * 2) + prand.charAt(sPos * 3) + prand.charAt(sPos * 4); if (sPos * 5 < prand.length) { tempmult += prand.charAt(sPos * 5); } var mult = parseInt(tempmult); var incr = Math.round(keyt.length / 2); var modu = Math.pow(2, 31) - 1; var salt = parseInt(str.substring(str.length - 8, str.length), 16); str = str.substring(0, str.length - 8); prand += salt; while (prand.length > 10) { prand = (parseInt(prand.substring(0, 10), 10) + parseInt(prand.substring(10, prand.length), 10)).toString(); } prand = (mult * prand + incr) % modu; var enc_chr = ""; var enc_str = ""; for (var i = 0; i < str.length; i += 2) { enc_chr = parseInt(parseInt(str.substring(i, i + 2), 16) ^ Math.floor((prand / modu) * 255)); enc_str += String.fromCharCode(enc_chr); prand = (mult * prand + incr) % modu; } return unescape(enc_str); } }); //浏览器相关方法 _.extend(BI, { isIE: function () { return /(msie|trident)/i.test(navigator.userAgent.toLowerCase()); }, getIEVersion: function () { var version = 0; var agent = navigator.userAgent.toLowerCase(); var v1 = agent.match(/(?:msie\s([\w.]+))/); var v2 = agent.match(/(?:trident.*rv:([\w.]+))/); if (v1 && v2 && v1[1] && v2[1]) { version = Math.max(v1[1] * 1, v2[1] * 1); } else if (v1 && v1[1]) { version = v1[1] * 1; } else if (v2 && v2[1]) { version = v2[1] * 1; } else { version = 0; } return version; }, isIE9Below: function () { if (!BI.isIE()) { return false; } return this.getIEVersion() < 9; }, isIE9: function () { return this.getIEVersion() === 9; }, isEdge: function () { return /edge/i.test(navigator.userAgent.toLowerCase()); }, isChrome: function () { return /chrome/i.test(navigator.userAgent.toLowerCase()); }, isFireFox: function () { return /firefox/i.test(navigator.userAgent.toLowerCase()); }, isOpera: function () { return /opera/i.test(navigator.userAgent.toLowerCase()); }, isSafari: function () { return /safari/i.test(navigator.userAgent.toLowerCase()); }, isKhtml: function () { return /Konqueror|Safari|KHTML/i.test(navigator.userAgent); }, isMac: function () { return /macintosh|mac os x/i.test(navigator.userAgent); }, isWindows: function () { return /windows|win32/i.test(navigator.userAgent); }, isSupportCss3: function (style) { var prefix = ['webkit', 'Moz', 'ms', 'o'], i, len, humpString = [], htmlStyle = document.documentElement.style, _toHumb = function (string) { return string.replace(/-(\w)/g, function ($0, $1) { return $1.toUpperCase(); }); }; for (i in prefix) { humpString.push(_toHumb(prefix[i] + '-' + style)); } humpString.push(_toHumb(style)); for (i = 0, len = humpString.length; i < len; i++) { if (humpString[i] in htmlStyle) { return true; } } return false; } }); //BI请求 _.extend(BI, { ajax: function (option) { option || (option = {}); var async = option.async; option.data = BI.cjkEncodeDO(option.data || {}); $.ajax({ url: option.url, type: "POST", data: option.data, async: async, error: option.error, complete: function (res, status) { if (BI.isFunction(option.complete)) { option.complete(BI.jsonDecode(res.responseText), status); } } }); } }); })(jQuery);/** * 客户端观察者,主要处理事件的添加、删除、执行等 * @class BI.OB * @abstract */ BI.OB = function (config) { var props = this.props; if (BI.isFunction(this.props)) { props = this.props(config); } this.options = $.extend(this._defaultConfig(config), props, config); this._init(); this._initRef(); }; $.extend(BI.OB.prototype, { props: {}, init: null, destroyed: null, _defaultConfig: function (config) { return {}; }, _init: function () { this._initListeners(); this.init && this.init(); }, _initListeners: function () { var self = this; if (this.options.listeners != null) { $.each(this.options.listeners, function (i, lis) { (lis.target ? lis.target : self)[lis.once ? 'once' : 'on'] (lis.eventName, _.bind(lis.action, self)) }); delete this.options.listeners; } }, //获得一个当前对象的引用 _initRef: function () { if (this.options.ref) { this.options.ref.call(this, this); } }, _getEvents: function () { if (!$.isArray(this.events)) { this.events = [] } return this.events; }, /** * 给观察者绑定一个事件 * @param {String} eventName 事件的名字 * @param {Function} fn 事件对应的执行函数 */ on: function (eventName, fn) { eventName = eventName.toLowerCase(); var fns = this._getEvents()[eventName]; if (!$.isArray(fns)) { fns = []; this._getEvents()[eventName] = fns; } fns.push(fn); }, /** * 给观察者绑定一个只执行一次的事件 * @param {String} eventName 事件的名字 * @param {Function} fn 事件对应的执行函数 */ once: function (eventName, fn) { var proxy = function () { fn.apply(this, arguments); this.un(eventName, proxy); }; this.on(eventName, proxy); }, /** * 解除观察者绑定的指定事件 * @param {String} eventName 要解除绑定事件的名字 * @param {Function} fn 事件对应的执行函数,该参数是可选的,没有该参数时,将解除绑定所有同名字的事件 */ un: function (eventName, fn) { eventName = eventName.toLowerCase(); /*alex:如果fn是null,就是把eventName上面所有方法都un掉*/ if (fn == null) { delete this._getEvents()[eventName]; } else { var fns = this._getEvents()[eventName]; if ($.isArray(fns)) { var newFns = []; $.each(fns, function (idx, ifn) { if (ifn != fn) { newFns.push(ifn); } }) this._getEvents()[eventName] = newFns; } } }, /** * 清除观察者的所有事件绑定 */ purgeListeners: function () { /*alex:清空events*/ this.events = []; }, /** * 触发绑定过的事件 * * @param {String} eventName 要触发的事件的名字 * @returns {Boolean} 如果事件函数返回false,则返回false并中断其他同名事件的执行,否则执行所有的同名事件并返回true */ fireEvent: function () { var eventName = arguments[0].toLowerCase(); var fns = this._getEvents()[eventName]; if (BI.isArray(fns)) { if (BI.isArguments(arguments[1])) { for (var i = 0; i < fns.length; i++) { if (fns[i].apply(this, arguments[1]) === false) { return false; } } } else { var args = Array.prototype.slice.call(arguments, 1); for (var i = 0; i < fns.length; i++) { if (fns[i].apply(this, args) === false) { return false; } } } } return true; }, destroy: function () { this.destroyed && this.destroyed(); this.purgeListeners(); } });/** * Widget超类 * @class BI.Widget * @extends BI.OB * * @cfg {JSON} options 配置属性 */ BI.Widget = BI.inherit(BI.OB, { _defaultConfig: function () { return BI.extend(BI.Widget.superclass._defaultConfig.apply(this), { root: false, tagName: "div", attributes: null, data: null, tag: null, disabled: false, invisible: false, invalid: false, baseCls: "", extraCls: "", cls: "" }) }, //生命周期函数 beforeCreate: null, created: null, render: null, beforeMounted: null, mounted: null, update: function () { }, beforeDestroyed: null, destroyed: null, _init: function () { BI.Widget.superclass._init.apply(this, arguments); this.beforeCreate && this.beforeCreate(); this._initRoot(); this._initElementWidth(); this._initElementHeight(); this._initVisual(); this._initState(); this._initElement(); this._initEffects(); this.created && this.created(); }, /** * 初始化根节点 * @private */ _initRoot: function () { var o = this.options; this.widgetName = o.widgetName || BI.uniqueId("widget"); this._isRoot = o.root; if (BI.isWidget(o.element)) { if (o.element instanceof BI.Widget) { this._parent = o.element; this._parent.addWidget(this.widgetName, this); } else { this._isRoot = true; } this.element = this.options.element.element; } else if (o.element) { // if (o.root !== true) { // throw new Error("root is a required property"); // } this.element = $(o.element); this._isRoot = true; } else { this.element = $(document.createElement(o.tagName)); } if (o.baseCls || o.extraCls || o.cls) { this.element.addClass((o.baseCls || "") + " " + (o.extraCls || "") + " " + (o.cls || "")); } if (o.attributes) { this.element.attr(o.attributes); } if (o.data) { this.element.data(o.data); } this._children = {}; }, _initElementWidth: function () { var o = this.options; if (BI.isWidthOrHeight(o.width)) { this.element.css("width", o.width); } }, _initElementHeight: function () { var o = this.options; if (BI.isWidthOrHeight(o.height)) { this.element.css("height", o.height); } }, _initVisual: function () { var o = this.options; if (o.invisible) { //用display属性做显示和隐藏,否则jquery会在显示时将display设为block会覆盖掉display:flex属性 this.element.css("display", "none"); } }, _initEffects: function () { var o = this.options; if (o.disabled || o.invalid) { if (this.options.disabled) { this.setEnable(false); } if (this.options.invalid) { this.setValid(false); } } }, _initState: function () { this._isMounted = false; }, _initElement: function () { var self = this; var els = this.render && this.render(); if (BI.isPlainObject(els)) { els = [els]; } if (BI.isArray(els)) { BI.each(els, function (i, el) { BI.createWidget(el, { element: self }) }) } // if (this._isRoot === true || !(this instanceof BI.Layout)) { this._mount(); // } }, _setParent: function (parent) { this._parent = parent; }, _mount: function () { var self = this; var isMounted = this._isMounted; if (isMounted || !this.isVisible()) { return; } if (this._isRoot === true) { isMounted = true; } else if (this._parent && this._parent._isMounted === true) { isMounted = true; } if (!isMounted) { return; } this.beforeMounted && this.beforeMounted(); this._isMounted = true; this._mountChildren && this._mountChildren(); BI.each(this._children, function (i, widget) { !self.isEnabled() && widget._setEnable(false); !self.isValid() && widget._setValid(false); widget._mount && widget._mount(); }); this.mounted && this.mounted(); }, _mountChildren: null, isMounted: function () { return this._isMounted; }, setWidth: function (w) { this.options.width = w; this._initElementWidth(); }, setHeight: function (h) { this.options.height = h; this._initElementHeight(); }, _setEnable: function (enable) { if (enable === true) { this.options.disabled = false; } else if (enable === false) { this.options.disabled = true; } //递归将所有子组件使能 BI.each(this._children, function (i, child) { !child._manualSetEnable && child._setEnable && child._setEnable(enable); }); }, _setValid: function (valid) { if (valid === true) { this.options.invalid = false; } else if (valid === false) { this.options.invalid = true; } //递归将所有子组件使有效 BI.each(this._children, function (i, child) { !child._manualSetValid && child._setValid && child._setValid(valid); }); }, _setVisible: function (visible) { if (visible === true) { this.options.invisible = false; } else if (visible === false) { this.options.invisible = true; } }, setEnable: function (enable) { this._manualSetEnable = true; this._setEnable(enable); if (enable === true) { this.element.removeClass("base-disabled disabled"); } else if (enable === false) { this.element.addClass("base-disabled disabled"); } }, setVisible: function (visible) { this._setVisible(visible); if (visible === true) { //用this.element.show()会把display属性改成block this.element.css("display", ""); this._mount(); } else if (visible === false) { this.element.css("display", "none"); } this.fireEvent(BI.Events.VIEW, visible); }, setValid: function (valid) { this._manualSetValid = true; this._setValid(valid); if (valid === true) { this.element.removeClass("base-invalid invalid"); } else if (valid === false) { this.element.addClass("base-invalid invalid"); } }, doBehavior: function () { var args = arguments; //递归将所有子组件使有效 BI.each(this._children, function (i, child) { child.doBehavior && child.doBehavior.apply(child, args); }); }, getWidth: function () { return this.options.width; }, getHeight: function () { return this.options.height; }, isValid: function () { return !this.options.invalid; }, addWidget: function (name, widget) { var self = this; if (name instanceof BI.Widget) { widget = name; name = widget.getName(); } if (BI.isKey(name)) { name = name + ""; } name = name || widget.getName() || BI.uniqueId("widget"); if (this._children[name]) { throw new Error("name has already been existed"); } widget._setParent && widget._setParent(this); widget.on(BI.Events.DESTROY, function () { BI.remove(self._children, this); }); return (this._children[name] = widget); }, getWidgetByName: function (name) { if (!BI.isKey(name) || name === this.getName()) { return this; } name = name + ""; var widget = void 0, other = {}; BI.any(this._children, function (i, wi) { if (i === name) { widget = wi; return true; } other[i] = wi; }); if (!widget) { BI.any(other, function (i, wi) { return (widget = wi.getWidgetByName(i)); }); } return widget; }, removeWidget: function (nameOrWidget) { var self = this; if (BI.isWidget(nameOrWidget)) { BI.remove(this._children, nameOrWidget); } else { delete this._children[nameOrWidget]; } }, hasWidget: function (name) { return this._children[name] != null; }, getName: function () { return this.widgetName; }, setTag: function (tag) { this.options.tag = tag; }, getTag: function () { return this.options.tag; }, attr: function (key, value) { var self = this; if (BI.isPlainObject(key)) { BI.each(key, function (k, v) { self.attr(k, v); }) return; } if (BI.isNotNull(value)) { return this.options[key] = value; } return this.options[key]; }, getText: function () { }, setText: function (text) { }, getValue: function () { }, setValue: function (value) { }, isEnabled: function () { return !this.options.disabled; }, isVisible: function () { return !this.options.invisible; }, disable: function () { this.setEnable(false); }, enable: function () { this.setEnable(true); }, valid: function () { this.setValid(true); }, invalid: function () { this.setValid(false); }, invisible: function () { this.setVisible(false); }, visible: function () { this.setVisible(true); }, __d: function () { this.beforeDestroyed && this.beforeDestroyed(); BI.each(this._children, function (i, widget) { widget._unMount && widget._unMount(); }); this._children = {}; this._parent = null; this._isMounted = false; this.destroyed && this.destroyed(); }, _unMount: function () { this.__d(); this.fireEvent(BI.Events.UNMOUNT); this.purgeListeners(); }, isolate: function () { if (this._parent) { this._parent.removeWidget(this); } BI.DOM.hang([this]); }, empty: function () { BI.each(this._children, function (i, widget) { widget._unMount && widget._unMount(); }); this._children = {}; this.element.empty(); }, _destroy: function () { this.__d(); this.element.destroy(); this.purgeListeners(); }, destroy: function () { this.__d(); this.element.destroy(); this.fireEvent(BI.Events.DESTROY); this.purgeListeners(); } });BI.Model = BI.inherit(BI.M, { props: {}, init: null, destroyed: null, _defaultConfig: function () { return BI.extend({ "default": "just a default", "current": void 0 }, this.props) }, _static: function () { return {}; }, _init: function () { BI.Model.superclass._init.apply(this, arguments); this.on("change:current", function (obj, val) { BI.isNotNull(val) && this.refresh(val); }).on("change", function (changed, prev, context, options) { if (this._start === true || BI.has(changed, "current")) { return; } this.actionStart(); if (!this.local()) { !BI.has(this._tmp, BI.keys(changed)) && this.parent && this.parent._change(this); this._changing_ = true; this.change(changed, prev, context, options); this._changing_ = false; } }); this._tmp = {};//过渡属性 this._hass = {}; this._gets = [];//记录交互行为 this._start = false; this._changing_ = false; this._read = BI.debounce(BI.bind(this.fetch, this), 30); this._save = BI.debounce(BI.bind(this.save, this), 30); this._F = []; this.init && this.init(); }, toJSON: function () { var json = BI.Model.superclass.toJSON.apply(this, arguments); delete json["baseCls"]; delete json["current"]; delete json["default"]; delete json["parent"]; delete json["rootURL"]; delete json["id"]; delete json["tag"]; BI.each(this._gets, function (i, action) { delete json[action]; }); return json; }, copy: function () { if (this._start === true || this._changing_ === true) { this._F.push({f: this.copy, arg: arguments}); return; } this.trigger("copy"); }, //子节点的一个类似副本 similar: function (value, key1, key2, key3) { return value; }, _map: function (child) { var self = this; var map = {}, current = {}; var mapping = function (key, ch) { key = key + ""; if (key === "") { return; } var keys = key.split('.'); if (!map[keys[0]]) { map[keys[0]] = self.get(keys[0]); } var parent = map, last = void 0; BI.each(keys, function (i, k) { last && (parent = parent[last] || (parent[last] = {})); last = k; }); parent[last] = ch.toJSON(); }; BI.each(this._childs, function (key, chs) { if (!BI.isArray(chs)) { chs = [chs]; } BI.each(chs, function (i, ch) { if (ch === child) { current[key] = child; return; } //mapping(key, ch); }) }); BI.each(current, function (key, ch) { mapping(key, ch); }); var tmp = {}; BI.each(this._tmp, function (k) { if (map[k]) { tmp[k] = map[k]; delete map[k]; } }); this.tmp(tmp); return map; }, _change: function (child) { var self = this; var childMap = this._map(child); //this.set(childMap); var changes = []; var changing = this._changing; var changed; var options = {}; this._changing = true; if (!changing) { this._previousAttributes = _.clone(this.attributes); this.changed = {}; } var current = this.attributes, prev = this._previousAttributes, val; for (var attr in childMap) { val = childMap[attr]; changes.push(attr); this.changed[attr] = val; current[attr] = val; } if (changes.length) this._pending = options; for (var i = 0, length = changes.length; i < length; i++) { this.trigger('change:' + changes[i], this, current[changes[i]], options); } if (changing) return this; changed = BI.clone(this.changed); while (this._pending) { options = this._pending; this._pending = false; this.trigger('change', changed, prev, this, options); } this._pending = false; this._changing = false; if (changes.length) { this.trigger("changed", changed, prev, this, options); } return this; }, splice: function (old, key1, key2, key3) { }, duplicate: function (copy, key1, key2, key3) { }, change: function (changed, prev) { }, actionStart: function () { this._start = true; return this; }, actionEnd: function () { var self = this; this._start = false; var _gets = this._gets.slice(0), _F = this._F.slice(0); this._gets = []; this._hass = {}; this._F = []; BI.each(_gets, function (i, action) { self.unset(action, {silent: true}); }); BI.each(_F, function (i, fn) { fn.f.apply(self, fn.arg); }); return this; }, addChild: function (name, child) { name = name + ""; var self = this; this._childs || (this._childs = {}); if (this._childs[name]) { if (BI.isArray(this._childs[name])) { this._childs[name].push(child); } else { this._childs[name] = [this._childs[name]].concat(child) } } else { this._childs[name] = child; } child && child.on("destroy", function () { var keys = name.split('.'); var g = self.get(keys[0]), p, c; var sset = !!self._tmp[keys[0]] ? "tmp" : "set", unset = "un" + sset; BI.each(keys, function (i, k) { if (i === 0) { c = g; return; } p = c; c = c[k]; }); self.removeChild(name, child); var newKeys = BI.clone(keys); keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g)); keys.length > 1 ? (delete p[keys[keys.length - 1]], self[sset](keys[0], g, {silent: true})) : self[unset](name, {silent: true}); !BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self); self.splice.apply(self, newKeys); self.trigger("splice", newKeys); BI.remove(self._childs, child); }).on("copy", function () { var keys = name.split('.'); var g = self.get(keys[0]), p, c; var sset = !!self._tmp[keys[0]] ? "tmp" : "set"; BI.each(keys, function (i, k) { if (i === 0) { c = g; return; } p = c; c = c[k]; }); var copy = BI.UUID(), newKeys = BI.clone(keys); keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g)); var backup = self.similar.apply(self, newKeys); if (BI.isKey(backup.id)) { copy = backup.id; delete backup.id; } keys.length > 1 ? (p[copy] = backup, self[sset](keys[0], g, {silent: true})) : self[sset](copy, backup, {silent: true}); keys.unshift(copy); !BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self); self.duplicate.apply(self, keys); self.trigger("duplicate", keys); }); }, removeChild: function (name, child) { if (BI.isArray(this._childs[name])) { BI.remove(this._childs[name], child); if (BI.isEmpty(this._childs[name])) { delete this._childs[name]; } return; } delete this._childs[name]; }, has: function (attr, istemp) { if (istemp === true) { return _.has(this.tmp, attr); } if (this._start === true && this._changing_ === false) { this._hass[attr] = true; } return BI.Model.superclass.has.apply(this, arguments); }, cat: function (attr) { if (_.has(this._tmp, attr)) { return this._tmp[attr]; } if (this._start === true && this._hass[attr]) { delete this._hass[attr]; switch (attr) { case "default": break; case "current": break; default : this._gets.push(attr); break; } } if (_.has(this.attributes, attr)) { return this.attributes[attr]; } var sta = _.result(this, "_static"); return BI.isFunction(sta[attr]) ? sta[attr].apply(this, BI.values(arguments).slice(1)) : sta[attr]; }, get: function () { return BI.deepClone(this.cat.apply(this, arguments)); }, set: function (key, val, options) { if (this._start === true || this._changing_ === true) { this._F.push({f: this.set, arg: arguments}); return this; } return BI.Model.superclass.set.apply(this, arguments); }, unset: function (attr, options) { var self = this; BI.each(this._childs, function (key, model) { key = key + ""; var keys = key.split('.'); if (_.isEqual(attr, keys[0])) { delete self._childs[attr]; if (!BI.isArray(model)) { model = [model]; } BI.each(model, function (i, m) { m.trigger("unset"); }); } }); return BI.Model.superclass.unset.apply(this, arguments); }, tmp: function (key, val, options) { if (this._start === true || this._changing_ === true) { this._F.push({f: this.tmp, arg: arguments}); return this; } var attr, attrs, unset, changes, silent, changing, changed, prev, current; if (key == null) return this; if (typeof key === 'object') { attrs = key; options = val; } else { (attrs = {})[key] = val; } options || (options = {}); unset = options.unset; silent = options.silent; changes = []; changing = this._changingTmp; this._changingTmp = true; if (!changing) { this._previousTmp = _.clone(this._tmp); this.changedTmp = {}; } if (!this._previousTmp) { this._previousTmp = _.clone(this._tmp); } current = this._tmp, prev = this._previousTmp; for (attr in attrs) { val = attrs[attr]; if (!_.isEqual(current[attr], val)) changes.push(attr); if (!_.isEqual(prev[attr], val)) { this.changedTmp[attr] = val; } else { delete this.changedTmp[attr]; } unset ? delete current[attr] : current[attr] = val; } if (!silent) { if (changes.length) this._pendingTmp = options; for (var i = 0, length = changes.length; i < length; i++) { this.trigger('change:' + changes[i], this, current[changes[i]], options); } } if (changing) return this; changed = BI.clone(this.changedTmp); if (!silent) { while (this._pendingTmp) { options = this._pendingTmp; this._pendingTmp = false; this.trigger('change', changed, prev, this, options); } } this._pendingTmp = false; this._changingTmp = false; if (!silent && changes.length) this.trigger("changed", changed, prev, this, options); return this; }, untmp: function (attr, options) { var self = this; BI.each(this._childs, function (key, model) { key = key + ""; var keys = key.split('.'); if (_.isEqual(attr, keys[0])) { delete self._childs[attr]; if (!BI.isArray(model)) { model = [model]; } BI.each(model, function (i, m) { m.trigger("unset"); }); } }); return this.tmp(attr, void 0, _.extend({}, options, {unset: true})); }, cancel: function (options) { var self = this; var tmp = BI.clone(this._tmp); this._tmp = {}; BI.each(tmp, function (k) { self.untmp(k, options); }); }, submit: function () { var tmp = BI.clone(this._tmp); this._tmp = {}; this.set(tmp); return this; }, urlRoot: function () { return BI.servletURL; }, parse: function (data) { return data; }, setEditing: function (edit) { this._editing = edit; }, getEditing: function () { if (this._start !== true) { throw new Error("getEditing函数只允许在local中调用"); } return this._editing; }, local: function () { }, load: function (data) { }, refresh: function () { }, /** * 更新整个model */ updateURL: function () { }, /** * 添加一个元素或删除一个元素或修改一个元素 */ patchURL: function () { }, /** * 删除整个model, destroy方法调用 */ deleteURL: function () { }, /** * 读取model */ readURL: function () { }, read: function (options) { if (this._start == true || this._changing_ === true) { this._F.push({f: this.read, arg: arguments}); return; } this._read(options); }, update: function (options) { if (this._start == true || this._changing_ === true) { this._F.push({f: this.update, arg: arguments}); return; } this._save(null, options); }, patch: function (options) { if (this._start == true || this._changing_ === true) { this._F.push({f: this.patch, arg: arguments}); return; } this._save(null, BI.extend({}, options, { patch: true })); }, _destroy: function () { var children = BI.extend({}, this._childs); this._childs = {}; BI.each(children, function (i, child) { child._destroy(); }); this.destroyed && this.destroyed(); }, destroy: function () { this._destroy(); BI.Model.superclass.destroy.apply(this, arguments); } });/** * @class BI.View * @extends BI.V * @type {*|void|Object} */ BI.View = BI.inherit(BI.V, { //生命周期函数 beforeCreate: null, created: null, beforeDestroyed: null, destroyed: null, _init: function () { BI.View.superclass._init.apply(this, arguments); this.beforeCreate && this.beforeCreate(); var self = this; this.listenTo(this.model, "change:current", function (obj, val) { if (BI.isNotNull(val) && val.length > 0) { this.refresh(val); } }).listenTo(this.model, "change", function (changed) { this.delegateEvents(); }).listenTo(this.model, "changed", function (changed, prev, context, options) { if (BI.has(changed, "current") && BI.size(changed) > 1) { throw new Error("refresh操作不能调用set操作"); } var notLocal = !BI.has(changed, "current") && !this.local() && this.notifyParent().notify(); this.model.actionEnd() && this.actionEnd(); this.model._changing_ = true; notLocal && !BI.isEmpty(changed) && this.change(changed, prev, context, options); this.model._changing_ = false; this.model.actionEnd() && this.actionEnd(); }).listenTo(this.model, "destroy", function () { this._destroy(); }).listenTo(this.model, "unset", function () { this._destroy(); }).listenTo(this.model, "splice", function (arg) { this.splice.apply(this, arg); }).listenTo(this.model, "duplicate", function (arg) { this.duplicate.apply(this, arg); }); this._F = []; var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"]; flatten = BI.makeObject(flatten, true); BI.each(this.constructor.caller.caller.prototype, function (key) { if (flatten[key]) { return; } var f = self[key]; if (BI.isFunction(f)) { self[key] = BI.bind(function () { if (this.model._start === true) { this._F.push({f: f, arg: arguments}); return; } return f.apply(this, arguments); }, self); } }); this.created && this.created(); }, change: function (changed, prev) { }, actionEnd: function () { var self = this; var _F = this._F.slice(0); this._F = []; BI.each(_F, function (i, f) { f.f.apply(self, f.arg); }); return this; }, delegateEvents: function (events) { if (!(events || (events = BI.deepClone(_.result(this, 'events'))))) return this; var delegateEventSplitter = /^(\S+)\s*(.*)$/; for (var key in events) { var method = events[key]; if (!_.isFunction(method)) method = this[events[key]]; if (!method) continue; var match = key.match(delegateEventSplitter); var ev = true; switch (match[1]) { case "draggable": break; case "droppable": break; case "sortable": break; case "resizable": break; case "hover": break; default : ev = false; break; } var off = new BI.OffList({ event: match[1] + '.delegateEvents' + this.cid }); var keys = match[2].split('.'); var handle = keys[1]; var bind = ev ? new BI.EventList({ event: match[1], handle: handle, callback: BI.bind(method, this) }) : new BI.ListenerList({ event: match[1] + '.delegateEvents' + this.cid, handle: handle, callback: BI.bind(method, this), context: this }); var list = []; if (this[keys[0]] && (this[keys[0]] instanceof $ || this[keys[0]].element instanceof $)) { list = [this[keys[0]]] delete events[key]; } else if (BI.isArray(this[keys[0]]) || BI.isPlainObject(this[keys[0]])) { list = this[keys[0]] delete events[key]; } off.populate(list); bind.populate(list); } return BI.View.superclass.delegateEvents.apply(this, [events]); }, _vessel: function () { this._cardLayouts = {}; this._cardLayouts[this.getName()] = new BI.CardLayout({ element: this }); var vessel = BI.createWidget(); this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel); return vessel; }, render: function (vessel) { return this; }, /** * 创建儿子所在容器 * @param key * @param vessel * @param options isLayer:是否是弹出层, defaultShowName:默认显示项 * @returns {BI.View} */ addSubVessel: function (key, vessel, options) { options || (options = {}); this._cardLayouts || (this._cardLayouts = {}); var id = key + this.cid; options.isLayer && (vessel = BI.Layers.has(id) ? BI.Layers.get(id) : BI.Layers.create(id, vessel)); if (this._cardLayouts[key]) { options.defaultShowName && this._cardLayouts[key].setDefaultShowName(options.defaultShowName); return this; } this._cardLayouts[key] = BI.createWidget({ type: "bi.card", element: vessel, defaultShowName: options.defaultShowName }); return this; }, removeSubVessel: function (key) { var self = this, id = key + this.cid; BI.Layers.remove(id); var cardNames = this._cardLayouts[key] && this._cardLayouts[key].getAllCardNames(); BI.each(cardNames, function (i, name) { delete self._cards[name]; }); this._cardLayouts[key] && this._cardLayouts[key]._destroy(); return this; }, createView: function (url, modelData, viewData) { return BI.Factory.createView(url, this.get(url), modelData, viewData); }, /** * 跳转到指定的card * @param cardName */ skipTo: function (cardName, layout, modelData, viewData, options) { if (this.model._start === true || this._changing_ === true) { this._F.push({f: this.skipTo, arg: arguments}); return this; } var self = this, isValid = BI.isKey(modelData), data = void 0; BI.isKey(layout) && (layout = layout + ""); layout = layout || this.getName(); options || (options = {}); if (isValid) { modelData = modelData + "";//避免modelData是数字 var keys = modelData.split('.'); BI.each(keys, function (i, k) { if (i === 0) { data = self.model.get(k) || {}; } else { data = data[k] || {}; } }); data.id = options.id || keys[keys.length - 1]; } else { data = modelData; } BI.extend(data, options.data); var action = options.action || new BI.ShowAction(); var cardLayout = this._cardLayouts[layout]; if (!cardLayout) { return this; } cardLayout.setVisible(true); if (BI.isKey(cardName) && !cardLayout.isCardExisted(cardName)) { var view = this.createView(this.rootURL + "/" + cardName, data, viewData); isValid && this.model.addChild(modelData, view.model); view.listenTo(view.model, "destroy", function () { delete self._cards[cardName]; cardLayout.deleteCardByName(cardName); if (cardLayout.isAllCardHide()) { cardLayout.setVisible(false); BI.Layers.hide(layout + self.cid); } }).listenTo(view.model, "unset", function () { delete self._cards[cardName]; cardLayout.deleteCardByName(cardName); }); cardLayout.addCardByName(cardName, view); this._cards || (this._cards = {}); this._cards[cardName] = view; data = {}; this.on("end:" + view.cid, function () { var isNew = false, t, keys; if (isValid) { keys = modelData.split('.'); BI.each(keys, function (i, k) { if (i === 0) { t = self.model.get(k) || (isNew = true); } else { t = t[k] || (isNew = true); } }); } if (isNew) { delete self._cards[cardName]; self.model.removeChild(modelData, view.model); cardLayout.deleteCardByName(cardName); view._destroy(); cardLayout.setVisible(false); } action.actionBack(view, null, function () { if (cardLayout.isAllCardHide()) { cardLayout.setVisible(false); BI.Layers.hide(layout + self.cid); } !isNew && (self.listenEnd.apply(self, isValid ? keys : [modelData]) !== false) && self.populate(); }) }).on("change:" + view.cid, _.bind(this.notifyParent, this)); } BI.isKey(cardName) && BI.Layers.show(layout + this.cid); cardLayout.showCardByName(cardName, action, function () { BI.isKey(cardName) && self._cards[cardName].populate(data, options); }); !BI.isKey(cardName) && BI.Layers.hide(layout + this.cid); return this._cards[cardName]; }, listenEnd: function (key1, key2, key3) { return this; }, /** * 告诉父亲我的操作结束了,后面的事情任由父亲处置 * @param force 强制下次再次进入该节点时不进行刷新操作, 默认执行刷新 * @returns {BI.View} */ notifyParentEnd: function (force) { this.parent && this.parent.trigger("end:" + this.cid); this.trigger("end"); !force && this.notify(); return this; }, /** * 通知父亲我的数据发生了变化 */ notifyParent: function () { this.parent && this.parent.notify().trigger("change:" + this.cid); return this; }, /** * 告诉Model数据改变了 */ notify: function () { this.model.unset("current", {silent: true}); return this; }, getName: function () { return "VIEW" }, /** * 全局刷新 * @param current */ refresh: function (current) { }, /** * 局部刷新 */ local: function () { return false; }, load: function (data) { }, readData: function (force, options) { options || (options = {}); var self = this; var args = [].slice.call(arguments, 2); if (!force && this._readed === true) {//只从后台获取一次数据 callback(this.model.toJSON()); return; } //采用静默方式读数据,该数据变化不引起data的change事件触发 var success = options.success; this.model.read(BI.extend({ silent: true }, options, { success: function (data, model) { callback(data); !force && (self._readed = true); self.delegateEvents(); success && success(data, model); } })); function callback(data) { self.model.load(data); self.load(data); BI.each(args, function (i, arg) { if (BI.isFunction(arg)) { arg.apply(self, [data]); } }) } }, //处理model的通用方法 cat: function () { return this.model.cat.apply(this.model, arguments); }, get: function () { return this.model.get.apply(this.model, arguments); }, set: function () { return this.model.set.apply(this.model, arguments); }, has: function () { return this.model.has.apply(this.model, arguments); }, getEditing: function () { return this.model.getEditing(); }, reading: function (options) { var self = this; var name = BI.UUID(); this.model.read(BI.extend({}, options, { beforeSend: function () { var loading = BI.createWidget({ type: 'bi.vertical', items: [{ type: "bi.layout", height: 30, cls: "loading-background" }], element: BI.Maskers.make(name, self) }); loading.setVisible(true); }, complete: function (data) { options.complete && options.complete(data); BI.Maskers.remove(name); } })); }, updating: function (options) { var self = this; var name = BI.UUID(); this.model.update(BI.extend({}, options, { noset: true, beforeSend: function () { var loading = BI.createWidget({ type: 'bi.vertical', items: [{ type: "bi.layout", height: 30, cls: "loading-background" }], element: BI.Maskers.make(name, self) }); loading.setVisible(true); }, complete: function (data) { options.complete && options.complete(data); BI.Maskers.remove(name); } })); }, patching: function (options) { var self = this; var name = BI.UUID(); this.model.patch(BI.extend({}, options, { noset: true, beforeSend: function () { var loading = BI.createWidget({ type: 'bi.vertical', items: [{ type: "bi.layout", height: 30, cls: "loading-background" }], element: BI.Maskers.make(name, self) }); loading.setVisible(true); }, complete: function (data) { options.complete && options.complete(data); BI.Maskers.remove(name); } })); }, populate: function (modelData, options) { var self = this; options || (options = {}); if (options.force === true) { this.notify(); } if (this._cardLayouts && this._cardLayouts[this.getName()]) { this._cardLayouts[this.getName()].showCardByName(this.getName()); } //BI.each(this._cardLayouts, function (key, layout) { // layout.showCardByName(layout.getDefaultShowName() || self.getName()); //}); //BI.each(this._cards, function (i, card) { // card.notify && card.notify(); //}); if (this._F.length > 0) { throw new Error("流程错误"); } if (options.force === true) { this.model.set(modelData, options).set({current: this.model.get("default")}); return; } if (options.force === false) { this.model.set(modelData); return; } var filter = BI.clone(modelData || {}); delete filter.id; var contains = BI.has(this.model.toJSON(), _.keys(filter)); var match = BI.isEmpty(filter) || (contains && this.model.matches(modelData)); if (match === true) { this.model.set({current: this.model.get("default")}); } else if (contains === false) { this.model.set(modelData); } else { this.model.set(modelData, options).set({current: this.model.get("default")}); } }, //删除子节点触发 splice: function (old, key1, key2, key3) { }, //复制子节点触发 duplicate: function (copy, key1, key2, key3) { }, _unMount: function () { this.beforeDestroyed && this.beforeDestroyed(); BI.each(this._cardLayouts, function (name, card) { card && card._unMount(); }); delete this._cardLayouts; delete this._cards; this.destroyed && this.destroyed(); this.trigger(BI.Events.UNMOUNT); this.off(); }, _destroy: function () { var self = this; BI.each(this._cardLayouts, function (name, card) { card && card._unMount(); BI.Layers.remove(name + self.cid); }); delete this._cardLayouts; delete this._cards; this.destroyed && this.destroyed(); this.remove(); this.trigger(BI.Events.DESTROY); this.off(); } });(function () { var kv = {}; BI.shortcut = function (xtype, cls) { if (kv[xtype] != null) { throw ("shortcut:[" + xtype + "] has been registed"); } kv[xtype] = cls; }; // 根据配置属性生成widget var createWidget = function (config) { if (config['classType']) { return new (new Function('return ' + config['classType'] + ';')())(config); } var xtype = config.type.toLowerCase(); var cls = kv[xtype]; return new cls(config); }; BI.createWidget = function (item, options) { var el; options || (options = {}); if (BI.isEmpty(item) && BI.isEmpty(options)) { return BI.createWidget({ type: "bi.layout" }); } if (BI.isWidget(item)) { return item; } if (item && (item.type || options.type)) { el = BI.extend({}, options, item); return BI.Plugin.getObject(el.type, createWidget(BI.Plugin.getWidget(el.type, el))); } if (item && item.el && (item.el.type || options.type)) { el = BI.extend({}, options, item.el); return BI.Plugin.getObject(el.type, createWidget(BI.Plugin.getWidget(el.type, el))); } if (item && BI.isWidget(item.el)) { return item.el; } throw new Error('无法根据item创建组件'); } })();(function (window, undefined) { function aspect(type) { return function (target, methodName, advice) { var exist = target[methodName], dispatcher; if (!exist || exist.target != target) { dispatcher = target[methodName] = function () { // before methods var beforeArr = dispatcher.before; var args = arguments, next; for (var l = beforeArr.length; l--;) { next = beforeArr[l].advice.apply(this, args); if (next === false) { return false; } args = next || args; } // target method var rs = dispatcher.method.apply(this, args); // after methods var afterArr = dispatcher.after; for (var i = 0, ii = afterArr.length; i < ii; i++) { next = afterArr[i].advice.call(this, rs, args); if (rs === false) { return false; } args = next || args; } return rs; }; dispatcher.before = []; dispatcher.after = []; if (exist) { dispatcher.method = exist; } dispatcher.target = target; } var aspectArr = (dispatcher || exist)[type]; var obj = { advice: advice, _index: aspectArr.length, remove: function () { aspectArr.splice(this._index, 1); } }; aspectArr.push(obj); return obj; }; } BI.aspect = { before: aspect("before"), after: aspect("after") }; return BI.aspect; })(window);; !(function () { var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; // private method for UTF-8 encoding var _utf8_encode = function (string) { string = string.replace(/\r\n/g, "\n"); var utftext = ""; for (var n = 0; n < string.length; n++) { var c = string.charCodeAt(n); if (c < 128) { utftext += String.fromCharCode(c); } else if ((c > 127) && (c < 2048)) { utftext += String.fromCharCode((c >> 6) | 192); utftext += String.fromCharCode((c & 63) | 128); } else { utftext += String.fromCharCode((c >> 12) | 224); utftext += String.fromCharCode(((c >> 6) & 63) | 128); utftext += String.fromCharCode((c & 63) | 128); } } return utftext; }; // private method for UTF-8 decoding var _utf8_decode = function (utftext) { var string = ""; var i = 0; var c = 0, c3 = 0, c2 = 0; while (i < utftext.length) { c = utftext.charCodeAt(i); if (c < 128) { string += String.fromCharCode(c); i++; } else if ((c > 191) && (c < 224)) { c2 = utftext.charCodeAt(i + 1); string += String.fromCharCode(((c & 31) << 6) | (c2 & 63)); i += 2; } else { c2 = utftext.charCodeAt(i + 1); c3 = utftext.charCodeAt(i + 2); string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); i += 3; } } return string; }; _.extend(BI, { encode: function (input) { var output = ""; var chr1, chr2, chr3, enc1, enc2, enc3, enc4; var i = 0; input = _utf8_encode(input); while (i < input.length) { chr1 = input.charCodeAt(i++); chr2 = input.charCodeAt(i++); chr3 = input.charCodeAt(i++); enc1 = chr1 >> 2; enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); enc4 = chr3 & 63; if (isNaN(chr2)) { enc3 = enc4 = 64; } else if (isNaN(chr3)) { enc4 = 64; } output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4); } return output; }, // public method for decoding decode: function (input) { var output = ""; var chr1, chr2, chr3; var enc1, enc2, enc3, enc4; var i = 0; input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); while (i < input.length) { enc1 = _keyStr.indexOf(input.charAt(i++)); enc2 = _keyStr.indexOf(input.charAt(i++)); enc3 = _keyStr.indexOf(input.charAt(i++)); enc4 = _keyStr.indexOf(input.charAt(i++)); chr1 = (enc1 << 2) | (enc2 >> 4); chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); chr3 = ((enc3 & 3) << 6) | enc4; output = output + String.fromCharCode(chr1); if (enc3 != 64) { output = output + String.fromCharCode(chr2); } if (enc4 != 64) { output = output + String.fromCharCode(chr3); } } output = _utf8_decode(output); return output; } }) })();BI.CellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize) { this._cellSizeGetter = cellSizeGetter; this._cellCount = cellCount; this._estimatedCellSize = estimatedCellSize; this._cellSizeAndPositionData = {}; this._lastMeasuredIndex = -1; }; BI.CellSizeAndPositionManager.prototype = { constructor: BI.CellSizeAndPositionManager, configure: function (cellCount, estimatedCellSize) { this._cellCount = cellCount; this._estimatedCellSize = estimatedCellSize; }, getCellCount: function () { return this._cellCount; }, getEstimatedCellSize: function () { return this._estimatedCellSize; }, getLastMeasuredIndex: function () { return this._lastMeasuredIndex; }, getSizeAndPositionOfCell: function (index) { if (index < 0 || index >= this._cellCount) { return; } if (index > this._lastMeasuredIndex) { var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); var offset = lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size; for (var i = this._lastMeasuredIndex + 1; i <= index; i++) { var size = this._cellSizeGetter(i); if (size == null || isNaN(size)) { continue; } this._cellSizeAndPositionData[i] = { offset: offset, size: size }; offset += size; } this._lastMeasuredIndex = index; } return this._cellSizeAndPositionData[index]; }, getSizeAndPositionOfLastMeasuredCell: function () { return this._lastMeasuredIndex >= 0 ? this._cellSizeAndPositionData[this._lastMeasuredIndex] : { offset: 0, size: 0 } }, getTotalSize: function () { var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); return lastMeasuredCellSizeAndPosition.offset + lastMeasuredCellSizeAndPosition.size + (this._cellCount - this._lastMeasuredIndex - 1) * this._estimatedCellSize }, getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) { var datum = this.getSizeAndPositionOfCell(targetIndex); var maxOffset = datum.offset; var minOffset = maxOffset - containerSize + datum.size; var idealOffset; switch (align) { case 'start': idealOffset = maxOffset; break; case 'end': idealOffset = minOffset; break; case 'center': idealOffset = maxOffset - ((containerSize - datum.size) / 2); break; default: idealOffset = Math.max(minOffset, Math.min(maxOffset, currentOffset)); break; } var totalSize = this.getTotalSize(); return Math.max(0, Math.min(totalSize - containerSize, idealOffset)); }, getVisibleCellRange: function (containerSize, offset) { var totalSize = this.getTotalSize(); if (totalSize === 0) { return {} } var maxOffset = offset + containerSize; var start = this._findNearestCell(offset); var datum = this.getSizeAndPositionOfCell(start); offset = datum.offset + datum.size; var stop = start; while (offset < maxOffset && stop < this._cellCount - 1) { stop++; offset += this.getSizeAndPositionOfCell(stop).size; } return { start: start, stop: stop } }, resetCell: function (index) { this._lastMeasuredIndex = Math.min(this._lastMeasuredIndex, index - 1) }, _binarySearch: function (high, low, offset) { var middle; var currentOffset; while (low <= high) { middle = low + Math.floor((high - low) / 2); currentOffset = this.getSizeAndPositionOfCell(middle).offset; if (currentOffset === offset) { return middle; } else if (currentOffset < offset) { low = middle + 1; } else if (currentOffset > offset) { high = middle - 1; } } if (low > 0) { return low - 1; } }, _exponentialSearch: function (index, offset) { var interval = 1; while (index < this._cellCount && this.getSizeAndPositionOfCell(index).offset < offset) { index += interval; interval *= 2; } return this._binarySearch(Math.min(index, this._cellCount - 1), Math.floor(index / 2), offset); }, _findNearestCell: function (offset) { if (isNaN(offset)) { return; } offset = Math.max(0, offset); var lastMeasuredCellSizeAndPosition = this.getSizeAndPositionOfLastMeasuredCell(); var lastMeasuredIndex = Math.max(0, this._lastMeasuredIndex); if (lastMeasuredCellSizeAndPosition.offset >= offset) { return this._binarySearch(lastMeasuredIndex, 0, offset); } else { return this._exponentialSearch(lastMeasuredIndex, offset); } } }; BI.ScalingCellSizeAndPositionManager = function (cellCount, cellSizeGetter, estimatedCellSize, maxScrollSize) { this._cellSizeAndPositionManager = new BI.CellSizeAndPositionManager(cellCount, cellSizeGetter, estimatedCellSize); this._maxScrollSize = maxScrollSize || 10000000 }; BI.ScalingCellSizeAndPositionManager.prototype = { constructor: BI.ScalingCellSizeAndPositionManager, configure: function () { this._cellSizeAndPositionManager.configure.apply(this._cellSizeAndPositionManager, arguments); }, getCellCount: function () { return this._cellSizeAndPositionManager.getCellCount() }, getEstimatedCellSize: function () { return this._cellSizeAndPositionManager.getEstimatedCellSize() }, getLastMeasuredIndex: function () { return this._cellSizeAndPositionManager.getLastMeasuredIndex() }, getOffsetAdjustment: function (containerSize, offset) { var totalSize = this._cellSizeAndPositionManager.getTotalSize(); var safeTotalSize = this.getTotalSize(); var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); return Math.round(offsetPercentage * (safeTotalSize - totalSize)); }, getSizeAndPositionOfCell: function (index) { return this._cellSizeAndPositionManager.getSizeAndPositionOfCell(index); }, getSizeAndPositionOfLastMeasuredCell: function () { return this._cellSizeAndPositionManager.getSizeAndPositionOfLastMeasuredCell(); }, getTotalSize: function () { return Math.min(this._maxScrollSize, this._cellSizeAndPositionManager.getTotalSize()); }, getUpdatedOffsetForIndex: function (align, containerSize, currentOffset, targetIndex) { currentOffset = this._safeOffsetToOffset(containerSize, currentOffset); var offset = this._cellSizeAndPositionManager.getUpdatedOffsetForIndex(align, containerSize, currentOffset, targetIndex); return this._offsetToSafeOffset(containerSize, offset); }, getVisibleCellRange: function (containerSize, offset) { offset = this._safeOffsetToOffset(containerSize, offset); return this._cellSizeAndPositionManager.getVisibleCellRange(containerSize, offset); }, resetCell: function (index) { this._cellSizeAndPositionManager.resetCell(index) }, _getOffsetPercentage: function (containerSize, offset, totalSize) { return totalSize <= containerSize ? 0 : offset / (totalSize - containerSize) }, _offsetToSafeOffset: function (containerSize, offset) { var totalSize = this._cellSizeAndPositionManager.getTotalSize(); var safeTotalSize = this.getTotalSize(); if (totalSize === safeTotalSize) { return offset; } else { var offsetPercentage = this._getOffsetPercentage(containerSize, offset, totalSize); return Math.round(offsetPercentage * (safeTotalSize - containerSize)); } }, _safeOffsetToOffset: function (containerSize, offset) { var totalSize = this._cellSizeAndPositionManager.getTotalSize(); var safeTotalSize = this.getTotalSize(); if (totalSize === safeTotalSize) { return offset; } else { var offsetPercentage = this._getOffsetPercentage(containerSize, offset, safeTotalSize); return Math.round(offsetPercentage * (totalSize - containerSize)); } } };/** * 汉字拼音索引 */ ; !(function () { var _ChineseFirstPY = "YDYQSXMWZSSXJBYMGCCZQPSSQBYCDSCDQLDYLYBSSJGYZZJJFKCCLZDHWDWZJLJPFYYNWJJTMYHZWZHFLZPPQHGSCYYYNJQYXXGJHHSDSJNKKTMOMLCRXYPSNQSECCQZGGLLYJLMYZZSECYKYYHQWJSSGGYXYZYJWWKDJHYCHMYXJTLXJYQBYXZLDWRDJRWYSRLDZJPCBZJJBR" + "CFTLECZSTZFXXZHTRQHYBDLYCZSSYMMRFMYQZPWWJJYFCRWFDFZQPYDDWYXKYJAWJFFXYPSFTZYHHYZYSWCJYXSCLCXXWZZXNBGNNXBXLZSZSBSGPYSYZDHMDZBQBZCWDZZYYTZHBTSYYBZGNTNXQYWQSKBPHHLXGYBFMJEBJHHGQTJCYSXSTKZHLYCKGLYSMZXYALMELDCCXGZ" + "YRJXSDLTYZCQKCNNJWHJTZZCQLJSTSTBNXBTYXCEQXGKWJYFLZQLYHYXSPSFXLMPBYSXXXYDJCZYLLLSJXFHJXPJBTFFYABYXBHZZBJYZLWLCZGGBTSSMDTJZXPTHYQTGLJSCQFZKJZJQNLZWLSLHDZBWJNCJZYZSQQYCQYRZCJJWYBRTWPYFTWEXCSKDZCTBZHYZZYYJXZCFFZ" + "ZMJYXXSDZZOTTBZLQWFCKSZSXFYRLNYJMBDTHJXSQQCCSBXYYTSYFBXDZTGBCNSLCYZZPSAZYZZSCJCSHZQYDXLBPJLLMQXTYDZXSQJTZPXLCGLQTZWJBHCTSYJSFXYEJJTLBGXSXJMYJQQPFZASYJNTYDJXKJCDJSZCBARTDCLYJQMWNQNCLLLKBYBZZSYHQQLTWLCCXTXLLZN" + "TYLNEWYZYXCZXXGRKRMTCNDNJTSYYSSDQDGHSDBJGHRWRQLYBGLXHLGTGXBQJDZPYJSJYJCTMRNYMGRZJCZGJMZMGXMPRYXKJNYMSGMZJYMKMFXMLDTGFBHCJHKYLPFMDXLQJJSMTQGZSJLQDLDGJYCALCMZCSDJLLNXDJFFFFJCZFMZFFPFKHKGDPSXKTACJDHHZDDCRRCFQYJ" + "KQCCWJDXHWJLYLLZGCFCQDSMLZPBJJPLSBCJGGDCKKDEZSQCCKJGCGKDJTJDLZYCXKLQSCGJCLTFPCQCZGWPJDQYZJJBYJHSJDZWGFSJGZKQCCZLLPSPKJGQJHZZLJPLGJGJJTHJJYJZCZMLZLYQBGJWMLJKXZDZNJQSYZMLJLLJKYWXMKJLHSKJGBMCLYYMKXJQLBMLLKMDXXK" + "WYXYSLMLPSJQQJQXYXFJTJDXMXXLLCXQBSYJBGWYMBGGBCYXPJYGPEPFGDJGBHBNSQJYZJKJKHXQFGQZKFHYGKHDKLLSDJQXPQYKYBNQSXQNSZSWHBSXWHXWBZZXDMNSJBSBKBBZKLYLXGWXDRWYQZMYWSJQLCJXXJXKJEQXSCYETLZHLYYYSDZPAQYZCMTLSHTZCFYZYXYLJSD" + "CJQAGYSLCQLYYYSHMRQQKLDXZSCSSSYDYCJYSFSJBFRSSZQSBXXPXJYSDRCKGJLGDKZJZBDKTCSYQPYHSTCLDJDHMXMCGXYZHJDDTMHLTXZXYLYMOHYJCLTYFBQQXPFBDFHHTKSQHZYYWCNXXCRWHOWGYJLEGWDQCWGFJYCSNTMYTOLBYGWQWESJPWNMLRYDZSZTXYQPZGCWXHN" + "GPYXSHMYQJXZTDPPBFYHZHTJYFDZWKGKZBLDNTSXHQEEGZZYLZMMZYJZGXZXKHKSTXNXXWYLYAPSTHXDWHZYMPXAGKYDXBHNHXKDPJNMYHYLPMGOCSLNZHKXXLPZZLBMLSFBHHGYGYYGGBHSCYAQTYWLXTZQCEZYDQDQMMHTKLLSZHLSJZWFYHQSWSCWLQAZYNYTLSXTHAZNKZZ" + "SZZLAXXZWWCTGQQTDDYZTCCHYQZFLXPSLZYGPZSZNGLNDQTBDLXGTCTAJDKYWNSYZLJHHZZCWNYYZYWMHYCHHYXHJKZWSXHZYXLYSKQYSPSLYZWMYPPKBYGLKZHTYXAXQSYSHXASMCHKDSCRSWJPWXSGZJLWWSCHSJHSQNHCSEGNDAQTBAALZZMSSTDQJCJKTSCJAXPLGGXHHGX" + "XZCXPDMMHLDGTYBYSJMXHMRCPXXJZCKZXSHMLQXXTTHXWZFKHCCZDYTCJYXQHLXDHYPJQXYLSYYDZOZJNYXQEZYSQYAYXWYPDGXDDXSPPYZNDLTWRHXYDXZZJHTCXMCZLHPYYYYMHZLLHNXMYLLLMDCPPXHMXDKYCYRDLTXJCHHZZXZLCCLYLNZSHZJZZLNNRLWHYQSNJHXYNTT" + "TKYJPYCHHYEGKCTTWLGQRLGGTGTYGYHPYHYLQYQGCWYQKPYYYTTTTLHYHLLTYTTSPLKYZXGZWGPYDSSZZDQXSKCQNMJJZZBXYQMJRTFFBTKHZKBXLJJKDXJTLBWFZPPTKQTZTGPDGNTPJYFALQMKGXBDCLZFHZCLLLLADPMXDJHLCCLGYHDZFGYDDGCYYFGYDXKSSEBDHYKDKDK" + "HNAXXYBPBYYHXZQGAFFQYJXDMLJCSQZLLPCHBSXGJYNDYBYQSPZWJLZKSDDTACTBXZDYZYPJZQSJNKKTKNJDJGYYPGTLFYQKASDNTCYHBLWDZHBBYDWJRYGKZYHEYYFJMSDTYFZJJHGCXPLXHLDWXXJKYTCYKSSSMTWCTTQZLPBSZDZWZXGZAGYKTYWXLHLSPBCLLOQMMZSSLCM" + "BJCSZZKYDCZJGQQDSMCYTZQQLWZQZXSSFPTTFQMDDZDSHDTDWFHTDYZJYQJQKYPBDJYYXTLJHDRQXXXHAYDHRJLKLYTWHLLRLLRCXYLBWSRSZZSYMKZZHHKYHXKSMDSYDYCJPBZBSQLFCXXXNXKXWYWSDZYQOGGQMMYHCDZTTFJYYBGSTTTYBYKJDHKYXBELHTYPJQNFXFDYKZH" + "QKZBYJTZBXHFDXKDASWTAWAJLDYJSFHBLDNNTNQJTJNCHXFJSRFWHZFMDRYJYJWZPDJKZYJYMPCYZNYNXFBYTFYFWYGDBNZZZDNYTXZEMMQBSQEHXFZMBMFLZZSRXYMJGSXWZJSPRYDJSJGXHJJGLJJYNZZJXHGXKYMLPYYYCXYTWQZSWHWLYRJLPXSLSXMFSWWKLCTNXNYNPSJ" + "SZHDZEPTXMYYWXYYSYWLXJQZQXZDCLEEELMCPJPCLWBXSQHFWWTFFJTNQJHJQDXHWLBYZNFJLALKYYJLDXHHYCSTYYWNRJYXYWTRMDRQHWQCMFJDYZMHMYYXJWMYZQZXTLMRSPWWCHAQBXYGZYPXYYRRCLMPYMGKSJSZYSRMYJSNXTPLNBAPPYPYLXYYZKYNLDZYJZCZNNLMZHH" + "ARQMPGWQTZMXXMLLHGDZXYHXKYXYCJMFFYYHJFSBSSQLXXNDYCANNMTCJCYPRRNYTYQNYYMBMSXNDLYLYSLJRLXYSXQMLLYZLZJJJKYZZCSFBZXXMSTBJGNXYZHLXNMCWSCYZYFZLXBRNNNYLBNRTGZQYSATSWRYHYJZMZDHZGZDWYBSSCSKXSYHYTXXGCQGXZZSHYXJSCRHMKK" + "BXCZJYJYMKQHZJFNBHMQHYSNJNZYBKNQMCLGQHWLZNZSWXKHLJHYYBQLBFCDSXDLDSPFZPSKJYZWZXZDDXJSMMEGJSCSSMGCLXXKYYYLNYPWWWGYDKZJGGGZGGSYCKNJWNJPCXBJJTQTJWDSSPJXZXNZXUMELPXFSXTLLXCLJXJJLJZXCTPSWXLYDHLYQRWHSYCSQYYBYAYWJJJ" + "QFWQCQQCJQGXALDBZZYJGKGXPLTZYFXJLTPADKYQHPMATLCPDCKBMTXYBHKLENXDLEEGQDYMSAWHZMLJTWYGXLYQZLJEEYYBQQFFNLYXRDSCTGJGXYYNKLLYQKCCTLHJLQMKKZGCYYGLLLJDZGYDHZWXPYSJBZKDZGYZZHYWYFQYTYZSZYEZZLYMHJJHTSMQWYZLKYYWZCSRKQY" + "TLTDXWCTYJKLWSQZWBDCQYNCJSRSZJLKCDCDTLZZZACQQZZDDXYPLXZBQJYLZLLLQDDZQJYJYJZYXNYYYNYJXKXDAZWYRDLJYYYRJLXLLDYXJCYWYWNQCCLDDNYYYNYCKCZHXXCCLGZQJGKWPPCQQJYSBZZXYJSQPXJPZBSBDSFNSFPZXHDWZTDWPPTFLZZBZDMYYPQJRSDZSQZ" + "SQXBDGCPZSWDWCSQZGMDHZXMWWFYBPDGPHTMJTHZSMMBGZMBZJCFZWFZBBZMQCFMBDMCJXLGPNJBBXGYHYYJGPTZGZMQBQTCGYXJXLWZKYDPDYMGCFTPFXYZTZXDZXTGKMTYBBCLBJASKYTSSQYYMSZXFJEWLXLLSZBQJJJAKLYLXLYCCTSXMCWFKKKBSXLLLLJYXTYLTJYYTDP" + "JHNHNNKBYQNFQYYZBYYESSESSGDYHFHWTCJBSDZZTFDMXHCNJZYMQWSRYJDZJQPDQBBSTJGGFBKJBXTGQHNGWJXJGDLLTHZHHYYYYYYSXWTYYYCCBDBPYPZYCCZYJPZYWCBDLFWZCWJDXXHYHLHWZZXJTCZLCDPXUJCZZZLYXJJTXPHFXWPYWXZPTDZZBDZCYHJHMLXBQXSBYLR" + "DTGJRRCTTTHYTCZWMXFYTWWZCWJWXJYWCSKYBZSCCTZQNHXNWXXKHKFHTSWOCCJYBCMPZZYKBNNZPBZHHZDLSYDDYTYFJPXYNGFXBYQXCBHXCPSXTYZDMKYSNXSXLHKMZXLYHDHKWHXXSSKQYHHCJYXGLHZXCSNHEKDTGZXQYPKDHEXTYKCNYMYYYPKQYYYKXZLTHJQTBYQHXBM" + "YHSQCKWWYLLHCYYLNNEQXQWMCFBDCCMLJGGXDQKTLXKGNQCDGZJWYJJLYHHQTTTNWCHMXCXWHWSZJYDJCCDBQCDGDNYXZTHCQRXCBHZTQCBXWGQWYYBXHMBYMYQTYEXMQKYAQYRGYZSLFYKKQHYSSQYSHJGJCNXKZYCXSBXYXHYYLSTYCXQTHYSMGSCPMMGCCCCCMTZTASMGQZJ" + "HKLOSQYLSWTMXSYQKDZLJQQYPLSYCZTCQQPBBQJZCLPKHQZYYXXDTDDTSJCXFFLLCHQXMJLWCJCXTSPYCXNDTJSHJWXDQQJSKXYAMYLSJHMLALYKXCYYDMNMDQMXMCZNNCYBZKKYFLMCHCMLHXRCJJHSYLNMTJZGZGYWJXSRXCWJGJQHQZDQJDCJJZKJKGDZQGJJYJYLXZXXCDQ" + "HHHEYTMHLFSBDJSYYSHFYSTCZQLPBDRFRZTZYKYWHSZYQKWDQZRKMSYNBCRXQBJYFAZPZZEDZCJYWBCJWHYJBQSZYWRYSZPTDKZPFPBNZTKLQYHBBZPNPPTYZZYBQNYDCPJMMCYCQMCYFZZDCMNLFPBPLNGQJTBTTNJZPZBBZNJKLJQYLNBZQHKSJZNGGQSZZKYXSHPZSNBCGZK" + "DDZQANZHJKDRTLZLSWJLJZLYWTJNDJZJHXYAYNCBGTZCSSQMNJPJYTYSWXZFKWJQTKHTZPLBHSNJZSYZBWZZZZLSYLSBJHDWWQPSLMMFBJDWAQYZTCJTBNNWZXQXCDSLQGDSDPDZHJTQQPSWLYYJZLGYXYZLCTCBJTKTYCZJTQKBSJLGMGZDMCSGPYNJZYQYYKNXRPWSZXMTNCS" + "ZZYXYBYHYZAXYWQCJTLLCKJJTJHGDXDXYQYZZBYWDLWQCGLZGJGQRQZCZSSBCRPCSKYDZNXJSQGXSSJMYDNSTZTPBDLTKZWXQWQTZEXNQCZGWEZKSSBYBRTSSSLCCGBPSZQSZLCCGLLLZXHZQTHCZMQGYZQZNMCOCSZJMMZSQPJYGQLJYJPPLDXRGZYXCCSXHSHGTZNLZWZKJCX" + "TCFCJXLBMQBCZZWPQDNHXLJCTHYZLGYLNLSZZPCXDSCQQHJQKSXZPBAJYEMSMJTZDXLCJYRYYNWJBNGZZTMJXLTBSLYRZPYLSSCNXPHLLHYLLQQZQLXYMRSYCXZLMMCZLTZSDWTJJLLNZGGQXPFSKYGYGHBFZPDKMWGHCXMSGDXJMCJZDYCABXJDLNBCDQYGSKYDQTXDJJYXMSZ" + "QAZDZFSLQXYJSJZYLBTXXWXQQZBJZUFBBLYLWDSLJHXJYZJWTDJCZFQZQZZDZSXZZQLZCDZFJHYSPYMPQZMLPPLFFXJJNZZYLSJEYQZFPFZKSYWJJJHRDJZZXTXXGLGHYDXCSKYSWMMZCWYBAZBJKSHFHJCXMHFQHYXXYZFTSJYZFXYXPZLCHMZMBXHZZSXYFYMNCWDABAZLXKT" + "CSHHXKXJJZJSTHYGXSXYYHHHJWXKZXSSBZZWHHHCWTZZZPJXSNXQQJGZYZYWLLCWXZFXXYXYHXMKYYSWSQMNLNAYCYSPMJKHWCQHYLAJJMZXHMMCNZHBHXCLXTJPLTXYJHDYYLTTXFSZHYXXSJBJYAYRSMXYPLCKDUYHLXRLNLLSTYZYYQYGYHHSCCSMZCTZQXKYQFPYYRPFFLK" + "QUNTSZLLZMWWTCQQYZWTLLMLMPWMBZSSTZRBPDDTLQJJBXZCSRZQQYGWCSXFWZLXCCRSZDZMCYGGDZQSGTJSWLJMYMMZYHFBJDGYXCCPSHXNZCSBSJYJGJMPPWAFFYFNXHYZXZYLREMZGZCYZSSZDLLJCSQFNXZKPTXZGXJJGFMYYYSNBTYLBNLHPFZDCYFBMGQRRSSSZXYSGTZ" + "RNYDZZCDGPJAFJFZKNZBLCZSZPSGCYCJSZLMLRSZBZZLDLSLLYSXSQZQLYXZLSKKBRXBRBZCYCXZZZEEYFGKLZLYYHGZSGZLFJHGTGWKRAAJYZKZQTSSHJJXDCYZUYJLZYRZDQQHGJZXSSZBYKJPBFRTJXLLFQWJHYLQTYMBLPZDXTZYGBDHZZRBGXHWNJTJXLKSCFSMWLSDQYS" + "JTXKZSCFWJLBXFTZLLJZLLQBLSQMQQCGCZFPBPHZCZJLPYYGGDTGWDCFCZQYYYQYSSCLXZSKLZZZGFFCQNWGLHQYZJJCZLQZZYJPJZZBPDCCMHJGXDQDGDLZQMFGPSYTSDYFWWDJZJYSXYYCZCYHZWPBYKXRYLYBHKJKSFXTZJMMCKHLLTNYYMSYXYZPYJQYCSYCWMTJJKQYRHL" + "LQXPSGTLYYCLJSCPXJYZFNMLRGJJTYZBXYZMSJYJHHFZQMSYXRSZCWTLRTQZSSTKXGQKGSPTGCZNJSJCQCXHMXGGZTQYDJKZDLBZSXJLHYQGGGTHQSZPYHJHHGYYGKGGCWJZZYLCZLXQSFTGZSLLLMLJSKCTBLLZZSZMMNYTPZSXQHJCJYQXYZXZQZCPSHKZZYSXCDFGMWQRLLQ" + "XRFZTLYSTCTMJCXJJXHJNXTNRZTZFQYHQGLLGCXSZSJDJLJCYDSJTLNYXHSZXCGJZYQPYLFHDJSBPCCZHJJJQZJQDYBSSLLCMYTTMQTBHJQNNYGKYRQYQMZGCJKPDCGMYZHQLLSLLCLMHOLZGDYYFZSLJCQZLYLZQJESHNYLLJXGJXLYSYYYXNBZLJSSZCQQCJYLLZLTJYLLZLL" + "BNYLGQCHXYYXOXCXQKYJXXXYKLXSXXYQXCYKQXQCSGYXXYQXYGYTQOHXHXPYXXXULCYEYCHZZCBWQBBWJQZSCSZSSLZYLKDESJZWMYMCYTSDSXXSCJPQQSQYLYYZYCMDJDZYWCBTJSYDJKCYDDJLBDJJSODZYSYXQQYXDHHGQQYQHDYXWGMMMAJDYBBBPPBCMUUPLJZSMTXERXJ" + "MHQNUTPJDCBSSMSSSTKJTSSMMTRCPLZSZMLQDSDMJMQPNQDXCFYNBFSDQXYXHYAYKQYDDLQYYYSSZBYDSLNTFQTZQPZMCHDHCZCWFDXTMYQSPHQYYXSRGJCWTJTZZQMGWJJTJHTQJBBHWZPXXHYQFXXQYWYYHYSCDYDHHQMNMTMWCPBSZPPZZGLMZFOLLCFWHMMSJZTTDHZZYFF" + "YTZZGZYSKYJXQYJZQBHMBZZLYGHGFMSHPZFZSNCLPBQSNJXZSLXXFPMTYJYGBXLLDLXPZJYZJYHHZCYWHJYLSJEXFSZZYWXKZJLUYDTMLYMQJPWXYHXSKTQJEZRPXXZHHMHWQPWQLYJJQJJZSZCPHJLCHHNXJLQWZJHBMZYXBDHHYPZLHLHLGFWLCHYYTLHJXCJMSCPXSTKPNHQ" + "XSRTYXXTESYJCTLSSLSTDLLLWWYHDHRJZSFGXTSYCZYNYHTDHWJSLHTZDQDJZXXQHGYLTZPHCSQFCLNJTCLZPFSTPDYNYLGMJLLYCQHYSSHCHYLHQYQTMZYPBYWRFQYKQSYSLZDQJMPXYYSSRHZJNYWTQDFZBWWTWWRXCWHGYHXMKMYYYQMSMZHNGCEPMLQQMTCWCTMMPXJPJJH" + "FXYYZSXZHTYBMSTSYJTTQQQYYLHYNPYQZLCYZHZWSMYLKFJXLWGXYPJYTYSYXYMZCKTTWLKSMZSYLMPWLZWXWQZSSAQSYXYRHSSNTSRAPXCPWCMGDXHXZDZYFJHGZTTSBJHGYZSZYSMYCLLLXBTYXHBBZJKSSDMALXHYCFYGMQYPJYCQXJLLLJGSLZGQLYCJCCZOTYXMTMTTLLW" + "TGPXYMZMKLPSZZZXHKQYSXCTYJZYHXSHYXZKXLZWPSQPYHJWPJPWXQQYLXSDHMRSLZZYZWTTCYXYSZZSHBSCCSTPLWSSCJCHNLCGCHSSPHYLHFHHXJSXYLLNYLSZDHZXYLSXLWZYKCLDYAXZCMDDYSPJTQJZLNWQPSSSWCTSTSZLBLNXSMNYYMJQBQHRZWTYYDCHQLXKPZWBGQY" + "BKFCMZWPZLLYYLSZYDWHXPSBCMLJBSCGBHXLQHYRLJXYSWXWXZSLDFHLSLYNJLZYFLYJYCDRJLFSYZFSLLCQYQFGJYHYXZLYLMSTDJCYHBZLLNWLXXYGYYHSMGDHXXHHLZZJZXCZZZCYQZFNGWPYLCPKPYYPMCLQKDGXZGGWQBDXZZKZFBXXLZXJTPJPTTBYTSZZDWSLCHZHSLT" + "YXHQLHYXXXYYZYSWTXZKHLXZXZPYHGCHKCFSYHUTJRLXFJXPTZTWHPLYXFCRHXSHXKYXXYHZQDXQWULHYHMJTBFLKHTXCWHJFWJCFPQRYQXCYYYQYGRPYWSGSUNGWCHKZDXYFLXXHJJBYZWTSXXNCYJJYMSWZJQRMHXZWFQSYLZJZGBHYNSLBGTTCSYBYXXWXYHXYYXNSQYXMQY" + "WRGYQLXBBZLJSYLPSYTJZYHYZAWLRORJMKSCZJXXXYXCHDYXRYXXJDTSQFXLYLTSFFYXLMTYJMJUYYYXLTZCSXQZQHZXLYYXZHDNBRXXXJCTYHLBRLMBRLLAXKYLLLJLYXXLYCRYLCJTGJCMTLZLLCYZZPZPCYAWHJJFYBDYYZSMPCKZDQYQPBPCJPDCYZMDPBCYYDYCNNPLMTM" + "LRMFMMGWYZBSJGYGSMZQQQZTXMKQWGXLLPJGZBQCDJJJFPKJKCXBLJMSWMDTQJXLDLPPBXCWRCQFBFQJCZAHZGMYKPHYYHZYKNDKZMBPJYXPXYHLFPNYYGXJDBKXNXHJMZJXSTRSTLDXSKZYSYBZXJLXYSLBZYSLHXJPFXPQNBYLLJQKYGZMCYZZYMCCSLCLHZFWFWYXZMWSXTY" + "NXJHPYYMCYSPMHYSMYDYSHQYZCHMJJMZCAAGCFJBBHPLYZYLXXSDJGXDHKXXTXXNBHRMLYJSLTXMRHNLXQJXYZLLYSWQGDLBJHDCGJYQYCMHWFMJYBMBYJYJWYMDPWHXQLDYGPDFXXBCGJSPCKRSSYZJMSLBZZJFLJJJLGXZGYXYXLSZQYXBEXYXHGCXBPLDYHWETTWWCJMBTXC" + "HXYQXLLXFLYXLLJLSSFWDPZSMYJCLMWYTCZPCHQEKCQBWLCQYDPLQPPQZQFJQDJHYMMCXTXDRMJWRHXCJZYLQXDYYNHYYHRSLSRSYWWZJYMTLTLLGTQCJZYABTCKZCJYCCQLJZQXALMZYHYWLWDXZXQDLLQSHGPJFJLJHJABCQZDJGTKHSSTCYJLPSWZLXZXRWGLDLZRLZXTGSL" + "LLLZLYXXWGDZYGBDPHZPBRLWSXQBPFDWOFMWHLYPCBJCCLDMBZPBZZLCYQXLDOMZBLZWPDWYYGDSTTHCSQSCCRSSSYSLFYBFNTYJSZDFNDPDHDZZMBBLSLCMYFFGTJJQWFTMTPJWFNLBZCMMJTGBDZLQLPYFHYYMJYLSDCHDZJWJCCTLJCLDTLJJCPDDSQDSSZYBNDBJLGGJZXS" + "XNLYCYBJXQYCBYLZCFZPPGKCXZDZFZTJJFJSJXZBNZYJQTTYJYHTYCZHYMDJXTTMPXSPLZCDWSLSHXYPZGTFMLCJTYCBPMGDKWYCYZCDSZZYHFLYCTYGWHKJYYLSJCXGYWJCBLLCSNDDBTZBSCLYZCZZSSQDLLMQYYHFSLQLLXFTYHABXGWNYWYYPLLSDLDLLBJCYXJZMLHLJDX" + "YYQYTDLLLBUGBFDFBBQJZZMDPJHGCLGMJJPGAEHHBWCQXAXHHHZCHXYPHJAXHLPHJPGPZJQCQZGJJZZUZDMQYYBZZPHYHYBWHAZYJHYKFGDPFQSDLZMLJXKXGALXZDAGLMDGXMWZQYXXDXXPFDMMSSYMPFMDMMKXKSYZYSHDZKXSYSMMZZZMSYDNZZCZXFPLSTMZDNMXCKJMZTY" + "YMZMZZMSXHHDCZJEMXXKLJSTLWLSQLYJZLLZJSSDPPMHNLZJCZYHMXXHGZCJMDHXTKGRMXFWMCGMWKDTKSXQMMMFZZYDKMSCLCMPCGMHSPXQPZDSSLCXKYXTWLWJYAHZJGZQMCSNXYYMMPMLKJXMHLMLQMXCTKZMJQYSZJSYSZHSYJZJCDAJZYBSDQJZGWZQQXFKDMSDJLFWEHK" + "ZQKJPEYPZYSZCDWYJFFMZZYLTTDZZEFMZLBNPPLPLPEPSZALLTYLKCKQZKGENQLWAGYXYDPXLHSXQQWQCQXQCLHYXXMLYCCWLYMQYSKGCHLCJNSZKPYZKCQZQLJPDMDZHLASXLBYDWQLWDNBQCRYDDZTJYBKBWSZDXDTNPJDTCTQDFXQQMGNXECLTTBKPWSLCTYQLPWYZZKLPYG" + "ZCQQPLLKCCYLPQMZCZQCLJSLQZDJXLDDHPZQDLJJXZQDXYZQKZLJCYQDYJPPYPQYKJYRMPCBYMCXKLLZLLFQPYLLLMBSGLCYSSLRSYSQTMXYXZQZFDZUYSYZTFFMZZSMZQHZSSCCMLYXWTPZGXZJGZGSJSGKDDHTQGGZLLBJDZLCBCHYXYZHZFYWXYZYMSDBZZYJGTSMTFXQYXQ" + "STDGSLNXDLRYZZLRYYLXQHTXSRTZNGZXBNQQZFMYKMZJBZYMKBPNLYZPBLMCNQYZZZSJZHJCTZKHYZZJRDYZHNPXGLFZTLKGJTCTSSYLLGZRZBBQZZKLPKLCZYSSUYXBJFPNJZZXCDWXZYJXZZDJJKGGRSRJKMSMZJLSJYWQSKYHQJSXPJZZZLSNSHRNYPZTWCHKLPSRZLZXYJQ" + "XQKYSJYCZTLQZYBBYBWZPQDWWYZCYTJCJXCKCWDKKZXSGKDZXWWYYJQYYTCYTDLLXWKCZKKLCCLZCQQDZLQLCSFQCHQHSFSMQZZLNBJJZBSJHTSZDYSJQJPDLZCDCWJKJZZLPYCGMZWDJJBSJQZSYZYHHXJPBJYDSSXDZNCGLQMBTSFSBPDZDLZNFGFJGFSMPXJQLMBLGQCYYXB" + "QKDJJQYRFKZTJDHCZKLBSDZCFJTPLLJGXHYXZCSSZZXSTJYGKGCKGYOQXJPLZPBPGTGYJZGHZQZZLBJLSQFZGKQQJZGYCZBZQTLDXRJXBSXXPZXHYZYCLWDXJJHXMFDZPFZHQHQMQGKSLYHTYCGFRZGNQXCLPDLBZCSCZQLLJBLHBZCYPZZPPDYMZZSGYHCKCPZJGSLJLNSCDSL" + "DLXBMSTLDDFJMKDJDHZLZXLSZQPQPGJLLYBDSZGQLBZLSLKYYHZTTNTJYQTZZPSZQZTLLJTYYLLQLLQYZQLBDZLSLYYZYMDFSZSNHLXZNCZQZPBWSKRFBSYZMTHBLGJPMCZZLSTLXSHTCSYZLZBLFEQHLXFLCJLYLJQCBZLZJHHSSTBRMHXZHJZCLXFNBGXGTQJCZTMSFZKJMSS" + "NXLJKBHSJXNTNLZDNTLMSJXGZJYJCZXYJYJWRWWQNZTNFJSZPZSHZJFYRDJSFSZJZBJFZQZZHZLXFYSBZQLZSGYFTZDCSZXZJBQMSZKJRHYJZCKMJKHCHGTXKXQGLXPXFXTRTYLXJXHDTSJXHJZJXZWZLCQSBTXWXGXTXXHXFTSDKFJHZYJFJXRZSDLLLTQSQQZQWZXSYQTWGWB" + "ZCGZLLYZBCLMQQTZHZXZXLJFRMYZFLXYSQXXJKXRMQDZDMMYYBSQBHGZMWFWXGMXLZPYYTGZYCCDXYZXYWGSYJYZNBHPZJSQSYXSXRTFYZGRHZTXSZZTHCBFCLSYXZLZQMZLMPLMXZJXSFLBYZMYQHXJSXRXSQZZZSSLYFRCZJRCRXHHZXQYDYHXSJJHZCXZBTYNSYSXJBQLPXZ" + "QPYMLXZKYXLXCJLCYSXXZZLXDLLLJJYHZXGYJWKJRWYHCPSGNRZLFZWFZZNSXGXFLZSXZZZBFCSYJDBRJKRDHHGXJLJJTGXJXXSTJTJXLYXQFCSGSWMSBCTLQZZWLZZKXJMLTMJYHSDDBXGZHDLBMYJFRZFSGCLYJBPMLYSMSXLSZJQQHJZFXGFQFQBPXZGYYQXGZTCQWYLTLGW" + "SGWHRLFSFGZJMGMGBGTJFSYZZGZYZAFLSSPMLPFLCWBJZCLJJMZLPJJLYMQDMYYYFBGYGYZMLYZDXQYXRQQQHSYYYQXYLJTYXFSFSLLGNQCYHYCWFHCCCFXPYLYPLLZYXXXXXKQHHXSHJZCFZSCZJXCPZWHHHHHAPYLQALPQAFYHXDYLUKMZQGGGDDESRNNZLTZGCHYPPYSQJJH" + "CLLJTOLNJPZLJLHYMHEYDYDSQYCDDHGZUNDZCLZYZLLZNTNYZGSLHSLPJJBDGWXPCDUTJCKLKCLWKLLCASSTKZZDNQNTTLYYZSSYSSZZRYLJQKCQDHHCRXRZYDGRGCWCGZQFFFPPJFZYNAKRGYWYQPQXXFKJTSZZXSWZDDFBBXTBGTZKZNPZZPZXZPJSZBMQHKCYXYLDKLJNYPK" + "YGHGDZJXXEAHPNZKZTZCMXCXMMJXNKSZQNMNLWBWWXJKYHCPSTMCSQTZJYXTPCTPDTNNPGLLLZSJLSPBLPLQHDTNJNLYYRSZFFJFQWDPHZDWMRZCCLODAXNSSNYZRESTYJWJYJDBCFXNMWTTBYLWSTSZGYBLJPXGLBOCLHPCBJLTMXZLJYLZXCLTPNCLCKXTPZJSWCYXSFYSZDK" + "NTLBYJCYJLLSTGQCBXRYZXBXKLYLHZLQZLNZCXWJZLJZJNCJHXMNZZGJZZXTZJXYCYYCXXJYYXJJXSSSJSTSSTTPPGQTCSXWZDCSYFPTFBFHFBBLZJCLZZDBXGCXLQPXKFZFLSYLTUWBMQJHSZBMDDBCYSCCLDXYCDDQLYJJWMQLLCSGLJJSYFPYYCCYLTJANTJJPWYCMMGQYYS" + "XDXQMZHSZXPFTWWZQSWQRFKJLZJQQYFBRXJHHFWJJZYQAZMYFRHCYYBYQWLPEXCCZSTYRLTTDMQLYKMBBGMYYJPRKZNPBSXYXBHYZDJDNGHPMFSGMWFZMFQMMBCMZZCJJLCNUXYQLMLRYGQZCYXZLWJGCJCGGMCJNFYZZJHYCPRRCMTZQZXHFQGTJXCCJEAQCRJYHPLQLSZDJRB" + "CQHQDYRHYLYXJSYMHZYDWLDFRYHBPYDTSSCNWBXGLPZMLZZTQSSCPJMXXYCSJYTYCGHYCJWYRXXLFEMWJNMKLLSWTXHYYYNCMMCWJDQDJZGLLJWJRKHPZGGFLCCSCZMCBLTBHBQJXQDSPDJZZGKGLFQYWBZYZJLTSTDHQHCTCBCHFLQMPWDSHYYTQWCNZZJTLBYMBPDYYYXSQKX" + "WYYFLXXNCWCXYPMAELYKKJMZZZBRXYYQJFLJPFHHHYTZZXSGQQMHSPGDZQWBWPJHZJDYSCQWZKTXXSQLZYYMYSDZGRXCKKUJLWPYSYSCSYZLRMLQSYLJXBCXTLWDQZPCYCYKPPPNSXFYZJJRCEMHSZMSXLXGLRWGCSTLRSXBZGBZGZTCPLUJLSLYLYMTXMTZPALZXPXJTJWTCYY" + "ZLBLXBZLQMYLXPGHDSLSSDMXMBDZZSXWHAMLCZCPJMCNHJYSNSYGCHSKQMZZQDLLKABLWJXSFMOCDXJRRLYQZKJMYBYQLYHETFJZFRFKSRYXFJTWDSXXSYSQJYSLYXWJHSNLXYYXHBHAWHHJZXWMYLJCSSLKYDZTXBZSYFDXGXZJKHSXXYBSSXDPYNZWRPTQZCZENYGCXQFJYKJ" + "BZMLJCMQQXUOXSLYXXLYLLJDZBTYMHPFSTTQQWLHOKYBLZZALZXQLHZWRRQHLSTMYPYXJJXMQSJFNBXYXYJXXYQYLTHYLQYFMLKLJTMLLHSZWKZHLJMLHLJKLJSTLQXYLMBHHLNLZXQJHXCFXXLHYHJJGBYZZKBXSCQDJQDSUJZYYHZHHMGSXCSYMXFEBCQWWRBPYYJQTYZCYQY" + "QQZYHMWFFHGZFRJFCDPXNTQYZPDYKHJLFRZXPPXZDBBGZQSTLGDGYLCQMLCHHMFYWLZYXKJLYPQHSYWMQQGQZMLZJNSQXJQSYJYCBEHSXFSZPXZWFLLBCYYJDYTDTHWZSFJMQQYJLMQXXLLDTTKHHYBFPWTYYSQQWNQWLGWDEBZWCMYGCULKJXTMXMYJSXHYBRWFYMWFRXYQMXY" + "SZTZZTFYKMLDHQDXWYYNLCRYJBLPSXCXYWLSPRRJWXHQYPHTYDNXHHMMYWYTZCSQMTSSCCDALWZTCPQPYJLLQZYJSWXMZZMMYLMXCLMXCZMXMZSQTZPPQQBLPGXQZHFLJJHYTJSRXWZXSCCDLXTYJDCQJXSLQYCLZXLZZXMXQRJMHRHZJBHMFLJLMLCLQNLDXZLLLPYPSYJYSXC" + "QQDCMQJZZXHNPNXZMEKMXHYKYQLXSXTXJYYHWDCWDZHQYYBGYBCYSCFGPSJNZDYZZJZXRZRQJJYMCANYRJTLDPPYZBSTJKXXZYPFDWFGZZRPYMTNGXZQBYXNBUFNQKRJQZMJEGRZGYCLKXZDSKKNSXKCLJSPJYYZLQQJYBZSSQLLLKJXTBKTYLCCDDBLSPPFYLGYDTZJYQGGKQT" + "TFZXBDKTYYHYBBFYTYYBCLPDYTGDHRYRNJSPTCSNYJQHKLLLZSLYDXXWBCJQSPXBPJZJCJDZFFXXBRMLAZHCSNDLBJDSZBLPRZTSWSBXBCLLXXLZDJZSJPYLYXXYFTFFFBHJJXGBYXJPMMMPSSJZJMTLYZJXSWXTYLEDQPJMYGQZJGDJLQJWJQLLSJGJGYGMSCLJJXDTYGJQJQJ" + "CJZCJGDZZSXQGSJGGCXHQXSNQLZZBXHSGZXCXYLJXYXYYDFQQJHJFXDHCTXJYRXYSQTJXYEFYYSSYYJXNCYZXFXMSYSZXYYSCHSHXZZZGZZZGFJDLTYLNPZGYJYZYYQZPBXQBDZTZCZYXXYHHSQXSHDHGQHJHGYWSZTMZMLHYXGEBTYLZKQWYTJZRCLEKYSTDBCYKQQSAYXCJXW" + "WGSBHJYZYDHCSJKQCXSWXFLTYNYZPZCCZJQTZWJQDZZZQZLJJXLSBHPYXXPSXSHHEZTXFPTLQYZZXHYTXNCFZYYHXGNXMYWXTZSJPTHHGYMXMXQZXTSBCZYJYXXTYYZYPCQLMMSZMJZZLLZXGXZAAJZYXJMZXWDXZSXZDZXLEYJJZQBHZWZZZQTZPSXZTDSXJJJZNYAZPHXYYSR" + "NQDTHZHYYKYJHDZXZLSWCLYBZYECWCYCRYLCXNHZYDZYDYJDFRJJHTRSQTXYXJRJHOJYNXELXSFSFJZGHPZSXZSZDZCQZBYYKLSGSJHCZSHDGQGXYZGXCHXZJWYQWGYHKSSEQZZNDZFKWYSSTCLZSTSYMCDHJXXYWEYXCZAYDMPXMDSXYBSQMJMZJMTZQLPJYQZCGQHXJHHLXXH" + "LHDLDJQCLDWBSXFZZYYSCHTYTYYBHECXHYKGJPXHHYZJFXHWHBDZFYZBCAPNPGNYDMSXHMMMMAMYNBYJTMPXYYMCTHJBZYFCGTYHWPHFTWZZEZSBZEGPFMTSKFTYCMHFLLHGPZJXZJGZJYXZSBBQSCZZLZCCSTPGXMJSFTCCZJZDJXCYBZLFCJSYZFGSZLYBCWZZBYZDZYPSWYJ" + "ZXZBDSYUXLZZBZFYGCZXBZHZFTPBGZGEJBSTGKDMFHYZZJHZLLZZGJQZLSFDJSSCBZGPDLFZFZSZYZYZSYGCXSNXXCHCZXTZZLJFZGQSQYXZJQDCCZTQCDXZJYQJQCHXZTDLGSCXZSYQJQTZWLQDQZTQCHQQJZYEZZZPBWKDJFCJPZTYPQYQTTYNLMBDKTJZPQZQZZFPZSBNJLG" + "YJDXJDZZKZGQKXDLPZJTCJDQBXDJQJSTCKNXBXZMSLYJCQMTJQWWCJQNJNLLLHJCWQTBZQYDZCZPZZDZYDDCYZZZCCJTTJFZDPRRTZTJDCQTQZDTJNPLZBCLLCTZSXKJZQZPZLBZRBTJDCXFCZDBCCJJLTQQPLDCGZDBBZJCQDCJWYNLLZYZCCDWLLXWZLXRXNTQQCZXKQLSGDF" + "QTDDGLRLAJJTKUYMKQLLTZYTDYYCZGJWYXDXFRSKSTQTENQMRKQZHHQKDLDAZFKYPBGGPZREBZZYKZZSPEGJXGYKQZZZSLYSYYYZWFQZYLZZLZHWCHKYPQGNPGBLPLRRJYXCCSYYHSFZFYBZYYTGZXYLXCZWXXZJZBLFFLGSKHYJZEYJHLPLLLLCZGXDRZELRHGKLZZYHZLYQSZ" + "ZJZQLJZFLNBHGWLCZCFJYSPYXZLZLXGCCPZBLLCYBBBBUBBCBPCRNNZCZYRBFSRLDCGQYYQXYGMQZWTZYTYJXYFWTEHZZJYWLCCNTZYJJZDEDPZDZTSYQJHDYMBJNYJZLXTSSTPHNDJXXBYXQTZQDDTJTDYYTGWSCSZQFLSHLGLBCZPHDLYZJYCKWTYTYLBNYTSDSYCCTYSZYYE" + "BHEXHQDTWNYGYCLXTSZYSTQMYGZAZCCSZZDSLZCLZRQXYYELJSBYMXSXZTEMBBLLYYLLYTDQYSHYMRQWKFKBFXNXSBYCHXBWJYHTQBPBSBWDZYLKGZSKYHXQZJXHXJXGNLJKZLYYCDXLFYFGHLJGJYBXQLYBXQPQGZTZPLNCYPXDJYQYDYMRBESJYYHKXXSTMXRCZZYWXYQYBMC" + "LLYZHQYZWQXDBXBZWZMSLPDMYSKFMZKLZCYQYCZLQXFZZYDQZPZYGYJYZMZXDZFYFYTTQTZHGSPCZMLCCYTZXJCYTJMKSLPZHYSNZLLYTPZCTZZCKTXDHXXTQCYFKSMQCCYYAZHTJPCYLZLYJBJXTPNYLJYYNRXSYLMMNXJSMYBCSYSYLZYLXJJQYLDZLPQBFZZBLFNDXQKCZFY" + "WHGQMRDSXYCYTXNQQJZYYPFZXDYZFPRXEJDGYQBXRCNFYYQPGHYJDYZXGRHTKYLNWDZNTSMPKLBTHBPYSZBZTJZSZZJTYYXZPHSSZZBZCZPTQFZMYFLYPYBBJQXZMXXDJMTSYSKKBJZXHJCKLPSMKYJZCXTMLJYXRZZQSLXXQPYZXMKYXXXJCLJPRMYYGADYSKQLSNDHYZKQXZY" + "ZTCGHZTLMLWZYBWSYCTBHJHJFCWZTXWYTKZLXQSHLYJZJXTMPLPYCGLTBZZTLZJCYJGDTCLKLPLLQPJMZPAPXYZLKKTKDZCZZBNZDYDYQZJYJGMCTXLTGXSZLMLHBGLKFWNWZHDXUHLFMKYSLGXDTWWFRJEJZTZHYDXYKSHWFZCQSHKTMQQHTZHYMJDJSKHXZJZBZZXYMPAGQMS" + "TPXLSKLZYNWRTSQLSZBPSPSGZWYHTLKSSSWHZZLYYTNXJGMJSZSUFWNLSOZTXGXLSAMMLBWLDSZYLAKQCQCTMYCFJBSLXCLZZCLXXKSBZQCLHJPSQPLSXXCKSLNHPSFQQYTXYJZLQLDXZQJZDYYDJNZPTUZDSKJFSLJHYLZSQZLBTXYDGTQFDBYAZXDZHZJNHHQBYKNXJJQCZML" + "LJZKSPLDYCLBBLXKLELXJLBQYCXJXGCNLCQPLZLZYJTZLJGYZDZPLTQCSXFDMNYCXGBTJDCZNBGBQYQJWGKFHTNPYQZQGBKPBBYZMTJDYTBLSQMPSXTBNPDXKLEMYYCJYNZCTLDYKZZXDDXHQSHDGMZSJYCCTAYRZLPYLTLKXSLZCGGEXCLFXLKJRTLQJAQZNCMBYDKKCXGLCZJ" + "ZXJHPTDJJMZQYKQSECQZDSHHADMLZFMMZBGNTJNNLGBYJBRBTMLBYJDZXLCJLPLDLPCQDHLXZLYCBLCXZZJADJLNZMMSSSMYBHBSQKBHRSXXJMXSDZNZPXLGBRHWGGFCXGMSKLLTSJYYCQLTSKYWYYHYWXBXQYWPYWYKQLSQPTNTKHQCWDQKTWPXXHCPTHTWUMSSYHBWCRWXHJM" + "KMZNGWTMLKFGHKJYLSYYCXWHYECLQHKQHTTQKHFZLDXQWYZYYDESBPKYRZPJFYYZJCEQDZZDLATZBBFJLLCXDLMJSSXEGYGSJQXCWBXSSZPDYZCXDNYXPPZYDLYJCZPLTXLSXYZYRXCYYYDYLWWNZSAHJSYQYHGYWWAXTJZDAXYSRLTDPSSYYFNEJDXYZHLXLLLZQZSJNYQYQQX" + "YJGHZGZCYJCHZLYCDSHWSHJZYJXCLLNXZJJYYXNFXMWFPYLCYLLABWDDHWDXJMCXZTZPMLQZHSFHZYNZTLLDYWLSLXHYMMYLMBWWKYXYADTXYLLDJPYBPWUXJMWMLLSAFDLLYFLBHHHBQQLTZJCQJLDJTFFKMMMBYTHYGDCQRDDWRQJXNBYSNWZDBYYTBJHPYBYTTJXAAHGQDQT" + "MYSTQXKBTZPKJLZRBEQQSSMJJBDJOTGTBXPGBKTLHQXJJJCTHXQDWJLWRFWQGWSHCKRYSWGFTGYGBXSDWDWRFHWYTJJXXXJYZYSLPYYYPAYXHYDQKXSHXYXGSKQHYWFDDDPPLCJLQQEEWXKSYYKDYPLTJTHKJLTCYYHHJTTPLTZZCDLTHQKZXQYSTEEYWYYZYXXYYSTTJKLLPZM" + "CYHQGXYHSRMBXPLLNQYDQHXSXXWGDQBSHYLLPJJJTHYJKYPPTHYYKTYEZYENMDSHLCRPQFDGFXZPSFTLJXXJBSWYYSKSFLXLPPLBBBLBSFXFYZBSJSSYLPBBFFFFSSCJDSTZSXZRYYSYFFSYZYZBJTBCTSBSDHRTJJBYTCXYJEYLXCBNEBJDSYXYKGSJZBXBYTFZWGENYHHTHZH" + "HXFWGCSTBGXKLSXYWMTMBYXJSTZSCDYQRCYTWXZFHMYMCXLZNSDJTTTXRYCFYJSBSDYERXJLJXBBDEYNJGHXGCKGSCYMBLXJMSZNSKGXFBNBPTHFJAAFXYXFPXMYPQDTZCXZZPXRSYWZDLYBBKTYQPQJPZYPZJZNJPZJLZZFYSBTTSLMPTZRTDXQSJEHBZYLZDHLJSQMLHTXTJE" + "CXSLZZSPKTLZKQQYFSYGYWPCPQFHQHYTQXZKRSGTTSQCZLPTXCDYYZXSQZSLXLZMYCPCQBZYXHBSXLZDLTCDXTYLZJYYZPZYZLTXJSJXHLPMYTXCQRBLZSSFJZZTNJYTXMYJHLHPPLCYXQJQQKZZSCPZKSWALQSBLCCZJSXGWWWYGYKTJBBZTDKHXHKGTGPBKQYSLPXPJCKBMLL" + "XDZSTBKLGGQKQLSBKKTFXRMDKBFTPZFRTBBRFERQGXYJPZSSTLBZTPSZQZSJDHLJQLZBPMSMMSXLQQNHKNBLRDDNXXDHDDJCYYGYLXGZLXSYGMQQGKHBPMXYXLYTQWLWGCPBMQXCYZYDRJBHTDJYHQSHTMJSBYPLWHLZFFNYPMHXXHPLTBQPFBJWQDBYGPNZTPFZJGSDDTQSHZE" + "AWZZYLLTYYBWJKXXGHLFKXDJTMSZSQYNZGGSWQSPHTLSSKMCLZXYSZQZXNCJDQGZDLFNYKLJCJLLZLMZZNHYDSSHTHZZLZZBBHQZWWYCRZHLYQQJBEYFXXXWHSRXWQHWPSLMSSKZTTYGYQQWRSLALHMJTQJSMXQBJJZJXZYZKXBYQXBJXSHZTSFJLXMXZXFGHKZSZGGYLCLSARJ" + "YHSLLLMZXELGLXYDJYTLFBHBPNLYZFBBHPTGJKWETZHKJJXZXXGLLJLSTGSHJJYQLQZFKCGNNDJSSZFDBCTWWSEQFHQJBSAQTGYPQLBXBMMYWXGSLZHGLZGQYFLZBYFZJFRYSFMBYZHQGFWZSYFYJJPHZBYYZFFWODGRLMFTWLBZGYCQXCDJYGZYYYYTYTYDWEGAZYHXJLZYYHL" + "RMGRXXZCLHNELJJTJTPWJYBJJBXJJTJTEEKHWSLJPLPSFYZPQQBDLQJJTYYQLYZKDKSQJYYQZLDQTGJQYZJSUCMRYQTHTEJMFCTYHYPKMHYZWJDQFHYYXWSHCTXRLJHQXHCCYYYJLTKTTYTMXGTCJTZAYYOCZLYLBSZYWJYTSJYHBYSHFJLYGJXXTMZYYLTXXYPZLXYJZYZYYPN" + "HMYMDYYLBLHLSYYQQLLNJJYMSOYQBZGDLYXYLCQYXTSZEGXHZGLHWBLJHEYXTWQMAKBPQCGYSHHEGQCMWYYWLJYJHYYZLLJJYLHZYHMGSLJLJXCJJYCLYCJPCPZJZJMMYLCQLNQLJQJSXYJMLSZLJQLYCMMHCFMMFPQQMFYLQMCFFQMMMMHMZNFHHJGTTHHKHSLNCHHYQDXTMMQ" + "DCYZYXYQMYQYLTDCYYYZAZZCYMZYDLZFFFMMYCQZWZZMABTBYZTDMNZZGGDFTYPCGQYTTSSFFWFDTZQSSYSTWXJHXYTSXXYLBYQHWWKXHZXWZNNZZJZJJQJCCCHYYXBZXZCYZTLLCQXYNJYCYYCYNZZQYYYEWYCZDCJYCCHYJLBTZYYCQWMPWPYMLGKDLDLGKQQBGYCHJXY"; //此处收录了375个多音字,数据来自于http://www.51window.net/page/pinyin var oMultiDiff = { "19969": "DZ", "19975": "WM", "19988": "QJ", "20048": "YL", "20056": "SC", "20060": "NM", "20094": "QG", "20127": "QJ", "20167": "QC", "20193": "YG", "20250": "KH", "20256": "ZC", "20282": "SC", "20285": "QJG", "20291": "TD", "20314": "YD", "20340": "NE", "20375": "TD", "20389": "YJ", "20391": "CZ", "20415": "PB", "20446": "YS", "20447": "SQ", "20504": "TC", "20608": "KG", "20854": "QJ", "20857": "ZC", "20911": "PF", "20504": "TC", "20608": "KG", "20854": "QJ", "20857": "ZC", "20911": "PF", "20985": "AW", "21032": "PB", "21048": "XQ", "21049": "SC", "21089": "YS", "21119": "JC", "21242": "SB", "21273": "SC", "21305": "YP", "21306": "QO", "21330": "ZC", "21333": "SDC", "21345": "QK", "21378": "CA", "21397": "SC", "21414": "XS", "21442": "SC", "21477": "JG", "21480": "TD", "21484": "ZS", "21494": "YX", "21505": "YX", "21512": "HG", "21523": "XH", "21537": "PB", "21542": "PF", "21549": "KH", "21571": "E", "21574": "DA", "21588": "TD", "21589": "O", "21618": "ZC", "21621": "KHA", "21632": "ZJ", "21654": "KG", "21679": "LKG", "21683": "KH", "21710": "A", "21719": "YH", "21734": "WOE", "21769": "A", "21780": "WN", "21804": "XH", "21834": "A", "21899": "ZD", "21903": "RN", "21908": "WO", "21939": "ZC", "21956": "SA", "21964": "YA", "21970": "TD", "22003": "A", "22031": "JG", "22040": "XS", "22060": "ZC", "22066": "ZC", "22079": "MH", "22129": "XJ", "22179": "XA", "22237": "NJ", "22244": "TD", "22280": "JQ", "22300": "YH", "22313": "XW", "22331": "YQ", "22343": "YJ", "22351": "PH", "22395": "DC", "22412": "TD", "22484": "PB", "22500": "PB", "22534": "ZD", "22549": "DH", "22561": "PB", "22612": "TD", "22771": "KQ", "22831": "HB", "22841": "JG", "22855": "QJ", "22865": "XQ", "23013": "ML", "23081": "WM", "23487": "SX", "23558": "QJ", "23561": "YW", "23586": "YW", "23614": "YW", "23615": "SN", "23631": "PB", "23646": "ZS", "23663": "ZT", "23673": "YG", "23762": "TD", "23769": "ZS", "23780": "QJ", "23884": "QK", "24055": "XH", "24113": "DC", "24162": "ZC", "24191": "GA", "24273": "QJ", "24324": "NL", "24377": "TD", "24378": "QJ", "24439": "PF", "24554": "ZS", "24683": "TD", "24694": "WE", "24733": "LK", "24925": "TN", "25094": "ZG", "25100": "XQ", "25103": "XH", "25153": "PB", "25170": "PB", "25179": "KG", "25203": "PB", "25240": "ZS", "25282": "FB", "25303": "NA", "25324": "KG", "25341": "ZY", "25373": "WZ", "25375": "XJ", "25384": "A", "25457": "A", "25528": "SD", "25530": "SC", "25552": "TD", "25774": "ZC", "25874": "ZC", "26044": "YW", "26080": "WM", "26292": "PB", "26333": "PB", "26355": "ZY", "26366": "CZ", "26397": "ZC", "26399": "QJ", "26415": "ZS", "26451": "SB", "26526": "ZC", "26552": "JG", "26561": "TD", "26588": "JG", "26597": "CZ", "26629": "ZS", "26638": "YL", "26646": "XQ", "26653": "KG", "26657": "XJ", "26727": "HG", "26894": "ZC", "26937": "ZS", "26946": "ZC", "26999": "KJ", "27099": "KJ", "27449": "YQ", "27481": "XS", "27542": "ZS", "27663": "ZS", "27748": "TS", "27784": "SC", "27788": "ZD", "27795": "TD", "27812": "O", "27850": "PB", "27852": "MB", "27895": "SL", "27898": "PL", "27973": "QJ", "27981": "KH", "27986": "HX", "27994": "XJ", "28044": "YC", "28065": "WG", "28177": "SM", "28267": "QJ", "28291": "KH", "28337": "ZQ", "28463": "TL", "28548": "DC", "28601": "TD", "28689": "PB", "28805": "JG", "28820": "QG", "28846": "PB", "28952": "TD", "28975": "ZC", "29100": "A", "29325": "QJ", "29575": "SL", "29602": "FB", "30010": "TD", "30044": "CX", "30058": "PF", "30091": "YSP", "30111": "YN", "30229": "XJ", "30427": "SC", "30465": "SX", "30631": "YQ", "30655": "QJ", "30684": "QJG", "30707": "SD", "30729": "XH", "30796": "LG", "30917": "PB", "31074": "NM", "31085": "JZ", "31109": "SC", "31181": "ZC", "31192": "MLB", "31293": "JQ", "31400": "YX", "31584": "YJ", "31896": "ZN", "31909": "ZY", "31995": "XJ", "32321": "PF", "32327": "ZY", "32418": "HG", "32420": "XQ", "32421": "HG", "32438": "LG", "32473": "GJ", "32488": "TD", "32521": "QJ", "32527": "PB", "32562": "ZSQ", "32564": "JZ", "32735": "ZD", "32793": "PB", "33071": "PF", "33098": "XL", "33100": "YA", "33152": "PB", "33261": "CX", "33324": "BP", "33333": "TD", "33406": "YA", "33426": "WM", "33432": "PB", "33445": "JG", "33486": "ZN", "33493": "TS", "33507": "QJ", "33540": "QJ", "33544": "ZC", "33564": "XQ", "33617": "YT", "33632": "QJ", "33636": "XH", "33637": "YX", "33694": "WG", "33705": "PF", "33728": "YW", "33882": "SR", "34067": "WM", "34074": "YW", "34121": "QJ", "34255": "ZC", "34259": "XL", "34425": "JH", "34430": "XH", "34485": "KH", "34503": "YS", "34532": "HG", "34552": "XS", "34558": "YE", "34593": "ZL", "34660": "YQ", "34892": "XH", "34928": "SC", "34999": "QJ", "35048": "PB", "35059": "SC", "35098": "ZC", "35203": "TQ", "35265": "JX", "35299": "JX", "35782": "SZ", "35828": "YS", "35830": "E", "35843": "TD", "35895": "YG", "35977": "MH", "36158": "JG", "36228": "QJ", "36426": "XQ", "36466": "DC", "36710": "JC", "36711": "ZYG", "36767": "PB", "36866": "SK", "36951": "YW", "37034": "YX", "37063": "XH", "37218": "ZC", "37325": "ZC", "38063": "PB", "38079": "TD", "38085": "QY", "38107": "DC", "38116": "TD", "38123": "YD", "38224": "HG", "38241": "XTC", "38271": "ZC", "38415": "YE", "38426": "KH", "38461": "YD", "38463": "AE", "38466": "PB", "38477": "XJ", "38518": "YT", "38551": "WK", "38585": "ZC", "38704": "XS", "38739": "LJ", "38761": "GJ", "38808": "SQ", "39048": "JG", "39049": "XJ", "39052": "HG", "39076": "CZ", "39271": "XT", "39534": "TD", "39552": "TD", "39584": "PB", "39647": "SB", "39730": "LG", "39748": "TPB", "40109": "ZQ", "40479": "ND", "40516": "HG", "40536": "HG", "40583": "QJ", "40765": "YQ", "40784": "QJ", "40840": "YK", "40863": "QJG" }; var _checkPYCh = function (ch) { var uni = ch.charCodeAt(0); // 如果不在汉字处理范围之内,返回原字符,也可以调用自己的处理函数 if (uni > 40869 || uni < 19968) return ch; // dealWithOthers(ch); return (oMultiDiff[uni] ? oMultiDiff[uni] : (_ChineseFirstPY.charAt(uni - 19968))); }; var _mkPYRslt = function (arr) { var arrRslt = [""], k; for (var i = 0, len = arr.length; i < len; i++) { var str = arr[i]; var strlen = str.length; if (strlen == 1) { for (k = 0; k < arrRslt.length; k++) { arrRslt[k] += str; } } else { var tmpArr = arrRslt.slice(0); arrRslt = []; for (k = 0; k < strlen; k++) { // 复制一个相同的arrRslt var tmp = tmpArr.slice(0); // 把当前字符str[k]添加到每个元素末尾 for (var j = 0; j < tmp.length; j++) { tmp[j] += str.charAt(k); } // 把复制并修改后的数组连接到arrRslt上 arrRslt = arrRslt.concat(tmp); } } } return arrRslt.join("").toLowerCase(); }; _.extend(BI, { makeFirstPY: function (str) { if (typeof (str) != "string") return '' + str; var arrResult = []; // 保存中间结果的数组 for (var i = 0, len = str.length; i < len; i++) { // 获得unicode码 var ch = str.charAt(i); // 检查该unicode码是否在处理范围之内,在则返回该码对映汉字的拼音首字母,不在则调用其它函数处理 arrResult.push(_checkPYCh(ch)); } // 处理arrResult,返回所有可能的拼音首字母串数组 return _mkPYRslt(arrResult); } }); })();/** * Detect Element Resize. * Forked in order to guard against unsafe 'window' and 'document' references. * * https://github.com/sdecima/javascript-detect-element-resize * Sebastian Decima * * version: 0.5.3 **/ !(function () { // Check `document` and `window` in case of server-side rendering var _window if (typeof window !== 'undefined') { _window = window } else if (typeof self !== 'undefined') { _window = self } else { _window = this } var addEventListener = typeof document !== 'undefined' && document.addEventListener; var stylesCreated = false; if (addEventListener) { var requestFrame = (function () { var raf = _window.requestAnimationFrame || _window.mozRequestAnimationFrame || _window.webkitRequestAnimationFrame || function (fn) { return _window.setTimeout(fn, 20); }; return function (fn) { return raf(fn); }; })(); var cancelFrame = (function () { var cancel = _window.cancelAnimationFrame || _window.mozCancelAnimationFrame || _window.webkitCancelAnimationFrame || _window.clearTimeout; return function (id) { return cancel(id); }; })(); var resetTriggers = function (element) { var triggers = element.__resizeTriggers__, expand = triggers.firstElementChild, contract = triggers.lastElementChild, expandChild = expand.firstElementChild; contract.scrollLeft = contract.scrollWidth; contract.scrollTop = contract.scrollHeight; expandChild.style.width = expand.offsetWidth + 1 + 'px'; expandChild.style.height = expand.offsetHeight + 1 + 'px'; expand.scrollLeft = expand.scrollWidth; expand.scrollTop = expand.scrollHeight; }; var checkTriggers = function (element) { return element.offsetWidth !== element.__resizeLast__.width || element.offsetHeight !== element.__resizeLast__.height; } var scrollListener = function (e) { var element = this; resetTriggers(this); if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__); this.__resizeRAF__ = requestFrame(function () { if (checkTriggers(element)) { element.__resizeLast__.width = element.offsetWidth; element.__resizeLast__.height = element.offsetHeight; element.__resizeListeners__.forEach(function (fn) { fn.call(element, e); }); } }); }; /* Detect CSS Animations support to detect element display/re-attach */ var animation = false, animationstring = 'animation', keyframeprefix = '', animationstartevent = 'animationstart', domPrefixes = 'Webkit Moz O ms'.split(' '), startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '), pfx = ''; { var elm = document.createElement('fakeelement'); if (elm.style.animationName !== undefined) { animation = true; } if (animation === false) { for (var i = 0; i < domPrefixes.length; i++) { if (elm.style[domPrefixes[i] + 'AnimationName'] !== undefined) { pfx = domPrefixes[i]; animationstring = pfx + 'Animation'; keyframeprefix = '-' + pfx.toLowerCase() + '-'; animationstartevent = startEvents[i]; animation = true; break; } } } } var animationName = 'resizeanim'; var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } '; var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; '; } var createStyles = function () { if (!stylesCreated) { //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360 var css = (animationKeyframes ? animationKeyframes : '') + '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' + '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }', head = document.head || document.getElementsByTagName('head')[0], style = document.createElement('style'); style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } head.appendChild(style); stylesCreated = true; } } var addResizeListener = function (element, fn) { if (addEventListener){ if (!element.__resizeTriggers__) { if (getComputedStyle(element).position === 'static') element.style.position = 'relative'; createStyles(); element.__resizeLast__ = {}; element.__resizeListeners__ = []; (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers'; element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' + '<div class="contract-trigger"></div>'; element.appendChild(element.__resizeTriggers__); resetTriggers(element); element.addEventListener('scroll', scrollListener, true); /* Listen for a css animation to detect element display/re-attach */ animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function (e) { if (e.animationName === animationName) resetTriggers(element); }); } element.__resizeListeners__.push(fn); } else { element.attachEvent('onresize', fn); } }; var removeResizeListener = function (element, fn) { if (addEventListener) { element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1); if (!element.__resizeListeners__.length) { element.removeEventListener('scroll', scrollListener, true); element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__); } } else { element.detachEvent('onresize', fn); } }; BI.ResizeDetector = { addResizeListener: function (widget, fn) { addResizeListener(widget.element[0], fn); return function () { removeResizeListener(widget.element[0], fn); } }, removeResizeListener: function (widget, fn) { removeResizeListener(widget.element[0], fn); } }; }()); ; (function () { function defaultComparator(a, b) { return a < b; } BI.Heap = function (items, comparator) { this._items = items || []; this._size = this._items.length; this._comparator = comparator || defaultComparator; this._heapify(); }; BI.Heap.prototype = { constructor: BI.Heap, empty: function () { return this._size === 0; }, pop: function () { if (this._size === 0) { return; } var elt = this._items[0]; var lastElt = this._items.pop(); this._size--; if (this._size > 0) { this._items[0] = lastElt; this._sinkDown(0); } return elt; }, push: function (item) { this._items[this._size++] = item; this._bubbleUp(this._size - 1); }, size: function () { return this._size; }, peek: function () { if (this._size === 0) { return; } return this._items[0]; }, _heapify: function () { for (var index = Math.floor((this._size + 1) / 2); index >= 0; index--) { this._sinkDown(index); } }, _bubbleUp: function (index) { var elt = this._items[index]; while (index > 0) { var parentIndex = Math.floor((index + 1) / 2) - 1; var parentElt = this._items[parentIndex]; // if parentElt < elt, stop if (this._comparator(parentElt, elt)) { return; } // swap this._items[parentIndex] = elt; this._items[index] = parentElt; index = parentIndex; } }, _sinkDown: function (index) { var elt = this._items[index]; while (true) { var leftChildIndex = 2 * (index + 1) - 1; var rightChildIndex = 2 * (index + 1); var swapIndex = -1; if (leftChildIndex < this._size) { var leftChild = this._items[leftChildIndex]; if (this._comparator(leftChild, elt)) { swapIndex = leftChildIndex; } } if (rightChildIndex < this._size) { var rightChild = this._items[rightChildIndex]; if (this._comparator(rightChild, elt)) { if (swapIndex === -1 || this._comparator(rightChild, this._items[swapIndex])) { swapIndex = rightChildIndex; } } } // if we don't have a swap, stop if (swapIndex === -1) { return; } this._items[index] = this._items[swapIndex]; this._items[swapIndex] = elt; index = swapIndex; } } } })(); ;(function () { var clamp = function (min, value, max) { if (value < min) { return min; } if (value > max) { return max; } return value; }; var BUFFER_ROWS = 5; var NO_ROWS_SCROLL_RESULT = { index: 0, offset: 0, position: 0, contentHeight: 0 }; BI.TableScrollHelper = function (rowCount, defaultRowHeight, viewportHeight, rowHeightGetter) { this._rowOffsets = BI.PrefixIntervalTree.uniform(rowCount, defaultRowHeight); this._storedHeights = new Array(rowCount); for (var i = 0; i < rowCount; ++i) { this._storedHeights[i] = defaultRowHeight; } this._rowCount = rowCount; this._position = 0; this._contentHeight = rowCount * defaultRowHeight; this._defaultRowHeight = defaultRowHeight; this._rowHeightGetter = rowHeightGetter ? rowHeightGetter : function () { return defaultRowHeight }; this._viewportHeight = viewportHeight; this._updateHeightsInViewport(0, 0); }; BI.TableScrollHelper.prototype = { constructor: BI.TableScrollHelper, setRowHeightGetter: function (rowHeightGetter) { this._rowHeightGetter = rowHeightGetter; }, setViewportHeight: function (viewportHeight) { this._viewportHeight = viewportHeight; }, getContentHeight: function () { return this._contentHeight; }, _updateHeightsInViewport: function (firstRowIndex, firstRowOffset) { var top = firstRowOffset; var index = firstRowIndex; while (top <= this._viewportHeight && index < this._rowCount) { this._updateRowHeight(index); top += this._storedHeights[index]; index++; } }, _updateHeightsAboveViewport: function (firstRowIndex) { var index = firstRowIndex - 1; while (index >= 0 && index >= firstRowIndex - BUFFER_ROWS) { var delta = this._updateRowHeight(index); this._position += delta; index--; } }, _updateRowHeight: function (rowIndex) { if (rowIndex < 0 || rowIndex >= this._rowCount) { return 0; } var newHeight = this._rowHeightGetter(rowIndex); if (newHeight !== this._storedHeights[rowIndex]) { var change = newHeight - this._storedHeights[rowIndex]; this._rowOffsets.set(rowIndex, newHeight); this._storedHeights[rowIndex] = newHeight; this._contentHeight += change; return change; } return 0; }, getRowPosition: function (rowIndex) { this._updateRowHeight(rowIndex); return this._rowOffsets.sumUntil(rowIndex); }, scrollBy: function (delta) { if (this._rowCount === 0) { return NO_ROWS_SCROLL_RESULT; } var firstRow = this._rowOffsets.greatestLowerBound(this._position); firstRow = clamp(firstRow, 0, Math.max(this._rowCount - 1, 0)); var firstRowPosition = this._rowOffsets.sumUntil(firstRow); var rowIndex = firstRow; var position = this._position; var rowHeightChange = this._updateRowHeight(rowIndex); if (firstRowPosition !== 0) { position += rowHeightChange; } var visibleRowHeight = this._storedHeights[rowIndex] - (position - firstRowPosition); if (delta >= 0) { while (delta > 0 && rowIndex < this._rowCount) { if (delta < visibleRowHeight) { position += delta; delta = 0; } else { delta -= visibleRowHeight; position += visibleRowHeight; rowIndex++; } if (rowIndex < this._rowCount) { this._updateRowHeight(rowIndex); visibleRowHeight = this._storedHeights[rowIndex]; } } } else if (delta < 0) { delta = -delta; var invisibleRowHeight = this._storedHeights[rowIndex] - visibleRowHeight; while (delta > 0 && rowIndex >= 0) { if (delta < invisibleRowHeight) { position -= delta; delta = 0; } else { position -= invisibleRowHeight; delta -= invisibleRowHeight; rowIndex--; } if (rowIndex >= 0) { var change = this._updateRowHeight(rowIndex); invisibleRowHeight = this._storedHeights[rowIndex]; position += change; } } } var maxPosition = this._contentHeight - this._viewportHeight; position = clamp(position, 0, maxPosition); this._position = position; var firstRowIndex = this._rowOffsets.greatestLowerBound(position); firstRowIndex = clamp(firstRowIndex, 0, Math.max(this._rowCount - 1, 0)); firstRowPosition = this._rowOffsets.sumUntil(firstRowIndex); var firstRowOffset = firstRowPosition - position; this._updateHeightsInViewport(firstRowIndex, firstRowOffset); this._updateHeightsAboveViewport(firstRowIndex); return { index: firstRowIndex, offset: firstRowOffset, position: this._position, contentHeight: this._contentHeight }; }, _getRowAtEndPosition: function (rowIndex) { // We need to update enough rows above the selected one to be sure that when // we scroll to selected position all rows between first shown and selected // one have most recent heights computed and will not resize this._updateRowHeight(rowIndex); var currentRowIndex = rowIndex; var top = this._storedHeights[currentRowIndex]; while (top < this._viewportHeight && currentRowIndex >= 0) { currentRowIndex--; if (currentRowIndex >= 0) { this._updateRowHeight(currentRowIndex); top += this._storedHeights[currentRowIndex]; } } var position = this._rowOffsets.sumTo(rowIndex) - this._viewportHeight; if (position < 0) { position = 0; } return position; }, scrollTo: function (position) { if (this._rowCount === 0) { return NO_ROWS_SCROLL_RESULT; } if (position <= 0) { // If position less than or equal to 0 first row should be fully visible // on top this._position = 0; this._updateHeightsInViewport(0, 0); return { index: 0, offset: 0, position: this._position, contentHeight: this._contentHeight }; } else if (position >= this._contentHeight - this._viewportHeight) { // If position is equal to or greater than max scroll value, we need // to make sure to have bottom border of last row visible. var rowIndex = this._rowCount - 1; position = this._getRowAtEndPosition(rowIndex); } this._position = position; var firstRowIndex = this._rowOffsets.greatestLowerBound(position); firstRowIndex = clamp(firstRowIndex, 0, Math.max(this._rowCount - 1, 0)); var firstRowPosition = this._rowOffsets.sumUntil(firstRowIndex); var firstRowOffset = firstRowPosition - position; this._updateHeightsInViewport(firstRowIndex, firstRowOffset); this._updateHeightsAboveViewport(firstRowIndex); return { index: firstRowIndex, offset: firstRowOffset, position: this._position, contentHeight: this._contentHeight }; }, /** * Allows to scroll to selected row with specified offset. It always * brings that row to top of viewport with that offset */ scrollToRow: function (rowIndex, offset) { rowIndex = clamp(rowIndex, 0, Math.max(this._rowCount - 1, 0)); offset = clamp(offset, -this._storedHeights[rowIndex], 0); var firstRow = this._rowOffsets.sumUntil(rowIndex); return this.scrollTo(firstRow - offset); }, /** * Allows to scroll to selected row by bringing it to viewport with minimal * scrolling. This that if row is fully visible, scroll will not be changed. * If top border of row is above top of viewport it will be scrolled to be * fully visible on the top of viewport. If the bottom border of row is * below end of viewport, it will be scrolled up to be fully visible on the * bottom of viewport. */ scrollRowIntoView: function (rowIndex) { rowIndex = clamp(rowIndex, 0, Math.max(this._rowCount - 1, 0)); var rowBegin = this._rowOffsets.sumUntil(rowIndex); var rowEnd = rowBegin + this._storedHeights[rowIndex]; if (rowBegin < this._position) { return this.scrollTo(rowBegin); } else if (this._position + this._viewportHeight < rowEnd) { var position = this._getRowAtEndPosition(rowIndex); return this.scrollTo(position); } return this.scrollTo(this._position); } }; })(); // Data structure that allows to store values and assign positions to them // in a way to minimize changing positions of stored values when new ones are // added or when some values are replaced. Stored elements are alwasy assigned // a consecutive set of positoins startin from 0 up to count of elements less 1 // Following actions can be executed // * get position assigned to given value (null if value is not stored) // * create new entry for new value and get assigned position back // * replace value that is furthest from specified value range with new value // and get it's position back // All operations take amortized log(n) time where n is number of elements in // the set. BI.IntegerBufferSet = function () { this._valueToPositionMap = {}; this._size = 0; this._smallValues = new BI.Heap( [], // Initial data in the heap this._smallerComparator ); this._largeValues = new BI.Heap( [], // Initial data in the heap this._greaterComparator ); }; BI.IntegerBufferSet.prototype = { constructor: BI.IntegerBufferSet, getSize: function () /*number*/ { return this._size; }, getValuePosition: function (/*number*/ value) /*?number*/ { if (this._valueToPositionMap[value] === undefined) { return null; } return this._valueToPositionMap[value]; }, getNewPositionForValue: function (/*number*/ value) /*number*/ { var newPosition = this._size; this._size++; this._pushToHeaps(newPosition, value); this._valueToPositionMap[value] = newPosition; return newPosition; }, replaceFurthestValuePosition: function (/*number*/ lowValue, /*number*/ highValue, /*number*/ newValue) /*?number*/ { this._cleanHeaps(); if (this._smallValues.empty() || this._largeValues.empty()) { // Threre are currently no values stored. We will have to create new // position for this value. return null; } var minValue = this._smallValues.peek().value; var maxValue = this._largeValues.peek().value; if (minValue >= lowValue && maxValue <= highValue) { // All values currently stored are necessary, we can't reuse any of them. return null; } var valueToReplace; if (lowValue - minValue > maxValue - highValue) { // minValue is further from provided range. We will reuse it's position. valueToReplace = minValue; this._smallValues.pop(); } else { valueToReplace = maxValue; this._largeValues.pop(); } var position = this._valueToPositionMap[valueToReplace]; delete this._valueToPositionMap[valueToReplace]; this._valueToPositionMap[newValue] = position; this._pushToHeaps(position, newValue); return position; }, _pushToHeaps: function (/*number*/ position, /*number*/ value) { var element = { position: position, value:value }; // We can reuse the same object in both heaps, because we don't mutate them this._smallValues.push(element); this._largeValues.push(element); }, _cleanHeaps: function () { // We not usually only remove object from one heap while moving value. // Here we make sure that there is no stale data on top of heaps. this._cleanHeap(this._smallValues); this._cleanHeap(this._largeValues); var minHeapSize = Math.min(this._smallValues.size(), this._largeValues.size()); var maxHeapSize = Math.max(this._smallValues.size(), this._largeValues.size()); if (maxHeapSize > 10 * minHeapSize) { // There are many old values in one of heaps. We nned to get rid of them // to not use too avoid memory leaks this._recreateHeaps(); } }, _recreateHeaps: function () { var sourceHeap = this._smallValues.size() < this._largeValues.size() ? this._smallValues : this._largeValues; var newSmallValues = new Heap( [], // Initial data in the heap this._smallerComparator ); var newLargeValues = new Heap( [], // Initial datat in the heap this._greaterComparator ); while (!sourceHeap.empty()) { var element = sourceHeap.pop(); // Push all stil valid elements to new heaps if (this._valueToPositionMap[element.value] !== undefined) { newSmallValues.push(element); newLargeValues.push(element); } } this._smallValues = newSmallValues; this._largeValues = newLargeValues; }, _cleanHeap: function (/*object*/ heap) { while (!heap.empty() && this._valueToPositionMap[heap.peek().value] === undefined) { heap.pop(); } }, _smallerComparator: function (/*object*/ lhs, /*object*/ rhs) /*boolean*/ { return lhs.value < rhs.value; }, _greaterComparator: function (/*object*/ lhs, /*object*/ rhs) /*boolean*/ { return lhs.value > rhs.value; } }; ; !(function () { BI.LinkHashMap = function () { this.array = []; this.map = {}; }; BI.LinkHashMap.prototype = { constructor: BI.LinkHashMap, has: function (key) { if (key in this.map) { return true; } return false; }, add: function (key, value) { if (typeof key == 'undefined') { return; } if (key in this.map) { this.map[key] = value; } else { this.array.push(key); this.map[key] = value; } }, remove: function (key) { if (key in this.map) { delete this.map[key]; for (var i = 0; i < this.array.length; i++) { if (this.array[i] == key) { this.array.splice(i, 1); break; } } } }, size: function () { return this.array.length; }, each: function (fn, scope) { var scope = scope || window; var fn = fn || null; if (fn == null || typeof (fn) != "function") { return; } for (var i = 0; i < this.array.length; i++) { var key = this.array[i]; var value = this.map[key]; var re = fn.call(scope, key, value, i, this.array, this.map); if (re == false) { break; } } }, get: function (key) { return this.map[key]; }, toArray: function () { var array = []; this.each(function (key, value) { array.push(value); }) return array; } } })();window.BI = window.BI || {}; $.extend(BI, { $defaultImport: function (options) { var config = $.extend({ op: 'resource', path: null, type: null, must: false }, options); config.url = BI.servletURL + '?op=' + config.op + '&resource=' + config.path; this.$import(config.url, config.type, config.must); }, $import: function () { var _LOADED = {}; // alex:保存加载过的 function loadReady(src, must) { var $scripts = $("head script, body script"); $.each($scripts, function (i, item) { if (item.src.indexOf(src) != -1) { _LOADED[src] = true; } }); var $links = $("head link"); $.each($links, function (i, item) { if (item.href.indexOf(src) != -1 && must) { _LOADED[src] = false; $(item).remove(); } }); } // must=true 强行加载 return function (src, ext, must) { loadReady(src, must); // alex:如果已经加载过了的,直接return if (_LOADED[src] === true) { return; } if (ext === 'css') { var link = document.createElement('link'); link.rel = 'stylesheet'; link.type = 'text/css'; link.href = src; var head = document.getElementsByTagName('head')[0]; head.appendChild(link); _LOADED[src] = true; } else { // alex:这里用同步调用的方式,必须等待ajax完成 $.ajax({ url: src, dataType: "script", // alex:指定dataType为script,jquery会帮忙做globalEval的事情 async: false, cache: true, complete: function (res, status) { /* * alex:发现jquery会很智能地判断一下返回的数据类型是不是script,然后做一个globalEval * 所以当status为success时就不需要再把其中的内容加到script里面去了 */ if (status == 'success') { _LOADED[src] = true; } } }) } } }() });; !(function () { BI.LRU = function (limit) { this.size = 0; this.limit = limit; this.head = this.tail = undefined; this._keymap = {}; }; var p = BI.LRU.prototype; p.put = function (key, value) { var removed; if (this.size === this.limit) { removed = this.shift(); } var entry = this.get(key, true); if (!entry) { entry = { key: key }; this._keymap[key] = entry; if (this.tail) { this.tail.newer = entry; entry.older = this.tail } else { this.head = entry } this.tail = entry; this.size++; } entry.value = value; return removed; }; p.shift = function () { var entry = this.head; if (entry) { this.head = this.head.newer; this.head.older = undefined; entry.newer = entry.older = undefined; this._keymap[entry.key] = undefined; this.size--; } return entry; }; p.get = function (key, returnEntry) { var entry = this._keymap[key]; if (entry === undefined) return; if (entry === this.tail) { return returnEntry ? entry : entry.value } // HEAD--------------TAIL // <.older .newer> // <--- add direction -- // A B C <D> E if (entry.newer) { if (entry === this.head) { this.head = entry.newer } entry.newer.older = entry.older; // C <-- E. } if (entry.older) { entry.older.newer = entry.newer; // C. --> E } entry.newer = undefined; // D --x entry.older = this.tail; // D. --> E if (this.tail) { this.tail.newer = entry; // E. <-- D } this.tail = entry; return returnEntry ? entry : entry.value }; p.has = function (key) { return this._keymap[key] != null; } })();; !(function () { var MD5 = function (hexcase) { this.hexcase = !hexcase ? 0 : 1; /* hex output format. 0 - lowercase; 1 - uppercase */ this.b64pad = ""; /* base-64 pad character. "=" for strict RFC compliance */ this.chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ }; /* * These are the functions you'll usually want to call * They take string arguments and return either hex or base-64 encoded strings */ MD5.prototype.hex_md5 = function (s) { return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz)); }; MD5.prototype.hex_md5_salt = function (s) { var md5ed = this.hex_md5(s); var items1 = []; var items2 = []; for (var i = 0; i < md5ed.length; i++) { if (i % 2 === 0) { items1.push(md5ed.charAt(i)); } else { items2.push(md5ed.charAt(i)); } } var result = ":" + items1.join("") + items2.join(""); return result; }; MD5.prototype.b64_md5 = function (s) { return this.binl2b64(this.core_md5(this.str2binl(s), s.length * this.chrsz)); }; MD5.prototype.hex_hmac_md5 = function (key, data) { return this.binl2hex(this.core_hmac_md5(key, data)); }; MD5.prototype.b64_hmac_md5 = function (key, data) { return this.binl2b64(this.core_hmac_md5(key, data)); }; /* Backwards compatibility - same as hex_md5() */ MD5.prototype.calcMD5 = function (s) { return this.binl2hex(this.core_md5(this.str2binl(s), s.length * this.chrsz)); }; MD5.prototype.core_md5 = function (x, len) { /* append padding */ x[len >> 5] |= 0x80 << ((len) % 32); x[(((len + 64) >>> 9) << 4) + 14] = len; var a = 1732584193; var b = -271733879; var c = -1732584194; var d = 271733878; for (var i = 0; i < x.length; i += 16) { var olda = a; var oldb = b; var oldc = c; var oldd = d; a = this.md5_ff(a, b, c, d, x[i + 0], 7, -680876936); d = this.md5_ff(d, a, b, c, x[i + 1], 12, -389564586); c = this.md5_ff(c, d, a, b, x[i + 2], 17, 606105819); b = this.md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); a = this.md5_ff(a, b, c, d, x[i + 4], 7, -176418897); d = this.md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); c = this.md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); b = this.md5_ff(b, c, d, a, x[i + 7], 22, -45705983); a = this.md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); d = this.md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); c = this.md5_ff(c, d, a, b, x[i + 10], 17, -42063); b = this.md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); a = this.md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); d = this.md5_ff(d, a, b, c, x[i + 13], 12, -40341101); c = this.md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); b = this.md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); a = this.md5_gg(a, b, c, d, x[i + 1], 5, -165796510); d = this.md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); c = this.md5_gg(c, d, a, b, x[i + 11], 14, 643717713); b = this.md5_gg(b, c, d, a, x[i + 0], 20, -373897302); a = this.md5_gg(a, b, c, d, x[i + 5], 5, -701558691); d = this.md5_gg(d, a, b, c, x[i + 10], 9, 38016083); c = this.md5_gg(c, d, a, b, x[i + 15], 14, -660478335); b = this.md5_gg(b, c, d, a, x[i + 4], 20, -405537848); a = this.md5_gg(a, b, c, d, x[i + 9], 5, 568446438); d = this.md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); c = this.md5_gg(c, d, a, b, x[i + 3], 14, -187363961); b = this.md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); a = this.md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); d = this.md5_gg(d, a, b, c, x[i + 2], 9, -51403784); c = this.md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); b = this.md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); a = this.md5_hh(a, b, c, d, x[i + 5], 4, -378558); d = this.md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); c = this.md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); b = this.md5_hh(b, c, d, a, x[i + 14], 23, -35309556); a = this.md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); d = this.md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); c = this.md5_hh(c, d, a, b, x[i + 7], 16, -155497632); b = this.md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); a = this.md5_hh(a, b, c, d, x[i + 13], 4, 681279174); d = this.md5_hh(d, a, b, c, x[i + 0], 11, -358537222); c = this.md5_hh(c, d, a, b, x[i + 3], 16, -722521979); b = this.md5_hh(b, c, d, a, x[i + 6], 23, 76029189); a = this.md5_hh(a, b, c, d, x[i + 9], 4, -640364487); d = this.md5_hh(d, a, b, c, x[i + 12], 11, -421815835); c = this.md5_hh(c, d, a, b, x[i + 15], 16, 530742520); b = this.md5_hh(b, c, d, a, x[i + 2], 23, -995338651); a = this.md5_ii(a, b, c, d, x[i + 0], 6, -198630844); d = this.md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); c = this.md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); b = this.md5_ii(b, c, d, a, x[i + 5], 21, -57434055); a = this.md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); d = this.md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); c = this.md5_ii(c, d, a, b, x[i + 10], 15, -1051523); b = this.md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); a = this.md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); d = this.md5_ii(d, a, b, c, x[i + 15], 10, -30611744); c = this.md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); b = this.md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); a = this.md5_ii(a, b, c, d, x[i + 4], 6, -145523070); d = this.md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); c = this.md5_ii(c, d, a, b, x[i + 2], 15, 718787259); b = this.md5_ii(b, c, d, a, x[i + 9], 21, -343485551); a = this.safe_add(a, olda); b = this.safe_add(b, oldb); c = this.safe_add(c, oldc); d = this.safe_add(d, oldd); } return Array(a, b, c, d); }; /* * These functions implement the four basic operations the algorithm uses. */ MD5.prototype.md5_cmn = function (q, a, b, x, s, t) { return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), this.safe_add(x, t)), s), b); }; MD5.prototype.md5_ff = function (a, b, c, d, x, s, t) { return this.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); }; MD5.prototype.md5_gg = function (a, b, c, d, x, s, t) { return this.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); }; MD5.prototype.md5_hh = function (a, b, c, d, x, s, t) { return this.md5_cmn(b ^ c ^ d, a, b, x, s, t); }; MD5.prototype.md5_ii = function (a, b, c, d, x, s, t) { return this.md5_cmn(c ^ (b | (~d)), a, b, x, s, t); }; /* * Calculate the HMAC-MD5, of a key and some data */ MD5.prototype.core_hmac_md5 = function (key, data) { var bkey = this.str2binl(key); if (bkey.length > 16) bkey = this.core_md5(bkey, key.length * this.chrsz); var ipad = Array(16), opad = Array(16); for (var i = 0; i < 16; i++) { ipad[i] = bkey[i] ^ 0x36363636; opad[i] = bkey[i] ^ 0x5C5C5C5C; } var hash = this.core_md5(ipad.concat(this.str2binl(data)), 512 + data.length * this.chrsz); return this.core_md5(opad.concat(hash), 512 + 128); }; /* * Add integers, wrapping at 2^32. This uses 16-bit operations internally * to work around bugs in some JS interpreters. */ MD5.prototype.safe_add = function (x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); }; /* * Bitwise rotate a 32-bit number to the left. */ MD5.prototype.bit_rol = function (num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }; /* * Convert a string to an array of little-endian words * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. */ MD5.prototype.str2binl = function (str) { var bin = Array(); var mask = (1 << this.chrsz) - 1; for (var i = 0; i < str.length * this.chrsz; i += this.chrsz) bin[i >> 5] |= (str.charCodeAt(i / this.chrsz) & mask) << (i % 32); return bin; }; /* * Convert an array of little-endian words to a hex string. */ MD5.prototype.binl2hex = function (binarray) { var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; var str = ""; for (var i = 0; i < binarray.length * 4; i++) { str += hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xF) + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xF); } return str; }; /* * Convert an array of little-endian words to a base-64 string */ MD5.prototype.binl2b64 = function (binarray) { var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; var str = ""; for (var i = 0; i < binarray.length * 4; i += 3) { var triplet = (((binarray[i >> 2] >> 8 * (i % 4)) & 0xFF) << 16) | (((binarray[i + 1 >> 2] >> 8 * ((i + 1) % 4)) & 0xFF) << 8) | ((binarray[i + 2 >> 2] >> 8 * ((i + 2) % 4)) & 0xFF); for (var j = 0; j < 4; j++) { if (i * 8 + j * 6 > binarray.length * 32) str += this.b64pad; else str += tab.charAt((triplet >> 6 * (3 - j)) & 0x3F); } } return str; }; BI.MD5 = new MD5(); })();//线段树 ;(function () { var parent = function (node) { return Math.floor(node / 2); }; var Int32Array = window.Int32Array || function (size) { var xs = []; for (var i = size - 1; i >= 0; --i) { xs[i] = 0; } return xs; }; var ceilLog2 = function (x) { var y = 1; while (y < x) { y *= 2; } return y; }; BI.PrefixIntervalTree = function (xs) { this._size = xs.length; this._half = ceilLog2(this._size); this._heap = new Int32Array(2 * this._half); var i; for (i = 0; i < this._size; ++i) { this._heap[this._half + i] = xs[i]; } for (i = this._half - 1; i > 0; --i) { this._heap[i] = this._heap[2 * i] + this._heap[2 * i + 1]; } }; BI.PrefixIntervalTree.prototype = { constructor: BI.PrefixIntervalTree, set: function (index, value) { var node = this._half + index; this._heap[node] = value; node = parent(node); for (; node !== 0; node = parent(node)) { this._heap[node] = this._heap[2 * node] + this._heap[2 * node + 1]; } }, get: function (index) { var node = this._half + index; return this._heap[node]; }, getSize: function () { return this._size; }, /** * get(0) + get(1) + ... + get(end - 1). */ sumUntil: function (end) { if (end === 0) { return 0; } var node = this._half + end - 1; var sum = this._heap[node]; for (; node !== 1; node = parent(node)) { if (node % 2 === 1) { sum += this._heap[node - 1]; } } return sum; }, /** * get(0) + get(1) + ... + get(inclusiveEnd). */ sumTo: function (inclusiveEnd) { return this.sumUntil(inclusiveEnd + 1); }, /** * sum get(begin) + get(begin + 1) + ... + get(end - 1). */ sum: function (begin, end) { return this.sumUntil(end) - this.sumUntil(begin); }, /** * Returns the smallest i such that 0 <= i <= size and sumUntil(i) <= t, or * -1 if no such i exists. */ greatestLowerBound: function (t) { if (t < 0) { return -1; } var node = 1; if (this._heap[node] <= t) { return this._size; } while (node < this._half) { var leftSum = this._heap[2 * node]; if (t < leftSum) { node = 2 * node; } else { node = 2 * node + 1; t -= leftSum; } } return node - this._half; }, /** * Returns the smallest i such that 0 <= i <= size and sumUntil(i) < t, or * -1 if no such i exists. */ greatestStrictLowerBound: function (t) { if (t <= 0) { return -1; } var node = 1; if (this._heap[node] < t) { return this._size; } while (node < this._half) { var leftSum = this._heap[2 * node]; if (t <= leftSum) { node = 2 * node; } else { node = 2 * node + 1; t -= leftSum; } } return node - this._half; }, /** * Returns the smallest i such that 0 <= i <= size and t <= sumUntil(i), or * size + 1 if no such i exists. */ leastUpperBound: function (t) { return this.greatestStrictLowerBound(t) + 1; }, /** * Returns the smallest i such that 0 <= i <= size and t < sumUntil(i), or * size + 1 if no such i exists. */ leastStrictUpperBound: function (t) { return this.greatestLowerBound(t) + 1; } }; BI.PrefixIntervalTree.uniform = function (size, initialValue) { var xs = []; for (var i = size - 1; i >= 0; --i) { xs[i] = initialValue; } return new BI.PrefixIntervalTree(xs); }; BI.PrefixIntervalTree.empty = function (size) { return BI.PrefixIntervalTree.uniform(size, 0); }; })(); ; !(function () { BI.Queue = function (capacity) { this.capacity = capacity; this.array = []; }; BI.Queue.prototype = { constructor: BI.Queue, contains: function (v) { return this.array.contains(v); }, indexOf: function (v) { return this.array.contains(v); }, getElementByIndex: function(index) { return this.array[index]; }, push: function (v) { this.array.push(v); if (this.capacity && this.array.length > this.capacity) { this.array.shift(); } }, pop: function () { this.array.pop(); }, shift: function () { this.array.shift(); }, unshift: function (v) { this.array.unshift(v); if (this.capacity && this.array.length > this.capacity) { this.array.pop(); } }, remove: function (v) { this.array.remove(v); }, splice: function() { this.array.splice.apply(this.array, arguments); }, slice: function() { this.array.slice.apply(this.array, arguments); }, size: function () { return this.array.length; }, each: function (fn, scope) { var scope = scope || window; var fn = fn || null; if (fn == null || typeof (fn) != "function") { return; } for (var i = 0; i < this.array.length; i++) { var re = fn.call(scope, i, this.array[i], this.array); if (re == false) { break; } } }, toArray: function () { return this.array; }, fromArray: function (array) { var self = this; BI.each(array, function (i, v) { self.push(v); }) }, clear: function () { this.array.clear(); } } })();!(function () { var Section = function (height, width, x, y) { this.height = height; this.width = width; this.x = x; this.y = y; this._indexMap = {}; this._indices = []; }; Section.prototype = { constructor: Section, addCellIndex: function (index) { if (!this._indexMap[index]) { this._indexMap[index] = true; this._indices.push(index); } }, getCellIndices: function () { return this._indices } }; var SECTION_SIZE = 100; BI.SectionManager = function (sectionSize) { this._sectionSize = sectionSize || SECTION_SIZE; this._cellMetadata = []; this._sections = {}; }; BI.SectionManager.prototype = { constructor: BI.SectionManager, getCellIndices: function (height, width, x, y) { var indices = {}; BI.each(this.getSections(height, width, x, y), function (i, section) { BI.each(section.getCellIndices(), function (j, index) { indices[index] = index }) }); return BI.map(BI.keys(indices), function (i, index) { return indices[index] }); }, getCellMetadata: function (index) { return this._cellMetadata[index]; }, getSections: function (height, width, x, y) { var sectionXStart = Math.floor(x / this._sectionSize); var sectionXStop = Math.floor((x + width - 1) / this._sectionSize); var sectionYStart = Math.floor(y / this._sectionSize); var sectionYStop = Math.floor((y + height - 1) / this._sectionSize); var sections = []; for (var sectionX = sectionXStart; sectionX <= sectionXStop; sectionX++) { for (var sectionY = sectionYStart; sectionY <= sectionYStop; sectionY++) { var key = sectionX + "." + sectionY; if (!this._sections[key]) { this._sections[key] = new Section(this._sectionSize, this._sectionSize, sectionX * this._sectionSize, sectionY * this._sectionSize) } sections.push(this._sections[key]) } } return sections }, getTotalSectionCount: function () { return BI.size(this._sections); }, registerCell: function (cellMetadatum, index) { this._cellMetadata[index] = cellMetadatum; BI.each(this.getSections(cellMetadatum.height, cellMetadatum.width, cellMetadatum.x, cellMetadatum.y), function (i, section) { section.addCellIndex(index); }); } } })();; (function () { var clamp = function (value, min, max) { if (value < min) { return min; } if (value > max) { return max; } return value; }; var MIN_BUFFER_ROWS = 6; var MAX_BUFFER_ROWS = 10; BI.TableRowBuffer = function (rowsCount, defaultRowHeight, viewportHeight, rowHeightGetter) { this._bufferSet = new BI.IntegerBufferSet(); this._defaultRowHeight = defaultRowHeight; this._viewportRowsBegin = 0; this._viewportRowsEnd = 0; this._maxVisibleRowCount = Math.ceil(viewportHeight / defaultRowHeight) + 1; // this._bufferRowsCount = Math.floor(this._maxVisibleRowCount / 2); this._bufferRowsCount = clamp( Math.floor(this._maxVisibleRowCount / 2), MIN_BUFFER_ROWS, MAX_BUFFER_ROWS ); this._rowsCount = rowsCount; this._rowHeightGetter = rowHeightGetter; this._rows = []; this._viewportHeight = viewportHeight; }; BI.TableRowBuffer.prototype = { constructor: BI.TableRowBuffer, getRowsWithUpdatedBuffer: function () { var remainingBufferRows = 2 * this._bufferRowsCount; var bufferRowIndex = Math.max(this._viewportRowsBegin - this._bufferRowsCount, 0); while (bufferRowIndex < this._viewportRowsBegin) { this._addRowToBuffer( bufferRowIndex, this._viewportRowsBegin, this._viewportRowsEnd - 1 ); bufferRowIndex++; remainingBufferRows--; } bufferRowIndex = this._viewportRowsEnd; while (bufferRowIndex < this._rowsCount && remainingBufferRows > 0) { this._addRowToBuffer( bufferRowIndex, this._viewportRowsBegin, this._viewportRowsEnd - 1 ); bufferRowIndex++; remainingBufferRows--; } return this._rows; }, getRows: function (firstRowIndex, firstRowOffset) { var top = firstRowOffset; var totalHeight = top; var rowIndex = firstRowIndex; var endIndex = Math.min(firstRowIndex + this._maxVisibleRowCount, this._rowsCount); this._viewportRowsBegin = firstRowIndex; while (rowIndex < endIndex || (totalHeight < this._viewportHeight && rowIndex < this._rowsCount)) { this._addRowToBuffer( rowIndex, firstRowIndex, endIndex - 1 ); totalHeight += this._rowHeightGetter(rowIndex); ++rowIndex; // Store index after the last viewport row as end, to be able to // distinguish when there are no rows rendered in viewport this._viewportRowsEnd = rowIndex; } return this._rows; }, _addRowToBuffer: function (rowIndex, firstViewportRowIndex, lastViewportRowIndex) { var rowPosition = this._bufferSet.getValuePosition(rowIndex); var viewportRowsCount = lastViewportRowIndex - firstViewportRowIndex + 1; var allowedRowsCount = viewportRowsCount + this._bufferRowsCount * 2; if (rowPosition === null && this._bufferSet.getSize() >= allowedRowsCount) { rowPosition = this._bufferSet.replaceFurthestValuePosition( firstViewportRowIndex, lastViewportRowIndex, rowIndex ); } if (rowPosition === null) { // We can't reuse any of existing positions for this row. We have to // create new position rowPosition = this._bufferSet.getNewPositionForValue(rowIndex); this._rows[rowPosition] = rowIndex; } else { // This row already is in the table with rowPosition position or it // can replace row that is in that position this._rows[rowPosition] = rowIndex; } } } })(); ; (function () { BI.Tree = function () { this.root = new BI.Node(BI.UUID()); }; BI.Tree.prototype = { constructor: BI.Tree, addNode: function (node, newNode, index) { if (BI.isNull(newNode)) { this.root.addChild(node, index); } else if (BI.isNull(node)) { this.root.addChild(newNode, index); } else { node.addChild(newNode, index); } }, isRoot: function (node) { return node === this.root; }, getRoot: function () { return this.root; }, clear: function () { this.root.clear(); }, initTree: function (nodes) { var self = this; this.clear(); var queue = []; BI.each(nodes, function (i, node) { var n = new BI.Node(node); n.set("data", node); self.addNode(n); queue.push(n); }); while (!BI.isEmpty(queue)) { var parent = queue.shift(); var node = parent.get("data"); BI.each(node.children, function (i, child) { var n = new BI.Node(child); n.set("data", child); queue.push(n); self.addNode(parent, n); }) } }, _toJSON: function (node) { var self = this; var children = []; BI.each(node.getChildren(), function (i, child) { children.push(self._toJSON(child)); }); return BI.extend({ id: node.id }, BI.deepClone(node.get("data")), (children.length > 0 ? { children: children } : {})); }, toJSON: function (node) { var self = this, result = []; BI.each((node || this.root).getChildren(), function (i, child) { result.push(self._toJSON(child)); }); return result; }, _toJSONWithNode: function (node) { var self = this; var children = []; BI.each(node.getChildren(), function (i, child) { children.push(self._toJSONWithNode(child)); }); return BI.extend({ id: node.id }, BI.deepClone(node.get("data")), { node: node }, (children.length > 0 ? { children: children } : {})); }, toJSONWithNode: function (node) { var self = this, result = []; BI.each((node || this.root).getChildren(), function (i, child) { result.push(self._toJSONWithNode(child)); }); return result; }, search: function (root, target, param) { if (!(root instanceof BI.Node)) { return arguments.callee.apply(this, [this.root, root, target]); } var self = this, next = null; if (BI.isNull(target)) { return null; } if (BI.isEqual(root[param || "id"], target)) { return root; } BI.any(root.getChildren(), function (i, child) { next = self.search(child, target, param); if (null !== next) { return true; } }); return next; }, _traverse: function (node, callback) { var queue = []; queue.push(node); while (!BI.isEmpty(queue)) { var temp = queue.shift(); var b = callback && callback(temp); if (b === false) { break; } if (b === true) { continue; } if (temp != null) { queue = queue.concat(temp.getChildren()); } } }, traverse: function (callback) { this._traverse(this.root, callback); }, _recursion: function (node, route, callback) { var self = this; return BI.every(node.getChildren(), function (i, child) { var next = BI.clone(route); next.push(child.id); var b = callback && callback(child, next); if (b === false) { return false; } if (b === true) { return true; } return self._recursion(child, next, callback); }); }, recursion: function (callback) { this._recursion(this.root, [], callback); }, inOrderTraverse: function (callback) { this._inOrderTraverse(this.root, callback); }, //中序遍历(递归) _inOrderTraverse: function (node, callback) { if (node != null) { this._inOrderTraverse(node.getLeft()); callback && callback(node); this._inOrderTraverse(node.getRight()); } }, //中序遍历(非递归) nrInOrderTraverse: function (callback) { var stack = []; var node = this.root; while (node != null || !BI.isEmpty(stack)) { while (node != null) { stack.push(node); node = node.getLeft(); } node = stack.pop(); callback && callback(node); node = node.getRight(); } }, preOrderTraverse: function (callback) { this._preOrderTraverse(this.root, callback); }, //先序遍历(递归) _preOrderTraverse: function (node, callback) { if (node != null) { callback && callback(node); this._preOrderTraverse(node.getLeft()); this._preOrderTraverse(node.getRight()); } }, //先序遍历(非递归) nrPreOrderTraverse: function (callback) { var stack = []; var node = this.root; while (node != null || !BI.isEmpty(stack)) { while (node != null) { callback && callback(node); stack.push(node); node = node.getLeft(); } node = stack.pop(); node = node.getRight(); } }, postOrderTraverse: function (callback) { this._postOrderTraverse(this.root, callback); }, //后序遍历(递归) _postOrderTraverse: function (node, callback) { if (node != null) { this._postOrderTraverse(node.getLeft()); this._postOrderTraverse(node.getRight()); callback && callback(node); } }, //后续遍历(非递归) nrPostOrderTraverse: function (callback) { var stack = []; var node = this.root; var preNode = null;//表示最近一次访问的节点 while (node != null || !BI.isEmpty(stack)) { while (node != null) { stack.push(node); node = node.getLeft(); } node = BI.last(stack); if (node.getRight() == null || node.getRight() == preNode) { callback && callback(node); node = stack.pop(); preNode = node; node = null; } else { node = node.getRight(); } } } }; BI.Node = function (id) { if (BI.isObject(id)) { BI.extend(this, id); } else { this.id = id; } this.clear.apply(this, arguments); }; BI.Node.prototype = { constructor: BI.Node, set: function (key, value) { if (BI.isObject(key)) { BI.extend(this, key); return; } this[key] = value; }, get: function (key) { return this[key]; }, isLeaf: function () { return BI.isEmpty(this.children); }, getChildren: function () { return this.children; }, getChildrenLength: function () { return this.children.length; }, getFirstChild: function () { return BI.first(this.children); }, getLastChild: function () { return BI.last(this.children); }, setLeft: function (left) { this.left = left; }, getLeft: function () { return this.left; }, setRight: function (right) { this.right = right; }, getRight: function () { return this.right; }, setParent: function (parent) { this.parent = parent; }, getParent: function () { return this.parent; }, getChild: function (index) { return this.children[index]; }, getChildIndex: function (id) { return BI.findIndex(this.children, function (i, ch) { return ch.get("id") === id; }); }, removeChild: function (id) { this.removeChildByIndex(this.getChildIndex(id)); }, removeChildByIndex: function (index) { var before = this.getChild(index - 1); var behind = this.getChild(index + 1); if (before != null) { before.setRight(behind || null); } if (behind != null) { behind.setLeft(before || null); } this.children.splice(index, 1); }, removeAllChilds: function () { this.children = []; }, addChild: function (child, index) { var cur = null; if (BI.isUndefined(index)) { cur = this.children.length - 1; } else { cur = index - 1; } child.setParent(this); if (cur >= 0) { this.getChild(cur).setRight(child); child.setLeft(this.getChild(cur)); } if (BI.isUndefined(index)) { this.children.push(child); } else { this.children.splice(index, 0, child); } }, equals: function (obj) { return this === obj || this.id === obj.id; }, clear: function () { this.parent = null; this.left = null; this.right = null; this.children = []; } }; BI.extend(BI.Tree, { transformToArrayFormat: function (nodes, pId) { if (!nodes) return []; var r = []; if (BI.isArray(nodes)) { for (var i = 0, l = nodes.length; i < l; i++) { var node = BI.clone(nodes[i]); node.pId = node.pId == null ? pId : node.pId; delete node.children; r.push(node); if (nodes[i]["children"]) { r = r.concat(BI.Tree.transformToArrayFormat(nodes[i]["children"], node.id)); } } } else { var newNodes = BI.clone(nodes); newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; delete newNodes.children; r.push(newNodes); if (nodes["children"]) { r = r.concat(BI.Tree.transformToArrayFormat(nodes["children"], newNodes.id)); } } return r; }, arrayFormat: function (nodes, pId) { if (!nodes) { return []; } var r = []; if (BI.isArray(nodes)) { for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; node.pId = node.pId == null ? pId : node.pId; r.push(node); if (nodes[i]["children"]) { r = r.concat(BI.Tree.arrayFormat(nodes[i]["children"], node.id)); } } } else { var newNodes = nodes; newNodes.pId = newNodes.pId == null ? pId : newNodes.pId; r.push(newNodes); if (nodes["children"]) { r = r.concat(BI.Tree.arrayFormat(nodes["children"], newNodes.id)); } } return r; }, transformToTreeFormat: function (sNodes) { var i, l; if (!sNodes) { return []; } if (BI.isArray(sNodes)) { var r = []; var tmpMap = []; for (i = 0, l = sNodes.length; i < l; i++) { if (BI.isNull(sNodes[i].id)) { return sNodes; } tmpMap[sNodes[i].id] = BI.clone(sNodes[i]); } for (i = 0, l = sNodes.length; i < l; i++) { if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { if (!tmpMap[sNodes[i].pId].children) { tmpMap[sNodes[i].pId].children = []; } tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]); } else { r.push(tmpMap[sNodes[i].id]); } delete tmpMap[sNodes[i].id].pId; } return r; } else { return [sNodes]; } }, treeFormat: function (sNodes) { var i, l; if (!sNodes) { return []; } if (BI.isArray(sNodes)) { var r = []; var tmpMap = []; for (i = 0, l = sNodes.length; i < l; i++) { if (BI.isNull(sNodes[i].id)) { return sNodes; } tmpMap[sNodes[i].id] = sNodes[i]; } for (i = 0, l = sNodes.length; i < l; i++) { if (tmpMap[sNodes[i].pId] && sNodes[i].id !== sNodes[i].pId) { if (!tmpMap[sNodes[i].pId].children) { tmpMap[sNodes[i].pId].children = []; } tmpMap[sNodes[i].pId].children.push(tmpMap[sNodes[i].id]); } else { r.push(tmpMap[sNodes[i].id]); } } return r; } else { return [sNodes]; } }, traversal: function (array, callback) { if (BI.isNull(array)) { return; } var self = this; BI.any(array, function (i, item) { if (callback(i, item) === false) { return true; } self.traversal(item.children, callback); }) } }) })();//向量操作 BI.Vector = function (x, y) { this.x = x; this.y = y; }; BI.Vector.prototype = { constructor: BI.Vector, cross: function (v) { return (this.x * v.y - this.y * v.x); }, length: function (v) { return (Math.sqrt(this.x * v.x + this.y * v.y)); } }; BI.Region = function (x, y, w, h) { this.x = x; this.y = y; this.w = w; this.h = h; }; BI.Region.prototype = { constructor: BI.Region, //判断两个区域是否相交,若相交,则要么顶点互相包含,要么矩形边界(或对角线)相交 isIntersects: function (obj) { if (this.isPointInside(obj.x, obj.y) || this.isPointInside(obj.x + obj.w, obj.y) || this.isPointInside(obj.x, obj.y + obj.h) || this.isPointInside(obj.x + obj.w, obj.y + obj.h)) { return true; } else if (obj.isPointInside(this.x, this.y) || obj.isPointInside(this.x + this.w, this.y) || obj.isPointInside(this.x, this.y + this.h) || obj.isPointInside(this.x + this.w, this.y + this.h)) { return true; } else if (obj.x != null && obj.y != null)//判断矩形对角线相交 |v1 X v2||v1 X v3| < 0 { var vector1 = new BI.Vector(this.w, this.h);//矩形对角线向量 var vector2 = new BI.Vector(obj.x - this.x, obj.y - this.y); var vector3 = new BI.Vector(vector2.x + obj.w, vector2.y + obj.h); if ((vector1.cross(vector2) * vector1.cross(vector3)) < 0) { return true; } } return false; }, //判断一个点是否在这个区域内部 isPointInside: function (x, y) { if (this.x == null || this.y == null) { return false; } if (x >= this.x && x <= this.x + this.w && y >= this.y && y <= this.y + this.h) { return true; } return false; }, //返回区域的重心,因为是矩形所以返回中点 getPosition: function () { var pos = []; pos.push(this.x + this.w / 2); pos.push(this.y + this.h / 2); return pos; } };// ; // !(function (BI) { // // if (BI.isIE()) { // XMLSerializer = null; // DOMParser = null; // } // // // var XML = { // Document: { // NodeType: { // ELEMENT: 1, // ATTRIBUTE: 2, // TEXT: 3, // CDATA_SECTION: 4, // ENTITY_REFERENCE: 5, // ENTITY: 6, // PROCESSING_INSTRUCTION: 7, // COMMENT: 8, // DOCUMENT: 9, // DOCUMENT_TYPE: 10, // DOCUMENT_FRAGMENT: 11, // NOTATION: 12 // } // } // }; // // XML.ResultType = { // single: 'single', // array: 'array' // }; // // XML.fromString = function (xmlStr) { // try { // var parser = new DOMParser(); // return parser.parseFromString(xmlStr, "text/xml"); // } catch (e) { // var arrMSXML = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.3.0"]; // for (var i = 0; i < arrMSXML.length; i++) { // try { // var xmlDoc = new ActiveXObject(arrMSXML[i]); // xmlDoc.setProperty("SelectionLanguage", "XPath"); // xmlDoc.async = false; // xmlDoc.loadXML(xmlStr); // return xmlDoc; // } catch (xmlError) { // } // } // } // }; // // XML.toString = function (xmlNode) { // if (!BI.isIE()) { // var xmlSerializer = new XMLSerializer(); // return xmlSerializer.serializeToString(xmlNode); // } else // return xmlNode.xml; // }; // // XML.getNSResolver = function (str) { // if (!str) { // return null; // } // var list = str.split(' '); // var namespaces = {}; // for (var i = 0; i < list.length; i++) { // var pair = list[i].split('='); // var fix = BI.trim(pair[0]).replace("xmlns:", ""); // namespaces[fix] = BI.trim(pair[1]).replace(/"/g, "").replace(/'/g, ""); // } // return function (prefix) { // return namespaces[prefix]; // }; // }; // // XML.eval = function (context, xpathExp, resultType, namespaces) { // if ((BI.isIE() && ('undefined' === typeof(context.selectSingleNode) || 'undefined' === typeof(context.selectNodes)))) { // return XML.eval2(context, xpathExp, resultType, namespaces); // } else { // if (BI.isIE()) { // namespaces = namespaces ? namespaces : ""; // var doc = (context.nodeType == XML.Document.NodeType.DOCUMENT) ? context : context.ownerDocument; // doc.setProperty("SelectionNamespaces", namespaces); // var result; // if (resultType == this.ResultType.single) { // result = context.selectSingleNode(xpathExp); // } else { // result = context.selectNodes(xpathExp) || []; // } // doc.setProperty("SelectionNamespaces", ""); // return result; // } else { // var node = context; // var xmlDoc = (context.nodeName.indexOf("document") == -1) ? context.ownerDocument : context; // var retType = (resultType == this.ResultType.single) ? XPathResult.FIRST_ORDERED_NODE_TYPE : XPathResult.ANY_TYPE; // var col = xmlDoc.evaluate(xpathExp, node, XML.getNSResolver(namespaces), retType, null); // // if (retType == XPathResult.FIRST_ORDERED_NODE_TYPE) { // return col.singleNodeValue; // } else { // var thisColMemb = col.iterateNext(); // var rowsCol = []; // while (thisColMemb) { // rowsCol[rowsCol.length] = thisColMemb; // thisColMemb = col.iterateNext(); // } // return rowsCol; // } // } // } // }; // // XML.eval2 = function (context, xpathExp, resultType, namespaces) { // if (resultType !== "single" && resultType !== undefined && resultType !== null) { // throw new Error("justep.SimpleXML.eval only be resultType='single', not" + resultType); // } // // if (context === null || context === undefined || xpathExp === null || xpathExp === undefined) { // return context; // } // // if (context.nodeType == XML.Document.NodeType.DOCUMENT) { // context = context.documentElement; // } // // var childs, i; // if (xpathExp.indexOf("/") != -1) { // var items = xpathExp.split("/"); // var isAbs = xpathExp.substring(0, 1) == "/"; // for (i = 0; i < items.length; i++) { // var item = items[i]; // if (item === "") { // continue; // } else { // var next = null; // var ii = i + 1; // for (; ii < items.length; ii++) { // if (next === null) { // next = items[ii]; // } else { // next = next + "/" + items[ii]; // } // } // // if (item == ".") { // return this.eval(context, next, resultType); // // } else if (item == "..") { // return this.eval2(context.parentNode, next, resultType); // // } else if (item == "*") { // if (isAbs) { // return this.eval2(context, next, resultType); // // } else { // childs = context.childNodes; // for (var j = 0; j < childs.length; j++) { // var tmp = this.eval2(childs[j], next, resultType); // if (tmp !== null) { // return tmp; // } // } // return null; // } // // } else { // if (isAbs) { // if (context.nodeName == item) { // return this.eval2(context, next, resultType); // } else { // return null; // } // } else { // var child = this.getChildByName(context, item); // if (child !== null) { // return this.eval2(child, next, resultType); // } else { // return null; // } // // } // } // // } // } // // return null; // // } else { // if ("text()" == xpathExp) { // childs = context.childNodes; // for (i = 0; i < childs.length; i++) { // if (childs[i].nodeType == XML.Document.NodeType.TEXT) { // return childs[i]; // } // } // return null; // } else { // return this.getChildByName(context, xpathExp); // } // } // }; // // XML.getChildByName = function (context, name) { // if (context === null || context === undefined || name === null || name === undefined) { // return null; // } // // if (context.nodeType == XML.Document.NodeType.DOCUMENT) { // context = context.documentElement; // } // // var childs = context.childNodes; // for (var i = 0; i < childs.length; i++) { // if (childs[i].nodeType == XML.Document.NodeType.ELEMENT && (childs[i].nodeName == name || name == "*")) { // return childs[i]; // } // } // // return null; // }; // // XML.appendChildren = function (context, xpathExp, nodes, isBefore) { // nodes = (typeof nodes.length != "undefined") ? nodes : [nodes]; // var finded = this.eval(context, xpathExp); // var count = finded.length; // for (var i = 0; i < count; i++) { // if (isBefore && finded[i].firstNode) { // this._insertBefore(finded[i], nodes, finded[i].firstNode); // } else { // for (var j = 0; j < nodes.length; j++) { // finded[i].appendChild(nodes[j]); // } // } // } // return count; // }; // // XML.removeNodes = function (context, xpathExp) { // var nodes = this.eval(context, xpathExp); // for (var i = 0; i < nodes.length; i++) { // nodes[i].parentNode.removeChild(nodes[i]); // } // }; // // XML._insertBefore = function (parent, newchildren, refchild) { // for (var i = 0; i < newchildren.length; i++) { // parent.insertBefore(newchildren[i], refchild); // } // }; // // XML.insertNodes = function (context, xpathExp, nodes, isBefore) { // nodes = (typeof nodes.length != "undefined") ? nodes : [nodes]; // var finded = this.eval(context, xpathExp); // var count = finded.length; // for (var i = 0; i < count; i++) { // var refnode = (isBefore) ? finded[i] : finded[i].nextSibling; // this._insertBefore(finded[i].parentNode, nodes, refnode); // } // return count; // }; // // XML.replaceNodes = function (context, xpathExp, nodes) { // nodes = (typeof nodes.length != "undefined") ? nodes : [nodes]; // var finded = this.eval(context, xpathExp); // var count = finded.length; // for (var i = 0; i < count; i++) { // var refnode = finded[i]; // var parent = refnode.parentNode; // this._insertBefore(parent, nodes, refnode); // parent.removeChild(refnode); // } // return count; // }; // // XML.setNodeText = function (context, xpathExp, text) { // var finded = this.eval(context, xpathExp, this.ResultType.single); // if (finded === null) { // return; // } // if (finded.nodeType == XML.Document.NodeType.ELEMENT) { // var textNode = this.eval(finded, "./text()", this.ResultType.single); // if (!textNode) { // textNode = finded.ownerDocument.createTextNode(""); // finded.appendChild(textNode); // } // textNode.nodeValue = text; // } else { // finded.nodeValue = text; // } // return; // }; // // XML.getNodeText = function (context, xpathExp, defaultValue) { // var finded = xpathExp ? this.eval(context, xpathExp, this.ResultType.single) : context; // if (finded && (finded.nodeType == XML.Document.NodeType.ELEMENT)) { // finded = this.eval(finded, "./text()", this.ResultType.single); // } // return (finded && finded.nodeValue) ? "" + finded.nodeValue : (defaultValue !== undefined) ? defaultValue : null; // }; // // XML.Namespaces = { // XMLSCHEMA: "http://www.w3.org/2001/XMLSchema#", // XMLSCHEMA_STRING: "http://www.w3.org/2001/XMLSchema#String", // XMLSCHEMA_LONG: "http://www.w3.org/2001/XMLSchema#Long", // XMLSCHEMA_INTEGER: 'http://www.w3.org/2001/XMLSchema#Integer', // XMLSCHEMA_FLOAT: 'http://www.w3.org/2001/XMLSchema#Float', // XMLSCHEMA_DOUBLE: 'http://www.w3.org/2001/XMLSchema#Double', // XMLSCHEMA_DECIMAL: 'http://www.w3.org/2001/XMLSchema#Decimal', // XMLSCHEMA_DATE: 'http://www.w3.org/2001/XMLSchema#Date', // XMLSCHEMA_TIME: 'http://www.w3.org/2001/XMLSchema#Time', // XMLSCHEMA_DATETIME: 'http://www.w3.org/2001/XMLSchema#DateTime', // XMLSCHEMA_BOOLEAN: 'http://www.w3.org/2001/XMLSchema#Boolean', // XMLSCHEMA_SYMBOL: 'http://www.w3.org/2001/XMLSchema#Symbol', // JUSTEPSCHEMA: "http://www.justep.com/xbiz#", // RDF: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", // JUSTEP: "http://www.justep.com/x5#", // 'get': function (type) { // type = type ? type.toLowerCase() : "string"; // if ("string" == type) { // return XML.Namespaces.XMLSCHEMA_STRING; // } // else if ("integer" == type) { // return XML.Namespaces.XMLSCHEMA_INTEGER; // } // else if ("long" == type) { // return XML.Namespaces.XMLSCHEMA_LONG; // } // else if ("float" == type) { // return XML.Namespaces.XMLSCHEMA_FLOAT; // } // else if ("double" == type) { // return XML.Namespaces.XMLSCHEMA_DOUBLE; // } // else if ("decimal" == type) { // return XML.Namespaces.XMLSCHEMA_DECIMAL; // } // else if ("date" == type) { // return XML.Namespaces.XMLSCHEMA_DATE; // } // else if ("time" == type) { // return XML.Namespaces.XMLSCHEMA_TIME; // } // else if ("datetime" == type) { // return XML.Namespaces.XMLSCHEMA_DATETIME; // } // else if ("boolean" == type) { // return XML.Namespaces.XMLSCHEMA_BOOLEAN; // } // } // }; // })(BI); BI.BehaviorFactory = { createBehavior: function(key, options){ var behavior; switch (key){ case "highlight": behavior = BI.HighlightBehavior; break; case "redmark": behavior = BI.RedMarkBehavior; break; } return new behavior(options); } } /** * guy * 行为控件 * @class BI.Behavior * @extends BI.OB */ BI.Behavior = BI.inherit(BI.OB, { _defaultConfig: function() { return BI.extend(BI.Behavior.superclass._defaultConfig.apply(this, arguments), { rule: function(){return true;} }); }, _init : function() { BI.Behavior.superclass._init.apply(this, arguments); }, doBehavior: function(){ } });/** * 布局容器类 * @class BI.Layout * @extends BI.Widget * * @cfg {JSON} options 配置属性 * @cfg {Boolean} [options.scrollable=false] 子组件超出容器边界之后是否会出现滚动条 * @cfg {Boolean} [options.scrollx=false] 子组件超出容器边界之后是否会出现横向滚动条 * @cfg {Boolean} [options.scrolly=false] 子组件超出容器边界之后是否会出现纵向滚动条 */ BI.Layout = BI.inherit(BI.Widget, { props: function () { return { scrollable: null, //true, false, null scrollx: false, //true, false scrolly: false, //true, false items: [] }; }, render: function () { this._init4Margin(); this._init4Scroll(); }, _init4Margin: function () { if (this.options.top) { this.element.css('top', this.options.top); } if (this.options.left) { this.element.css('left', this.options.left); } if (this.options.bottom) { this.element.css('bottom', this.options.bottom); } if (this.options.right) { this.element.css('right', this.options.right); } }, _init4Scroll: function () { switch (this.options.scrollable) { case true: this.element.css("overflow", "auto"); break; case false: this.element.css("overflow", "hidden"); break; default : break; } if (this.options.scrollx) { this.element.css({ "overflow-x": "auto", "overflow-y": "hidden" }); } if (this.options.scrolly) { this.element.css({ "overflow-x": "hidden", "overflow-y": "auto" }); } }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.element.append(frag); } }, _getChildName: function (index) { return index + ""; }, _addElement: function (i, item) { var self = this, w; if (!this.hasWidget(this._getChildName(i))) { w = BI.createWidget(item); w.on(BI.Events.DESTROY, function () { BI.each(self._children, function (name, child) { if (child === w) { BI.remove(self._children, child); self.removeItemAt(name | 0); } }); }); this.addWidget(this._getChildName(i), w); } else { w = this.getWidgetByName(this._getChildName(i)); } return w; }, _getOptions: function (item) { if (item instanceof BI.Widget) { item = item.options; } item = BI.stripEL(item); if (item instanceof BI.Widget) { item = item.options; } return item; }, _compare: function (item1, item2) { var self = this; return eq(item1, item2); //不比较函数 function eq(a, b, aStack, bStack) { if (a === b) { return a !== 0 || 1 / a === 1 / b; } if (a == null || b == null) { return a === b; } var className = Object.prototype.toString.call(a); switch (className) { case '[object RegExp]': case '[object String]': return '' + a === '' + b; case '[object Number]': if (+a !== +a) { return +b !== +b; } return +a === 0 ? 1 / +a === 1 / b : +a === +b; case '[object Date]': case '[object Boolean]': return +a === +b; } var areArrays = className === '[object Array]'; if (!areArrays) { if (BI.isFunction(a) && BI.isFunction(b)) { return true; } a = self._getOptions(a); b = self._getOptions(b); } aStack = aStack || []; bStack = bStack || []; var length = aStack.length; while (length--) { if (aStack[length] === a) { return bStack[length] === b; } } aStack.push(a); bStack.push(b); if (areArrays) { length = a.length; if (length !== b.length) { return false; } while (length--) { if (!eq(a[length], b[length], aStack, bStack)) { return false; } } } else { var keys = _.keys(a), key; length = keys.length; if (_.keys(b).length !== length) { return false; } while (length--) { key = keys[length]; if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) { return false; } } } aStack.pop(); bStack.pop(); return true; } }, _getWrapper: function () { return this.element; }, _addItemAt: function (index, item) { for (var i = this.options.items.length; i > index; i--) { this._children[this._getChildName(i)] = this._children[this._getChildName(i - 1)]; } delete this._children[this._getChildName(index)]; this.options.items.splice(index, 0, item); }, _removeItemAt: function (index) { for (var i = index; i < this.options.items.length - 1; i++) { this._children[this._getChildName(i)] = this._children[this._getChildName(i + 1)]; } delete this._children[this._getChildName(this.options.items.length - 1)]; this.options.items.splice(index, 1); }, /** * 添加一个子组件到容器中 * @param {JSON/BI.Widget} item 子组件 */ addItem: function (item) { return this.addItemAt(this.options.items.length, item); }, prependItem: function (item) { return this.addItemAt(0, item); }, addItemAt: function (index, item) { if (index < 0 || index > this.options.items.length) { return; } this._addItemAt(index, item); var w = this._addElement(index, item); if (index > 0) { this._children[this._getChildName(index - 1)].element.after(w.element); } else { w.element.prependTo(this._getWrapper()); } w._mount(); return w; }, removeItemAt: function (indexes) { indexes = BI.isArray(indexes) ? indexes : [indexes]; var deleted = []; var newItems = [], newChildren = {}; for (var i = 0, len = this.options.items.length; i < len; i++) { var child = this._children[this._getChildName(i)]; if (indexes.contains(i)) { child && deleted.push(child); } else { newChildren[this._getChildName(newItems.length)] = child; newItems.push(this.options.items[i]); } } this.options.items = newItems; this._children = newChildren; BI.each(deleted, function (i, c) { c._destroy(); }); }, updateItemAt: function (index, item) { if (index < 0 || index > this.options.items.length - 1) { return; } var child = this._children[this._getChildName(index)]; var updated; if (updated = child.update(this._getOptions(item))) { return updated; } var del = this._children[this._getChildName(index)]; delete this._children[this._getChildName(index)]; this.options.items.splice(index, 1); var w = this._addElement(index, item); this.options.items.splice(index, 0, item); this._children[this._getChildName(index)] = w; if (index > 0) { this._children[this._getChildName(index - 1)].element.after(w.element); } else { w.element.prependTo(this._getWrapper()); } del._destroy(); w._mount(); }, addItems: function (items) { var self = this, o = this.options; var fragment = document.createDocumentFragment(); var added = []; BI.each(items, function (i, item) { var w = self._addElement(o.items.length, item); self._children[self._getChildName(o.items.length)] = w; o.items.push(item); added.push(w); fragment.appendChild(w.element[0]); }); this._getWrapper().append(fragment); BI.each(added, function (i, w) { w._mount(); }) }, prependItems: function (items) { var self = this; items = items || []; var fragment = document.createDocumentFragment(); var added = []; for (var i = items.length - 1; i >= 0; i--) { this._addItemAt(0, items[i]); var w = this._addElement(0, items[i]); self._children[self._getChildName(0)] = w; this.options.items.unshift(items[i]); added.push(w); fragment.appendChild(w.element[0]); } this._getWrapper().prepend(fragment); BI.each(added, function (i, w) { w._mount(); }) }, getValue: function () { var self = this, value = [], child; BI.each(this.options.items, function (i) { if (child = self._children[self._getChildName(i)]) { var v = child.getValue(); v = BI.isArray(v) ? v : [v]; value = value.concat(v); } }); return value; }, setValue: function (v) { var self = this, child; BI.each(this.options.items, function (i) { if (child = self._children[self._getChildName(i)]) { child.setValue(v); } }) }, setText: function (v) { var self = this, child; BI.each(this.options.items, function (i) { if (child = self._children[self._getChildName(i)]) { child.setText(v); } }) }, update: function (item) { var o = this.options; var items = item.items || []; var updated, i, len; for (i = 0, len = Math.min(o.items.length, items.length); i < len; i++) { if (!this._compare(o.items[i], items[i])) { updated = this.updateItemAt(i, items[i]) || updated; } } if (o.items.length > items.length) { var deleted = []; for (i = items.length; i < o.items.length; i++) { deleted.push(this._children[this._getChildName(i)]); delete this._children[this._getChildName(i)]; } o.items.splice(items.length); BI.each(deleted, function (i, w) { w._destroy(); }) } else if (items.length > o.items.length) { for (i = o.items.length; i < items.length; i++) { this.addItemAt(i, items[i]); } } return updated; }, stroke: function (items) { var self = this; BI.each(items, function (i, item) { if (!!item) { self._addElement(i, item); } }); }, removeWidget: function (nameOrWidget) { var removeIndex; if (BI.isWidget(nameOrWidget)) { BI.each(this._children, function (name, child) { if (child === nameOrWidget) { removeIndex = name; } }) } else { removeIndex = nameOrWidget; } if (removeIndex) { this._removeItemAt(removeIndex | 0); } }, empty: function () { BI.Layout.superclass.empty.apply(this, arguments); this.options.items = []; }, destroy: function () { BI.Layout.superclass.destroy.apply(this, arguments); this.options.items = []; }, populate: function (items) { var self = this, o = this.options; items = items || []; if (this._isMounted) { this.update({items: items}); return; } this.options.items = items; this.stroke(items); }, resize: function () { } }); BI.shortcut('bi.layout', BI.Layout);/** * guy * 由一个元素切换到另一个元素的行为 * @class BI.Action * @extends BI.OB * @abstract */ BI.Action = BI.inherit(BI.OB, { _defaultConfig: function() { return BI.extend(BI.Action.superclass._defaultConfig.apply(this, arguments), { src: null, tar: null }); }, _init : function() { BI.Action.superclass._init.apply(this, arguments); }, actionPerformed: function(src, tar, callback){ }, actionBack: function(tar, src, callback){ } }); BI.ActionFactory = { createAction: function(key, options){ var action; switch (key){ case "show": action = BI.ShowAction; break; } return new action(options); } }/** * guy * 由一个元素切换到另一个元素的行为 * @class BI.ShowAction * @extends BI.Action */ BI.ShowAction = BI.inherit(BI.Action, { _defaultConfig: function () { return BI.extend(BI.ShowAction.superclass._defaultConfig.apply(this, arguments), {}); }, _init: function () { BI.ShowAction.superclass._init.apply(this, arguments); }, actionPerformed: function (src, tar, callback) { tar = tar || this.options.tar; tar.setVisible(true); callback && callback(); }, actionBack: function (tar, src, callback) { tar = tar || this.options.tar; tar.setVisible(false); callback && callback(); } });/** * @class BI.FloatSection * @extends BI.View * @abstract */ BI.FloatSection = BI.inherit(BI.View, { _init : function() { BI.FloatSection.superclass._init.apply(this, arguments); var self = this; var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"]; flatten = BI.makeObject(flatten, true); BI.each(this.constructor.caller.caller.caller.prototype, function (key) { if (flatten[key]) { return; } var f = self[key]; if (BI.isFunction(f)) { self[key] = BI.bind(function () { if (this.model._start === true) { this._F.push({f: f, arg: arguments}); return; } return f.apply(this, arguments); }, self); } }) }, rebuildNorth : function(north) { return true; }, rebuildCenter : function(center) {}, rebuildSouth : function(south) { return false; }, close: function(){ this.notifyParentEnd(); this.trigger(BI.PopoverSection.EVENT_CLOSE); }, end: function(){ } }); /** * 弹出层 * @class BI.PopoverSection * @extends BI.Widget * @abstract */ BI.PopoverSection = BI.inherit(BI.Widget, { _init : function() { BI.PopoverSection.superclass._init.apply(this, arguments); }, rebuildNorth : function(north) { return true; }, rebuildCenter : function(center) {}, rebuildSouth : function(south) { return false; }, close: function(){ this.fireEvent(BI.PopoverSection.EVENT_CLOSE); }, end: function(){ } }); BI.PopoverSection.EVENT_CLOSE = "EVENT_CLOSE";;(function () { if (!window.BI) { window.BI = {}; } function isEmpty(value) { // 判断是否为空值 var result = value === "" || value === null || value === undefined; return result; } // 判断是否是无效的日期 function isInvalidDate(date) { return date == "Invalid Date" || date == "NaN"; } /** * 科学计数格式 */ function _eFormat(text, fmt) { var e = fmt.indexOf("E"); var eleft = fmt.substr(0, e), eright = fmt.substr(e + 1); if (/^[0\.-]+$/.test(text)) { text = BI._numberFormat(0.0, eleft) + 'E' + BI._numberFormat(0, eright) } else { var isNegative = text < 0; if (isNegative) { text = text.substr(1); } var elvl = (eleft.split('.')[0] || '').length; var point = text.indexOf("."); if (point < 0) { point = text.length; } var i = 0; //第一个不为0的数的位置 text = text.replace('.', ''); for (var len = text.length; i < len; i++) { var ech = text.charAt(i); if (ech <= '9' && ech >= '1') { break; } } var right = point - i - elvl; var left = text.substr(i, elvl); var dis = i + elvl - text.length; if (dis > 0) { //末位补全0 for (var k = 0; k < dis; k++) { left += '0'; } } else { left += '.' + text.substr(i + elvl); } left = left.replace(/^[0]+/, ''); if (right < 0 && eright.indexOf('-') < 0) { eright += ';-' + eright; } text = BI._numberFormat(left, eleft) + 'E' + BI._numberFormat(right, eright); if (isNegative) { text = '-' + text; } } return text; } /** * 数字格式 */ function _numberFormat(text, format) { var text = text + ''; //数字格式,区分正负数 var numMod = format.indexOf(';'); if (numMod > -1) { if (text >= 0) { return _numberFormat(text + "", format.substring(0, numMod)); } else { return _numberFormat((-text) + "", format.substr(numMod + 1)); } } else { //兼容格式处理负数的情况(copy:fr-jquery.format.js) if (+text < 0 && format.charAt(0) !== '-') { return _numberFormat((-text) + "", '-' + format); } } var tp = text.split('.'), fp = format.split('.'), tleft = tp[0] || '', fleft = fp[0] || '', tright = tp[1] || '', fright = fp[1] || ''; //百分比,千分比的小数点移位处理 if (/[%‰]$/.test(format)) { var paddingZero = /[%]$/.test(format) ? '00' : '000'; tright += paddingZero; tleft += tright.substr(0, paddingZero.length); tleft = tleft.replace(/^0+/gi, ''); tright = tright.substr(paddingZero.length).replace(/0+$/gi, ''); } var right = _dealWithRight(tright, fright); if (right.leftPlus) { //小数点后有进位 tleft = parseInt(tleft) + 1 + ''; tleft = isNaN(tleft) ? '1' : tleft; } right = right.num; var left = _dealWithLeft(tleft, fleft); if (!(/[0-9]/.test(left))) { left = left + '0'; } if (!(/[0-9]/.test(right))) { return left + right; } else { return left + '.' + right; } } /** * 处理小数点右边小数部分 * @param tright 右边内容 * @param fright 右边格式 * @returns {JSON} 返回处理结果和整数部分是否需要进位 * @private */ function _dealWithRight(tright, fright) { var right = '', j = 0, i = 0; for (var len = fright.length; i < len; i++) { var ch = fright.charAt(i); var c = tright.charAt(j); switch (ch) { case '0': if (isEmpty(c)) { c = '0'; } right += c; j++; break; case '#': right += c; j++; break; default : right += ch; break; } } var rll = tright.substr(j); var result = {}; if (!isEmpty(rll) && rll.charAt(0) > 4) { //有多余字符,需要四舍五入 result.leftPlus = true; var numReg = right.match(/^[0-9]+/); if (numReg) { var num = numReg[0]; var orilen = num.length; var newnum = parseInt(num) + 1 + ''; //进位到整数部分 if (newnum.length > orilen) { newnum = newnum.substr(1); } else { newnum = String.leftPad(newnum, orilen, '0'); result.leftPlus = false; } right = right.replace(/^[0-9]+/, newnum); } } result.num = right; return result; } /** * 处理小数点左边整数部分 * @param tleft 左边内容 * @param fleft 左边格式 * @returns {string} 返回处理结果 * @private */ function _dealWithLeft(tleft, fleft) { var left = ''; var j = tleft.length - 1; var combo = -1, last = -1; var i = fleft.length - 1; for (; i >= 0; i--) { var ch = fleft.charAt(i); var c = tleft.charAt(j); switch (ch) { case '0': if (isEmpty(c)) { c = '0'; } last = -1; left = c + left; j--; break; case '#': last = i; left = c + left; j--; break; case ',': if (!isEmpty(c)) { //计算一个,分隔区间的长度 var com = fleft.match(/,[#0]+/); if (com) { combo = com[0].length - 1; } left = ',' + left; } break; default : left = ch + left; break; } } if (last > -1) { //处理剩余字符 var tll = tleft.substr(0, j + 1); left = left.substr(0, last) + tll + left.substr(last); } if (combo > 0) { //处理,分隔区间 var res = left.match(/[0-9]+,/); if (res) { res = res[0]; var newstr = '', n = res.length - 1 - combo; for (; n >= 0; n = n - combo) { newstr = res.substr(n, combo) + ',' + newstr; } var lres = res.substr(0, n + combo); if (!isEmpty(lres)) { newstr = lres + ',' + newstr; } } left = left.replace(/[0-9]+,/, newstr); } return left; } BI.cjkEncode = function (text) { // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) if (typeof text !== 'string') { return text; } var newText = ""; for (var i = 0; i < text.length; i++) { var code = text.charCodeAt(i); if (code >= 128 || code === 91 || code === 93) {//91 is "[", 93 is "]". newText += "[" + code.toString(16) + "]"; } else { newText += text.charAt(i); } } return newText }; BI.cjkEncodeDO = function (o) { if (BI.isPlainObject(o)) { var result = {}; $.each(o, function (k, v) { if (!(typeof v == "string")) { v = BI.jsonEncode(v); } //wei:bug 43338,如果key是中文,cjkencode后o的长度就加了1,ie9以下版本死循环,所以新建对象result。 k = BI.cjkEncode(k); result[k] = BI.cjkEncode(v); }); return result; } return o; }; BI.jsonEncode = function (o) { //james:这个Encode是抄的EXT的 var useHasOwn = {}.hasOwnProperty ? true : false; // crashes Safari in some instances //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/; var m = { "\b": '\\b', "\t": '\\t', "\n": '\\n', "\f": '\\f', "\r": '\\r', '"': '\\"', "\\": '\\\\' }; var encodeString = function (s) { if (/["\\\x00-\x1f]/.test(s)) { return '"' + s.replace(/([\x00-\x1f\\"])/g, function (a, b) { var c = m[b]; if (c) { return c; } c = b.charCodeAt(); return "\\u00" + Math.floor(c / 16).toString(16) + (c % 16).toString(16); }) + '"'; } return '"' + s + '"'; }; var encodeArray = function (o) { var a = ["["], b, i, l = o.length, v; for (i = 0; i < l; i += 1) { v = o[i]; switch (typeof v) { case "undefined": case "function": case "unknown": break; default: if (b) { a.push(','); } a.push(v === null ? "null" : BI.jsonEncode(v)); b = true; } } a.push("]"); return a.join(""); }; if (typeof o == "undefined" || o === null) { return "null"; } else if (BI.isArray(o)) { return encodeArray(o); } else if (o instanceof Date) { /* * alex:原来只是把年月日时分秒简单地拼成一个String,无法decode * 现在这么处理就可以decode了,但是JS.jsonDecode和Java.JSONObject也要跟着改一下 */ return BI.jsonEncode({ __time__: o.getTime() }) } else if (typeof o == "string") { return encodeString(o); } else if (typeof o == "number") { return isFinite(o) ? String(o) : "null"; } else if (typeof o == "boolean") { return String(o); } else if (BI.isFunction(o)) { return String(o); } else { var a = ["{"], b, i, v; for (i in o) { if (!useHasOwn || o.hasOwnProperty(i)) { v = o[i]; switch (typeof v) { case "undefined": case "unknown": break; default: if (b) { a.push(','); } a.push(BI.jsonEncode(i), ":", v === null ? "null" : BI.jsonEncode(v)); b = true; } } } a.push("}"); return a.join(""); } }; BI.jsonDecode = function (text) { try { // 注意0啊 //var jo = $.parseJSON(text) || {}; var jo = $.parseJSON(text); if (jo == null) { jo = {}; } } catch (e) { /* * richie:浏览器只支持标准的JSON字符串转换,而jQuery会默认调用浏览器的window.JSON.parse()函数进行解析 * 比如:var str = "{'a':'b'}",这种形式的字符串转换为JSON就会抛异常 */ try { jo = new Function("return " + text)() || {}; } catch (e) { //do nothing } if (jo == null) { jo = []; } } if (!_hasDateInJson(text)) { return jo; } function _hasDateInJson(json) { if (!json || typeof json !== "string") { return false; } return json.indexOf("__time__") != -1; } return (function (o) { if (typeof o === "string") { return o; } if (o && o.__time__ != null) { return new Date(o.__time__); } for (var a in o) { if (o[a] == o || typeof o[a] == 'object' || $.isFunction(o[a])) { break; } o[a] = arguments.callee(o[a]); } return o; })(jo); }; BI.contentFormat = function (cv, fmt) { if (isEmpty(cv)) { //原值为空,返回空字符 return ''; } var text = cv.toString(); if (isEmpty(fmt)) { //格式为空,返回原字符 return text; } if (fmt.match(/^T/)) { //T - 文本格式 return text; } else if (fmt.match(/^D/)) { //D - 日期(时间)格式 if (!(cv instanceof Date)) { if (typeof cv === 'number') { //毫秒数类型 cv = new Date(cv); } else { //字符串类型,如yyyyMMdd、MMddyyyy等这样无分隔符的结构 cv = Date.parseDate(cv + "", Date.patterns.ISO8601Long); } } if (!BI.isNull(cv)) { var needTrim = fmt.match(/^DT/); text = BI.date2Str(cv, fmt.substring(needTrim ? 2 : 1)); } } else if (fmt.match(/E/)) { //科学计数格式 text = _eFormat(text, fmt); } else { //数字格式 text = _numberFormat(text, fmt); } //¤ - 货币格式 text = text.replace(/¤/g, '¥'); return text; }; /** * 把日期对象按照指定格式转化成字符串 * * @example * var date = new Date('Thu Dec 12 2013 00:00:00 GMT+0800'); * var result = BI.date2Str(date, 'yyyy-MM-dd');//2013-12-12 * * @class BI.date2Str * @param date 日期 * @param format 日期格式 * @returns {String} */ BI.date2Str = function (date, format) { if (!date) { return ''; } // O(len(format)) var len = format.length, result = ''; if (len > 0) { var flagch = format.charAt(0), start = 0, str = flagch; for (var i = 1; i < len; i++) { var ch = format.charAt(i); if (flagch !== ch) { result += compileJFmt({ 'char': flagch, 'str': str, 'len': i - start }, date); flagch = ch; start = i; str = flagch; } else { str += ch; } } result += compileJFmt({ 'char': flagch, 'str': str, 'len': len - start }, date); } return result; function compileJFmt(jfmt, date) { var str = jfmt.str, len = jfmt.len, ch = jfmt['char']; switch (ch) { case 'E': //星期 str = Date._DN[date.getDay()]; break; case 'y': //年 if (len <= 3) { str = (date.getFullYear() + '').slice(2, 4); } else { str = date.getFullYear(); } break; case 'M': //月 if (len > 2) { str = Date._MN[date.getMonth()]; } else if (len < 2) { str = date.getMonth() + 1; } else { str = String.leftPad(date.getMonth() + 1 + '', 2, '0'); } break; case 'd': //日 if (len > 1) { str = String.leftPad(date.getDate() + '', 2, '0'); } else { str = date.getDate(); } break; case 'h': //时(12) var hour = date.getHours() % 12; if (hour === 0) { hour = 12; } if (len > 1) { str = String.leftPad(hour + '', 2, '0'); } else { str = hour; } break; case 'H': //时(24) if (len > 1) { str = String.leftPad(date.getHours() + '', 2, '0'); } else { str = date.getHours(); } break; case 'm': if (len > 1) { str = String.leftPad(date.getMinutes() + '', 2, '0'); } else { str = date.getMinutes(); } break; case 's': if (len > 1) { str = String.leftPad(date.getSeconds() + '', 2, '0'); } else { str = date.getSeconds(); } break; case 'a': str = date.getHours() < 12 ? 'am' : 'pm'; break; case 'z': str = date.getTimezone(); break; default: str = jfmt.str; break; } return str; } }; BI.object2Number = function (value) { if (value == null) { return 0; } if (typeof value == 'number') { return value; } else { var str = value + ""; if (str.indexOf(".") === -1) { return parseInt(str); } else { return parseFloat(str); } } }; BI.object2Date = function (obj) { if (obj == null) { return new Date(); } if (obj instanceof Date) { return obj; } else if (typeof obj == 'number') { return new Date(obj); } else { var str = obj + ""; str = str.replace(/-/g, '/'); var dt = new Date(str); if (!isInvalidDate(dt)) { return dt; } return new Date(); } }; BI.object2Time = function (obj) { if (obj == null) { return new Date(); } if (obj instanceof Date) { return obj; } else { var str = obj + ""; str = str.replace(/-/g, '/'); var dt = new Date(str); if (!isInvalidDate(dt)) { return dt; } if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { dt = new Date("1970/01/01 " + str); if (!isInvalidDate(dt)) { return dt; } } dt = BI.str2Date(str, "HH:mm:ss"); if (!isInvalidDate(dt)) { return dt; } return new Date(); } }; })(); /** * guy * * @class BI.HighlightBehavior * @extends BI.Behavior */ BI.HighlightBehavior = BI.inherit(BI.Behavior, { _defaultConfig: function () { return BI.extend(BI.HighlightBehavior.superclass._defaultConfig.apply(this, arguments), {}); }, _init: function () { BI.HighlightBehavior.superclass._init.apply(this, arguments); }, doBehavior: function (items) { var args = Array.prototype.slice.call(arguments, 1), o = this.options; BI.each(items, function (i, item) { if (item instanceof BI.Single) { var rule = o.rule(item.getValue(), item); function doBe(run) { if (run === true) { item.doHighLight.apply(item, args); } else { item.unHighLight.apply(item, args); } } if (BI.isFunction(rule)) { rule(doBe); } else { doBe(rule); } } else { item.doBehavior.apply(item, args); } }) } });/** * guy * 标红行为 * @class BI.RedMarkBehavior * @extends BI.Behavior */ BI.RedMarkBehavior = BI.inherit(BI.Behavior, { _defaultConfig: function() { return BI.extend(BI.RedMarkBehavior.superclass._defaultConfig.apply(this, arguments), { }); }, _init : function() { BI.RedMarkBehavior.superclass._init.apply(this, arguments); }, doBehavior: function(items){ var args = Array.prototype.slice.call(arguments, 1), o = this.options; BI.each(items, function(i, item){ if(item instanceof BI.Single) { if (o.rule(item.getValue(), item)) { item.doRedMark.apply(item, args); } else { item.unRedMark.apply(item, args); } } else { item.doBehavior.apply(item, args); } }) } });/** * guy * 控制器 * Controller层超类 * @class BI.Controller * @extends BI.OB * @abstract */ BI.Controller = BI.inherit(BI.OB, { _defaultConfig: function() { return BI.extend(BI.Controller.superclass._defaultConfig.apply(this, arguments), { }) }, _init : function() { BI.Controller.superclass._init.apply(this, arguments); }, destroy: function(){ } }); BI.Controller.EVENT_CHANGE = "__EVENT_CHANGE__";/** * 广播 * * Created by GUY on 2015/12/23. * @class */ BI.BroadcastController = BI.inherit(BI.Controller, { _defaultConfig: function () { return BI.extend(BI.BroadcastController.superclass._defaultConfig.apply(this, arguments), {}); }, _init: function () { BI.BroadcastController.superclass._init.apply(this, arguments); this._broadcasts = {}; }, on: function (name, fn) { var self = this; if (!this._broadcasts[name]) { this._broadcasts[name] = []; } this._broadcasts[name].push(fn); return function () { self.remove(name, fn); } }, send: function (name) { var args = [].slice.call(arguments, 1); BI.each(this._broadcasts[name], function (i, fn) { fn.apply(null, args); }); }, remove: function (name, fn) { if (fn) { this._broadcasts[name].remove(fn); if (this._broadcasts[name].length === 0) { delete this._broadcasts[name]; } } else { delete this._broadcasts[name]; } return this; } });/** * 气泡图控制器 * 控制气泡图的显示方向 * * Created by GUY on 2015/8/21. * @class */ BI.BubblesController = BI.inherit(BI.Controller, { _defaultConfig: function () { return BI.extend(BI.BubblesController.superclass._defaultConfig.apply(this, arguments), {}); }, _const: { bubbleHeight: 35 }, _init: function () { BI.BubblesController.superclass._init.apply(this, arguments); this.bubblesManager = {}; this.storeBubbles = {}; }, _createBubble: function (direct, text, height) { return BI.createWidget({ type: "bi.bubble", text: text, height: height || 35, direction: direct }); }, _getOffsetLeft: function (name, context, offsetStyle) { var left = 0; if ("center" === offsetStyle) { left = context.element.offset().left + (context.element.bounds().width - this.get(name).element.bounds().width) / 2; if (left < 0) { left = 0; } return left; } if ("right" === offsetStyle) { left = context.element.offset().left + context.element.bounds().width - this.get(name).element.bounds().width; if (left < 0) { left = 0; } return left; } return context.element.offset().left; }, _getOffsetTop: function (name, context, offsetStyle) { var top = 0; if ("center" === offsetStyle) { top = context.element.offset().top + (context.element.bounds().height - this.get(name).element.bounds().height) / 2; if (top < 0) { top = 0; } return top; } else if ("right" === offsetStyle) { top = context.element.offset().top + context.element.bounds().height - this.get(name).element.bounds().height; if (top < 0) { top = 0; } return top; } return context.element.offset().top; }, _getLeftPosition: function (name, context, offsetStyle) { var position = $.getLeftPosition(context, this.get(name)); position.top = this._getOffsetTop(name, context, offsetStyle); return position; }, _getBottomPosition: function (name, context, offsetStyle) { var position = $.getBottomPosition(context, this.get(name)); position.left = this._getOffsetLeft(name, context, offsetStyle); return position; }, _getTopPosition: function (name, context, offsetStyle) { var position = $.getTopPosition(context, this.get(name)); position.left = this._getOffsetLeft(name, context, offsetStyle); return position; }, _getRightPosition: function (name, context, offsetStyle) { var position = $.getRightPosition(context, this.get(name)); position.top = this._getOffsetTop(name, context, offsetStyle); return position; }, /** * * @param name * @param text * @param context * @param offsetStyle center, left, right三种类型, 默认left * @returns {BI.BubblesController} */ show: function (name, text, context, opt) { opt || (opt = {}); var container = opt.container || context; var offsetStyle = opt.offsetStyle || {}; if (!this.storeBubbles[name]) { this.storeBubbles[name] = {}; } if (!this.storeBubbles[name]["top"]) { this.storeBubbles[name]["top"] = this._createBubble("top", text); } BI.createWidget({ type: "bi.absolute", element: container, items: [{ el: this.storeBubbles[name]["top"] }] }); this.set(name, this.storeBubbles[name]["top"]); var position = this._getTopPosition(name, context, offsetStyle); this.get(name).element.css({left: position.left, top: position.top}); this.get(name).invisible(); if (!$.isTopSpaceEnough(context, this.get(name))) { if (!this.storeBubbles[name]["left"]) { this.storeBubbles[name]["left"] = this._createBubble("left", text, 30); } BI.createWidget({ type: "bi.absolute", element: container, items: [{ el: this.storeBubbles[name]["left"] }] }); this.set(name, this.storeBubbles[name]["left"]); var position = this._getLeftPosition(name, context, offsetStyle); this.get(name).element.css({left: position.left, top: position.top}); this.get(name).invisible(); if (!$.isLeftSpaceEnough(context, this.get(name))) { if (!this.storeBubbles[name]["right"]) { this.storeBubbles[name]["right"] = this._createBubble("right", text, 30); } BI.createWidget({ type: "bi.absolute", element: container, items: [{ el: this.storeBubbles[name]["right"] }] }); this.set(name, this.storeBubbles[name]["right"]); var position = this._getRightPosition(name, context, offsetStyle); this.get(name).element.css({left: position.left, top: position.top}); this.get(name).invisible(); if (!$.isRightSpaceEnough(context, this.get(name))) { if (!this.storeBubbles[name]["bottom"]) { this.storeBubbles[name]["bottom"] = this._createBubble("bottom", text); } BI.createWidget({ type: "bi.absolute", element: container, items: [{ el: this.storeBubbles[name]["bottom"] }] }); this.set(name, this.storeBubbles[name]["bottom"]); var position = this._getBottomPosition(name, context, offsetStyle); this.get(name).element.css({left: position.left, top: position.top}); this.get(name).invisible(); } } } this.get(name).setText(text); this.get(name).visible(); return this; }, hide: function (name) { if (!this.has(name)) { return this; } this.get(name).invisible(); return this; }, add: function (name, bubble) { if (this.has(name)) { return this; } this.set(name, bubble); return this; }, get: function (name) { return this.bubblesManager[name]; }, set: function (name, bubble) { this.bubblesManager[name] = bubble; }, has: function (name) { return this.bubblesManager[name] != null; }, remove: function (name) { if (!this.has(name)) { return this; } BI.each(this.storeBubbles[name], function (dir, bubble) { bubble.destroy(); }); delete this.storeBubbles[name]; delete this.bubblesManager[name]; return this; } });/** * guy * FloatBox弹出层控制器, z-index在100w层级 * @class BI.FloatBoxController * @extends BI.Controller */ BI.FloatBoxController = BI.inherit(BI.Controller, { _defaultConfig: function () { return BI.extend(BI.FloatBoxController.superclass._defaultConfig.apply(this, arguments), { modal: true, // 模态窗口 render: "body" }); }, _init: function () { BI.FloatBoxController.superclass._init.apply(this, arguments); this.modal = this.options.modal; this.floatManager = {}; this.floatLayer = {}; this.floatContainer = {}; this.floatOpened = {}; this.zindex = BI.zIndex_floatbox; this.zindexMap = {}; }, _check: function (name) { return BI.isNotNull(this.floatManager[name]); }, create: function (name, section, options) { if (this._check(name)) { return this; } var floatbox = BI.createWidget({ type: "bi.float_box" }, options); floatbox.populate(section); this.add(name, floatbox, options); return this; }, add: function (name, floatbox, options) { var self = this; options || (options = {}); if (this._check(name)) { return this; } this.floatContainer[name] = BI.createWidget({ type: "bi.absolute", cls: "bi-popup-view", items: [{ el: (this.floatLayer[name] = BI.createWidget({ type: 'bi.absolute', items: [floatbox] })), left: 0, right: 0, top: 0, bottom: 0 }] }); this.floatManager[name] = floatbox; (function (key) { floatbox.on(BI.FloatBox.EVENT_FLOAT_BOX_CLOSED, function () { self.close(key); }) })(name); BI.createWidget({ type: "bi.absolute", element: options.container || this.options.render, items: [{ el: this.floatContainer[name], left: 0, right: 0, top: 0, bottom: 0 }] }); return this; }, open: function (name) { if (!this._check(name)) { return this; } if (!this.floatOpened[name]) { this.floatOpened[name] = true; var container = this.floatContainer[name]; container.element.css("zIndex", this.zindex++); this.modal && container.element.__hasZIndexMask__(this.zindexMap[name]) && container.element.__releaseZIndexMask__(this.zindexMap[name]); this.zindexMap[name] = this.zindex; this.modal && container.element.__buildZIndexMask__(this.zindex++); this.get(name).setZindex(this.zindex++); this.floatContainer[name].visible(); var floatbox = this.get(name); floatbox.show(); var W = $(this.options.render).width(), H = $(this.options.render).height(); var w = floatbox.element.width(), h = floatbox.element.height(); var left = (W - w) / 2, top = (H - h) / 2; if (left < 0) { left = 0; } if (top < 0) { top = 0; } floatbox.element.css({ left: left + "px", top: top + "px" }); } return this; }, close: function (name) { if (!this._check(name)) { return this; } if (this.floatOpened[name]) { delete this.floatOpened[name]; this.floatContainer[name].invisible(); this.modal && this.floatContainer[name].element.__releaseZIndexMask__(this.zindexMap[name]); } return this; }, get: function (name) { return this.floatManager[name]; }, remove: function (name) { if (!this._check(name)) { return this; } this.floatContainer[name].destroy(); this.modal && this.floatContainer[name].element.__releaseZIndexMask__(this.zindexMap[name]); delete this.floatManager[name]; delete this.floatLayer[name]; delete this.zindexMap[name]; delete this.floatContainer[name]; delete this.floatOpened[name]; return this; } });/** * 弹出层面板控制器, z-index在10w层级 * * Created by GUY on 2015/6/24. * @class */ BI.LayerController = BI.inherit(BI.Controller, { _defaultConfig: function () { return BI.extend(BI.LayerController.superclass._defaultConfig.apply(this, arguments), { render: "body" }); }, _init: function () { BI.LayerController.superclass._init.apply(this, arguments); this.layerManager = {}; this.layouts = {}; this.zindex = BI.zIndex_layer; BI.Resizers.add("layerController" + BI.uniqueId(), BI.bind(this._resize, this)); }, _resize: function () { BI.each(this.layouts, function (i, layer) { if (layer.element.is(":visible")) { layer.element.trigger("__resize__"); } }) }, make: function (name, container, op) { if (this.has(name)) { return this.get(name); } op || (op = {}); var widget = BI.createWidget((op.render || {}), { type: "bi.layout" }); BI.createWidget({ type: "bi.absolute", element: container || this.options.render, items: [BI.extend({ el: widget }, { top: 0, left: 0, right: 0, bottom: 0 }, op.offset)] }); this.add(name, widget, widget); return widget; }, create: function (name, from, op) { if (this.has(name)) { return this.get(name); } op || (op = {}); var offset = op.offset || {}; var w = from; if (BI.isWidget(from)) { w = from.element; } if (BI.isNotEmptyString(w)) { w = $(w); } if (this.has(name)) { return this.get(name); } var widget = BI.createWidget((op.render || {}), { type: "bi.layout", cls: op.cls }); var layout = BI.createWidget({ type: "bi.absolute", items: [{ el: widget, left: 0, right: 0, top: 0, bottom: 0 }] }); BI.createWidget({ type: "bi.absolute", element: op.container || this.options.render, items: [{ el: layout, left: offset.left || 0, right: offset.right || 0, top: offset.top || 0, bottom: offset.bottom || 0 }] }); if (w) { layout.element.addClass("bi-popup-view"); layout.element.css({ left: w.offset().left + (offset.left || 0), top: w.offset().top + (offset.top || 0), width: offset.width || (w.outerWidth() - (offset.right || 0)) || "", height: offset.height || (w.outerHeight() - (offset.bottom || 0)) || "" }); layout.element.on("__resize__", function () { w.is(":visible") && layout.element.css({ left: w.offset().left + (offset.left || 0), top: w.offset().top + (offset.top || 0), width: offset.width || (w.outerWidth() - (offset.right || 0)) || "", height: offset.height || (w.outerHeight() - (offset.bottom || 0)) || "" }); }); } this.add(name, widget, layout); return widget; }, hide: function (name, callback) { if (!this.has(name)) { return this; } this._getLayout(name).invisible(); this._getLayout(name).element.hide(0, callback); return this; }, show: function (name, callback) { if (!this.has(name)) { return this; } this._getLayout(name).visible(); this._getLayout(name).element.css("z-index", this.zindex++).show(0, callback).trigger("__resize__"); return this; }, isVisible: function (name) { return this.has(name) && this._getLayout(name).isVisible(); }, add: function (name, layer, layout) { if (this.has(name)) { throw new Error("name is already exist"); } layout.setVisible(false); this.layerManager[name] = layer; this.layouts[name] = layout; layout.element.css("z-index", this.zindex++); return this; }, _getLayout: function (name) { return this.layouts[name]; }, get: function (name) { return this.layerManager[name]; }, has: function (name) { return this.layerManager[name] != null; }, remove: function (name) { if (!this.has(name)) { return this; } this.layerManager[name].destroy(); this.layouts[name].destroy(); delete this.layerManager[name]; delete this.layouts[name]; return this; } });/** * 遮罩面板, z-index在1亿层级 * * Created by GUY on 2015/6/24. * @class */ BI.MaskersController = BI.inherit(BI.LayerController, { _defaultConfig: function () { return BI.extend(BI.MaskersController.superclass._defaultConfig.apply(this, arguments), {}); }, _init: function () { BI.MaskersController.superclass._init.apply(this, arguments); this.zindex = BI.zIndex_masker; } });/** * window.resize 控制器 * * Created by GUY on 2015/6/24. * @class */ BI.ResizeController = BI.inherit(BI.Controller, { _defaultConfig: function () { return BI.extend(BI.ResizeController.superclass._defaultConfig.apply(this, arguments), {}); }, _init: function () { BI.ResizeController.superclass._init.apply(this, arguments); var self = this; this.resizerManger = {}; var fn = BI.debounce(function (ev) { //if (BI.isWindow(ev.target)) { self._resize(ev); //} }, 30); $(window).resize(fn); }, _resize: function (ev) { BI.each(this.resizerManger, function (key, resizer) { if (resizer instanceof $) { if (resizer.is(":visible")) { resizer.trigger("__resize__"); } return; } if (resizer instanceof BI.Layout) { resizer.resize(); return; } if (BI.isFunction(resizer)) { resizer(ev); return; } }) }, add: function (name, resizer) { var self = this; if (this.has(name)) { return this; } this.resizerManger[name] = resizer; return function () { self.remove(name); }; }, get: function (name) { return this.resizerManger[name]; }, has: function (name) { return this.resizerManger[name] != null; }, remove: function (name) { if (!this.has(name)) { return this; } delete this.resizerManger[name]; return this; } });/** * tooltip控制器 * 控制tooltip的显示, 且页面中只有一个tooltip显示 * * Created by GUY on 2015/9/8. * @class BI.TooltipsController * @extends BI.Controller */ BI.TooltipsController = BI.inherit(BI.Controller, { _defaultConfig: function () { return BI.extend(BI.TooltipsController.superclass._defaultConfig.apply(this, arguments), {}); }, _const: { height: 20 }, _init: function () { BI.TooltipsController.superclass._init.apply(this, arguments); this.tooltipsManager = {}; this.showingTips = {};//存储正在显示的tooltip }, _createTooltip: function (text, level) { return BI.createWidget({ type: "bi.tooltip", text: text, level: level, stopEvent: true, height: this._const.height }); }, hide: function (name, callback) { if (!this.has(name)) { return this; } delete this.showingTips[name]; this.get(name).element.hide(0, callback); this.get(name).invisible(); return this; }, create: function (name, text, level, context) { if (!this.has(name)) { var tooltip = this._createTooltip(text, level); this.add(name, tooltip); BI.createWidget({ type: "bi.absolute", element: context || "body", items: [{ el: tooltip }] }); tooltip.invisible(); } return this.get(name); }, //opt: {container: '', belowMouse: false} show: function (e, name, text, level, context, opt) { opt || (opt = {}); var self = this; BI.each(this.showingTips, function (i, tip) { self.hide(i); }); this.showingTips = {}; if (!this.has(name)) { this.create(name, text, level, opt.container || context); } var offset = context.element.offset(); var bounds = context.element.bounds(); var top = offset.top + bounds.height + 5; var tooltip = this.get(name); tooltip.setText(text); tooltip.element.css({ left: "0px", top: "0px" }); tooltip.visible(); tooltip.element.height(tooltip.element[0].scrollHeight); this.showingTips[name] = true; var x = e.pageX || e.clientX, y = (e.pageY || e.clientY) + 15; if (x + tooltip.element.outerWidth() > $("body").outerWidth()) { x -= tooltip.element.outerWidth(); } if (y + tooltip.element.outerHeight() > $("body").outerHeight()) { y -= tooltip.element.outerHeight() + 15; top = offset.top - tooltip.element.outerHeight() - 5; !opt.belowMouse && (y = Math.min(y, top)); } else { !opt.belowMouse && (y = Math.max(y, top)); } tooltip.element.css({ left: x < 0 ? 0 : x + "px", top: y < 0 ? 0 : y + "px" }); tooltip.element.hover(function () { self.remove(name); context.element.trigger("mouseleave.title" + context.getName()); }); return this; }, add: function (name, bubble) { if (this.has(name)) { return this; } this.set(name, bubble); return this; }, get: function (name) { return this.tooltipsManager[name]; }, set: function (name, bubble) { this.tooltipsManager[name] = bubble; }, has: function (name) { return this.tooltipsManager[name] != null; }, remove: function (name) { if (!this.has(name)) { return this; } this.tooltipsManager[name].destroy(); delete this.tooltipsManager[name]; return this; } });/** * * @class BI.FloatBoxRouter * @extends BI.WRouter */ BI.FloatBoxRouter = BI.inherit(BI.WRouter, { routes: {}, _init: function () { this.store = {}; this.views = {}; }, createView: function (url, modelData, viewData, context) { return BI.Factory.createView(url, this.get(url), modelData || {}, viewData || {}, context) }, open: function (url, modelData, viewData, context, options) { var self = this, isValid = BI.isKey(modelData); options || (options = {}); url = context.rootURL + "/" + url; var data = void 0; if (isValid) { modelData = modelData + "";//避免modelData是数字 var keys = modelData.split('.'); BI.each(keys, function (i, k) { if (i === 0) { data = context.model.get(k) || {}; } else { data = data[k] || {}; } }); data.id = options.id || keys[keys.length - 1]; } else { data = modelData; } BI.extend(data, options.data); if (!this.controller) { this.controller = new BI.FloatBoxController(); } if (!this.store[url]) { this.store[url] = BI.createWidget({ type: "bi.float_box" }, options); var view = this.createView(url, data, viewData, context); isValid && context.model.addChild(modelData, view.model); view.listenTo(view.model, "destroy", function () { self.remove(url, context); }); context.on(BI.Events.UNMOUNT, function () { self.remove(url, context); }); this.store[url].populate(view); this.views[url] = view; this.controller.add(url, this.store[url]); context && context.on("end:" + view.cid, function () { BI.nextTick(function () { self.close(url); // view.end(); (context.listenEnd.apply(context, isValid ? modelData.split('.') : [modelData]) !== false) && context.populate(); }, 30) }).on("change:" + view.cid, _.bind(context.notifyParent, context)) } this.controller.open(url); this.views[url].populate(data, options.force || true); return this; }, close: function (url) { if (this.controller) { this.controller.close(url); } return this; }, remove: function (url, context) { url = context.rootURL + "/" + url; if (this.controller) { this.controller.remove(url); delete this.store[url]; this.views[url] && this.views[url].model.destroy(); delete this.views[url]; } return this; } });/** * 统一绑定事件 * @type {*|void|Object} */ BI.EventList = BI.inherit(BI.OB, { _defaultConfig: function() { return BI.extend(BI.EventList.superclass._defaultConfig.apply(this, arguments), { event: "click", callback: BI.emptyFn, handle: "", items:[] }); }, _init : function() { BI.EventList.superclass._init.apply(this, arguments); this.populate(this.options.items); }, _getHandle: function(item){ var handle = this.options.handle ? _.result(item, this.options.handle) : item; return handle.element || handle; }, populate: function(items){ var self = this, event = this.options.event, callback = this.options.callback; BI.nextTick(function(){ BI.each(items, function(i, item){ var fn = callback(item); BI.isFunction(fn) && (fn = BI.debounce(fn, BI.EVENT_RESPONSE_TIME, true)); self._getHandle(item)[event](fn); }) }) } });/** * 统一监听jquery事件 * @type {*|void|Object} */ BI.ListenerList = BI.inherit(BI.OB, { _defaultConfig: function() { return BI.extend(BI.ListenerList.superclass._defaultConfig.apply(this, arguments), { event: "click", callback: BI.emptyFn, items:[] }); }, _init : function() { BI.ListenerList.superclass._init.apply(this, arguments); this.populate(this.options.items); }, _getHandle: function(item){ var handle = this.options.handle ? _.result(item, this.options.handle) : item; return handle.element || handle; }, populate: function(items){ var self = this, event = this.options.event, callback = this.options.callback; BI.nextTick(function(){ BI.each(items, function(i, item){ var fn = callback(item); BI.isFunction(fn) && (fn = BI.debounce(fn, BI.EVENT_RESPONSE_TIME, true)); self._getHandle(item).on(event, fn); }) }) } });/** * Created by GUY on 2015/6/25. */ /** * 统一监听jquery事件 * @type {*|void|Object} */ BI.OffList = BI.inherit(BI.OB, { _defaultConfig: function() { return BI.extend(BI.OffList.superclass._defaultConfig.apply(this, arguments), { event: "click", items:[] }); }, _init : function() { BI.OffList.superclass._init.apply(this, arguments); this.populate(this.options.items); }, _getHandle: function(item){ var handle = this.options.handle ? _.result(item, this.options.handle) : item; return handle.element || handle; }, populate: function(items){ var self = this, event = this.options.event; BI.each(items, function(i, item){ self._getHandle(item).off(event); }) } });/** * 事件集合 * @class BI.Events */ _.extend(BI, { Events: { /** * @static * @property keydown事件 */ KEYDOWN: "_KEYDOWN", /** * @static * @property 回撤事件 */ BACKSPACE: "_BACKSPACE", /** * @static * @property 空格事件 */ SPACE: "_SPACE", /** * @static * @property 回车事件 */ ENTER: "_ENTER", /** * @static * @property 确定事件 */ CONFIRM: '_CONFIRM', /** * @static * @property 错误事件 */ ERROR: '_ERROR', /** * @static * @property 暂停事件 */ PAUSE: '_PAUSE', /** * @static * @property destroy事件 */ DESTROY: '_DESTROY', /** * @static * @property 取消挂载事件 */ UNMOUNT: '_UNMOUNT', /** * @static * @property 清除选择 */ CLEAR: '_CLEAR', /** * @static * @property 添加数据 */ ADD: '_ADD', /** * @static * @property 正在编辑状态事件 */ EDITING: '_EDITING', /** * @static * @property 空状态事件 */ EMPTY: '_EMPTY', /** * @static * @property 显示隐藏事件 */ VIEW: '_VIEW', /** * @static * @property 窗体改变大小 */ RESIZE: "_RESIZE", /** * @static * @property 编辑前事件 */ BEFOREEDIT: '_BEFOREEDIT', /** * @static * @property 编辑后事件 */ AFTEREDIT: '_AFTEREDIT', /** * @static * @property 开始编辑事件 */ STARTEDIT: '_STARTEDIT', /** * @static * @property 停止编辑事件 */ STOPEDIT: '_STOPEDIT', /** * @static * @property 值改变事件 */ CHANGE: '_CHANGE', /** * @static * @property 下拉弹出菜单事件 */ EXPAND: '_EXPAND', /** * @static * @property 关闭下拉菜单事件 */ COLLAPSE: '_COLLAPSE', /** * @static * @property 回调事件 */ CALLBACK: '_CALLBACK', /** * @static * @property 点击事件 */ CLICK: '_CLICK', /** * @static * @property 状态改变事件,一般是用在复选按钮和单选按钮 */ STATECHANGE: '_STATECHANGE', /** * @static * @property 状态改变前事件 */ BEFORESTATECHANGE: '_BEFORESTATECHANGE', /** * @static * @property 初始化事件 */ INIT: '_INIT', /** * @static * @property 初始化后事件 */ AFTERINIT: '_AFTERINIT', /** * @static * @property 滚动条滚动事件 */ SCROLL: '_SCROLL', /** * @static * @property 开始加载事件 */ STARTLOAD: '_STARTLOAD', /** * @static * @property 加载后事件 */ AFTERLOAD: '_AFTERLOAD', /** * @static * @property 提交前事件 */ BS: 'beforesubmit', /** * @static * @property 提交后事件 */ AS: 'aftersubmit', /** * @static * @property 提交完成事件 */ SC: 'submitcomplete', /** * @static * @property 提交失败事件 */ SF: 'submitfailure', /** * @static * @property 提交成功事件 */ SS: 'submitsuccess', /** * @static * @property 校验提交前事件 */ BVW: 'beforeverifywrite', /** * @static * @property 校验提交后事件 */ AVW: 'afterverifywrite', /** * @static * @property 校验后事件 */ AV: 'afterverify', /** * @static * @property 填报前事件 */ BW: 'beforewrite', /** * @static * @property 填报后事件 */ AW: 'afterwrite', /** * @static * @property 填报成功事件 */ WS: 'writesuccess', /** * @static * @property 填报失败事件 */ WF: 'writefailure', /** * @static * @property 添加行前事件 */ BA: 'beforeappend', /** * @static * @property 添加行后事件 */ AA: 'afterappend', /** * @static * @property 删除行前事件 */ BD: 'beforedelete', /** * @static * @property 删除行后事件 */ AD: 'beforedelete', /** * @static * @property 未提交离开事件 */ UC: 'unloadcheck', /** * @static * @property PDF导出前事件 */ BTOPDF: 'beforetopdf', /** * @static * @property PDF导出后事件 */ ATOPDF: 'aftertopdf', /** * @static * @property Excel导出前事件 */ BTOEXCEL: 'beforetoexcel', /** * @static * @property Excel导出后事件 */ ATOEXCEL: 'aftertoexcel', /** * @static * @property Word导出前事件 */ BTOWORD: 'beforetoword', /** * @static * @property Word导出后事件 */ ATOWORD: 'aftertoword', /** * @static * @property 图片导出前事件 */ BTOIMAGE: 'beforetoimage', /** * @static * @property 图片导出后事件 */ ATOIMAGE: 'aftertoimage', /** * @static * @property HTML导出前事件 */ BTOHTML: 'beforetohtml', /** * @static * @property HTML导出后事件 */ ATOHTML: 'aftertohtml', /** * @static * @property Excel导入前事件 */ BIMEXCEL: 'beforeimportexcel', /** * @static * @property Excel导出后事件 */ AIMEXCEL: 'afterimportexcel', /** * @static * @property PDF打印前事件 */ BPDFPRINT: 'beforepdfprint', /** * @static * @property PDF打印后事件 */ APDFPRINT: 'afterpdfprint', /** * @static * @property Flash打印前事件 */ BFLASHPRINT: 'beforeflashprint', /** * @static * @property Flash打印后事件 */ AFLASHPRINT: 'afterflashprint', /** * @static * @property Applet打印前事件 */ BAPPLETPRINT: 'beforeappletprint', /** * @static * @property Applet打印后事件 */ AAPPLETPRINT: 'afterappletprint', /** * @static * @property 服务器打印前事件 */ BSEVERPRINT: 'beforeserverprint', /** * @static * @property 服务器打印后事件 */ ASERVERPRINT: 'afterserverprint', /** * @static * @property 邮件发送前事件 */ BEMAIL: 'beforeemail', /** * @static * @property 邮件发送后事件 */ AEMAIL: 'afteremail' } });/** * guy * 最基础的dom操作 */ BI.extend(jQuery.fn, { destroy: function () { this.remove(); if (BI.isIE() === true) { this[0].outerHTML = ''; } }, /** * 高亮显示 * @param text 必需 * @param keyword * @param py 必需 * @returns {*} * @private */ __textKeywordMarked__: function (text, keyword, py) { if (!BI.isKey(keyword) || (text + "").length > 100) { return this.text((text + "").replaceAll(" ", " ")); } keyword = keyword + ""; keyword = BI.toUpperCase(keyword); var textLeft = (text || "") + ""; py = (py || BI.makeFirstPY(text)) + ""; if (py != null) { py = BI.toUpperCase(py); } this.empty(); while (true) { var tidx = BI.toUpperCase(textLeft).indexOf(keyword); var pidx = null; if (py != null) { pidx = py.indexOf(keyword); if (pidx >= 0) { pidx = pidx % text.length; } } if (tidx >= 0) { this.append(textLeft.substr(0, tidx)); this.append($("<span>").addClass("bi-keyword-red-mark") .text(textLeft.substr(tidx, keyword.length).replaceAll(" ", " "))); textLeft = textLeft.substr(tidx + keyword.length); if (py != null) { py = py.substr(tidx + keyword.length); } } else if (pidx != null && pidx >= 0 && Math.floor(pidx / text.length) === Math.floor((pidx + keyword.length - 1) / text.length)) { this.append(textLeft.substr(0, pidx)); this.append($("<span>").addClass("bi-keyword-red-mark") .text(textLeft.substr(pidx, keyword.length).replaceAll(" ", " "))); if (py != null) { py = py.substr(pidx + keyword.length); } textLeft = textLeft.substr(pidx + keyword.length); } else { this.append(textLeft); break; } } return this; }, getDomHeight: function (parent) { var clone = $(this).clone(); clone.appendTo($(parent || "body")); var height = clone.height(); clone.remove(); return height; }, //是否有竖直滚动条 hasVerticalScroll: function () { return this.height() > 0 && this[0].clientWidth < this[0].offsetWidth; }, //是否有水平滚动条 hasHorizonScroll: function () { return this.width() > 0 && this[0].clientHeight < this[0].offsetHeight; }, //获取计算后的样式 getStyle: function (name) { var node = this[0]; var computedStyle = void 0; // W3C Standard if (window.getComputedStyle) { // In certain cases such as within an iframe in FF3, this returns null. computedStyle = window.getComputedStyle(node, null); if (computedStyle) { return computedStyle.getPropertyValue(BI.hyphenate(name)); } } // Safari if (document.defaultView && document.defaultView.getComputedStyle) { computedStyle = document.defaultView.getComputedStyle(node, null); // A Safari bug causes this to return null for `display: none` elements. if (computedStyle) { return computedStyle.getPropertyValue(BI.hyphenate(name)); } if (name === 'display') { return 'none'; } } // Internet Explorer if (node.currentStyle) { if (name === 'float') { return node.currentStyle.cssFloat || node.currentStyle.styleFloat; } return node.currentStyle[BI.camelize(name)]; } return node.style && node.style[BI.camelize(name)]; }, __isMouseInBounds__: function (e) { var offset2Body = this.offset(); return !(e.pageX < offset2Body.left || e.pageX > offset2Body.left + this.outerWidth() || e.pageY < offset2Body.top || e.pageY > offset2Body.top + this.outerHeight()) }, __hasZIndexMask__: function (zindex) { return zindex && this.zIndexMask[zindex] != null; }, __buildZIndexMask__: function (zindex, domArray) { this.zIndexMask = this.zIndexMask || {};//存储z-index的mask this.indexMask = this.indexMask || [];//存储mask var mask = BI.createWidget({ type: "bi.center_adapt", cls: "bi-z-index-mask", items: domArray }); mask.element.css({"z-index": zindex}); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: mask, left: 0, right: 0, top: 0, bottom: 0 }] }); this.indexMask.push(mask); zindex && (this.zIndexMask[zindex] = mask); return mask.element; }, __releaseZIndexMask__: function (zindex) { if (zindex && this.zIndexMask[zindex]) { this.indexMask.remove(this.zIndexMask[zindex]); this.zIndexMask[zindex].destroy(); return; } this.indexMask = this.indexMask || []; var indexMask = this.indexMask.pop(); indexMask && indexMask.destroy(); } }); BI.extend(jQuery, { getLeftPosition: function (combo, popup, extraWidth) { return { left: combo.element.offset().left - popup.element.outerWidth() - (extraWidth || 0) }; }, getRightPosition: function (combo, popup, extraWidth) { var el = combo.element; return { left: el.offset().left + el.outerWidth() + (extraWidth || 0) } }, getTopPosition: function (combo, popup, extraHeight) { return { top: combo.element.offset().top - popup.element.outerHeight() - (extraHeight || 0) }; }, getBottomPosition: function (combo, popup, extraHeight) { var el = combo.element; return { top: el.offset().top + el.outerHeight() + (extraHeight || 0) }; }, isLeftSpaceEnough: function (combo, popup, extraWidth) { return $.getLeftPosition(combo, popup, extraWidth).left >= 0; }, isRightSpaceEnough: function (combo, popup, extraWidth) { var viewBounds = popup.element.bounds(), windowBounds = $("body").bounds(); return $.getRightPosition(combo, popup, extraWidth).left + viewBounds.width <= windowBounds.width; }, isTopSpaceEnough: function (combo, popup, extraHeight) { return $.getTopPosition(combo, popup, extraHeight).top >= 0; }, isBottomSpaceEnough: function (combo, popup, extraHeight) { var viewBounds = popup.element.bounds(), windowBounds = $("body").bounds(); return $.getBottomPosition(combo, popup, extraHeight).top + viewBounds.height <= windowBounds.height; }, isRightSpaceLarger: function (combo) { var windowBounds = $("body").bounds(); return windowBounds.width - combo.element.offset().left - combo.element.bounds().width >= combo.element.offset().left; }, isBottomSpaceLarger: function (combo) { var windowBounds = $("body").bounds(); return windowBounds.height - combo.element.offset().top - combo.element.bounds().height >= combo.element.offset().top; }, getLeftAlignPosition: function (combo, popup, extraWidth) { var viewBounds = popup.element.bounds(), windowBounds = $("body").bounds(); var left = combo.element.offset().left + extraWidth; if (left + viewBounds.width > windowBounds.width) { left = windowBounds.width - viewBounds.width; } if (left < 0) { left = 0; } return { left: left } }, getLeftAdaptPosition: function (combo, popup, extraWidth) { if ($.isLeftSpaceEnough(combo, popup, extraWidth)) { return $.getLeftPosition(combo, popup, extraWidth); } return { left: 0 } }, getRightAlignPosition: function (combo, popup, extraWidth) { var comboBounds = combo.element.bounds(), viewBounds = popup.element.bounds(); var left = combo.element.offset().left + comboBounds.width - viewBounds.width - extraWidth; if (left < 0) { left = 0; } return { left: left } }, getRightAdaptPosition: function (combo, popup, extraWidth) { if ($.isRightSpaceEnough(combo, popup, extraWidth)) { return $.getRightPosition(combo, popup, extraWidth); } return { left: $("body").bounds().width - popup.element.bounds().width } }, getTopAlignPosition: function (combo, popup, extraHeight, needAdaptHeight) { var comboOffset = combo.element.offset(); var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds(); var top, adaptHeight; if ($.isBottomSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) { top = comboOffset.top + extraHeight; } else if (needAdaptHeight) { top = comboOffset.top + extraHeight; adaptHeight = windowBounds.height - top; } else { top = windowBounds.height - popupBounds.height; if (top < extraHeight) { adaptHeight = windowBounds.height - extraHeight; } } if (top < extraHeight) { top = extraHeight; } return adaptHeight ? { top: top, adaptHeight: adaptHeight } : { top: top } }, getTopAdaptPosition: function (combo, popup, extraHeight, needAdaptHeight) { var popupBounds = popup.element.bounds(), windowBounds = $("body").bounds(); if ($.isTopSpaceEnough(combo, popup, extraHeight)) { return $.getTopPosition(combo, popup, extraHeight); } if (needAdaptHeight) { return { top: 0, adaptHeight: combo.element.offset().top - extraHeight } } if (popupBounds.height + extraHeight > windowBounds.height) { return { top: 0, adaptHeight: windowBounds.height - extraHeight } } return { top: 0 } }, getBottomAlignPosition: function (combo, popup, extraHeight, needAdaptHeight) { var comboOffset = combo.element.offset(); var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds(); var top, adaptHeight; if ($.isTopSpaceEnough(combo, popup, -1 * comboBounds.height + extraHeight)) { top = comboOffset.top + comboBounds.height - popupBounds.height - extraHeight; } else if (needAdaptHeight) { top = 0; adaptHeight = comboOffset.top + comboBounds.height - extraHeight; } else { top = 0; if (popupBounds.height + extraHeight > windowBounds.height) { adaptHeight = windowBounds.height - extraHeight; } } if (top < 0) { top = 0; } return adaptHeight ? { top: top, adaptHeight: adaptHeight } : { top: top } }, getBottomAdaptPosition: function (combo, popup, extraHeight, needAdaptHeight) { var comboOffset = combo.element.offset(); var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds(); if ($.isBottomSpaceEnough(combo, popup, extraHeight)) { return $.getBottomPosition(combo, popup, extraHeight); } if (needAdaptHeight) { return { top: comboOffset.top + comboBounds.height + extraHeight, adaptHeight: windowBounds.height - comboOffset.top - comboBounds.height - extraHeight } } if (popupBounds.height + extraHeight > windowBounds.height) { return { top: extraHeight, adaptHeight: windowBounds.height - extraHeight } } return { top: windowBounds.height - popupBounds.height - extraHeight } }, getCenterAdaptPosition: function (combo, popup) { var comboOffset = combo.element.offset(); var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds(); var left; if (comboOffset.left + comboBounds.width / 2 + popupBounds.width / 2 > windowBounds.width) { left = windowBounds.width - popupBounds.width; } else { left = comboOffset.left + comboBounds.width / 2 - popupBounds.width / 2; } if (left < 0) { left = 0; } return { left: left } }, getMiddleAdaptPosition: function (combo, popup) { var comboOffset = combo.element.offset(); var comboBounds = combo.element.bounds(), popupBounds = popup.element.bounds(), windowBounds = $("body").bounds(); var top; if (comboOffset.top + comboBounds.height / 2 + popupBounds.height / 2 > windowBounds.height) { top = windowBounds.height - popupBounds.height; } else { top = comboOffset.top + comboBounds.height / 2 - popupBounds.height / 2; } if (top < 0) { top = 0; } return { top: top } }, getComboPositionByDirections: function (combo, popup, extraWidth, extraHeight, needAdaptHeight, directions) { extraWidth || (extraWidth = 0); extraHeight || (extraHeight = 0); var i, direct; var leftRight = [], topBottom = []; var isNeedAdaptHeight = false, tbFirst = false, lrFirst = false; var left, top, pos; for (i = 0; i < directions.length; i++) { direct = directions[i]; switch (direct) { case "left": leftRight.push(direct); break; case "right": leftRight.push(direct); break; case "top": topBottom.push(direct); break; case "bottom": topBottom.push(direct); break; } } for (i = 0; i < directions.length; i++) { direct = directions[i]; switch (direct) { case "left": if (!isNeedAdaptHeight) { var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? 0 : extraHeight; if ($.isLeftSpaceEnough(combo, popup, tW)) { left = $.getLeftPosition(combo, popup, tW).left; if (topBottom[0] === "bottom") { pos = $.getTopAlignPosition(combo, popup, tH, needAdaptHeight); pos.dir = "left,bottom"; } else { pos = $.getBottomAlignPosition(combo, popup, tH, needAdaptHeight); pos.dir = "left,top"; } if (tbFirst) { pos.change = "left"; } pos.left = left; return pos; } } lrFirst = true; break; case "right": if (!isNeedAdaptHeight) { var tW = tbFirst ? extraHeight : extraWidth, tH = tbFirst ? extraWidth : extraHeight; if ($.isRightSpaceEnough(combo, popup, tW)) { left = $.getRightPosition(combo, popup, tW).left; if (topBottom[0] === "bottom") { pos = $.getTopAlignPosition(combo, popup, tH, needAdaptHeight); pos.dir = "right,bottom"; } else { pos = $.getBottomAlignPosition(combo, popup, tH, needAdaptHeight); pos.dir = "right,top"; } if (tbFirst) { pos.change = "right"; } pos.left = left; return pos; } } lrFirst = true; break; case "top": var tW = lrFirst ? extraHeight : extraWidth, tH = lrFirst ? extraWidth : extraHeight; if ($.isTopSpaceEnough(combo, popup, tH)) { top = $.getTopPosition(combo, popup, tH).top; if (leftRight[0] === "right") { pos = $.getLeftAlignPosition(combo, popup, tW, needAdaptHeight); pos.dir = "top,right"; } else { pos = $.getRightAlignPosition(combo, popup, tW); pos.dir = "top,left"; } if (lrFirst) { pos.change = "top"; } pos.top = top; return pos; } if (needAdaptHeight) { isNeedAdaptHeight = true; } tbFirst = true; break; case "bottom": var tW = lrFirst ? extraHeight : extraWidth, tH = lrFirst ? extraWidth : extraHeight; if ($.isBottomSpaceEnough(combo, popup, tH)) { top = $.getBottomPosition(combo, popup, tH).top; if (leftRight[0] === "right") { pos = $.getLeftAlignPosition(combo, popup, tW, needAdaptHeight); pos.dir = "bottom,right"; } else { pos = $.getRightAlignPosition(combo, popup, tW); pos.dir = "bottom,left"; } if (lrFirst) { pos.change = "bottom"; } pos.top = top; return pos; } if (needAdaptHeight) { isNeedAdaptHeight = true; } tbFirst = true; break; } } switch (directions[0]) { case "left": case "right": if ($.isRightSpaceLarger(combo)) { left = $.getRightAdaptPosition(combo, popup, extraWidth).left; } else { left = $.getLeftAdaptPosition(combo, popup, extraWidth).left; } if (topBottom[0] === "bottom") { pos = $.getTopAlignPosition(combo, popup, extraHeight, needAdaptHeight); pos.left = left; pos.dir = directions[0] + ",bottom"; return pos; } pos = $.getBottomAlignPosition(combo, popup, extraHeight, needAdaptHeight); pos.left = left; pos.dir = directions[0] + ",top"; return pos; default : if ($.isBottomSpaceLarger(combo)) { pos = $.getBottomAdaptPosition(combo, popup, extraHeight, needAdaptHeight); } else { pos = $.getTopAdaptPosition(combo, popup, extraHeight, needAdaptHeight); } if (leftRight[0] === "right") { left = $.getLeftAlignPosition(combo, popup, extraWidth, needAdaptHeight).left; pos.left = left; pos.dir = directions[0] + ",right"; return pos; } left = $.getRightAlignPosition(combo, popup, extraWidth).left; pos.left = left; pos.dir = directions[0] + ",left"; return pos; } }, getComboPosition: function (combo, popup, extraWidth, extraHeight, needAdaptHeight, directions, offsetStyle) { extraWidth || (extraWidth = 0); extraHeight || (extraHeight = 0); var bodyHeight = $("body").bounds().height - extraHeight; var maxHeight = Math.min(popup.attr("maxHeight") || bodyHeight, bodyHeight); popup.resetHeight && popup.resetHeight(maxHeight); var position = $.getComboPositionByDirections(combo, popup, extraWidth, extraHeight, needAdaptHeight, directions || ['bottom', 'top', 'right', 'left']); switch (offsetStyle) { case "center": if (position.change) { var p = $.getMiddleAdaptPosition(combo, popup); position.top = p.top; } else { var p = $.getCenterAdaptPosition(combo, popup); position.left = p.left; } break; case "middle": if (position.change) { var p = $.getCenterAdaptPosition(combo, popup); position.left = p.left; } else { var p = $.getMiddleAdaptPosition(combo, popup); position.top = p.top; } break; } if (needAdaptHeight === true) { popup.resetHeight && popup.resetHeight(Math.min(bodyHeight - position.top, maxHeight)); } return position; } });/** * 基本的函数 * Created by GUY on 2015/6/24. */ BI.Func = {}; BI.extend(BI.Func, { /** * 获取搜索结果 * @param items * @param keyword * @param param 搜索哪个属性 */ getSearchResult: function (items, keyword, param) { var isArray = BI.isArray(items); items = isArray ? BI.flatten(items) : items; param || (param = "text"); if (!BI.isKey(keyword)) { return { finded: BI.deepClone(items), matched: isArray ? [] : {} }; } var t, text, py; keyword = BI.toUpperCase(keyword); var matched = isArray ? [] : {}, finded = isArray ? [] : {}; BI.each(items, function (i, item) { item = BI.deepClone(item); t = BI.stripEL(item); text = t[param] || t.text || t.value || t.name || t; py = BI.makeFirstPY(text); text = BI.toUpperCase(text); py = BI.toUpperCase(py); var pidx; if (text.indexOf(keyword) > -1) { if (text === keyword) { isArray ? matched.push(item) : (matched[i] = item); } else { isArray ? finded.push(item) : (finded[i] = item); } } else if (pidx = py.indexOf(keyword), (pidx > -1 && Math.floor(pidx / text.length) === Math.floor((pidx + keyword.length - 1) / text.length))) { if (text === keyword || keyword.length === text.length) { isArray ? matched.push(item) : (matched[i] = item); } else { isArray ? finded.push(item) : (finded[i] = item); } } }); return { matched: matched, finded: finded } }, }); /** * 对DOM操作的通用函数 * @type {{}} */ BI.DOM = {}; BI.extend(BI.DOM, { /** * 把dom数组或元素悬挂起来,使其不对html产生影响 * @param dom */ hang: function (doms) { if (BI.isEmpty(doms)) { return; } var frag = document.createDocumentFragment(); BI.each(doms, function (i, dom) { dom instanceof BI.Widget && (dom = dom.element); dom instanceof $ && dom[0] && frag.appendChild(dom[0]); }); return frag; }, isExist: function (obj) { return $("body").find(obj.element).length > 0; }, //预加载图片 preloadImages: function (srcArray, onload) { var count = 0, images = []; function complete() { count++; if (count >= srcArray.length) { onload(); } } BI.each(srcArray, function (i, src) { images[i] = new Image(); images[i].src = src; images[i].onload = function () { complete() }; images[i].onerror = function () { complete() }; }); }, isColor: function (color) { return color && (this.isRGBColor(color) || this.isHexColor(color)); }, isRGBColor: function (color) { if (!color) { return false; } return color.substr(0, 3) === "rgb"; }, isHexColor: function (color) { if (!color) { return false; } return color[0] === "#" && color.length === 7; }, isDarkColor: function (hex) { if (!hex || !this.isHexColor(hex)) { return false; } var rgb = this.rgb2json(this.hex2rgb(hex)); var grayLevel = Math.round(rgb.r * 0.299 + rgb.g * 0.587 + rgb.b * 0.114); if (grayLevel < 192/**网上给的是140**/) { return true; } return false; }, //获取对比颜色 getContrastColor: function (color) { if (!color || !this.isColor(color)) { return ""; } if (this.isDarkColor(color)) { return "#ffffff"; } return "#1a1a1a"; }, rgb2hex: function (rgbColour) { if (!rgbColour || rgbColour.substr(0, 3) != "rgb") { return ""; } var rgbValues = rgbColour.match(/\d+(\.\d+)?/g); var red = BI.parseInt(rgbValues[0]); var green = BI.parseInt(rgbValues[1]); var blue = BI.parseInt(rgbValues[2]); var hexColour = "#" + this.int2hex(red) + this.int2hex(green) + this.int2hex(blue); return hexColour; }, rgb2json: function (rgbColour) { if (!rgbColour) { return {}; } if (!this.isRGBColor(rgbColour)) { return {}; } var rgbValues = rgbColour.match(/\d+(\.\d+)?/g); return { r: BI.parseInt(rgbValues[0]), g: BI.parseInt(rgbValues[1]), b: BI.parseInt(rgbValues[2]) }; }, rgba2json: function (rgbColour) { if (!rgbColour) { return {}; } var rgbValues = rgbColour.match(/\d+(\.\d+)?/g); return { r: BI.parseInt(rgbValues[0]), g: BI.parseInt(rgbValues[1]), b: BI.parseInt(rgbValues[2]), a: BI.parseFloat(rgbValues[3]) }; }, json2rgb: function (rgb) { if (!BI.isKey(rgb.r) || !BI.isKey(rgb.g) || !BI.isKey(rgb.b)) { return ""; } return "rgb(" + rgb.r + "," + rgb.g + "," + rgb.b + ")"; }, json2rgba: function (rgba) { if (!BI.isKey(rgba.r) || !BI.isKey(rgba.g) || !BI.isKey(rgba.b)) { return ""; } return "rgba(" + rgba.r + "," + rgba.g + "," + rgba.b + "," + rgba.a + ")"; }, int2hex: function (strNum) { var hexdig = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; return hexdig[strNum >>> 4] + '' + hexdig[strNum & 15]; }, hex2rgb: function (color) { if (!color) { return ""; } if (!this.isHexColor(color)) { return color; } var tempValue = "rgb(", colorArray; if (color.length === 7) { colorArray = [BI.parseInt('0x' + color.substring(1, 3)), BI.parseInt('0x' + color.substring(3, 5)), BI.parseInt('0x' + color.substring(5, 7))]; } else if (color.length === 4) { colorArray = [BI.parseInt('0x' + color.substring(1, 2)), BI.parseInt('0x' + color.substring(2, 3)), BI.parseInt('0x' + color.substring(3, 4))]; } tempValue += colorArray[0] + ","; tempValue += colorArray[1] + ","; tempValue += colorArray[2] + ")"; return tempValue; }, rgba2rgb: function (rgbColour, BGcolor) { if (BI.isNull(BGcolor)) { BGcolor = 1; } if (rgbColour.substr(0, 4) != "rgba") { return ""; } var rgbValues = rgbColour.match(/\d+(\.\d+)?/g); if (rgbValues.length < 4) { return ""; } var R = BI.parseFloat(rgbValues[0]); var G = BI.parseFloat(rgbValues[1]); var B = BI.parseFloat(rgbValues[2]); var A = BI.parseFloat(rgbValues[3]); return "rgb(" + Math.floor(255 * (BGcolor * (1 - A )) + R * A) + "," + Math.floor(255 * (BGcolor * (1 - A )) + G * A) + "," + Math.floor(255 * (BGcolor * (1 - A )) + B * A) + ")"; }, getTextSizeWidth: function (text, fontSize) { var span = $("<span></span>").addClass("text-width-span").appendTo($("body")); if (fontSize == null) { fontSize = 12; } fontSize = fontSize + "px"; span.css("font-size", fontSize).text(text); var width = span.width(); span.remove(); return width; }, //获取滚动条的宽度 getScrollWidth: function () { if (this._scrollWidth == null) { var ul = $("<div>").width(50).height(50).css({ position: "absolute", top: "-9999px", overflow: "scroll" }).appendTo($("body")); this._scrollWidth = ul[0].offsetWidth - ul[0].clientWidth; ul.destroy(); } return this._scrollWidth; } });/** * guy * 检测某个Widget的EventChange事件然后去show某个card * @type {*|void|Object} * @class BI.ShowListener * @extends BI.OB */ BI.ShowListener = BI.inherit(BI.OB, { _defaultConfig: function () { return BI.extend(BI.ShowListener.superclass._defaultConfig.apply(this, arguments), { eventObj: BI.createWidget(), cardLayout: null, cardNameCreator: function (v) { return v; }, cardCreator: BI.emptyFn, afterCardCreated: BI.emptyFn, afterCardShow: BI.emptyFn }); }, _init: function () { BI.ShowListener.superclass._init.apply(this, arguments); var self = this, o = this.options; o.eventObj.on(BI.Controller.EVENT_CHANGE, function (type, v, ob) { if (type === BI.Events.CLICK) { v = v || o.eventObj.getValue(); v = BI.isArray(v) ? (v.length > 1 ? v.toString() : v[0]) : v; if (BI.isNull(v)) { throw new Error("value cannot be null"); } var cardName = o.cardNameCreator(v); if (!o.cardLayout.isCardExisted(cardName)) { var card = o.cardCreator(cardName); o.cardLayout.addCardByName(cardName, card); o.afterCardCreated(cardName); } o.cardLayout.showCardByName(cardName); BI.nextTick(function () { o.afterCardShow(cardName); self.fireEvent(BI.ShowListener.EVENT_CHANGE, cardName); }); } }) } }); BI.ShowListener.EVENT_CHANGE = "ShowListener.EVENT_CHANGE";/** * style加载管理器 * * Created by GUY on 2015/9/7. * @class */ BI.StyleLoaderManager = BI.inherit(BI.OB, { _defaultConfig: function () { return BI.extend(BI.StyleLoaderManager.superclass._defaultConfig.apply(this, arguments), {}); }, _init: function () { BI.StyleLoaderManager.superclass._init.apply(this, arguments); this.stylesManager = {}; }, loadStyle: function (name, styleString) { var d = document, styles = d.createElement('style'); d.getElementsByTagName('head')[0].appendChild(styles); styles.setAttribute('type', 'text/css'); if (styles.styleSheet) { styles.styleSheet.cssText = styleString; } else { styles.appendChild(document.createTextNode(styleString)); } this.stylesManager[name] = styles; return this; }, get: function (name) { return this.stylesManager[name]; }, has: function (name) { return this.stylesManager[name] != null; }, removeStyle: function (name) { if (!this.has(name)) { return this; } this.stylesManager[name].parentNode.removeChild(this.stylesManager[name]); delete this.stylesManager[name]; return this; } });/** * @class BI.Logic * @extends BI.OB */ BI.Logic = BI.inherit(BI.OB, { createLogic: function () { return this.options || {}; } }); BI.LogicFactory = { Type: { Vertical: "vertical", Horizontal: "horizontal", Table: "table", HorizontalFill: "horizontal_fill" }, createLogic: function (key, options) { var logic; switch (key) { case BI.LogicFactory.Type.Vertical: logic = BI.VerticalLayoutLogic; break; case BI.LogicFactory.Type.Horizontal: logic = BI.HorizontalLayoutLogic; break; case BI.LogicFactory.Type.Table: logic = BI.TableLayoutLogic; break; case BI.LogicFactory.Type.HorizontalFill: logic = BI.HorizontalFillLayoutLogic; break; default : logic = BI.Logic; break; } return new logic(options).createLogic(); }, createLogicTypeByDirection: function (direction) { switch (direction) { case BI.Direction.Top: case BI.Direction.Bottom: case BI.Direction.Custom: return BI.LogicFactory.Type.Vertical; break; case BI.Direction.Left: case BI.Direction.Right: return BI.LogicFactory.Type.Horizontal; } }, createLogicItemsByDirection: function (direction) { var layout; var items = Array.prototype.slice.call(arguments, 1); items = BI.map(items, function (i, item) { if (BI.isWidget(item)) { return { el: item, width: item.options.width, height: item.options.height } } return item; }); switch (direction) { case BI.Direction.Bottom: layout = BI.LogicFactory.Type.Vertical; items.reverse(); break; case BI.Direction.Right: layout = BI.LogicFactory.Type.Horizontal; items.reverse(); break; case BI.Direction.Custom: items = items.slice(1); break; } return items; } };/** * guy * 上下布局逻辑 * 上下布局的时候要考虑到是动态布局还是静态布局 * * @class BI.VerticalLayoutLogic * @extends BI.Logic */ BI.VerticalLayoutLogic = BI.inherit(BI.Logic, { _defaultConfig: function () { return BI.extend(BI.VerticalLayoutLogic.superclass._defaultConfig.apply(this, arguments), { dynamic: false, scrollable: null, scrolly: false, scrollx: false, items: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, createLogic: function () { var layout, o = this.options; if (o.dynamic) { layout = "bi.vertical"; } else { layout = "bi.vtape"; } return { type: layout, scrollable: o.scrollable, scrolly: o.scrolly, scrollx: o.scrollx, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, items: o.items } }, _init: function () { BI.VerticalLayoutLogic.superclass._init.apply(this, arguments); } }); /** * guy * 左右布局逻辑 * 左右布局的时候要考虑到是动态布局还是静态布局 * * @class BI.HorizontalLayoutLogic * @extends BI.Logic */ BI.HorizontalLayoutLogic = BI.inherit(BI.Logic, { _defaultConfig: function () { return BI.extend(BI.HorizontalLayoutLogic.superclass._defaultConfig.apply(this, arguments), { dynamic: false, scrollable: null, scrolly: false, scrollx: false, items: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, createLogic: function () { var layout, o = this.options; if (o.dynamic) { layout = "bi.horizontal"; } else { layout = "bi.htape"; } return { type: layout, scrollable: o.scrollable, scrolly: o.scrolly, scrollx: o.scrollx, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, items: o.items } }, _init: function () { BI.HorizontalLayoutLogic.superclass._init.apply(this, arguments); } }); /** * guy * 表格布局逻辑 * 表格布局的时候要考虑到是动态布局还是静态布局 * * @class BI.TableLayoutLogic * @extends BI.OB */ BI.TableLayoutLogic = BI.inherit(BI.Logic, { _defaultConfig: function () { return BI.extend(BI.TableLayoutLogic.superclass._defaultConfig.apply(this, arguments), { dynamic: false, scrollable: null, scrolly: false, scrollx: false, columns: 0, rows: 0, columnSize: [], rowSize: [], hgap: 0, vgap: 0, items: [] }); }, createLogic: function () { var layout, o = this.options; if (o.dynamic) { layout = "bi.table"; } else { layout = "bi.window"; } return { type: layout, scrollable: o.scrollable, scrolly: o.scrolly, scrollx: o.scrollx, columns: o.columns, rows: o.rows, columnSize: o.columnSize, rowSize: o.rowSize, hgap: o.hgap, vgap: o.vgap, items: o.items } }, _init: function () { BI.TableLayoutLogic.superclass._init.apply(this, arguments); } }); /** * guy * 左右充满布局逻辑 * * @class BI.HorizontalFillLayoutLogic * @extends BI.Logic */ BI.HorizontalFillLayoutLogic = BI.inherit(BI.Logic, { _defaultConfig: function () { return BI.extend(BI.HorizontalFillLayoutLogic.superclass._defaultConfig.apply(this, arguments), { dynamic: false, scrollable: null, scrolly: false, scrollx: false, items: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, createLogic: function () { var layout, o = this.options; var columnSize = []; BI.each(o.items, function (i, item) { columnSize.push(item.width || 0); }); if (o.dynamic) { layout = "bi.horizontal_adapt"; } else { layout = "bi.htape"; } return { type: layout, columnSize: columnSize, scrollable: o.scrollable, scrolly: o.scrolly, scrollx: o.scrollx, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, items: o.items } }, _init: function () { BI.HorizontalFillLayoutLogic.superclass._init.apply(this, arguments); } });BI.Plugin = BI.Plugin || {}; ; (function () { var _WidgetsPlugin = {}; var _ObjectPlugin = {}; BI.extend(BI.Plugin, { getWidget: function (type, options) { if (_WidgetsPlugin[type]) { var res; for (var i = _WidgetsPlugin[type].length-1; i >=0; i--) { if (res = _WidgetsPlugin[type][i](options)) { return res; } } } return options; }, registerWidget: function (type, fn) { if (!_WidgetsPlugin[type]) { _WidgetsPlugin[type] = []; } if (_WidgetsPlugin[type].length > 0) { console.log("组件已经注册过了!"); } _WidgetsPlugin[type].push(fn); }, relieveWidget: function (type) { delete _WidgetsPlugin[type]; }, getObject: function (type, object) { if (_ObjectPlugin[type]) { var res; for (var i = 0, len = _ObjectPlugin[type].length; i < len; i++) { res = _ObjectPlugin[type][i](object); } } return res || object; }, registerObject: function (type, fn) { if (!_ObjectPlugin[type]) { _ObjectPlugin[type] = []; } if (_ObjectPlugin[type].length > 0) { console.log("对象已经注册过了!"); } _ObjectPlugin[type].push(fn); }, relieveObject: function (type) { delete _ObjectPlugin[type]; } }); })();/** * 对数组对象的扩展 * @class Array */ $.extend(Array.prototype, { contains: function (o) { return this.indexOf(o) > -1; }, /** * 从数组中移除指定的值,如果值不在数组中,则不产生任何效果 * @param {Object} o 要移除的值 * @return {Array} 移除制定值后的数组 */ remove: function (o) { var index = this.indexOf(o); if (index !== -1) { this.splice(index, 1); } return this; }, pushArray: function (array) { for (var i = 0; i < array.length; i++) { this.push(array[i]); } }, pushDistinct: function (obj) { if (!this.contains(obj)) { this.push(obj); } }, pushDistinctArray: function (array) { for (var i = 0, len = array.length; i < len; i++) { this.pushDistinct(array[i]); } } }); BI.Cache = { _prefix: "bi", setUsername: function (username) { localStorage.setItem(BI.Cache._prefix + ".username", (username + "" || "").toUpperCase()); }, getUsername: function () { return localStorage.getItem(BI.Cache._prefix + ".username") || ""; }, _getKeyPrefix: function () { return BI.Cache.getUsername() + "." + BI.Cache._prefix + "."; }, _generateKey: function (key) { return BI.Cache._getKeyPrefix() + (key || ""); }, getItem: function (key) { return localStorage.getItem(BI.Cache._generateKey(key)); }, setItem: function (key, value) { localStorage.setItem(BI.Cache._generateKey(key), value); }, removeItem: function (key) { localStorage.removeItem(BI.Cache._generateKey(key)); }, clear: function () { for (var i = localStorage.length; i >= 0; i--) { var key = localStorage.key(i); if (key) { if (key.indexOf(BI.Cache._getKeyPrefix()) === 0) { localStorage.removeItem(key); } } } }, keys: function () { var result = []; for (var i = localStorage.length; i >= 0; i--) { var key = localStorage.key(i); if (key) { var prefix = BI.Cache._getKeyPrefix(); if (key.indexOf(prefix) === 0) { result[result.length] = key.substring(prefix.length); } } } return result; }, addCookie: function (name, value, path, expiresHours) { var cookieString = name + "=" + escape(value); // 判断是否设置过期时间 if (expiresHours && expiresHours > 0) { var date = new Date(); date.setTime(date.getTime() + expiresHours * 3600 * 1000); cookieString = cookieString + "; expires=" + date.toGMTString(); } if (path) { cookieString = cookieString + "; path=" + path; } document.cookie = cookieString; }, getCookie: function (name) { var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)"); if (arr = document.cookie.match(reg)) return unescape(arr[2]); else return null; }, deleteCookie: function (name, path) { var date = new Date(); date.setTime(date.getTime() - 10000); var cookieString = name + "=v; expires=" + date.toGMTString(); if (path) { cookieString = cookieString + "; path=" + path; } document.cookie = cookieString; } };// full day names Date._DN = [BI.i18nText("BI-Basic_Sunday"), BI.i18nText("BI-Basic_Monday"), BI.i18nText("BI-Basic_Tuesday"), BI.i18nText("BI-Basic_Wednesday"), BI.i18nText("BI-Basic_Thursday"), BI.i18nText("BI-Basic_Friday"), BI.i18nText("BI-Basic_Saturday"), BI.i18nText("BI-Basic_Sunday")]; // short day names Date._SDN = [BI.i18nText("BI-Basic_Simple_Sunday"), BI.i18nText("BI-Basic_Simple_Monday"), BI.i18nText("BI-Basic_Simple_Tuesday"), BI.i18nText("BI-Basic_Simple_Wednesday"), BI.i18nText("BI-Basic_Simple_Thursday"), BI.i18nText("BI-Basic_Simple_Friday"), BI.i18nText("BI-Basic_Simple_Saturday"), BI.i18nText("BI-Basic_Simple_Sunday")]; // Monday first, etc. Date._FD = 1; // full month namesdat Date._MN = [ BI.i18nText("BI-Basic_January"), BI.i18nText("BI-Basic_February"), BI.i18nText("BI-Basic_March"), BI.i18nText("BI-Basic_April"), BI.i18nText("BI-Basic_May"), BI.i18nText("BI-Basic_June"), BI.i18nText("BI-Basic_July"), BI.i18nText("BI-Basic_August"), BI.i18nText("BI-Basic_September"), BI.i18nText("BI-Basic_October"), BI.i18nText("BI-Basic_November"), BI.i18nText("BI-Basic_December")]; // short month names Date._SMN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; Date._QN = ["", BI.i18nText("BI-Quarter_1"), BI.i18nText("BI-Quarter_2"), BI.i18nText("BI-Quarter_3"), BI.i18nText("BI-Quarter_4")]; /** Adds the number of days array to the Date object. */ Date._MD = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; /** Constants used for time computations */ Date.SECOND = 1000 /* milliseconds */; Date.MINUTE = 60 * Date.SECOND; Date.HOUR = 60 * Date.MINUTE; Date.DAY = 24 * Date.HOUR; Date.WEEK = 7 * Date.DAY; /** * 获取时区 * @returns {String} */ Date.prototype.getTimezone = function () { return this.toString().replace(/^.* (?:\((.*)\)|([A-Z]{1,4})(?:[\-+][0-9]{4})?(?: -?\d+)?)$/, "$1$2").replace(/[^A-Z]/g, ""); }; /** Returns the number of days in the current month */ Date.prototype.getMonthDays = function (month) { var year = this.getFullYear(); if (typeof month == "undefined") { month = this.getMonth(); } if (((0 == (year % 4)) && ( (0 != (year % 100)) || (0 == (year % 400)))) && month == 1) { return 29; } else { return Date._MD[month]; } }; /** Returns the number of day in the year. */ Date.prototype.getDayOfYear = function () { var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0); var time = now - then; return Math.floor(time / Date.DAY); }; /** Returns the number of the week in year, as defined in ISO 8601. */ Date.prototype.getWeekNumber = function () { var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0); var week = d.getDay(); if (this.getMonth() === 0 && this.getDate() <= week) { return 1; } d.setDate(this.getDate() - week); var ms = d.valueOf(); // GMT d.setMonth(0); d.setDate(1); var offset = Math.floor((ms - d.valueOf()) / (7 * 864e5)) + 1; if (d.getDay() > 0) { offset++; } return offset; }; //离当前时间多少天的时间 Date.prototype.getOffsetDate = function (offset) { return new Date(this.getTime() + offset * 864e5); }; Date.prototype.getAfterMulQuarter = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() + n * 3); return dt; }; //获得n个季度前的日期 Date.prototype.getBeforeMulQuarter = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() - n * 3); return dt; }; //得到本季度的起始月份 Date.prototype.getQuarterStartMonth = function () { var quarterStartMonth = 0; var nowMonth = this.getMonth(); if (nowMonth < 3) { quarterStartMonth = 0; } if (2 < nowMonth && nowMonth < 6) { quarterStartMonth = 3; } if (5 < nowMonth && nowMonth < 9) { quarterStartMonth = 6; } if (nowMonth > 8) { quarterStartMonth = 9; } return quarterStartMonth; }; //获得本季度的起始日期 Date.prototype.getQuarterStartDate = function () { return new Date(this.getFullYear(), this.getQuarterStartMonth(), 1); }; //得到本季度的结束日期 Date.prototype.getQuarterEndDate = function () { var quarterEndMonth = this.getQuarterStartMonth() + 2; return new Date(this.getFullYear(), quarterEndMonth, this.getMonthDays(quarterEndMonth)); }; Date.prototype.getAfterMultiMonth = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() + n | 0); return dt; }; Date.prototype.getBeforeMultiMonth = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() - n | 0); return dt; }; Date.prototype.getAfterMulQuarter = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() + n * 3); return dt; }; //获得n个季度前的日期 Date.prototype.getBeforeMulQuarter = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() - n * 3); return dt; }; //得到本季度的起始月份 Date.prototype.getQuarterStartMonth = function () { var quarterStartMonth = 0; var nowMonth = this.getMonth(); if (nowMonth < 3) { quarterStartMonth = 0; } if (2 < nowMonth && nowMonth < 6) { quarterStartMonth = 3; } if (5 < nowMonth && nowMonth < 9) { quarterStartMonth = 6; } if (nowMonth > 8) { quarterStartMonth = 9; } return quarterStartMonth; }; //指定日期n个月之前或之后的日期 Date.prototype.getOffsetMonth = function (n) { var dt = new Date(this.getTime()); var day = dt.getDate(); var monthDay = new Date(dt.getFullYear(), dt.getMonth() + parseInt(n), 1).getMonthDays(); if (day > monthDay) { day = monthDay; } dt.setDate(day); dt.setMonth(dt.getMonth() + parseInt(n)); return dt; }; //获得本周的起始日期 Date.prototype.getWeekStartDate = function () { var w = this.getDay(); return this.getOffsetDate(-w); }; //得到本周的结束日期 Date.prototype.getWeekEndDate = function () { var w = this.getDay(); var offset = (w === 0 ? 6 : 6 - w); return this.getOffsetDate(offset); }; //获得本季度的起始日期 Date.prototype.getQuarterStartDate = function () { return new Date(this.getFullYear(), this.getQuarterStartMonth(), 1); }; //得到本季度的结束日期 Date.prototype.getQuarterEndDate = function () { var quarterEndMonth = this.getQuarterStartMonth() + 2; return new Date(this.getFullYear(), quarterEndMonth, this.getMonthDays(quarterEndMonth)); }; Date.prototype.getAfterMultiMonth = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() + n | 0); return dt; }; Date.prototype.getBeforeMultiMonth = function (n) { var dt = new Date(this.getTime()); dt.setMonth(dt.getMonth() - n | 0); return dt; }; /** Checks date and time equality */ Date.prototype.equalsTo = function (date) { return ((this.getFullYear() == date.getFullYear()) && (this.getMonth() == date.getMonth()) && (this.getDate() == date.getDate()) && (this.getHours() == date.getHours()) && (this.getMinutes() == date.getMinutes()) && (this.getSeconds() == date.getSeconds())); }; /** Set only the year, month, date parts (keep existing time) */ Date.prototype.setDateOnly = function (date) { var tmp = new Date(date); this.setDate(1); this.setFullYear(tmp.getFullYear()); this.setMonth(tmp.getMonth()); this.setDate(tmp.getDate()); }; /** Prints the date in a string according to the given format. */ Date.prototype.print = function (str) { var m = this.getMonth(); var d = this.getDate(); var y = this.getFullYear(); var wn = this.getWeekNumber(); var w = this.getDay(); var s = {}; var hr = this.getHours(); var pm = (hr >= 12); var ir = (pm) ? (hr - 12) : hr; var dy = this.getDayOfYear(); if (ir == 0) { ir = 12; } var min = this.getMinutes(); var sec = this.getSeconds(); s["%a"] = Date._SDN[w]; // abbreviated weekday name [FIXME: I18N] s["%A"] = Date._DN[w]; // full weekday name s["%b"] = Date._SMN[m]; // abbreviated month name [FIXME: I18N] s["%B"] = Date._MN[m]; // full month name // FIXME: %c : preferred date and time representation for the current locale s["%C"] = 1 + Math.floor(y / 100); // the century number s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31) s["%e"] = d; // the day of the month (range 1 to 31) // FIXME: %D : american date style: %m/%d/%y // FIXME: %E, %F, %G, %g, %h (man strftime) s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format) s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format) s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366) s["%k"] = hr; // hour, range 0 to 23 (24h format) s["%l"] = ir; // hour, range 1 to 12 (12h format) s["%X"] = (m < 9) ? ("0" + (1 + m)) : (1 + m); // month, range 01 to 12 s["%x"] = m + 1 // month, range 1 to 12 s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59 s["%n"] = "\n"; // a newline character s["%p"] = pm ? "PM" : "AM"; s["%P"] = pm ? "pm" : "am"; // FIXME: %r : the time in am/pm notation %I:%M:%S %p // FIXME: %R : the time in 24-hour notation %H:%M s["%s"] = Math.floor(this.getTime() / 1000); s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59 s["%t"] = "\t"; // a tab character // FIXME: %T : the time in 24-hour notation (%H:%M:%S) s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn; s["%u"] = w + 1; // the day of the week (range 1 to 7, 1 = MON) s["%w"] = w; // the day of the week (range 0 to 6, 0 = SUN) // FIXME: %x : preferred date representation for the current locale without the time // FIXME: %X : preferred time representation for the current locale without the date s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99) s["%Y"] = y; // year with the century s["%%"] = "%"; // a literal '%' character var re = /%./g; if (!BI.isKhtml()) { return str.replace(re, function (par) { return s[par] || par; }); } var a = str.match(re); for (var i = 0; i < a.length; i++) { var tmp = s[a[i]]; if (tmp) { re = new RegExp(a[i], 'g'); str = str.replace(re, tmp); } } return str; }; /** * 是否是闰年 * @param year * @returns {boolean} */ Date.isLeap = function (year) { return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; }; /** * 检测是否在有效期 * * @param YY 年 * @param MM 月 * @param DD 日 * @param minDate '1900-01-01' * @param maxDate '2099-12-31' * @returns {Array} 若无效返回无效状态 */ Date.checkVoid = function (YY, MM, DD, minDate, maxDate) { var back = []; YY = YY | 0; MM = MM | 0; DD = DD | 0; minDate = BI.isString(minDate) ? minDate.match(/\d+/g) : minDate; maxDate = BI.isString(maxDate) ? maxDate.match(/\d+/g) : maxDate; if (YY < minDate[0]) { back = ['y']; } else if (YY > maxDate[0]) { back = ['y', 1]; } else if (YY >= minDate[0] && YY <= maxDate[0]) { if (YY == minDate[0]) { if (MM < minDate[1]) { back = ['m']; } else if (MM == minDate[1]) { if (DD < minDate[2]) { back = ['d']; } } } if (YY == maxDate[0]) { if (MM > maxDate[1]) { back = ['m', 1]; } else if (MM == maxDate[1]) { if (DD > maxDate[2]) { back = ['d', 1]; } } } } return back; }; Date.checkLegal = function (str) { var ar = str.match(/\d+/g); var YY = ar[0] | 0, MM = ar[1] | 0, DD = ar[2] | 0; if (ar.length <= 1) { return true; } if (ar.length <= 2) { return MM >= 1 && MM <= 12; } var MD = Date._MD.slice(0); MD[1] = Date.isLeap(YY) ? 29 : 28; return MM >= 1 && MM <= 12 && DD <= MD[MM - 1]; }; Date.parseDateTime = function (str, fmt) { var today = new Date(); var y = 0; var m = 0; var d = 1; //wei : 对于fmt为‘YYYYMM’或者‘YYYYMMdd’的格式,str的值为类似'201111'的形式,因为年月之间没有分隔符,所以正则表达式分割无效,导致bug7376。 var a = str.split(/\W+/); if (fmt.toLowerCase() == '%y%x' || fmt.toLowerCase() == '%y%x%d') { var yearlength = 4; var otherlength = 2; a[0] = str.substring(0, yearlength); a[1] = str.substring(yearlength, yearlength + otherlength); a[2] = str.substring(yearlength + otherlength, yearlength + otherlength * 2); } var b = fmt.match(/%./g); var i = 0, j = 0; var hr = 0; var min = 0; var sec = 0; for (i = 0; i < a.length; ++i) { switch (b[i]) { case "%d": case "%e": d = parseInt(a[i], 10); break; case "%X": m = parseInt(a[i], 10) - 1; break; case "%x": m = parseInt(a[i], 10) - 1; break; case "%Y": case "%y": y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); break; case "%b": case "%B": for (j = 0; j < 12; ++j) { if (Date._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; } } break; case "%H": case "%I": case "%k": case "%l": hr = parseInt(a[i], 10); break; case "%P": case "%p": if (/pm/i.test(a[i]) && hr < 12) { hr += 12; } else if (/am/i.test(a[i]) && hr >= 12) { hr -= 12; } break; case "%M": min = parseInt(a[i], 10); case "%S": sec = parseInt(a[i], 10); break; } } // if (!a[i]) { // continue; // } if (isNaN(y)) { y = today.getFullYear(); } if (isNaN(m)) { m = today.getMonth(); } if (isNaN(d)) { d = today.getDate(); } if (isNaN(hr)) { hr = today.getHours(); } if (isNaN(min)) { min = today.getMinutes(); } if (isNaN(sec)) { sec = today.getSeconds(); } if (y != 0) { return new Date(y, m, d, hr, min, sec); } y = 0; m = -1; d = 0; for (i = 0; i < a.length; ++i) { if (a[i].search(/[a-zA-Z]+/) != -1) { var t = -1; for (j = 0; j < 12; ++j) { if (Date._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; } } if (t != -1) { if (m != -1) { d = m + 1; } m = t; } } else if (parseInt(a[i], 10) <= 12 && m == -1) { m = a[i] - 1; } else if (parseInt(a[i], 10) > 31 && y == 0) { y = parseInt(a[i], 10); (y < 100) && (y += (y > 29) ? 1900 : 2000); } else if (d == 0) { d = a[i]; } } if (y == 0) { y = today.getFullYear(); } if (m != -1 && d != 0) { return new Date(y, m, d, hr, min, sec); } return today; }; /* * 给jQuery.Event对象添加的工具方法 */ $.extend($.Event.prototype, { // event.stopEvent stopEvent: function () { this.stopPropagation(); this.preventDefault(); } });Function.prototype.before = function (func) { var __self = this; return function () { if (func.apply(this, arguments) === false) { return false; } return __self.apply(this, arguments); } }; Function.prototype.after = function (func) { var __self = this; return function () { var ret = __self.apply(this, arguments); if (ret === false) { return false; } func.apply(this, arguments); return ret; } };/*! * jLayout JQuery Plugin v0.11 * * Licensed under the revised BSD License. * Copyright 2008, Bram Stein * All rights reserved. */ if (jQuery) { (function ($) { // richer:容器在其各个边缘留出的空间 if (!$.fn.insets) { $.fn.insets = function () { var p = this.padding(), b = this.border(); return { 'top': p.top, 'bottom': p.bottom + b.bottom + b.top, 'left': p.left, 'right': p.right + b.right + b.left }; }; } // richer:获取 && 设置jQuery元素的边界 if (!$.fn.bounds) { $.fn.bounds = function (value) { var tmp = {hasIgnoredBounds: true}; if (value) { if (!isNaN(value.x)) { tmp.left = value.x; } if (!isNaN(value.y)) { tmp.top = value.y; } if (value.width != null) { tmp.width = (value.width - (this.outerWidth(true) - this.width())); tmp.width = (tmp.width >= 0) ? tmp.width : value.width; // fix chrome //tmp.width = (tmp.width >= 0) ? tmp.width : 0; } if (value.height != null) { tmp.height = value.height - (this.outerHeight(true) - this.height()); tmp.height = (tmp.height >= 0) ? tmp.height : value.height; // fix chrome //tmp.height = (tmp.height >= 0) ? tmp.height : value.0; } this.css(tmp); return this; } else { // richer:注意此方法只对可见元素有效 tmp = this.position(); return { 'x': tmp.left, 'y': tmp.top, // richer:这里计算外部宽度和高度的时候,都不包括边框 'width': this.outerWidth(), 'height': this.outerHeight() }; } }; } })(jQuery); } ;if (!Number.prototype.toFixed || (0.00008).toFixed(3) !== '0.000' || (0.9).toFixed(0) === '0' || (1.255).toFixed(2) !== '1.25' || (1000000000000000128).toFixed(0) !== "1000000000000000128") { (function () { var base, size, data, i; base = 1e7; size = 6; data = [0, 0, 0, 0, 0, 0]; function multiply(n, c) { var i = -1; while (++i < size) { c += n * data[i]; data[i] = c % base; c = Math.floor(c / base); } } function divide(n) { var i = size, c = 0; while (--i >= 0) { c += data[i]; data[i] = Math.floor(c / n); c = (c % n) * base; } } function toString() { var i = size; var s = ''; while (--i >= 0) { if (s !== '' || i === 0 || data[i] !== 0) { var t = String(data[i]); if (s === '') { s = t; } else { s += '0000000'.slice(0, 7 - t.length) + t; } } } return s; } function pow(x, n, acc) { return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc))); } function log(x) { var n = 0; while (x >= 4096) { n += 12; x /= 4096; } while (x >= 2) { n += 1; x /= 2; } return n; } Number.prototype.toFixed = function (fractionDigits) { var f, x, s, m, e, z, j, k; f = Number(fractionDigits); f = f !== f ? 0 : Math.floor(f); if (f < 0 || f > 20) { throw new RangeError('Number.toFixed called with invalid number of decimals'); } x = Number(this); if (x !== x) { return "NaN"; } if (x <= -1e21 || x > 1e21) { return String(x); } s = ""; if (x < 0) { s = "-"; x = -x; } m = "0"; if (x > 1e-21) { //1e-21<x<1e21 //-70<log2(x)<70 e = log(x * pow(2, 69, 1)) - 69; z = (e < 0 ? x * pow(2, -e, 1) : x / pow(2, e, 1)); z *= 0x10000000000000;//Math.pow(2,52); e = 52 - e; //-18<e<122 //x=z/2^e if (e > 0) { multiply(0, z); j = f; while (j >= 7) { multiply(1e7, 0); j -= 7; } multiply(pow(10, j, 1), 0); j = e - 1; while (j >= 23) { divide(1 << 23); j -= 23; } divide(1 << j); multiply(1, 1); divide(2); m = toString(); } else { multiply(0, z); multiply(1 << (-e), 0); m = toString() + '0.00000000000000000000'.slice(2, 2 + f); } } if (f > 0) { k = m.length; if (k <= f) { m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m; } else { m = s + m.slice(0, k - f) + '.' + m.slice(k - f); } } else { m = s + m; } return m; } })(); } /** ** 加法函数,用来得到精确的加法结果 ** 说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果。 ** 调用:accAdd(arg1,arg2) ** 返回值:arg1加上arg2的精确结果 **/ function accAdd(arg1, arg2) { var r1, r2, m, c; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } c = Math.abs(r1 - r2); m = Math.pow(10, Math.max(r1, r2)); if (c > 0) { var cm = Math.pow(10, c); if (r1 > r2) { arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")) * cm; } else { arg1 = Number(arg1.toString().replace(".", "")) * cm; arg2 = Number(arg2.toString().replace(".", "")); } } else { arg1 = Number(arg1.toString().replace(".", "")); arg2 = Number(arg2.toString().replace(".", "")); } return (arg1 + arg2) / m; } //给Number类型增加一个add方法,调用起来更加方便。 Number.prototype.add = function (arg) { return accAdd(arg, this); }; /** ** 减法函数,用来得到精确的减法结果 ** 说明:javascript的减法结果会有误差,在两个浮点数相减的时候会比较明显。这个函数返回较为精确的减法结果。 ** 调用:accSub(arg1,arg2) ** 返回值:arg1加上arg2的精确结果 **/ function accSub(arg1, arg2) { var r1, r2, m, n; try { r1 = arg1.toString().split(".")[1].length; } catch (e) { r1 = 0; } try { r2 = arg2.toString().split(".")[1].length; } catch (e) { r2 = 0; } m = Math.pow(10, Math.max(r1, r2)); //last modify by deeka //动态控制精度长度 n = (r1 >= r2) ? r1 : r2; return ((arg1 * m - arg2 * m) / m).toFixed(n); } // 给Number类型增加一个mul方法,调用起来更加方便。 Number.prototype.sub = function (arg) { return accSub(this, arg); }; /** ** 乘法函数,用来得到精确的乘法结果 ** 说明:javascript的乘法结果会有误差,在两个浮点数相乘的时候会比较明显。这个函数返回较为精确的乘法结果。 ** 调用:accMul(arg1,arg2) ** 返回值:arg1乘以 arg2的精确结果 **/ function accMul(arg1, arg2) { var m = 0, s1 = arg1.toString(), s2 = arg2.toString(); try { m += s1.split(".")[1].length; } catch (e) { } try { m += s2.split(".")[1].length; } catch (e) { } return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m); } // 给Number类型增加一个mul方法,调用起来更加方便。 Number.prototype.mul = function (arg) { return accMul(arg, this); }; /** ** 除法函数,用来得到精确的除法结果 ** 说明:javascript的除法结果会有误差,在两个浮点数相除的时候会比较明显。这个函数返回较为精确的除法结果。 ** 调用:accDiv(arg1,arg2) ** 返回值:arg1除以arg2的精确结果 **/ function accDiv(arg1, arg2) { var t1 = 0, t2 = 0, r1, r2; try { t1 = arg1.toString().split(".")[1].length; } catch (e) { } try { t2 = arg2.toString().split(".")[1].length; } catch (e) { } with (Math) { r1 = Number(arg1.toString().replace(".", "")); r2 = Number(arg2.toString().replace(".", "")); return (t2 > t1) ? (r1 / r2) * pow(10, t2 - t1) : (r1 / r2) / pow(10, t1 - t2); } } //给Number类型增加一个div方法,调用起来更加方便。 Number.prototype.div = function (arg) { return accDiv(this, arg); };/** * 对字符串对象的扩展 * @class String */ $.extend(String.prototype, { /** * 判断字符串是否已指定的字符串开始 * @param {String} startTag 指定的开始字符串 * @return {Boolean} 如果字符串以指定字符串开始则返回true,否则返回false */ startWith: function (startTag) { if (startTag == null || startTag == "" || this.length === 0 || startTag.length > this.length) { return false; } return this.substr(0, startTag.length) == startTag; }, /** * 判断字符串是否以指定的字符串结束 * @param {String} endTag 指定的字符串 * @return {Boolean} 如果字符串以指定字符串结束则返回true,否则返回false */ endWith: function (endTag) { if (endTag == null || endTag == "" || this.length === 0 || endTag.length > this.length) { return false; } return this.substring(this.length - endTag.length) == endTag; }, /** * 获取url中指定名字的参数 * @param {String} name 参数的名字 * @return {String} 参数的值 */ getQuery: function (name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = this.substr(this.indexOf("?") + 1).match(reg); if (r) { return unescape(r[2]); } return null; }, /** * 给url加上给定的参数 * @param {Object} paras 参数对象,是一个键值对对象 * @return {String} 添加了给定参数的url */ appendQuery: function (paras) { if (!paras) { return this; } var src = this; // 没有问号说明还没有参数 if (src.indexOf("?") === -1) { src += "?"; } // 如果以问号结尾,说明没有其他参数 if (src.endWith("?") !== false) { } else { src += "&"; } $.each(paras, function (name, value) { if (typeof(name) === 'string') { src += name + "=" + value + "&"; } }); src = src.substr(0, src.length - 1); return src; }, /** * 将所有符合第一个字符串所表示的字符串替换成为第二个字符串 * @param {String} s1 要替换的字符串的正则表达式 * @param {String} s2 替换的结果字符串 * @returns {String} 替换后的字符串 */ replaceAll: function (s1, s2) { return this.replace(new RegExp(s1, "gm"), s2); }, /** * 总是让字符串以指定的字符开头 * @param {String} start 指定的字符 * @returns {String} 以指定字符开头的字符串 */ perfectStart: function (start) { if (this.startWith(start)) { return this; } else { return start + this; } }, /** * 获取字符串中某字符串的所有项位置数组 * @param {String} sub 子字符串 * @return {Number[]} 子字符串在父字符串中出现的所有位置组成的数组 */ allIndexOf: function (sub) { if (typeof sub != 'string') { return []; } var str = this; var location = []; var offset = 0; while (str.length > 0) { var loc = str.indexOf(sub); if (loc === -1) { break; } location.push(offset + loc); str = str.substring(loc + sub.length, str.length); offset += loc + sub.length; } return location; } }); /** * 对字符串对象的扩展 * @class String */ $.extend(String, { /** * 对字符串中的'和\做编码处理 * @static * @param {String} string 要做编码处理的字符串 * @return {String} 编码后的字符串 */ escape: function (string) { return string.replace(/('|\\)/g, "\\$1"); }, /** * 让字符串通过指定字符做补齐的函数 * * var s = String.leftPad('123', 5, '0');//s的值为:'00123' * * @static * @param {String} val 原始值 * @param {Number} size 总共需要的位数 * @param {String} ch 用于补齐的字符 * @return {String} 补齐后的字符串 */ leftPad: function (val, size, ch) { var result = String(val); if (!ch) { ch = " "; } while (result.length < size) { result = ch + result; } return result.toString(); }, /** * 对字符串做替换的函数 * * var cls = 'my-class', text = 'Some text'; * var res = String.format('<div class="{0}>{1}</div>"', cls, text); * //res的值为:'<div class="my-class">Some text</div>'; * * @static * @param {String} format 要做替换的字符串,替换字符串1,替换字符串2... * @return {String} 做了替换后的字符串 */ format: function (format) { var args = Array.prototype.slice.call(arguments, 1); return format.replace(/\{(\d+)\}/g, function (m, i) { return args[i]; }); } });BI.EventListener = { listen: function listen(target, eventType, callback) { if (target.addEventListener) { target.addEventListener(eventType, callback, false); return { remove: function remove() { target.removeEventListener(eventType, callback, false); } }; } else if (target.attachEvent) { target.attachEvent('on' + eventType, callback); return { remove: function remove() { target.detachEvent('on' + eventType, callback); } }; } }, capture: function capture(target, eventType, callback) { if (target.addEventListener) { target.addEventListener(eventType, callback, true); return { remove: function remove() { target.removeEventListener(eventType, callback, true); } }; } else { return { remove: BI.emptyFn }; } }, registerDefault: function registerDefault() { } };!(function () { var cancelAnimationFrame = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame || window.clearTimeout; var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout; BI.MouseMoveTracker = function (onMove, onMoveEnd, domNode) { this._isDragging = false; this._animationFrameID = null; this._domNode = domNode; this._onMove = onMove; this._onMoveEnd = onMoveEnd; this._onMouseMove = BI.bind(this._onMouseMove, this); this._onMouseUp = BI.bind(this._onMouseUp, this); this._didMouseMove = BI.bind(this._didMouseMove, this); }; BI.MouseMoveTracker.prototype = { constructor: BI.MouseMoveTracker, captureMouseMoves: function (/*object*/ event) { if (!this._eventMoveToken && !this._eventUpToken) { this._eventMoveToken = BI.EventListener.listen( this._domNode, 'mousemove', this._onMouseMove ); this._eventUpToken = BI.EventListener.listen( this._domNode, 'mouseup', this._onMouseUp ); } if (!this._isDragging) { this._deltaX = 0; this._deltaY = 0; this._isDragging = true; this._x = event.clientX; this._y = event.clientY; } event.preventDefault ? event.preventDefault() : (event.returnValue = false); }, releaseMouseMoves: function () { if (this._eventMoveToken && this._eventUpToken) { this._eventMoveToken.remove(); this._eventMoveToken = null; this._eventUpToken.remove(); this._eventUpToken = null; } if (this._animationFrameID !== null) { cancelAnimationFrame(this._animationFrameID); this._animationFrameID = null; } if (this._isDragging) { this._isDragging = false; this._x = null; this._y = null; } }, isDragging: function () /*boolean*/ { return this._isDragging; }, _onMouseMove: function (/*object*/ event) { var x = event.clientX; var y = event.clientY; this._deltaX += (x - this._x); this._deltaY += (y - this._y); if (this._animationFrameID === null) { // The mouse may move faster then the animation frame does. // Use `requestAnimationFrame` to avoid over-updating. this._animationFrameID = requestAnimationFrame(this._didMouseMove); } this._x = x; this._y = y; event.preventDefault ? event.preventDefault() : (event.returnValue = false); }, _didMouseMove: function () { this._animationFrameID = null; this._onMove(this._deltaX, this._deltaY); this._deltaX = 0; this._deltaY = 0; }, _onMouseUp: function () { if (this._animationFrameID) { this._didMouseMove(); } this._onMoveEnd(); } }; })();!(function () { var PIXEL_STEP = 10; var LINE_HEIGHT = 40; var PAGE_HEIGHT = 800; var requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || window.setTimeout; function normalizeWheel(/*object*/event) /*object*/ { var sX = 0, sY = 0, // spinX, spinY pX = 0, pY = 0; // pixelX, pixelY // Legacy if ('detail' in event) { sY = event.detail; } if ('wheelDelta' in event) { sY = -event.wheelDelta / 120; } if ('wheelDeltaY' in event) { sY = -event.wheelDeltaY / 120; } if ('wheelDeltaX' in event) { sX = -event.wheelDeltaX / 120; } // side scrolling on FF with DOMMouseScroll if ('axis' in event && event.axis === event.HORIZONTAL_AXIS) { sX = sY; sY = 0; } pX = sX * PIXEL_STEP; pY = sY * PIXEL_STEP; if ('deltaY' in event) { pY = event.deltaY; } if ('deltaX' in event) { pX = event.deltaX; } if ((pX || pY) && event.deltaMode) { if (event.deltaMode === 1) { // delta in LINE units pX *= LINE_HEIGHT; pY *= LINE_HEIGHT; } else { // delta in PAGE units pX *= PAGE_HEIGHT; pY *= PAGE_HEIGHT; } } // Fall-back if spin cannot be determined if (pX && !sX) { sX = pX < 1 ? -1 : 1; } if (pY && !sY) { sY = pY < 1 ? -1 : 1; } return { spinX: sX, spinY: sY, pixelX: pX, pixelY: pY }; } BI.WheelHandler = function (onWheel, handleScrollX, handleScrollY, stopPropagation) { this._animationFrameID = null; this._deltaX = 0; this._deltaY = 0; this._didWheel = BI.bind(this._didWheel, this); if (typeof handleScrollX !== 'function') { handleScrollX = handleScrollX ? function () { return true } : function () { return false }; } if (typeof handleScrollY !== 'function') { handleScrollY = handleScrollY ? function () { return true } : function () { return false }; } if (typeof stopPropagation !== 'function') { stopPropagation = stopPropagation ? function () { return true } : function () { return false }; } this._handleScrollX = handleScrollX; this._handleScrollY = handleScrollY; this._stopPropagation = stopPropagation; this._onWheelCallback = onWheel; this.onWheel = BI.bind(this.onWheel, this); }; BI.WheelHandler.prototype = { constructor: BI.WheelHandler, onWheel: function (/*object*/ event) { var normalizedEvent = normalizeWheel(event); var deltaX = this._deltaX + normalizedEvent.pixelX; var deltaY = this._deltaY + normalizedEvent.pixelY; var handleScrollX = this._handleScrollX(deltaX, deltaY); var handleScrollY = this._handleScrollY(deltaY, deltaX); if (!handleScrollX && !handleScrollY) { return; } this._deltaX += handleScrollX ? normalizedEvent.pixelX : 0; this._deltaY += handleScrollY ? normalizedEvent.pixelY : 0; event.preventDefault ? event.preventDefault() : (event.returnValue = false); var changed; if (this._deltaX !== 0 || this._deltaY !== 0) { if (this._stopPropagation()) { event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true); } changed = true; } if (changed === true && this._animationFrameID === null) { this._animationFrameID = requestAnimationFrame(this._didWheel); } }, _didWheel: function () { this._animationFrameID = null; this._onWheelCallback(this._deltaX, this._deltaY); this._deltaX = 0; this._deltaY = 0; } }; })();/** * 常量 */ _.extend(BI, { MAX: 0xfffffffffffffff, MIN: -0xfffffffffffffff, EVENT_RESPONSE_TIME: 200, zIndex_layer: 1e5, zIndex_floatbox: 1e6, zIndex_popup: 1e7, zIndex_masker: 1e8, zIndex_tip: 1e9, emptyStr: "", emptyFn: function () { }, empty: null, KeyCode: { BACKSPACE: 8, COMMA: 188, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, LEFT: 37, NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SPACE: 32, TAB: 9, UP: 38 }, Status: { SUCCESS: 1, WRONG: 2, START: 3, END: 4, WAITING: 5, READY: 6, RUNNING: 7, OUTOFBOUNDS: 8, NULL: -1 }, Direction: { Top: "top", Bottom: "bottom", Left: "left", Right: "right", Custom: "custom" }, Axis: { Vertical: "vertical", Horizontal: "horizontal" }, Selection: { Default: -2, None: -1, Single: 0, Multi: 1, All: 2 }, HorizontalAlign: { Left: "left", Right: "right", Center: "center" }, VerticalAlign: { Middle: "middle", Top: "top", Bottom: "bottom" } });BI.version = "2.0";/** * absolute实现的居中布局 * @class BI.AbsoluteCenterLayout * @extends BI.Layout */ BI.AbsoluteCenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.AbsoluteCenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-absolute-center-layout", hgap: 0, lgap: 0, rgap: 0, vgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.AbsoluteCenterLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.AbsoluteCenterLayout.superclass._addElement.apply(this, arguments); w.element.css({ "position": "absolute", "left": o.hgap + o.lgap + (item.lgap || 0), "right": o.hgap + o.rgap + (item.rgap || 0), "top": o.vgap + o.tgap + (item.tgap || 0), "bottom": o.vgap + o.bgap + (item.bgap || 0), "margin": "auto" }); return w; }, resize: function () { // console.log("absolute_center_adapt布局不需要resize"); }, populate: function (items) { BI.AbsoluteCenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.absolute_center_adapt', BI.AbsoluteCenterLayout);/** * absolute实现的居中布局 * @class BI.AbsoluteHorizontalLayout * @extends BI.Layout */ BI.AbsoluteHorizontalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.AbsoluteHorizontalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-absolute-horizontal-layout", hgap: 0, lgap: 0, rgap: 0, vgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.AbsoluteHorizontalLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.AbsoluteHorizontalLayout.superclass._addElement.apply(this, arguments); w.element.css({ "position": "absolute", "left": o.hgap + o.lgap + (item.lgap || 0), "right": o.hgap + o.rgap + (item.rgap || 0), "margin": "auto" }); if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css("top", o.vgap + o.tgap + (item.tgap || 0)); } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css("bottom", o.vgap + o.bgap + (item.bgap || 0)); } return w; }, resize: function () { // console.log("absolute_horizontal_adapt布局不需要resize"); }, populate: function (items) { BI.AbsoluteHorizontalLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.absolute_horizontal_adapt', BI.AbsoluteHorizontalLayout);/** * absolute实现的居中布局 * @class BI.AbsoluteVerticalLayout * @extends BI.Layout */ BI.AbsoluteVerticalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.AbsoluteVerticalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-absolute-vertical-layout", hgap: 0, lgap: 0, rgap: 0, vgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.AbsoluteVerticalLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.AbsoluteVerticalLayout.superclass._addElement.apply(this, arguments); w.element.css({ "position": "absolute", "left": item.lgap, "right": item.rgap, "top": o.vgap + o.tgap + (item.tgap || 0), "bottom": o.vgap + o.bgap + (item.bgap || 0), "margin": "auto" }); if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css("left", o.hgap + o.lgap + (item.lgap || 0)); } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css("right", o.hgap + o.rgap + (item.rgap || 0)); } return w; }, resize: function () { // console.log("absolute_vertical_adapt布局不需要resize"); }, populate: function (items) { BI.AbsoluteVerticalLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.absolute_vertical_adapt', BI.AbsoluteVerticalLayout);/** * 自适应水平和垂直方向都居中容器 * @class BI.CenterAdaptLayout * @extends BI.Layout */ BI.CenterAdaptLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.CenterAdaptLayout.superclass.props.apply(this, arguments), { baseCls: "bi-center-adapt-layout", columnSize: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.CenterAdaptLayout.superclass.render.apply(this, arguments); this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({ "position": "relative", "width": "100%", "height": "100%", "white-space": "nowrap", "border-spacing": "0px", "border": "none", "border-collapse": "separate" }); this.$tr = $("<tr>"); this.$tr.appendTo(this.$table); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var td; var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i]; if (!this.hasWidget(this._getChildName(i))) { var w = BI.createWidget(item); w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"}); td = BI.createWidget({ type: "bi.default", tagName: "td", attributes: { width: width }, items: [w] }); this.addWidget(this._getChildName(i), td); } else { td = this.getWidgetByName(this._getChildName(i)); td.element.attr("width", width); } td.element.css({"max-width": o.columnSize[i]}); if (i === 0) { td.element.addClass("first-element"); } td.element.css({ "position": "relative", "height": "100%", "vertical-align": "middle", "margin": "0", "padding": "0", "border": "none" }); if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return td; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$tr.append(frag); this.element.append(this.$table); } }, resize: function () { // console.log("center_adapt布局不需要resize"); }, _getWrapper: function(){ return this.$tr; }, populate: function (items) { BI.CenterAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.center_adapt', BI.CenterAdaptLayout);/** * 水平方向居中容器 * @class BI.HorizontalAdaptLayout * @extends BI.Layout */ BI.HorizontalAdaptLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.HorizontalAdaptLayout.superclass.props.apply(this, arguments), { baseCls: "bi-horizontal-adapt-layout", verticalAlign: BI.VerticalAlign.Middle, columnSize: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.HorizontalAdaptLayout.superclass.render.apply(this, arguments); this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({ "position": "relative", "width": "100%", "white-space": "nowrap", "border-spacing": "0px", "border": "none", "border-collapse": "separate" }); this.$tr = $("<tr>"); this.$tr.appendTo(this.$table); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var td; var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i]; if (!this.hasWidget(this._getChildName(i))) { var w = BI.createWidget(item); w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"}); td = BI.createWidget({ type: "bi.default", tagName: "td", attributes: { width: width }, items: [w] }); this.addWidget(this._getChildName(i), td); } else { td = this.getWidgetByName(this._getChildName(i)); td.element.attr("width", width); } td.element.css({"max-width": o.columnSize[i] + "px"}); if (i === 0) { td.element.addClass("first-element"); } td.element.css({ "position": "relative", "vertical-align": o.verticalAlign, "margin": "0", "padding": "0", "border": "none" }); if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return td; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$tr.append(frag); this.element.append(this.$table); } }, resize: function () { // console.log("horizontal_adapt布局不需要resize"); }, _getWrapper: function () { return this.$tr; }, populate: function (items) { BI.HorizontalAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.horizontal_adapt', BI.HorizontalAdaptLayout);/** * 左右分离,垂直方向居中容器 * items:{ left: [{el:{type:"bi.button"}}], right:[{el:{type:"bi.button"}}] } * @class BI.LeftRightVerticalAdaptLayout * @extends BI.Layout */ BI.LeftRightVerticalAdaptLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.LeftRightVerticalAdaptLayout.superclass.props.apply(this, arguments), { baseCls: "bi-left-right-vertical-adapt-layout", items: {}, llgap: 0, lrgap: 0, lhgap: 0, rlgap: 0, rrgap: 0, rhgap: 0 }); }, render: function () { BI.LeftRightVerticalAdaptLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("left_right_vertical_adapt布局不需要resize"); }, addItem: function () { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var o = this.options; if ("left" in items) { var left = BI.createWidget({ type: "bi.vertical_adapt", items: items.left, hgap: o.lhgap, lgap: o.llgap, rgap: o.lrgap }); left.element.css("height", "100%"); BI.createWidget({ type: "bi.left", element: this, items: [left] }); } if ("right" in items) { var right = BI.createWidget({ type: "bi.vertical_adapt", items: items.right, hgap: o.rhgap, lgap: o.rlgap, rgap: o.rrgap }); right.element.css("height", "100%"); BI.createWidget({ type: "bi.right", element: this, items: [right] }); } }, populate: function (items) { BI.LeftRightVerticalAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.left_right_vertical_adapt', BI.LeftRightVerticalAdaptLayout); BI.LeftVerticalAdaptLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.LeftRightVerticalAdaptLayout.superclass.props.apply(this, arguments), { baseCls: "bi-left-vertical-adapt-layout", items: [], lgap: 0, rgap: 0, hgap: 0 }); }, render: function () { BI.LeftVerticalAdaptLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("left_vertical_adapt布局不需要resize"); }, addItem: function () { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var o = this.options; var left = BI.createWidget({ type: "bi.vertical_adapt", items: items, lgap: o.lgap, hgap: o.hgap, rgap: o.rgap }); left.element.css("height", "100%"); BI.createWidget({ type: "bi.left", element: this, items: [left] }); }, populate: function (items) { BI.LeftVerticalAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.left_vertical_adapt', BI.LeftVerticalAdaptLayout); BI.RightVerticalAdaptLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.RightVerticalAdaptLayout.superclass.props.apply(this, arguments), { baseCls: "bi-right-vertical-adapt-layout", items: [], lgap: 0, rgap: 0, hgap: 0 }); }, render: function () { BI.RightVerticalAdaptLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { }, addItem: function () { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var o = this.options; var right = BI.createWidget({ type: "bi.vertical_adapt", items: items, lgap: o.lgap, hgap: o.hgap, rgap: o.rgap }); right.element.css("height", "100%"); BI.createWidget({ type: "bi.right", element: this, items: [right] }); }, populate: function (items) { BI.RightVerticalAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.right_vertical_adapt', BI.RightVerticalAdaptLayout);/** * 垂直方向居中容器 * @class BI.VerticalAdaptLayout * @extends BI.Layout */ BI.VerticalAdaptLayout = BI.inherit(BI.Layout, { props: { baseCls: "bi-vertical-adapt-layout", columnSize: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }, render: function () { BI.VerticalAdaptLayout.superclass.render.apply(this, arguments); this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({ "position": "relative", "height": "100%", "white-space": "nowrap", "border-spacing": "0px", "border": "none", "border-collapse": "separate" }); this.$tr = $("<tr>"); this.$tr.appendTo(this.$table); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var td; var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i]; if (!this.hasWidget(this._getChildName(i))) { var w = BI.createWidget(item); w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"}); td = BI.createWidget({ type: "bi.default", tagName: "td", attributes: { width: width }, items: [w] }); this.addWidget(this._getChildName(i), td); } else { td = this.getWidgetByName(this._getChildName(i)); td.element.attr("width", width); } if (i === 0) { td.element.addClass("first-element"); } td.element.css({ "position": "relative", "height": "100%", "vertical-align": "middle", "margin": "0", "padding": "0", "border": "none" }); if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return td; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$tr.append(frag); this.element.append(this.$table); } }, _getWrapper: function(){ return this.$tr; }, resize: function () { // console.log("vertical_adapt布局不需要resize"); }, populate: function (items) { BI.VerticalAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.vertical_adapt', BI.VerticalAdaptLayout);/** * 水平方向居中自适应容器 * @class BI.HorizontalAutoLayout * @extends BI.Layout */ BI.HorizontalAutoLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.HorizontalAutoLayout.superclass.props.apply(this, arguments), { baseCls: "bi-horizon-auto-layout", hgap: 0, lgap: 0, rgap: 0, vgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.HorizontalAutoLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.HorizontalAutoLayout.superclass._addElement.apply(this, arguments); w.element.css({ "position": "relative", "margin": "0px auto" }); if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, resize: function () { // console.log("horizontal_adapt布局不需要resize"); }, populate: function (items) { BI.HorizontalAutoLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.horizontal_auto', BI.HorizontalAutoLayout);/** * 浮动的居中布局 */ BI.FloatCenterAdaptLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FloatCenterAdaptLayout.superclass.props.apply(this, arguments), { baseCls: "bi-float-center-adapt-layout", items: [], hgap: 0, vgap: 0, tgap: 0, bgap: 0, lgap: 0, rgap: 0 }); }, render: function () { BI.FloatCenterAdaptLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("float_center_adapt布局不需要resize"); }, addItem: function () { //do nothing throw new Error("cannot be added") }, mounted: function () { var self = this; var width = this.left.element.outerWidth(), height = this.left.element.outerHeight(); this.left.element.width(width).height(height).css("float", "none"); BI.remove(this._children, function (i, wi) { if (wi === self.container) { delete self._children[i]; } }); BI.createWidget({ type: "bi.center_adapt", element: this, items: [this.left] }); }, stroke: function (items) { var self = this, o = this.options; this.left = BI.createWidget({ type: "bi.vertical", items: items, hgap: o.hgap, vgap: o.vgap, tgap: o.tgap, bgap: o.bgap, lgap: o.lgap, rgap: o.rgap }); this.container = BI.createWidget({ type: "bi.left", element: this, items: [this.left] }); }, populate: function (items) { BI.FloatCenterAdaptLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.float_center_adapt', BI.FloatCenterAdaptLayout);/** * 浮动的水平居中布局 */ BI.FloatHorizontalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FloatHorizontalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-float-horizontal-adapt-layout", items: [], hgap: 0, vgap: 0, tgap: 0, bgap: 0, lgap: 0, rgap: 0 }); }, render: function () { BI.FloatHorizontalLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("float_horizontal_adapt布局不需要resize"); }, mounted: function () { var self = this; var width = this.left.element.width(), height = this.left.element.height(); this.left.element.width(width).height(height).css("float", "none"); BI.remove(this._children, function (i, wi) { if (wi === self.container) { delete self._children[i]; } }); BI.createWidget({ type: "bi.horizontal_auto", element: this, items: [this.left] }); }, _addElement: function (i, item) { var self = this, o = this.options; this.left = BI.createWidget({ type: "bi.vertical", items: [item], hgap: o.hgap, vgap: o.vgap, tgap: o.tgap, bgap: o.bgap, lgap: o.lgap, rgap: o.rgap }); this.container = BI.createWidget({ type: "bi.left", element: this, items: [this.left] }); return this.left; }, populate: function (items) { BI.HorizontalAutoLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.horizontal_float', BI.FloatHorizontalLayout);/** *自适应水平和垂直方向都居中容器 * Created by GUY on 2016/12/2. * * @class BI.FlexCenterLayout * @extends BI.Layout */ BI.FlexCenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FlexCenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-flex-center-layout" }); }, render: function () { BI.FlexCenterLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FlexCenterLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative", "flex-shrink": "0"}); return w; }, resize: function () { // console.log("flex_center布局不需要resize"); }, populate: function (items) { BI.FlexCenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.flex_center', BI.FlexCenterLayout);/** *自适应水平和垂直方向都居中容器 * Created by GUY on 2016/12/2. * * @class BI.FlexHorizontalLayout * @extends BI.Layout */ BI.FlexHorizontalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FlexHorizontalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-flex-horizontal-layout", verticalAlign: "middle", columnSize: [], scrollx: true, hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FlexHorizontalLayout.superclass.render.apply(this, arguments); var o = this.options; this.element.addClass(o.verticalAlign); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FlexHorizontalLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative", "flex-shrink": "0"}); if (o.hgap + o.lgap + (item.lgap || 0) > 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) > 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) > 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) > 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, resize: function () { // console.log("flex_horizontal布局不需要resize"); }, populate: function (items) { BI.FlexHorizontalLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.flex_horizontal', BI.FlexHorizontalLayout);/** *自适应水平和垂直方向都居中容器 * Created by GUY on 2016/12/2. * * @class BI.FlexVerticalCenter * @extends BI.Layout */ BI.FlexVerticalCenter = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FlexVerticalCenter.superclass.props.apply(this, arguments), { baseCls: "bi-flex-vertical-center", columnSize: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FlexVerticalCenter.superclass.render.apply(this, arguments); var o = this.options; this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FlexVerticalCenter.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative", "flex-shrink": "0"}); if (o.hgap + o.lgap + (item.lgap || 0) > 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) > 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) > 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) > 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, resize: function () { // console.log("flex_vertical_center布局不需要resize"); }, populate: function (items) { BI.FlexVerticalCenter.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.flex_vertical_center', BI.FlexVerticalCenter);/** *自适应水平和垂直方向都居中容器 * Created by GUY on 2016/12/2. * * @class BI.FlexCenterLayout * @extends BI.Layout */ BI.FlexCenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FlexCenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-flex-wrapper-center-layout clearfix" }); }, render: function () { BI.FlexCenterLayout.superclass.render.apply(this, arguments); this.$wrapper = $("<div>").addClass("flex-wrapper-center-layout-wrapper"); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FlexCenterLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative"}); return w; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$wrapper.append(frag); this.element.append(this.$wrapper); } }, _getWrapper: function(){ return this.$wrapper; }, resize: function () { // console.log("flex_center布局不需要resize"); }, populate: function (items) { BI.FlexCenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.flex_wrapper_center', BI.FlexCenterLayout);/** *自适应水平和垂直方向都居中容器 * Created by GUY on 2016/12/2. * * @class BI.FlexHorizontalLayout * @extends BI.Layout */ BI.FlexHorizontalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FlexHorizontalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-flex-wrapper-horizontal-layout clearfix", verticalAlign: "middle", columnSize: [], scrollx: true, hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FlexHorizontalLayout.superclass.render.apply(this, arguments); var o = this.options; this.$wrapper = $("<div>").addClass("flex-wrapper-horizontal-layout-wrapper " + o.verticalAlign); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FlexHorizontalLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative"}); if (o.hgap + o.lgap + (item.lgap || 0) > 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) > 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) > 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) > 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$wrapper.append(frag); this.element.append(this.$wrapper); } }, _getWrapper: function(){ return this.$wrapper; }, resize: function () { // console.log("flex_horizontal布局不需要resize"); }, populate: function (items) { BI.FlexHorizontalLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.flex_wrapper_horizontal', BI.FlexHorizontalLayout);/** *自适应水平和垂直方向都居中容器 * Created by GUY on 2016/12/2. * * @class BI.FlexVerticalCenter * @extends BI.Layout */ BI.FlexVerticalCenter = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FlexVerticalCenter.superclass.props.apply(this, arguments), { baseCls: "bi-flex-wrapper-vertical-center clearfix", columnSize: [], hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FlexVerticalCenter.superclass.render.apply(this, arguments); var o = this.options; this.$wrapper = $("<div>").addClass("flex-wrapper-vertical-center-wrapper"); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FlexVerticalCenter.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative"}); if (o.hgap + o.lgap + (item.lgap || 0) > 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) > 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) > 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) > 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$wrapper.append(frag); this.element.append(this.$wrapper); } }, _getWrapper: function(){ return this.$wrapper; }, resize: function () { // console.log("flex_vertical_center布局不需要resize"); }, populate: function (items) { BI.FlexVerticalCenter.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.flex_wrapper_vertical_center', BI.FlexVerticalCenter);/** * 固定子组件上下左右的布局容器 * @class BI.AbsoluteLayout * @extends BI.Layout */ BI.AbsoluteLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.AbsoluteLayout.superclass.props.apply(this, arguments), { baseCls: "bi-absolute-layout", hgap: null, vgap: null, lgap: null, rgap: null, tgap: null, bgap: null }); }, render: function () { BI.AbsoluteLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.AbsoluteLayout.superclass._addElement.apply(this, arguments); var left = 0, right = 0, top = 0, bottom = 0; if (BI.isNotNull(item.left)) { w.element.css({"left": item.left}); left += item.left; } if (BI.isNotNull(item.right)) { w.element.css({"right": item.right}); right += item.right; } if (BI.isNotNull(item.top)) { w.element.css({"top": item.top}); top += item.top; } if (BI.isNotNull(item.bottom)) { w.element.css({"bottom": item.bottom}); bottom += item.bottom; } if (BI.isNotNull(o.hgap)) { left += o.hgap; w.element.css({"left": left}); right += o.hgap; w.element.css({"right": right}); } if (BI.isNotNull(o.vgap)) { top += o.vgap; w.element.css({"top": top}); bottom += o.vgap; w.element.css({"bottom": bottom}); } if (BI.isNotNull(o.lgap)) { left += o.lgap; w.element.css({"left": left}); } if (BI.isNotNull(o.rgap)) { right += o.rgap; w.element.css({"right": right}); } if (BI.isNotNull(o.tgap)) { top += o.tgap; w.element.css({"top": top}); } if (BI.isNotNull(o.bgap)) { bottom += o.bgap; w.element.css({"bottom": bottom}); } if (BI.isNotNull(item.width)) { w.element.css({"width": item.width}); } if (BI.isNotNull(item.height)) { w.element.css({"height": item.height}); } w.element.css({"position": "absolute"}); return w; }, resize: function () { this.stroke(this.options.items); }, stroke: function (items) { this.options.items = items || []; var self = this; BI.each(items, function (i, item) { if (!!item) { if (!BI.isWidget(item) && !item.el) { throw new Error("el must be exist"); } self._addElement(i, item); } }); }, populate: function (items) { BI.AbsoluteLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.absolute', BI.AbsoluteLayout);BI.AdaptiveLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.AdaptiveLayout.superclass.props.apply(this, arguments), { baseCls: "bi-adaptive-layout", hgap: null, vgap: null, lgap: null, rgap: null, tgap: null, bgap: null }); }, render: function () { BI.AdaptiveLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.AdaptiveLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative"}); var left = 0, right = 0, top = 0, bottom = 0; if (BI.isNotNull(item.left)) { w.element.css({ "margin-left": item.left }) } if (BI.isNotNull(item.right)) { w.element.css({ "margin-right": item.right }) } if (BI.isNotNull(item.top)) { w.element.css({ "margin-top": item.top }) } if (BI.isNotNull(item.bottom)) { w.element.css({ "margin-bottom": item.bottom }) } if (BI.isNotNull(o.hgap)) { left += o.hgap; w.element.css({"left": left}); right += o.hgap; w.element.css({"right": right}); } if (BI.isNotNull(o.vgap)) { top += o.vgap; w.element.css({"top": top}); bottom += o.vgap; w.element.css({"bottom": bottom}); } if (BI.isNotNull(o.lgap)) { left += o.lgap; w.element.css({"left": left}); } if (BI.isNotNull(o.rgap)) { right += o.rgap; w.element.css({"right": right}); } if (BI.isNotNull(o.tgap)) { top += o.tgap; w.element.css({"top": top}); } if (BI.isNotNull(o.bgap)) { bottom += o.bgap; w.element.css({"bottom": bottom}); } if (BI.isNotNull(item.width)) { w.element.css({"width": item.width}); } if (BI.isNotNull(item.height)) { w.element.css({"height": item.height}); } return w; }, resize: function () { this.stroke(this.options.items); }, populate: function (items) { BI.AbsoluteLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.adaptive', BI.AdaptiveLayout);/** * 上下的高度固定/左右的宽度固定,中间的高度/宽度自适应 * * @class BI.BorderLayout * @extends BI.Layout */ BI.BorderLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.BorderLayout.superclass.props.apply(this, arguments), { baseCls: "bi-border-layout", items: {} }); }, render: function () { BI.BorderLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { this.stroke(this.options.items); }, addItem: function (item) { // do nothing throw new Error("cannot be added") }, stroke: function(regions){ var item; var top = 0; var bottom = 0; var left = 0; var right = 0; if ("north" in regions) { item = regions["north"]; if (item != null) { if (item.el) { if (!this.hasWidget(this.getName() + "north")) { var w = BI.createWidget(item); this.addWidget(this.getName() + "north", w); } this.getWidgetByName(this.getName() + "north").element.height(item.height) .css({ "position": "absolute", "top": (item.top || 0), "left": (item.left || 0), "right": (item.right || 0), "bottom": "initial" }); } top = (item.height || 0) + (item.top || 0) + (item.bottom || 0); } } if ("south" in regions) { item = regions["south"]; if (item != null) { if (item.el) { if (!this.hasWidget(this.getName() + "south")) { var w = BI.createWidget(item); this.addWidget(this.getName() + "south", w); } this.getWidgetByName(this.getName() + "south").element.height(item.height) .css({ "position": "absolute", "bottom": (item.bottom || 0), "left": (item.left || 0), "right": (item.right || 0), "top": "initial" }); } bottom = (item.height || 0) + (item.top || 0) + (item.bottom || 0); } } if ("west" in regions) { item = regions["west"]; if (item != null) { if (item.el) { if (!this.hasWidget(this.getName() + "west")) { var w = BI.createWidget(item); this.addWidget(this.getName() + "west", w); } this.getWidgetByName(this.getName() + "west").element.width(item.width) .css({ "position": "absolute", "left": (item.left || 0), top: top, bottom: bottom, "right": "initial" }); } left = (item.width || 0) + (item.left || 0) + (item.right || 0); } } if ("east" in regions) { item = regions["east"]; if (item != null) { if (item.el) { if (!this.hasWidget(this.getName() + "east")) { var w = BI.createWidget(item); this.addWidget(this.getName() + "east", w); } this.getWidgetByName(this.getName() + "east").element.width(item.width) .css({ "position": "absolute", "right": (item.right || 0), top: top, bottom: bottom, "left": "initial" }); } right = (item.width || 0) + (item.left || 0) + (item.right || 0); } } if ("center" in regions) { item = regions["center"]; if (item != null) { if (!this.hasWidget(this.getName() + "center")) { var w = BI.createWidget(item); this.addWidget(this.getName() + "center", w); } this.getWidgetByName(this.getName() + "center").element .css({"position": "absolute", "top": top, "bottom": bottom, "left": left, "right": right}); } } }, populate: function (items) { BI.BorderLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.border', BI.BorderLayout);/** * 卡片布局,可以做到当前只显示一个组件,其他的都隐藏 * @class BI.CardLayout * @extends BI.Layout * * @cfg {JSON} options 配置属性 * @cfg {String} options.defaultShowName 默认展示的子组件名 */ BI.CardLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.CardLayout.superclass.props.apply(this, arguments), { baseCls: "bi-card-layout", items: [] }); }, render: function () { BI.CardLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("default布局不需要resize"); }, stroke: function (items) { var self = this, o = this.options; this.showIndex = void 0; BI.each(items, function (i, item) { if (!!item) { if (!self.hasWidget(item.cardName)) { var w = BI.createWidget(item); w.on(BI.Events.DESTROY, function () { var index = BI.findIndex(o.items, function (i, tItem) { return tItem.cardName == item.cardName; }); if (index > -1) { o.items.splice(index, 1); } }); self.addWidget(item.cardName, w); } else { var w = self.getWidgetByName(item.cardName); } w.element.css({"position": "absolute", "top": "0", "right": "0", "bottom": "0", "left": "0"}); w.setVisible(false); } }); }, update: function () { }, empty: function () { BI.CardLayout.superclass.empty.apply(this, arguments); this.options.items = []; }, populate: function (items) { BI.CardLayout.superclass.populate.apply(this, arguments); this._mount(); this.options.defaultShowName && this.showCardByName(this.options.defaultShowName); }, isCardExisted: function (cardName) { return BI.some(this.options.items, function (i, item) { return item.cardName == cardName && item.el; }); }, getCardByName: function (cardName) { if (!this.isCardExisted(cardName)) { throw new Error("cardName is not exist"); } return this._children[cardName]; }, _deleteCardByName: function (cardName) { delete this._children[cardName]; var index = BI.findIndex(this.options.items, function (i, item) { return item.cardName == cardName; }); if (index > -1) { this.options.items.splice(index, 1); } }, deleteCardByName: function (cardName) { if (!this.isCardExisted(cardName)) { throw new Error("cardName is not exist"); } var child = this._children[cardName]; this._deleteCardByName(cardName); child && child._destroy(); }, addCardByName: function (cardName, cardItem) { if (this.isCardExisted(cardName)) { throw new Error("cardName is already exist"); } var widget = BI.createWidget(cardItem); widget.element.css({ "position": "relative", "top": "0", "left": "0", "width": "100%", "height": "100%" }).appendTo(this.element); widget.invisible(); this.addWidget(cardName, widget); this.options.items.push({el: cardItem, cardName: cardName}); return widget; }, showCardByName: function (name, action, callback) { var self = this; //name不存在的时候全部隐藏 var exist = this.isCardExisted(name); if (this.showIndex != null) { this.lastShowIndex = this.showIndex; } this.showIndex = name; var flag = false; BI.each(this.options.items, function (i, item) { var el = self._children[item.cardName]; if (el) { if (name != item.cardName) { //动画效果只有在全部都隐藏的时候才有意义,且只要执行一次动画操作就够了 !flag && !exist && (BI.Action && action instanceof BI.Action) ? (action.actionBack(el), flag = true) : el.invisible(); } else { (BI.Action && action instanceof BI.Action) ? action.actionPerformed(void 0, el, callback) : (el.visible(), callback && callback()) } } }); }, showLastCard: function () { var self = this; this.showIndex = this.lastShowIndex; BI.each(this.options.items, function (i, item) { self._children[item.cardName].setVisible(self.showIndex == i); }) }, setDefaultShowName: function (name) { this.options.defaultShowName = name; return this; }, getDefaultShowName: function () { return this.options.defaultShowName; }, getAllCardNames: function () { return BI.map(this.options.items, function (i, item) { return item.cardName; }) }, getShowingCard: function () { if (!BI.isKey(this.showIndex)) { return void 0; } return this.getWidgetByName(this.showIndex); }, deleteAllCard: function () { var self = this; BI.each(this.getAllCardNames(), function (i, name) { self.deleteCardByName(name); }) }, hideAllCard: function () { var self = this; BI.each(this.options.items, function (i, item) { self._children[item.cardName].invisible(); }); }, isAllCardHide: function () { var self = this; var flag = true; BI.some(this.options.items, function (i, item) { if (self._children[item.cardName].isVisible()) { flag = false; return false; } }); return flag; }, removeWidget: function (nameOrWidget) { var removeName; if (BI.isWidget(nameOrWidget)) { BI.each(this._children, function (name, child) { if (child === nameOrWidget) { removeName = name; } }) } else { removeName = nameOrWidget; } if (removeName) { this._deleteCardByName(removeName); } } }); BI.shortcut('bi.card', BI.CardLayout);/** * 默认的布局方式 * * @class BI.DefaultLayout * @extends BI.Layout */ BI.DefaultLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.DefaultLayout.superclass.props.apply(this, arguments), { hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, items: [] }); }, render: function () { BI.DefaultLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.DefaultLayout.superclass._addElement.apply(this, arguments); if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, resize: function () { // console.log("default布局不需要resize") }, populate: function (items) { BI.DefaultLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.default', BI.DefaultLayout);/** * 分隔容器的控件,按照宽度和高度所占比平分整个容器 * * @class BI.DivisionLayout * @extends BI.Layout */ BI.DivisionLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.DivisionLayout.superclass.props.apply(this, arguments), { baseCls: "bi-division-layout", columns: null, rows: null, items: [] // [ // { // column: 0, // row: 0, // width: 0.25, // height: 0.33, // el: {type: 'bi.button', text: 'button1'} // }, // { // column: 1, // row: 1, // width: 0.25, // height: 0.33, // el: {type: 'bi.button', text: 'button2'} // }, // { // column: 3, // row: 2, // width: 0.25, // height: 0.33, // el: {type: 'bi.button', text: 'button3'} // } //] }); }, render: function () { BI.DivisionLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { this.stroke(this.opitons.items); }, addItem: function (item) { // do nothing throw new Error("cannot be added") }, stroke: function(items){ var o = this.options; var rows = o.rows || o.items.length, columns = o.columns || ((o.items[0] && o.items[0].length) | 0); var map = BI.makeArray(rows), widths = {}, heights = {}; function firstElement(item, row, col) { if (row === 0) { item.addClass("first-row") } if (col === 0) { item.addClass("first-col"); } item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row"); item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col"); item.addClass("center-element"); } function firstObject(item, row, col) { var cls = ""; if (row === 0) { cls += " first-row"; } if (col === 0) { cls += " first-col"; } BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row"); BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col"); item.cls = (item.cls || "") + cls + " center-element"; } function first(item, row, col) { if (item instanceof BI.Widget) { firstElement(item.element, row, col); } else if (item.el instanceof BI.Widget) { firstElement(item.el.element, row, col); } else if (item.el) { firstObject(item.el, row, col) } else { firstObject(item, row, col); } } BI.each(map, function (i) { map[i] = BI.makeArray(columns); }); BI.each(items, function (i, item) { if (BI.isArray(item)) { BI.each(item, function (j, el) { widths[i] = (widths[i] || 0) + item.width; heights[j] = (heights[j] || 0) + item.height; map[i][j] = el; }); return; } widths[item.row] = (widths[item.row] || 0) + item.width; heights[item.column] = (heights[item.column] || 0) + item.height; map[item.row][item.column] = item; }); for (var i = 0; i < rows; i++) { var totalW = 0; for (var j = 0; j < columns; j++) { if (!map[i][j]) { throw new Error("item be required"); } if(!this.hasWidget(this.getName() + i + "_" + j)) { var w = BI.createWidget(map[i][j]); this.addWidget(this.getName() + i + "_" + j, w); } else { w = this.getWidgetByName(this.getName() + i + "_" + j); } var left = totalW * 100 / widths[i]; w.element.css({"position": "absolute", "left": left + "%"}); if (j > 0) { var lastW = this.getWidgetByName(this.getName() + i + "_" + (j - 1)); lastW.element.css({"right": (100 - left) + "%"}); } if (j == o.columns - 1) { w.element.css({"right": "0%"}); } first(w, i, j); totalW += map[i][j].width; } } for (var j = 0; j < o.columns; j++) { var totalH = 0; for (var i = 0; i < o.rows; i++) { var w = this.getWidgetByName(this.getName() + i + "_" + j); var top = totalH * 100 / heights[j]; w.element.css({"top": top + "%"}); if (i > 0) { var lastW = this.getWidgetByName(this.getName() + (i - 1) + "_" + j); lastW.element.css({"bottom": (100 - top) + "%"}); } if (i == o.rows - 1) { w.element.css({"bottom": "0%"}); } totalH += map[i][j].height; } } }, populate: function (items) { BI.DivisionLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.division', BI.DivisionLayout);/** * 靠左对齐的自由浮动布局 * @class BI.FloatLeftLayout * @extends BI.Layout * * @cfg {JSON} options 配置属性 * @cfg {Number} [hgap=0] 水平间隙 * @cfg {Number} [vgap=0] 垂直间隙 */ BI.FloatLeftLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FloatLeftLayout.superclass.props.apply(this, arguments), { baseCls: "bi-float-left-layout clearfix", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FloatLeftLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FloatLeftLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative", "float": "left"}); if (BI.isNotNull(item.left)) { w.element.css({"left": item.left}); } if (BI.isNotNull(item.right)) { w.element.css({"right": item.right}); } if (BI.isNotNull(item.top)) { w.element.css({"top": item.top}); } if ((item.lgap || 0) + o.hgap + o.lgap !== 0) { w.element.css("margin-left", (item.lgap || 0) + o.hgap + o.lgap); } if ((item.rgap || 0) + o.hgap + o.rgap !== 0) { w.element.css("margin-right", (item.rgap || 0) + o.hgap + o.rgap); } if ((item.tgap || 0) + o.vgap + o.tgap !== 0) { w.element.css("margin-top", (item.tgap || 0) + o.vgap + o.tgap); } if ((item.bgap || 0) + o.vgap + o.bgap !== 0) { w.element.css("margin-bottom", (item.bgap || 0) + o.vgap + o.bgap); } return w; }, resize: function () { this.stroke(this.options.items); }, populate: function (items) { BI.FloatLeftLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.left', BI.FloatLeftLayout); /** * 靠右对齐的自由浮动布局 * @class BI.FloatRightLayout * @extends BI.Layout * * @cfg {JSON} options 配置属性 * @cfg {Number} [hgap=0] 水平间隙 * @cfg {Number} [vgap=0] 垂直间隙 */ BI.FloatRightLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FloatRightLayout.superclass.props.apply(this, arguments), { baseCls: "bi-float-right-layout clearfix", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FloatRightLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.FloatRightLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative", "float": "right"}); if (BI.isNotNull(item.left)) { w.element.css({"left": item.left}); } if (BI.isNotNull(item.right)) { w.element.css({"right": item.right}); } if (BI.isNotNull(item.top)) { w.element.css({"top": item.top}); } if ((item.lgap || 0) + o.hgap + o.lgap !== 0) { w.element.css("margin-left", (item.lgap || 0) + o.hgap + o.lgap); } if ((item.rgap || 0) + o.hgap + o.rgap !== 0) { w.element.css("margin-right", (item.rgap || 0) + o.hgap + o.rgap); } if ((item.tgap || 0) + o.vgap + o.tgap !== 0) { w.element.css("margin-top", (item.tgap || 0) + o.vgap + o.tgap); } if ((item.bgap || 0) + o.vgap + o.bgap !== 0) { w.element.css("margin-bottom", (item.bgap || 0) + o.vgap + o.bgap); } return w; }, resize: function () { this.stroke(this.options.items); }, populate: function (items) { BI.FloatRightLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.right', BI.FloatRightLayout);/** * 上下的高度固定/左右的宽度固定,中间的高度/宽度自适应 * * @class BI.BorderLayout * @extends BI.Layout */ BI.GridLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.GridLayout.superclass.props.apply(this, arguments), { baseCls: "bi-grid-layout", columns: null, rows: null, items: [] /*[ { column: 0, row: 0, el: {type: 'bi.button', text: 'button1'} }, { column: 1, row: 1, el: {type: 'bi.button', text: 'button2'} }, { column: 3, row: 2, el: {type: 'bi.button', text: 'button3'} } ]*/ }); }, render: function () { BI.GridLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("grid布局不需要resize") }, addItem: function () { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var o = this.options; var rows = o.rows || o.items.length, columns = o.columns || ((o.items[0] && o.items[0].length) | 0); var width = 100 / columns, height = 100 / rows; var els = []; for (var i = 0; i < rows; i++) { els[i] = []; } function firstElement(item, row, col) { if (row === 0) { item.addClass("first-row") } if (col === 0) { item.addClass("first-col"); } item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row"); item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col"); item.addClass("center-element"); } function firstObject(item, row, col) { var cls = ""; if (row === 0) { cls += " first-row"; } if (col === 0) { cls += " first-col"; } BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row"); BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col"); item.cls = (item.cls || "") + cls + " center-element"; } function first(item, row, col) { if (item instanceof BI.Widget) { firstElement(item.element, row, col); } else if (item.el instanceof BI.Widget) { firstElement(item.el.element, row, col); } else if (item.el) { firstObject(item.el, row, col) } else { firstObject(item, row, col); } } BI.each(items, function (i, item) { if (BI.isArray(item)) { BI.each(item, function (j, el) { els[i][j] = BI.createWidget(el); }); return; } els[item.row][item.column] = BI.createWidget(item); }); for (var i = 0; i < rows; i++) { for (var j = 0; j < columns; j++) { if (!els[i][j]) { els[i][j] = BI.createWidget({ type: "bi.layout" }); } first(els[i][j], i, j); els[i][j].element.css({ "position": "absolute", "top": height * i + "%", "left": width * j + "%", "right": (100 - (width * (j + 1))) + "%", "bottom": (100 - (height * (i + 1))) + "%" }); this.addWidget(els[i][j]); } } }, populate: function (items) { BI.GridLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.grid', BI.GridLayout);/** * 水平布局 * @class BI.HorizontalLayout * @extends BI.Layout */ BI.HorizontalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.HorizontalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-horizontal-layout", verticalAlign: "middle", columnSize: [], scrollx: true, hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.HorizontalLayout.superclass.render.apply(this, arguments); this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({ "position": "relative", "white-space": "nowrap", "border-spacing": "0px", "border": "none", "border-collapse": "separate" }); this.$tr = $("<tr>"); this.$tr.appendTo(this.$table); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var td; var width = o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i]; if (!this.hasWidget(this._getChildName(i))) { var w = BI.createWidget(item); w.element.css({"position": "relative", "margin": "0px auto"}); td = BI.createWidget({ type: "bi.default", tagName: "td", attributes: { width: width }, items: [w] }); this.addWidget(this._getChildName(i), td); } else { td = this.getWidgetByName(this._getChildName(i)); td.element.attr("width", width); } if (i === 0) { td.element.addClass("first-element"); } td.element.css({ "position": "relative", "vertical-align": o.verticalAlign, "margin": "0", "padding": "0", "border": "none" }); if (o.hgap + o.lgap + (item.lgap || 0) > 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) > 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.tgap + (item.tgap || 0) > 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) > 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return td; }, _mountChildren: function () { var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$tr.append(frag); this.element.append(this.$table); } }, resize: function () { // console.log("horizontal layout do not need to resize"); }, _getWrapper: function(){ return this.$tr; }, populate: function (items) { BI.HorizontalLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.horizontal', BI.HorizontalLayout); /** * 水平布局 * @class BI.HorizontalCellLayout * @extends BI.Layout */ BI.HorizontalCellLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.HorizontalCellLayout.superclass.props.apply(this, arguments), { baseCls: "bi-horizontal-cell-layout", scrollable: true, hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.HorizontalCellLayout.superclass.render.apply(this, arguments); this.element.css({"display": "table", "vertical-align": "top"}); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.HorizontalCellLayout.superclass._addElement.apply(this, arguments); w.element.css({"position": "relative", "display": "table-cell", "vertical-align": "middle"}); if (o.hgap + o.lgap > 0) { w.element.css({ "margin-left": o.hgap + o.lgap + "px" }) } if (o.hgap + o.rgap > 0) { w.element.css({ "margin-right": o.hgap + o.rgap + "px" }) } if (o.vgap + o.tgap > 0) { w.element.css({ "margin-top": o.vgap + o.tgap + "px" }) } if (o.vgap + o.bgap > 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + "px" }) } return w; }, resize: function () { // console.log("horizontal do not need to resize"); }, populate: function (items) { BI.HorizontalCellLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.horizontal_cell', BI.HorizontalCellLayout);/** * 靠左对齐的自由浮动布局 * @class BI.LatticeLayout * @extends BI.Layout * * @cfg {JSON} options 配置属性 * @cfg {Number} [hgap=0] 水平间隙 * @cfg {Number} [vgap=0] 垂直间隙 */ BI.LatticeLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.LatticeLayout.superclass.props.apply(this, arguments), { baseCls: "bi-lattice-layout clearfix" //columnSize: [0.2, 0.2, 0.6], }); }, render: function () { BI.LatticeLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.LatticeLayout.superclass._addElement.apply(this, arguments); if (o.columnSize && o.columnSize[i]) { var width = o.columnSize[i] / BI.sum(o.columnSize) * 100 + "%"; } else { var width = 1 / this.options.items.length * 100 + "%" } w.element.css({"position": "relative", "float": "left", "width": width}); return w; }, addItem: function (item) { var w = BI.LatticeLayout.superclass.addItem.apply(this, arguments); this.resize(); return w; }, addItemAt: function (item) { var w = BI.LatticeLayout.superclass.addItemAt.apply(this, arguments); this.resize(); return w; }, resize: function () { this.stroke(this.options.items); }, populate: function (items) { BI.LatticeLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.lattice', BI.LatticeLayout);/** * 上下的高度固定/左右的宽度固定,中间的高度/宽度自适应 * * @class BI.TableLayout * @extends BI.Layout */ BI.TableLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.TableLayout.superclass.props.apply(this, arguments), { baseCls: "bi-table-layout", scrolly: true, columnSize: [200, 200, 'fill'], rowSize: 30, //or [30,30,30] hgap: 0, vgap: 0, items: [[ { el: {text: 'label1'} }, { el: {text: 'label2'} }, { el: {text: 'label3'} } ]] }); }, render: function () { BI.TableLayout.superclass.render.apply(this, arguments); this.rows = 0; this.populate(this.options.items); }, _addElement: function (idx, arr) { var o = this.options; var abs = [], left = 0, right = 0, i, j; function firstElement(item, row, col) { if (row === 0) { item.addClass("first-row") } if (col === 0) { item.addClass("first-col"); } item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row"); item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col"); item.addClass("center-element"); } function firstObject(item, row, col) { var cls = ""; if (row === 0) { cls += " first-row"; } if (col === 0) { cls += " first-col"; } BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row"); BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col"); item.cls = (item.cls || "") + cls + " center-element"; } function first(item, row, col) { if (item instanceof BI.Widget) { firstElement(item.element, row, col); } else if (item.el instanceof BI.Widget) { firstElement(item.el.element, row, col); } else if (item.el) { firstObject(item.el, row, col) } else { firstObject(item, row, col); } } for (i = 0; i < arr.length; i++) { if (BI.isNumber(o.columnSize[i])) { first(arr[i], this.rows, i); abs.push(BI.extend({ top: 0, bottom: 0, left: o.columnSize[i] <= 1 ? left * 100 + "%" : left, width: o.columnSize[i] <= 1 ? o.columnSize[i] * 100 + "%" : o.columnSize[i] }, arr[i])); left += o.columnSize[i] + (o.columnSize[i] < 1 ? 0 : o.hgap); } else { break; } } for (j = arr.length - 1; j > i; j--) { if (BI.isNumber(o.columnSize[j])) { first(arr[j], this.rows, j); abs.push(BI.extend({ top: 0, bottom: 0, right: o.columnSize[j] <= 1 ? right * 100 + "%" : right, width: o.columnSize[j] <= 1 ? o.columnSize[j] * 100 + "%" : o.columnSize[j] }, arr[j])) right += o.columnSize[j] + (o.columnSize[j] < 1 ? 0 : o.hgap); } else { throw new Error("item with fill can only be one"); } } if (i >= 0 && i < arr.length) { first(arr[i], this.rows, i); abs.push(BI.extend({ top: 0, bottom: 0, left: left <= 1 ? left * 100 + "%" : left, right: right <= 1 ? right * 100 + "%" : right }, arr[i])) } var w = BI.createWidget({ type: "bi.absolute", height: BI.isArray(o.rowSize) ? o.rowSize[this.rows] : o.rowSize, items: abs }); if (this.rows > 0) { this.getWidgetByName(this.getName() + (this.rows - 1)).element.css({ "margin-bottom": o.vgap }) } w.element.css({ "position": "relative" }); this.addWidget(this.getName() + (this.rows++), w); return w; }, resize: function () { // console.log("table布局不需要resize"); }, addItem: function (arr) { if (!BI.isArray(arr)) { throw new Error("item must be array"); } return BI.TableLayout.superclass.addItem.apply(this, arguments); }, populate: function (items) { BI.TableLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.table', BI.TableLayout);/** * 水平tape布局 * @class BI.HTapeLayout * @extends BI.Layout */ BI.HTapeLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.HTapeLayout.superclass.props.apply(this, arguments), { baseCls: "bi-h-tape-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, items: [ { width: 100, el: {type: 'bi.button', text: 'button1'} }, { width: 'fill', el: {type: 'bi.button', text: 'button2'} }, { width: 200, el: {type: 'bi.button', text: 'button3'} } ] }); }, render: function () { BI.HTapeLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { this.stroke(this.options.items); }, addItem: function (item) { // do nothing throw new Error("cannot be added") }, stroke: function (items) { var self = this, o = this.options; items = BI.compact(items); BI.each(items, function (i, item) { if (!self.hasWidget(self.getName() + i + "")) { var w = BI.createWidget(item); self.addWidget(self.getName() + i + "", w); } else { w = self.getWidgetByName(self.getName() + i + ""); } w.element.css({"position": "absolute", top: o.vgap + o.tgap + "px", bottom: o.vgap + o.bgap + "px"}); }); var left = {}, right = {}; left[0] = 0; right[items.length - 1] = 0; BI.any(items, function (i, item) { var w = self.getWidgetByName(self.getName() + i + ""); if (BI.isNull(left[i])) { left[i] = left[i - 1] + items[i - 1].width + 2 * o.hgap + o.lgap + o.rgap; } if (item.width < 1 && item.width >= 0) { w.element.css({"left": left[i] * 100 + "%", width: item.width * 100 + "%"}) } else { w.element.css({ "left": left[i] + o.hgap + o.lgap + "px", width: BI.isNumber(item.width) ? item.width : "" }); } if (!BI.isNumber(item.width)) { return true; } }); BI.backAny(items, function (i, item) { var w = self.getWidgetByName(self.getName() + i + ""); if (BI.isNull(right[i])) { right[i] = right[i + 1] + items[i + 1].width + 2 * o.hgap + o.lgap + o.rgap; } if (item.width < 1 && item.width >= 0) { w.element.css({"right": right[i] * 100 + "%", width: item.width * 100 + "%"}) } else { w.element.css({ "right": right[i] + o.hgap + o.rgap + "px", width: BI.isNumber(item.width) ? item.width : "" }); } if (!BI.isNumber(item.width)) { return true; } }) }, populate: function (items) { BI.HTapeLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.htape', BI.HTapeLayout); /** * 垂直tape布局 * @class BI.VTapeLayout * @extends BI.Layout */ BI.VTapeLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.VTapeLayout.superclass.props.apply(this, arguments), { baseCls: "bi-v-tape-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, items: [ { height: 100, el: {type: 'bi.button', text: 'button1'} }, { height: 'fill', el: {type: 'bi.button', text: 'button2'} }, { height: 200, el: {type: 'bi.button', text: 'button3'} } ] }); }, render: function () { BI.VTapeLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { this.stroke(this.options.items); }, addItem: function (item) { // do nothing throw new Error("cannot be added") }, stroke: function (items) { var self = this, o = this.options; items = BI.compact(items); BI.each(items, function (i, item) { if (!self.hasWidget(self.getName() + i + "")) { var w = BI.createWidget(item); self.addWidget(self.getName() + i + "", w); } else { w = self.getWidgetByName(self.getName() + i + ""); } w.element.css({"position": "absolute", left: o.hgap + o.lgap + "px", right: o.hgap + o.rgap + "px"}); }); var top = {}, bottom = {}; top[0] = 0; bottom[items.length - 1] = 0; BI.any(items, function (i, item) { var w = self.getWidgetByName(self.getName() + i + ""); if (BI.isNull(top[i])) { top[i] = top[i - 1] + items[i - 1].height + 2 * o.vgap + o.tgap + o.bgap; } if (item.height < 1 && item.height >= 0) { w.element.css({"top": top[i] * 100 + "%", height: item.height * 100 + "%"}) } else { w.element.css({ "top": top[i] + o.vgap + o.tgap + "px", height: BI.isNumber(item.height) ? item.height : "" }); } if (!BI.isNumber(item.height)) { return true; } }); BI.backAny(items, function (i, item) { var w = self.getWidgetByName(self.getName() + i + ""); if (BI.isNull(bottom[i])) { bottom[i] = bottom[i + 1] + items[i + 1].height + 2 * o.vgap + o.tgap + o.bgap; } if (item.height < 1 && item.height >= 0) { w.element.css({"bottom": bottom[i] * 100 + "%", height: item.height * 100 + "%"}) } else { w.element.css({ "bottom": bottom[i] + o.vgap + o.bgap + "px", height: BI.isNumber(item.height) ? item.height : "" }); } if (!BI.isNumber(item.height)) { return true; } }) }, populate: function (items) { BI.VTapeLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.vtape', BI.VTapeLayout);/** * td布局 * @class BI.TdLayout * @extends BI.Layout */ BI.TdLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.TdLayout.superclass.props.apply(this, arguments), { baseCls: "bi-td-layout", columnSize: [200, 200, 200], hgap: 0, vgap: 0, items: [[ { el: {text: 'label1'} }, { el: {text: 'label2'} }, { el: {text: 'label3'} } ]] }); }, render: function () { BI.TdLayout.superclass.render.apply(this, arguments); this.$table = $("<table>").attr({"cellspacing": 0, "cellpadding": 0}).css({ "position": "relative", "width": "100%", "height": "100%", "border-spacing": "0px", "border": "none", "border-collapse": "separate" }); this.rows = 0; this.populate(this.options.items); }, _addElement: function (idx, arr) { var o = this.options; function firstElement(item, row, col) { if (row === 0) { item.addClass("first-row") } if (col === 0) { item.addClass("first-col"); } item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row"); item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col"); item.addClass("center-element"); } function firstObject(item, row, col) { var cls = ""; if (row === 0) { cls += " first-row"; } if (col === 0) { cls += " first-col"; } BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row"); BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col"); item.cls = (item.cls || "") + cls + " center-element"; } function first(item, row, col) { if (item instanceof BI.Widget) { firstElement(item.element, row, col); } else if (item.el instanceof BI.Widget) { firstElement(item.el.element, row, col); } else if (item.el) { firstObject(item.el, row, col) } else { firstObject(item, row, col); } } var tr = BI.createWidget({ type: "bi.default", tagName: "tr" }); for (var i = 0; i < arr.length; i++) { var w = BI.createWidget(arr[i]); w.element.css({"position": "relative", "top": "0", "left": "0", "margin": "0px auto"}); first(w, this.rows++, i); var td = BI.createWidget({ type: 'bi.default', attributes: { width: o.columnSize[i] <= 1 ? (o.columnSize[i] * 100 + "%") : o.columnSize[i] }, tagName: 'td', items: [w] }); td.element.css({ "position": "relative", "vertical-align": "middle", "margin": "0", "padding": "0", "border": "none" }); tr.addItem(td); } this.addWidget(this.getName() + idx, tr); return tr; }, _mountChildren: function(){ var self = this; var frag = document.createDocumentFragment(); var hasChild = false; BI.each(this._children, function (i, widget) { if (widget.element !== self.element) { frag.appendChild(widget.element[0]); hasChild = true; } }); if (hasChild === true) { this.$table.append(frag); this.element.append(this.$table); } }, resize: function () { // console.log("td布局不需要resize"); }, addItem: function (arr) { if (!BI.isArray(arr)) { throw new Error("item must be array"); } return BI.TdLayout.superclass.addItem.apply(this, arguments); }, populate: function (items) { BI.TdLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.td', BI.TdLayout);/** * 垂直布局 * @class BI.VerticalLayout * @extends BI.Layout */ BI.VerticalLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.VerticalLayout.superclass.props.apply(this, arguments), { baseCls: "bi-vertical-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, scrolly: true }); }, render: function () { BI.VerticalLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, _addElement: function (i, item) { var o = this.options; var w = BI.VerticalLayout.superclass._addElement.apply(this, arguments); w.element.css({ "position": "relative" }); if (o.vgap + o.tgap + (item.tgap || 0) !== 0) { w.element.css({ "margin-top": o.vgap + o.tgap + (item.tgap || 0) + "px" }) } if (o.hgap + o.lgap + (item.lgap || 0) !== 0) { w.element.css({ "margin-left": o.hgap + o.lgap + (item.lgap || 0) + "px" }) } if (o.hgap + o.rgap + (item.rgap || 0) !== 0) { w.element.css({ "margin-right": o.hgap + o.rgap + (item.rgap || 0) + "px" }) } if (o.vgap + o.bgap + (item.bgap || 0) !== 0) { w.element.css({ "margin-bottom": o.vgap + o.bgap + (item.bgap || 0) + "px" }) } return w; }, resize: function () { this.stroke(this.options.items); }, populate: function (items) { BI.VerticalLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.vertical', BI.VerticalLayout);/** * * @class BI.WindowLayout * @extends BI.Layout */ BI.WindowLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.WindowLayout.superclass.props.apply(this, arguments), { baseCls: "bi-window-layout", columns: 3, rows: 2, hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, columnSize: [100, "fill", 200], rowSize: [100, "fill"], items: [[ { el: {type: 'bi.button', text: 'button1'} }, { el: {type: 'bi.button', text: 'button2'} }, { el: {type: 'bi.button', text: 'button3'} } ]] }); }, render: function () { BI.WindowLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { this.stroke(this.options.items); }, addItem: function (item) { // do nothing throw new Error("cannot be added") }, stroke: function (items) { var o = this.options; if (BI.isNumber(o.rowSize)) { o.rowSize = BI.makeArray(o.items.length, 1 / o.items.length); } if (BI.isNumber(o.columnSize)) { o.columnSize = BI.makeArray(o.items[0].length, 1 / o.items[0].length); } function firstElement(item, row, col) { if (row === 0) { item.addClass("first-row") } if (col === 0) { item.addClass("first-col"); } item.addClass(BI.isOdd(row + 1) ? "odd-row" : "even-row"); item.addClass(BI.isOdd(col + 1) ? "odd-col" : "even-col"); item.addClass("center-element"); } function firstObject(item, row, col) { var cls = ""; if (row === 0) { cls += " first-row"; } if (col === 0) { cls += " first-col"; } BI.isOdd(row + 1) ? (cls += " odd-row") : (cls += " even-row"); BI.isOdd(col + 1) ? (cls += " odd-col") : (cls += " even-col"); item.cls = (item.cls || "") + cls + " center-element"; } function first(item, row, col) { if (item instanceof BI.Widget) { firstElement(item.element, row, col); } else if (item.el instanceof BI.Widget) { firstElement(item.el.element, row, col); } else if (item.el) { firstObject(item.el, row, col) } else { firstObject(item, row, col); } } for (var i = 0; i < o.rows; i++) { for (var j = 0; j < o.columns; j++) { if (!o.items[i][j]) { throw new Error("item be required"); } if (!this.hasWidget(this.getName() + i + "_" + j)) { var w = BI.createWidget(o.items[i][j]); w.element.css({"position": "absolute"}); this.addWidget(this.getName() + i + "_" + j, w); } } } var left = {}, right = {}, top = {}, bottom = {}; left[0] = 0; top[0] = 0; right[o.columns - 1] = 0; bottom[o.rows - 1] = 0; //从上到下 for (var i = 0; i < o.rows; i++) { for (var j = 0; j < o.columns; j++) { var wi = this.getWidgetByName(this.getName() + i + "_" + j); if (BI.isNull(top[i])) { top[i] = top[i - 1] + (o.rowSize[i - 1] < 1 ? o.rowSize[i - 1] : o.rowSize[i - 1] + o.vgap + o.bgap); } var t = top[i] <= 1 ? top[i] * 100 + "%" : top[i] + o.vgap + o.tgap + "px", h = ""; if (BI.isNumber(o.rowSize[i])) { h = o.rowSize[i] <= 1 ? o.rowSize[i] * 100 + "%" : o.rowSize[i] + "px"; } wi.element.css({"top": t, height: h}); first(wi, i, j); } if (!BI.isNumber(o.rowSize[i])) { break; } } //从下到上 for (var i = o.rows - 1; i >= 0; i--) { for (var j = 0; j < o.columns; j++) { var wi = this.getWidgetByName(this.getName() + i + "_" + j); if (BI.isNull(bottom[i])) { bottom[i] = bottom[i + 1] + (o.rowSize[i + 1] < 1 ? o.rowSize[i + 1] : o.rowSize[i + 1] + o.vgap + o.tgap); } var b = bottom[i] <= 1 ? bottom[i] * 100 + "%" : bottom[i] + o.vgap + o.bgap + "px", h = ""; if (BI.isNumber(o.rowSize[i])) { h = o.rowSize[i] <= 1 ? o.rowSize[i] * 100 + "%" : o.rowSize[i] + "px"; } wi.element.css({"bottom": b, height: h}); first(wi, i, j); } if (!BI.isNumber(o.rowSize[i])) { break; } } //从左到右 for (var j = 0; j < o.columns; j++) { for (var i = 0; i < o.rows; i++) { var wi = this.getWidgetByName(this.getName() + i + "_" + j); if (BI.isNull(left[j])) { left[j] = left[j - 1] + (o.columnSize[j - 1] < 1 ? o.columnSize[j - 1] : o.columnSize[j - 1] + o.hgap + o.rgap); } var l = left[j] <= 1 ? left[j] * 100 + "%" : left[j] + o.hgap + o.lgap + "px", w = ""; if (BI.isNumber(o.columnSize[j])) { w = o.columnSize[j] <= 1 ? o.columnSize[j] * 100 + "%" : o.columnSize[j] + "px"; } wi.element.css({"left": l, width: w}); first(wi, i, j); } if (!BI.isNumber(o.columnSize[j])) { break; } } //从右到左 for (var j = o.columns - 1; j >= 0; j--) { for (var i = 0; i < o.rows; i++) { var wi = this.getWidgetByName(this.getName() + i + "_" + j); if (BI.isNull(right[j])) { right[j] = right[j + 1] + (o.columnSize[j + 1] < 1 ? o.columnSize[j + 1] : o.columnSize[j + 1] + o.hgap + o.lgap) } var r = right[j] <= 1 ? right[j] * 100 + "%" : right[j] + o.hgap + o.rgap + "px", w = ""; if (BI.isNumber(o.columnSize[j])) { w = o.columnSize[j] <= 1 ? o.columnSize[j] * 100 + "%" : o.columnSize[j] + "px"; } wi.element.css({"right": r, width: w}); first(wi, i, j); } if (!BI.isNumber(o.columnSize[j])) { break; } } }, populate: function (items) { BI.WindowLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.window', BI.WindowLayout);/** * 水平和垂直方向都居中容器, 非自适应,用于宽度高度固定的面板 * @class BI.CenterLayout * @extends BI.Layout */ BI.CenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.CenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-center-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.CenterLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("center布局不需要resize"); }, addItem: function (item) { //do nothing throw new Error("cannot be added"); }, stroke: function (items) { var self = this, o = this.options; var list = []; BI.each(items, function (i) { list.push({ column: i, row: 0, el: BI.createWidget({ type: "bi.default", cls: "center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "") }) }); }); BI.each(items, function (i, item) { if (!!item) { var w = BI.createWidget(item); w.element.css({ position: "absolute", left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap, width: "auto", height: "auto" }); list[i].el.addItem(w); } }); BI.createWidget({ type: "bi.grid", element: this, columns: list.length, rows: 1, items: list }); }, populate: function (items) { BI.CenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.center', BI.CenterLayout);/** * 浮动布局实现的居中容器 * @class BI.FloatCenterLayout * @extends BI.Layout */ BI.FloatCenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.FloatCenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-float-center-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.FloatCenterLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("floatcenter布局不需要resize"); }, addItem: function (item) { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var self = this, o = this.options; var list = [], width = 100 / items.length; BI.each(items, function (i) { var widget = BI.createWidget({ type: "bi.default" }); widget.element.addClass("center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "")).css({ width: width + "%", height: "100%" }); list.push({ el: widget }); }); BI.each(items, function (i, item) { if (!!item) { var w = BI.createWidget(item); w.element.css({ position: "absolute", left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap, width: "auto", height: "auto" }); list[i].el.addItem(w); } }); BI.createWidget({ type: "bi.left", element: this, items: list }); }, populate: function (items) { BI.FloatCenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.float_center', BI.FloatCenterLayout);/** * 水平和垂直方向都居中容器, 非自适应,用于宽度高度固定的面板 * @class BI.HorizontalCenterLayout * @extends BI.Layout */ BI.HorizontalCenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.HorizontalCenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-horizontal-center-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.HorizontalCenterLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("horizontal_center布局不需要resize"); }, addItem: function (item) { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var o = this.options; var list = []; BI.each(items, function (i) { list.push({ column: i, row: 0, el: BI.createWidget({ type: "bi.default", cls: "center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "") }) }); }); BI.each(items, function (i, item) { if (!!item) { var w = BI.createWidget(item); w.element.css({ position: "absolute", left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap, width: "auto" }); list[i].el.addItem(w); } }); BI.createWidget({ type: "bi.grid", element: this, columns: list.length, rows: 1, items: list }); }, populate: function (items) { BI.HorizontalCenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.horizontal_center', BI.HorizontalCenterLayout);/** * 垂直方向都居中容器, 非自适应,用于高度不固定的面板 * @class BI.VerticalCenterLayout * @extends BI.Layout */ BI.VerticalCenterLayout = BI.inherit(BI.Layout, { props: function () { return BI.extend(BI.VerticalCenterLayout.superclass.props.apply(this, arguments), { baseCls: "bi-vertical-center-layout", hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0 }); }, render: function () { BI.VerticalCenterLayout.superclass.render.apply(this, arguments); this.populate(this.options.items); }, resize: function () { // console.log("vertical_center布局不需要resize"); }, addItem: function (item) { //do nothing throw new Error("cannot be added") }, stroke: function (items) { var self = this, o = this.options; var list = []; BI.each(items, function (i) { list.push({ column: 0, row: i, el: BI.createWidget({ type: "bi.default", cls: "center-element " + (i === 0 ? "first-element " : "") + (i === items.length - 1 ? "last-element" : "") }) }); }); BI.each(items, function (i, item) { if (!!item) { var w = BI.createWidget(item); w.element.css({ position: "absolute", left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap, height: "auto" }); list[i].el.addItem(w); } }); BI.createWidget({ type: "bi.grid", element: this, columns: 1, rows: list.length, items: list }); }, populate: function (items) { BI.VerticalCenterLayout.superclass.populate.apply(this, arguments); this._mount(); } }); BI.shortcut('bi.vertical_center', BI.VerticalCenterLayout);/** * 保存数据,将js里面用到的常量数据都分离 * */ BI.Data = Data = {}; /** * 存放bi里面通用的一些常量 * @type {{}} */ Data.Constant = BI.Constant = BICst = {}; /** * 缓冲池 * @type {{Buffer: {}}} */ ; (function () { var Buffer = {}; var MODE = false;//设置缓存模式为关闭 Data.BufferPool = { put: function (name, cache) { if (BI.isNotNull(Buffer[name])) { throw new Error("Buffer Pool has the key already!"); } Buffer[name] = cache; }, get: function (name) { return Buffer[name]; }, }; })();/** * 共享池 * @type {{Shared: {}}} */ ; (function () { var _Shared = {}; Data.SharingPool = { _Shared: _Shared, put: function (name, shared) { _Shared[name] = shared; }, cat: function () { var args = Array.prototype.slice.call(arguments, 0), copy = _Shared; for (var i = 0; i < args.length; i++) { copy = copy[args[i]]; } return copy; }, get: function () { return BI.deepClone(this.cat.apply(this, arguments)); }, remove: function (key) { delete _Shared[key]; } }; })();Data.Req = { }; Data.Source = BISource = { };//工程配置 $(function () { //注册布局 var isSupportFlex = BI.isSupportCss3("flex"); BI.Plugin.registerWidget("bi.horizontal", function (ob) { if (isSupportFlex) { return BI.extend(ob, {type: "bi.flex_horizontal"}); } else { return ob; } }); BI.Plugin.registerWidget("bi.center_adapt", function (ob) { if (isSupportFlex && ob.items && ob.items.length <= 1) { //有滚动条的情况下需要用到flex_wrapper_center布局 if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) { //不是IE用flex_wrapper_center布局 if (!BI.isIE()) { return BI.extend(ob, {type: "bi.flex_wrapper_center"}); } return ob; } return BI.extend(ob, {type: "bi.flex_center"}); } else { return ob; } }); BI.Plugin.registerWidget("bi.vertical_adapt", function (ob) { if (isSupportFlex) { //有滚动条的情况下需要用到flex_wrapper_center布局 if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) { //不是IE用flex_wrapper_center布局 if (!BI.isIE()) { return BI.extend({}, ob, {type: "bi.flex_wrapper_vertical_center"}); } return ob; } return BI.extend(ob, {type: "bi.flex_vertical_center"}); } else { return ob; } }); BI.Plugin.registerWidget("bi.float_center_adapt", function (ob) { if (isSupportFlex) { //有滚动条的情况下需要用到flex_wrapper_center布局 if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) { //不是IE用flex_wrapper_center布局 if (!BI.isIE()) { return BI.extend({}, ob, {type: "bi.flex_wrapper_center"}); } return ob; } return BI.extend(ob, {type: "bi.flex_center"}); } else { return ob; } }); //注册滚动条 BI.Plugin.registerWidget("bi.grid_table_scrollbar", function (ob) { if (BI.isIE9Below()) { return BI.extend(ob, {type: "bi.native_table_scrollbar"}); } else { return ob; } }); BI.Plugin.registerWidget("bi.grid_table_horizontal_scrollbar", function (ob) { if (BI.isIE9Below()) { return BI.extend(ob, {type: "bi.native_table_horizontal_scrollbar"}); } else { return ob; } }); //注册控件 BI.Plugin.registerWidget("bi.grid_table", function (ob) { //非chrome下滚动条滑动效果不好,禁止掉 if (!(BI.isChrome() && BI.isWindows() && !BI.isEdge())) { return BI.extend(ob, {type: "bi.quick_grid_table"}); } else { return ob; } }); BI.Plugin.registerWidget("bi.collection_table", function (ob) { //非chrome下滚动条滑动效果不好,禁止掉 if (!(BI.isChrome() && BI.isWindows() && !BI.isEdge())) { return BI.extend(ob, {type: "bi.quick_collection_table"}); } else { return ob; } }); //IE8下滚动条用原生的 if (BI.isIE9Below()) { BI.GridTableScrollbar.SIZE = 18; } });/*! * jQuery Mousewheel 3.1.13 * * Copyright jQuery Foundation and other contributors * Released under the MIT license * http://jquery.org/license */ (function (factory) { if ( typeof define === 'function' && define.amd ) { // AMD. Register as an anonymous module. define(['../core/jquery'], factory); } else if (typeof exports === 'object') { // Node/CommonJS style for Browserify module.exports = factory; } else { // Browser globals factory(jQuery); } }(function ($) { var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'], toBind = ( 'onwheel' in document || document.documentMode >= 9 ) ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'], slice = Array.prototype.slice, nullLowestDeltaTimeout, lowestDelta; if ( $.event.fixHooks ) { for ( var i = toFix.length; i; ) { $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks; } } var special = $.event.special.mousewheel = { version: '3.1.12', setup: function() { if ( this.addEventListener ) { for ( var i = toBind.length; i; ) { this.addEventListener( toBind[--i], handler, false ); } } else { this.onmousewheel = handler; } }, teardown: function() { if ( this.removeEventListener ) { for ( var i = toBind.length; i; ) { this.removeEventListener( toBind[--i], handler, false ); } } else { this.onmousewheel = null; } }, settings: { adjustOldDeltas: true, // see shouldAdjustOldDeltas() below normalizeOffset: true // calls getBoundingClientRect for each event } }; $.fn.extend({ mousewheel: function(fn) { return fn ? this.bind('mousewheel', fn) : this.trigger('mousewheel'); }, unmousewheel: function(fn) { return this.unbind('mousewheel', fn); } }); function handler(event) { var orgEvent = event || window.event, args = slice.call(arguments, 1), delta = 0, deltaX = 0, deltaY = 0, absDelta = 0, offsetX = 0, offsetY = 0; event = $.event.fix(orgEvent); event.type = 'mousewheel'; // Old school scrollwheel delta if ( 'detail' in orgEvent ) { deltaY = orgEvent.detail * -1; } if ( 'wheelDelta' in orgEvent ) { deltaY = orgEvent.wheelDelta; } if ( 'wheelDeltaY' in orgEvent ) { deltaY = orgEvent.wheelDeltaY; } if ( 'wheelDeltaX' in orgEvent ) { deltaX = orgEvent.wheelDeltaX * -1; } // Firefox < 17 horizontal scrolling related to DOMMouseScroll event if ( 'axis' in orgEvent && orgEvent.axis === orgEvent.HORIZONTAL_AXIS ) { deltaX = deltaY * -1; deltaY = 0; } // Set delta to be deltaY or deltaX if deltaY is 0 for backwards compatabilitiy delta = deltaY === 0 ? deltaX : deltaY; // New school wheel delta (wheel event) if ( 'deltaY' in orgEvent ) { deltaY = orgEvent.deltaY * -1; delta = deltaY; } if ( 'deltaX' in orgEvent ) { deltaX = orgEvent.deltaX; if ( deltaY === 0 ) { delta = deltaX * -1; } } // No change actually happened, no reason to go any further if ( deltaY === 0 && deltaX === 0 ) { return; } // Need to convert lines and pages to pixels if we aren't already in pixels // There are three delta modes: // * deltaMode 0 is by pixels, nothing to do // * deltaMode 1 is by lines // * deltaMode 2 is by pages if ( orgEvent.deltaMode === 1 ) { var lineHeight = 40; delta *= lineHeight; deltaY *= lineHeight; deltaX *= lineHeight; } else if ( orgEvent.deltaMode === 2 ) { var pageHeight = 800; delta *= pageHeight; deltaY *= pageHeight; deltaX *= pageHeight; } // Store lowest absolute delta to normalize the delta values absDelta = Math.max( Math.abs(deltaY), Math.abs(deltaX) ); if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; // Adjust older deltas if necessary if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { lowestDelta /= 40; } } // Adjust older deltas if necessary if ( shouldAdjustOldDeltas(orgEvent, absDelta) ) { // Divide all the things by 40! delta /= 40; deltaX /= 40; deltaY /= 40; } // Get a whole, normalized value for the deltas delta = Math[ delta >= 1 ? 'floor' : 'ceil' ](delta / lowestDelta); deltaX = Math[ deltaX >= 1 ? 'floor' : 'ceil' ](deltaX / lowestDelta); deltaY = Math[ deltaY >= 1 ? 'floor' : 'ceil' ](deltaY / lowestDelta); // Normalise offsetX and offsetY properties if ( special.settings.normalizeOffset && this.getBoundingClientRect ) { var boundingRect = this.getBoundingClientRect(); offsetX = event.clientX - boundingRect.left; offsetY = event.clientY - boundingRect.top; } // Add information to the event object event.deltaX = deltaX; event.deltaY = deltaY; event.deltaFactor = lowestDelta; event.offsetX = offsetX; event.offsetY = offsetY; // Go ahead and set deltaMode to 0 since we converted to pixels // Although this is a little odd since we overwrite the deltaX/Y // properties with normalized deltas. event.deltaMode = 0; // Add event and delta to the front of the arguments args.unshift(event, delta, deltaX, deltaY); // Clearout lowestDelta after sometime to better // handle multiple device types that give different // a different lowestDelta // Ex: trackpad = 3 and mouse wheel = 120 if (nullLowestDeltaTimeout) { clearTimeout(nullLowestDeltaTimeout); } nullLowestDeltaTimeout = setTimeout(nullLowestDelta, 200); return ($.event.dispatch || $.event.handle).apply(this, args); } function nullLowestDelta() { lowestDelta = null; } function shouldAdjustOldDeltas(orgEvent, absDelta) { // If this is an older event and the delta is divisable by 120, // then we are assuming that the browser is treating this as an // older mouse wheel event and that we should divide the deltas // by 40 to try and get a more usable deltaFactor. // Side note, this actually impacts the reported scroll distance // in older browsers and can cause scrolling to be slower than native. // Turn this off by setting $.event.special.mousewheel.settings.adjustOldDeltas to false. return special.settings.adjustOldDeltas && orgEvent.type === 'mousewheel' && absDelta % 120 === 0; } }));/** * 当没有元素时有提示信息的view * * Created by GUY on 2015/9/8. * @class BI.Pane * @extends BI.Widget * @abstract */ BI.Pane = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Pane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-pane", tipText: BI.i18nText("BI-No_Selected_Item"), overlap: true, onLoaded: BI.emptyFn }) }, _init: function () { BI.Pane.superclass._init.apply(this, arguments); }, _assertTip: function () { var o = this.options; if (!this._tipText) { this._tipText = BI.createWidget({ type: "bi.label", cls: "bi-tips", text: o.tipText, height: 25 }); BI.createWidget({ type: "bi.vertical", element: this, items: [this._tipText], bgap: 25 }); } }, loading: function () { var self = this, o = this.options; if (o.overlap === true) { if (!BI.Layers.has(this.getName())) { BI.createWidget({ type: 'bi.vtape', items: [{ el: { type: "bi.layout", cls: "loading-background" }, height: 30 }], element: BI.Layers.make(this.getName(), this) }); } BI.Layers.show(self.getName()); } else if (BI.isNull(this._loading)) { this._loading = BI.createWidget({ type: "bi.layout", cls: "loading-background", height: 30 }); this._loading.element.css("zIndex", 1); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this._loading, left: 0, right: 0, top: 0 }] }) } }, loaded: function () { var self = this, o = this.options; BI.Layers.remove(self.getName()); this._loading && this._loading.destroy(); this._loading && (this._loading = null); o.onLoaded(); self.fireEvent(BI.Pane.EVENT_LOADED); }, check: function () { this.setTipVisible(BI.isEmpty(this.options.items)); }, setTipVisible: function (b) { if (b === true) { this._assertTip(); this._tipText.setVisible(true); } else { this._tipText && this._tipText.setVisible(false); } }, populate: function (items) { this.options.items = items || []; this.check(); }, empty: function () { } }); BI.Pane.EVENT_LOADED = "EVENT_LOADED";/** * guy * 这仅仅只是一个超类, 所有简单控件的基类 * 1、类的控制, * 2、title的控制 * 3、文字超过边界显示3个点 * 4、cursor默认pointor * @class BI.Single * @extends BI.Widget * @abstract */ BI.Single = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.Single.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-single", readonly: false, title: null, warningTitle: null, tipType: null, // success或warning value: null }) }, _showToolTip: function (e, opt) { opt || (opt = {}); var self = this; var type = this.getTipType() || (this.isEnabled() ? "success" : "warning"); var title = type === "success" ? this.getTitle() : (this.getWarningTitle() || this.getTitle()); if (BI.isKey(title)) { BI.Tooltips.show(e, this.getName(), title, type, this, opt); } }, _hideTooltip: function () { var self = this; var tooltip = BI.Tooltips.get(this.getName()); if (BI.isNotNull(tooltip)) { tooltip.element.fadeOut(200, function () { BI.Tooltips.remove(self.getName()); }); } }, _init: function () { BI.Single.superclass._init.apply(this, arguments); var self = this, o = this.options; if (BI.isKey(o.title) || BI.isKey(o.warningTitle) || BI.isFunction(o.title) || BI.isFunction(o.warningTitle)) { this.enableHover(); } }, enableHover: function (opt) { opt || (opt = {}); var self = this; if (!this._hoverBinded) { this.element.on("mouseenter.title" + this.getName(), function (e) { self._e = e; if (self.getTipType() === "warning" || (BI.isKey(self.getWarningTitle()) && !self.isEnabled())) { self.timeout = BI.delay(function () { self._showToolTip(self._e || e, opt); }, 200); } else if (self.getTipType() === "success" || self.isEnabled()) { self.timeout = BI.delay(function () { self._showToolTip(self._e || e, opt); }, 500); } }); this.element.on("mousemove.title" + this.getName(), function (e) { self._e = e; if (!self.element.__isMouseInBounds__(e)) { if (BI.isNotNull(self.timeout)) { clearTimeout(self.timeout); } self._hideTooltip(); } }); this.element.on("mouseleave.title" + this.getName(), function () { self._e = null; if (BI.isNotNull(self.timeout)) { clearTimeout(self.timeout); } self._hideTooltip(); }); this._hoverBinded = true; } }, disabledHover: function () { //取消hover事件 if (BI.isNotNull(this.timeout)) { clearTimeout(this.timeout); } this._hideTooltip(); $(this.element).unbind("mouseenter.title" + this.getName()) .unbind("mousemove.title" + this.getName()) .unbind("mouseleave.title" + this.getName()); this._hoverBinded = false; }, populate: function (items) { this.items = items || []; }, //opt: {container: '', belowMouse: false} setTitle: function (title, opt) { this.options.title = title; if (BI.isKey(title)) { this.enableHover(opt); } else { this.disabledHover(); } }, setWarningTitle: function (title, opt) { this.options.warningTitle = title; if (BI.isKey(title)) { this.enableHover(opt); } else { this.disabledHover(); } }, getTipType: function () { return this.options.tipType; }, isReadOnly: function () { return !!this.options.readonly; }, getTitle: function () { var title = this.options.title; if(BI.isFunction(title)) { return title(); } return title; }, getWarningTitle: function () { var title = this.options.warningTitle; if(BI.isFunction(title)) { return title(); } return title; }, setValue: function (val) { if (!this.options.readonly) { this.options.value = val; } }, getValue: function () { return this.options.value; } });/** * guy 表示一行数据,通过position来定位位置的数据 * @class BI.Text * @extends BI.Single */ BI.Text = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Text.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text", textAlign: "left", whiteSpace: "normal", lineHeight: null, handler: null,//如果传入handler,表示处理文字的点击事件,不是区域的 hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, text: "", py: "" }) }, _init: function () { BI.Text.superclass._init.apply(this, arguments); var self = this, o = this.options; if (o.hgap + o.lgap > 0) { this.element.css({ "padding-left": o.hgap + o.lgap + "px" }) } if (o.hgap + o.rgap > 0) { this.element.css({ "padding-right": o.hgap + o.rgap + "px" }) } if (o.vgap + o.tgap > 0) { this.element.css({ "padding-top": o.vgap + o.tgap + "px" }) } if (o.vgap + o.bgap > 0) { this.element.css({ "padding-bottom": o.vgap + o.bgap + "px" }) } if (BI.isNumber(o.height)) { this.element.css({"lineHeight": o.height + "px"}); } if (BI.isNumber(o.lineHeight)) { this.element.css({"lineHeight": o.lineHeight + "px"}); } this.element.css({ "textAlign": o.textAlign, "whiteSpace": o.whiteSpace }); if (o.handler) { this.text = BI.createWidget({ type: "bi.layout", tagName: 'span' }); this.text.element.click(function () { o.handler(self.getValue()); }); BI.createWidget({ type: "bi.default", element: this, items: [this.text] }); } else { this.text = this; } if (BI.isKey(o.text)) { this.setText(o.text); } else if (BI.isKey(o.value)) { this.setText(o.value); } if (BI.isKey(o.keyword)) { this.text.element.__textKeywordMarked__(o.text, o.keyword, o.py); } }, doRedMark: function (keyword) { var o = this.options; this.text.element.__textKeywordMarked__(o.text || o.value, keyword, o.py); }, unRedMark: function () { var o = this.options; this.text.element.__textKeywordMarked__(o.text || o.value, "", o.py); }, doHighLight: function () { this.text.element.addClass("bi-high-light"); }, unHighLight: function () { this.text.element.removeClass("bi-high-light"); }, setValue: function (text) { BI.Text.superclass.setValue.apply(this, arguments); if (!this.isReadOnly()) { this.setText(text); } }, setStyle: function (css) { this.text.element.css(css) }, setText: function (text) { BI.Text.superclass.setText.apply(this, arguments); this.options.text = text; this.text.element.text((text + "").replaceAll(" ", " ")); } }); BI.shortcut("bi.text", BI.Text);/** * guy * @class BI.BasicButton * @extends BI.Single * * 一般的button父级 */ BI.BasicButton = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.BasicButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-basic-button" + (conf.invalid ? "" : " cursor-pointer"), value: "", text: "", stopEvent: false, stopPropagation: false, selected: false, once: false, //点击一次选中有效,再点无效 forceSelected: false, //点击即选中, 选中了就不会被取消,与once的区别是forceSelected不影响事件的触发 forceNotSelected: false, //无论怎么点击都不会被选中 disableSelected: false, //使能选中 shadow: false, isShadowShowingOnSelected: false, //选中状态下是否显示阴影 trigger: null, handler: BI.emptyFn }) }, _init: function () { BI.BasicButton.superclass._init.apply(this, arguments); var opts = this.options; if (opts.selected === true) { BI.nextTick(BI.bind(function () { this.setSelected(opts.selected); }, this)); } BI.nextTick(BI.bind(this.bindEvent, this)); if (opts.shadow) { this._createShadow(); } }, _createShadow: function () { var self = this, o = this.options; var assertMask = function () { if (!self.$mask) { self.$mask = BI.createWidget(BI.isObject(o.shadow) ? o.shadow : {}, { type: "bi.layout", cls: "bi-button-mask" }); self.$mask.invisible(); BI.createWidget({ type: "bi.absolute", element: self, items: [{ el: self.$mask, left: 0, right: 0, top: 0, bottom: 0 }] }); } }; this.element.mouseup(function () { if (!self._hover && !o.isShadowShowingOnSelected) { assertMask(); self.$mask.invisible(); } }); this.element.on("mouseenter." + this.getName(), function (e) { if (self.element.__isMouseInBounds__(e)) { if (self.isEnabled() && !self._hover && (o.isShadowShowingOnSelected || !self.isSelected())) { assertMask(); self.$mask.visible(); } } }); this.element.on("mousemove." + this.getName(), function (e) { if (!self.element.__isMouseInBounds__(e)) { if (self.isEnabled() && !self._hover) { assertMask(); self.$mask.invisible(); } } }); this.element.on("mouseleave." + this.getName(), function () { if (self.isEnabled() && !self._hover) { assertMask(); self.$mask.invisible(); } }); }, bindEvent: function () { var self = this; var o = this.options, hand = this.handle(); if (!hand) { return; } hand = hand.element; var triggerArr = (o.trigger || "").split(","); BI.each(triggerArr, function (idx, trigger) { switch (trigger) { case "mouseup": var mouseDown = false; hand.mousedown(function () { mouseDown = true; ev(e); }); hand.mouseup(function (e) { if (mouseDown === true) { clk(e); } mouseDown = false; ev(e); }); break; case "mousedown": var mouseDown = false; var selected = false; hand.mousedown(function (e) { // if (e.button === 0) { $(document).bind("mouseup." + self.getName(), function (e) { // if (e.button === 0) { if (BI.DOM.isExist(self) && !hand.__isMouseInBounds__(e) && mouseDown === true && !selected) { // self.setSelected(!self.isSelected()); self._trigger(); } mouseDown = false; $(document).unbind("mouseup." + self.getName()); // } }); if (mouseDown === true) { return; } if (self.isSelected()) { selected = true; } else { clk(e); } mouseDown = true; ev(e); // } }); hand.mouseup(function (e) { // if (e.button === 0) { if (BI.DOM.isExist(self) && mouseDown === true && selected === true) { clk(e); } mouseDown = false; selected = false; $(document).unbind("mouseup." + self.getName()); // } }); break; case "dblclick": hand.dblclick(clk); break; case "lclick": var mouseDown = false; var interval; hand.mousedown(function (e) { $(document).bind("mouseup." + self.getName(), function (e) { interval && clearInterval(interval); interval = null; mouseDown = false; $(document).unbind("mouseup." + self.getName()); }); if (mouseDown === true) { return; } if (!self.isEnabled() || (self.isOnce() && self.isSelected())) { return; } interval = setInterval(function () { self.doClick(); }, 100); mouseDown = true; ev(e); }); break; default: if (o.stopEvent || o.stopPropagation) { hand.mousedown(function (e) { ev(e); }); hand.mouseup(function (e) { ev(e); }); } hand.click(clk); break; } }); //之后的300ms点击无效 var onClick = BI.debounce(this._doClick, BI.EVENT_RESPONSE_TIME, true); function ev(e) { if (o.stopEvent) { e.stopEvent(); } if (o.stopPropagation) { e.stopPropagation(); } } function clk(e) { ev(e); if (!self.isEnabled() || (self.isOnce() && self.isSelected())) { return; } onClick.apply(self, arguments); } }, _trigger: function () { var o = this.options; if(!this.isEnabled()){ return; } if (!this.isDisableSelected()) { this.isForceSelected() ? this.setSelected(true) : (this.isForceNotSelected() ? this.setSelected(false) : this.setSelected(!this.isSelected())); } if (this.isValid()) { o.handler.call(this, this.getValue(), this); var v = this.getValue(); this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, v, this); this.fireEvent(BI.BasicButton.EVENT_CHANGE, v, this); } }, _doClick: function (e) { if (this.isValid()) { this.beforeClick(e); } this._trigger(); if (this.isValid()) { this.doClick(e); } }, beforeClick: function () { }, doClick: function () { }, handle: function () { return this; }, hover: function () { this._hover = true; this.handle().element.addClass("hover"); if (this.options.shadow) { this.$mask && this.$mask.setVisible(true); } }, dishover: function () { this._hover = false; this.handle().element.removeClass("hover"); if (this.options.shadow) { this.$mask && this.$mask.setVisible(false); } }, setSelected: function (b) { var o = this.options; o.selected = b; if (b) { this.handle().element.addClass("active"); } else { this.handle().element.removeClass("active"); } if (o.shadow && !o.isShadowShowingOnSelected) { this.$mask && this.$mask.setVisible(false); } }, isSelected: function () { return this.options.selected; }, isOnce: function () { return this.options.once; }, isForceSelected: function () { return this.options.forceSelected; }, isForceNotSelected: function () { return this.options.forceNotSelected; }, isDisableSelected: function () { return this.options.disableSelected; }, setText: function (text) { this.options.text = text; }, getText: function () { return this.options.text; }, _setEnable: function (enable) { BI.BasicButton.superclass._setEnable.apply(this, arguments); if (enable === true) { this.element.removeClass("base-disabled disabled"); } else if (enable === false) { this.element.addClass("base-disabled disabled"); } if (!enable) { if (this.options.shadow) { this.$mask && this.$mask.setVisible(false); } } }, empty: function () { $(document).unbind("mouseup." + this.getName()); BI.BasicButton.superclass.empty.apply(this, arguments); }, destroy: function () { BI.BasicButton.superclass.destroy.apply(this, arguments); } }); BI.BasicButton.EVENT_CHANGE = "BasicButton.EVENT_CHANGE";/** * 表示一个可以展开的节点, 不仅有选中状态而且有展开状态 * * Created by GUY on 2015/9/9. * @class BI.NodeButton * @extends BI.BasicButton * @abstract */ BI.NodeButton = BI.inherit(BI.BasicButton, { _defaultConfig: function() { var conf = BI.NodeButton.superclass._defaultConfig.apply(this, arguments); return BI.extend( conf, { baseCls: (conf.baseCls || "") + " bi-node", open: false }) }, _init:function() { BI.NodeButton.superclass._init.apply(this, arguments); var self = this; BI.nextTick(function(){ self.setOpened(self.isOpened()); }) }, doClick: function(){ BI.NodeButton.superclass.doClick.apply(this, arguments); this.setOpened(!this.isOpened()); }, isOnce: function(){ return false; }, isOpened: function(){ return !!this.options.open; }, setOpened: function(b){ this.options.open = !!b; }, triggerCollapse: function(){ if(this.isOpened()) { this.setOpened(false); this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, this.getValue(), this); } }, triggerExpand: function(){ if(!this.isOpened()) { this.setOpened(true); this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, this.getValue(), this); } } });/** * guy * tip提示 * zIndex在10亿级别 * @class BI.Tip * @extends BI.Single * @abstract */ BI.Tip = BI.inherit(BI.Single, { _defaultConfig: function() { var conf = BI.Link.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-tip", zIndex: BI.zIndex_tip }) }, _init : function() { BI.Tip.superclass._init.apply(this, arguments); this.element.css({"zIndex": this.options.zIndex}); } });/** * Created by GUY on 2015/6/26. * @class BI.ButtonGroup * @extends BI.Widget */ BI.ButtonGroup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ButtonGroup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-button-group", behaviors: {}, items: [], chooseType: BI.Selection.Single, layouts: [{ type: "bi.center", hgap: 0, vgap: 0 }] }) }, _init: function () { BI.ButtonGroup.superclass._init.apply(this, arguments); var behaviors = {}; BI.each(this.options.behaviors, function (key, rule) { behaviors[key] = BI.BehaviorFactory.createBehavior(key, { rule: rule }) }); this.behaviors = behaviors; this.populate(this.options.items); }, _createBtns: function (items) { var o = this.options; return BI.createWidgets(BI.createItems(items, { type: "bi.text_button" })); }, _btnsCreator: function (items) { var self = this, args = Array.prototype.slice.call(arguments), o = this.options; var buttons = this._createBtns(items); args[0] = buttons; BI.each(this.behaviors, function (i, behavior) { behavior.doBehavior.apply(behavior, args); }); BI.each(buttons, function (i, btn) { btn.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (type === BI.Events.CLICK) { switch (o.chooseType) { case BI.ButtonGroup.CHOOSE_TYPE_SINGLE: self.setValue(btn.getValue()); break; case BI.ButtonGroup.CHOOSE_TYPE_NONE: self.setValue([]); break; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj); } else { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); } }); btn.on(BI.Events.DESTROY, function () { BI.remove(self.buttons, btn); }) }); return buttons; }, _packageBtns: function (btns) { var o = this.options; for (var i = o.layouts.length - 1; i > 0; i--) { btns = BI.map(btns, function (k, it) { return BI.extend({}, o.layouts[i], { items: [ BI.extend({}, o.layouts[i].el, { el: it }) ] }) }) } return btns; }, _packageSimpleItems: function (btns) { var o = this.options; return BI.map(o.items, function (i, item) { if (BI.stripEL(item) === item) { return btns[i]; } return BI.extend({}, item, { el: btns[i] }) }) }, _packageItems: function (items, packBtns) { return BI.createItems(BI.makeArrayByArray(items, {}), BI.clone(packBtns)); }, _packageLayout: function (items) { var o = this.options, layout = BI.deepClone(o.layouts[0]); var lay = BI.formatEL(layout).el; while (lay && lay.items && !BI.isEmpty(lay.items)) { lay = BI.formatEL(lay.items[0]).el; } lay.items = items; return layout; }, //如果是一个简单的layout _isSimpleLayout: function () { var o = this.options; return o.layouts.length === 1 && !BI.isArray(o.items[0]) }, doBehavior: function () { var args = Array.prototype.slice.call(arguments); args.unshift(this.buttons); BI.each(this.behaviors, function (i, behavior) { behavior.doBehavior.apply(behavior, args); }) }, prependItems: function (items) { var o = this.options; var btns = this._btnsCreator.apply(this, arguments); this.buttons = BI.concat(btns, this.buttons); if (this._isSimpleLayout() && this.layouts && this.layouts.prependItems) { this.layouts.prependItems(btns); return; } items = this._packageItems(items, this._packageBtns(btns)); this.layouts.prependItems(this._packageLayout(items).items); }, addItems: function (items) { var o = this.options; var btns = this._btnsCreator.apply(this, arguments); this.buttons = BI.concat(this.buttons, btns); //如果是一个简单的layout if (this._isSimpleLayout() && this.layouts && this.layouts.addItems) { this.layouts.addItems(btns); return; } items = this._packageItems(items, this._packageBtns(btns)); this.layouts.addItems(this._packageLayout(items).items); }, removeItemAt: function (indexes) { BI.removeAt(this.buttons, indexes); this.layouts.removeItemAt(indexes); }, removeItems: function (values) { values = BI.isArray(values) ? values : [values]; var deleted = []; BI.each(this.buttons, function (i, button) { if (BI.deepContains(values, button.getValue())) { deleted.push(i); } }); BI.removeAt(this.buttons, deleted); this.layouts.removeItemAt(deleted); }, populate: function (items) { items = items || []; this.empty(); this.options.items = items; this.buttons = this._btnsCreator.apply(this, arguments); if (this._isSimpleLayout()) { items = this._packageSimpleItems(this.buttons); } else { items = this._packageItems(items, this._packageBtns(this.buttons)); } this.layouts = BI.createWidget(BI.extend({element: this}, this._packageLayout(items))); }, setNotSelectedValue: function (v) { v = BI.isArray(v) ? v : [v]; BI.each(this.buttons, function (i, item) { if (BI.deepContains(v, item.getValue())) { item.setSelected && item.setSelected(false); } else { item.setSelected && item.setSelected(true); } }); }, setEnabledValue: function (v) { v = BI.isArray(v) ? v : [v]; BI.each(this.buttons, function (i, item) { if (BI.deepContains(v, item.getValue())) { item.setEnable(true); } else { item.setEnable(false); } }); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; BI.each(this.buttons, function (i, item) { if (BI.deepContains(v, item.getValue())) { item.setSelected && item.setSelected(true); } else { item.setSelected && item.setSelected(false); } }); }, getNotSelectedValue: function () { var v = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !(item.isSelected && item.isSelected())) { v.push(item.getValue()); } }); return v; }, getValue: function () { var v = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && item.isSelected && item.isSelected()) { v.push(item.getValue()); } }); return v; }, getAllButtons: function () { return this.buttons; }, getAllLeaves: function () { return this.buttons; }, getSelectedButtons: function () { var btns = []; BI.each(this.buttons, function (i, item) { if (item.isSelected && item.isSelected()) { btns.push(item); } }); return btns; }, getNotSelectedButtons: function () { var btns = []; BI.each(this.buttons, function (i, item) { if (item.isSelected && !item.isSelected()) { btns.push(item); } }); return btns; }, getIndexByValue: function (value) { var index = -1; BI.any(this.buttons, function (i, item) { if (item.isEnabled() && item.getValue() === value) { index = i; return true; } }); return index; }, getNodeById: function (id) { var node; BI.any(this.buttons, function (i, item) { if (item.isEnabled() && item.options.id === id) { node = item; return true; } }); return node; }, getNodeByValue: function (value) { var node; BI.any(this.buttons, function (i, item) { if (item.isEnabled() && item.getValue() === value) { node = item; return true; } }); return node; }, empty: function () { BI.ButtonGroup.superclass.empty.apply(this, arguments); this.options.items = []; }, destroy: function () { BI.ButtonGroup.superclass.destroy.apply(this, arguments); this.options.items = []; } }); BI.extend(BI.ButtonGroup, { CHOOSE_TYPE_SINGLE: BI.Selection.Single, CHOOSE_TYPE_MULTI: BI.Selection.Multi, CHOOSE_TYPE_ALL: BI.Selection.All, CHOOSE_TYPE_NONE: BI.Selection.None, CHOOSE_TYPE_DEFAULT: BI.Selection.Default }); BI.ButtonGroup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.button_group", BI.ButtonGroup);/** * Created by GUY on 2015/8/10. * @class BI.ButtonTree * @extends BI.ButtonGroup */ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { _defaultConfig: function () { return BI.extend(BI.ButtonTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-button-tree" }) }, _init: function () { BI.ButtonTree.superclass._init.apply(this, arguments); }, setNotSelectedValue: function (v) { v = BI.isArray(v) ? v : [v]; BI.each(this.buttons, function (i, item) { if (!BI.isFunction(item.setSelected)) { item.setNotSelectedValue(v); return; } if (BI.deepContains(v, item.getValue())) { item.setSelected(false); } else { item.setSelected(true); } }); }, setEnabledValue: function (v) { v = BI.isArray(v) ? v : [v]; BI.each(this.buttons, function (i, item) { if (BI.isFunction(item.setEnabledValue)) { item.setEnabledValue(v); return; } if (BI.deepContains(v, item.getValue())) { item.setEnable(true); } else { item.setEnable(false); } }); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; BI.each(this.buttons, function (i, item) { if (!BI.isFunction(item.setSelected)) { item.setValue(v); return; } if (BI.deepContains(v, item.getValue())) { item.setSelected(true); } else { item.setSelected(false); } }); }, getNotSelectedValue: function () { var v = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { v = BI.concat(v, item.getNotSelectedValue()); return; } if (item.isEnabled() && item.isSelected && !item.isSelected()) { v.push(item.getValue()); } }); return v; }, getValue: function () { var v = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { v = BI.concat(v, item.getValue()); return; } if (item.isEnabled() && item.isSelected && item.isSelected()) { v.push(item.getValue()); } }); return v; }, getSelectedButtons: function () { var btns = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { btns = btns.concat(item.getSelectedButtons()); return; } if (item.isSelected && item.isSelected()) { btns.push(item); } }); return btns; }, getNotSelectedButtons: function () { var btns = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { btns = btns.concat(item.getNotSelectedButtons()); return; } if (item.isSelected && !item.isSelected()) { btns.push(item); } }); return btns; }, //获取所有的叶子节点 getAllLeaves: function () { var leaves = []; BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { leaves = leaves.concat(item.getAllLeaves()); return; } if (item.isEnabled()) { leaves.push(item); } }); return leaves; }, getIndexByValue: function (value) { var index = -1; BI.any(this.buttons, function (i, item) { var vs = item.getValue(); if (item.isEnabled() && (vs === value || BI.contains(vs, value))) { index = i; return true; } }); return index; }, getNodeById: function (id) { var node; BI.any(this.buttons, function (i, item) { if (item.isEnabled()) { if (item.attr("id") === id) { node = item; return true; } else if (BI.isFunction(item.getNodeById)) { if (node = item.getNodeById(id)) { return true; } } } }); return node; }, getNodeByValue: function (value) { var node; BI.any(this.buttons, function (i, item) { if (item.isEnabled()) { if (BI.isFunction(item.getNodeByValue)) { if (node = item.getNodeByValue(value)) { return true; } } else if (item.attr("value") === value) { node = item; return true; } } }); return node; } }); BI.ButtonTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.button_tree", BI.ButtonTree);/** * guy * 异步树 * @class BI.TreeView * @extends BI.Pane */ BI.TreeView = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.TreeView.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-tree", paras: {}, itemsCreator: BI.emptyFn }) }, _init: function () { BI.TreeView.superclass._init.apply(this, arguments); this._stop = false; this._createTree(); this.tip = BI.createWidget({ type: "bi.loading_bar", invisible: true, handler: BI.bind(this._loadMore, this) }); BI.createWidget({ type: "bi.vertical", scrollable: true, scrolly: false, element: this, items: [this.tip] }); }, _createTree: function () { this.id = "bi-tree" + BI.UUID(); if (this.nodes) { this.nodes.destroy(); } if (this.tree) { this.tree.destroy(); } this.tree = BI.createWidget({ type: "bi.layout", element: "<ul id='" + this.id + "' class='ztree'></ul>" }); BI.createWidget({ type: "bi.default", element: this.element, items: [this.tree] }); }, //选择节点触发方法 _selectTreeNode: function (treeId, treeNode) { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, treeNode, this); this.fireEvent(BI.TreeView.EVENT_CHANGE, treeNode, this); }, //配置属性 _configSetting: function () { var paras = this.options.paras; var self = this; var setting = { async: { enable: true, url: getUrl, autoParam: ["id", "name"], otherParam: BI.cjkEncodeDO(paras) }, check: { enable: true }, data: { key: { title: "title", name: "text" }, simpleData: { enable: true } }, view: { showIcon: false, expandSpeed: "", nameIsHTML: true, dblClickExpand: false }, callback: { beforeExpand: beforeExpand, onAsyncSuccess: onAsyncSuccess, onAsyncError: onAsyncError, beforeCheck: beforeCheck, onCheck: onCheck, onExpand: onExpand, onCollapse: onCollapse, onClick: onClick } }; var className = "dark", perTime = 100; function onClick(event, treeId, treeNode) { self.nodes.checkNode(treeNode, !treeNode.checked, true, true); } function getUrl(treeId, treeNode) { var parentNode = self._getParentValues(treeNode); treeNode.times = treeNode.times || 1; var param = "id=" + treeNode.id + "×=" + (treeNode.times++) + "&parentValues= " + window.encodeURIComponent(BI.jsonEncode(parentNode)) + "&checkState=" + window.encodeURIComponent(BI.jsonEncode(treeNode.getCheckStatus())); return BI.servletURL + '?op=' + self.options.op + '&cmd=' + self.options.cmd + "&" + param; } function beforeExpand(treeId, treeNode) { if (!treeNode.isAjaxing) { if (!treeNode.children) { treeNode.times = 1; ajaxGetNodes(treeNode, "refresh"); } return true; } else { BI.Msg.toast("Please Wait。", "warning"); return false; } } function onAsyncSuccess(event, treeId, treeNode, msg) { treeNode.halfCheck = false; if (!msg || msg.length === 0 || /^<html>[\s,\S]*<\/html>$/gi.test(msg) || self._stop) { return; } var zTree = self.nodes; var totalCount = treeNode.count || 0; //尝试去获取下一组节点,若获取值为空数组,表示获取完成 // TODO by GUY if (treeNode.children.length > totalCount) { treeNode.count = treeNode.children.length; BI.delay(function () { ajaxGetNodes(treeNode); }, perTime); } else { //treeNode.icon = ""; zTree.updateNode(treeNode); zTree.selectNode(treeNode.children[0]); //className = (className === "dark" ? "":"dark"); } } function onAsyncError(event, treeId, treeNode, XMLHttpRequest, textStatus, errorThrown) { var zTree = self.nodes; BI.Msg.toast("Error!", "warning"); //treeNode.icon = ""; //zTree.updateNode(treeNode); } function ajaxGetNodes(treeNode, reloadType) { var zTree = self.nodes; if (reloadType == "refresh") { //treeNode.icon = BI.servletURL +"?op=resource&resource=/com/fr/bi/web/css/base/third/ztree/img/loading.gif"; zTree.updateNode(treeNode); } zTree.reAsyncChildNodes(treeNode, reloadType, true); } function beforeCheck(treeId, treeNode) { treeNode.halfCheck = false; if (treeNode.checked === true) { //将展开的节点halfCheck设为false,解决展开节点存在halfCheck=true的情况 guy //所有的半选状态都需要取消halfCheck=true的情况 function track(children) { BI.each(children, function (i, ch) { if (ch.halfCheck === true) { ch.halfCheck = false; track(ch.children); } }) } track(treeNode.children); var treeObj = self.nodes; var nodes = treeObj.getSelectedNodes(); $.each(nodes, function (index, node) { node.halfCheck = false; }) } } function onCheck(event, treeId, treeNode) { self._selectTreeNode(treeId, treeNode); } function onExpand(event, treeId, treeNode) { treeNode.halfCheck = false; } function onCollapse(event, treeId, treeNode) { } return setting; }, _getParentValues: function (treeNode) { if (!treeNode.getParentNode()) { return []; } var parentNode = treeNode.getParentNode(); var result = this._getParentValues(parentNode); result = result.concat([this._getNodeValue(parentNode)]); return result; }, _getNodeValue: function (node) { //去除标红 return node.value == null ? node.text.replace(/<[^>]+>/g, "").replaceAll(" ", " ") : node.value; }, //获取半选框值 _getHalfSelectedValues: function (map, node) { var self = this; var checkState = node.getCheckStatus(); //将未选的去掉 if (checkState.checked === false && checkState.half === false) { return; } //如果节点已展开,并且是半选 if (BI.isNotEmptyArray(node.children) && checkState.half === true) { var children = node.children; BI.each(children, function (i, ch) { self._getHalfSelectedValues(map, ch); }); return; } var parent = node.parentValues || self._getParentValues(node); var path = parent.concat(this._getNodeValue(node)); if (BI.isNotEmptyArray(node.children) || checkState.half === false) { this._buildTree(map, path); return; } var storeValues = BI.deepClone(this.options.paras.selectedValues); var treeNode = this._getTree(storeValues, path); this._addTreeNode(map, parent, this._getNodeValue(node), treeNode); }, _getTree: function (map, values) { var cur = map; BI.any(values, function (i, value) { if (cur[value] == null) { return true; } cur = cur[value]; }); return cur; }, _addTreeNode: function (map, values, key, value) { var cur = map; BI.each(values, function (i, value) { if (cur[value] == null) { cur[value] = {}; } cur = cur[value]; }); cur[key] = value; }, //构造树节点 _buildTree: function (map, values) { var cur = map; BI.each(values, function (i, value) { if (cur[value] == null) { cur[value] = {}; } cur = cur[value]; }) }, //获取选中的值 _getSelectedValues: function () { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); track(rootNoots); function track(nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); if (checkState.checked === true || checkState.half === true) { if (checkState.half === true) { self._getHalfSelectedValues(hashMap, node); } else { var parentValues = node.parentValues || self._getParentValues(node); var values = parentValues.concat([self._getNodeValue(node)]); self._buildTree(hashMap, values); } } }) } return hashMap; }, //处理节点 _dealWidthNodes: function (nodes) { var self = this, o = this.options; var ns = BI.Tree.arrayFormat(nodes); BI.each(ns, function (i, n) { n.title = n.title || n.text || n.value; //处理标红 if (BI.isKey(o.paras.keyword)) { n.text = $("<div>").__textKeywordMarked__(n.text, o.paras.keyword, n.py).html(); } else { n.text = (n.text + "").replaceAll(" ", " "); } }); return nodes; }, _loadMore: function () { var self = this, o = this.options; this.tip.setLoading(); var op = BI.extend({}, o.paras, { times: ++this.times }); o.itemsCreator(op, function (res) { if (self._stop === true) { return; } var hasNext = !!res.hasNext, nodes = res.items || []; if (!hasNext) { self.tip.setEnd(); } else { self.tip.setLoaded(); } if (nodes.length > 0) { self.nodes.addNodes(null, self._dealWidthNodes(nodes)); } }); }, //生成树内部方法 _initTree: function (setting) { var self = this, o = this.options; self.fireEvent(BI.Events.INIT); this.times = 1; var tree = this.tree; tree.empty(); this.loading(); this.tip.setVisible(false); var callback = function (nodes) { if (self._stop === true) { return; } self.nodes = $.fn.zTree.init(tree.element, setting, nodes); }; var op = BI.extend({}, o.paras, { times: 1 }); o.itemsCreator(op, function (res) { if (self._stop === true) { return; } var hasNext = !!res.hasNext, nodes = res.items || []; if (nodes.length > 0) { callback(self._dealWidthNodes(nodes)); } self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { self.tip.invisible(); } else { self.tip.setLoaded(); } op.times === 1 && self.fireEvent(BI.Events.AFTERINIT); }); }, //构造树结构, initTree: function (nodes, setting) { var setting = setting || { async: { enable: false }, check: { enable: false }, data: { key: { title: "title", name: "text" }, simpleData: { enable: true } }, view: { showIcon: false, expandSpeed: "", nameIsHTML: true }, callback: {} }; this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); }, start: function () { this._stop = false; }, stop: function () { this._stop = true; }, //生成树方法 stroke: function (config) { delete this.options.keyword; BI.extend(this.options.paras, config); var setting = this._configSetting(); this._createTree(); this.start(); this._initTree(setting); }, populate: function () { this.stroke.apply(this, arguments); }, hasChecked: function () { var treeObj = this.nodes; return treeObj.getCheckedNodes(true).length > 0; }, checkAll: function (checked) { function setNode(children) { BI.each(children, function (i, child) { child.halfCheck = false; setNode(child.children); }); } BI.each(this.nodes.getNodes(), function (i, node) { node.halfCheck = false; setNode(node.children); }); this.nodes && this.nodes.checkAllNodes(checked); }, expandAll: function (flag) { this.nodes && this.nodes.expandAll(flag); }, //设置树节点的状态 setValue: function (value, param) { this.checkAll(false); this.updateValue(value, param); this.refresh(); }, setSelectedValue: function (value) { this.options.paras.selectedValues = BI.deepClone(value || {}); }, updateValue: function (values, param) { if (!this.nodes) { return; } param || (param = "value"); var treeObj = this.nodes; BI.each(values, function (v, op) { var nodes = treeObj.getNodesByParam(param, v, null); BI.each(nodes, function (j, node) { BI.extend(node, {checked: true}, op); treeObj.updateNode(node); }) }); }, refresh: function () { this.nodes && this.nodes.refresh(); }, getValue: function () { if (!this.nodes) { return null; } return this._getSelectedValues(); }, destroyed: function () { this.stop(); this.nodes && this.nodes.destroy(); } }); BI.extend(BI.TreeView, { REQ_TYPE_INIT_DATA: 1, REQ_TYPE_ADJUST_DATA: 2, REQ_TYPE_SELECT_DATA: 3, REQ_TYPE_GET_SELECTED_DATA: 4 }); BI.TreeView.EVENT_CHANGE = "EVENT_CHANGE"; BI.TreeView.EVENT_INIT = BI.Events.INIT; BI.TreeView.EVENT_AFTERINIT = BI.Events.AFTERINIT; BI.shortcut("bi.tree_view", BI.TreeView);/** * guy * 同步树 * @class BI.AsyncTree * @extends BI.TreeView */ BI.AsyncTree = BI.inherit(BI.TreeView, { _defaultConfig: function () { return BI.extend(BI.AsyncTree.superclass._defaultConfig.apply(this, arguments), {}) }, _init: function () { BI.AsyncTree.superclass._init.apply(this, arguments); }, //配置属性 _configSetting: function () { var paras = this.options.paras; var self = this; var setting = { async: { enable: false, otherParam: BI.cjkEncodeDO(paras) }, check: { enable: true }, data: { key: { title: "title", name: "text" }, simpleData: { enable: true } }, view: { showIcon: false, expandSpeed: "", nameIsHTML: true, dblClickExpand: false }, callback: { beforeCheck: beforeCheck, onCheck: onCheck, beforeExpand: beforeExpand, onExpand: onExpand, onCollapse: onCollapse, onClick: onClick } }; function onClick(event, treeId, treeNode) { var zTree = $.fn.zTree.getZTreeObj(treeId); zTree.checkNode(treeNode, !treeNode.checked, true, true); } function beforeCheck(treeId, treeNode) { treeNode.halfCheck = false; if (treeNode.checked === true) { //将展开的节点halfCheck设为false,解决展开节点存在halfCheck=true的情况 guy //所有的半选状态都需要取消halfCheck=true的情况 function track(children) { BI.each(children, function (i, ch) { if (ch.halfCheck === true) { ch.halfCheck = false; track(ch.children); } }) } track(treeNode.children); var treeObj = $.fn.zTree.getZTreeObj(treeId); var nodes = treeObj.getSelectedNodes(); BI.each(nodes, function (index, node) { node.halfCheck = false; }) } } function beforeExpand(treeId, treeNode) { self._beforeExpandNode(treeId, treeNode); } function onCheck(event, treeId, treeNode) { self._selectTreeNode(treeId, treeNode); } function onExpand(event, treeId, treeNode) { treeNode.halfCheck = false; } function onCollapse(event, treeId, treeNode) { treeNode.halfCheck = false; } return setting; }, _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); // var values = parentValues.concat([name]); if (treeNode.checked === true) { } else { var tNode = treeNode; var pNode = this._getTree(this.options.paras.selectedValues, parentValues); if (BI.isNotNull(pNode[name])) { delete pNode[name]; } while (tNode != null && BI.isEmpty(pNode)) { parentValues = parentValues.slice(0, parentValues.length - 1); tNode = tNode.getParentNode(); if (tNode != null) { pNode = this._getTree(this.options.paras.selectedValues, parentValues); name = this._getNodeValue(tNode); delete pNode[name]; } } } BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); }, //展开节点 _beforeExpandNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = treeNode.parentValues || self._getParentValues(treeNode); var op = BI.extend({}, o.paras, { id: treeNode.id, times: 1, parentValues: parentValues.concat(this._getNodeValue(treeNode)), checkState: treeNode.getCheckStatus() }); var complete = function (d) { var nodes = d.items || []; if (nodes.length > 0) { callback(self._dealWidthNodes(nodes), !!d.hasNext); } }; var times = 1; function callback(nodes, hasNext) { self.nodes.addNodes(treeNode, nodes); if (hasNext === true) { BI.delay(function () { times++; op.times = times; o.itemsCreator(op, complete); }, 100); } } if (!treeNode.children) { o.itemsCreator(op, complete) } }, _join: function (valueA, valueB) { var self = this; var map = {}; track([], valueA, valueB); track([], valueB, valueA); function track(parent, node, compare) { BI.each(node, function (n, item) { if (BI.isNull(compare[n])) { self._addTreeNode(map, parent, n, item); } else if (BI.isEmpty(compare[n])) { self._addTreeNode(map, parent, n, {}); } else { track(parent.concat([n]), node[n], compare[n]); } }) } return map; }, hasChecked: function () { return !BI.isEmpty(this.options.paras.selectedValues) || BI.AsyncTree.superclass.hasChecked.apply(this, arguments); }, getValue: function () { if (!this.nodes) { return {}; } var checkedValues = this._getSelectedValues(); if (BI.isEmpty(checkedValues)) { return BI.deepClone(this.options.paras.selectedValues); } if (BI.isEmpty(this.options.paras.selectedValues)) { return checkedValues; } return this._join(checkedValues, this.options.paras.selectedValues); }, //生成树方法 stroke: function (config) { delete this.options.keyword; BI.extend(this.options.paras, config); var setting = this._configSetting(); this._initTree(setting); } }); BI.shortcut("bi.async_tree", BI.AsyncTree);/** * guy * 局部树,两个请求树, 第一个请求构造树,第二个请求获取节点 * @class BI.PartTree * @extends BI.AsyncTree */ BI.PartTree = BI.inherit(BI.AsyncTree, { _defaultConfig: function () { return BI.extend(BI.PartTree.superclass._defaultConfig.apply(this, arguments), {}) }, _init: function () { BI.PartTree.superclass._init.apply(this, arguments); }, _loadMore: function () { var self = this, o = this.options; var op = BI.extend({}, o.paras, { type: BI.TreeView.REQ_TYPE_INIT_DATA, times: ++this.times }); this.tip.setLoading(); o.itemsCreator(op, function (d) { var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; if (self._stop === true) { return; } if (!hasNext) { self.tip.setEnd(); } else { self.tip.setLoaded(); } if (nodes.length > 0) { self.nodes.addNodes(null, self._dealWidthNodes(nodes)); } }); }, _selectTreeNode: function (treeId, treeNode) { var self = this, o = this.options; var parentValues = BI.deepClone(treeNode.parentValues || self._getParentValues(treeNode)); var name = this._getNodeValue(treeNode); if (treeNode.checked === true) { BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); } else { //如果选中的值中不存在该值不处理 var t = this.options.paras.selectedValues; var p = parentValues.concat(name); for (var i = 0, len = p.length; i < len; i++) { t = t[p[i]]; if (t == null) { return; } if (BI.isEmpty(t)) { break; } } o.itemsCreator(BI.extend({}, o.paras, { type: BI.TreeView.REQ_TYPE_SELECT_DATA, notSelectedValue: name, parentValues: parentValues }), function (new_values) { self.options.paras.selectedValues = new_values; BI.AsyncTree.superclass._selectTreeNode.apply(self, arguments); }); } }, _getSelectedValues: function () { var self = this; var hashMap = {}; var rootNoots = this.nodes.getNodes(); track(rootNoots); function track(nodes) { BI.each(nodes, function (i, node) { var checkState = node.getCheckStatus(); if (checkState.checked === false) { return true; } var parentValues = node.parentValues || self._getParentValues(node); //把文字中的html去掉,其实就是把文字颜色去掉 var values = parentValues.concat([self._getNodeValue(node)]); self._buildTree(hashMap, values); // if(checkState.checked === true && checkState.half === false && nodes[i].flag === true){ // continue; // } if (BI.isNotEmptyArray(node.children)) { track(node.children); return true; } if (checkState.half === true) { self._getHalfSelectedValues(hashMap, node); } }) } return hashMap; }, _initTree: function (setting, keyword) { var self = this, o = this.options; this.times = 1; var tree = this.tree; tree.empty(); self.tip.setVisible(false); this.loading(); var op = BI.extend({}, o.paras, { type: BI.TreeView.REQ_TYPE_INIT_DATA, times: this.times }); var complete = function (d) { if (self._stop === true || keyword != o.paras.keyword) { return; } var hasNext = !!d.hasNext, nodes = d.items || []; o.paras.lastSearchValue = d.lastSearchValue; if (nodes.length > 0) { callback(self._dealWidthNodes(nodes)); } self.setTipVisible(nodes.length <= 0); self.loaded(); if (!hasNext) { self.tip.invisible(); } else { self.tip.setLoaded(); } self.fireEvent(BI.Events.AFTERINIT); }; function callback(nodes) { if (self._stop === true) { return; } self.nodes = $.fn.zTree.init(tree.element, setting, nodes); } BI.delay(function () { o.itemsCreator(op, complete); }, 100); }, getValue: function () { var o = this.options; var result = BI.PartTree.superclass.getValue.apply(this, arguments); o.itemsCreator({ type: BI.TreeView.REQ_TYPE_ADJUST_DATA, selectedValues: result }, function (res) { result = res; }); return result; }, //生成树方法 stroke: function (config) { var o = this.options; delete o.paras.keyword; BI.extend(o.paras, config); delete o.paras.lastSearchValue; var setting = this._configSetting(); this._initTree(setting, o.paras.keyword); } }); BI.shortcut("bi.part_tree", BI.PartTree);BI.Resizers = new BI.ResizeController(); BI.Layers = new BI.LayerController(); BI.Maskers = new BI.MaskersController(); BI.Bubbles = new BI.BubblesController(); BI.Tooltips = new BI.TooltipsController(); BI.Popovers = new BI.FloatBoxController(); BI.Broadcasts = new BI.BroadcastController(); BI.StyleLoaders = new BI.StyleLoaderManager();/** * canvas绘图 * * Created by GUY on 2015/11/18. * @class BI.Canvas * @extends BI.Widget */ BI.Canvas = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Canvas.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-canvas" }) }, _init: function () { BI.Canvas.superclass._init.apply(this, arguments); var self = this, o = this.options; var canvas = document.createElement("canvas"); if (!document.createElement('canvas').getContext) { canvas = window.G_vmlCanvasManager.initElement(canvas); } this.element.append(canvas); canvas.width = o.width; canvas.height = o.height; $(canvas).width("100%"); $(canvas).height("100%"); this.canvas = canvas; this._queue = []; }, _getContext: function () { if (!this.ctx) { this.ctx = this.canvas.getContext('2d'); } return this.ctx; }, _attr: function (key, value) { var self = this; if (BI.isNull(key)) { return; } if (BI.isObject(key)) { BI.each(key, function (k, v) { self._queue.push({k: k, v: v}); }); return; } this._queue.push({k: key, v: value}); }, _line: function (x0, y0) { var self = this; var args = [].slice.call(arguments, 2); if (BI.isOdd(args.length)) { this._attr(BI.last(args)); args = BI.initial(args); } this._attr("moveTo", [x0, y0]); var odd = BI.filter(args, function (i) { return i % 2 === 0; }); var even = BI.filter(args, function (i) { return i % 2 !== 0; }); args = BI.zip(odd, even); BI.each(args, function (i, point) { self._attr("lineTo", point); }); }, line: function (x0, y0, x1, y1) { this._line.apply(this, arguments); this._attr("stroke", []); }, rect: function (x, y, w, h, color) { this._attr("fillStyle", color); this._attr("fillRect", [x, y, w, h]); }, circle: function (x, y, radius, color) { this._attr({ fillStyle: color, beginPath: [], arc: [x, y, radius, 0, Math.PI * 2, true], closePath: [], fill: [] }); }, hollow: function () { this._attr("beginPath", []); this._line.apply(this, arguments); this._attr("closePath", []); this._attr("stroke", []); }, solid: function () { this.hollow.apply(this, arguments); this._attr("fill", []); }, gradient: function (x0, y0, x1, y1, start, end) { var grd = this._getContext().createLinearGradient(x0, y0, x1, y1); grd.addColorStop(0, start); grd.addColorStop(1, end); return grd; }, reset: function () { this._getContext().clearRect(0, 0, this.canvas.width, this.canvas.height); }, stroke: function (callback) { var self = this; BI.nextTick(function () { var ctx = self._getContext(); BI.each(self._queue, function (i, q) { if (BI.isFunction(ctx[q.k])) { ctx[q.k].apply(ctx, q.v); } else { ctx[q.k] = q.v; } }); self._queue = []; callback && callback(); }); } }); BI.shortcut("bi.canvas", BI.Canvas);/** * CollectionView * * Created by GUY on 2016/1/15. * @class BI.CollectionView * @extends BI.Widget */ BI.CollectionView = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.CollectionView.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-collection", // width: 400, //必设 // height: 300, //必设 overflowX: true, overflowY: true, cellSizeAndPositionGetter: BI.emptyFn, horizontalOverscanSize: 0, verticalOverscanSize: 0, scrollLeft: 0, scrollTop: 0, items: [] }); }, _init: function () { BI.CollectionView.superclass._init.apply(this, arguments); var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; }, 1000 / 60); this.container = BI.createWidget({ type: "bi.absolute" }); this.element.scroll(function () { if (self._scrollLock === true) { return; } o.scrollLeft = self.element.scrollLeft(); o.scrollTop = self.element.scrollTop(); self._calculateChildrenToRender(); self.fireEvent(BI.CollectionView.EVENT_SCROLL, { scrollLeft: o.scrollLeft, scrollTop: o.scrollTop }); }); BI.createWidget({ type: "bi.vertical", element: this, scrollable: o.overflowX === true && o.overflowY === true, scrolly: o.overflowX === false && o.overflowY === true, scrollx: o.overflowX === true && o.overflowY === false, items: [this.container] }); if (o.items.length > 0) { this._calculateSizeAndPositionData(); this._populate(); } if (o.scrollLeft !== 0 || o.scrollTop !== 0) { BI.nextTick(function () { self.element.scrollTop(o.scrollTop); self.element.scrollLeft(o.scrollLeft); }); } }, _calculateSizeAndPositionData: function () { var o = this.options; var cellMetadata = []; var sectionManager = new BI.SectionManager(); var height = 0; var width = 0; for (var index = 0, len = o.items.length; index < len; index++) { var cellMetadatum = o.cellSizeAndPositionGetter(index); if (cellMetadatum.height == null || isNaN(cellMetadatum.height) || cellMetadatum.width == null || isNaN(cellMetadatum.width) || cellMetadatum.x == null || isNaN(cellMetadatum.x) || cellMetadatum.y == null || isNaN(cellMetadatum.y)) { throw Error(); } height = Math.max(height, cellMetadatum.y + cellMetadatum.height); width = Math.max(width, cellMetadatum.x + cellMetadatum.width); cellMetadatum.index = index; cellMetadata[index] = cellMetadatum; sectionManager.registerCell(cellMetadatum, index); } this._cellMetadata = cellMetadata; this._sectionManager = sectionManager; this._height = height; this._width = width; }, _cellRenderers: function (height, width, x, y) { this._lastRenderedCellIndices = this._sectionManager.getCellIndices(height, width, x, y); return this._cellGroupRenderer() }, _cellGroupRenderer: function () { var self = this, o = this.options; var rendered = []; BI.each(this._lastRenderedCellIndices, function (i, index) { var cellMetadata = self._sectionManager.getCellMetadata(index); rendered.push(cellMetadata); }); return rendered; }, _calculateChildrenToRender: function () { var self = this, o = this.options; var scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()); var scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()); var left = Math.max(0, scrollLeft - o.horizontalOverscanSize); var top = Math.max(0, scrollTop - o.verticalOverscanSize); var right = Math.min(this._width, scrollLeft + o.width + o.horizontalOverscanSize); var bottom = Math.min(this._height, scrollTop + o.height + o.verticalOverscanSize); if (right > 0 && bottom > 0) { //如果滚动的区间并没有超出渲染的范围 if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { return; } var childrenToDisplay = this._cellRenderers(bottom - top, right - left, left, top); var renderedCells = [], renderedKeys = [], renderedWidgets = {}; //存储所有的left和top var lefts = {}, tops = {}; for (var i = 0, len = childrenToDisplay.length; i < len; i++) { var datum = childrenToDisplay[i]; lefts[datum.x] = datum.x; lefts[datum.x + datum.width] = datum.x + datum.width; tops[datum.y] = datum.y; tops[datum.y + datum.height] = datum.y + datum.height; } lefts = BI.toArray(lefts); tops = BI.toArray(tops); var leftMap = BI.invert(lefts); var topMap = BI.invert(tops); //存储上下左右四个边界 var leftBorder = {}, rightBorder = {}, topBorder = {}, bottomBorder = {}; var assertMinBorder = function (border, offset) { if (border[offset] == null) { border[offset] = Number.MAX_VALUE; } }; var assertMaxBorder = function (border, offset) { if (border[offset] == null) { border[offset] = 0; } }; for (var i = 0, len = childrenToDisplay.length; i < len; i++) { var datum = childrenToDisplay[i]; var index = BI.deepIndexOf(this.renderedKeys, datum.index); var child; if (index > -1) { if (datum.width !== this.renderedCells[index]._width) { this.renderedCells[index]._width = datum.width; this.renderedCells[index].el.setWidth(datum.width); } if (datum.height !== this.renderedCells[index]._height) { this.renderedCells[index]._height = datum.height; this.renderedCells[index].el.setHeight(datum.height); } if (this.renderedCells[index]._left !== datum.x) { this.renderedCells[index].el.element.css("left", datum.x + "px"); } if (this.renderedCells[index]._top !== datum.y) { this.renderedCells[index].el.element.css("top", datum.y + "px"); } renderedCells.push(child = this.renderedCells[index]); } else { child = BI.createWidget(BI.extend({ type: "bi.label", width: datum.width, height: datum.height }, o.items[datum.index], { cls: (o.items[datum.index].cls || "") + " container-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), _left: datum.x, _top: datum.y })); renderedCells.push({ el: child, left: datum.x, top: datum.y, _left: datum.x, _top: datum.y, _width: datum.width, _height: datum.height }); } var startTopIndex = topMap[datum.y] | 0; var endTopIndex = topMap[datum.y + datum.height] | 0; for (var k = startTopIndex; k <= endTopIndex; k++) { var t = tops[k]; assertMinBorder(leftBorder, t); assertMaxBorder(rightBorder, t); leftBorder[t] = Math.min(leftBorder[t], datum.x); rightBorder[t] = Math.max(rightBorder[t], datum.x + datum.width); } var startLeftIndex = leftMap[datum.x] | 0; var endLeftIndex = leftMap[datum.x + datum.width] | 0; for (var k = startLeftIndex; k <= endLeftIndex; k++) { var l = lefts[k]; assertMinBorder(topBorder, l); assertMaxBorder(bottomBorder, l); topBorder[l] = Math.min(topBorder[l], datum.y); bottomBorder[l] = Math.max(bottomBorder[l], datum.y + datum.height); } renderedKeys.push(datum.index); renderedWidgets[i] = child; } //已存在的, 需要添加的和需要删除的 var existSet = {}, addSet = {}, deleteArray = []; BI.each(renderedKeys, function (i, key) { if (BI.deepContains(self.renderedKeys, key)) { existSet[i] = key; } else { addSet[i] = key; } }); BI.each(this.renderedKeys, function (i, key) { if (BI.deepContains(existSet, key)) { return; } if (BI.deepContains(addSet, key)) { return; } deleteArray.push(i); }); BI.each(deleteArray, function (i, index) { //性能优化,不调用destroy方法防止触发destroy事件 self.renderedCells[index].el._destroy(); }); var addedItems = []; BI.each(addSet, function (index) { addedItems.push(renderedCells[index]) }); this.container.addItems(addedItems); //拦截父子级关系 this.container._children = renderedWidgets; this.container.attr("items", renderedCells); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; //Todo 左右比较特殊 var minX = BI.min(leftBorder); var maxX = BI.max(rightBorder); var minY = BI.max(topBorder); var maxY = BI.min(bottomBorder); this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } }, _getMaxScrollLeft: function () { return Math.max(0, this._width - this.options.width + (this.options.overflowX ? BI.DOM.getScrollWidth() : 0)); }, _getMaxScrollTop: function () { return Math.max(0, this._height - this.options.height + (this.options.overflowY ? BI.DOM.getScrollWidth() : 0)); }, _populate: function (items) { var o = this.options; this._reRange(); if (items && items !== this.options.items) { this.options.items = items; this._calculateSizeAndPositionData(); } if (o.items.length > 0) { this.container.setWidth(this._width); this.container.setHeight(this._height); this._calculateChildrenToRender(); this.element.scrollTop(o.scrollTop); this.element.scrollLeft(o.scrollLeft); } }, setScrollLeft: function (scrollLeft) { if (this.options.scrollLeft === scrollLeft) { return; } this._scrollLock = true; this.options.scrollLeft = BI.clamp(scrollLeft || 0, 0, this._getMaxScrollLeft()); this._debounceRelease(); this._calculateChildrenToRender(); this.element.scrollLeft(this.options.scrollLeft); }, setScrollTop: function (scrollTop) { if (this.options.scrollTop === scrollTop) { return; } this._scrollLock = true; this.options.scrollTop = BI.clamp(scrollTop || 0, 0, this._getMaxScrollTop()); this._debounceRelease(); this._calculateChildrenToRender(); this.element.scrollTop(this.options.scrollTop); }, setOverflowX: function (b) { var self = this; if (this.options.overflowX !== !!b) { this.options.overflowX = !!b; BI.nextTick(function () { self.element.css({overflowX: !!b ? "auto" : "hidden"}); }); } }, setOverflowY: function (b) { var self = this; if (this.options.overflowY !== !!b) { this.options.overflowY = !!b; BI.nextTick(function () { self.element.css({overflowY: !!b ? "auto" : "hidden"}); }); } }, getScrollLeft: function () { return this.options.scrollLeft; }, getScrollTop: function () { return this.options.scrollTop; }, getMaxScrollLeft: function () { return this._getMaxScrollLeft(); }, getMaxScrollTop: function () { return this._getMaxScrollTop(); }, //重新计算children _reRange: function () { this.renderRange = {}; }, _clearChildren: function () { this.container._children = {}; this.container.attr("items", []); }, restore: function () { BI.each(this.renderedCells, function (i, cell) { cell.el._destroy(); }); this._clearChildren(); this.renderedCells = []; this.renderedKeys = []; this.renderRange = {}; this._scrollLock = false; }, populate: function (items) { if (items && items !== this.options.items) { this.restore(); } this._populate(items); } }); BI.CollectionView.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut('bi.collection_view', BI.CollectionView);/** * @class BI.Combo * @extends BI.Widget */ BI.Combo = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.Combo.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-combo", trigger: "click", toggle: true, direction: "bottom", //top||bottom||left||right||top,left||top,right||bottom,left||bottom,right isDefaultInit: false, destroyWhenHide: false, isNeedAdjustHeight: true,//是否需要高度调整 isNeedAdjustWidth: true, stopEvent: false, stopPropagation: false, adjustLength: 0,//调整的距离 adjustXOffset: 0, adjustYOffset: 0, hideChecker: BI.emptyFn, offsetStyle: "left", //left,right,center el: {}, popup: {}, comboClass: "bi-combo-popup", hoverClass: "bi-combo-hover" }) }, _init: function () { BI.Combo.superclass._init.apply(this, arguments); var self = this, o = this.options; this._initCombo(); this._initPullDownAction(); this.combo.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (self.isEnabled() && self.isValid()) { if (type === BI.Events.EXPAND) { self._popupView(); } if (type === BI.Events.COLLAPSE) { self._hideView(); } if (type === BI.Events.EXPAND) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.fireEvent(BI.Combo.EVENT_EXPAND); } if (type === BI.Events.COLLAPSE) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.isViewVisible() && self.fireEvent(BI.Combo.EVENT_COLLAPSE); } if (type === BI.Events.CLICK) { self.fireEvent(BI.Combo.EVENT_TRIGGER_CHANGE, obj); } } }); self.element.on("mouseenter." + self.getName(), function (e) { if (self.isEnabled() && self.isValid() && self.combo.isEnabled() && self.combo.isValid()) { self.element.addClass(o.hoverClass); } }); self.element.on("mouseleave." + self.getName(), function (e) { if (self.isEnabled() && self.isValid() && self.combo.isEnabled() && self.combo.isValid()) { self.element.removeClass(o.hoverClass); } }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [ {el: this.combo} ] }); o.isDefaultInit && (this._assertPopupView()); BI.Resizers.add(this.getName(), BI.bind(function () { if (this.isViewVisible()) { this._hideView(); } }, this)); }, _toggle: function () { this._assertPopupViewRender(); if (this.popupView.isVisible()) { this._hideView(); } else { if (this.isEnabled()) { this._popupView(); } } }, _initPullDownAction: function () { var self = this, o = this.options; var evs = this.options.trigger.split(","); var st = function (e) { if (o.stopEvent) { e.stopEvent(); } if (o.stopPropagation) { e.stopPropagation(); } }; BI.each(evs, function (i, ev) { switch (ev) { case "hover": self.element.on("mouseenter." + self.getName(), function (e) { if (self.isEnabled() && self.isValid() && self.combo.isEnabled() && self.combo.isValid()) { self._popupView(); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, "", self.combo); self.fireEvent(BI.Combo.EVENT_EXPAND); } }); self.element.on("mouseleave." + self.getName(), function (e) { if (self.isEnabled() && self.isValid() && self.combo.isEnabled() && self.combo.isValid() && o.toggle === true) { self._hideView(); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", self.combo); self.fireEvent(BI.Combo.EVENT_COLLAPSE); } }); break; case "click": var debounce = BI.debounce(function (e) { if (self.combo.element.__isMouseInBounds__(e)) { if (self.isEnabled() && self.isValid() && self.combo.isEnabled() && self.combo.isValid()) { o.toggle ? self._toggle() : self._popupView(); if (self.isViewVisible()) { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, "", self.combo); self.fireEvent(BI.Combo.EVENT_EXPAND); } else { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, "", self.combo); self.fireEvent(BI.Combo.EVENT_COLLAPSE); } } } }, BI.EVENT_RESPONSE_TIME, true); self.element.off(ev + "." + self.getName()).on(ev + "." + self.getName(), function (e) { debounce(e); st(e); }); break; } }); }, _initCombo: function () { this.combo = BI.createWidget(this.options.el); }, _assertPopupView: function () { var self = this; if (this.popupView == null) { this.popupView = BI.createWidget(this.options.popup, { type: "bi.popup_view" }); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (type === BI.Events.CLICK) { self.combo.setValue(self.getValue()); self.fireEvent(BI.Combo.EVENT_CHANGE, value, obj); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.popupView.setVisible(false); BI.nextTick(function () { self.fireEvent(BI.Combo.EVENT_AFTER_INIT); }); } }, _assertPopupViewRender: function () { this._assertPopupView(); if (!this._rendered) { BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [ {el: this.popupView} ] }); this._rendered = true; } }, _hideIf: function (e) { // if (this.element.__isMouseInBounds__(e) || (this.popupView && this.popupView.element.__isMouseInBounds__(e))) { // return; // } if (this.element.find(e.target).length > 0) { return; } var isHide = this.options.hideChecker.apply(this, [e]); if (isHide === false) { return; } this._hideView(); }, _hideView: function () { this.fireEvent(BI.Combo.EVENT_BEFORE_HIDEVIEW); if (this.options.destroyWhenHide === true) { this.popupView && this.popupView.destroy(); this.popupView = null; this._rendered = false; } else { this.popupView && this.popupView.invisible(); } this.element.removeClass(this.options.comboClass); $(document).unbind("mousedown." + this.getName()).unbind("mousewheel." + this.getName()); this.fireEvent(BI.Combo.EVENT_AFTER_HIDEVIEW); }, _popupView: function () { this._assertPopupViewRender(); this.fireEvent(BI.Combo.EVENT_BEFORE_POPUPVIEW); this.popupView.visible(); this.adjustWidth(); this.adjustHeight(); this.element.addClass(this.options.comboClass); $(document).bind("mousedown." + this.getName(), BI.bind(this._hideIf, this)).bind("mousewheel." + this.getName(), BI.bind(this._hideIf, this)); this.fireEvent(BI.Combo.EVENT_AFTER_POPUPVIEW); }, adjustWidth: function () { var o = this.options; if (!this.popupView) { return; } if (o.isNeedAdjustWidth === true) { this.resetListWidth(""); var width = this.popupView.element.outerWidth(); var maxW = this.element.outerWidth() || o.width; if (width > maxW + 80) { maxW = maxW + 80; } else if (width > maxW) { maxW = width; } this.resetListWidth(maxW < 100 ? 100 : maxW); } }, adjustHeight: function () { var o = this.options, p = {}; if (!this.popupView) { return; } var isVisible = this.popupView.isVisible(); this.popupView.visible(); switch (o.direction) { case "bottom": case "bottom,right": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['bottom', 'top', 'right', 'left'], o.offsetStyle); break; case "top": case "top,right": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['top', 'bottom', 'right', 'left'], o.offsetStyle); break; case "left": case "left,bottom": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['left', 'right', 'bottom', 'top'], o.offsetStyle); break; case "right": case "right,bottom": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['right', 'left', 'bottom', 'top'], o.offsetStyle); break; case "top,left": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['top', 'bottom', 'left', 'right'], o.offsetStyle); break; case "bottom,left": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight, ['bottom', 'top', 'left', 'right'], o.offsetStyle); break; case "left,top": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['left', 'right', 'top', 'bottom'], o.offsetStyle); break; case "right,top": p = $.getComboPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength, o.adjustYOffset, o.isNeedAdjustHeight, ['right', 'left', 'top', 'bottom'], o.offsetStyle); break; case "top,custom": case "custom,top": p = $.getTopAdaptPosition(this.combo, this.popupView, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight); break; case "custom,bottom": case "bottom,custom": p = $.getBottomAdaptPosition(this.combo, this.popupView, o.adjustYOffset || o.adjustLength, o.isNeedAdjustHeight); break; case "left,custom": case "custom,left": p = $.getLeftAdaptPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength); delete p.top; delete p.adaptHeight; break; case "custom,right": case "right,custom": p = $.getRightAdaptPosition(this.combo, this.popupView, o.adjustXOffset || o.adjustLength); delete p.top; delete p.adaptHeight; break; } if ("adaptHeight" in p) { this.resetListHeight(p['adaptHeight']); } if ("left" in p) { this.popupView.element.css({ left: p.left }); } if ("top" in p) { this.popupView.element.css({ top: p.top }); } this.position = p; this.popupView.setVisible(isVisible); }, resetListHeight: function (h) { this._assertPopupView(); this.popupView.resetHeight && this.popupView.resetHeight(h); }, resetListWidth: function (w) { this._assertPopupView(); this.popupView.resetWidth && this.popupView.resetWidth(w); }, populate: function (items) { this._assertPopupView(); this.popupView.populate.apply(this.popupView, arguments); this.combo.populate.apply(this.combo, arguments); }, _setEnable: function (arg) { BI.Combo.superclass._setEnable.apply(this, arguments); !arg && this.element.removeClass(this.options.hoverClass); !arg && this.isViewVisible() && this._hideView(); }, setValue: function (v) { this._assertPopupView(); this.combo.setValue(v); this.popupView && this.popupView.setValue(v); }, getValue: function () { this._assertPopupView(); return this.popupView && this.popupView.getValue(); }, isViewVisible: function () { return this.isEnabled() && this.combo.isEnabled() && !!this.popupView && this.popupView.isVisible(); }, showView: function () { if (this.isEnabled() && this.combo.isEnabled()) { this._popupView(); } }, hideView: function () { this._hideView(); }, getView: function () { return this.popupView; }, getPopupPosition: function () { return this.position; }, toggle: function () { this._toggle(); }, destroy: function () { $(document).unbind("mousedown." + this.getName()) .unbind("mousewheel." + this.getName()) .unbind("mouseenter." + this.getName()) .unbind("mousemove." + this.getName()) .unbind("mouseleave." + this.getName()); BI.Resizers.remove(this.getName()); BI.Combo.superclass.destroy.apply(this, arguments); } }); BI.Combo.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE"; BI.Combo.EVENT_CHANGE = "EVENT_CHANGE"; BI.Combo.EVENT_EXPAND = "EVENT_EXPAND"; BI.Combo.EVENT_COLLAPSE = "EVENT_COLLAPSE"; BI.Combo.EVENT_AFTER_INIT = "EVENT_AFTER_INIT"; BI.Combo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.Combo.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW"; BI.Combo.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW"; BI.Combo.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW"; BI.shortcut("bi.combo", BI.Combo);/** * * 某个可以展开的节点 * * Created by GUY on 2015/9/10. * @class BI.Expander * @extends BI.Widget */ BI.Expander = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Expander.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-expander", trigger: "click", toggle: true, //direction: "bottom", //top,bottom四个方向 isDefaultInit: false, //是否默认初始化子节点 el: {}, popup: {}, expanderClass: "bi-expander-popup", hoverClass: "bi-expander-hover" }) }, _init: function () { BI.Expander.superclass._init.apply(this, arguments); var self = this, o = this.options; this._expanded = !!o.el.open; this._initExpander(); this._initPullDownAction(); this.expander.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (self.isEnabled() && self.isValid()) { if (type === BI.Events.EXPAND) { self._popupView(); } if (type === BI.Events.COLLAPSE) { self._hideView(); } if (type === BI.Events.EXPAND) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.fireEvent(BI.Expander.EVENT_EXPAND); } if (type === BI.Events.COLLAPSE) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.isViewVisible() && self.fireEvent(BI.Expander.EVENT_COLLAPSE); } if (type === BI.Events.CLICK) { self.fireEvent(BI.Expander.EVENT_TRIGGER_CHANGE, value, obj); } } }); this.element.hover(function () { if (self.isEnabled() && self.isValid() && self.expander.isEnabled() && self.expander.isValid()) { self.element.addClass(o.hoverClass); } }, function () { if (self.isEnabled() && self.isValid() && self.expander.isEnabled() && self.expander.isValid()) { self.element.removeClass(o.hoverClass); } }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [ {el: this.expander} ] }); o.isDefaultInit && this._assertPopupView(); if (this.expander.isOpened() === true) { this._popupView(); } }, _toggle: function () { this._assertPopupViewRender(); if (this.popupView.isVisible()) { this._hideView(); } else { if (this.isEnabled()) { this._popupView(); } } }, _initPullDownAction: function () { var self = this, o = this.options; var evs = this.options.trigger.split(","); BI.each(evs, function (i, e) { switch (e) { case "hover": self.element[e](function (e) { if (self.isEnabled() && self.isValid() && self.expander.isEnabled() && self.expander.isValid()) { self._popupView(); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, '', self.expander); self.fireEvent(BI.Expander.EVENT_EXPAND); } }, function () { if (self.isEnabled() && self.isValid() && self.expander.isEnabled() && self.expander.isValid() && o.toggle) { self._hideView(); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.expander); self.fireEvent(BI.Expander.EVENT_COLLAPSE); } }); break; default : if (e) { self.element.off(e + "." + self.getName()).on(e + "." + self.getName(), BI.debounce(function (e) { if (self.expander.element.__isMouseInBounds__(e)) { if (self.isEnabled() && self.isValid() && self.expander.isEnabled() && self.expander.isValid()) { o.toggle ? self._toggle() : self._popupView(); if (self.isExpanded()) { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, "", self.expander); self.fireEvent(BI.Expander.EVENT_EXPAND); } else { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.expander); self.fireEvent(BI.Expander.EVENT_COLLAPSE); } } } }, BI.EVENT_RESPONSE_TIME, true)); } break; } }) }, _initExpander: function () { this.expander = BI.createWidget(this.options.el); }, _assertPopupView: function () { var self = this; if (this.popupView == null) { this.popupView = BI.createWidget(this.options.popup, { type: "bi.button_group", cls: "expander-popup", layouts: [{ type: "bi.vertical", hgap: 0, vgap: 0 }] }); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { //self.setValue(self.getValue()); self.fireEvent(BI.Expander.EVENT_CHANGE, value, obj); } }); this.popupView.setVisible(this.isExpanded()); BI.nextTick(function () { self.fireEvent(BI.Expander.EVENT_AFTER_INIT); }); } }, _assertPopupViewRender: function () { this._assertPopupView(); if (!this._rendered) { BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [ {el: this.popupView} ] }); this._rendered = true; } }, _hideView: function () { this.fireEvent(BI.Expander.EVENT_BEFORE_HIDEVIEW); this._expanded = false; this.expander.setOpened(false); this.popupView && this.popupView.invisible(); this.element.removeClass(this.options.expanderClass); this.fireEvent(BI.Expander.EVENT_AFTER_HIDEVIEW); }, _popupView: function () { this._assertPopupViewRender(); this.fireEvent(BI.Expander.EVENT_BEFORE_POPUPVIEW); this._expanded = true; this.expander.setOpened(true); this.popupView.visible(); this.element.addClass(this.options.expanderClass); this.fireEvent(BI.Expander.EVENT_AFTER_POPUPVIEW); }, populate: function (items) { //this._assertPopupView(); this.popupView && this.popupView.populate.apply(this.popupView, arguments); this.expander.populate.apply(this.expander, arguments); }, _setEnable: function (arg) { BI.Expander.superclass._setEnable.apply(this, arguments); !arg && this.element.removeClass(this.options.hoverClass); !arg && this.isViewVisible() && this._hideView(); }, setValue: function (v) { //this._assertPopupView(); this.expander.setValue(v); this.popupView && this.popupView.setValue(v); }, getValue: function () { //this._assertPopupView(); return this.popupView ? this.popupView.getValue() : []; }, isViewVisible: function () { return this.isEnabled() && this.expander.isEnabled() && !!this.popupView && this.popupView.isVisible(); }, isExpanded: function () { return this._expanded; }, showView: function () { if (this.isEnabled() && this.expander.isEnabled()) { this._popupView(); } }, hideView: function () { this._hideView(); }, getView: function () { return this.popupView; }, getAllLeaves: function () { return this.popupView && this.popupView.getAllLeaves(); }, getNodeById: function (id) { if (this.expander.options.id === id) { return this.expander; } return this.popupView && this.popupView.getNodeById(id); }, getNodeByValue: function (value) { if (this.expander.getValue() === value) { return this.expander; } return this.popupView && this.popupView.getNodeByValue(value); }, destroy: function () { BI.Expander.superclass.destroy.apply(this, arguments); } }); BI.Expander.EVENT_EXPAND = "EVENT_EXPAND"; BI.Expander.EVENT_COLLAPSE = "EVENT_COLLAPSE"; BI.Expander.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE"; BI.Expander.EVENT_CHANGE = "EVENT_CHANGE"; BI.Expander.EVENT_AFTER_INIT = "EVENT_AFTER_INIT"; BI.Expander.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.Expander.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW"; BI.Expander.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW"; BI.Expander.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW"; BI.shortcut("bi.expander", BI.Expander);/** * Created by GUY on 2015/8/10. */ BI.ComboGroup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ComboGroup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-combo-group bi-list-item", //以下这些属性对每一个combo都是公用的 trigger: "click,hover", direction: "right", adjustLength: 0, isDefaultInit: false, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: {type: "bi.text_button", text: "", value: ""}, children: [], popup: { el: { type: "bi.button_tree", chooseType: 0, layouts: [{ type: "bi.vertical" }] } } }) }, _init: function () { BI.ComboGroup.superclass._init.apply(this, arguments); this.populate(this.options.el); }, populate: function (item) { var self = this, o = this.options; var children = o.children; if (BI.isEmpty(children)) { throw new Error("ComboGroup构造错误"); } BI.each(children, function (i, ch) { var son = BI.formatEL(ch).el.children; ch = BI.formatEL(ch).el; if (!BI.isEmpty(son)) { ch.el = BI.clone(ch); ch.children = son; ch.type = "bi.combo_group"; ch.action = o.action; ch.height = o.height; ch.direction = o.direction; ch.isDefaultInit = o.isDefaultInit; ch.isNeedAdjustHeight = o.isNeedAdjustHeight; ch.isNeedAdjustWidth = o.isNeedAdjustWidth; ch.adjustLength = o.adjustLength; ch.popup = o.popup; } }) this.combo = BI.createWidget({ type: "bi.combo", element: this, height: o.height, trigger: o.trigger, direction: o.direction, isDefaultInit: o.isDefaultInit, isNeedAdjustWidth: o.isNeedAdjustWidth, isNeedAdjustHeight: o.isNeedAdjustHeight, adjustLength: o.adjustLength, el: item, popup: BI.extend({}, o.popup, { el: BI.extend({ items: children }, o.popup.el) }) }) this.combo.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.ComboGroup.EVENT_CHANGE, obj); } }) }, getValue: function () { return this.combo.getValue(); }, setValue: function (v) { this.combo.setValue(v); } }); BI.ComboGroup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.combo_group", BI.ComboGroup);BI.VirtualGroup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.VirtualGroup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-virtual-group", items: [], layouts: [{ type: "bi.center", hgap: 0, vgap: 0 }] }) }, render: function () { this.populate(this.options.items); }, _packageBtns: function (items) { var o = this.options; for (var i = o.layouts.length - 1; i > 0; i--) { items = BI.map(items, function (k, it) { return BI.extend({}, o.layouts[i], { items: [ BI.extend({}, o.layouts[i].el, { el: BI.stripEL(it) }) ] }) }) } return items; }, _packageItems: function (items, packBtns) { return BI.createItems(BI.makeArrayByArray(items, {}), BI.clone(packBtns)); }, _packageLayout: function (items) { var o = this.options, layout = BI.deepClone(o.layouts[0]); var lay = BI.formatEL(layout).el; while (lay && lay.items && !BI.isEmpty(lay.items)) { lay = BI.formatEL(lay.items[0]).el; } lay.items = items; return layout; }, addItems: function (items) { this.layouts.addItems(items); }, prependItems: function (items) { this.layouts.prependItems(items); }, setValue: function (v) { this.layouts.setValue(v); }, getValue: function () { return this.layouts.getValue(); }, empty: function () { this.layouts.empty(); }, populate: function (items) { var self = this; items = items || []; this.options.items = items; items = this._packageBtns(items); if (!this.layouts) { this.layouts = BI.createWidget(BI.extend({element: this}, this._packageLayout(items))); } else { this.layouts.populate(items); } } }); BI.VirtualGroup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.virtual_group", BI.VirtualGroup);/** * 加载控件 * * Created by GUY on 2015/8/31. * @class BI.Loader * @extends BI.Widget */ BI.Loader = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Loader.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-loader", direction: "top", isDefaultInit: true,//是否默认初始化数据 logic: { dynamic: true, scrolly: true }, //下面是button_group的属性 el: { type: "bi.button_group" }, items: [], itemsCreator: BI.emptyFn, onLoaded: BI.emptyFn, //下面是分页信息 count: false, prev: false, next: {}, hasPrev: BI.emptyFn, hasNext: BI.emptyFn }) }, _prevLoad: function () { var self = this, o = this.options; this.prev.setLoading(); o.itemsCreator.apply(this, [{times: --this.times}, function () { self.prev.setLoaded(); self.prependItems.apply(self, arguments); }]); }, _nextLoad: function () { var self = this, o = this.options; this.next.setLoading(); o.itemsCreator.apply(this, [{times: ++this.times}, function () { self.next.setLoaded(); self.addItems.apply(self, arguments); }]); }, _init: function () { BI.Loader.superclass._init.apply(this, arguments); var self = this, o = this.options; if (o.itemsCreator === false) { o.prev = false; o.next = false; } if (o.prev !== false) { this.prev = BI.createWidget(BI.extend({ type: "bi.loading_bar" }, o.prev)); this.prev.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self._prevLoad(); } }); } this.button_group = BI.createWidget(o.el, { type: "bi.button_group", chooseType: 0, items: o.items, behaviors: {}, layouts: [{ type: "bi.vertical" }] }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.Loader.EVENT_CHANGE, obj); } }); if (o.next !== false) { this.next = BI.createWidget(BI.extend({ type: "bi.loading_bar" }, o.next)); this.next.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self._nextLoad(); } }) } BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({ scrolly: true }, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.prev, this.button_group, this.next) })))); o.isDefaultInit && BI.isEmpty(o.items) && BI.nextTick(BI.bind(function () { o.isDefaultInit && BI.isEmpty(o.items) && this.populate(); }, this)); if (BI.isNotEmptyArray(o.items)) { this.populate(o.items); } }, hasPrev: function () { var o = this.options; if (BI.isNumber(o.count)) { return this.count < o.count; } return !!o.hasPrev.apply(this, [{ times: this.times, count: this.count }]) }, hasNext: function () { var o = this.options; if (BI.isNumber(o.count)) { return this.count < o.count; } return !!o.hasNext.apply(this, [{ times: this.times, count: this.count }]) }, prependItems: function (items) { this.count += items.length; if (this.next !== false) { if (this.hasPrev()) { this.options.items = this.options.items.concat(items); this.prev.setLoaded(); } else { this.prev.setEnd(); } } this.button_group.prependItems.apply(this.button_group, arguments); }, addItems: function (items) { this.count += items.length; if (BI.isObject(this.next)) { if (this.hasNext()) { this.options.items = this.options.items.concat(items); this.next.setLoaded(); } else { this.next.setEnd(); } } this.button_group.addItems.apply(this.button_group, arguments); }, populate: function (items) { var self = this, o = this.options; if (arguments.length === 0 && (BI.isFunction(o.itemsCreator))) { o.itemsCreator.apply(this, [{times: 1}, function () { if (arguments.length === 0) { throw new Error("arguments can not be null!!!"); } self.populate.apply(self, arguments); o.onLoaded(); }]); return; } this.options.items = items; this.times = 1; this.count = 0; this.count += items.length; if (BI.isObject(this.next)) { if (this.hasNext()) { this.next.setLoaded(); } else { this.next.invisible(); } } if (BI.isObject(this.prev)) { if (this.hasPrev()) { this.prev.setLoaded(); } else { this.prev.invisible(); } } this.button_group.populate.apply(this.button_group, arguments); }, setNotSelectedValue: function () { this.button_group.setNotSelectedValue.apply(this.button_group, arguments); }, getNotSelectedValue: function () { return this.button_group.getNotSelectedValue(); }, setValue: function () { this.button_group.setValue.apply(this.button_group, arguments); }, getValue: function () { return this.button_group.getValue.apply(this.button_group, arguments); }, getAllButtons: function () { return this.button_group.getAllButtons(); }, getAllLeaves: function () { return this.button_group.getAllLeaves(); }, getSelectedButtons: function () { return this.button_group.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.button_group.getNotSelectedButtons(); }, getIndexByValue: function (value) { return this.button_group.getIndexByValue(value); }, getNodeById: function (id) { return this.button_group.getNodeById(id); }, getNodeByValue: function (value) { return this.button_group.getNodeByValue(value); }, empty: function () { this.button_group.empty(); BI.each([this.prev, this.next], function (i, ob) { ob && ob.setVisible(false); }); }, destroy: function () { BI.Loader.superclass.destroy.apply(this, arguments); } }); BI.Loader.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.loader", BI.Loader);/** * Created by GUY on 2015/6/26. */ BI.Navigation = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Navigation.superclass._defaultConfig.apply(this, arguments), { direction: "bottom",//top, bottom, left, right, custom logic: { dynamic: false }, single: false, defaultShowIndex: false, tab: false, cardCreator: function (v) { return BI.createWidget(); }, afterCardCreated: BI.emptyFn, afterCardShow: BI.emptyFn }) }, render: function () { var self = this, o = this.options; this.tab = BI.createWidget(this.options.tab, {type: "bi.button_group"}); this.cardMap = {}; this.showIndex = 0; this.layout = BI.createWidget({ type: "bi.card" }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout) })))); new BI.ShowListener({ eventObj: this.tab, cardLayout: this.layout, cardNameCreator: function (v) { return self.showIndex + v; }, cardCreator: function (v) { var card = o.cardCreator(v); self.cardMap[v] = card; return card; }, afterCardCreated: BI.bind(this.afterCardCreated, this), afterCardShow: BI.bind(this.afterCardShow, this) }); }, mounted: function () { var o = this.options; if (o.defaultShowIndex !== false) { this.setSelect(o.defaultShowIndex); } }, _deleteOtherCards: function (currCardName) { var self = this, o = this.options; if (o.single === true) { BI.each(this.cardMap, function (name, card) { if (name !== (currCardName + "")) { self.layout.deleteCardByName(name); delete self.cardMap[name]; } }); } }, afterCardCreated: function (v) { var self = this; this.cardMap[v].on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.Navigation.EVENT_CHANGE, obj); } }); this.options.afterCardCreated.apply(this, arguments); }, afterCardShow: function (v) { this.showIndex = v; this._deleteOtherCards(v); this.options.afterCardShow.apply(this, arguments); }, populate: function () { var card = this.layout.getShowingCard(); if (card) { return card.populate.apply(card, arguments); } }, _assertCard: function (v) { if (!this.layout.isCardExisted(v)) { var card = this.options.cardCreator(v); this.cardMap[v] = card; this.layout.addCardByName(v, card); this.afterCardCreated(v); } }, setSelect: function (v) { this._assertCard(v); this.layout.showCardByName(v); this._deleteOtherCards(v); if (this.showIndex !== v) { this.showIndex = v; BI.nextTick(BI.bind(this.afterCardShow, this, v)); } }, getSelect: function () { return this.showIndex; }, getSelectedCard: function () { if (BI.isKey(this.showIndex)) { return this.cardMap[this.showIndex]; } }, /** * @override */ setValue: function (v) { var card = this.layout.getShowingCard(); if (card) { card.setValue(v); } }, /** * @override */ getValue: function () { var card = this.layout.getShowingCard(); if (card) { return card.getValue(); } }, empty: function () { this.layout.deleteAllCard(); this.cardMap = {}; }, destroy: function () { BI.Navigation.superclass.destroy.apply(this, arguments); } }); BI.Navigation.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.navigation", BI.Navigation);/** * 搜索逻辑控件 * * Created by GUY on 2015/9/28. * @class BI.Searcher * @extends BI.Widget */ BI.Searcher = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Searcher.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-searcher", lgap: 0, rgap: 0, tgap: 0, bgap: 0, vgap: 0, hgap: 0, isDefaultInit: false, isAutoSearch: true, //是否自动搜索 isAutoSync: true, //是否自动同步数据, 即是否保持搜索面板和adapter面板状态值的统一 chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, //isAutoSearch为false时启用 onSearch: function (op, callback) { callback([]) }, el: { type: "bi.search_editor" }, popup: { type: "bi.searcher_view" }, adapter: null, masker: { //masker层 offset: {} } }) }, _init: function () { BI.Searcher.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget(o.el, { type: "bi.search_editor" }); BI.createWidget({ type: "bi.vertical", element: this, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, vgap: o.vgap, hgap: o.hgap, items: [this.editor] }); o.isDefaultInit && (this._assertPopupView()); var search = BI.debounce(BI.bind(this._search, this), BI.EVENT_RESPONSE_TIME, true); this.editor.on(BI.Controller.EVENT_CHANGE, function (type) { switch (type) { case BI.Events.STARTEDIT: self._startSearch(); break; case BI.Events.EMPTY: self._stopSearch(); break; case BI.Events.CHANGE: search(); break; case BI.Events.PAUSE: self._pauseSearch(); break; } }) }, _assertPopupView: function () { var self = this, o = this.options; if ((o.masker && !BI.Maskers.has(this.getName())) || (o.masker === false && !this.popupView)) { this.popupView = BI.createWidget(o.popup, { type: "bi.searcher_view", chooseType: o.chooseType }); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { if (o.isAutoSync) { var values = o.adapter && o.adapter.getValue(); if (!obj.isSelected()) { o.adapter && o.adapter.setValue(BI.deepWithout(values, obj.getValue())); } else { switch (o.chooseType) { case BI.ButtonGroup.CHOOSE_TYPE_SINGLE: o.adapter && o.adapter.setValue([obj.getValue()]); break; case BI.ButtonGroup.CHOOSE_TYPE_MULTI: values.push(obj.getValue()); o.adapter && o.adapter.setValue(values); break; } } } self.fireEvent(BI.Searcher.EVENT_CHANGE, value, obj); } }); BI.nextTick(function () { self.fireEvent(BI.Searcher.EVENT_AFTER_INIT); }); } if (o.masker && !BI.Maskers.has(this.getName())) { BI.Maskers.create(this.getName(), o.adapter, BI.extend({ container: this, render: this.popupView }, o.masker)); } }, _startSearch: function () { this._assertPopupView(); this._stop = false; this._isSearching = true; this.fireEvent(BI.Searcher.EVENT_START); this.popupView.startSearch && this.popupView.startSearch(); //搜索前先清空dom // BI.Maskers.get(this.getName()).empty(); BI.nextTick(function (name) { BI.Maskers.show(name); }, this.getName()); }, _pauseSearch: function () { var o = this.options, name = this.getName(); this._stop = true; BI.nextTick(function (name) { BI.Maskers.hide(name); }, this.getName()); if (this._isSearching === true) { this.popupView && this.popupView.pauseSearch && this.popupView.pauseSearch(); this.fireEvent(BI.Searcher.EVENT_PAUSE); } this._isSearching = false; }, _stopSearch: function () { var o = this.options, name = this.getName(); this._stop = true; BI.Maskers.hide(name); if (this._isSearching === true) { this.popupView && this.popupView.stopSearch && this.popupView.stopSearch(); this.fireEvent(BI.Searcher.EVENT_STOP); } this._isSearching = false; }, _search: function () { var self = this, o = this.options, keyword = this.editor.getValue(); if (keyword === "" || this._stop) { return; } if (o.isAutoSearch) { var items = (o.adapter && ((o.adapter.getItems && o.adapter.getItems()) || o.adapter.attr("items"))) || []; var finding = BI.Func.getSearchResult(items, keyword); var matched = finding.matched, finded = finding.finded; this.popupView.populate(finded, matched, keyword); o.isAutoSync && o.adapter && o.adapter.getValue && this.popupView.setValue(o.adapter.getValue()); self.fireEvent(BI.Searcher.EVENT_SEARCHING); return; } this.popupView.loading && this.popupView.loading(); o.onSearch({ times: 1, keyword: keyword, selectedValues: o.adapter && o.adapter.getValue() }, function (searchResult, matchResult) { if (!self._stop) { var args = [].slice.call(arguments); if (args.length > 0) { args.push(keyword); } BI.Maskers.show(self.getName()); self.popupView.populate.apply(self.popupView, args); o.isAutoSync && o.adapter && o.adapter.getValue && self.popupView.setValue(o.adapter.getValue()); self.popupView.loaded && self.popupView.loaded(); self.fireEvent(BI.Searcher.EVENT_SEARCHING); } }); }, setAdapter: function (adapter) { this.options.adapter = adapter; BI.Maskers.remove(this.getName()); }, doSearch: function () { if (this.isSearching()) { this._search(); } }, stopSearch: function () { this._stopSearch();//先停止搜索,然后再去设置editor为空 //important:停止搜索必须退出编辑状态,这里必须加上try(input框不显示时blur会抛异常) try { this.editor.blur(); } catch (e) { if (!this.editor.blur) { throw new Error("editor没有实现blur方法"); } } finally { this.editor.setValue(""); } }, isSearching: function () { return this._isSearching; }, isViewVisible: function () { return this.editor.isEnabled() && BI.Maskers.isVisible(this.getName()); }, getView: function () { return this.popupView; }, hasMatched: function () { this._assertPopupView(); return this.popupView.hasMatched(); }, adjustHeight: function () { if (BI.Maskers.has(this.getName()) && BI.Maskers.get(this.getName()).isVisible()) { BI.Maskers.show(this.getName()); } }, adjustView: function () { this.isViewVisible() && BI.Maskers.show(this.getName()); }, setValue: function (v) { this._assertPopupView(); this.popupView && this.popupView.setValue(v); }, getKeyword: function () { return this.editor.getValue(); }, getKeywords: function () { return this.editor.getKeywords(); }, getValue: function () { var o = this.options; if (o.isAutoSync && o.adapter && o.adapter.getValue) { return o.adapter.getValue(); } if (this.isSearching()) { return this.popupView.getValue(); } else if (o.adapter && o.adapter.getValue) { return o.adapter.getValue(); } else { return this.popupView.getValue(); } }, populate: function (result, searchResult, keyword) { var o = this.options; this._assertPopupView(); this.popupView.populate.apply(this.popupView, arguments); if (o.isAutoSync && o.adapter && o.adapter.getValue) { this.popupView.setValue(o.adapter.getValue()); } }, empty: function () { this.popupView && this.popupView.empty(); }, destroy: function () { BI.Maskers.remove(this.getName()); BI.Searcher.superclass.destroy.apply(this, arguments); } }); BI.Searcher.EVENT_CHANGE = "EVENT_CHANGE"; BI.Searcher.EVENT_START = "EVENT_START"; BI.Searcher.EVENT_STOP = "EVENT_STOP"; BI.Searcher.EVENT_PAUSE = "EVENT_PAUSE"; BI.Searcher.EVENT_SEARCHING = "EVENT_SEARCHING"; BI.Searcher.EVENT_AFTER_INIT = "EVENT_AFTER_INIT"; BI.shortcut("bi.searcher", BI.Searcher);/** * * 切换显示或隐藏面板 * * Created by GUY on 2015/11/2. * @class BI.Switcher * @extends BI.Widget */ BI.Switcher = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Switcher.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-switcher", direction: BI.Direction.Top, trigger: "click", toggle: true, el: {}, popup: {}, adapter: null, masker: {}, switcherClass: "bi-switcher-popup", hoverClass: "bi-switcher-hover" }) }, _init: function () { BI.Switcher.superclass._init.apply(this, arguments); var self = this, o = this.options; this._initSwitcher(); this._initPullDownAction(); this.switcher.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (self.isEnabled() && self.isValid()) { if (type === BI.Events.EXPAND) { self._popupView(); } if (type === BI.Events.COLLAPSE) { self._hideView(); } if (type === BI.Events.EXPAND) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.fireEvent(BI.Switcher.EVENT_EXPAND); } if (type === BI.Events.COLLAPSE) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.isViewVisible() && self.fireEvent(BI.Switcher.EVENT_COLLAPSE); } if (type === BI.Events.CLICK) { self.fireEvent(BI.Switcher.EVENT_TRIGGER_CHANGE, value, obj); } } }); this.element.hover(function () { if (self.isEnabled() && self.switcher.isEnabled()) { self.element.addClass(o.hoverClass); } }, function () { if (self.isEnabled() && self.switcher.isEnabled()) { self.element.removeClass(o.hoverClass); } }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [ {el: this.switcher} ] }); o.isDefaultInit && (this._assertPopupView()); }, _toggle: function () { this._assertPopupView(); if (this.isExpanded()) { this._hideView(); } else { if (this.isEnabled()) { this._popupView(); } } }, _initPullDownAction: function () { var self = this, o = this.options; var evs = this.options.trigger.split(","); BI.each(evs, function (i, e) { switch (e) { case "hover": self.element[e](function (e) { if (self.isEnabled() && self.switcher.isEnabled()) { self._popupView(); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, '', self.switcher); self.fireEvent(BI.Switcher.EVENT_EXPAND); } }, function () { if (self.isEnabled() && self.switcher.isEnabled() && o.toggle) { self._hideView(); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.switcher); self.fireEvent(BI.Switcher.EVENT_COLLAPSE); } }); break; default : if (e) { self.element.off(e + "." + self.getName()).on(e + "." + self.getName(), BI.debounce(function (e) { if (self.switcher.element.__isMouseInBounds__(e)) { if (self.isEnabled() && self.switcher.isEnabled()) { o.toggle ? self._toggle() : self._popupView(); if (self.isExpanded()) { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, '', self.switcher); self.fireEvent(BI.Switcher.EVENT_EXPAND); } else { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.COLLAPSE, '', self.switcher); self.fireEvent(BI.Switcher.EVENT_COLLAPSE); } } } }, BI.EVENT_RESPONSE_TIME, true)); } break; } }) }, _initSwitcher: function () { this.switcher = BI.createWidget(this.options.el); }, _assertPopupView: function () { var self = this, o = this.options; if (!this._created) { this.popupView = BI.createWidget(o.popup, { type: "bi.button_group", element: o.adapter && BI.Maskers.create(this.getName(), o.adapter, BI.extend({container: this}, o.masker)), cls: "switcher-popup", layouts: [{ type: "bi.vertical", hgap: 0, vgap: 0 }] }); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.Switcher.EVENT_CHANGE, value, obj); } }); if (o.direction !== BI.Direction.Custom && !o.adapter) { BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [ {el: this.popupView} ] }); } this._created = true; BI.nextTick(function () { self.fireEvent(BI.Switcher.EVENT_AFTER_INIT); }); } }, _hideView: function () { this.fireEvent(BI.Switcher.EVENT_BEFORE_HIDEVIEW); var self = this, o = this.options; o.adapter ? BI.Maskers.hide(self.getName()) : (self.popupView && self.popupView.setVisible(false)); BI.nextTick(function () { o.adapter ? BI.Maskers.hide(self.getName()) : (self.popupView && self.popupView.setVisible(false)); self.element.removeClass(o.switcherClass); self.fireEvent(BI.Switcher.EVENT_AFTER_HIDEVIEW); }); }, _popupView: function () { var self = this, o = this.options; this._assertPopupView(); this.fireEvent(BI.Switcher.EVENT_BEFORE_POPUPVIEW); o.adapter ? BI.Maskers.show(this.getName()) : self.popupView.setVisible(true); BI.nextTick(function (name) { o.adapter ? BI.Maskers.show(name) : self.popupView.setVisible(true); self.element.addClass(o.switcherClass); self.fireEvent(BI.Switcher.EVENT_AFTER_POPUPVIEW); }, this.getName()); }, populate: function (items) { this._assertPopupView(); this.popupView.populate.apply(this.popupView, arguments); this.switcher.populate.apply(this.switcher, arguments); }, _setEnable: function (arg) { BI.Switcher.superclass._setEnable.apply(this, arguments); !arg && this.isViewVisible() && this._hideView(); }, setValue: function (v) { this._assertPopupView(); this.switcher.setValue(v); this.popupView && this.popupView.setValue(v); }, getValue: function () { this._assertPopupView(); return this.popupView ? this.popupView.getValue() : []; }, setAdapter: function (adapter) { this.options.adapter = adapter; BI.Maskers.remove(this.getName()); }, isViewVisible: function () { return this.isEnabled() && this.switcher.isEnabled() && (this.options.adapter ? BI.Maskers.isVisible(this.getName()) : (this.popupView && this.popupView.isVisible())); }, isExpanded: function () { return this.isViewVisible(); }, showView: function () { if (this.isEnabled() && this.switcher.isEnabled()) { this._popupView(); } }, hideView: function () { this._hideView(); }, getView: function () { return this.popupView; }, adjustView: function () { this.isViewVisible() && BI.Maskers.show(this.getName()); }, getAllLeaves: function () { return this.popupView && this.popupView.getAllLeaves(); }, getNodeById: function (id) { if (this.switcher.attr("id") === id) { return this.switcher; } return this.popupView && this.popupView.getNodeById(id); }, getNodeByValue: function (value) { if (this.switcher.getValue() === value) { return this.switcher; } return this.popupView && this.popupView.getNodeByValue(value); }, empty: function () { this.popupView && this.popupView.empty(); }, destroy: function () { BI.Switcher.superclass.destroy.apply(this, arguments); } }); BI.Switcher.EVENT_EXPAND = "EVENT_EXPAND"; BI.Switcher.EVENT_COLLAPSE = "EVENT_COLLAPSE"; BI.Switcher.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE"; BI.Switcher.EVENT_CHANGE = "EVENT_CHANGE"; BI.Switcher.EVENT_AFTER_INIT = "EVENT_AFTER_INIT"; BI.Switcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.Switcher.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW"; BI.Switcher.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW"; BI.Switcher.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW"; BI.shortcut("bi.switcher", BI.Switcher);/** * Created by GUY on 2015/6/26. */ BI.Tab = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Tab.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-tab", direction: "top",//top, bottom, left, right, custom single: false, //是不是单页面 logic: { dynamic: false }, defaultShowIndex: false, tab: false, cardCreator: function (v) { return BI.createWidget(); } }) }, render: function () { var self = this, o = this.options; if (BI.isObject(o.tab)) { this.tab = BI.createWidget(this.options.tab, {type: "bi.button_group"}); this.tab.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }) } this.cardMap = {}; this.layout = BI.createWidget({ type: "bi.card" }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout) })))); var listener = new BI.ShowListener({ eventObj: this.tab, cardLayout: this.layout, cardCreator: function (v) { var card = o.cardCreator.apply(self, arguments); self.cardMap[v] = card; return card; }, afterCardShow: function (v) { self._deleteOtherCards(v); self.curr = v; } }); listener.on(BI.ShowListener.EVENT_CHANGE, function (value) { self.fireEvent(BI.Tab.EVENT_CHANGE, value, self); }); }, _deleteOtherCards: function (currCardName) { var self = this, o = this.options; if (o.single === true) { BI.each(this.cardMap, function (name, card) { if (name !== (currCardName + "")) { self.layout.deleteCardByName(name); delete self.cardMap[name]; } }); } }, _assertCard: function (v) { if (!this.layout.isCardExisted(v)) { var card = this.options.cardCreator(v); this.cardMap[v] = card; this.layout.addCardByName(v, card); } }, mounted: function () { var o = this.options; if (o.defaultShowIndex !== false) { this.setSelect(o.defaultShowIndex); } }, setSelect: function (v) { this.tab && this.tab.setValue(v); this._assertCard(v); this.layout.showCardByName(v); this._deleteOtherCards(v); if (this.curr !== v) { this.curr = v; } }, removeTab: function (cardname) { var self = this, o = this.options; BI.any(this.cardMap, function (name, card) { if (BI.isEqual(name, (cardname + ""))) { self.layout.deleteCardByName(name); delete self.cardMap[name]; return true; } }); }, getSelect: function () { return this.curr; }, getSelectedTab: function () { return this.layout.getShowingCard(); }, getTab: function (v) { this._assertCard(v); return this.layout.getCardByName(v); }, setValue: function (v) { var card = this.layout.getShowingCard(); if (card) { card.setValue(v); } }, getValue: function () { var card = this.layout.getShowingCard(); if (card) { return card.getValue(); } }, populate: function () { var card = this.layout.getShowingCard(); if (card) { return card.populate && card.populate.apply(card, arguments); } }, empty: function () { this.layout.deleteAllCard(); this.cardMap = {}; }, destroy: function () { this.cardMap = {}; BI.Tab.superclass.destroy.apply(this, arguments); } }); BI.Tab.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.tab", BI.Tab);/** * 表示当前对象 * * Created by GUY on 2015/9/7. * @class BI.EL * @extends BI.Widget */ BI.EL = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.EL.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-el", el: {}, layout: {} }); }, _init: function () { BI.EL.superclass._init.apply(this, arguments); var self = this, o = this.options; this.ele = BI.createWidget(o.el); BI.createWidget(o.layout, { type: "bi.adaptive", element: this, items: [this.ele] }); this.ele.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }) }, setValue: function (v) { this.ele.setValue(v); }, getValue: function () { return this.ele.getValue(); }, populate: function () { this.ele.populate.apply(this, arguments); } }); BI.shortcut('bi.el', BI.EL);// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE // This is CodeMirror (http://codemirror.net), a code editor // implemented in JavaScript on top of the browser's DOM. // // You can find some technical background for some of the code below // at http://marijnhaverbeke.nl/blog/#cm-internals . (function(mod) { this.CodeMirror = mod(); })(function() { "use strict"; // BROWSER SNIFFING // Kludges for bugs and behavior differences that can't be feature // detected are enabled based on userAgent etc sniffing. var gecko = /gecko\/\d/i.test(navigator.userAgent); var ie_upto10 = /MSIE \d/.test(navigator.userAgent); var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent); var ie = ie_upto10 || ie_11up; var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]); var webkit = /WebKit\//.test(navigator.userAgent); var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(navigator.userAgent); var chrome = /Chrome\//.test(navigator.userAgent); var presto = /Opera\//.test(navigator.userAgent); var safari = /Apple Computer/.test(navigator.vendor); var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(navigator.userAgent); var phantom = /PhantomJS/.test(navigator.userAgent); var ios = /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); // This is woefully incomplete. Suggestions for alternative methods welcome. var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(navigator.userAgent); var mac = ios || /Mac/.test(navigator.platform); var windows = /win/i.test(navigator.platform); var presto_version = presto && navigator.userAgent.match(/Version\/(\d*\.\d*)/); if (presto_version) presto_version = Number(presto_version[1]); if (presto_version && presto_version >= 15) { presto = false; webkit = true; } // Some browsers use the wrong event properties to signal cmd/ctrl on OS X var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11)); var captureRightClick = gecko || (ie && ie_version >= 9); // Optimize some code when these features are not used. var sawReadOnlySpans = false, sawCollapsedSpans = false; // EDITOR CONSTRUCTOR // A CodeMirror instance represents an editor. This is the object // that user code is usually dealing with. function CodeMirror(place, options) { if (!(this instanceof CodeMirror)) return new CodeMirror(place, options); this.options = options = options ? copyObj(options) : {}; // Determine effective options based on given values and defaults. copyObj(defaults, options, false); setGuttersForLineNumbers(options); var doc = options.value; if (typeof doc == "string") doc = new Doc(doc, options.mode); this.doc = doc; var input = new CodeMirror.inputStyles[options.inputStyle](this); var display = this.display = new Display(place, doc, input); display.wrapper.CodeMirror = this; updateGutters(this); themeChanged(this); if (options.lineWrapping) this.display.wrapper.className += " CodeMirror-wrap"; if (options.autofocus && !mobile) display.input.focus(); initScrollbars(this); this.state = { keyMaps: [], // stores maps added by addKeyMap overlays: [], // highlighting overlays, as added by addOverlay modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info overwrite: false, delayingBlurEvent: false, focused: false, suppressEdits: false, // used to disable editing during key handlers when in readOnly mode pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll draggingText: false, highlight: new Delayed(), // stores highlight worker timeout keySeq: null, // Unfinished key sequence specialChars: null }; var cm = this; // Override magic textarea content restore that IE sometimes does // on our hidden textarea on reload if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20); registerEventHandlers(this); ensureGlobalHandlers(); startOperation(this); this.curOp.forceUpdate = true; attachDoc(this, doc); if ((options.autofocus && !mobile) || cm.hasFocus()) setTimeout(bind(onFocus, this), 20); else onBlur(this); for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt)) optionHandlers[opt](this, options[opt], Init); maybeUpdateLineNumberWidth(this); if (options.finishInit) options.finishInit(this); for (var i = 0; i < initHooks.length; ++i) initHooks[i](this); endOperation(this); // Suppress optimizelegibility in Webkit, since it breaks text // measuring on line wrapping boundaries. if (webkit && options.lineWrapping && getComputedStyle(display.lineDiv).textRendering == "optimizelegibility") display.lineDiv.style.textRendering = "auto"; } // DISPLAY CONSTRUCTOR // The display handles the DOM integration, both for input reading // and content drawing. It holds references to DOM nodes and // display-related state. function Display(place, doc, input) { var d = this; this.input = input; // Covers bottom-right square when both scrollbars are present. d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler"); d.scrollbarFiller.setAttribute("cm-not-content", "true"); // Covers bottom of gutter when coverGutterNextToScrollbar is on // and h scrollbar is present. d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler"); d.gutterFiller.setAttribute("cm-not-content", "true"); // Will contain the actual code, positioned to cover the viewport. d.lineDiv = elt("div", null, "CodeMirror-code"); // Elements are added to these to represent selection and cursors. d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1"); d.cursorDiv = elt("div", null, "CodeMirror-cursors"); // A visibility: hidden element used to find the size of things. d.measure = elt("div", null, "CodeMirror-measure"); // When lines outside of the viewport are measured, they are drawn in this. d.lineMeasure = elt("div", null, "CodeMirror-measure"); // Wraps everything that needs to exist inside the vertically-padded coordinate system d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv], null, "position: relative; outline: none"); // Moved around its parent to cover visible view. d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative"); // Set to the height of the document, allowing scrolling. d.sizer = elt("div", [d.mover], "CodeMirror-sizer"); d.sizerWidth = null; // Behavior of elts with overflow: auto and padding is // inconsistent across browsers. This is used to ensure the // scrollable area is big enough. d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;"); // Will contain the gutters, if any. d.gutters = elt("div", null, "CodeMirror-gutters"); d.lineGutter = null; // Actual scrollable element. d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll"); d.scroller.setAttribute("tabIndex", "-1"); // The element in which the editor lives. d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror"); // Work around IE7 z-index bug (not perfect, hence IE7 not really being supported) if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; } if (!webkit && !(gecko && mobile)) d.scroller.draggable = true; if (place) { if (place.appendChild) place.appendChild(d.wrapper); else place(d.wrapper); } // Current rendered range (may be bigger than the view window). d.viewFrom = d.viewTo = doc.first; d.reportedViewFrom = d.reportedViewTo = doc.first; // Information about the rendered lines. d.view = []; d.renderedView = null; // Holds info about a single rendered line when it was rendered // for measurement, while not in view. d.externalMeasured = null; // Empty space (in pixels) above the view d.viewOffset = 0; d.lastWrapHeight = d.lastWrapWidth = 0; d.updateLineNumbers = null; d.nativeBarWidth = d.barHeight = d.barWidth = 0; d.scrollbarsClipped = false; // Used to only resize the line number gutter when necessary (when // the amount of lines crosses a boundary that makes its width change) d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null; // Set to true when a non-horizontal-scrolling line widget is // added. As an optimization, line widget aligning is skipped when // this is false. d.alignWidgets = false; d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; // Tracks the maximum line length so that the horizontal scrollbar // can be kept static when scrolling. d.maxLine = null; d.maxLineLength = 0; d.maxLineChanged = false; // Used for measuring wheel scrolling granularity d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null; // True when shift is held down. d.shift = false; // Used to track whether anything happened since the context menu // was opened. d.selForContextMenu = null; d.activeTouch = null; input.init(d); } // STATE UPDATES // Used to get the editor into a consistent state again when options change. function loadMode(cm) { cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption); resetModeState(cm); } function resetModeState(cm) { cm.doc.iter(function(line) { if (line.stateAfter) line.stateAfter = null; if (line.styles) line.styles = null; }); cm.doc.frontier = cm.doc.first; startWorker(cm, 100); cm.state.modeGen++; if (cm.curOp) regChange(cm); } function wrappingChanged(cm) { if (cm.options.lineWrapping) { addClass(cm.display.wrapper, "CodeMirror-wrap"); cm.display.sizer.style.minWidth = ""; cm.display.sizerWidth = null; } else { rmClass(cm.display.wrapper, "CodeMirror-wrap"); findMaxLine(cm); } estimateLineHeights(cm); regChange(cm); clearCaches(cm); setTimeout(function(){updateScrollbars(cm);}, 100); } // Returns a function that estimates the height of a line, to use as // first approximation until the line becomes visible (and is thus // properly measurable). function estimateHeight(cm) { var th = textHeight(cm.display), wrapping = cm.options.lineWrapping; var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3); return function(line) { if (lineIsHidden(cm.doc, line)) return 0; var widgetsHeight = 0; if (line.widgets) for (var i = 0; i < line.widgets.length; i++) { if (line.widgets[i].height) widgetsHeight += line.widgets[i].height; } if (wrapping) return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th; else return widgetsHeight + th; }; } function estimateLineHeights(cm) { var doc = cm.doc, est = estimateHeight(cm); doc.iter(function(line) { var estHeight = est(line); if (estHeight != line.height) updateLineHeight(line, estHeight); }); } function themeChanged(cm) { cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-"); clearCaches(cm); } function guttersChanged(cm) { updateGutters(cm); regChange(cm); setTimeout(function(){alignHorizontally(cm);}, 20); } // Rebuild the gutter elements, ensure the margin to the left of the // code matches their width. function updateGutters(cm) { var gutters = cm.display.gutters, specs = cm.options.gutters; removeChildren(gutters); for (var i = 0; i < specs.length; ++i) { var gutterClass = specs[i]; var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass)); if (gutterClass == "CodeMirror-linenumbers") { cm.display.lineGutter = gElt; gElt.style.width = (cm.display.lineNumWidth || 1) + "px"; } } gutters.style.display = i ? "" : "none"; updateGutterSpace(cm); } function updateGutterSpace(cm) { var width = cm.display.gutters.offsetWidth; cm.display.sizer.style.marginLeft = width + "px"; } // Compute the character length of a line, taking into account // collapsed ranges (see markText) that might hide parts, and join // other lines onto it. function lineLength(line) { if (line.height == 0) return 0; var len = line.text.length, merged, cur = line; while (merged = collapsedSpanAtStart(cur)) { var found = merged.find(0, true); cur = found.from.line; len += found.from.ch - found.to.ch; } cur = line; while (merged = collapsedSpanAtEnd(cur)) { var found = merged.find(0, true); len -= cur.text.length - found.from.ch; cur = found.to.line; len += cur.text.length - found.to.ch; } return len; } // Find the longest line in the document. function findMaxLine(cm) { var d = cm.display, doc = cm.doc; d.maxLine = getLine(doc, doc.first); d.maxLineLength = lineLength(d.maxLine); d.maxLineChanged = true; doc.iter(function(line) { var len = lineLength(line); if (len > d.maxLineLength) { d.maxLineLength = len; d.maxLine = line; } }); } // Make sure the gutters options contains the element // "CodeMirror-linenumbers" when the lineNumbers option is true. function setGuttersForLineNumbers(options) { var found = indexOf(options.gutters, "CodeMirror-linenumbers"); if (found == -1 && options.lineNumbers) { options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]); } else if (found > -1 && !options.lineNumbers) { options.gutters = options.gutters.slice(0); options.gutters.splice(found, 1); } } // SCROLLBARS // Prepare DOM reads needed to update the scrollbars. Done in one // shot to minimize update/measure roundtrips. function measureForScrollbars(cm) { var d = cm.display, gutterW = d.gutters.offsetWidth; var docH = Math.round(cm.doc.height + paddingVert(cm.display)); return { clientHeight: d.scroller.clientHeight, viewHeight: d.wrapper.clientHeight, scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth, viewWidth: d.wrapper.clientWidth, barLeft: cm.options.fixedGutter ? gutterW : 0, docHeight: docH, scrollHeight: docH + scrollGap(cm) + d.barHeight, nativeBarWidth: d.nativeBarWidth, gutterWidth: gutterW }; } function NativeScrollbars(place, scroll, cm) { this.cm = cm; var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar"); var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar"); place(vert); place(horiz); on(vert, "scroll", function() { if (vert.clientHeight) scroll(vert.scrollTop, "vertical"); }); on(horiz, "scroll", function() { if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal"); }); this.checkedOverlay = false; // Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8). if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; } NativeScrollbars.prototype = copyObj({ update: function(measure) { var needsH = measure.scrollWidth > measure.clientWidth + 1; var needsV = measure.scrollHeight > measure.clientHeight + 1; var sWidth = measure.nativeBarWidth; if (needsV) { this.vert.style.display = "block"; this.vert.style.bottom = needsH ? sWidth + "px" : "0"; var totalHeight = measure.viewHeight - (needsH ? sWidth : 0); // A bug in IE8 can cause this value to be negative, so guard it. this.vert.firstChild.style.height = Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px"; } else { this.vert.style.display = ""; this.vert.firstChild.style.height = "0"; } if (needsH) { this.horiz.style.display = "block"; this.horiz.style.right = needsV ? sWidth + "px" : "0"; this.horiz.style.left = measure.barLeft + "px"; var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0); this.horiz.firstChild.style.width = (measure.scrollWidth - measure.clientWidth + totalWidth) + "px"; } else { this.horiz.style.display = ""; this.horiz.firstChild.style.width = "0"; } if (!this.checkedOverlay && measure.clientHeight > 0) { if (sWidth == 0) this.overlayHack(); this.checkedOverlay = true; } return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}; }, setScrollLeft: function(pos) { if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos; }, setScrollTop: function(pos) { if (this.vert.scrollTop != pos) this.vert.scrollTop = pos; }, overlayHack: function() { var w = mac && !mac_geMountainLion ? "12px" : "18px"; this.horiz.style.minHeight = this.vert.style.minWidth = w; var self = this; var barMouseDown = function(e) { if (e_target(e) != self.vert && e_target(e) != self.horiz) operation(self.cm, onMouseDown)(e); }; on(this.vert, "mousedown", barMouseDown); on(this.horiz, "mousedown", barMouseDown); }, clear: function() { var parent = this.horiz.parentNode; parent.removeChild(this.horiz); parent.removeChild(this.vert); } }, NativeScrollbars.prototype); function NullScrollbars() {} NullScrollbars.prototype = copyObj({ update: function() { return {bottom: 0, right: 0}; }, setScrollLeft: function() {}, setScrollTop: function() {}, clear: function() {} }, NullScrollbars.prototype); CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars}; function initScrollbars(cm) { if (cm.display.scrollbars) { cm.display.scrollbars.clear(); if (cm.display.scrollbars.addClass) rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); } cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) { cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller); // Prevent clicks in the scrollbars from killing focus on(node, "mousedown", function() { if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0); }); node.setAttribute("cm-not-content", "true"); }, function(pos, axis) { if (axis == "horizontal") setScrollLeft(cm, pos); else setScrollTop(cm, pos); }, cm); if (cm.display.scrollbars.addClass) addClass(cm.display.wrapper, cm.display.scrollbars.addClass); } function updateScrollbars(cm, measure) { if (!measure) measure = measureForScrollbars(cm); var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight; updateScrollbarsInner(cm, measure); for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) { if (startWidth != cm.display.barWidth && cm.options.lineWrapping) updateHeightsInViewport(cm); updateScrollbarsInner(cm, measureForScrollbars(cm)); startWidth = cm.display.barWidth; startHeight = cm.display.barHeight; } } // Re-synchronize the fake scrollbars with the actual size of the // content. function updateScrollbarsInner(cm, measure) { var d = cm.display; var sizes = d.scrollbars.update(measure); d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px"; d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px"; if (sizes.right && sizes.bottom) { d.scrollbarFiller.style.display = "block"; d.scrollbarFiller.style.height = sizes.bottom + "px"; d.scrollbarFiller.style.width = sizes.right + "px"; } else d.scrollbarFiller.style.display = ""; if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) { d.gutterFiller.style.display = "block"; d.gutterFiller.style.height = sizes.bottom + "px"; d.gutterFiller.style.width = measure.gutterWidth + "px"; } else d.gutterFiller.style.display = ""; } // Compute the lines that are visible in a given viewport (defaults // the the current scroll position). viewport may contain top, // height, and ensure (see op.scrollToPos) properties. function visibleLines(display, doc, viewport) { var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop; top = Math.floor(top - paddingTop(display)); var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight; var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom); // Ensure is a {from: {line, ch}, to: {line, ch}} object, and // forces those lines into the viewport (if possible). if (viewport && viewport.ensure) { var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line; if (ensureFrom < from) { from = ensureFrom; to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight); } else if (Math.min(ensureTo, doc.lastLine()) >= to) { from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight); to = ensureTo; } } return {from: from, to: Math.max(to, from + 1)}; } // LINE NUMBERS // Re-align line numbers and gutter marks to compensate for // horizontal scrolling. function alignHorizontally(cm) { var display = cm.display, view = display.view; if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return; var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft; var gutterW = display.gutters.offsetWidth, left = comp + "px"; for (var i = 0; i < view.length; i++) if (!view[i].hidden) { if (cm.options.fixedGutter && view[i].gutter) view[i].gutter.style.left = left; var align = view[i].alignable; if (align) for (var j = 0; j < align.length; j++) align[j].style.left = left; } if (cm.options.fixedGutter) display.gutters.style.left = (comp + gutterW) + "px"; } // Used to ensure that the line number gutter is still the right // size for the current document size. Returns true when an update // is needed. function maybeUpdateLineNumberWidth(cm) { if (!cm.options.lineNumbers) return false; var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display; if (last.length != display.lineNumChars) { var test = display.measure.appendChild(elt("div", [elt("div", last)], "CodeMirror-linenumber CodeMirror-gutter-elt")); var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW; display.lineGutter.style.width = ""; display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1; display.lineNumWidth = display.lineNumInnerWidth + padding; display.lineNumChars = display.lineNumInnerWidth ? last.length : -1; display.lineGutter.style.width = display.lineNumWidth + "px"; updateGutterSpace(cm); return true; } return false; } function lineNumberFor(options, i) { return String(options.lineNumberFormatter(i + options.firstLineNumber)); } // Computes display.scroller.scrollLeft + display.gutters.offsetWidth, // but using getBoundingClientRect to get a sub-pixel-accurate // result. function compensateForHScroll(display) { return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left; } // DISPLAY DRAWING function DisplayUpdate(cm, viewport, force) { var display = cm.display; this.viewport = viewport; // Store some values that we'll need later (but don't want to force a relayout for) this.visible = visibleLines(display, cm.doc, viewport); this.editorIsHidden = !display.wrapper.offsetWidth; this.wrapperHeight = display.wrapper.clientHeight; this.wrapperWidth = display.wrapper.clientWidth; this.oldDisplayWidth = displayWidth(cm); this.force = force; this.dims = getDimensions(cm); this.events = []; } DisplayUpdate.prototype.signal = function(emitter, type) { if (hasHandler(emitter, type)) this.events.push(arguments); }; DisplayUpdate.prototype.finish = function() { for (var i = 0; i < this.events.length; i++) signal.apply(null, this.events[i]); }; function maybeClipScrollbars(cm) { var display = cm.display; if (!display.scrollbarsClipped && display.scroller.offsetWidth) { display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth; display.heightForcer.style.height = scrollGap(cm) + "px"; display.sizer.style.marginBottom = -display.nativeBarWidth + "px"; display.sizer.style.borderRightWidth = scrollGap(cm) + "px"; display.scrollbarsClipped = true; } } // Does the actual updating of the line display. Bails out // (returning false) when there is nothing to be done and forced is // false. function updateDisplayIfNeeded(cm, update) { var display = cm.display, doc = cm.doc; if (update.editorIsHidden) { resetView(cm); return false; } // Bail out if the visible area is already rendered and nothing changed. if (!update.force && update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) && display.renderedView == display.view && countDirtyView(cm) == 0) return false; if (maybeUpdateLineNumberWidth(cm)) { resetView(cm); update.dims = getDimensions(cm); } // Compute a suitable new viewport (from & to) var end = doc.first + doc.size; var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first); var to = Math.min(end, update.visible.to + cm.options.viewportMargin); if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom); if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo); if (sawCollapsedSpans) { from = visualLineNo(cm.doc, from); to = visualLineEndNo(cm.doc, to); } var different = from != display.viewFrom || to != display.viewTo || display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth; adjustView(cm, from, to); display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom)); // Position the mover div to align with the current scroll position cm.display.mover.style.top = display.viewOffset + "px"; var toUpdate = countDirtyView(cm); if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view && (display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo)) return false; // For big changes, we hide the enclosing element during the // update, since that speeds up the operations on most browsers. var focused = activeElt(); if (toUpdate > 4) display.lineDiv.style.display = "none"; patchDisplay(cm, display.updateLineNumbers, update.dims); if (toUpdate > 4) display.lineDiv.style.display = ""; display.renderedView = display.view; // There might have been a widget with a focused element that got // hidden or updated, if so re-focus it. if (focused && activeElt() != focused && focused.offsetHeight) focused.focus(); // Prevent selection and cursors from interfering with the scroll // width and height. removeChildren(display.cursorDiv); removeChildren(display.selectionDiv); display.gutters.style.height = 0; if (different) { display.lastWrapHeight = update.wrapperHeight; display.lastWrapWidth = update.wrapperWidth; startWorker(cm, 400); } display.updateLineNumbers = null; return true; } function postUpdateDisplay(cm, update) { var viewport = update.viewport; for (var first = true;; first = false) { if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) { // Clip forced viewport to actual scrollable area. if (viewport && viewport.top != null) viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; // Updated line heights might result in the drawn area not // actually covering the viewport. Keep looping until it does. update.visible = visibleLines(cm.display, cm.doc, viewport); if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo) break; } if (!updateDisplayIfNeeded(cm, update)) break; updateHeightsInViewport(cm); var barMeasure = measureForScrollbars(cm); updateSelection(cm); setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); } update.signal(cm, "update", cm); if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) { update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo); cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo; } } function updateDisplaySimple(cm, viewport) { var update = new DisplayUpdate(cm, viewport); if (updateDisplayIfNeeded(cm, update)) { updateHeightsInViewport(cm); postUpdateDisplay(cm, update); var barMeasure = measureForScrollbars(cm); updateSelection(cm); setDocumentHeight(cm, barMeasure); updateScrollbars(cm, barMeasure); update.finish(); } } function setDocumentHeight(cm, measure) { cm.display.sizer.style.minHeight = measure.docHeight + "px"; var total = measure.docHeight + cm.display.barHeight; cm.display.heightForcer.style.top = total + "px"; cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px"; } // Read the actual heights of the rendered lines, and update their // stored heights to match. function updateHeightsInViewport(cm) { var display = cm.display; var prevBottom = display.lineDiv.offsetTop; for (var i = 0; i < display.view.length; i++) { var cur = display.view[i], height; if (cur.hidden) continue; if (ie && ie_version < 8) { var bot = cur.node.offsetTop + cur.node.offsetHeight; height = bot - prevBottom; prevBottom = bot; } else { var box = cur.node.getBoundingClientRect(); height = box.bottom - box.top; } var diff = cur.line.height - height; if (height < 2) height = textHeight(display); if (diff > .001 || diff < -.001) { updateLineHeight(cur.line, height); updateWidgetHeight(cur.line); if (cur.rest) for (var j = 0; j < cur.rest.length; j++) updateWidgetHeight(cur.rest[j]); } } } // Read and store the height of line widgets associated with the // given line. function updateWidgetHeight(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; ++i) line.widgets[i].height = line.widgets[i].node.offsetHeight; } // Do a bulk-read of the DOM positions and sizes needed to draw the // view, so that we don't interleave reading and writing to the DOM. function getDimensions(cm) { var d = cm.display, left = {}, width = {}; var gutterLeft = d.gutters.clientLeft; for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) { left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft; width[cm.options.gutters[i]] = n.clientWidth; } return {fixedPos: compensateForHScroll(d), gutterTotalWidth: d.gutters.offsetWidth, gutterLeft: left, gutterWidth: width, wrapperWidth: d.wrapper.clientWidth}; } // Sync the actual display DOM structure with display.view, removing // nodes for lines that are no longer in view, and creating the ones // that are not there yet, and updating the ones that are out of // date. function patchDisplay(cm, updateNumbersFrom, dims) { var display = cm.display, lineNumbers = cm.options.lineNumbers; var container = display.lineDiv, cur = container.firstChild; function rm(node) { var next = node.nextSibling; // Works around a throw-scroll bug in OS X Webkit if (webkit && mac && cm.display.currentWheelTarget == node) node.style.display = "none"; else node.parentNode.removeChild(node); return next; } var view = display.view, lineN = display.viewFrom; // Loop over the elements in the view, syncing cur (the DOM nodes // in display.lineDiv) with the view as we go. for (var i = 0; i < view.length; i++) { var lineView = view[i]; if (lineView.hidden) { } else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet var node = buildLineElement(cm, lineView, lineN, dims); container.insertBefore(node, cur); } else { // Already drawn while (cur != lineView.node) cur = rm(cur); var updateNumber = lineNumbers && updateNumbersFrom != null && updateNumbersFrom <= lineN && lineView.lineNumber; if (lineView.changes) { if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false; updateLineForChanges(cm, lineView, lineN, dims); } if (updateNumber) { removeChildren(lineView.lineNumber); lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN))); } cur = lineView.node.nextSibling; } lineN += lineView.size; } while (cur) cur = rm(cur); } // When an aspect of a line changes, a string is added to // lineView.changes. This updates the relevant part of the line's // DOM structure. function updateLineForChanges(cm, lineView, lineN, dims) { for (var j = 0; j < lineView.changes.length; j++) { var type = lineView.changes[j]; if (type == "text") updateLineText(cm, lineView); else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims); else if (type == "class") updateLineClasses(lineView); else if (type == "widget") updateLineWidgets(cm, lineView, dims); } lineView.changes = null; } // Lines with gutter elements, widgets or a background class need to // be wrapped, and have the extra elements added to the wrapper div function ensureLineWrapped(lineView) { if (lineView.node == lineView.text) { lineView.node = elt("div", null, null, "position: relative"); if (lineView.text.parentNode) lineView.text.parentNode.replaceChild(lineView.node, lineView.text); lineView.node.appendChild(lineView.text); if (ie && ie_version < 8) lineView.node.style.zIndex = 2; } return lineView.node; } function updateLineBackground(lineView) { var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass; if (cls) cls += " CodeMirror-linebackground"; if (lineView.background) { if (cls) lineView.background.className = cls; else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; } } else if (cls) { var wrap = ensureLineWrapped(lineView); lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild); } } // Wrapper around buildLineContent which will reuse the structure // in display.externalMeasured when possible. function getLineContent(cm, lineView) { var ext = cm.display.externalMeasured; if (ext && ext.line == lineView.line) { cm.display.externalMeasured = null; lineView.measure = ext.measure; return ext.built; } return buildLineContent(cm, lineView); } // Redraw the line's text. Interacts with the background and text // classes because the mode may output tokens that influence these // classes. function updateLineText(cm, lineView) { var cls = lineView.text.className; var built = getLineContent(cm, lineView); if (lineView.text == lineView.node) lineView.node = built.pre; lineView.text.parentNode.replaceChild(built.pre, lineView.text); lineView.text = built.pre; if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) { lineView.bgClass = built.bgClass; lineView.textClass = built.textClass; updateLineClasses(lineView); } else if (cls) { lineView.text.className = cls; } } function updateLineClasses(lineView) { updateLineBackground(lineView); if (lineView.line.wrapClass) ensureLineWrapped(lineView).className = lineView.line.wrapClass; else if (lineView.node != lineView.text) lineView.node.className = ""; var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass; lineView.text.className = textClass || ""; } function updateLineGutter(cm, lineView, lineN, dims) { if (lineView.gutter) { lineView.node.removeChild(lineView.gutter); lineView.gutter = null; } var markers = lineView.line.gutterMarkers; if (cm.options.lineNumbers || markers) { var wrap = ensureLineWrapped(lineView); var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + dims.gutterTotalWidth + "px"); cm.display.input.setUneditable(gutterWrap); wrap.insertBefore(gutterWrap, lineView.text); if (lineView.line.gutterClass) gutterWrap.className += " " + lineView.line.gutterClass; if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"])) lineView.lineNumber = gutterWrap.appendChild( elt("div", lineNumberFor(cm.options, lineN), "CodeMirror-linenumber CodeMirror-gutter-elt", "left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: " + cm.display.lineNumInnerWidth + "px")); if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) { var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id]; if (found) gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " + dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px")); } } } function updateLineWidgets(cm, lineView, dims) { if (lineView.alignable) lineView.alignable = null; for (var node = lineView.node.firstChild, next; node; node = next) { var next = node.nextSibling; if (node.className == "CodeMirror-linewidget") lineView.node.removeChild(node); } insertLineWidgets(cm, lineView, dims); } // Build a line's DOM representation from scratch function buildLineElement(cm, lineView, lineN, dims) { var built = getLineContent(cm, lineView); lineView.text = lineView.node = built.pre; if (built.bgClass) lineView.bgClass = built.bgClass; if (built.textClass) lineView.textClass = built.textClass; updateLineClasses(lineView); updateLineGutter(cm, lineView, lineN, dims); insertLineWidgets(cm, lineView, dims); return lineView.node; } // A lineView may contain multiple logical lines (when merged by // collapsed spans). The widgets for all of them need to be drawn. function insertLineWidgets(cm, lineView, dims) { insertLineWidgetsFor(cm, lineView.line, lineView, dims, true); if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) { if (!line.widgets) return; var wrap = ensureLineWrapped(lineView); for (var i = 0, ws = line.widgets; i < ws.length; ++i) { var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget"); if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true"); positionLineWidget(widget, node, lineView, dims); cm.display.input.setUneditable(node); if (allowAbove && widget.above) wrap.insertBefore(node, lineView.gutter || lineView.text); else wrap.appendChild(node); signalLater(widget, "redraw"); } } function positionLineWidget(widget, node, lineView, dims) { if (widget.noHScroll) { (lineView.alignable || (lineView.alignable = [])).push(node); var width = dims.wrapperWidth; node.style.left = dims.fixedPos + "px"; if (!widget.coverGutter) { width -= dims.gutterTotalWidth; node.style.paddingLeft = dims.gutterTotalWidth + "px"; } node.style.width = width + "px"; } if (widget.coverGutter) { node.style.zIndex = 5; node.style.position = "relative"; if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px"; } } // POSITION OBJECT // A Pos instance represents a position within the text. var Pos = CodeMirror.Pos = function(line, ch) { if (!(this instanceof Pos)) return new Pos(line, ch); this.line = line; this.ch = ch; }; // Compare two positions, return 0 if they are the same, a negative // number when a is less, and a positive number otherwise. var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; }; function copyPos(x) {return Pos(x.line, x.ch);} function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; } function minPos(a, b) { return cmp(a, b) < 0 ? a : b; } // INPUT HANDLING function ensureFocus(cm) { if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); } } function isReadOnly(cm) { return cm.options.readOnly || cm.doc.cantEdit; } // This will be set to an array of strings when copying, so that, // when pasting, we know what kind of selections the copied text // was made out of. var lastCopied = null; function applyTextInput(cm, inserted, deleted, sel, origin) { var doc = cm.doc; cm.display.shift = false; if (!sel) sel = doc.sel; var paste = cm.state.pasteIncoming || origin == "paste"; var textLines = splitLines(inserted), multiPaste = null; // When pasing N lines into N selections, insert one line per selection if (paste && sel.ranges.length > 1) { if (lastCopied && lastCopied.join("\n") == inserted) multiPaste = sel.ranges.length % lastCopied.length == 0 && map(lastCopied, splitLines); else if (textLines.length == sel.ranges.length) multiPaste = map(textLines, function(l) { return [l]; }); } // Normal behavior is to insert the new text into every selection for (var i = sel.ranges.length - 1; i >= 0; i--) { var range = sel.ranges[i]; var from = range.from(), to = range.to(); if (range.empty()) { if (deleted && deleted > 0) // Handle deletion from = Pos(from.line, from.ch - deleted); else if (cm.state.overwrite && !paste) // Handle overwrite to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); } var updateInput = cm.curOp.updateInput; var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines, origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")}; makeChange(cm.doc, changeEvent); signalLater(cm, "inputRead", cm, changeEvent); } if (inserted && !paste) triggerElectric(cm, inserted); ensureCursorVisible(cm); cm.curOp.updateInput = updateInput; cm.curOp.typing = true; cm.state.pasteIncoming = cm.state.cutIncoming = false; } function handlePaste(e, cm) { var pasted = e.clipboardData && e.clipboardData.getData("text/plain"); if (pasted) { e.preventDefault(); runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); }); return true; } } function triggerElectric(cm, inserted) { // When an 'electric' character is inserted, immediately trigger a reindent if (!cm.options.electricChars || !cm.options.smartIndent) return; var sel = cm.doc.sel; for (var i = sel.ranges.length - 1; i >= 0; i--) { var range = sel.ranges[i]; if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue; var mode = cm.getModeAt(range.head); var indented = false; if (mode.electricChars) { for (var j = 0; j < mode.electricChars.length; j++) if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) { indented = indentLine(cm, range.head.line, "smart"); break; } } else if (mode.electricInput) { if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch))) indented = indentLine(cm, range.head.line, "smart"); } if (indented) signalLater(cm, "electricInput", cm, range.head.line); } } function copyableRanges(cm) { var text = [], ranges = []; for (var i = 0; i < cm.doc.sel.ranges.length; i++) { var line = cm.doc.sel.ranges[i].head.line; var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)}; ranges.push(lineRange); text.push(cm.getRange(lineRange.anchor, lineRange.head)); } return {text: text, ranges: ranges}; } function disableBrowserMagic(field) { field.setAttribute("autocorrect", "off"); field.setAttribute("autocapitalize", "off"); field.setAttribute("spellcheck", "false"); } // TEXTAREA INPUT STYLE function TextareaInput(cm) { this.cm = cm; // See input.poll and input.reset this.prevInput = ""; // Flag that indicates whether we expect input to appear real soon // now (after some event like 'keypress' or 'input') and are // polling intensively. this.pollingFast = false; // Self-resetting timeout for the poller this.polling = new Delayed(); // Tracks when input.reset has punted to just putting a short // string into the textarea instead of the full selection. this.inaccurateSelection = false; // Used to work around IE issue with selection being forgotten when focus moves away from textarea this.hasSelection = false; this.composing = null; }; function hiddenTextarea() { var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none"); var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;"); // The textarea is kept positioned near the cursor to prevent the // fact that it'll be scrolled into view on input from scrolling // our fake cursor out of view. On webkit, when wrap=off, paste is // very slow. So make the area wide instead. if (webkit) te.style.width = "1000px"; else te.setAttribute("wrap", "off"); // If border: 0; -- iOS fails to open keyboard (issue #1287) if (ios) te.style.border = "1px solid black"; disableBrowserMagic(te); return div; } TextareaInput.prototype = copyObj({ init: function(display) { var input = this, cm = this.cm; // Wraps and hides input textarea var div = this.wrapper = hiddenTextarea(); // The semihidden textarea that is focused when the editor is // focused, and receives input. var te = this.textarea = div.firstChild; display.wrapper.insertBefore(div, display.wrapper.firstChild); // Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore) if (ios) te.style.width = "0px"; on(te, "input", function() { if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null; input.poll(); }); on(te, "paste", function(e) { if (handlePaste(e, cm)) return true; cm.state.pasteIncoming = true; input.fastPoll(); }); function prepareCopyCut(e) { if (cm.somethingSelected()) { lastCopied = cm.getSelections(); if (input.inaccurateSelection) { input.prevInput = ""; input.inaccurateSelection = false; te.value = lastCopied.join("\n"); selectInput(te); } } else if (!cm.options.lineWiseCopyCut) { return; } else { var ranges = copyableRanges(cm); lastCopied = ranges.text; if (e.type == "cut") { cm.setSelections(ranges.ranges, null, sel_dontScroll); } else { input.prevInput = ""; te.value = ranges.text.join("\n"); selectInput(te); } } if (e.type == "cut") cm.state.cutIncoming = true; } on(te, "cut", prepareCopyCut); on(te, "copy", prepareCopyCut); on(display.scroller, "paste", function(e) { if (eventInWidget(display, e)) return; cm.state.pasteIncoming = true; input.focus(); }); // Prevent normal selection in the editor (we handle our own) on(display.lineSpace, "selectstart", function(e) { if (!eventInWidget(display, e)) e_preventDefault(e); }); on(te, "compositionstart", function() { var start = cm.getCursor("from"); input.composing = { start: start, range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"}) }; }); on(te, "compositionend", function() { if (input.composing) { input.poll(); input.composing.range.clear(); input.composing = null; } }); }, prepareSelection: function() { // Redraw the selection and/or cursor var cm = this.cm, display = cm.display, doc = cm.doc; var result = prepareSelection(cm); // Move the hidden textarea near the cursor to prevent scrolling artifacts if (cm.options.moveInputWithCursor) { var headPos = cursorCoords(cm, doc.sel.primary().head, "div"); var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect(); result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10, headPos.top + lineOff.top - wrapOff.top)); result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10, headPos.left + lineOff.left - wrapOff.left)); } return result; }, showSelection: function(drawn) { var cm = this.cm, display = cm.display; removeChildrenAndAdd(display.cursorDiv, drawn.cursors); removeChildrenAndAdd(display.selectionDiv, drawn.selection); if (drawn.teTop != null) { this.wrapper.style.top = drawn.teTop + "px"; this.wrapper.style.left = drawn.teLeft + "px"; } }, // Reset the input to correspond to the selection (or to be empty, // when not typing and nothing is selected) reset: function(typing) { if (this.contextMenuPending) return; var minimal, selected, cm = this.cm, doc = cm.doc; if (cm.somethingSelected()) { this.prevInput = ""; var range = doc.sel.primary(); minimal = hasCopyEvent && (range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000); var content = minimal ? "-" : selected || cm.getSelection(); this.textarea.value = content; if (cm.state.focused) selectInput(this.textarea); if (ie && ie_version >= 9) this.hasSelection = content; } else if (!typing) { this.prevInput = this.textarea.value = ""; if (ie && ie_version >= 9) this.hasSelection = null; } this.inaccurateSelection = minimal; }, getField: function() { return this.textarea; }, supportsTouch: function() { return false; }, focus: function() { if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) { try { this.textarea.focus(); } catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM } }, blur: function() { this.textarea.blur(); }, resetPosition: function() { this.wrapper.style.top = this.wrapper.style.left = 0; }, receivedFocus: function() { this.slowPoll(); }, // Poll for input changes, using the normal rate of polling. This // runs as long as the editor is focused. slowPoll: function() { var input = this; if (input.pollingFast) return; input.polling.set(this.cm.options.pollInterval, function() { input.poll(); if (input.cm.state.focused) input.slowPoll(); }); }, // When an event has just come in that is likely to add or change // something in the input textarea, we poll faster, to ensure that // the change appears on the screen quickly. fastPoll: function() { var missed = false, input = this; input.pollingFast = true; function p() { var changed = input.poll(); if (!changed && !missed) {missed = true; input.polling.set(60, p);} else {input.pollingFast = false; input.slowPoll();} } input.polling.set(20, p); }, // Read input from the textarea, and update the document to match. // When something is selected, it is present in the textarea, and // selected (unless it is huge, in which case a placeholder is // used). When nothing is selected, the cursor sits after previously // seen text (can be empty), which is stored in prevInput (we must // not reset the textarea when typing, because that breaks IME). poll: function() { var cm = this.cm, input = this.textarea, prevInput = this.prevInput; // Since this is called a *lot*, try to bail out as cheaply as // possible when it is clear that nothing happened. hasSelection // will be the case when there is a lot of text in the textarea, // in which case reading its value would be expensive. if (this.contextMenuPending || !cm.state.focused || (hasSelection(input) && !prevInput) || isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq) return false; var text = input.value; // If nothing changed, bail. if (text == prevInput && !cm.somethingSelected()) return false; // Work around nonsensical selection resetting in IE9/10, and // inexplicable appearance of private area unicode characters on // some key combos in Mac (#2689). if (ie && ie_version >= 9 && this.hasSelection === text || mac && /[\uf700-\uf7ff]/.test(text)) { cm.display.input.reset(); return false; } if (cm.doc.sel == cm.display.selForContextMenu) { var first = text.charCodeAt(0); if (first == 0x200b && !prevInput) prevInput = "\u200b"; if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); } } // Find the part of the input that is actually new var same = 0, l = Math.min(prevInput.length, text.length); while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same; var self = this; runInOp(cm, function() { applyTextInput(cm, text.slice(same), prevInput.length - same, null, self.composing ? "*compose" : null); // Don't leave long text in the textarea, since it makes further polling slow if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = ""; else self.prevInput = text; if (self.composing) { self.composing.range.clear(); self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"), {className: "CodeMirror-composing"}); } }); return true; }, ensurePolled: function() { if (this.pollingFast && this.poll()) this.pollingFast = false; }, onKeyPress: function() { if (ie && ie_version >= 9) this.hasSelection = null; this.fastPoll(); }, onContextMenu: function(e) { var input = this, cm = input.cm, display = cm.display, te = input.textarea; var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop; if (!pos || presto) return; // Opera is difficult. // Reset the current text selection only if the click is done outside of the selection // and 'resetSelectionOnContextMenu' option is true. var reset = cm.options.resetSelectionOnContextMenu; if (reset && cm.doc.sel.contains(pos) == -1) operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); var oldCSS = te.style.cssText; input.wrapper.style.position = "absolute"; te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) + "px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + "; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);"; if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712) display.input.focus(); if (webkit) window.scrollTo(null, oldScrollY); display.input.reset(); // Adds "Select all" to context menu in FF if (!cm.somethingSelected()) te.value = input.prevInput = " "; input.contextMenuPending = true; display.selForContextMenu = cm.doc.sel; clearTimeout(display.detectingSelectAll); // Select-all will be greyed out if there's nothing to select, so // this adds a zero-width space so that we can later check whether // it got selected. function prepareSelectAllHack() { if (te.selectionStart != null) { var selected = cm.somethingSelected(); var extval = "\u200b" + (selected ? te.value : ""); te.value = "\u21da"; // Used to catch context-menu undo te.value = extval; input.prevInput = selected ? "" : "\u200b"; te.selectionStart = 1; te.selectionEnd = extval.length; // Re-set this, in case some other handler touched the // selection in the meantime. display.selForContextMenu = cm.doc.sel; } } function rehide() { input.contextMenuPending = false; input.wrapper.style.position = "relative"; te.style.cssText = oldCSS; if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); // Try to detect the user choosing select-all if (te.selectionStart != null) { if (!ie || (ie && ie_version < 9)) prepareSelectAllHack(); var i = 0, poll = function() { if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 && te.selectionEnd > 0 && input.prevInput == "\u200b") operation(cm, commands.selectAll)(cm); else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500); else display.input.reset(); }; display.detectingSelectAll = setTimeout(poll, 200); } } if (ie && ie_version >= 9) prepareSelectAllHack(); if (captureRightClick) { e_stop(e); var mouseup = function() { off(window, "mouseup", mouseup); setTimeout(rehide, 20); }; on(window, "mouseup", mouseup); } else { setTimeout(rehide, 50); } }, setUneditable: nothing, needsContentAttribute: false }, TextareaInput.prototype); // CONTENTEDITABLE INPUT STYLE function ContentEditableInput(cm) { this.cm = cm; this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null; this.polling = new Delayed(); this.gracePeriod = false; } ContentEditableInput.prototype = copyObj({ init: function(display) { var input = this, cm = input.cm; var div = input.div = display.lineDiv; div.contentEditable = "true"; disableBrowserMagic(div); on(div, "paste", function(e) { handlePaste(e, cm); }) on(div, "compositionstart", function(e) { var data = e.data; input.composing = {sel: cm.doc.sel, data: data, startData: data}; if (!data) return; var prim = cm.doc.sel.primary(); var line = cm.getLine(prim.head.line); var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length)); if (found > -1 && found <= prim.head.ch) input.composing.sel = simpleSelection(Pos(prim.head.line, found), Pos(prim.head.line, found + data.length)); }); on(div, "compositionupdate", function(e) { input.composing.data = e.data; }); on(div, "compositionend", function(e) { var ours = input.composing; if (!ours) return; if (e.data != ours.startData && !/\u200b/.test(e.data)) ours.data = e.data; // Need a small delay to prevent other code (input event, // selection polling) from doing damage when fired right after // compositionend. setTimeout(function() { if (!ours.handled) input.applyComposition(ours); if (input.composing == ours) input.composing = null; }, 50); }); on(div, "touchstart", function() { input.forceCompositionEnd(); }); on(div, "input", function() { if (input.composing) return; if (!input.pollContent()) runInOp(input.cm, function() {regChange(cm);}); }); function onCopyCut(e) { if (cm.somethingSelected()) { lastCopied = cm.getSelections(); if (e.type == "cut") cm.replaceSelection("", null, "cut"); } else if (!cm.options.lineWiseCopyCut) { return; } else { var ranges = copyableRanges(cm); lastCopied = ranges.text; if (e.type == "cut") { cm.operation(function() { cm.setSelections(ranges.ranges, 0, sel_dontScroll); cm.replaceSelection("", null, "cut"); }); } } // iOS exposes the clipboard API, but seems to discard content inserted into it if (e.clipboardData && !ios) { e.preventDefault(); e.clipboardData.clearData(); e.clipboardData.setData("text/plain", lastCopied.join("\n")); } else { // Old-fashioned briefly-focus-a-textarea hack var kludge = hiddenTextarea(), te = kludge.firstChild; cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild); te.value = lastCopied.join("\n"); var hadFocus = document.activeElement; selectInput(te); setTimeout(function() { cm.display.lineSpace.removeChild(kludge); hadFocus.focus(); }, 50); } } on(div, "copy", onCopyCut); on(div, "cut", onCopyCut); }, prepareSelection: function() { var result = prepareSelection(this.cm, false); result.focus = this.cm.state.focused; return result; }, showSelection: function(info) { if (!info || !this.cm.display.view.length) return; if (info.focus) this.showPrimarySelection(); this.showMultipleSelections(info); }, showPrimarySelection: function() { var sel = window.getSelection(), prim = this.cm.doc.sel.primary(); var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset); var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset); if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad && cmp(minPos(curAnchor, curFocus), prim.from()) == 0 && cmp(maxPos(curAnchor, curFocus), prim.to()) == 0) return; var start = posToDOM(this.cm, prim.from()); var end = posToDOM(this.cm, prim.to()); if (!start && !end) return; var view = this.cm.display.view; var old = sel.rangeCount && sel.getRangeAt(0); if (!start) { start = {node: view[0].measure.map[2], offset: 0}; } else if (!end) { // FIXME dangerously hacky var measure = view[view.length - 1].measure; var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map; end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]}; } try { var rng = range(start.node, start.offset, end.offset, end.node); } catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible if (rng) { sel.removeAllRanges(); sel.addRange(rng); if (old && sel.anchorNode == null) sel.addRange(old); else if (gecko) this.startGracePeriod(); } this.rememberSelection(); }, startGracePeriod: function() { var input = this; clearTimeout(this.gracePeriod); this.gracePeriod = setTimeout(function() { input.gracePeriod = false; if (input.selectionChanged()) input.cm.operation(function() { input.cm.curOp.selectionChanged = true; }); }, 20); }, showMultipleSelections: function(info) { removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors); removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection); }, rememberSelection: function() { var sel = window.getSelection(); this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset; this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset; }, selectionInEditor: function() { var sel = window.getSelection(); if (!sel.rangeCount) return false; var node = sel.getRangeAt(0).commonAncestorContainer; return contains(this.div, node); }, focus: function() { if (this.cm.options.readOnly != "nocursor") this.div.focus(); }, blur: function() { this.div.blur(); }, getField: function() { return this.div; }, supportsTouch: function() { return true; }, receivedFocus: function() { var input = this; if (this.selectionInEditor()) this.pollSelection(); else runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; }); function poll() { if (input.cm.state.focused) { input.pollSelection(); input.polling.set(input.cm.options.pollInterval, poll); } } this.polling.set(this.cm.options.pollInterval, poll); }, selectionChanged: function() { var sel = window.getSelection(); return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset || sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset; }, pollSelection: function() { if (!this.composing && !this.gracePeriod && this.selectionChanged()) { var sel = window.getSelection(), cm = this.cm; this.rememberSelection(); var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset); var head = domToPos(cm, sel.focusNode, sel.focusOffset); if (anchor && head) runInOp(cm, function() { setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll); if (anchor.bad || head.bad) cm.curOp.selectionChanged = true; }); } }, pollContent: function() { var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary(); var from = sel.from(), to = sel.to(); if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false; var fromIndex; if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) { var fromLine = lineNo(display.view[0].line); var fromNode = display.view[0].node; } else { var fromLine = lineNo(display.view[fromIndex].line); var fromNode = display.view[fromIndex - 1].node.nextSibling; } var toIndex = findViewIndex(cm, to.line); if (toIndex == display.view.length - 1) { var toLine = display.viewTo - 1; var toNode = display.lineDiv.lastChild; } else { var toLine = lineNo(display.view[toIndex + 1].line) - 1; var toNode = display.view[toIndex + 1].node.previousSibling; } var newText = splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine)); var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length)); while (newText.length > 1 && oldText.length > 1) { if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; } else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; } else break; } var cutFront = 0, cutEnd = 0; var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length); while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront)) ++cutFront; var newBot = lst(newText), oldBot = lst(oldText); var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0), oldBot.length - (oldText.length == 1 ? cutFront : 0)); while (cutEnd < maxCutEnd && newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) ++cutEnd; newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd); newText[0] = newText[0].slice(cutFront); var chFrom = Pos(fromLine, cutFront); var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0); if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) { replaceRange(cm.doc, newText, chFrom, chTo, "+input"); return true; } }, ensurePolled: function() { this.forceCompositionEnd(); }, reset: function() { this.forceCompositionEnd(); }, forceCompositionEnd: function() { if (!this.composing || this.composing.handled) return; this.applyComposition(this.composing); this.composing.handled = true; this.div.blur(); this.div.focus(); }, applyComposition: function(composing) { if (composing.data && composing.data != composing.startData) operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel); }, setUneditable: function(node) { node.setAttribute("contenteditable", "false"); }, onKeyPress: function(e) { e.preventDefault(); operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }, onContextMenu: nothing, resetPosition: nothing, needsContentAttribute: true }, ContentEditableInput.prototype); function posToDOM(cm, pos) { var view = findViewForLine(cm, pos.line); if (!view || view.hidden) return null; var line = getLine(cm.doc, pos.line); var info = mapFromLineView(view, line, pos.line); var order = getOrder(line), side = "left"; if (order) { var partPos = getBidiPartAt(order, pos.ch); side = partPos % 2 ? "right" : "left"; } var result = nodeAndOffsetInLineMap(info.map, pos.ch, side); result.offset = result.collapse == "right" ? result.end : result.start; return result; } function badPos(pos, bad) { if (bad) pos.bad = true; return pos; } function domToPos(cm, node, offset) { var lineNode; if (node == cm.display.lineDiv) { lineNode = cm.display.lineDiv.childNodes[offset]; if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true); node = null; offset = 0; } else { for (lineNode = node;; lineNode = lineNode.parentNode) { if (!lineNode || lineNode == cm.display.lineDiv) return null; if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break; } } for (var i = 0; i < cm.display.view.length; i++) { var lineView = cm.display.view[i]; if (lineView.node == lineNode) return locateNodeInLineView(lineView, node, offset); } } function locateNodeInLineView(lineView, node, offset) { var wrapper = lineView.text.firstChild, bad = false; if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true); if (node == wrapper) { bad = true; node = wrapper.childNodes[offset]; offset = 0; if (!node) { var line = lineView.rest ? lst(lineView.rest) : lineView.line; return badPos(Pos(lineNo(line), line.text.length), bad); } } var textNode = node.nodeType == 3 ? node : null, topNode = node; if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) { textNode = node.firstChild; if (offset) offset = textNode.nodeValue.length; } while (topNode.parentNode != wrapper) topNode = topNode.parentNode; var measure = lineView.measure, maps = measure.maps; function find(textNode, topNode, offset) { for (var i = -1; i < (maps ? maps.length : 0); i++) { var map = i < 0 ? measure.map : maps[i]; for (var j = 0; j < map.length; j += 3) { var curNode = map[j + 2]; if (curNode == textNode || curNode == topNode) { var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]); var ch = map[j] + offset; if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)]; return Pos(line, ch); } } } } var found = find(textNode, topNode, offset); if (found) return badPos(found, bad); // FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) { found = find(after, after.firstChild, 0); if (found) return badPos(Pos(found.line, found.ch - dist), bad); else dist += after.textContent.length; } for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) { found = find(before, before.firstChild, -1); if (found) return badPos(Pos(found.line, found.ch + dist), bad); else dist += after.textContent.length; } } function domTextBetween(cm, from, to, fromLine, toLine) { var text = "", closing = false; function recognizeMarker(id) { return function(marker) { return marker.id == id; }; } function walk(node) { if (node.nodeType == 1) { var cmText = node.getAttribute("cm-text"); if (cmText != null) { if (cmText == "") cmText = node.textContent.replace(/\u200b/g, ""); text += cmText; return; } var markerID = node.getAttribute("cm-marker"), range; if (markerID) { var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID)); if (found.length && (range = found[0].find())) text += getBetween(cm.doc, range.from, range.to).join("\n"); return; } if (node.getAttribute("contenteditable") == "false") return; for (var i = 0; i < node.childNodes.length; i++) walk(node.childNodes[i]); if (/^(pre|div|p)$/i.test(node.nodeName)) closing = true; } else if (node.nodeType == 3) { var val = node.nodeValue; if (!val) return; if (closing) { text += "\n"; closing = false; } text += val; } } for (;;) { walk(from); if (from == to) break; from = from.nextSibling; } return text; } CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput}; // SELECTION / CURSOR // Selection objects are immutable. A new one is created every time // the selection changes. A selection is one or more non-overlapping // (and non-touching) ranges, sorted, and an integer that indicates // which one is the primary selection (the one that's scrolled into // view, that getCursor returns, etc). function Selection(ranges, primIndex) { this.ranges = ranges; this.primIndex = primIndex; } Selection.prototype = { primary: function() { return this.ranges[this.primIndex]; }, equals: function(other) { if (other == this) return true; if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false; for (var i = 0; i < this.ranges.length; i++) { var here = this.ranges[i], there = other.ranges[i]; if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false; } return true; }, deepCopy: function() { for (var out = [], i = 0; i < this.ranges.length; i++) out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head)); return new Selection(out, this.primIndex); }, somethingSelected: function() { for (var i = 0; i < this.ranges.length; i++) if (!this.ranges[i].empty()) return true; return false; }, contains: function(pos, end) { if (!end) end = pos; for (var i = 0; i < this.ranges.length; i++) { var range = this.ranges[i]; if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0) return i; } return -1; } }; function Range(anchor, head) { this.anchor = anchor; this.head = head; } Range.prototype = { from: function() { return minPos(this.anchor, this.head); }, to: function() { return maxPos(this.anchor, this.head); }, empty: function() { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch; } }; // Take an unsorted, potentially overlapping set of ranges, and // build a selection out of it. 'Consumes' ranges array (modifying // it). function normalizeSelection(ranges, primIndex) { var prim = ranges[primIndex]; ranges.sort(function(a, b) { return cmp(a.from(), b.from()); }); primIndex = indexOf(ranges, prim); for (var i = 1; i < ranges.length; i++) { var cur = ranges[i], prev = ranges[i - 1]; if (cmp(prev.to(), cur.from()) >= 0) { var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to()); var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head; if (i <= primIndex) --primIndex; ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to)); } } return new Selection(ranges, primIndex); } function simpleSelection(anchor, head) { return new Selection([new Range(anchor, head || anchor)], 0); } // Most of the external API clips given positions to make sure they // actually exist within the document. function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));} function clipPos(doc, pos) { if (pos.line < doc.first) return Pos(doc.first, 0); var last = doc.first + doc.size - 1; if (pos.line > last) return Pos(last, getLine(doc, last).text.length); return clipToLen(pos, getLine(doc, pos.line).text.length); } function clipToLen(pos, linelen) { var ch = pos.ch; if (ch == null || ch > linelen) return Pos(pos.line, linelen); else if (ch < 0) return Pos(pos.line, 0); else return pos; } function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;} function clipPosArray(doc, array) { for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]); return out; } // SELECTION UPDATES // The 'scroll' parameter given to many of these indicated whether // the new cursor position should be scrolled into view after // modifying the selection. // If shift is held or the extend flag is set, extends a range to // include a given position (and optionally a second position). // Otherwise, simply returns the range between the given positions. // Used for cursor motion and such. function extendRange(doc, range, head, other) { if (doc.cm && doc.cm.display.shift || doc.extend) { var anchor = range.anchor; if (other) { var posBefore = cmp(head, anchor) < 0; if (posBefore != (cmp(other, anchor) < 0)) { anchor = head; head = other; } else if (posBefore != (cmp(head, other) < 0)) { head = other; } } return new Range(anchor, head); } else { return new Range(other || head, head); } } // Extend the primary selection range, discard the rest. function extendSelection(doc, head, other, options) { setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options); } // Extend all selections (pos is an array of selections with length // equal the number of selections) function extendSelections(doc, heads, options) { for (var out = [], i = 0; i < doc.sel.ranges.length; i++) out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null); var newSel = normalizeSelection(out, doc.sel.primIndex); setSelection(doc, newSel, options); } // Updates a single range in the selection. function replaceOneSelection(doc, i, range, options) { var ranges = doc.sel.ranges.slice(0); ranges[i] = range; setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options); } // Reset the selection to a single range. function setSimpleSelection(doc, anchor, head, options) { setSelection(doc, simpleSelection(anchor, head), options); } // Give beforeSelectionChange handlers a change to influence a // selection update. function filterSelectionChange(doc, sel) { var obj = { ranges: sel.ranges, update: function(ranges) { this.ranges = []; for (var i = 0; i < ranges.length; i++) this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor), clipPos(doc, ranges[i].head)); } }; signal(doc, "beforeSelectionChange", doc, obj); if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj); if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1); else return sel; } function setSelectionReplaceHistory(doc, sel, options) { var done = doc.history.done, last = lst(done); if (last && last.ranges) { done[done.length - 1] = sel; setSelectionNoUndo(doc, sel, options); } else { setSelection(doc, sel, options); } } // Set a new selection. function setSelection(doc, sel, options) { setSelectionNoUndo(doc, sel, options); addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options); } function setSelectionNoUndo(doc, sel, options) { if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange")) sel = filterSelectionChange(doc, sel); var bias = options && options.bias || (cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1); setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true)); if (!(options && options.scroll === false) && doc.cm) ensureCursorVisible(doc.cm); } function setSelectionInner(doc, sel) { if (sel.equals(doc.sel)) return; doc.sel = sel; if (doc.cm) { doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true; signalCursorActivity(doc.cm); } signalLater(doc, "cursorActivity", doc); } // Verify that the selection does not partially select any atomic // marked ranges. function reCheckSelection(doc) { setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll); } // Return a selection that does not partially select any atomic // ranges. function skipAtomicInSelection(doc, sel, bias, mayClear) { var out; for (var i = 0; i < sel.ranges.length; i++) { var range = sel.ranges[i]; var newAnchor = skipAtomic(doc, range.anchor, bias, mayClear); var newHead = skipAtomic(doc, range.head, bias, mayClear); if (out || newAnchor != range.anchor || newHead != range.head) { if (!out) out = sel.ranges.slice(0, i); out[i] = new Range(newAnchor, newHead); } } return out ? normalizeSelection(out, sel.primIndex) : sel; } // Ensure a given position is not inside an atomic range. function skipAtomic(doc, pos, bias, mayClear) { var flipped = false, curPos = pos; var dir = bias || 1; doc.cantEdit = false; search: for (;;) { var line = getLine(doc, curPos.line); if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) { var sp = line.markedSpans[i], m = sp.marker; if ((sp.from == null || (m.inclusiveLeft ? sp.from <= curPos.ch : sp.from < curPos.ch)) && (sp.to == null || (m.inclusiveRight ? sp.to >= curPos.ch : sp.to > curPos.ch))) { if (mayClear) { signal(m, "beforeCursorEnter"); if (m.explicitlyCleared) { if (!line.markedSpans) break; else {--i; continue;} } } if (!m.atomic) continue; var newPos = m.find(dir < 0 ? -1 : 1); if (cmp(newPos, curPos) == 0) { newPos.ch += dir; if (newPos.ch < 0) { if (newPos.line > doc.first) newPos = clipPos(doc, Pos(newPos.line - 1)); else newPos = null; } else if (newPos.ch > line.text.length) { if (newPos.line < doc.first + doc.size - 1) newPos = Pos(newPos.line + 1, 0); else newPos = null; } if (!newPos) { if (flipped) { // Driven in a corner -- no valid cursor position found at all // -- try again *with* clearing, if we didn't already if (!mayClear) return skipAtomic(doc, pos, bias, true); // Otherwise, turn off editing until further notice, and return the start of the doc doc.cantEdit = true; return Pos(doc.first, 0); } flipped = true; newPos = pos; dir = -dir; } } curPos = newPos; continue search; } } } return curPos; } } // SELECTION DRAWING function updateSelection(cm) { cm.display.input.showSelection(cm.display.input.prepareSelection()); } function prepareSelection(cm, primary) { var doc = cm.doc, result = {}; var curFragment = result.cursors = document.createDocumentFragment(); var selFragment = result.selection = document.createDocumentFragment(); for (var i = 0; i < doc.sel.ranges.length; i++) { if (primary === false && i == doc.sel.primIndex) continue; var range = doc.sel.ranges[i]; var collapsed = range.empty(); if (collapsed || cm.options.showCursorWhenSelecting) drawSelectionCursor(cm, range, curFragment); if (!collapsed) drawSelectionRange(cm, range, selFragment); } return result; } // Draws a cursor for the given range function drawSelectionCursor(cm, range, output) { var pos = cursorCoords(cm, range.head, "div", null, null, !cm.options.singleCursorHeightPerLine); var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor")); cursor.style.left = pos.left + "px"; cursor.style.top = pos.top + "px"; cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px"; if (pos.other) { // Secondary cursor, shown when on a 'jump' in bi-directional text var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor")); otherCursor.style.display = ""; otherCursor.style.left = pos.other.left + "px"; otherCursor.style.top = pos.other.top + "px"; otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px"; } } // Draws the given range as a highlighted selection function drawSelectionRange(cm, range, output) { var display = cm.display, doc = cm.doc; var fragment = document.createDocumentFragment(); var padding = paddingH(cm.display), leftSide = padding.left; var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right; function add(left, top, width, bottom) { if (top < 0) top = 0; top = Math.round(top); bottom = Math.round(bottom); fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left + "px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px; height: " + (bottom - top) + "px")); } function drawForLine(line, fromArg, toArg) { var lineObj = getLine(doc, line); var lineLen = lineObj.text.length; var start, end; function coords(ch, bias) { return charCoords(cm, Pos(line, ch), "div", lineObj, bias); } iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) { var leftPos = coords(from, "left"), rightPos, left, right; if (from == to) { rightPos = leftPos; left = right = leftPos.left; } else { rightPos = coords(to - 1, "right"); if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; } left = leftPos.left; right = rightPos.right; } if (fromArg == null && from == 0) left = leftSide; if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part add(left, leftPos.top, null, leftPos.bottom); left = leftSide; if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top); } if (toArg == null && to == lineLen) right = rightSide; if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left) start = leftPos; if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right) end = rightPos; if (left < leftSide + 1) left = leftSide; add(left, rightPos.top, right - left, rightPos.bottom); }); return {start: start, end: end}; } var sFrom = range.from(), sTo = range.to(); if (sFrom.line == sTo.line) { drawForLine(sFrom.line, sFrom.ch, sTo.ch); } else { var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line); var singleVLine = visualLine(fromLine) == visualLine(toLine); var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end; var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start; if (singleVLine) { if (leftEnd.top < rightStart.top - 2) { add(leftEnd.right, leftEnd.top, null, leftEnd.bottom); add(leftSide, rightStart.top, rightStart.left, rightStart.bottom); } else { add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom); } } if (leftEnd.bottom < rightStart.top) add(leftSide, leftEnd.bottom, null, rightStart.top); } output.appendChild(fragment); } // Cursor-blinking function restartBlink(cm) { if (!cm.state.focused) return; var display = cm.display; clearInterval(display.blinker); var on = true; display.cursorDiv.style.visibility = ""; if (cm.options.cursorBlinkRate > 0) display.blinker = setInterval(function() { display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; }, cm.options.cursorBlinkRate); else if (cm.options.cursorBlinkRate < 0) display.cursorDiv.style.visibility = "hidden"; } // HIGHLIGHT WORKER function startWorker(cm, time) { if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo) cm.state.highlight.set(time, bind(highlightWorker, cm)); } function highlightWorker(cm) { var doc = cm.doc; if (doc.frontier < doc.first) doc.frontier = doc.first; if (doc.frontier >= cm.display.viewTo) return; var end = +new Date + cm.options.workTime; var state = copyState(doc.mode, getStateBefore(cm, doc.frontier)); var changedLines = []; doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) { if (doc.frontier >= cm.display.viewFrom) { // Visible var oldStyles = line.styles; var highlighted = highlightLine(cm, line, state, true); line.styles = highlighted.styles; var oldCls = line.styleClasses, newCls = highlighted.classes; if (newCls) line.styleClasses = newCls; else if (oldCls) line.styleClasses = null; var ischange = !oldStyles || oldStyles.length != line.styles.length || oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass); for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i]; if (ischange) changedLines.push(doc.frontier); line.stateAfter = copyState(doc.mode, state); } else { processLine(cm, line.text, state); line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null; } ++doc.frontier; if (+new Date > end) { startWorker(cm, cm.options.workDelay); return true; } }); if (changedLines.length) runInOp(cm, function() { for (var i = 0; i < changedLines.length; i++) regLineChange(cm, changedLines[i], "text"); }); } // Finds the line to start with when starting a parse. Tries to // find a line with a stateAfter, so that it can start with a // valid state. If that fails, it returns the line with the // smallest indentation, which tends to need the least context to // parse correctly. function findStartLine(cm, n, precise) { var minindent, minline, doc = cm.doc; var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100); for (var search = n; search > lim; --search) { if (search <= doc.first) return doc.first; var line = getLine(doc, search - 1); if (line.stateAfter && (!precise || search <= doc.frontier)) return search; var indented = countColumn(line.text, null, cm.options.tabSize); if (minline == null || minindent > indented) { minline = search - 1; minindent = indented; } } return minline; } function getStateBefore(cm, n, precise) { var doc = cm.doc, display = cm.display; if (!doc.mode.startState) return true; var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter; if (!state) state = startState(doc.mode); else state = copyState(doc.mode, state); doc.iter(pos, n, function(line) { processLine(cm, line.text, state); var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo; line.stateAfter = save ? copyState(doc.mode, state) : null; ++pos; }); if (precise) doc.frontier = pos; return state; } // POSITION MEASUREMENT function paddingTop(display) {return display.lineSpace.offsetTop;} function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;} function paddingH(display) { if (display.cachedPaddingH) return display.cachedPaddingH; var e = removeChildrenAndAdd(display.measure, elt("pre", "x")); var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle; var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)}; if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data; return data; } function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; } function displayWidth(cm) { return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth; } function displayHeight(cm) { return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight; } // Ensure the lineView.wrapping.heights array is populated. This is // an array of bottom offsets for the lines that make up a drawn // line. When lineWrapping is on, there might be more than one // height. function ensureLineHeights(cm, lineView, rect) { var wrapping = cm.options.lineWrapping; var curWidth = wrapping && displayWidth(cm); if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) { var heights = lineView.measure.heights = []; if (wrapping) { lineView.measure.width = curWidth; var rects = lineView.text.firstChild.getClientRects(); for (var i = 0; i < rects.length - 1; i++) { var cur = rects[i], next = rects[i + 1]; if (Math.abs(cur.bottom - next.bottom) > 2) heights.push((cur.bottom + next.top) / 2 - rect.top); } } heights.push(rect.bottom - rect.top); } } // Find a line map (mapping character offsets to text nodes) and a // measurement cache for the given line number. (A line view might // contain multiple lines when collapsed ranges are present.) function mapFromLineView(lineView, line, lineN) { if (lineView.line == line) return {map: lineView.measure.map, cache: lineView.measure.cache}; for (var i = 0; i < lineView.rest.length; i++) if (lineView.rest[i] == line) return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]}; for (var i = 0; i < lineView.rest.length; i++) if (lineNo(lineView.rest[i]) > lineN) return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true}; } // Render a line into the hidden node display.externalMeasured. Used // when measurement is needed for a line that's not in the viewport. function updateExternalMeasurement(cm, line) { line = visualLine(line); var lineN = lineNo(line); var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN); view.lineN = lineN; var built = view.built = buildLineContent(cm, view); view.text = built.pre; removeChildrenAndAdd(cm.display.lineMeasure, built.pre); return view; } // Get a {top, bottom, left, right} box (in line-local coordinates) // for a given character. function measureChar(cm, line, ch, bias) { return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias); } // Find a line view that corresponds to the given line number. function findViewForLine(cm, lineN) { if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo) return cm.display.view[findViewIndex(cm, lineN)]; var ext = cm.display.externalMeasured; if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size) return ext; } // Measurement can be split in two steps, the set-up work that // applies to the whole line, and the measurement of the actual // character. Functions like coordsChar, that need to do a lot of // measurements in a row, can thus ensure that the set-up work is // only done once. function prepareMeasureForLine(cm, line) { var lineN = lineNo(line); var view = findViewForLine(cm, lineN); if (view && !view.text) view = null; else if (view && view.changes) updateLineForChanges(cm, view, lineN, getDimensions(cm)); if (!view) view = updateExternalMeasurement(cm, line); var info = mapFromLineView(view, line, lineN); return { line: line, view: view, rect: null, map: info.map, cache: info.cache, before: info.before, hasHeights: false }; } // Given a prepared measurement object, measures the position of an // actual character (or fetches it from the cache). function measureCharPrepared(cm, prepared, ch, bias, varHeight) { if (prepared.before) ch = -1; var key = ch + (bias || ""), found; if (prepared.cache.hasOwnProperty(key)) { found = prepared.cache[key]; } else { if (!prepared.rect) prepared.rect = prepared.view.text.getBoundingClientRect(); if (!prepared.hasHeights) { ensureLineHeights(cm, prepared.view, prepared.rect); prepared.hasHeights = true; } found = measureCharInner(cm, prepared, ch, bias); if (!found.bogus) prepared.cache[key] = found; } return {left: found.left, right: found.right, top: varHeight ? found.rtop : found.top, bottom: varHeight ? found.rbottom : found.bottom}; } var nullRect = {left: 0, right: 0, top: 0, bottom: 0}; function nodeAndOffsetInLineMap(map, ch, bias) { var node, start, end, collapse; // First, search the line map for the text node corresponding to, // or closest to, the target character. for (var i = 0; i < map.length; i += 3) { var mStart = map[i], mEnd = map[i + 1]; if (ch < mStart) { start = 0; end = 1; collapse = "left"; } else if (ch < mEnd) { start = ch - mStart; end = start + 1; } else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) { end = mEnd - mStart; start = end - 1; if (ch >= mEnd) collapse = "right"; } if (start != null) { node = map[i + 2]; if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right")) collapse = bias; if (bias == "left" && start == 0) while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) { node = map[(i -= 3) + 2]; collapse = "left"; } if (bias == "right" && start == mEnd - mStart) while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) { node = map[(i += 3) + 2]; collapse = "right"; } break; } } return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}; } function measureCharInner(cm, prepared, ch, bias) { var place = nodeAndOffsetInLineMap(prepared.map, ch, bias); var node = place.node, start = place.start, end = place.end, collapse = place.collapse; var rect; if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates. for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start; while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end; if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) { rect = node.parentNode.getBoundingClientRect(); } else if (ie && cm.options.lineWrapping) { var rects = range(node, start, end).getClientRects(); if (rects.length) rect = rects[bias == "right" ? rects.length - 1 : 0]; else rect = nullRect; } else { rect = range(node, start, end).getBoundingClientRect() || nullRect; } if (rect.left || rect.right || start == 0) break; end = start; start = start - 1; collapse = "right"; } if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect); } else { // If it is a widget, simply get the box for the whole widget. if (start > 0) collapse = bias = "right"; var rects; if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1) rect = rects[bias == "right" ? rects.length - 1 : 0]; else rect = node.getBoundingClientRect(); } if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) { var rSpan = node.parentNode.getClientRects()[0]; if (rSpan) rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; else rect = nullRect; } var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top; var mid = (rtop + rbot) / 2; var heights = prepared.view.measure.heights; for (var i = 0; i < heights.length - 1; i++) if (mid < heights[i]) break; var top = i ? heights[i - 1] : 0, bot = heights[i]; var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left, right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left, top: top, bottom: bot}; if (!rect.left && !rect.right) result.bogus = true; if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; } return result; } // Work around problem with bounding client rects on ranges being // returned incorrectly when zoomed on IE10 and below. function maybeUpdateRectForZooming(measure, rect) { if (!window.screen || screen.logicalXDPI == null || screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure)) return rect; var scaleX = screen.logicalXDPI / screen.deviceXDPI; var scaleY = screen.logicalYDPI / screen.deviceYDPI; return {left: rect.left * scaleX, right: rect.right * scaleX, top: rect.top * scaleY, bottom: rect.bottom * scaleY}; } function clearLineMeasurementCacheFor(lineView) { if (lineView.measure) { lineView.measure.cache = {}; lineView.measure.heights = null; if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++) lineView.measure.caches[i] = {}; } } function clearLineMeasurementCache(cm) { cm.display.externalMeasure = null; removeChildren(cm.display.lineMeasure); for (var i = 0; i < cm.display.view.length; i++) clearLineMeasurementCacheFor(cm.display.view[i]); } function clearCaches(cm) { clearLineMeasurementCache(cm); cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null; if (!cm.options.lineWrapping) cm.display.maxLineChanged = true; cm.display.lineNumChars = null; } function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; } function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; } // Converts a {top, bottom, left, right} box from line-local // coordinates into another coordinate system. Context may be one of // "line", "div" (display.lineDiv), "local"/null (editor), "window", // or "page". function intoCoordSystem(cm, lineObj, rect, context) { if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) { var size = widgetHeight(lineObj.widgets[i]); rect.top += size; rect.bottom += size; } if (context == "line") return rect; if (!context) context = "local"; var yOff = heightAtLine(lineObj); if (context == "local") yOff += paddingTop(cm.display); else yOff -= cm.display.viewOffset; if (context == "page" || context == "window") { var lOff = cm.display.lineSpace.getBoundingClientRect(); yOff += lOff.top + (context == "window" ? 0 : pageScrollY()); var xOff = lOff.left + (context == "window" ? 0 : pageScrollX()); rect.left += xOff; rect.right += xOff; } rect.top += yOff; rect.bottom += yOff; return rect; } // Coverts a box from "div" coords to another coordinate system. // Context may be "window", "page", "div", or "local"/null. function fromCoordSystem(cm, coords, context) { if (context == "div") return coords; var left = coords.left, top = coords.top; // First move into "page" coordinate system if (context == "page") { left -= pageScrollX(); top -= pageScrollY(); } else if (context == "local" || !context) { var localBox = cm.display.sizer.getBoundingClientRect(); left += localBox.left; top += localBox.top; } var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect(); return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}; } function charCoords(cm, pos, context, lineObj, bias) { if (!lineObj) lineObj = getLine(cm.doc, pos.line); return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context); } // Returns a box for a given cursor position, which may have an // 'other' property containing the position of the secondary cursor // on a bidi boundary. function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) { lineObj = lineObj || getLine(cm.doc, pos.line); if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj); function get(ch, right) { var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight); if (right) m.left = m.right; else m.right = m.left; return intoCoordSystem(cm, lineObj, m, context); } function getBidi(ch, partPos) { var part = order[partPos], right = part.level % 2; if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) { part = order[--partPos]; ch = bidiRight(part) - (part.level % 2 ? 0 : 1); right = true; } else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) { part = order[++partPos]; ch = bidiLeft(part) - part.level % 2; right = false; } if (right && ch == part.to && ch > part.from) return get(ch - 1); return get(ch, right); } var order = getOrder(lineObj), ch = pos.ch; if (!order) return get(ch); var partPos = getBidiPartAt(order, ch); var val = getBidi(ch, partPos); if (bidiOther != null) val.other = getBidi(ch, bidiOther); return val; } // Used to cheaply estimate the coordinates for a position. Used for // intermediate scroll updates. function estimateCoords(cm, pos) { var left = 0, pos = clipPos(cm.doc, pos); if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch; var lineObj = getLine(cm.doc, pos.line); var top = heightAtLine(lineObj) + paddingTop(cm.display); return {left: left, right: left, top: top, bottom: top + lineObj.height}; } // Positions returned by coordsChar contain some extra information. // xRel is the relative x position of the input coordinates compared // to the found position (so xRel > 0 means the coordinates are to // the right of the character position, for example). When outside // is true, that means the coordinates lie outside the line's // vertical range. function PosWithInfo(line, ch, outside, xRel) { var pos = Pos(line, ch); pos.xRel = xRel; if (outside) pos.outside = true; return pos; } // Compute the character position closest to the given coordinates. // Input must be lineSpace-local ("div" coordinate system). function coordsChar(cm, x, y) { var doc = cm.doc; y += cm.display.viewOffset; if (y < 0) return PosWithInfo(doc.first, 0, true, -1); var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1; if (lineN > last) return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1); if (x < 0) x = 0; var lineObj = getLine(doc, lineN); for (;;) { var found = coordsCharInner(cm, lineObj, lineN, x, y); var merged = collapsedSpanAtEnd(lineObj); var mergedPos = merged && merged.find(0, true); if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0)) lineN = lineNo(lineObj = mergedPos.to.line); else return found; } } function coordsCharInner(cm, lineObj, lineNo, x, y) { var innerOff = y - heightAtLine(lineObj); var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth; var preparedMeasure = prepareMeasureForLine(cm, lineObj); function getX(ch) { var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure); wrongLine = true; if (innerOff > sp.bottom) return sp.left - adjust; else if (innerOff < sp.top) return sp.left + adjust; else wrongLine = false; return sp.left; } var bidi = getOrder(lineObj), dist = lineObj.text.length; var from = lineLeft(lineObj), to = lineRight(lineObj); var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine; if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1); // Do a binary search between these bounds. for (;;) { if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) { var ch = x < fromX || x - fromX <= toX - x ? from : to; var xDiff = x - (ch == from ? fromX : toX); while (isExtendingChar(lineObj.text.charAt(ch))) ++ch; var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside, xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0); return pos; } var step = Math.ceil(dist / 2), middle = from + step; if (bidi) { middle = from; for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1); } var middleX = getX(middle); if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;} else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;} } } var measureText; // Compute the default text height. function textHeight(display) { if (display.cachedTextHeight != null) return display.cachedTextHeight; if (measureText == null) { measureText = elt("pre"); // Measure a bunch of lines, for browsers that compute // fractional heights. for (var i = 0; i < 49; ++i) { measureText.appendChild(document.createTextNode("x")); measureText.appendChild(elt("br")); } measureText.appendChild(document.createTextNode("x")); } removeChildrenAndAdd(display.measure, measureText); var height = measureText.offsetHeight / 50; if (height > 3) display.cachedTextHeight = height; removeChildren(display.measure); return height || 1; } // Compute the default character width. function charWidth(display) { if (display.cachedCharWidth != null) return display.cachedCharWidth; var anchor = elt("span", "xxxxxxxxxx"); var pre = elt("pre", [anchor]); removeChildrenAndAdd(display.measure, pre); var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10; if (width > 2) display.cachedCharWidth = width; return width || 10; } // OPERATIONS // Operations are used to wrap a series of changes to the editor // state in such a way that each change won't have to update the // cursor and display (which would be awkward, slow, and // error-prone). Instead, display updates are batched and then all // combined and executed at once. var operationGroup = null; var nextOpId = 0; // Start a new operation. function startOperation(cm) { cm.curOp = { cm: cm, viewChanged: false, // Flag that indicates that lines might need to be redrawn startHeight: cm.doc.height, // Used to detect need to update scrollbar forceUpdate: false, // Used to force a redraw updateInput: null, // Whether to reset the input textarea typing: false, // Whether this reset should be careful to leave existing text (for compositing) changeObjs: null, // Accumulated changes, for firing change events cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already selectionChanged: false, // Whether the selection needs to be redrawn updateMaxLine: false, // Set when the widest line needs to be determined anew scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet scrollToPos: null, // Used to scroll to a specific position focus: false, id: ++nextOpId // Unique ID }; if (operationGroup) { operationGroup.ops.push(cm.curOp); } else { cm.curOp.ownsGroup = operationGroup = { ops: [cm.curOp], delayedCallbacks: [] }; } } function fireCallbacksForOps(group) { // Calls delayed callbacks and cursorActivity handlers until no // new ones appear var callbacks = group.delayedCallbacks, i = 0; do { for (; i < callbacks.length; i++) callbacks[i](); for (var j = 0; j < group.ops.length; j++) { var op = group.ops[j]; if (op.cursorActivityHandlers) while (op.cursorActivityCalled < op.cursorActivityHandlers.length) op.cursorActivityHandlers[op.cursorActivityCalled++](op.cm); } } while (i < callbacks.length); } // Finish an operation, updating the display and signalling delayed events function endOperation(cm) { var op = cm.curOp, group = op.ownsGroup; if (!group) return; try { fireCallbacksForOps(group); } finally { operationGroup = null; for (var i = 0; i < group.ops.length; i++) group.ops[i].cm.curOp = null; endOperations(group); } } // The DOM updates done when an operation finishes are batched so // that the minimum number of relayouts are required. function endOperations(group) { var ops = group.ops; for (var i = 0; i < ops.length; i++) // Read DOM endOperation_R1(ops[i]); for (var i = 0; i < ops.length; i++) // Write DOM (maybe) endOperation_W1(ops[i]); for (var i = 0; i < ops.length; i++) // Read DOM endOperation_R2(ops[i]); for (var i = 0; i < ops.length; i++) // Write DOM (maybe) endOperation_W2(ops[i]); for (var i = 0; i < ops.length; i++) // Read DOM endOperation_finish(ops[i]); } function endOperation_R1(op) { var cm = op.cm, display = cm.display; maybeClipScrollbars(cm); if (op.updateMaxLine) findMaxLine(cm); op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null || op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom || op.scrollToPos.to.line >= display.viewTo) || display.maxLineChanged && cm.options.lineWrapping; op.update = op.mustUpdate && new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate); } function endOperation_W1(op) { op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update); } function endOperation_R2(op) { var cm = op.cm, display = cm.display; if (op.updatedDisplay) updateHeightsInViewport(cm); op.barMeasure = measureForScrollbars(cm); // If the max line changed since it was last measured, measure it, // and ensure the document's width matches it. // updateDisplay_W2 will use these properties to do the actual resizing if (display.maxLineChanged && !cm.options.lineWrapping) { op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3; cm.display.sizerWidth = op.adjustWidthTo; op.barMeasure.scrollWidth = Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth); op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm)); } if (op.updatedDisplay || op.selectionChanged) op.preparedSelection = display.input.prepareSelection(); } function endOperation_W2(op) { var cm = op.cm; if (op.adjustWidthTo != null) { cm.display.sizer.style.minWidth = op.adjustWidthTo + "px"; if (op.maxScrollLeft < cm.doc.scrollLeft) setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); cm.display.maxLineChanged = false; } if (op.preparedSelection) cm.display.input.showSelection(op.preparedSelection); if (op.updatedDisplay) setDocumentHeight(cm, op.barMeasure); if (op.updatedDisplay || op.startHeight != cm.doc.height) updateScrollbars(cm, op.barMeasure); if (op.selectionChanged) restartBlink(cm); if (cm.state.focused && op.updateInput) cm.display.input.reset(op.typing); if (op.focus && op.focus == activeElt()) ensureFocus(op.cm); } function endOperation_finish(op) { var cm = op.cm, display = cm.display, doc = cm.doc; if (op.updatedDisplay) postUpdateDisplay(cm, op.update); // Abort mouse wheel delta measurement, when scrolling explicitly if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos)) display.wheelStartX = display.wheelStartY = null; // Propagate the scroll position to the actual DOM scroller if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) { doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop)); display.scrollbars.setScrollTop(doc.scrollTop); display.scroller.scrollTop = doc.scrollTop; } if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) { doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft)); display.scrollbars.setScrollLeft(doc.scrollLeft); display.scroller.scrollLeft = doc.scrollLeft; alignHorizontally(cm); } // If we need to scroll a specific position into view, do so. if (op.scrollToPos) { var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from), clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin); if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords); } // Fire events for markers that are hidden/unidden by editing or // undoing var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers; if (hidden) for (var i = 0; i < hidden.length; ++i) if (!hidden[i].lines.length) signal(hidden[i], "hide"); if (unhidden) for (var i = 0; i < unhidden.length; ++i) if (unhidden[i].lines.length) signal(unhidden[i], "unhide"); if (display.wrapper.offsetHeight) doc.scrollTop = cm.display.scroller.scrollTop; // Fire change events, and delayed event handlers if (op.changeObjs) signal(cm, "changes", cm, op.changeObjs); if (op.update) op.update.finish(); } // Run the given function in an operation function runInOp(cm, f) { if (cm.curOp) return f(); startOperation(cm); try { return f(); } finally { endOperation(cm); } } // Wraps a function in an operation. Returns the wrapped function. function operation(cm, f) { return function() { if (cm.curOp) return f.apply(cm, arguments); startOperation(cm); try { return f.apply(cm, arguments); } finally { endOperation(cm); } }; } // Used to add methods to editor and doc instances, wrapping them in // operations. function methodOp(f) { return function() { if (this.curOp) return f.apply(this, arguments); startOperation(this); try { return f.apply(this, arguments); } finally { endOperation(this); } }; } function docMethodOp(f) { return function() { var cm = this.cm; if (!cm || cm.curOp) return f.apply(this, arguments); startOperation(cm); try { return f.apply(this, arguments); } finally { endOperation(cm); } }; } // VIEW TRACKING // These objects are used to represent the visible (currently drawn) // part of the document. A LineView may correspond to multiple // logical lines, if those are connected by collapsed ranges. function LineView(doc, line, lineN) { // The starting line this.line = line; // Continuing lines, if any this.rest = visualLineContinued(line); // Number of logical lines in this visual line this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1; this.node = this.text = null; this.hidden = lineIsHidden(doc, line); } // Create a range of LineView objects for the given lines. function buildViewArray(cm, from, to) { var array = [], nextPos; for (var pos = from; pos < to; pos = nextPos) { var view = new LineView(cm.doc, getLine(cm.doc, pos), pos); nextPos = pos + view.size; array.push(view); } return array; } // Updates the display.view data structure for a given change to the // document. From and to are in pre-change coordinates. Lendiff is // the amount of lines added or subtracted by the change. This is // used for changes that span multiple lines, or change the way // lines are divided into visual lines. regLineChange (below) // registers single-line changes. function regChange(cm, from, to, lendiff) { if (from == null) from = cm.doc.first; if (to == null) to = cm.doc.first + cm.doc.size; if (!lendiff) lendiff = 0; var display = cm.display; if (lendiff && to < display.viewTo && (display.updateLineNumbers == null || display.updateLineNumbers > from)) display.updateLineNumbers = from; cm.curOp.viewChanged = true; if (from >= display.viewTo) { // Change after if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) resetView(cm); } else if (to <= display.viewFrom) { // Change before if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { resetView(cm); } else { display.viewFrom += lendiff; display.viewTo += lendiff; } } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap resetView(cm); } else if (from <= display.viewFrom) { // Top overlap var cut = viewCuttingPoint(cm, to, to + lendiff, 1); if (cut) { display.view = display.view.slice(cut.index); display.viewFrom = cut.lineN; display.viewTo += lendiff; } else { resetView(cm); } } else if (to >= display.viewTo) { // Bottom overlap var cut = viewCuttingPoint(cm, from, from, -1); if (cut) { display.view = display.view.slice(0, cut.index); display.viewTo = cut.lineN; } else { resetView(cm); } } else { // Gap in the middle var cutTop = viewCuttingPoint(cm, from, from, -1); var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1); if (cutTop && cutBot) { display.view = display.view.slice(0, cutTop.index) .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) .concat(display.view.slice(cutBot.index)); display.viewTo += lendiff; } else { resetView(cm); } } var ext = display.externalMeasured; if (ext) { if (to < ext.lineN) ext.lineN += lendiff; else if (from < ext.lineN + ext.size) display.externalMeasured = null; } } // Register a change to a single line. Type must be one of "text", // "gutter", "class", "widget" function regLineChange(cm, line, type) { cm.curOp.viewChanged = true; var display = cm.display, ext = cm.display.externalMeasured; if (ext && line >= ext.lineN && line < ext.lineN + ext.size) display.externalMeasured = null; if (line < display.viewFrom || line >= display.viewTo) return; var lineView = display.view[findViewIndex(cm, line)]; if (lineView.node == null) return; var arr = lineView.changes || (lineView.changes = []); if (indexOf(arr, type) == -1) arr.push(type); } // Clear the view. function resetView(cm) { cm.display.viewFrom = cm.display.viewTo = cm.doc.first; cm.display.view = []; cm.display.viewOffset = 0; } // Find the view element corresponding to a given line. Return null // when the line isn't visible. function findViewIndex(cm, n) { if (n >= cm.display.viewTo) return null; n -= cm.display.viewFrom; if (n < 0) return null; var view = cm.display.view; for (var i = 0; i < view.length; i++) { n -= view[i].size; if (n < 0) return i; } } function viewCuttingPoint(cm, oldN, newN, dir) { var index = findViewIndex(cm, oldN), diff, view = cm.display.view; if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) return {index: index, lineN: newN}; for (var i = 0, n = cm.display.viewFrom; i < index; i++) n += view[i].size; if (n != oldN) { if (dir > 0) { if (index == view.length - 1) return null; diff = (n + view[index].size) - oldN; index++; } else { diff = n - oldN; } oldN += diff; newN += diff; } while (visualLineNo(cm.doc, newN) != newN) { if (index == (dir < 0 ? 0 : view.length - 1)) return null; newN += dir * view[index - (dir < 0 ? 1 : 0)].size; index += dir; } return {index: index, lineN: newN}; } // Force the view to cover a given range, adding empty view element // or clipping off existing ones as needed. function adjustView(cm, from, to) { var display = cm.display, view = display.view; if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { display.view = buildViewArray(cm, from, to); display.viewFrom = from; } else { if (display.viewFrom > from) display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); else if (display.viewFrom < from) display.view = display.view.slice(findViewIndex(cm, from)); display.viewFrom = from; if (display.viewTo < to) display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); else if (display.viewTo > to) display.view = display.view.slice(0, findViewIndex(cm, to)); } display.viewTo = to; } // Count the number of lines in the view whose DOM representation is // out of date (or nonexistent). function countDirtyView(cm) { var view = cm.display.view, dirty = 0; for (var i = 0; i < view.length; i++) { var lineView = view[i]; if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty; } return dirty; } // EVENT HANDLERS // Attach the necessary event handlers when initializing the editor function registerEventHandlers(cm) { var d = cm.display; on(d.scroller, "mousedown", operation(cm, onMouseDown)); // Older IE's will not fire a second mousedown for a double click if (ie && ie_version < 11) on(d.scroller, "dblclick", operation(cm, function(e) { if (signalDOMEvent(cm, e)) return; var pos = posFromMouse(cm, e); if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return; e_preventDefault(e); var word = cm.findWordAt(pos); extendSelection(cm.doc, word.anchor, word.head); })); else on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); }); // Some browsers fire contextmenu *after* opening the menu, at // which point we can't mess with it anymore. Context menu is // handled in onMouseDown for these browsers. if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);}); // Used to suppress mouse event handling when a touch happens var touchFinished, prevTouch = {end: 0}; function finishTouch() { if (d.activeTouch) { touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000); prevTouch = d.activeTouch; prevTouch.end = +new Date; } }; function isMouseLikeTouchEvent(e) { if (e.touches.length != 1) return false; var touch = e.touches[0]; return touch.radiusX <= 1 && touch.radiusY <= 1; } function farAway(touch, other) { if (other.left == null) return true; var dx = other.left - touch.left, dy = other.top - touch.top; return dx * dx + dy * dy > 20 * 20; } on(d.scroller, "touchstart", function(e) { if (!isMouseLikeTouchEvent(e)) { clearTimeout(touchFinished); var now = +new Date; d.activeTouch = {start: now, moved: false, prev: now - prevTouch.end <= 300 ? prevTouch : null}; if (e.touches.length == 1) { d.activeTouch.left = e.touches[0].pageX; d.activeTouch.top = e.touches[0].pageY; } } }); on(d.scroller, "touchmove", function() { if (d.activeTouch) d.activeTouch.moved = true; }); on(d.scroller, "touchend", function(e) { var touch = d.activeTouch; if (touch && !eventInWidget(d, e) && touch.left != null && !touch.moved && new Date - touch.start < 300) { var pos = cm.coordsChar(d.activeTouch, "page"), range; if (!touch.prev || farAway(touch, touch.prev)) // Single tap range = new Range(pos, pos); else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap range = cm.findWordAt(pos); else // Triple tap range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); cm.setSelection(range.anchor, range.head); cm.focus(); e_preventDefault(e); } finishTouch(); }); on(d.scroller, "touchcancel", finishTouch); // Sync scrolling between fake scrollbars and real scrollable // area, ensure viewport is updated when scrolling. on(d.scroller, "scroll", function() { if (d.scroller.clientHeight) { setScrollTop(cm, d.scroller.scrollTop); setScrollLeft(cm, d.scroller.scrollLeft, true); signal(cm, "scroll", cm); } }); // Listen to wheel events in order to try and update the viewport on time. on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);}); on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);}); // Prevent wrapper from ever scrolling on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; }); d.dragFunctions = { simple: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);}, start: function(e){onDragStart(cm, e);}, drop: operation(cm, onDrop) }; var inp = d.input.getField(); on(inp, "keyup", function(e) { onKeyUp.call(cm, e); }); on(inp, "keydown", operation(cm, onKeyDown)); on(inp, "keypress", operation(cm, onKeyPress)); on(inp, "focus", bind(onFocus, cm)); on(inp, "blur", bind(onBlur, cm)); } function dragDropChanged(cm, value, old) { var wasOn = old && old != CodeMirror.Init; if (!value != !wasOn) { var funcs = cm.display.dragFunctions; var toggle = value ? on : off; toggle(cm.display.scroller, "dragstart", funcs.start); toggle(cm.display.scroller, "dragenter", funcs.simple); toggle(cm.display.scroller, "dragover", funcs.simple); toggle(cm.display.scroller, "drop", funcs.drop); } } // Called when the window resizes function onResize(cm) { var d = cm.display; if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth) return; // Might be a text scaling operation, clear size caches. d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null; d.scrollbarsClipped = false; cm.setSize(); } // MOUSE EVENTS // Return true when the given mouse event happened in a widget function eventInWidget(display, e) { for (var n = e_target(e); n != display.wrapper; n = n.parentNode) { if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") || (n.parentNode == display.sizer && n != display.mover)) return true; } } // Given a mouse event, find the corresponding position. If liberal // is false, it checks whether a gutter or scrollbar was clicked, // and returns null if it was. forRect is used by rectangular // selections, and tries to estimate a character position even for // coordinates beyond the right of the text. function posFromMouse(cm, e, liberal, forRect) { var display = cm.display; if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null; var x, y, space = display.lineSpace.getBoundingClientRect(); // Fails unpredictably on IE[67] when mouse is dragged around quickly. try { x = e.clientX - space.left; y = e.clientY - space.top; } catch (e) { return null; } var coords = coordsChar(cm, x, y), line; if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) { var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length; coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff)); } return coords; } // A mouse down can be a single click, double click, triple click, // start of selection drag, start of text drag, new cursor // (ctrl-click), rectangle drag (alt-drag), or xwin // middle-click-paste. Or it might be a click on something we should // not interfere with, such as a scrollbar or widget. function onMouseDown(e) { var cm = this, display = cm.display; if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return; display.shift = e.shiftKey; if (eventInWidget(display, e)) { if (!webkit) { // Briefly turn off draggability, to allow widgets to do // normal dragging things. display.scroller.draggable = false; setTimeout(function(){display.scroller.draggable = true;}, 100); } return; } if (clickInGutter(cm, e)) return; var start = posFromMouse(cm, e); window.focus(); switch (e_button(e)) { case 1: if (start) leftButtonDown(cm, e, start); else if (e_target(e) == display.scroller) e_preventDefault(e); break; case 2: if (webkit) cm.state.lastMiddleDown = +new Date; if (start) extendSelection(cm.doc, start); setTimeout(function() {display.input.focus();}, 20); e_preventDefault(e); break; case 3: if (captureRightClick) onContextMenu(cm, e); else delayBlurEvent(cm); break; } } var lastClick, lastDoubleClick; function leftButtonDown(cm, e, start) { if (ie) setTimeout(bind(ensureFocus, cm), 0); else cm.curOp.focus = activeElt(); var now = +new Date, type; if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) { type = "triple"; } else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) { type = "double"; lastDoubleClick = {time: now, pos: start}; } else { type = "single"; lastClick = {time: now, pos: start}; } var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained; if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) && type == "single" && (contained = sel.contains(start)) > -1 && (cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) && (cmp(contained.to(), start) > 0 || start.xRel < 0)) leftButtonStartDrag(cm, e, start, modifier); else leftButtonSelect(cm, e, start, type, modifier); } // Start a text drag. When it ends, see if any dragging actually // happen, and treat as a click if it didn't. function leftButtonStartDrag(cm, e, start, modifier) { var display = cm.display, startTime = +new Date; var dragEnd = operation(cm, function(e2) { if (webkit) display.scroller.draggable = false; cm.state.draggingText = false; off(document, "mouseup", dragEnd); off(display.scroller, "drop", dragEnd); if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) { e_preventDefault(e2); if (!modifier && +new Date - 200 < startTime) extendSelection(cm.doc, start); // Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081) if (webkit || ie && ie_version == 9) setTimeout(function() {document.body.focus(); display.input.focus();}, 20); else display.input.focus(); } }); // Let the drag handler handle this. if (webkit) display.scroller.draggable = true; cm.state.draggingText = dragEnd; // IE's approach to draggable if (display.scroller.dragDrop) display.scroller.dragDrop(); on(document, "mouseup", dragEnd); on(display.scroller, "drop", dragEnd); } // Normal selection, as opposed to text dragging. function leftButtonSelect(cm, e, start, type, addNew) { var display = cm.display, doc = cm.doc; e_preventDefault(e); var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges; if (addNew && !e.shiftKey) { ourIndex = doc.sel.contains(start); if (ourIndex > -1) ourRange = ranges[ourIndex]; else ourRange = new Range(start, start); } else { ourRange = doc.sel.primary(); ourIndex = doc.sel.primIndex; } if (e.altKey) { type = "rect"; if (!addNew) ourRange = new Range(start, start); start = posFromMouse(cm, e, true, true); ourIndex = -1; } else if (type == "double") { var word = cm.findWordAt(start); if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, word.anchor, word.head); else ourRange = word; } else if (type == "triple") { var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0))); if (cm.display.shift || doc.extend) ourRange = extendRange(doc, ourRange, line.anchor, line.head); else ourRange = line; } else { ourRange = extendRange(doc, ourRange, start); } if (!addNew) { ourIndex = 0; setSelection(doc, new Selection([ourRange], 0), sel_mouse); startSel = doc.sel; } else if (ourIndex == -1) { ourIndex = ranges.length; setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex), {scroll: false, origin: "*mouse"}); } else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) { setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0)); startSel = doc.sel; } else { replaceOneSelection(doc, ourIndex, ourRange, sel_mouse); } var lastPos = start; function extendTo(pos) { if (cmp(lastPos, pos) == 0) return; lastPos = pos; if (type == "rect") { var ranges = [], tabSize = cm.options.tabSize; var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize); var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize); var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol); for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line)); line <= end; line++) { var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize); if (left == right) ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); else if (text.length > leftPos) ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); } if (!ranges.length) ranges.push(new Range(start, start)); setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex), {origin: "*mouse", scroll: false}); cm.scrollIntoView(pos); } else { var oldRange = ourRange; var anchor = oldRange.anchor, head = pos; if (type != "single") { if (type == "double") var range = cm.findWordAt(pos); else var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0))); if (cmp(range.anchor, anchor) > 0) { head = range.head; anchor = minPos(oldRange.from(), range.anchor); } else { head = range.anchor; anchor = maxPos(oldRange.to(), range.head); } } var ranges = startSel.ranges.slice(0); ranges[ourIndex] = new Range(clipPos(doc, anchor), head); setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse); } } var editorSize = display.wrapper.getBoundingClientRect(); // Used to ensure timeout re-tries don't fire when another extend // happened in the meantime (clearTimeout isn't reliable -- at // least on Chrome, the timeouts still happen even when cleared, // if the clear happens after their scheduled firing time). var counter = 0; function extend(e) { var curCount = ++counter; var cur = posFromMouse(cm, e, true, type == "rect"); if (!cur) return; if (cmp(cur, lastPos) != 0) { cm.curOp.focus = activeElt(); extendTo(cur); var visible = visibleLines(display, doc); if (cur.line >= visible.to || cur.line < visible.from) setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150); } else { var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0; if (outside) setTimeout(operation(cm, function() { if (counter != curCount) return; display.scroller.scrollTop += outside; extend(e); }), 50); } } function done(e) { counter = Infinity; e_preventDefault(e); display.input.focus(); off(document, "mousemove", move); off(document, "mouseup", up); doc.history.lastSelOrigin = null; } var move = operation(cm, function(e) { if (!e_button(e)) done(e); else extend(e); }); var up = operation(cm, done); on(document, "mousemove", move); on(document, "mouseup", up); } // Determines whether an event happened in the gutter, and fires the // handlers for the corresponding event. function gutterEvent(cm, e, type, prevent, signalfn) { try { var mX = e.clientX, mY = e.clientY; } catch(e) { return false; } if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false; if (prevent) e_preventDefault(e); var display = cm.display; var lineBox = display.lineDiv.getBoundingClientRect(); if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e); mY -= lineBox.top - display.viewOffset; for (var i = 0; i < cm.options.gutters.length; ++i) { var g = display.gutters.childNodes[i]; if (g && g.getBoundingClientRect().right >= mX) { var line = lineAtHeight(cm.doc, mY); var gutter = cm.options.gutters[i]; signalfn(cm, type, cm, line, gutter, e); return e_defaultPrevented(e); } } } function clickInGutter(cm, e) { return gutterEvent(cm, e, "gutterClick", true, signalLater); } // Kludge to work around strange IE behavior where it'll sometimes // re-fire a series of drag-related events right after the drop (#1551) var lastDrop = 0; function onDrop(e) { var cm = this; if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; e_preventDefault(e); if (ie) lastDrop = +new Date; var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files; if (!pos || isReadOnly(cm)) return; // Might be a file drop, in which case we simply extract the text // and insert it. if (files && files.length && window.FileReader && window.File) { var n = files.length, text = Array(n), read = 0; var loadFile = function(file, i) { var reader = new FileReader; reader.onload = operation(cm, function() { text[i] = reader.result; if (++read == n) { pos = clipPos(cm.doc, pos); var change = {from: pos, to: pos, text: splitLines(text.join("\n")), origin: "paste"}; makeChange(cm.doc, change); setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))); } }); reader.readAsText(file); }; for (var i = 0; i < n; ++i) loadFile(files[i], i); } else { // Normal drop // Don't do a replace if the drop happened inside of the selected text. if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { cm.state.draggingText(e); // Ensure the editor is re-focused setTimeout(function() {cm.display.input.focus();}, 20); return; } try { var text = e.dataTransfer.getData("Text"); if (text) { if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey)) var selected = cm.listSelections(); setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)); if (selected) for (var i = 0; i < selected.length; ++i) replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag"); cm.replaceSelection(text, "around", "paste"); cm.display.input.focus(); } } catch(e){} } } function onDragStart(cm, e) { if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; } if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return; e.dataTransfer.setData("Text", cm.getSelection()); // Use dummy image instead of default browsers image. // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. if (e.dataTransfer.setDragImage && !safari) { var img = elt("img", null, null, "position: fixed; left: 0; top: 0;"); img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; if (presto) { img.width = img.height = 1; cm.display.wrapper.appendChild(img); // Force a relayout, or Opera won't use our image for some obscure reason img._top = img.offsetTop; } e.dataTransfer.setDragImage(img, 0, 0); if (presto) img.parentNode.removeChild(img); } } // SCROLL EVENTS // Sync the scrollable area and scrollbars, ensure the viewport // covers the visible area. function setScrollTop(cm, val) { if (Math.abs(cm.doc.scrollTop - val) < 2) return; cm.doc.scrollTop = val; if (!gecko) updateDisplaySimple(cm, {top: val}); if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val; cm.display.scrollbars.setScrollTop(val); if (gecko) updateDisplaySimple(cm); startWorker(cm, 100); } // Sync scroller and scrollbar, ensure the gutter elements are // aligned. function setScrollLeft(cm, val, isScroller) { if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return; val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth); cm.doc.scrollLeft = val; alignHorizontally(cm); if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val; cm.display.scrollbars.setScrollLeft(val); } // Since the delta values reported on mouse wheel events are // unstandardized between browsers and even browser versions, and // generally horribly unpredictable, this code starts by measuring // the scroll effect that the first few mouse wheel events have, // and, from that, detects the way it can convert deltas to pixel // offsets afterwards. // // The reason we want to know the amount a wheel event will scroll // is that it gives us a chance to update the display before the // actual scrolling happens, reducing flickering. var wheelSamples = 0, wheelPixelsPerUnit = null; // Fill in a browser-detected starting value on browsers where we // know one. These don't have to be accurate -- the result of them // being wrong would just be a slight flicker on the first wheel // scroll (if it is large enough). if (ie) wheelPixelsPerUnit = -.53; else if (gecko) wheelPixelsPerUnit = 15; else if (chrome) wheelPixelsPerUnit = -.7; else if (safari) wheelPixelsPerUnit = -1/3; var wheelEventDelta = function(e) { var dx = e.wheelDeltaX, dy = e.wheelDeltaY; if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail; if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail; else if (dy == null) dy = e.wheelDelta; return {x: dx, y: dy}; }; CodeMirror.wheelEventPixels = function(e) { var delta = wheelEventDelta(e); delta.x *= wheelPixelsPerUnit; delta.y *= wheelPixelsPerUnit; return delta; }; function onScrollWheel(cm, e) { var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y; var display = cm.display, scroll = display.scroller; // Quit if there's nothing to scroll here if (!(dx && scroll.scrollWidth > scroll.clientWidth || dy && scroll.scrollHeight > scroll.clientHeight)) return; // Webkit browsers on OS X abort momentum scrolls when the target // of the scroll event is removed from the scrollable element. // This hack (see related code in patchDisplay) makes sure the // element is kept around. if (dy && mac && webkit) { outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) { for (var i = 0; i < view.length; i++) { if (view[i].node == cur) { cm.display.currentWheelTarget = cur; break outer; } } } } // On some browsers, horizontal scrolling will cause redraws to // happen before the gutter has been realigned, causing it to // wriggle around in a most unseemly way. When we have an // estimated pixels/delta value, we just handle horizontal // scrolling entirely here. It'll be slightly off from native, but // better than glitching out. if (dx && !gecko && !presto && wheelPixelsPerUnit != null) { if (dy) setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight))); setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth))); e_preventDefault(e); display.wheelStartX = null; // Abort measurement, if in progress return; } // 'Project' the visible viewport to cover the area that is being // scrolled into view (if we know enough to estimate it). if (dy && wheelPixelsPerUnit != null) { var pixels = dy * wheelPixelsPerUnit; var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight; if (pixels < 0) top = Math.max(0, top + pixels - 50); else bot = Math.min(cm.doc.height, bot + pixels + 50); updateDisplaySimple(cm, {top: top, bottom: bot}); } if (wheelSamples < 20) { if (display.wheelStartX == null) { display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop; display.wheelDX = dx; display.wheelDY = dy; setTimeout(function() { if (display.wheelStartX == null) return; var movedX = scroll.scrollLeft - display.wheelStartX; var movedY = scroll.scrollTop - display.wheelStartY; var sample = (movedY && display.wheelDY && movedY / display.wheelDY) || (movedX && display.wheelDX && movedX / display.wheelDX); display.wheelStartX = display.wheelStartY = null; if (!sample) return; wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1); ++wheelSamples; }, 200); } else { display.wheelDX += dx; display.wheelDY += dy; } } } // KEY EVENTS // Run a handler that was bound to a key. function doHandleBinding(cm, bound, dropShift) { if (typeof bound == "string") { bound = commands[bound]; if (!bound) return false; } // Ensure previous input has been read, so that the handler sees a // consistent view of the document cm.display.input.ensurePolled(); var prevShift = cm.display.shift, done = false; try { if (isReadOnly(cm)) cm.state.suppressEdits = true; if (dropShift) cm.display.shift = false; done = bound(cm) != Pass; } finally { cm.display.shift = prevShift; cm.state.suppressEdits = false; } return done; } function lookupKeyForEditor(cm, name, handle) { for (var i = 0; i < cm.state.keyMaps.length; i++) { var result = lookupKey(name, cm.state.keyMaps[i], handle, cm); if (result) return result; } return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm)) || lookupKey(name, cm.options.keyMap, handle, cm); } var stopSeq = new Delayed; function dispatchKey(cm, name, e, handle) { var seq = cm.state.keySeq; if (seq) { if (isModifierKey(name)) return "handled"; stopSeq.set(50, function() { if (cm.state.keySeq == seq) { cm.state.keySeq = null; cm.display.input.reset(); } }); name = seq + " " + name; } var result = lookupKeyForEditor(cm, name, handle); if (result == "multi") cm.state.keySeq = name; if (result == "handled") signalLater(cm, "keyHandled", cm, name, e); if (result == "handled" || result == "multi") { e_preventDefault(e); restartBlink(cm); } if (seq && !result && /\'$/.test(name)) { e_preventDefault(e); return true; } return !!result; } // Handle a key from the keydown event. function handleKeyBinding(cm, e) { var name = keyName(e, true); if (!name) return false; if (e.shiftKey && !cm.state.keySeq) { // First try to resolve full name (including 'Shift-'). Failing // that, see if there is a cursor-motion command (starting with // 'go') bound to the keyname without 'Shift-'. return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);}) || dispatchKey(cm, name, e, function(b) { if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion) return doHandleBinding(cm, b); }); } else { return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); }); } } // Handle a key from the keypress event function handleCharBinding(cm, e, ch) { return dispatchKey(cm, "'" + ch + "'", e, function(b) { return doHandleBinding(cm, b, true); }); } var lastStoppedKey = null; function onKeyDown(e) { var cm = this; cm.curOp.focus = activeElt(); if (signalDOMEvent(cm, e)) return; // IE does strange things with escape. if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false; var code = e.keyCode; cm.display.shift = code == 16 || e.shiftKey; var handled = handleKeyBinding(cm, e); if (presto) { lastStoppedKey = handled ? code : null; // Opera has no cut event... we try to at least catch the key combo if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey)) cm.replaceSelection("", null, "cut"); } // Turn mouse into crosshair when Alt is held on Mac. if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className)) showCrossHair(cm); } function showCrossHair(cm) { var lineDiv = cm.display.lineDiv; addClass(lineDiv, "CodeMirror-crosshair"); function up(e) { if (e.keyCode == 18 || !e.altKey) { rmClass(lineDiv, "CodeMirror-crosshair"); off(document, "keyup", up); off(document, "mouseover", up); } } on(document, "keyup", up); on(document, "mouseover", up); } function onKeyUp(e) { if (e.keyCode == 16) this.doc.sel.shift = false; signalDOMEvent(this, e); } function onKeyPress(e) { var cm = this; if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return; var keyCode = e.keyCode, charCode = e.charCode; if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;} if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return; var ch = String.fromCharCode(charCode == null ? keyCode : charCode); if (handleCharBinding(cm, e, ch)) return; cm.display.input.onKeyPress(e); } // FOCUS/BLUR EVENTS function delayBlurEvent(cm) { cm.state.delayingBlurEvent = true; setTimeout(function() { if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; onBlur(cm); } }, 100); } function onFocus(cm) { if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false; if (cm.options.readOnly == "nocursor") return; if (!cm.state.focused) { signal(cm, "focus", cm); cm.state.focused = true; addClass(cm.display.wrapper, "CodeMirror-focused"); // This test prevents this from firing when a context // menu is closed (since the input reset would kill the // select-all detection hack) if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) { cm.display.input.reset(); if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730 } cm.display.input.receivedFocus(); } restartBlink(cm); } function onBlur(cm) { if (cm.state.delayingBlurEvent) return; if (cm.state.focused) { signal(cm, "blur", cm); cm.state.focused = false; rmClass(cm.display.wrapper, "CodeMirror-focused"); } clearInterval(cm.display.blinker); setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150); } // CONTEXT MENU HANDLING // To make the context menu work, we need to briefly unhide the // textarea (making it as unobtrusive as possible) to let the // right-click take effect on it. function onContextMenu(cm, e) { if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return; cm.display.input.onContextMenu(e); } function contextMenuInGutter(cm, e) { if (!hasHandler(cm, "gutterContextMenu")) return false; return gutterEvent(cm, e, "gutterContextMenu", false, signal); } // UPDATING // Compute the position of the end of a change (its 'to' property // refers to the pre-change end). var changeEnd = CodeMirror.changeEnd = function(change) { if (!change.text) return change.to; return Pos(change.from.line + change.text.length - 1, lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0)); }; // Adjust a position to refer to the post-change position of the // same text, or the end of the change if the change covers it. function adjustForChange(pos, change) { if (cmp(pos, change.from) < 0) return pos; if (cmp(pos, change.to) <= 0) return changeEnd(change); var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch; if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch; return Pos(line, ch); } function computeSelAfterChange(doc, change) { var out = []; for (var i = 0; i < doc.sel.ranges.length; i++) { var range = doc.sel.ranges[i]; out.push(new Range(adjustForChange(range.anchor, change), adjustForChange(range.head, change))); } return normalizeSelection(out, doc.sel.primIndex); } function offsetPos(pos, old, nw) { if (pos.line == old.line) return Pos(nw.line, pos.ch - old.ch + nw.ch); else return Pos(nw.line + (pos.line - old.line), pos.ch); } // Used by replaceSelections to allow moving the selection to the // start or around the replaced test. Hint may be "start" or "around". function computeReplacedSel(doc, changes, hint) { var out = []; var oldPrev = Pos(doc.first, 0), newPrev = oldPrev; for (var i = 0; i < changes.length; i++) { var change = changes[i]; var from = offsetPos(change.from, oldPrev, newPrev); var to = offsetPos(changeEnd(change), oldPrev, newPrev); oldPrev = change.to; newPrev = to; if (hint == "around") { var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0; out[i] = new Range(inv ? to : from, inv ? from : to); } else { out[i] = new Range(from, from); } } return new Selection(out, doc.sel.primIndex); } // Allow "beforeChange" event handlers to influence a change function filterChange(doc, change, update) { var obj = { canceled: false, from: change.from, to: change.to, text: change.text, origin: change.origin, cancel: function() { this.canceled = true; } }; if (update) obj.update = function(from, to, text, origin) { if (from) this.from = clipPos(doc, from); if (to) this.to = clipPos(doc, to); if (text) this.text = text; if (origin !== undefined) this.origin = origin; }; signal(doc, "beforeChange", doc, obj); if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj); if (obj.canceled) return null; return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}; } // Apply a change to a document, and add it to the document's // history, and propagating it to all linked documents. function makeChange(doc, change, ignoreReadOnly) { if (doc.cm) { if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly); if (doc.cm.state.suppressEdits) return; } if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) { change = filterChange(doc, change, true); if (!change) return; } // Possibly split or suppress the update based on the presence // of read-only spans in its range. var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to); if (split) { for (var i = split.length - 1; i >= 0; --i) makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text}); } else { makeChangeInner(doc, change); } } function makeChangeInner(doc, change) { if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return; var selAfter = computeSelAfterChange(doc, change); addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN); makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change)); var rebased = []; linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { rebaseHist(doc.history, change); rebased.push(doc.history); } makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change)); }); } // Revert a change stored in a document's history. function makeChangeFromHistory(doc, type, allowSelectionOnly) { if (doc.cm && doc.cm.state.suppressEdits) return; var hist = doc.history, event, selAfter = doc.sel; var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done; // Verify that there is a useable event (so that ctrl-z won't // needlessly clear selection events) for (var i = 0; i < source.length; i++) { event = source[i]; if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges) break; } if (i == source.length) return; hist.lastOrigin = hist.lastSelOrigin = null; for (;;) { event = source.pop(); if (event.ranges) { pushSelectionToHistory(event, dest); if (allowSelectionOnly && !event.equals(doc.sel)) { setSelection(doc, event, {clearRedo: false}); return; } selAfter = event; } else break; } // Build up a reverse change object to add to the opposite history // stack (redo when undoing, and vice versa). var antiChanges = []; pushSelectionToHistory(selAfter, dest); dest.push({changes: antiChanges, generation: hist.generation}); hist.generation = event.generation || ++hist.maxGeneration; var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange"); for (var i = event.changes.length - 1; i >= 0; --i) { var change = event.changes[i]; change.origin = type; if (filter && !filterChange(doc, change, false)) { source.length = 0; return; } antiChanges.push(historyChangeFromChange(doc, change)); var after = i ? computeSelAfterChange(doc, change) : lst(source); makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change)); if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); var rebased = []; // Propagate to the linked documents linkedDocs(doc, function(doc, sharedHist) { if (!sharedHist && indexOf(rebased, doc.history) == -1) { rebaseHist(doc.history, change); rebased.push(doc.history); } makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change)); }); } } // Sub-views need their line numbers shifted when text is added // above or below them in the parent document. function shiftDoc(doc, distance) { if (distance == 0) return; doc.first += distance; doc.sel = new Selection(map(doc.sel.ranges, function(range) { return new Range(Pos(range.anchor.line + distance, range.anchor.ch), Pos(range.head.line + distance, range.head.ch)); }), doc.sel.primIndex); if (doc.cm) { regChange(doc.cm, doc.first, doc.first - distance, distance); for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++) regLineChange(doc.cm, l, "gutter"); } } // More lower-level change function, handling only a single document // (not linked ones). function makeChangeSingleDoc(doc, change, selAfter, spans) { if (doc.cm && !doc.cm.curOp) return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans); if (change.to.line < doc.first) { shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line)); return; } if (change.from.line > doc.lastLine()) return; // Clip the change to the size of this doc if (change.from.line < doc.first) { var shift = change.text.length - 1 - (doc.first - change.from.line); shiftDoc(doc, shift); change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch), text: [lst(change.text)], origin: change.origin}; } var last = doc.lastLine(); if (change.to.line > last) { change = {from: change.from, to: Pos(last, getLine(doc, last).text.length), text: [change.text[0]], origin: change.origin}; } change.removed = getBetween(doc, change.from, change.to); if (!selAfter) selAfter = computeSelAfterChange(doc, change); if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans); else updateDoc(doc, change, spans); setSelectionNoUndo(doc, selAfter, sel_dontScroll); } // Handle the interaction of a change to a document with the editor // that this document is part of. function makeChangeSingleDocInEditor(cm, change, spans) { var doc = cm.doc, display = cm.display, from = change.from, to = change.to; var recomputeMaxLength = false, checkWidthStart = from.line; if (!cm.options.lineWrapping) { checkWidthStart = lineNo(visualLine(getLine(doc, from.line))); doc.iter(checkWidthStart, to.line + 1, function(line) { if (line == display.maxLine) { recomputeMaxLength = true; return true; } }); } if (doc.sel.contains(change.from, change.to) > -1) signalCursorActivity(cm); updateDoc(doc, change, spans, estimateHeight(cm)); if (!cm.options.lineWrapping) { doc.iter(checkWidthStart, from.line + change.text.length, function(line) { var len = lineLength(line); if (len > display.maxLineLength) { display.maxLine = line; display.maxLineLength = len; display.maxLineChanged = true; recomputeMaxLength = false; } }); if (recomputeMaxLength) cm.curOp.updateMaxLine = true; } // Adjust frontier, schedule worker doc.frontier = Math.min(doc.frontier, from.line); startWorker(cm, 400); var lendiff = change.text.length - (to.line - from.line) - 1; // Remember that these lines changed, for updating the display if (change.full) regChange(cm); else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change)) regLineChange(cm, from.line, "text"); else regChange(cm, from.line, to.line + 1, lendiff); var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change"); if (changeHandler || changesHandler) { var obj = { from: from, to: to, text: change.text, removed: change.removed, origin: change.origin }; if (changeHandler) signalLater(cm, "change", cm, obj); if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); } cm.display.selForContextMenu = null; } function replaceRange(doc, code, from, to, origin) { if (!to) to = from; if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; } if (typeof code == "string") code = splitLines(code); makeChange(doc, {from: from, to: to, text: code, origin: origin}); } // SCROLLING THINGS INTO VIEW // If an editor sits on the top or bottom of the window, partially // scrolled out of view, this ensures that the cursor is visible. function maybeScrollWindow(cm, coords) { if (signalDOMEvent(cm, "scrollCursorIntoView")) return; var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null; if (coords.top + box.top < 0) doScroll = true; else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false; if (doScroll != null && !phantom) { var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " + (coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " + (coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " + coords.left + "px; width: 2px;"); cm.display.lineSpace.appendChild(scrollNode); scrollNode.scrollIntoView(doScroll); cm.display.lineSpace.removeChild(scrollNode); } } // Scroll a given position into view (immediately), verifying that // it actually became visible (as line heights are accurately // measured, the position of something may 'drift' during drawing). function scrollPosIntoView(cm, pos, end, margin) { if (margin == null) margin = 0; for (var limit = 0; limit < 5; limit++) { var changed = false, coords = cursorCoords(cm, pos); var endCoords = !end || end == pos ? coords : cursorCoords(cm, end); var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left), Math.min(coords.top, endCoords.top) - margin, Math.max(coords.left, endCoords.left), Math.max(coords.bottom, endCoords.bottom) + margin); var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft; if (scrollPos.scrollTop != null) { setScrollTop(cm, scrollPos.scrollTop); if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true; } if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true; } if (!changed) break; } return coords; } // Scroll a given set of coordinates into view (immediately). function scrollIntoView(cm, x1, y1, x2, y2) { var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2); if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop); if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft); } // Calculate a new scroll position needed to scroll the given // rectangle into view. Returns an object with scrollTop and // scrollLeft properties. When these are undefined, the // vertical/horizontal position does not need to be adjusted. function calculateScrollPos(cm, x1, y1, x2, y2) { var display = cm.display, snapMargin = textHeight(cm.display); if (y1 < 0) y1 = 0; var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop; var screen = displayHeight(cm), result = {}; if (y2 - y1 > screen) y2 = y1 + screen; var docBottom = cm.doc.height + paddingVert(display); var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin; if (y1 < screentop) { result.scrollTop = atTop ? 0 : y1; } else if (y2 > screentop + screen) { var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen); if (newTop != screentop) result.scrollTop = newTop; } var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft; var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0); var tooWide = x2 - x1 > screenw; if (tooWide) x2 = x1 + screenw; if (x1 < 10) result.scrollLeft = 0; else if (x1 < screenleft) result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10)); else if (x2 > screenw + screenleft - 3) result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw; return result; } // Store a relative adjustment to the scroll position in the current // operation (to be applied when the operation finishes). function addToScrollPos(cm, left, top) { if (left != null || top != null) resolveScrollToPos(cm); if (left != null) cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left; if (top != null) cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top; } // Make sure that at the end of the operation the current cursor is // shown. function ensureCursorVisible(cm) { resolveScrollToPos(cm); var cur = cm.getCursor(), from = cur, to = cur; if (!cm.options.lineWrapping) { from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur; to = Pos(cur.line, cur.ch + 1); } cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true}; } // When an operation has its scrollToPos property set, and another // scroll action is applied before the end of the operation, this // 'simulates' scrolling that position into view in a cheap way, so // that the effect of intermediate scroll commands is not ignored. function resolveScrollToPos(cm) { var range = cm.curOp.scrollToPos; if (range) { cm.curOp.scrollToPos = null; var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to); var sPos = calculateScrollPos(cm, Math.min(from.left, to.left), Math.min(from.top, to.top) - range.margin, Math.max(from.right, to.right), Math.max(from.bottom, to.bottom) + range.margin); cm.scrollTo(sPos.scrollLeft, sPos.scrollTop); } } // API UTILITIES // Indent the given line. The how parameter can be "smart", // "add"/null, "subtract", or "prev". When aggressive is false // (typically set to true for forced single-line indents), empty // lines are not indented, and places where the mode returns Pass // are left alone. function indentLine(cm, n, how, aggressive) { var doc = cm.doc, state; if (how == null) how = "add"; if (how == "smart") { // Fall back to "prev" when the mode doesn't have an indentation // method. if (!doc.mode.indent) how = "prev"; else state = getStateBefore(cm, n); } var tabSize = cm.options.tabSize; var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize); if (line.stateAfter) line.stateAfter = null; var curSpaceString = line.text.match(/^\s*/)[0], indentation; if (!aggressive && !/\S/.test(line.text)) { indentation = 0; how = "not"; } else if (how == "smart") { indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text); if (indentation == Pass || indentation > 150) { if (!aggressive) return; how = "prev"; } } if (how == "prev") { if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize); else indentation = 0; } else if (how == "add") { indentation = curSpace + cm.options.indentUnit; } else if (how == "subtract") { indentation = curSpace - cm.options.indentUnit; } else if (typeof how == "number") { indentation = curSpace + how; } indentation = Math.max(0, indentation); var indentString = "", pos = 0; if (cm.options.indentWithTabs) for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} if (pos < indentation) indentString += spaceStr(indentation - pos); if (indentString != curSpaceString) { replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input"); line.stateAfter = null; return true; } else { // Ensure that, if the cursor was in the whitespace at the start // of the line, it is moved to the end of that space. for (var i = 0; i < doc.sel.ranges.length; i++) { var range = doc.sel.ranges[i]; if (range.head.line == n && range.head.ch < curSpaceString.length) { var pos = Pos(n, curSpaceString.length); replaceOneSelection(doc, i, new Range(pos, pos)); break; } } } } // Utility for applying a change to a line by handle or number, // returning the number and optionally registering the line as // changed. function changeLine(doc, handle, changeType, op) { var no = handle, line = handle; if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle)); else no = lineNo(handle); if (no == null) return null; if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType); return line; } // Helper for deleting text near the selection(s), used to implement // backspace, delete, and similar functionality. function deleteNearSelection(cm, compute) { var ranges = cm.doc.sel.ranges, kill = []; // Build up a set of ranges to kill first, merging overlapping // ranges. for (var i = 0; i < ranges.length; i++) { var toKill = compute(ranges[i]); while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) { var replaced = kill.pop(); if (cmp(replaced.from, toKill.from) < 0) { toKill.from = replaced.from; break; } } kill.push(toKill); } // Next, remove those actual ranges. runInOp(cm, function() { for (var i = kill.length - 1; i >= 0; i--) replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); ensureCursorVisible(cm); }); } // Used for horizontal relative motion. Dir is -1 or 1 (left or // right), unit can be "char", "column" (like char, but doesn't // cross line boundaries), "word" (across next word), or "group" (to // the start of next group of word or non-word-non-whitespace // chars). The visually param controls whether, in right-to-left // text, direction 1 means to move towards the next index in the // string, or towards the character to the right of the current // position. The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosH(doc, pos, dir, unit, visually) { var line = pos.line, ch = pos.ch, origDir = dir; var lineObj = getLine(doc, line); var possible = true; function findNextLine() { var l = line + dir; if (l < doc.first || l >= doc.first + doc.size) return (possible = false); line = l; return lineObj = getLine(doc, l); } function moveOnce(boundToLine) { var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true); if (next == null) { if (!boundToLine && findNextLine()) { if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj); else ch = dir < 0 ? lineObj.text.length : 0; } else return (possible = false); } else ch = next; return true; } if (unit == "char") moveOnce(); else if (unit == "column") moveOnce(true); else if (unit == "word" || unit == "group") { var sawType = null, group = unit == "group"; var helper = doc.cm && doc.cm.getHelper(pos, "wordChars"); for (var first = true;; first = false) { if (dir < 0 && !moveOnce(!first)) break; var cur = lineObj.text.charAt(ch) || "\n"; var type = isWordChar(cur, helper) ? "w" : group && cur == "\n" ? "n" : !group || /\s/.test(cur) ? null : "p"; if (group && !first && !type) type = "s"; if (sawType && sawType != type) { if (dir < 0) {dir = 1; moveOnce();} break; } if (type) sawType = type; if (dir > 0 && !moveOnce(!first)) break; } } var result = skipAtomic(doc, Pos(line, ch), origDir, true); if (!possible) result.hitSide = true; return result; } // For relative vertical movement. Dir may be -1 or 1. Unit can be // "page" or "line". The resulting position will have a hitSide=true // property if it reached the end of the document. function findPosV(cm, pos, dir, unit) { var doc = cm.doc, x = pos.left, y; if (unit == "page") { var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight); y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display)); } else if (unit == "line") { y = dir > 0 ? pos.bottom + 3 : pos.top - 3; } for (;;) { var target = coordsChar(cm, x, y); if (!target.outside) break; if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; } y += dir * 5; } return target; } // EDITOR METHODS // The publicly visible API. Note that methodOp(f) means // 'wrap f in an operation, performed on its `this` parameter'. // This is not the complete set of editor methods. Most of the // methods defined on the Doc type are also injected into // CodeMirror.prototype, for backwards compatibility and // convenience. CodeMirror.prototype = { constructor: CodeMirror, focus: function(){window.focus(); this.display.input.focus();}, setOption: function(option, value) { var options = this.options, old = options[option]; if (options[option] == value && option != "mode") return; options[option] = value; if (optionHandlers.hasOwnProperty(option)) operation(this, optionHandlers[option])(this, value, old); }, getOption: function(option) {return this.options[option];}, getDoc: function() {return this.doc;}, addKeyMap: function(map, bottom) { this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map)); }, removeKeyMap: function(map) { var maps = this.state.keyMaps; for (var i = 0; i < maps.length; ++i) if (maps[i] == map || maps[i].name == map) { maps.splice(i, 1); return true; } }, addOverlay: methodOp(function(spec, options) { var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec); if (mode.startState) throw new Error("Overlays may not be stateful."); this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque}); this.state.modeGen++; regChange(this); }), removeOverlay: methodOp(function(spec) { var overlays = this.state.overlays; for (var i = 0; i < overlays.length; ++i) { var cur = overlays[i].modeSpec; if (cur == spec || typeof spec == "string" && cur.name == spec) { overlays.splice(i, 1); this.state.modeGen++; regChange(this); return; } } }), indentLine: methodOp(function(n, dir, aggressive) { if (typeof dir != "string" && typeof dir != "number") { if (dir == null) dir = this.options.smartIndent ? "smart" : "prev"; else dir = dir ? "add" : "subtract"; } if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive); }), indentSelection: methodOp(function(how) { var ranges = this.doc.sel.ranges, end = -1; for (var i = 0; i < ranges.length; i++) { var range = ranges[i]; if (!range.empty()) { var from = range.from(), to = range.to(); var start = Math.max(end, from.line); end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1; for (var j = start; j < end; ++j) indentLine(this, j, how); var newRanges = this.doc.sel.ranges; if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0) replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); } else if (range.head.line > end) { indentLine(this, range.head.line, how, true); end = range.head.line; if (i == this.doc.sel.primIndex) ensureCursorVisible(this); } } }), // Fetch the parser token for a given character. Useful for hacks // that want to inspect the mode state (say, for completion). getTokenAt: function(pos, precise) { return takeToken(this, pos, precise); }, getLineTokens: function(line, precise) { return takeToken(this, Pos(line), precise, true); }, getTokenTypeAt: function(pos) { pos = clipPos(this.doc, pos); var styles = getLineStyles(this, getLine(this.doc, pos.line)); var before = 0, after = (styles.length - 1) / 2, ch = pos.ch; var type; if (ch == 0) type = styles[2]; else for (;;) { var mid = (before + after) >> 1; if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid; else if (styles[mid * 2 + 1] < ch) before = mid + 1; else { type = styles[mid * 2 + 2]; break; } } var cut = type ? type.indexOf("cm-overlay ") : -1; return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1); }, getModeAt: function(pos) { var mode = this.doc.mode; if (!mode.innerMode) return mode; return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode; }, getHelper: function(pos, type) { return this.getHelpers(pos, type)[0]; }, getHelpers: function(pos, type) { var found = []; if (!helpers.hasOwnProperty(type)) return found; var help = helpers[type], mode = this.getModeAt(pos); if (typeof mode[type] == "string") { if (help[mode[type]]) found.push(help[mode[type]]); } else if (mode[type]) { for (var i = 0; i < mode[type].length; i++) { var val = help[mode[type][i]]; if (val) found.push(val); } } else if (mode.helperType && help[mode.helperType]) { found.push(help[mode.helperType]); } else if (help[mode.name]) { found.push(help[mode.name]); } for (var i = 0; i < help._global.length; i++) { var cur = help._global[i]; if (cur.pred(mode, this) && indexOf(found, cur.val) == -1) found.push(cur.val); } return found; }, getStateAfter: function(line, precise) { var doc = this.doc; line = clipLine(doc, line == null ? doc.first + doc.size - 1: line); return getStateBefore(this, line + 1, precise); }, cursorCoords: function(start, mode) { var pos, range = this.doc.sel.primary(); if (start == null) pos = range.head; else if (typeof start == "object") pos = clipPos(this.doc, start); else pos = start ? range.from() : range.to(); return cursorCoords(this, pos, mode || "page"); }, charCoords: function(pos, mode) { return charCoords(this, clipPos(this.doc, pos), mode || "page"); }, coordsChar: function(coords, mode) { coords = fromCoordSystem(this, coords, mode || "page"); return coordsChar(this, coords.left, coords.top); }, lineAtHeight: function(height, mode) { height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top; return lineAtHeight(this.doc, height + this.display.viewOffset); }, heightAtLine: function(line, mode) { var end = false, lineObj; if (typeof line == "number") { var last = this.doc.first + this.doc.size - 1; if (line < this.doc.first) line = this.doc.first; else if (line > last) { line = last; end = true; } lineObj = getLine(this.doc, line); } else { lineObj = line; } return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top + (end ? this.doc.height - heightAtLine(lineObj) : 0); }, defaultTextHeight: function() { return textHeight(this.display); }, defaultCharWidth: function() { return charWidth(this.display); }, setGutterMarker: methodOp(function(line, gutterID, value) { return changeLine(this.doc, line, "gutter", function(line) { var markers = line.gutterMarkers || (line.gutterMarkers = {}); markers[gutterID] = value; if (!value && isEmpty(markers)) line.gutterMarkers = null; return true; }); }), clearGutter: methodOp(function(gutterID) { var cm = this, doc = cm.doc, i = doc.first; doc.iter(function(line) { if (line.gutterMarkers && line.gutterMarkers[gutterID]) { line.gutterMarkers[gutterID] = null; regLineChange(cm, i, "gutter"); if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null; } ++i; }); }), lineInfo: function(line) { if (typeof line == "number") { if (!isLine(this.doc, line)) return null; var n = line; line = getLine(this.doc, line); if (!line) return null; } else { var n = lineNo(line); if (n == null) return null; } return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers, textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass, widgets: line.widgets}; }, getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};}, addWidget: function(pos, node, scroll, vert, horiz) { var display = this.display; pos = cursorCoords(this, clipPos(this.doc, pos)); var top = pos.bottom, left = pos.left; node.style.position = "absolute"; node.setAttribute("cm-ignore-events", "true"); this.display.input.setUneditable(node); display.sizer.appendChild(node); if (vert == "over") { top = pos.top; } else if (vert == "above" || vert == "near") { var vspace = Math.max(display.wrapper.clientHeight, this.doc.height), hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth); // Default to positioning above (if specified and possible); otherwise default to positioning below if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight) top = pos.top - node.offsetHeight; else if (pos.bottom + node.offsetHeight <= vspace) top = pos.bottom; if (left + node.offsetWidth > hspace) left = hspace - node.offsetWidth; } node.style.top = top + "px"; node.style.left = node.style.right = ""; if (horiz == "right") { left = display.sizer.clientWidth - node.offsetWidth; node.style.right = "0px"; } else { if (horiz == "left") left = 0; else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2; node.style.left = left + "px"; } if (scroll) scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight); }, triggerOnKeyDown: methodOp(onKeyDown), triggerOnKeyPress: methodOp(onKeyPress), triggerOnKeyUp: onKeyUp, execCommand: function(cmd) { if (commands.hasOwnProperty(cmd)) return commands[cmd](this); }, triggerElectric: methodOp(function(text) { triggerElectric(this, text); }), findPosH: function(from, amount, unit, visually) { var dir = 1; if (amount < 0) { dir = -1; amount = -amount; } for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { cur = findPosH(this.doc, cur, dir, unit, visually); if (cur.hitSide) break; } return cur; }, moveH: methodOp(function(dir, unit) { var cm = this; cm.extendSelectionsBy(function(range) { if (cm.display.shift || cm.doc.extend || range.empty()) return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually); else return dir < 0 ? range.from() : range.to(); }, sel_move); }), deleteH: methodOp(function(dir, unit) { var sel = this.doc.sel, doc = this.doc; if (sel.somethingSelected()) doc.replaceSelection("", null, "+delete"); else deleteNearSelection(this, function(range) { var other = findPosH(doc, range.head, dir, unit, false); return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other}; }); }), findPosV: function(from, amount, unit, goalColumn) { var dir = 1, x = goalColumn; if (amount < 0) { dir = -1; amount = -amount; } for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) { var coords = cursorCoords(this, cur, "div"); if (x == null) x = coords.left; else coords.left = x; cur = findPosV(this, coords, dir, unit); if (cur.hitSide) break; } return cur; }, moveV: methodOp(function(dir, unit) { var cm = this, doc = this.doc, goals = []; var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected(); doc.extendSelectionsBy(function(range) { if (collapse) return dir < 0 ? range.from() : range.to(); var headPos = cursorCoords(cm, range.head, "div"); if (range.goalColumn != null) headPos.left = range.goalColumn; goals.push(headPos.left); var pos = findPosV(cm, headPos, dir, unit); if (unit == "page" && range == doc.sel.primary()) addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top); return pos; }, sel_move); if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++) doc.sel.ranges[i].goalColumn = goals[i]; }), // Find the word at the given position (as returned by coordsChar). findWordAt: function(pos) { var doc = this.doc, line = getLine(doc, pos.line).text; var start = pos.ch, end = pos.ch; if (line) { var helper = this.getHelper(pos, "wordChars"); if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end; var startChar = line.charAt(start); var check = isWordChar(startChar, helper) ? function(ch) { return isWordChar(ch, helper); } : /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);} : function(ch) {return !/\s/.test(ch) && !isWordChar(ch);}; while (start > 0 && check(line.charAt(start - 1))) --start; while (end < line.length && check(line.charAt(end))) ++end; } return new Range(Pos(pos.line, start), Pos(pos.line, end)); }, toggleOverwrite: function(value) { if (value != null && value == this.state.overwrite) return; if (this.state.overwrite = !this.state.overwrite) addClass(this.display.cursorDiv, "CodeMirror-overwrite"); else rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); signal(this, "overwriteToggle", this, this.state.overwrite); }, hasFocus: function() { return this.display.input.getField() == activeElt(); }, scrollTo: methodOp(function(x, y) { if (x != null || y != null) resolveScrollToPos(this); if (x != null) this.curOp.scrollLeft = x; if (y != null) this.curOp.scrollTop = y; }), getScrollInfo: function() { var scroller = this.display.scroller; return {left: scroller.scrollLeft, top: scroller.scrollTop, height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight, width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth, clientHeight: displayHeight(this), clientWidth: displayWidth(this)}; }, scrollIntoView: methodOp(function(range, margin) { if (range == null) { range = {from: this.doc.sel.primary().head, to: null}; if (margin == null) margin = this.options.cursorScrollMargin; } else if (typeof range == "number") { range = {from: Pos(range, 0), to: null}; } else if (range.from == null) { range = {from: range, to: null}; } if (!range.to) range.to = range.from; range.margin = margin || 0; if (range.from.line != null) { resolveScrollToPos(this); this.curOp.scrollToPos = range; } else { var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left), Math.min(range.from.top, range.to.top) - range.margin, Math.max(range.from.right, range.to.right), Math.max(range.from.bottom, range.to.bottom) + range.margin); this.scrollTo(sPos.scrollLeft, sPos.scrollTop); } }), setSize: methodOp(function(width, height) { var cm = this; function interpret(val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; } if (width != null) cm.display.wrapper.style.width = interpret(width); if (height != null) cm.display.wrapper.style.height = interpret(height); if (cm.options.lineWrapping) clearLineMeasurementCache(this); var lineNo = cm.display.viewFrom; cm.doc.iter(lineNo, cm.display.viewTo, function(line) { if (line.widgets) for (var i = 0; i < line.widgets.length; i++) if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; } ++lineNo; }); cm.curOp.forceUpdate = true; signal(cm, "refresh", this); }), operation: function(f){return runInOp(this, f);}, refresh: methodOp(function() { var oldHeight = this.display.cachedTextHeight; regChange(this); this.curOp.forceUpdate = true; clearCaches(this); this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop); updateGutterSpace(this); if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5) estimateLineHeights(this); signal(this, "refresh", this); }), swapDoc: methodOp(function(doc) { var old = this.doc; old.cm = null; attachDoc(this, doc); clearCaches(this); this.display.input.reset(); this.scrollTo(doc.scrollLeft, doc.scrollTop); this.curOp.forceScroll = true; signalLater(this, "swapDoc", this, old); return old; }), getInputField: function(){return this.display.input.getField();}, getWrapperElement: function(){return this.display.wrapper;}, getScrollerElement: function(){return this.display.scroller;}, getGutterElement: function(){return this.display.gutters;} }; eventMixin(CodeMirror); // OPTION DEFAULTS // The default configuration options. var defaults = CodeMirror.defaults = {}; // Functions to run when options are changed. var optionHandlers = CodeMirror.optionHandlers = {}; function option(name, deflt, handle, notOnInit) { CodeMirror.defaults[name] = deflt; if (handle) optionHandlers[name] = notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle; } // Passed to option handlers when there is no old value. var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}}; // These two are, on init, called from the constructor because they // have to be initialized before the editor can start at all. option("value", "", function(cm, val) { cm.setValue(val); }, true); option("mode", null, function(cm, val) { cm.doc.modeOption = val; loadMode(cm); }, true); option("indentUnit", 2, loadMode, true); option("indentWithTabs", false); option("smartIndent", true); option("tabSize", 4, function(cm) { resetModeState(cm); clearCaches(cm); regChange(cm); }, true); option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) { cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g"); if (old != CodeMirror.Init) cm.refresh(); }); option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true); option("electricChars", true); option("inputStyle", mobile ? "contenteditable" : "textarea", function() { throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME }, true); option("rtlMoveVisually", !windows); option("wholeLineUpdateBefore", true); option("theme", "default", function(cm) { themeChanged(cm); guttersChanged(cm); }, true); option("keyMap", "default", function(cm, val, old) { var next = getKeyMap(val); var prev = old != CodeMirror.Init && getKeyMap(old); if (prev && prev.detach) prev.detach(cm, next); if (next.attach) next.attach(cm, prev || null); }); option("extraKeys", null); option("lineWrapping", false, wrappingChanged, true); option("gutters", [], function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); }, true); option("fixedGutter", true, function(cm, val) { cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0"; cm.refresh(); }, true); option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true); option("scrollbarStyle", "native", function(cm) { initScrollbars(cm); updateScrollbars(cm); cm.display.scrollbars.setScrollTop(cm.doc.scrollTop); cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft); }, true); option("lineNumbers", false, function(cm) { setGuttersForLineNumbers(cm.options); guttersChanged(cm); }, true); option("firstLineNumber", 1, guttersChanged, true); option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true); option("showCursorWhenSelecting", false, updateSelection, true); option("resetSelectionOnContextMenu", true); option("lineWiseCopyCut", true); option("readOnly", false, function(cm, val) { if (val == "nocursor") { onBlur(cm); cm.display.input.blur(); cm.display.disabled = true; } else { cm.display.disabled = false; if (!val) cm.display.input.reset(); } }); option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true); option("dragDrop", true, dragDropChanged); option("cursorBlinkRate", 530); option("cursorScrollMargin", 0); option("cursorHeight", 1, updateSelection, true); option("singleCursorHeightPerLine", true, updateSelection, true); option("workTime", 100); option("workDelay", 100); option("flattenSpans", true, resetModeState, true); option("addModeClass", false, resetModeState, true); option("pollInterval", 100); option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;}); option("historyEventDelay", 1250); option("viewportMargin", 10, function(cm){cm.refresh();}, true); option("maxHighlightLength", 10000, resetModeState, true); option("moveInputWithCursor", true, function(cm, val) { if (!val) cm.display.input.resetPosition(); }); option("tabindex", null, function(cm, val) { cm.display.input.getField().tabIndex = val || ""; }); option("autofocus", null); // MODE DEFINITION AND QUERYING // Known modes, by name and by MIME var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {}; // Extra arguments are stored as the mode's dependencies, which is // used by (legacy) mechanisms like loadmode.js to automatically // load a mode. (Preferred mechanism is the require/define calls.) CodeMirror.defineMode = function(name, mode) { if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name; if (arguments.length > 2) mode.dependencies = Array.prototype.slice.call(arguments, 2); modes[name] = mode; }; CodeMirror.defineMIME = function(mime, spec) { mimeModes[mime] = spec; }; // Given a MIME type, a {name, ...options} config object, or a name // string, return a mode config object. CodeMirror.resolveMode = function(spec) { if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { spec = mimeModes[spec]; } else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { var found = mimeModes[spec.name]; if (typeof found == "string") found = {name: found}; spec = createObj(found, spec); spec.name = found.name; } else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { return CodeMirror.resolveMode("application/xml"); } if (typeof spec == "string") return {name: spec}; else return spec || {name: "null"}; }; // Given a mode spec (anything that resolveMode accepts), find and // initialize an actual mode object. CodeMirror.getMode = function(options, spec) { var spec = CodeMirror.resolveMode(spec); var mfactory = modes[spec.name]; if (!mfactory) return CodeMirror.getMode(options, "text/plain"); var modeObj = mfactory(options, spec); if (modeExtensions.hasOwnProperty(spec.name)) { var exts = modeExtensions[spec.name]; for (var prop in exts) { if (!exts.hasOwnProperty(prop)) continue; if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop]; modeObj[prop] = exts[prop]; } } modeObj.name = spec.name; if (spec.helperType) modeObj.helperType = spec.helperType; if (spec.modeProps) for (var prop in spec.modeProps) modeObj[prop] = spec.modeProps[prop]; return modeObj; }; // Minimal default mode. CodeMirror.defineMode("null", function() { return {token: function(stream) {stream.skipToEnd();}}; }); CodeMirror.defineMIME("text/plain", "null"); // This can be used to attach properties to mode objects from // outside the actual mode definition. var modeExtensions = CodeMirror.modeExtensions = {}; CodeMirror.extendMode = function(mode, properties) { var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); copyObj(properties, exts); }; // EXTENSIONS CodeMirror.defineExtension = function(name, func) { CodeMirror.prototype[name] = func; }; CodeMirror.defineDocExtension = function(name, func) { Doc.prototype[name] = func; }; CodeMirror.defineOption = option; var initHooks = []; CodeMirror.defineInitHook = function(f) {initHooks.push(f);}; var helpers = CodeMirror.helpers = {}; CodeMirror.registerHelper = function(type, name, value) { if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []}; helpers[type][name] = value; }; CodeMirror.registerGlobalHelper = function(type, name, predicate, value) { CodeMirror.registerHelper(type, name, value); helpers[type]._global.push({pred: predicate, val: value}); }; // MODE STATE HANDLING // Utility functions for working with state. Exported because nested // modes need to do this for their inner modes. var copyState = CodeMirror.copyState = function(mode, state) { if (state === true) return state; if (mode.copyState) return mode.copyState(state); var nstate = {}; for (var n in state) { var val = state[n]; if (val instanceof Array) val = val.concat([]); nstate[n] = val; } return nstate; }; var startState = CodeMirror.startState = function(mode, a1, a2) { return mode.startState ? mode.startState(a1, a2) : true; }; // Given a mode and a state (for that mode), find the inner mode and // state at the position that the state refers to. CodeMirror.innerMode = function(mode, state) { while (mode.innerMode) { var info = mode.innerMode(state); if (!info || info.mode == mode) break; state = info.state; mode = info.mode; } return info || {mode: mode, state: state}; }; // STANDARD COMMANDS // Commands are parameter-less actions that can be performed on an // editor, mostly used for keybindings. var commands = CodeMirror.commands = { selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);}, singleSelection: function(cm) { cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); }, killLine: function(cm) { deleteNearSelection(cm, function(range) { if (range.empty()) { var len = getLine(cm.doc, range.head.line).text.length; if (range.head.ch == len && range.head.line < cm.lastLine()) return {from: range.head, to: Pos(range.head.line + 1, 0)}; else return {from: range.head, to: Pos(range.head.line, len)}; } else { return {from: range.from(), to: range.to()}; } }); }, deleteLine: function(cm) { deleteNearSelection(cm, function(range) { return {from: Pos(range.from().line, 0), to: clipPos(cm.doc, Pos(range.to().line + 1, 0))}; }); }, delLineLeft: function(cm) { deleteNearSelection(cm, function(range) { return {from: Pos(range.from().line, 0), to: range.from()}; }); }, delWrappedLineLeft: function(cm) { deleteNearSelection(cm, function(range) { var top = cm.charCoords(range.head, "div").top + 5; var leftPos = cm.coordsChar({left: 0, top: top}, "div"); return {from: leftPos, to: range.from()}; }); }, delWrappedLineRight: function(cm) { deleteNearSelection(cm, function(range) { var top = cm.charCoords(range.head, "div").top + 5; var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); return {from: range.from(), to: rightPos }; }); }, undo: function(cm) {cm.undo();}, redo: function(cm) {cm.redo();}, undoSelection: function(cm) {cm.undoSelection();}, redoSelection: function(cm) {cm.redoSelection();}, goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));}, goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));}, goLineStart: function(cm) { cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); }, {origin: "+move", bias: 1}); }, goLineStartSmart: function(cm) { cm.extendSelectionsBy(function(range) { return lineStartSmart(cm, range.head); }, {origin: "+move", bias: 1}); }, goLineEnd: function(cm) { cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); }, {origin: "+move", bias: -1}); }, goLineRight: function(cm) { cm.extendSelectionsBy(function(range) { var top = cm.charCoords(range.head, "div").top + 5; return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div"); }, sel_move); }, goLineLeft: function(cm) { cm.extendSelectionsBy(function(range) { var top = cm.charCoords(range.head, "div").top + 5; return cm.coordsChar({left: 0, top: top}, "div"); }, sel_move); }, goLineLeftSmart: function(cm) { cm.extendSelectionsBy(function(range) { var top = cm.charCoords(range.head, "div").top + 5; var pos = cm.coordsChar({left: 0, top: top}, "div"); if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head); return pos; }, sel_move); }, goLineUp: function(cm) {cm.moveV(-1, "line");}, goLineDown: function(cm) {cm.moveV(1, "line");}, goPageUp: function(cm) {cm.moveV(-1, "page");}, goPageDown: function(cm) {cm.moveV(1, "page");}, goCharLeft: function(cm) {cm.moveH(-1, "char");}, goCharRight: function(cm) {cm.moveH(1, "char");}, goColumnLeft: function(cm) {cm.moveH(-1, "column");}, goColumnRight: function(cm) {cm.moveH(1, "column");}, goWordLeft: function(cm) {cm.moveH(-1, "word");}, goGroupRight: function(cm) {cm.moveH(1, "group");}, goGroupLeft: function(cm) {cm.moveH(-1, "group");}, goWordRight: function(cm) {cm.moveH(1, "word");}, delCharBefore: function(cm) {cm.deleteH(-1, "char");}, delCharAfter: function(cm) {cm.deleteH(1, "char");}, delWordBefore: function(cm) {cm.deleteH(-1, "word");}, delWordAfter: function(cm) {cm.deleteH(1, "word");}, delGroupBefore: function(cm) {cm.deleteH(-1, "group");}, delGroupAfter: function(cm) {cm.deleteH(1, "group");}, indentAuto: function(cm) {cm.indentSelection("smart");}, indentMore: function(cm) {cm.indentSelection("add");}, indentLess: function(cm) {cm.indentSelection("subtract");}, insertTab: function(cm) {cm.replaceSelection("\t");}, insertSoftTab: function(cm) { var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize; for (var i = 0; i < ranges.length; i++) { var pos = ranges[i].from(); var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize); spaces.push(new Array(tabSize - col % tabSize + 1).join(" ")); } cm.replaceSelections(spaces); }, defaultTab: function(cm) { if (cm.somethingSelected()) cm.indentSelection("add"); else cm.execCommand("insertTab"); }, transposeChars: function(cm) { runInOp(cm, function() { var ranges = cm.listSelections(), newSel = []; for (var i = 0; i < ranges.length; i++) { var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text; if (line) { if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1); if (cur.ch > 0) { cur = new Pos(cur.line, cur.ch + 1); cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2), Pos(cur.line, cur.ch - 2), cur, "+transpose"); } else if (cur.line > cm.doc.first) { var prev = getLine(cm.doc, cur.line - 1).text; if (prev) cm.replaceRange(line.charAt(0) + "\n" + prev.charAt(prev.length - 1), Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose"); } } newSel.push(new Range(cur, cur)); } cm.setSelections(newSel); }); }, newlineAndIndent: function(cm) { runInOp(cm, function() { var len = cm.listSelections().length; for (var i = 0; i < len; i++) { var range = cm.listSelections()[i]; cm.replaceRange("\n", range.anchor, range.head, "+input"); cm.indentLine(range.from().line + 1, null, true); ensureCursorVisible(cm); } }); }, toggleOverwrite: function(cm) {cm.toggleOverwrite();} }; // STANDARD KEYMAPS var keyMap = CodeMirror.keyMap = {}; keyMap.basic = { "Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown", "End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown", "Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore", "Tab": "defaultTab", "Shift-Tab": "indentAuto", "Enter": "newlineAndIndent", "Insert": "toggleOverwrite", "Esc": "singleSelection" }; // Note that the save and find-related commands aren't defined by // default. User code or addons can define them. Unknown commands // are simply ignored. keyMap.pcDefault = { "Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo", "Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown", "Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd", "Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find", "Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll", "Ctrl-[": "indentLess", "Ctrl-]": "indentMore", "Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection", fallthrough: "basic" }; // Very basic readline/emacs-style bindings, which are standard on Mac. keyMap.emacsy = { "Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown", "Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd", "Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore", "Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars" }; keyMap.macDefault = { "Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo", "Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft", "Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore", "Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find", "Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll", "Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight", "Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd", fallthrough: ["basic", "emacsy"] }; keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault; // KEYMAP DISPATCH function normalizeKeyName(name) { var parts = name.split(/-(?!$)/), name = parts[parts.length - 1]; var alt, ctrl, shift, cmd; for (var i = 0; i < parts.length - 1; i++) { var mod = parts[i]; if (/^(cmd|meta|m)$/i.test(mod)) cmd = true; else if (/^a(lt)?$/i.test(mod)) alt = true; else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true; else if (/^s(hift)$/i.test(mod)) shift = true; else throw new Error("Unrecognized modifier name: " + mod); } if (alt) name = "Alt-" + name; if (ctrl) name = "Ctrl-" + name; if (cmd) name = "Cmd-" + name; if (shift) name = "Shift-" + name; return name; } // This is a kludge to keep keymaps mostly working as raw objects // (backwards compatibility) while at the same time support features // like normalization and multi-stroke key bindings. It compiles a // new normalized keymap, and then updates the old object to reflect // this. CodeMirror.normalizeKeyMap = function(keymap) { var copy = {}; for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) { var value = keymap[keyname]; if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue; if (value == "...") { delete keymap[keyname]; continue; } var keys = map(keyname.split(" "), normalizeKeyName); for (var i = 0; i < keys.length; i++) { var val, name; if (i == keys.length - 1) { name = keys.join(" "); val = value; } else { name = keys.slice(0, i + 1).join(" "); val = "..."; } var prev = copy[name]; if (!prev) copy[name] = val; else if (prev != val) throw new Error("Inconsistent bindings for " + name); } delete keymap[keyname]; } for (var prop in copy) keymap[prop] = copy[prop]; return keymap; }; var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) { map = getKeyMap(map); var found = map.call ? map.call(key, context) : map[key]; if (found === false) return "nothing"; if (found === "...") return "multi"; if (found != null && handle(found)) return "handled"; if (map.fallthrough) { if (Object.prototype.toString.call(map.fallthrough) != "[object Array]") return lookupKey(key, map.fallthrough, handle, context); for (var i = 0; i < map.fallthrough.length; i++) { var result = lookupKey(key, map.fallthrough[i], handle, context); if (result) return result; } } }; // Modifier key presses don't count as 'real' key presses for the // purpose of keymap fallthrough. var isModifierKey = CodeMirror.isModifierKey = function(value) { var name = typeof value == "string" ? value : keyNames[value.keyCode]; return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"; }; // Look up the name of a key as indicated by an event object. var keyName = CodeMirror.keyName = function(event, noShift) { if (presto && event.keyCode == 34 && event["char"]) return false; var base = keyNames[event.keyCode], name = base; if (name == null || event.altGraphKey) return false; if (event.altKey && base != "Alt") name = "Alt-" + name; if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name; if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name; if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name; return name; }; function getKeyMap(val) { return typeof val == "string" ? keyMap[val] : val; } // FROMTEXTAREA CodeMirror.fromTextArea = function(textarea, options) { options = options ? copyObj(options) : {}; options.value = textarea.value; if (!options.tabindex && textarea.tabIndex) options.tabindex = textarea.tabIndex; if (!options.placeholder && textarea.placeholder) options.placeholder = textarea.placeholder; // Set autofocus to true if this textarea is focused, or if it has // autofocus and no other element is focused. if (options.autofocus == null) { var hasFocus = activeElt(); options.autofocus = hasFocus == textarea || textarea.getAttribute("autofocus") != null && hasFocus == document.body; } function save() {textarea.value = cm.getValue();} if (textarea.form) { on(textarea.form, "submit", save); // Deplorable hack to make the submit method do the right thing. if (!options.leaveSubmitMethodAlone) { var form = textarea.form, realSubmit = form.submit; try { var wrappedSubmit = form.submit = function() { save(); form.submit = realSubmit; form.submit(); form.submit = wrappedSubmit; }; } catch(e) {} } } options.finishInit = function(cm) { cm.save = save; cm.getTextArea = function() { return textarea; }; cm.toTextArea = function() { cm.toTextArea = isNaN; // Prevent this from being ran twice save(); textarea.parentNode.removeChild(cm.getWrapperElement()); textarea.style.display = ""; if (textarea.form) { off(textarea.form, "submit", save); if (typeof textarea.form.submit == "function") textarea.form.submit = realSubmit; } }; }; textarea.style.display = "none"; var cm = CodeMirror(function(node) { textarea.parentNode.insertBefore(node, textarea.nextSibling); }, options); return cm; }; // STRING STREAM // Fed to the mode parsers, provides helper functions to make // parsers more succinct. var StringStream = CodeMirror.StringStream = function(string, tabSize) { this.pos = this.start = 0; this.string = string; this.tabSize = tabSize || 8; this.lastColumnPos = this.lastColumnValue = 0; this.lineStart = 0; }; StringStream.prototype = { eol: function() {return this.pos >= this.string.length;}, sol: function() {return this.pos == this.lineStart;}, peek: function() {return this.string.charAt(this.pos) || undefined;}, next: function() { if (this.pos < this.string.length) return this.string.charAt(this.pos++); }, eat: function(match) { var ch = this.string.charAt(this.pos); if (typeof match == "string") var ok = ch == match; else var ok = ch && (match.test ? match.test(ch) : match(ch)); if (ok) {++this.pos; return ch;} }, eatWhile: function(match) { var start = this.pos; while (this.eat(match)){} return this.pos > start; }, eatSpace: function() { var start = this.pos; while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos; return this.pos > start; }, skipToEnd: function() {this.pos = this.string.length;}, skipTo: function(ch) { var found = this.string.indexOf(ch, this.pos); if (found > -1) {this.pos = found; return true;} }, backUp: function(n) {this.pos -= n;}, column: function() { if (this.lastColumnPos < this.start) { this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); this.lastColumnPos = this.start; } return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); }, indentation: function() { return countColumn(this.string, null, this.tabSize) - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0); }, match: function(pattern, consume, caseInsensitive) { if (typeof pattern == "string") { var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;}; var substr = this.string.substr(this.pos, pattern.length); if (cased(substr) == cased(pattern)) { if (consume !== false) this.pos += pattern.length; return true; } } else { var match = this.string.slice(this.pos).match(pattern); if (match && match.index > 0) return null; if (match && consume !== false) this.pos += match[0].length; return match; } }, current: function(){return this.string.slice(this.start, this.pos);}, hideFirstChars: function(n, inner) { this.lineStart += n; try { return inner(); } finally { this.lineStart -= n; } } }; // TEXTMARKERS // Created with markText and setBookmark methods. A TextMarker is a // handle that can be used to clear or find a marked position in the // document. Line objects hold arrays (markedSpans) containing // {from, to, marker} object pointing to such marker objects, and // indicating that such a marker is present on that line. Multiple // lines may point to the same marker when it spans across lines. // The spans will have null for their from/to properties when the // marker continues beyond the start/end of the line. Markers have // links back to the lines they currently touch. var nextMarkerId = 0; var TextMarker = CodeMirror.TextMarker = function(doc, type) { this.lines = []; this.type = type; this.doc = doc; this.id = ++nextMarkerId; }; eventMixin(TextMarker); // Clear the marker. TextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; var cm = this.doc.cm, withOp = cm && !cm.curOp; if (withOp) startOperation(cm); if (hasHandler(this, "clear")) { var found = this.find(); if (found) signalLater(this, "clear", found.from, found.to); } var min = null, max = null; for (var i = 0; i < this.lines.length; ++i) { var line = this.lines[i]; var span = getMarkedSpanFor(line.markedSpans, this); if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text"); else if (cm) { if (span.to != null) max = lineNo(line); if (span.from != null) min = lineNo(line); } line.markedSpans = removeMarkedSpan(line.markedSpans, span); if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm) updateLineHeight(line, textHeight(cm.display)); } if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) { var visual = visualLine(this.lines[i]), len = lineLength(visual); if (len > cm.display.maxLineLength) { cm.display.maxLine = visual; cm.display.maxLineLength = len; cm.display.maxLineChanged = true; } } if (min != null && cm && this.collapsed) regChange(cm, min, max + 1); this.lines.length = 0; this.explicitlyCleared = true; if (this.atomic && this.doc.cantEdit) { this.doc.cantEdit = false; if (cm) reCheckSelection(cm.doc); } if (cm) signalLater(cm, "markerCleared", cm, this); if (withOp) endOperation(cm); if (this.parent) this.parent.clear(); }; // Find the position of the marker in the document. Returns a {from, // to} object by default. Side can be passed to get a specific side // -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the // Pos objects returned contain a line object, rather than a line // number (used to prevent looking up the same line twice). TextMarker.prototype.find = function(side, lineObj) { if (side == null && this.type == "bookmark") side = 1; var from, to; for (var i = 0; i < this.lines.length; ++i) { var line = this.lines[i]; var span = getMarkedSpanFor(line.markedSpans, this); if (span.from != null) { from = Pos(lineObj ? line : lineNo(line), span.from); if (side == -1) return from; } if (span.to != null) { to = Pos(lineObj ? line : lineNo(line), span.to); if (side == 1) return to; } } return from && {from: from, to: to}; }; // Signals that the marker's widget changed, and surrounding layout // should be recomputed. TextMarker.prototype.changed = function() { var pos = this.find(-1, true), widget = this, cm = this.doc.cm; if (!pos || !cm) return; runInOp(cm, function() { var line = pos.line, lineN = lineNo(pos.line); var view = findViewForLine(cm, lineN); if (view) { clearLineMeasurementCacheFor(view); cm.curOp.selectionChanged = cm.curOp.forceUpdate = true; } cm.curOp.updateMaxLine = true; if (!lineIsHidden(widget.doc, line) && widget.height != null) { var oldHeight = widget.height; widget.height = null; var dHeight = widgetHeight(widget) - oldHeight; if (dHeight) updateLineHeight(line, line.height + dHeight); } }); }; TextMarker.prototype.attachLine = function(line) { if (!this.lines.length && this.doc.cm) { var op = this.doc.cm.curOp; if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1) (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); } this.lines.push(line); }; TextMarker.prototype.detachLine = function(line) { this.lines.splice(indexOf(this.lines, line), 1); if (!this.lines.length && this.doc.cm) { var op = this.doc.cm.curOp; (op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this); } }; // Collapsed markers have unique ids, in order to be able to order // them, which is needed for uniquely determining an outer marker // when they overlap (they may nest, but not partially overlap). var nextMarkerId = 0; // Create a marker, wire it up to the right lines, and function markText(doc, from, to, options, type) { // Shared markers (across linked documents) are handled separately // (markTextShared will call out to this again, once per // document). if (options && options.shared) return markTextShared(doc, from, to, options, type); // Ensure we are in an operation. if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type); var marker = new TextMarker(doc, type), diff = cmp(from, to); if (options) copyObj(options, marker, false); // Don't connect empty markers unless clearWhenEmpty is false if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false) return marker; if (marker.replacedWith) { // Showing up as a widget implies collapsed (widget replaces text) marker.collapsed = true; marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget"); if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true"); if (options.insertLeft) marker.widgetNode.insertLeft = true; } if (marker.collapsed) { if (conflictingCollapsedRange(doc, from.line, from, to, marker) || from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker)) throw new Error("Inserting collapsed marker partially overlapping an existing one"); sawCollapsedSpans = true; } if (marker.addToHistory) addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); var curLine = from.line, cm = doc.cm, updateMaxLine; doc.iter(curLine, to.line + 1, function(line) { if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine) updateMaxLine = true; if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0); addMarkedSpan(line, new MarkedSpan(marker, curLine == from.line ? from.ch : null, curLine == to.line ? to.ch : null)); ++curLine; }); // lineIsHidden depends on the presence of the spans, so needs a second pass if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) { if (lineIsHidden(doc, line)) updateLineHeight(line, 0); }); if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); }); if (marker.readOnly) { sawReadOnlySpans = true; if (doc.history.done.length || doc.history.undone.length) doc.clearHistory(); } if (marker.collapsed) { marker.id = ++nextMarkerId; marker.atomic = true; } if (cm) { // Sync editor state if (updateMaxLine) cm.curOp.updateMaxLine = true; if (marker.collapsed) regChange(cm, from.line, to.line + 1); else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css) for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text"); if (marker.atomic) reCheckSelection(cm.doc); signalLater(cm, "markerAdded", cm, marker); } return marker; } // SHARED TEXTMARKERS // A shared marker spans multiple linked documents. It is // implemented as a meta-marker-object controlling multiple normal // markers. var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) { this.markers = markers; this.primary = primary; for (var i = 0; i < markers.length; ++i) markers[i].parent = this; }; eventMixin(SharedTextMarker); SharedTextMarker.prototype.clear = function() { if (this.explicitlyCleared) return; this.explicitlyCleared = true; for (var i = 0; i < this.markers.length; ++i) this.markers[i].clear(); signalLater(this, "clear"); }; SharedTextMarker.prototype.find = function(side, lineObj) { return this.primary.find(side, lineObj); }; function markTextShared(doc, from, to, options, type) { options = copyObj(options); options.shared = false; var markers = [markText(doc, from, to, options, type)], primary = markers[0]; var widget = options.widgetNode; linkedDocs(doc, function(doc) { if (widget) options.widgetNode = widget.cloneNode(true); markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type)); for (var i = 0; i < doc.linked.length; ++i) if (doc.linked[i].isParent) return; primary = lst(markers); }); return new SharedTextMarker(markers, primary); } function findSharedMarkers(doc) { return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function(m) { return m.parent; }); } function copySharedMarkers(doc, markers) { for (var i = 0; i < markers.length; i++) { var marker = markers[i], pos = marker.find(); var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to); if (cmp(mFrom, mTo)) { var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type); marker.markers.push(subMark); subMark.parent = marker; } } } function detachSharedMarkers(markers) { for (var i = 0; i < markers.length; i++) { var marker = markers[i], linked = [marker.primary.doc];; linkedDocs(marker.primary.doc, function(d) { linked.push(d); }); for (var j = 0; j < marker.markers.length; j++) { var subMarker = marker.markers[j]; if (indexOf(linked, subMarker.doc) == -1) { subMarker.parent = null; marker.markers.splice(j--, 1); } } } } // TEXTMARKER SPANS function MarkedSpan(marker, from, to) { this.marker = marker; this.from = from; this.to = to; } // Search an array of spans for a span matching the given marker. function getMarkedSpanFor(spans, marker) { if (spans) for (var i = 0; i < spans.length; ++i) { var span = spans[i]; if (span.marker == marker) return span; } } // Remove a span from an array, returning undefined if no spans are // left (we don't store arrays for lines without spans). function removeMarkedSpan(spans, span) { for (var r, i = 0; i < spans.length; ++i) if (spans[i] != span) (r || (r = [])).push(spans[i]); return r; } // Add a span to a line. function addMarkedSpan(line, span) { line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]; span.marker.attachLine(line); } // Used for the algorithm that adjusts markers for a change in the // document. These functions cut an array of spans at a given // character position, returning an array of remaining chunks (or // undefined if nothing remains). function markedSpansBefore(old, startCh, isInsert) { if (old) for (var i = 0, nw; i < old.length; ++i) { var span = old[i], marker = span.marker; var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh); if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) { var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh); (nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to)); } } return nw; } function markedSpansAfter(old, endCh, isInsert) { if (old) for (var i = 0, nw; i < old.length; ++i) { var span = old[i], marker = span.marker; var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh); if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) { var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh); (nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh, span.to == null ? null : span.to - endCh)); } } return nw; } // Given a change object, compute the new set of marker spans that // cover the line in which the change took place. Removes spans // entirely within the change, reconnects spans belonging to the // same marker that appear on both sides of the change, and cuts off // spans partially within the change. Returns an array of span // arrays with one element for each line in (after) the change. function stretchSpansOverChange(doc, change) { if (change.full) return null; var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans; var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans; if (!oldFirst && !oldLast) return null; var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0; // Get the spans that 'stick out' on both sides var first = markedSpansBefore(oldFirst, startCh, isInsert); var last = markedSpansAfter(oldLast, endCh, isInsert); // Next, merge those two ends var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0); if (first) { // Fix up .to properties of first for (var i = 0; i < first.length; ++i) { var span = first[i]; if (span.to == null) { var found = getMarkedSpanFor(last, span.marker); if (!found) span.to = startCh; else if (sameLine) span.to = found.to == null ? null : found.to + offset; } } } if (last) { // Fix up .from in last (or move them into first in case of sameLine) for (var i = 0; i < last.length; ++i) { var span = last[i]; if (span.to != null) span.to += offset; if (span.from == null) { var found = getMarkedSpanFor(first, span.marker); if (!found) { span.from = offset; if (sameLine) (first || (first = [])).push(span); } } else { span.from += offset; if (sameLine) (first || (first = [])).push(span); } } } // Make sure we didn't create any zero-length spans if (first) first = clearEmptySpans(first); if (last && last != first) last = clearEmptySpans(last); var newMarkers = [first]; if (!sameLine) { // Fill gap with whole-line-spans var gap = change.text.length - 2, gapMarkers; if (gap > 0 && first) for (var i = 0; i < first.length; ++i) if (first[i].to == null) (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null)); for (var i = 0; i < gap; ++i) newMarkers.push(gapMarkers); newMarkers.push(last); } return newMarkers; } // Remove spans that are empty and don't have a clearWhenEmpty // option of false. function clearEmptySpans(spans) { for (var i = 0; i < spans.length; ++i) { var span = spans[i]; if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false) spans.splice(i--, 1); } if (!spans.length) return null; return spans; } // Used for un/re-doing changes from the history. Combines the // result of computing the existing spans with the set of spans that // existed in the history (so that deleting around a span and then // undoing brings back the span). function mergeOldSpans(doc, change) { var old = getOldSpans(doc, change); var stretched = stretchSpansOverChange(doc, change); if (!old) return stretched; if (!stretched) return old; for (var i = 0; i < old.length; ++i) { var oldCur = old[i], stretchCur = stretched[i]; if (oldCur && stretchCur) { spans: for (var j = 0; j < stretchCur.length; ++j) { var span = stretchCur[j]; for (var k = 0; k < oldCur.length; ++k) if (oldCur[k].marker == span.marker) continue spans; oldCur.push(span); } } else if (stretchCur) { old[i] = stretchCur; } } return old; } // Used to 'clip' out readOnly ranges when making a change. function removeReadOnlyRanges(doc, from, to) { var markers = null; doc.iter(from.line, to.line + 1, function(line) { if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) { var mark = line.markedSpans[i].marker; if (mark.readOnly && (!markers || indexOf(markers, mark) == -1)) (markers || (markers = [])).push(mark); } }); if (!markers) return null; var parts = [{from: from, to: to}]; for (var i = 0; i < markers.length; ++i) { var mk = markers[i], m = mk.find(0); for (var j = 0; j < parts.length; ++j) { var p = parts[j]; if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue; var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to); if (dfrom < 0 || !mk.inclusiveLeft && !dfrom) newParts.push({from: p.from, to: m.from}); if (dto > 0 || !mk.inclusiveRight && !dto) newParts.push({from: m.to, to: p.to}); parts.splice.apply(parts, newParts); j += newParts.length - 1; } } return parts; } // Connect or disconnect spans from a line. function detachMarkedSpans(line) { var spans = line.markedSpans; if (!spans) return; for (var i = 0; i < spans.length; ++i) spans[i].marker.detachLine(line); line.markedSpans = null; } function attachMarkedSpans(line, spans) { if (!spans) return; for (var i = 0; i < spans.length; ++i) spans[i].marker.attachLine(line); line.markedSpans = spans; } // Helpers used when computing which overlapping collapsed span // counts as the larger one. function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; } function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; } // Returns a number indicating which of two overlapping collapsed // spans is larger (and thus includes the other). Falls back to // comparing ids when the spans cover exactly the same range. function compareCollapsedMarkers(a, b) { var lenDiff = a.lines.length - b.lines.length; if (lenDiff != 0) return lenDiff; var aPos = a.find(), bPos = b.find(); var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b); if (fromCmp) return -fromCmp; var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b); if (toCmp) return toCmp; return b.id - a.id; } // Find out whether a line ends or starts in a collapsed span. If // so, return the marker for that span. function collapsedSpanAtSide(line, start) { var sps = sawCollapsedSpans && line.markedSpans, found; if (sps) for (var sp, i = 0; i < sps.length; ++i) { sp = sps[i]; if (sp.marker.collapsed && (start ? sp.from : sp.to) == null && (!found || compareCollapsedMarkers(found, sp.marker) < 0)) found = sp.marker; } return found; } function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); } function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); } // Test whether there exists a collapsed span that partially // overlaps (covers the start or end, but not both) of a new span. // Such overlap is not allowed. function conflictingCollapsedRange(doc, lineNo, from, to, marker) { var line = getLine(doc, lineNo); var sps = sawCollapsedSpans && line.markedSpans; if (sps) for (var i = 0; i < sps.length; ++i) { var sp = sps[i]; if (!sp.marker.collapsed) continue; var found = sp.marker.find(0); var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker); var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker); if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue; if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) || fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight))) return true; } } // A visual line is a line as drawn on the screen. Folding, for // example, can cause multiple logical lines to appear on the same // visual line. This finds the start of the visual line that the // given line is part of (usually that is the line itself). function visualLine(line) { var merged; while (merged = collapsedSpanAtStart(line)) line = merged.find(-1, true).line; return line; } // Returns an array of logical lines that continue the visual line // started by the argument, or undefined if there are no such lines. function visualLineContinued(line) { var merged, lines; while (merged = collapsedSpanAtEnd(line)) { line = merged.find(1, true).line; (lines || (lines = [])).push(line); } return lines; } // Get the line number of the start of the visual line that the // given line number is part of. function visualLineNo(doc, lineN) { var line = getLine(doc, lineN), vis = visualLine(line); if (line == vis) return lineN; return lineNo(vis); } // Get the line number of the start of the next visual line after // the given line. function visualLineEndNo(doc, lineN) { if (lineN > doc.lastLine()) return lineN; var line = getLine(doc, lineN), merged; if (!lineIsHidden(doc, line)) return lineN; while (merged = collapsedSpanAtEnd(line)) line = merged.find(1, true).line; return lineNo(line) + 1; } // Compute whether a line is hidden. Lines count as hidden when they // are part of a visual line that starts with another line, or when // they are entirely covered by collapsed, non-widget span. function lineIsHidden(doc, line) { var sps = sawCollapsedSpans && line.markedSpans; if (sps) for (var sp, i = 0; i < sps.length; ++i) { sp = sps[i]; if (!sp.marker.collapsed) continue; if (sp.from == null) return true; if (sp.marker.widgetNode) continue; if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp)) return true; } } function lineIsHiddenInner(doc, line, span) { if (span.to == null) { var end = span.marker.find(1, true); return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker)); } if (span.marker.inclusiveRight && span.to == line.text.length) return true; for (var sp, i = 0; i < line.markedSpans.length; ++i) { sp = line.markedSpans[i]; if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to && (sp.to == null || sp.to != span.from) && (sp.marker.inclusiveLeft || span.marker.inclusiveRight) && lineIsHiddenInner(doc, line, sp)) return true; } } // LINE WIDGETS // Line widgets are block elements displayed above or below a line. var LineWidget = CodeMirror.LineWidget = function(doc, node, options) { if (options) for (var opt in options) if (options.hasOwnProperty(opt)) this[opt] = options[opt]; this.doc = doc; this.node = node; }; eventMixin(LineWidget); function adjustScrollWhenAboveVisible(cm, line, diff) { if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop)) addToScrollPos(cm, null, diff); } LineWidget.prototype.clear = function() { var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line); if (no == null || !ws) return; for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1); if (!ws.length) line.widgets = null; var height = widgetHeight(this); updateLineHeight(line, Math.max(0, line.height - height)); if (cm) runInOp(cm, function() { adjustScrollWhenAboveVisible(cm, line, -height); regLineChange(cm, no, "widget"); }); }; LineWidget.prototype.changed = function() { var oldH = this.height, cm = this.doc.cm, line = this.line; this.height = null; var diff = widgetHeight(this) - oldH; if (!diff) return; updateLineHeight(line, line.height + diff); if (cm) runInOp(cm, function() { cm.curOp.forceUpdate = true; adjustScrollWhenAboveVisible(cm, line, diff); }); }; function widgetHeight(widget) { if (widget.height != null) return widget.height; var cm = widget.doc.cm; if (!cm) return 0; if (!contains(document.body, widget.node)) { var parentStyle = "position: relative;"; if (widget.coverGutter) parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; if (widget.noHScroll) parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle)); } return widget.height = widget.node.offsetHeight; } function addLineWidget(doc, handle, node, options) { var widget = new LineWidget(doc, node, options); var cm = doc.cm; if (cm && widget.noHScroll) cm.display.alignWidgets = true; changeLine(doc, handle, "widget", function(line) { var widgets = line.widgets || (line.widgets = []); if (widget.insertAt == null) widgets.push(widget); else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); widget.line = line; if (cm && !lineIsHidden(doc, line)) { var aboveVisible = heightAtLine(line) < doc.scrollTop; updateLineHeight(line, line.height + widgetHeight(widget)); if (aboveVisible) addToScrollPos(cm, null, widget.height); cm.curOp.forceUpdate = true; } return true; }); return widget; } // LINE DATA STRUCTURE // Line objects. These hold state related to a line, including // highlighting info (the styles array). var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) { this.text = text; attachMarkedSpans(this, markedSpans); this.height = estimateHeight ? estimateHeight(this) : 1; }; eventMixin(Line); Line.prototype.lineNo = function() { return lineNo(this); }; // Change the content (text, markers) of a line. Automatically // invalidates cached information and tries to re-estimate the // line's height. function updateLine(line, text, markedSpans, estimateHeight) { line.text = text; if (line.stateAfter) line.stateAfter = null; if (line.styles) line.styles = null; if (line.order != null) line.order = null; detachMarkedSpans(line); attachMarkedSpans(line, markedSpans); var estHeight = estimateHeight ? estimateHeight(line) : 1; if (estHeight != line.height) updateLineHeight(line, estHeight); } // Detach a line from the document tree and its markers. function cleanUpLine(line) { line.parent = null; detachMarkedSpans(line); } function extractLineClasses(type, output) { if (type) for (;;) { var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/); if (!lineClass) break; type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length); var prop = lineClass[1] ? "bgClass" : "textClass"; if (output[prop] == null) output[prop] = lineClass[2]; else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop])) output[prop] += " " + lineClass[2]; } return type; } function callBlankLine(mode, state) { if (mode.blankLine) return mode.blankLine(state); if (!mode.innerMode) return; var inner = CodeMirror.innerMode(mode, state); if (inner.mode.blankLine) return inner.mode.blankLine(inner.state); } function readToken(mode, stream, state, inner) { for (var i = 0; i < 10; i++) { if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode; var style = mode.token(stream, state); if (stream.pos > stream.start) return style; } throw new Error("Mode " + mode.name + " failed to advance stream."); } // Utility for getTokenAt and getLineTokens function takeToken(cm, pos, precise, asArray) { function getObj(copy) { return {start: stream.start, end: stream.pos, string: stream.current(), type: style || null, state: copy ? copyState(doc.mode, state) : state}; } var doc = cm.doc, mode = doc.mode, style; pos = clipPos(doc, pos); var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise); var stream = new StringStream(line.text, cm.options.tabSize), tokens; if (asArray) tokens = []; while ((asArray || stream.pos < pos.ch) && !stream.eol()) { stream.start = stream.pos; style = readToken(mode, stream, state); if (asArray) tokens.push(getObj(true)); } return asArray ? tokens : getObj(); } // Run the given mode's parser over a line, calling f for each token. function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) { var flattenSpans = mode.flattenSpans; if (flattenSpans == null) flattenSpans = cm.options.flattenSpans; var curStart = 0, curStyle = null; var stream = new StringStream(text, cm.options.tabSize), style; var inner = cm.options.addModeClass && [null]; if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses); while (!stream.eol()) { if (stream.pos > cm.options.maxHighlightLength) { flattenSpans = false; if (forceToEnd) processLine(cm, text, state, stream.pos); stream.pos = text.length; style = null; } else { style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses); } if (inner) { var mName = inner[0].name; if (mName) style = "m-" + (style ? mName + " " + style : mName); } if (!flattenSpans || curStyle != style) { while (curStart < stream.start) { curStart = Math.min(stream.start, curStart + 50000); f(curStart, curStyle); } curStyle = style; } stream.start = stream.pos; } while (curStart < stream.pos) { // Webkit seems to refuse to render text nodes longer than 57444 characters var pos = Math.min(stream.pos, curStart + 50000); f(pos, curStyle); curStart = pos; } } // Compute a style array (an array starting with a mode generation // -- for invalidation -- followed by pairs of end positions and // style strings), which is used to highlight the tokens on the // line. function highlightLine(cm, line, state, forceToEnd) { // A styles array always starts with a number identifying the // mode/overlays that it is based on (for easy invalidation). var st = [cm.state.modeGen], lineClasses = {}; // Compute the base array of styles runMode(cm, line.text, cm.doc.mode, state, function(end, style) { st.push(end, style); }, lineClasses, forceToEnd); // Run overlays, adjust style array. for (var o = 0; o < cm.state.overlays.length; ++o) { var overlay = cm.state.overlays[o], i = 1, at = 0; runMode(cm, line.text, overlay.mode, true, function(end, style) { var start = i; // Ensure there's a token end at the current position, and that i points at it while (at < end) { var i_end = st[i]; if (i_end > end) st.splice(i, 1, end, st[i+1], i_end); i += 2; at = Math.min(end, i_end); } if (!style) return; if (overlay.opaque) { st.splice(start, i - start, end, "cm-overlay " + style); i = start + 2; } else { for (; start < i; start += 2) { var cur = st[start+1]; st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style; } } }, lineClasses); } return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}; } function getLineStyles(cm, line, updateFrontier) { if (!line.styles || line.styles[0] != cm.state.modeGen) { var result = highlightLine(cm, line, line.stateAfter = getStateBefore(cm, lineNo(line))); line.styles = result.styles; if (result.classes) line.styleClasses = result.classes; else if (line.styleClasses) line.styleClasses = null; if (updateFrontier === cm.doc.frontier) cm.doc.frontier++; } return line.styles; } // Lightweight form of highlight -- proceed over this line and // update state, but don't save a style array. Used for lines that // aren't currently visible. function processLine(cm, text, state, startAt) { var mode = cm.doc.mode; var stream = new StringStream(text, cm.options.tabSize); stream.start = stream.pos = startAt || 0; if (text == "") callBlankLine(mode, state); while (!stream.eol() && stream.pos <= cm.options.maxHighlightLength) { readToken(mode, stream, state); stream.start = stream.pos; } } // Convert a style as returned by a mode (either null, or a string // containing one or more styles) to a CSS style. This is cached, // and also looks for line-wide styles. var styleToClassCache = {}, styleToClassCacheWithMode = {}; function interpretTokenStyle(style, options) { if (!style || /^\s*$/.test(style)) return null; var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache; return cache[style] || (cache[style] = style.replace(/\S+/g, "cm-$&")); } // Render the DOM representation of the text of a line. Also builds // up a 'line map', which points at the DOM nodes that represent // specific stretches of text, and is used by the measuring code. // The returned object contains the DOM node, this map, and // information about line-wide styles that were set by the mode. function buildLineContent(cm, lineView) { // The padding-right forces the element to have a 'border', which // is needed on Webkit to be able to get line-level bounding // rectangles for it (in measureChar). var content = elt("span", null, null, webkit ? "padding-right: .1px" : null); var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content, col: 0, pos: 0, cm: cm, splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")}; lineView.measure = {}; // Iterate over the logical lines that make up this visual line. for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) { var line = i ? lineView.rest[i - 1] : lineView.line, order; builder.pos = 0; builder.addToken = buildToken; // Optionally wire in some hacks into the token-rendering // algorithm, to deal with browser quirks. if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line))) builder.addToken = buildTokenBadBidi(builder.addToken, order); builder.map = []; var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line); insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate)); if (line.styleClasses) { if (line.styleClasses.bgClass) builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); if (line.styleClasses.textClass) builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); } // Ensure at least a single node is present, for measuring. if (builder.map.length == 0) builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); // Store the map and a cache object for the current logical line if (i == 0) { lineView.measure.map = builder.map; lineView.measure.cache = {}; } else { (lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map); (lineView.measure.caches || (lineView.measure.caches = [])).push({}); } } // See issue #2901 if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className)) builder.content.className = "cm-tab-wrap-hack"; signal(cm, "renderLine", cm, lineView.line, builder.pre); if (builder.pre.className) builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); return builder; } function defaultSpecialCharPlaceholder(ch) { var token = elt("span", "\u2022", "cm-invalidchar"); token.title = "\\u" + ch.charCodeAt(0).toString(16); token.setAttribute("aria-label", token.title); return token; } // Build up the DOM representation for a single token, and add it to // the line map. Takes care to render special characters separately. function buildToken(builder, text, style, startStyle, endStyle, title, css) { if (!text) return; var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text; var special = builder.cm.state.specialChars, mustWrap = false; if (!special.test(text)) { builder.col += text.length; var content = document.createTextNode(displayText); builder.map.push(builder.pos, builder.pos + text.length, content); if (ie && ie_version < 9) mustWrap = true; builder.pos += text.length; } else { var content = document.createDocumentFragment(), pos = 0; while (true) { special.lastIndex = pos; var m = special.exec(text); var skipped = m ? m.index - pos : text.length - pos; if (skipped) { var txt = document.createTextNode(displayText.slice(pos, pos + skipped)); if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); else content.appendChild(txt); builder.map.push(builder.pos, builder.pos + skipped, txt); builder.col += skipped; builder.pos += skipped; } if (!m) break; pos += skipped + 1; if (m[0] == "\t") { var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize; var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab")); txt.setAttribute("role", "presentation"); txt.setAttribute("cm-text", "\t"); builder.col += tabWidth; } else { var txt = builder.cm.options.specialCharPlaceholder(m[0]); txt.setAttribute("cm-text", m[0]); if (ie && ie_version < 9) content.appendChild(elt("span", [txt])); else content.appendChild(txt); builder.col += 1; } builder.map.push(builder.pos, builder.pos + 1, txt); builder.pos++; } } if (style || startStyle || endStyle || mustWrap || css) { var fullStyle = style || ""; if (startStyle) fullStyle += startStyle; if (endStyle) fullStyle += endStyle; var token = elt("span", [content], fullStyle, css); if (title) token.title = title; return builder.content.appendChild(token); } builder.content.appendChild(content); } function splitSpaces(old) { var out = " "; for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0"; out += " "; return out; } // Work around nonsense dimensions being reported for stretches of // right-to-left text. function buildTokenBadBidi(inner, order) { return function(builder, text, style, startStyle, endStyle, title, css) { style = style ? style + " cm-force-border" : "cm-force-border"; var start = builder.pos, end = start + text.length; for (;;) { // Find the part that overlaps with the start of this text for (var i = 0; i < order.length; i++) { var part = order[i]; if (part.to > start && part.from <= start) break; } if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css); inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css); startStyle = null; text = text.slice(part.to - start); start = part.to; } }; } function buildCollapsedSpan(builder, size, marker, ignoreWidget) { var widget = !ignoreWidget && marker.widgetNode; if (widget) builder.map.push(builder.pos, builder.pos + size, widget); if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) { if (!widget) widget = builder.content.appendChild(document.createElement("span")); widget.setAttribute("cm-marker", marker.id); } if (widget) { builder.cm.display.input.setUneditable(widget); builder.content.appendChild(widget); } builder.pos += size; } // Outputs a number of spans to make up a line, taking highlighting // and marked text into account. function insertLineContent(line, builder, styles) { var spans = line.markedSpans, allText = line.text, at = 0; if (!spans) { for (var i = 1; i < styles.length; i+=2) builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options)); return; } var len = allText.length, pos = 0, i = 1, text = "", style, css; var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed; for (;;) { if (nextChange == pos) { // Update current marker set spanStyle = spanEndStyle = spanStartStyle = title = css = ""; collapsed = null; nextChange = Infinity; var foundBookmarks = []; for (var j = 0; j < spans.length; ++j) { var sp = spans[j], m = sp.marker; if (m.type == "bookmark" && sp.from == pos && m.widgetNode) { foundBookmarks.push(m); } else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) { if (sp.to != null && sp.to != pos && nextChange > sp.to) { nextChange = sp.to; spanEndStyle = ""; } if (m.className) spanStyle += " " + m.className; if (m.css) css = m.css; if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle; if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle; if (m.title && !title) title = m.title; if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0)) collapsed = sp; } else if (sp.from > pos && nextChange > sp.from) { nextChange = sp.from; } } if (collapsed && (collapsed.from || 0) == pos) { buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos, collapsed.marker, collapsed.from == null); if (collapsed.to == null) return; if (collapsed.to == pos) collapsed = false; } if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j) buildCollapsedSpan(builder, 0, foundBookmarks[j]); } if (pos >= len) break; var upto = Math.min(len, nextChange); while (true) { if (text) { var end = pos + text.length; if (!collapsed) { var tokenText = end > upto ? text.slice(0, upto - pos) : text; builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle, spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css); } if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;} pos = end; spanStartStyle = ""; } text = allText.slice(at, at = styles[i++]); style = interpretTokenStyle(styles[i++], builder.cm.options); } } } // DOCUMENT DATA STRUCTURE // By default, updates that start and end at the beginning of a line // are treated specially, in order to make the association of line // widgets and marker elements with the text behave more intuitive. function isWholeLineUpdate(doc, change) { return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" && (!doc.cm || doc.cm.options.wholeLineUpdateBefore); } // Perform a change on the document data structure. function updateDoc(doc, change, markedSpans, estimateHeight) { function spansFor(n) {return markedSpans ? markedSpans[n] : null;} function update(line, text, spans) { updateLine(line, text, spans, estimateHeight); signalLater(line, "change", line, change); } function linesFor(start, end) { for (var i = start, result = []; i < end; ++i) result.push(new Line(text[i], spansFor(i), estimateHeight)); return result; } var from = change.from, to = change.to, text = change.text; var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line); var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line; // Adjust the line structure if (change.full) { doc.insert(0, linesFor(0, text.length)); doc.remove(text.length, doc.size - text.length); } else if (isWholeLineUpdate(doc, change)) { // This is a whole-line replace. Treated specially to make // sure line objects move the way they are supposed to. var added = linesFor(0, text.length - 1); update(lastLine, lastLine.text, lastSpans); if (nlines) doc.remove(from.line, nlines); if (added.length) doc.insert(from.line, added); } else if (firstLine == lastLine) { if (text.length == 1) { update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans); } else { var added = linesFor(1, text.length - 1); added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight)); update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); doc.insert(from.line + 1, added); } } else if (text.length == 1) { update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0)); doc.remove(from.line + 1, nlines); } else { update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0)); update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans); var added = linesFor(1, text.length - 1); if (nlines > 1) doc.remove(from.line + 1, nlines - 1); doc.insert(from.line + 1, added); } signalLater(doc, "change", doc, change); } // The document is represented as a BTree consisting of leaves, with // chunk of lines in them, and branches, with up to ten leaves or // other branch nodes below them. The top node is always a branch // node, and is the document object itself (meaning it has // additional methods and properties). // // All nodes have parent links. The tree is used both to go from // line numbers to line objects, and to go from objects to numbers. // It also indexes by height, and is used to convert between height // and line object, and to find the total height of the document. // // See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html function LeafChunk(lines) { this.lines = lines; this.parent = null; for (var i = 0, height = 0; i < lines.length; ++i) { lines[i].parent = this; height += lines[i].height; } this.height = height; } LeafChunk.prototype = { chunkSize: function() { return this.lines.length; }, // Remove the n lines at offset 'at'. removeInner: function(at, n) { for (var i = at, e = at + n; i < e; ++i) { var line = this.lines[i]; this.height -= line.height; cleanUpLine(line); signalLater(line, "delete"); } this.lines.splice(at, n); }, // Helper used to collapse a small branch into a single leaf. collapse: function(lines) { lines.push.apply(lines, this.lines); }, // Insert the given array of lines at offset 'at', count them as // having the given height. insertInner: function(at, lines, height) { this.height += height; this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at)); for (var i = 0; i < lines.length; ++i) lines[i].parent = this; }, // Used to iterate over a part of the tree. iterN: function(at, n, op) { for (var e = at + n; at < e; ++at) if (op(this.lines[at])) return true; } }; function BranchChunk(children) { this.children = children; var size = 0, height = 0; for (var i = 0; i < children.length; ++i) { var ch = children[i]; size += ch.chunkSize(); height += ch.height; ch.parent = this; } this.size = size; this.height = height; this.parent = null; } BranchChunk.prototype = { chunkSize: function() { return this.size; }, removeInner: function(at, n) { this.size -= n; for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var rm = Math.min(n, sz - at), oldHeight = child.height; child.removeInner(at, rm); this.height -= oldHeight - child.height; if (sz == rm) { this.children.splice(i--, 1); child.parent = null; } if ((n -= rm) == 0) break; at = 0; } else at -= sz; } // If the result is smaller than 25 lines, ensure that it is a // single leaf node. if (this.size - n < 25 && (this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) { var lines = []; this.collapse(lines); this.children = [new LeafChunk(lines)]; this.children[0].parent = this; } }, collapse: function(lines) { for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines); }, insertInner: function(at, lines, height) { this.size += lines.length; this.height += height; for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at <= sz) { child.insertInner(at, lines, height); if (child.lines && child.lines.length > 50) { while (child.lines.length > 50) { var spilled = child.lines.splice(child.lines.length - 25, 25); var newleaf = new LeafChunk(spilled); child.height -= newleaf.height; this.children.splice(i + 1, 0, newleaf); newleaf.parent = this; } this.maybeSpill(); } break; } at -= sz; } }, // When a node has grown, check whether it should be split. maybeSpill: function() { if (this.children.length <= 10) return; var me = this; do { var spilled = me.children.splice(me.children.length - 5, 5); var sibling = new BranchChunk(spilled); if (!me.parent) { // Become the parent node var copy = new BranchChunk(me.children); copy.parent = me; me.children = [copy, sibling]; me = copy; } else { me.size -= sibling.size; me.height -= sibling.height; var myIndex = indexOf(me.parent.children, me); me.parent.children.splice(myIndex + 1, 0, sibling); } sibling.parent = me.parent; } while (me.children.length > 10); me.parent.maybeSpill(); }, iterN: function(at, n, op) { for (var i = 0; i < this.children.length; ++i) { var child = this.children[i], sz = child.chunkSize(); if (at < sz) { var used = Math.min(n, sz - at); if (child.iterN(at, used, op)) return true; if ((n -= used) == 0) break; at = 0; } else at -= sz; } } }; var nextDocId = 0; var Doc = CodeMirror.Doc = function(text, mode, firstLine) { if (!(this instanceof Doc)) return new Doc(text, mode, firstLine); if (firstLine == null) firstLine = 0; BranchChunk.call(this, [new LeafChunk([new Line("", null)])]); this.first = firstLine; this.scrollTop = this.scrollLeft = 0; this.cantEdit = false; this.cleanGeneration = 1; this.frontier = firstLine; var start = Pos(firstLine, 0); this.sel = simpleSelection(start); this.history = new History(null); this.id = ++nextDocId; this.modeOption = mode; if (typeof text == "string") text = splitLines(text); updateDoc(this, {from: start, to: start, text: text}); setSelection(this, simpleSelection(start), sel_dontScroll); }; Doc.prototype = createObj(BranchChunk.prototype, { constructor: Doc, // Iterate over the document. Supports two forms -- with only one // argument, it calls that for each line in the document. With // three, it iterates over the range given by the first two (with // the second being non-inclusive). iter: function(from, to, op) { if (op) this.iterN(from - this.first, to - from, op); else this.iterN(this.first, this.first + this.size, from); }, // Non-public interface for adding and removing lines. insert: function(at, lines) { var height = 0; for (var i = 0; i < lines.length; ++i) height += lines[i].height; this.insertInner(at - this.first, lines, height); }, remove: function(at, n) { this.removeInner(at - this.first, n); }, // From here, the methods are part of the public interface. Most // are also available from CodeMirror (editor) instances. getValue: function(lineSep, lineFilter) { var lines = getLines(this, this.first, this.first + this.size, lineFilter); if (lineSep === false) return lines; return lines.join(lineSep || "\n"); }, setValue: docMethodOp(function(code) { var top = Pos(this.first, 0), last = this.first + this.size - 1; makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length), text: splitLines(code), origin: "setValue", full: true}, true); setSelection(this, simpleSelection(top)); }), replaceRange: function(code, from, to, origin) { from = clipPos(this, from); to = to ? clipPos(this, to) : from; replaceRange(this, code, from, to, origin); }, getRange: function(from, to, lineSep) { var lines = getBetween(this, clipPos(this, from), clipPos(this, to)); if (lineSep === false) return lines; return lines.join(lineSep || "\n"); }, getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;}, getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);}, getLineNumber: function(line) {return lineNo(line);}, getLineHandleVisualStart: function(line) { if (typeof line == "number") line = getLine(this, line); return visualLine(line); }, lineCount: function() {return this.size;}, firstLine: function() {return this.first;}, lastLine: function() {return this.first + this.size - 1;}, clipPos: function(pos) {return clipPos(this, pos);}, getCursor: function(start) { var range = this.sel.primary(), pos; if (start == null || start == "head") pos = range.head; else if (start == "anchor") pos = range.anchor; else if (start == "end" || start == "to" || start === false) pos = range.to(); else pos = range.from(); return pos; }, listSelections: function() { return this.sel.ranges; }, somethingSelected: function() {return this.sel.somethingSelected();}, setCursor: docMethodOp(function(line, ch, options) { setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options); }), setSelection: docMethodOp(function(anchor, head, options) { setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options); }), extendSelection: docMethodOp(function(head, other, options) { extendSelection(this, clipPos(this, head), other && clipPos(this, other), options); }), extendSelections: docMethodOp(function(heads, options) { extendSelections(this, clipPosArray(this, heads, options)); }), extendSelectionsBy: docMethodOp(function(f, options) { extendSelections(this, map(this.sel.ranges, f), options); }), setSelections: docMethodOp(function(ranges, primary, options) { if (!ranges.length) return; for (var i = 0, out = []; i < ranges.length; i++) out[i] = new Range(clipPos(this, ranges[i].anchor), clipPos(this, ranges[i].head)); if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex); setSelection(this, normalizeSelection(out, primary), options); }), addSelection: docMethodOp(function(anchor, head, options) { var ranges = this.sel.ranges.slice(0); ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor))); setSelection(this, normalizeSelection(ranges, ranges.length - 1), options); }), getSelection: function(lineSep) { var ranges = this.sel.ranges, lines; for (var i = 0; i < ranges.length; i++) { var sel = getBetween(this, ranges[i].from(), ranges[i].to()); lines = lines ? lines.concat(sel) : sel; } if (lineSep === false) return lines; else return lines.join(lineSep || "\n"); }, getSelections: function(lineSep) { var parts = [], ranges = this.sel.ranges; for (var i = 0; i < ranges.length; i++) { var sel = getBetween(this, ranges[i].from(), ranges[i].to()); if (lineSep !== false) sel = sel.join(lineSep || "\n"); parts[i] = sel; } return parts; }, replaceSelection: function(code, collapse, origin) { var dup = []; for (var i = 0; i < this.sel.ranges.length; i++) dup[i] = code; this.replaceSelections(dup, collapse, origin || "+input"); }, replaceSelections: docMethodOp(function(code, collapse, origin) { var changes = [], sel = this.sel; for (var i = 0; i < sel.ranges.length; i++) { var range = sel.ranges[i]; changes[i] = {from: range.from(), to: range.to(), text: splitLines(code[i]), origin: origin}; } var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse); for (var i = changes.length - 1; i >= 0; i--) makeChange(this, changes[i]); if (newSel) setSelectionReplaceHistory(this, newSel); else if (this.cm) ensureCursorVisible(this.cm); }), undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}), redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}), undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}), redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}), setExtending: function(val) {this.extend = val;}, getExtending: function() {return this.extend;}, historySize: function() { var hist = this.history, done = 0, undone = 0; for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done; for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone; return {undo: done, redo: undone}; }, clearHistory: function() {this.history = new History(this.history.maxGeneration);}, markClean: function() { this.cleanGeneration = this.changeGeneration(true); }, changeGeneration: function(forceSplit) { if (forceSplit) this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; return this.history.generation; }, isClean: function (gen) { return this.history.generation == (gen || this.cleanGeneration); }, getHistory: function() { return {done: copyHistoryArray(this.history.done), undone: copyHistoryArray(this.history.undone)}; }, setHistory: function(histData) { var hist = this.history = new History(this.history.maxGeneration); hist.done = copyHistoryArray(histData.done.slice(0), null, true); hist.undone = copyHistoryArray(histData.undone.slice(0), null, true); }, addLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass"; if (!line[prop]) line[prop] = cls; else if (classTest(cls).test(line[prop])) return false; else line[prop] += " " + cls; return true; }); }), removeLineClass: docMethodOp(function(handle, where, cls) { return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) { var prop = where == "text" ? "textClass" : where == "background" ? "bgClass" : where == "gutter" ? "gutterClass" : "wrapClass"; var cur = line[prop]; if (!cur) return false; else if (cls == null) line[prop] = null; else { var found = cur.match(classTest(cls)); if (!found) return false; var end = found.index + found[0].length; line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null; } return true; }); }), addLineWidget: docMethodOp(function(handle, node, options) { return addLineWidget(this, handle, node, options); }), removeLineWidget: function(widget) { widget.clear(); }, markText: function(from, to, options) { return markText(this, clipPos(this, from), clipPos(this, to), options, "range"); }, setBookmark: function(pos, options) { var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options), insertLeft: options && options.insertLeft, clearWhenEmpty: false, shared: options && options.shared, handleMouseEvents: options && options.handleMouseEvents}; pos = clipPos(this, pos); return markText(this, pos, pos, realOpts, "bookmark"); }, findMarksAt: function(pos) { pos = clipPos(this, pos); var markers = [], spans = getLine(this, pos.line).markedSpans; if (spans) for (var i = 0; i < spans.length; ++i) { var span = spans[i]; if ((span.from == null || span.from <= pos.ch) && (span.to == null || span.to >= pos.ch)) markers.push(span.marker.parent || span.marker); } return markers; }, findMarks: function(from, to, filter) { from = clipPos(this, from); to = clipPos(this, to); var found = [], lineNo = from.line; this.iter(from.line, to.line + 1, function(line) { var spans = line.markedSpans; if (spans) for (var i = 0; i < spans.length; i++) { var span = spans[i]; if (!(lineNo == from.line && from.ch > span.to || span.from == null && lineNo != from.line|| lineNo == to.line && span.from > to.ch) && (!filter || filter(span.marker))) found.push(span.marker.parent || span.marker); } ++lineNo; }); return found; }, getAllMarks: function() { var markers = []; this.iter(function(line) { var sps = line.markedSpans; if (sps) for (var i = 0; i < sps.length; ++i) if (sps[i].from != null) markers.push(sps[i].marker); }); return markers; }, posFromIndex: function(off) { var ch, lineNo = this.first; this.iter(function(line) { var sz = line.text.length + 1; if (sz > off) { ch = off; return true; } off -= sz; ++lineNo; }); return clipPos(this, Pos(lineNo, ch)); }, indexFromPos: function (coords) { coords = clipPos(this, coords); var index = coords.ch; if (coords.line < this.first || coords.ch < 0) return 0; this.iter(this.first, coords.line, function (line) { index += line.text.length + 1; }); return index; }, copy: function(copyHistory) { var doc = new Doc(getLines(this, this.first, this.first + this.size), this.modeOption, this.first); doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft; doc.sel = this.sel; doc.extend = false; if (copyHistory) { doc.history.undoDepth = this.history.undoDepth; doc.setHistory(this.getHistory()); } return doc; }, linkedDoc: function(options) { if (!options) options = {}; var from = this.first, to = this.first + this.size; if (options.from != null && options.from > from) from = options.from; if (options.to != null && options.to < to) to = options.to; var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from); if (options.sharedHist) copy.history = this.history; (this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist}); copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}]; copySharedMarkers(copy, findSharedMarkers(this)); return copy; }, unlinkDoc: function(other) { if (other instanceof CodeMirror) other = other.doc; if (this.linked) for (var i = 0; i < this.linked.length; ++i) { var link = this.linked[i]; if (link.doc != other) continue; this.linked.splice(i, 1); other.unlinkDoc(this); detachSharedMarkers(findSharedMarkers(this)); break; } // If the histories were shared, split them again if (other.history == this.history) { var splitIds = [other.id]; linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true); other.history = new History(null); other.history.done = copyHistoryArray(this.history.done, splitIds); other.history.undone = copyHistoryArray(this.history.undone, splitIds); } }, iterLinkedDocs: function(f) {linkedDocs(this, f);}, getMode: function() {return this.mode;}, getEditor: function() {return this.cm;} }); // Public alias. Doc.prototype.eachLine = Doc.prototype.iter; // Set up methods on CodeMirror's prototype to redirect to the editor's document. var dontDelegate = "iter insert remove copy getEditor constructor".split(" "); for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0) CodeMirror.prototype[prop] = (function(method) { return function() {return method.apply(this.doc, arguments);}; })(Doc.prototype[prop]); eventMixin(Doc); // Call f for all linked documents. function linkedDocs(doc, f, sharedHistOnly) { function propagate(doc, skip, sharedHist) { if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) { var rel = doc.linked[i]; if (rel.doc == skip) continue; var shared = sharedHist && rel.sharedHist; if (sharedHistOnly && !shared) continue; f(rel.doc, shared); propagate(rel.doc, doc, shared); } } propagate(doc, null, true); } // Attach a document to an editor. function attachDoc(cm, doc) { if (doc.cm) throw new Error("This document is already in use."); cm.doc = doc; doc.cm = cm; estimateLineHeights(cm); loadMode(cm); if (!cm.options.lineWrapping) findMaxLine(cm); cm.options.mode = doc.modeOption; regChange(cm); } // LINE UTILITIES // Find the line object corresponding to the given line number. function getLine(doc, n) { n -= doc.first; if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document."); for (var chunk = doc; !chunk.lines;) { for (var i = 0;; ++i) { var child = chunk.children[i], sz = child.chunkSize(); if (n < sz) { chunk = child; break; } n -= sz; } } return chunk.lines[n]; } // Get the part of a document between two positions, as an array of // strings. function getBetween(doc, start, end) { var out = [], n = start.line; doc.iter(start.line, end.line + 1, function(line) { var text = line.text; if (n == end.line) text = text.slice(0, end.ch); if (n == start.line) text = text.slice(start.ch); out.push(text); ++n; }); return out; } // Get the lines between from and to, as array of strings. function getLines(doc, from, to, lineFilter) { var out = []; doc.iter(from, to, function(line) { var text = line.text; if(lineFilter){ text = lineFilter(line); } out.push(text); }); return out; } // Update the height of a line, propagating the height change // upwards to parent nodes. function updateLineHeight(line, height) { var diff = height - line.height; if (diff) for (var n = line; n; n = n.parent) n.height += diff; } // Given a line object, find its line number by walking up through // its parent links. function lineNo(line) { if (line.parent == null) return null; var cur = line.parent, no = indexOf(cur.lines, line); for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) { for (var i = 0;; ++i) { if (chunk.children[i] == cur) break; no += chunk.children[i].chunkSize(); } } return no + cur.first; } // Find the line at the given vertical position, using the height // information in the document tree. function lineAtHeight(chunk, h) { var n = chunk.first; outer: do { for (var i = 0; i < chunk.children.length; ++i) { var child = chunk.children[i], ch = child.height; if (h < ch) { chunk = child; continue outer; } h -= ch; n += child.chunkSize(); } return n; } while (!chunk.lines); for (var i = 0; i < chunk.lines.length; ++i) { var line = chunk.lines[i], lh = line.height; if (h < lh) break; h -= lh; } return n + i; } // Find the height above the given line. function heightAtLine(lineObj) { lineObj = visualLine(lineObj); var h = 0, chunk = lineObj.parent; for (var i = 0; i < chunk.lines.length; ++i) { var line = chunk.lines[i]; if (line == lineObj) break; else h += line.height; } for (var p = chunk.parent; p; chunk = p, p = chunk.parent) { for (var i = 0; i < p.children.length; ++i) { var cur = p.children[i]; if (cur == chunk) break; else h += cur.height; } } return h; } // Get the bidi ordering for the given line (and cache it). Returns // false for lines that are fully left-to-right, and an array of // BidiSpan objects otherwise. function getOrder(line) { var order = line.order; if (order == null) order = line.order = bidiOrdering(line.text); return order; } // HISTORY function History(startGen) { // Arrays of change events and selections. Doing something adds an // event to done and clears undo. Undoing moves events from done // to undone, redoing moves them in the other direction. this.done = []; this.undone = []; this.undoDepth = Infinity; // Used to track when changes can be merged into a single undo // event this.lastModTime = this.lastSelTime = 0; this.lastOp = this.lastSelOp = null; this.lastOrigin = this.lastSelOrigin = null; // Used by the isClean() method this.generation = this.maxGeneration = startGen || 1; } // Create a history change event from an updateDoc-style change // object. function historyChangeFromChange(doc, change) { var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)}; attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true); return histChange; } // Pop all selection events off the end of a history array. Stop at // a change event. function clearSelectionEvents(array) { while (array.length) { var last = lst(array); if (last.ranges) array.pop(); else break; } } // Find the top change event in the history. Pop off selection // events that are in the way. function lastChangeEvent(hist, force) { if (force) { clearSelectionEvents(hist.done); return lst(hist.done); } else if (hist.done.length && !lst(hist.done).ranges) { return lst(hist.done); } else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) { hist.done.pop(); return lst(hist.done); } } // Register a change in the history. Merges changes that are within // a single operation, ore are close together with an origin that // allows merging (starting with "+") into a single event. function addChangeToHistory(doc, change, selAfter, opId) { var hist = doc.history; hist.undone.length = 0; var time = +new Date, cur; if ((hist.lastOp == opId || hist.lastOrigin == change.origin && change.origin && ((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) || change.origin.charAt(0) == "*")) && (cur = lastChangeEvent(hist, hist.lastOp == opId))) { // Merge this change into the last event var last = lst(cur.changes); if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) { // Optimized case for simple insertion -- don't want to add // new changesets for every character typed last.to = changeEnd(change); } else { // Add new sub-event cur.changes.push(historyChangeFromChange(doc, change)); } } else { // Can not be merged, start a new event. var before = lst(hist.done); if (!before || !before.ranges) pushSelectionToHistory(doc.sel, hist.done); cur = {changes: [historyChangeFromChange(doc, change)], generation: hist.generation}; hist.done.push(cur); while (hist.done.length > hist.undoDepth) { hist.done.shift(); if (!hist.done[0].ranges) hist.done.shift(); } } hist.done.push(selAfter); hist.generation = ++hist.maxGeneration; hist.lastModTime = hist.lastSelTime = time; hist.lastOp = hist.lastSelOp = opId; hist.lastOrigin = hist.lastSelOrigin = change.origin; if (!last) signal(doc, "historyAdded"); } function selectionEventCanBeMerged(doc, origin, prev, sel) { var ch = origin.charAt(0); return ch == "*" || ch == "+" && prev.ranges.length == sel.ranges.length && prev.somethingSelected() == sel.somethingSelected() && new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500); } // Called whenever the selection changes, sets the new selection as // the pending selection in the history, and pushes the old pending // selection into the 'done' array when it was significantly // different (in number of selected ranges, emptiness, or time). function addSelectionToHistory(doc, sel, opId, options) { var hist = doc.history, origin = options && options.origin; // A new event is started when the previous origin does not match // the current, or the origins don't allow matching. Origins // starting with * are always merged, those starting with + are // merged when similar and close together in time. if (opId == hist.lastSelOp || (origin && hist.lastSelOrigin == origin && (hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin || selectionEventCanBeMerged(doc, origin, lst(hist.done), sel)))) hist.done[hist.done.length - 1] = sel; else pushSelectionToHistory(sel, hist.done); hist.lastSelTime = +new Date; hist.lastSelOrigin = origin; hist.lastSelOp = opId; if (options && options.clearRedo !== false) clearSelectionEvents(hist.undone); } function pushSelectionToHistory(sel, dest) { var top = lst(dest); if (!(top && top.ranges && top.equals(sel))) dest.push(sel); } // Used to store marked span information in the history. function attachLocalSpans(doc, change, from, to) { var existing = change["spans_" + doc.id], n = 0; doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) { if (line.markedSpans) (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; ++n; }); } // When un/re-doing restores text containing marked spans, those // that have been explicitly cleared should not be restored. function removeClearedSpans(spans) { if (!spans) return null; for (var i = 0, out; i < spans.length; ++i) { if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); } else if (out) out.push(spans[i]); } return !out ? spans : out.length ? out : null; } // Retrieve and filter the old marked spans stored in a change event. function getOldSpans(doc, change) { var found = change["spans_" + doc.id]; if (!found) return null; for (var i = 0, nw = []; i < change.text.length; ++i) nw.push(removeClearedSpans(found[i])); return nw; } // Used both to provide a JSON-safe object in .getHistory, and, when // detaching a document, to split the history in two function copyHistoryArray(events, newGroup, instantiateSel) { for (var i = 0, copy = []; i < events.length; ++i) { var event = events[i]; if (event.ranges) { copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event); continue; } var changes = event.changes, newChanges = []; copy.push({changes: newChanges}); for (var j = 0; j < changes.length; ++j) { var change = changes[j], m; newChanges.push({from: change.from, to: change.to, text: change.text}); if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) { if (indexOf(newGroup, Number(m[1])) > -1) { lst(newChanges)[prop] = change[prop]; delete change[prop]; } } } } return copy; } // Rebasing/resetting history to deal with externally-sourced changes function rebaseHistSelSingle(pos, from, to, diff) { if (to < pos.line) { pos.line += diff; } else if (from < pos.line) { pos.line = from; pos.ch = 0; } } // Tries to rebase an array of history events given a change in the // document. If the change touches the same lines as the event, the // event, and everything 'behind' it, is discarded. If the change is // before the event, the event's positions are updated. Uses a // copy-on-write scheme for the positions, to avoid having to // reallocate them all on every rebase, but also avoid problems with // shared position objects being unsafely updated. function rebaseHistArray(array, from, to, diff) { for (var i = 0; i < array.length; ++i) { var sub = array[i], ok = true; if (sub.ranges) { if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; } for (var j = 0; j < sub.ranges.length; j++) { rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff); rebaseHistSelSingle(sub.ranges[j].head, from, to, diff); } continue; } for (var j = 0; j < sub.changes.length; ++j) { var cur = sub.changes[j]; if (to < cur.from.line) { cur.from = Pos(cur.from.line + diff, cur.from.ch); cur.to = Pos(cur.to.line + diff, cur.to.ch); } else if (from <= cur.to.line) { ok = false; break; } } if (!ok) { array.splice(0, i + 1); i = 0; } } } function rebaseHist(hist, change) { var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1; rebaseHistArray(hist.done, from, to, diff); rebaseHistArray(hist.undone, from, to, diff); } // EVENT UTILITIES // Due to the fact that we still support jurassic IE versions, some // compatibility wrappers are needed. var e_preventDefault = CodeMirror.e_preventDefault = function(e) { if (e.preventDefault) e.preventDefault(); else e.returnValue = false; }; var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) { if (e.stopPropagation) e.stopPropagation(); else e.cancelBubble = true; }; function e_defaultPrevented(e) { return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false; } var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);}; function e_target(e) {return e.target || e.srcElement;} function e_button(e) { var b = e.which; if (b == null) { if (e.button & 1) b = 1; else if (e.button & 2) b = 3; else if (e.button & 4) b = 2; } if (mac && e.ctrlKey && b == 1) b = 3; return b; } // EVENT HANDLING // Lightweight event framework. on/off also work on DOM nodes, // registering native DOM handlers. var on = CodeMirror.on = function(emitter, type, f) { if (emitter.addEventListener) emitter.addEventListener(type, f, false); else if (emitter.attachEvent) emitter.attachEvent("on" + type, f); else { var map = emitter._handlers || (emitter._handlers = {}); var arr = map[type] || (map[type] = []); arr.push(f); } }; var off = CodeMirror.off = function(emitter, type, f) { if (emitter.removeEventListener) emitter.removeEventListener(type, f, false); else if (emitter.detachEvent) emitter.detachEvent("on" + type, f); else { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; for (var i = 0; i < arr.length; ++i) if (arr[i] == f) { arr.splice(i, 1); break; } } }; var signal = CodeMirror.signal = function(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; var args = Array.prototype.slice.call(arguments, 2); for (var i = 0; i < arr.length; ++i) arr[i].apply(null, args); }; var orphanDelayedCallbacks = null; // Often, we want to signal events at a point where we are in the // middle of some work, but don't want the handler to start calling // other methods on the editor, which might be in an inconsistent // state or simply not expect any other events to happen. // signalLater looks whether there are any handlers, and schedules // them to be executed when the last operation ends, or, if no // operation is active, when a timeout fires. function signalLater(emitter, type /*, values...*/) { var arr = emitter._handlers && emitter._handlers[type]; if (!arr) return; var args = Array.prototype.slice.call(arguments, 2), list; if (operationGroup) { list = operationGroup.delayedCallbacks; } else if (orphanDelayedCallbacks) { list = orphanDelayedCallbacks; } else { list = orphanDelayedCallbacks = []; setTimeout(fireOrphanDelayed, 0); } function bnd(f) {return function(){f.apply(null, args);};}; for (var i = 0; i < arr.length; ++i) list.push(bnd(arr[i])); } function fireOrphanDelayed() { var delayed = orphanDelayedCallbacks; orphanDelayedCallbacks = null; for (var i = 0; i < delayed.length; ++i) delayed[i](); } // The DOM events that CodeMirror handles can be overridden by // registering a (non-DOM) handler on the editor for the event name, // and preventDefault-ing the event in that handler. function signalDOMEvent(cm, e, override) { if (typeof e == "string") e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; signal(cm, override || e.type, cm, e); return e_defaultPrevented(e) || e.codemirrorIgnore; } function signalCursorActivity(cm) { var arr = cm._handlers && cm._handlers.cursorActivity; if (!arr) return; var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []); for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1) set.push(arr[i]); } function hasHandler(emitter, type) { var arr = emitter._handlers && emitter._handlers[type]; return arr && arr.length > 0; } // Add on and off methods to a constructor's prototype, to make // registering events on such objects more convenient. function eventMixin(ctor) { ctor.prototype.on = function(type, f) {on(this, type, f);}; ctor.prototype.off = function(type, f) {off(this, type, f);}; } // MISC UTILITIES // Number of pixels added to scroller and sizer to hide scrollbar var scrollerGap = 30; // Returned or thrown by various protocols to signal 'I'm not // handling this'. var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}}; // Reused option objects for setSelection & friends var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"}; function Delayed() {this.id = null;} Delayed.prototype.set = function(ms, f) { clearTimeout(this.id); this.id = setTimeout(f, ms); }; // Counts the column offset in a string, taking tabs into account. // Used mostly to find indentation. var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) { if (end == null) { end = string.search(/[^\s\u00a0]/); if (end == -1) end = string.length; } for (var i = startIndex || 0, n = startValue || 0;;) { var nextTab = string.indexOf("\t", i); if (nextTab < 0 || nextTab >= end) return n + (end - i); n += nextTab - i; n += tabSize - (n % tabSize); i = nextTab + 1; } }; // The inverse of countColumn -- find the offset that corresponds to // a particular column. function findColumn(string, goal, tabSize) { for (var pos = 0, col = 0;;) { var nextTab = string.indexOf("\t", pos); if (nextTab == -1) nextTab = string.length; var skipped = nextTab - pos; if (nextTab == string.length || col + skipped >= goal) return pos + Math.min(skipped, goal - col); col += nextTab - pos; col += tabSize - (col % tabSize); pos = nextTab + 1; if (col >= goal) return pos; } } var spaceStrs = [""]; function spaceStr(n) { while (spaceStrs.length <= n) spaceStrs.push(lst(spaceStrs) + " "); return spaceStrs[n]; } function lst(arr) { return arr[arr.length-1]; } var selectInput = function(node) { node.select(); }; if (ios) // Mobile Safari apparently has a bug where select() is broken. selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; else if (ie) // Suppress mysterious IE10 errors selectInput = function(node) { try { node.select(); } catch(_e) {} }; function indexOf(array, elt) { for (var i = 0; i < array.length; ++i) if (array[i] == elt) return i; return -1; } function map(array, f) { var out = []; for (var i = 0; i < array.length; i++) out[i] = f(array[i], i); return out; } function nothing() {} function createObj(base, props) { var inst; if (Object.create) { inst = Object.create(base); } else { nothing.prototype = base; inst = new nothing(); } if (props) copyObj(props, inst); return inst; }; function copyObj(obj, target, overwrite) { if (!target) target = {}; for (var prop in obj) if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) target[prop] = obj[prop]; return target; } function bind(f) { var args = Array.prototype.slice.call(arguments, 1); return function(){return f.apply(null, args);}; } var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; var isWordCharBasic = CodeMirror.isWordChar = function(ch) { return /\w/.test(ch) || ch > "\x80" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch)); }; function isWordChar(ch, helper) { if (!helper) return isWordCharBasic(ch); if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true; return helper.test(ch); } function isEmpty(obj) { for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false; return true; } // Extending unicode characters. A series of a non-extending char + // any number of extending chars is treated as a single unit as far // as editing and measuring is concerned. This is not fully correct, // since some scripts/font/browsers also treat other configurations // of code points as a group. var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/; function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); } // DOM UTILITIES function elt(tag, content, className, style) { var e = document.createElement(tag); if (className) e.className = className; if (style) e.style.cssText = style; if (typeof content == "string") e.appendChild(document.createTextNode(content)); else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]); return e; } var range; if (document.createRange) range = function(node, start, end, endNode) { var r = document.createRange(); r.setEnd(endNode || node, end); r.setStart(node, start); return r; }; else range = function(node, start, end) { var r = document.body.createTextRange(); try { r.moveToElementText(node.parentNode); } catch(e) { return r; } r.collapse(true); r.moveEnd("character", end); r.moveStart("character", start); return r; }; function removeChildren(e) { for (var count = e.childNodes.length; count > 0; --count) e.removeChild(e.firstChild); return e; } function removeChildrenAndAdd(parent, e) { return removeChildren(parent).appendChild(e); } var contains = CodeMirror.contains = function(parent, child) { if (child.nodeType == 3) // Android browser always returns false when child is a textnode child = child.parentNode; if (parent.contains) return parent.contains(child); do { if (child.nodeType == 11) child = child.host; if (child == parent) return true; } while (child = child.parentNode); }; function activeElt() { return document.activeElement; } // Older versions of IE throws unspecified error when touching // document.activeElement in some cases (during loading, in iframe) if (ie && ie_version < 11) activeElt = function() { try { return document.activeElement; } catch(e) { return document.body; } }; function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); } var rmClass = CodeMirror.rmClass = function(node, cls) { var current = node.className; var match = classTest(cls).exec(current); if (match) { var after = current.slice(match.index + match[0].length); node.className = current.slice(0, match.index) + (after ? match[1] + after : ""); } }; var addClass = CodeMirror.addClass = function(node, cls) { var current = node.className; if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls; }; function joinClasses(a, b) { var as = a.split(" "); for (var i = 0; i < as.length; i++) if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i]; return b; } // WINDOW-WIDE EVENTS // These must be handled carefully, because naively registering a // handler for each editor will cause the editors to never be // garbage collected. function forEachCodeMirror(f) { if (!document.body.getElementsByClassName) return; var byClass = document.body.getElementsByClassName("CodeMirror"); for (var i = 0; i < byClass.length; i++) { var cm = byClass[i].CodeMirror; if (cm) f(cm); } } var globalsRegistered = false; function ensureGlobalHandlers() { if (globalsRegistered) return; registerGlobalHandlers(); globalsRegistered = true; } function registerGlobalHandlers() { // When the window resizes, we need to refresh active editors. var resizeTimer; on(window, "resize", function() { if (resizeTimer == null) resizeTimer = setTimeout(function() { resizeTimer = null; forEachCodeMirror(onResize); }, 100); }); // When the window loses focus, we want to show the editor as blurred on(window, "blur", function() { forEachCodeMirror(onBlur); }); } // FEATURE DETECTION // Detect drag-and-drop var dragAndDrop = function() { // There is *some* kind of drag-and-drop support in IE6-8, but I // couldn't get it to work yet. if (ie && ie_version < 9) return false; var div = elt('div'); return "draggable" in div || "dragDrop" in div; }(); var zwspSupported; function zeroWidthElement(measure) { if (zwspSupported == null) { var test = elt("span", "\u200b"); removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")])); if (measure.firstChild.offsetHeight != 0) zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); } var node = zwspSupported ? elt("span", "\u200b") : elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px"); node.setAttribute("cm-text", ""); return node; } // Feature-detect IE's crummy client rect reporting for bidi text var badBidiRects; function hasBadBidiRects(measure) { if (badBidiRects != null) return badBidiRects; var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA")); var r0 = range(txt, 0, 1).getBoundingClientRect(); if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780) var r1 = range(txt, 1, 2).getBoundingClientRect(); return badBidiRects = (r1.right - r0.right < 3); } // See if "".split is the broken IE version, if so, provide an // alternative way to split lines. var splitLines = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) { var pos = 0, result = [], l = string.length; while (pos <= l) { var nl = string.indexOf("\n", pos); if (nl == -1) nl = string.length; var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl); var rt = line.indexOf("\r"); if (rt != -1) { result.push(line.slice(0, rt)); pos += rt + 1; } else { result.push(line); pos = nl + 1; } } return result; } : function(string){return string.split(/\r\n?|\n/);}; var hasSelection = window.getSelection ? function(te) { try { return te.selectionStart != te.selectionEnd; } catch(e) { return false; } } : function(te) { try {var range = te.ownerDocument.selection.createRange();} catch(e) {} if (!range || range.parentElement() != te) return false; return range.compareEndPoints("StartToEnd", range) != 0; }; var hasCopyEvent = (function() { var e = elt("div"); if ("oncopy" in e) return true; e.setAttribute("oncopy", "return;"); return typeof e.oncopy == "function"; })(); var badZoomedRects = null; function hasBadZoomedRects(measure) { if (badZoomedRects != null) return badZoomedRects; var node = removeChildrenAndAdd(measure, elt("span", "x")); var normal = node.getBoundingClientRect(); var fromRange = range(node, 0, 1).getBoundingClientRect(); return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1; } // KEY NAMES var keyNames = {3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt", 19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End", 36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert", 46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod", 107: "=", 109: "-", 127: "Delete", 173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\", 221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete", 63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"}; CodeMirror.keyNames = keyNames; (function() { // Number keys for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i); // Alphabetic keys for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i); // Function keys for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i; })(); // BIDI HELPERS function iterateBidiSections(order, from, to, f) { if (!order) return f(from, to, "ltr"); var found = false; for (var i = 0; i < order.length; ++i) { var part = order[i]; if (part.from < to && part.to > from || from == to && part.to == from) { f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr"); found = true; } } if (!found) f(from, to, "ltr"); } function bidiLeft(part) { return part.level % 2 ? part.to : part.from; } function bidiRight(part) { return part.level % 2 ? part.from : part.to; } function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; } function lineRight(line) { var order = getOrder(line); if (!order) return line.text.length; return bidiRight(lst(order)); } function lineStart(cm, lineN) { var line = getLine(cm.doc, lineN); var visual = visualLine(line); if (visual != line) lineN = lineNo(visual); var order = getOrder(visual); var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual); return Pos(lineN, ch); } function lineEnd(cm, lineN) { var merged, line = getLine(cm.doc, lineN); while (merged = collapsedSpanAtEnd(line)) { line = merged.find(1, true).line; lineN = null; } var order = getOrder(line); var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line); return Pos(lineN == null ? lineNo(line) : lineN, ch); } function lineStartSmart(cm, pos) { var start = lineStart(cm, pos.line); var line = getLine(cm.doc, start.line); var order = getOrder(line); if (!order || order[0].level == 0) { var firstNonWS = Math.max(0, line.text.search(/\S/)); var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch; return Pos(start.line, inWS ? 0 : firstNonWS); } return start; } function compareBidiLevel(order, a, b) { var linedir = order[0].level; if (a == linedir) return true; if (b == linedir) return false; return a < b; } var bidiOther; function getBidiPartAt(order, pos) { bidiOther = null; for (var i = 0, found; i < order.length; ++i) { var cur = order[i]; if (cur.from < pos && cur.to > pos) return i; if ((cur.from == pos || cur.to == pos)) { if (found == null) { found = i; } else if (compareBidiLevel(order, cur.level, order[found].level)) { if (cur.from != cur.to) bidiOther = found; return i; } else { if (cur.from != cur.to) bidiOther = i; return found; } } } return found; } function moveInLine(line, pos, dir, byUnit) { if (!byUnit) return pos + dir; do pos += dir; while (pos > 0 && isExtendingChar(line.text.charAt(pos))); return pos; } // This is needed in order to move 'visually' through bi-directional // text -- i.e., pressing left should make the cursor go left, even // when in RTL text. The tricky part is the 'jumps', where RTL and // LTR text touch each other. This often requires the cursor offset // to move more than one unit, in order to visually move one unit. function moveVisually(line, start, dir, byUnit) { var bidi = getOrder(line); if (!bidi) return moveLogically(line, start, dir, byUnit); var pos = getBidiPartAt(bidi, start), part = bidi[pos]; var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit); for (;;) { if (target > part.from && target < part.to) return target; if (target == part.from || target == part.to) { if (getBidiPartAt(bidi, target) == pos) return target; part = bidi[pos += dir]; return (dir > 0) == part.level % 2 ? part.to : part.from; } else { part = bidi[pos += dir]; if (!part) return null; if ((dir > 0) == part.level % 2) target = moveInLine(line, part.to, -1, byUnit); else target = moveInLine(line, part.from, 1, byUnit); } } } function moveLogically(line, start, dir, byUnit) { var target = start + dir; if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir; return target < 0 || target > line.text.length ? null : target; } // Bidirectional ordering algorithm // See http://unicode.org/reports/tr9/tr9-13.html for the algorithm // that this (partially) implements. // One-char codes used for character types: // L (L): Left-to-Right // R (R): Right-to-Left // r (AL): Right-to-Left Arabic // 1 (EN): European Number // + (ES): European Number Separator // % (ET): European Number Terminator // n (AN): Arabic Number // , (CS): Common Number Separator // m (NSM): Non-Spacing Mark // b (BN): Boundary Neutral // s (B): Paragraph Separator // t (S): Segment Separator // w (WS): Whitespace // N (ON): Other Neutrals // Returns null if characters are ordered as they appear // (left-to-right), or an array of sections ({from, to, level} // objects) in the order in which they occur visually. var bidiOrdering = (function() { // Character types for codepoints 0 to 0xff var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN"; // Character types for codepoints 0x600 to 0x6ff var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm"; function charType(code) { if (code <= 0xf7) return lowTypes.charAt(code); else if (0x590 <= code && code <= 0x5f4) return "R"; else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600); else if (0x6ee <= code && code <= 0x8ac) return "r"; else if (0x2000 <= code && code <= 0x200b) return "w"; else if (code == 0x200c) return "b"; else return "L"; } var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/; var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/; // Browsers seem to always treat the boundaries of block elements as being L. var outerType = "L"; function BidiSpan(level, from, to) { this.level = level; this.from = from; this.to = to; } return function(str) { if (!bidiRE.test(str)) return false; var len = str.length, types = []; for (var i = 0, type; i < len; ++i) types.push(type = charType(str.charCodeAt(i))); // W1. Examine each non-spacing mark (NSM) in the level run, and // change the type of the NSM to the type of the previous // character. If the NSM is at the start of the level run, it will // get the type of sor. for (var i = 0, prev = outerType; i < len; ++i) { var type = types[i]; if (type == "m") types[i] = prev; else prev = type; } // W2. Search backwards from each instance of a European number // until the first strong type (R, L, AL, or sor) is found. If an // AL is found, change the type of the European number to Arabic // number. // W3. Change all ALs to R. for (var i = 0, cur = outerType; i < len; ++i) { var type = types[i]; if (type == "1" && cur == "r") types[i] = "n"; else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; } } // W4. A single European separator between two European numbers // changes to a European number. A single common separator between // two numbers of the same type changes to that type. for (var i = 1, prev = types[0]; i < len - 1; ++i) { var type = types[i]; if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1"; else if (type == "," && prev == types[i+1] && (prev == "1" || prev == "n")) types[i] = prev; prev = type; } // W5. A sequence of European terminators adjacent to European // numbers changes to all European numbers. // W6. Otherwise, separators and terminators change to Other // Neutral. for (var i = 0; i < len; ++i) { var type = types[i]; if (type == ",") types[i] = "N"; else if (type == "%") { for (var end = i + 1; end < len && types[end] == "%"; ++end) {} var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N"; for (var j = i; j < end; ++j) types[j] = replace; i = end - 1; } } // W7. Search backwards from each instance of a European number // until the first strong type (R, L, or sor) is found. If an L is // found, then change the type of the European number to L. for (var i = 0, cur = outerType; i < len; ++i) { var type = types[i]; if (cur == "L" && type == "1") types[i] = "L"; else if (isStrong.test(type)) cur = type; } // N1. A sequence of neutrals takes the direction of the // surrounding strong text if the text on both sides has the same // direction. European and Arabic numbers act as if they were R in // terms of their influence on neutrals. Start-of-level-run (sor) // and end-of-level-run (eor) are used at level run boundaries. // N2. Any remaining neutrals take the embedding direction. for (var i = 0; i < len; ++i) { if (isNeutral.test(types[i])) { for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {} var before = (i ? types[i-1] : outerType) == "L"; var after = (end < len ? types[end] : outerType) == "L"; var replace = before || after ? "L" : "R"; for (var j = i; j < end; ++j) types[j] = replace; i = end - 1; } } // Here we depart from the documented algorithm, in order to avoid // building up an actual levels array. Since there are only three // levels (0, 1, 2) in an implementation that doesn't take // explicit embedding into account, we can build up the order on // the fly, without following the level-based algorithm. var order = [], m; for (var i = 0; i < len;) { if (countsAsLeft.test(types[i])) { var start = i; for (++i; i < len && countsAsLeft.test(types[i]); ++i) {} order.push(new BidiSpan(0, start, i)); } else { var pos = i, at = order.length; for (++i; i < len && types[i] != "L"; ++i) {} for (var j = pos; j < i;) { if (countsAsNum.test(types[j])) { if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j)); var nstart = j; for (++j; j < i && countsAsNum.test(types[j]); ++j) {} order.splice(at, 0, new BidiSpan(2, nstart, j)); pos = j; } else ++j; } if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i)); } } if (order[0].level == 1 && (m = str.match(/^\s+/))) { order[0].from = m[0].length; order.unshift(new BidiSpan(0, 0, m[0].length)); } if (lst(order).level == 1 && (m = str.match(/\s+$/))) { lst(order).to -= m[0].length; order.push(new BidiSpan(0, len - m[0].length, len)); } if (order[0].level == 2) order.unshift(new BidiSpan(1, order[0].to, order[0].to)); if (order[0].level != lst(order).level) order.push(new BidiSpan(order[0].level, len, len)); return order; }; })(); // THE END CodeMirror.version = "5.4.1"; return CodeMirror; });(function (mod) { mod(CodeMirror); })(function (CodeMirror) { var Pos = CodeMirror.Pos; function forEach(arr, f) { for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); } function arrayContains(arr, item) { if (!Array.prototype.indexOf) { var i = arr.length; while (i--) { if (arr[i] === item) { return true; } } return false; } return arr.indexOf(item) != -1; } function scriptHint(editor, keywords, getToken, options) { // Find the token at the cursor var cur = editor.getCursor(), token = getToken(editor, cur); if (/\b(?:string)\b/.test(token.type)) { return; } token.state = CodeMirror.innerMode(editor.getMode(), token.state).state; if (!/^[\w$_]*$/.test(token.string)) { token = { start: cur.ch, end: cur.ch, string: "", state: token.state, type: token.string == "." ? "property" : null }; } else if (token.end > cur.ch) { token.end = cur.ch; token.string = token.string.slice(0, cur.ch - token.start); } var tprop = token; // If it is a property, find out what it is a property of. while (tprop.type == "property") { tprop = getToken(editor, Pos(cur.line, tprop.start)); if (tprop.string != ".") return; tprop = getToken(editor, Pos(cur.line, tprop.start)); if (!context) var context = []; context.push(tprop); } return { list: getCompletions(token, context, keywords, options), from: Pos(cur.line, token.start), to: Pos(cur.line, token.end) }; } function getFormulaKeywords() { return BI.FormulaCollections; } function formulaHint(editor, options) { return scriptHint(editor, getFormulaKeywords(), function (e, cur) { return e.getTokenAt(cur); }, options); }; CodeMirror.registerHelper("hint", "formula", formulaHint); function getCompletions(token, context, keywords, options) { var found = [], start = token.string; if (!start) { return found; } function maybeAdd(str) { if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) { found.push(str); } } if (context && context.length) { context.pop(); } else { forEach(keywords, maybeAdd); } return found; } });(function (mod) { mod(CodeMirror); })(function (CodeMirror) { "use strict"; CodeMirror.defineMode('formula', function () { function wordObj(words) { var o = {}; for (var i = 0, e = words.length; i < e; ++i) o[words[i]] = true; return o; } var atoms = wordObj(['false', 'true']); var keywords = wordObj(BI.FormulaCollections); function tokenBase(stream, state) { if (stream.eatSpace()) { return null; } var ch = stream.next(); if (ch === '"' || ch === '\'') { nextUntilUnescaped(stream, ch); return "string"; } if (/[\[\],\(\)]/.test(ch)) { return 'bracket'; } // richie:暂时不需要解析操作符号 //if (/[+\-*\/=<>!&|]/.test(ch)) { // return 'operator'; //} //if (/\d|\d./.test(ch)) { // stream.eatWhile(/\d|\./); // if (stream.eol() || !/\w/.test(stream.peek())) { // return 'number'; // } //} stream.eatWhile(/[\w-]/); var word = stream.current(); if (atoms.hasOwnProperty(word)) { return "atom"; } if (keywords.hasOwnProperty(word)) { return "keyword"; } return null; } function nextUntilUnescaped(stream, end) { var escaped = false, next; while ((next = stream.next()) != null) { if (next === end && !escaped) { return false; } escaped = !escaped && next === "\\"; } return escaped; } function tokenize(stream, state) { return (state.tokens[0] || tokenBase)(stream, state); } return { startState: function () { return {tokens: []}; }, token: function (stream, state) { return tokenize(stream, state); }, fold: "brace" }; }); CodeMirror.defineMIME("text/fx-formula", "formula"); });// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: http://codemirror.net/LICENSE (function (mod) { mod(CodeMirror); })(function (CodeMirror) { "use strict"; var HINT_ELEMENT_CLASS = "CodeMirror-hint"; var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; // This is the old interface, kept around for now to stay // backwards-compatible. CodeMirror.showHint = function (cm, getHints, options) { if (!getHints) return cm.showHint(options); if (options && options.async) getHints.async = true; var newOpts = {hint: getHints}; if (options) for (var prop in options) newOpts[prop] = options[prop]; return cm.showHint(newOpts); }; CodeMirror.defineExtension("showHint", function (options) { // We want a single cursor position. if (this.listSelections().length > 1 || this.somethingSelected()) return; if (this.state.completionActive) this.state.completionActive.close(); var completion = this.state.completionActive = new Completion(this, options); if (!completion.options.hint) return; CodeMirror.signal(this, "startCompletion", this); completion.update(true); }); function Completion(cm, options) { this.cm = cm; this.options = this.buildOptions(options); this.widget = null; this.debounce = 0; this.tick = 0; this.startPos = this.cm.getCursor(); this.startLen = this.cm.getLine(this.startPos.line).length; var self = this; cm.on("cursorActivity", this.activityFunc = function () { self.cursorActivity(); }); } var requestAnimationFrame = window.requestAnimationFrame || function (fn) { return setTimeout(fn, 1000 / 60); }; var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; Completion.prototype = { close: function () { if (!this.active()) return; this.cm.state.completionActive = null; this.tick = null; this.cm.off("cursorActivity", this.activityFunc); if (this.widget && this.data) CodeMirror.signal(this.data, "close"); if (this.widget) this.widget.close(); CodeMirror.signal(this.cm, "endCompletion", this.cm); }, active: function () { return this.cm.state.completionActive == this; }, pick: function (data, i) { var completion = data.list[i]; if (completion.hint) completion.hint(this.cm, data, completion); else { this.cm.replaceRange(getText(completion), completion.from || data.from, completion.to || data.to, "complete"); var to = this.cm.getCursor(); this.cm.markText(completion.from || data.from, to, {className: "#function", atomic: true}); this.cm.replaceSelection("() "); to = this.cm.getCursor(); to.ch = to.ch - 2; this.cm.setCursor(to); this.cm.focus(); } CodeMirror.signal(data, "pick", completion); this.close(); }, cursorActivity: function () { if (this.debounce) { cancelAnimationFrame(this.debounce); this.debounce = 0; } var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || pos.ch < this.startPos.ch || this.cm.somethingSelected() || (pos.ch && this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { this.close(); } else { var self = this; this.debounce = requestAnimationFrame(function () { self.update(); }); if (this.widget) this.widget.disable(); } }, update: function (first) { if (this.tick == null) return; if (this.data) CodeMirror.signal(this.data, "update"); if (!this.options.hint.async) { this.finishUpdate(this.options.hint(this.cm, this.options), first); } else { var myTick = ++this.tick, self = this; this.options.hint(this.cm, function (data) { if (self.tick == myTick) self.finishUpdate(data, first); }, this.options); } }, finishUpdate: function (data, first) { this.data = data; var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); if (this.widget) this.widget.close(); if (data && data.list.length) { if (picked && data.list.length == 1) { this.pick(data, 0); } else { this.widget = new Widget(this, data); CodeMirror.signal(data, "shown"); } } }, buildOptions: function (options) { var editor = this.cm.options.hintOptions; var out = {}; for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; if (editor) for (var prop in editor) if (editor[prop] !== undefined) out[prop] = editor[prop]; if (options) for (var prop in options) if (options[prop] !== undefined) out[prop] = options[prop]; return out; } }; function getText(completion) { if (typeof completion == "string") return completion; else return completion.text; } function buildKeyMap(completion, handle) { var baseMap = { Up: function () { handle.moveFocus(-1); }, Down: function () { handle.moveFocus(1); }, PageUp: function () { handle.moveFocus(-handle.menuSize() + 1, true); }, PageDown: function () { handle.moveFocus(handle.menuSize() - 1, true); }, Home: function () { handle.setFocus(0); }, End: function () { handle.setFocus(handle.length - 1); }, Enter: handle.pick, Tab: handle.pick, Esc: handle.close }; var custom = completion.options.customKeys; var ourMap = custom ? {} : baseMap; function addBinding(key, val) { var bound; if (typeof val != "string") bound = function (cm) { return val(cm, handle); }; // This mechanism is deprecated else if (baseMap.hasOwnProperty(val)) bound = baseMap[val]; else bound = val; ourMap[key] = bound; } if (custom) for (var key in custom) if (custom.hasOwnProperty(key)) addBinding(key, custom[key]); var extra = completion.options.extraKeys; if (extra) for (var key in extra) if (extra.hasOwnProperty(key)) addBinding(key, extra[key]); return ourMap; } function getHintElement(hintsElement, el) { while (el && el != hintsElement) { if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; el = el.parentNode; } } function Widget(completion, data) { this.completion = completion; this.data = data; this.picked = false; var widget = this, cm = completion.cm; var hints = this.hints = document.createElement("ul"); hints.className = "CodeMirror-hints"; this.selectedHint = data.selectedHint || 0; var completions = data.list; for (var i = 0; i < completions.length; ++i) { var elt = hints.appendChild(document.createElement("li")), cur = completions[i]; var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); if (cur.className != null) className = cur.className + " " + className; elt.className = className; if (cur.render) cur.render(elt, data, cur); else elt.appendChild(document.createTextNode(cur.displayText || getText(cur))); elt.hintId = i; } var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); var left = pos.left, top = pos.bottom, below = true; hints.style.left = left + "px"; hints.style.top = top + "px"; // If we're at the edge of the screen, then we want the menu to appear on the left of the cursor. var winW = window.innerWidth || Math.max(document.body.offsetWidth, document.documentElement.offsetWidth); var winH = window.innerHeight || Math.max(document.body.offsetHeight, document.documentElement.offsetHeight); (completion.options.container || document.body).appendChild(hints); var box = hints.getBoundingClientRect(), overlapY = box.bottom - winH; if (overlapY > 0) { var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); if (curTop - height > 0) { // Fits above cursor hints.style.top = (top = pos.top - height) + "px"; below = false; } else if (height > winH) { hints.style.height = (winH - 5) + "px"; hints.style.top = (top = pos.bottom - box.top) + "px"; var cursor = cm.getCursor(); if (data.from.ch != cursor.ch) { pos = cm.cursorCoords(cursor); hints.style.left = (left = pos.left) + "px"; box = hints.getBoundingClientRect(); } } } var overlapX = box.right - winW; if (overlapX > 0) { if (box.right - box.left > winW) { hints.style.width = (winW - 5) + "px"; overlapX -= (box.right - box.left) - winW; } hints.style.left = (left = pos.left - overlapX) + "px"; } cm.addKeyMap(this.keyMap = buildKeyMap(completion, { moveFocus: function (n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, setFocus: function (n) { widget.changeActive(n); }, menuSize: function () { return widget.screenAmount(); }, length: completions.length, close: function () { completion.close(); }, pick: function () { widget.pick(); }, data: data })); if (completion.options.closeOnUnfocus) { var closingOnBlur; cm.on("blur", this.onBlur = function () { closingOnBlur = setTimeout(function () { completion.close(); }, 100); }); cm.on("focus", this.onFocus = function () { clearTimeout(closingOnBlur); }); } var startScroll = cm.getScrollInfo(); cm.on("scroll", this.onScroll = function () { var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); var newTop = top + startScroll.top - curScroll.top; var point = newTop - (window.pageYOffset || (document.documentElement || document.body).scrollTop); if (!below) point += hints.offsetHeight; if (point <= editor.top || point >= editor.bottom) return completion.close(); hints.style.top = newTop + "px"; hints.style.left = (left + startScroll.left - curScroll.left) + "px"; }); CodeMirror.on(hints, "dblclick", function (e) { var t = getHintElement(hints, e.target || e.srcElement); if (t && t.hintId != null) { widget.changeActive(t.hintId); widget.pick(); } }); CodeMirror.on(hints, "click", function (e) { var t = getHintElement(hints, e.target || e.srcElement); if (t && t.hintId != null) { widget.changeActive(t.hintId); if (completion.options.completeOnSingleClick) widget.pick(); } }); CodeMirror.on(hints, "mousedown", function () { setTimeout(function () { cm.focus(); }, 20); }); CodeMirror.signal(data, "select", completions[0], hints.firstChild); return true; } Widget.prototype = { close: function () { if (this.completion.widget != this) return; this.completion.widget = null; this.hints.parentNode.removeChild(this.hints); this.completion.cm.removeKeyMap(this.keyMap); var cm = this.completion.cm; if (this.completion.options.closeOnUnfocus) { cm.off("blur", this.onBlur); cm.off("focus", this.onFocus); } cm.off("scroll", this.onScroll); }, disable: function () { this.completion.cm.removeKeyMap(this.keyMap); var widget = this; this.keyMap = { Enter: function () { widget.picked = true; } }; this.completion.cm.addKeyMap(this.keyMap); }, pick: function () { this.completion.pick(this.data, this.selectedHint); }, changeActive: function (i, avoidWrap) { if (i >= this.data.list.length) i = avoidWrap ? this.data.list.length - 1 : 0; else if (i < 0) i = avoidWrap ? 0 : this.data.list.length - 1; if (this.selectedHint == i) return; var node = this.hints.childNodes[this.selectedHint]; node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); node = this.hints.childNodes[this.selectedHint = i]; node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; if (node.offsetTop < this.hints.scrollTop) this.hints.scrollTop = node.offsetTop - 3; else if (node.offsetTop + node.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) this.hints.scrollTop = node.offsetTop + node.offsetHeight - this.hints.clientHeight + 3; CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); }, screenAmount: function () { return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; } }; CodeMirror.registerHelper("hint", "auto", function (cm, options) { var helpers = cm.getHelpers(cm.getCursor(), "hint"), words; if (helpers.length) { for (var i = 0; i < helpers.length; i++) { var cur = helpers[i](cm, options); if (cur && cur.list.length) return cur; } } else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { if (words) return CodeMirror.hint.fromList(cm, {words: words}); } else if (CodeMirror.hint.anyword) { return CodeMirror.hint.anyword(cm, options); } }); CodeMirror.registerHelper("hint", "fromList", function (cm, options) { var cur = cm.getCursor(), token = cm.getTokenAt(cur); var found = []; for (var i = 0; i < options.words.length; i++) { var word = options.words[i]; if (word.slice(0, token.string.length) == token.string) found.push(word); } if (found.length) return { list: found, from: CodeMirror.Pos(cur.line, token.start), to: CodeMirror.Pos(cur.line, token.end) }; }); CodeMirror.commands.autocomplete = CodeMirror.showHint; var defaultOptions = { hint: CodeMirror.hint.auto, completeSingle: true, alignWithWord: true, closeCharacters: /[\s()\[\]{};:>,]/, closeOnUnfocus: true, completeOnSingleClick: true, container: null, customKeys: null, extraKeys: null }; CodeMirror.defineOption("hintOptions", null); });/** * Created by User on 2017/3/21. */ BI.FormulaCollections = ["abs","ABS","acos","ACOS","acosh","ACOSH","add2array","ADD2ARRAY","and","AND","array","ARRAY","asin","ASIN","asinh","ASINH","atan","ATAN","atan2","ATAN2","atanh","ATANH","average","AVERAGE","bitnot","BITNOT","bitoperation","BITOPERATION","ceiling","CEILING","char","CHAR","circular","CIRCULAR","class","CLASS","cnmoney","CNMONEY","code","CODE","col","COL","colcount","COLCOUNT","colname","COLNAME","combin","COMBIN","concatenate","CONCATENATE","correl","CORREL","cos","COS","cosh","COSH","count","COUNT","crosslayertotal","CROSSLAYERTOTAL","date","DATE","datedelta","DATEDELTA","datedif","DATEDIF","dateinmonth","DATEINMONTH","dateinquarter","DATEINQUARTER","dateinweek","DATEINWEEK","dateinyear","DATEINYEAR","datesubdate","DATESUBDATE","datetime","DATETIME","datetonumber","DATETONUMBER","day","DAY","days360","DAYS360","daysofmonth","DAYSOFMONTH","daysofquarter","DAYSOFQUARTER","daysofyear","DAYSOFYEAR","dayvalue","DAYVALUE","decimal","DECIMAL","decode","DECODE","degrees","DEGREES","encode","ENCODE","endwith","ENDWITH","enmoney","ENMONEY","ennumber","ENNUMBER","eval","EVAL","even","EVEN","exact","EXACT","exp","EXP","fact","FACT","fields","FIELDS","filename","FILENAME","filesize","FILESIZE","filetype","FILETYPE","find","FIND","floor","FLOOR","format","FORMAT","getuserdepartments","GETUSERDEPARTMENTS","getuserjobtitles","GETUSERJOBTITLES","greparray","GREPARRAY","hierarchy","HIERARCHY","hour","HOUR","i18n","I18N","if","IF","inarray","INARRAY","index","INDEX","indexof","INDEXOF","indexofarray","INDEXOFARRAY","int","INT","isnull","ISNULL","joinarray","JOINARRAY","jvm","JVM","layertotal","LAYERTOTAL","left","LEFT","len","LEN","let","LET","ln","LN","log","LOG","log10","LOG10","lower","LOWER","lunar","LUNAR","map","MAP","maparray","MAPARRAY","max","MAX","median","MEDIAN","mid","MID","min","MIN","minute","MINUTE","mod","MOD","mom","MOM","month","MONTH","monthdelta","MONTHDELTA","now","NOW","numto","NUMTO","nvl","NVL","odd","ODD","or","OR","pi","PI","power","POWER","product","PRODUCT","promotion","PROMOTION","proper","PROPER","proportion","PROPORTION","radians","RADIANS","rand","RAND","randbetween","RANDBETWEEN","range","RANGE","rank","RANK","records","RECORDS","regexp","REGEXP","removearray","REMOVEARRAY","repeat","REPEAT","replace","REPLACE","reverse","REVERSE","reversearray","REVERSEARRAY","right","RIGHT","round","ROUND","round5","ROUND5","rounddown","ROUNDDOWN","roundup","ROUNDUP","row","ROW","rowcount","ROWCOUNT","second","SECOND","seq","SEQ","sign","SIGN","sin","SIN","sinh","SINH","slicearray","SLICEARRAY","sort","SORT","sortarray","SORTARRAY","split","SPLIT","sql","SQL","sqrt","SQRT","startwith","STARTWITH","stdev","STDEV","substitute","SUBSTITUTE","sum","SUM","sumsq","SUMSQ","switch","SWITCH","tabledatafields","TABLEDATAFIELDS","tabledatas","TABLEDATAS","tables","TABLES","tan","TAN","tanh","TANH","time","TIME","tobigdecimal","TOBIGDECIMAL","tobinary","TOBINARY","todate","TODATE","today","TODAY","todouble","TODOUBLE","tohex","TOHEX","toimage","TOIMAGE","tointeger","TOINTEGER","tooctal","TOOCTAL","totext","TOTEXT","treelayer","TREELAYER","trim","TRIM","trunc","TRUNC","uniquearray","UNIQUEARRAY","upper","UPPER","uuid","UUID","value","VALUE","webimage","WEBIMAGE","week","WEEK","weekdate","WEEKDATE","weekday","WEEKDAY","weightedaverage","WEIGHTEDAVERAGE","year","YEAR","yeardelta","YEARDELTA"]; /** * 公式编辑控件 * @class BI.FormulaEditor * @extends BI.Widget */ BI.FormulaEditor = BI.inherit(BI.Single, { _defaultConfig: function () { return $.extend(BI.FormulaEditor.superclass._defaultConfig.apply(), { baseCls: 'bi-formula-editor bi-card', watermark: '', value: '', fieldTextValueMap: {}, showHint: true, lineHeight: 2 }); }, _init: function () { BI.FormulaEditor.superclass._init.apply(this, arguments); var o = this.options, self = this; this.editor = CodeMirror(this.element[0], { textWrapping: true, lineWrapping: true, lineNumbers: false, mode: 'formula' }); o.lineHeight === 1 ? this.element.addClass("codemirror-low-line-height") : this.element.addClass("codemirror-high-line-height"); this.editor.on("change", function (cm, change) { self._checkWaterMark(); if (o.showHint) { CodeMirror.showHint(cm, CodeMirror.formulaHint, {completeSingle: false}); } BI.nextTick(function () { self.fireEvent(BI.FormulaEditor.EVENT_CHANGE) }); }); this.editor.on("focus", function () { self._checkWaterMark(); self.fireEvent(BI.FormulaEditor.EVENT_FOCUS); }); this.editor.on("blur", function () { self.fireEvent(BI.FormulaEditor.EVENT_BLUR); }); if (BI.isKey(o.value)) { self.setValue(o.value); } if (BI.isKey(this.options.watermark)) { var self = this; this.watermark = BI.createWidget({ type: "bi.label", cls: "bi-water-mark", text: this.options.watermark, whiteSpace: "nowrap", textAlign: "left" }); BI.createWidget({ type: "bi.absolute", element: self, items: [{ el: self.watermark, left: 0, top: 0 }] }); this.watermark.element.bind( "mousedown", function (e) { self.insertString(""); self.editor.focus(); e.stopEvent(); } ); this.watermark.element.bind("click", function (e) { self.editor.focus(); e.stopEvent(); }); this.watermark.element.css({ position: "absolute", left: 3, right: 3, top: 6, bottom: 0 }); } }, _checkWaterMark: function () { var o = this.options; if (!this.disabledWaterMark && BI.isEmptyString(this.editor.getValue()) && BI.isKey(o.watermark)) { this.watermark && this.watermark.visible(); } else { this.watermark && this.watermark.invisible(); } }, disableWaterMark: function () { this.disabledWaterMark = true; this._checkWaterMark(); }, focus: function () { this.editor.focus(); }, /** * 添加字段 * @param field */ insertField: function (field) { var from = this.editor.getCursor(); this.editor.replaceSelection(field); var to = this.editor.getCursor(); this.editor.markText(from, to, {className: 'fieldName', atomic: true, startStyle: "start", endStyle: "end"}); this.editor.replaceSelection(" "); this.editor.focus(); }, insertFunction: function (fn) { var from = this.editor.getCursor(); this.editor.replaceSelection(fn); var to = this.editor.getCursor(); this.editor.markText(from, to, {className: "#function", atomic: true}); this.editor.replaceSelection("() "); to = this.editor.getCursor(); to.ch = to.ch - 2; this.editor.setCursor(to); this.editor.focus(); }, insertOperator: function (op) { var from = this.editor.getCursor(); this.editor.replaceSelection(op); var to = this.editor.getCursor(); this.editor.markText(from, to, {className: "%operator", atomic: true}); this.editor.replaceSelection(" "); this.editor.focus(); }, setFunction: function (v) { var from = this.editor.getCursor(); this.editor.replaceSelection(v); var to = this.editor.getCursor(); this.editor.markText(from, to, {className: "#function", atomic: true}); }, insertString: function (str) { this.editor.replaceSelection(str); this.editor.focus(); }, getFormulaString: function () { return this.editor.getValue(); }, getUsedFields: function () { var fieldMap = this.options.fieldTextValueMap; var fields = []; this.editor.getValue(true, function (line) { var value = line.text; _.forEach(line.markedSpans, function (i, ms) { switch (i.marker.className) { case "fieldName": var dId = fieldMap[value.substr(i.from, i.to - i.from)]; if (!fields.contains(dId)) { fields.push(dId); } } }); }); return fields; }, getCheckString: function () { return this.editor.getValue(true, function (line) { var rawText = line.text, value = line.text, num = 0; value.text = rawText; _.forEach(line.markedSpans, function (i, ms) { switch (i.marker.className) { case "fieldName": var fieldNameLength = i.to - i.from; value = value.substr(0, i.from + num) + "$a" + value.substr(i.to + num, value.length); num = num + 2 - fieldNameLength; break; } }); return value; }); }, getValue: function () { var fieldMap = this.options.fieldTextValueMap; return this.editor.getValue("\n", function (line) { var rawText = line.text, value = line.text, num = 0; value.text = rawText; _.forEach(line.markedSpans, function (i, ms) { switch (i.marker.className) { case "fieldName": var fieldNameLength = i.to - i.from; var fieldId = fieldMap[value.substr(i.from + num, fieldNameLength)]; value = value.substr(0, i.from + num) + "$\{" + fieldMap[value.substr(i.from + num, fieldNameLength)] + "\}" + value.substr(i.to + num, value.length); num += fieldId.length - fieldNameLength + 3; break; } }); return value; }); }, setValue: function (value) { this.editor.setValue(value); }, setFieldTextValueMap: function (fieldTextValueMap) { this.options.fieldTextValueMap = fieldTextValueMap; }, refresh: function () { var self = this; BI.nextTick(function () { self.editor.refresh(); }); } }); BI.FormulaEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.FormulaEditor.EVENT_BLUR = "EVENT_BLUR"; BI.FormulaEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.shortcut("bi.formula_editor", BI.FormulaEditor); /** * z-index在1亿层级 * 弹出提示消息框,用于模拟阻塞操作(通过回调函数实现) * @class BI.Msg */ $.extend(BI, { Msg: function () { var messageShow, $mask, $pop; return { alert: function (title, message, callback) { this._show(false, title, message, callback); }, confirm: function (title, message, callback) { this._show(true, title, message, callback); }, prompt: function (title, message, value, callback, min_width) { // BI.Msg.prompt(title, message, value, callback, min_width); }, toast: function (message, level, context) { context = context || $("body"); var toast = BI.createWidget({ type: "bi.toast", level: level, text: message }); BI.createWidget({ type: "bi.absolute", element: context, items: [{ el: toast, left: "50%", top: 0 }] }); if (toast.element.outerWidth() > context.outerWidth()) { toast.setWidth(context.width()); } toast.element.css({"margin-left": -1 * toast.element.outerWidth() / 2}); toast.invisible(); toast.element.slideDown(500, function () { BI.delay(function () { toast.element.slideUp(500, function () { toast.destroy(); }) }, 5000) }) }, _show: function (hasCancel, title, message, callback) { $mask = $('<div class="bi-z-index-mask">').css({ position: 'absolute', 'zIndex': BI.zIndex_tip - 2, top: 0, left: 0, right: 0, bottom: 0, opacity: 0.5 }).appendTo('body'); $pop = $('<div class="bi-message-depend">').css({ position: 'absolute', 'zIndex': BI.zIndex_tip - 1, top: 0, left: 0, right: 0, bottom: 0 }).appendTo('body'); var close = function () { messageShow.destroy(); $mask.remove(); }; var controlItems = []; if (hasCancel === true) { controlItems.push({ el: { type: 'bi.button', text: BI.i18nText("BI-Basic_Cancel"), height: 30, level: 'ignore', handler: function () { close(); if (BI.isFunction(callback)) { callback.apply(null, [false]); } } } }); } controlItems.push({ el: { type: 'bi.button', text: BI.i18nText("BI-Basic_OK"), height: 30, handler: function () { close(); if (BI.isFunction(callback)) { callback.apply(null, [true]); } } } }); var conf = { element: $pop, type: 'bi.center_adapt', items: [ { type: 'bi.border', cls: 'bi-message-content bi-card', items: { 'north': { el: { type: 'bi.border', cls: 'bi-message-title bi-background', items: { center: { el: { type: 'bi.label', text: title || BI.i18nText("BI-Basic_Prompt"), textAlign: 'left', hgap: 20, height: 50 } }, east: { el: { type: 'bi.icon_button', cls: 'bi-message-close close-font', // height: 50, handler: function () { close(); } }, width: 60 } } }, height: 50 }, 'center': { el: { type: "bi.text", cls: "bi-message-text", tgap: 60, hgap: 20, lineHeight: 30, whiteSpace: "normal", text: message } }, 'south': { el: { type: "bi.absolute", items: [{ el: { type: 'bi.right_vertical_adapt', hgap: 5, items: controlItems }, top: 0, left: 20, right: 20, bottom: 0 }] }, height: 60 } }, width: 400, height: 300 } ] }; messageShow = BI.createWidget(conf); } }; }() });/** * GridView * * Created by GUY on 2016/1/11. * @class BI.GridView * @extends BI.Widget */ BI.GridView = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.GridView.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-grid-view", // width: 400, //必设 // height: 300, //必设 overflowX: true, overflowY: true, overscanColumnCount: 0, overscanRowCount: 0, rowHeightGetter: BI.emptyFn, //number类型或function类型 columnWidthGetter: BI.emptyFn, //number类型或function类型 // estimatedColumnSize: 100, //columnWidthGetter为function时必设 // estimatedRowSize: 30, //rowHeightGetter为function时必设 scrollLeft: 0, scrollTop: 0, items: [] }); }, _init: function () { BI.GridView.superclass._init.apply(this, arguments); var self = this, o = this.options; this.renderedCells = []; this.renderedKeys = []; this.renderRange = {}; this._scrollLock = false; this._debounceRelease = BI.debounce(function () { self._scrollLock = false; }, 1000 / 60); this.container = BI.createWidget({ type: "bi.absolute" }); this.element.scroll(function () { if (self._scrollLock === true) { return; } o.scrollLeft = self.element.scrollLeft(); o.scrollTop = self.element.scrollTop(); self._calculateChildrenToRender(); self.fireEvent(BI.GridView.EVENT_SCROLL, { scrollLeft: o.scrollLeft, scrollTop: o.scrollTop }); }); BI.createWidget({ type: "bi.vertical", element: this, scrollable: o.overflowX === true && o.overflowY === true, scrolly: o.overflowX === false && o.overflowY === true, scrollx: o.overflowX === true && o.overflowY === false, items: [this.container] }); if (o.items.length > 0) { this._populate(); } if (o.scrollLeft !== 0 || o.scrollTop !== 0) { BI.nextTick(function () { self.element.scrollTop(o.scrollTop); self.element.scrollLeft(o.scrollLeft); }); } }, _getOverscanIndices: function (cellCount, overscanCellsCount, startIndex, stopIndex) { return { overscanStartIndex: Math.max(0, startIndex - overscanCellsCount), overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount) } }, _calculateChildrenToRender: function () { var self = this, o = this.options; var width = o.width, height = o.height, scrollLeft = BI.clamp(o.scrollLeft, 0, this._getMaxScrollLeft()), scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop()), overscanColumnCount = o.overscanColumnCount, overscanRowCount = o.overscanRowCount; if (height > 0 && width > 0) { var visibleColumnIndices = this._columnSizeAndPositionManager.getVisibleCellRange(width, scrollLeft); var visibleRowIndices = this._rowSizeAndPositionManager.getVisibleCellRange(height, scrollTop); if (BI.isEmpty(visibleColumnIndices) || BI.isEmpty(visibleRowIndices)) { return; } var horizontalOffsetAdjustment = this._columnSizeAndPositionManager.getOffsetAdjustment(width, scrollLeft); var verticalOffsetAdjustment = this._rowSizeAndPositionManager.getOffsetAdjustment(height, scrollTop); this._renderedColumnStartIndex = visibleColumnIndices.start; this._renderedColumnStopIndex = visibleColumnIndices.stop; this._renderedRowStartIndex = visibleRowIndices.start; this._renderedRowStopIndex = visibleRowIndices.stop; var overscanColumnIndices = this._getOverscanIndices(this.columnCount, overscanColumnCount, this._renderedColumnStartIndex, this._renderedColumnStopIndex) var overscanRowIndices = this._getOverscanIndices(this.rowCount, overscanRowCount, this._renderedRowStartIndex, this._renderedRowStopIndex); var columnStartIndex = overscanColumnIndices.overscanStartIndex; var columnStopIndex = overscanColumnIndices.overscanStopIndex; var rowStartIndex = overscanRowIndices.overscanStartIndex; var rowStopIndex = overscanRowIndices.overscanStopIndex; //算区间size var minRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStartIndex); var minColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStartIndex); var maxRowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowStopIndex); var maxColumnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnStopIndex); var top = minRowDatum.offset + verticalOffsetAdjustment; var left = minColumnDatum.offset + horizontalOffsetAdjustment; var bottom = maxRowDatum.offset + verticalOffsetAdjustment + maxRowDatum.size; var right = maxColumnDatum.offset + horizontalOffsetAdjustment + maxColumnDatum.size; //如果滚动的区间并没有超出渲染的范围 if (top >= this.renderRange.minY && bottom <= this.renderRange.maxY && left >= this.renderRange.minX && right <= this.renderRange.maxX) { return; } var renderedCells = [], renderedKeys = [], renderedWidgets = {}; var minX = this._getMaxScrollLeft(), minY = this._getMaxScrollTop(), maxX = 0, maxY = 0; var count = 0; for (var rowIndex = rowStartIndex; rowIndex <= rowStopIndex; rowIndex++) { var rowDatum = this._rowSizeAndPositionManager.getSizeAndPositionOfCell(rowIndex); for (var columnIndex = columnStartIndex; columnIndex <= columnStopIndex; columnIndex++) { var key = [rowIndex, columnIndex]; var columnDatum = this._columnSizeAndPositionManager.getSizeAndPositionOfCell(columnIndex); var index = BI.deepIndexOf(this.renderedKeys, key); var child; if (index > -1) { if (columnDatum.size !== this.renderedCells[index]._width) { this.renderedCells[index]._width = columnDatum.size; this.renderedCells[index].el.setWidth(columnDatum.size); } if (rowDatum.size !== this.renderedCells[index]._height) { this.renderedCells[index]._height = rowDatum.size; this.renderedCells[index].el.setHeight(rowDatum.size); } if (this.renderedCells[index]._left !== columnDatum.offset + horizontalOffsetAdjustment) { this.renderedCells[index].el.element.css("left", (columnDatum.offset + horizontalOffsetAdjustment) + "px"); } if (this.renderedCells[index]._top !== rowDatum.offset + verticalOffsetAdjustment) { this.renderedCells[index].el.element.css("top", (rowDatum.offset + verticalOffsetAdjustment) + "px"); } renderedCells.push(child = this.renderedCells[index]); } else { child = BI.createWidget(BI.extend({ type: "bi.label", width: columnDatum.size, height: rowDatum.size }, o.items[rowIndex][columnIndex], { cls: (o.items[rowIndex][columnIndex].cls || "") + " grid-cell" + (rowIndex === 0 ? " first-row" : "") + (columnIndex === 0 ? " first-col" : ""), _rowIndex: rowIndex, _columnIndex: columnIndex, _left: columnDatum.offset + horizontalOffsetAdjustment, _top: rowDatum.offset + verticalOffsetAdjustment })); renderedCells.push({ el: child, left: columnDatum.offset + horizontalOffsetAdjustment, top: rowDatum.offset + verticalOffsetAdjustment, _left: columnDatum.offset + horizontalOffsetAdjustment, _top: rowDatum.offset + verticalOffsetAdjustment, _width: columnDatum.size, _height: rowDatum.size }); } minX = Math.min(minX, columnDatum.offset + horizontalOffsetAdjustment); maxX = Math.max(maxX, columnDatum.offset + horizontalOffsetAdjustment + columnDatum.size); minY = Math.min(minY, rowDatum.offset + verticalOffsetAdjustment); maxY = Math.max(maxY, rowDatum.offset + verticalOffsetAdjustment + rowDatum.size); renderedKeys.push(key); renderedWidgets[count++] = child; } } //已存在的, 需要添加的和需要删除的 var existSet = {}, addSet = {}, deleteArray = []; BI.each(renderedKeys, function (i, key) { if (BI.deepContains(self.renderedKeys, key)) { existSet[i] = key; } else { addSet[i] = key; } }); BI.each(this.renderedKeys, function (i, key) { if (BI.deepContains(existSet, key)) { return; } if (BI.deepContains(addSet, key)) { return; } deleteArray.push(i); }); BI.each(deleteArray, function (i, index) { //性能优化,不调用destroy方法防止触发destroy事件 self.renderedCells[index].el._destroy(); }); var addedItems = []; BI.each(addSet, function (index) { addedItems.push(renderedCells[index]) }); this.container.addItems(addedItems); //拦截父子级关系 this.container._children = renderedWidgets; this.container.attr("items", renderedCells); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; } }, _getMaxScrollLeft: function () { return Math.max(0, this._columnSizeAndPositionManager.getTotalSize() - this.options.width + (this.options.overflowX ? BI.DOM.getScrollWidth() : 0)); }, _getMaxScrollTop: function () { return Math.max(0, this._rowSizeAndPositionManager.getTotalSize() - this.options.height + (this.options.overflowY ? BI.DOM.getScrollWidth() : 0)); }, _populate: function (items) { var self = this, o = this.options; this._reRange(); if (items && items !== this.options.items) { this.options.items = items; } if (o.items.length > 0) { this.columnCount = o.items[0].length; this.rowCount = o.items.length; } else { this.rowCount = 0; this.columnCount = 0; } this.container.setWidth(this.columnCount * o.estimatedColumnSize); this.container.setHeight(this.rowCount * o.estimatedRowSize); this._columnSizeAndPositionManager = new BI.ScalingCellSizeAndPositionManager(this.columnCount, o.columnWidthGetter, o.estimatedColumnSize); this._rowSizeAndPositionManager = new BI.ScalingCellSizeAndPositionManager(this.rowCount, o.rowHeightGetter, o.estimatedRowSize); this._calculateChildrenToRender(); this.element.scrollTop(o.scrollTop); this.element.scrollLeft(o.scrollLeft); }, setScrollLeft: function (scrollLeft) { if (this.options.scrollLeft === scrollLeft) { return; } this._scrollLock = true; this.options.scrollLeft = BI.clamp(scrollLeft || 0, 0, this._getMaxScrollLeft()); this._debounceRelease(); this._calculateChildrenToRender(); this.element.scrollLeft(this.options.scrollLeft); }, setScrollTop: function (scrollTop) { if (this.options.scrollTop === scrollTop) { return; } this._scrollLock = true; this.options.scrollTop = BI.clamp(scrollTop || 0, 0, this._getMaxScrollTop()); this._debounceRelease(); this._calculateChildrenToRender(); this.element.scrollTop(this.options.scrollTop); }, setOverflowX: function (b) { var self = this; if (this.options.overflowX !== !!b) { this.options.overflowX = !!b; BI.nextTick(function () { self.element.css({overflowX: !!b ? "auto" : "hidden"}); }); } }, setOverflowY: function (b) { var self = this; if (this.options.overflowY !== !!b) { this.options.overflowY = !!b; BI.nextTick(function () { self.element.css({overflowY: !!b ? "auto" : "hidden"}); }); } }, getScrollLeft: function () { return this.options.scrollLeft; }, getScrollTop: function () { return this.options.scrollTop; }, getMaxScrollLeft: function () { return this._getMaxScrollLeft(); }, getMaxScrollTop: function () { return this._getMaxScrollTop(); }, setEstimatedColumnSize: function (width) { this.options.estimatedColumnSize = width; }, setEstimatedRowSize: function (height) { this.options.estimatedRowSize = height; }, //重新计算children _reRange: function () { this.renderRange = {}; }, _clearChildren: function () { this.container._children = {}; this.container.attr("items", []); }, restore: function () { BI.each(this.renderedCells, function (i, cell) { cell.el._destroy(); }); this._clearChildren(); this.renderedCells = []; this.renderedKeys = []; this.renderRange = {}; this._scrollLock = false; }, populate: function (items) { if (items && items !== this.options.items) { this.restore(); } this._populate(items); } }); BI.GridView.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut('bi.grid_view', BI.GridView);/** * floatBox弹出层, * @class BI.FloatBox * @extends BI.Widget */ BI.FloatBox = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FloatBox.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-float-box bi-card", width: 600, height: 500 }) }, _init: function () { BI.FloatBox.superclass._init.apply(this, arguments); var self = this, o = this.options; this.showAction = new BI.ShowAction({ tar: this }); this._center = BI.createWidget(); this._north = BI.createWidget(); this.element.draggable && this.element.draggable({ handle: ".bi-message-title", drag: function (e, ui) { var W = $("body").width(), H = $("body").height(); if (ui.position.left + o.width > W) { ui.position.left = W - o.width; } if (ui.position.top + o.height > H) { ui.position.top = H - o.height; } if (ui.position.left < 0) { ui.position.left = 0; } if (ui.position.top < 0) { ui.position.top = 0; } } }); this._south = BI.createWidget(); BI.createWidget({ type: 'bi.border', element: this, items: { 'north': { el: { type: 'bi.border', cls: 'bi-message-title bi-background', items: { center: { el: { type: "bi.absolute", items: [{ el: this._north, left: 10, top: 0, right: 0, bottom: 0 }] } }, east: { el: { type: 'bi.icon_button', cls: 'bi-message-close close-font', height: 50, handler: function () { self.currentSectionProvider.close(); } }, width: 60 } } }, height: 50 }, 'center': { el: { type: "bi.absolute", items: [{ el: this._center, left: 10, top: 10, right: 10, bottom: 10 }] } }, 'south': { el: { type: "bi.absolute", items: [{ el: this._south, left: 10, top: 0, right: 10, bottom: 0 }] }, height: 60 } } }) }, populate: function (sectionProvider) { var self = this; if (this.currentSectionProvider && this.currentSectionProvider !== sectionProvider) { this.currentSectionProvider.destroy(); } this.currentSectionProvider = sectionProvider; sectionProvider.rebuildNorth(this._north); sectionProvider.rebuildCenter(this._center); sectionProvider.rebuildSouth(this._south); sectionProvider.on(BI.PopoverSection.EVENT_CLOSE, function () { self.close(); }) }, show: function () { this.showAction.actionPerformed(); }, hide: function () { this.showAction.actionBack(); }, open: function () { this.show(); this.fireEvent(BI.FloatBox.EVENT_FLOAT_BOX_OPEN); }, close: function () { this.hide(); this.fireEvent(BI.FloatBox.EVENT_FLOAT_BOX_CLOSED); }, setZindex: function (zindex) { this.element.css({"z-index": zindex}); }, destroyed: function () { this.currentSectionProvider && this.currentSectionProvider.destroy(); } }); BI.shortcut("bi.float_box", BI.FloatBox); BI.FloatBox.EVENT_FLOAT_BOX_CLOSED = "EVENT_FLOAT_BOX_CLOSED"; BI.FloatBox.EVENT_FLOAT_BOX_OPEN = "EVENT_FLOAT_BOX_CLOSED"; /** * 下拉框弹出层, zIndex在1000w * @class BI.PopupView * @extends BI.Widget */ BI.PopupView = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.PopupView.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-popup-view", maxWidth: 'auto', minWidth: 100, //maxHeight: 200, minHeight: 25, lgap: 0, rgap: 0, tgap: 0, bgap: 0, vgap: 0, hgap: 0, direction: BI.Direction.Top, //工具栏的方向 stopEvent: false,//是否停止mousedown、mouseup事件 stopPropagation: false, //是否停止mousedown、mouseup向上冒泡 logic: { dynamic: true }, tool: false, //自定义工具栏 tabs: [], //导航栏 buttons: [], //toolbar栏 el: { type: "bi.button_group", items: [], chooseType: 0, behaviors: {}, layouts: [{ type: "bi.vertical" }] } }) }, _init: function () { BI.PopupView.superclass._init.apply(this, arguments); var self = this, o = this.options; var fn = function (e) { e.stopPropagation(); }, stop = function (e) { e.stopEvent(); return false; }; this.element.css({ "z-index": BI.zIndex_popup, "min-width": o.minWidth + "px", "max-width": o.maxWidth + "px" }).bind({"click": fn}); this.element.bind("mousewheel", fn); o.stopPropagation && this.element.bind({"mousedown": fn, "mouseup": fn, "mouseover": fn}); o.stopEvent && this.element.bind({"mousedown": stop, "mouseup": stop, "mouseover": stop}); this.tool = this._createTool(); this.tab = this._createTab(); this.view = this._createView(); this.toolbar = this._createToolBar(); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.PopupView.EVENT_CHANGE); } }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { scrolly: false, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, vgap: o.vgap, hgap: o.hgap, items: BI.LogicFactory.createLogicItemsByDirection(o.direction, BI.extend({ cls: "list-view-outer bi-card bi-border" }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tool, this.tab, this.view, this.toolbar) }))) ) })))); }, _createView: function () { var o = this.options; this.button_group = BI.createWidget(o.el, {type: "bi.button_group"}); this.button_group.element.css({"min-height": o.minHeight + "px"}); return this.button_group; }, _createTool: function () { var o = this.options; if (false === o.tool) { return; } return BI.createWidget(o.tool) }, _createTab: function () { var o = this.options; if (o.tabs.length === 0) { return; } return BI.createWidget({ type: "bi.center", cls: "list-view-tab", height: 25, items: o.tabs }) }, _createToolBar: function () { var o = this.options; if (o.buttons.length === 0) { return; } return BI.createWidget({ type: "bi.center", cls: "list-view-toolbar bi-high-light bi-border-top", height: 30, items: BI.createItems(o.buttons, { once: false, shadow: true, isShadowShowingOnSelected: true }) }) }, getView: function () { return this.button_group; }, populate: function (items) { this.button_group.populate.apply(this.button_group, arguments); }, resetWidth: function (w) { this.options.width = w; this.element.width(w); }, resetHeight: function (h) { var tbHeight = this.toolbar ? (this.toolbar.attr("height") || 30) : 0, tabHeight = this.tab ? (this.tab.attr("height") || 25) : 0, toolHeight = ((this.tool && this.tool.attr("height")) || 25) * ((this.tool && this.tool.isVisible()) ? 1 : 0); this.view.resetHeight ? this.view.resetHeight(h - tbHeight - tabHeight - toolHeight - 2) : this.view.element.css({"max-height": (h - tbHeight - tabHeight - toolHeight - 2) + "px"}) }, setValue: function (selectedValues) { this.tab && this.tab.setValue(selectedValues); this.button_group.setValue(selectedValues); }, getValue: function () { return this.button_group.getValue(); } }); BI.PopupView.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.popup_view", BI.PopupView);/** * 搜索面板 * * Created by GUY on 2015/9/28. * @class BI.SearcherView * @extends BI.Pane */ BI.SearcherView = BI.inherit(BI.Pane, { _defaultConfig: function () { var conf = BI.SearcherView.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-searcher-view bi-card", tipText: BI.i18nText("BI-No_Select"), chooseType: BI.Selection.Single, matcher: {//完全匹配的构造器 type: "bi.button_group", behaviors: { redmark: function () { return true; } }, items: [], layouts: [{ type: "bi.vertical" }] }, searcher: { type: "bi.button_group", behaviors: { redmark: function () { return true; } }, items: [], layouts: [{ type: "bi.vertical" }] } }) }, _init: function () { BI.SearcherView.superclass._init.apply(this, arguments); var self = this, o = this.options; this.matcher = BI.createWidget(o.matcher, { type: "bi.button_group", chooseType: o.chooseType, behaviors: { redmark: function () { return true; } }, layouts: [{ type: "bi.vertical" }] }); this.matcher.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.SearcherView.EVENT_CHANGE, val, ob); } }); this.spliter = BI.createWidget({ type: "bi.vertical", height: 1, hgap: 10, items: [{ type: "bi.layout", height: 1, cls: "searcher-view-spliter bi-background" }] }); this.searcher = BI.createWidget(o.searcher, { type: "bi.button_group", chooseType: o.chooseType, behaviors: { redmark: function () { return true; } }, layouts: [{ type: "bi.vertical" }] }); this.searcher.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.SearcherView.EVENT_CHANGE, val, ob); } }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.matcher, this.spliter, this.searcher] }); }, startSearch: function () { }, stopSearch: function () { }, setValue: function (v) { this.matcher.setValue(v); this.searcher.setValue(v); }, getValue: function () { return this.matcher.getValue().concat(this.searcher.getValue()); }, populate: function (searchResult, matchResult, keyword) { searchResult || (searchResult = []); matchResult || (matchResult = []); this.setTipVisible(searchResult.length + matchResult.length === 0); this.spliter.setVisible(BI.isNotEmptyArray(matchResult) && BI.isNotEmptyArray(searchResult)); this.matcher.populate(matchResult, keyword); this.searcher.populate(searchResult, keyword); }, empty: function () { this.searcher.empty(); this.matcher.empty(); }, hasMatched: function () { return this.matcher.getAllButtons().length > 0; } }); BI.SearcherView.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.searcher_view", BI.SearcherView);/** * 表示当前对象 * * Created by GUY on 2017/5/23. * @class BI.ListView * @extends BI.Widget */ BI.ListView = BI.inherit(BI.Widget, { props: function () { return { baseCls: "bi-list-view", overscanHeight: 100, blockSize: 10, scrollTop: 0, el: {}, items: [] }; }, init: function () { var self = this; this.renderedIndex = -1; this.cache = {}; }, render: function () { var self = this, o = this.options; return { type: "bi.vertical", items: [BI.extend({ type: "bi.vertical", scrolly: false, ref: function () { self.container = this; } }, o.el)], element: this } }, mounted: function () { var self = this, o = this.options; this._populate(); this.element.scroll(function (e) { o.scrollTop = self.element.scrollTop(); self._calculateBlocksToRender(); }); BI.ResizeDetector.addResizeListener(this, function () { self._calculateBlocksToRender(); }); }, _renderMoreIf: function () { var self = this, o = this.options; var height = this.element.height(); var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0, cnt = this.renderedIndex + 1; var lastHeight; var getElementHeight = function () { return self.container.element.height(); }; while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items); var addedHeight = getElementHeight() - lastHeight; this.cache[cnt] = { index: index, scrollTop: lastHeight, height: addedHeight }; this.renderedIndex = cnt; cnt++; index += o.blockSize; } }, _calculateBlocksToRender: function () { var o = this.options; this._renderMoreIf(); }, _populate: function (items) { var o = this.options; if (items && this.options.items !== items) { this.options.items = items; } this._calculateBlocksToRender(); this.element.scrollTop(o.scrollTop); }, restore: function () { this.renderedIndex = -1; this.container.empty(); this.cache = {}; }, populate: function (items) { if (items && this.options.items !== items) { this.restore(); } this._populate(); }, destroyed: function () { this.restore(); } }); BI.shortcut('bi.list_view', BI.ListView); /** * 表示当前对象 * * Created by GUY on 2017/5/22. * @class BI.VirtualList * @extends BI.Widget */ BI.VirtualList = BI.inherit(BI.Widget, { props: function () { return { baseCls: "bi-virtual-list", overscanHeight: 100, blockSize: 10, scrollTop: 0, items: [] }; }, init: function () { var self = this; this.renderedIndex = -1; this.cache = {}; }, render: function () { var self = this, o = this.options; return { type: "bi.vertical", items: [{ type: "bi.layout", ref: function () { self.topBlank = this; } }, { type: "bi.vertical", scrolly: false, ref: function () { self.container = this; } }, { type: "bi.layout", ref: function () { self.bottomBlank = this; } }], element: this } }, mounted: function () { var self = this, o = this.options; this._populate(); this.element.scroll(function (e) { o.scrollTop = self.element.scrollTop(); self._calculateBlocksToRender(); }); BI.ResizeDetector.addResizeListener(this, function () { self._calculateBlocksToRender(); }); }, _renderMoreIf: function () { var self = this, o = this.options; var height = this.element.height(); var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0, cnt = this.renderedIndex + 1; var lastHeight; var getElementHeight = function () { return self.container.element.height() + self.topBlank.element.height() + self.bottomBlank.element.height(); }; while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items); var addedHeight = getElementHeight() - lastHeight; this.cache[cnt] = { index: index, scrollTop: lastHeight, height: addedHeight }; this.tree.set(cnt, addedHeight); this.renderedIndex = cnt; cnt++; index += o.blockSize; } }, _calculateBlocksToRender: function () { var o = this.options; this._renderMoreIf(); var height = this.element.height(); var minContentHeightFrom = o.scrollTop - o.overscanHeight; var minContentHeightTo = o.scrollTop + height + o.overscanHeight; var start = this.tree.greatestLowerBound(minContentHeightFrom); var end = this.tree.leastUpperBound(minContentHeightTo); var needDestroyed = []; for (var i = 0; i < start; i++) { var index = this.cache[i].index; if (!this.cache[i].destroyed) { for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { needDestroyed.push(this.container._children[j]); this.container._children[j] = null; } this.cache[i].destroyed = true; } } for (var i = end + 1; i <= this.renderedIndex; i++) { var index = this.cache[i].index; if (!this.cache[i].destroyed) { for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { needDestroyed.push(this.container._children[j]); this.container._children[j] = null; } this.cache[i].destroyed = true; } } var firstFragment = document.createDocumentFragment(), lastFragment = document.createDocumentFragment(); var currentFragment = firstFragment; for (var i = (start < 0 ? 0 : start); i <= end && i <= this.renderedIndex; i++) { var index = this.cache[i].index; if (!this.cache[i].destroyed) { currentFragment = lastFragment; } if (this.cache[i].destroyed === true) { for (var j = index; j < index + o.blockSize && j < o.items.length; j++) { var w = this.container._addElement(j, BI.extend({root: true}, BI.stripEL(o.items[j]))); currentFragment.appendChild(w.element[0]); } this.cache[i].destroyed = false; } } this.container.element.prepend(firstFragment); this.container.element.append(lastFragment); this.topBlank.setHeight(this.cache[start < 0 ? 0 : start].scrollTop); var lastCache = this.cache[Math.min(end, this.renderedIndex)]; this.bottomBlank.setHeight(this.tree.sumTo(this.renderedIndex) - lastCache.scrollTop - lastCache.height); BI.each(needDestroyed, function (i, child) { child && child._destroy(); }); }, _populate: function (items) { var o = this.options; if (items && this.options.items !== items) { this.options.items = items; } this.tree = BI.PrefixIntervalTree.empty(Math.ceil(o.items.length / o.blockSize)); this._calculateBlocksToRender(); this.element.scrollTop(o.scrollTop); }, _clearChildren: function () { BI.each(this.container._children, function (i, cell) { cell && cell.el._destroy(); }); this.container._children = {}; this.container.attr("items", []); }, restore: function () { this.renderedIndex = -1; this._clearChildren(); this.cache = {}; this.options.scrollTop = 0; }, populate: function (items) { if (items && this.options.items !== items) { this.restore(); } this._populate(); }, destroyed: function () { this.restore(); } }); BI.shortcut('bi.virtual_list', BI.VirtualList); /** * 分页控件 * * Created by GUY on 2015/8/31. * @class BI.Pager * @extends BI.Widget */ BI.Pager = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Pager.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-pager", behaviors: {}, layouts: [{ type: "bi.horizontal", hgap: 10, vgap: 0 }], dynamicShow: true, //是否动态显示上一页、下一页、首页、尾页, 若为false,则指对其设置使能状态 //dynamicShow为false时以下两个有用 dynamicShowFirstLast: false,//是否动态显示首页、尾页 dynamicShowPrevNext: false,//是否动态显示上一页、下一页 pages: false, //总页数 curr: function () { return 1; }, //初始化当前页 groups: 0, //连续显示分页数 jump: BI.emptyFn, //分页的回调函数 first: false, //是否显示首页 last: false, //是否显示尾页 prev: "上一页", next: "下一页", firstPage: 1, lastPage: function () { //在万不得已时才会调用这个函数获取最后一页的页码, 主要作用于setValue方法 return 1; }, hasPrev: BI.emptyFn, //pages不可用时有效 hasNext: BI.emptyFn //pages不可用时有效 }) }, _init: function () { BI.Pager.superclass._init.apply(this, arguments); var self = this; this.currPage = BI.result(this.options, "curr"); //翻页太灵敏 // this._lock = false; // this._debouce = BI.debounce(function () { // self._lock = false; // }, 300); this._populate(); }, _populate: function () { var self = this, o = this.options, view = [], dict = {}; this.empty(); var pages = BI.result(o, "pages"); var curr = BI.result(this, "currPage"); var groups = BI.result(o, "groups"); var first = BI.result(o, "first"); var last = BI.result(o, "last"); var prev = BI.result(o, "prev"); var next = BI.result(o, "next"); if (pages === false) { groups = 0; first = false; last = false; } else { groups > pages && (groups = pages); } //计算当前组 dict.index = Math.ceil((curr + ((groups > 1 && groups !== pages) ? 1 : 0)) / (groups === 0 ? 1 : groups)); //当前页非首页,则输出上一页 if (((!o.dynamicShow && !o.dynamicShowPrevNext) || curr > 1) && prev !== false) { if (BI.isKey(prev)) { view.push({ text: prev, value: "prev", disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false) }) } else { view.push(BI.extend({ disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false) }, prev)); } } //当前组非首组,则输出首页 if (((!o.dynamicShow && !o.dynamicShowFirstLast) || (dict.index > 1 && groups !== 0)) && first) { view.push({ text: first, value: "first", disabled: !(dict.index > 1 && groups !== 0) }); if (dict.index > 1 && groups !== 0) { view.push({ type: "bi.label", cls: "page-ellipsis", text: "\u2026" }); } } //输出当前页组 dict.poor = Math.floor((groups - 1) / 2); dict.start = dict.index > 1 ? curr - dict.poor : 1; dict.end = dict.index > 1 ? (function () { var max = curr + (groups - dict.poor - 1); return max > pages ? pages : max; }()) : groups; if (dict.end - dict.start < groups - 1) { //最后一组状态 dict.start = dict.end - groups + 1; } var s = dict.start, e = dict.end; if (first && last && (dict.index > 1 && groups !== 0) && (pages > groups && dict.end < pages && groups !== 0)) { s++; e--; } for (; s <= e; s++) { if (s === curr) { view.push({ text: s, value: s, selected: true }) } else { view.push({ text: s, value: s }) } } //总页数大于连续分页数,且当前组最大页小于总页,输出尾页 if (((!o.dynamicShow && !o.dynamicShowFirstLast) || (pages > groups && dict.end < pages && groups !== 0)) && last) { if (pages > groups && dict.end < pages && groups !== 0) { view.push({ type: "bi.label", cls: "page-ellipsis", text: "\u2026" }); } view.push({ text: last, value: "last", disabled: !(pages > groups && dict.end < pages && groups !== 0) }) } //当前页不为尾页时,输出下一页 dict.flow = !prev && groups === 0; if (((!o.dynamicShow && !o.dynamicShowPrevNext) && next) || (curr !== pages && next || dict.flow)) { view.push((function () { if (BI.isKey(next)) { if (pages === false) { return {text: next, value: "next", disabled: o.hasNext(curr) === false} } return (dict.flow && curr === pages) ? {text: next, value: "next", disabled: true} : {text: next, value: "next", disabled: !(curr !== pages && next || dict.flow)}; } else { return BI.extend({ disabled: pages === false ? o.hasNext(curr) === false : !(curr !== pages && next || dict.flow) }, next); } }())); } this.button_group = BI.createWidget({ type: "bi.button_group", element: this, items: BI.createItems(view, { cls: "bi-list-item-select", height: 23, hgap: 10 }), behaviors: o.behaviors, layouts: o.layouts }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { // if (self._lock === true) { // return; // } // self._lock = true; // self._debouce(); if (type === BI.Events.CLICK) { var v = self.button_group.getValue()[0]; switch (v) { case "first": self.currPage = 1; break; case "last": self.currPage = pages; break; case "prev": self.currPage--; break; case "next": self.currPage++; break; default: self.currPage = v; break; } o.jump.apply(self, [{ pages: pages, curr: self.currPage }]); self._populate(); self.fireEvent(BI.Pager.EVENT_CHANGE, obj); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.fireEvent(BI.Pager.EVENT_AFTER_POPULATE); }, getCurrentPage: function () { return this.currPage; }, setAllPages: function (pages) { this.options.pages = pages; }, hasPrev: function (v) { v || (v = 1); var o = this.options; var pages = this.options.pages; return pages === false ? o.hasPrev(v) : v > 1; }, hasNext: function (v) { v || (v = 1); var o = this.options; var pages = this.options.pages; return pages === false ? o.hasNext(v) : v < pages; }, setValue: function (v) { var o = this.options; v = v | 0; v = v < 1 ? 1 : v; if (o.pages === false) { var lastPage = BI.result(o, "lastPage"), firstPage = 1; this.currPage = v > lastPage ? lastPage : ((firstPage = BI.result(o, "firstPage")), (v < firstPage ? firstPage : v)); } else { v = v > o.pages ? o.pages : v; this.currPage = v; } this._populate(); }, getValue: function () { var val = this.button_group.getValue()[0]; switch (val) { case "prev": return -1; case "next": return 1; case "first": return BI.MIN; case "last": return BI.MAX; default : return val; } }, attr: function (key, value) { BI.Pager.superclass.attr.apply(this, arguments); if (key === "curr") { this.currPage = BI.result(this.options, "curr"); } }, populate: function () { this._populate(); } }); BI.Pager.EVENT_CHANGE = "EVENT_CHANGE"; BI.Pager.EVENT_AFTER_POPULATE = "EVENT_AFTER_POPULATE"; BI.shortcut("bi.pager", BI.Pager);/** * 超链接 * * Created by GUY on 2015/9/9. * @class BI.A * @extends BI.Text * @abstract */ BI.A = BI.inherit(BI.Text, { _defaultConfig: function () { var conf = BI.A.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-a display-block", href: "", target: "_blank", el: null, element: "<a/>" }) }, _init: function () { var o = this.options; BI.A.superclass._init.apply(this, arguments); this.element.attr({href: o.href, target: o.target}); if (o.el) { BI.createWidget(o.el, { element: this }); } } }); BI.shortcut("bi.a", BI.A);/** * guy * 加载条 * @type {*|void|Object} */ BI.LoadingBar = BI.inherit(BI.Single, { consts: { loadedText: BI.i18nText("BI-Load_More"), endText: BI.i18nText("BI-No_More_Data") }, _defaultConfig: function() { var conf = BI.LoadingBar.superclass._defaultConfig.apply(this, arguments); return BI.extend( conf, { baseCls : (conf.baseCls ||"")+' bi-loading-bar bi-tips', height: 30, handler: BI.emptyFn }) }, _init : function() { BI.LoadingBar.superclass._init.apply(this, arguments); var self = this; this.loaded = BI.createWidget({ type: "bi.text_button", cls: "loading-text bi-list-item-simple", text: this.consts.loadedText, width: 120, handler: this.options.handler }) this.loaded.on(BI.Controller.EVENT_CHANGE, function(type){ self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }) this.loading = BI.createWidget({ type: "bi.layout", width: this.options.height, height:this.options.height, cls: "loading-background cursor-default" }) var loaded = BI.createWidget({ type: "bi.center_adapt", items: [this.loaded] }) var loading = BI.createWidget({ type: "bi.center_adapt", items: [this.loading] }) this.cardLayout = BI.createWidget({ type: "bi.card", element: this, items: [{ el: loaded, cardName: "loaded" }, { el: loading, cardName: "loading" }] }) this.invisible(); }, _reset: function(){ this.visible(); this.loaded.setText(this.consts.loadedText); this.loaded.enable(); }, setLoaded: function(){ this._reset(); this.cardLayout.showCardByName("loaded"); }, setEnd: function(){ this.setLoaded(); this.loaded.setText(this.consts.endText); this.loaded.disable(); }, setLoading: function(){ this._reset(); this.cardLayout.showCardByName("loading"); } }); BI.shortcut("bi.loading_bar", BI.LoadingBar);/** * @class BI.IconButton * @extends BI.BasicButton * 图标的button */ BI.IconButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.IconButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-button horizon-center", iconWidth: null, iconHeight: null }) }, _init: function () { BI.IconButton.superclass._init.apply(this, arguments); var o = this.options; this.element.css({ textAlign: 'center' }); this.icon = BI.createWidget({ type: 'bi.icon', width: o.iconWidth, height: o.iconHeight }); if (BI.isNumber(o.height) && o.height > 0 && BI.isNull(o.iconWidth) && BI.isNull(o.iconHeight)) { this.element.css("lineHeight", o.height + "px"); BI.createWidget({ type: "bi.default", element: this, items: [this.icon] }) } else { BI.createWidget({ element: this, type: 'bi.center_adapt', items: [this.icon] }); } }, doClick: function () { BI.IconButton.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.IconButton.EVENT_CHANGE, this); } } }); BI.IconButton.EVENT_CHANGE = "IconButton.EVENT_CHANGE"; BI.shortcut("bi.icon_button", BI.IconButton);/** * 图片的button * * Created by GUY on 2016/1/27. * @class BI.ImageButton * @extends BI.BasicButton */ BI.ImageButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.ImageButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-image-button", src: "", iconWidth: "100%", iconHeight: "100%" }) }, _init: function () { BI.ImageButton.superclass._init.apply(this, arguments); var o = this.options; this.image = BI.createWidget({ type: "bi.img", width: o.iconWidth, height: o.iconHeight, src: o.src }); if (BI.isNumber(o.iconWidth) || BI.isNumber(o.iconHeight)) { BI.createWidget({ type: "bi.center_adapt", element: this, items: [this.image] }) } else { BI.createWidget({ type: "bi.adaptive", element: this, items: [this.image], scrollable: false }) } }, setWidth: function (w) { BI.ImageButton.superclass.setWidth.apply(this, arguments); this.options.width = w; }, setHeight: function (h) { BI.ImageButton.superclass.setHeight.apply(this, arguments); this.options.height = h; }, setImageWidth: function (w) { this.image.setWidth(w); }, setImageHeight: function (h) { this.image.setHeight(h); }, getImageWidth: function () { return this.image.element.width(); }, getImageHeight: function () { return this.image.element.height(); }, setSrc: function (src) { this.options.src = src; this.image.setSrc(src); }, getSrc: function () { return this.image.getSrc(); }, doClick: function () { BI.ImageButton.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.ImageButton.EVENT_CHANGE, this); } } }); BI.ImageButton.EVENT_CHANGE = "ImageButton.EVENT_CHANGE"; BI.shortcut("bi.image_button", BI.ImageButton);(function ($) { /** * 文字类型的按钮 * @class BI.Button * @extends BI.BasicButton * * @cfg {JSON} options 配置属性 * @cfg {'common'/'success'/'warning'/'ignore'} [options.level='common'] 按钮类型,用不同颜色强调不同的场景 */ BI.Button = BI.inherit(BI.BasicButton, { _defaultConfig: function (props) { var conf = BI.Button.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + ' bi-button', minWidth: (props.block === true || props.clear === true) ? 0 : 90, shadow: props.clear !== true, isShadowShowingOnSelected: true, readonly: true, iconClass: "", level: 'common', block: false, //是否块状显示,即不显示边框,没有最小宽度的限制 clear: false, //是否去掉边框和背景 textAlign: "center", whiteSpace: "nowrap", forceCenter: false, textWidth: null, textHeight: null, hgap: props.clear ? 0 : 10, vgap: 0, tgap: 0, bgap: 0, lgap: 0, rgap: 0 }) }, _init: function () { BI.Button.superclass._init.apply(this, arguments); var o = this.options, self = this; if (BI.isNumber(o.height) && !o.clear && !o.block) { this.element.css({height: o.height + "px", lineHeight: o.height + "px"}); } else { this.element.css({lineHeight: o.height + "px"}); } if (BI.isKey(o.iconClass)) { this.icon = BI.createWidget({ type: "bi.icon", width: 18 }); this.text = BI.createWidget({ type: "bi.label", text: o.text, value: o.value }); BI.createWidget({ type: "bi.horizontal_auto", cls: "button-" + o.level + " " + o.iconClass, element: this, hgap: o.hgap, vgap: o.vgap, tgap: o.tgap, bgap: o.bgap, lgap: o.lgap, rgap: o.rgap, items: [{ type: "bi.horizontal", items: [this.icon, this.text] }] }) } else { this.text = BI.createWidget({ type: "bi.label", cls: "button-" + o.level, textAlign: o.textAlign, whiteSpace: o.whiteSpace, forceCenter: o.forceCenter, textWidth: o.textWidth, textHeight: o.textHeight, hgap: o.hgap, vgap: o.vgap, tgap: o.tgap, bgap: o.bgap, lgap: o.lgap, rgap: o.rgap, element: this, text: o.text, value: o.value }); } if (o.block === true) { this.element.addClass("block"); } if (o.clear === true) { this.element.addClass("clear"); } if (o.minWidth > 0) { this.element.css({"min-width": o.minWidth + "px"}); } }, doClick: function () { BI.Button.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.Button.EVENT_CHANGE, this); } }, setText: function (text) { BI.Button.superclass.setText.apply(this, arguments); this.text.setText(text); }, setValue: function (text) { BI.Button.superclass.setValue.apply(this, arguments); if (!this.isReadOnly()) { this.text.setValue(text); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, destroy: function () { BI.Button.superclass.destroy.apply(this, arguments); } }); BI.shortcut('bi.button', BI.Button); BI.Button.EVENT_CHANGE = "EVENT_CHANGE"; })(jQuery);/** * guy * 可以点击的一行文字 * @class BI.TextButton * @extends BI.BasicButton * 文字button */ BI.TextButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.TextButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-button", textAlign: "center", whiteSpace: "nowrap", forceCenter: false, textWidth: null, textHeight: null, hgap: 0, lgap: 0, rgap: 0, text: "", py: "" }) }, _init: function () { BI.TextButton.superclass._init.apply(this, arguments); var o = this.options; this.text = BI.createWidget({ type: "bi.label", element: this, textAlign: o.textAlign, whiteSpace: o.whiteSpace, textWidth: o.textWidth, textHeight: o.textHeight, forceCenter: o.forceCenter, width: o.width, height: o.height, hgap: o.hgap, lgap: o.lgap, rgap: o.rgap, text: o.text, value: o.value, py: o.py }); }, doClick: function () { BI.TextButton.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.TextButton.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, setText: function (text) { BI.TextButton.superclass.setText.apply(this, arguments); text = BI.isArray(text) ? text.join(",") : text; this.text.setText(text); }, setStyle: function (style) { this.text.setStyle(style); }, setValue: function (text) { BI.TextButton.superclass.setValue.apply(this, arguments); if (!this.isReadOnly()) { text = BI.isArray(text) ? text.join(",") : text; this.text.setValue(text); } } }); BI.TextButton.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_button", BI.TextButton);/** * 带有一个占位 * * Created by GUY on 2015/9/11. * @class BI.BlankIconIconTextItem * @extends BI.BasicButton */ BI.BlankIconIconTextItem = BI.inherit(BI.BasicButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.BlankIconIconTextItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-blank-icon-text-item", logic: { dynamic: false }, iconCls1: "close-ha-font", iconCls2: "close-ha-font", blankWidth: 0, iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.BlankIconIconTextItem.superclass._init.apply(this, arguments); var o = this.options, c = this._const; var blank = BI.createWidget({ type: "bi.layout", width: o.blankWidth }) this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }); this.icon1 = BI.createWidget({ type: "bi.icon_button", cls: o.iconCls1, forceNotSelected: true, width: c.commonWidth }); this.icon2 = BI.createWidget({ type: "bi.icon_button", cls: o.iconCls2, forceNotSelected: true, width: c.commonWidth }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", blank, this.icon1, this.icon2, this.text) })))); }, doClick: function () { BI.BlankIconIconTextItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.BlankIconIconTextItem.EVENT_CHANGE, this.getValue(), this); } }, setSelected: function (b) { BI.BlankIconIconTextItem.superclass.setSelected.apply(this, arguments); this.icon1.setSelected(b); this.icon2.setSelected(b); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); } }); BI.BlankIconIconTextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.blank_icon_icon_text_item", BI.BlankIconIconTextItem);/** * guy * 一个占位符和两个icon和一行数 组成的一行listitem * * Created by GUY on 2015/9/15. * @class BI.BlankIconTextIconItem * @extends BI.BasicButton */ BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.BlankIconTextIconItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-blank-icon-text-icon-item", logic: { dynamic: false }, iconCls1: "close-ha-font", iconCls2: "close-ha-font", blankWidth: 0, iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.BlankIconTextIconItem.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }) var icon1 = BI.createWidget({ type: "bi.center_adapt", cls: o.iconCls1, width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }) BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: { type: "bi.center_adapt", cls: o.iconCls2, width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }, top: 0, bottom: 0, right: 0 }] }) BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", { type: "bi.layout", width: o.blankWidth }, icon1, this.text, { type: "bi.layout", width: c.commonWidth }) })))); }, doClick: function () { BI.BlankIconTextIconItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.BlankIconTextIconItem.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); } }); BI.BlankIconTextIconItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.blank_icon_text_icon_item", BI.BlankIconTextIconItem);/** * 带有一个占位 * * Created by GUY on 2015/9/11. * @class BI.BlankIconTextItem * @extends BI.BasicButton */ BI.BlankIconTextItem = BI.inherit(BI.BasicButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.BlankIconTextItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-blank-icon-text-item", logic: { dynamic: false }, cls: "close-ha-font", blankWidth: 0, iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.BlankIconTextItem.superclass._init.apply(this, arguments); var o = this.options, c = this._const; var blank = BI.createWidget({ type: "bi.layout", width: o.blankWidth }) this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }) this.icon = BI.createWidget({ type: "bi.center_adapt", width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", blank, this.icon, this.text) })))); }, doClick: function () { BI.BlankIconTextItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.BlankIconTextItem.EVENT_CHANGE, this.getValue(), this); } }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); } }); BI.BlankIconTextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.blank_icon_text_item", BI.BlankIconTextItem);/** * guy * 两个icon和一行数 组成的一行listitem * * Created by GUY on 2015/9/9. * @class BI.IconTextIconItem * @extends BI.BasicButton */ BI.IconTextIconItem = BI.inherit(BI.BasicButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.IconTextIconItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-icon-item", logic: { dynamic: false }, iconCls1: "close-ha-font", iconCls2: "close-ha-font", iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.IconTextIconItem.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }) var icon1 = BI.createWidget({ type: "bi.center_adapt", cls: o.iconCls1, width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }) var blank = BI.createWidget({ type: "bi.layout", width: c.commonWidth }) BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: { type: "bi.center_adapt", cls: o.iconCls2, width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }, top: 0, bottom: 0, right: 0 }] }) BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", icon1, this.text, blank) })))); }, doClick: function () { BI.IconTextIconItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.IconTextIconItem.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); } }); BI.IconTextIconItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_icon_item", BI.IconTextIconItem);/** * guy * * Created by GUY on 2015/9/9. * @class BI.IconTextItem * @extends BI.BasicButton */ BI.IconTextItem = BI.inherit(BI.BasicButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.IconTextItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-item", direction: BI.Direction.Left, logic: { dynamic: false }, iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.IconTextItem.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }); this.icon = BI.createWidget({ type: "bi.center_adapt", width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.icon, this.text) })))); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); }, doClick: function () { BI.IconTextItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.IconTextItem.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); } }); BI.IconTextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_item", BI.IconTextItem);/** * * 图标的button * * Created by GUY on 2015/9/9. * @class BI.TextIconItem * @extends BI.BasicButton */ BI.TextIconItem = BI.inherit(BI.BasicButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.TextIconItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-icon-item", logic: { dynamic: false }, cls: "close-ha-font", iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.TextIconItem.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }); this.icon = BI.createWidget({ type: "bi.center_adapt", width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", this.text, this.icon) })))); }, doClick: function () { BI.TextIconItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.TextIconItem.EVENT_CHANGE, this.getValue(), this); } }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); } }); BI.TextIconItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_icon_item", BI.TextIconItem);/** * guy * 一个button和一行数 组成的一行listitem * * Created by GUY on 2015/9/9. * @class BI.TextItem * @extends BI.BasicButton */ BI.TextItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.TextItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-item", textAlign: "left", whiteSpace: "nowrap", textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.TextItem.superclass._init.apply(this, arguments); var o = this.options; this.text = BI.createWidget({ type: "bi.label", element: this, textAlign: o.textAlign, whiteSpace: o.whiteSpace, textHeight: o.whiteSpace == "nowrap" ? o.height : o.textHeight, height: o.height, hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, py: o.py }); }, doClick: function () { BI.TextItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.TextItem.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); } }); BI.TextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_item", BI.TextItem);/** * guy * Created by GUY on 2015/9/9. * @class BI.IconTextIconNode * @extends BI.NodeButton */ BI.IconTextIconNode = BI.inherit(BI.NodeButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.IconTextIconNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-icon-node", logic: { dynamic: false }, iconCls1: "close-ha-font", iconCls2: "close-ha-font", iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.IconTextIconNode.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }) var icon1 = BI.createWidget({ type: "bi.center_adapt", cls: o.iconCls1, width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }) var blank = BI.createWidget({ type: "bi.layout", width: c.commonWidth }) BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: { type: "bi.center_adapt", cls: o.iconCls2, width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }, top: 0, bottom: 0, right: 0 }] }) BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", icon1, this.text, blank) })))); }, doClick: function () { BI.IconTextIconNode.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.IconTextIconNode.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); } }); BI.IconTextIconNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_icon_node", BI.IconTextIconNode);/** * guy * Created by GUY on 2015/9/9. * @class BI.IconTextNode * @extends BI.NodeButton */ BI.IconTextNode = BI.inherit(BI.NodeButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.IconTextNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-node", logic: { dynamic: false }, cls: "close-ha-font", iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.IconTextNode.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }) this.icon = BI.createWidget({ type: "bi.center_adapt", width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }) BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon, this.text) })))); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); }, doClick: function () { BI.IconTextNode.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.IconTextNode.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); } }); BI.IconTextNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_node", BI.IconTextNode);/** * Created by GUY on 2015/9/9. * @class BI.TextIconNode * @extends BI.NodeButton */ BI.TextIconNode = BI.inherit(BI.NodeButton, { _const: { commonWidth: 25 }, _defaultConfig: function () { var conf = BI.TextIconNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-icon-node", logic: { dynamic: false }, cls: "close-ha-font", iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.TextIconNode.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, height: o.height }) this.icon = BI.createWidget({ type: "bi.center_adapt", width: c.commonWidth, items: [{ el: { type: "bi.icon", width: o.iconWidth, height: o.iconHeight } }] }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", this.text, this.icon) })))); }, doClick: function () { BI.TextIconNode.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.TextIconNode.EVENT_CHANGE, this.getValue(), this); } }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); } }); BI.TextIconNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_icon_node", BI.TextIconNode);/** * guy * * Created by GUY on 2015/9/9. * @class BI.TextNode * @extends BI.NodeButton */ BI.TextNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.TextNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-node", textAlign: "left", whiteSpace: "nowrap", textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.TextNode.superclass._init.apply(this, arguments); var o = this.options; this.text = BI.createWidget({ type: "bi.label", element: this, textAlign: o.textAlign, whiteSpace: o.whiteSpace, textHeight: o.whiteSpace == "nowrap" ? o.height : o.textHeight, height: o.height, hgap: o.textHgap, vgap: o.textVgap, lgap: o.textLgap, rgap: o.textRgap, text: o.text, value: o.value, keyword: o.keyword, py: o.py }); }, doClick: function () { BI.TextNode.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.TextNode.EVENT_CHANGE, this.getValue(), this); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, setValue: function () { if (!this.isReadOnly()) { this.text.setValue.apply(this.text, arguments); } }, getValue: function () { return this.text.getValue(); }, setText: function () { this.text.setText.apply(this.text, arguments); }, getText: function () { return this.text.getText(); } }); BI.TextNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_node", BI.TextNode);/** * * Created by GUY on 2016/1/15. * @class BI.CodeEditor * @extends BI.Single */ BI.CodeEditor = BI.inherit(BI.Single, { _defaultConfig: function () { return $.extend(BI.CodeEditor.superclass._defaultConfig.apply(), { baseCls: 'bi-code-editor bi-card', value: '', watermark: "", lineHeight: 2, readOnly: false, //参数显示值构造函数 paramFormatter: function (v) { return v; } }); }, _init: function () { BI.CodeEditor.superclass._init.apply(this, arguments); var o = this.options, self = this; this.editor = CodeMirror(this.element[0], { textWrapping: true, lineWrapping: true, lineNumbers: false, readOnly: o.readOnly }); o.lineHeight === 1 ? this.element.addClass("codemirror-low-line-height") : this.element.addClass("codemirror-high-line-height"); this.editor.on("change", function (cm, change) { BI.nextTick(function () { self.fireEvent(BI.CodeEditor.EVENT_CHANGE) }); }); this.editor.on("focus", function () { self.watermark.setVisible(false); self.fireEvent(BI.CodeEditor.EVENT_FOCUS); }); this.editor.on("blur", function () { self.watermark.setVisible(BI.isEmptyString(self.getValue())); self.fireEvent(BI.CodeEditor.EVENT_BLUR); }); // this.editor.on("blur", function () { // self.editor.execCommand("goLineEnd"); // }); //水印 this.watermark = BI.createWidget({ type: "bi.label", text: o.watermark, cls: "bi-water-mark", whiteSpace: "nowrap", textAlign: "left" }); this.watermark.element.bind( "mousedown", function (e) { self.insertString(""); self.editor.focus(); e.stopEvent(); } ); this.watermark.element.bind("click", function (e) { self.editor.focus(); e.stopEvent(); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.watermark, top: 0, left: 5 }] }); if (BI.isKey(o.value)) { BI.nextTick(function () { self.setValue(o.value); }); } }, _setEnable: function (b) { BI.CodeEditor.superclass._setEnable.apply(this, arguments); this.editor.setOption("readOnly", b === true ? false : "nocursor") }, _checkWaterMark: function () { var o = this.options; if (BI.isEmptyString(this.editor.getValue()) && BI.isKey(o.watermark)) { this.watermark && this.watermark.visible(); } else { this.watermark && this.watermark.invisible(); } }, insertParam: function (param) { var value = param; param = this.options.paramFormatter(param); var from = this.editor.getCursor(); this.editor.replaceSelection(param); var to = this.editor.getCursor(); var options = {className: 'param', atomic: true}; if (BI.isNotNull(param.match(/^<!.*!>$/))) { options.className = 'error-param'; } options.value = value; this.editor.markText(from, to, options); this.editor.replaceSelection(" "); this.editor.focus(); }, insertString: function (str) { this.editor.replaceSelection(str); this.editor.focus(); }, getValue: function () { return this.editor.getValue("\n", function (line) { var rawText = line.text, value = line.text, num = 0; value.text = rawText; _.forEach(line.markedSpans, function (i, ms) { switch (i.marker.className) { case "param": case "error-param": var fieldNameLength = i.to - i.from; value = value.substr(0, i.from + num) + "$\{" + i.marker.value + "\}" + value.substr(i.to + num, value.length); //加上${}的偏移 num += 3; //加上实际值和显示值的长度差的偏移 num += (i.marker.value.length - fieldNameLength); break; } }); return value; }); }, _analyzeContent: function (v) { var regx = /\$[\{][^\}]*[\}]|(\s+)|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)|\n/g; return v.match(regx); }, setValue: function (v) { var self = this, result; this.refresh(); self.editor.setValue(""); result = this._analyzeContent(v || ""); BI.each(result, function (i, item) { var fieldRegx = /\$[\{][^\}]*[\}]/; var str = item.match(fieldRegx); if (BI.isNotEmptyArray(str)) { self.insertParam(str[0].substring(2, item.length - 1)); } else { self.insertString(item); } }); this._checkWaterMark(); }, focus: function () { this.editor.focus(); }, blur: function () { this.editor.getInputField().blur(); }, setStyle: function (style) { this.style = style; this.element.css(style); }, getStyle: function () { return this.style; }, refresh: function () { var self = this; BI.nextTick(function () { self.editor.refresh(); }); } }); BI.CodeEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.CodeEditor.EVENT_BLUR = "EVENT_BLUR"; BI.CodeEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.shortcut("bi.code_editor", BI.CodeEditor);/** * Created by GUY on 2015/4/15. * @class BI.Editor * @extends BI.Single */ BI.Editor = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Editor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-editor", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, //title,warningTitle这两个属性没用 tipType: "warning", inputType: "text", validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: false, watermark: "", errorText: "" }) }, _init: function () { BI.Editor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = this.addWidget(BI.createWidget({ type: "bi.input", element: "<input type='" + o.inputType + "'/>", root: true, watermark: o.watermark, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank })); this.editor.element.css({ "width": "100%", "height": "100%", "border": "none", "outline": "none", "padding": "0", "margin": "0" }); if (BI.isKey(this.options.watermark)) { this.watermark = BI.createWidget({ type: "bi.label", cls: "bi-water-mark", text: this.options.watermark, forceCenter: true, height: o.height - 2 * (o.vgap + o.tgap), whiteSpace: "nowrap", textAlign: "left" }); this.watermark.element.bind({ mousedown: function (e) { if (self.isEnabled()) { self.editor.isEditing() || self.editor.focus(); } else { self.editor.isEditing() && self.editor.blur(); } e.stopEvent(); } }); this.watermark.element.bind("click", function (e) { if (self.isEnabled()) { self.editor.isEditing() || self.editor.focus(); } else { self.editor.isEditing() && self.editor.blur(); } e.stopEvent(); }); this.watermark.element.css({ position: "absolute", left: "3px", right: "3px", top: "0px", bottom: "0px" }); } var items = [{ el: { type: "bi.default", items: this.watermark ? [this.editor, this.watermark] : [this.editor] }, left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap }]; BI.createWidget({ type: "bi.absolute", element: this, items: items }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Input.EVENT_FOCUS, function () { self._checkError(); self.element.addClass("bi-editor-focus"); self.fireEvent(BI.Editor.EVENT_FOCUS, arguments); }); this.editor.on(BI.Input.EVENT_BLUR, function () { self.setErrorVisible(false); self.element.removeClass("bi-editor-focus"); self.fireEvent(BI.Editor.EVENT_BLUR, arguments); }); this.editor.on(BI.Input.EVENT_CLICK, function () { self.fireEvent(BI.Editor.EVENT_CLICK, arguments); }); this.editor.on(BI.Input.EVENT_CHANGE, function () { self.fireEvent(BI.Editor.EVENT_CHANGE, arguments); }); this.editor.on(BI.Input.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.Editor.EVENT_KEY_DOWN, arguments); }); this.editor.on(BI.Input.EVENT_QUICK_DOWN, function (v) { self.watermark && self.watermark.invisible(); }); this.editor.on(BI.Input.EVENT_VALID, function () { self._checkWaterMark(); self.setErrorVisible(false); self.fireEvent(BI.Editor.EVENT_VALID, arguments); }); this.editor.on(BI.Input.EVENT_ERROR, function () { self._checkWaterMark(); self.fireEvent(BI.Editor.EVENT_ERROR, arguments); self.setErrorVisible(self.isEditing()); }); this.editor.on(BI.Input.EVENT_RESTRICT, function () { self._checkWaterMark(); var tip = self.setErrorVisible(true); tip && tip.element.fadeOut(100, function () { tip.element.fadeIn(100); }); self.fireEvent(BI.Editor.EVENT_RESTRICT, arguments); }); this.editor.on(BI.Input.EVENT_EMPTY, function () { self._checkWaterMark(); self.fireEvent(BI.Editor.EVENT_EMPTY, arguments); }); this.editor.on(BI.Input.EVENT_ENTER, function () { self.fireEvent(BI.Editor.EVENT_ENTER, arguments); }); this.editor.on(BI.Input.EVENT_SPACE, function () { self.fireEvent(BI.Editor.EVENT_SPACE, arguments); }); this.editor.on(BI.Input.EVENT_BACKSPACE, function () { self.fireEvent(BI.Editor.EVENT_BACKSPACE, arguments); }); this.editor.on(BI.Input.EVENT_REMOVE, function () { self.fireEvent(BI.Editor.EVENT_REMOVE, arguments); }); this.editor.on(BI.Input.EVENT_START, function () { self.fireEvent(BI.Editor.EVENT_START, arguments); }); this.editor.on(BI.Input.EVENT_PAUSE, function () { self.fireEvent(BI.Editor.EVENT_PAUSE, arguments); }); this.editor.on(BI.Input.EVENT_STOP, function () { self.fireEvent(BI.Editor.EVENT_STOP, arguments); }); this.editor.on(BI.Input.EVENT_CONFIRM, function () { self.fireEvent(BI.Editor.EVENT_CONFIRM, arguments); }); this.element.click(function (e) { e.stopPropagation(); return false; }); if (BI.isKey(this.options.value) || BI.isEmptyString(this.options.value)) { this.setValue(this.options.value); } else { this._checkWaterMark(); } }, _checkToolTip: function () { var o = this.options; var errorText = o.errorText; if (BI.isFunction(errorText)) { errorText = errorText(this.editor.getValue()); } if (BI.isKey(errorText)) { if (!this.isEnabled() || this.isValid() || (BI.Bubbles.has(this.getName()) && BI.Bubbles.get(this.getName()).isVisible())) { this.setTitle(""); } else { this.setTitle(errorText); } } }, _checkError: function () { this.setErrorVisible(this.isEnabled() && !this.isValid()); this._checkToolTip(); }, _checkWaterMark: function () { var o = this.options; if (!this.disabledWaterMark && this.editor.getValue() === "" && BI.isKey(o.watermark)) { this.watermark && this.watermark.visible(); } else { this.watermark && this.watermark.invisible(); } }, setErrorText: function (text) { this.options.errorText = text; }, getErrorText: function () { return this.options.errorText; }, setErrorVisible: function (b) { var o = this.options; var errorText = o.errorText; if (BI.isFunction(errorText)) { errorText = errorText(this.editor.getValue()); } if (!this.disabledError && BI.isKey(errorText)) { BI.Bubbles[b ? "show" : "hide"](this.getName(), errorText, this); this._checkToolTip(); return BI.Bubbles.get(this.getName()); } }, disableError: function () { this.disabledError = true; this._checkError(); }, enableError: function () { this.disabledError = false; this._checkError(); }, disableWaterMark: function () { this.disabledWaterMark = true; this._checkWaterMark(); }, enableWaterMark: function () { this.disabledWaterMark = false; this._checkWaterMark(); }, focus: function () { this.element.addClass("text-editor-focus"); this.editor.focus(); }, blur: function () { this.element.removeClass("text-editor-focus"); this.editor.blur(); }, selectAll: function () { this.editor.selectAll(); }, onKeyDown: function (k) { this.editor.onKeyDown(k); }, setValue: function (v) { BI.Editor.superclass.setValue.apply(this, arguments); this.editor.setValue(v); this._checkError(); this._checkWaterMark(); }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, resetLastValidValue: function () { this.editor.resetLastValidValue(); }, getValue: function () { if (!this.isValid()) { return BI.trim(this.editor.getLastValidValue()); } return BI.trim(this.editor.getValue()); }, isEditing: function () { return this.editor.isEditing(); }, isValid: function () { return this.editor.isValid(); } }); BI.Editor.EVENT_CHANGE = "EVENT_CHANGE"; BI.Editor.EVENT_FOCUS = "EVENT_FOCUS"; BI.Editor.EVENT_BLUR = "EVENT_BLUR"; BI.Editor.EVENT_CLICK = "EVENT_CLICK"; BI.Editor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.Editor.EVENT_SPACE = "EVENT_SPACE"; BI.Editor.EVENT_BACKSPACE = "EVENT_BACKSPACE"; BI.Editor.EVENT_START = "EVENT_START"; BI.Editor.EVENT_PAUSE = "EVENT_PAUSE"; BI.Editor.EVENT_STOP = "EVENT_STOP"; BI.Editor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.Editor.EVENT_VALID = "EVENT_VALID"; BI.Editor.EVENT_ERROR = "EVENT_ERROR"; BI.Editor.EVENT_ENTER = "EVENT_ENTER"; BI.Editor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.Editor.EVENT_REMOVE = "EVENT_REMOVE"; BI.Editor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.editor", BI.Editor);/** * 多文件 * * Created by GUY on 2016/4/13. * @class BI.MultifileEditor * @extends BI.Single * @abstract */ BI.MultifileEditor = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.MultifileEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-multifile-editor", multiple: false, maxSize: -1,//1024 * 1024 accept: "", url: "" }) }, _init: function () { var self = this, o = this.options; BI.MultifileEditor.superclass._init.apply(this, arguments); this.file = BI.createWidget({ type: "bi.file", cls: "multifile-editor", width: "100%", height: "100%", name: o.name, url: o.url, multiple: o.multiple, accept: o.accept, maxSize: o.maxSize }); this.file.on(BI.File.EVENT_CHANGE, function () { self.fireEvent(BI.MultifileEditor.EVENT_CHANGE, arguments); }); this.file.on(BI.File.EVENT_UPLOADSTART, function () { self.fireEvent(BI.MultifileEditor.EVENT_UPLOADSTART, arguments); }); this.file.on(BI.File.EVENT_ERROR, function () { self.fireEvent(BI.MultifileEditor.EVENT_ERROR, arguments); }); this.file.on(BI.File.EVENT_PROGRESS, function () { self.fireEvent(BI.MultifileEditor.EVENT_PROGRESS, arguments); }); this.file.on(BI.File.EVENT_UPLOADED, function () { self.fireEvent(BI.MultifileEditor.EVENT_UPLOADED, arguments); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: { type: "bi.adaptive", scrollable: false, items: [this.file] }, top: 0, right: 0, left: 0, bottom: 0 }] }); }, select: function () { this.file.select(); }, getValue: function () { return this.file.getValue(); }, upload: function () { this.file.upload(); }, reset: function () { this.file.reset(); } }); BI.MultifileEditor.EVENT_CHANGE = "MultifileEditor.EVENT_CHANGE"; BI.MultifileEditor.EVENT_UPLOADSTART = "MultifileEditor.EVENT_UPLOADSTART"; BI.MultifileEditor.EVENT_ERROR = "MultifileEditor.EVENT_ERROR"; BI.MultifileEditor.EVENT_PROGRESS = "MultifileEditor.EVENT_PROGRESS"; BI.MultifileEditor.EVENT_UPLOADED = "MultifileEditor.EVENT_UPLOADED"; BI.shortcut("bi.multifile_editor", BI.MultifileEditor);/** * * Created by GUY on 2016/1/18. * @class BI.TextAreaEditor * @extends BI.Single */ BI.TextAreaEditor = BI.inherit(BI.Single, { _defaultConfig: function () { return $.extend(BI.TextAreaEditor.superclass._defaultConfig.apply(), { baseCls: 'bi-textarea-editor bi-card', value: '' }); }, _init: function () { BI.TextAreaEditor.superclass._init.apply(this, arguments); var o = this.options, self = this; this.content = BI.createWidget({ type: "bi.layout", tagName: "textarea", width: "100%", height: "100%", cls: "bi-textarea textarea-editor-content display-block" }); this.content.element.css({"resize": "none"}); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: { type: "bi.adaptive", items: [this.content] }, left: 0, right: 3, top: 0, bottom: 5 }] }); this.content.element.on("input propertychange", function (e) { self._checkWaterMark(); self.fireEvent(BI.TextAreaEditor.EVENT_CHANGE); }); this.content.element.focus(function () { if (self.isValid()) { self._focus(); self.fireEvent(BI.TextAreaEditor.EVENT_FOCUS); } $(document).bind("mousedown." + self.getName(), function (e) { if (BI.DOM.isExist(self) && !self.element.__isMouseInBounds__(e)) { $(document).unbind("mousedown." + self.getName()); self.content.element.blur(); } }); }); this.content.element.blur(function () { if (self.isValid()) { self._blur(); self.fireEvent(BI.TextAreaEditor.EVENT_BLUR); } $(document).unbind("mousedown." + self.getName()); }); if (BI.isKey(o.value)) { self.setValue(o.value); } if (BI.isNotNull(o.style)) { self.setValue(o.style); } this._checkWaterMark(); }, _checkWaterMark: function () { var self = this, o = this.options; var val = this.getValue(); if (BI.isNotEmptyString(val)) { this.watermark && this.watermark.destroy(); this.watermark = null; } else { if (BI.isNotEmptyString(o.watermark)) { if (!this.watermark) { this.watermark = BI.createWidget({ type: "bi.text_button", cls: "bi-water-mark", textAlign: "left", height: 30, text: o.watermark, invalid: o.invalid, disabled: o.disabled }); this.watermark.on(BI.TextButton.EVENT_CHANGE, function () { self.focus(); }); BI.createWidget({ type: 'bi.absolute', element: this, items: [{ el: this.watermark, left: 0, top: 0, right: 0 }] }) } else { this.watermark.setText(o.watermark); this.watermark.setValid(!o.invalid); this.watermark.setEnable(!o.disabled); } } } }, _focus: function () { this.content.element.addClass("textarea-editor-focus"); this._checkWaterMark(); }, _blur: function () { this.content.element.removeClass("textarea-editor-focus"); this._checkWaterMark(); }, focus: function () { this._focus(); this.content.element.focus(); }, blur: function () { this._blur(); this.content.element.blur(); }, getValue: function () { return this.content.element.val(); }, setValue: function (value) { this.content.element.val(value); this._checkWaterMark(); }, setStyle: function (style) { this.style = style; this.element.css(style); this.content.element.css(style) }, getStyle: function () { return this.style; }, _setValid: function (b) { BI.TextAreaEditor.superclass._setValid.apply(this, arguments); // this.content.setValid(b); // this.watermark && this.watermark.setValid(b); } }); BI.TextAreaEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.TextAreaEditor.EVENT_BLUR = "EVENT_BLUR"; BI.TextAreaEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.shortcut("bi.textarea_editor", BI.TextAreaEditor);/** * guy 图标 * @class BI.Icon * @extends BI.Single */ BI.Icon = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Icon.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { tagName: "i", baseCls: (conf.baseCls || "") + " x-icon b-font horizon-center display-block" }) }, _init: function () { BI.Icon.superclass._init.apply(this, arguments); if (BI.isIE9Below()) { this.element.addClass("hack"); } } }); BI.shortcut("bi.icon", BI.Icon);/** * @class BI.Iframe * @extends BI.Single * @abstract * Created by GameJian on 2016/3/2. */ BI.Iframe = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Iframe.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-iframe", src: "", width: "100%", height: "100%" }) }, _init: function () { var o = this.options; this.options.element = $("<iframe frameborder='0' src='" + o.src + "'>"); BI.Iframe.superclass._init.apply(this, arguments); }, setSrc: function (src) { this.options.src = src; this.element.attr("src", src); }, getSrc: function () { return this.options.src; }, setName: function (name) { this.options.name = name; this.element.attr("name", name); }, getName: function () { return this.options.name; }, getWidth: function () { return this.options.width }, getHeight: function () { return this.options.height } }); BI.shortcut("bi.iframe", BI.Iframe);/** * ͼƬ * * Created by GUY on 2016/1/26. * @class BI.Img * @extends BI.Single * @abstract */ BI.Img = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Img.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-img display-block", src: "", width: "100%", height: "100%" }) }, _init: function () { var o = this.options; this.options.element = $("<img src='" + o.src + "'>"); BI.Img.superclass._init.apply(this, arguments); }, setSrc: function (src) { this.options.src = src; this.element.attr("src", src); }, getSrc: function () { return this.options.src; } }); BI.shortcut("bi.img", BI.Img); /** * guy * @extends BI.Single * @type {*|void|Object} */ BI.Checkbox = BI.inherit(BI.IconButton, { _defaultConfig: function() { var conf = BI.Checkbox.superclass._defaultConfig.apply(this,arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-checkbox check-box-icon", selected: false, handler: BI.emptyFn, width: 16, height: 16, iconWidth: 16, iconHeight: 16 }) }, _init : function() { BI.Checkbox.superclass._init.apply(this, arguments); }, doClick: function(){ BI.Checkbox.superclass.doClick.apply(this, arguments); if(this.isValid()){ this.fireEvent(BI.Checkbox.EVENT_CHANGE); } } }); BI.Checkbox.EVENT_CHANGE = "Checkbox.EVENT_CHANGE"; BI.shortcut("bi.checkbox", BI.Checkbox);/** * 文件 * * Created by GUY on 2016/1/27. * @class BI.File * @extends BI.Single * @abstract */ (function () { /** * @description normalize input.files. create if not present, add item method if not present * @param Object generated wrap object * @return Object the wrap object itself */ var F = (function (item) { return function (input) { var files = input.files || [input]; if (!files.item) { files.item = item; } return files; }; })(function (i) { return this[i]; }); var event = { /** * @description add an event via addEventListener or attachEvent * @param DOMElement the element to add event * @param String event name without "on" (e.g. "mouseover") * @param Function the callback to associate as event * @return Object noswfupload.event */ add: document.addEventListener ? function (node, name, callback) { node.addEventListener(name, callback, false); return this; } : function (node, name, callback) { node.attachEvent("on" + name, callback); return this; }, /** * @description remove an event via removeEventListener or detachEvent * @param DOMElement the element to remove event * @param String event name without "on" (e.g. "mouseover") * @param Function the callback associated as event * @return Object noswfupload.event */ del: document.removeEventListener ? function (node, name, callback) { node.removeEventListener(name, callback, false); return this; } : function (node, name, callback) { node.detachEvent("on" + name, callback); return this; }, /** * @description to block event propagation and prevent event default * @param void generated event or undefined * @return Boolean false */ stop: function (e) { if (!e) { if (self.event) { event.returnValue = !(event.cancelBubble = true); } } else { e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; e.preventDefault ? e.preventDefault() : e.returnValue = false; } ; return false; } }; var sendFile = (function (toString) { var multipart = function (boundary, name, file) { return "--".concat( boundary, CRLF, 'Content-Disposition: form-data; name="', name, '"; filename="', BI.cjkEncode(file.fileName), '"', CRLF, "Content-Type: application/octet-stream", CRLF, CRLF, file.getAsBinary(), CRLF, "--", boundary, "--", CRLF ); }, isFunction = function (Function) { return toString.call(Function) === "[object Function]"; }, split = "onabort.onerror.onloadstart.onprogress".split("."), length = split.length, CRLF = "\r\n", xhr = this.XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject("Microsoft.XMLHTTP"), sendFile; // FireFox 3+, Safari 4 beta (Chrome 2 beta file is buggy and will not work) if (xhr.upload || xhr.sendAsBinary) { sendFile = function (handler, maxSize, width, height) { if (-1 < maxSize && maxSize < handler.file.fileSize) { if (isFunction(handler.onerror)) { handler.onerror(); } return; } for (var xhr = new XMLHttpRequest, upload = xhr.upload || { addEventListener: function (event, callback) { this["on" + event] = callback } }, i = 0; i < length; i++ ) { upload.addEventListener( split[i].substring(2), (function (event) { return function (rpe) { if (isFunction(handler[event])) { handler[event](rpe, xhr); } }; })(split[i]), false ); } upload.addEventListener( "load", function (rpe) { if (handler.onreadystatechange === false) { if (isFunction(handler.onload)) { handler.onload(rpe, xhr); } } else { setTimeout(function () { if (xhr.readyState === 4) { if (isFunction(handler.onload)) { handler.onload(rpe, xhr); } } else { setTimeout(arguments.callee, 15); } }, 15); } }, false ); xhr.open("post", handler.url + '&filename=' + window.encodeURIComponent(handler.file.fileName), true); if (!xhr.upload) { var rpe = {loaded: 0, total: handler.file.fileSize || handler.file.size, simulation: true}; rpe.interval = setInterval(function () { rpe.loaded += 1024 / 4; if (rpe.total <= rpe.loaded) { rpe.loaded = rpe.total; } upload.onprogress(rpe); }, 100); xhr.onabort = function () { upload.onabort({}); }; xhr.onerror = function () { upload.onerror({}); }; xhr.onreadystatechange = function () { switch (xhr.readyState) { case 2: case 3: if (rpe.total <= rpe.loaded) rpe.loaded = rpe.total; upload.onprogress(rpe); break; case 4: clearInterval(rpe.interval); rpe.interval = 0; rpe.loaded = rpe.total; upload.onprogress(rpe); if (199 < xhr.status && xhr.status < 400) { upload["onload"]({}); var attachO = BI.jsonDecode(xhr.responseText); attachO.filename = handler.file.fileName; if (handler.file.type.indexOf('image') != -1) { attachO.attach_type = "image"; } handler.attach_array.push(attachO); } else { upload["onerror"]({}); } break; } }; upload.onloadstart(rpe); } else { xhr.onreadystatechange = function () { switch (xhr.readyState) { case 4: var attachO = BI.jsonDecode(xhr.responseText); if (handler.file.type.indexOf('image') != -1) { attachO.attach_type = "image"; } attachO.filename = handler.file.fileName; if (handler.maxlength == 1) { handler.attach_array[0] = attachO; // handler.attach_array.push(attachO); } else { handler.attach_array.push(attachO); } break; } } } var boundary = "AjaxUploadBoundary" + (new Date).getTime(); xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + boundary); if (handler.file.getAsBinary) { xhr[xhr.sendAsBinary ? "sendAsBinary" : "send"](multipart(boundary, handler.name, handler.file)); } else { xhr.setRequestHeader("Content-Type", "multipart/form-data"); // xhr.setRequestHeader("X-Name", handler.name); // xhr.setRequestHeader("X-File-Name", handler.file.fileName); var form = new FormData(); form.append("FileData", handler.file); xhr.send(form); } return handler; }; } // Internet Explorer, Opera, others else { sendFile = function (handler, maxSize, width, height) { var url = handler.url.concat(-1 === handler.url.indexOf("?") ? "?" : "&", "AjaxUploadFrame=true"), rpe = { loaded: 1, total: 100, simulation: true, interval: setInterval(function () { if (rpe.loaded < rpe.total) ++rpe.loaded; if (isFunction(handler.onprogress)) handler.onprogress(rpe, {}); }, 100) }, onload = function () { iframe.onreadystatechange = iframe.onload = iframe.onerror = null; form.parentNode.removeChild(form); form = null; clearInterval(rpe.interval); //rpe.loaded = rpe.total; try { var responseText = (iframe.contentWindow.document || iframe.contentWindow.contentDocument).body.innerHTML; var attachO = BI.jsonDecode(responseText); if (handler.file.type.indexOf('image') != -1) { attachO.attach_type = "image"; } //attachO.fileSize = responseText.length; attachO.filename = BI.cjkDecode(handler.file.fileName); if (handler.maxlength == 1) { handler.attach_array[0] = attachO; } else { handler.attach_array.push(attachO); } } catch (e) { if (isFunction(handler.onerror)) handler.onerror(rpe, event || window.event); } if (isFunction(handler.onload)) handler.onload(rpe, {responseText: responseText}); }, target = ["AjaxUpload", (new Date).getTime(), String(Math.random()).substring(2)].join("_"); try { // IE < 8 does not accept enctype attribute ... var form = document.createElement('<form enctype="multipart/form-data"></form>'), iframe = handler.iframe || (handler.iframe = document.createElement('<iframe id="' + target + '" name="' + target + '" src="' + url + '"></iframe>')); } catch (e) { var form = document.createElement('form'), iframe = handler.iframe || (handler.iframe = document.createElement("iframe")); form.setAttribute("enctype", "multipart/form-data"); iframe.setAttribute("name", iframe.id = target); iframe.setAttribute("src", url); } iframe.style.position = "absolute"; iframe.style.left = iframe.style.top = "-10000px"; iframe.onload = onload; iframe.onerror = function (event) { if (isFunction(handler.onerror)) { handler.onerror(rpe, event || window.event); } }; iframe.onreadystatechange = function () { if (/loaded|complete/i.test(iframe.readyState)) { onload(); //wei : todo,将附件信息放到handler.attach } else if (isFunction(handler.onloadprogress)) { if (rpe.loaded < rpe.total) { ++rpe.loaded; } handler.onloadprogress(rpe, { readyState: { loading: 2, interactive: 3, loaded: 4, complete: 4 }[iframe.readyState] || 1 }); } }; form.setAttribute("action", handler.url); form.setAttribute("target", iframe.id); form.setAttribute("method", "post"); form.appendChild(handler.file); form.style.display = "none"; if (isFunction(handler.onloadstart)) { handler.onloadstart(rpe, {}); } with (document.body || document.documentElement) { appendChild(iframe); appendChild(form); form.submit(); } ; return handler; }; } xhr = null; return sendFile; })(Object.prototype.toString); var sendFiles = function (handler, maxSize, width, height) { var length = handler.files.length, i = 0, onload = handler.onload, onloadstart = handler.onloadstart; handler.current = 0; handler.total = 0; handler.sent = 0; while (handler.current < length) { handler.total += (handler.files[handler.current].fileSize || handler.files[handler.current].size); handler.current++; } handler.current = 0; if (length && handler.files[0].fileSize !== -1) { handler.file = handler.files[handler.current]; sendFile(handler, maxSize, width, height).onload = function (rpe, xhr) { handler.onloadstart = null; handler.sent += (handler.files[handler.current].fileSize || handler.files[handler.current].size); if (++handler.current < length) { handler.file = handler.files[handler.current]; sendFile(handler, maxSize, width, height).onload = arguments.callee; } else if (onload) { handler.onloadstart = onloadstart; handler.onload = onload; handler.onload(rpe, xhr); } }; } else if (length) { handler.total = length * 100; handler.file = handler.files[handler.current]; sendFile(handler, maxSize, width, height).onload = function (rpe, xhr) { var callee = arguments.callee; handler.onloadstart = null; handler.sent += 100; if (++handler.current < length) { if (/\b(chrome|safari)\b/i.test(navigator.userAgent)) { handler.iframe.parentNode.removeChild(handler.iframe); handler.iframe = null; } setTimeout(function () { handler.file = handler.files[handler.current]; sendFile(handler, maxSize, width, height).onload = callee; }, 15); } else if (onload) { setTimeout(function () { handler.iframe.parentNode.removeChild(handler.iframe); handler.iframe = null; handler.onloadstart = onloadstart; handler.onload = onload; handler.onload(rpe, xhr); }, 15); } }; } return handler; }; BI.File = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.File.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-file display-block", element: "<input type='file'>", name: "", url: "", multiple: true, accept: "", /**'*.jpg; *.zip'**/ maxSize: -1 //1024 * 1024 }) }, _init: function () { var self = this, o = this.options; BI.File.superclass._init.apply(this, arguments); if (o.multiple === true) { this.element.attr("multiple", "multiple"); } this.element.attr("name", o.name || this.getName()); BI.nextTick(function () { // create the noswfupload.wrap Object // wrap.maxSize 文件大小限制 // wrap.maxlength 文件个数限制 var _wrap = self.wrap = self._wrap(self.element[0], o.maxSize); // fileType could contain whatever text but filter checks *.{extension} // if present // handlers _wrap.onloadstart = function (rpe, xhr) { //BI.Msg.toast("loadstart"); self.fireEvent(BI.File.EVENT_UPLOADSTART); }; _wrap.onprogress = function (rpe, xhr) { //BI.Msg.toast("onprogress"); // percent for each bar // fileSize is -1 only if browser does not support file info access // this if splits recent browsers from others if (this.file.fileSize !== -1) { // simulation property indicates when the progress event is fake if (rpe.simulation) { } else { } } else { // if fileSIze is -1 browser is using an iframe because it does // not support // files sent via Ajax (XMLHttpRequest) // We can still show some information } self.fireEvent(BI.File.EVENT_PROGRESS, { file: this.file, total: rpe.total, loaded: rpe.loaded, simulation: rpe.simulation }); }; // generated if there is something wrong during upload _wrap.onerror = function () { // just inform the user something was wrong self.fireEvent(BI.File.EVENT_ERROR); }; // generated when every file has been sent (one or more, it does not // matter) _wrap.onload = function (rpe, xhr) { var self_ = this; // just show everything is fine ... // ... and after a second reset the component setTimeout(function () { self_.clean(); // remove files from list self_.hide(); // hide progress bars and enable input file //BI.Msg.toast("onload"); self.fireEvent(BI.File.EVENT_UPLOADED); // enable again the submit button/element }, 1000); }; _wrap.url = o.url ? o.url : BI.servletURL + '?op=fr_attach&cmd=ah_upload'; _wrap.fileType = o.accept; //文件类型限制 _wrap.attach_array = []; _wrap.attach_names = []; _wrap.attachNum = 0; }); }, _events: function (wrap) { var self = this; event.add(wrap.dom.input, "change", function () { event.del(wrap.dom.input, "change", arguments.callee); for (var input = wrap.dom.input.cloneNode(true), i = 0, files = F(wrap.dom.input); i < files.length; i++) { var item = files.item(i); var tempFile = item.value || item.name; var value = item.fileName || (item.fileName = tempFile.split("\\").pop()), ext = -1 !== value.indexOf(".") ? value.split(".").pop().toLowerCase() : "unknown", size = item.fileSize || item.size; if (wrap.fileType && -1 === wrap.fileType.indexOf("*." + ext)) { //文件类型不支持 BI.Msg.toast(BI.i18nText("BI-Upload_File_Type_Error")); self.fireEvent(BI.File.EVENT_ERROR, { errorType: 0, file: item }); } else if (wrap.maxSize !== -1 && size && wrap.maxSize < size) { //文件大小不支持 BI.Msg.toast(BI.i18nText("BI-Upload_File_Size_Error")); self.fireEvent(BI.File.EVENT_ERROR, { errorType: 1, file: item }); } else { wrap.files.unshift(item); //BI.Msg.toast(value); self.fireEvent(BI.File.EVENT_CHANGE, { file: item }); } } input.value = ""; wrap.dom.input.parentNode.replaceChild(input, wrap.dom.input); wrap.dom.input = input; event.add(wrap.dom.input, "change", arguments.callee); }); return wrap; }, _wrap: function () { var self = this, o = this.options; // be sure input accept multiple files var input = this.element[0]; if (o.multiple === true) { this.element.attr("multiple", "multiple"); } input.value = ""; // wrap Object return this._events({ // DOM namespace dom: { input: input, // input file disabled: false // internal use, checks input file state }, name: input.name, // name to send for each file ($_FILES[{name}] in the server) // maxSize is the maximum amount of bytes for each file maxSize: o.maxSize ? o.maxSize >> 0 : -1, files: [], // file list // remove every file from the noswfupload component clean: function () { this.files = []; }, // upload one file a time (which make progress possible rather than all files in one shot) // the handler is an object injected into the wrap one, could be the wrap itself or // something like {onload:function(){alert("OK")},onerror:function(){alert("Error")}, etc ...} upload: function (handler) { if (handler) { for (var key in handler) { this[key] = handler[key]; } } sendFiles(this, this.maxSize); return this; }, // hide progress bar (total + current) and enable files selection hide: function () { if (this.dom.disabled) { this.dom.disabled = false; this.dom.input.removeAttribute("disabled"); } }, // show progress bar and disable file selection (used during upload) // total and current are pixels used to style bars // totalProp and currentProp are properties to change, "height" by default show: function (total, current, totalProp, currentProp) { if (!this.dom.disabled) { this.dom.disabled = true; this.dom.input.setAttribute("disabled", "disabled"); } } }); }, select: function () { $(this.wrap.dom.input).click(); }, upload: function (handler) { this.wrap.upload(handler); }, getValue: function () { return this.wrap.attach_array; }, reset: function () { this.wrap.attach_array = []; this.wrap.attach_names = []; this.wrap.attachNum = 0; }, _setEnable: function (enable) { BI.File.superclass._setEnable.apply(this, arguments); if (enable === true) { this.element.attr("disabled", "disabled"); } else { this.element.removeAttr("disabled"); } } }); BI.File.EVENT_CHANGE = "BI.File.EVENT_CHANGE"; BI.File.EVENT_UPLOADSTART = "EVENT_UPLOADSTART"; BI.File.EVENT_ERROR = "EVENT_ERROR"; BI.File.EVENT_PROGRESS = "EVENT_PROGRESS"; BI.File.EVENT_UPLOADED = "EVENT_UPLOADED"; BI.shortcut("bi.file", BI.File); })();/** * guy * @class BI.Input 一个button和一行数 组成的一行listitem * @extends BI.Single * @type {*|void|Object} */ BI.Input = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Input.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-input display-block", element: "<input/>", validationChecker: BI.emptyFn, quitChecker: BI.emptyFn,//按确定键能否退出编辑 mouseOut: false, allowBlank: false }) }, _init: function () { BI.Input.superclass._init.apply(this, arguments); var self = this; var ctrlKey = false; var inputEventValid = false; var _keydown = BI.debounce(function (keyCode) { self.onKeyDown(keyCode, ctrlKey); self._keydown_ = false; }, 300); var _clk = BI.debounce(BI.bind(this._click, this), BI.EVENT_RESPONSE_TIME, true); this._blurDebounce = BI.debounce(BI.bind(this._blur, this), BI.EVENT_RESPONSE_TIME, true); this.element .keydown(function (e) { inputEventValid = false; ctrlKey = e.ctrlKey; self.fireEvent(BI.Input.EVENT_QUICK_DOWN); }) .keyup(function (e) { if (!(inputEventValid && e.keyCode === BI.KeyCode.ENTER)) { self._keydown_ = true; _keydown(e.keyCode); } }) .on("input propertychange", function (e) { inputEventValid = true; self._keydown_ = true; _keydown(e.keyCode); }) .click(function (e) { e.stopPropagation(); _clk(); }) .mousedown(function (e) { self.element.val(self.element.val()); }) .focusout(function (e) { self._blurDebounce(); }); }, _focus: function () { this.element.addClass("bi-input-focus"); this._checkValidationOnValueChange(); this._isEditing = true; if (this.getValue() == "") { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this); this.fireEvent(BI.Input.EVENT_EMPTY); } this.fireEvent(BI.Input.EVENT_FOCUS); }, _blur: function () { var self = this; if (self._keydown_ === true) { BI.delay(blur, 300); } else { blur(); } function blur() { if (!self.isValid() && self.options.quitChecker.apply(self, [BI.trim(self.getValue())]) !== false) { self.element.val(self._lastValidValue ? self._lastValidValue : ""); self._checkValidationOnValueChange(); self._defaultState(); } self.element.removeClass("bi-input-focus"); self._isEditing = false; self._start = false; if (self.isValid()) { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CONFIRM, self.getValue(), self); self.fireEvent(BI.Input.EVENT_CONFIRM); } self.fireEvent(BI.Input.EVENT_BLUR); } }, _click: function () { if (this._isEditing !== true) { this._focus(); this.selectAll(); this.fireEvent(BI.Input.EVENT_CLICK); } }, onClick: function () { this._click(); }, onKeyDown: function (keyCode, ctrlKey) { if (!this.isValid() || BI.trim(this._lastValidValue) !== BI.trim(this.getValue())) { this._checkValidationOnValueChange(); } if (this.isValid() && BI.trim(this.getValue()) !== "") { if (BI.trim(this.getValue()) !== this._lastValue && (!this._start || this._lastValue == null || this._lastValue === "") || (this._pause === true && !/(\s|\u00A0)$/.test(this.getValue()))) { this._start = true; this._pause = false; this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STARTEDIT, this.getValue(), this); this.fireEvent(BI.Input.EVENT_START); } } if (ctrlKey === true && keyCode === 86) {//ctrlKey+V this._valueChange(); } else { if (keyCode == BI.KeyCode.ENTER) { if (this.isValid() || this.options.quitChecker.apply(this, [BI.trim(this.getValue())]) !== false) { this.blur(); this.fireEvent(BI.Input.EVENT_ENTER); } else { this.fireEvent(BI.Input.EVENT_RESTRICT); } } if (keyCode == BI.KeyCode.SPACE) { this.fireEvent(BI.Input.EVENT_SPACE); } if (keyCode == BI.KeyCode.BACKSPACE && this._lastValue == "") { this.fireEvent(BI.Input.EVENT_REMOVE); } if (keyCode == BI.KeyCode.BACKSPACE || keyCode == BI.KeyCode.DELETE) { this.fireEvent(BI.Input.EVENT_BACKSPACE); } } this.fireEvent(BI.Input.EVENT_KEY_DOWN); if (BI.isEndWithBlank(this.getValue())) { this._pause = true; this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.PAUSE, "", this); this.fireEvent(BI.Input.EVENT_PAUSE); this._defaultState(); } else if ((keyCode === BI.KeyCode.BACKSPACE || keyCode === BI.KeyCode.DELETE) && BI.trim(this.getValue()) === "" && (this._lastValue !== null && BI.trim(this._lastValue) !== "")) { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT, this.getValue(), this); this.fireEvent(BI.Input.EVENT_STOP); this._valueChange(); } else { this._valueChange(); } }, //初始状态 _defaultState: function () { if (this.getValue() == "") { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this); this.fireEvent(BI.Input.EVENT_EMPTY); } this._lastValue = this.getValue(); this._lastSubmitValue = null; }, _valueChange: function () { if (this.isValid() && BI.trim(this.getValue()) !== this._lastSubmitValue) { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CHANGE, this.getValue(), this); this.fireEvent(BI.Input.EVENT_CHANGE); this._lastSubmitValue = BI.trim(this.getValue()); } if (this.getValue() == "") { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this); this.fireEvent(BI.Input.EVENT_EMPTY); } this._lastValue = this.getValue(); }, _checkValidationOnValueChange: function () { var o = this.options; var v = this.getValue(); this.setValid( (o.allowBlank === true && BI.trim(v) == "") || (BI.isNotEmptyString(BI.trim(v)) && (v === this._lastValidValue || o.validationChecker.apply(this, [BI.trim(v)]) !== false)) ); }, focus: function () { if (!this.element.is(":visible")) { throw new Error("input输入框在不可见下不能focus"); } if (!this._isEditing === true) { this.element.focus(); this._focus(); this.selectAll(); } }, blur: function () { if (!this.element.is(":visible")) { throw new Error("input输入框在不可见下不能blur"); } if (this._isEditing === true) { this.element.blur(); this._blurDebounce(); } }, selectAll: function () { if (!this.element.is(":visible")) { throw new Error("input输入框在不可见下不能select"); } this.element.select(); this._isEditing = true; }, setValue: function (textValue) { this.element.val(textValue); BI.nextTick(BI.bind(function () { this._checkValidationOnValueChange(); this._defaultState(); if (this.isValid()) { this._lastSubmitValue = this.getValue(); } }, this)); }, getValue: function () { return this.element.val() || ""; }, isEditing: function () { return this._isEditing; }, getLastValidValue: function () { return this._lastValidValue; }, _setValid: function () { BI.Input.superclass._setValid.apply(this, arguments); if (this.isValid()) { this._lastValidValue = this.getValue(); this.element.removeClass("bi-input-error"); this.fireEvent(BI.Input.EVENT_VALID, BI.trim(this.getValue()), this); } else { if (this._lastValidValue === this.getValue()) { this._lastValidValue = null; } this.element.addClass("bi-input-error"); this.fireEvent(BI.Input.EVENT_ERROR, BI.trim(this.getValue()), this); } }, _setEnable: function (b) { BI.Input.superclass._setEnable.apply(this, [b]); this.element[0].disabled = !b; } }); BI.Input.EVENT_CHANGE = "EVENT_CHANGE"; BI.Input.EVENT_FOCUS = "EVENT_FOCUS"; BI.Input.EVENT_CLICK = "EVENT_CLICK"; BI.Input.EVENT_BLUR = "EVENT_BLUR"; BI.Input.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.Input.EVENT_QUICK_DOWN = "EVENT_QUICK_DOWN"; BI.Input.EVENT_SPACE = "EVENT_SPACE"; BI.Input.EVENT_BACKSPACE = "EVENT_BACKSPACE"; BI.Input.EVENT_START = "EVENT_START"; BI.Input.EVENT_PAUSE = "EVENT_PAUSE"; BI.Input.EVENT_STOP = "EVENT_STOP"; BI.Input.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.Input.EVENT_REMOVE = "EVENT_REMOVE"; BI.Input.EVENT_EMPTY = "EVENT_EMPTY"; BI.Input.EVENT_VALID = "EVENT_VALID"; BI.Input.EVENT_ERROR = "EVENT_ERROR"; BI.Input.EVENT_ENTER = "EVENT_ENTER"; BI.Input.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.shortcut("bi.input", BI.Input);/** * guy * @extends BI.Single * @type {*|void|Object} */ BI.Radio = BI.inherit(BI.IconButton, { _defaultConfig: function() { var conf = BI.Radio.superclass._defaultConfig.apply(this,arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-radio radio-icon", selected: false, handler: BI.emptyFn, width: 16, height: 16, iconWidth: 16, iconHeight: 16 }) }, _init : function() { BI.Radio.superclass._init.apply(this, arguments); }, doClick: function(){ BI.Radio.superclass.doClick.apply(this, arguments); if(this.isValid()){ this.fireEvent(BI.Radio.EVENT_CHANGE); } } }); BI.Radio.EVENT_CHANGE = "Radio.EVENT_CHANGE"; BI.shortcut("bi.radio", BI.Radio);/** * Created by GUY on 2015/6/26. */ BI.Label = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Label.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-label", textAlign: "center", whiteSpace: "nowrap", //normal or nowrap forceCenter: false, //是否无论如何都要居中, 不考虑超出边界的情况, 在未知宽度和高度时有效 textWidth: null, textHeight: null, hgap: 0, vgap: 0, lgap: 0, rgap: 0, tgap: 0, bgap: 0, text: "", py: "", keyword: "" }) }, _createJson: function () { var o = this.options; return { type: "bi.text", textAlign: o.textAlign, whiteSpace: o.whiteSpace, lineHeight: o.textHeight, text: o.text, value: o.value, py: o.py, keyword: o.keyword }; }, _init: function () { BI.Label.superclass._init.apply(this, arguments); if (this.options.textAlign === "center") { this._createCenterEl(); } else { this._createNotCenterEl(); } }, _createCenterEl: function () { var o = this.options; var json = this._createJson(); if (BI.isNumber(o.width) && o.width > 0) { if (BI.isNumber(o.textWidth) && o.textWidth > 0) { if (BI.isNumber(o.height) && o.height > 0) { var gap = (o.width - o.textWidth) / 2; BI.createWidget({ type: "bi.adaptive", height: o.height, scrollable: o.whiteSpace === "normal", element: this, items: [ { el: (this.text = BI.createWidget(json)), left: gap + o.hgap + o.lgap, right: gap + o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap } ] }); this.element.css({"line-height": o.height + "px"}); return; } json.width = o.textWidth; BI.createWidget({ type: "bi.center_adapt", scrollable: o.whiteSpace === "normal", element: this, items: [ { el: (this.text = BI.createWidget(json)) } ] }); return; } if (o.whiteSpace == "normal") { this.text = BI.createWidget(json); BI.createWidget({ type: "bi.center_adapt", scrollable: o.whiteSpace === "normal", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, element: this, items: [this.text] }); return; } if (BI.isNumber(o.height) && o.height > 0) { this.element.css({ "line-height": o.height + "px" }); BI.createWidget({ type: "bi.absolute", scrollable: o.whiteSpace === "normal", element: this, items: [{ el: (this.text = BI.createWidget(json)), left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap }] }); return; } json.width = o.width - 2 * o.hgap; BI.createWidget({ type: "bi.center_adapt", scrollable: o.whiteSpace === "normal", element: this, items: [{ el: (this.text = BI.createWidget(json)) }] }); return; } if (BI.isNumber(o.textWidth) && o.textWidth > 0) { json.width = o.textWidth; BI.createWidget({ type: "bi.center_adapt", scrollable: o.whiteSpace === "normal", element: this, items: [ { el: (this.text = BI.createWidget(json)) } ] }); return; } if (o.whiteSpace == "normal") { this.text = BI.createWidget(json); BI.createWidget({ type: "bi.center_adapt", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, scrollable: o.whiteSpace === "normal", element: this, items: [this.text] }); return; } if (BI.isNumber(o.height) && o.height > 0) { if (BI.isNumber(o.textHeight) && o.textHeight > 0) { this.element.css({ "line-height": o.height + "px" }); BI.createWidget({ type: "bi.adaptive", height: o.height, scrollable: o.whiteSpace === "normal", element: this, items: [{ el: (this.text = BI.createWidget(json)), left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap }] }); return; } BI.extend(json, { hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap }); this.element.css({ "line-height": o.height + "px" }); this.text = BI.createWidget(BI.extend(json, { element: this })); BI.createWidget({ type: "bi.layout", element: this.text, scrollable: o.whiteSpace === "normal" }); return; } BI.extend(json, { hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap }); if (o.forceCenter) { this.text = BI.createWidget(json); BI.createWidget({ type: "bi.center_adapt", element: this, items: [this.text] }); return; } this.text = BI.createWidget(BI.extend(json, { element: this })); BI.createWidget({ type: "bi.layout", element: this.text, scrollable: o.whiteSpace === "normal" }) }, _createNotCenterEl: function () { var o = this.options; var json = this._createJson(); if (BI.isNumber(o.width) && o.width > 0) { if (BI.isNumber(o.textWidth) && o.textWidth > 0) { if (BI.isNumber(o.height) && o.height > 0) { BI.createWidget({ type: "bi.adaptive", height: o.height, scrollable: o.whiteSpace === "normal", element: this, items: [ { el: (this.text = BI.createWidget(json)), left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap } ] }); this.element.css({"line-height": o.height + "px"}); return; } json.width = o.textWidth; BI.createWidget({ type: "bi.vertical_adapt", scrollable: o.whiteSpace === "normal", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, element: this, items: [ { el: (this.text = BI.createWidget(json)) } ] }); return; } if (o.whiteSpace == "normal") { this.text = BI.createWidget(json); BI.createWidget({ type: "bi.vertical_adapt", scrollable: o.whiteSpace === "normal", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, element: this, items: [this.text] }); return; } if (BI.isNumber(o.height) && o.height > 0) { this.element.css({ "line-height": o.height + "px" }); BI.createWidget({ type: "bi.absolute", scrollable: o.whiteSpace === "normal", element: this, items: [{ el: (this.text = BI.createWidget(json)), left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap }] }); return; } json.width = o.width - 2 * o.hgap - o.lgap - o.rgap; BI.createWidget({ type: "bi.vertical_adapt", scrollable: o.whiteSpace === "normal", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, element: this, items: [{ el: (this.text = BI.createWidget(json)) }] }); return; } if (BI.isNumber(o.textWidth) && o.textWidth > 0) { json.width = o.textWidth; BI.createWidget({ type: "bi.vertical_adapt", scrollable: o.whiteSpace === "normal", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, element: this, items: [ { el: (this.text = BI.createWidget(json)) } ] }); return; } if (o.whiteSpace == "normal") { this.text = BI.createWidget(json) BI.createWidget({ type: "bi.vertical_adapt", scrollable: o.whiteSpace === "normal", hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, element: this, items: [this.text] }); return; } if (BI.isNumber(o.height) && o.height > 0) { if (BI.isNumber(o.textHeight) && o.textHeight > 0) { this.element.css({ "line-height": o.height + "px" }); BI.createWidget({ type: "bi.adaptive", height: o.height, scrollable: o.whiteSpace === "normal", element: this, items: [{ el: (this.text = BI.createWidget(json)), left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, bottom: o.vgap + o.bgap }] }); return; } BI.extend(json, { hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap }); this.element.css({ "line-height": o.height + "px" }); this.text = BI.createWidget(BI.extend(json, { element: this })); BI.createWidget({ type: "bi.layout", element: this.text, scrollable: o.whiteSpace === "normal" }); return; } BI.extend(json, { hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap }); if (o.forceCenter) { this.text = BI.createWidget(json); BI.createWidget({ type: "bi.vertical_adapt", element: this, items: [this.text] }); return; } this.text = BI.createWidget(BI.extend(json, { element: this })); BI.createWidget({ type: "bi.layout", element: this.text, scrollable: o.whiteSpace === "normal" }) }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, setText: function (v) { this.options.text = v; this.text.setText(v); }, getText: function () { return this.options.text; }, setStyle: function (css) { this.text.setStyle(css) }, setValue: function (v) { BI.Label.superclass.setValue.apply(this, arguments); if (!this.isReadOnly()) { this.text.setValue(v); } }, populate: function () { BI.Label.superclass.populate.apply(this, arguments); } }); BI.shortcut("bi.label", BI.Label);/** * guy a元素 * @class BI.Link * @extends BI.Text */ BI.Link = BI.inherit(BI.Label, { _defaultConfig: function() { var conf = BI.Link.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-link", href: "", target: "_blank" }) }, _createJson: function(){ var o = this.options; return { type:"bi.a", textAlign: o.textAlign, whiteSpace: o.whiteSpace, lineHeight: o.textHeight, text: o.text, keyword: o.keyword, value: o.value, py: o.py, href: o.href, target: o.target }; }, _init : function() { BI.Link.superclass._init.apply(this, arguments); } }); BI.shortcut("bi.link", BI.Link);/** * guy * 气泡提示 * @class BI.Bubble * @extends BI.Tip * @type {*|void|Object} */ BI.Bubble = BI.inherit(BI.Tip, { _defaultConfig: function() { return BI.extend(BI.Bubble.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-bubble", direction: "top", text: "", height: 35 }) }, _init : function() { BI.Bubble.superclass._init.apply(this, arguments); var fn = function (e) { e.stopPropagation(); e.stopEvent(); return false; }; this.element.bind({"click": fn, "mousedown": fn, "mouseup": fn, "mouseover": fn, "mouseenter": fn, "mouseleave": fn, "mousemove": fn}); BI.createWidget({ type: "bi.left", element: this, items: [this["_" + this.options.direction]()] }) }, _createBubbleText: function(){ return (this.text = BI.createWidget({ type: "bi.label", cls: "bubble-text", text: this.options.text, hgap: 10, height: 30 })); }, _top: function(){ return BI.createWidget({ type: "bi.vertical", items: [{ el: this._createBubbleText(), height: 30 }, { el: { type: "bi.layout" }, height: 3 }] }) }, _bottom: function(){ return BI.createWidget({ type: "bi.vertical", items: [{ el: { type: "bi.layout" }, height: 3 }, { el: this._createBubbleText(), height: 30 }] }) }, _left: function(){ return BI.createWidget({ type: "bi.right", items: [{ el: { type: "bi.layout", width: 3, height: 30 } }, { el: this._createBubbleText() }] }) }, _right: function(){ return BI.createWidget({ type: "bi.left", items: [{ el: { type: "bi.layout", width: 3, height: 30 } }, { el: this._createBubbleText() }] }) }, setText: function(text){ this.text.setText(text); } }); BI.shortcut("bi.bubble", BI.Bubble);/** * toast提示 * * Created by GUY on 2015/9/7. * @class BI.Toast * @extends BI.Tip */ BI.Toast = BI.inherit(BI.Tip, { _const: { minWidth: 200, hgap: 20 }, _defaultConfig: function () { return BI.extend(BI.Toast.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-toast", text: "", level: "success",//success或warning height: 30 }) }, _init: function () { BI.Toast.superclass._init.apply(this, arguments); var o = this.options; this.element.css({ minWidth: this._const.minWidth + "px" }) this.element.addClass("toast-" + o.level); var fn = function (e) { e.stopPropagation(); e.stopEvent(); return false; }; this.element.bind({"click": fn, "mousedown": fn, "mouseup": fn, "mouseover": fn, "mouseenter": fn, "mouseleave": fn, "mousemove": fn}); this.text = BI.createWidget({ type: "bi.label", element: this, text: o.text, height: 30, hgap: this._const.hgap }) }, setWidth: function(width){ this.element.width(width); }, setText: function (text) { this.text.setText(text); } }); BI.shortcut("bi.toast", BI.Toast);/** * toast提示 * * Created by GUY on 2015/9/7. * @class BI.Tooltip * @extends BI.Tip */ BI.Tooltip = BI.inherit(BI.Tip, { _const: { hgap: 10 }, _defaultConfig: function () { return BI.extend(BI.Tooltip.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-tooltip", text: "", level: "success",//success或warning stopEvent: false, stopPropagation: false, height: 20 }) }, _init: function () { BI.Tooltip.superclass._init.apply(this, arguments); var self = this, o = this.options; this.element.addClass("tooltip-" + o.level); var fn = function (e) { o.stopPropagation && e.stopPropagation(); o.stopEvent && e.stopEvent(); }; this.element.bind({ "click": fn, "mousedown": fn, "mouseup": fn, "mouseover": fn, "mouseenter": fn, "mouseleave": fn, "mousemove": fn }); var texts = (o.text + "").split("\n"); if (texts.length > 1) { BI.createWidget({ type: "bi.vertical", element: this, hgap: this._const.hgap, items: BI.map(texts, function (i, text) { return { type: "bi.label", textAlign: "left", whiteSpace: "normal", text: text, textHeight: 16 } }) }) } else { this.text = BI.createWidget({ type: "bi.label", element: this, textAlign: "left", whiteSpace: "normal", text: o.text, textHeight: 20, hgap: this._const.hgap }); } }, setWidth: function (width) { this.element.width(width - 2 * this._const.hgap); }, setText: function (text) { this.text && this.text.setText(text); }, setLevel: function (level) { this.element.removeClass("tooltip-success").removeClass("tooltip-warning"); this.element.addClass("tooltip-" + level); } }); BI.shortcut("bi.tooltip", BI.Tooltip);/** * 下拉 * @class BI.Trigger * @extends BI.Single * @abstract */ BI.Trigger = BI.inherit(BI.Single, { _defaultConfig: function() { var conf = BI.Trigger.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-trigger cursor-pointer", height: 30 }) }, _init : function() { BI.Trigger.superclass._init.apply(this, arguments); }, setKey: function(){ }, getKey: function(){ } });// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ┌────────────────────────────────────────────────────────────┐ \\ // │ Eve 0.4.2 - JavaScript Events Library │ \\ // ├────────────────────────────────────────────────────────────┤ \\ // │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ // └────────────────────────────────────────────────────────────┘ \\ (function (glob, factory) { if (typeof define === "function" && define.amd) { define("eve", function() { return factory(); }); } else if (typeof exports === "object") { module.exports = factory(); } else { glob.eve = factory(); } }(this, function(){ var version = "0.4.2", has = "hasOwnProperty", separator = /[\.\/]/, wildcard = "*", fun = function () {}, numsort = function (a, b) { return a - b; }, current_event, stop, events = {n: {}}, /*\ * eve [ method ] * Fires event with given `name`, given scope and other parameters. > Arguments - name (string) name of the *event*, dot (`.`) or slash (`/`) separated - scope (object) context for the event handlers - varargs (...) the rest of arguments will be sent to event handlers = (object) array of returned values from the listeners \*/ eve = function (name, scope) { name = String(name); var e = events, oldstop = stop, args = Array.prototype.slice.call(arguments, 2), listeners = eve.listeners(name), z = 0, f = false, l, indexed = [], queue = {}, out = [], ce = current_event, errors = []; current_event = name; stop = 0; for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { indexed.push(listeners[i].zIndex); if (listeners[i].zIndex < 0) { queue[listeners[i].zIndex] = listeners[i]; } } indexed.sort(numsort); while (indexed[z] < 0) { l = queue[indexed[z++]]; out.push(l.apply(scope, args)); if (stop) { stop = oldstop; return out; } } for (i = 0; i < ii; i++) { l = listeners[i]; if ("zIndex" in l) { if (l.zIndex == indexed[z]) { out.push(l.apply(scope, args)); if (stop) { break; } do { z++; l = queue[indexed[z]]; l && out.push(l.apply(scope, args)); if (stop) { break; } } while (l) } else { queue[l.zIndex] = l; } } else { out.push(l.apply(scope, args)); if (stop) { break; } } } stop = oldstop; current_event = ce; return out.length ? out : null; }; // Undocumented. Debug only. eve._events = events; /*\ * eve.listeners [ method ] * Internal method which gives you array of all event handlers that will be triggered by the given `name`. > Arguments - name (string) name of the event, dot (`.`) or slash (`/`) separated = (array) array of event handlers \*/ eve.listeners = function (name) { var names = name.split(separator), e = events, item, items, k, i, ii, j, jj, nes, es = [e], out = []; for (i = 0, ii = names.length; i < ii; i++) { nes = []; for (j = 0, jj = es.length; j < jj; j++) { e = es[j].n; items = [e[names[i]], e[wildcard]]; k = 2; while (k--) { item = items[k]; if (item) { nes.push(item); out = out.concat(item.f || []); } } } es = nes; } return out; }; /*\ * eve.on [ method ] ** * Binds given event handler with a given name. You can use wildcards “`*`” for the names: | eve.on("*.under.*", f); | eve("mouse.under.floor"); // triggers f * Use @eve to trigger the listener. ** > Arguments ** - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards - f (function) event handler function ** = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. > Example: | eve.on("mouse", eatIt)(2); | eve.on("mouse", scream); | eve.on("mouse", catchIt)(1); * This will ensure that `catchIt()` function will be called before `eatIt()`. * * If you want to put your handler before non-indexed handlers, specify a negative value. * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. \*/ eve.on = function (name, f) { name = String(name); if (typeof f != "function") { return function () {}; } var names = name.split(separator), e = events; for (var i = 0, ii = names.length; i < ii; i++) { e = e.n; e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); } e.f = e.f || []; for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { return fun; } e.f.push(f); return function (zIndex) { if (+zIndex == +zIndex) { f.zIndex = +zIndex; } }; }; /*\ * eve.f [ method ] ** * Returns function that will fire given event with optional arguments. * Arguments that will be passed to the result function will be also * concated to the list of final arguments. | el.onclick = eve.f("click", 1, 2); | eve.on("click", function (a, b, c) { | console.log(a, b, c); // 1, 2, [event object] | }); > Arguments - event (string) event name - varargs (…) and any other arguments = (function) possible event handler function \*/ eve.f = function (event) { var attrs = [].slice.call(arguments, 1); return function () { eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); }; }; /*\ * eve.stop [ method ] ** * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. \*/ eve.stop = function () { stop = 1; }; /*\ * eve.nt [ method ] ** * Could be used inside event handler to figure out actual name of the event. ** > Arguments ** - subname (string) #optional subname of the event ** = (string) name of the event, if `subname` is not specified * or = (boolean) `true`, if current event’s name contains `subname` \*/ eve.nt = function (subname) { if (subname) { return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); } return current_event; }; /*\ * eve.nts [ method ] ** * Could be used inside event handler to figure out actual name of the event. ** ** = (array) names of the event \*/ eve.nts = function () { return current_event.split(separator); }; /*\ * eve.off [ method ] ** * Removes given function from the list of event listeners assigned to given name. * If no arguments specified all the events will be cleared. ** > Arguments ** - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards - f (function) event handler function \*/ /*\ * eve.unbind [ method ] ** * See @eve.off \*/ eve.off = eve.unbind = function (name, f) { if (!name) { eve._events = events = {n: {}}; return; } var names = name.split(separator), e, key, splice, i, ii, j, jj, cur = [events]; for (i = 0, ii = names.length; i < ii; i++) { for (j = 0; j < cur.length; j += splice.length - 2) { splice = [j, 1]; e = cur[j].n; if (names[i] != wildcard) { if (e[names[i]]) { splice.push(e[names[i]]); } } else { for (key in e) if (e[has](key)) { splice.push(e[key]); } } cur.splice.apply(cur, splice); } } for (i = 0, ii = cur.length; i < ii; i++) { e = cur[i]; while (e.n) { if (f) { if (e.f) { for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { e.f.splice(j, 1); break; } !e.f.length && delete e.f; } for (key in e.n) if (e.n[has](key) && e.n[key].f) { var funcs = e.n[key].f; for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { funcs.splice(j, 1); break; } !funcs.length && delete e.n[key].f; } } else { delete e.f; for (key in e.n) if (e.n[has](key) && e.n[key].f) { delete e.n[key].f; } } e = e.n; } } }; /*\ * eve.once [ method ] ** * Binds given event handler with a given name to only run once then unbind itself. | eve.once("login", f); | eve("login"); // triggers f | eve("login"); // no listeners * Use @eve to trigger the listener. ** > Arguments ** - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards - f (function) event handler function ** = (function) same return function as @eve.on \*/ eve.once = function (name, f) { var f2 = function () { eve.unbind(name, f2); return f.apply(this, arguments); }; return eve.on(name, f2); }; /*\ * eve.version [ property (string) ] ** * Current version of the library. \*/ eve.version = version; eve.toString = function () { return "You are running Eve " + version; }; return eve; })); // ┌────────────────────────────────────────────────────────────────────┐ \\ // │ Raphaël 2.1.4 - JavaScript Vector Library │ \\ // ├────────────────────────────────────────────────────────────────────┤ \\ // │ Core Module │ \\ // ├────────────────────────────────────────────────────────────────────┤ \\ // │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\ // └────────────────────────────────────────────────────────────────────┘ \\ (function (glob, factory) { if (typeof define === "function" && define.amd) { define("raphael.core", ["eve"], function(eve) { return factory(eve); }); } else if (typeof exports === "object") { module.exports = factory(require("eve")); } else { glob.Raphael = factory(glob.eve); } }(this, function (eve) { /*\ * Raphael [ method ] ** * Creates a canvas object on which to draw. * You must do this first, as all future calls to drawing methods * from this instance will be bound to this canvas. > Parameters ** - container (HTMLElement|string) DOM element or its ID which is going to be a parent for drawing surface - width (number) - height (number) - callback (function) #optional callback function which is going to be executed in the context of newly created paper * or - x (number) - y (number) - width (number) - height (number) - callback (function) #optional callback function which is going to be executed in the context of newly created paper * or - all (array) (first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, <attributes>}). See @Paper.add. - callback (function) #optional callback function which is going to be executed in the context of newly created paper * or - onReadyCallback (function) function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns `undefined`. = (object) @Paper > Usage | // Each of the following examples create a canvas | // that is 320px wide by 200px high. | // Canvas is created at the viewport’s 10,50 coordinate. | var paper = Raphael(10, 50, 320, 200); | // Canvas is created at the top left corner of the #notepad element | // (or its top right corner in dir="rtl" elements) | var paper = Raphael(document.getElementById("notepad"), 320, 200); | // Same as above | var paper = Raphael("notepad", 320, 200); | // Image dump | var set = Raphael(["notepad", 320, 200, { | type: "rect", | x: 10, | y: 10, | width: 25, | height: 25, | stroke: "#f00" | }, { | type: "text", | x: 30, | y: 40, | text: "Dump" | }]); \*/ function R(first) { if (R.is(first, "function")) { return loaded ? first() : eve.on("raphael.DOMload", first); } else if (R.is(first, array)) { return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first); } else { var args = Array.prototype.slice.call(arguments, 0); if (R.is(args[args.length - 1], "function")) { var f = args.pop(); return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("raphael.DOMload", function () { f.call(R._engine.create[apply](R, args)); }); } else { return R._engine.create[apply](R, arguments); } } } R.version = "2.1.4"; R.eve = eve; var loaded, separator = /[, ]+/, elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, formatrg = /\{(\d+)\}/g, proto = "prototype", has = "hasOwnProperty", g = { doc: document, win: window }, oldRaphael = { was: Object.prototype[has].call(g.win, "Raphael"), is: g.win.Raphael }, Paper = function () { /*\ * Paper.ca [ property (object) ] ** * Shortcut for @Paper.customAttributes \*/ /*\ * Paper.customAttributes [ property (object) ] ** * If you have a set of attributes that you would like to represent * as a function of some number you can do it easily with custom attributes: > Usage | paper.customAttributes.hue = function (num) { | num = num % 1; | return {fill: "hsb(" + num + ", 0.75, 1)"}; | }; | // Custom attribute “hue” will change fill | // to be given hue with fixed saturation and brightness. | // Now you can use it like this: | var c = paper.circle(10, 10, 10).attr({hue: .45}); | // or even like this: | c.animate({hue: 1}, 1e3); | | // You could also create custom attribute | // with multiple parameters: | paper.customAttributes.hsb = function (h, s, b) { | return {fill: "hsb(" + [h, s, b].join(",") + ")"}; | }; | c.attr({hsb: "0.5 .8 1"}); | c.animate({hsb: [1, 0, 0.5]}, 1e3); \*/ this.ca = this.customAttributes = {}; }, paperproto, appendChild = "appendChild", apply = "apply", concat = "concat", supportsTouch = ('ontouchstart' in g.win) || g.win.DocumentTouch && g.doc instanceof DocumentTouch, //taken from Modernizr touch test E = "", S = " ", Str = String, split = "split", events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), touchMap = { mousedown: "touchstart", mousemove: "touchmove", mouseup: "touchend" }, lowerCase = Str.prototype.toLowerCase, math = Math, mmax = math.max, mmin = math.min, abs = math.abs, pow = math.pow, PI = math.PI, nu = "number", string = "string", array = "array", toString = "toString", fillString = "fill", objectToString = Object.prototype.toString, paper = {}, push = "push", ISURL = R._ISURL = /^url\(['"]?(.+?)['"]?\)$/i, colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i, isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1}, bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, round = math.round, setAttribute = "setAttribute", toFloat = parseFloat, toInt = parseInt, upperCase = Str.prototype.toUpperCase, availableAttrs = R._availableAttrs = { "arrow-end": "none", "arrow-start": "none", blur: 0, "clip-rect": "0 0 1e9 1e9", cursor: "default", cx: 0, cy: 0, fill: "#fff", "fill-opacity": 1, font: '10px "Arial"', "font-family": '"Arial"', "font-size": "10", "font-style": "normal", "font-weight": 400, gradient: 0, height: 0, href: "http://raphaeljs.com/", "letter-spacing": 0, opacity: 1, path: "M0,0", r: 0, rx: 0, ry: 0, src: "", stroke: "#000", "stroke-dasharray": "", "stroke-linecap": "butt", "stroke-linejoin": "butt", "stroke-miterlimit": 0, "stroke-opacity": 1, "stroke-width": 1, target: "_blank", "text-anchor": "middle", title: "Raphael", transform: "", width: 0, x: 0, y: 0 }, availableAnimAttrs = R._availableAnimAttrs = { blur: nu, "clip-rect": "csv", cx: nu, cy: nu, fill: "colour", "fill-opacity": nu, "font-size": nu, height: nu, opacity: nu, path: "path", r: nu, rx: nu, ry: nu, stroke: "colour", "stroke-opacity": nu, "stroke-width": nu, transform: "transform", width: nu, x: nu, y: nu }, whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g, commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/, hsrg = {hs: 1, rg: 1}, p2s = /,?([achlmqrstvxz]),?/gi, pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig, tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig, pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig, radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/, eldata = {}, sortByKey = function (a, b) { return a.key - b.key; }, sortByNumber = function (a, b) { return toFloat(a) - toFloat(b); }, fun = function () {}, pipe = function (x) { return x; }, rectPath = R._rectPath = function (x, y, w, h, r) { if (r) { return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]]; } return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; }, ellipsePath = function (x, y, rx, ry) { if (ry == null) { ry = rx; } return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]]; }, getPath = R._getPath = { path: function (el) { return el.attr("path"); }, circle: function (el) { var a = el.attrs; return ellipsePath(a.cx, a.cy, a.r); }, ellipse: function (el) { var a = el.attrs; return ellipsePath(a.cx, a.cy, a.rx, a.ry); }, rect: function (el) { var a = el.attrs; return rectPath(a.x, a.y, a.width, a.height, a.r); }, image: function (el) { var a = el.attrs; return rectPath(a.x, a.y, a.width, a.height); }, text: function (el) { var bbox = el._getBBox(); return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); }, set : function(el) { var bbox = el._getBBox(); return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); } }, /*\ * Raphael.mapPath [ method ] ** * Transform the path string with given matrix. > Parameters - path (string) path string - matrix (object) see @Matrix = (string) transformed path string \*/ mapPath = R.mapPath = function (path, matrix) { if (!matrix) { return path; } var x, y, i, j, ii, jj, pathi; path = path2curve(path); for (i = 0, ii = path.length; i < ii; i++) { pathi = path[i]; for (j = 1, jj = pathi.length; j < jj; j += 2) { x = matrix.x(pathi[j], pathi[j + 1]); y = matrix.y(pathi[j], pathi[j + 1]); pathi[j] = x; pathi[j + 1] = y; } } return path; }; R._g = g; /*\ * Raphael.type [ property (string) ] ** * Can be “SVG”, “VML” or empty, depending on browser support. \*/ R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); if (R.type == "VML") { var d = g.doc.createElement("div"), b; d.innerHTML = '<v:shape adj="1"/>'; b = d.firstChild; b.style.behavior = "url(#default#VML)"; if (!(b && typeof b.adj == "object")) { return (R.type = E); } d = null; } /*\ * Raphael.svg [ property (boolean) ] ** * `true` if browser supports SVG. \*/ /*\ * Raphael.vml [ property (boolean) ] ** * `true` if browser supports VML. \*/ R.svg = !(R.vml = R.type == "VML"); R._Paper = Paper; /*\ * Raphael.fn [ property (object) ] ** * You can add your own method to the canvas. For example if you want to draw a pie chart, * you can create your own pie chart function and ship it as a Raphaël plugin. To do this * you need to extend the `Raphael.fn` object. You should modify the `fn` object before a * Raphaël instance is created, otherwise it will take no effect. Please note that the * ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to * ensure any namespacing ensures proper context. > Usage | Raphael.fn.arrow = function (x1, y1, x2, y2, size) { | return this.path( ... ); | }; | // or create namespace | Raphael.fn.mystuff = { | arrow: function () {…}, | star: function () {…}, | // etc… | }; | var paper = Raphael(10, 10, 630, 480); | // then use it | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"}); | paper.mystuff.arrow(); | paper.mystuff.star(); \*/ R.fn = paperproto = Paper.prototype = R.prototype; R._id = 0; R._oid = 0; /*\ * Raphael.is [ method ] ** * Handful of replacements for `typeof` operator. > Parameters - o (…) any object or primitive - type (string) name of the type, i.e. “string”, “function”, “number”, etc. = (boolean) is given value is of given type \*/ R.is = function (o, type) { type = lowerCase.call(type); if (type == "finite") { return !isnan[has](+o); } if (type == "array") { return o instanceof Array; } return (type == "null" && o === null) || (type == typeof o && o !== null) || (type == "object" && o === Object(o)) || (type == "array" && Array.isArray && Array.isArray(o)) || objectToString.call(o).slice(8, -1).toLowerCase() == type; }; function clone(obj) { if (typeof obj == "function" || Object(obj) !== obj) { return obj; } var res = new obj.constructor; for (var key in obj) if (obj[has](key)) { res[key] = clone(obj[key]); } return res; } /*\ * Raphael.angle [ method ] ** * Returns angle between two or three points > Parameters - x1 (number) x coord of first point - y1 (number) y coord of first point - x2 (number) x coord of second point - y2 (number) y coord of second point - x3 (number) #optional x coord of third point - y3 (number) #optional y coord of third point = (number) angle in degrees. \*/ R.angle = function (x1, y1, x2, y2, x3, y3) { if (x3 == null) { var x = x1 - x2, y = y1 - y2; if (!x && !y) { return 0; } return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; } else { return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); } }; /*\ * Raphael.rad [ method ] ** * Transform angle to radians > Parameters - deg (number) angle in degrees = (number) angle in radians. \*/ R.rad = function (deg) { return deg % 360 * PI / 180; }; /*\ * Raphael.deg [ method ] ** * Transform angle to degrees > Parameters - rad (number) angle in radians = (number) angle in degrees. \*/ R.deg = function (rad) { return Math.round ((rad * 180 / PI% 360)* 1000) / 1000; }; /*\ * Raphael.snapTo [ method ] ** * Snaps given value to given grid. > Parameters - values (array|number) given array of values or step of the grid - value (number) value to adjust - tolerance (number) #optional tolerance for snapping. Default is `10`. = (number) adjusted value. \*/ R.snapTo = function (values, value, tolerance) { tolerance = R.is(tolerance, "finite") ? tolerance : 10; if (R.is(values, array)) { var i = values.length; while (i--) if (abs(values[i] - value) <= tolerance) { return values[i]; } } else { values = +values; var rem = value % values; if (rem < tolerance) { return value - rem; } if (rem > values - tolerance) { return value - rem + values; } } return value; }; /*\ * Raphael.createUUID [ method ] ** * Returns RFC4122, version 4 ID \*/ var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { return function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); }; })(/[xy]/g, function (c) { var r = math.random() * 16 | 0, v = c == "x" ? r : (r & 3 | 8); return v.toString(16); }); /*\ * Raphael.setWindow [ method ] ** * Used when you need to draw in `<iframe>`. Switched window to the iframe one. > Parameters - newwin (window) new window object \*/ R.setWindow = function (newwin) { eve("raphael.setWindow", R, g.win, newwin); g.win = newwin; g.doc = g.win.document; if (R._engine.initWin) { R._engine.initWin(g.win); } }; var toHex = function (color) { if (R.vml) { // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ var trim = /^\s+|\s+$/g; var bod; try { var docum = new ActiveXObject("htmlfile"); docum.write("<body>"); docum.close(); bod = docum.body; } catch(e) { bod = createPopup().document.body; } var range = bod.createTextRange(); toHex = cacher(function (color) { try { bod.style.color = Str(color).replace(trim, E); var value = range.queryCommandValue("ForeColor"); value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); return "#" + ("000000" + value.toString(16)).slice(-6); } catch(e) { return "none"; } }); } else { var i = g.doc.createElement("i"); i.title = "Rapha\xebl Colour Picker"; i.style.display = "none"; g.doc.body.appendChild(i); toHex = cacher(function (color) { i.style.color = color; return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); }); } return toHex(color); }, hsbtoString = function () { return "hsb(" + [this.h, this.s, this.b] + ")"; }, hsltoString = function () { return "hsl(" + [this.h, this.s, this.l] + ")"; }, rgbtoString = function () { return this.hex; }, prepareRGB = function (r, g, b) { if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { b = r.b; g = r.g; r = r.r; } if (g == null && R.is(r, string)) { var clr = R.getRGB(r); r = clr.r; g = clr.g; b = clr.b; } if (r > 1 || g > 1 || b > 1) { r /= 255; g /= 255; b /= 255; } return [r, g, b]; }, packageRGB = function (r, g, b, o) { r *= 255; g *= 255; b *= 255; var rgb = { r: r, g: g, b: b, hex: R.rgb(r, g, b), toString: rgbtoString }; R.is(o, "finite") && (rgb.opacity = o); return rgb; }; /*\ * Raphael.color [ method ] ** * Parses the color string and returns object with all values for the given color. > Parameters - clr (string) color string in one of the supported formats (see @Raphael.getRGB) = (object) Combined RGB & HSB object in format: o { o r (number) red, o g (number) green, o b (number) blue, o hex (string) color in HTML/CSS format: #••••••, o error (boolean) `true` if string can’t be parsed, o h (number) hue, o s (number) saturation, o v (number) value (brightness), o l (number) lightness o } \*/ R.color = function (clr) { var rgb; if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { rgb = R.hsb2rgb(clr); clr.r = rgb.r; clr.g = rgb.g; clr.b = rgb.b; clr.hex = rgb.hex; } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { rgb = R.hsl2rgb(clr); clr.r = rgb.r; clr.g = rgb.g; clr.b = rgb.b; clr.hex = rgb.hex; } else { if (R.is(clr, "string")) { clr = R.getRGB(clr); } if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) { rgb = R.rgb2hsl(clr); clr.h = rgb.h; clr.s = rgb.s; clr.l = rgb.l; rgb = R.rgb2hsb(clr); clr.v = rgb.b; } else { clr = {hex: "none"}; clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; } } clr.toString = rgbtoString; return clr; }; /*\ * Raphael.hsb2rgb [ method ] ** * Converts HSB values to RGB object. > Parameters - h (number) hue - s (number) saturation - v (number) value or brightness = (object) RGB object in format: o { o r (number) red, o g (number) green, o b (number) blue, o hex (string) color in HTML/CSS format: #•••••• o } \*/ R.hsb2rgb = function (h, s, v, o) { if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { v = h.b; s = h.s; o = h.o; h = h.h; } h *= 360; var R, G, B, X, C; h = (h % 360) / 60; C = v * s; X = C * (1 - abs(h % 2 - 1)); R = G = B = v - C; h = ~~h; R += [C, X, 0, 0, X, C][h]; G += [X, C, C, X, 0, 0][h]; B += [0, 0, X, C, C, X][h]; return packageRGB(R, G, B, o); }; /*\ * Raphael.hsl2rgb [ method ] ** * Converts HSL values to RGB object. > Parameters - h (number) hue - s (number) saturation - l (number) luminosity = (object) RGB object in format: o { o r (number) red, o g (number) green, o b (number) blue, o hex (string) color in HTML/CSS format: #•••••• o } \*/ R.hsl2rgb = function (h, s, l, o) { if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { l = h.l; s = h.s; h = h.h; } if (h > 1 || s > 1 || l > 1) { h /= 360; s /= 100; l /= 100; } h *= 360; var R, G, B, X, C; h = (h % 360) / 60; C = 2 * s * (l < .5 ? l : 1 - l); X = C * (1 - abs(h % 2 - 1)); R = G = B = l - C / 2; h = ~~h; R += [C, X, 0, 0, X, C][h]; G += [X, C, C, X, 0, 0][h]; B += [0, 0, X, C, C, X][h]; return packageRGB(R, G, B, o); }; /*\ * Raphael.rgb2hsb [ method ] ** * Converts RGB values to HSB object. > Parameters - r (number) red - g (number) green - b (number) blue = (object) HSB object in format: o { o h (number) hue o s (number) saturation o b (number) brightness o } \*/ R.rgb2hsb = function (r, g, b) { b = prepareRGB(r, g, b); r = b[0]; g = b[1]; b = b[2]; var H, S, V, C; V = mmax(r, g, b); C = V - mmin(r, g, b); H = (C == 0 ? null : V == r ? (g - b) / C : V == g ? (b - r) / C + 2 : (r - g) / C + 4 ); H = ((H + 360) % 6) * 60 / 360; S = C == 0 ? 0 : C / V; return {h: H, s: S, b: V, toString: hsbtoString}; }; /*\ * Raphael.rgb2hsl [ method ] ** * Converts RGB values to HSL object. > Parameters - r (number) red - g (number) green - b (number) blue = (object) HSL object in format: o { o h (number) hue o s (number) saturation o l (number) luminosity o } \*/ R.rgb2hsl = function (r, g, b) { b = prepareRGB(r, g, b); r = b[0]; g = b[1]; b = b[2]; var H, S, L, M, m, C; M = mmax(r, g, b); m = mmin(r, g, b); C = M - m; H = (C == 0 ? null : M == r ? (g - b) / C : M == g ? (b - r) / C + 2 : (r - g) / C + 4); H = ((H + 360) % 6) * 60 / 360; L = (M + m) / 2; S = (C == 0 ? 0 : L < .5 ? C / (2 * L) : C / (2 - 2 * L)); return {h: H, s: S, l: L, toString: hsltoString}; }; R._path2string = function () { return this.join(",").replace(p2s, "$1"); }; function repush(array, item) { for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { return array.push(array.splice(i, 1)[0]); } } function cacher(f, scope, postprocessor) { function newf() { var arg = Array.prototype.slice.call(arguments, 0), args = arg.join("\u2400"), cache = newf.cache = newf.cache || {}, count = newf.count = newf.count || []; if (cache[has](args)) { repush(count, args); return postprocessor ? postprocessor(cache[args]) : cache[args]; } count.length >= 1e3 && delete cache[count.shift()]; count.push(args); cache[args] = f[apply](scope, arg); return postprocessor ? postprocessor(cache[args]) : cache[args]; } return newf; } var preload = R._preload = function (src, f) { var img = g.doc.createElement("img"); img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; img.onload = function () { f.call(this); this.onload = null; g.doc.body.removeChild(this); }; img.onerror = function () { g.doc.body.removeChild(this); }; g.doc.body.appendChild(img); img.src = src; }; function clrToString() { return this.hex; } /*\ * Raphael.getRGB [ method ] ** * Parses colour string as RGB object > Parameters - colour (string) colour string in one of formats: # <ul> # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li> # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li> # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li> # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li> # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li> # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li> # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> # <li>hsl(•••, •••, •••) — same as hsb</li> # <li>hsl(•••%, •••%, •••%) — same as hsb</li> # </ul> = (object) RGB object in format: o { o r (number) red, o g (number) green, o b (number) blue o hex (string) color in HTML/CSS format: #••••••, o error (boolean) true if string can’t be parsed o } \*/ R.getRGB = cacher(function (colour) { if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; } if (colour == "none") { return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString}; } !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); var res, red, green, blue, opacity, t, values, rgb = colour.match(colourRegExp); if (rgb) { if (rgb[2]) { blue = toInt(rgb[2].substring(5), 16); green = toInt(rgb[2].substring(3, 5), 16); red = toInt(rgb[2].substring(1, 3), 16); } if (rgb[3]) { blue = toInt((t = rgb[3].charAt(3)) + t, 16); green = toInt((t = rgb[3].charAt(2)) + t, 16); red = toInt((t = rgb[3].charAt(1)) + t, 16); } if (rgb[4]) { values = rgb[4][split](commaSpaces); red = toFloat(values[0]); values[0].slice(-1) == "%" && (red *= 2.55); green = toFloat(values[1]); values[1].slice(-1) == "%" && (green *= 2.55); blue = toFloat(values[2]); values[2].slice(-1) == "%" && (blue *= 2.55); rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); values[3] && values[3].slice(-1) == "%" && (opacity /= 100); } if (rgb[5]) { values = rgb[5][split](commaSpaces); red = toFloat(values[0]); values[0].slice(-1) == "%" && (red *= 2.55); green = toFloat(values[1]); values[1].slice(-1) == "%" && (green *= 2.55); blue = toFloat(values[2]); values[2].slice(-1) == "%" && (blue *= 2.55); (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); values[3] && values[3].slice(-1) == "%" && (opacity /= 100); return R.hsb2rgb(red, green, blue, opacity); } if (rgb[6]) { values = rgb[6][split](commaSpaces); red = toFloat(values[0]); values[0].slice(-1) == "%" && (red *= 2.55); green = toFloat(values[1]); values[1].slice(-1) == "%" && (green *= 2.55); blue = toFloat(values[2]); values[2].slice(-1) == "%" && (blue *= 2.55); (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); values[3] && values[3].slice(-1) == "%" && (opacity /= 100); return R.hsl2rgb(red, green, blue, opacity); } rgb = {r: red, g: green, b: blue, toString: clrToString}; rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); R.is(opacity, "finite") && (rgb.opacity = opacity); return rgb; } return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; }, R); /*\ * Raphael.hsb [ method ] ** * Converts HSB values to hex representation of the colour. > Parameters - h (number) hue - s (number) saturation - b (number) value or brightness = (string) hex representation of the colour. \*/ R.hsb = cacher(function (h, s, b) { return R.hsb2rgb(h, s, b).hex; }); /*\ * Raphael.hsl [ method ] ** * Converts HSL values to hex representation of the colour. > Parameters - h (number) hue - s (number) saturation - l (number) luminosity = (string) hex representation of the colour. \*/ R.hsl = cacher(function (h, s, l) { return R.hsl2rgb(h, s, l).hex; }); /*\ * Raphael.rgb [ method ] ** * Converts RGB values to hex representation of the colour. > Parameters - r (number) red - g (number) green - b (number) blue = (string) hex representation of the colour. \*/ R.rgb = cacher(function (r, g, b) { function round(x) { return (x + 0.5) | 0; } return "#" + (16777216 | round(b) | (round(g) << 8) | (round(r) << 16)).toString(16).slice(1); }); /*\ * Raphael.getColor [ method ] ** * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset > Parameters - value (number) #optional brightness, default is `0.75` = (string) hex representation of the colour. \*/ R.getColor = function (value) { var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, rgb = this.hsb2rgb(start.h, start.s, start.b); start.h += .075; if (start.h > 1) { start.h = 0; start.s -= .2; start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); } return rgb.hex; }; /*\ * Raphael.getColor.reset [ method ] ** * Resets spectrum position for @Raphael.getColor back to red. \*/ R.getColor.reset = function () { delete this.start; }; // http://schepers.cc/getting-to-the-point function catmullRom2bezier(crp, z) { var d = []; for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { var p = [ {x: +crp[i - 2], y: +crp[i - 1]}, {x: +crp[i], y: +crp[i + 1]}, {x: +crp[i + 2], y: +crp[i + 3]}, {x: +crp[i + 4], y: +crp[i + 5]} ]; if (z) { if (!i) { p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; } else if (iLen - 4 == i) { p[3] = {x: +crp[0], y: +crp[1]}; } else if (iLen - 2 == i) { p[2] = {x: +crp[0], y: +crp[1]}; p[3] = {x: +crp[2], y: +crp[3]}; } } else { if (iLen - 4 == i) { p[3] = p[2]; } else if (!i) { p[0] = {x: +crp[i], y: +crp[i + 1]}; } } d.push(["C", (-p[0].x + 6 * p[1].x + p[2].x) / 6, (-p[0].y + 6 * p[1].y + p[2].y) / 6, (p[1].x + 6 * p[2].x - p[3].x) / 6, (p[1].y + 6*p[2].y - p[3].y) / 6, p[2].x, p[2].y ]); } return d; } /*\ * Raphael.parsePathString [ method ] ** * Utility method ** * Parses given path string into an array of arrays of path segments. > Parameters - pathString (string|array) path string or array of segments (in the last case it will be returned straight away) = (array) array of segments. \*/ R.parsePathString = function (pathString) { if (!pathString) { return null; } var pth = paths(pathString); if (pth.arr) { return pathClone(pth.arr); } var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0}, data = []; if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption data = pathClone(pathString); } if (!data.length) { Str(pathString).replace(pathCommand, function (a, b, c) { var params = [], name = b.toLowerCase(); c.replace(pathValues, function (a, b) { b && params.push(+b); }); if (name == "m" && params.length > 2) { data.push([b][concat](params.splice(0, 2))); name = "l"; b = b == "m" ? "l" : "L"; } if (name == "r") { data.push([b][concat](params)); } else while (params.length >= paramCounts[name]) { data.push([b][concat](params.splice(0, paramCounts[name]))); if (!paramCounts[name]) { break; } } }); } data.toString = R._path2string; pth.arr = pathClone(data); return data; }; /*\ * Raphael.parseTransformString [ method ] ** * Utility method ** * Parses given path string into an array of transformations. > Parameters - TString (string|array) transform string or array of transformations (in the last case it will be returned straight away) = (array) array of transformations. \*/ R.parseTransformString = cacher(function (TString) { if (!TString) { return null; } var paramCounts = {r: 3, s: 4, t: 2, m: 6}, data = []; if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption data = pathClone(TString); } if (!data.length) { Str(TString).replace(tCommand, function (a, b, c) { var params = [], name = lowerCase.call(b); c.replace(pathValues, function (a, b) { b && params.push(+b); }); data.push([b][concat](params)); }); } data.toString = R._path2string; return data; }); // PATHS var paths = function (ps) { var p = paths.ps = paths.ps || {}; if (p[ps]) { p[ps].sleep = 100; } else { p[ps] = { sleep: 100 }; } setTimeout(function () { for (var key in p) if (p[has](key) && key != ps) { p[key].sleep--; !p[key].sleep && delete p[key]; } }); return p[ps]; }; /*\ * Raphael.findDotsAtSegment [ method ] ** * Utility method ** * Find dot coordinates on the given cubic bezier curve at the given t. > Parameters - p1x (number) x of the first point of the curve - p1y (number) y of the first point of the curve - c1x (number) x of the first anchor of the curve - c1y (number) y of the first anchor of the curve - c2x (number) x of the second anchor of the curve - c2y (number) y of the second anchor of the curve - p2x (number) x of the second point of the curve - p2y (number) y of the second point of the curve - t (number) position on the curve (0..1) = (object) point information in format: o { o x: (number) x coordinate of the point o y: (number) y coordinate of the point o m: { o x: (number) x coordinate of the left anchor o y: (number) y coordinate of the left anchor o } o n: { o x: (number) x coordinate of the right anchor o y: (number) y coordinate of the right anchor o } o start: { o x: (number) x coordinate of the start of the curve o y: (number) y coordinate of the start of the curve o } o end: { o x: (number) x coordinate of the end of the curve o y: (number) y coordinate of the end of the curve o } o alpha: (number) angle of the curve derivative at the point o } \*/ R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { var t1 = 1 - t, t13 = pow(t1, 3), t12 = pow(t1, 2), t2 = t * t, t3 = t2 * t, x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), ax = t1 * p1x + t * c1x, ay = t1 * p1y + t * c1y, cx = t1 * c2x + t * p2x, cy = t1 * c2y + t * p2y, alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); (mx > nx || my < ny) && (alpha += 180); return { x: x, y: y, m: {x: mx, y: my}, n: {x: nx, y: ny}, start: {x: ax, y: ay}, end: {x: cx, y: cy}, alpha: alpha }; }; /*\ * Raphael.bezierBBox [ method ] ** * Utility method ** * Return bounding box of a given cubic bezier curve > Parameters - p1x (number) x of the first point of the curve - p1y (number) y of the first point of the curve - c1x (number) x of the first anchor of the curve - c1y (number) y of the first anchor of the curve - c2x (number) x of the second anchor of the curve - c2y (number) y of the second anchor of the curve - p2x (number) x of the second point of the curve - p2y (number) y of the second point of the curve * or - bez (array) array of six points for bezier curve = (object) point information in format: o { o min: { o x: (number) x coordinate of the left point o y: (number) y coordinate of the top point o } o max: { o x: (number) x coordinate of the right point o y: (number) y coordinate of the bottom point o } o } \*/ R.bezierBBox = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { if (!R.is(p1x, "array")) { p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; } var bbox = curveDim.apply(null, p1x); return { x: bbox.min.x, y: bbox.min.y, x2: bbox.max.x, y2: bbox.max.y, width: bbox.max.x - bbox.min.x, height: bbox.max.y - bbox.min.y }; }; /*\ * Raphael.isPointInsideBBox [ method ] ** * Utility method ** * Returns `true` if given point is inside bounding boxes. > Parameters - bbox (string) bounding box - x (string) x coordinate of the point - y (string) y coordinate of the point = (boolean) `true` if point inside \*/ R.isPointInsideBBox = function (bbox, x, y) { return x >= bbox.x && x <= bbox.x2 && y >= bbox.y && y <= bbox.y2; }; /*\ * Raphael.isBBoxIntersect [ method ] ** * Utility method ** * Returns `true` if two bounding boxes intersect > Parameters - bbox1 (string) first bounding box - bbox2 (string) second bounding box = (boolean) `true` if they intersect \*/ R.isBBoxIntersect = function (bbox1, bbox2) { var i = R.isPointInsideBBox; return i(bbox2, bbox1.x, bbox1.y) || i(bbox2, bbox1.x2, bbox1.y) || i(bbox2, bbox1.x, bbox1.y2) || i(bbox2, bbox1.x2, bbox1.y2) || i(bbox1, bbox2.x, bbox2.y) || i(bbox1, bbox2.x2, bbox2.y) || i(bbox1, bbox2.x, bbox2.y2) || i(bbox1, bbox2.x2, bbox2.y2) || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); }; function base3(t, p1, p2, p3, p4) { var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; return t * t2 - 3 * p1 + 3 * p2; } function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { if (z == null) { z = 1; } z = z > 1 ? 1 : z < 0 ? 0 : z; var z2 = z / 2, n = 12, Tvalues = [-0.1252,0.1252,-0.3678,0.3678,-0.5873,0.5873,-0.7699,0.7699,-0.9041,0.9041,-0.9816,0.9816], Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], sum = 0; for (var i = 0; i < n; i++) { var ct = z2 * Tvalues[i] + z2, xbase = base3(ct, x1, x2, x3, x4), ybase = base3(ct, y1, y2, y3, y4), comb = xbase * xbase + ybase * ybase; sum += Cvalues[i] * math.sqrt(comb); } return z2 * sum; } function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { return; } var t = 1, step = t / 2, t2 = t - step, l, e = .01; l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); while (abs(l - ll) > e) { step /= 2; t2 += (l < ll ? 1 : -1) * step; l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); } return t2; } function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { if ( mmax(x1, x2) < mmin(x3, x4) || mmin(x1, x2) > mmax(x3, x4) || mmax(y1, y2) < mmin(y3, y4) || mmin(y1, y2) > mmax(y3, y4) ) { return; } var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); if (!denominator) { return; } var px = nx / denominator, py = ny / denominator, px2 = +px.toFixed(2), py2 = +py.toFixed(2); if ( px2 < +mmin(x1, x2).toFixed(2) || px2 > +mmax(x1, x2).toFixed(2) || px2 < +mmin(x3, x4).toFixed(2) || px2 > +mmax(x3, x4).toFixed(2) || py2 < +mmin(y1, y2).toFixed(2) || py2 > +mmax(y1, y2).toFixed(2) || py2 < +mmin(y3, y4).toFixed(2) || py2 > +mmax(y3, y4).toFixed(2) ) { return; } return {x: px, y: py}; } function inter(bez1, bez2) { return interHelper(bez1, bez2); } function interCount(bez1, bez2) { return interHelper(bez1, bez2, 1); } function interHelper(bez1, bez2, justCount) { var bbox1 = R.bezierBBox(bez1), bbox2 = R.bezierBBox(bez2); if (!R.isBBoxIntersect(bbox1, bbox2)) { return justCount ? 0 : []; } var l1 = bezlen.apply(0, bez1), l2 = bezlen.apply(0, bez2), n1 = mmax(~~(l1 / 5), 1), n2 = mmax(~~(l2 / 5), 1), dots1 = [], dots2 = [], xy = {}, res = justCount ? 0 : []; for (var i = 0; i < n1 + 1; i++) { var p = R.findDotsAtSegment.apply(R, bez1.concat(i / n1)); dots1.push({x: p.x, y: p.y, t: i / n1}); } for (i = 0; i < n2 + 1; i++) { p = R.findDotsAtSegment.apply(R, bez2.concat(i / n2)); dots2.push({x: p.x, y: p.y, t: i / n2}); } for (i = 0; i < n1; i++) { for (var j = 0; j < n2; j++) { var di = dots1[i], di1 = dots1[i + 1], dj = dots2[j], dj1 = dots2[j + 1], ci = abs(di1.x - di.x) < .001 ? "y" : "x", cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); if (is) { if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { continue; } xy[is.x.toFixed(4)] = is.y.toFixed(4); var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); if (t1 >= 0 && t1 <= 1.001 && t2 >= 0 && t2 <= 1.001) { if (justCount) { res++; } else { res.push({ x: is.x, y: is.y, t1: mmin(t1, 1), t2: mmin(t2, 1) }); } } } } } return res; } /*\ * Raphael.pathIntersection [ method ] ** * Utility method ** * Finds intersections of two paths > Parameters - path1 (string) path string - path2 (string) path string = (array) dots of intersection o [ o { o x: (number) x coordinate of the point o y: (number) y coordinate of the point o t1: (number) t value for segment of path1 o t2: (number) t value for segment of path2 o segment1: (number) order number for segment of path1 o segment2: (number) order number for segment of path2 o bez1: (array) eight coordinates representing beziér curve for the segment of path1 o bez2: (array) eight coordinates representing beziér curve for the segment of path2 o } o ] \*/ R.pathIntersection = function (path1, path2) { return interPathHelper(path1, path2); }; R.pathIntersectionNumber = function (path1, path2) { return interPathHelper(path1, path2, 1); }; function interPathHelper(path1, path2, justCount) { path1 = R._path2curve(path1); path2 = R._path2curve(path2); var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, res = justCount ? 0 : []; for (var i = 0, ii = path1.length; i < ii; i++) { var pi = path1[i]; if (pi[0] == "M") { x1 = x1m = pi[1]; y1 = y1m = pi[2]; } else { if (pi[0] == "C") { bez1 = [x1, y1].concat(pi.slice(1)); x1 = bez1[6]; y1 = bez1[7]; } else { bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; x1 = x1m; y1 = y1m; } for (var j = 0, jj = path2.length; j < jj; j++) { var pj = path2[j]; if (pj[0] == "M") { x2 = x2m = pj[1]; y2 = y2m = pj[2]; } else { if (pj[0] == "C") { bez2 = [x2, y2].concat(pj.slice(1)); x2 = bez2[6]; y2 = bez2[7]; } else { bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; x2 = x2m; y2 = y2m; } var intr = interHelper(bez1, bez2, justCount); if (justCount) { res += intr; } else { for (var k = 0, kk = intr.length; k < kk; k++) { intr[k].segment1 = i; intr[k].segment2 = j; intr[k].bez1 = bez1; intr[k].bez2 = bez2; } res = res.concat(intr); } } } } } return res; } /*\ * Raphael.isPointInsidePath [ method ] ** * Utility method ** * Returns `true` if given point is inside a given closed path. > Parameters - path (string) path string - x (number) x of the point - y (number) y of the point = (boolean) true, if point is inside the path \*/ R.isPointInsidePath = function (path, x, y) { var bbox = R.pathBBox(path); return R.isPointInsideBBox(bbox, x, y) && interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; }; R._removedFactory = function (methodname) { return function () { eve("raphael.log", null, "Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object", methodname); }; }; /*\ * Raphael.pathBBox [ method ] ** * Utility method ** * Return bounding box of a given path > Parameters - path (string) path string = (object) bounding box o { o x: (number) x coordinate of the left top point of the box o y: (number) y coordinate of the left top point of the box o x2: (number) x coordinate of the right bottom point of the box o y2: (number) y coordinate of the right bottom point of the box o width: (number) width of the box o height: (number) height of the box o cx: (number) x coordinate of the center of the box o cy: (number) y coordinate of the center of the box o } \*/ var pathDimensions = R.pathBBox = function (path) { var pth = paths(path); if (pth.bbox) { return clone(pth.bbox); } if (!path) { return {x: 0, y: 0, width: 0, height: 0, x2: 0, y2: 0}; } path = path2curve(path); var x = 0, y = 0, X = [], Y = [], p; for (var i = 0, ii = path.length; i < ii; i++) { p = path[i]; if (p[0] == "M") { x = p[1]; y = p[2]; X.push(x); Y.push(y); } else { var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); X = X[concat](dim.min.x, dim.max.x); Y = Y[concat](dim.min.y, dim.max.y); x = p[5]; y = p[6]; } } var xmin = mmin[apply](0, X), ymin = mmin[apply](0, Y), xmax = mmax[apply](0, X), ymax = mmax[apply](0, Y), width = xmax - xmin, height = ymax - ymin, bb = { x: xmin, y: ymin, x2: xmax, y2: ymax, width: width, height: height, cx: xmin + width / 2, cy: ymin + height / 2 }; pth.bbox = clone(bb); return bb; }, pathClone = function (pathArray) { var res = clone(pathArray); res.toString = R._path2string; return res; }, pathToRelative = R._pathToRelative = function (pathArray) { var pth = paths(pathArray); if (pth.rel) { return pathClone(pth.rel); } if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption pathArray = R.parsePathString(pathArray); } var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0; if (pathArray[0][0] == "M") { x = pathArray[0][1]; y = pathArray[0][2]; mx = x; my = y; start++; res.push(["M", x, y]); } for (var i = start, ii = pathArray.length; i < ii; i++) { var r = res[i] = [], pa = pathArray[i]; if (pa[0] != lowerCase.call(pa[0])) { r[0] = lowerCase.call(pa[0]); switch (r[0]) { case "a": r[1] = pa[1]; r[2] = pa[2]; r[3] = pa[3]; r[4] = pa[4]; r[5] = pa[5]; r[6] = +(pa[6] - x).toFixed(3); r[7] = +(pa[7] - y).toFixed(3); break; case "v": r[1] = +(pa[1] - y).toFixed(3); break; case "m": mx = pa[1]; my = pa[2]; default: for (var j = 1, jj = pa.length; j < jj; j++) { r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); } } } else { r = res[i] = []; if (pa[0] == "m") { mx = pa[1] + x; my = pa[2] + y; } for (var k = 0, kk = pa.length; k < kk; k++) { res[i][k] = pa[k]; } } var len = res[i].length; switch (res[i][0]) { case "z": x = mx; y = my; break; case "h": x += +res[i][len - 1]; break; case "v": y += +res[i][len - 1]; break; default: x += +res[i][len - 2]; y += +res[i][len - 1]; } } res.toString = R._path2string; pth.rel = pathClone(res); return res; }, pathToAbsolute = R._pathToAbsolute = function (pathArray) { var pth = paths(pathArray); if (pth.abs) { return pathClone(pth.abs); } if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption pathArray = R.parsePathString(pathArray); } if (!pathArray || !pathArray.length) { return [["M", 0, 0]]; } var res = [], x = 0, y = 0, mx = 0, my = 0, start = 0; if (pathArray[0][0] == "M") { x = +pathArray[0][1]; y = +pathArray[0][2]; mx = x; my = y; start++; res[0] = ["M", x, y]; } var crz = pathArray.length == 3 && pathArray[0][0] == "M" && pathArray[1][0].toUpperCase() == "R" && pathArray[2][0].toUpperCase() == "Z"; for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { res.push(r = []); pa = pathArray[i]; if (pa[0] != upperCase.call(pa[0])) { r[0] = upperCase.call(pa[0]); switch (r[0]) { case "A": r[1] = pa[1]; r[2] = pa[2]; r[3] = pa[3]; r[4] = pa[4]; r[5] = pa[5]; r[6] = +(pa[6] + x); r[7] = +(pa[7] + y); break; case "V": r[1] = +pa[1] + y; break; case "H": r[1] = +pa[1] + x; break; case "R": var dots = [x, y][concat](pa.slice(1)); for (var j = 2, jj = dots.length; j < jj; j++) { dots[j] = +dots[j] + x; dots[++j] = +dots[j] + y; } res.pop(); res = res[concat](catmullRom2bezier(dots, crz)); break; case "M": mx = +pa[1] + x; my = +pa[2] + y; default: for (j = 1, jj = pa.length; j < jj; j++) { r[j] = +pa[j] + ((j % 2) ? x : y); } } } else if (pa[0] == "R") { dots = [x, y][concat](pa.slice(1)); res.pop(); res = res[concat](catmullRom2bezier(dots, crz)); r = ["R"][concat](pa.slice(-2)); } else { for (var k = 0, kk = pa.length; k < kk; k++) { r[k] = pa[k]; } } switch (r[0]) { case "Z": x = mx; y = my; break; case "H": x = r[1]; break; case "V": y = r[1]; break; case "M": mx = r[r.length - 2]; my = r[r.length - 1]; default: x = r[r.length - 2]; y = r[r.length - 1]; } } res.toString = R._path2string; pth.abs = pathClone(res); return res; }, l2c = function (x1, y1, x2, y2) { return [x1, y1, x2, y2, x2, y2]; }, q2c = function (x1, y1, ax, ay, x2, y2) { var _13 = 1 / 3, _23 = 2 / 3; return [ _13 * x1 + _23 * ax, _13 * y1 + _23 * ay, _13 * x2 + _23 * ax, _13 * y2 + _23 * ay, x2, y2 ]; }, a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { // for more information of where this math came from visit: // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes var _120 = PI * 120 / 180, rad = PI / 180 * (+angle || 0), res = [], xy, rotate = cacher(function (x, y, rad) { var X = x * math.cos(rad) - y * math.sin(rad), Y = x * math.sin(rad) + y * math.cos(rad); return {x: X, y: Y}; }); if (!recursive) { xy = rotate(x1, y1, -rad); x1 = xy.x; y1 = xy.y; xy = rotate(x2, y2, -rad); x2 = xy.x; y2 = xy.y; var cos = math.cos(PI / 180 * angle), sin = math.sin(PI / 180 * angle), x = (x1 - x2) / 2, y = (y1 - y2) / 2; var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); if (h > 1) { h = math.sqrt(h); rx = h * rx; ry = h * ry; } var rx2 = rx * rx, ry2 = ry * ry, k = (large_arc_flag == sweep_flag ? -1 : 1) * math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), cx = k * rx * y / ry + (x1 + x2) / 2, cy = k * -ry * x / rx + (y1 + y2) / 2, f1 = math.asin(((y1 - cy) / ry).toFixed(9)), f2 = math.asin(((y2 - cy) / ry).toFixed(9)); f1 = x1 < cx ? PI - f1 : f1; f2 = x2 < cx ? PI - f2 : f2; f1 < 0 && (f1 = PI * 2 + f1); f2 < 0 && (f2 = PI * 2 + f2); if (sweep_flag && f1 > f2) { f1 = f1 - PI * 2; } if (!sweep_flag && f2 > f1) { f2 = f2 - PI * 2; } } else { f1 = recursive[0]; f2 = recursive[1]; cx = recursive[2]; cy = recursive[3]; } var df = f2 - f1; if (abs(df) > _120) { var f2old = f2, x2old = x2, y2old = y2; f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); x2 = cx + rx * math.cos(f2); y2 = cy + ry * math.sin(f2); res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); } df = f2 - f1; var c1 = math.cos(f1), s1 = math.sin(f1), c2 = math.cos(f2), s2 = math.sin(f2), t = math.tan(df / 4), hx = 4 / 3 * rx * t, hy = 4 / 3 * ry * t, m1 = [x1, y1], m2 = [x1 + hx * s1, y1 - hy * c1], m3 = [x2 + hx * s2, y2 - hy * c2], m4 = [x2, y2]; m2[0] = 2 * m1[0] - m2[0]; m2[1] = 2 * m1[1] - m2[1]; if (recursive) { return [m2, m3, m4][concat](res); } else { res = [m2, m3, m4][concat](res).join()[split](","); var newres = []; for (var i = 0, ii = res.length; i < ii; i++) { newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; } return newres; } }, findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { var t1 = 1 - t; return { x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y }; }, curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), b = 2 * (c1x - p1x) - 2 * (c2x - c1x), c = p1x - c1x, t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, y = [p1y, p2y], x = [p1x, p2x], dot; abs(t1) > "1e12" && (t1 = .5); abs(t2) > "1e12" && (t2 = .5); if (t1 > 0 && t1 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); x.push(dot.x); y.push(dot.y); } if (t2 > 0 && t2 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); x.push(dot.x); y.push(dot.y); } a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); b = 2 * (c1y - p1y) - 2 * (c2y - c1y); c = p1y - c1y; t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; abs(t1) > "1e12" && (t1 = .5); abs(t2) > "1e12" && (t2 = .5); if (t1 > 0 && t1 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); x.push(dot.x); y.push(dot.y); } if (t2 > 0 && t2 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); x.push(dot.x); y.push(dot.y); } return { min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} }; }), path2curve = R._path2curve = cacher(function (path, path2) { var pth = !path2 && paths(path); if (!path2 && pth.curve) { return pathClone(pth.curve); } var p = pathToAbsolute(path), p2 = path2 && pathToAbsolute(path2), attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, processPath = function (path, d, pcom) { var nx, ny, tq = {T:1, Q:1}; if (!path) { return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; } !(path[0] in tq) && (d.qx = d.qy = null); switch (path[0]) { case "M": d.X = path[1]; d.Y = path[2]; break; case "A": path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); break; case "S": if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. nx = d.x * 2 - d.bx; // And reflect the previous ny = d.y * 2 - d.by; // command's control point relative to the current point. } else { // or some else or nothing nx = d.x; ny = d.y; } path = ["C", nx, ny][concat](path.slice(1)); break; case "T": if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. d.qx = d.x * 2 - d.qx; // And make a reflection similar d.qy = d.y * 2 - d.qy; // to case "S". } else { // or something else or nothing d.qx = d.x; d.qy = d.y; } path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); break; case "Q": d.qx = path[1]; d.qy = path[2]; path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); break; case "L": path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); break; case "H": path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); break; case "V": path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); break; case "Z": path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); break; } return path; }, fixArc = function (pp, i) { if (pp[i].length > 7) { pp[i].shift(); var pi = pp[i]; while (pi.length) { pcoms1[i]="A"; // if created multiple C:s, their original seg is saved p2 && (pcoms2[i]="A"); // the same as above pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); } pp.splice(i, 1); ii = mmax(p.length, p2 && p2.length || 0); } }, fixM = function (path1, path2, a1, a2, i) { if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { path2.splice(i, 0, ["M", a2.x, a2.y]); a1.bx = 0; a1.by = 0; a1.x = path1[i][1]; a1.y = path1[i][2]; ii = mmax(p.length, p2 && p2.length || 0); } }, pcoms1 = [], // path commands of original path p pcoms2 = [], // path commands of original path p2 pfirst = "", // temporary holder for original path command pcom = ""; // holder for previous path command of original path for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { p[i] && (pfirst = p[i][0]); // save current path command if (pfirst != "C") // C is not saved yet, because it may be result of conversion { pcoms1[i] = pfirst; // Save current path command i && ( pcom = pcoms1[i-1]); // Get previous path command pcom } p[i] = processPath(p[i], attrs, pcom); // Previous path command is inputted to processPath if (pcoms1[i] != "A" && pfirst == "C") pcoms1[i] = "C"; // A is the only command // which may produce multiple C:s // so we have to make sure that C is also C in original path fixArc(p, i); // fixArc adds also the right amount of A:s to pcoms1 if (p2) { // the same procedures is done to p2 p2[i] && (pfirst = p2[i][0]); if (pfirst != "C") { pcoms2[i] = pfirst; i && (pcom = pcoms2[i-1]); } p2[i] = processPath(p2[i], attrs2, pcom); if (pcoms2[i]!="A" && pfirst=="C") pcoms2[i]="C"; fixArc(p2, i); } fixM(p, p2, attrs, attrs2, i); fixM(p2, p, attrs2, attrs, i); var seg = p[i], seg2 = p2 && p2[i], seglen = seg.length, seg2len = p2 && seg2.length; attrs.x = seg[seglen - 2]; attrs.y = seg[seglen - 1]; attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; attrs.by = toFloat(seg[seglen - 3]) || attrs.y; attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); attrs2.x = p2 && seg2[seg2len - 2]; attrs2.y = p2 && seg2[seg2len - 1]; } if (!p2) { pth.curve = pathClone(p); } return p2 ? [p, p2] : p; }, null, pathClone), parseDots = R._parseDots = cacher(function (gradient) { var dots = []; for (var i = 0, ii = gradient.length; i < ii; i++) { var dot = {}, par = gradient[i].match(/^([^:]*):?([\d\.]*)/); dot.color = R.getRGB(par[1]); if (dot.color.error) { return null; } dot.opacity = dot.color.opacity; dot.color = dot.color.hex; par[2] && (dot.offset = par[2] + "%"); dots.push(dot); } for (i = 1, ii = dots.length - 1; i < ii; i++) { if (!dots[i].offset) { var start = toFloat(dots[i - 1].offset || 0), end = 0; for (var j = i + 1; j < ii; j++) { if (dots[j].offset) { end = dots[j].offset; break; } } if (!end) { end = 100; j = ii; } end = toFloat(end); var d = (end - start) / (j - i + 1); for (; i < j; i++) { start += d; dots[i].offset = start + "%"; } } } return dots; }), tear = R._tear = function (el, paper) { el == paper.top && (paper.top = el.prev); el == paper.bottom && (paper.bottom = el.next); el.next && (el.next.prev = el.prev); el.prev && (el.prev.next = el.next); }, tofront = R._tofront = function (el, paper) { if (paper.top === el) { return; } tear(el, paper); el.next = null; el.prev = paper.top; paper.top.next = el; paper.top = el; }, toback = R._toback = function (el, paper) { if (paper.bottom === el) { return; } tear(el, paper); el.next = paper.bottom; el.prev = null; paper.bottom.prev = el; paper.bottom = el; }, insertafter = R._insertafter = function (el, el2, paper) { tear(el, paper); el2 == paper.top && (paper.top = el); el2.next && (el2.next.prev = el); el.next = el2.next; el.prev = el2; el2.next = el; }, insertbefore = R._insertbefore = function (el, el2, paper) { tear(el, paper); el2 == paper.bottom && (paper.bottom = el); el2.prev && (el2.prev.next = el); el.prev = el2.prev; el2.prev = el; el.next = el2; }, /*\ * Raphael.toMatrix [ method ] ** * Utility method ** * Returns matrix of transformations applied to a given path > Parameters - path (string) path string - transform (string|array) transformation string = (object) @Matrix \*/ toMatrix = R.toMatrix = function (path, transform) { var bb = pathDimensions(path), el = { _: { transform: E }, getBBox: function () { return bb; } }; extractTransform(el, transform); return el.matrix; }, /*\ * Raphael.transformPath [ method ] ** * Utility method ** * Returns path transformed by a given transformation > Parameters - path (string) path string - transform (string|array) transformation string = (string) path \*/ transformPath = R.transformPath = function (path, transform) { return mapPath(path, toMatrix(path, transform)); }, extractTransform = R._extractTransform = function (el, tstr) { if (tstr == null) { return el._.transform; } tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); var tdata = R.parseTransformString(tstr), deg = 0, dx = 0, dy = 0, sx = 1, sy = 1, _ = el._, m = new Matrix; _.transform = tdata || []; if (tdata) { for (var i = 0, ii = tdata.length; i < ii; i++) { var t = tdata[i], tlen = t.length, command = Str(t[0]).toLowerCase(), absolute = t[0] != command, inver = absolute ? m.invert() : 0, x1, y1, x2, y2, bb; if (command == "t" && tlen == 3) { if (absolute) { x1 = inver.x(0, 0); y1 = inver.y(0, 0); x2 = inver.x(t[1], t[2]); y2 = inver.y(t[1], t[2]); m.translate(x2 - x1, y2 - y1); } else { m.translate(t[1], t[2]); } } else if (command == "r") { if (tlen == 2) { bb = bb || el.getBBox(1); m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); deg += t[1]; } else if (tlen == 4) { if (absolute) { x2 = inver.x(t[2], t[3]); y2 = inver.y(t[2], t[3]); m.rotate(t[1], x2, y2); } else { m.rotate(t[1], t[2], t[3]); } deg += t[1]; } } else if (command == "s") { if (tlen == 2 || tlen == 3) { bb = bb || el.getBBox(1); m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); sx *= t[1]; sy *= t[tlen - 1]; } else if (tlen == 5) { if (absolute) { x2 = inver.x(t[3], t[4]); y2 = inver.y(t[3], t[4]); m.scale(t[1], t[2], x2, y2); } else { m.scale(t[1], t[2], t[3], t[4]); } sx *= t[1]; sy *= t[2]; } } else if (command == "m" && tlen == 7) { m.add(t[1], t[2], t[3], t[4], t[5], t[6]); } _.dirtyT = 1; el.matrix = m; } } /*\ * Element.matrix [ property (object) ] ** * Keeps @Matrix object, which represents element transformation \*/ el.matrix = m; _.sx = sx; _.sy = sy; _.deg = deg; _.dx = dx = m.e; _.dy = dy = m.f; if (sx == 1 && sy == 1 && !deg && _.bbox) { _.bbox.x += +dx; _.bbox.y += +dy; } else { _.dirtyT = 1; } }, getEmpty = function (item) { var l = item[0]; switch (l.toLowerCase()) { case "t": return [l, 0, 0]; case "m": return [l, 1, 0, 0, 1, 0, 0]; case "r": if (item.length == 4) { return [l, 0, item[2], item[3]]; } else { return [l, 0]; } case "s": if (item.length == 5) { return [l, 1, 1, item[3], item[4]]; } else if (item.length == 3) { return [l, 1, 1]; } else { return [l, 1]; } } }, equaliseTransform = R._equaliseTransform = function (t1, t2) { t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); t1 = R.parseTransformString(t1) || []; t2 = R.parseTransformString(t2) || []; var maxlength = mmax(t1.length, t2.length), from = [], to = [], i = 0, j, jj, tt1, tt2; for (; i < maxlength; i++) { tt1 = t1[i] || getEmpty(t2[i]); tt2 = t2[i] || getEmpty(tt1); if ((tt1[0] != tt2[0]) || (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) ) { return; } from[i] = []; to[i] = []; for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { j in tt1 && (from[i][j] = tt1[j]); j in tt2 && (to[i][j] = tt2[j]); } } return { from: from, to: to }; }; R._getContainer = function (x, y, w, h) { var container; container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; if (container == null) { return; } if (container.tagName) { if (y == null) { return { container: container, width: container.style.pixelWidth || container.offsetWidth, height: container.style.pixelHeight || container.offsetHeight }; } else { return { container: container, width: y, height: w }; } } return { container: 1, x: x, y: y, width: w, height: h }; }; /*\ * Raphael.pathToRelative [ method ] ** * Utility method ** * Converts path to relative form > Parameters - pathString (string|array) path string or array of segments = (array) array of segments. \*/ R.pathToRelative = pathToRelative; R._engine = {}; /*\ * Raphael.path2curve [ method ] ** * Utility method ** * Converts path to a new path where all segments are cubic bezier curves. > Parameters - pathString (string|array) path string or array of segments = (array) array of segments. \*/ R.path2curve = path2curve; /*\ * Raphael.matrix [ method ] ** * Utility method ** * Returns matrix based on given parameters. > Parameters - a (number) - b (number) - c (number) - d (number) - e (number) - f (number) = (object) @Matrix \*/ R.matrix = function (a, b, c, d, e, f) { return new Matrix(a, b, c, d, e, f); }; function Matrix(a, b, c, d, e, f) { if (a != null) { this.a = +a; this.b = +b; this.c = +c; this.d = +d; this.e = +e; this.f = +f; } else { this.a = 1; this.b = 0; this.c = 0; this.d = 1; this.e = 0; this.f = 0; } } (function (matrixproto) { /*\ * Matrix.add [ method ] ** * Adds given matrix to existing one. > Parameters - a (number) - b (number) - c (number) - d (number) - e (number) - f (number) or - matrix (object) @Matrix \*/ matrixproto.add = function (a, b, c, d, e, f) { var out = [[], [], []], m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], matrix = [[a, c, e], [b, d, f], [0, 0, 1]], x, y, z, res; if (a && a instanceof Matrix) { matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; } for (x = 0; x < 3; x++) { for (y = 0; y < 3; y++) { res = 0; for (z = 0; z < 3; z++) { res += m[x][z] * matrix[z][y]; } out[x][y] = res; } } this.a = out[0][0]; this.b = out[1][0]; this.c = out[0][1]; this.d = out[1][1]; this.e = out[0][2]; this.f = out[1][2]; }; /*\ * Matrix.invert [ method ] ** * Returns inverted version of the matrix = (object) @Matrix \*/ matrixproto.invert = function () { var me = this, x = me.a * me.d - me.b * me.c; return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); }; /*\ * Matrix.clone [ method ] ** * Returns copy of the matrix = (object) @Matrix \*/ matrixproto.clone = function () { return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); }; /*\ * Matrix.translate [ method ] ** * Translate the matrix > Parameters - x (number) - y (number) \*/ matrixproto.translate = function (x, y) { this.add(1, 0, 0, 1, x, y); }; /*\ * Matrix.scale [ method ] ** * Scales the matrix > Parameters - x (number) - y (number) #optional - cx (number) #optional - cy (number) #optional \*/ matrixproto.scale = function (x, y, cx, cy) { y == null && (y = x); (cx || cy) && this.add(1, 0, 0, 1, cx, cy); this.add(x, 0, 0, y, 0, 0); (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); }; /*\ * Matrix.rotate [ method ] ** * Rotates the matrix > Parameters - a (number) - x (number) - y (number) \*/ matrixproto.rotate = function (a, x, y) { a = R.rad(a); x = x || 0; y = y || 0; var cos = +math.cos(a).toFixed(9), sin = +math.sin(a).toFixed(9); this.add(cos, sin, -sin, cos, x, y); this.add(1, 0, 0, 1, -x, -y); }; /*\ * Matrix.x [ method ] ** * Return x coordinate for given point after transformation described by the matrix. See also @Matrix.y > Parameters - x (number) - y (number) = (number) x \*/ matrixproto.x = function (x, y) { return x * this.a + y * this.c + this.e; }; /*\ * Matrix.y [ method ] ** * Return y coordinate for given point after transformation described by the matrix. See also @Matrix.x > Parameters - x (number) - y (number) = (number) y \*/ matrixproto.y = function (x, y) { return x * this.b + y * this.d + this.f; }; matrixproto.get = function (i) { return +this[Str.fromCharCode(97 + i)].toFixed(4); }; matrixproto.toString = function () { return R.svg ? "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" : [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join(); }; matrixproto.toFilter = function () { return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) + ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) + ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')"; }; matrixproto.offset = function () { return [this.e.toFixed(4), this.f.toFixed(4)]; }; function norm(a) { return a[0] * a[0] + a[1] * a[1]; } function normalize(a) { var mag = math.sqrt(norm(a)); a[0] && (a[0] /= mag); a[1] && (a[1] /= mag); } /*\ * Matrix.split [ method ] ** * Splits matrix into primitive transformations = (object) in format: o dx (number) translation by x o dy (number) translation by y o scalex (number) scale by x o scaley (number) scale by y o shear (number) shear o rotate (number) rotation in deg o isSimple (boolean) could it be represented via simple transformations \*/ matrixproto.split = function () { var out = {}; // translation out.dx = this.e; out.dy = this.f; // scale and shear var row = [[this.a, this.c], [this.b, this.d]]; out.scalex = math.sqrt(norm(row[0])); normalize(row[0]); out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; out.scaley = math.sqrt(norm(row[1])); normalize(row[1]); out.shear /= out.scaley; // rotation var sin = -row[0][1], cos = row[1][1]; if (cos < 0) { out.rotate = R.deg(math.acos(cos)); if (sin < 0) { out.rotate = 360 - out.rotate; } } else { out.rotate = R.deg(math.asin(sin)); } out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; out.noRotation = !+out.shear.toFixed(9) && !out.rotate; return out; }; /*\ * Matrix.toTransformString [ method ] ** * Return transform string that represents given matrix = (string) transform string \*/ matrixproto.toTransformString = function (shorter) { var s = shorter || this[split](); if (s.isSimple) { s.scalex = +s.scalex.toFixed(4); s.scaley = +s.scaley.toFixed(4); s.rotate = +s.rotate.toFixed(4); return (s.dx || s.dy ? "t" + [s.dx, s.dy] : E) + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + (s.rotate ? "r" + [s.rotate, 0, 0] : E); } else { return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; } }; })(Matrix.prototype); var preventDefault = function () { this.returnValue = false; }, preventTouch = function () { return this.originalEvent.preventDefault(); }, stopPropagation = function () { this.cancelBubble = true; }, stopTouch = function () { return this.originalEvent.stopPropagation(); }, getEventPosition = function (e) { var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; return { x: e.clientX + scrollX, y: e.clientY + scrollY }; }, addEvent = (function () { if (g.doc.addEventListener) { return function (obj, type, fn, element) { var f = function (e) { var pos = getEventPosition(e); return fn.call(element, e, pos.x, pos.y); }; obj.addEventListener(type, f, false); if (supportsTouch && touchMap[type]) { var _f = function (e) { var pos = getEventPosition(e), olde = e; for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { if (e.targetTouches[i].target == obj) { e = e.targetTouches[i]; e.originalEvent = olde; e.preventDefault = preventTouch; e.stopPropagation = stopTouch; break; } } return fn.call(element, e, pos.x, pos.y); }; obj.addEventListener(touchMap[type], _f, false); } return function () { obj.removeEventListener(type, f, false); if (supportsTouch && touchMap[type]) obj.removeEventListener(touchMap[type], _f, false); return true; }; }; } else if (g.doc.attachEvent) { return function (obj, type, fn, element) { var f = function (e) { e = e || g.win.event; var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, x = e.clientX + scrollX, y = e.clientY + scrollY; e.preventDefault = e.preventDefault || preventDefault; e.stopPropagation = e.stopPropagation || stopPropagation; return fn.call(element, e, x, y); }; obj.attachEvent("on" + type, f); var detacher = function () { obj.detachEvent("on" + type, f); return true; }; return detacher; }; } })(), drag = [], dragMove = function (e) { var x = e.clientX, y = e.clientY, scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, dragi, j = drag.length; while (j--) { dragi = drag[j]; if (supportsTouch && e.touches) { var i = e.touches.length, touch; while (i--) { touch = e.touches[i]; if (touch.identifier == dragi.el._drag.id) { x = touch.clientX; y = touch.clientY; (e.originalEvent ? e.originalEvent : e).preventDefault(); break; } } } else { e.preventDefault(); } var node = dragi.el.node, o, next = node.nextSibling, parent = node.parentNode, display = node.style.display; g.win.opera && parent.removeChild(node); node.style.display = "none"; o = dragi.el.paper.getElementByPoint(x, y); node.style.display = display; g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o); x += scrollX; y += scrollY; eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); } }, dragUp = function (e) { R.unmousemove(dragMove).unmouseup(dragUp); var i = drag.length, dragi; while (i--) { dragi = drag[i]; dragi.el._drag = {}; eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); } drag = []; }, /*\ * Raphael.el [ property (object) ] ** * You can add your own method to elements. This is usefull when you want to hack default functionality or * want to wrap some common transformation or attributes in one method. In difference to canvas methods, * you can redefine element method at any time. Expending element methods wouldn’t affect set. > Usage | Raphael.el.red = function () { | this.attr({fill: "#f00"}); | }; | // then use it | paper.circle(100, 100, 20).red(); \*/ elproto = R.el = {}; /*\ * Element.click [ method ] ** * Adds event handler for click for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.unclick [ method ] ** * Removes event handler for click for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.dblclick [ method ] ** * Adds event handler for double click for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.undblclick [ method ] ** * Removes event handler for double click for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.mousedown [ method ] ** * Adds event handler for mousedown for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.unmousedown [ method ] ** * Removes event handler for mousedown for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.mousemove [ method ] ** * Adds event handler for mousemove for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.unmousemove [ method ] ** * Removes event handler for mousemove for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.mouseout [ method ] ** * Adds event handler for mouseout for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.unmouseout [ method ] ** * Removes event handler for mouseout for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.mouseover [ method ] ** * Adds event handler for mouseover for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.unmouseover [ method ] ** * Removes event handler for mouseover for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.mouseup [ method ] ** * Adds event handler for mouseup for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.unmouseup [ method ] ** * Removes event handler for mouseup for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.touchstart [ method ] ** * Adds event handler for touchstart for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.untouchstart [ method ] ** * Removes event handler for touchstart for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.touchmove [ method ] ** * Adds event handler for touchmove for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.untouchmove [ method ] ** * Removes event handler for touchmove for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.touchend [ method ] ** * Adds event handler for touchend for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.untouchend [ method ] ** * Removes event handler for touchend for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ /*\ * Element.touchcancel [ method ] ** * Adds event handler for touchcancel for the element. > Parameters - handler (function) handler for the event = (object) @Element \*/ /*\ * Element.untouchcancel [ method ] ** * Removes event handler for touchcancel for the element. > Parameters - handler (function) #optional handler for the event = (object) @Element \*/ for (var i = events.length; i--;) { (function (eventName) { R[eventName] = elproto[eventName] = function (fn, scope) { if (R.is(fn, "function")) { this.events = this.events || []; this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); } return this; }; R["un" + eventName] = elproto["un" + eventName] = function (fn) { var events = this.events || [], l = events.length; while (l--){ if (events[l].name == eventName && (R.is(fn, "undefined") || events[l].f == fn)) { events[l].unbind(); events.splice(l, 1); !events.length && delete this.events; } } return this; }; })(events[i]); } /*\ * Element.data [ method ] ** * Adds or retrieves given value asociated with given key. ** * See also @Element.removeData > Parameters - key (string) key to store data - value (any) #optional value to store = (object) @Element * or, if value is not specified: = (any) value * or, if key and value are not specified: = (object) Key/value pairs for all the data associated with the element. > Usage | for (var i = 0, i < 5, i++) { | paper.circle(10 + 15 * i, 10, 10) | .attr({fill: "#000"}) | .data("i", i) | .click(function () { | alert(this.data("i")); | }); | } \*/ elproto.data = function (key, value) { var data = eldata[this.id] = eldata[this.id] || {}; if (arguments.length == 0) { return data; } if (arguments.length == 1) { if (R.is(key, "object")) { for (var i in key) if (key[has](i)) { this.data(i, key[i]); } return this; } eve("raphael.data.get." + this.id, this, data[key], key); return data[key]; } data[key] = value; eve("raphael.data.set." + this.id, this, value, key); return this; }; elproto.datum = function(){ return arguments.length == 0 ? this._bindData : ((this._bindData = arguments[0]), this); }; /*\ * Element.removeData [ method ] ** * Removes value associated with an element by given key. * If key is not provided, removes all the data of the element. > Parameters - key (string) #optional key = (object) @Element \*/ elproto.removeData = function (key) { if (key == null) { eldata[this.id] = {}; } else { eldata[this.id] && delete eldata[this.id][key]; } return this; }; /*\ * Element.getData [ method ] ** * Retrieves the element data = (object) data \*/ elproto.getData = function () { return clone(eldata[this.id] || {}); }; /*\ * Element.hover [ method ] ** * Adds event handlers for hover for the element. > Parameters - f_in (function) handler for hover in - f_out (function) handler for hover out - icontext (object) #optional context for hover in handler - ocontext (object) #optional context for hover out handler = (object) @Element \*/ elproto.hover = function (f_in, f_out, scope_in, scope_out) { return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); }; /*\ * Element.unhover [ method ] ** * Removes event handlers for hover for the element. > Parameters - f_in (function) handler for hover in - f_out (function) handler for hover out = (object) @Element \*/ elproto.unhover = function (f_in, f_out) { return this.unmouseover(f_in).unmouseout(f_out); }; var draggable = []; /*\ * Element.drag [ method ] ** * Adds event handlers for drag of the element. > Parameters - onmove (function) handler for moving - onstart (function) handler for drag start - onend (function) handler for drag end - mcontext (object) #optional context for moving handler - scontext (object) #optional context for drag start handler - econtext (object) #optional context for drag end handler * Additionaly following `drag` events will be triggered: `drag.start.<id>` on start, * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element will be dragged over another element * `drag.over.<id>` will be fired as well. * * Start event and start handler will be called in specified context or in context of the element with following parameters: o x (number) x position of the mouse o y (number) y position of the mouse o event (object) DOM event object * Move event and move handler will be called in specified context or in context of the element with following parameters: o dx (number) shift by x from the start point o dy (number) shift by y from the start point o x (number) x position of the mouse o y (number) y position of the mouse o event (object) DOM event object * End event and end handler will be called in specified context or in context of the element with following parameters: o event (object) DOM event object = (object) @Element \*/ elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { function start(e) { (e.originalEvent || e).preventDefault(); var x = e.clientX, y = e.clientY, scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; this._drag.id = e.identifier; if (supportsTouch && e.touches) { var i = e.touches.length, touch; while (i--) { touch = e.touches[i]; this._drag.id = touch.identifier; if (touch.identifier == this._drag.id) { x = touch.clientX; y = touch.clientY; break; } } } this._drag.x = x + scrollX; this._drag.y = y + scrollY; !drag.length && R.mousemove(dragMove).mouseup(dragUp); drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); onstart && eve.on("raphael.drag.start." + this.id, onstart); onmove && eve.on("raphael.drag.move." + this.id, onmove); onend && eve.on("raphael.drag.end." + this.id, onend); eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); } this._drag = {}; draggable.push({el: this, start: start}); this.mousedown(start); return this; }; /*\ * Element.onDragOver [ method ] ** * Shortcut for assigning event handler for `drag.over.<id>` event, where id is id of the element (see @Element.id). > Parameters - f (function) handler for event, first argument would be the element you are dragging over \*/ elproto.onDragOver = function (f) { f ? eve.on("raphael.drag.over." + this.id, f) : eve.unbind("raphael.drag.over." + this.id); }; /*\ * Element.undrag [ method ] ** * Removes all drag event handlers from given element. \*/ elproto.undrag = function () { var i = draggable.length; while (i--) if (draggable[i].el == this) { this.unmousedown(draggable[i].start); draggable.splice(i, 1); eve.unbind("raphael.drag.*." + this.id); } !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp); drag = []; }; /*\ * Paper.circle [ method ] ** * Draws a circle. ** > Parameters ** - x (number) x coordinate of the centre - y (number) y coordinate of the centre - r (number) radius = (object) Raphaël element object with type “circle” ** > Usage | var c = paper.circle(50, 50, 40); \*/ paperproto.circle = function (x, y, r) { var out = R._engine.circle(this, x || 0, y || 0, r || 0); this.__set__ && this.__set__.push(out); return out; }; /*\ * Paper.rect [ method ] * * Draws a rectangle. ** > Parameters ** - x (number) x coordinate of the top left corner - y (number) y coordinate of the top left corner - width (number) width - height (number) height - r (number) #optional radius for rounded corners, default is 0 = (object) Raphaël element object with type “rect” ** > Usage | // regular rectangle | var c = paper.rect(10, 10, 50, 50); | // rectangle with rounded corners | var c = paper.rect(40, 40, 50, 50, 10); \*/ paperproto.rect = function (x, y, w, h, r) { var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0); this.__set__ && this.__set__.push(out); return out; }; /*\ * Paper.ellipse [ method ] ** * Draws an ellipse. ** > Parameters ** - x (number) x coordinate of the centre - y (number) y coordinate of the centre - rx (number) horizontal radius - ry (number) vertical radius = (object) Raphaël element object with type “ellipse” ** > Usage | var c = paper.ellipse(50, 50, 40, 20); \*/ paperproto.ellipse = function (x, y, rx, ry) { var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0); this.__set__ && this.__set__.push(out); return out; }; /*\ * Paper.path [ method ] ** * Creates a path element by given path data string. > Parameters - pathString (string) #optional path string in SVG format. * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example: | "M10,20L30,40" * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative. * # <p>Here is short list of commands available, for more details see <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path's data attribute's format are described in the SVG specification.">SVG path string format</a>.</p> # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier. * Note: there is a special case when path consist of just three commands: “M10,10R…z”. In this case path will smoothly connects to its beginning. > Usage | var c = paper.path("M10 10L90 90"); | // draw a diagonal line: | // move to 10,10, line to 90,90 * For example of path strings, check out these icons: http://raphaeljs.com/icons/ \*/ paperproto.path = function (pathString) { pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); var out = R._engine.path(R.format[apply](R, arguments), this); this.__set__ && this.__set__.push(out); return out; }; /*\ * Paper.image [ method ] ** * Embeds an image into the surface. ** > Parameters ** - src (string) URI of the source image - x (number) x coordinate position - y (number) y coordinate position - width (number) width of the image - height (number) height of the image = (object) Raphaël element object with type “image” ** > Usage | var c = paper.image("apple.png", 10, 10, 80, 80); \*/ paperproto.image = function (src, x, y, w, h) { var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); this.__set__ && this.__set__.push(out); return out; }; /*\ * Paper.text [ method ] ** * Draws a text string. If you need line breaks, put “\n” in the string. ** > Parameters ** - x (number) x coordinate position - y (number) y coordinate position - text (string) The text string to draw = (object) Raphaël element object with type “text” ** > Usage | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!"); \*/ paperproto.text = function (x, y, text) { var out = R._engine.text(this, x || 0, y || 0, Str(text)); this.__set__ && this.__set__.push(out); return out; }; /*\ * Paper.set [ method ] ** * Creates array-like object to keep and operate several elements at once. * Warning: it doesn’t create any elements for itself in the page, it just groups existing elements. * Sets act as pseudo elements — all methods available to an element can be used on a set. = (object) array-like object that represents set of elements ** > Usage | var st = paper.set(); | st.push( | paper.circle(10, 10, 5), | paper.circle(30, 10, 5) | ); | st.attr({fill: "red"}); // changes the fill of both circles \*/ paperproto.set = function (itemsArray) { !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); var out = new Set(itemsArray); this.__set__ && this.__set__.push(out); out["paper"] = this; out["type"] = "set"; return out; }; /*\ * Paper.setStart [ method ] ** * Creates @Paper.set. All elements that will be created after calling this method and before calling * @Paper.setFinish will be added to the set. ** > Usage | paper.setStart(); | paper.circle(10, 10, 5), | paper.circle(30, 10, 5) | var st = paper.setFinish(); | st.attr({fill: "red"}); // changes the fill of both circles \*/ paperproto.setStart = function (set) { this.__set__ = set || this.set(); }; /*\ * Paper.setFinish [ method ] ** * See @Paper.setStart. This method finishes catching and returns resulting set. ** = (object) set \*/ paperproto.setFinish = function (set) { var out = this.__set__; delete this.__set__; return out; }; /*\ * Paper.getSize [ method ] ** * Obtains current paper actual size. ** = (object) \*/ paperproto.getSize = function () { var container = this.canvas.parentNode; return { width: container.offsetWidth, height: container.offsetHeight }; }; /*\ * Paper.setSize [ method ] ** * If you need to change dimensions of the canvas call this method ** > Parameters ** - width (number) new width of the canvas - height (number) new height of the canvas \*/ paperproto.setSize = function (width, height) { return R._engine.setSize.call(this, width, height); }; /*\ * Paper.setViewBox [ method ] ** * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by * specifying new boundaries. ** > Parameters ** - x (number) new x position, default is `0` - y (number) new y position, default is `0` - w (number) new width of the canvas - h (number) new height of the canvas - fit (boolean) `true` if you want graphics to fit into new boundary box \*/ paperproto.setViewBox = function (x, y, w, h, fit) { return R._engine.setViewBox.call(this, x, y, w, h, fit); }; /*\ * Paper.top [ property ] ** * Points to the topmost element on the paper \*/ /*\ * Paper.bottom [ property ] ** * Points to the bottom element on the paper \*/ paperproto.top = paperproto.bottom = null; /*\ * Paper.raphael [ property ] ** * Points to the @Raphael object/function \*/ paperproto.raphael = R; var getOffset = function (elem) { var box = elem.getBoundingClientRect(), doc = elem.ownerDocument, body = doc.body, docElem = doc.documentElement, clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; return { y: top, x: left }; }; /*\ * Paper.getElementByPoint [ method ] ** * Returns you topmost element under given point. ** = (object) Raphaël element object > Parameters ** - x (number) x coordinate from the top left corner of the window - y (number) y coordinate from the top left corner of the window > Usage | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); \*/ paperproto.getElementByPoint = function (x, y) { var paper = this, svg = paper.canvas, target = g.doc.elementFromPoint(x, y); if (g.win.opera && target.tagName == "svg") { var so = getOffset(svg), sr = svg.createSVGRect(); sr.x = x - so.x; sr.y = y - so.y; sr.width = sr.height = 1; var hits = svg.getIntersectionList(sr, null); if (hits.length) { target = hits[hits.length - 1]; } } if (!target) { return null; } while (target.parentNode && target != svg.parentNode && !target.raphael) { target = target.parentNode; } target == paper.canvas.parentNode && (target = svg); target = target && target.raphael ? paper.getById(target.raphaelid) : null; return target; }; /*\ * Paper.getElementsByBBox [ method ] ** * Returns set of elements that have an intersecting bounding box ** > Parameters ** - bbox (object) bbox to check with = (object) @Set \*/ paperproto.getElementsByBBox = function (bbox) { var set = this.set(); this.forEach(function (el) { if (R.isBBoxIntersect(el.getBBox(), bbox)) { set.push(el); } }); return set; }; /*\ * Paper.getById [ method ] ** * Returns you element by its internal ID. ** > Parameters ** - id (number) id = (object) Raphaël element object \*/ paperproto.getById = function (id) { var bot = this.bottom; while (bot) { if (bot.id == id) { return bot; } bot = bot.next; } return null; }; /*\ * Paper.forEach [ method ] ** * Executes given function for each element on the paper * * If callback function returns `false` it will stop loop running. ** > Parameters ** - callback (function) function to run - thisArg (object) context object for the callback = (object) Paper object > Usage | paper.forEach(function (el) { | el.attr({ stroke: "blue" }); | }); \*/ paperproto.forEach = function (callback, thisArg) { var bot = this.bottom; while (bot) { if (callback.call(thisArg, bot) === false) { return this; } bot = bot.next; } return this; }; /*\ * Paper.getElementsByPoint [ method ] ** * Returns set of elements that have common point inside ** > Parameters ** - x (number) x coordinate of the point - y (number) y coordinate of the point = (object) @Set \*/ paperproto.getElementsByPoint = function (x, y) { var set = this.set(); this.forEach(function (el) { if (el.isPointInside(x, y)) { set.push(el); } }); return set; }; function x_y() { return this.x + S + this.y; } function x_y_w_h() { return this.x + S + this.y + S + this.width + " \xd7 " + this.height; } /*\ * Element.isPointInside [ method ] ** * Determine if given point is inside this element’s shape ** > Parameters ** - x (number) x coordinate of the point - y (number) y coordinate of the point = (boolean) `true` if point inside the shape \*/ elproto.isPointInside = function (x, y) { var rp = this.realPath = getPath[this.type](this); if (this.attr('transform') && this.attr('transform').length) { rp = R.transformPath(rp, this.attr('transform')); } return R.isPointInsidePath(rp, x, y); }; /*\ * Element.getBBox [ method ] ** * Return bounding box for a given element ** > Parameters ** - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`. = (object) Bounding box object: o { o x: (number) top left corner x o y: (number) top left corner y o x2: (number) bottom right corner x o y2: (number) bottom right corner y o width: (number) width o height: (number) height o } \*/ elproto.getBBox = function (isWithoutTransform) { if (this.removed) { return {}; } var _ = this._; if (isWithoutTransform) { if (_.dirty || !_.bboxwt) { this.realPath = getPath[this.type](this); _.bboxwt = pathDimensions(this.realPath); _.bboxwt.toString = x_y_w_h; _.dirty = 0; } return _.bboxwt; } if (_.dirty || _.dirtyT || !_.bbox) { if (_.dirty || !this.realPath) { _.bboxwt = 0; this.realPath = getPath[this.type](this); } _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); _.bbox.toString = x_y_w_h; _.dirty = _.dirtyT = 0; } return _.bbox; }; /*\ * Element.clone [ method ] ** = (object) clone of a given element ** \*/ elproto.clone = function () { if (this.removed) { return null; } var out = this.paper[this.type]().attr(this.attr()); this.__set__ && this.__set__.push(out); return out; }; /*\ * Element.glow [ method ] ** * Return set of elements that create glow-like effect around given element. See @Paper.set. * * Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself. ** > Parameters ** - glow (object) #optional parameters object with all properties optional: o { o width (number) size of the glow, default is `10` o fill (boolean) will it be filled, default is `false` o opacity (number) opacity, default is `0.5` o offsetx (number) horizontal offset, default is `0` o offsety (number) vertical offset, default is `0` o color (string) glow colour, default is `black` o } = (object) @Paper.set of elements that represents glow \*/ elproto.glow = function (glow) { if (this.type == "text") { return null; } glow = glow || {}; var s = { width: (glow.width || 10) + (+this.attr("stroke-width") || 1), fill: glow.fill || false, opacity: glow.opacity == null ? .5 : glow.opacity, offsetx: glow.offsetx || 0, offsety: glow.offsety || 0, color: glow.color || "#000" }, c = s.width / 2, r = this.paper, out = r.set(), path = this.realPath || getPath[this.type](this); path = this.matrix ? mapPath(path, this.matrix) : path; for (var i = 1; i < c + 1; i++) { out.push(r.path(path).attr({ stroke: s.color, fill: s.fill ? s.color : "none", "stroke-linejoin": "round", "stroke-linecap": "round", "stroke-width": +(s.width / c * i).toFixed(3), opacity: +(s.opacity / c).toFixed(3) })); } return out.insertBefore(this).translate(s.offsetx, s.offsety); }; var curveslengths = {}, getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { if (length == null) { return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); } else { return R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); } }, getLengthFactory = function (istotal, subpath) { return function (path, length, onlystart) { path = path2curve(path); var x, y, p, l, sp = "", subpaths = {}, point, len = 0; for (var i = 0, ii = path.length; i < ii; i++) { p = path[i]; if (p[0] == "M") { x = +p[1]; y = +p[2]; } else { l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); if (len + l > length) { if (subpath && !subpaths.start) { point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; if (onlystart) {return sp;} subpaths.start = sp; sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); len += l; x = +p[5]; y = +p[6]; continue; } if (!istotal && !subpath) { point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); return {x: point.x, y: point.y, alpha: point.alpha}; } } len += l; x = +p[5]; y = +p[6]; } sp += p.shift() + p; } subpaths.end = sp; point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); return point; }; }; var getTotalLength = getLengthFactory(1), getPointAtLength = getLengthFactory(), getSubpathsAtLength = getLengthFactory(0, 1); /*\ * Raphael.getTotalLength [ method ] ** * Returns length of the given path in pixels. ** > Parameters ** - path (string) SVG path string. ** = (number) length. \*/ R.getTotalLength = getTotalLength; /*\ * Raphael.getPointAtLength [ method ] ** * Return coordinates of the point located at the given length on the given path. ** > Parameters ** - path (string) SVG path string - length (number) ** = (object) representation of the point: o { o x: (number) x coordinate o y: (number) y coordinate o alpha: (number) angle of derivative o } \*/ R.getPointAtLength = getPointAtLength; /*\ * Raphael.getSubpath [ method ] ** * Return subpath of a given path from given length to given length. ** > Parameters ** - path (string) SVG path string - from (number) position of the start of the segment - to (number) position of the end of the segment ** = (string) pathstring for the segment \*/ R.getSubpath = function (path, from, to) { if (this.getTotalLength(path) - to < 1e-6) { return getSubpathsAtLength(path, from).end; } var a = getSubpathsAtLength(path, to, 1); return from ? getSubpathsAtLength(a, from).end : a; }; /*\ * Element.getTotalLength [ method ] ** * Returns length of the path in pixels. Only works for element of “path” type. = (number) length. \*/ elproto.getTotalLength = function () { var path = this.getPath(); if (!path) { return; } if (this.node.getTotalLength) { return this.node.getTotalLength(); } return getTotalLength(path); }; /*\ * Element.getPointAtLength [ method ] ** * Return coordinates of the point located at the given length on the given path. Only works for element of “path” type. ** > Parameters ** - length (number) ** = (object) representation of the point: o { o x: (number) x coordinate o y: (number) y coordinate o alpha: (number) angle of derivative o } \*/ elproto.getPointAtLength = function (length) { var path = this.getPath(); if (!path) { return; } return getPointAtLength(path, length); }; /*\ * Element.getPath [ method ] ** * Returns path of the element. Only works for elements of “path” type and simple elements like circle. = (object) path ** \*/ elproto.getPath = function () { var path, getPath = R._getPath[this.type]; if (this.type == "text" || this.type == "set") { return; } if (getPath) { path = getPath(this); } return path; }; /*\ * Element.getSubpath [ method ] ** * Return subpath of a given element from given length to given length. Only works for element of “path” type. ** > Parameters ** - from (number) position of the start of the segment - to (number) position of the end of the segment ** = (string) pathstring for the segment \*/ elproto.getSubpath = function (from, to) { var path = this.getPath(); if (!path) { return; } return R.getSubpath(path, from, to); }; /*\ * Raphael.easing_formulas [ property ] ** * Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing: # <ul> # <li>“linear”</li> # <li>“<” or “easeIn” or “ease-in”</li> # <li>“>” or “easeOut” or “ease-out”</li> # <li>“<>” or “easeInOut” or “ease-in-out”</li> # <li>“backIn” or “back-in”</li> # <li>“backOut” or “back-out”</li> # <li>“elastic”</li> # <li>“bounce”</li> # </ul> # <p>See also <a href="http://raphaeljs.com/easing.html">Easing demo</a>.</p> \*/ var ef = R.easing_formulas = { linear: function (n) { return n; }, "<": function (n) { return pow(n, 1.7); }, ">": function (n) { return pow(n, .48); }, "<>": function (n) { var q = .48 - n / 1.04, Q = math.sqrt(.1734 + q * q), x = Q - q, X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), y = -Q - q, Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), t = X + Y + .5; return (1 - t) * 3 * t * t + t * t * t; }, backIn: function (n) { var s = 1.70158; return n * n * ((s + 1) * n - s); }, backOut: function (n) { n = n - 1; var s = 1.70158; return n * n * ((s + 1) * n + s) + 1; }, elastic: function (n) { if (n == !!n) { return n; } return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; }, bounce: function (n) { var s = 7.5625, p = 2.75, l; if (n < (1 / p)) { l = s * n * n; } else { if (n < (2 / p)) { n -= (1.5 / p); l = s * n * n + .75; } else { if (n < (2.5 / p)) { n -= (2.25 / p); l = s * n * n + .9375; } else { n -= (2.625 / p); l = s * n * n + .984375; } } } return l; } }; ef.easeIn = ef["ease-in"] = ef["<"]; ef.easeOut = ef["ease-out"] = ef[">"]; ef.easeInOut = ef["ease-in-out"] = ef["<>"]; ef["back-in"] = ef.backIn; ef["back-out"] = ef.backOut; var animationElements = [], requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) { setTimeout(callback, 16); }, animation = function () { var Now = +new Date, l = 0; for (; l < animationElements.length; l++) { var e = animationElements[l]; if (e.el.removed || e.paused) { continue; } var time = Now - e.start, ms = e.ms, easing = e.easing, from = e.from, diff = e.diff, to = e.to, t = e.t, that = e.el, set = {}, now, init = {}, key; if (e.initstatus) { time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; e.status = e.initstatus; delete e.initstatus; e.stop && animationElements.splice(l--, 1); } else { e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; } if (time < 0) { continue; } if (time < ms) { var pos = easing(time / ms); for (var attr in from) if (from[has](attr)) { switch (availableAnimAttrs[attr]) { case nu: now = +from[attr] + pos * ms * diff[attr]; break; case "colour": now = "rgb(" + [ upto255(round(from[attr].r + pos * ms * diff[attr].r)), upto255(round(from[attr].g + pos * ms * diff[attr].g)), upto255(round(from[attr].b + pos * ms * diff[attr].b)) ].join(",") + ")"; break; case "path": now = []; for (var i = 0, ii = from[attr].length; i < ii; i++) { now[i] = [from[attr][i][0]]; for (var j = 1, jj = from[attr][i].length; j < jj; j++) { now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; } now[i] = now[i].join(S); } now = now.join(S); break; case "transform": if (diff[attr].real) { now = []; for (i = 0, ii = from[attr].length; i < ii; i++) { now[i] = [from[attr][i][0]]; for (j = 1, jj = from[attr][i].length; j < jj; j++) { now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; } } } else { var get = function (i) { return +from[attr][i] + pos * ms * diff[attr][i]; }; // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; } break; case "csv": if (attr == "clip-rect") { now = []; i = 4; while (i--) { now[i] = +from[attr][i] + pos * ms * diff[attr][i]; } } break; default: var from2 = [][concat](from[attr]); now = []; i = that.paper.customAttributes[attr].length; while (i--) { now[i] = +from2[i] + pos * ms * diff[attr][i]; } break; } set[attr] = now; } that.attr(set); (function (id, that, anim) { setTimeout(function () { eve("raphael.anim.frame." + id, that, anim); }); })(that.id, that, e.anim); } else { (function(f, el, a) { setTimeout(function() { eve("raphael.anim.frame." + el.id, el, a); eve("raphael.anim.finish." + el.id, el, a); R.is(f, "function") && f.call(el); }); })(e.callback, that, e.anim); that.attr(to); animationElements.splice(l--, 1); if (e.repeat > 1 && !e.next) { for (key in to) if (to[has](key)) { init[key] = e.totalOrigin[key]; } e.el.attr(init); runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1); } if (e.next && !e.stop) { runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat); } } } animationElements.length && requestAnimFrame(animation); }, upto255 = function (color) { return color > 255 ? 255 : color < 0 ? 0 : color; }; /*\ * Element.animateWith [ method ] ** * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element. ** > Parameters ** - el (object) element to sync with - anim (object) animation to sync with - params (object) #optional final attributes for the element, see also @Element.attr - ms (number) #optional number of milliseconds for animation to run - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` - callback (function) #optional callback function. Will be called at the end of animation. * or - element (object) element to sync with - anim (object) animation to sync with - animation (object) #optional animation object, see @Raphael.animation ** = (object) original element \*/ elproto.animateWith = function (el, anim, params, ms, easing, callback) { var element = this; if (element.removed) { callback && callback.call(element); return element; } var a = params instanceof Animation ? params : R.animation(params, ms, easing, callback), x, y; runAnimation(a, element, a.percents[0], null, element.attr()); for (var i = 0, ii = animationElements.length; i < ii; i++) { if (animationElements[i].anim == anim && animationElements[i].el == el) { animationElements[ii - 1].start = animationElements[i].start; break; } } return element; // // // var a = params ? R.animation(params, ms, easing, callback) : anim, // status = element.status(anim); // return this.animate(a).status(a, status * anim.ms / a.ms); }; function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { var cx = 3 * p1x, bx = 3 * (p2x - p1x) - cx, ax = 1 - cx - bx, cy = 3 * p1y, by = 3 * (p2y - p1y) - cy, ay = 1 - cy - by; function sampleCurveX(t) { return ((ax * t + bx) * t + cx) * t; } function solve(x, epsilon) { var t = solveCurveX(x, epsilon); return ((ay * t + by) * t + cy) * t; } function solveCurveX(x, epsilon) { var t0, t1, t2, x2, d2, i; for(t2 = x, i = 0; i < 8; i++) { x2 = sampleCurveX(t2) - x; if (abs(x2) < epsilon) { return t2; } d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; if (abs(d2) < 1e-6) { break; } t2 = t2 - x2 / d2; } t0 = 0; t1 = 1; t2 = x; if (t2 < t0) { return t0; } if (t2 > t1) { return t1; } while (t0 < t1) { x2 = sampleCurveX(t2); if (abs(x2 - x) < epsilon) { return t2; } if (x > x2) { t0 = t2; } else { t1 = t2; } t2 = (t1 - t0) / 2 + t0; } return t2; } return solve(t, 1 / (200 * duration)); } elproto.onAnimation = function (f) { f ? eve.on("raphael.anim.frame." + this.id, f) : eve.unbind("raphael.anim.frame." + this.id); return this; }; function Animation(anim, ms) { var percents = [], newAnim = {}; this.ms = ms; this.times = 1; if (anim) { for (var attr in anim) if (anim[has](attr)) { newAnim[toFloat(attr)] = anim[attr]; percents.push(toFloat(attr)); } percents.sort(sortByNumber); } this.anim = newAnim; this.top = percents[percents.length - 1]; this.percents = percents; } /*\ * Animation.delay [ method ] ** * Creates a copy of existing animation object with given delay. ** > Parameters ** - delay (number) number of ms to pass between animation start and actual animation ** = (object) new altered Animation object | var anim = Raphael.animation({cx: 10, cy: 20}, 2e3); | circle1.animate(anim); // run the given animation immediately | circle2.animate(anim.delay(500)); // run the given animation after 500 ms \*/ Animation.prototype.delay = function (delay) { var a = new Animation(this.anim, this.ms); a.times = this.times; a.del = +delay || 0; return a; }; /*\ * Animation.repeat [ method ] ** * Creates a copy of existing animation object with given repetition. ** > Parameters ** - repeat (number) number iterations of animation. For infinite animation pass `Infinity` ** = (object) new altered Animation object \*/ Animation.prototype.repeat = function (times) { var a = new Animation(this.anim, this.ms); a.del = this.del; a.times = math.floor(mmax(times, 0)) || 1; return a; }; function runAnimation(anim, element, percent, status, totalOrigin, times) { percent = toFloat(percent); var params, isInAnim, isInAnimSet, percents = [], next, prev, timestamp, ms = anim.ms, from = {}, to = {}, diff = {}; if (status) { for (i = 0, ii = animationElements.length; i < ii; i++) { var e = animationElements[i]; if (e.el.id == element.id && e.anim == anim) { if (e.percent != percent) { animationElements.splice(i, 1); isInAnimSet = 1; } else { isInAnim = e; } element.attr(e.totalOrigin); break; } } } else { status = +to; // NaN } for (var i = 0, ii = anim.percents.length; i < ii; i++) { if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { percent = anim.percents[i]; prev = anim.percents[i - 1] || 0; ms = ms / anim.top * (percent - prev); next = anim.percents[i + 1]; params = anim.anim[percent]; break; } else if (status) { element.attr(anim.anim[anim.percents[i]]); } } if (!params) { return; } if (!isInAnim) { for (var attr in params) if (params[has](attr)) { if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { from[attr] = element.attr(attr); (from[attr] == null) && (from[attr] = availableAttrs[attr]); to[attr] = params[attr]; switch (availableAnimAttrs[attr]) { case nu: diff[attr] = (to[attr] - from[attr]) / ms; break; case "colour": from[attr] = R.getRGB(from[attr]); var toColour = R.getRGB(to[attr]); diff[attr] = { r: (toColour.r - from[attr].r) / ms, g: (toColour.g - from[attr].g) / ms, b: (toColour.b - from[attr].b) / ms }; break; case "path": var pathes = path2curve(from[attr], to[attr]), toPath = pathes[1]; from[attr] = pathes[0]; diff[attr] = []; for (i = 0, ii = from[attr].length; i < ii; i++) { diff[attr][i] = [0]; for (var j = 1, jj = from[attr][i].length; j < jj; j++) { diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; } } break; case "transform": var _ = element._, eq = equaliseTransform(_[attr], to[attr]); if (eq) { from[attr] = eq.from; to[attr] = eq.to; diff[attr] = []; diff[attr].real = true; for (i = 0, ii = from[attr].length; i < ii; i++) { diff[attr][i] = [from[attr][i][0]]; for (j = 1, jj = from[attr][i].length; j < jj; j++) { diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; } } } else { var m = (element.matrix || new Matrix), to2 = { _: {transform: _.transform}, getBBox: function () { return element.getBBox(1); } }; from[attr] = [ m.a, m.b, m.c, m.d, m.e, m.f ]; extractTransform(to2, to[attr]); to[attr] = to2._.transform; diff[attr] = [ (to2.matrix.a - m.a) / ms, (to2.matrix.b - m.b) / ms, (to2.matrix.c - m.c) / ms, (to2.matrix.d - m.d) / ms, (to2.matrix.e - m.e) / ms, (to2.matrix.f - m.f) / ms ]; // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; // extractTransform(to2, to[attr]); // diff[attr] = [ // (to2._.sx - _.sx) / ms, // (to2._.sy - _.sy) / ms, // (to2._.deg - _.deg) / ms, // (to2._.dx - _.dx) / ms, // (to2._.dy - _.dy) / ms // ]; } break; case "csv": var values = Str(params[attr])[split](separator), from2 = Str(from[attr])[split](separator); if (attr == "clip-rect") { from[attr] = from2; diff[attr] = []; i = from2.length; while (i--) { diff[attr][i] = (values[i] - from[attr][i]) / ms; } } to[attr] = values; break; default: values = [][concat](params[attr]); from2 = [][concat](from[attr]); diff[attr] = []; i = element.paper.customAttributes[attr].length; while (i--) { diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; } break; } } } var easing = params.easing, easyeasy = R.easing_formulas[easing]; if (!easyeasy) { easyeasy = Str(easing).match(bezierrg); if (easyeasy && easyeasy.length == 5) { var curve = easyeasy; easyeasy = function (t) { return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); }; } else { easyeasy = pipe; } } timestamp = params.start || anim.start || +new Date; e = { anim: anim, percent: percent, timestamp: timestamp, start: timestamp + (anim.del || 0), status: 0, initstatus: status || 0, stop: false, ms: ms, easing: easyeasy, from: from, diff: diff, to: to, el: element, callback: params.callback, prev: prev, next: next, repeat: times || anim.times, origin: element.attr(), totalOrigin: totalOrigin }; animationElements.push(e); if (status && !isInAnim && !isInAnimSet) { e.stop = true; e.start = new Date - ms * status; if (animationElements.length == 1) { return animation(); } } if (isInAnimSet) { e.start = new Date - e.ms * status; } animationElements.length == 1 && requestAnimFrame(animation); } else { isInAnim.initstatus = status; isInAnim.start = new Date - isInAnim.ms * status; } eve("raphael.anim.start." + element.id, element, anim); } /*\ * Raphael.animation [ method ] ** * Creates an animation object that can be passed to the @Element.animate or @Element.animateWith methods. * See also @Animation.delay and @Animation.repeat methods. ** > Parameters ** - params (object) final attributes for the element, see also @Element.attr - ms (number) number of milliseconds for animation to run - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` - callback (function) #optional callback function. Will be called at the end of animation. ** = (object) @Animation \*/ R.animation = function (params, ms, easing, callback) { if (params instanceof Animation) { return params; } if (R.is(easing, "function") || !easing) { callback = callback || easing || null; easing = null; } params = Object(params); ms = +ms || 0; var p = {}, json, attr; for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { json = true; p[attr] = params[attr]; } if (!json) { // if percent-like syntax is used and end-of-all animation callback used if(callback){ // find the last one var lastKey = 0; for(var i in params){ var percent = toInt(i); if(params[has](i) && percent > lastKey){ lastKey = percent; } } lastKey += '%'; // if already defined callback in the last keyframe, skip !params[lastKey].callback && (params[lastKey].callback = callback); } return new Animation(params, ms); } else { easing && (p.easing = easing); callback && (p.callback = callback); return new Animation({100: p}, ms); } }; /*\ * Element.animate [ method ] ** * Creates and starts animation for given element. ** > Parameters ** - params (object) final attributes for the element, see also @Element.attr - ms (number) number of milliseconds for animation to run - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` - callback (function) #optional callback function. Will be called at the end of animation. * or - animation (object) animation object, see @Raphael.animation ** = (object) original element \*/ elproto.animate = function (params, ms, easing, callback) { var element = this; if (element.removed) { callback && callback.call(element); return element; } var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); runAnimation(anim, element, anim.percents[0], null, element.attr()); return element; }; /*\ * Element.setTime [ method ] ** * Sets the status of animation of the element in milliseconds. Similar to @Element.status method. ** > Parameters ** - anim (object) animation object - value (number) number of milliseconds from the beginning of the animation ** = (object) original element if `value` is specified * Note, that during animation following events are triggered: * * On each animation frame event `anim.frame.<id>`, on start `anim.start.<id>` and on end `anim.finish.<id>`. \*/ elproto.setTime = function (anim, value) { if (anim && value != null) { this.status(anim, mmin(value, anim.ms) / anim.ms); } return this; }; /*\ * Element.status [ method ] ** * Gets or sets the status of animation of the element. ** > Parameters ** - anim (object) #optional animation object - value (number) #optional 0 – 1. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position. ** = (number) status * or = (array) status if `anim` is not specified. Array of objects in format: o { o anim: (object) animation object o status: (number) status o } * or = (object) original element if `value` is specified \*/ elproto.status = function (anim, value) { var out = [], i = 0, len, e; if (value != null) { runAnimation(anim, this, -1, mmin(value, 1)); return this; } else { len = animationElements.length; for (; i < len; i++) { e = animationElements[i]; if (e.el.id == this.id && (!anim || e.anim == anim)) { if (anim) { return e.status; } out.push({ anim: e.anim, status: e.status }); } } if (anim) { return 0; } return out; } }; /*\ * Element.pause [ method ] ** * Stops animation of the element with ability to resume it later on. ** > Parameters ** - anim (object) #optional animation object ** = (object) original element \*/ elproto.pause = function (anim) { for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { if (eve("raphael.anim.pause." + this.id, this, animationElements[i].anim) !== false) { animationElements[i].paused = true; } } return this; }; /*\ * Element.resume [ method ] ** * Resumes animation if it was paused with @Element.pause method. ** > Parameters ** - anim (object) #optional animation object ** = (object) original element \*/ elproto.resume = function (anim) { for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { var e = animationElements[i]; if (eve("raphael.anim.resume." + this.id, this, e.anim) !== false) { delete e.paused; this.status(e.anim, e.status); } } return this; }; /*\ * Element.stop [ method ] ** * Stops animation of the element. ** > Parameters ** - anim (object) #optional animation object ** = (object) original element \*/ elproto.stop = function (anim) { for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { if (eve("raphael.anim.stop." + this.id, this, animationElements[i].anim) !== false) { animationElements.splice(i--, 1); } } return this; }; function stopAnimation(paper) { for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.paper == paper) { animationElements.splice(i--, 1); } } eve.on("raphael.remove", stopAnimation); eve.on("raphael.clear", stopAnimation); elproto.toString = function () { return "Rapha\xebl\u2019s object"; }; // Set var Set = function (items) { this.items = []; this.length = 0; this.type = "set"; if (items) { for (var i = 0, ii = items.length; i < ii; i++) { if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) { this[this.items.length] = this.items[this.items.length] = items[i]; this.length++; } } } }, setproto = Set.prototype; /*\ * Set.push [ method ] ** * Adds each argument to the current set. = (object) original element \*/ setproto.push = function () { var item, len; for (var i = 0, ii = arguments.length; i < ii; i++) { item = arguments[i]; if (item && (item.constructor == elproto.constructor || item.constructor == Set)) { len = this.items.length; this[len] = this.items[len] = item; this.length++; } } return this; }; /*\ * Set.pop [ method ] ** * Removes last element and returns it. = (object) element \*/ setproto.pop = function () { this.length && delete this[this.length--]; return this.items.pop(); }; /*\ * Set.forEach [ method ] ** * Executes given function for each element in the set. * * If function returns `false` it will stop loop running. ** > Parameters ** - callback (function) function to run - thisArg (object) context object for the callback = (object) Set object \*/ setproto.forEach = function (callback, thisArg) { for (var i = 0, ii = this.items.length; i < ii; i++) { if (callback.call(thisArg, this.items[i], i) === false) { return this; } } return this; }; for (var method in elproto) if (elproto[has](method)) { setproto[method] = (function (methodname) { return function () { var arg = arguments; return this.forEach(function (el) { el[methodname][apply](el, arg); }); }; })(method); } setproto.attr = function (name, value) { if (name && R.is(name, array) && R.is(name[0], "object")) { for (var j = 0, jj = name.length; j < jj; j++) { this.items[j].attr(name[j]); } } else { for (var i = 0, ii = this.items.length; i < ii; i++) { this.items[i].attr(name, value); } } return this; }; /*\ * Set.clear [ method ] ** * Removes all elements from the set \*/ setproto.clear = function () { while (this.length) { this.pop(); } }; /*\ * Set.splice [ method ] ** * Removes given element from the set ** > Parameters ** - index (number) position of the deletion - count (number) number of element to remove - insertion… (object) #optional elements to insert = (object) set elements that were deleted \*/ setproto.splice = function (index, count, insertion) { index = index < 0 ? mmax(this.length + index, 0) : index; count = mmax(0, mmin(this.length - index, count)); var tail = [], todel = [], args = [], i; for (i = 2; i < arguments.length; i++) { args.push(arguments[i]); } for (i = 0; i < count; i++) { todel.push(this[index + i]); } for (; i < this.length - index; i++) { tail.push(this[index + i]); } var arglen = args.length; for (i = 0; i < arglen + tail.length; i++) { this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; } i = this.items.length = this.length -= count - arglen; while (this[i]) { delete this[i++]; } return new Set(todel); }; /*\ * Set.exclude [ method ] ** * Removes given element from the set ** > Parameters ** - element (object) element to remove = (boolean) `true` if object was found & removed from the set \*/ setproto.exclude = function (el) { for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { this.splice(i, 1); return true; } }; setproto.animate = function (params, ms, easing, callback) { (R.is(easing, "function") || !easing) && (callback = easing || null); var len = this.items.length, i = len, item, set = this, collector; if (!len) { return this; } callback && (collector = function () { !--len && callback.call(set); }); easing = R.is(easing, string) ? easing : collector; var anim = R.animation(params, ms, easing, collector); item = this.items[--i].animate(anim); while (i--) { this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim, anim); (this.items[i] && !this.items[i].removed) || len--; } return this; }; setproto.insertAfter = function (el) { var i = this.items.length; while (i--) { this.items[i].insertAfter(el); } return this; }; setproto.getBBox = function () { var x = [], y = [], x2 = [], y2 = []; for (var i = this.items.length; i--;) if (!this.items[i].removed) { var box = this.items[i].getBBox(); x.push(box.x); y.push(box.y); x2.push(box.x + box.width); y2.push(box.y + box.height); } x = mmin[apply](0, x); y = mmin[apply](0, y); x2 = mmax[apply](0, x2); y2 = mmax[apply](0, y2); return { x: x, y: y, x2: x2, y2: y2, width: x2 - x, height: y2 - y }; }; setproto.clone = function (s) { s = this.paper.set(); for (var i = 0, ii = this.items.length; i < ii; i++) { s.push(this.items[i].clone()); } return s; }; setproto.toString = function () { return "Rapha\xebl\u2018s set"; }; setproto.glow = function(glowConfig) { var ret = this.paper.set(); this.forEach(function(shape, index){ var g = shape.glow(glowConfig); if(g != null){ g.forEach(function(shape2, index2){ ret.push(shape2); }); } }); return ret; }; /*\ * Set.isPointInside [ method ] ** * Determine if given point is inside this set’s elements ** > Parameters ** - x (number) x coordinate of the point - y (number) y coordinate of the point = (boolean) `true` if point is inside any of the set's elements \*/ setproto.isPointInside = function (x, y) { var isPointInside = false; this.forEach(function (el) { if (el.isPointInside(x, y)) { isPointInside = true; return false; // stop loop } }); return isPointInside; }; /*\ * Raphael.registerFont [ method ] ** * Adds given font to the registered set of font for Raphaël. Should be used as an internal call from within Cufón’s font file. * Returns original parameter, so it could be used with chaining. # <a href="http://wiki.github.com/sorccu/cufon/about">More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.</a> ** > Parameters ** - font (object) the font to register = (object) the font you passed in > Usage | Cufon.registerFont(Raphael.registerFont({…})); \*/ R.registerFont = function (font) { if (!font.face) { return font; } this.fonts = this.fonts || {}; var fontcopy = { w: font.w, face: {}, glyphs: {} }, family = font.face["font-family"]; for (var prop in font.face) if (font.face[has](prop)) { fontcopy.face[prop] = font.face[prop]; } if (this.fonts[family]) { this.fonts[family].push(fontcopy); } else { this.fonts[family] = [fontcopy]; } if (!font.svg) { fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { var path = font.glyphs[glyph]; fontcopy.glyphs[glyph] = { w: path.w, k: {}, d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; }) + "z" }; if (path.k) { for (var k in path.k) if (path[has](k)) { fontcopy.glyphs[glyph].k[k] = path.k[k]; } } } } return font; }; /*\ * Paper.getFont [ method ] ** * Finds font object in the registered font by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”. ** > Parameters ** - family (string) font family name or any word from it - weight (string) #optional font weight - style (string) #optional font style - stretch (string) #optional font stretch = (object) the font object > Usage | paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30); \*/ paperproto.getFont = function (family, weight, style, stretch) { stretch = stretch || "normal"; style = style || "normal"; weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; if (!R.fonts) { return; } var font = R.fonts[family]; if (!font) { var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); for (var fontName in R.fonts) if (R.fonts[has](fontName)) { if (name.test(fontName)) { font = R.fonts[fontName]; break; } } } var thefont; if (font) { for (var i = 0, ii = font.length; i < ii; i++) { thefont = font[i]; if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { break; } } } return thefont; }; /*\ * Paper.print [ method ] ** * Creates path that represent given text written using given font at given position with given size. * Result of the method is path element that contains whole text as a separate path. ** > Parameters ** - x (number) x position of the text - y (number) y position of the text - string (string) text to print - font (object) font object, see @Paper.getFont - size (number) #optional size of the font, default is `16` - origin (string) #optional could be `"baseline"` or `"middle"`, default is `"middle"` - letter_spacing (number) #optional number in range `-1..1`, default is `0` - line_spacing (number) #optional number in range `1..3`, default is `1` = (object) resulting path element, which consist of all letters > Usage | var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"}); \*/ paperproto.print = function (x, y, string, font, size, origin, letter_spacing, line_spacing) { origin = origin || "middle"; // baseline|middle letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); line_spacing = mmax(mmin(line_spacing || 1, 3), 1); var letters = Str(string)[split](E), shift = 0, notfirst = 0, path = E, scale; R.is(font, "string") && (font = this.getFont(font)); if (font) { scale = (size || 16) / font.face["units-per-em"]; var bb = font.face.bbox[split](separator), top = +bb[0], lineHeight = bb[3] - bb[1], shifty = 0, height = +bb[1] + (origin == "baseline" ? lineHeight + (+font.face.descent) : lineHeight / 2); for (var i = 0, ii = letters.length; i < ii; i++) { if (letters[i] == "\n") { shift = 0; curr = 0; notfirst = 0; shifty += lineHeight * line_spacing; } else { var prev = notfirst && font.glyphs[letters[i - 1]] || {}, curr = font.glyphs[letters[i]]; shift += notfirst ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; notfirst = 1; } if (curr && curr.d) { path += R.transformPath(curr.d, ["t", shift * scale, shifty * scale, "s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); } } } return this.path(path).attr({ fill: "#000", stroke: "none" }); }; /*\ * Paper.add [ method ] ** * Imports elements in JSON array in format `{type: type, <attributes>}` ** > Parameters ** - json (array) = (object) resulting set of imported elements > Usage | paper.add([ | { | type: "circle", | cx: 10, | cy: 10, | r: 5 | }, | { | type: "rect", | x: 10, | y: 10, | width: 10, | height: 10, | fill: "#fc0" | } | ]); \*/ paperproto.add = function (json) { if (R.is(json, "array")) { var res = this.set(), i = 0, ii = json.length, j; for (; i < ii; i++) { j = json[i] || {}; elements[has](j.type) && res.push(this[j.type]().attr(j)); } } return res; }; /*\ * Raphael.format [ method ] ** * Simple format function. Replaces construction of type “`{<number>}`” to the corresponding argument. ** > Parameters ** - token (string) string to format - … (string) rest of arguments will be treated as parameters for replacement = (string) formated string > Usage | var x = 10, | y = 20, | width = 40, | height = 50; | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width)); \*/ R.format = function (token, params) { var args = R.is(params, array) ? [0][concat](params) : arguments; token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { return args[++i] == null ? E : args[i]; })); return token || E; }; /*\ * Raphael.fullfill [ method ] ** * A little bit more advanced format function than @Raphael.format. Replaces construction of type “`{<name>}`” to the corresponding argument. ** > Parameters ** - token (string) string to format - json (object) object which properties will be used as a replacement = (string) formated string > Usage | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" | paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { | x: 10, | y: 20, | dim: { | width: 40, | height: 50, | "negative width": -40 | } | })); \*/ R.fullfill = (function () { var tokenRegex = /\{([^\}]+)\}/g, objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties replacer = function (all, key, obj) { var res = obj; key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { name = name || quotedName; if (res) { if (name in res) { res = res[name]; } typeof res == "function" && isFunc && (res = res()); } }); res = (res == null || res == obj ? all : res) + ""; return res; }; return function (str, obj) { return String(str).replace(tokenRegex, function (all, key) { return replacer(all, key, obj); }); }; })(); /*\ * Raphael.ninja [ method ] ** * If you want to leave no trace of Raphaël (Well, Raphaël creates only one global variable `Raphael`, but anyway.) You can use `ninja` method. * Beware, that in this case plugins could stop working, because they are depending on global variable existence. ** = (object) Raphael object > Usage | (function (local_raphael) { | var paper = local_raphael(10, 10, 320, 200); | … | })(Raphael.ninja()); \*/ R.ninja = function () { oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; return R; }; /*\ * Raphael.st [ property (object) ] ** * You can add your own method to elements and sets. It is wise to add a set method for each element method * you added, so you will be able to call the same method on sets too. ** * See also @Raphael.el. > Usage | Raphael.el.red = function () { | this.attr({fill: "#f00"}); | }; | Raphael.st.red = function () { | this.forEach(function (el) { | el.red(); | }); | }; | // then use it | paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red(); \*/ R.st = setproto; eve.on("raphael.DOMload", function () { loaded = true; }); // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html (function (doc, loaded, f) { if (doc.readyState == null && doc.addEventListener){ doc.addEventListener(loaded, f = function () { doc.removeEventListener(loaded, f, false); doc.readyState = "complete"; }, false); doc.readyState = "loading"; } function isLoaded() { (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload"); } isLoaded(); })(document, "DOMContentLoaded"); return R; })); // ┌─────────────────────────────────────────────────────────────────────┐ \\ // │ Raphaël 2.1.4 - JavaScript Vector Library │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ // │ SVG Module │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ // └─────────────────────────────────────────────────────────────────────┘ \\ (function (glob, factory) { if (typeof define === "function" && define.amd) { define("raphael.svg", ["raphael.core"], function(raphael) { return factory(raphael); }); } else if (typeof exports === "object") { factory(require("raphael.core")); } else { factory(glob.Raphael); } }(this, function(R) { if (R && !R.svg) { return; } var has = "hasOwnProperty", Str = String, toFloat = parseFloat, toInt = parseInt, math = Math, mmax = math.max, abs = math.abs, pow = math.pow, separator = /[, ]+/, eve = R.eve, E = "", S = " "; var xlink = "http://www.w3.org/1999/xlink", markers = { block: "M5,0 0,2.5 5,5z", classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", open: "M6,1 1,3.5 6,6", oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" }, markerCounter = {}; R.toString = function () { return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; }; var $ = function (el, attr) { if (attr) { if (typeof el == "string") { el = $(el); } for (var key in attr) if (attr[has](key)) { if (key.substring(0, 6) == "xlink:") { el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); } else { el.setAttribute(key, Str(attr[key])); } } } else { el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); } return el; }, addGradientFill = function (element, gradient) { var type = "linear", id = element.id + gradient, fx = .5, fy = .5, o = element.node, SVG = element.paper, s = o.style, el = R._g.doc.getElementById(id); if (!el) { gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { type = "radial"; if (_fx && _fy) { fx = toFloat(_fx); fy = toFloat(_fy); var dir = ((fy > .5) * 2 - 1); pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && fy != .5 && (fy = fy.toFixed(5) - 1e-5 * dir); } return E; }); gradient = gradient.split(/\s*\-\s*/); if (type == "linear") { var angle = gradient.shift(); angle = -toFloat(angle); if (isNaN(angle)) { return null; } var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); vector[2] *= max; vector[3] *= max; if (vector[2] < 0) { vector[0] = -vector[2]; vector[2] = 0; } if (vector[3] < 0) { vector[1] = -vector[3]; vector[3] = 0; } } var dots = R._parseDots(gradient); if (!dots) { return null; } id = id.replace(/[\(\)\s,\xb0#]/g, "_"); if (element.gradient && id != element.gradient.id) { SVG.defs.removeChild(element.gradient); delete element.gradient; } if (!element.gradient) { el = $(type + "Gradient", {id: id}); element.gradient = el; $(el, type == "radial" ? { fx: fx, fy: fy } : { x1: vector[0], y1: vector[1], x2: vector[2], y2: vector[3], gradientTransform: element.matrix.invert() }); SVG.defs.appendChild(el); for (var i = 0, ii = dots.length; i < ii; i++) { el.appendChild($("stop", { offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", "stop-color": dots[i].color || "#fff", "stop-opacity": isFinite(dots[i].opacity) ? dots[i].opacity : 1 })); } } } $(o, { fill: "url('" + document.location.origin + document.location.pathname + "#" + id + "')", opacity: 1, "fill-opacity": 1 }); s.fill = E; s.opacity = 1; s.fillOpacity = 1; return 1; }, updatePosition = function (o) { var bbox = o.getBBox(1); $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); }, addArrow = function (o, value, isEnd) { if (o.type == "path") { var values = Str(value).toLowerCase().split("-"), p = o.paper, se = isEnd ? "end" : "start", node = o.node, attrs = o.attrs, stroke = attrs["stroke-width"], i = values.length, type = "classic", from, to, dx, refX, attr, w = 3, h = 3, t = 5; while (i--) { switch (values[i]) { case "block": case "classic": case "oval": case "diamond": case "open": case "none": type = values[i]; break; case "wide": h = 5; break; case "narrow": h = 2; break; case "long": w = 5; break; case "short": w = 2; break; } } if (type == "open") { w += 2; h += 2; t += 2; dx = 1; refX = isEnd ? 4 : 1; attr = { fill: "none", stroke: attrs.stroke }; } else { refX = dx = w / 2; attr = { fill: attrs.stroke, stroke: "none" }; } if (o._.arrows) { if (isEnd) { o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; } else { o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; } } else { o._.arrows = {}; } if (type != "none") { var pathId = "raphael-marker-" + type, markerId = "raphael-marker-" + se + type + w + h + "-obj" + o.id; if (!R._g.doc.getElementById(pathId)) { p.defs.appendChild($($("path"), { "stroke-linecap": "round", d: markers[type], id: pathId })); markerCounter[pathId] = 1; } else { markerCounter[pathId]++; } var marker = R._g.doc.getElementById(markerId), use; if (!marker) { marker = $($("marker"), { id: markerId, markerHeight: h, markerWidth: w, orient: "auto", refX: refX, refY: h / 2 }); use = $($("use"), { "xlink:href": "#" + pathId, transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")", "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4) }); marker.appendChild(use); p.defs.appendChild(marker); markerCounter[markerId] = 1; } else { markerCounter[markerId]++; use = marker.getElementsByTagName("use")[0]; } $(use, attr); var delta = dx * (type != "diamond" && type != "oval"); if (isEnd) { from = o._.arrows.startdx * stroke || 0; to = R.getTotalLength(attrs.path) - delta * stroke; } else { from = delta * stroke; to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); } attr = {}; attr["marker-" + se] = "url(#" + markerId + ")"; if (to || from) { attr.d = R.getSubpath(attrs.path, from, to); } $(node, attr); o._.arrows[se + "Path"] = pathId; o._.arrows[se + "Marker"] = markerId; o._.arrows[se + "dx"] = delta; o._.arrows[se + "Type"] = type; o._.arrows[se + "String"] = value; } else { if (isEnd) { from = o._.arrows.startdx * stroke || 0; to = R.getTotalLength(attrs.path) - from; } else { from = 0; to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); } o._.arrows[se + "Path"] && $(node, {d: R.getSubpath(attrs.path, from, to)}); delete o._.arrows[se + "Path"]; delete o._.arrows[se + "Marker"]; delete o._.arrows[se + "dx"]; delete o._.arrows[se + "Type"]; delete o._.arrows[se + "String"]; } for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { var item = R._g.doc.getElementById(attr); item && item.parentNode.removeChild(item); } } }, dasharray = { "-": [3, 1], ".": [1, 1], "-.": [3, 1, 1, 1], "-..": [3, 1, 1, 1, 1, 1], ". ": [1, 3], "- ": [4, 3], "--": [8, 3], "- .": [4, 3, 1, 3], "--.": [8, 3, 1, 3], "--..": [8, 3, 1, 3, 1, 3] }, addDashes = function (o, value, params) { value = dasharray[Str(value).toLowerCase()]; if (value) { var width = o.attrs["stroke-width"] || "1", butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, dashes = [], i = value.length; while (i--) { dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; } $(o.node, {"stroke-dasharray": dashes.join(",")}); } else { $(o.node, {"stroke-dasharray": "none"}); } }, setFillAndStroke = function (o, params) { var node = o.node, attrs = o.attrs, vis = node.style.visibility; node.style.visibility = "hidden"; for (var att in params) { if (params[has](att)) { if (!R._availableAttrs[has](att)) { continue; } var value = params[att]; attrs[att] = value; switch (att) { case "blur": o.blur(value); break; case "title": var title = node.getElementsByTagName("title"); // Use the existing <title>. if (title.length && (title = title[0])) { title.firstChild.nodeValue = value; } else { title = $("title"); var val = R._g.doc.createTextNode(value); title.appendChild(val); node.appendChild(title); } break; case "href": case "target": var pn = node.parentNode; if (pn.tagName.toLowerCase() != "a") { var hl = $("a"); pn.insertBefore(hl, node); hl.appendChild(node); pn = hl; } if (att == "target") { pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value); } else { pn.setAttributeNS(xlink, att, value); } break; case "cursor": node.style.cursor = value; break; case "transform": o.transform(value); break; case "arrow-start": addArrow(o, value); break; case "arrow-end": addArrow(o, value, 1); break; case "clip-rect": var rect = Str(value).split(separator); if (rect.length == 4) { o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); var el = $("clipPath"), rc = $("rect"); el.id = R.createUUID(); $(rc, { x: rect[0], y: rect[1], width: rect[2], height: rect[3] }); el.appendChild(rc); o.paper.defs.appendChild(el); $(node, {"clip-path": "url(#" + el.id + ")"}); o.clip = rc; } if (!value) { var path = node.getAttribute("clip-path"); if (path) { var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E)); clip && clip.parentNode.removeChild(clip); $(node, {"clip-path": E}); delete o.clip; } } break; case "path": if (o.type == "path") { $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); o._.dirty = 1; if (o._.arrows) { "startString" in o._.arrows && addArrow(o, o._.arrows.startString); "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); } } break; case "width": node.setAttribute(att, value); o._.dirty = 1; if (attrs.fx) { att = "x"; value = attrs.x; } else { break; } case "x": if (attrs.fx) { value = -attrs.x - (attrs.width || 0); } case "rx": if (att == "rx" && o.type == "rect") { break; } case "cx": node.setAttribute(att, value); o.pattern && updatePosition(o); o._.dirty = 1; break; case "height": node.setAttribute(att, value); o._.dirty = 1; if (attrs.fy) { att = "y"; value = attrs.y; } else { break; } case "y": if (attrs.fy) { value = -attrs.y - (attrs.height || 0); } case "ry": if (att == "ry" && o.type == "rect") { break; } case "cy": node.setAttribute(att, value); o.pattern && updatePosition(o); o._.dirty = 1; break; case "r": if (o.type == "rect") { $(node, {rx: value, ry: value}); } else { node.setAttribute(att, value); } o._.dirty = 1; break; case "src": if (o.type == "image") { node.setAttributeNS(xlink, "href", value); } break; case "stroke-width": if (o._.sx != 1 || o._.sy != 1) { value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; } node.setAttribute(att, value); if (attrs["stroke-dasharray"]) { addDashes(o, attrs["stroke-dasharray"], params); } if (o._.arrows) { "startString" in o._.arrows && addArrow(o, o._.arrows.startString); "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); } break; case "stroke-dasharray": addDashes(o, value, params); break; case "fill": var isURL = Str(value).match(R._ISURL); if (isURL) { el = $("pattern"); var ig = $("image"); el.id = R.createUUID(); $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); el.appendChild(ig); (function (el) { R._preload(isURL[1], function () { var w = this.offsetWidth, h = this.offsetHeight; $(el, {width: w, height: h}); $(ig, {width: w, height: h}); }); })(el); o.paper.defs.appendChild(el); $(node, {fill: "url(#" + el.id + ")"}); o.pattern = el; o.pattern && updatePosition(o); break; } var clr = R.getRGB(value); if (!clr.error) { delete params.gradient; delete attrs.gradient; !R.is(attrs.opacity, "undefined") && R.is(params.opacity, "undefined") && $(node, {opacity: attrs.opacity}); !R.is(attrs["fill-opacity"], "undefined") && R.is(params["fill-opacity"], "undefined") && $(node, {"fill-opacity": attrs["fill-opacity"]}); } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { if ("opacity" in attrs || "fill-opacity" in attrs) { var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); if (gradient) { var stops = gradient.getElementsByTagName("stop"); $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); } } attrs.gradient = value; attrs.fill = "none"; break; } clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); case "stroke": clr = R.getRGB(value); node.setAttribute(att, clr.hex); att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); if (att == "stroke" && o._.arrows) { "startString" in o._.arrows && addArrow(o, o._.arrows.startString); "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); } break; case "gradient": (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); break; case "opacity": if (attrs.gradient && !attrs[has]("stroke-opacity")) { $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); } // fall case "fill-opacity": if (attrs.gradient) { gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); if (gradient) { stops = gradient.getElementsByTagName("stop"); $(stops[stops.length - 1], {"stop-opacity": value}); } break; } default: att == "font-size" && (value = toInt(value, 10) + "px"); var cssrule = att.replace(/(\-.)/g, function (w) { return w.substring(1).toUpperCase(); }); node.style[cssrule] = value; o._.dirty = 1; node.setAttribute(att, value); break; } } } tuneText(o, params); node.style.visibility = vis; }, leading = 1.2, tuneText = function (el, params) { if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { return; } var a = el.attrs, node = el.node, fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; if (params[has]("text")) { a.text = params.text; while (node.firstChild) { node.removeChild(node.firstChild); } var texts = Str(params.text).split("\n"), tspans = [], tspan; for (var i = 0, ii = texts.length; i < ii; i++) { tspan = $("tspan"); i && $(tspan, {dy: fontSize * leading, x: a.x}); tspan.appendChild(R._g.doc.createTextNode(texts[i])); node.appendChild(tspan); tspans[i] = tspan; } } else { tspans = node.getElementsByTagName("tspan"); for (i = 0, ii = tspans.length; i < ii; i++) if (i) { $(tspans[i], {dy: fontSize * leading, x: a.x}); } else { $(tspans[0], {dy: 0}); } } $(node, {x: a.x, y: a.y}); el._.dirty = 1; var bb = el._getBBox(), dif = a.y - (bb.y + bb.height / 2); dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); }, getRealNode = function (node) { if (node.parentNode && node.parentNode.tagName.toLowerCase() === "a") { return node.parentNode; } else { return node; } }, Element = function (node, svg) { var X = 0, Y = 0; /*\ * Element.node [ property (object) ] ** * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. ** * Note: Don’t mess with it. > Usage | // draw a circle at coordinate 10,10 with radius of 10 | var c = paper.circle(10, 10, 10); | c.node.onclick = function () { | c.attr("fill", "red"); | }; \*/ this[0] = this.node = node; /*\ * Element.raphael [ property (object) ] ** * Internal reference to @Raphael object. In case it is not available. > Usage | Raphael.el.red = function () { | var hsb = this.paper.raphael.rgb2hsb(this.attr("fill")); | hsb.h = 1; | this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex}); | } \*/ node.raphael = true; /*\ * Element.id [ property (number) ] ** * Unique id of the element. Especially useful when you want to listen to events of the element, * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method. \*/ this.id = R._oid++; node.raphaelid = this.id; this.matrix = R.matrix(); this.realPath = null; /*\ * Element.paper [ property (object) ] ** * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions. > Usage | Raphael.el.cross = function () { | this.attr({fill: "red"}); | this.paper.path("M10,10L50,50M50,10L10,50") | .attr({stroke: "red"}); | } \*/ this.paper = svg; this.attrs = this.attrs || {}; this._ = { transform: [], sx: 1, sy: 1, deg: 0, dx: 0, dy: 0, dirty: 1 }; !svg.bottom && (svg.bottom = this); /*\ * Element.prev [ property (object) ] ** * Reference to the previous element in the hierarchy. \*/ this.prev = svg.top; svg.top && (svg.top.next = this); svg.top = this; /*\ * Element.next [ property (object) ] ** * Reference to the next element in the hierarchy. \*/ this.next = null; }, elproto = R.el; Element.prototype = elproto; elproto.constructor = Element; R._engine.path = function (pathString, SVG) { var el = $("path"); SVG.canvas && SVG.canvas.appendChild(el); var p = new Element(el, SVG); p.type = "path"; setFillAndStroke(p, { fill: "none", stroke: "#000", path: pathString }); return p; }; /*\ * Element.rotate [ method ] ** * Deprecated! Use @Element.transform instead. * Adds rotation by given angle around given point to the list of * transformations of the element. > Parameters - deg (number) angle in degrees - cx (number) #optional x coordinate of the centre of rotation - cy (number) #optional y coordinate of the centre of rotation * If cx & cy aren’t specified centre of the shape is used as a point of rotation. = (object) @Element \*/ elproto.rotate = function (deg, cx, cy) { if (this.removed) { return this; } deg = Str(deg).split(separator); if (deg.length - 1) { cx = toFloat(deg[1]); cy = toFloat(deg[2]); } deg = toFloat(deg[0]); (cy == null) && (cx = cy); if (cx == null || cy == null) { var bbox = this.getBBox(1); cx = bbox.x + bbox.width / 2; cy = bbox.y + bbox.height / 2; } this.transform(this._.transform.concat([["r", deg, cx, cy]])); return this; }; /*\ * Element.scale [ method ] ** * Deprecated! Use @Element.transform instead. * Adds scale by given amount relative to given point to the list of * transformations of the element. > Parameters - sx (number) horisontal scale amount - sy (number) vertical scale amount - cx (number) #optional x coordinate of the centre of scale - cy (number) #optional y coordinate of the centre of scale * If cx & cy aren’t specified centre of the shape is used instead. = (object) @Element \*/ elproto.scale = function (sx, sy, cx, cy) { if (this.removed) { return this; } sx = Str(sx).split(separator); if (sx.length - 1) { sy = toFloat(sx[1]); cx = toFloat(sx[2]); cy = toFloat(sx[3]); } sx = toFloat(sx[0]); (sy == null) && (sy = sx); (cy == null) && (cx = cy); if (cx == null || cy == null) { var bbox = this.getBBox(1); } cx = cx == null ? bbox.x + bbox.width / 2 : cx; cy = cy == null ? bbox.y + bbox.height / 2 : cy; this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); return this; }; /*\ * Element.translate [ method ] ** * Deprecated! Use @Element.transform instead. * Adds translation by given amount to the list of transformations of the element. > Parameters - dx (number) horisontal shift - dy (number) vertical shift = (object) @Element \*/ elproto.translate = function (dx, dy) { if (this.removed) { return this; } dx = Str(dx).split(separator); if (dx.length - 1) { dy = toFloat(dx[1]); } dx = toFloat(dx[0]) || 0; dy = +dy || 0; this.transform(this._.transform.concat([["t", dx, dy]])); return this; }; /*\ * Element.transform [ method ] ** * Adds transformation to the element which is separate to other attributes, * i.e. translation doesn’t change `x` or `y` of the rectange. The format * of transformation string is similar to the path string syntax: | "t100,100r30,100,100s2,2,100,100r45s1.5" * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for * scale and `m` is for matrix. * * There are also alternative “absolute” translation, rotation and scale: `T`, `R` and `S`. They will not take previous transformation into account. For example, `...T100,0` will always move element 100 px horisontally, while `...t100,0` could move it vertically if there is `r90` before. Just compare results of `r90t100,0` and `r90T100,0`. * * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100; * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin * coordinates as optional parameters, the default is the centre point of the element. * Matrix accepts six parameters. > Usage | var el = paper.rect(10, 20, 300, 200); | // translate 100, 100, rotate 45°, translate -100, 0 | el.transform("t100,100r45t-100,0"); | // if you want you can append or prepend transformations | el.transform("...t50,50"); | el.transform("s2..."); | // or even wrap | el.transform("t50,50...t-50-50"); | // to reset transformation call method with empty string | el.transform(""); | // to get current value call it without parameters | console.log(el.transform()); > Parameters - tstr (string) #optional transformation string * If tstr isn’t specified = (string) current transformation string * else = (object) @Element \*/ elproto.transform = function (tstr) { var _ = this._; if (tstr == null) { return _.transform; } R._extractTransform(this, tstr); this.clip && $(this.clip, {transform: this.matrix.invert()}); this.pattern && updatePosition(this); this.node && $(this.node, {transform: this.matrix}); if (_.sx != 1 || _.sy != 1) { var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; this.attr({"stroke-width": sw}); } return this; }; /*\ * Element.hide [ method ] ** * Makes element invisible. See @Element.show. = (object) @Element \*/ elproto.hide = function () { if(!this.removed) this.node.style.display = "none"; return this; }; /*\ * Element.show [ method ] ** * Makes element visible. See @Element.hide. = (object) @Element \*/ elproto.show = function () { if(!this.removed) this.node.style.display = ""; return this; }; /*\ * Element.remove [ method ] ** * Removes element from the paper. \*/ elproto.remove = function () { var node = getRealNode(this.node); if (this.removed || !node.parentNode) { return; } var paper = this.paper; paper.__set__ && paper.__set__.exclude(this); eve.unbind("raphael.*.*." + this.id); if (this.gradient) { paper.defs.removeChild(this.gradient); } R._tear(this, paper); node.parentNode.removeChild(node); // Remove custom data for element this.removeData(); for (var i in this) { this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } this.removed = true; }; elproto._getBBox = function () { if (this.node.style.display == "none") { this.show(); var hide = true; } var canvasHidden = false, containerStyle; if (this.paper.canvas.parentElement) { containerStyle = this.paper.canvas.parentElement.style; } //IE10+ can't find parentElement else if (this.paper.canvas.parentNode) { containerStyle = this.paper.canvas.parentNode.style; } if(containerStyle && containerStyle.display == "none") { canvasHidden = true; containerStyle.display = ""; } var bbox = {}; try { bbox = this.node.getBBox(); } catch(e) { // Firefox 3.0.x, 25.0.1 (probably more versions affected) play badly here - possible fix bbox = { x: this.node.clientLeft, y: this.node.clientTop, width: this.node.clientWidth, height: this.node.clientHeight } } finally { bbox = bbox || {}; if(canvasHidden){ containerStyle.display = "none"; } } hide && this.hide(); return bbox; }; /*\ * Element.attr [ method ] ** * Sets the attributes of the element. > Parameters - attrName (string) attribute’s name - value (string) value * or - params (object) object of name/value pairs * or - attrName (string) attribute’s name * or - attrNames (array) in this case method returns array of current values for given attribute names = (object) @Element if attrsName & value or params are passed in. = (...) value of the attribute if only attrsName is passed in. = (array) array of values of the attribute if attrsNames is passed in. = (object) object of attributes if nothing is passed in. > Possible parameters # <p>Please refer to the <a href="http://www.w3.org/TR/SVG/" title="The W3C Recommendation for the SVG language describes these properties in detail.">SVG specification</a> for an explanation of these parameters.</p> o arrow-end (string) arrowhead on the end of the path. The format for string is `<type>[-<width>[-<length>]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `medium`, length: `long`, `short`, `midium`. o clip-rect (string) comma or space separated values: x, y, width and height o cursor (string) CSS type of the cursor o cx (number) the x-axis coordinate of the center of the circle, or ellipse o cy (number) the y-axis coordinate of the center of the circle, or ellipse o fill (string) colour, gradient or image o fill-opacity (number) o font (string) o font-family (string) o font-size (number) font size in pixels o font-weight (string) o height (number) o href (string) URL, if specified element behaves as hyperlink o opacity (number) o path (string) SVG path string format o r (number) radius of the circle, ellipse or rounded corner on the rect o rx (number) horisontal radius of the ellipse o ry (number) vertical radius of the ellipse o src (string) image URL, only works for @Element.image element o stroke (string) stroke colour o stroke-dasharray (string) [“”, “none”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”] o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”] o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”] o stroke-miterlimit (number) o stroke-opacity (number) o stroke-width (number) stroke width in pixels, default is '1' o target (string) used with href o text (string) contents of the text element. Use `\n` for multiline text o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`” o title (string) will create tooltip with a given text o transform (string) see @Element.transform o width (number) o x (number) o y (number) > Gradients * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90° * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black. * * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” – * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses. > Path String # <p>Please refer to <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path’s data attribute’s format are described in the SVG specification.">SVG documentation regarding path string</a>. Raphaël fully supports it.</p> > Colour Parsing # <ul> # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li> # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li> # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li> # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li> # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li> # <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(200, 100, 0, .5)</code>”)</li> # <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%, 175%, 0%, 50%)</code>”)</li> # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li> # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> # <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li> # <li>hsl(•••, •••, •••) — almost the same as hsb, see <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" title="HSL and HSV - Wikipedia, the free encyclopedia">Wikipedia page</a></li> # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> # <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li> # <li>Optionally for hsb and hsl you could specify hue as a degree: “<code>hsl(240deg, 1, .5)</code>” or, if you want to go fancy, “<code>hsl(240°, 1, .5)</code>”</li> # </ul> \*/ elproto.attr = function (name, value) { if (this.removed) { return this; } if (name == null) { var res = {}; for (var a in this.attrs) if (this.attrs[has](a)) { res[a] = this.attrs[a]; } res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; res.transform = this._.transform; return res; } if (value == null && R.is(name, "string")) { if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { return this.attrs.gradient; } if (name == "transform") { return this._.transform; } var names = name.split(separator), out = {}; for (var i = 0, ii = names.length; i < ii; i++) { name = names[i]; if (name in this.attrs) { out[name] = this.attrs[name]; } else if (R.is(this.paper.customAttributes[name], "function")) { out[name] = this.paper.customAttributes[name].def; } else { out[name] = R._availableAttrs[name]; } } return ii - 1 ? out : out[names[0]]; } if (value == null && R.is(name, "array")) { out = {}; for (i = 0, ii = name.length; i < ii; i++) { out[name[i]] = this.attr(name[i]); } return out; } if (value != null) { var params = {}; params[name] = value; } else if (name != null && R.is(name, "object")) { params = name; } for (var key in params) { eve("raphael.attr." + key + "." + this.id, this, params[key]); } for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); this.attrs[key] = params[key]; for (var subkey in par) if (par[has](subkey)) { params[subkey] = par[subkey]; } } setFillAndStroke(this, params); return this; }; /*\ * Element.toFront [ method ] ** * Moves the element so it is the closest to the viewer’s eyes, on top of other elements. = (object) @Element \*/ elproto.toFront = function () { if (this.removed) { return this; } var node = getRealNode(this.node); node.parentNode.appendChild(node); var svg = this.paper; svg.top != this && R._tofront(this, svg); return this; }; /*\ * Element.toBack [ method ] ** * Moves the element so it is the furthest from the viewer’s eyes, behind other elements. = (object) @Element \*/ elproto.toBack = function () { if (this.removed) { return this; } var node = getRealNode(this.node); var parentNode = node.parentNode; parentNode.insertBefore(node, parentNode.firstChild); R._toback(this, this.paper); var svg = this.paper; return this; }; /*\ * Element.insertAfter [ method ] ** * Inserts current object after the given one. = (object) @Element \*/ elproto.insertAfter = function (element) { if (this.removed || !element) { return this; } var node = getRealNode(this.node); var afterNode = getRealNode(element.node || element[element.length - 1].node); if (afterNode.nextSibling) { afterNode.parentNode.insertBefore(node, afterNode.nextSibling); } else { afterNode.parentNode.appendChild(node); } R._insertafter(this, element, this.paper); return this; }; /*\ * Element.insertBefore [ method ] ** * Inserts current object before the given one. = (object) @Element \*/ elproto.insertBefore = function (element) { if (this.removed || !element) { return this; } var node = getRealNode(this.node); var beforeNode = getRealNode(element.node || element[0].node); beforeNode.parentNode.insertBefore(node, beforeNode); R._insertbefore(this, element, this.paper); return this; }; elproto.blur = function (size) { // Experimental. No Safari support. Use it on your own risk. var t = this; if (+size !== 0) { var fltr = $("filter"), blur = $("feGaussianBlur"); t.attrs.blur = size; fltr.id = R.createUUID(); $(blur, {stdDeviation: +size || 1.5}); fltr.appendChild(blur); t.paper.defs.appendChild(fltr); t._blur = fltr; $(t.node, {filter: "url(#" + fltr.id + ")"}); } else { if (t._blur) { t._blur.parentNode.removeChild(t._blur); delete t._blur; delete t.attrs.blur; } t.node.removeAttribute("filter"); } return t; }; R._engine.circle = function (svg, x, y, r) { var el = $("circle"); svg.canvas && svg.canvas.appendChild(el); var res = new Element(el, svg); res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; res.type = "circle"; $(el, res.attrs); return res; }; R._engine.rect = function (svg, x, y, w, h, r) { var el = $("rect"); svg.canvas && svg.canvas.appendChild(el); var res = new Element(el, svg); res.attrs = {x: x, y: y, width: w, height: h, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; res.type = "rect"; $(el, res.attrs); return res; }; R._engine.ellipse = function (svg, x, y, rx, ry) { var el = $("ellipse"); svg.canvas && svg.canvas.appendChild(el); var res = new Element(el, svg); res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; res.type = "ellipse"; $(el, res.attrs); return res; }; R._engine.image = function (svg, src, x, y, w, h) { var el = $("image"); $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); el.setAttributeNS(xlink, "href", src); svg.canvas && svg.canvas.appendChild(el); var res = new Element(el, svg); res.attrs = {x: x, y: y, width: w, height: h, src: src}; res.type = "image"; return res; }; R._engine.text = function (svg, x, y, text) { var el = $("text"); svg.canvas && svg.canvas.appendChild(el); var res = new Element(el, svg); res.attrs = { x: x, y: y, "text-anchor": "middle", text: text, "font-family": R._availableAttrs["font-family"], "font-size": R._availableAttrs["font-size"], stroke: "none", fill: "#000" }; res.type = "text"; setFillAndStroke(res, res.attrs); return res; }; R._engine.setSize = function (width, height) { this.width = width || this.width; this.height = height || this.height; this.canvas.setAttribute("width", this.width); this.canvas.setAttribute("height", this.height); if (this._viewBox) { this.setViewBox.apply(this, this._viewBox); } return this; }; R._engine.create = function () { var con = R._getContainer.apply(0, arguments), container = con && con.container, x = con.x, y = con.y, width = con.width, height = con.height; if (!container) { throw new Error("SVG container not found."); } var cnvs = $("svg"), css = "overflow:hidden;", isFloating; x = x || 0; y = y || 0; width = width || 512; height = height || 342; $(cnvs, { height: height, version: 1.1, width: width, xmlns: "http://www.w3.org/2000/svg", "xmlns:xlink": "http://www.w3.org/1999/xlink" }); if (container == 1) { cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; R._g.doc.body.appendChild(cnvs); isFloating = 1; } else { cnvs.style.cssText = css + "position:relative"; if (container.firstChild) { container.insertBefore(cnvs, container.firstChild); } else { container.appendChild(cnvs); } } container = new R._Paper; container.width = width; container.height = height; container.canvas = cnvs; container.clear(); container._left = container._top = 0; isFloating && (container.renderfix = function () {}); container.renderfix(); return container; }; R._engine.setViewBox = function (x, y, w, h, fit) { eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]); var paperSize = this.getSize(), size = mmax(w / paperSize.width, h / paperSize.height), top = this.top, aspectRatio = fit ? "xMidYMid meet" : "xMinYMin", vb, sw; if (x == null) { if (this._vbSize) { size = 1; } delete this._vbSize; vb = "0 0 " + this.width + S + this.height; } else { this._vbSize = size; vb = x + S + y + S + w + S + h; } $(this.canvas, { viewBox: vb, preserveAspectRatio: aspectRatio }); while (size && top) { sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; top.attr({"stroke-width": sw}); top._.dirty = 1; top._.dirtyT = 1; top = top.prev; } this._viewBox = [x, y, w, h, !!fit]; return this; }; /*\ * Paper.renderfix [ method ] ** * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependant * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness. * This method fixes the issue. ** Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method. \*/ R.prototype.renderfix = function () { var cnvs = this.canvas, s = cnvs.style, pos; try { pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(); } catch (e) { pos = cnvs.createSVGMatrix(); } var left = -pos.e % 1, top = -pos.f % 1; if (left || top) { if (left) { this._left = (this._left + left) % 1; s.left = this._left + "px"; } if (top) { this._top = (this._top + top) % 1; s.top = this._top + "px"; } } }; /*\ * Paper.clear [ method ] ** * Clears the paper, i.e. removes all the elements. \*/ R.prototype.clear = function () { R.eve("raphael.clear", this); var c = this.canvas; while (c.firstChild) { c.removeChild(c.firstChild); } this.bottom = this.top = null; (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); c.appendChild(this.desc); c.appendChild(this.defs = $("defs")); }; /*\ * Paper.remove [ method ] ** * Removes the paper from the DOM. \*/ R.prototype.remove = function () { eve("raphael.remove", this); this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); for (var i in this) { this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } }; var setproto = R.st; for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { setproto[method] = (function (methodname) { return function () { var arg = arguments; return this.forEach(function (el) { el[methodname].apply(el, arg); }); }; })(method); } })); // ┌─────────────────────────────────────────────────────────────────────┐ \\ // │ Raphaël 2.1.4 - JavaScript Vector Library │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ // │ VML Module │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ // │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ // │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ // │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ // └─────────────────────────────────────────────────────────────────────┘ \\ (function (glob, factory) { if (typeof define === "function" && define.amd) { define("raphael.vml", ["raphael.core"], function(raphael) { return factory(raphael); }); } else if (typeof exports === "object") { factory(require("raphael")); } else { factory(glob.Raphael); } }(this, function(R) { if (R && !R.vml) { return; } var has = "hasOwnProperty", Str = String, toFloat = parseFloat, math = Math, round = math.round, mmax = math.max, mmin = math.min, abs = math.abs, fillString = "fill", separator = /[, ]+/, eve = R.eve, ms = " progid:DXImageTransform.Microsoft", S = " ", E = "", map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, bites = /([clmz]),?([^clmz]*)/gi, blurregexp = / progid:\S+Blur\([^\)]+\)/g, val = /-?[^,\s-]+/g, cssDot = "position:absolute;left:0;top:0;width:1px;height:1px;behavior:url(#default#VML)", zoom = 21600, pathTypes = {path: 1, rect: 1, image: 1}, ovalTypes = {circle: 1, ellipse: 1}, path2vml = function (path) { var total = /[ahqstv]/ig, command = R._pathToAbsolute; Str(path).match(total) && (command = R._path2curve); total = /[clmz]/g; if (command == R._pathToAbsolute && !Str(path).match(total)) { var res = Str(path).replace(bites, function (all, command, args) { var vals = [], isMove = command.toLowerCase() == "m", res = map[command]; args.replace(val, function (value) { if (isMove && vals.length == 2) { res += vals + map[command == "m" ? "l" : "L"]; vals = []; } vals.push(round(value * zoom)); }); return res + vals; }); return res; } var pa = command(path), p, r; res = []; for (var i = 0, ii = pa.length; i < ii; i++) { p = pa[i]; r = pa[i][0].toLowerCase(); r == "z" && (r = "x"); for (var j = 1, jj = p.length; j < jj; j++) { r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); } res.push(r); } return res.join(S); }, compensation = function (deg, dx, dy) { var m = R.matrix(); m.rotate(-deg, .5, .5); return { dx: m.x(dx, dy), dy: m.y(dx, dy) }; }, setCoords = function (p, sx, sy, dx, dy, deg) { var _ = p._, m = p.matrix, fillpos = _.fillpos, o = p.node, s = o.style, y = 1, flip = "", dxdy, kx = zoom / sx, ky = zoom / sy; s.visibility = "hidden"; if (!sx || !sy) { return; } o.coordsize = abs(kx) + S + abs(ky); s.rotation = deg * (sx * sy < 0 ? -1 : 1); if (deg) { var c = compensation(deg, dx, dy); dx = c.dx; dy = c.dy; } sx < 0 && (flip += "x"); sy < 0 && (flip += " y") && (y = -1); s.flip = flip; o.coordorigin = (dx * -kx) + S + (dy * -ky); if (fillpos || _.fillsize) { var fill = o.getElementsByTagName(fillString); fill = fill && fill[0]; o.removeChild(fill); if (fillpos) { c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); fill.position = c.dx * y + S + c.dy * y; } if (_.fillsize) { fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); } o.appendChild(fill); } s.visibility = "visible"; }; R.toString = function () { return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; }; var addArrow = function (o, value, isEnd) { var values = Str(value).toLowerCase().split("-"), se = isEnd ? "end" : "start", i = values.length, type = "classic", w = "medium", h = "medium"; while (i--) { switch (values[i]) { case "block": case "classic": case "oval": case "diamond": case "open": case "none": type = values[i]; break; case "wide": case "narrow": h = values[i]; break; case "long": case "short": w = values[i]; break; } } var stroke = o.node.getElementsByTagName("stroke")[0]; stroke[se + "arrow"] = type; stroke[se + "arrowlength"] = w; stroke[se + "arrowwidth"] = h; }, setFillAndStroke = function (o, params) { // o.paper.canvas.style.display = "none"; o.attrs = o.attrs || {}; var node = o.node, a = o.attrs, s = node.style, xy, newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r), isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), res = o; for (var par in params) if (params[has](par)) { a[par] = params[par]; } if (newpath) { a.path = R._getPath[o.type](o); o._.dirty = 1; } params.href && (node.href = params.href); params.title && (node.title = params.title); params.target && (node.target = params.target); params.cursor && (s.cursor = params.cursor); "blur" in params && o.blur(params.blur); if (params.path && o.type == "path" || newpath) { node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); o._.dirty = 1; if (o.type == "image") { o._.fillpos = [a.x, a.y]; o._.fillsize = [a.width, a.height]; setCoords(o, 1, 1, 0, 0, 0); } } "transform" in params && o.transform(params.transform); if (isOval) { var cx = +a.cx, cy = +a.cy, rx = +a.rx || +a.r || 0, ry = +a.ry || +a.r || 0; node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom)); o._.dirty = 1; } if ("clip-rect" in params) { var rect = Str(params["clip-rect"]).split(separator); if (rect.length == 4) { rect[2] = +rect[2] + (+rect[0]); rect[3] = +rect[3] + (+rect[1]); var div = node.clipRect || R._g.doc.createElement("div"), dstyle = div.style; dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); if (!node.clipRect) { dstyle.position = "absolute"; dstyle.top = 0; dstyle.left = 0; dstyle.width = o.paper.width + "px"; dstyle.height = o.paper.height + "px"; node.parentNode.insertBefore(div, node); div.appendChild(node); node.clipRect = div; } } if (!params["clip-rect"]) { node.clipRect && (node.clipRect.style.clip = "auto"); } } if (o.textpath) { var textpathStyle = o.textpath.style; params.font && (textpathStyle.font = params.font); params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); params["font-size"] && (textpathStyle.fontSize = params["font-size"]); params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); } if ("arrow-start" in params) { addArrow(res, params["arrow-start"]); } if ("arrow-end" in params) { addArrow(res, params["arrow-end"], 1); } if (params.opacity != null || params["stroke-width"] != null || params.fill != null || params.src != null || params.stroke != null || params["stroke-width"] != null || params["stroke-opacity"] != null || params["fill-opacity"] != null || params["stroke-dasharray"] != null || params["stroke-miterlimit"] != null || params["stroke-linejoin"] != null || params["stroke-linecap"] != null) { var fill = node.getElementsByTagName(fillString), newfill = false; fill = fill && fill[0]; !fill && (newfill = fill = createNode(fillString)); if (o.type == "image" && params.src) { fill.src = params.src; } params.fill && (fill.on = true); if (fill.on == null || params.fill == "none" || params.fill === null) { fill.on = false; } if (fill.on && params.fill) { var isURL = Str(params.fill).match(R._ISURL); if (isURL) { fill.parentNode == node && node.removeChild(fill); fill.rotate = true; fill.src = isURL[1]; fill.type = "tile"; var bbox = o.getBBox(1); fill.position = bbox.x + S + bbox.y; o._.fillpos = [bbox.x, bbox.y]; R._preload(isURL[1], function () { o._.fillsize = [this.offsetWidth, this.offsetHeight]; }); } else { fill.color = R.getRGB(params.fill).hex; fill.src = E; fill.type = "solid"; if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { a.fill = "none"; a.gradient = params.fill; fill.rotate = false; } } } if ("fill-opacity" in params || "opacity" in params) { var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); opacity = mmin(mmax(opacity, 0), 1); fill.opacity = opacity; if (fill.src) { fill.color = "none"; } } node.appendChild(fill); var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), newstroke = false; !stroke && (newstroke = stroke = createNode("stroke")); if ((params.stroke && params.stroke != "none") || params["stroke-width"] || params["stroke-opacity"] != null || params["stroke-dasharray"] || params["stroke-miterlimit"] || params["stroke-linejoin"] || params["stroke-linecap"]) { stroke.on = true; } (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); var strokeColor = R.getRGB(params.stroke); stroke.on && params.stroke && (stroke.color = strokeColor.hex); opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); var width = (toFloat(params["stroke-width"]) || 1) * .75; opacity = mmin(mmax(opacity, 0), 1); params["stroke-width"] == null && (width = a["stroke-width"]); params["stroke-width"] && (stroke.weight = width); width && width < 1 && (opacity *= width) && (stroke.weight = 1); stroke.opacity = opacity; params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); stroke.miterlimit = params["stroke-miterlimit"] || 8; params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); if ("stroke-dasharray" in params) { var dasharray = { "-": "shortdash", ".": "shortdot", "-.": "shortdashdot", "-..": "shortdashdotdot", ". ": "dot", "- ": "dash", "--": "longdash", "- .": "dashdot", "--.": "longdashdot", "--..": "longdashdotdot" }; stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; } newstroke && node.appendChild(stroke); } if (res.type == "text") { res.paper.canvas.style.display = E; var span = res.paper.span, m = 100, fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); s = span.style; a.font && (s.font = a.font); a["font-family"] && (s.fontFamily = a["font-family"]); a["font-weight"] && (s.fontWeight = a["font-weight"]); a["font-style"] && (s.fontStyle = a["font-style"]); fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10; s.fontSize = fontSize * m + "px"; res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "<").replace(/&/g, "&").replace(/\n/g, "<br>")); var brect = span.getBoundingClientRect(); res.W = a.w = (brect.right - brect.left) / m; res.H = a.h = (brect.bottom - brect.top) / m; // res.paper.canvas.style.display = "none"; res.X = a.x; res.Y = a.y + res.H / 2; ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1)); var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { res._.dirty = 1; break; } // text-anchor emulation switch (a["text-anchor"]) { case "start": res.textpath.style["v-text-align"] = "left"; res.bbx = res.W / 2; break; case "end": res.textpath.style["v-text-align"] = "right"; res.bbx = -res.W / 2; break; default: res.textpath.style["v-text-align"] = "center"; res.bbx = 0; break; } res.textpath.style["v-text-kern"] = true; } // res.paper.canvas.style.display = E; }, addGradientFill = function (o, gradient, fill) { o.attrs = o.attrs || {}; var attrs = o.attrs, pow = Math.pow, opacity, oindex, type = "linear", fxfy = ".5 .5"; o.attrs.gradient = gradient; gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { type = "radial"; if (fx && fy) { fx = toFloat(fx); fy = toFloat(fy); pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); fxfy = fx + S + fy; } return E; }); gradient = gradient.split(/\s*\-\s*/); if (type == "linear") { var angle = gradient.shift(); angle = -toFloat(angle); if (isNaN(angle)) { return null; } } var dots = R._parseDots(gradient); if (!dots) { return null; } o = o.shape || o.node; if (dots.length) { o.removeChild(fill); fill.on = true; fill.method = "none"; fill.color = dots[0].color; fill.color2 = dots[dots.length - 1].color; var clrs = []; for (var i = 0, ii = dots.length; i < ii; i++) { dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); } fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; if (type == "radial") { fill.type = "gradientTitle"; fill.focus = "100%"; fill.focussize = "0 0"; fill.focusposition = fxfy; fill.angle = 0; } else { // fill.rotate= true; fill.type = "gradient"; fill.angle = (270 - angle) % 360; } o.appendChild(fill); } return 1; }, Element = function (node, vml) { this[0] = this.node = node; node.raphael = true; this.id = R._oid++; node.raphaelid = this.id; this.X = 0; this.Y = 0; this.attrs = {}; this.paper = vml; this.matrix = R.matrix(); this._ = { transform: [], sx: 1, sy: 1, dx: 0, dy: 0, deg: 0, dirty: 1, dirtyT: 1 }; !vml.bottom && (vml.bottom = this); this.prev = vml.top; vml.top && (vml.top.next = this); vml.top = this; this.next = null; }; var elproto = R.el; Element.prototype = elproto; elproto.constructor = Element; elproto.transform = function (tstr) { if (tstr == null) { return this._.transform; } var vbs = this.paper._viewBoxShift, vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, oldt; if (vbs) { oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); } R._extractTransform(this, vbt + tstr); var matrix = this.matrix.clone(), skew = this.skew, o = this.node, split, isGrad = ~Str(this.attrs.fill).indexOf("-"), isPatt = !Str(this.attrs.fill).indexOf("url("); matrix.translate(1, 1); if (isPatt || isGrad || this.type == "image") { skew.matrix = "1 0 0 1"; skew.offset = "0 0"; split = matrix.split(); if ((isGrad && split.noRotation) || !split.isSimple) { o.style.filter = matrix.toFilter(); var bb = this.getBBox(), bbt = this.getBBox(1), dx = bb.x - bbt.x, dy = bb.y - bbt.y; o.coordorigin = (dx * -zoom) + S + (dy * -zoom); setCoords(this, 1, 1, dx, dy, 0); } else { o.style.filter = E; setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); } } else { o.style.filter = E; skew.matrix = Str(matrix); skew.offset = matrix.offset(); } if (oldt !== null) { // empty string value is true as well this._.transform = oldt; R._extractTransform(this, oldt); } return this; }; elproto.rotate = function (deg, cx, cy) { if (this.removed) { return this; } if (deg == null) { return; } deg = Str(deg).split(separator); if (deg.length - 1) { cx = toFloat(deg[1]); cy = toFloat(deg[2]); } deg = toFloat(deg[0]); (cy == null) && (cx = cy); if (cx == null || cy == null) { var bbox = this.getBBox(1); cx = bbox.x + bbox.width / 2; cy = bbox.y + bbox.height / 2; } this._.dirtyT = 1; this.transform(this._.transform.concat([["r", deg, cx, cy]])); return this; }; elproto.translate = function (dx, dy) { if (this.removed) { return this; } dx = Str(dx).split(separator); if (dx.length - 1) { dy = toFloat(dx[1]); } dx = toFloat(dx[0]) || 0; dy = +dy || 0; if (this._.bbox) { this._.bbox.x += dx; this._.bbox.y += dy; } this.transform(this._.transform.concat([["t", dx, dy]])); return this; }; elproto.scale = function (sx, sy, cx, cy) { if (this.removed) { return this; } sx = Str(sx).split(separator); if (sx.length - 1) { sy = toFloat(sx[1]); cx = toFloat(sx[2]); cy = toFloat(sx[3]); isNaN(cx) && (cx = null); isNaN(cy) && (cy = null); } sx = toFloat(sx[0]); (sy == null) && (sy = sx); (cy == null) && (cx = cy); if (cx == null || cy == null) { var bbox = this.getBBox(1); } cx = cx == null ? bbox.x + bbox.width / 2 : cx; cy = cy == null ? bbox.y + bbox.height / 2 : cy; this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); this._.dirtyT = 1; return this; }; elproto.hide = function () { !this.removed && (this.node.style.display = "none"); return this; }; elproto.show = function () { !this.removed && (this.node.style.display = E); return this; }; // Needed to fix the vml setViewBox issues elproto.auxGetBBox = R.el.getBBox; elproto.getBBox = function(){ var b = this.auxGetBBox(); if (this.paper && this.paper._viewBoxShift) { var c = {}; var z = 1/this.paper._viewBoxShift.scale; c.x = b.x - this.paper._viewBoxShift.dx; c.x *= z; c.y = b.y - this.paper._viewBoxShift.dy; c.y *= z; c.width = b.width * z; c.height = b.height * z; c.x2 = c.x + c.width; c.y2 = c.y + c.height; return c; } return b; }; elproto._getBBox = function () { if (this.removed) { return {}; } return { x: this.X + (this.bbx || 0) - this.W / 2, y: this.Y - this.H, width: this.W, height: this.H }; }; elproto.remove = function () { if (this.removed || !this.node.parentNode) { return; } this.paper.__set__ && this.paper.__set__.exclude(this); R.eve.unbind("raphael.*.*." + this.id); R._tear(this, this.paper); this.node.parentNode.removeChild(this.node); this.shape && this.shape.parentNode.removeChild(this.shape); for (var i in this) { this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } this.removed = true; }; elproto.attr = function (name, value) { if (this.removed) { return this; } if (name == null) { var res = {}; for (var a in this.attrs) if (this.attrs[has](a)) { res[a] = this.attrs[a]; } res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; res.transform = this._.transform; return res; } if (value == null && R.is(name, "string")) { if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { return this.attrs.gradient; } var names = name.split(separator), out = {}; for (var i = 0, ii = names.length; i < ii; i++) { name = names[i]; if (name in this.attrs) { out[name] = this.attrs[name]; } else if (R.is(this.paper.customAttributes[name], "function")) { out[name] = this.paper.customAttributes[name].def; } else { out[name] = R._availableAttrs[name]; } } return ii - 1 ? out : out[names[0]]; } if (this.attrs && value == null && R.is(name, "array")) { out = {}; for (i = 0, ii = name.length; i < ii; i++) { out[name[i]] = this.attr(name[i]); } return out; } var params; if (value != null) { params = {}; params[name] = value; } value == null && R.is(name, "object") && (params = name); for (var key in params) { eve("raphael.attr." + key + "." + this.id, this, params[key]); } if (params) { for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); this.attrs[key] = params[key]; for (var subkey in par) if (par[has](subkey)) { params[subkey] = par[subkey]; } } // this.paper.canvas.style.display = "none"; if (params.text && this.type == "text") { this.textpath.string = params.text; } setFillAndStroke(this, params); // this.paper.canvas.style.display = E; } return this; }; elproto.toFront = function () { !this.removed && this.node.parentNode.appendChild(this.node); this.paper && this.paper.top != this && R._tofront(this, this.paper); return this; }; elproto.toBack = function () { if (this.removed) { return this; } if (this.node.parentNode.firstChild != this.node) { this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); R._toback(this, this.paper); } return this; }; elproto.insertAfter = function (element) { if (this.removed) { return this; } if (element.constructor == R.st.constructor) { element = element[element.length - 1]; } if (element.node.nextSibling) { element.node.parentNode.insertBefore(this.node, element.node.nextSibling); } else { element.node.parentNode.appendChild(this.node); } R._insertafter(this, element, this.paper); return this; }; elproto.insertBefore = function (element) { if (this.removed) { return this; } if (element.constructor == R.st.constructor) { element = element[0]; } element.node.parentNode.insertBefore(this.node, element.node); R._insertbefore(this, element, this.paper); return this; }; elproto.blur = function (size) { var s = this.node.runtimeStyle, f = s.filter; f = f.replace(blurregexp, E); if (+size !== 0) { this.attrs.blur = size; s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); } else { s.filter = f; s.margin = 0; delete this.attrs.blur; } return this; }; R._engine.path = function (pathString, vml) { var el = createNode("shape"); el.style.cssText = cssDot; el.coordsize = zoom + S + zoom; el.coordorigin = vml.coordorigin; var p = new Element(el, vml), attr = {fill: "none", stroke: "#000"}; pathString && (attr.path = pathString); p.type = "path"; p.path = []; p.Path = E; setFillAndStroke(p, attr); vml.canvas.appendChild(el); var skew = createNode("skew"); skew.on = true; el.appendChild(skew); p.skew = skew; p.transform(E); return p; }; R._engine.rect = function (vml, x, y, w, h, r) { var path = R._rectPath(x, y, w, h, r), res = vml.path(path), a = res.attrs; res.X = a.x = x; res.Y = a.y = y; res.W = a.width = w; res.H = a.height = h; a.r = r; a.path = path; res.type = "rect"; return res; }; R._engine.ellipse = function (vml, x, y, rx, ry) { var res = vml.path(), a = res.attrs; res.X = x - rx; res.Y = y - ry; res.W = rx * 2; res.H = ry * 2; res.type = "ellipse"; setFillAndStroke(res, { cx: x, cy: y, rx: rx, ry: ry }); return res; }; R._engine.circle = function (vml, x, y, r) { var res = vml.path(), a = res.attrs; res.X = x - r; res.Y = y - r; res.W = res.H = r * 2; res.type = "circle"; setFillAndStroke(res, { cx: x, cy: y, r: r }); return res; }; R._engine.image = function (vml, src, x, y, w, h) { var path = R._rectPath(x, y, w, h), res = vml.path(path).attr({stroke: "none"}), a = res.attrs, node = res.node, fill = node.getElementsByTagName(fillString)[0]; a.src = src; res.X = a.x = x; res.Y = a.y = y; res.W = a.width = w; res.H = a.height = h; a.path = path; res.type = "image"; fill.parentNode == node && node.removeChild(fill); fill.rotate = true; fill.src = src; fill.type = "tile"; res._.fillpos = [x, y]; res._.fillsize = [w, h]; node.appendChild(fill); setCoords(res, 1, 1, 0, 0, 0); return res; }; R._engine.text = function (vml, x, y, text) { var el = createNode("shape"), path = createNode("path"), o = createNode("textpath"); x = x || 0; y = y || 0; text = text || ""; path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); path.textpathok = true; o.string = Str(text); o.on = true; el.style.cssText = cssDot; el.coordsize = zoom + S + zoom; el.coordorigin = "0 0"; var p = new Element(el, vml), attr = { fill: "#000", stroke: "none", font: R._availableAttrs.font, text: text }; p.shape = el; p.path = path; p.textpath = o; p.type = "text"; p.attrs.text = Str(text); p.attrs.x = x; p.attrs.y = y; p.attrs.w = 1; p.attrs.h = 1; setFillAndStroke(p, attr); el.appendChild(o); el.appendChild(path); vml.canvas.appendChild(el); var skew = createNode("skew"); skew.on = true; el.appendChild(skew); p.skew = skew; p.transform(E); return p; }; R._engine.setSize = function (width, height) { var cs = this.canvas.style; this.width = width; this.height = height; width == +width && (width += "px"); height == +height && (height += "px"); cs.width = width; cs.height = height; cs.clip = "rect(0 " + width + " " + height + " 0)"; if (this._viewBox) { R._engine.setViewBox.apply(this, this._viewBox); } return this; }; R._engine.setViewBox = function (x, y, w, h, fit) { R.eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]); var paperSize = this.getSize(), width = paperSize.width, height = paperSize.height, H, W; if (fit) { H = height / h; W = width / w; if (w * H < width) { x -= (width - w * H) / 2 / H; } if (h * W < height) { y -= (height - h * W) / 2 / W; } } this._viewBox = [x, y, w, h, !!fit]; this._viewBoxShift = { dx: -x, dy: -y, scale: paperSize }; this.forEach(function (el) { el.transform("..."); }); return this; }; var createNode; R._engine.initWin = function (win) { var doc = win.document; if (doc.styleSheets.length < 31) { doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); } else { // no more room, add to the existing one // http://msdn.microsoft.com/en-us/library/ms531194%28VS.85%29.aspx doc.styleSheets[0].addRule(".rvml", "behavior:url(#default#VML)"); } try { !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); createNode = function (tagName) { return doc.createElement('<rvml:' + tagName + ' class="rvml">'); }; } catch (e) { createNode = function (tagName) { return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); }; } }; R._engine.initWin(R._g.win); R._engine.create = function () { var con = R._getContainer.apply(0, arguments), container = con.container, height = con.height, s, width = con.width, x = con.x, y = con.y; if (!container) { throw new Error("VML container not found."); } var res = new R._Paper, c = res.canvas = R._g.doc.createElement("div"), cs = c.style; x = x || 0; y = y || 0; width = width || 512; height = height || 342; res.width = width; res.height = height; width == +width && (width += "px"); height == +height && (height += "px"); res.coordsize = zoom * 1e3 + S + zoom * 1e3; res.coordorigin = "0 0"; res.span = R._g.doc.createElement("span"); res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; c.appendChild(res.span); cs.cssText = R.format("top:0;left:0;display:inline-block;position:absolute;clip:rect(0 {0} {1} 0);", width, height); if (container == 1) { R._g.doc.body.appendChild(c); cs.left = x + "px"; cs.top = y + "px"; cs.position = "absolute"; } else { if (container.firstChild) { container.insertBefore(c, container.firstChild); } else { container.appendChild(c); } } res.renderfix = function () {}; return res; }; R.prototype.clear = function () { R.eve("raphael.clear", this); this.canvas.innerHTML = E; this.span = R._g.doc.createElement("span"); this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; this.canvas.appendChild(this.span); this.bottom = this.top = null; }; R.prototype.remove = function () { R.eve("raphael.remove", this); this.canvas.parentNode.removeChild(this.canvas); for (var i in this) { this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } return true; }; var setproto = R.st; for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { setproto[method] = (function (methodname) { return function () { var arg = arguments; return this.forEach(function (el) { el[methodname].apply(el, arg); }); }; })(method); } })); // ┌────────────────────────────────────────────────────────────────────┐ \\ // │ Raphaël 2.1.4 - JavaScript Vector Library │ \\ // ├────────────────────────────────────────────────────────────────────┤ \\ // │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ // │ Copyright © 2008-2012 Sencha Labs (http://sencha.com) │ \\ // ├────────────────────────────────────────────────────────────────────┤ \\ // │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\ // └────────────────────────────────────────────────────────────────────┘ \\ (function (glob, factory) { if (typeof define === "function" && define.amd) { define("raphael", ["raphael.core", "raphael.svg", "raphael.vml"], function(Raphael) { return factory(Raphael); }); } else if (typeof exports === "object") { var raphael = require("raphael.core"); require("raphael.svg"); require("raphael.vml"); module.exports = factory(raphael); } else { //glob.Raphael = factory(glob.Raphael); } }(this, function (Raphael) { return Raphael.ninja(); }));/** * svg绘图 * * Created by GUY on 2015/12/3. * @class BI.Svg * @extends BI.Widget */ BI.Svg = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Svg.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-svg" }) }, _init: function () { BI.Svg.superclass._init.apply(this, arguments); this.paper = Raphael(this.element[0]); this.element.css("overflow", "hidden"); $(this.paper.canvas).width("100%").height("100%").css({"left": "0", "top": "0"}).appendTo(this.element); this.top = this.paper.top; this.bottom = this.paper.bottom; this.customAttributes = this.paper.customAttributes; this.ca = this.paper.ca; this.raphael = this.paper.raphael; }, add: function () { return this.paper.add.apply(this.paper, arguments); }, path: function () { return this.paper.path.apply(this.paper, arguments); }, image: function () { return this.paper.image.apply(this.paper, arguments); }, rect: function () { return this.paper.rect.apply(this.paper, arguments); }, circle: function () { return this.paper.circle.apply(this.paper, arguments); }, ellipse: function () { return this.paper.ellipse.apply(this.paper, arguments); }, text: function () { return this.paper.text.apply(this.paper, arguments); }, print: function () { return this.paper.print.apply(this.paper, arguments); }, setStart: function () { return this.paper.setStart.apply(this.paper, arguments); }, setFinish: function () { return this.paper.setFinish.apply(this.paper, arguments); }, setSize: function () { return this.paper.setSize.apply(this.paper, arguments); }, setViewBox: function () { return this.paper.setViewBox.apply(this.paper, arguments); }, getById: function () { return this.paper.getById.apply(this.paper, arguments); }, getElementByPoint: function () { return this.paper.getElementByPoint.apply(this.paper, arguments); }, getElementsByPoint: function () { return this.paper.getElementsByPoint.apply(this.paper, arguments); }, getFont: function () { return this.paper.getFont.apply(this.paper, arguments); }, set: function () { return this.paper.set.apply(this.paper, arguments); }, remove: function () { return this.paper.remove.apply(this.paper, arguments); }, clear: function () { return this.paper.clear.apply(this.paper, arguments); } }); BI.shortcut("bi.svg", BI.Svg);/** * * 原生表格滚动条,为了IE8的兼容 * * Created by GUY on 2016/1/12. * @class BI.NativeTableScrollbar * @extends BI.Widget */ BI.NativeTableScrollbar = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.NativeTableScrollbar.superclass._defaultConfig.apply(this, arguments), { attributes: { tabIndex: 0 }, contentSize: 0, defaultPosition: 0, position: 0, size: 0 }) }, render: function () { var self = this, o = this.options; //把滚动台size改掉 this.element.width(36); var throttle = BI.throttle(function () { self.fireEvent(BI.NativeTableScrollbar.EVENT_SCROLL, self.element.scrollTop()); }, 150, {leading: false}); this.element.scroll(function () { throttle(); }); return { type: "bi.default", scrolly: true, items: [{ type: "bi.layout", width: 1, ref: function (_ref) { self.inner = _ref; } }] } }, mounted: function () { this._populate(); }, _populate: function () { var self = this, o = this.options; if (o.size < 1 || o.contentSize <= o.size) { this.setVisible(false); return; } this.setVisible(true); try { this.element.scrollTop(o.position); } catch (e) { } this.inner.element.height(o.contentSize); }, setContentSize: function (contentSize) { this.options.contentSize = contentSize; }, setPosition: function (position) { this.options.position = position; }, setSize: function (size) { this.setHeight(size); this.options.size = size; }, populate: function () { this._populate(); } }); BI.NativeTableScrollbar.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut("bi.native_table_scrollbar", BI.NativeTableScrollbar); BI.NativeTableHorizontalScrollbar = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.NativeTableHorizontalScrollbar.superclass._defaultConfig.apply(this, arguments), { attributes: { tabIndex: 0 }, contentSize: 0, position: 0, size: 0 }) }, render: function () { var self = this, o = this.options; //把滚动台size改掉 this.element.height(36); var throttle = BI.throttle(function () { self.fireEvent(BI.NativeTableScrollbar.EVENT_SCROLL, self.element.scrollLeft()); }, 150, {leading: false}); this.element.scroll(function () { throttle(); }); return { type: "bi.default", scrollx: true, items: [{ type: "bi.layout", height: 1, ref: function (_ref) { self.inner = _ref; } }] } }, setContentSize: function (contentSize) { this.options.contentSize = contentSize; }, setPosition: function (position) { this.options.position = position; }, setSize: function (size) { this.setWidth(size); this.options.size = size; }, _populate: function () { var self = this, o = this.options; if (o.size < 1 || o.contentSize <= o.size) { this.setVisible(false); return; } this.setVisible(true); try { this.element.scrollLeft(o.position); } catch (e) { } this.inner.element.width(o.contentSize); }, populate: function () { this._populate(); } }); BI.NativeTableHorizontalScrollbar.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut("bi.native_table_horizontal_scrollbar", BI.NativeTableHorizontalScrollbar);/** * * 表格 * * Created by GUY on 2015/9/22. * @class BI.TableCell * @extends BI.Single */ BI.TableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.TableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-table-cell", textAlign: "left", text: "" }) }, _init: function () { BI.TableCell.superclass._init.apply(this, arguments); BI.createWidget({ type: "bi.label", element: this, whiteSpace: "nowrap", textAlign: this.options.textAlign, height: this.options.height, text: this.options.text, value: this.options.value, lgap: 5 }) } }); BI.shortcut("bi.table_cell", BI.TableCell);/** * * 表格单元格 * * Created by GUY on 2016/1/12. * @class BI.CollectionTableCell * @extends BI.Widget */ BI.CollectionTableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.CollectionTableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-collection-table-cell bi-border-right bi-border-bottom", width: 0, height: 0, _left: 0, _top: 0, cell: {} }) }, _init: function () { BI.CollectionTableCell.superclass._init.apply(this, arguments); var o = this.options; this.cell = BI.createWidget(BI.extend({ type: "bi.label" }, o.cell, { cls: (o.cell.cls || "") + " collection-table-cell-wrapper", width: o.width - (o._left === 0 ? 1 : 0) - 1, height: o.height - (o._top === 0 ? 1 : 0) - 1 })); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.cell, left: 0, right: 0, top: 0, bottom: 0 }] }); }, setWidth: function (width) { BI.CollectionTableCell.superclass.setWidth.apply(this, arguments); var o = this.options; this.cell.setWidth(o.width - (o._left === 0 ? 1 : 0) - 1); }, setHeight: function (height) { BI.CollectionTableCell.superclass.setHeight.apply(this, arguments); var o = this.options; this.cell.setHeight(o.height - (o._top === 0 ? 1 : 0) - 1); } }); BI.shortcut("bi.collection_table_cell", BI.CollectionTableCell);/** * CollectionTable * * Created by GUY on 2016/1/12. * @class BI.CollectionTable * @extends BI.Widget */ BI.CollectionTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.CollectionTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-collection-table", headerRowSize: 25, rowSize: 25, columnSize: [], isNeedFreeze: false, freezeCols: [], isNeedMerge: false, mergeCols: [], mergeRule: BI.emptyFn, header: [], items: [], regionColumnSize: [] }); }, render: function () { var self = this, o = this.options; this._width = 0; this._height = 0; this._scrollBarSize = BI.DOM.getScrollWidth(); this.topLeftCollection = BI.createWidget({ type: "bi.collection_view", cellSizeAndPositionGetter: function (index) { return self.topLeftItems[index]; } }); this.topLeftCollection.on(BI.CollectionView.EVENT_SCROLL, function (scroll) { self.bottomLeftCollection.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.topRightCollection = BI.createWidget({ type: "bi.collection_view", cellSizeAndPositionGetter: function (index) { return self.topRightItems[index]; } }); this.topRightCollection.on(BI.CollectionView.EVENT_SCROLL, function (scroll) { self.bottomRightCollection.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.bottomLeftCollection = BI.createWidget({ type: "bi.collection_view", cellSizeAndPositionGetter: function (index) { return self.bottomLeftItems[index]; } }); this.bottomLeftCollection.on(BI.CollectionView.EVENT_SCROLL, function (scroll) { self.bottomRightCollection.setScrollTop(scroll.scrollTop); self.topLeftCollection.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.bottomRightCollection = BI.createWidget({ type: "bi.collection_view", cellSizeAndPositionGetter: function (index) { return self.bottomRightItems[index]; } }); this.bottomRightCollection.on(BI.CollectionView.EVENT_SCROLL, function (scroll) { self.bottomLeftCollection.setScrollTop(scroll.scrollTop); self.topRightCollection.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.topLeft = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.topLeftCollection] }); this.topRight = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.topRightCollection] }); this.bottomLeft = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.bottomLeftCollection] }); this.bottomRight = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.bottomRightCollection] }); this.contextLayout = BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.topLeft, top: 0, left: 0 }, { el: this.topRight, top: 0 }, { el: this.bottomLeft, left: 0 }, { el: this.bottomRight }] }); this.topScrollbar = BI.createWidget({ type: "bi.grid_table_scrollbar", width: BI.GridTableScrollbar.SIZE }); this.topScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollTop) { self.bottomLeftCollection.setScrollTop(scrollTop); self.bottomRightCollection.setScrollTop(scrollTop); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.leftScrollbar = BI.createWidget({ type: "bi.grid_table_horizontal_scrollbar", height: BI.GridTableScrollbar.SIZE }); this.leftScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollLeft) { self.topLeftCollection.setScrollLeft(scrollLeft); self.bottomLeftCollection.setScrollLeft(scrollLeft); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.rightScrollbar = BI.createWidget({ type: "bi.grid_table_horizontal_scrollbar", height: BI.GridTableScrollbar.SIZE }); this.rightScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollLeft) { self.topRightCollection.setScrollLeft(scrollLeft); self.bottomRightCollection.setScrollLeft(scrollLeft); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.scrollBarLayout = BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.topScrollbar, right: 0, top: 0 }, { el: this.leftScrollbar, left: 0 }, { el: this.rightScrollbar, }] }); this._width = o.width - BI.GridTableScrollbar.SIZE; this._height = o.height - BI.GridTableScrollbar.SIZE; }, mounted: function () { var o = this.options; if (o.items.length > 0 || o.header.length > 0) { this._digest(); this._populate(); } }, _getFreezeColLength: function () { return this.options.isNeedFreeze ? this.options.freezeCols.length : 0; }, _getFreezeHeaderHeight: function () { var o = this.options; if (o.header.length * o.headerRowSize >= this._height) { return 0; } return o.header.length * o.headerRowSize; }, _getActualItems: function () { var o = this.options; if (o.header.length * o.headerRowSize >= this._height) { return o.header.concat(o.items); } return o.items; }, _populateScrollbar: function () { var o = this.options; var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = []; BI.each(o.columnSize, function (i, size) { if (o.isNeedFreeze === true && o.freezeCols.contains(i)) { totalLeftColumnSize += size; } else { totalRightColumnSize += size; } totalColumnSize += size; if (i === 0) { summaryColumnSizeArray[i] = size; } else { summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size; } }); this.topScrollbar.setContentSize(this._getActualItems().length * o.rowSize); this.topScrollbar.setSize(this._height - this._getFreezeHeaderHeight()); this.topScrollbar.setPosition(this.bottomRightCollection.getScrollTop()); this.topScrollbar.populate(); this.leftScrollbar.setContentSize(totalLeftColumnSize); this.leftScrollbar.setSize(regionSize); this.leftScrollbar.setPosition(this.bottomLeftCollection.getScrollLeft()); this.leftScrollbar.populate(); this.rightScrollbar.setContentSize(totalRightColumnSize); this.rightScrollbar.setSize(this._width - regionSize); this.rightScrollbar.setPosition(this.bottomRightCollection.getScrollLeft()); this.rightScrollbar.populate(); var items = this.scrollBarLayout.attr("items"); items[0].top = this._getFreezeHeaderHeight(); items[1].top = this._height; items[2].top = this._height; items[2].left = regionSize; this.scrollBarLayout.attr("items", items); this.scrollBarLayout.resize(); }, _populateTable: function () { var self = this, o = this.options; var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = []; BI.each(o.columnSize, function (i, size) { if (o.isNeedFreeze === true && o.freezeCols.contains(i)) { totalLeftColumnSize += size; } else { totalRightColumnSize += size; } totalColumnSize += size; if (i === 0) { summaryColumnSizeArray[i] = size; } else { summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size; } }); var otlw = regionSize; var otlh = this._getFreezeHeaderHeight(); var otrw = this._width - regionSize; var otrh = this._getFreezeHeaderHeight(); var oblw = regionSize; var oblh = this._height - otlh; var obrw = this._width - regionSize; var obrh = this._height - otrh; var tlw = otlw + this._scrollBarSize; var tlh = otlh + this._scrollBarSize; var trw = otrw + this._scrollBarSize; var trh = otrh + this._scrollBarSize; var blw = oblw + this._scrollBarSize; var blh = oblh + this._scrollBarSize; var brw = obrw + this._scrollBarSize; var brh = obrh + this._scrollBarSize; var digest = function (el) { el.element.css({ overflow: "scroll", overflowX: "scroll", overflowY: "scroll" }) }; this.topLeft.setWidth(otlw); this.topLeft.setHeight(otlh); this.topRight.setWidth(otrw); this.topRight.setHeight(otrh); this.bottomLeft.setWidth(oblw); this.bottomLeft.setHeight(oblh); this.bottomRight.setWidth(obrw); this.bottomRight.setHeight(obrh); this.topLeftCollection.setWidth(tlw); this.topLeftCollection.setHeight(tlh); this.topRightCollection.setWidth(trw); this.topRightCollection.setHeight(trh); this.bottomLeftCollection.setWidth(blw); this.bottomLeftCollection.setHeight(blh); this.bottomRightCollection.setWidth(brw); this.bottomRightCollection.setHeight(brh); digest(this.topLeftCollection); digest(this.topRightCollection); digest(this.bottomLeftCollection); digest(this.bottomRightCollection); var items = this.contextLayout.attr("items"); items[1].left = regionSize; items[2].top = this._getFreezeHeaderHeight(); items[3].left = regionSize; items[3].top = this._getFreezeHeaderHeight(); this.contextLayout.attr("items", items); this.contextLayout.resize(); var leftHeader = [], rightHeader = [], leftItems = [], rightItems = []; var run = function (positions, items, rendered) { BI.each(positions, function (i, item) { var cell = { type: "bi.collection_table_cell", cell: items[item.row][item.col] }; rendered.push(cell); }); }; run(this.topLeftItems, o.header, leftHeader); run(this.topRightItems, o.header, rightHeader); run(this.bottomLeftItems, this._getActualItems(), leftItems); run(this.bottomRightItems, this._getActualItems(), rightItems); this.topLeftCollection._populate(leftHeader); this.topRightCollection._populate(rightHeader); this.bottomLeftCollection._populate(leftItems); this.bottomRightCollection._populate(rightItems); }, _digest: function () { var o = this.options; var freezeColLength = this._getFreezeColLength(); //如果表头位置不够,取消表头冻结 if (this._getFreezeHeaderHeight() <= 0) { this.topLeftItems = []; this.topRightItems = []; this.bottomLeftItems = this._serialize(this._getActualItems(), 0, freezeColLength, o.rowSize, o.columnSize, o.mergeCols, BI.range(o.header.length)); this.bottomRightItems = this._serialize(this._getActualItems(), freezeColLength, o.columnSize.length, o.rowSize, o.columnSize, o.mergeCols, BI.range(o.header.length)); } else { this.topLeftItems = this._serialize(o.header, 0, freezeColLength, o.headerRowSize, o.columnSize, o.mergeCols); this.topRightItems = this._serialize(o.header, freezeColLength, o.columnSize.length, o.headerRowSize, o.columnSize, true); this.bottomLeftItems = this._serialize(o.items, 0, freezeColLength, o.rowSize, o.columnSize, o.mergeCols); this.bottomRightItems = this._serialize(o.items, freezeColLength, o.columnSize.length, o.rowSize, o.columnSize, o.mergeCols); } }, _serialize: function (items, startCol, endCol, rowHeight, columnSize, mergeCols, mergeRows) { mergeCols = mergeCols || []; mergeRows = mergeRows || []; var self = this, o = this.options; var result = [], cache = {}, preCol = {}, preRow = {}, map = {}; var summaryColumnSize = []; for (var i = startCol; i < endCol; i++) { if (i === startCol) { summaryColumnSize[i] = columnSize[i]; } else { summaryColumnSize[i] = summaryColumnSize[i - 1] + columnSize[i]; } } var mergeRow = function (i, j) { preCol[j]._height += rowHeight; preCol[j].__mergeRows.push(i); }; var mergeCol = function (i, j) { preRow[i]._width += columnSize[j]; preRow[i].__mergeCols.push(j); }; var createOneEl = function (r, c) { var width = columnSize[c]; var height = rowHeight; map[r][c]._row = r; map[r][c]._col = c; map[r][c]._width = width; map[r][c]._height = height; preCol[c] = map[r][c]; preCol[c].__mergeRows = [r]; preRow[r] = map[r][c]; preRow[r].__mergeCols = [c]; result.push({ x: summaryColumnSize[c] - columnSize[c], y: +r * rowHeight, item: map[r][c] }); }; BI.each(items, function (i, cols) { for (var j = startCol; j < endCol; j++) { if (!cache[i]) { cache[i] = {}; } if (!map[i]) { map[i] = {}; } cache[i][j] = cols[j]; map[i][j] = {}; if (mergeCols === true || mergeCols.indexOf(j) > -1 || mergeRows === true || mergeRows.indexOf(i) > -1) { if (i === 0 && j === startCol) { createOneEl(0, startCol); } else if (j === startCol && i > 0) { var isNeedMergeRow = o.mergeRule(cache[i][j], cache[i - 1][j]); if (isNeedMergeRow === true) { mergeRow(i, j); preRow[i] = preCol[j]; } else { createOneEl(i, j); } } else if (i === 0 && j > startCol) { var isNeedMergeCol = o.mergeRule(cache[i][j], cache[i][j - 1]); if (isNeedMergeCol === true) { mergeCol(i, j); preCol[j] = preRow[i]; } else { createOneEl(i, j); } } else { var isNeedMergeRow = o.mergeRule(cache[i][j], cache[i - 1][j]); var isNeedMergeCol = o.mergeRule(cache[i][j], cache[i][j - 1]); if (isNeedMergeCol && isNeedMergeRow) { continue; //mergeRow(i, j);//优先合并列 } if (isNeedMergeCol) { mergeCol(i, j); } if (isNeedMergeRow) { mergeRow(i, j); } if (!isNeedMergeCol && !isNeedMergeRow) { createOneEl(i, j); } } } else { createOneEl(i, j); } } }); return BI.map(result, function (i, item) { return { x: item.x, y: item.y, row: item.item._row, col: item.item._col, width: item.item._width, height: item.item._height } }); }, _populate: function () { if (this._width <= 0 || this._height <= 0) { return; } if (this._isNeedDigest === true) { this._digest(); } this._isNeedDigest = false; this._populateTable(); this._populateScrollbar(); }, getRegionSize: function () { var o = this.options; var regionSize = o.regionColumnSize[0] || 0; if (o.isNeedFreeze === false || o.freezeCols.length === 0) { return 0; } if (!regionSize) { BI.each(o.freezeCols, function (i, col) { regionSize += o.columnSize[col]; }); } return regionSize; }, setVerticalScroll: function (scrollTop) { this.bottomLeftCollection.setScrollTop(scrollTop); this.bottomRightCollection.setScrollTop(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.topLeftCollection.setScrollLeft(scrollLeft); this.bottomLeftCollection.setScrollLeft(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.topRightCollection.setScrollLeft(scrollLeft); this.bottomRightCollection.setScrollLeft(scrollLeft); }, getVerticalScroll: function () { return this.bottomRightCollection.getScrollTop(); }, getLeftHorizontalScroll: function () { return this.bottomLeftCollection.getScrollLeft(); }, getRightHorizontalScroll: function () { return this.bottomRightCollection.getScrollLeft(); }, setWidth: function (width) { BI.CollectionTable.superclass.setWidth.apply(this, arguments); this._width = this.options.width - BI.GridTableScrollbar.SIZE; }, setHeight: function (height) { BI.CollectionTable.superclass.setHeight.apply(this, arguments); this._height = this.options.height - BI.GridTableScrollbar.SIZE; }, setColumnSize: function (columnSize) { this._isNeedDigest = true; this.options.columnSize = columnSize; }, setRegionColumnSize: function (regionColumnSize) { this._isNeedDigest = true; this.options.regionColumnSize = regionColumnSize; }, getColumnSize: function () { return this.options.columnSize; }, getRegionColumnSize: function () { return this.options.regionColumnSize; }, populate: function (items, header) { if (items && items !== this.options.items) { this._isNeedDigest = true; this.options.items = items; this._restore(); } if (header && header !== this.options.header) { this._isNeedDigest = true; this.options.header = header; this._restore(); } this._populate(); }, _restore: function () { this.topLeftCollection.restore(); this.topRightCollection.restore(); this.bottomLeftCollection.restore(); this.bottomRightCollection.restore(); }, restore: function () { this._restore(); } }); BI.shortcut('bi.collection_table', BI.CollectionTable);/** * QuickCollectionTable * * Created by GUY on 2016/1/12. * @class BI.QuickCollectionTable * @extends BI.CollectionTable */ BI.QuickCollectionTable = BI.inherit(BI.CollectionTable, { _defaultConfig: function () { return BI.extend(BI.QuickCollectionTable.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-quick-collection-table" }); }, render: function () { BI.QuickCollectionTable.superclass.render.apply(this, arguments); var self = this, o = this.options; this.topLeftCollection.setOverflowX(false); this.topLeftCollection.setOverflowY(false); this.topRightCollection.setOverflowX(false); this.topRightCollection.setOverflowY(false); this.bottomLeftCollection.setOverflowX(false); this.bottomLeftCollection.setOverflowY(false); this.bottomRightCollection.setOverflowX(false); this.bottomRightCollection.setOverflowY(false); }, mounted: function () { BI.QuickCollectionTable.superclass.mounted.apply(this, arguments); var self = this; this._topLeftWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelLeft, this), BI.bind(this._shouldHandleLeftX, this), BI.bind(this._shouldHandleY, this) ); this._topRightWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelRight, this), BI.bind(this._shouldHandleRightX, this), BI.bind(this._shouldHandleY, this) ); this._bottomLeftWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelLeft, this), BI.bind(this._shouldHandleLeftX, this), BI.bind(this._shouldHandleY, this) ); this._bottomRightWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelRight, this), BI.bind(this._shouldHandleRightX, this), BI.bind(this._shouldHandleY, this) ); this.topLeftCollection.element.mousewheel(function (e) { self._topLeftWheelHandler.onWheel(e.originalEvent); }); this.topRightCollection.element.mousewheel(function (e) { self._topRightWheelHandler.onWheel(e.originalEvent); }); this.bottomLeftCollection.element.mousewheel(function (e) { self._bottomLeftWheelHandler.onWheel(e.originalEvent); }); this.bottomRightCollection.element.mousewheel(function (e) { self._bottomRightWheelHandler.onWheel(e.originalEvent); }); }, _shouldHandleLeftX: function (delta) { if (delta > 0) { return this.bottomLeftCollection.getScrollLeft() < this.bottomLeftCollection.getMaxScrollLeft(); } else { return this.bottomLeftCollection.getScrollLeft() > 0; } }, _shouldHandleRightX: function (delta) { if (delta > 0) { return this.bottomRightCollection.getScrollLeft() < this.bottomRightCollection.getMaxScrollLeft(); } else { return this.bottomRightCollection.getScrollLeft() > 0; } }, _shouldHandleY: function (delta) { if (delta > 0) { return this.bottomRightCollection.getScrollTop() < this.bottomRightCollection.getMaxScrollTop(); } else { return this.bottomRightCollection.getScrollTop() > 0; } }, _onWheelLeft: function (deltaX, deltaY) { var self = this; var scrollTop = this.bottomLeftCollection.getScrollTop(); var scrollLeft = this.bottomLeftCollection.getScrollLeft(); scrollTop += deltaY; scrollLeft += deltaX; this.bottomLeftCollection.setScrollTop(scrollTop); this.bottomRightCollection.setScrollTop(scrollTop); this.topLeftCollection.setScrollLeft(scrollLeft); this.bottomLeftCollection.setScrollLeft(scrollLeft); self._populateScrollbar(); this.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }, _onWheelRight: function (deltaX, deltaY) { var self = this; var scrollTop = this.bottomRightCollection.getScrollTop(); var scrollLeft = this.bottomRightCollection.getScrollLeft(); scrollTop += deltaY; scrollLeft += deltaX; this.bottomLeftCollection.setScrollTop(scrollTop); this.bottomRightCollection.setScrollTop(scrollTop); this.topRightCollection.setScrollLeft(scrollLeft); this.bottomRightCollection.setScrollLeft(scrollLeft); self._populateScrollbar(); this.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }, _populateTable: function () { var self = this, o = this.options; var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = [] BI.each(o.columnSize, function (i, size) { if (o.isNeedFreeze === true && o.freezeCols.contains(i)) { totalLeftColumnSize += size; } else { totalRightColumnSize += size; } totalColumnSize += size; if (i === 0) { summaryColumnSizeArray[i] = size; } else { summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size; } }); var otlw = regionSize; var otlh = this._getFreezeHeaderHeight(); var otrw = this._width - regionSize; var otrh = this._getFreezeHeaderHeight(); var oblw = regionSize; var oblh = this._height - otlh; var obrw = this._width - regionSize; var obrh = this._height - otrh; this.topLeft.setWidth(otlw); this.topLeft.setHeight(otlh); this.topRight.setWidth(otrw); this.topRight.setHeight(otrh); this.bottomLeft.setWidth(oblw); this.bottomLeft.setHeight(oblh); this.bottomRight.setWidth(obrw); this.bottomRight.setHeight(obrh); this.topLeftCollection.setWidth(otlw); this.topLeftCollection.setHeight(otlh); this.topRightCollection.setWidth(otrw); this.topRightCollection.setHeight(otrh); this.bottomLeftCollection.setWidth(oblw); this.bottomLeftCollection.setHeight(oblh); this.bottomRightCollection.setWidth(obrw); this.bottomRightCollection.setHeight(obrh); var items = this.contextLayout.attr("items"); items[1].left = regionSize; items[2].top = this._getFreezeHeaderHeight(); items[3].left = regionSize; items[3].top = this._getFreezeHeaderHeight(); this.contextLayout.attr("items", items); this.contextLayout.resize(); var leftHeader = [], rightHeader = [], leftItems = [], rightItems = []; var run = function (positions, items, rendered) { BI.each(positions, function (i, item) { var cell = { type: "bi.collection_table_cell", cell: items[item.row][item.col] }; rendered.push(cell); }); }; run(this.topLeftItems, o.header, leftHeader); run(this.topRightItems, o.header, rightHeader); run(this.bottomLeftItems, this._getActualItems(), leftItems); run(this.bottomRightItems, this._getActualItems(), rightItems); this.topLeftCollection.populate(leftHeader); this.topRightCollection.populate(rightHeader); this.bottomLeftCollection.populate(leftItems); this.bottomRightCollection.populate(rightItems); } }); BI.shortcut('bi.quick_collection_table', BI.QuickCollectionTable);/** * * 表格单元格 * * Created by GUY on 2016/1/12. * @class BI.GridTableCell * @extends BI.Widget */ BI.GridTableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.GridTableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-grid-table-cell bi-border-right bi-border-bottom", width: 0, height: 0, _rowIndex: 0, _columnIndex: 0, _left: 0, _top: 0, cell: {} }) }, _init: function () { BI.GridTableCell.superclass._init.apply(this, arguments); var o = this.options; this.cell = BI.createWidget(BI.extend({ type: "bi.label" }, o.cell, { cls: (o.cell.cls || "") + "grid-table-cell-wrapper", width: o.width - (o._columnIndex === 0 ? 1 : 0) - 1, height: o.height - (o._rowIndex === 0 ? 1 : 0) - 1 })); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.cell, left: 0, right: 0, top: 0, bottom: 0 }] }); }, setWidth: function (width) { BI.GridTableCell.superclass.setWidth.apply(this, arguments); var o = this.options; this.cell.setWidth(o.width - (o._columnIndex === 0 ? 1 : 0) - 1); }, setHeight: function (height) { BI.GridTableCell.superclass.setHeight.apply(this, arguments); var o = this.options; this.cell.setHeight(o.height - (o._rowIndex === 0 ? 1 : 0) - 1); } }); BI.shortcut("bi.grid_table_cell", BI.GridTableCell);/** * GridTable * * Created by GUY on 2016/1/12. * @class BI.GridTable * @extends BI.Widget */ BI.GridTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.GridTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-grid-table", headerRowSize: 25, rowSize: 25, columnSize: [], isNeedFreeze: false, freezeCols: [], header: [], items: [], regionColumnSize: [] }); }, render: function () { var self = this, o = this.options; this._width = 0; this._height = 0; this._scrollBarSize = BI.DOM.getScrollWidth(); var rowHeightGetter = function () { return o.rowSize; }; var columnLeftWidthGetter = function (index) { return o.columnSize[index]; }; var columnRightWidthGetter = function (index) { return o.columnSize[index + self._getFreezeColLength()]; }; this.topLeftGrid = BI.createWidget({ type: "bi.grid_view", rowHeightGetter: rowHeightGetter, columnWidthGetter: columnLeftWidthGetter }); this.topLeftGrid.on(BI.GridView.EVENT_SCROLL, function (scroll) { self.bottomLeftGrid.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.topRightGrid = BI.createWidget({ type: "bi.grid_view", rowHeightGetter: rowHeightGetter, columnWidthGetter: columnRightWidthGetter }); this.topRightGrid.on(BI.GridView.EVENT_SCROLL, function (scroll) { self.bottomRightGrid.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.bottomLeftGrid = BI.createWidget({ type: "bi.grid_view", rowHeightGetter: rowHeightGetter, columnWidthGetter: columnLeftWidthGetter }); this.bottomLeftGrid.on(BI.GridView.EVENT_SCROLL, function (scroll) { self.bottomRightGrid.setScrollTop(scroll.scrollTop); self.topLeftGrid.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.bottomRightGrid = BI.createWidget({ type: "bi.grid_view", rowHeightGetter: rowHeightGetter, columnWidthGetter: columnRightWidthGetter }); this.bottomRightGrid.on(BI.GridView.EVENT_SCROLL, function (scroll) { self.bottomLeftGrid.setScrollTop(scroll.scrollTop); self.topRightGrid.setScrollLeft(scroll.scrollLeft); self._populateScrollbar(); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.topLeft = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.topLeftGrid] }); this.topRight = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.topRightGrid] }); this.bottomLeft = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.bottomLeftGrid] }); this.bottomRight = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.bottomRightGrid] }); this.contextLayout = BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.topLeft, top: 0, left: 0 }, { el: this.topRight, top: 0 }, { el: this.bottomLeft, left: 0 }, { el: this.bottomRight }] }); this.topScrollbar = BI.createWidget({ type: "bi.grid_table_scrollbar", width: BI.GridTableScrollbar.SIZE }); this.topScrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function (scrollTop) { self.bottomLeftGrid.setScrollTop(scrollTop); self.bottomRightGrid.setScrollTop(scrollTop); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.leftScrollbar = BI.createWidget({ type: "bi.grid_table_horizontal_scrollbar", height: BI.GridTableScrollbar.SIZE }); this.leftScrollbar.on(BI.GridTableHorizontalScrollbar.EVENT_SCROLL, function (scrollLeft) { self.topLeftGrid.setScrollLeft(scrollLeft); self.bottomLeftGrid.setScrollLeft(scrollLeft); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.rightScrollbar = BI.createWidget({ type: "bi.grid_table_horizontal_scrollbar", height: BI.GridTableScrollbar.SIZE }); this.rightScrollbar.on(BI.GridTableHorizontalScrollbar.EVENT_SCROLL, function (scrollLeft) { self.topRightGrid.setScrollLeft(scrollLeft); self.bottomRightGrid.setScrollLeft(scrollLeft); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.scrollBarLayout = BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.topScrollbar, right: 0, top: 0 }, { el: this.leftScrollbar, left: 0 }, { el: this.rightScrollbar }] }); this._width = o.width - BI.GridTableScrollbar.SIZE; this._height = o.height - BI.GridTableScrollbar.SIZE; this.header = this._getHeader(); this.items = this._getItems(); }, mounted: function () { var o = this.options; if (o.items.length > 0 || o.header.length > 0) { this._populate(); } }, _getFreezeColLength: function () { return this.options.isNeedFreeze ? this.options.freezeCols.length : 0; }, _getFreezeHeaderHeight: function () { var o = this.options; if (o.header.length * o.headerRowSize >= this._height) { return 0; } return o.header.length * o.headerRowSize; }, _getActualItems: function () { var o = this.options; if (o.header.length * o.headerRowSize >= this._height) { return o.header.concat(o.items); } return o.items; }, _populateScrollbar: function () { var o = this.options; var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = []; BI.each(o.columnSize, function (i, size) { if (o.isNeedFreeze === true && o.freezeCols.contains(i)) { totalLeftColumnSize += size; } else { totalRightColumnSize += size; } totalColumnSize += size; if (i === 0) { summaryColumnSizeArray[i] = size; } else { summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size; } }); this.topScrollbar.setContentSize(this._getActualItems().length * o.rowSize); this.topScrollbar.setSize(this._height - this._getFreezeHeaderHeight()); this.topScrollbar.setPosition(Math.min(this.bottomLeftGrid.getScrollTop(), this.bottomRightGrid.getScrollTop())); this.topScrollbar.populate(); this.leftScrollbar.setContentSize(totalLeftColumnSize); this.leftScrollbar.setSize(regionSize); this.leftScrollbar.setPosition(this.bottomLeftGrid.getScrollLeft()); this.leftScrollbar.populate(); this.rightScrollbar.setContentSize(totalRightColumnSize); this.rightScrollbar.setSize(this._width - regionSize); this.rightScrollbar.setPosition(this.bottomRightGrid.getScrollLeft()); this.rightScrollbar.populate(); var items = this.scrollBarLayout.attr("items"); items[0].top = this._getFreezeHeaderHeight(); items[1].top = this._height; items[2].top = this._height; items[2].left = regionSize; this.scrollBarLayout.attr("items", items); this.scrollBarLayout.resize(); }, _getHeader: function () { var o = this.options; var freezeColLength = this._getFreezeColLength(); var leftHeader = [], rightHeader = []; BI.each(o.header, function (i, cols) { leftHeader[i] = []; rightHeader[i] = []; BI.each(cols, function (j, col) { var cell = { type: "bi.grid_table_cell", cell: col }; if (j < freezeColLength) { leftHeader[i].push(cell); } else { rightHeader[i].push(cell); } }); }); return [leftHeader, rightHeader]; }, _getItems: function () { var o = this.options; var freezeColLength = this._getFreezeColLength(); var leftItems = [], rightItems = []; BI.each(this._getActualItems(), function (i, cols) { leftItems[i] = []; rightItems[i] = []; BI.each(cols, function (j, col) { var cell = { type: "bi.grid_table_cell", cell: col }; if (j < freezeColLength) { leftItems[i].push(cell); } else { rightItems[i].push(cell); } }); }); return [leftItems, rightItems]; }, _populateTable: function () { var self = this, o = this.options; var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = []; var freezeColLength = this._getFreezeColLength(); BI.each(o.columnSize, function (i, size) { if (o.isNeedFreeze === true && o.freezeCols.contains(i)) { totalLeftColumnSize += size; } else { totalRightColumnSize += size; } totalColumnSize += size; if (i === 0) { summaryColumnSizeArray[i] = size; } else { summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size; } }); var otlw = regionSize; var otlh = this._getFreezeHeaderHeight(); var otrw = this._width - regionSize; var otrh = this._getFreezeHeaderHeight(); var oblw = regionSize; var oblh = this._height - otlh; var obrw = this._width - regionSize; var obrh = this._height - otrh; var tlw = otlw + this._scrollBarSize; var tlh = otlh + this._scrollBarSize; var trw = otrw + this._scrollBarSize; var trh = otrh + this._scrollBarSize; var blw = oblw + this._scrollBarSize; var blh = oblh + this._scrollBarSize; var brw = obrw + this._scrollBarSize; var brh = obrh + this._scrollBarSize; var digest = function (el) { el.element.css({ overflow: "scroll", overflowX: "scroll", overflowY: "scroll" }) }; this.topLeft.setWidth(otlw); this.topLeft.setHeight(otlh); this.topRight.setWidth(otrw); this.topRight.setHeight(otrh); this.bottomLeft.setWidth(oblw); this.bottomLeft.setHeight(oblh); this.bottomRight.setWidth(obrw); this.bottomRight.setHeight(obrh); this.topLeftGrid.setWidth(tlw); this.topLeftGrid.setHeight(tlh); this.topRightGrid.setWidth(trw); this.topRightGrid.setHeight(trh); this.bottomLeftGrid.setWidth(blw); this.bottomLeftGrid.setHeight(blh); this.bottomRightGrid.setWidth(brw); this.bottomRightGrid.setHeight(brh); digest(this.topLeftGrid); digest(this.topRightGrid); digest(this.bottomLeftGrid); digest(this.bottomRightGrid); this.topLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0); this.topLeftGrid.setEstimatedRowSize(o.headerRowSize); this.topRightGrid.setEstimatedColumnSize((o.columnSize.length - freezeColLength) > 0 ? (totalRightColumnSize / (o.columnSize.length - freezeColLength)) : 0); this.topRightGrid.setEstimatedRowSize(o.headerRowSize); this.bottomLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0); this.bottomLeftGrid.setEstimatedRowSize(o.rowSize); this.bottomRightGrid.setEstimatedColumnSize((o.columnSize.length - freezeColLength) > 0 ? (totalRightColumnSize / (o.columnSize.length - freezeColLength)) : 0); this.bottomRightGrid.setEstimatedRowSize(o.rowSize); var items = this.contextLayout.attr("items"); items[1].left = regionSize; items[2].top = this._getFreezeHeaderHeight(); items[3].left = regionSize; items[3].top = this._getFreezeHeaderHeight(); this.contextLayout.attr("items", items); this.contextLayout.resize(); this.topLeftGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); this.topRightGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); this.bottomLeftGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); this.bottomRightGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); function overscan(grid, w, h, rSize, cSize) { var rCount = h / rSize; var cCount = w / cSize; if (cCount * (120 / rSize) >= 60 || rCount * (120 / cSize) >= 60) { grid.attr("overscanRowCount", 100); grid.attr("overscanColumnCount", 100); } } if (freezeColLength > 0) { overscan(this.topLeftGrid, tlw, tlh, o.headerRowSize, totalLeftColumnSize / freezeColLength); overscan(this.bottomLeftGrid, blw, blh, o.rowSize, totalLeftColumnSize / freezeColLength); } if (o.columnSize.length - freezeColLength > 0) { overscan(this.topRight, trw, trh, o.headerRowSize, totalRightColumnSize / (o.columnSize.length - freezeColLength)); overscan(this.bottomRightGrid, brw, brh, o.rowSize, totalRightColumnSize / (o.columnSize.length - freezeColLength)); } this.topLeftGrid._populate(this.header[0]); this.topRightGrid._populate(this.header[1]); this.bottomLeftGrid._populate(this.items[0]); this.bottomRightGrid._populate(this.items[1]); }, _populate: function () { if (this._width <= 0 || this._height <= 0) { return; } this._populateTable(); this._populateScrollbar(); }, getRegionSize: function () { var o = this.options; var regionSize = o.regionColumnSize[0] || 0; if (o.isNeedFreeze === false || o.freezeCols.length === 0) { return 0; } if (!regionSize) { BI.each(o.freezeCols, function (i, col) { regionSize += o.columnSize[col]; }); } return regionSize; }, setVerticalScroll: function (scrollTop) { this.bottomLeftGrid.setScrollTop(scrollTop); this.bottomRightGrid.setScrollTop(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.topLeftGrid.setScrollLeft(scrollLeft); this.bottomLeftGrid.setScrollLeft(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.topRightGrid.setScrollLeft(scrollLeft); this.bottomRightGrid.setScrollLeft(scrollLeft); }, getVerticalScroll: function () { return this.bottomRightGrid.getScrollTop(); }, getLeftHorizontalScroll: function () { return this.bottomLeftGrid.getScrollLeft(); }, getRightHorizontalScroll: function () { return this.bottomRightGrid.getScrollLeft(); }, setWidth: function (width) { BI.GridTable.superclass.setWidth.apply(this, arguments); this._width = this.options.width - BI.GridTableScrollbar.SIZE; }, setHeight: function (height) { BI.GridTable.superclass.setHeight.apply(this, arguments); this._height = this.options.height - BI.GridTableScrollbar.SIZE; }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; this._isNeedDigest = true; }, setRegionColumnSize: function (regionColumnSize) { this.options.regionColumnSize = regionColumnSize; this._isNeedDigest = true; }, getColumnSize: function () { return this.options.columnSize; }, getRegionColumnSize: function () { return this.options.regionColumnSize; }, populate: function (items, header) { if (items && this.options.items !== items) { this.options.items = items; this.items = this._getItems(); this._restore(); } if (header && this.options.header !== header) { this.options.header = header; this.header = this._getHeader(); this._restore(); } this._populate(); }, _restore: function () { this.topLeftGrid.restore(); this.topRightGrid.restore(); this.bottomLeftGrid.restore(); this.bottomRightGrid.restore(); }, restore: function () { this._restore(); } }); BI.shortcut('bi.grid_table', BI.GridTable);/** * QuickGridTable * * Created by GUY on 2016/1/12. * @class BI.QuickGridTable * @extends BI.GridTable */ BI.QuickGridTable = BI.inherit(BI.GridTable, { _defaultConfig: function () { return BI.extend(BI.QuickGridTable.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-quick-grid-table" }); }, render: function () { BI.QuickGridTable.superclass.render.apply(this, arguments); var self = this, o = this.options; this.topLeftGrid.setOverflowX(false); this.topLeftGrid.setOverflowY(false); this.topRightGrid.setOverflowX(false); this.topRightGrid.setOverflowY(false); this.bottomLeftGrid.setOverflowX(false); this.bottomLeftGrid.setOverflowY(false); this.bottomRightGrid.setOverflowX(false); this.bottomRightGrid.setOverflowY(false); }, mounted: function () { BI.QuickGridTable.superclass.mounted.apply(this, arguments); var self = this; this._topLeftWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelLeft, this), BI.bind(this._shouldHandleLeftX, this), BI.bind(this._shouldHandleY, this) ); this._topRightWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelRight, this), BI.bind(this._shouldHandleRightX, this), BI.bind(this._shouldHandleY, this) ); this._bottomLeftWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelLeft, this), BI.bind(this._shouldHandleLeftX, this), BI.bind(this._shouldHandleY, this) ); this._bottomRightWheelHandler = new BI.WheelHandler( BI.bind(this._onWheelRight, this), BI.bind(this._shouldHandleRightX, this), BI.bind(this._shouldHandleY, this) ); this.topLeftGrid.element.mousewheel(function (e) { self._topLeftWheelHandler.onWheel(e.originalEvent); }); this.topRightGrid.element.mousewheel(function (e) { self._topRightWheelHandler.onWheel(e.originalEvent); }); this.bottomLeftGrid.element.mousewheel(function (e) { self._bottomLeftWheelHandler.onWheel(e.originalEvent); }); this.bottomRightGrid.element.mousewheel(function (e) { self._bottomRightWheelHandler.onWheel(e.originalEvent); }); }, _shouldHandleLeftX: function (delta) { if (delta > 0) { return this.bottomLeftGrid.getScrollLeft() < this.bottomLeftGrid.getMaxScrollLeft(); } else { return this.bottomLeftGrid.getScrollLeft() > 0; } }, _shouldHandleRightX: function (delta) { if (delta > 0) { return this.bottomRightGrid.getScrollLeft() < this.bottomRightGrid.getMaxScrollLeft(); } else { return this.bottomRightGrid.getScrollLeft() > 0; } }, _shouldHandleY: function (delta) { if (delta > 0) { return this.bottomRightGrid.getScrollTop() < this.bottomRightGrid.getMaxScrollTop(); } else { return this.bottomRightGrid.getScrollTop() > 0; } }, _onWheelLeft: function (deltaX, deltaY) { var self = this; var scrollTop = this.bottomLeftGrid.getScrollTop(); var scrollLeft = this.bottomLeftGrid.getScrollLeft(); scrollTop += deltaY; scrollLeft += deltaX; this.bottomLeftGrid.setScrollTop(scrollTop); this.bottomRightGrid.setScrollTop(scrollTop); this.topLeftGrid.setScrollLeft(scrollLeft); this.bottomLeftGrid.setScrollLeft(scrollLeft); self._populateScrollbar(); this.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }, _onWheelRight: function (deltaX, deltaY) { var self = this; var scrollTop = this.bottomRightGrid.getScrollTop(); var scrollLeft = this.bottomRightGrid.getScrollLeft(); scrollTop += deltaY; scrollLeft += deltaX; this.bottomLeftGrid.setScrollTop(scrollTop); this.bottomRightGrid.setScrollTop(scrollTop); this.topRightGrid.setScrollLeft(scrollLeft); this.bottomRightGrid.setScrollLeft(scrollLeft); self._populateScrollbar(); this.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }, _populateTable: function () { var self = this, o = this.options; var regionSize = this.getRegionSize(), totalLeftColumnSize = 0, totalRightColumnSize = 0, totalColumnSize = 0, summaryColumnSizeArray = []; var freezeColLength = this._getFreezeColLength(); BI.each(o.columnSize, function (i, size) { if (o.isNeedFreeze === true && o.freezeCols.contains(i)) { totalLeftColumnSize += size; } else { totalRightColumnSize += size; } totalColumnSize += size; if (i === 0) { summaryColumnSizeArray[i] = size; } else { summaryColumnSizeArray[i] = summaryColumnSizeArray[i - 1] + size; } }); var otlw = regionSize; var otlh = this._getFreezeHeaderHeight(); var otrw = this._width - regionSize; var otrh = this._getFreezeHeaderHeight(); var oblw = regionSize; var oblh = this._height - otlh; var obrw = this._width - regionSize; var obrh = this._height - otrh; this.topLeft.setWidth(otlw); this.topLeft.setHeight(otlh); this.topRight.setWidth(otrw); this.topRight.setHeight(otrh); this.bottomLeft.setWidth(oblw); this.bottomLeft.setHeight(oblh); this.bottomRight.setWidth(obrw); this.bottomRight.setHeight(obrh); this.topLeftGrid.setWidth(otlw); this.topLeftGrid.setHeight(otlh); this.topRightGrid.setWidth(otrw); this.topRightGrid.setHeight(otrh); this.bottomLeftGrid.setWidth(oblw); this.bottomLeftGrid.setHeight(oblh); this.bottomRightGrid.setWidth(obrw); this.bottomRightGrid.setHeight(obrh); this.topLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0); this.topLeftGrid.setEstimatedRowSize(o.headerRowSize); this.topRightGrid.setEstimatedColumnSize((o.columnSize.length - freezeColLength) > 0 ? (totalRightColumnSize / (o.columnSize.length - freezeColLength)) : 0); this.topRightGrid.setEstimatedRowSize(o.headerRowSize); this.bottomLeftGrid.setEstimatedColumnSize(freezeColLength > 0 ? totalLeftColumnSize / freezeColLength : 0); this.bottomLeftGrid.setEstimatedRowSize(o.rowSize); this.bottomRightGrid.setEstimatedColumnSize((o.columnSize.length - freezeColLength) > 0 ? (totalRightColumnSize / (o.columnSize.length - freezeColLength)) : 0); this.bottomRightGrid.setEstimatedRowSize(o.rowSize); var items = this.contextLayout.attr("items"); items[1].left = regionSize; items[2].top = this._getFreezeHeaderHeight(); items[3].left = regionSize; items[3].top = this._getFreezeHeaderHeight(); this.contextLayout.attr("items", items); this.contextLayout.resize(); var leftHeader = [], rightHeader = [], leftItems = [], rightItems = []; BI.each(o.header, function (i, cols) { leftHeader[i] = []; rightHeader[i] = []; BI.each(cols, function (j, col) { var cell = { type: "bi.grid_table_cell", cell: col }; if (j < freezeColLength) { leftHeader[i].push(cell); } else { rightHeader[i].push(cell); } }); }); BI.each(this._getActualItems(), function (i, cols) { leftItems[i] = []; rightItems[i] = []; BI.each(cols, function (j, col) { var cell = { type: "bi.grid_table_cell", cell: col }; if (j < freezeColLength) { leftItems[i].push(cell); } else { rightItems[i].push(cell); } }); }); this.topLeftGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); this.topRightGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); this.bottomLeftGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); this.bottomRightGrid.attr({ overscanColumnCount: 0, overscanRowCount: 0 }); function overscan(grid, w, h, rSize, cSize) { var rCount = h / rSize; var cCount = w / cSize; if (cCount * (120 / rSize) >= 60 || rCount * (120 / cSize) >= 60) { grid.attr("overscanRowCount", 100); grid.attr("overscanColumnCount", 100); } } if (freezeColLength > 0) { overscan(this.topLeftGrid, otlw, otlh, o.headerRowSize, totalLeftColumnSize / freezeColLength); overscan(this.bottomLeftGrid, oblw, oblh, o.rowSize, totalLeftColumnSize / freezeColLength); } if (o.columnSize.length - freezeColLength > 0) { overscan(this.topRight, otrw, otrh, o.headerRowSize, totalRightColumnSize / (o.columnSize.length - freezeColLength)); overscan(this.bottomRightGrid, obrw, obrh, o.rowSize, totalRightColumnSize / (o.columnSize.length - freezeColLength)); } this.topLeftGrid.populate(leftHeader); this.topRightGrid.populate(rightHeader); this.bottomLeftGrid.populate(leftItems); this.bottomRightGrid.populate(rightItems); } }); BI.shortcut('bi.quick_grid_table', BI.QuickGridTable);/** * * 表格滚动条 * * Created by GUY on 2016/1/12. * @class BI.GridTableScrollbar * @extends BI.Widget */ BI.GridTableScrollbar = BI.inherit(BI.Widget, { _const: { FACE_MARGIN: 4, FACE_MARGIN_2: 4 * 2, FACE_SIZE_MIN: 30, KEYBOARD_SCROLL_AMOUNT: 40 }, _defaultConfig: function () { return BI.extend(BI.GridTableScrollbar.superclass._defaultConfig.apply(this, arguments), { baseCls: "scrollbar-layout-main public-scrollbar-main", attributes: { tabIndex: 0 }, contentSize: 0, defaultPosition: 0, isOpaque: false, orientation: "vertical", position: 0, size: 0 }) }, render: function () { var self = this, o = this.options; this.focused = false; this.isDragging = false; this.face = BI.createWidget({ type: "bi.layout", cls: "scrollbar-layout-face public-scrollbar-face " + (this._isHorizontal() ? "scrollbar-layout-face-horizontal" : "scrollbar-layout-face-vertical") }); this.contextLayout = BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.face, left: 0, top: 0 }] }); }, mounted: function () { var self = this, o = this.options; var onWheel = o.orientation === 'horizontal' ? this._onWheelX : this._onWheelY; this._wheelHandler = new BI.WheelHandler( BI.bind(onWheel, this), BI.bind(this._shouldHandleX, this), BI.bind(this._shouldHandleY, this) ); this._mouseMoveTracker = new BI.MouseMoveTracker( BI.bind(this._onMouseMove, this), BI.bind(this._onMouseMoveEnd, this), document ); this.element.on("mousedown", BI.bind(this._onMouseDown, this)); this.element.on("mousewheel", function (e) { self._wheelHandler.onWheel(e.originalEvent); }); this.element.on("keydown", BI.bind(this._onKeyDown, this)); this.element.on("focus", function () { self.focused = true; self._populate(); }); this.element.on("blur", function () { self.focused = false; self._populate(); }); if (this._isHorizontal()) { this.element.addClass("scrollbar-layout-main-horizontal"); } else { this.element.addClass("scrollbar-layout-main-vertical"); } this._populate(); }, _isHorizontal: function () { return this.options.orientation === 'horizontal' }, _getScale: function () { var o = this.options; var scale = o.size / o.contentSize; var faceSize = o.size * scale; if (faceSize < this._const.FACE_SIZE_MIN) { scale = (o.size - this._const.FACE_SIZE_MIN) / (o.contentSize - o.size); } return scale; }, _getFaceSize: function () { var o = this.options; var scale = o.size / o.contentSize; var faceSize = o.size * scale; if (faceSize < this._const.FACE_SIZE_MIN) { faceSize = this._const.FACE_SIZE_MIN; } return faceSize; }, _shouldHandleX: function (delta) { return this.options.orientation === 'horizontal' ? this._shouldHandleChange(delta) : false; }, _shouldHandleY: function (delta) { return this.options.orientation !== 'horizontal' ? this._shouldHandleChange(delta) : false; }, _shouldHandleChange: function (delta) { return this.options.position + delta !== this.options.position; }, _onWheelY: function (deltaX, deltaY) { this._onWheel(deltaY); }, _onWheelX: function (deltaX, deltaY) { this._onWheel(deltaX); }, _onWheel: function (delta) { var maxPosition = this.options.contentSize - this.options.size; this.options.position += delta; if (this.options.position < 0) { this.options.position = 0; } else if (this.options.position > maxPosition) { this.options.position = maxPosition; } this._populate(); this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position); }, _onMouseDown: function (e) { if (e.target !== this.face.element[0]) { var position = this._isHorizontal() ? e.offsetX : e.offsetY; position /= this._getScale(); this.options.position = BI.clamp(position - (this._getFaceSize() * 0.5 / this._getScale()), 0, this.options.contentSize - this.options.size); this._populate(); this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position); } else { this._mouseMoveTracker.captureMouseMoves(e); } try { this.element[0].focus(); } catch (e) { } }, _onMouseMove: function (deltaX, deltaY) { var delta = this._isHorizontal() ? deltaX : deltaY; delta /= this._getScale(); this.options.position = BI.clamp(this.options.position + delta, 0, this.options.contentSize - this.options.size); this.isDragging = this._mouseMoveTracker.isDragging(); this._populate(); this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position); }, _onMouseMoveEnd: function (event) { this._mouseMoveTracker.releaseMouseMoves(); if (this.isDragging === true) { this.isDragging = false; this._populate(); } }, _onKeyDown: function (event) { var Keys = { BACKSPACE: 8, TAB: 9, RETURN: 13, ALT: 18, ESC: 27, SPACE: 32, PAGE_UP: 33, PAGE_DOWN: 34, END: 35, HOME: 36, LEFT: 37, UP: 38, RIGHT: 39, DOWN: 40, DELETE: 46, COMMA: 188, PERIOD: 190, A: 65, Z: 90, ZERO: 48, NUMPAD_0: 96, NUMPAD_9: 105 }; var keyCode = event.keyCode; if (keyCode === Keys.TAB) { return; } var distance = 40; var direction = 0; if (this._isHorizontal()) { switch (keyCode) { case Keys.HOME: direction = -1; distance = this.options.contentSize; break; case Keys.LEFT: direction = -1; break; case Keys.RIGHT: direction = 1; break; default: return; } } if (!this._isHorizontal()) { switch (keyCode) { case Keys.SPACE: if (event.shiftKey) { direction = -1; } else { direction = 1; } break; case Keys.HOME: direction = -1; distance = this.options.contentSize; break; case Keys.UP: direction = -1; break; case Keys.DOWN: direction = 1; break; case Keys.PAGE_UP: direction = -1; distance = this.options.size; break; case Keys.PAGE_DOWN: direction = 1; distance = this.options.size; break; default: return; } } this.options.position = BI.clamp(this.options.position + (distance * direction), 0, this.options.contentSize - this.options.size); event.preventDefault(); this._populate(); this.fireEvent(BI.GridTableScrollbar.EVENT_SCROLL, this.options.position); }, _populate: function () { var self = this, o = this.options; if (o.size < 1 || o.contentSize <= o.size) { this.setVisible(false); return; } this.setVisible(true); var size = o.size; var isHorizontal = this._isHorizontal(); var isActive = this.focused || this.isDragging; var faceSize = this._getFaceSize(); var isOpaque = o.isOpaque; this.element[isOpaque === true ? "addClass" : "removeClass"]("public-scrollbar-main-opaque"); this.element[isActive === true ? "addClass" : "removeClass"]("public-scrollbar-main-active"); this.face.element[isActive === true ? "addClass" : "removeClass"]("public-scrollbar-face-active"); var position = o.position * this._getScale() + this._const.FACE_MARGIN; var items = this.contextLayout.attr("items"); if (isHorizontal) { this.setWidth(size); this.face.setWidth(faceSize - this._const.FACE_MARGIN_2); items[0].left = position; items[0].top = 0; } else { this.setHeight(size); this.face.setHeight(faceSize - this._const.FACE_MARGIN_2); items[0].left = 0; items[0].top = position; } this.contextLayout.attr("items", items); this.contextLayout.resize(); }, setContentSize: function (contentSize) { this.options.contentSize = contentSize; }, setPosition: function (position) { this.options.position = position; }, setSize: function (size) { this.options.size = size; }, populate: function () { this._populate(); } }); BI.GridTableScrollbar.SIZE = 10; BI.GridTableScrollbar.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut("bi.grid_table_scrollbar", BI.GridTableScrollbar); BI.GridTableHorizontalScrollbar = BI.inherit(BI.Widget, { _const: { FACE_MARGIN: 4, FACE_MARGIN_2: 4 * 2, FACE_SIZE_MIN: 30, KEYBOARD_SCROLL_AMOUNT: 40 }, _defaultConfig: function () { return BI.extend(BI.GridTableHorizontalScrollbar.superclass._defaultConfig.apply(this, arguments), { attributes: { tabIndex: 0 }, contentSize: 0, position: 0, size: 0 }) }, _init: function () { BI.GridTableHorizontalScrollbar.superclass._init.apply(this, arguments); var self = this, o = this.options; this.scrollbar = BI.createWidget({ type: "bi.grid_table_scrollbar", orientation: "horizontal", isOpaque: true, position: o.position, contentSize: o.contentSize, size: o.size }); this.scrollbar.on(BI.GridTableScrollbar.EVENT_SCROLL, function () { self.fireEvent(BI.GridTableHorizontalScrollbar.EVENT_SCROLL, arguments); }); BI.createWidget({ type: "bi.absolute", cls: "horizontal-scrollbar", element: this, width: o.size, height: BI.GridTableScrollbar.SIZE, items: [{ el: { type: "bi.absolute", scrollable: false, height: BI.GridTableScrollbar.SIZE, items: [{ el: this.scrollbar, left: 0, top: 0 }] }, top: 0, left: 0, right: 0 }] }); }, setContentSize: function (contentSize) { this.options.contentSize = contentSize; this.scrollbar.setContentSize(contentSize); }, setPosition: function (position) { this.options.position = position; this.scrollbar.setPosition(position); }, setSize: function (size) { this.setWidth(size); this.options.size = size; this.scrollbar.setSize(size); }, populate: function () { this.scrollbar.populate(); var o = this.options; if (o.size < 1 || o.contentSize <= o.size) { this.setVisible(false); return; } this.setVisible(true); } }); BI.GridTableHorizontalScrollbar.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut("bi.grid_table_horizontal_scrollbar", BI.GridTableHorizontalScrollbar);/** * * 表格 * * Created by GUY on 2015/9/22. * @class BI.TableHeaderCell * @extends BI.Single */ BI.TableHeaderCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.TableHeaderCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-table-header-cell", text: "" }) }, _init: function () { BI.TableHeaderCell.superclass._init.apply(this, arguments); BI.createWidget({ type: "bi.label", element: this, textAlign: "center", height: this.options.height, text: this.options.text, value: this.options.value }) } }); BI.shortcut("bi.table_header_cell", BI.TableHeaderCell);/** * * 表格 * * 能处理静态宽度以及动态宽度的表, 百分比宽度的表请使用PreviewTable * * Created by GUY on 2015/9/22. * @class BI.Table * @extends BI.Widget */ BI.Table = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Table.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-table", logic: { //冻结的页面布局逻辑 dynamic: false }, isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效 isNeedMerge: false,//是否需要合并单元格 mergeCols: [], //合并的单元格列号 mergeRule: function (row1, row2) { //合并规则, 默认相等时合并 return BI.isEqual(row1, row2); }, columnSize: [], headerRowSize: 25, footerRowSize: 25, rowSize: 25, regionColumnSize: false, header: [], footer: false, items: [] //二维数组 }) }, _calculateWidth: function (width) { if (!width || width === "0") { return ""; } width = BI.parseFloat(width); if (width < 0) { width = 0; } return width > 1.01 ? width : (width * 100 + "%"); }, _calculateHeight: function (height) { return height ? height : ""; }, _isRightFreeze: function () { return BI.isNotEmptyArray(this.options.freezeCols) && BI.first(this.options.freezeCols) !== 0; }, _createTopLeft: function () { var o = this.options, isRight = this._isRightFreeze(); this.topLeftColGroupTds = {}; this.topLeftBodyTds = {}; this.topLeftBodyItems = {}; var table = this._table(); var colgroup = this._createColGroup(this.columnLeft, this.topLeftColGroupTds); var body = this.topLeftBody = this._body(); body.element.append(this._createHeaderCells(this.topLeftItems, this.columnLeft, this.mergeLeft, this.topLeftBodyTds, this.topLeftBodyItems)); BI.createWidget({ type: "bi.adaptive", element: table, items: [colgroup, body] }); if (isRight) { var w = 0; BI.each(o.columnSize, function (i, col) { if (!o.freezeCols.contains(i)) { w += col; } }); if (BI.isNumeric(w) && w > 1) { w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length; } } return (this.topLeftContainer = BI.createWidget({ type: "bi.adaptive", width: this._calculateWidth(w), items: [table] })); }, _createTopRight: function () { var o = this.options, isRight = this._isRightFreeze(); this.topRightColGroupTds = {}; this.topRightBodyTds = {}; this.topRightBodyItems = {}; var table = this._table(); var colgroup = this._createColGroup(this.columnRight, this.topRightColGroupTds); var body = this.topRightBody = this._body(); body.element.append(this._createHeaderCells(this.topRightItems, this.columnRight, this.mergeRight, this.topRightBodyTds, this.topRightBodyItems, this.columnLeft.length)); BI.createWidget({ type: "bi.adaptive", element: table, items: [colgroup, body] }); if (!isRight) { var w = 0; BI.each(o.columnSize, function (i, col) { if (!o.freezeCols.contains(i)) { w += col; } }); if (BI.isNumeric(w)) { w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length; } } return (this.topRightContainer = BI.createWidget({ type: "bi.adaptive", width: w || undefined, items: [table] })); }, _createBottomLeft: function () { var o = this.options, isRight = this._isRightFreeze(); this.bottomLeftColGroupTds = {}; this.bottomLeftBodyTds = {}; this.bottomLeftBodyItems = {}; var table = this._table(); var colgroup = this._createColGroup(this.columnLeft, this.bottomLeftColGroupTds); var body = this._createBottomLeftBody(); BI.createWidget({ type: "bi.adaptive", element: table, items: [colgroup, body] }); if (isRight) { var w = 0; BI.each(o.columnSize, function (i, col) { if (!o.freezeCols.contains(i)) { w += col; } }); if (BI.isNumeric(w) && w > 1) { w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length; } } return (this.bottomLeftContainer = BI.createWidget({ type: "bi.adaptive", width: this._calculateWidth(w), items: [table] })); }, _createBottomLeftBody: function () { var body = this.bottomLeftBody = this._body(); body.element.append(this._createCells(this.bottomLeftItems, this.columnLeft, this.mergeLeft, this.bottomLeftBodyTds, this.bottomLeftBodyItems)); return body; }, _createBottomRight: function () { var o = this.options, isRight = this._isRightFreeze(); this.bottomRightColGroupTds = {}; this.bottomRightBodyTds = {}; this.bottomRightBodyItems = {}; var table = this._table(); var colgroup = this._createColGroup(this.columnRight, this.bottomRightColGroupTds); var body = this._createBottomRightBody(); BI.createWidget({ type: "bi.adaptive", element: table, items: [colgroup, body] }); if (!isRight) { var w = 0; BI.each(o.columnSize, function (i, col) { if (!o.freezeCols.contains(i)) { w += col; } }); if (BI.isNumeric(w) && w > 1) { w = BI.parseFloat(w) + o.columnSize.length - o.freezeCols.length; } } return (this.bottomRightContainer = BI.createWidget({ type: "bi.adaptive", width: this._calculateWidth(w), items: [table] })); }, _createBottomRightBody: function () { var body = this.bottomRightBody = this._body(); body.element.append(this._createCells(this.bottomRightItems, this.columnRight, this.mergeRight, this.bottomRightBodyTds, this.bottomRightBodyItems, this.columnLeft.length)); return body; }, _createFreezeTable: function () { var self = this, o = this.options; var isRight = this._isRightFreeze(); var split = this._split(o.header); this.topLeftItems = split.left; this.topRightItems = split.right; split = this._split(o.items); this.bottomLeftItems = split.left; this.bottomRightItems = split.right; this.columnLeft = []; this.columnRight = []; BI.each(o.columnSize, function (i, size) { if (o.freezeCols.contains(i)) { self[isRight ? "columnRight" : "columnLeft"].push(size); } else { self[isRight ? "columnLeft" : "columnRight"].push(size); } }); this.mergeLeft = []; this.mergeRight = []; BI.each(o.mergeCols, function (i, col) { if (o.freezeCols.contains(col)) { self[isRight ? "mergeRight" : "mergeLeft"].push(col); } else { self[isRight ? "mergeLeft" : "mergeRight"].push(col); } }); var topLeft = this._createTopLeft(); var topRight = this._createTopRight(); var bottomLeft = this._createBottomLeft(); var bottomRight = this._createBottomRight(); this.scrollTopLeft = BI.createWidget({ type: "bi.adaptive", cls: "scroll-top-left", width: "100%", height: "100%", scrollable: false, items: [topLeft] }); this.scrollTopRight = BI.createWidget({ type: "bi.adaptive", cls: "scroll-top-right", width: "100%", height: "100%", scrollable: false, items: [topRight] }); this.scrollBottomLeft = BI.createWidget({ type: "bi.adaptive", cls: "scroll-bottom-left", width: "100%", height: "100%", scrollable: isRight || null, scrollx: !isRight, items: [bottomLeft] }); this.scrollBottomRight = BI.createWidget({ type: "bi.adaptive", cls: "scroll-bottom-right", width: "100%", height: "100%", scrollable: !isRight || null, scrollx: isRight, items: [bottomRight] }); this.topLeft = BI.createWidget({ type: "bi.adaptive", cls: "top-left", scrollable: false, items: [this.scrollTopLeft] }); this.topRight = BI.createWidget({ type: "bi.adaptive", cls: "top-right", scrollable: false, items: [this.scrollTopRight] }); this.bottomLeft = BI.createWidget({ type: "bi.adaptive", cls: "bottom-left", // scrollable: false, items: [this.scrollBottomLeft] }); this.bottomRight = BI.createWidget({ type: "bi.adaptive", cls: "bottom-right", scrollable: false, items: [this.scrollBottomRight] }); var headerHeight = o.header.length * ((o.headerRowSize || o.rowSize) + 1) + 1; var leftWidth = BI.sum(o.freezeCols, function (i, col) { return o.columnSize[col] > 1 ? o.columnSize[col] + 1 : o.columnSize[col]; }); this._resize = function () { if (self.scrollBottomLeft.element.is(":visible")) { self.scrollBottomLeft.element.css({"overflow-x": "auto"}); self.scrollBottomRight.element.css({"overflow-x": "auto"}); self.setColumnSize(o.columnSize); if (isRight) { self.scrollBottomLeft.element.css({"overflow-y": "auto"}); } else { self.scrollBottomRight.element.css({"overflow-y": "auto"}); } if (self.scrollBottomLeft.element.hasHorizonScroll() || self.scrollBottomRight.element.hasHorizonScroll()) { self.scrollBottomLeft.element.css("overflow-x", "scroll"); self.scrollBottomRight.element.css("overflow-x", "scroll"); } if (self.scrollBottomRight.element.hasVerticalScroll()) { self.scrollTopRight.element.css("overflow-y", "scroll"); } else { self.scrollTopRight.element.css("overflow-y", "hidden"); } if (self.scrollBottomLeft.element.hasVerticalScroll()) { self.scrollTopLeft.element.css("overflow-y", "scroll"); } else { self.scrollTopLeft.element.css("overflow-y", "hidden"); } self.scrollTopLeft.element[0].scrollLeft = self.scrollBottomLeft.element[0].scrollLeft; self.scrollTopRight.element[0].scrollLeft = self.scrollBottomRight.element[0].scrollLeft; self.scrollBottomLeft.element[0].scrollTop = self.scrollBottomRight.element[0].scrollTop; } }; var regionColumnSize = o.regionColumnSize; if (o.freezeCols.length === 0) { regionColumnSize = isRight ? ['fill', 0] : [0, 'fill']; } else if (o.freezeCols.length >= o.columnSize.length) { regionColumnSize = isRight ? [0, 'fill'] : ['fill', 0]; } this.partitions = BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("table", BI.extend({}, o.logic, { rows: 2, columns: 2, columnSize: regionColumnSize || (isRight ? ['fill', leftWidth] : [leftWidth, 'fill']), rowSize: [headerHeight, 'fill'], items: [[{ el: this.topLeft }, { el: this.topRight }], [{ el: this.bottomLeft }, { el: this.bottomRight }]] })))); this._initFreezeScroll(); BI.nextTick(function () { if (self.element.is(":visible")) { self._resize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT); } }); BI.ResizeDetector.addResizeListener(this, function () { self._resize(); self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); }); }, _initFreezeScroll: function () { var self = this, o = this.options; scroll(this.scrollBottomRight.element, this.scrollTopRight.element, this.scrollBottomLeft.element); // scroll(this.scrollBottomLeft.element, this.scrollTopLeft.element, this.scrollBottomRight.element); function scroll(scrollElement, scrollTopElement, otherElement) { scrollElement.scroll(function (e) { otherElement.scrollTop(scrollElement.scrollTop()); scrollTopElement.scrollLeft(scrollElement.scrollLeft()); self.fireEvent(BI.Table.EVENT_TABLE_SCROLL); }); } }, resize: function () { this._resize && this._resize(); }, _createCells: function (items, columnSize, mergeCols, TDs, Ws, start, rowSize) { var self = this, o = this.options, preCol = {}, preRow = {}, preRW = {}, preCW = {}, map = {}; columnSize = columnSize || o.columnSize; mergeCols = mergeCols || o.mergeCols; TDs = TDs || {}; Ws = Ws || {}; start = start || 0; rowSize || (rowSize = o.rowSize); var frag = document.createDocumentFragment(); BI.each(items, function (i, rows) { var tr = $("<tr>").addClass((i & 1) === 0 ? "odd" : "even"); BI.each(rows, function (j, row) { if (!map[i]) { map[i] = {}; } if (!TDs[i]) { TDs[i] = {}; } if (!Ws[i]) { Ws[i] = {}; } map[i][j] = row; if (o.isNeedMerge && mergeCols.contains(j)) { if (i === 0 && j === 0) { createOneEl(0, 0); } else if (j === 0 && i > 0) { var isNeedMergeRow = o.mergeRule(map[i][j], map[i - 1][j]); if (isNeedMergeRow === true) { mergeRow(i, j); preRow[i] = preCol[j]; preRW[i] = preCW[j]; } else { createOneEl(i, j); } } else if (i === 0 && j > 0) { var isNeedMergeCol = o.mergeRule(map[i][j], map[i][j - 1]); if (isNeedMergeCol === true) { mergeCol(i, j); preCol[j] = preRow[i]; preCW[j] = preRW[i]; } else { createOneEl(i, j); } } else { var isNeedMergeRow = o.mergeRule(map[i][j], map[i - 1][j]); var isNeedMergeCol = o.mergeRule(map[i][j], map[i][j - 1]); if (isNeedMergeCol && isNeedMergeRow) { return; } if (isNeedMergeCol) { mergeCol(i, j); } if (isNeedMergeRow) { mergeRow(i, j); } if (!isNeedMergeCol && !isNeedMergeRow) { createOneEl(i, j); } } } else { createOneEl(i, j); } }); function mergeRow(i, j) { var height = (preCol[j].attr("height") | 0) + rowSize + 1; preCol[j].attr("height", height).css("height", height); //preCW[j].element.css("height", height); var rowspan = ((preCol[j].attr("rowspan") || 1) | 0) + 1; preCol[j].attr("rowspan", rowspan); preCol[j].__mergeRows.pushDistinct(i); TDs[i][j] = preCol[j]; Ws[i][j] = preCW[j]; } function mergeCol(i, j) { if (columnSize[j]) { var width = preRow[i].attr("width") | 0; if (width > 1.05 && columnSize[j]) { width = width + columnSize[j] + 1; if (j === columnSize.length - 1) { width--; } } else { width = width + columnSize[j] } width = self._calculateWidth(width); preRow[i].attr("width", width).css("width", width); preRW[i].element.width(width); } var colspan = ((preRow[i].attr("colspan") || 1) | 0) + 1; preRow[i].attr("colspan", colspan); preRow[i].__mergeCols.pushDistinct(j); TDs[i][j] = preRow[i]; Ws[i][j] = preRW[i]; } function createOneEl(r, c) { var width = self._calculateWidth(columnSize[c]); if (width > 1.05 && c === columnSize.length - 1) { width--; } var height = self._calculateHeight(rowSize); var td = $("<td>").attr("height", height) .attr("width", width).css({"width": width, "height": height, "position": "relative"}) .addClass((c & 1) === 0 ? "odd-col" : "even-col") .addClass(r === 0 ? "first-row" : "") .addClass(c === 0 ? "first-col" : "") .addClass(c === rows.length - 1 ? "last-col" : ""); var w = BI.createWidget(map[r][c], { type: "bi.table_cell", textAlign: "left", width: BI.isNumeric(width) ? width : "", height: BI.isNumeric(height) ? height : "", _row: r, _col: c + start }); self.addWidget(w.getName(), w); w._mount(); w.element.css("position", "relative"); td.append(w.element); tr.append(td); preCol[c] = td; preCol[c].__mergeRows = [r]; preCW[c] = w; preRow[r] = td; preRow[r].__mergeCols = [c]; preRW[r] = w; TDs[r][c] = td; Ws[r][c] = w; } frag.appendChild(tr[0]); }); return frag; }, _createColGroupCells: function (columnSize, store) { var self = this, o = this.options; columnSize = columnSize || o.columnSize; store = store || {}; var frag = document.createDocumentFragment(); BI.each(columnSize, function (i, size) { var width = self._calculateWidth(size); var col = $("<col>").attr("width", width).css("width", width); store[i] = col; frag.appendChild(col[0]); }); return frag; }, _createHeaderCells: function (items, columnSize, mergeCols, TDs, Ws, start) { var self = this, o = this.options; start || (start = 0); var frag = this._createCells(items, columnSize, BI.range(o.columnSize.length), TDs, Ws, start, o.headerRowSize || o.rowSize); return frag; }, _createFooterCells: function (items, columnSize, TDs, Ws) { var o = this.options; var frag = this._createCells(items, columnSize, [], TDs, Ws, 0); return frag; }, _createColGroup: function (columnSize, store, widgets) { var self = this, o = this.options; this.colgroup = this._colgroup(); this.colgroup.element.append(this._createColGroupCells(columnSize, store, widgets)); return this.colgroup; }, _createHeader: function () { var self = this, o = this.options; if (o.header === false) { return; } this.header = this._header(); this.header.element.append(this._createHeaderCells(o.header, null, null, this.headerTds, this.headerItems)); return this.header; }, _createFooter: function (columnSize, store, widgets) { var self = this, o = this.options; if (o.footer === false) { return; } this.footer = this._footer(); this.footer.element.append(this._createFooterCells(o.footer, null, this.footerTds, this.footerItems)); return this.footer; }, _createBody: function () { var self = this, o = this.options; this.body = this._body(); this.body.element.append(this._createCells(o.items, null, null, this.bodyTds, this.bodyItems)); return this.body; }, _createNormalTable: function () { var self = this, o = this.options, table = this._table(); this.colgroupTds = {}; this.headerTds = {}; this.footerTds = {}; this.bodyTds = {}; this.headerItems = {}; this.footerItems = {}; this.bodyItems = {}; var colgroup = this._createColGroup(null, this.colgroupTds); var header = this._createHeader(); var footer = this._createFooter(); var body = this._createBody(); BI.createWidget({ type: "bi.adaptive", element: table, items: [colgroup, header, footer, body] }); var w = BI.sum(this.options.columnSize) || undefined; w = this._calculateWidth(w); if (BI.isNumeric(w) && w > 1) { w += o.columnSize.length; } this.tableContainer = BI.createWidget({ type: "bi.adaptive", width: this._calculateWidth(w), items: [table] }); this.scrollBottomRight = BI.createWidget({ type: "bi.adaptive", width: "100%", height: "100%", cls: "scroll-bottom-right", scrollable: true, items: [this.tableContainer] }); BI.createWidget({ type: "bi.adaptive", cls: "bottom-right", element: this, scrollable: false, items: [this.scrollBottomRight] }); this._initNormalScroll(); BI.nextTick(function () { if (self.element.is(":visible")) { self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT); } }); }, _initNormalScroll: function () { var self = this; this.scrollBottomRight.element.scroll(function (e) { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL); }); }, _split: function (items) { var o = this.options, left = [], right = [], isRight = this._isRightFreeze(); BI.each(items, function (i, rows) { left.push([]); right.push([]); BI.each(rows, function (j, cell) { if (o.freezeCols.contains(j)) { (isRight ? right : left)[i].push(cell); } else { (isRight ? left : right)[i].push(cell); } }) }); return { left: left, right: right } }, _table: function () { return BI.createWidget({ type: "bi.layout", tagName: "table", cls: "table", attribute: {"cellspacing": 0, "cellpadding": 0} }); }, _header: function () { return BI.createWidget({ type: "bi.layout", cls: "header", tagName: "thead" }); }, _footer: function () { return BI.createWidget({ type: "bi.layout", cls: "footer", tagName: "tfoot" }); }, _body: function () { return BI.createWidget({ type: "bi.layout", tagName: "tbody", cls: "body" }); }, _colgroup: function () { return BI.createWidget({ type: "bi.layout", tagName: "colgroup" }); }, _init: function () { BI.Table.superclass._init.apply(this, arguments); this.populate(this.options.items); }, setColumnSize: function (columnSize) { var self = this, o = this.options; var isRight = this._isRightFreeze(); o.columnSize = columnSize || []; if (o.isNeedFreeze) { var columnLeft = []; var columnRight = []; BI.each(o.columnSize, function (i, size) { if (o.freezeCols.contains(i)) { isRight ? columnRight.push(size) : columnLeft.push(size); } else { isRight ? columnLeft.push(size) : columnRight.push(size); } }); var topleft = 0, topright = 1, bottomleft = 2, bottomright = 3; var run = function (direction) { var colgroupTds, bodyTds, bodyItems, sizes; switch (direction) { case topleft: colgroupTds = self.topLeftColGroupTds; bodyTds = self.topLeftBodyTds; bodyItems = self.topLeftBodyItems; sizes = columnLeft; break; case topright: colgroupTds = self.topRightColGroupTds; bodyTds = self.topRightBodyTds; bodyItems = self.topRightBodyItems; sizes = columnRight; break; case bottomleft: colgroupTds = self.bottomLeftColGroupTds; bodyTds = self.bottomLeftBodyTds; bodyItems = self.bottomLeftBodyItems; sizes = columnLeft; break; case bottomright: colgroupTds = self.bottomRightColGroupTds; bodyTds = self.bottomRightBodyTds; bodyItems = self.bottomRightBodyItems; sizes = columnRight; break; } BI.each(colgroupTds, function (i, colgroup) { var width = colgroup.attr("width") | 0; if (sizes[i] !== "" && width !== sizes[i]) { var w = self._calculateWidth(sizes[i]); colgroup.attr("width", w).css("width", w); BI.each(bodyTds, function (j, items) { if (items[i]) { if (items[i].__mergeCols.length > 1) { var wid = 0; BI.each(sizes, function (t, s) { if (items[i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += items[i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].attr("width", wid - 1).css("width", wid - 1); } else { items[i].attr("width", wid).css("width", wid); } } else { items[i].attr("width", "").css("width", ""); } } else { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } } }); BI.each(bodyItems, function (j, items) { if (items[i]) { if (bodyTds[j][i].__mergeCols.length > 1) { var wid = 0; BI.each(sizes, function (t, s) { if (bodyTds[j][i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += bodyTds[j][i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].element.attr("width", "").css("width", ""); } } else { if (BI.isNumeric(w)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", w - 1).css("width", w - 1); } else { items[i].element.attr("width", w).css("width", w); } } else { items[i].element.attr("width", "").css("width", ""); } } } }); } }) }; run(topleft); run(topright); run(bottomleft); run(bottomright); var lw = 0, rw = 0; this.columnLeft = []; this.columnRight = []; BI.each(o.columnSize, function (i, size) { if (o.freezeCols.contains(i)) { lw += size; self[isRight ? "columnRight" : "columnLeft"].push(size); } else { rw += size; self[isRight ? "columnLeft" : "columnRight"].push(size); } }); lw = this._calculateWidth(lw); rw = this._calculateWidth(rw); if (BI.isNumeric(lw)) { lw = BI.parseFloat(lw) + o.freezeCols.length; } if (BI.isNumeric(rw)) { rw = BI.parseFloat(rw) + o.columnSize.length - o.freezeCols.length; } this.topLeftContainer.element.width(isRight ? rw : lw); this.bottomLeftContainer.element.width(isRight ? rw : lw); this.topRightContainer.element.width(isRight ? lw : rw); this.bottomRightContainer.element.width(isRight ? lw : rw); this.scrollTopLeft.element[0].scrollLeft = this.scrollBottomLeft.element[0].scrollLeft; this.scrollTopRight.element[0].scrollLeft = this.scrollBottomRight.element[0].scrollLeft; } else { BI.each(this.colgroupTds, function (i, colgroup) { var width = colgroup.attr("width") | 0; if (o.columnSize[i] !== "" && width !== o.columnSize[i]) { var w = self._calculateWidth(o.columnSize[i]); colgroup.attr("width", w).css("width", w); BI.each(self.bodyTds, function (j, items) { if (items[i]) { if (items[i].__mergeCols.length > 1) { var wid = 0; BI.each(o.columnSize, function (t, s) { if (items[i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += items[i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } else { items[i].attr("width", "").css("width", ""); } } else { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } } }); BI.each(self.headerTds, function (j, items) { if (items[i]) { if (items[i].__mergeCols.length > 1) { var wid = 0; BI.each(o.columnSize, function (t, s) { if (items[i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += items[i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } else { items[i].attr("width", "").css("width", ""); } } else { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } } }); BI.each(self.footerTds, function (j, items) { if (items[i]) { if (items[i].__mergeCols.length > 1) { var wid = 0; BI.each(o.columnSize, function (t, s) { if (items[i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += items[i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } else { items[i].attr("width", "").css("width", ""); } } else { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } } }); BI.each(self.bodyItems, function (j, items) { if (items[i]) { if (self.bodyTds[j][i].__mergeCols.length > 1) { var wid = 0; BI.each(o.columnSize, function (t, s) { if (self.bodyTds[j][i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += self.bodyTds[j][i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].element.attr("width", "").css("width", ""); } } else { if (BI.isNumeric(w)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", w - 1).css("width", w - 1); } else { items[i].element.attr("width", w).css("width", w); } } else { items[i].element.attr("width", "").css("width", ""); } } } }); BI.each(self.headerItems, function (j, items) { if (items[i]) { if (self.headerTds[j][i].__mergeCols.length > 1) { var wid = 0; BI.each(o.columnSize, function (t, s) { if (self.headerTds[j][i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += self.headerTds[j][i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].element.attr("width", "").css("width", ""); } } else { if (BI.isNumeric(w)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", w - 1).css("width", w - 1); } else { items[i].element.attr("width", w).css("width", w); } } else { items[i].element.attr("width", "").css("width", ""); } } } }); BI.each(self.footerItems, function (j, items) { if (items[i]) { if (self.footerTds[j][i].__mergeCols.length > 1) { var wid = 0; BI.each(o.columnSize, function (t, s) { if (self.footerTds[j][i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += self.footerTds[j][i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].element.attr("width", "").css("width", ""); } } else { if (BI.isNumeric(w)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", w - 1).css("width", w - 1); } else { items[i].element.attr("width", w).css("width", w); } } else { items[i].element.attr("width", "").css("width", ""); } } } }); } }); var w = this._calculateWidth(BI.sum(o.columnSize)); if (w > 1.05) { w += o.columnSize.length; } if (w > 1.05) { this.tableContainer.element.width(w); } } }, getColumnSize: function () { return this.options.columnSize; }, getCalculateColumnSize: function () { var self = this, o = this.options; var columnSize = []; if (o.isNeedFreeze === true) { if (BI.size(this.bottomLeftBodyTds) > 0 || BI.size(this.bottomRightBodyTds) > 0) { if (!BI.any(this.bottomLeftBodyTds, function (i, tds) { if (!BI.any(tds, function (i, item) { if (item.__mergeCols.length > 1) { return true; } })) { BI.each(tds, function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(tds) - 1) { width++; } columnSize.push(width); }); return true; } })) { BI.each(this.bottomLeftBodyTds[0], function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(self.bottomLeftBodyTds[0]) - 1) { width++; } columnSize.push(width); }); } if (!BI.any(this.bottomRightBodyTds, function (i, tds) { if (!BI.any(tds, function (i, item) { if (item.__mergeCols.length > 1) { return true; } })) { BI.each(tds, function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(tds) - 1) { width++; } columnSize.push(width); }); return true; } })) { BI.each(this.bottomRightBodyTds[0], function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(self.bottomRightBodyTds[0]) - 1) { width++; } columnSize.push(width); }); } return columnSize; } if (!BI.any(this.topLeftBodyTds, function (i, tds) { if (!BI.any(tds, function (i, item) { if (item.__mergeCols.length > 1) { return true; } })) { BI.each(tds, function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(tds) - 1) { width++; } columnSize.push(width); }); return true; } })) { BI.each(this.topLeftBodyTds[BI.size(this.topLeftBodyTds) - 1], function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(self.topLeftBodyTds[BI.size(self.topLeftBodyTds) - 1]) - 1) { width++; } columnSize.push(width); }); } if (!BI.any(this.topRightBodyTds, function (i, tds) { if (!BI.any(tds, function (i, item) { if (item.__mergeCols.length > 1) { return true; } })) { BI.each(tds, function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(tds) - 1) { width++; } columnSize.push(width); }); return true; } })) { BI.each(this.topRightBodyTds[BI.size(this.topRightBodyTds) - 1], function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(self.topRightBodyTds[BI.size(self.topRightBodyTds) - 1]) - 1) { width++; } columnSize.push(width); }); } } else { BI.each(this.headerTds[BI.size(this.headerTds) - 1], function (i, item) { var width = item.width() / item.__mergeCols.length; if (i == BI.size(self.headerTds[BI.size(self.headerTds) - 1]) - 1) { width++; } columnSize.push(width); }); } return columnSize; }, setHeaderColumnSize: function (columnSize) { var self = this, o = this.options; var isRight = this._isRightFreeze(); if (o.isNeedFreeze) { var columnLeft = []; var columnRight = []; BI.each(columnSize, function (i, size) { if (o.freezeCols.contains(i)) { isRight ? columnRight.push(size) : columnLeft.push(size); } else { isRight ? columnLeft.push(size) : columnRight.push(size); } }); var topleft = 0, topright = 1; var run = function (direction) { var colgroupTds, bodyTds, bodyItems, sizes; switch (direction) { case topleft: colgroupTds = self.topLeftColGroupTds; bodyTds = self.topLeftBodyTds; bodyItems = self.topLeftBodyItems; sizes = columnLeft; break; case topright: colgroupTds = self.topRightColGroupTds; bodyTds = self.topRightBodyTds; bodyItems = self.topRightBodyItems; sizes = columnRight; break; } BI.each(colgroupTds, function (i, colgroup) { var width = colgroup.attr("width") | 0; if (width !== sizes[i]) { var w = self._calculateWidth(sizes[i]); colgroup.attr("width", w).css("width", w); BI.each(bodyTds, function (j, items) { if (items[i]) { if (items[i].__mergeCols.length > 1) { var wid = 0; BI.each(sizes, function (t, s) { if (items[i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += items[i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].attr("width", wid - 1).css("width", wid - 1); } else { items[i].attr("width", wid).css("width", wid); } } else { items[i].attr("width", "").css("width", ""); } } else { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } } }); BI.each(bodyItems, function (j, items) { if (items[i]) { if (bodyTds[j][i].__mergeCols.length > 1) { var wid = 0; BI.each(sizes, function (t, s) { if (bodyTds[j][i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += bodyTds[j][i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].element.attr("width", "").css("width", ""); } } else { if (BI.isNumeric(w)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", w - 1).css("width", w - 1); } else { items[i].element.attr("width", w).css("width", w); } } else { items[i].element.attr("width", "").css("width", ""); } } } }); } }) }; run(topleft); run(topright); var lw = 0, rw = 0; BI.each(columnSize, function (i, size) { if (o.freezeCols.contains(i)) { lw += size; } else { rw += size; } }); lw = this._calculateWidth(lw); rw = this._calculateWidth(rw); if (BI.isNumeric(lw)) { lw = BI.parseFloat(lw) + o.freezeCols.length; } if (BI.isNumeric(rw)) { rw = BI.parseFloat(rw) + columnSize.length - o.freezeCols.length; } this.topLeftContainer.element.width(isRight ? rw : lw); this.topRightContainer.element.width(isRight ? lw : rw); this.scrollTopLeft.element[0].scrollLeft = this.scrollBottomLeft.element[0].scrollLeft; this.scrollTopRight.element[0].scrollLeft = this.scrollBottomRight.element[0].scrollLeft; } else { BI.each(this.colgroupTds, function (i, colgroup) { var width = colgroup.attr("width") | 0; if (width !== columnSize[i]) { var w = self._calculateWidth(columnSize[i]); colgroup.attr("width", w).css("width", w); BI.each(self.headerTds, function (j, items) { if (items[i]) { if (items[i].__mergeCols.length > 1) { var wid = 0; BI.each(columnSize, function (t, s) { if (items[i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += items[i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].attr("width", "").css("width", ""); } } else { if (i == BI.size(items) - 1) { items[i].attr("width", w - 1).css("width", w - 1); } else { items[i].attr("width", w).css("width", w); } } } }); BI.each(self.headerItems, function (j, items) { if (items[i]) { if (self.headerTds[j][i].__mergeCols.length > 1) { var wid = 0; BI.each(columnSize, function (t, s) { if (self.headerTds[j][i].__mergeCols.contains(t)) { wid += s; } }); wid = self._calculateWidth(wid); if (wid > 1) { wid += self.headerTds[j][i].__mergeCols.length - 1; } if (BI.isNumeric(wid)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", wid - 1).css("width", wid - 1); } else { items[i].element.attr("width", wid).css("width", wid); } } else { items[i].element.attr("width", "").css("width", ""); } } else { if (BI.isNumeric(w)) { if (i == BI.size(items) - 1) { items[i].element.attr("width", w - 1).css("width", w - 1); } else { items[i].element.attr("width", w).css("width", w); } } else { items[i].element.attr("width", "").css("width", ""); } } } }); } }); var cW = this._calculateWidth(BI.sum(columnSize)); if (cW > 1.05) { cW = cW + columnSize.length; } this.tableContainer.element.width(cW); } }, setRegionColumnSize: function (columnSize) { var self = this, o = this.options; o.regionColumnSize = columnSize; if (o.freezeCols.length === 0) { if (o.isNeedFreeze) { this.partitions.attr("columnSize", this._isRightFreeze() ? ['fill', 0] : [0, 'fill']); this.partitions.resize(); } else { this.tableContainer.element.width(columnSize[0]); } } else if (o.freezeCols.length > 0 && o.freezeCols.length < o.columnSize.length) { if (o.isNeedFreeze) { this.partitions.attr("columnSize", columnSize); this.partitions.resize(); } else { this.tableContainer.element.width(columnSize[0]); } } else { if (o.isNeedFreeze) { this.partitions.attr("columnSize", this._isRightFreeze() ? [0, 'fill'] : ['fill', 0]); this.partitions.resize(); } else { this.tableContainer.element.width(columnSize[0]); } } }, getRegionColumnSize: function () { return this.options.regionColumnSize; }, getCalculateRegionColumnSize: function () { var o = this.options; if (o.isNeedFreeze) { return [this.scrollBottomLeft.element.width(), this.scrollBottomRight.element.width()]; } return [this.scrollBottomRight.element.width()]; }, getCalculateRegionRowSize: function () { var o = this.options; if (o.isNeedFreeze) { return [this.scrollTopRight.element.height(), this.scrollBottomRight.element.height()]; } return [this.scrollBottomRight.element.height()]; }, getClientRegionColumnSize: function () { var o = this.options; if (o.isNeedFreeze) { return [this.scrollBottomLeft.element[0].clientWidth, this.scrollBottomRight.element[0].clientWidth]; } return [this.scrollBottomRight.element[0].clientWidth]; }, getClientRegionRowSize: function () { var o = this.options; if (o.isNeedFreeze) { return [this.scrollBottomLeft.element[0].clientHeight, this.scrollBottomRight.element[0].clientHeight]; } return [this.scrollBottomRight.element[0].clientHeight]; }, getScrollRegionColumnSize: function () { var o = this.options; if (o.isNeedFreeze) { return [this.scrollBottomLeft.element[0].scrollWidth, this.scrollBottomRight.element[0].scrollWidth]; } return [this.scrollBottomRight.element[0].scrollWidth]; }, getScrollRegionRowSize: function () { var o = this.options; if (o.isNeedFreeze) { if (o.freezeCols.length < o.columnSize.length) { return [this.scrollTopRight.element[0].scrollHeight, this.scrollBottomRight.element[0].scrollHeight]; } else { return [this.scrollTopLeft.element[0].scrollHeight, this.scrollBottomLeft.element[0].scrollHeight]; } } return [this.scrollBottomRight.element[0].scrollHeight]; }, hasVerticalScroll: function () { var o = this.options; if (o.isNeedFreeze) { return this.scrollBottomRight.element.hasVerticalScroll() || this.scrollBottomLeft.element.hasVerticalScroll(); } return this.scrollBottomRight.element.hasVerticalScroll(); }, setVerticalScroll: function (scrollTop) { var o = this.options; if (o.isNeedFreeze) { if (this.scrollBottomRight.element[0].scrollTop !== scrollTop) { this.scrollBottomRight.element[0].scrollTop = scrollTop; } if (this.scrollBottomLeft.element[0].scrollTop !== scrollTop) { this.scrollBottomLeft.element[0].scrollTop = scrollTop; } } else { if (this.scrollBottomRight.element[0].scrollTop !== scrollTop) { this.scrollBottomRight.element[0].scrollTop = scrollTop; } } }, setLeftHorizontalScroll: function (scrollLeft) { var o = this.options; if (o.isNeedFreeze) { if (this.scrollBottomLeft.element[0].scrollLeft !== scrollLeft) { this.scrollBottomLeft.element[0].scrollLeft = scrollLeft; } if (this.scrollTopLeft.element[0].scrollLeft !== scrollLeft) { this.scrollTopLeft.element[0].scrollLeft = scrollLeft; } } else { if (this.scrollBottomRight.element[0].scrollLeft !== scrollLeft) { this.scrollBottomRight.element[0].scrollLeft = scrollLeft; } } }, setRightHorizontalScroll: function (scrollLeft) { var o = this.options; if (o.isNeedFreeze) { if (this.scrollBottomRight.element[0].scrollLeft !== scrollLeft) { this.scrollBottomRight.element[0].scrollLeft = scrollLeft; } if (this.scrollTopRight.element[0].scrollLeft !== scrollLeft) { this.scrollTopRight.element[0].scrollLeft = scrollLeft; } } else { if (this.scrollBottomRight.element[0].scrollLeft !== scrollLeft) { this.scrollBottomRight.element[0].scrollLeft = scrollLeft; } } }, getVerticalScroll: function () { var o = this.options; if (o.isNeedFreeze) { return this.scrollBottomRight.element[0].scrollTop || this.scrollBottomLeft.element[0].scrollTop; } return this.scrollBottomRight.element[0].scrollTop; }, getLeftHorizontalScroll: function () { var o = this.options; if (o.isNeedFreeze) { return this.scrollBottomLeft.element[0].scrollLeft; } return this.scrollBottomRight.element[0].scrollLeft; }, getRightHorizontalScroll: function () { var o = this.options; if (o.isNeedFreeze) { return this.scrollBottomRight.element[0].scrollLeft; } return this.scrollBottomRight.element[0].scrollLeft; }, getColumns: function () { var o = this.options; if (o.isNeedFreeze) { return { topLeft: this.topLeftBodyItems, topRight: this.topRightBodyItems, bottomLeft: this.bottomLeftBodyItems, bottomRight: this.bottomRightBodyItems } } else { return { header: this.headerItems, body: this.bodyItems, footer: this.footerItems } } }, populate: function (items, header) { this.options.items = items || []; if (header) { this.options.header = header; } this.empty(); if (this.options.isNeedFreeze) { this._createFreezeTable(); } else { this._createNormalTable(); } } }) ; BI.Table.EVENT_TABLE_AFTER_INIT = "EVENT_TABLE_AFTER_INIT"; BI.Table.EVENT_TABLE_RESIZE = "EVENT_TABLE_RESIZE"; BI.Table.EVENT_TABLE_SCROLL = "EVENT_TABLE_SCROLL"; BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE = "EVENT_TABLE_BEFORE_COLUMN_RESIZE"; BI.Table.EVENT_TABLE_COLUMN_RESIZE = "EVENT_TABLE_COLUMN_RESIZE"; BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE = "EVENT_TABLE_AFTER_COLUMN_RESIZE"; BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE = "EVENT_TABLE_BEFORE_REGION_RESIZE"; BI.Table.EVENT_TABLE_REGION_RESIZE = "EVENT_TABLE_REGION_RESIZE"; BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE = "EVENT_TABLE_AFTER_REGION_RESIZE"; BI.shortcut("bi.table_view", BI.Table); /** * * 表格单元格 * * Created by GUY on 2016/1/12. * @class BI.ResizableTableCell * @extends BI.Widget */ BI.ResizableTableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ResizableTableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-resizable-table-cell", cell: {}, minSize: 15, // suitableSize, maxSize: Number.MAX_VALUE, start: BI.emptyFn, resize: BI.emptyFn, stop: BI.emptyFn }) }, _init: function () { BI.ResizableTableCell.superclass._init.apply(this, arguments); var self = this, o = this.options; this.cell = BI.createWidget(BI.extend({type: "bi.label"}, o.cell, {width: o.width, height: o.height})); var startDrag = false; var size = 0, offset = 0, defaultSize = o.width; function optimizeSize(s) { var optSize = BI.clamp(s, o.minSize, o.maxSize || Number.MAX_VALUE); // if (o.suitableSize) { // if (Math.abs(o.suitableSize - optSize) < 5) { // optSize = o.suitableSize; // self.handler.element.addClass("suitable"); // } else { // self.handler.element.removeClass("suitable"); // } // } return optSize; } var mouseMoveTracker = new BI.MouseMoveTracker(function (deltaX, deltaY) { if (mouseMoveTracker.isDragging()) { startDrag = true; offset += deltaX; size = optimizeSize(defaultSize + offset); self.handler.element.addClass("dragging"); o.resize(size); } }, function () { if (startDrag === true) { size = optimizeSize(size); o.stop(size); size = 0; offset = 0; defaultSize = o.width; startDrag = false; } self.handler.element.removeClass("dragging"); self.handler.element.removeClass("suitable"); mouseMoveTracker.releaseMouseMoves(); }, document); this.handler = BI.createWidget({ type: "bi.absolute", cls: "resizable-table-cell-resizer-container", width: 6, items: [{ el: { type: "bi.layout", cls: "resizable-table-cell-resizer-knob", width: 4 }, right: 0, top: 0, bottom: 0 }] }); this.handler.element.on("mousedown", function (event) { defaultSize = o.width; optimizeSize(defaultSize); mouseMoveTracker.captureMouseMoves(event); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.cell, left: 0, right: 0, top: 0, bottom: 0 }, { el: this.handler, right: 0, top: 0, bottom: 0 }] }) }, setWidth: function (width) { BI.ResizableTableCell.superclass.setWidth.apply(this, arguments); var o = this.options; this.cell.setWidth(o.width); }, setHeight: function (height) { BI.ResizableTableCell.superclass.setHeight.apply(this, arguments); var o = this.options; this.cell.setHeight(o.height); } }); BI.shortcut("bi.resizable_table_cell", BI.ResizableTableCell);/** * * 可调整列宽的grid表格 * * Created by GUY on 2016/1/12. * @class BI.ResizableTable * @extends BI.Widget */ BI.ResizableTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ResizableTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-resizable-table", el: { type: "bi.grid_table" }, isNeedFreeze: false, isNeedResize: true, isResizeAdapt: false, headerRowSize: 25, rowSize: 25, isNeedMerge: true,//是否需要合并单元格 mergeCols: [], mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], freezeCols: [], header: [], items: [], regionColumnSize: [] }) }, _init: function () { BI.ResizableTable.superclass._init.apply(this, arguments); var self = this, o = this.options; this.resizer = BI.createWidget({ type: "bi.layout", cls: "resizable-table-resizer", invisible: true, width: 2 }); this.regionResizerHandler = this._createResizerHandler(); this.table = BI.createWidget(o.el, { type: "bi.grid_table", element: this, width: o.width, height: o.height, headerRowSize: o.headerRowSize, rowSize: o.rowSize, columnSize: o.columnSize, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: BI.bind(this._mergeRule, this), header: this._formatHeader(o.header), items: o.items, regionColumnSize: o.regionColumnSize }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.regionResizerHandler, left: 0, top: 0, bottom: 0 }, { el: this.resizer, left: 0, top: 0 }] }); this._populate(); }, _mergeRule: function (row1, row2) { var o = this.options; if (row1.type === "bi.resizable_table_cell") { row1 = row1.cell; } if (row2.type === "bi.resizable_table_cell") { row2 = row2.cell; } return o.mergeRule(row1, row2); }, _createResizerHandler: function () { var self = this, o = this.options; var regionResizerHandler = BI.createWidget({ type: "bi.absolute", cls: "resizable-table-region-resizer", invisible: true, width: 6, items: [{ el: { type: "bi.layout", width: 2, cls: "resizable-table-region-resizer-knob" }, left: 2, top: 0, bottom: 0 }] }); var size = 0, offset = 0, defaultSize = 0, start = false; var mouseMoveTracker = new BI.MouseMoveTracker(function (deltaX, deltaY) { if (mouseMoveTracker.isDragging()) { start = true; offset += deltaX; size = BI.clamp(defaultSize + offset, 15, o.width - 15); self.regionResizerHandler.element.addClass("dragging"); self._setRegionResizerHandlerPosition(size - 3, 0); } }, function () { if (start === true) { o.regionColumnSize[0] = BI.clamp(size, 15, o.width - 15); self.table.setRegionColumnSize(o.regionColumnSize); if (o.isResizeAdapt === true) { var freezeColumnSize = self._getFreezeColumnSize(); o.columnSize[self._getFreezeColLength() - 1] += o.regionColumnSize[0] - freezeColumnSize; self.table.setColumnSize(o.columnSize); } self.table.populate(); self._populate(); self.regionResizerHandler.element.removeClass("dragging"); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE); start = false; } mouseMoveTracker.releaseMouseMoves(); }, document); regionResizerHandler.element.on("mousedown", function (event) { defaultSize = size = self._getRegionSize(); offset = 0; self._setResizerPosition(0, 0); mouseMoveTracker.captureMouseMoves(event); }); return regionResizerHandler; }, _setResizerPosition: function (left, top) { this.resizer.element.css({ left: left + "px", top: top + "px" }); }, _setRegionResizerHandlerPosition: function (left, top) { this.regionResizerHandler.element.css({ left: left + "px", top: top + "px" }); }, _getRegionSize: function () { var o = this.options; var regionSize = o.regionColumnSize[0] || 0; if (o.isNeedFreeze === false || o.freezeCols.length === 0) { return 0; } if (!regionSize) { BI.each(o.freezeCols, function (i, col) { regionSize += o.columnSize[col]; }); } return regionSize; }, _getRegionRowSize: function () { var o = this.options; return [o.header.length * o.headerRowSize, Math.min(o.height - o.header.length * o.headerRowSize, o.items.length * o.rowSize)]; }, _getFreezeColLength: function () { return this.options.freezeCols.length; }, _getFreezeColumnSize: function () { var columnSize = this.options.columnSize; var sum = 0; for (var i = 0, len = this._getFreezeColLength(); i < len; i++) { sum += columnSize[i]; } return sum; }, _getResizerLeft: function (j) { var left = 0; var columnSize = this.options.columnSize; var freezeColLength = this._getFreezeColLength(); for (var i = (j >= freezeColLength ? freezeColLength : 0); i < j; i++) { left += columnSize[i] || 0; } if (j >= freezeColLength) { left += this.table.getRegionSize(); left -= this.table.getRightHorizontalScroll(); } else { left -= this.table.getLeftHorizontalScroll(); } return left; }, _formatHeader: function (header) { var self = this, o = this.options; var result = []; var resize = function (j, size) { self.resizer.setVisible(true); var height = o.headerRowSize + self._getRegionRowSize()[1]; self.resizer.setHeight(height); //TODO 不知道为什么加入这段代码会使得列宽调整出问题 // if (o.minColumnSize[j]) { // if (size === o.minColumnSize[j]) { // self.resizer.element.addClass("suitable"); // } else { // self.resizer.element.removeClass("suitable"); // } // } self._setResizerPosition(self._getResizerLeft(j) + size, (o.header.length - 1) * o.headerRowSize); }; var stop = function (j, size) { self.resizer.setVisible(false); var columnSize = o.columnSize.slice(); columnSize[j] = size; o.columnSize = columnSize; self.table.setColumnSize(columnSize); self.table.populate(); self._populate(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE); }; BI.each(header, function (i, cols) { if (i === header.length - 1) { result[i] = []; BI.each(cols, function (j, col) { if (j === self._getFreezeColLength() - 1 || j === cols.length - 1) { result[i][j] = col; } else { result[i][j] = { type: "bi.resizable_table_cell", cell: col, suitableSize: o.minColumnSize[j], maxSize: o.maxColumnSize[j], resize: BI.bind(resize, null, j), stop: BI.bind(stop, null, j) }; if (o.isNeedMerge) { var r = i; while (r > 0 && self._mergeRule(result[r][j], result[r - 1][j])) { result[r - 1][j] = { type: "bi.resizable_table_cell", cell: result[r - 1][j], suitableSize: o.minColumnSize[j], maxSize: o.maxColumnSize[j], resize: BI.bind(resize, null, j), stop: BI.bind(stop, null, j) }; r--; } } } }); } else { result.push(cols); } }); return result; }, _populate: function () { var o = this.options; var regionSize = this._getRegionSize(); if (regionSize > 0) { this.regionResizerHandler.setVisible(true); this._setRegionResizerHandlerPosition(regionSize - 3, 0); } else { this.regionResizerHandler.setVisible(false); } }, setWidth: function (width) { BI.ResizableTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(width) }, setHeight: function (height) { BI.ResizableTable.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; this.table.setColumnSize(columnSize); }, getColumnSize: function () { return this.table.getColumnSize(); }, setRegionColumnSize: function (columnSize) { this.options.regionColumnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, attr: function () { BI.ResizableTable.superclass.attr.apply(this, arguments); this.table.attr.apply(this.table, arguments); }, restore: function () { this.table.restore(); }, populate: function (items, header) { if (items) { this.options.items = items; } if (header) { this.options.header = header; if (this.options.isNeedResize) { header = this._formatHeader(header); } } this.table.populate(items, header); this._populate(); } }); BI.shortcut("bi.resizable_table", BI.ResizableTable);/** * * 自定义树 * * Created by GUY on 2015/9/7. * @class BI.CustomTree * @extends BI.Single */ BI.CustomTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.CustomTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-custom-tree", expander: { el: {}, popup: { type: "bi.custom_tree" } }, items: [], itemsCreator: BI.emptyFn, el: { type: "bi.button_tree", chooseType: 0, layouts: [{ type: "bi.vertical" }] } }) }, _init: function () { BI.CustomTree.superclass._init.apply(this, arguments); this.initTree(this.options.items); }, _formatItems: function (nodes) { var self = this, o = this.options; nodes = BI.Tree.transformToTreeFormat(nodes); var items = []; BI.each(nodes, function (i, node) { if (BI.isNotEmptyArray(node.children) || node.isParent === true) { var item = BI.extend({ type: "bi.expander", el: {}, popup: {type: "bi.custom_tree"} }, BI.deepClone(o.expander), { id: node.id, pId: node.pId, value: node.value }); var el = BI.stripEL(node); if (!BI.isWidget(el)) { el = BI.clone(el); delete el.children; BI.extend(item.el, el); } else { item.el = el; } item.popup.expander = BI.deepClone(o.expander); item.items = item.popup.items = node.children; item.itemsCreator = item.popup.itemsCreator = function (op) { if (BI.isNotNull(op.node)) {//从子节点传过来的itemsCreator直接向上传递 return o.itemsCreator.apply(self, arguments); } var args = Array.prototype.slice.call(arguments, 0); args[0].node = node; return o.itemsCreator.apply(self, args); }; BI.isNull(item.popup.el) && (item.popup.el = BI.deepClone(o.el)); items.push(item); } else { items.push(node); } }); return items; }, //构造树结构, initTree: function (nodes) { var self = this, o = this.options; this.tree = BI.createWidget(o.el, { element: this, items: this._formatItems(nodes), itemsCreator: function (op, callback) { o.itemsCreator.apply(this, [op, function (items) { var args = Array.prototype.slice.call(arguments, 0); args[0] = self._formatItems(items); callback.apply(null, args); }]); } }); this.tree.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.CustomTree.EVENT_CHANGE, val, obj); } }) }, //生成树方法 stroke: function (nodes) { this.populate.apply(this, arguments); }, populate: function (nodes) { var args = Array.prototype.slice.call(arguments, 0); if (arguments.length > 0) { args[0] = this._formatItems(nodes); } this.tree.populate.apply(this.tree, args); }, setValue: function (v) { this.tree && this.tree.setValue(v); }, getValue: function () { return this.tree ? this.tree.getValue() : []; }, getAllButtons: function () { return this.tree ? this.tree.getAllButtons() : []; }, getAllLeaves: function () { return this.tree ? this.tree.getAllLeaves() : []; }, getNodeById: function (id) { return this.tree && this.tree.getNodeById(id); }, getNodeByValue: function (id) { return this.tree && this.tree.getNodeByValue(id); }, empty: function () { this.tree.empty(); } }); BI.CustomTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.custom_tree", BI.CustomTree);/* * JQuery zTree core v3.5.18 * http://zTree.me/ * * Copyright (c) 2010 Hunter.z * * Licensed same as jquery - MIT License * http://www.opensource.org/licenses/mit-license.php * * email: hunter.z@263.net * Date: 2015-06-18 */ (function($){ var settings = {}, roots = {}, caches = {}, //default consts of core _consts = { className: { BUTTON: "button", LEVEL: "level", ICO_LOADING: "ico_loading", SWITCH: "switch" }, event: { NODECREATED: "ztree_nodeCreated", CLICK: "ztree_click", EXPAND: "ztree_expand", COLLAPSE: "ztree_collapse", ASYNC_SUCCESS: "ztree_async_success", ASYNC_ERROR: "ztree_async_error", REMOVE: "ztree_remove", SELECTED: "ztree_selected", UNSELECTED: "ztree_unselected" }, id: { A: "_a", ICON: "_ico", SPAN: "_span", SWITCH: "_switch", UL: "_ul" }, line: { ROOT: "root", ROOTS: "roots", CENTER: "center", BOTTOM: "bottom", NOLINE: "noline", LINE: "line" }, folder: { OPEN: "open", CLOSE: "close", DOCU: "docu" }, node: { CURSELECTED: "curSelectedNode" } }, //default setting of core _setting = { treeId: "", treeObj: null, view: { addDiyDom: null, autoCancelSelected: true, dblClickExpand: true, expandSpeed: "fast", fontCss: {}, nameIsHTML: false, selectedMulti: true, showIcon: true, showLine: true, showTitle: true, txtSelectedEnable: false }, data: { key: { children: "children", name: "name", title: "", url: "url" }, simpleData: { enable: false, idKey: "id", pIdKey: "pId", rootPId: null }, keep: { parent: false, leaf: false } }, async: { enable: false, contentType: "application/x-www-form-urlencoded", type: "post", dataType: "text", url: "", autoParam: [], otherParam: [], dataFilter: null }, callback: { beforeAsync:null, beforeClick:null, beforeDblClick:null, beforeRightClick:null, beforeMouseDown:null, beforeMouseUp:null, beforeExpand:null, beforeCollapse:null, beforeRemove:null, onAsyncError:null, onAsyncSuccess:null, onNodeCreated:null, onClick:null, onDblClick:null, onRightClick:null, onMouseDown:null, onMouseUp:null, onExpand:null, onCollapse:null, onRemove:null } }, //default root of core //zTree use root to save full data _initRoot = function (setting) { var r = data.getRoot(setting); if (!r) { r = {}; data.setRoot(setting, r); } r[setting.data.key.children] = []; r.expandTriggerFlag = false; r.curSelectedList = []; r.noSelection = true; r.createdNodes = []; r.zId = 0; r._ver = (new Date()).getTime(); }, //default cache of core _initCache = function(setting) { var c = data.getCache(setting); if (!c) { c = {}; data.setCache(setting, c); } c.nodes = []; c.doms = []; }, //default bindEvent of core _bindEvent = function(setting) { var o = setting.treeObj, c = consts.event; o.bind(c.NODECREATED, function (event, treeId, node) { tools.apply(setting.callback.onNodeCreated, [event, treeId, node]); }); o.bind(c.CLICK, function (event, srcEvent, treeId, node, clickFlag) { tools.apply(setting.callback.onClick, [srcEvent, treeId, node, clickFlag]); }); o.bind(c.EXPAND, function (event, treeId, node) { tools.apply(setting.callback.onExpand, [event, treeId, node]); }); o.bind(c.COLLAPSE, function (event, treeId, node) { tools.apply(setting.callback.onCollapse, [event, treeId, node]); }); o.bind(c.ASYNC_SUCCESS, function (event, treeId, node, msg) { tools.apply(setting.callback.onAsyncSuccess, [event, treeId, node, msg]); }); o.bind(c.ASYNC_ERROR, function (event, treeId, node, XMLHttpRequest, textStatus, errorThrown) { tools.apply(setting.callback.onAsyncError, [event, treeId, node, XMLHttpRequest, textStatus, errorThrown]); }); o.bind(c.REMOVE, function (event, treeId, treeNode) { tools.apply(setting.callback.onRemove, [event, treeId, treeNode]); }); o.bind(c.SELECTED, function (event, srcEvent, treeId, node) { tools.apply(setting.callback.onSelected, [srcEvent, treeId, node]); }); o.bind(c.UNSELECTED, function (event, srcEvent, treeId, node) { tools.apply(setting.callback.onUnSelected, [srcEvent, treeId, node]); }); }, _unbindEvent = function(setting) { var o = setting.treeObj, c = consts.event; o.unbind(c.NODECREATED) .unbind(c.CLICK) .unbind(c.EXPAND) .unbind(c.COLLAPSE) .unbind(c.ASYNC_SUCCESS) .unbind(c.ASYNC_ERROR) .unbind(c.REMOVE) .unbind(c.SELECTED) .unbind(c.UNSELECTED); }, //default event proxy of core _eventProxy = function(event) { var target = event.target, setting = data.getSetting(event.data.treeId), tId = "", node = null, nodeEventType = "", treeEventType = "", nodeEventCallback = null, treeEventCallback = null, tmp = null; if (tools.eqs(event.type, "mousedown")) { treeEventType = "mousedown"; } else if (tools.eqs(event.type, "mouseup")) { treeEventType = "mouseup"; } else if (tools.eqs(event.type, "contextmenu")) { treeEventType = "contextmenu"; } else if (tools.eqs(event.type, "click")) { if (tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.SWITCH) !== null) { tId = tools.getNodeMainDom(target).id; nodeEventType = "switchNode"; } else { tmp = tools.getMDom(setting, target, [{tagName:"a", attrName:"treeNode"+consts.id.A}]); if (tmp) { tId = tools.getNodeMainDom(tmp).id; nodeEventType = "clickNode"; } } } else if (tools.eqs(event.type, "dblclick")) { treeEventType = "dblclick"; tmp = tools.getMDom(setting, target, [{tagName:"a", attrName:"treeNode"+consts.id.A}]); if (tmp) { tId = tools.getNodeMainDom(tmp).id; nodeEventType = "switchNode"; } } if (treeEventType.length > 0 && tId.length == 0) { tmp = tools.getMDom(setting, target, [{tagName:"a", attrName:"treeNode"+consts.id.A}]); if (tmp) {tId = tools.getNodeMainDom(tmp).id;} } // event to node if (tId.length>0) { node = data.getNodeCache(setting, tId); switch (nodeEventType) { case "switchNode" : if (!node.isParent) { nodeEventType = ""; } else if (tools.eqs(event.type, "click") || (tools.eqs(event.type, "dblclick") && tools.apply(setting.view.dblClickExpand, [setting.treeId, node], setting.view.dblClickExpand))) { nodeEventCallback = handler.onSwitchNode; } else { nodeEventType = ""; } break; case "clickNode" : nodeEventCallback = handler.onClickNode; break; } } // event to zTree switch (treeEventType) { case "mousedown" : treeEventCallback = handler.onZTreeMousedown; break; case "mouseup" : treeEventCallback = handler.onZTreeMouseup; break; case "dblclick" : treeEventCallback = handler.onZTreeDblclick; break; case "contextmenu" : treeEventCallback = handler.onZTreeContextmenu; break; } var proxyResult = { stop: false, node: node, nodeEventType: nodeEventType, nodeEventCallback: nodeEventCallback, treeEventType: treeEventType, treeEventCallback: treeEventCallback }; return proxyResult }, //default init node of core _initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { if (!n) return; var r = data.getRoot(setting), childKey = setting.data.key.children; n.level = level; n.tId = setting.treeId + "_" + (++r.zId); n.parentTId = parentNode ? parentNode.tId : null; n.open = (typeof n.open == "string") ? tools.eqs(n.open, "true") : !!n.open; if (n[childKey] && n[childKey].length > 0) { n.isParent = true; n.zAsync = true; } else { n.isParent = (typeof n.isParent == "string") ? tools.eqs(n.isParent, "true") : !!n.isParent; n.open = (n.isParent && !setting.async.enable) ? n.open : false; n.zAsync = !n.isParent; } n.isFirstNode = isFirstNode; n.isLastNode = isLastNode; n.getParentNode = function() {return data.getNodeCache(setting, n.parentTId);}; n.getPreNode = function() {return data.getPreNode(setting, n);}; n.getNextNode = function() {return data.getNextNode(setting, n);}; n.isAjaxing = false; data.fixPIdKeyValue(setting, n); }, _init = { bind: [_bindEvent], unbind: [_unbindEvent], caches: [_initCache], nodes: [_initNode], proxys: [_eventProxy], roots: [_initRoot], beforeA: [], afterA: [], innerBeforeA: [], innerAfterA: [], zTreeTools: [] }, //method of operate data data = { addNodeCache: function(setting, node) { data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = node; }, getNodeCacheId: function(tId) { return tId.substring(tId.lastIndexOf("_")+1); }, addAfterA: function(afterA) { _init.afterA.push(afterA); }, addBeforeA: function(beforeA) { _init.beforeA.push(beforeA); }, addInnerAfterA: function(innerAfterA) { _init.innerAfterA.push(innerAfterA); }, addInnerBeforeA: function(innerBeforeA) { _init.innerBeforeA.push(innerBeforeA); }, addInitBind: function(bindEvent) { _init.bind.push(bindEvent); }, addInitUnBind: function(unbindEvent) { _init.unbind.push(unbindEvent); }, addInitCache: function(initCache) { _init.caches.push(initCache); }, addInitNode: function(initNode) { _init.nodes.push(initNode); }, addInitProxy: function(initProxy, isFirst) { if (!!isFirst) { _init.proxys.splice(0,0,initProxy); } else { _init.proxys.push(initProxy); } }, addInitRoot: function(initRoot) { _init.roots.push(initRoot); }, addNodesData: function(setting, parentNode, nodes) { var childKey = setting.data.key.children; if (!parentNode[childKey]) parentNode[childKey] = []; if (parentNode[childKey].length > 0) { parentNode[childKey][parentNode[childKey].length - 1].isLastNode = false; view.setNodeLineIcos(setting, parentNode[childKey][parentNode[childKey].length - 1]); } parentNode.isParent = true; parentNode[childKey] = parentNode[childKey].concat(nodes); }, addSelectedNode: function(setting, node) { var root = data.getRoot(setting); if (!data.isSelectedNode(setting, node)) { root.curSelectedList.push(node); } }, addCreatedNode: function(setting, node) { if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) { var root = data.getRoot(setting); root.createdNodes.push(node); } }, addZTreeTools: function(zTreeTools) { _init.zTreeTools.push(zTreeTools); }, exSetting: function(s) { $.extend(true, _setting, s); }, fixPIdKeyValue: function(setting, node) { if (setting.data.simpleData.enable) { node[setting.data.simpleData.pIdKey] = node.parentTId ? node.getParentNode()[setting.data.simpleData.idKey] : setting.data.simpleData.rootPId; } }, getAfterA: function(setting, node, array) { for (var i=0, j=_init.afterA.length; i<j; i++) { _init.afterA[i].apply(this, arguments); } }, getBeforeA: function(setting, node, array) { for (var i=0, j=_init.beforeA.length; i<j; i++) { _init.beforeA[i].apply(this, arguments); } }, getInnerAfterA: function(setting, node, array) { for (var i=0, j=_init.innerAfterA.length; i<j; i++) { _init.innerAfterA[i].apply(this, arguments); } }, getInnerBeforeA: function(setting, node, array) { for (var i=0, j=_init.innerBeforeA.length; i<j; i++) { _init.innerBeforeA[i].apply(this, arguments); } }, getCache: function(setting) { return caches[setting.treeId]; }, getNextNode: function(setting, node) { if (!node) return null; var childKey = setting.data.key.children, p = node.parentTId ? node.getParentNode() : data.getRoot(setting); for (var i=0, l=p[childKey].length-1; i<=l; i++) { if (p[childKey][i] === node) { return (i==l ? null : p[childKey][i+1]); } } return null; }, getNodeByParam: function(setting, nodes, key, value) { if (!nodes || !key) return null; var childKey = setting.data.key.children; for (var i = 0, l = nodes.length; i < l; i++) { if (nodes[i][key] == value) { return nodes[i]; } var tmp = data.getNodeByParam(setting, nodes[i][childKey], key, value); if (tmp) return tmp; } return null; }, getNodeCache: function(setting, tId) { if (!tId) return null; var n = caches[setting.treeId].nodes[data.getNodeCacheId(tId)]; return n ? n : null; }, getNodeName: function(setting, node) { var nameKey = setting.data.key.name; return "" + node[nameKey]; }, getNodeTitle: function(setting, node) { var t = setting.data.key.title === "" ? setting.data.key.name : setting.data.key.title; return "" + node[t]; }, getNodes: function(setting) { return data.getRoot(setting)[setting.data.key.children]; }, getNodesByParam: function(setting, nodes, key, value) { if (!nodes || !key) return []; var childKey = setting.data.key.children, result = []; for (var i = 0, l = nodes.length; i < l; i++) { if (nodes[i][key] == value) { result.push(nodes[i]); } result = result.concat(data.getNodesByParam(setting, nodes[i][childKey], key, value)); } return result; }, getNodesByParamFuzzy: function(setting, nodes, key, value) { if (!nodes || !key) return []; var childKey = setting.data.key.children, result = []; value = value.toLowerCase(); for (var i = 0, l = nodes.length; i < l; i++) { if (typeof nodes[i][key] == "string" && nodes[i][key].toLowerCase().indexOf(value)>-1) { result.push(nodes[i]); } result = result.concat(data.getNodesByParamFuzzy(setting, nodes[i][childKey], key, value)); } return result; }, getNodesByFilter: function(setting, nodes, filter, isSingle, invokeParam) { if (!nodes) return (isSingle ? null : []); var childKey = setting.data.key.children, result = isSingle ? null : []; for (var i = 0, l = nodes.length; i < l; i++) { if (tools.apply(filter, [nodes[i], invokeParam], false)) { if (isSingle) {return nodes[i];} result.push(nodes[i]); } var tmpResult = data.getNodesByFilter(setting, nodes[i][childKey], filter, isSingle, invokeParam); if (isSingle && !!tmpResult) {return tmpResult;} result = isSingle ? tmpResult : result.concat(tmpResult); } return result; }, getPreNode: function(setting, node) { if (!node) return null; var childKey = setting.data.key.children, p = node.parentTId ? node.getParentNode() : data.getRoot(setting); for (var i=0, l=p[childKey].length; i<l; i++) { if (p[childKey][i] === node) { return (i==0 ? null : p[childKey][i-1]); } } return null; }, getRoot: function(setting) { return setting ? roots[setting.treeId] : null; }, getRoots: function() { return roots; }, getSetting: function(treeId) { return settings[treeId]; }, getSettings: function() { return settings; }, getZTreeTools: function(treeId) { var r = this.getRoot(this.getSetting(treeId)); return r ? r.treeTools : null; }, initCache: function(setting) { for (var i=0, j=_init.caches.length; i<j; i++) { _init.caches[i].apply(this, arguments); } }, initNode: function(setting, level, node, parentNode, preNode, nextNode) { for (var i=0, j=_init.nodes.length; i<j; i++) { _init.nodes[i].apply(this, arguments); } }, initRoot: function(setting) { for (var i=0, j=_init.roots.length; i<j; i++) { _init.roots[i].apply(this, arguments); } }, isSelectedNode: function(setting, node) { var root = data.getRoot(setting); for (var i=0, j=root.curSelectedList.length; i<j; i++) { if(node === root.curSelectedList[i]) return true; } return false; }, removeNodeCache: function(setting, node) { var childKey = setting.data.key.children; if (node[childKey]) { for (var i=0, l=node[childKey].length; i<l; i++) { arguments.callee(setting, node[childKey][i]); } } data.getCache(setting).nodes[data.getNodeCacheId(node.tId)] = null; }, removeSelectedNode: function(setting, node) { var root = data.getRoot(setting); for (var i=0, j=root.curSelectedList.length; i<j; i++) { if(node === root.curSelectedList[i] || !data.getNodeCache(setting, root.curSelectedList[i].tId)) { root.curSelectedList.splice(i, 1); i--;j--; } } }, setCache: function(setting, cache) { caches[setting.treeId] = cache; }, setRoot: function(setting, root) { roots[setting.treeId] = root; }, setZTreeTools: function(setting, zTreeTools) { for (var i=0, j=_init.zTreeTools.length; i<j; i++) { _init.zTreeTools[i].apply(this, arguments); } }, transformToArrayFormat: function (setting, nodes) { if (!nodes) return []; var childKey = setting.data.key.children, r = []; if (tools.isArray(nodes)) { for (var i=0, l=nodes.length; i<l; i++) { r.push(nodes[i]); if (nodes[i][childKey]) r = r.concat(data.transformToArrayFormat(setting, nodes[i][childKey])); } } else { r.push(nodes); if (nodes[childKey]) r = r.concat(data.transformToArrayFormat(setting, nodes[childKey])); } return r; }, transformTozTreeFormat: function(setting, sNodes) { var i,l, key = setting.data.simpleData.idKey, parentKey = setting.data.simpleData.pIdKey, childKey = setting.data.key.children; if (!key || key=="" || !sNodes) return []; if (tools.isArray(sNodes)) { var r = []; var tmpMap = []; for (i=0, l=sNodes.length; i<l; i++) { tmpMap[sNodes[i][key]] = sNodes[i]; } for (i=0, l=sNodes.length; i<l; i++) { if (tmpMap[sNodes[i][parentKey]] && sNodes[i][key] != sNodes[i][parentKey]) { if (!tmpMap[sNodes[i][parentKey]][childKey]) tmpMap[sNodes[i][parentKey]][childKey] = []; tmpMap[sNodes[i][parentKey]][childKey].push(sNodes[i]); } else { r.push(sNodes[i]); } } return r; }else { return [sNodes]; } } }, //method of event proxy event = { bindEvent: function(setting) { for (var i=0, j=_init.bind.length; i<j; i++) { _init.bind[i].apply(this, arguments); } }, unbindEvent: function(setting) { for (var i=0, j=_init.unbind.length; i<j; i++) { _init.unbind[i].apply(this, arguments); } }, bindTree: function(setting) { var eventParam = { treeId: setting.treeId }, o = setting.treeObj; if (!setting.view.txtSelectedEnable) { // for can't select text o.bind('selectstart', function(e){ var node var n = e.originalEvent.srcElement.nodeName.toLowerCase(); return (n === "input" || n === "textarea" ); }).css({ "-moz-user-select":"-moz-none" }); } o.bind('click', eventParam, event.proxy); o.bind('dblclick', eventParam, event.proxy); o.bind('mouseover', eventParam, event.proxy); o.bind('mouseout', eventParam, event.proxy); o.bind('mousedown', eventParam, event.proxy); o.bind('mouseup', eventParam, event.proxy); o.bind('contextmenu', eventParam, event.proxy); }, unbindTree: function(setting) { var o = setting.treeObj; o.unbind('click', event.proxy) .unbind('dblclick', event.proxy) .unbind('mouseover', event.proxy) .unbind('mouseout', event.proxy) .unbind('mousedown', event.proxy) .unbind('mouseup', event.proxy) .unbind('contextmenu', event.proxy); }, doProxy: function(e) { var results = []; for (var i=0, j=_init.proxys.length; i<j; i++) { var proxyResult = _init.proxys[i].apply(this, arguments); results.push(proxyResult); if (proxyResult.stop) { break; } } return results; }, proxy: function(e) { var setting = data.getSetting(e.data.treeId); if (!tools.uCanDo(setting, e)) return true; var results = event.doProxy(e), r = true, x = false; for (var i=0, l=results.length; i<l; i++) { var proxyResult = results[i]; if (proxyResult.nodeEventCallback) { x = true; r = proxyResult.nodeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r; } if (proxyResult.treeEventCallback) { x = true; r = proxyResult.treeEventCallback.apply(proxyResult, [e, proxyResult.node]) && r; } } return r; } }, //method of event handler handler = { onSwitchNode: function (event, node) { var setting = data.getSetting(event.data.treeId); if (node.open) { if (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false) return true; data.getRoot(setting).expandTriggerFlag = true; view.switchNode(setting, node); } else { if (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false) return true; data.getRoot(setting).expandTriggerFlag = true; view.switchNode(setting, node); } return true; }, onClickNode: function (event, node) { var setting = data.getSetting(event.data.treeId), clickFlag = ( (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey)) && data.isSelectedNode(setting, node)) ? 0 : (setting.view.autoCancelSelected && (event.ctrlKey || event.metaKey) && setting.view.selectedMulti) ? 2 : 1; if (tools.apply(setting.callback.beforeClick, [setting.treeId, node, clickFlag], true) == false) return true; if (clickFlag === 0) { view.cancelPreSelectedNode(setting, node); } else { view.selectNode(setting, node, clickFlag === 2); } setting.treeObj.trigger(consts.event.CLICK, [event, setting.treeId, node, clickFlag]); return true; }, onZTreeMousedown: function(event, node) { var setting = data.getSetting(event.data.treeId); if (tools.apply(setting.callback.beforeMouseDown, [setting.treeId, node], true)) { tools.apply(setting.callback.onMouseDown, [event, setting.treeId, node]); } return true; }, onZTreeMouseup: function(event, node) { var setting = data.getSetting(event.data.treeId); if (tools.apply(setting.callback.beforeMouseUp, [setting.treeId, node], true)) { tools.apply(setting.callback.onMouseUp, [event, setting.treeId, node]); } return true; }, onZTreeDblclick: function(event, node) { var setting = data.getSetting(event.data.treeId); if (tools.apply(setting.callback.beforeDblClick, [setting.treeId, node], true)) { tools.apply(setting.callback.onDblClick, [event, setting.treeId, node]); } return true; }, onZTreeContextmenu: function(event, node) { var setting = data.getSetting(event.data.treeId); if (tools.apply(setting.callback.beforeRightClick, [setting.treeId, node], true)) { tools.apply(setting.callback.onRightClick, [event, setting.treeId, node]); } return (typeof setting.callback.onRightClick) != "function"; } }, //method of tools for zTree tools = { apply: function(fun, param, defaultValue) { if ((typeof fun) == "function") { return fun.apply(zt, param?param:[]); } return defaultValue; }, canAsync: function(setting, node) { var childKey = setting.data.key.children; return (setting.async.enable && node && node.isParent && !(node.zAsync || (node[childKey] && node[childKey].length > 0))); }, clone: function (obj){ if (obj === null) return null; var o = tools.isArray(obj) ? [] : {}; for(var i in obj){ o[i] = (obj[i] instanceof Date) ? new Date(obj[i].getTime()) : (typeof obj[i] === "object" ? arguments.callee(obj[i]) : obj[i]); } return o; }, eqs: function(str1, str2) { return str1.toLowerCase() === str2.toLowerCase(); }, isArray: function(arr) { return Object.prototype.toString.apply(arr) === "[object Array]"; }, $: function(node, exp, setting) { if (!!exp && typeof exp != "string") { setting = exp; exp = ""; } if (typeof node == "string") { return $(node, setting ? setting.treeObj.get(0).ownerDocument : null); } else { return $("#" + node.tId + exp, setting ? setting.treeObj : null); } }, getMDom: function (setting, curDom, targetExpr) { if (!curDom) return null; while (curDom && curDom.id !== setting.treeId) { for (var i=0, l=targetExpr.length; curDom.tagName && i<l; i++) { if (tools.eqs(curDom.tagName, targetExpr[i].tagName) && curDom.getAttribute(targetExpr[i].attrName) !== null) { return curDom; } } curDom = curDom.parentNode; } return null; }, getNodeMainDom:function(target) { return ($(target).parent("li").get(0) || $(target).parentsUntil("li").parent().get(0)); }, isChildOrSelf: function(dom, parentId) { return ( $(dom).closest("#" + parentId).length> 0 ); }, uCanDo: function(setting, e) { return true; } }, //method of operate ztree dom view = { addNodes: function(setting, parentNode, newNodes, isSilent) { if (setting.data.keep.leaf && parentNode && !parentNode.isParent) { return; } if (!tools.isArray(newNodes)) { newNodes = [newNodes]; } if (setting.data.simpleData.enable) { newNodes = data.transformTozTreeFormat(setting, newNodes); } if (parentNode) { var target_switchObj = $$(parentNode, consts.id.SWITCH, setting), target_icoObj = $$(parentNode, consts.id.ICON, setting), target_ulObj = $$(parentNode, consts.id.UL, setting); if (!parentNode.open) { view.replaceSwitchClass(parentNode, target_switchObj, consts.folder.CLOSE); view.replaceIcoClass(parentNode, target_icoObj, consts.folder.CLOSE); parentNode.open = false; target_ulObj.css({ "display": "none" }); } data.addNodesData(setting, parentNode, newNodes); view.createNodes(setting, parentNode.level + 1, newNodes, parentNode); if (!isSilent) { view.expandCollapseParentNode(setting, parentNode, true); } } else { data.addNodesData(setting, data.getRoot(setting), newNodes); view.createNodes(setting, 0, newNodes, null); } }, appendNodes: function(setting, level, nodes, parentNode, initFlag, openFlag) { if (!nodes) return []; var html = [], childKey = setting.data.key.children; for (var i = 0, l = nodes.length; i < l; i++) { var node = nodes[i]; if (initFlag) { var tmpPNode = (parentNode) ? parentNode: data.getRoot(setting), tmpPChild = tmpPNode[childKey], isFirstNode = ((tmpPChild.length == nodes.length) && (i == 0)), isLastNode = (i == (nodes.length - 1)); data.initNode(setting, level, node, parentNode, isFirstNode, isLastNode, openFlag); data.addNodeCache(setting, node); } var childHtml = []; if (node[childKey] && node[childKey].length > 0) { //make child html first, because checkType childHtml = view.appendNodes(setting, level + 1, node[childKey], node, initFlag, openFlag && node.open); } if (openFlag) { view.makeDOMNodeMainBefore(html, setting, node); view.makeDOMNodeLine(html, setting, node); data.getBeforeA(setting, node, html); view.makeDOMNodeNameBefore(html, setting, node); data.getInnerBeforeA(setting, node, html); view.makeDOMNodeIcon(html, setting, node); data.getInnerAfterA(setting, node, html); view.makeDOMNodeNameAfter(html, setting, node); data.getAfterA(setting, node, html); if (node.isParent && node.open) { view.makeUlHtml(setting, node, html, childHtml.join('')); } view.makeDOMNodeMainAfter(html, setting, node); data.addCreatedNode(setting, node); } } return html; }, appendParentULDom: function(setting, node) { var html = [], nObj = $$(node, setting); if (!nObj.get(0) && !!node.parentTId) { view.appendParentULDom(setting, node.getParentNode()); nObj = $$(node, setting); } var ulObj = $$(node, consts.id.UL, setting); if (ulObj.get(0)) { ulObj.remove(); } var childKey = setting.data.key.children, childHtml = view.appendNodes(setting, node.level+1, node[childKey], node, false, true); view.makeUlHtml(setting, node, html, childHtml.join('')); nObj.append(html.join('')); }, asyncNode: function(setting, node, isSilent, callback) { var i, l; if (node && !node.isParent) { tools.apply(callback); return false; } else if (node && node.isAjaxing) { return false; } else if (tools.apply(setting.callback.beforeAsync, [setting.treeId, node], true) == false) { tools.apply(callback); return false; } if (node) { node.isAjaxing = true; var icoObj = $$(node, consts.id.ICON, setting); icoObj.attr({"style":"", "class":consts.className.BUTTON + " " + consts.className.ICO_LOADING}); } var tmpParam = {}; for (i = 0, l = setting.async.autoParam.length; node && i < l; i++) { var pKey = setting.async.autoParam[i].split("="), spKey = pKey; if (pKey.length>1) { spKey = pKey[1]; pKey = pKey[0]; } tmpParam[spKey] = node[pKey]; } if (tools.isArray(setting.async.otherParam)) { for (i = 0, l = setting.async.otherParam.length; i < l; i += 2) { tmpParam[setting.async.otherParam[i]] = setting.async.otherParam[i + 1]; } } else { for (var p in setting.async.otherParam) { tmpParam[p] = setting.async.otherParam[p]; } } var _tmpV = data.getRoot(setting)._ver; $.ajax({ contentType: setting.async.contentType, cache: false, type: setting.async.type, url: tools.apply(setting.async.url, [setting.treeId, node], setting.async.url), data: tmpParam, dataType: setting.async.dataType, success: function(msg) { if (_tmpV != data.getRoot(setting)._ver) { return; } var newNodes = []; try { if (!msg || msg.length == 0) { newNodes = []; } else if (typeof msg == "string") { newNodes = eval("(" + msg + ")"); } else { newNodes = msg; } } catch(err) { newNodes = msg; } if (node) { node.isAjaxing = null; node.zAsync = true; } view.setNodeLineIcos(setting, node); if (newNodes && newNodes !== "") { newNodes = tools.apply(setting.async.dataFilter, [setting.treeId, node, newNodes], newNodes); view.addNodes(setting, node, !!newNodes ? tools.clone(newNodes) : [], !!isSilent); } else { view.addNodes(setting, node, [], !!isSilent); } setting.treeObj.trigger(consts.event.ASYNC_SUCCESS, [setting.treeId, node, msg]); tools.apply(callback); }, error: function(XMLHttpRequest, textStatus, errorThrown) { if (_tmpV != data.getRoot(setting)._ver) { return; } if (node) node.isAjaxing = null; view.setNodeLineIcos(setting, node); setting.treeObj.trigger(consts.event.ASYNC_ERROR, [setting.treeId, node, XMLHttpRequest, textStatus, errorThrown]); } }); return true; }, cancelPreSelectedNode: function (setting, node, excludeNode) { var list = data.getRoot(setting).curSelectedList, i, n; for (i=list.length-1; i>=0; i--) { n = list[i]; if (node === n || (!node && (!excludeNode || excludeNode !== n))) { $$(n, consts.id.A, setting).removeClass(consts.node.CURSELECTED); if (node) { data.removeSelectedNode(setting, node); setting.treeObj.trigger(consts.event.UNSELECTED, [event, setting.treeId, n]); break; } else { list.splice(i, 1); setting.treeObj.trigger(consts.event.UNSELECTED, [event, setting.treeId, n]); } } } }, createNodeCallback: function(setting) { if (!!setting.callback.onNodeCreated || !!setting.view.addDiyDom) { var root = data.getRoot(setting); while (root.createdNodes.length>0) { var node = root.createdNodes.shift(); tools.apply(setting.view.addDiyDom, [setting.treeId, node]); if (!!setting.callback.onNodeCreated) { setting.treeObj.trigger(consts.event.NODECREATED, [setting.treeId, node]); } } } }, createNodes: function(setting, level, nodes, parentNode) { if (!nodes || nodes.length == 0) return; var root = data.getRoot(setting), childKey = setting.data.key.children, openFlag = !parentNode || parentNode.open || !!$$(parentNode[childKey][0], setting).get(0); root.createdNodes = []; var zTreeHtml = view.appendNodes(setting, level, nodes, parentNode, true, openFlag); if (!parentNode) { setting.treeObj.append(zTreeHtml.join('')); } else { var ulObj = $$(parentNode, consts.id.UL, setting); if (ulObj.get(0)) { ulObj.append(zTreeHtml.join('')); } } view.createNodeCallback(setting); }, destroy: function(setting) { if (!setting) return; data.initCache(setting); data.initRoot(setting); event.unbindTree(setting); event.unbindEvent(setting); setting.treeObj.empty(); delete settings[setting.treeId]; }, expandCollapseNode: function(setting, node, expandFlag, animateFlag, callback) { var root = data.getRoot(setting), childKey = setting.data.key.children; if (!node) { tools.apply(callback, []); return; } if (root.expandTriggerFlag) { var _callback = callback; callback = function(){ if (_callback) _callback(); if (node.open) { setting.treeObj.trigger(consts.event.EXPAND, [setting.treeId, node]); } else { setting.treeObj.trigger(consts.event.COLLAPSE, [setting.treeId, node]); } }; root.expandTriggerFlag = false; } if (!node.open && node.isParent && ((!$$(node, consts.id.UL, setting).get(0)) || (node[childKey] && node[childKey].length>0 && !$$(node[childKey][0], setting).get(0)))) { view.appendParentULDom(setting, node); view.createNodeCallback(setting); } if (node.open == expandFlag) { tools.apply(callback, []); return; } var ulObj = $$(node, consts.id.UL, setting), switchObj = $$(node, consts.id.SWITCH, setting), icoObj = $$(node, consts.id.ICON, setting); if (node.isParent) { node.open = !node.open; if (node.iconOpen && node.iconClose) { icoObj.attr("style", view.makeNodeIcoStyle(setting, node)); } if (node.open) { view.replaceSwitchClass(node, switchObj, consts.folder.OPEN); view.replaceIcoClass(node, icoObj, consts.folder.OPEN); if (animateFlag == false || setting.view.expandSpeed == "") { ulObj.show(); tools.apply(callback, []); } else { if (node[childKey] && node[childKey].length > 0) { ulObj.slideDown(setting.view.expandSpeed, callback); } else { ulObj.show(); tools.apply(callback, []); } } } else { view.replaceSwitchClass(node, switchObj, consts.folder.CLOSE); view.replaceIcoClass(node, icoObj, consts.folder.CLOSE); if (animateFlag == false || setting.view.expandSpeed == "" || !(node[childKey] && node[childKey].length > 0)) { ulObj.hide(); tools.apply(callback, []); } else { ulObj.slideUp(setting.view.expandSpeed, callback); } } } else { tools.apply(callback, []); } }, expandCollapseParentNode: function(setting, node, expandFlag, animateFlag, callback) { if (!node) return; if (!node.parentTId) { view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback); return; } else { view.expandCollapseNode(setting, node, expandFlag, animateFlag); } if (node.parentTId) { view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, animateFlag, callback); } }, expandCollapseSonNode: function(setting, node, expandFlag, animateFlag, callback) { var root = data.getRoot(setting), childKey = setting.data.key.children, treeNodes = (node) ? node[childKey]: root[childKey], selfAnimateSign = (node) ? false : animateFlag, expandTriggerFlag = data.getRoot(setting).expandTriggerFlag; data.getRoot(setting).expandTriggerFlag = false; if (treeNodes) { for (var i = 0, l = treeNodes.length; i < l; i++) { if (treeNodes[i]) view.expandCollapseSonNode(setting, treeNodes[i], expandFlag, selfAnimateSign); } } data.getRoot(setting).expandTriggerFlag = expandTriggerFlag; view.expandCollapseNode(setting, node, expandFlag, animateFlag, callback ); }, isSelectedNode: function (setting, node) { if (!node) { return false; } var list = data.getRoot(setting).curSelectedList, i; for (i=list.length-1; i>=0; i--) { if (node === list[i]) { return true; } } return false; }, makeDOMNodeIcon: function(html, setting, node) { var nameStr = data.getNodeName(setting, node), name = setting.view.nameIsHTML ? nameStr : nameStr.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>'); html.push("<span id='", node.tId, consts.id.ICON, "' title='' treeNode", consts.id.ICON," class='", view.makeNodeIcoClass(setting, node), "' style='", view.makeNodeIcoStyle(setting, node), "'></span><span id='", node.tId, consts.id.SPAN, "'>",name,"</span>"); }, makeDOMNodeLine: function(html, setting, node) { html.push("<span id='", node.tId, consts.id.SWITCH, "' title='' class='", view.makeNodeLineClass(setting, node), "' treeNode", consts.id.SWITCH,"></span>"); }, makeDOMNodeMainAfter: function(html, setting, node) { html.push("</li>"); }, makeDOMNodeMainBefore: function(html, setting, node) { html.push("<li id='", node.tId, "' class='", consts.className.LEVEL, node.level,"' tabindex='0' hidefocus='true' treenode>"); }, makeDOMNodeNameAfter: function(html, setting, node) { html.push("</a>"); }, makeDOMNodeNameBefore: function(html, setting, node) { var title = data.getNodeTitle(setting, node), url = view.makeNodeUrl(setting, node), fontcss = view.makeNodeFontCss(setting, node), fontStyle = []; for (var f in fontcss) { fontStyle.push(f, ":", fontcss[f], ";"); } html.push("<a id='", node.tId, consts.id.A, "' class='", consts.className.LEVEL, node.level,"' treeNode", consts.id.A," onclick=\"", (node.click || ''), "\" ", ((url != null && url.length > 0) ? "href='" + url + "'" : ""), " target='",view.makeNodeTarget(node),"' style='", fontStyle.join(''), "'"); if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle) && title) {html.push("title='", title.replace(/'/g,"'").replace(/</g,'<').replace(/>/g,'>'),"'");} html.push(">"); }, makeNodeFontCss: function(setting, node) { var fontCss = tools.apply(setting.view.fontCss, [setting.treeId, node], setting.view.fontCss); return (fontCss && ((typeof fontCss) != "function")) ? fontCss : {}; }, makeNodeIcoClass: function(setting, node) { var icoCss = ["ico"]; if (!node.isAjaxing) { icoCss[0] = (node.iconSkin ? node.iconSkin + "_" : "") + icoCss[0]; if (node.isParent) { icoCss.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE); } else { icoCss.push(consts.folder.DOCU); } } return consts.className.BUTTON + " " + icoCss.join('_'); }, makeNodeIcoStyle: function(setting, node) { var icoStyle = []; if (!node.isAjaxing) { var icon = (node.isParent && node.iconOpen && node.iconClose) ? (node.open ? node.iconOpen : node.iconClose) : node.icon; if (icon) icoStyle.push("background:url(", icon, ") 0 0 no-repeat;"); if (setting.view.showIcon == false || !tools.apply(setting.view.showIcon, [setting.treeId, node], true)) { icoStyle.push("width:0px;height:0px;"); } } return icoStyle.join(''); }, makeNodeLineClass: function(setting, node) { var lineClass = []; if (setting.view.showLine) { if (node.level == 0 && node.isFirstNode && node.isLastNode) { lineClass.push(consts.line.ROOT); } else if (node.level == 0 && node.isFirstNode) { lineClass.push(consts.line.ROOTS); } else if (node.isLastNode) { lineClass.push(consts.line.BOTTOM); } else { lineClass.push(consts.line.CENTER); } } else { lineClass.push(consts.line.NOLINE); } if (node.isParent) { lineClass.push(node.open ? consts.folder.OPEN : consts.folder.CLOSE); } else { lineClass.push(consts.folder.DOCU); } return view.makeNodeLineClassEx(node) + lineClass.join('_'); }, makeNodeLineClassEx: function(node) { return consts.className.BUTTON + " " + consts.className.LEVEL + node.level + " " + consts.className.SWITCH + " "; }, makeNodeTarget: function(node) { return (node.target || "_blank"); }, makeNodeUrl: function(setting, node) { var urlKey = setting.data.key.url; return node[urlKey] ? node[urlKey] : null; }, makeUlHtml: function(setting, node, html, content) { html.push("<ul id='", node.tId, consts.id.UL, "' class='", consts.className.LEVEL, node.level, " ", view.makeUlLineClass(setting, node), "' style='display:", (node.open ? "block": "none"),"'>"); html.push(content); html.push("</ul>"); }, makeUlLineClass: function(setting, node) { return ((setting.view.showLine && !node.isLastNode) ? consts.line.LINE : ""); }, removeChildNodes: function(setting, node) { if (!node) return; var childKey = setting.data.key.children, nodes = node[childKey]; if (!nodes) return; for (var i = 0, l = nodes.length; i < l; i++) { data.removeNodeCache(setting, nodes[i]); } data.removeSelectedNode(setting); delete node[childKey]; if (!setting.data.keep.parent) { node.isParent = false; node.open = false; var tmp_switchObj = $$(node, consts.id.SWITCH, setting), tmp_icoObj = $$(node, consts.id.ICON, setting); view.replaceSwitchClass(node, tmp_switchObj, consts.folder.DOCU); view.replaceIcoClass(node, tmp_icoObj, consts.folder.DOCU); $$(node, consts.id.UL, setting).remove(); } else { $$(node, consts.id.UL, setting).empty(); } }, setFirstNode: function(setting, parentNode) { var childKey = setting.data.key.children, childLength = parentNode[childKey].length; if ( childLength > 0) { parentNode[childKey][0].isFirstNode = true; } }, setLastNode: function(setting, parentNode) { var childKey = setting.data.key.children, childLength = parentNode[childKey].length; if ( childLength > 0) { parentNode[childKey][childLength - 1].isLastNode = true; } }, removeNode: function(setting, node) { var root = data.getRoot(setting), childKey = setting.data.key.children, parentNode = (node.parentTId) ? node.getParentNode() : root; node.isFirstNode = false; node.isLastNode = false; node.getPreNode = function() {return null;}; node.getNextNode = function() {return null;}; if (!data.getNodeCache(setting, node.tId)) { return; } $$(node, setting).remove(); data.removeNodeCache(setting, node); data.removeSelectedNode(setting, node); for (var i = 0, l = parentNode[childKey].length; i < l; i++) { if (parentNode[childKey][i].tId == node.tId) { parentNode[childKey].splice(i, 1); break; } } view.setFirstNode(setting, parentNode); view.setLastNode(setting, parentNode); var tmp_ulObj,tmp_switchObj,tmp_icoObj, childLength = parentNode[childKey].length; //repair nodes old parent if (!setting.data.keep.parent && childLength == 0) { //old parentNode has no child nodes parentNode.isParent = false; parentNode.open = false; tmp_ulObj = $$(parentNode, consts.id.UL, setting); tmp_switchObj = $$(parentNode, consts.id.SWITCH, setting); tmp_icoObj = $$(parentNode, consts.id.ICON, setting); view.replaceSwitchClass(parentNode, tmp_switchObj, consts.folder.DOCU); view.replaceIcoClass(parentNode, tmp_icoObj, consts.folder.DOCU); tmp_ulObj.css("display", "none"); } else if (setting.view.showLine && childLength > 0) { //old parentNode has child nodes var newLast = parentNode[childKey][childLength - 1]; tmp_ulObj = $$(newLast, consts.id.UL, setting); tmp_switchObj = $$(newLast, consts.id.SWITCH, setting); tmp_icoObj = $$(newLast, consts.id.ICON, setting); if (parentNode == root) { if (parentNode[childKey].length == 1) { //node was root, and ztree has only one root after move node view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.ROOT); } else { var tmp_first_switchObj = $$(parentNode[childKey][0], consts.id.SWITCH, setting); view.replaceSwitchClass(parentNode[childKey][0], tmp_first_switchObj, consts.line.ROOTS); view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM); } } else { view.replaceSwitchClass(newLast, tmp_switchObj, consts.line.BOTTOM); } tmp_ulObj.removeClass(consts.line.LINE); } }, replaceIcoClass: function(node, obj, newName) { if (!obj || node.isAjaxing) return; var tmpName = obj.attr("class"); if (tmpName == undefined) return; var tmpList = tmpName.split("_"); switch (newName) { case consts.folder.OPEN: case consts.folder.CLOSE: case consts.folder.DOCU: tmpList[tmpList.length-1] = newName; break; } obj.attr("class", tmpList.join("_")); }, replaceSwitchClass: function(node, obj, newName) { if (!obj) return; var tmpName = obj.attr("class"); if (tmpName == undefined) return; var tmpList = tmpName.split("_"); switch (newName) { case consts.line.ROOT: case consts.line.ROOTS: case consts.line.CENTER: case consts.line.BOTTOM: case consts.line.NOLINE: tmpList[0] = view.makeNodeLineClassEx(node) + newName; break; case consts.folder.OPEN: case consts.folder.CLOSE: case consts.folder.DOCU: tmpList[1] = newName; break; } obj.attr("class", tmpList.join("_")); if (newName !== consts.folder.DOCU) { obj.removeAttr("disabled"); } else { obj.attr("disabled", "disabled"); } }, selectNode: function(setting, node, addFlag) { if (!addFlag) { view.cancelPreSelectedNode(setting, null, node); } $$(node, consts.id.A, setting).addClass(consts.node.CURSELECTED); data.addSelectedNode(setting, node); setting.treeObj.trigger(consts.event.SELECTED, [event, setting.treeId, node]); }, setNodeFontCss: function(setting, treeNode) { var aObj = $$(treeNode, consts.id.A, setting), fontCss = view.makeNodeFontCss(setting, treeNode); if (fontCss) { aObj.css(fontCss); } }, setNodeLineIcos: function(setting, node) { if (!node) return; var switchObj = $$(node, consts.id.SWITCH, setting), ulObj = $$(node, consts.id.UL, setting), icoObj = $$(node, consts.id.ICON, setting), ulLine = view.makeUlLineClass(setting, node); if (ulLine.length==0) { ulObj.removeClass(consts.line.LINE); } else { ulObj.addClass(ulLine); } switchObj.attr("class", view.makeNodeLineClass(setting, node)); if (node.isParent) { switchObj.removeAttr("disabled"); } else { switchObj.attr("disabled", "disabled"); } icoObj.removeAttr("style"); icoObj.attr("style", view.makeNodeIcoStyle(setting, node)); icoObj.attr("class", view.makeNodeIcoClass(setting, node)); }, setNodeName: function(setting, node) { var title = data.getNodeTitle(setting, node), nObj = $$(node, consts.id.SPAN, setting); nObj.empty(); if (setting.view.nameIsHTML) { nObj.html(data.getNodeName(setting, node)); } else { nObj.text(data.getNodeName(setting, node)); } if (tools.apply(setting.view.showTitle, [setting.treeId, node], setting.view.showTitle)) { var aObj = $$(node, consts.id.A, setting); aObj.attr("title", !title ? "" : title); } }, setNodeTarget: function(setting, node) { var aObj = $$(node, consts.id.A, setting); aObj.attr("target", view.makeNodeTarget(node)); }, setNodeUrl: function(setting, node) { var aObj = $$(node, consts.id.A, setting), url = view.makeNodeUrl(setting, node); if (url == null || url.length == 0) { aObj.removeAttr("href"); } else { aObj.attr("href", url); } }, switchNode: function(setting, node) { if (node.open || !tools.canAsync(setting, node)) { view.expandCollapseNode(setting, node, !node.open); } else if (setting.async.enable) { if (!view.asyncNode(setting, node)) { view.expandCollapseNode(setting, node, !node.open); return; } } else if (node) { view.expandCollapseNode(setting, node, !node.open); } } }; // zTree defind $.fn.zTree = { consts : _consts, _z : { tools: tools, view: view, event: event, data: data }, getZTreeObj: function(treeId) { var o = data.getZTreeTools(treeId); return o ? o : null; }, destroy: function(treeId) { if (!!treeId && treeId.length > 0) { view.destroy(data.getSetting(treeId)); } else { for(var s in settings) { view.destroy(settings[s]); } } }, init: function(obj, zSetting, zNodes) { var setting = tools.clone(_setting); $.extend(true, setting, zSetting); setting.treeId = obj.attr("id"); setting.treeObj = obj; setting.treeObj.empty(); settings[setting.treeId] = setting; //For some older browser,(e.g., ie6) if(typeof document.body.style.maxHeight === "undefined") { setting.view.expandSpeed = ""; } data.initRoot(setting); var root = data.getRoot(setting), childKey = setting.data.key.children; zNodes = zNodes ? tools.clone(tools.isArray(zNodes)? zNodes : [zNodes]) : []; if (setting.data.simpleData.enable) { root[childKey] = data.transformTozTreeFormat(setting, zNodes); } else { root[childKey] = zNodes; } data.initCache(setting); event.unbindTree(setting); event.bindTree(setting); event.unbindEvent(setting); event.bindEvent(setting); var zTreeTools = { setting : setting, addNodes : function(parentNode, newNodes, isSilent) { if (!newNodes) return null; if (!parentNode) parentNode = null; if (parentNode && !parentNode.isParent && setting.data.keep.leaf) return null; var xNewNodes = tools.clone(tools.isArray(newNodes)? newNodes: [newNodes]); function addCallback() { view.addNodes(setting, parentNode, xNewNodes, (isSilent==true)); } if (tools.canAsync(setting, parentNode)) { view.asyncNode(setting, parentNode, isSilent, addCallback); } else { addCallback(); } return xNewNodes; }, cancelSelectedNode : function(node) { view.cancelPreSelectedNode(setting, node); }, destroy : function() { view.destroy(setting); }, expandAll : function(expandFlag) { expandFlag = !!expandFlag; view.expandCollapseSonNode(setting, null, expandFlag, true); return expandFlag; }, expandNode : function(node, expandFlag, sonSign, focus, callbackFlag) { if (!node || !node.isParent) return null; if (expandFlag !== true && expandFlag !== false) { expandFlag = !node.open; } callbackFlag = !!callbackFlag; if (callbackFlag && expandFlag && (tools.apply(setting.callback.beforeExpand, [setting.treeId, node], true) == false)) { return null; } else if (callbackFlag && !expandFlag && (tools.apply(setting.callback.beforeCollapse, [setting.treeId, node], true) == false)) { return null; } if (expandFlag && node.parentTId) { view.expandCollapseParentNode(setting, node.getParentNode(), expandFlag, false); } if (expandFlag === node.open && !sonSign) { return null; } data.getRoot(setting).expandTriggerFlag = callbackFlag; if (!tools.canAsync(setting, node) && sonSign) { view.expandCollapseSonNode(setting, node, expandFlag, true, function() { if (focus !== false) {try{$$(node, setting).focus().blur();}catch(e){}} }); } else { node.open = !expandFlag; view.switchNode(this.setting, node); if (focus !== false) {try{$$(node, setting).focus().blur();}catch(e){}} } return expandFlag; }, getNodes : function() { return data.getNodes(setting); }, getNodeByParam : function(key, value, parentNode) { if (!key) return null; return data.getNodeByParam(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), key, value); }, getNodeByTId : function(tId) { return data.getNodeCache(setting, tId); }, getNodesByParam : function(key, value, parentNode) { if (!key) return null; return data.getNodesByParam(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), key, value); }, getNodesByParamFuzzy : function(key, value, parentNode) { if (!key) return null; return data.getNodesByParamFuzzy(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), key, value); }, getNodesByFilter: function(filter, isSingle, parentNode, invokeParam) { isSingle = !!isSingle; if (!filter || (typeof filter != "function")) return (isSingle ? null : []); return data.getNodesByFilter(setting, parentNode?parentNode[setting.data.key.children]:data.getNodes(setting), filter, isSingle, invokeParam); }, getNodeIndex : function(node) { if (!node) return null; var childKey = setting.data.key.children, parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting); for (var i=0, l = parentNode[childKey].length; i < l; i++) { if (parentNode[childKey][i] == node) return i; } return -1; }, getSelectedNodes : function() { var r = [], list = data.getRoot(setting).curSelectedList; for (var i=0, l=list.length; i<l; i++) { r.push(list[i]); } return r; }, isSelectedNode : function(node) { return data.isSelectedNode(setting, node); }, reAsyncChildNodes : function(parentNode, reloadType, isSilent) { if (!this.setting.async.enable) return; var isRoot = !parentNode; if (isRoot) { parentNode = data.getRoot(setting); } if (reloadType=="refresh") { var childKey = this.setting.data.key.children; for (var i = 0, l = parentNode[childKey] ? parentNode[childKey].length : 0; i < l; i++) { data.removeNodeCache(setting, parentNode[childKey][i]); } data.removeSelectedNode(setting); parentNode[childKey] = []; if (isRoot) { this.setting.treeObj.empty(); } else { var ulObj = $$(parentNode, consts.id.UL, setting); ulObj.empty(); } } view.asyncNode(this.setting, isRoot? null:parentNode, !!isSilent); }, refresh : function() { this.setting.treeObj.empty(); var root = data.getRoot(setting), nodes = root[setting.data.key.children] data.initRoot(setting); root[setting.data.key.children] = nodes data.initCache(setting); view.createNodes(setting, 0, root[setting.data.key.children]); }, removeChildNodes : function(node) { if (!node) return null; var childKey = setting.data.key.children, nodes = node[childKey]; view.removeChildNodes(setting, node); return nodes ? nodes : null; }, removeNode : function(node, callbackFlag) { if (!node) return; callbackFlag = !!callbackFlag; if (callbackFlag && tools.apply(setting.callback.beforeRemove, [setting.treeId, node], true) == false) return; view.removeNode(setting, node); if (callbackFlag) { this.setting.treeObj.trigger(consts.event.REMOVE, [setting.treeId, node]); } }, selectNode : function(node, addFlag) { if (!node) return; if (tools.uCanDo(setting)) { addFlag = setting.view.selectedMulti && addFlag; if (node.parentTId) { view.expandCollapseParentNode(setting, node.getParentNode(), true, false, function() { try{$$(node, setting).focus().blur();}catch(e){} }); } else { try{$$(node, setting).focus().blur();}catch(e){} } view.selectNode(setting, node, addFlag); } }, transformTozTreeNodes : function(simpleNodes) { return data.transformTozTreeFormat(setting, simpleNodes); }, transformToArray : function(nodes) { return data.transformToArrayFormat(setting, nodes); }, updateNode : function(node, checkTypeFlag) { if (!node) return; var nObj = $$(node, setting); if (nObj.get(0) && tools.uCanDo(setting)) { view.setNodeName(setting, node); view.setNodeTarget(setting, node); view.setNodeUrl(setting, node); view.setNodeLineIcos(setting, node); view.setNodeFontCss(setting, node); } } } root.treeTools = zTreeTools; data.setZTreeTools(setting, zTreeTools); if (root[childKey] && root[childKey].length > 0) { view.createNodes(setting, 0, root[childKey]); } else if (setting.async.enable && setting.async.url && setting.async.url !== '') { view.asyncNode(setting); } return zTreeTools; } }; var zt = $.fn.zTree, $$ = tools.$, consts = zt.consts; })(jQuery);/* * JQuery zTree excheck v3.5.18 * http://zTree.me/ * * Copyright (c) 2010 Hunter.z * * Licensed same as jquery - MIT License * http://www.opensource.org/licenses/mit-license.php * * email: hunter.z@263.net * Date: 2015-06-18 */ (function($){ //default consts of excheck var _consts = { event: { CHECK: "ztree_check" }, id: { CHECK: "_check" }, checkbox: { STYLE: "checkbox", DEFAULT: "chk", DISABLED: "disable", FALSE: "false", TRUE: "true", FULL: "full", PART: "part", FOCUS: "focus" }, radio: { STYLE: "radio", TYPE_ALL: "all", TYPE_LEVEL: "level" } }, //default setting of excheck _setting = { check: { enable: false, autoCheckTrigger: false, chkStyle: _consts.checkbox.STYLE, nocheckInherit: false, chkDisabledInherit: false, radioType: _consts.radio.TYPE_LEVEL, chkboxType: { "Y": "ps", "N": "ps" } }, data: { key: { checked: "checked" } }, callback: { beforeCheck:null, onCheck:null } }, //default root of excheck _initRoot = function (setting) { var r = data.getRoot(setting); r.radioCheckedList = []; }, //default cache of excheck _initCache = function(treeId) {}, //default bind event of excheck _bindEvent = function(setting) { var o = setting.treeObj, c = consts.event; o.bind(c.CHECK, function (event, srcEvent, treeId, node) { event.srcEvent = srcEvent; tools.apply(setting.callback.onCheck, [event, treeId, node]); }); }, _unbindEvent = function(setting) { var o = setting.treeObj, c = consts.event; o.unbind(c.CHECK); }, //default event proxy of excheck _eventProxy = function(e) { var target = e.target, setting = data.getSetting(e.data.treeId), tId = "", node = null, nodeEventType = "", treeEventType = "", nodeEventCallback = null, treeEventCallback = null; if (tools.eqs(e.type, "mouseover")) { if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) { tId = tools.getNodeMainDom(target).id; nodeEventType = "mouseoverCheck"; } } else if (tools.eqs(e.type, "mouseout")) { if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) { tId = tools.getNodeMainDom(target).id; nodeEventType = "mouseoutCheck"; } } else if (tools.eqs(e.type, "click")) { if (setting.check.enable && tools.eqs(target.tagName, "span") && target.getAttribute("treeNode"+ consts.id.CHECK) !== null) { tId = tools.getNodeMainDom(target).id; nodeEventType = "checkNode"; } } if (tId.length>0) { node = data.getNodeCache(setting, tId); switch (nodeEventType) { case "checkNode" : nodeEventCallback = _handler.onCheckNode; break; case "mouseoverCheck" : nodeEventCallback = _handler.onMouseoverCheck; break; case "mouseoutCheck" : nodeEventCallback = _handler.onMouseoutCheck; break; } } var proxyResult = { stop: nodeEventType === "checkNode", node: node, nodeEventType: nodeEventType, nodeEventCallback: nodeEventCallback, treeEventType: treeEventType, treeEventCallback: treeEventCallback }; return proxyResult }, //default init node of excheck _initNode = function(setting, level, n, parentNode, isFirstNode, isLastNode, openFlag) { if (!n) return; var checkedKey = setting.data.key.checked; if (typeof n[checkedKey] == "string") n[checkedKey] = tools.eqs(n[checkedKey], "true"); n[checkedKey] = !!n[checkedKey]; n.checkedOld = n[checkedKey]; if (typeof n.nocheck == "string") n.nocheck = tools.eqs(n.nocheck, "true"); n.nocheck = !!n.nocheck || (setting.check.nocheckInherit && parentNode && !!parentNode.nocheck); if (typeof n.chkDisabled == "string") n.chkDisabled = tools.eqs(n.chkDisabled, "true"); n.chkDisabled = !!n.chkDisabled || (setting.check.chkDisabledInherit && parentNode && !!parentNode.chkDisabled); if (typeof n.halfCheck == "string") n.halfCheck = tools.eqs(n.halfCheck, "true"); n.halfCheck = !!n.halfCheck; n.check_Child_State = -1; n.check_Focus = false; n.getCheckStatus = function() {return data.getCheckStatus(setting, n);}; if (setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL && n[checkedKey] ) { var r = data.getRoot(setting); r.radioCheckedList.push(n); } }, //add dom for check _beforeA = function(setting, node, html) { var checkedKey = setting.data.key.checked; if (setting.check.enable) { data.makeChkFlag(setting, node); html.push("<span ID='", node.tId, consts.id.CHECK, "' class='", view.makeChkClass(setting, node), "' treeNode", consts.id.CHECK, (node.nocheck === true?" style='display:none;'":""),"></span>"); } }, //update zTreeObj, add method of check _zTreeTools = function(setting, zTreeTools) { zTreeTools.checkNode = function(node, checked, checkTypeFlag, callbackFlag) { var checkedKey = this.setting.data.key.checked; if (node.chkDisabled === true) return; if (checked !== true && checked !== false) { checked = !node[checkedKey]; } callbackFlag = !!callbackFlag; if (node[checkedKey] === checked && !checkTypeFlag) { return; } else if (callbackFlag && tools.apply(this.setting.callback.beforeCheck, [this.setting.treeId, node], true) == false) { return; } if (tools.uCanDo(this.setting) && this.setting.check.enable && node.nocheck !== true) { node[checkedKey] = checked; var checkObj = $$(node, consts.id.CHECK, this.setting); if (checkTypeFlag || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node); view.setChkClass(this.setting, checkObj, node); view.repairParentChkClassWithSelf(this.setting, node); if (callbackFlag) { this.setting.treeObj.trigger(consts.event.CHECK, [null, this.setting.treeId, node]); } } } zTreeTools.checkAllNodes = function(checked) { view.repairAllChk(this.setting, !!checked); } zTreeTools.getCheckedNodes = function(checked) { var childKey = this.setting.data.key.children; checked = (checked !== false); return data.getTreeCheckedNodes(this.setting, data.getRoot(this.setting)[childKey], checked); } zTreeTools.getChangeCheckedNodes = function() { var childKey = this.setting.data.key.children; return data.getTreeChangeCheckedNodes(this.setting, data.getRoot(this.setting)[childKey]); } zTreeTools.setChkDisabled = function(node, disabled, inheritParent, inheritChildren) { disabled = !!disabled; inheritParent = !!inheritParent; inheritChildren = !!inheritChildren; view.repairSonChkDisabled(this.setting, node, disabled, inheritChildren); view.repairParentChkDisabled(this.setting, node.getParentNode(), disabled, inheritParent); } var _updateNode = zTreeTools.updateNode; zTreeTools.updateNode = function(node, checkTypeFlag) { if (_updateNode) _updateNode.apply(zTreeTools, arguments); if (!node || !this.setting.check.enable) return; var nObj = $$(node, this.setting); if (nObj.get(0) && tools.uCanDo(this.setting)) { var checkObj = $$(node, consts.id.CHECK, this.setting); if (checkTypeFlag == true || this.setting.check.chkStyle === consts.radio.STYLE) view.checkNodeRelation(this.setting, node); view.setChkClass(this.setting, checkObj, node); view.repairParentChkClassWithSelf(this.setting, node); } } }, //method of operate data _data = { getRadioCheckedList: function(setting) { var checkedList = data.getRoot(setting).radioCheckedList; for (var i=0, j=checkedList.length; i<j; i++) { if(!data.getNodeCache(setting, checkedList[i].tId)) { checkedList.splice(i, 1); i--; j--; } } return checkedList; }, getCheckStatus: function(setting, node) { if (!setting.check.enable || node.nocheck || node.chkDisabled) return null; var checkedKey = setting.data.key.checked, r = { checked: node[checkedKey], half: node.halfCheck ? node.halfCheck : (setting.check.chkStyle == consts.radio.STYLE ? (node.check_Child_State === 2) : (node[checkedKey] ? (node.check_Child_State > -1 && node.check_Child_State < 2) : (node.check_Child_State > 0))) }; return r; }, getTreeCheckedNodes: function(setting, nodes, checked, results) { if (!nodes) return []; var childKey = setting.data.key.children, checkedKey = setting.data.key.checked, onlyOne = (checked && setting.check.chkStyle == consts.radio.STYLE && setting.check.radioType == consts.radio.TYPE_ALL); results = !results ? [] : results; for (var i = 0, l = nodes.length; i < l; i++) { if (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] == checked) { results.push(nodes[i]); if(onlyOne) { break; } } data.getTreeCheckedNodes(setting, nodes[i][childKey], checked, results); if(onlyOne && results.length > 0) { break; } } return results; }, getTreeChangeCheckedNodes: function(setting, nodes, results) { if (!nodes) return []; var childKey = setting.data.key.children, checkedKey = setting.data.key.checked; results = !results ? [] : results; for (var i = 0, l = nodes.length; i < l; i++) { if (nodes[i].nocheck !== true && nodes[i].chkDisabled !== true && nodes[i][checkedKey] != nodes[i].checkedOld) { results.push(nodes[i]); } data.getTreeChangeCheckedNodes(setting, nodes[i][childKey], results); } return results; }, makeChkFlag: function(setting, node) { if (!node) return; var childKey = setting.data.key.children, checkedKey = setting.data.key.checked, chkFlag = -1; if (node[childKey]) { for (var i = 0, l = node[childKey].length; i < l; i++) { var cNode = node[childKey][i]; var tmp = -1; if (setting.check.chkStyle == consts.radio.STYLE) { if (cNode.nocheck === true || cNode.chkDisabled === true) { tmp = cNode.check_Child_State; } else if (cNode.halfCheck === true) { tmp = 2; } else if (cNode[checkedKey]) { tmp = 2; } else { tmp = cNode.check_Child_State > 0 ? 2:0; } if (tmp == 2) { chkFlag = 2; break; } else if (tmp == 0){ chkFlag = 0; } } else if (setting.check.chkStyle == consts.checkbox.STYLE) { if (cNode.nocheck === true || cNode.chkDisabled === true) { tmp = cNode.check_Child_State; } else if (cNode.halfCheck === true) { tmp = 1; } else if (cNode[checkedKey] ) { tmp = (cNode.check_Child_State === -1 || cNode.check_Child_State === 2) ? 2 : 1; } else { tmp = (cNode.check_Child_State > 0) ? 1 : 0; } if (tmp === 1) { chkFlag = 1; break; } else if (tmp === 2 && chkFlag > -1 && i > 0 && tmp !== chkFlag) { chkFlag = 1; break; } else if (chkFlag === 2 && tmp > -1 && tmp < 2) { chkFlag = 1; break; } else if (tmp > -1) { chkFlag = tmp; } } } } node.check_Child_State = chkFlag; } }, //method of event proxy _event = { }, //method of event handler _handler = { onCheckNode: function (event, node) { if (node.chkDisabled === true) return false; var setting = data.getSetting(event.data.treeId), checkedKey = setting.data.key.checked; if (tools.apply(setting.callback.beforeCheck, [setting.treeId, node], true) == false) return true; node[checkedKey] = !node[checkedKey]; view.checkNodeRelation(setting, node); var checkObj = $$(node, consts.id.CHECK, setting); view.setChkClass(setting, checkObj, node); view.repairParentChkClassWithSelf(setting, node); setting.treeObj.trigger(consts.event.CHECK, [event, setting.treeId, node]); return true; }, onMouseoverCheck: function(event, node) { if (node.chkDisabled === true) return false; var setting = data.getSetting(event.data.treeId), checkObj = $$(node, consts.id.CHECK, setting); node.check_Focus = true; view.setChkClass(setting, checkObj, node); return true; }, onMouseoutCheck: function(event, node) { if (node.chkDisabled === true) return false; var setting = data.getSetting(event.data.treeId), checkObj = $$(node, consts.id.CHECK, setting); node.check_Focus = false; view.setChkClass(setting, checkObj, node); return true; } }, //method of tools for zTree _tools = { }, //method of operate ztree dom _view = { checkNodeRelation: function(setting, node) { var pNode, i, l, childKey = setting.data.key.children, checkedKey = setting.data.key.checked, r = consts.radio; if (setting.check.chkStyle == r.STYLE) { var checkedList = data.getRadioCheckedList(setting); if (node[checkedKey]) { if (setting.check.radioType == r.TYPE_ALL) { for (i = checkedList.length-1; i >= 0; i--) { pNode = checkedList[i]; if (pNode[checkedKey] && pNode != node) { pNode[checkedKey] = false; checkedList.splice(i, 1); view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode); if (pNode.parentTId != node.parentTId) { view.repairParentChkClassWithSelf(setting, pNode); } } } checkedList.push(node); } else { var parentNode = (node.parentTId) ? node.getParentNode() : data.getRoot(setting); for (i = 0, l = parentNode[childKey].length; i < l; i++) { pNode = parentNode[childKey][i]; if (pNode[checkedKey] && pNode != node) { pNode[checkedKey] = false; view.setChkClass(setting, $$(pNode, consts.id.CHECK, setting), pNode); } } } } else if (setting.check.radioType == r.TYPE_ALL) { for (i = 0, l = checkedList.length; i < l; i++) { if (node == checkedList[i]) { checkedList.splice(i, 1); break; } } } } else { if (node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.Y.indexOf("s") > -1)) { view.setSonNodeCheckBox(setting, node, true); } if (!node[checkedKey] && (!node[childKey] || node[childKey].length==0 || setting.check.chkboxType.N.indexOf("s") > -1)) { view.setSonNodeCheckBox(setting, node, false); } if (node[checkedKey] && setting.check.chkboxType.Y.indexOf("p") > -1) { view.setParentNodeCheckBox(setting, node, true); } if (!node[checkedKey] && setting.check.chkboxType.N.indexOf("p") > -1) { view.setParentNodeCheckBox(setting, node, false); } } }, makeChkClass: function(setting, node) { var checkedKey = setting.data.key.checked, c = consts.checkbox, r = consts.radio, fullStyle = ""; if (node.chkDisabled === true) { fullStyle = c.DISABLED; } else if (node.halfCheck) { fullStyle = c.PART; } else if (setting.check.chkStyle == r.STYLE) { fullStyle = (node.check_Child_State < 1)? c.FULL:c.PART; } else { fullStyle = node[checkedKey] ? ((node.check_Child_State === 2 || node.check_Child_State === -1) ? c.FULL:c.PART) : ((node.check_Child_State < 1)? c.FULL:c.PART); } var chkName = setting.check.chkStyle + "_" + (node[checkedKey] ? c.TRUE : c.FALSE) + "_" + fullStyle; chkName = (node.check_Focus && node.chkDisabled !== true) ? chkName + "_" + c.FOCUS : chkName; return consts.className.BUTTON + " " + c.DEFAULT + " " + chkName; }, repairAllChk: function(setting, checked) { if (setting.check.enable && setting.check.chkStyle === consts.checkbox.STYLE) { var checkedKey = setting.data.key.checked, childKey = setting.data.key.children, root = data.getRoot(setting); for (var i = 0, l = root[childKey].length; i<l ; i++) { var node = root[childKey][i]; if (node.nocheck !== true && node.chkDisabled !== true) { node[checkedKey] = checked; } view.setSonNodeCheckBox(setting, node, checked); } } }, repairChkClass: function(setting, node) { if (!node) return; data.makeChkFlag(setting, node); if (node.nocheck !== true) { var checkObj = $$(node, consts.id.CHECK, setting); view.setChkClass(setting, checkObj, node); } }, repairParentChkClass: function(setting, node) { if (!node || !node.parentTId) return; var pNode = node.getParentNode(); view.repairChkClass(setting, pNode); view.repairParentChkClass(setting, pNode); }, repairParentChkClassWithSelf: function(setting, node) { if (!node) return; var childKey = setting.data.key.children; if (node[childKey] && node[childKey].length > 0) { view.repairParentChkClass(setting, node[childKey][0]); } else { view.repairParentChkClass(setting, node); } }, repairSonChkDisabled: function(setting, node, chkDisabled, inherit) { if (!node) return; var childKey = setting.data.key.children; if (node.chkDisabled != chkDisabled) { node.chkDisabled = chkDisabled; } view.repairChkClass(setting, node); if (node[childKey] && inherit) { for (var i = 0, l = node[childKey].length; i < l; i++) { var sNode = node[childKey][i]; view.repairSonChkDisabled(setting, sNode, chkDisabled, inherit); } } }, repairParentChkDisabled: function(setting, node, chkDisabled, inherit) { if (!node) return; if (node.chkDisabled != chkDisabled && inherit) { node.chkDisabled = chkDisabled; } view.repairChkClass(setting, node); view.repairParentChkDisabled(setting, node.getParentNode(), chkDisabled, inherit); }, setChkClass: function(setting, obj, node) { if (!obj) return; if (node.nocheck === true) { obj.hide(); } else { obj.show(); } obj.attr('class', view.makeChkClass(setting, node)); }, setParentNodeCheckBox: function(setting, node, value, srcNode) { var childKey = setting.data.key.children, checkedKey = setting.data.key.checked, checkObj = $$(node, consts.id.CHECK, setting); if (!srcNode) srcNode = node; data.makeChkFlag(setting, node); if (node.nocheck !== true && node.chkDisabled !== true) { node[checkedKey] = value; view.setChkClass(setting, checkObj, node); if (setting.check.autoCheckTrigger && node != srcNode) { setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]); } } if (node.parentTId) { var pSign = true; if (!value) { var pNodes = node.getParentNode()[childKey]; for (var i = 0, l = pNodes.length; i < l; i++) { if ((pNodes[i].nocheck !== true && pNodes[i].chkDisabled !== true && pNodes[i][checkedKey]) || ((pNodes[i].nocheck === true || pNodes[i].chkDisabled === true) && pNodes[i].check_Child_State > 0)) { pSign = false; break; } } } if (pSign) { view.setParentNodeCheckBox(setting, node.getParentNode(), value, srcNode); } } }, setSonNodeCheckBox: function(setting, node, value, srcNode) { if (!node) return; var childKey = setting.data.key.children, checkedKey = setting.data.key.checked, checkObj = $$(node, consts.id.CHECK, setting); if (!srcNode) srcNode = node; var hasDisable = false; if (node[childKey]) { for (var i = 0, l = node[childKey].length; i < l && node.chkDisabled !== true; i++) { var sNode = node[childKey][i]; view.setSonNodeCheckBox(setting, sNode, value, srcNode); if (sNode.chkDisabled === true) hasDisable = true; } } if (node != data.getRoot(setting) && node.chkDisabled !== true) { if (hasDisable && node.nocheck !== true) { data.makeChkFlag(setting, node); } if (node.nocheck !== true && node.chkDisabled !== true) { node[checkedKey] = value; if (!hasDisable) node.check_Child_State = (node[childKey] && node[childKey].length > 0) ? (value ? 2 : 0) : -1; } else { node.check_Child_State = -1; } view.setChkClass(setting, checkObj, node); if (setting.check.autoCheckTrigger && node != srcNode && node.nocheck !== true && node.chkDisabled !== true) { setting.treeObj.trigger(consts.event.CHECK, [null, setting.treeId, node]); } } } }, _z = { tools: _tools, view: _view, event: _event, data: _data }; $.extend(true, $.fn.zTree.consts, _consts); $.extend(true, $.fn.zTree._z, _z); var zt = $.fn.zTree, tools = zt._z.tools, consts = zt.consts, view = zt._z.view, data = zt._z.data, event = zt._z.event, $$ = tools.$; data.exSetting(_setting); data.addInitBind(_bindEvent); data.addInitUnBind(_unbindEvent); data.addInitCache(_initCache); data.addInitNode(_initNode); data.addInitProxy(_eventProxy, true); data.addInitRoot(_initRoot); data.addBeforeA(_beforeA); data.addZTreeTools(_zTreeTools); var _createNodes = view.createNodes; view.createNodes = function(setting, level, nodes, parentNode) { if (_createNodes) _createNodes.apply(view, arguments); if (!nodes) return; view.repairParentChkClassWithSelf(setting, parentNode); } var _removeNode = view.removeNode; view.removeNode = function(setting, node) { var parentNode = node.getParentNode(); if (_removeNode) _removeNode.apply(view, arguments); if (!node || !parentNode) return; view.repairChkClass(setting, parentNode); view.repairParentChkClass(setting, parentNode); } var _appendNodes = view.appendNodes; view.appendNodes = function(setting, level, nodes, parentNode, initFlag, openFlag) { var html = ""; if (_appendNodes) { html = _appendNodes.apply(view, arguments); } if (parentNode) { data.makeChkFlag(setting, parentNode); } return html; } })(jQuery);/** * 可以改变图标的button * * Created by GUY on 2016/2/2. * * @class BI.IconChangeButton * @extends BI.Single */ BI.IconChangeButton = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.IconChangeButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-icon-change-button", iconClass: "", iconWidth: null, iconHeight: null, stopEvent: false, stopPropagation: false, selected: false, once: false, //点击一次选中有效,再点无效 forceSelected: false, //点击即选中, 选中了就不会被取消 forceNotSelected: false, //无论怎么点击都不会被选中 disableSelected: false, //使能选中 shadow: false, isShadowShowingOnSelected: false, //选中状态下是否显示阴影 trigger: null, handler: BI.emptyFn }) }, _init: function () { BI.IconChangeButton.superclass._init.apply(this, arguments); var self = this, o = this.options; this.button = BI.createWidget({ type: "bi.icon_button", element: this, cls: o.iconClass, height: o.height, iconWidth: o.iconWidth, iconHeight: o.iconHeight, stopEvent: o.stopEvent, stopPropagation: o.stopPropagation, selected: o.selected, once: o.once, forceSelected: o.forceSelected, forceNotSelected: o.forceNotSelected, disableSelected: o.disableSelected, shadow: o.shadow, isShadowShowingOnSelected: o.isShadowShowingOnSelected, trigger: o.trigger, handler: o.handler }); this.button.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.button.on(BI.IconButton.EVENT_CHANGE, function () { self.fireEvent(BI.IconChangeButton.EVENT_CHANGE, arguments); }); }, isSelected: function () { return this.button.isSelected(); }, setSelected: function (b) { this.button.setSelected(b); }, setIcon: function (cls) { var o = this.options; if (o.iconClass !== cls) { this.element.removeClass(o.iconClass).addClass(cls); o.iconClass = cls; } } }); BI.IconChangeButton.EVENT_CHANGE = "IconChangeButton.EVENT_CHANGE"; BI.shortcut("bi.icon_change_button", BI.IconChangeButton);/** * guy * @extends BI.Single * @type {*|void|Object} */ BI.HalfIconButton = BI.inherit(BI.IconButton, { _defaultConfig: function() { var conf = BI.HalfIconButton.superclass._defaultConfig.apply(this,arguments); return BI.extend(conf, { extraCls: "bi-half-icon-button check-half-select-icon", height: 16, width: 16, iconWidth: 16, iconHeight: 16, selected: false }) }, _init : function() { BI.HalfIconButton.superclass._init.apply(this, arguments); }, doClick: function(){ BI.HalfIconButton.superclass.doClick.apply(this, arguments); if(this.isValid()){ this.fireEvent(BI.HalfIconButton.EVENT_CHANGE); } } }); BI.HalfIconButton.EVENT_CHANGE = "HalfIconButton.EVENT_CHANGE"; BI.shortcut("bi.half_icon_button", BI.HalfIconButton);/** * 统一的trigger图标按钮 * * Created by GUY on 2015/9/16. * @class BI.TriggerIconButton * @extends BI.IconButton */ BI.TriggerIconButton = BI.inherit(BI.IconButton, { _defaultConfig: function () { var conf = BI.TriggerIconButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-trigger-icon-button", extraCls: "pull-down-font" }); }, _init: function () { BI.TriggerIconButton.superclass._init.apply(this, arguments); }, doClick: function () { BI.TriggerIconButton.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.TriggerIconButton.EVENT_CHANGE, this); } } }); BI.TriggerIconButton.EVENT_CHANGE = "TriggerIconButton.EVENT_CHANGE"; BI.shortcut("bi.trigger_icon_button", BI.TriggerIconButton);/** * guy * 复选框item * @type {*|void|Object} */ BI.MultiSelectItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MultiSelectItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-multi-select-item", height: 25, logic: { dynamic: false } }) }, _init: function () { BI.MultiSelectItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.checkbox" }); this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, rgap: o.rgap, text: o.text, keyword: o.keyword, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", { type: "bi.center_adapt", items: [this.checkbox], width: 36 }, this.text) })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.MultiSelectItem.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); if (this.isValid()) { this.fireEvent(BI.MultiSelectItem.EVENT_CHANGE, this.getValue(), this); } }, setSelected: function (v) { BI.MultiSelectItem.superclass.setSelected.apply(this, arguments); this.checkbox.setSelected(v); } }); BI.MultiSelectItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multi_select_item", BI.MultiSelectItem);/** * Created by GUY on 2016/2/2. * * @class BI.SingleSelectIconTextItem * @extends BI.BasicButton */ BI.SingleSelectIconTextItem = BI.inherit(BI.Single, { _defaultConfig: function () { return BI.extend(BI.SingleSelectIconTextItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-single-select-icon-text-item bi-list-item-active", iconClass: "", hgap: 10, height: 25 }) }, _init: function () { BI.SingleSelectIconTextItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.text = BI.createWidget({ type: "bi.icon_text_item", element: this, cls: o.iconClass, once: o.once, selected: o.selected, height: o.height, iconHeight: o.iconHeight, iconWidth: o.iconWidth, text: o.text, keyword: o.keyword, value: o.value, py: o.py }); this.text.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, isSelected: function () { return this.text.isSelected(); }, setSelected: function (b) { this.text.setSelected(b); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.SingleSelectIconTextItem.superclass.doClick.apply(this, arguments); } }); BI.shortcut("bi.single_select_icon_text_item", BI.SingleSelectIconTextItem);/** * guy * 复选框item * @type {*|void|Object} */ BI.SingleSelectItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.SingleSelectItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-single-select-item bi-list-item-active", hgap: 10, height: 25, textAlign: "left", }) }, _init: function () { BI.SingleSelectItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.text = BI.createWidget({ type: "bi.label", element: this, textAlign: o.textAlign, whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, keyword: o.keyword, value: o.value, py: o.py }); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.SingleSelectItem.superclass.doClick.apply(this, arguments); }, setSelected: function (v) { BI.SingleSelectItem.superclass.setSelected.apply(this, arguments); } }); BI.shortcut("bi.single_select_item", BI.SingleSelectItem);/** * guy * 单选框item * @type {*|void|Object} */ BI.SingleSelectRadioItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.SingleSelectRadioItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-single-select-radio-item bi-list-item-active", logic: { dynamic: false }, hgap: 10, height: 25 }) }, _init: function () { BI.SingleSelectRadioItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.radio = BI.createWidget({ type: "bi.radio" }); this.radio.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(!self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, keyword: o.keyword, value: o.value, py: o.py }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", { type: "bi.center_adapt", items: [this.radio], width: 36 }, this.text) })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.SingleSelectRadioItem.superclass.doClick.apply(this, arguments); this.radio.setSelected(this.isSelected()); }, setSelected: function (v) { BI.SingleSelectRadioItem.superclass.setSelected.apply(this, arguments); this.radio.setSelected(v); } }); BI.shortcut("bi.single_select_radio_item", BI.SingleSelectRadioItem);/** * Created by roy on 15/10/16. */ BI.ArrowNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.ArrowNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-arrow-group-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25 }); }, _init: function () { var self = this, o = this.options; BI.ArrowNode.superclass._init.apply(this, arguments); this.checkbox = BI.createWidget({ type: "bi.arrow_tree_group_node_checkbox", iconWidth: 13, iconHeight: 13 }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.ArrowNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isOpened()); }, setValue: function (v) { this.text.setValue(v); }, setOpened: function (v) { BI.ArrowNode.superclass.setOpened.apply(this, arguments); this.checkbox.setSelected(v); } }); BI.shortcut("bi.arrow_group_node", BI.ArrowNode);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.FirstPlusGroupNode * @extends BI.NodeButton */ BI.FirstPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.FirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-first-plus-group-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.FirstPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.first_tree_node_checkbox", stopPropagation: true }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.FirstPlusGroupNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setOpened: function (v) { BI.FirstPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.first_plus_group_node", BI.FirstPlusGroupNode);/** * Created by User on 2016/3/31. */ /** * > + icon + 文本 * @class BI.IconArrowNode * @extends BI.NodeButton */ BI.IconArrowNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.IconArrowNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-arrow-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25, iconHeight: 13, iconWidth: 13, iconCls: "" }) }, _init: function () { BI.IconArrowNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.tree_group_node_checkbox", width: 23, stopPropagation: true }); var icon = BI.createWidget({ type: "bi.center_adapt", cls: o.iconCls, width: 23, items: [{ type: "bi.icon", height: o.iconHeight, width: o.iconWidth }] }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, { width: 23, el: icon }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.IconArrowNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setOpened: function (v) { BI.IconArrowNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.icon_arrow_node", BI.IconArrowNode);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.LastPlusGroupNode * @extends BI.NodeButton */ BI.LastPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.LastPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-last-plus-group-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.LastPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.last_tree_node_checkbox", stopPropagation: true }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if(type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.LastPlusGroupNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setOpened: function (v) { BI.LastPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.last_plus_group_node", BI.LastPlusGroupNode);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.MidPlusGroupNode * @extends BI.NodeButton */ BI.MidPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MidPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-mid-plus-group-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.MidPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.mid_tree_node_checkbox", stopPropagation: true }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.MidPlusGroupNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MidPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.mid_plus_group_node", BI.MidPlusGroupNode);BI.MultiLayerIconArrowNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerIconArrowNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-icon-arrow-node bi-list-item", layer: 0,//第几层级 id: "", pId: "", open: false, height: 25, iconHeight: 13, iconWidth: 13, iconCls: "" }) }, _init: function () { BI.MultiLayerIconArrowNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.icon_arrow_node", iconCls: o.iconCls, //logic: { // dynamic: true //}, id: o.id, pId: o.pId, open: o.open, height: o.height, iconHeight: o.iconHeight, iconWidth: o.iconWidth, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { self.setSelected(self.isSelected()); self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, isOnce: function () { return true; }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, isSelected: function () { return this.node.isSelected(); }, setSelected: function (b) { BI.MultiLayerIconArrowNode.superclass.setSelected.apply(this, arguments); this.node.setSelected(b); }, doClick: function () { BI.NodeButton.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerIconArrowNode.superclass.setOpened.apply(this, arguments); this.node.setOpened(v); } }); BI.shortcut("bi.multilayer_icon_arrow_node", BI.MultiLayerIconArrowNode);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.PlusGroupNode * @extends BI.NodeButton */ BI.PlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.PlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-plus-group-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.PlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.tree_node_checkbox" }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.PlusGroupNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setOpened: function (v) { BI.PlusGroupNode.superclass.setOpened.apply(this, arguments); if (this.checkbox) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.plus_group_node", BI.PlusGroupNode);/** * 三角号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.TriangleGroupNode * @extends BI.NodeButton */ BI.TriangleGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.TriangleGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-triangle-group-node bi-list-item", logic: { dynamic: false }, id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.TriangleGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ iconWidth: 13, iconHeight: 13, type: "bi.tree_group_node_checkbox" }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py, keyword: o.keyword }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.TriangleGroupNode.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isOpened()); }, setOpened: function (v) { BI.TriangleGroupNode.superclass.setOpened.apply(this, arguments); this.checkbox.setSelected(v); }, setText: function(text){ BI.TriangleGroupNode.superclass.setText.apply(this, arguments); this.text.setText(text); } }); BI.shortcut("bi.triangle_group_node", BI.TriangleGroupNode);/** * guy * 复选框item * @type {*|void|Object} */ BI.FirstTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.FirstTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-first-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, id: "", pId: "", layer: 0, height: 25 }) }, _init: function () { BI.FirstTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.checkbox" }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, ((o.layer === 0) ? "" : { width: 13, el: { type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height } }), { width: 25, el: { type: "bi.layout", cls: "mid-line-conn-background", width: 25, height: o.height } }, { el: this.text }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.FirstTreeLeafItem.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setSelected: function (v) { BI.FirstTreeLeafItem.superclass.setSelected.apply(this, arguments); this.checkbox.setSelected(v); } }); BI.shortcut("bi.first_tree_leaf_item", BI.FirstTreeLeafItem);BI.IconTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.IconTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-icon-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, height: 25, iconWidth: 16, iconHeight: 16, iconCls: "" }) }, _init: function () { BI.IconTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; var icon = BI.createWidget({ type: "bi.center_adapt", width: 23, cls: o.iconCls, items: [{ type: "bi.icon", width: o.iconWidth, height: o.iconHeight }] }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 23, el: icon }, { el: this.text }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.IconTreeLeafItem.superclass.doClick.apply(this, arguments); }, setSelected: function (v) { BI.IconTreeLeafItem.superclass.setSelected.apply(this, arguments); } }); BI.shortcut("bi.icon_tree_leaf_item", BI.IconTreeLeafItem);/** * guy * 复选框item * @type {*|void|Object} */ BI.LastTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.LastTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-last-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, id: "", pId: "", layer: 0, height: 25 }) }, _init: function () { BI.LastTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.checkbox" }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, ((o.layer === 0) ? "" : { width: 13, el: { type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height } }), { width: 25, el: { type: "bi.layout", cls: "mid-line-conn-background", width: 25, height: o.height } }, { el: this.text }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.LastTreeLeafItem.superclass.doClick.apply(this, arguments); // this.checkbox.setSelected(this.isSelected()); }, setSelected: function (v) { BI.LastTreeLeafItem.superclass.setSelected.apply(this, arguments); // this.checkbox.setSelected(v); } }); BI.shortcut("bi.last_tree_leaf_item", BI.LastTreeLeafItem);/** * guy * 复选框item * @type {*|void|Object} */ BI.MidTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MidTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-mid-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, id: "", pId: "", layer: 0, height: 25 }) }, _init: function () { BI.MidTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.checkbox" }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.setSelected(self.isSelected()); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, ((o.layer === 0) ? "" : { width: 13, el: { type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height } }), { width: 25, el: { type: "bi.layout", cls: "mid-line-conn-background", width: 25, height: o.height } }, { el: this.text }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.MidTreeLeafItem.superclass.doClick.apply(this, arguments); this.checkbox.setSelected(this.isSelected()); }, setSelected: function (v) { BI.MidTreeLeafItem.superclass.setSelected.apply(this, arguments); this.checkbox.setSelected(v); } }); BI.shortcut("bi.mid_tree_leaf_item", BI.MidTreeLeafItem);/** * @class BI.MultiLayerIconTreeLeafItem * @extends BI.BasicButton */ BI.MultiLayerIconTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MultiLayerIconTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-multilayer-icon-tree-leaf-item bi-list-item-active", layer: 0, height: 25, iconCls: "", iconHeight: 14, iconWidth: 12 }) }, _init: function () { BI.MultiLayerIconTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.item = BI.createWidget({ type: "bi.icon_tree_leaf_item", cls: "bi-list-item-none", iconCls: o.iconCls, id: o.id, pId: o.pId, isFront: true, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py, iconWidth: o.iconWidth, iconHeight: o.iconHeight }); this.item.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", width: 13, height: o.height }) }); items.push(this.item); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }); }, doRedMark: function () { this.item.doRedMark.apply(this.item, arguments); }, unRedMark: function () { this.item.unRedMark.apply(this.item, arguments); }, doHighLight: function () { this.item.doHighLight.apply(this.item, arguments); }, unHighLight: function () { this.item.unHighLight.apply(this.item, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.MultiLayerIconTreeLeafItem.superclass.doClick.apply(this, arguments); this.item.setSelected(this.isSelected()); }, setSelected: function (v) { BI.MultiLayerIconTreeLeafItem.superclass.setSelected.apply(this, arguments); this.item.setSelected(v); }, getValue: function(){ return this.options.value; } }); BI.shortcut("bi.multilayer_icon_tree_leaf_item", BI.MultiLayerIconTreeLeafItem);/** * 树叶子节点 * Created by GUY on 2015/9/6. * @class BI.TreeTextLeafItem * @extends BI.BasicButton */ BI.TreeTextLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function() { return BI.extend(BI.TreeTextLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-tree-text-leaf-item bi-list-item-active", id: "", pId: "", height: 25, hgap: 0, lgap: 0, rgap: 0 }) }, _init : function() { BI.TreeTextLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, lgap: o.lgap, rgap: o.hgap, text: o.text, value: o.value, py: o.py }); BI.createWidget({ type: "bi.htape", element: this, items: [{ el: this.text }] }) }, doRedMark: function(){ this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function(){ this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function(){ this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function(){ this.text.unHighLight.apply(this.text, arguments); }, getId: function(){ return this.options.id; }, getPId: function(){ return this.options.pId; } }); BI.shortcut("bi.tree_text_leaf_item", BI.TreeTextLeafItem);/** * Created by GUY on 2015/8/28. * @class BI.Calendar * @extends BI.Widget */ BI.Calendar = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.Calendar.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-calendar", logic: { dynamic: false }, min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 year: 2015, month: 7, //7表示八月 day: 25 }) }, _dateCreator: function (Y, M, D) { var self = this, o = this.options, log = {}, De = new Date(); var mins = o.min.match(/\d+/g); var maxs = o.max.match(/\d+/g); Y < (mins[0] | 0) && (Y = (mins[0] | 0)); Y > (maxs[0] | 0) && (Y = (maxs[0] | 0)); De.setFullYear(Y, M, D); log.ymd = [De.getFullYear(), De.getMonth(), De.getDate()]; var MD = Date._MD.slice(0); MD[1] = Date.isLeap(log.ymd[0]) ? 29 : 28; De.setFullYear(log.ymd[0], log.ymd[1], 1); log.FDay = De.getDay(); log.PDay = MD[M === 0 ? 11 : M - 1] - log.FDay + 1; log.NDay = 1; var items = []; BI.each(BI.range(42), function (i) { var td = {}, YY = log.ymd[0], MM = log.ymd[1] + 1, DD; if (i < log.FDay) { td.lastMonth = true; DD = i + log.PDay; MM === 1 && (YY -= 1); MM = MM === 1 ? 12 : MM - 1; } else if (i >= log.FDay && i < log.FDay + MD[log.ymd[1]]) { DD = i - log.FDay + 1; if (i - log.FDay + 1 === log.ymd[2]) { td.currentDay = true; } } else { td.nextMonth = true; DD = log.NDay++; MM === 12 && (YY += 1); MM = MM === 12 ? 1 : MM + 1; } if (Date.checkVoid(YY, MM, DD, mins, maxs)[0]) { td.disabled = true; } td.text = DD; items.push(td); }) return items; }, _init: function () { BI.Calendar.superclass._init.apply(this, arguments); var self = this, o = this.options; var items = BI.map(Date._SDN.slice(0, 7), function (i, value) { return { type: "bi.label", height: 25, text: value } }) var title = BI.createWidget({ type: "bi.button_group", height: 25, items: items }) var days = this._dateCreator(o.year, o.month, o.day); items = []; items.push(days.slice(0, 7)); items.push(days.slice(7, 14)); items.push(days.slice(14, 21)); items.push(days.slice(21, 28)); items.push(days.slice(28, 35)); items.push(days.slice(35, 42)); items = BI.map(items, function (i, item) { return BI.map(item, function (j, td) { return BI.extend(td, { type: "bi.text_item", cls: "bi-list-item-active", textAlign: "center", whiteSpace: "normal", once: false, forceSelected: true, height: 25, value: o.year + "-" + o.month + "-" + td.text, disabled: td.lastMonth || td.nextMonth || td.disabled //selected: td.currentDay }); }); }); this.days = BI.createWidget({ type: "bi.button_group", items: BI.createItems(items, {}), layouts: [BI.LogicFactory.createLogic("table", BI.extend({}, o.logic, { columns: 7, rows: 6, columnSize: [1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7, 1 / 7], rowSize: 25 }))] }); this.days.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }) BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("vertical", BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("top", title, this.days) })))); }, isFrontDate: function () { var o = this.options, c = this._const; var Y = o.year, M = o.month, De = new Date(), day = De.getDay(); Y = Y | 0; De.setFullYear(Y, M, 1); var newDate = De.getOffsetDate(-1 * (day + 1)); return !!Date.checkVoid(newDate.getFullYear(), newDate.getMonth(), newDate.getDate(), o.min, o.max)[0]; }, isFinalDate: function () { var o = this.options, c = this._const; var Y = o.year, M = o.month, De = new Date(), day = De.getDay(); Y = Y | 0; De.setFullYear(Y, M, 1); var newDate = De.getOffsetDate(42 - day); return !!Date.checkVoid(newDate.getFullYear(), newDate.getMonth(), newDate.getDate(), o.min, o.max)[0]; }, setValue: function (ob) { this.days.setValue([ob.year + "-" + ob.month + "-" + ob.day]); }, getValue: function () { var date = this.days.getValue()[0].match(/\d+/g); return { year: date[0] | 0, month: date[1] | 0, day: date[2] | 0 } } }); BI.extend(BI.Calendar, { getPageByDateJSON: function (json) { var year = new Date().getFullYear(); var month = new Date().getMonth(); var page = (json.year - year) * 12; page += json.month - month; return page; }, getDateJSONByPage: function(v){ var months = new Date().getMonth(); var page = v; //对当前page做偏移,使到当前年初 page = page + months; var year = BI.parseInt(page / 12); if(page < 0 && page % 12 !== 0){ year--; } var month = page >= 0 ? (page % 12) : ((12 + page % 12) % 12); return { year: new Date().getFullYear() + year, month: month } } }); BI.shortcut("bi.calendar", BI.Calendar);/** * Created by GUY on 2015/8/28. * @class BI.YearCalendar * @extends BI.Widget */ BI.YearCalendar = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.YearCalendar.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-year-calendar", behaviors: {}, logic: { dynamic: false }, min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 year: null }) }, _yearCreator: function (Y) { var o = this.options; Y = Y | 0; var start = BI.YearCalendar.getStartYear(Y); var items = []; BI.each(BI.range(BI.YearCalendar.INTERVAL), function (i) { var td = {}; if (Date.checkVoid(start + i, 1, 1, o.min, o.max)[0]) { td.disabled = true; } td.text = start + i; items.push(td); }); return items; }, _init: function () { BI.YearCalendar.superclass._init.apply(this, arguments); var self = this, o = this.options; this.currentYear = new Date().getFullYear(); var years = this._yearCreator(o.year || this.currentYear); //纵向排列年 var len = years.length, tyears = BI.makeArray(len, ""); var map = [0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11]; BI.each(years, function (i, y) { tyears[i] = years[map[i]]; }); var items = []; items.push(tyears.slice(0, 2)); items.push(tyears.slice(2, 4)); items.push(tyears.slice(4, 6)); items.push(tyears.slice(6, 8)); items.push(tyears.slice(8, 10)); items.push(tyears.slice(10, 12)); items = BI.map(items, function (i, item) { return BI.map(item, function (j, td) { return BI.extend(td, { type: "bi.text_item", cls: "bi-list-item-active", textAlign: "center", whiteSpace: "normal", once: false, forceSelected: true, height: 23, width: 38, value: td.text, disabled: td.disabled }); }); }); this.years = BI.createWidget({ type: "bi.button_group", behaviors: o.behaviors, items: BI.createItems(items, {}), layouts: [BI.LogicFactory.createLogic("table", BI.extend({}, o.logic, { columns: 2, rows: 6, columnSize: [1 / 2, 1 / 2], rowSize: 25 })), { type: "bi.center_adapt", vgap: 1 }] }); this.years.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("vertical", BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("top", this.years) })))); }, isFrontYear: function () { var o = this.options; var Y = o.year; Y = Y | 0; return !!Date.checkVoid(BI.YearCalendar.getStartYear(Y) - 1, 1, 1, o.min, o.max)[0]; }, isFinalYear: function () { var o = this.options, c = this._const; var Y = o.year; Y = Y | 0; return !!Date.checkVoid(BI.YearCalendar.getEndYear(Y) + 1, 1, 1, o.min, o.max)[0]; }, setValue: function (val) { this.years.setValue([val]); }, getValue: function () { return this.years.getValue()[0]; } }); //类方法 BI.extend(BI.YearCalendar, { INTERVAL: 12, //获取显示的第一年 getStartYear: function (year) { var cur = new Date().getFullYear(); return year - ((year - cur + 3) % BI.YearCalendar.INTERVAL + 12) % BI.YearCalendar.INTERVAL; }, getEndYear: function (year) { return BI.YearCalendar.getStartYear(year) + BI.YearCalendar.INTERVAL; }, getPageByYear: function (year) { var cur = new Date().getFullYear(); year = BI.YearCalendar.getStartYear(year); return (year - cur + 3) / BI.YearCalendar.INTERVAL; } }); BI.shortcut("bi.year_calendar", BI.YearCalendar);/** * 绘制一些较复杂的canvas * * Created by GUY on 2015/11/24. * @class BI.ComplexCanvas * @extends BI.Widget */ BI.ComplexCanvas = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ComplexCanvas.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-complex-canvas" }) }, _init: function () { BI.ComplexCanvas.superclass._init.apply(this, arguments); var o = this.options; this.canvas = BI.createWidget({ type: "bi.canvas", element: this, width: o.width, height: o.height }); }, //绘制树枝节点 branch: function (x0, y0, x1, y1, x2, y2) { var self = this, args = [].slice.call(arguments); if (args.length <= 5) { return this.canvas.line.apply(this.canvas, arguments); } var options; if (BI.isOdd(args.length)) { options = BI.last(args); args = BI.initial(args); } args = [].slice.call(args, 2); var odd = BI.filter(args, function (i) { return i % 2 === 0; }); var even = BI.filter(args, function (i) { return i % 2 !== 0; }); options || (options = {}); var offset = options.offset || 20; if ((y0 > y1 && y0 > y2) || (y0 < y1 && y0 < y2)) { if (y0 > y1 && y0 > y2) { var y = Math.max.apply(this, even) + offset; } else { var y = Math.min.apply(this, even) - offset; } var minx = Math.min.apply(this, odd); var minix = BI.indexOf(odd, minx); var maxx = Math.max.apply(this, odd); var maxix = BI.indexOf(odd, maxx); this.canvas.line(minx, even[minix], minx, y, maxx, y, maxx, even[maxix], options); BI.each(odd, function (i, dot) { if (i !== maxix && i !== minix) { self.canvas.line(dot, even[i], dot, y, options); } }); this.canvas.line(x0, y, x0, y0, options); return; } if ((x0 > x1 && x0 > x2) || (x0 < x1 && x0 < x2)) { if (x0 > x1 && x0 > x2) { var x = Math.max.apply(this, odd) + offset; } else { var x = Math.min.apply(this, odd) - offset; } var miny = Math.min.apply(this, even); var miniy = BI.indexOf(even, miny); var maxy = Math.max.apply(this, even); var maxiy = BI.indexOf(even, maxy); this.canvas.line(odd[miniy], miny, x, miny, x, maxy, odd[maxiy], maxy, options); BI.each(even, function (i, dot) { if (i !== miniy && i !== maxiy) { self.canvas.line(odd[i], dot, x, dot, options); } }); this.canvas.line(x, y0, x0, y0, options); return; } }, stroke: function (callback) { this.canvas.stroke(callback); } }); BI.shortcut("bi.complex_canvas", BI.ComplexCanvas);/** * Created by roy on 15/10/16. * 上箭头与下箭头切换的树节点 */ BI.ArrowTreeGroupNodeCheckbox=BI.inherit(BI.IconButton,{ _defaultConfig:function(){ return BI.extend(BI.ArrowTreeGroupNodeCheckbox.superclass._defaultConfig.apply(this,arguments),{ extraCls:"bi-arrow-tree-group-node", iconWidth: 13, iconHeight: 13 }); }, _init:function(){ BI.ArrowTreeGroupNodeCheckbox.superclass._init.apply(this,arguments); }, setSelected: function(v){ BI.ArrowTreeGroupNodeCheckbox.superclass.setSelected.apply(this, arguments); if(v) { this.element.removeClass("column-next-page-h-font").addClass("column-pre-page-h-font"); } else { this.element.removeClass("column-pre-page-h-font").addClass("column-next-page-h-font"); } } }); BI.shortcut("bi.arrow_tree_group_node_checkbox",BI.ArrowTreeGroupNodeCheckbox);/** * 十字型的树节点 * @class BI.CheckingMarkNode * @extends BI.IconButton */ BI.CheckingMarkNode = BI.inherit(BI.IconButton, { _defaultConfig: function() { return BI.extend( BI.CheckingMarkNode.superclass._defaultConfig.apply(this, arguments), { extraCls: "check-mark-font", iconWidth: 13, iconHeight: 13 }); }, _init:function() { BI.CheckingMarkNode.superclass._init.apply(this, arguments); this.setSelected(this.options.selected); }, setSelected: function(v){ BI.CheckingMarkNode.superclass.setSelected.apply(this, arguments); if(v===true) { this.element.addClass("check-mark-font"); } else { this.element.removeClass("check-mark-font"); } } }); BI.shortcut("bi.checking_mark_node", BI.CheckingMarkNode);/** * 十字型的树节点 * @class BI.FirstTreeNodeCheckbox * @extends BI.IconButton */ BI.FirstTreeNodeCheckbox = BI.inherit(BI.IconButton, { _defaultConfig: function() { return BI.extend( BI.FirstTreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), { extraCls: "tree-collapse-icon-type2", iconWidth: 25, iconHeight: 25 }); }, _init:function() { BI.FirstTreeNodeCheckbox.superclass._init.apply(this, arguments); }, setSelected: function(v){ BI.FirstTreeNodeCheckbox.superclass.setSelected.apply(this, arguments); if(v===true) { this.element.addClass("tree-expand-icon-type2"); } else { this.element.removeClass("tree-expand-icon-type2"); } } }); BI.shortcut("bi.first_tree_node_checkbox", BI.FirstTreeNodeCheckbox);/** * 十字型的树节点 * @class BI.LastTreeNodeCheckbox * @extends BI.IconButton */ BI.LastTreeNodeCheckbox = BI.inherit(BI.IconButton, { _defaultConfig: function() { return BI.extend( BI.LastTreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), { extraCls: "tree-collapse-icon-type4", iconWidth: 25, iconHeight: 25 }); }, _init:function() { BI.LastTreeNodeCheckbox.superclass._init.apply(this, arguments); }, setSelected: function(v){ BI.LastTreeNodeCheckbox.superclass.setSelected.apply(this, arguments); if(v===true) { this.element.addClass("tree-expand-icon-type3"); } else { this.element.removeClass("tree-expand-icon-type3"); } } }); BI.shortcut("bi.last_tree_node_checkbox", BI.LastTreeNodeCheckbox);/** * 十字型的树节点 * @class BI.MidTreeNodeCheckbox * @extends BI.IconButton */ BI.MidTreeNodeCheckbox = BI.inherit(BI.IconButton, { _defaultConfig: function() { return BI.extend( BI.MidTreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), { extraCls: "tree-collapse-icon-type3", iconWidth: 25, iconHeight: 25 }); }, _init:function() { BI.MidTreeNodeCheckbox.superclass._init.apply(this, arguments); }, setSelected: function(v){ BI.MidTreeNodeCheckbox.superclass.setSelected.apply(this, arguments); if(v===true) { this.element.addClass("tree-expand-icon-type3"); } else { this.element.removeClass("tree-expand-icon-type3"); } } }); BI.shortcut("bi.mid_tree_node_checkbox", BI.MidTreeNodeCheckbox);/** * 三角形的树节点 * Created by GUY on 2015/9/6. * @class BI.TreeGroupNodeCheckbox * @extends BI.IconButton */ BI.TreeGroupNodeCheckbox = BI.inherit(BI.IconButton, { _defaultConfig: function() { return BI.extend( BI.TreeGroupNodeCheckbox.superclass._defaultConfig.apply(this, arguments), { extraCls: "tree-node-triangle-collapse-font", iconWidth: 13, iconHeight: 13 }); }, _init:function() { BI.TreeGroupNodeCheckbox.superclass._init.apply(this, arguments); }, setSelected: function(v){ BI.TreeGroupNodeCheckbox.superclass.setSelected.apply(this, arguments); if(v) { this.element.removeClass("tree-node-triangle-collapse-font").addClass("tree-node-triangle-expand-font"); } else { this.element.removeClass("tree-node-triangle-expand-font").addClass("tree-node-triangle-collapse-font"); } } }); BI.shortcut("bi.tree_group_node_checkbox", BI.TreeGroupNodeCheckbox);/** * 十字型的树节点 * @class BI.TreeNodeCheckbox * @extends BI.IconButton */ BI.TreeNodeCheckbox = BI.inherit(BI.IconButton, { _defaultConfig: function() { return BI.extend( BI.TreeNodeCheckbox.superclass._defaultConfig.apply(this, arguments), { extraCls: "tree-collapse-icon-type1", iconWidth: 25, iconHeight: 25 }); }, _init:function() { BI.TreeNodeCheckbox.superclass._init.apply(this, arguments); }, setSelected: function(v){ BI.TreeNodeCheckbox.superclass.setSelected.apply(this, arguments); if(v) { this.element.addClass("tree-expand-icon-type1"); } else { this.element.removeClass("tree-expand-icon-type1"); } } }); BI.shortcut("bi.tree_node_checkbox", BI.TreeNodeCheckbox);/*! * clipboard.js v1.6.1 * https://zenorocha.github.io/clipboard.js * * Licensed MIT © Zeno Rocha */ try {//IE8下会抛错 (function (f) { if (typeof exports === "object" && typeof module !== "undefined") { module.exports = f() } else if (typeof define === "function" && define.amd) { define([], f) } else { var g; if (typeof window !== "undefined") { g = window } else if (typeof global !== "undefined") { g = global } else if (typeof self !== "undefined") { g = self } else { g = this } g.Clipboard = f() } })(function () { var define, module, exports; return (function e(t, n, r) { function s(o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require == "function" && require; if (!u && a)return a(o, !0); if (i)return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = "MODULE_NOT_FOUND", f } var l = n[o] = {exports: {}}; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require == "function" && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({ 1: [function (require, module, exports) { var DOCUMENT_NODE_TYPE = 9; /** * A polyfill for Element.matches() */ if (typeof Element !== 'undefined' && !Element.prototype.matches) { var proto = Element.prototype; proto.matches = proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector; } /** * Finds the closest parent that matches a selector. * * @param {Element} element * @param {String} selector * @return {Function} */ function closest(element, selector) { while (element && element.nodeType !== DOCUMENT_NODE_TYPE) { if (element.matches(selector)) return element; element = element.parentNode; } } module.exports = closest; }, {}], 2: [function (require, module, exports) { var closest = require('./closest'); /** * Delegates event to a selector. * * @param {Element} element * @param {String} selector * @param {String} type * @param {Function} callback * @param {Boolean} useCapture * @return {Object} */ function delegate(element, selector, type, callback, useCapture) { var listenerFn = listener.apply(this, arguments); element.addEventListener(type, listenerFn, useCapture); return { destroy: function () { element.removeEventListener(type, listenerFn, useCapture); } } } /** * Finds closest match and invokes callback. * * @param {Element} element * @param {String} selector * @param {String} type * @param {Function} callback * @return {Function} */ function listener(element, selector, type, callback) { return function (e) { e.delegateTarget = closest(e.target, selector); if (e.delegateTarget) { callback.call(element, e); } } } module.exports = delegate; }, {"./closest": 1}], 3: [function (require, module, exports) { /** * Check if argument is a HTML element. * * @param {Object} value * @return {Boolean} */ exports.node = function (value) { return value !== undefined && value instanceof HTMLElement && value.nodeType === 1; }; /** * Check if argument is a list of HTML elements. * * @param {Object} value * @return {Boolean} */ exports.nodeList = function (value) { var type = Object.prototype.toString.call(value); return value !== undefined && (type === '[object NodeList]' || type === '[object HTMLCollection]') && ('length' in value) && (value.length === 0 || exports.node(value[0])); }; /** * Check if argument is a string. * * @param {Object} value * @return {Boolean} */ exports.string = function (value) { return typeof value === 'string' || value instanceof String; }; /** * Check if argument is a function. * * @param {Object} value * @return {Boolean} */ exports.fn = function (value) { var type = Object.prototype.toString.call(value); return type === '[object Function]'; }; }, {}], 4: [function (require, module, exports) { var is = require('./is'); var delegate = require('delegate'); /** * Validates all params and calls the right * listener function based on its target type. * * @param {String|HTMLElement|HTMLCollection|NodeList} target * @param {String} type * @param {Function} callback * @return {Object} */ function listen(target, type, callback) { if (!target && !type && !callback) { throw new Error('Missing required arguments'); } if (!is.string(type)) { throw new TypeError('Second argument must be a String'); } if (!is.fn(callback)) { throw new TypeError('Third argument must be a Function'); } if (is.node(target)) { return listenNode(target, type, callback); } else if (is.nodeList(target)) { return listenNodeList(target, type, callback); } else if (is.string(target)) { return listenSelector(target, type, callback); } else { throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList'); } } /** * Adds an event listener to a HTML element * and returns a remove listener function. * * @param {HTMLElement} node * @param {String} type * @param {Function} callback * @return {Object} */ function listenNode(node, type, callback) { node.addEventListener(type, callback); return { destroy: function () { node.removeEventListener(type, callback); } } } /** * Add an event listener to a list of HTML elements * and returns a remove listener function. * * @param {NodeList|HTMLCollection} nodeList * @param {String} type * @param {Function} callback * @return {Object} */ function listenNodeList(nodeList, type, callback) { Array.prototype.forEach.call(nodeList, function (node) { node.addEventListener(type, callback); }); return { destroy: function () { Array.prototype.forEach.call(nodeList, function (node) { node.removeEventListener(type, callback); }); } } } /** * Add an event listener to a selector * and returns a remove listener function. * * @param {String} selector * @param {String} type * @param {Function} callback * @return {Object} */ function listenSelector(selector, type, callback) { return delegate(document.body, selector, type, callback); } module.exports = listen; }, {"./is": 3, "delegate": 2}], 5: [function (require, module, exports) { function select(element) { var selectedText; if (element.nodeName === 'SELECT') { element.focus(); selectedText = element.value; } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') { var isReadOnly = element.hasAttribute('readonly'); if (!isReadOnly) { element.setAttribute('readonly', ''); } element.select(); element.setSelectionRange(0, element.value.length); if (!isReadOnly) { element.removeAttribute('readonly'); } selectedText = element.value; } else { if (element.hasAttribute('contenteditable')) { element.focus(); } var selection = window.getSelection(); var range = document.createRange(); range.selectNodeContents(element); selection.removeAllRanges(); selection.addRange(range); selectedText = selection.toString(); } return selectedText; } module.exports = select; }, {}], 6: [function (require, module, exports) { function E() { // Keep this empty so it's easier to inherit from // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3) } E.prototype = { on: function (name, callback, ctx) { var e = this.e || (this.e = {}); (e[name] || (e[name] = [])).push({ fn: callback, ctx: ctx }); return this; }, once: function (name, callback, ctx) { var self = this; function listener() { self.off(name, listener); callback.apply(ctx, arguments); }; listener._ = callback return this.on(name, listener, ctx); }, emit: function (name) { var data = [].slice.call(arguments, 1); var evtArr = ((this.e || (this.e = {}))[name] || []).slice(); var i = 0; var len = evtArr.length; for (i; i < len; i++) { evtArr[i].fn.apply(evtArr[i].ctx, data); } return this; }, off: function (name, callback) { var e = this.e || (this.e = {}); var evts = e[name]; var liveEvents = []; if (evts && callback) { for (var i = 0, len = evts.length; i < len; i++) { if (evts[i].fn !== callback && evts[i].fn._ !== callback) liveEvents.push(evts[i]); } } // Remove event from queue to prevent memory leak // Suggested by https://github.com/lazd // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910 (liveEvents.length) ? e[name] = liveEvents : delete e[name]; return this; } }; module.exports = E; }, {}], 7: [function (require, module, exports) { (function (global, factory) { if (typeof define === "function" && define.amd) { define(['module', 'select'], factory); } else if (typeof exports !== "undefined") { factory(module, require('select')); } else { var mod = { exports: {} }; factory(mod, global.select); global.clipboardAction = mod.exports; } })(this, function (module, _select) { 'use strict'; var _select2 = _interopRequireDefault(_select); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var ClipboardAction = function () { /** * @param {Object} options */ function ClipboardAction(options) { _classCallCheck(this, ClipboardAction); this.resolveOptions(options); this.initSelection(); } /** * Defines base properties passed from constructor. * @param {Object} options */ _createClass(ClipboardAction, [{ key: 'resolveOptions', value: function resolveOptions() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.action = options.action; this.emitter = options.emitter; this.target = options.target; this.text = options.text; this.trigger = options.trigger; this.selectedText = ''; } }, { key: 'initSelection', value: function initSelection() { if (this.text) { this.selectFake(); } else if (this.target) { this.selectTarget(); } } }, { key: 'selectFake', value: function selectFake() { var _this = this; var isRTL = document.documentElement.getAttribute('dir') == 'rtl'; this.removeFake(); this.fakeHandlerCallback = function () { return _this.removeFake(); }; this.fakeHandler = document.body.addEventListener('click', this.fakeHandlerCallback) || true; this.fakeElem = document.createElement('textarea'); // Prevent zooming on iOS this.fakeElem.style.fontSize = '12pt'; // Reset box model this.fakeElem.style.border = '0'; this.fakeElem.style.padding = '0'; this.fakeElem.style.margin = '0'; // Move element out of screen horizontally this.fakeElem.style.position = 'absolute'; this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically var yPosition = window.pageYOffset || document.documentElement.scrollTop; this.fakeElem.style.top = yPosition + 'px'; this.fakeElem.setAttribute('readonly', ''); this.fakeElem.value = this.text; document.body.appendChild(this.fakeElem); this.selectedText = (0, _select2["default"])(this.fakeElem); this.copyText(); } }, { key: 'removeFake', value: function removeFake() { if (this.fakeHandler) { document.body.removeEventListener('click', this.fakeHandlerCallback); this.fakeHandler = null; this.fakeHandlerCallback = null; } if (this.fakeElem) { document.body.removeChild(this.fakeElem); this.fakeElem = null; } } }, { key: 'selectTarget', value: function selectTarget() { this.selectedText = (0, _select2["default"])(this.target); this.copyText(); } }, { key: 'copyText', value: function copyText() { var succeeded = void 0; try { succeeded = document.execCommand(this.action); } catch (err) { succeeded = false; } this.handleResult(succeeded); } }, { key: 'handleResult', value: function handleResult(succeeded) { this.emitter.emit(succeeded ? 'success' : 'error', { action: this.action, text: this.selectedText, trigger: this.trigger, clearSelection: this.clearSelection.bind(this) }); } }, { key: 'clearSelection', value: function clearSelection() { if (this.target) { this.target.blur(); } window.getSelection().removeAllRanges(); } }, { key: 'destroy', value: function destroy() { this.removeFake(); } }, { key: 'action', set: function set() { var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy'; this._action = action; if (this._action !== 'copy' && this._action !== 'cut') { throw new Error('Invalid "action" value, use either "copy" or "cut"'); } }, get: function get() { return this._action; } }, { key: 'target', set: function set(target) { if (target !== undefined) { if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) { if (this.action === 'copy' && target.hasAttribute('disabled')) { throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); } if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) { throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); } this._target = target; } else { throw new Error('Invalid "target" value, use a valid Element'); } } }, get: function get() { return this._target; } }]); return ClipboardAction; }(); module.exports = ClipboardAction; }); }, {"select": 5}], 8: [function (require, module, exports) { (function (global, factory) { if (typeof define === "function" && define.amd) { define(['module', './clipboard-action', 'tiny-emitter', 'good-listener'], factory); } else if (typeof exports !== "undefined") { factory(module, require('./clipboard-action'), require('tiny-emitter'), require('good-listener')); } else { var mod = { exports: {} }; factory(mod, global.clipboardAction, global.tinyEmitter, global.goodListener); global.clipboard = mod.exports; } })(this, function (module, _clipboardAction, _tinyEmitter, _goodListener) { 'use strict'; var _clipboardAction2 = _interopRequireDefault(_clipboardAction); var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter); var _goodListener2 = _interopRequireDefault(_goodListener); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var Clipboard = function (_Emitter) { _inherits(Clipboard, _Emitter); /** * @param {String|HTMLElement|HTMLCollection|NodeList} trigger * @param {Object} options */ function Clipboard(trigger, options) { _classCallCheck(this, Clipboard); var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this)); _this.resolveOptions(options); _this.listenClick(trigger); return _this; } /** * Defines if attributes would be resolved using internal setter functions * or custom functions that were passed in the constructor. * @param {Object} options */ _createClass(Clipboard, [{ key: 'resolveOptions', value: function resolveOptions() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.action = typeof options.action === 'function' ? options.action : this.defaultAction; this.target = typeof options.target === 'function' ? options.target : this.defaultTarget; this.text = typeof options.text === 'function' ? options.text : this.defaultText; } }, { key: 'listenClick', value: function listenClick(trigger) { var _this2 = this; this.listener = (0, _goodListener2["default"])(trigger, 'click', function (e) { return _this2.onClick(e); }); } }, { key: 'onClick', value: function onClick(e) { var trigger = e.delegateTarget || e.currentTarget; if (this.clipboardAction) { this.clipboardAction = null; } this.clipboardAction = new _clipboardAction2["default"]({ action: this.action(trigger), target: this.target(trigger), text: this.text(trigger), trigger: trigger, emitter: this }); } }, { key: 'defaultAction', value: function defaultAction(trigger) { return getAttributeValue('action', trigger); } }, { key: 'defaultTarget', value: function defaultTarget(trigger) { var selector = getAttributeValue('target', trigger); if (selector) { return document.querySelector(selector); } } }, { key: 'defaultText', value: function defaultText(trigger) { return getAttributeValue('text', trigger); } }, { key: 'destroy', value: function destroy() { this.listener.destroy(); if (this.clipboardAction) { this.clipboardAction.destroy(); this.clipboardAction = null; } } }], [{ key: 'isSupported', value: function isSupported() { var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut']; var actions = typeof action === 'string' ? [action] : action; var support = !!document.queryCommandSupported; actions.forEach(function (action) { support = support && !!document.queryCommandSupported(action); }); return support; } }]); return Clipboard; }(_tinyEmitter2["default"]); /** * Helper function to retrieve attribute value. * @param {String} suffix * @param {Element} element */ function getAttributeValue(suffix, element) { var attribute = 'data-clipboard-' + suffix; if (!element.hasAttribute(attribute)) { return; } return element.getAttribute(attribute); } module.exports = Clipboard; }); }, {"./clipboard-action": 7, "good-listener": 4, "tiny-emitter": 6}] }, {}, [8])(8) }); } catch (e) { /* * zClip :: jQuery ZeroClipboard v1.1.1 * http://steamdev.com/zclip * * Copyright 2011, SteamDev * Released under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Date: Wed Jun 01, 2011 */ (function ($) { $.fn.zclip = function (params) { if (typeof params == "object" && !params.length) { var settings = $.extend({ path: 'ZeroClipboard.swf', copy: null, beforeCopy: null, afterCopy: null, clickAfter: true, setHandCursor: true, setCSSEffects: true }, params); return this.each(function () { var o = $(this); if (o.is(':visible') && (typeof settings.copy == 'string' || $.isFunction(settings.copy))) { ZeroClipboard.setMoviePath(settings.path); var clip = new ZeroClipboard.Client(); if ($.isFunction(settings.copy)) { o.bind('zClip_copy', settings.copy); } if ($.isFunction(settings.beforeCopy)) { o.bind('zClip_beforeCopy', settings.beforeCopy); } if ($.isFunction(settings.afterCopy)) { o.bind('zClip_afterCopy', settings.afterCopy); } clip.setHandCursor(settings.setHandCursor); clip.setCSSEffects(settings.setCSSEffects); clip.addEventListener('mouseOver', function (client) { o.trigger('mouseenter'); }); clip.addEventListener('mouseOut', function (client) { o.trigger('mouseleave'); }); clip.addEventListener('mouseDown', function (client) { o.trigger('mousedown'); if (!$.isFunction(settings.copy)) { clip.setText(settings.copy); } else { clip.setText(o.triggerHandler('zClip_copy')); } if ($.isFunction(settings.beforeCopy)) { o.trigger('zClip_beforeCopy'); } }); clip.addEventListener('complete', function (client, text) { if ($.isFunction(settings.afterCopy)) { o.trigger('zClip_afterCopy'); } else { if (text.length > 500) { text = text.substr(0, 500) + "...\n\n(" + (text.length - 500) + " characters not shown)"; } o.removeClass('hover'); alert("Copied text to clipboard:\n\n " + text); } if (settings.clickAfter) { o.trigger('click'); } }); clip.glue(o[0], o.parent()[0]); $(window).bind('load resize', function () { clip.reposition(); }); } }); } else if (typeof params == "string") { return this.each(function () { var o = $(this); params = params.toLowerCase(); var zclipId = o.data('zclipId'); var clipElm = $('#' + zclipId + '.zclip'); if (params == "remove") { clipElm.remove(); o.removeClass('active hover'); } else if (params == "hide") { clipElm.hide(); o.removeClass('active hover'); } else if (params == "show") { clipElm.show(); } }); } } })(jQuery); // ZeroClipboard // Simple Set Clipboard System // Author: Joseph Huckaby var ZeroClipboard = { version: "1.0.7", clients: {}, // registered upload clients on page, indexed by id moviePath: 'ZeroClipboard.swf', // URL to movie nextId: 1, // ID of next movie $: function (thingy) { // simple DOM lookup utility function if (typeof(thingy) == 'string') thingy = document.getElementById(thingy); if (!thingy.addClass) { // extend element with a few useful methods thingy.hide = function () { this.style.display = 'none'; }; thingy.show = function () { this.style.display = ''; }; thingy.addClass = function (name) { this.removeClass(name); this.className += ' ' + name; }; thingy.removeClass = function (name) { var classes = this.className.split(/\s+/); var idx = -1; for (var k = 0; k < classes.length; k++) { if (classes[k] == name) { idx = k; k = classes.length; } } if (idx > -1) { classes.splice(idx, 1); this.className = classes.join(' '); } return this; }; thingy.hasClass = function (name) { return !!this.className.match(new RegExp("\\s*" + name + "\\s*")); }; } return thingy; }, setMoviePath: function (path) { // set path to ZeroClipboard.swf this.moviePath = path; }, dispatch: function (id, eventName, args) { // receive event from flash movie, send to client var client = this.clients[id]; if (client) { client.receiveEvent(eventName, args); } }, register: function (id, client) { // register new client to receive events this.clients[id] = client; }, getDOMObjectPosition: function (obj, stopObj) { // get absolute coordinates for dom element var info = { left: 0, top: 0, width: obj.width ? obj.width : obj.offsetWidth, height: obj.height ? obj.height : obj.offsetHeight }; if (obj && (obj != stopObj)) { info.left += obj.offsetLeft; info.top += obj.offsetTop; } return info; }, Client: function (elem) { // constructor for new simple upload client this.handlers = {}; // unique ID this.id = ZeroClipboard.nextId++; this.movieId = 'ZeroClipboardMovie_' + this.id; // register client with singleton to receive flash events ZeroClipboard.register(this.id, this); // create movie if (elem) this.glue(elem); } }; ZeroClipboard.Client.prototype = { id: 0, // unique ID for us ready: false, // whether movie is ready to receive events or not movie: null, // reference to movie object clipText: '', // text to copy to clipboard handCursorEnabled: true, // whether to show hand cursor, or default pointer cursor cssEffects: true, // enable CSS mouse effects on dom container handlers: null, // user event handlers glue: function (elem, appendElem, stylesToAdd) { // glue to DOM element // elem can be ID or actual DOM element object this.domElement = ZeroClipboard.$(elem); // float just above object, or zIndex 99 if dom element isn't set var zIndex = 99; if (this.domElement.style.zIndex) { zIndex = parseInt(this.domElement.style.zIndex, 10) + 1; } if (typeof(appendElem) == 'string') { appendElem = ZeroClipboard.$(appendElem); } else if (typeof(appendElem) == 'undefined') { appendElem = document.getElementsByTagName('body')[0]; } // find X/Y position of domElement var box = ZeroClipboard.getDOMObjectPosition(this.domElement, appendElem); // create floating DIV above element this.div = document.createElement('div'); this.div.className = "zclip"; this.div.id = "zclip-" + this.movieId; $(this.domElement).data('zclipId', 'zclip-' + this.movieId); var style = this.div.style; style.position = 'absolute'; style.left = '' + box.left + 'px'; style.top = '' + box.top + 'px'; style.width = '' + box.width + 'px'; style.height = '' + box.height + 'px'; style.zIndex = zIndex; if (typeof(stylesToAdd) == 'object') { for (addedStyle in stylesToAdd) { style[addedStyle] = stylesToAdd[addedStyle]; } } // style.backgroundColor = '#f00'; // debug appendElem.appendChild(this.div); this.div.innerHTML = this.getHTML(box.width, box.height); }, getHTML: function (width, height) { // return HTML for movie var html = ''; var flashvars = 'id=' + this.id + '&width=' + width + '&height=' + height; if (navigator.userAgent.match(/MSIE/)) { // IE gets an OBJECT tag var protocol = location.href.match(/^https/i) ? 'https://' : 'http://'; html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="' + protocol + 'download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="' + width + '" height="' + height + '" id="' + this.movieId + '" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="' + ZeroClipboard.moviePath + '" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="' + flashvars + '"/><param name="wmode" value="transparent"/></object>'; } else { // all other browsers get an EMBED tag html += '<embed id="' + this.movieId + '" src="' + ZeroClipboard.moviePath + '" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="' + width + '" height="' + height + '" name="' + this.movieId + '" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="' + flashvars + '" wmode="transparent" />'; } return html; }, hide: function () { // temporarily hide floater offscreen if (this.div) { this.div.style.left = '-2000px'; } }, show: function () { // show ourselves after a call to hide() this.reposition(); }, destroy: function () { // destroy control and floater if (this.domElement && this.div) { this.hide(); this.div.innerHTML = ''; var body = document.getElementsByTagName('body')[0]; try { body.removeChild(this.div); } catch (e) { ; } this.domElement = null; this.div = null; } }, reposition: function (elem) { // reposition our floating div, optionally to new container // warning: container CANNOT change size, only position if (elem) { this.domElement = ZeroClipboard.$(elem); if (!this.domElement) this.hide(); } if (this.domElement && this.div) { var box = ZeroClipboard.getDOMObjectPosition(this.domElement); var style = this.div.style; style.left = '' + box.left + 'px'; style.top = '' + box.top + 'px'; } }, setText: function (newText) { // set text to be copied to clipboard this.clipText = newText; if (this.ready) { this.movie.setText(newText); } }, addEventListener: function (eventName, func) { // add user event listener for event // event types: load, queueStart, fileStart, fileComplete, queueComplete, progress, error, cancel eventName = eventName.toString().toLowerCase().replace(/^on/, ''); if (!this.handlers[eventName]) { this.handlers[eventName] = []; } this.handlers[eventName].push(func); }, setHandCursor: function (enabled) { // enable hand cursor (true), or default arrow cursor (false) this.handCursorEnabled = enabled; if (this.ready) { this.movie.setHandCursor(enabled); } }, setCSSEffects: function (enabled) { // enable or disable CSS effects on DOM container this.cssEffects = !!enabled; }, receiveEvent: function (eventName, args) { // receive event from flash eventName = eventName.toString().toLowerCase().replace(/^on/, ''); // special behavior for certain events switch (eventName) { case 'load': // movie claims it is ready, but in IE this isn't always the case... // bug fix: Cannot extend EMBED DOM elements in Firefox, must use traditional function this.movie = document.getElementById(this.movieId); if (!this.movie) { var self = this; setTimeout(function () { self.receiveEvent('load', null); }, 1); return; } // firefox on pc needs a "kick" in order to set these in certain cases if (!this.ready && navigator.userAgent.match(/Firefox/) && navigator.userAgent.match(/Windows/)) { var self = this; setTimeout(function () { self.receiveEvent('load', null); }, 100); this.ready = true; return; } this.ready = true; try { this.movie.setText(this.clipText); } catch (e) { } try { this.movie.setHandCursor(this.handCursorEnabled); } catch (e) { } break; case 'mouseover': if (this.domElement && this.cssEffects) { this.domElement.addClass('hover'); if (this.recoverActive) { this.domElement.addClass('active'); } } break; case 'mouseout': if (this.domElement && this.cssEffects) { this.recoverActive = false; if (this.domElement.hasClass('active')) { this.domElement.removeClass('active'); this.recoverActive = true; } this.domElement.removeClass('hover'); } break; case 'mousedown': if (this.domElement && this.cssEffects) { this.domElement.addClass('active'); } break; case 'mouseup': if (this.domElement && this.cssEffects) { this.domElement.removeClass('active'); this.recoverActive = false; } break; } // switch eventName if (this.handlers[eventName]) { for (var idx = 0, len = this.handlers[eventName].length; idx < len; idx++) { var func = this.handlers[eventName][idx]; if (typeof(func) == 'function') { // actual function reference func(this, args); } else if ((typeof(func) == 'object') && (func.length == 2)) { // PHP style object + method, i.e. [myObject, 'myMethod'] func[0][func[1]](this, args); } else if (typeof(func) == 'string') { // name of function window[func](this, args); } } // foreach event handler defined } // user defined handler for event } }; }/** * 复制 * Created by GUY on 2016/2/16. * @class BI.ClipBoard * @extends BI.BasicButton */ BI.ClipBoard = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.ClipBoard.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-clipboard", copy: BI.emptyFn, afterCopy: BI.emptyFn }) }, _init: function () { BI.ClipBoard.superclass._init.apply(this, arguments); }, mounted: function () { var self = this, o = this.options; if (window.Clipboard) { this.clipboard = new Clipboard(this.element[0], { text: function () { return BI.isFunction(o.copy) ? o.copy() : o.copy; } }); this.clipboard.on("success", o.afterCopy) } else { this.element.zclip({ path: BI.resourceURL + "/ZeroClipboard.swf", copy: o.copy, beforeCopy: o.beforeCopy, afterCopy: o.afterCopy }); } }, destroyed: function () { this.clipboard && this.clipboard.destroy(); } }); BI.shortcut("bi.clipboard", BI.ClipBoard);/** * 自定义选色 * * Created by GUY on 2015/11/17. * @class BI.CustomColorChooser * @extends BI.Widget */ BI.CustomColorChooser = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.CustomColorChooser.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-custom-color-chooser", width: 227, height: 245 }) }, _init: function () { BI.CustomColorChooser.superclass._init.apply(this, arguments); var self = this; this.editor = BI.createWidget({ type: "bi.color_picker_editor", width: 195 }); this.editor.on(BI.ColorPickerEditor.EVENT_CHANGE, function () { self.setValue(this.getValue()); }); this.farbtastic = BI.createWidget({ type: "bi.farbtastic" }); this.farbtastic.on(BI.Farbtastic.EVENT_CHANGE, function () { self.setValue(this.getValue()); }); BI.createWidget({ type: "bi.vtape", element: this, items: [{ type: "bi.absolute", items: [{ el: this.editor, left: 15, top: 10, right: 15 }], height: 30 }, { type: "bi.absolute", items: [{ el: this.farbtastic, left: 15, right: 15, top: 10 }], height: 215 }] }) }, setValue: function (color) { this.editor.setValue(color); this.farbtastic.setValue(color); }, getValue: function () { return this.editor.getValue(); } }); BI.CustomColorChooser.EVENT_CHANGE = "CustomColorChooser.EVENT_CHANGE"; BI.shortcut("bi.custom_color_chooser", BI.CustomColorChooser);/** * 选色控件 * * Created by GUY on 2015/11/17. * @class BI.ColorChooser * @extends BI.Widget */ BI.ColorChooser = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ColorChooser.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-color-chooser", el: {} }) }, _init: function () { BI.ColorChooser.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(BI.extend({ type: "bi.color_chooser_trigger", width: o.width, height: o.height }, o.el)); this.colorPicker = BI.createWidget({ type: "bi.color_chooser_popup" }); this.combo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 1, el: this.trigger, popup: { el: this.colorPicker, stopPropagation: false, minWidth: 202 } }); var fn = function () { var color = self.colorPicker.getValue(); self.trigger.setValue(color); var colors = BI.string2Array(BI.Cache.getItem("colors") || ""); var que = new BI.Queue(8); que.fromArray(colors); que.remove(color); que.unshift(color); BI.Cache.setItem("colors", BI.array2String(que.toArray())); }; this.colorPicker.on(BI.ColorChooserPopup.EVENT_VALUE_CHANGE, function () { fn(); }); this.colorPicker.on(BI.ColorChooserPopup.EVENT_CHANGE, function () { fn(); self.combo.hideView(); }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.colorPicker.setStoreColors(BI.string2Array(BI.Cache.getItem("colors") || "")); }); this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () { self.fireEvent(BI.ColorChooser.EVENT_CHANGE, arguments); }) }, isViewVisible: function () { return this.combo.isViewVisible(); }, setValue: function (color) { this.combo.setValue(color); }, getValue: function () { return this.colorPicker.getValue(); } }); BI.ColorChooser.EVENT_CHANGE = "ColorChooser.EVENT_CHANGE"; BI.shortcut("bi.color_chooser", BI.ColorChooser);/** * 选色控件 * * Created by GUY on 2015/11/17. * @class BI.ColorChooserPopup * @extends BI.Widget */ BI.ColorChooserPopup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ColorChooserPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-color-chooser-popup", height: 145 }) }, _init: function () { BI.ColorChooserPopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.colorEditor = BI.createWidget({ type: "bi.color_picker_editor" }); this.colorEditor.on(BI.ColorPickerEditor.EVENT_CHANGE, function () { self.setValue(this.getValue()); self.fireEvent(BI.ColorChooserPopup.EVENT_VALUE_CHANGE, arguments); }); this.storeColors = BI.createWidget({ type: "bi.color_picker", items: [[{ value: "", disabled: true }, { value: "", disabled: true }, { value: "", disabled: true }, { value: "", disabled: true }, { value: "", disabled: true }, { value: "", disabled: true }, { value: "", disabled: true }, { value: "", disabled: true }]], width: 190, height: 25 }); this.storeColors.on(BI.ColorPicker.EVENT_CHANGE, function () { self.setValue(this.getValue()[0]); self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments); }); this.colorPicker = BI.createWidget({ type: "bi.color_picker", width: 190, height: 50 }); this.colorPicker.on(BI.ColorPicker.EVENT_CHANGE, function () { self.setValue(this.getValue()[0]); self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments); }); this.customColorChooser = BI.createWidget({ type: "bi.custom_color_chooser" }); var panel = BI.createWidget({ type: "bi.popup_panel", buttons: [BI.i18nText("BI-Basic_Cancel"), BI.i18nText("BI-Basic_Save")], title: BI.i18nText("BI-Custom_Color"), el: this.customColorChooser, stopPropagation: false, bgap: -1, rgap: 1, lgap: 1, minWidth: 227 }); this.more = BI.createWidget({ type: "bi.combo", direction: "right,top", isNeedAdjustHeight: false, el: { type: "bi.text_item", cls: "color-chooser-popup-more bi-list-item", textAlign: "center", height: 20, text: BI.i18nText("BI-Basic_More") + "..." }, popup: panel }); this.more.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () { self.customColorChooser.setValue(self.getValue()); }); panel.on(BI.PopupPanel.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { switch (index) { case 0: self.more.hideView(); break; case 1: self.setValue(self.customColorChooser.getValue()); self.more.hideView(); self.fireEvent(BI.ColorChooserPopup.EVENT_CHANGE, arguments); break; } }); BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: { type: "bi.absolute", cls: "bi-background bi-border-bottom", items: [{ el: this.colorEditor, left: 0, right: 0, top: 5 }] }, height: 30 }, { el: { type: "bi.absolute", items: [{ el: this.storeColors, left: 5, right: 5, top: 5 }] }, height: 30 }, { el: { type: "bi.absolute", items: [{ el: this.colorPicker, left: 5, right: 5, top: 5 }] }, height: 65 }, { el: this.more, height: 20 }] }) }, setStoreColors: function (colors) { if (BI.isArray(colors)) { var items = BI.map(colors, function (i, color) { return { value: color } }); BI.count(colors.length, 8, function (i) { items.push({ value: "", disabled: true }) }); this.storeColors.populate([items]); } }, setValue: function (color) { this.colorEditor.setValue(color); this.colorPicker.setValue(color); this.storeColors.setValue(color); }, getValue: function () { return this.colorEditor.getValue(); } }); BI.ColorChooserPopup.EVENT_VALUE_CHANGE = "ColorChooserPopup.EVENT_VALUE_CHANGE"; BI.ColorChooserPopup.EVENT_CHANGE = "ColorChooserPopup.EVENT_CHANGE"; BI.shortcut("bi.color_chooser_popup", BI.ColorChooserPopup);/** * 选色控件 * * Created by GUY on 2015/11/17. * @class BI.ColorChooserTrigger * @extends BI.Trigger */ BI.ColorChooserTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { var conf = BI.ColorChooserTrigger.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-color-chooser-trigger", height: 30 }) }, _init: function () { BI.ColorChooserTrigger.superclass._init.apply(this, arguments); this.colorContainer = BI.createWidget({ type: "bi.layout", cls: "bi-card color-chooser-trigger-content" }); var down = BI.createWidget({ type: "bi.icon_button", disableSelected: true, cls: "icon-combo-down-icon trigger-triangle-font", width: 12, height: 8 }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.colorContainer, left: 3, right: 3, top: 3, bottom: 3 }, { el: down, right: 3, bottom: 3 }] }); if (this.options.value) { this.setValue(this.options.value); } }, setValue: function (color) { BI.ColorChooserTrigger.superclass.setValue.apply(this, arguments); if (color === "") { this.colorContainer.element.css("background-color", "").removeClass("trans-color-background").addClass("auto-color-background"); } else if (color === "transparent") { this.colorContainer.element.css("background-color", "").removeClass("auto-color-background").addClass("trans-color-background") } else { this.colorContainer.element.css({"background-color": color}).removeClass("auto-color-background").removeClass("trans-color-background"); } } }); BI.ColorChooserTrigger.EVENT_CHANGE = "ColorChooserTrigger.EVENT_CHANGE"; BI.shortcut("bi.color_chooser_trigger", BI.ColorChooserTrigger);/** * 简单选色控件按钮 * * Created by GUY on 2015/11/16. * @class BI.ColorPickerButton * @extends BI.BasicButton */ BI.ColorPickerButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.ColorPickerButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-color-picker-button bi-background bi-border-top bi-border-left" }) }, _init: function () { BI.ColorPickerButton.superclass._init.apply(this, arguments); var self = this, o = this.options; if (o.value) { this.element.css("background-color", o.value); var name = this.getName(); this.element.hover(function () { self._createMask(); if (self.isEnabled()) { BI.Maskers.show(name); } }, function () { if (!self.isSelected()) { BI.Maskers.hide(name); } }); } }, _createMask: function () { var o = this.options, name = this.getName(); if (this.isEnabled() && !BI.Maskers.has(name)) { var w = BI.Maskers.make(name, this, { offset: { left: -1, top: -1, right: -1, bottom: -1 } }); w.element.addClass("color-picker-button-mask").css("background-color", o.value); } }, setSelected: function (b) { BI.ColorPickerButton.superclass.setSelected.apply(this, arguments); if (!!b) { this._createMask(); } BI.Maskers[!!b ? "show" : "hide"](this.getName()); } }); BI.ColorPickerButton.EVENT_CHANGE = "ColorPickerButton.EVENT_CHANGE"; BI.shortcut("bi.color_picker_button", BI.ColorPickerButton);/** * 简单选色控件 * * Created by GUY on 2015/11/16. * @class BI.ColorPicker * @extends BI.Widget */ BI.ColorPicker = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ColorPicker.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-color-picker", items: null }) }, _items: [ [{ value: "#ffffff" }, { value: "#f2f2f2" }, { value: "#e5e5e5" }, { value: "#d9d9d9" }, { value: "#cccccc" }, { value: "#bfbfbf" }, { value: "#b2b2b2" }, { value: "#a6a6a6" }, { value: "#999999" }, { value: "#8c8c8c" }, { value: "#808080" }, { value: "#737373" }, { value: "#666666" }, { value: "#4d4d4d" }, { value: "#333333" }, { value: "#000000" }], [{ value: "#d8b5a6" }, { value: "#ff9e9a" }, { value: "#ffc17d" }, { value: "#f5e56b" }, { value: "#d8e698" }, { value: "#e0ebaf" }, { value: "#c3d825" }, { value: "#bce2e8" }, { value: "#85d3cd" }, { value: "#bce2e8" }, { value: "#a0d8ef" }, { value: "#89c3eb" }, { value: "#bbc8e6" }, { value: "#bbbcde" }, { value: "#d6b4cc" }, { value: "#fbc0d3" }], [{ value: "#bb9581" }, { value: "#f37d79" }, { value: "#fba74f" }, { value: "#ffdb4f" }, { value: "#c7dc68" }, { value: "#b0ca71" }, { value: "#99ab4e" }, { value: "#84b9cb" }, { value: "#00a3af" }, { value: "#2ca9e1" }, { value: "#0095d9" }, { value: "#4c6cb3" }, { value: "#8491c3" }, { value: "#a59aca" }, { value: "#cc7eb1" }, { value: "#e89bb4" }], [{ value: "#9d775f" }, { value: "#dd4b4b" }, { value: "#ef8b07" }, { value: "#fcc800" }, { value: "#aacf53" }, { value: "#82ae46" }, { value: "#69821b" }, { value: "#59b9c6" }, { value: "#2a83a2" }, { value: "#007bbb" }, { value: "#19448e" }, { value: "#274a78" }, { value: "#4a488e" }, { value: "#7058a3" }, { value: "#884898" }, { value: "#d47596" }] ], _init: function () { BI.ColorPicker.superclass._init.apply(this, arguments); var self = this, o = this.options; this.colors = BI.createWidget({ type: "bi.button_group", element: this, items: BI.createItems(o.items || this._items, { type: "bi.color_picker_button", once: false }), layouts: [{ type: "bi.grid" }] }); this.colors.on(BI.ButtonGroup.EVENT_CHANGE, function () { self.fireEvent(BI.ColorPicker.EVENT_CHANGE, arguments); }) }, populate: function(items){ var args =[].slice.call(arguments); args[0] = BI.createItems(items, { type: "bi.color_picker_button", once: false }); this.colors.populate.apply(this.colors, args); }, setValue: function (color) { this.colors.setValue(color); }, getValue: function () { return this.colors.getValue(); } }); BI.ColorPicker.EVENT_CHANGE = "ColorPicker.EVENT_CHANGE"; BI.shortcut("bi.color_picker", BI.ColorPicker);/** * 简单选色控件 * * Created by GUY on 2015/11/16. * @class BI.ColorPickerEditor * @extends BI.Widget */ BI.ColorPickerEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ColorPickerEditor.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-color-picker-editor", width: 200, height: 20 }) }, _init: function () { BI.ColorPickerEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.colorShow = BI.createWidget({ type: "bi.layout", cls: "color-picker-editor-display bi-card", height: 20 }); var RGB = BI.createWidgets(BI.createItems([{text: "R"}, {text: "G"}, {text: "B"}], { type: "bi.label", cls: "color-picker-editor-label", width: 10, height: 20 })); var checker = function (v) { return BI.isNumeric(v) && (v | 0) >= 0 && (v | 0) <= 255; }; var Ws = BI.createWidgets([{}, {}, {}], { type: "bi.small_text_editor", cls: "color-picker-editor-input", validationChecker: checker, errorText: BI.i18nText("BI-Color_Picker_Error_Text"), allowBlank: true, value: 255, width: 32, height: 20 }); BI.each(Ws, function (i, w) { w.on(BI.TextEditor.EVENT_CHANGE, function () { if (self.R.isValid() && self.G.isValid() && self.B.isValid()) { self.colorShow.element.css("background-color", self.getValue()); self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE); } }); }); this.R = Ws[0]; this.G = Ws[1]; this.B = Ws[2]; this.none = BI.createWidget({ type: "bi.checkbox", title: BI.i18nText("BI-Basic_Auto") }); this.none.on(BI.Checkbox.EVENT_CHANGE, function () { if (this.isSelected()) { self.lastColor = self.getValue(); self.setValue(""); } else { self.setValue(self.lastColor || "#000000"); } if (self.R.isValid() && self.G.isValid() && self.B.isValid()) { self.colorShow.element.css("background-color", self.getValue()); self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE); } }); this.transparent = BI.createWidget({ type: "bi.checkbox", title: BI.i18nText("BI-Transparent_Color") }); this.transparent.on(BI.Checkbox.EVENT_CHANGE, function () { if (this.isSelected()) { self.lastColor = self.getValue(); self.setValue("transparent"); } else { self.setValue(self.lastColor || "#000000"); } if (self.R.isValid() && self.G.isValid() && self.B.isValid()) { self.colorShow.element.css("background-color", self.getValue()); self.fireEvent(BI.ColorPickerEditor.EVENT_CHANGE); } }); BI.createWidget({ type: "bi.htape", element: this, items: [{ el: this.colorShow, width: 'fill' }, { el: RGB[0], lgap: 10, width: 16 }, { el: this.R, width: 32 }, { el: RGB[1], lgap: 10, width: 16 }, { el: this.G, width: 32 }, { el: RGB[2], lgap: 10, width: 16 }, { el: this.B, width: 32 }, { el: { type: "bi.center_adapt", items: [this.none] }, width: 18 }, { el: { type: "bi.center_adapt", items: [this.transparent] }, width: 18 }] }) }, setValue: function (color) { if (color === "transparent") { this.transparent.setSelected(true); this.none.setSelected(false); this.R.setValue(""); this.G.setValue(""); this.B.setValue(""); return; } if (!color) { color = ""; this.none.setSelected(true); } else { this.none.setSelected(false); } this.transparent.setSelected(false); this.colorShow.element.css("background-color", color); var json = BI.DOM.rgb2json(BI.DOM.hex2rgb(color)); this.R.setValue(BI.isNull(json.r) ? "" : json.r); this.G.setValue(BI.isNull(json.g) ? "" : json.g); this.B.setValue(BI.isNull(json.b) ? "" : json.b); }, getValue: function () { if (this.transparent.isSelected()) { return "transparent"; } return BI.DOM.rgb2hex(BI.DOM.json2rgb({ r: this.R.getValue(), g: this.G.getValue(), b: this.B.getValue() })) } }); BI.ColorPickerEditor.EVENT_CHANGE = "ColorPickerEditor.EVENT_CHANGE"; BI.shortcut("bi.color_picker_editor", BI.ColorPickerEditor);/** * 选色控件 * * Created by GUY on 2015/11/16. * @class BI.Farbtastic * @extends BI.Widget */ BI.Farbtastic = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Farbtastic.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-farbtastic", width: 195, height: 195 }) }, _init: function () { BI.Farbtastic.superclass._init.apply(this, arguments); }, mounted: function () { var self = this; this.farbtastic = $.farbtastic(this.element, function (v) { self.fireEvent(BI.Farbtastic.EVENT_CHANGE, self.getValue(), self); }); }, setValue: function (color) { this.farbtastic.setColor(color); }, getValue: function () { return this.farbtastic.color; } }); BI.Farbtastic.EVENT_CHANGE = "Farbtastic.EVENT_CHANGE"; BI.shortcut("bi.farbtastic", BI.Farbtastic);/** * Farbtastic Color Picker 1.2 * © 2008 Steven Wittens * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ jQuery.fn.farbtastic = function (callback) { $.farbtastic(this, callback); return this; }; jQuery.farbtastic = function (container, callback) { var container = $(container).get(0); return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback)); } jQuery._farbtastic = function (container, callback) { // Store farbtastic object var fb = this; // Insert markup $(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>'); var e = $('.farbtastic', container); fb.wheel = $('.wheel', container).get(0); // Dimensions fb.radius = 84; fb.square = 100; fb.width = 194; // Fix background PNGs in IE6 if (navigator.appVersion.match(/MSIE [0-6]\./)) { $('*', e).each(function () { if (this.currentStyle.backgroundImage != 'none') { var image = this.currentStyle.backgroundImage; image = this.currentStyle.backgroundImage.substring(5, image.length - 2); $(this).css({ 'backgroundImage': 'none', 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')" }); } }); } /** * Link to the given element(s) or callback. */ fb.linkTo = function (callback) { // Unbind previous nodes if (typeof fb.callback == 'object') { $(fb.callback).unbind('keyup', fb.updateValue); } // Reset color fb.color = null; // Bind callback or elements if (typeof callback == 'function') { fb.callback = callback; } else if (typeof callback == 'object' || typeof callback == 'string') { fb.callback = $(callback); fb.callback.bind('keyup', fb.updateValue); if (fb.callback.get(0).value) { fb.setColor(fb.callback.get(0).value); } } return this; } fb.updateValue = function (event) { if (this.value && this.value != fb.color) { fb.setColor(this.value); } } /** * Change color with HTML syntax #123456 */ fb.setColor = function (color) { var unpack = fb.unpack(color); if (fb.color != color && unpack) { fb.color = color; fb.rgb = unpack; fb.hsl = fb.RGBToHSL(fb.rgb); fb.updateDisplay(); } return this; } /** * Change color with HSL triplet [0..1, 0..1, 0..1] */ fb.setHSL = function (hsl) { fb.hsl = hsl; fb.rgb = fb.HSLToRGB(hsl); fb.color = fb.pack(fb.rgb); fb.updateDisplay(); return this; } ///////////////////////////////////////////////////// /** * Retrieve the coordinates of the given event relative to the center * of the widget. */ fb.widgetCoords = function (event) { var x, y; var el = event.target || event.srcElement; var reference = fb.wheel; if (typeof event.offsetX != 'undefined') { // Use offset coordinates and find common offsetParent var pos = { x: event.offsetX, y: event.offsetY }; // Send the coordinates upwards through the offsetParent chain. var e = el; while (e) { e.mouseX = pos.x; e.mouseY = pos.y; pos.x += e.offsetLeft; pos.y += e.offsetTop; e = e.offsetParent; } // Look for the coordinates starting from the wheel widget. var e = reference; var offset = { x: 0, y: 0 } while (e) { if (typeof e.mouseX != 'undefined') { x = e.mouseX - offset.x; y = e.mouseY - offset.y; break; } offset.x += e.offsetLeft; offset.y += e.offsetTop; e = e.offsetParent; } // Reset stored coordinates e = el; while (e) { e.mouseX = undefined; e.mouseY = undefined; e = e.offsetParent; } } else { // Use absolute coordinates var pos = fb.absolutePosition(reference); x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x; y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y; } // Subtract distance to middle return { x: x - fb.width / 2, y: y - fb.width / 2 }; } /** * Mousedown handler */ fb.mousedown = function (event) { // Capture mouse if (!document.dragging) { $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup); document.dragging = true; } // Check which area is being dragged var pos = fb.widgetCoords(event); fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square; // Process fb.mousemove(event); return false; } /** * Mousemove handler */ fb.mousemove = function (event) { // Get coordinates relative to color picker center var pos = fb.widgetCoords(event); // Set new HSL parameters if (fb.circleDrag) { var hue = Math.atan2(pos.x, -pos.y) / 6.28; if (hue < 0) hue += 1; fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]); } else { var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5)); var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5)); fb.setHSL([fb.hsl[0], sat, lum]); } return false; } /** * Mouseup handler */ fb.mouseup = function () { // Uncapture mouse $(document).unbind('mousemove', fb.mousemove); $(document).unbind('mouseup', fb.mouseup); document.dragging = false; } /** * Update the markers and styles */ fb.updateDisplay = function () { // Markers var angle = fb.hsl[0] * 6.28; $('.h-marker', e).css({ left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px', top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px' }); $('.sl-marker', e).css({ left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px', top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px' }); // Saturation/Luminance gradient $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5]))); // Linked elements or callback if (typeof fb.callback == 'object') { // Set background/foreground color $(fb.callback).css({ backgroundColor: fb.color, color: fb.hsl[2] > 0.5 ? '#000' : '#fff' }); // Change linked value $(fb.callback).each(function() { if (this.value && this.value != fb.color) { this.value = fb.color; } }); } else if (typeof fb.callback == 'function') { fb.callback.call(fb, fb.color); } } /** * Get absolute position of element */ fb.absolutePosition = function (el) { var r = { x: el.offsetLeft, y: el.offsetTop }; // Resolve relative to offsetParent if (el.offsetParent) { var tmp = fb.absolutePosition(el.offsetParent); r.x += tmp.x; r.y += tmp.y; } return r; }; /* Various color utility functions */ fb.pack = function (rgb) { var r = Math.round(rgb[0] * 255); var g = Math.round(rgb[1] * 255); var b = Math.round(rgb[2] * 255); return '#' + (r < 16 ? '0' : '') + r.toString(16) + (g < 16 ? '0' : '') + g.toString(16) + (b < 16 ? '0' : '') + b.toString(16); } fb.unpack = function (color) { if (color.length == 7) { return [parseInt('0x' + color.substring(1, 3)) / 255, parseInt('0x' + color.substring(3, 5)) / 255, parseInt('0x' + color.substring(5, 7)) / 255]; } else if (color.length == 4) { return [parseInt('0x' + color.substring(1, 2)) / 15, parseInt('0x' + color.substring(2, 3)) / 15, parseInt('0x' + color.substring(3, 4)) / 15]; } } fb.HSLToRGB = function (hsl) { var m1, m2, r, g, b; var h = hsl[0], s = hsl[1], l = hsl[2]; m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s; m1 = l * 2 - m2; return [this.hueToRGB(m1, m2, h+0.33333), this.hueToRGB(m1, m2, h), this.hueToRGB(m1, m2, h-0.33333)]; } fb.hueToRGB = function (m1, m2, h) { h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; if (h * 2 < 1) return m2; if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6; return m1; } fb.RGBToHSL = function (rgb) { var min, max, delta, h, s, l; var r = rgb[0], g = rgb[1], b = rgb[2]; min = Math.min(r, Math.min(g, b)); max = Math.max(r, Math.max(g, b)); delta = max - min; l = (min + max) / 2; s = 0; if (l > 0 && l < 1) { s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l)); } h = 0; if (delta > 0) { if (max == r && max != g) h += (g - b) / delta; if (max == g && max != b) h += (2 + (b - r) / delta); if (max == b && max != r) h += (4 + (r - g) / delta); h /= 6; } return [h, s, l]; } // Install mousedown handler (the others are set on the document on-demand) $('*', e).mousedown(fb.mousedown); // Init color fb.setColor('#000000'); // Set linked elements/callback if (callback) { fb.linkTo(callback); } }/** * Created by GUY on 2017/2/8. * * @class BI.BubbleCombo * @extends BI.Widget */ BI.BubbleCombo = BI.inherit(BI.Widget, { _const: { TRIANGLE_LENGTH: 6 }, _defaultConfig: function () { return BI.extend(BI.BubbleCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-bubble-combo", trigger: "click", toggle: true, direction: "bottom", //top||bottom||left||right||top,left||top,right||bottom,left||bottom,right isDefaultInit: false, destroyWhenHide: false, isNeedAdjustHeight: true,//是否需要高度调整 isNeedAdjustWidth: true, stopPropagation: false, adjustLength: 0,//调整的距离 // adjustXOffset: 0, // adjustYOffset: 10, hideChecker: BI.emptyFn, offsetStyle: "left", //left,right,center el: {}, popup: {}, }) }, _init: function () { BI.BubbleCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.combo = BI.createWidget({ type: "bi.combo", element: this, trigger: o.trigger, toggle: o.toggle, direction: o.direction, isDefaultInit: o.isDefaultInit, destroyWhenHide: o.destroyWhenHide, isNeedAdjustHeight: o.isNeedAdjustHeight, isNeedAdjustWidth: o.isNeedAdjustWidth, adjustLength: this._getAdjustLength(), stopPropagation: o.stopPropagation, adjustXOffset: 0, adjustYOffset: 0, hideChecker: o.hideChecker, offsetStyle: o.offsetStyle, el: o.el, popup: BI.extend({ type: "bi.bubble_popup_view" }, o.popup), }); this.combo.on(BI.Combo.EVENT_TRIGGER_CHANGE, function () { self.fireEvent(BI.BubbleCombo.EVENT_TRIGGER_CHANGE, arguments); }); this.combo.on(BI.Combo.EVENT_CHANGE, function () { self.fireEvent(BI.BubbleCombo.EVENT_CHANGE, arguments); }); this.combo.on(BI.Combo.EVENT_EXPAND, function () { self.fireEvent(BI.BubbleCombo.EVENT_EXPAND, arguments); }); this.combo.on(BI.Combo.EVENT_COLLAPSE, function () { self.fireEvent(BI.BubbleCombo.EVENT_COLLAPSE, arguments); }); this.combo.on(BI.Combo.EVENT_AFTER_INIT, function () { self.fireEvent(BI.BubbleCombo.EVENT_AFTER_INIT, arguments); }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.BubbleCombo.EVENT_BEFORE_POPUPVIEW, arguments); }); this.combo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () { self._showTriangle(); self.fireEvent(BI.BubbleCombo.EVENT_AFTER_POPUPVIEW, arguments); }); this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { self._hideTriangle(); self.fireEvent(BI.BubbleCombo.EVENT_BEFORE_HIDEVIEW, arguments); }); this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () { self.fireEvent(BI.BubbleCombo.EVENT_AFTER_HIDEVIEW, arguments); }); }, _getAdjustLength: function () { return this._const.TRIANGLE_LENGTH + this.options.adjustLength; }, _createTriangle: function (direction) { var pos = {}, op = {}; var adjustLength = this.options.adjustLength; var offset = this.element.offset(); var left = offset.left, right = offset.left + this.element.outerWidth(); var top = offset.top, bottom = offset.top + this.element.outerHeight(); switch (direction) { case "left": pos = { top: top, height: this.element.outerHeight(), left: left - adjustLength - this._const.TRIANGLE_LENGTH }; op = {width: this._const.TRIANGLE_LENGTH}; break; case "right": pos = { top: top, height: this.element.outerHeight(), left: right + adjustLength }; op = {width: this._const.TRIANGLE_LENGTH}; break; case "top": pos = { left: left, width: this.element.outerWidth(), top: top - adjustLength - this._const.TRIANGLE_LENGTH }; op = {height: this._const.TRIANGLE_LENGTH}; break; case "bottom": pos = { left: left, width: this.element.outerWidth(), top: bottom + adjustLength }; op = {height: this._const.TRIANGLE_LENGTH}; break; default: break; } this.triangle && this.triangle.destroy(); this.triangle = BI.createWidget(op, { type: "bi.center_adapt", cls: "button-combo-triangle-wrapper", items: [{ type: "bi.layout", cls: "bubble-combo-triangle-" + direction + " bi-high-light-border" }] }); pos.el = this.triangle; BI.createWidget({ type: "bi.absolute", element: this, items: [pos] }) }, _createLeftTriangle: function () { this._createTriangle("left"); }, _createRightTriangle: function () { this._createTriangle("right"); }, _createTopTriangle: function () { this._createTriangle("top"); }, _createBottomTriangle: function () { this._createTriangle("bottom"); }, _showTriangle: function () { var pos = this.combo.getPopupPosition(); switch (pos.dir) { case "left,top": case "left,bottom": this._createLeftTriangle(); this.combo.getView().showLine("right"); break; case "right,top": case "right,bottom": this._createRightTriangle(); this.combo.getView().showLine("left"); break; case "top,left": case "top,right": this._createTopTriangle(); this.combo.getView().showLine("bottom"); break; case "bottom,left": case "bottom,right": this._createBottomTriangle(); this.combo.getView().showLine("top"); break; } }, _hideTriangle: function () { this.triangle && this.triangle.destroy(); this.triangle = null; this.combo.getView() && this.combo.getView().hideLine(); }, hideView: function () { this._hideTriangle(); this.combo && this.combo.hideView(); }, showView: function () { this.combo && this.combo.showView(); }, isViewVisible: function () { return this.combo.isViewVisible(); } }); BI.BubbleCombo.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE"; BI.BubbleCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.BubbleCombo.EVENT_EXPAND = "EVENT_EXPAND"; BI.BubbleCombo.EVENT_COLLAPSE = "EVENT_COLLAPSE"; BI.BubbleCombo.EVENT_AFTER_INIT = "EVENT_AFTER_INIT"; BI.BubbleCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.BubbleCombo.EVENT_AFTER_POPUPVIEW = "EVENT_AFTER_POPUPVIEW"; BI.BubbleCombo.EVENT_BEFORE_HIDEVIEW = "EVENT_BEFORE_HIDEVIEW"; BI.BubbleCombo.EVENT_AFTER_HIDEVIEW = "EVENT_AFTER_HIDEVIEW"; BI.shortcut("bi.bubble_combo", BI.BubbleCombo);/** * Created by GUY on 2017/2/8. * * @class BI.BubblePopupView * @extends BI.PopupView */ BI.BubblePopupView = BI.inherit(BI.PopupView, { _defaultConfig: function () { var config = BI.BubblePopupView.superclass._defaultConfig.apply(this, arguments); return BI.extend(config, { baseCls: config.baseCls + " bi-bubble-popup-view" }) }, _init: function () { BI.BubblePopupView.superclass._init.apply(this, arguments); }, showLine: function (direction) { var pos = {}, op = {}; switch (direction) { case "left": pos = { top: 0, bottom: 0, left: -1 }; op = {width: 3}; break; case "right": pos = { top: 0, bottom: 0, right: -1 }; op = {width: 3}; break; case "top": pos = { left: 0, right: 0, top: -1 }; op = {height: 3}; break; case "bottom": pos = { left: 0, right: 0, bottom: -1 }; op = {height: 3}; break; default: break; } this.line = BI.createWidget(op, { type: "bi.layout", cls: "bubble-popup-line bi-high-light-background" }); pos.el = this.line; BI.createWidget({ type: "bi.absolute", element: this, items: [pos] }) }, hideLine: function () { this.line && this.line.destroy(); } }); BI.shortcut("bi.bubble_popup_view", BI.BubblePopupView); /** * Created by GUY on 2017/2/8. * * @class BI.BubblePopupBarView * @extends BI.BubblePopupView */ BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, { _defaultConfig: function () { return BI.extend(BI.BubblePopupBarView.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-bubble-bar-popup-view", buttons: [{value: BI.i18nText(BI.i18nText("BI-Basic_Sure"))}, {value: BI.i18nText("BI-Basic_Cancel"), level: "ignore"}] }) }, _init: function () { BI.BubblePopupBarView.superclass._init.apply(this, arguments); }, _createToolBar: function () { var o = this.options, self = this; var items = []; BI.each(o.buttons.reverse(), function (i, buttonOpt) { if(BI.isWidget(buttonOpt)){ items.push(buttonOpt); }else{ items.push(BI.extend({ type: 'bi.button', height: 30, handler: function (v) { self.fireEvent(BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON, v); } }, buttonOpt)) } }); return BI.createWidget({ type: 'bi.right_vertical_adapt', height: 40, hgap: 10, bgap: 10, items: items }); } }); BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON"; BI.shortcut("bi.bubble_bar_popup_view", BI.BubblePopupBarView);/** * Created by Young's on 2016/4/28. */ BI.EditorIconCheckCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.EditorIconCheckCombo.superclass._defaultConfig.apply(this, arguments), { baseClass: "bi-check-editor-combo", width: 100, height: 30, chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, allowBlank: true, watermark: "", errorText: "" }) }, _init: function () { BI.EditorIconCheckCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.editor_trigger", items: o.items, height: o.height, validationChecker: o.validationChecker, quitChecker: o.quitChecker, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.trigger.on(BI.EditorTrigger.EVENT_CHANGE, function () { self.popup.setValue(this.getValue()); self.fireEvent(BI.EditorIconCheckCombo.EVENT_CHANGE); }); this.popup = BI.createWidget({ type: "bi.text_value_check_combo_popup", chooseType: o.chooseType, items: o.items }); this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.editorIconCheckCombo.hideView(); self.fireEvent(BI.EditorIconCheckCombo.EVENT_CHANGE); }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editorIconCheckCombo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup, maxHeight: 300 } }); }, setValue: function (v) { this.editorIconCheckCombo.setValue(v); }, getValue: function () { return this.trigger.getValue(); }, populate: function (items) { this.options.items = items; this.editorIconCheckCombo.populate(items); } }); BI.EditorIconCheckCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.editor_icon_check_combo", BI.EditorIconCheckCombo);/** * Created by GUY on 2016/4/25. * * @class BI.FormulaCombo * @extend BI.Widget */ BI.FormulaCombo = BI.inherit(BI.Widget, { _constant: { POPUP_HEIGHT: 450, POPUP_WIDTH: 600, POPUP_V_GAP: 10, POPUP_H_GAP: 10, ADJUST_LENGTH: 2, HEIGHT_MAX: 10000, MAX_HEIGHT: 500, MAX_WIDTH: 600, COMBO_TRIGGER_WIDTH: 300 }, _defaultConfig: function () { return BI.extend(BI.FormulaCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-formula-combo", height: 30, items: [] }) }, _init: function () { BI.FormulaCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.formula_ids = []; this.input = BI.createWidget({ type: "bi.formula_combo_trigger", height: o.height, items: o.items }); this.formulaPopup = BI.createWidget({ type: "bi.formula_combo_popup", fieldItems: o.items }); this.formulaInputCombo = BI.createWidget({ type: "bi.combo", element: this, isNeedAdjustHeight: true, isNeedAdjustWidth: false, adjustLength: this._constant.ADJUST_LENGTH, el: this.input, popup: { el: { type: "bi.absolute", height: this._constant.HEIGHT_MAX, width: this._constant.POPUP_WIDTH, items: [{ el: this.formulaPopup, top: this._constant.POPUP_V_GAP, left: this._constant.POPUP_H_GAP, right: this._constant.POPUP_V_GAP, bottom: 0 }] }, stopPropagation: false, maxHeight: this._constant.MAX_HEIGHT, width: this._constant.MAX_WIDTH } }); this.formulaInputCombo.on(BI.Combo.EVENT_AFTER_POPUPVIEW, function () { self.formulaPopup.setValue(self.input.getValue()); }); this.formulaPopup.on(BI.FormulaComboPopup.EVENT_CHANGE, function () { self.setValue(self.formulaPopup.getValue()); self.formulaInputCombo.hideView(); self.fireEvent(BI.FormulaCombo.EVENT_CHANGE); }); this.formulaPopup.on(BI.FormulaComboPopup.EVENT_VALUE_CANCEL, function () { self.formulaInputCombo.hideView(); }); }, setValue: function (v) { if (this.formulaInputCombo.isViewVisible()) { this.formulaInputCombo.hideView(); } this.input.setValue(v); this.input.setText(BI.Func.getFormulaStringFromFormulaValue(v)); this.formulaPopup.setValue(this.input.getValue()); }, getFormulaTargetIds: function() { return this.formulaPopup.getFormulaTargetIds(); }, getValue: function () { return this.input.getValue(); } }); BI.FormulaCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.formula_combo", BI.FormulaCombo);/** * Created by GUY on 2016/4/25. * * @class BI.FormulaComboPopup * @extend BI.Widget */ BI.FormulaComboPopup = BI.inherit(BI.Widget, { _constant: { BUTTON_HEIGHT: 30, SOUTH_HEIGHT: 60, SOUTH_H_GAP: 10 }, _defaultConfig: function () { return BI.extend(BI.FormulaComboPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-formula-pane-popup" }) }, _init: function () { BI.FormulaComboPopup.superclass._init.apply(this, arguments); this.populate(); }, populate: function () { var self = this, fieldItems = this.options.fieldItems; this.formula = BI.createWidget({ type: "bi.formula_insert" }); this.formula.populate(fieldItems); var confirmButton = BI.createWidget({ type: "bi.button", level: "common", height: this._constant.BUTTON_HEIGHT, text: BI.i18nText("BI-Basic_OK") }); var cancelButton = BI.createWidget({ type: "bi.button", level: "ignore", height: this._constant.BUTTON_HEIGHT, text: BI.i18nText("BI-Basic_Cancel") }); this.formula.on(BI.FormulaInsert.EVENT_CHANGE, function () { confirmButton.setEnable(self.formula.checkValidation()); }); confirmButton.on(BI.Button.EVENT_CHANGE, function () { self.fireEvent(BI.FormulaComboPopup.EVENT_CHANGE); }); cancelButton.on(BI.Button.EVENT_CHANGE, function () { self.setValue(self.oldValue); self.fireEvent(BI.FormulaComboPopup.EVENT_VALUE_CANCEL); }); BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: this.formula, height: "fill" }, { el: { type: "bi.right_vertical_adapt", height: this._constant.SOUTH_HEIGHT, items: [cancelButton, confirmButton], hgap: this._constant.SOUTH_H_GAP }, height: this._constant.SOUTH_HEIGHT }] }) }, getFormulaTargetIds: function(){ return this.formula.getUsedFields(); }, getValue: function () { return this.formula.getValue(); }, setValue: function (v) { this.oldValue = v; this.formula.setValue(v); } }); BI.FormulaComboPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.FormulaComboPopup.EVENT_VALUE_CANCEL = "EVENT_VALUE_CANCEL"; BI.shortcut("bi.formula_combo_popup", BI.FormulaComboPopup);/** * Created by GUY on 2016/4/25. * * @class BI.FormulaComboTrigger * @extend BI.Widget */ BI.FormulaComboTrigger = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FormulaComboTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-formula-combo-trigger", height: 30, items: [] }) }, _init: function () { BI.FormulaComboTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options; this.label = BI.createWidget({ type: "bi.label", element: this, textAlign: "left", textHeight: this.options.height, lgap: 10 }); }, _getTextFromFormulaValue: function (formulaValue) { var self = this; var formulaString = ""; var regx = /\$[\{][^\}]*[\}]|\w*\w|\$\{[^\$\(\)\+\-\*\/)\$,]*\w\}|\$\{[^\$\(\)\+\-\*\/]*\w\}|\$\{[^\$\(\)\+\-\*\/]*[\u4e00-\u9fa5]\}|\w|(.)/g; var result = formulaValue.match(regx); BI.each(result, function (i, item) { var fieldRegx = /\$[\{][^\}]*[\}]/; var str = item.match(fieldRegx); if (BI.isNotEmptyArray(str)) { var id = str[0].substring(2, item.length - 1); var item = BI.find(BI.flatten(self.options.items), function (i, item) { return id === item.value; }); formulaString = formulaString + item.text; } else { formulaString = formulaString + item; } }); return formulaString; }, getValue: function () { return this.options.value; }, setValue: function (v) { this.options.value = v; this.label.setText(this._getTextFromFormulaValue(v)); } }); BI.shortcut("bi.formula_combo_trigger", BI.FormulaComboTrigger);/** * Created by GUY on 2016/2/2. * * @class BI.IconCombo * @extend BI.Widget */ BI.IconCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.IconCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-icon-combo", width: 24, height: 24, iconClass: "", el: {}, popup: {}, minWidth: 100, maxWidth: 'auto', maxHeight: 300, direction: "bottom", adjustLength: 3,//调整的距离 adjustXOffset: 0, adjustYOffset: 0, offsetStyle: "left", chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE }) }, _init: function () { BI.IconCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(o.el, { type: "bi.icon_combo_trigger", iconClass: o.iconClass, title: o.title, items: o.items, width: o.width, height: o.height, iconWidth: o.iconWidth, iconHeight: o.iconHeight }); this.popup = BI.createWidget(o.popup, { type: "bi.icon_combo_popup", chooseType: o.chooseType, items: o.items }); this.popup.on(BI.IconComboPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.iconCombo.hideView(); self.fireEvent(BI.IconCombo.EVENT_CHANGE); }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.iconCombo = BI.createWidget({ type: "bi.combo", element: this, direction: o.direction, adjustLength: o.adjustLength, adjustXOffset: o.adjustXOffset, adjustYOffset: o.adjustYOffset, offsetStyle: o.offsetStyle, el: this.trigger, popup: { el: this.popup, maxWidth: o.maxWidth, maxHeight: o.maxHeight, minWidth: o.minWidth } }); }, showView: function () { this.iconCombo.showView(); }, hideView: function () { this.iconCombo.hideView(); }, setValue: function (v) { this.iconCombo.setValue(v); }, getValue: function () { return this.iconCombo.getValue(); }, populate: function (items) { this.options.items = items; this.iconCombo.populate(items); } }); BI.IconCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_combo", BI.IconCombo);/** * Created by GUY on 2016/2/2. * * @class BI.IconComboPopup * @extend BI.Pane */ BI.IconComboPopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.IconComboPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi.icon-combo-popup", chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE }); }, _init: function () { BI.IconComboPopup.superclass._init.apply(this, arguments); var o = this.options, self = this; this.popup = BI.createWidget({ type: "bi.button_group", items: BI.createItems(o.items, { type: "bi.single_select_icon_text_item", height: 30 }), chooseType: o.chooseType, layouts: [{ type: "bi.vertical" }] }); this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.IconComboPopup.EVENT_CHANGE, val, obj); } }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.popup] }); }, populate: function (items) { BI.IconComboPopup.superclass.populate.apply(this, arguments); items = BI.createItems(items, { type: "bi.single_select_icon_text_item", height: 30 }); this.popup.populate(items); }, getValue: function () { return this.popup.getValue(); }, setValue: function (v) { this.popup.setValue(v); } }); BI.IconComboPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_combo_popup", BI.IconComboPopup);/** * Created by GUY on 2016/2/2. * * @class BI.IconComboTrigger * @extend BI.Widget */ BI.IconComboTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { return BI.extend(BI.IconComboTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-icon-combo-trigger", el: {}, items: [], iconClass: "", width: 25, height: 25, isShowDown: true }); }, _init: function () { BI.IconComboTrigger.superclass._init.apply(this, arguments); var o = this.options, self = this; this.button = BI.createWidget(o.el, { type: "bi.icon_change_button", cls: "icon-combo-trigger-icon " + o.iconClass, disableSelected: true, width: o.width, height: o.height, iconWidth: o.iconWidth, iconHeight: o.iconHeight }); this.down = BI.createWidget({ type: "bi.icon_button", disableSelected: true, cls: "icon-combo-down-icon trigger-triangle-font", width: 12, height: 8 }); this.down.setVisible(o.isShowDown); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.button, left: 0, right: 0, top: 0, bottom: 0 }, { el: this.down, right: 0, bottom: 0 }] }); if (BI.isKey(o.value)) { this.setValue(o.value); } }, populate: function (items) { var o = this.options; this.options.items = items || []; this.button.setIcon(o.iconClass); this.button.setSelected(false); this.down.setSelected(false); }, setValue: function (v) { BI.IconComboTrigger.superclass.setValue.apply(this, arguments); var o = this.options; var iconClass = ""; v = BI.isArray(v) ? v[0] : v; if (BI.any(this.options.items, function (i, item) { if (v === item.value) { iconClass = item.iconClass; return true; } })) { this.button.setIcon(iconClass); this.button.setSelected(true); this.down.setSelected(true); } else { this.button.setIcon(o.iconClass); this.button.setSelected(false); this.down.setSelected(false); } } }); BI.IconComboTrigger.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_combo_trigger", BI.IconComboTrigger);/** * 单选combo * * @class BI.StaticCombo * @extend BI.Widget */ BI.StaticCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.StaticCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-static-combo", height: 30, text: "", el: {}, items: [], chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE }) }, _init: function () { BI.StaticCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(o.el, { type: "bi.text_icon_item", cls: "bi-select-text-trigger bi-border pull-down-font", text: o.text, readonly: true, textLgap: 5, height: o.height - 2 }); this.popup = BI.createWidget({ type: "bi.text_value_combo_popup", textAlign: o.textAlign, chooseType: o.chooseType, items: o.items }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () { self.combo.hideView(); self.fireEvent(BI.StaticCombo.EVENT_CHANGE, arguments); }); this.combo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup } }); }, populate: function (items) { this.combo.populate(items); }, setValue: function (v) { this.combo.setValue(v); }, getValue: function () { return this.combo.getValue(); } }); BI.StaticCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.static_combo", BI.StaticCombo);/** * @class BI.TextValueCheckCombo * @extend BI.Widget * combo : text + icon, popup : check + text */ BI.TextValueCheckCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.TextValueCheckCombo.superclass._defaultConfig.apply(this, arguments), { baseClass: "bi-text-value-check-combo", width: 100, height: 30, chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, text: "" }) }, _init: function () { BI.TextValueCheckCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.select_text_trigger", items: o.items, height: o.height, text: o.text }); this.popup = BI.createWidget({ type: "bi.text_value_check_combo_popup", chooseType: o.chooseType, items: o.items }); this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.textIconCheckCombo.hideView(); self.fireEvent(BI.TextValueCheckCombo.EVENT_CHANGE); }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.textIconCheckCombo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup, maxHeight: 300 } }); }, setTitle: function (title) { this.trigger.setTitle(title); }, setValue: function (v) { this.textIconCheckCombo.setValue(v); }, setWarningTitle: function (title) { this.trigger.setWarningTitle(title); }, getValue: function () { return this.textIconCheckCombo.getValue(); }, populate: function (items) { this.options.items = items; this.textIconCheckCombo.populate(items); } }); BI.TextValueCheckCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_value_check_combo", BI.TextValueCheckCombo);/** * @class BI.SmallTextValueCheckCombo * @extend BI.Widget * combo : text + icon, popup : check + text */ BI.SmallTextValueCheckCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SmallTextValueCheckCombo.superclass._defaultConfig.apply(this, arguments), { width: 100, height: 24, chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, text: "" }) }, _init: function () { BI.SmallTextValueCheckCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.small_select_text_trigger", items: o.items, height: o.height, text: o.text }); this.popup = BI.createWidget({ type: "bi.text_value_check_combo_popup", chooseType: o.chooseType, items: o.items }); this.popup.on(BI.TextValueCheckComboPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.SmallTextIconCheckCombo.hideView(); self.fireEvent(BI.SmallTextValueCheckCombo.EVENT_CHANGE); }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.SmallTextIconCheckCombo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup, maxHeight: 300 } }); }, setValue: function (v) { this.SmallTextIconCheckCombo.setValue(v); }, getValue: function () { return this.SmallTextIconCheckCombo.getValue(); }, populate: function (items) { this.options.items = items; this.SmallTextIconCheckCombo.populate(items); } }); BI.SmallTextValueCheckCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.small_text_value_check_combo", BI.SmallTextValueCheckCombo);BI.TextValueCheckComboPopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.TextValueCheckComboPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-text-icon-popup", chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE }); }, _init: function () { BI.TextValueCheckComboPopup.superclass._init.apply(this, arguments); var o = this.options, self = this; this.popup = BI.createWidget({ type: "bi.button_group", items: this._formatItems(o.items), chooseType: o.chooseType, layouts: [{ type: "bi.vertical" }] }); this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.TextValueCheckComboPopup.EVENT_CHANGE, val, obj); } }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.popup] }); }, _formatItems: function (items) { return BI.map(items, function (i, item) { return BI.extend({ type: "bi.icon_text_item", cls: "item-check-font bi-list-item", height: 30 }, item); }); }, populate: function (items) { BI.TextValueCheckComboPopup.superclass.populate.apply(this, arguments); this.popup.populate(this._formatItems(items)); }, getValue: function () { return this.popup.getValue(); }, setValue: function (v) { this.popup.setValue(v); } }); BI.TextValueCheckComboPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_value_check_combo_popup", BI.TextValueCheckComboPopup);/** * @class BI.TextValueCombo * @extend BI.Widget * combo : text + icon, popup : text * 参见场景dashboard布局方式选择 */ BI.TextValueCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.TextValueCombo.superclass._defaultConfig.apply(this, arguments), { baseClass: "bi-text-value-combo", height: 30, chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, text: "", el: {} }) }, _init: function () { BI.TextValueCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(o.el, { type: "bi.select_text_trigger", items: o.items, height: o.height, text: o.text }); this.popup = BI.createWidget({ type: "bi.text_value_combo_popup", chooseType: o.chooseType, items: o.items }); this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.textIconCombo.hideView(); self.fireEvent(BI.TextValueCombo.EVENT_CHANGE, arguments); }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.textIconCombo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup, maxHeight: 300 } }); }, setValue: function (v) { this.textIconCombo.setValue(v); }, getValue: function () { return this.textIconCombo.getValue(); }, populate: function (items) { this.options.items = items; this.textIconCombo.populate(items); } }); BI.TextValueCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_value_combo", BI.TextValueCombo);/** * @class BI.SmallTextValueCombo * @extend BI.Widget * combo : text + icon, popup : text * 参见场景dashboard布局方式选择 */ BI.SmallTextValueCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SmallTextValueCombo.superclass._defaultConfig.apply(this, arguments), { width: 100, height: 24, chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, el: {}, text: "" }) }, _init: function () { BI.SmallTextValueCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(o.el, { type: "bi.small_select_text_trigger", items: o.items, height: o.height, text: o.text }); this.popup = BI.createWidget({ type: "bi.text_value_combo_popup", chooseType: o.chooseType, items: o.items }); this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.SmallTextValueCombo.hideView(); self.fireEvent(BI.SmallTextValueCombo.EVENT_CHANGE); }); this.popup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.SmallTextValueCombo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup, maxHeight: 300 } }); }, setValue: function (v) { this.SmallTextValueCombo.setValue(v); }, getValue: function () { return this.SmallTextValueCombo.getValue(); }, populate: function (items) { this.options.items = items; this.SmallTextValueCombo.populate(items); } }); BI.SmallTextValueCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.small_text_value_combo", BI.SmallTextValueCombo);BI.TextValueComboPopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.TextValueComboPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-text-icon-popup", chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE }); }, _init: function () { BI.TextValueComboPopup.superclass._init.apply(this, arguments); var o = this.options, self = this; this.popup = BI.createWidget({ type: "bi.button_group", items: BI.createItems(o.items, { type: "bi.single_select_item", textAlign: o.textAlign, height: 30 }), chooseType: o.chooseType, layouts: [{ type: "bi.vertical" }] }); this.popup.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.TextValueComboPopup.EVENT_CHANGE, val, obj); } }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.popup] }); }, populate: function (items) { BI.TextValueComboPopup.superclass.populate.apply(this, arguments); items = BI.createItems(items, { type: "bi.single_select_item", height: 30 }); this.popup.populate(items); }, getValue: function () { return this.popup.getValue(); }, setValue: function (v) { this.popup.setValue(v); } }); BI.TextValueComboPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_value_combo_popup", BI.TextValueComboPopup);/** * @class BI.TextValueDownListCombo * @extend BI.Widget */ BI.TextValueDownListCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.TextValueDownListCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-text-value-down-list-combo", height: 30, text: "" }) }, _init: function () { BI.TextValueDownListCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this._createValueMap(); this.trigger = BI.createWidget({ type: "bi.down_list_select_text_trigger", height: o.height, items: o.items }); this.combo = BI.createWidget({ type: "bi.down_list_combo", element: this, chooseType: BI.Selection.Single, adjustLength: 2, height: o.height, el: this.trigger, items: BI.deepClone(o.items) }); this.combo.on(BI.DownListCombo.EVENT_CHANGE, function () { self.setValue(self.combo.getValue()[0].value); self.fireEvent(BI.TextValueDownListCombo.EVENT_CHANGE); }); this.combo.on(BI.DownListCombo.EVENT_SON_VALUE_CHANGE, function () { self.setValue(self.combo.getValue()[0].childValue); self.fireEvent(BI.TextValueDownListCombo.EVENT_CHANGE); }); }, _createValueMap: function () { var self = this; this.valueMap = {}; BI.each(BI.flatten(this.options.items), function (idx, item) { if (BI.has(item, "el")) { BI.each(item.children, function (id, it) { self.valueMap[it.value] = {value: item.el.value, childValue: it.value} }); } else { self.valueMap[item.value] = {value: item.value}; } }); }, setValue: function (v) { v = this.valueMap[v]; this.combo.setValue([v]); this.trigger.setValue(v.childValue || v.value); }, getValue: function () { var v = this.combo.getValue()[0]; return [v.childValue || v.value]; }, populate: function (items) { this.options.items = BI.flatten(items); this.combo.populate(items); this._createValueMap(); } }); BI.TextValueDownListCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_value_down_list_combo", BI.TextValueDownListCombo);/** * 选择字段trigger, downlist专用 * 显示形式为 父亲值(儿子值) * * @class BI.DownListSelectTextTrigger * @extends BI.Trigger */ BI.DownListSelectTextTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { return BI.extend(BI.DownListSelectTextTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-down-list-select-text-trigger", height: 24, text: "" }); }, _init: function () { BI.DownListSelectTextTrigger.superclass._init.apply(this, arguments); var o = this.options; this.trigger = BI.createWidget({ type: "bi.select_text_trigger", element: this, height: o.height, items: this._formatItemArray(o.items), text: o.text }); }, _formatItemArray: function(){ var sourceArray = BI.flatten(BI.deepClone(this.options.items)); var targetArray = []; BI.each(sourceArray, function(idx, item){ if(BI.has(item, "el")){ BI.each(item.children, function(id, it){ it.text = item.el.text + "(" + it.text + ")"; }); targetArray = BI.concat(targetArray, item.children); }else{ targetArray.push(item); } }); return targetArray; }, setValue: function (vals) { this.trigger.setValue(vals); }, populate: function (items) { this.trigger.populate(this._formatItemArray(items)); } }); BI.shortcut("bi.down_list_select_text_trigger", BI.DownListSelectTextTrigger);/** * 有清楚按钮的文本框 * Created by GUY on 2015/9/29. * @class BI.SmallTextEditor * @extends BI.SearchEditor */ BI.ClearEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.ClearEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-clear-editor", height: 30, errorText: "", watermark: "", validationChecker: BI.emptyFn, quitChecker: BI.emptyFn }); }, _init: function () { BI.ClearEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, watermark: o.watermark, allowBlank: true, errorText: o.errorText, validationChecker: o.validationChecker, quitChecker: o.quitChecker }); this.clear = BI.createWidget({ type: "bi.icon_button", stopEvent: true, cls: "search-close-h-font" }); this.clear.on(BI.IconButton.EVENT_CHANGE, function () { self.setValue(""); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT); self.fireEvent(BI.ClearEditor.EVENT_CLEAR); }); BI.createWidget({ element: this, type: "bi.htape", items: [ { el: this.editor }, { el: this.clear, width: 25 }] }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.ClearEditor.EVENT_FOCUS); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.ClearEditor.EVENT_BLUR); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.ClearEditor.EVENT_CLICK); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self._checkClear(); self.fireEvent(BI.ClearEditor.EVENT_CHANGE); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.ClearEditor.EVENT_KEY_DOWN, v); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.ClearEditor.EVENT_SPACE) }); this.editor.on(BI.Editor.EVENT_BACKSPACE, function () { self.fireEvent(BI.ClearEditor.EVENT_BACKSPACE) }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.ClearEditor.EVENT_VALID) }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self.fireEvent(BI.ClearEditor.EVENT_ERROR) }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.ClearEditor.EVENT_ENTER); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.ClearEditor.EVENT_RESTRICT) }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self._checkClear(); self.fireEvent(BI.ClearEditor.EVENT_EMPTY) }); this.editor.on(BI.Editor.EVENT_REMOVE, function () { self.fireEvent(BI.ClearEditor.EVENT_REMOVE) }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self.fireEvent(BI.ClearEditor.EVENT_CONFIRM) }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.ClearEditor.EVENT_START); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.ClearEditor.EVENT_PAUSE); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.ClearEditor.EVENT_STOP); }); this.clear.invisible(); }, _checkClear: function () { if (!this.getValue()) { this.clear.invisible(); } else { this.clear.visible(); } }, focus: function () { this.editor.focus(); }, blur: function () { this.editor.blur(); }, getValue: function () { if (this.isValid()) { var res = this.editor.getValue().match(/[\S]+/g); return BI.isNull(res) ? "" : res[res.length - 1]; } }, setValue: function (v) { this.editor.setValue(v); if (BI.isKey(v)) { this.clear.visible(); } }, isValid: function () { return this.editor.isValid(); } }); BI.ClearEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.ClearEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.ClearEditor.EVENT_BLUR = "EVENT_BLUR"; BI.ClearEditor.EVENT_CLICK = "EVENT_CLICK"; BI.ClearEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.ClearEditor.EVENT_SPACE = "EVENT_SPACE"; BI.ClearEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE"; BI.ClearEditor.EVENT_CLEAR = "EVENT_CLEAR"; BI.ClearEditor.EVENT_START = "EVENT_START"; BI.ClearEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.ClearEditor.EVENT_STOP = "EVENT_STOP"; BI.ClearEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.ClearEditor.EVENT_VALID = "EVENT_VALID"; BI.ClearEditor.EVENT_ERROR = "EVENT_ERROR"; BI.ClearEditor.EVENT_ENTER = "EVENT_ENTER"; BI.ClearEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.ClearEditor.EVENT_REMOVE = "EVENT_REMOVE"; BI.ClearEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.clear_editor", BI.ClearEditor);/** * Created by roy on 15/9/14. */ BI.SearchEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.SearchEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-search-editor bi-border", height: 30, errorText: "", watermark: BI.i18nText("BI-Basic_Search"), validationChecker: BI.emptyFn, quitChecker: BI.emptyFn }); }, _init: function () { this.options.height -= 2; BI.SearchEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, watermark: o.watermark, allowBlank: true, errorText: o.errorText, validationChecker: o.validationChecker, quitChecker: o.quitChecker }); this.clear = BI.createWidget({ type: "bi.icon_button", stopEvent: true, cls: "search-close-h-font" }); this.clear.on(BI.IconButton.EVENT_CHANGE, function () { self.setValue(""); self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT); self.fireEvent(BI.SearchEditor.EVENT_CLEAR); }); BI.createWidget({ element: this, type: "bi.htape", items: [ { el: { type: "bi.center_adapt", cls: "search-font", items: [{ el: { type: "bi.icon" } }] }, width: 25 }, { el: self.editor }, { el: this.clear, width: 25 } ] }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.SearchEditor.EVENT_FOCUS); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.SearchEditor.EVENT_BLUR); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.SearchEditor.EVENT_CLICK); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self._checkClear(); self.fireEvent(BI.SearchEditor.EVENT_CHANGE); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.SearchEditor.EVENT_KEY_DOWN, v); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.SearchEditor.EVENT_SPACE) }); this.editor.on(BI.Editor.EVENT_BACKSPACE, function () { self.fireEvent(BI.SearchEditor.EVENT_BACKSPACE) }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.SearchEditor.EVENT_VALID) }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self.fireEvent(BI.SearchEditor.EVENT_ERROR) }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.SearchEditor.EVENT_ENTER); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.SearchEditor.EVENT_RESTRICT) }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self._checkClear(); self.fireEvent(BI.SearchEditor.EVENT_EMPTY) }); this.editor.on(BI.Editor.EVENT_REMOVE, function () { self.fireEvent(BI.SearchEditor.EVENT_REMOVE) }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self.fireEvent(BI.SearchEditor.EVENT_CONFIRM) }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.SearchEditor.EVENT_START); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.SearchEditor.EVENT_PAUSE); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.SearchEditor.EVENT_STOP); }); this.clear.invisible(); }, _checkClear: function () { if (!this.getValue()) { this.clear.invisible(); } else { this.clear.visible(); } }, focus: function () { this.editor.focus(); }, blur: function () { this.editor.blur(); }, getValue: function () { if (this.isValid()) { var res = this.editor.getValue().match(/[\S]+/g); return BI.isNull(res) ? "" : res[res.length - 1]; } }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, setValue: function (v) { this.editor.setValue(v); if (BI.isKey(v)) { this.clear.visible(); } }, isEditing: function () { return this.editor.isEditing(); }, isValid: function () { return this.editor.isValid(); } }); BI.SearchEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.SearchEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.SearchEditor.EVENT_BLUR = "EVENT_BLUR"; BI.SearchEditor.EVENT_CLICK = "EVENT_CLICK"; BI.SearchEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.SearchEditor.EVENT_SPACE = "EVENT_SPACE"; BI.SearchEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE"; BI.SearchEditor.EVENT_CLEAR = "EVENT_CLEAR"; BI.SearchEditor.EVENT_START = "EVENT_START"; BI.SearchEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.SearchEditor.EVENT_STOP = "EVENT_STOP"; BI.SearchEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.SearchEditor.EVENT_VALID = "EVENT_VALID"; BI.SearchEditor.EVENT_ERROR = "EVENT_ERROR"; BI.SearchEditor.EVENT_ENTER = "EVENT_ENTER"; BI.SearchEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.SearchEditor.EVENT_REMOVE = "EVENT_REMOVE"; BI.SearchEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.search_editor", BI.SearchEditor);/** * 小号搜索框 * Created by GUY on 2015/9/29. * @class BI.SmallSearchEditor * @extends BI.SearchEditor */ BI.SmallSearchEditor = BI.inherit(BI.SearchEditor, { _defaultConfig: function () { var conf = BI.SmallSearchEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-small-search-editor", height: 24 }); }, _init: function () { BI.SmallSearchEditor.superclass._init.apply(this, arguments); } }); BI.shortcut("bi.small_search_editor", BI.SmallSearchEditor);/** * 带标记的文本框 * Created by GUY on 2016/1/25. * @class BI.ShelterEditor * @extends BI.Widget */ BI.ShelterEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.ShelterEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-shelter-editor", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: true, watermark: "", errorText: "", height: 30, textAlign: "left" }) }, _init: function () { BI.ShelterEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.text = BI.createWidget({ type: "bi.text_button", cls: "shelter-editor-text", title: o.title, warningTitle: o.warningTitle, tipType: o.tipType, textAlign: o.textAlign, height: o.height, hgap: 4 }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.text, left: 0, right: 0, top: 0, bottom: 0 }] }); this.text.on(BI.Controller.EVENT_CHANGE, function () { arguments[2] = self; self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.text.on(BI.TextButton.EVENT_CHANGE, function () { self.fireEvent(BI.ShelterEditor.EVENT_CLICK_LABEL); }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.ShelterEditor.EVENT_FOCUS, arguments); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.ShelterEditor.EVENT_BLUR, arguments); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.ShelterEditor.EVENT_CLICK, arguments); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self.fireEvent(BI.ShelterEditor.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.ShelterEditor.EVENT_KEY_DOWN, arguments); }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.ShelterEditor.EVENT_VALID, arguments); }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self._showHint(); self._checkText(); self.fireEvent(BI.ShelterEditor.EVENT_CONFIRM, arguments); }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.ShelterEditor.EVENT_START, arguments); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.ShelterEditor.EVENT_PAUSE, arguments); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.ShelterEditor.EVENT_STOP, arguments); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.ShelterEditor.EVENT_SPACE, arguments); }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self._checkText(); self.fireEvent(BI.ShelterEditor.EVENT_ERROR, arguments); }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.ShelterEditor.EVENT_ENTER, arguments); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.ShelterEditor.EVENT_RESTRICT, arguments); }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self.fireEvent(BI.ShelterEditor.EVENT_EMPTY, arguments); }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [this.editor] }); this._showHint(); self._checkText(); }, _checkText: function () { var o = this.options; if (this.editor.getValue() === "") { this.text.setValue(o.watermark || ""); this.text.element.addClass("bi-water-mark"); } else { this.text.setValue(this.editor.getValue()); this.text.element.removeClass("bi-water-mark"); } }, _showInput: function () { this.editor.visible(); this.text.invisible(); }, _showHint: function () { this.editor.invisible(); this.text.visible(); }, setTitle: function (title) { this.text.setTitle(title); }, setWarningTitle: function (title) { this.text.setWarningTitle(title); }, focus: function () { this._showInput(); this.editor.focus(); }, blur: function () { this.editor.blur(); this._showHint(); this._checkText(); }, doRedMark: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, isValid: function () { return this.editor.isValid(); }, setErrorText: function (text) { this.editor.setErrorText(text); }, getErrorText: function () { return this.editor.getErrorText(); }, isEditing: function () { return this.editor.isEditing(); }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, setTextStyle: function (style) { this.text.setStyle(style); }, setValue: function (k) { this.editor.setValue(k); this._checkText(); }, getValue: function () { return this.editor.getValue(); }, getState: function () { return this.text.getValue(); }, setState: function (v) { this._showHint(); this.text.setValue(v); } }); BI.ShelterEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.ShelterEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.ShelterEditor.EVENT_BLUR = "EVENT_BLUR"; BI.ShelterEditor.EVENT_CLICK = "EVENT_CLICK"; BI.ShelterEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.ShelterEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL"; BI.ShelterEditor.EVENT_START = "EVENT_START"; BI.ShelterEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.ShelterEditor.EVENT_STOP = "EVENT_STOP"; BI.ShelterEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.ShelterEditor.EVENT_VALID = "EVENT_VALID"; BI.ShelterEditor.EVENT_ERROR = "EVENT_ERROR"; BI.ShelterEditor.EVENT_ENTER = "EVENT_ENTER"; BI.ShelterEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.ShelterEditor.EVENT_SPACE = "EVENT_SPACE"; BI.ShelterEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.shelter_editor", BI.ShelterEditor);/** * Created by User on 2017/7/28. */ BI.SignInitialEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.SignInitialEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-sign-initial-editor", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: true, watermark: "", errorText: "", value: "", text: "", height: 30 }) }, _init: function () { BI.SignInitialEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.text = BI.createWidget({ type: "bi.text_button", cls: "sign-editor-text", title: o.title, warningTitle: o.warningTitle, tipType: o.tipType, textAlign: "left", height: o.height, hgap: 4, handler: function () { self._showInput(); self.editor.focus(); self.editor.selectAll(); } }); this.text.on(BI.TextButton.EVENT_CHANGE, function () { BI.nextTick(function () { self.fireEvent(BI.SignInitialEditor.EVENT_CLICK_LABEL) }); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.text, left: 0, right: 0, top: 0, bottom: 0 }] }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.SignInitialEditor.EVENT_FOCUS, arguments); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.SignInitialEditor.EVENT_BLUR, arguments); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.SignInitialEditor.EVENT_CLICK, arguments); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self.fireEvent(BI.SignInitialEditor.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.SignInitialEditor.EVENT_KEY_DOWN, arguments); }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.SignInitialEditor.EVENT_VALID, arguments); }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self._showHint(); self._checkText(); self.fireEvent(BI.SignInitialEditor.EVENT_CONFIRM, arguments); }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.SignInitialEditor.EVENT_START, arguments); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.SignInitialEditor.EVENT_PAUSE, arguments); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.SignInitialEditor.EVENT_STOP, arguments); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.SignInitialEditor.EVENT_SPACE, arguments); }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self._checkText(); self.fireEvent(BI.SignInitialEditor.EVENT_ERROR, arguments); }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.SignInitialEditor.EVENT_ENTER, arguments); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.SignInitialEditor.EVENT_RESTRICT, arguments); }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self.fireEvent(BI.SignInitialEditor.EVENT_EMPTY, arguments); }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [this.editor] }); this._showHint(); self._checkText(); }, _checkText: function () { var o = this.options; BI.nextTick(BI.bind(function () { if (this.editor.getValue() === "") { this.text.setValue(o.watermark || ""); this.text.element.addClass("bi-water-mark"); } else { var v = this.editor.getValue(); v = (BI.isEmpty(v) || v == o.text) ? o.text : v + "(" + o.text + ")"; this.text.setValue(v); this.text.element.removeClass("bi-water-mark"); } }, this)); }, _showInput: function () { this.editor.visible(); this.text.invisible(); }, _showHint: function () { this.editor.invisible(); this.text.visible(); }, setTitle: function (title) { this.text.setTitle(title); }, setWarningTitle: function (title) { this.text.setWarningTitle(title); }, focus: function () { this._showInput(); this.editor.focus(); }, blur: function () { this.editor.blur(); this._showHint(); this._checkText(); }, doRedMark: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, isValid: function () { return this.editor.isValid(); }, setErrorText: function (text) { this.editor.setErrorText(text); }, getErrorText: function () { return this.editor.getErrorText(); }, isEditing: function () { return this.editor.isEditing(); }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, setValue: function (v) { var o = this.options; this.editor.setValue(v.value); o.text = v.text || o.text; this._checkText(); }, getValue: function () { return { value: this.editor.getValue(), text: this.options.text } }, getState: function () { return this.text.getValue(); }, setState: function (v) { var o = this.options; this._showHint(); v = (BI.isEmpty(v) || v == o.text) ? o.text : v + "(" + o.text + ")"; this.text.setValue(v); } }); BI.SignInitialEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.SignInitialEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.SignInitialEditor.EVENT_BLUR = "EVENT_BLUR"; BI.SignInitialEditor.EVENT_CLICK = "EVENT_CLICK"; BI.SignInitialEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.SignInitialEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL"; BI.SignInitialEditor.EVENT_START = "EVENT_START"; BI.SignInitialEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.SignInitialEditor.EVENT_STOP = "EVENT_STOP"; BI.SignInitialEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.SignInitialEditor.EVENT_VALID = "EVENT_VALID"; BI.SignInitialEditor.EVENT_ERROR = "EVENT_ERROR"; BI.SignInitialEditor.EVENT_ENTER = "EVENT_ENTER"; BI.SignInitialEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.SignInitialEditor.EVENT_SPACE = "EVENT_SPACE"; BI.SignInitialEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.sign_initial_editor", BI.SignInitialEditor);/** * 带标记的文本框 * Created by GUY on 2015/8/28. * @class BI.SignEditor * @extends BI.Widget */ BI.SignEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.SignEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-sign-editor", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: true, watermark: "", errorText: "", height: 30 }) }, _init: function () { BI.SignEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.text = BI.createWidget({ type: "bi.text_button", cls: "sign-editor-text", title: o.title, warningTitle: o.warningTitle, tipType: o.tipType, textAlign: "left", height: o.height, hgap: 4, handler: function () { self._showInput(); self.editor.focus(); self.editor.selectAll(); } }); this.text.on(BI.TextButton.EVENT_CHANGE, function () { BI.nextTick(function () { self.fireEvent(BI.SignEditor.EVENT_CLICK_LABEL) }); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.text, left: 0, right: 0, top: 0, bottom: 0 }] }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.SignEditor.EVENT_FOCUS, arguments); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.SignEditor.EVENT_BLUR, arguments); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.SignEditor.EVENT_CLICK, arguments); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self.fireEvent(BI.SignEditor.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.SignEditor.EVENT_KEY_DOWN, arguments); }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.SignEditor.EVENT_VALID, arguments); }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self._showHint(); self._checkText(); self.fireEvent(BI.SignEditor.EVENT_CONFIRM, arguments); }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.SignEditor.EVENT_START, arguments); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.SignEditor.EVENT_PAUSE, arguments); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.SignEditor.EVENT_STOP, arguments); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.SignEditor.EVENT_SPACE, arguments); }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self._checkText(); self.fireEvent(BI.SignEditor.EVENT_ERROR, arguments); }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.SignEditor.EVENT_ENTER, arguments); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.SignEditor.EVENT_RESTRICT, arguments); }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self.fireEvent(BI.SignEditor.EVENT_EMPTY, arguments); }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [this.editor] }); this._showHint(); self._checkText(); }, _checkText: function () { var o = this.options; BI.nextTick(BI.bind(function () { if (this.editor.getValue() === "") { this.text.setValue(o.watermark || ""); this.text.element.addClass("bi-water-mark"); } else { this.text.setValue(this.editor.getValue()); this.text.element.removeClass("bi-water-mark"); } }, this)); }, _showInput: function () { this.editor.visible(); this.text.invisible(); }, _showHint: function () { this.editor.invisible(); this.text.visible(); }, setTitle: function (title) { this.text.setTitle(title); }, setWarningTitle: function (title) { this.text.setWarningTitle(title); }, focus: function () { this._showInput(); this.editor.focus(); }, blur: function () { this.editor.blur(); this._showHint(); this._checkText(); }, doRedMark: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, isValid: function () { return this.editor.isValid(); }, setErrorText: function (text) { this.editor.setErrorText(text); }, getErrorText: function () { return this.editor.getErrorText(); }, isEditing: function () { return this.editor.isEditing(); }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, setValue: function (k) { this.editor.setValue(k); this._checkText(); }, getValue: function () { return this.editor.getValue(); }, getState: function () { return this.text.getValue(); }, setState: function (v) { this._showHint(); this.text.setValue(v); } }); BI.SignEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.SignEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.SignEditor.EVENT_BLUR = "EVENT_BLUR"; BI.SignEditor.EVENT_CLICK = "EVENT_CLICK"; BI.SignEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.SignEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL"; BI.SignEditor.EVENT_START = "EVENT_START"; BI.SignEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.SignEditor.EVENT_STOP = "EVENT_STOP"; BI.SignEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.SignEditor.EVENT_VALID = "EVENT_VALID"; BI.SignEditor.EVENT_ERROR = "EVENT_ERROR"; BI.SignEditor.EVENT_ENTER = "EVENT_ENTER"; BI.SignEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.SignEditor.EVENT_SPACE = "EVENT_SPACE"; BI.SignEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.sign_editor", BI.SignEditor);/** * guy * 记录状态的输入框 * @class BI.StateEditor * @extends BI.Single */ BI.StateEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.StateEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-state-editor", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: true, watermark: "", errorText: "", height: 30 }) }, _init: function () { BI.StateEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.text = BI.createWidget({ type: "bi.text_button", cls: "state-editor-infinite-text bi-disabled", textAlign: "left", height: o.height, text: BI.i18nText("BI-Basic_Unrestricted"), hgap: 4, handler: function () { self._showInput(); self.editor.focus(); self.editor.setValue(""); } }); this.text.on(BI.TextButton.EVENT_CHANGE, function () { BI.nextTick(function () { self.fireEvent(BI.StateEditor.EVENT_CLICK_LABEL); }); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.text, left: 0, right: 0, top: 0, bottom: 0 }] }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.StateEditor.EVENT_FOCUS, arguments); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.StateEditor.EVENT_BLUR, arguments); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.StateEditor.EVENT_CLICK, arguments); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self.fireEvent(BI.StateEditor.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.StateEditor.EVENT_KEY_DOWN, arguments); }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.StateEditor.EVENT_VALID, arguments); }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self._showHint(); self.fireEvent(BI.StateEditor.EVENT_CONFIRM, arguments); }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.StateEditor.EVENT_START, arguments); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.StateEditor.EVENT_PAUSE, arguments); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.StateEditor.EVENT_STOP, arguments); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.StateEditor.EVENT_SPACE, arguments); }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self.fireEvent(BI.StateEditor.EVENT_ERROR, arguments); }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.StateEditor.EVENT_ENTER, arguments); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.StateEditor.EVENT_RESTRICT, arguments); }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self.fireEvent(BI.StateEditor.EVENT_EMPTY, arguments); }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [this.editor] }); this._showHint(); }, doRedMark: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, focus: function () { if (this.options.disabled === false) { this._showInput(); this.editor.focus(); } }, blur: function () { this.editor.blur(); this._showHint(); }, _showInput: function () { this.editor.visible(); this.text.invisible(); }, _showHint: function () { this.editor.invisible(); this.text.visible(); }, isValid: function () { return this.editor.isValid(); }, setErrorText: function (text) { this.editor.setErrorText(text); }, getErrorText: function () { return this.editor.getErrorText(); }, isEditing: function () { return this.editor.isEditing(); }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, setValue: function (k) { this.editor.setValue(k); }, getValue: function () { return this.editor.getValue(); }, getState: function () { return this.editor.getValue().match(/[^\s]+/g); }, setState: function (v) { BI.StateEditor.superclass.setValue.apply(this, arguments); if (BI.isNumber(v)) { if (v === BI.Selection.All) { this.text.setText(BI.i18nText("BI-Select_All")); this.text.setTitle(""); this.text.element.removeClass("state-editor-infinite-text"); } else if (v === BI.Selection.Multi) { this.text.setText(BI.i18nText("BI-Select_Part")); this.text.setTitle(""); this.text.element.removeClass("state-editor-infinite-text"); } else { this.text.setText(BI.i18nText("BI-Basic_Unrestricted")); this.text.setTitle(""); this.text.element.addClass("state-editor-infinite-text"); } return; } if (BI.isString(v)) { // if (BI.isEmpty(v)) { // this.text.setText(BI.i18nText("BI-Basic_Unrestricted")); // this.text.setTitle(""); // this.text.element.addClass("state-editor-infinite-text"); // } else { this.text.setText(v); this.text.setTitle(v); this.text.element.removeClass("state-editor-infinite-text"); // } return; } if (BI.isArray(v)) { if (BI.isEmpty(v)) { this.text.setText(BI.i18nText("BI-Basic_Unrestricted")); this.text.element.addClass("state-editor-infinite-text"); } else if (v.length === 1) { this.text.setText(v[0]); this.text.setTitle(v[0]); this.text.element.removeClass("state-editor-infinite-text"); } else { this.text.setText(BI.i18nText("BI-Select_Part")); this.text.setTitle(""); this.text.element.removeClass("state-editor-infinite-text"); } } } }); BI.StateEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.StateEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.StateEditor.EVENT_BLUR = "EVENT_BLUR"; BI.StateEditor.EVENT_CLICK = "EVENT_CLICK"; BI.StateEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.StateEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL"; BI.StateEditor.EVENT_START = "EVENT_START"; BI.StateEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.StateEditor.EVENT_STOP = "EVENT_STOP"; BI.StateEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.StateEditor.EVENT_VALID = "EVENT_VALID"; BI.StateEditor.EVENT_ERROR = "EVENT_ERROR"; BI.StateEditor.EVENT_ENTER = "EVENT_ENTER"; BI.StateEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.StateEditor.EVENT_SPACE = "EVENT_SPACE"; BI.StateEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.state_editor", BI.StateEditor);/** * 无限制-已选择状态输入框 * Created by GUY on 2016/5/18. * @class BI.SimpleStateEditor * @extends BI.Single */ BI.SimpleStateEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.SimpleStateEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-simple-state-editor", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: true, watermark: "", errorText: "", height: 30 }) }, _init: function () { BI.SimpleStateEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.editor", height: o.height, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.text = BI.createWidget({ type: "bi.text_button", cls: "state-editor-infinite-text bi-disabled", textAlign: "left", height: o.height, text: BI.i18nText("BI-Basic_Unrestricted"), hgap: 4, handler: function () { self._showInput(); self.editor.focus(); self.editor.setValue(""); } }); this.text.on(BI.TextButton.EVENT_CHANGE, function () { BI.nextTick(function () { self.fireEvent(BI.SimpleStateEditor.EVENT_CLICK_LABEL); }); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.text, left: 0, right: 0, top: 0, bottom: 0 }] }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_FOCUS, arguments); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_BLUR, arguments); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_CLICK, arguments); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.SimpleStateEditor.EVENT_KEY_DOWN, arguments); }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_VALID, arguments); }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self._showHint(); self.fireEvent(BI.SimpleStateEditor.EVENT_CONFIRM, arguments); }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_START, arguments); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_PAUSE, arguments); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_STOP, arguments); }); this.editor.on(BI.Editor.EVENT_SPACE, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_SPACE, arguments); }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_ERROR, arguments); }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_ENTER, arguments); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_RESTRICT, arguments); }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self.fireEvent(BI.SimpleStateEditor.EVENT_EMPTY, arguments); }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [this.editor] }); this._showHint(); }, doRedMark: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doHighLight: function () { if (this.editor.getValue() === "" && BI.isKey(this.options.watermark)) { return; } this.text.doHighLight.apply(this.text, arguments); }, unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); }, focus: function () { this._showInput(); this.editor.focus(); }, blur: function () { this.editor.blur(); this._showHint(); }, _showInput: function () { this.editor.visible(); this.text.invisible(); }, _showHint: function () { this.editor.invisible(); this.text.visible(); }, isValid: function () { return this.editor.isValid(); }, setErrorText: function (text) { this.editor.setErrorText(text); }, getErrorText: function () { return this.editor.getErrorText(); }, isEditing: function () { return this.editor.isEditing(); }, getLastValidValue: function () { return this.editor.getLastValidValue(); }, setValue: function (k) { this.editor.setValue(k); }, getValue: function () { return this.editor.getValue(); }, getState: function () { return this.editor.getValue().match(/[^\s]+/g); }, setState: function (v) { BI.SimpleStateEditor.superclass.setValue.apply(this, arguments); if (BI.isNumber(v)) { if (v === BI.Selection.All) { this.text.setText(BI.i18nText("BI-Already_Selected")); this.text.element.removeClass("state-editor-infinite-text"); } else if (v === BI.Selection.Multi) { this.text.setText(BI.i18nText("BI-Already_Selected")); this.text.element.removeClass("state-editor-infinite-text"); } else { this.text.setText(BI.i18nText("BI-Basic_Unrestricted")); this.text.element.addClass("state-editor-infinite-text"); } return; } if (!BI.isArray(v) || v.length === 1) { this.text.setText(v); this.text.setTitle(v); this.text.element.removeClass("state-editor-infinite-text"); } else if (BI.isEmpty(v)) { this.text.setText(BI.i18nText("BI-Basic_Unrestricted")); this.text.element.addClass("state-editor-infinite-text"); } else { this.text.setText(BI.i18nText("BI-Already_Selected")); this.text.element.removeClass("state-editor-infinite-text"); } } }); BI.SimpleStateEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.SimpleStateEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.SimpleStateEditor.EVENT_BLUR = "EVENT_BLUR"; BI.SimpleStateEditor.EVENT_CLICK = "EVENT_CLICK"; BI.SimpleStateEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.SimpleStateEditor.EVENT_CLICK_LABEL = "EVENT_CLICK_LABEL"; BI.SimpleStateEditor.EVENT_START = "EVENT_START"; BI.SimpleStateEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.SimpleStateEditor.EVENT_STOP = "EVENT_STOP"; BI.SimpleStateEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.SimpleStateEditor.EVENT_VALID = "EVENT_VALID"; BI.SimpleStateEditor.EVENT_ERROR = "EVENT_ERROR"; BI.SimpleStateEditor.EVENT_ENTER = "EVENT_ENTER"; BI.SimpleStateEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.SimpleStateEditor.EVENT_SPACE = "EVENT_SPACE"; BI.SimpleStateEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.simple_state_editor", BI.SimpleStateEditor);/** * guy * @class BI.TextEditor * @extends BI.Single */ BI.TextEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.TextEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-text-editor bi-border", hgap: 4, vgap: 2, lgap: 0, rgap: 0, tgap: 0, bgap: 0, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, mouseOut: false, allowBlank: false, watermark: "", errorText: "", height: 30 }) }, _init: function () { BI.TextEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; if (BI.isNumber(o.height)) { this.element.css({height: o.height - 2}); } if (BI.isNumber(o.width)) { this.element.css({width: o.width - 2}); } this.editor = BI.createWidget({ type: "bi.editor", height: o.height - 2, hgap: o.hgap, vgap: o.vgap, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: o.mouseOut, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.Editor.EVENT_FOCUS, function () { self.fireEvent(BI.TextEditor.EVENT_FOCUS); }); this.editor.on(BI.Editor.EVENT_BLUR, function () { self.fireEvent(BI.TextEditor.EVENT_BLUR); }); this.editor.on(BI.Editor.EVENT_CLICK, function () { self.fireEvent(BI.TextEditor.EVENT_CLICK); }); this.editor.on(BI.Editor.EVENT_CHANGE, function () { self.fireEvent(BI.TextEditor.EVENT_CHANGE); }); this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) { self.fireEvent(BI.TextEditor.EVENT_KEY_DOWN); }); this.editor.on(BI.Editor.EVENT_SPACE, function (v) { self.fireEvent(BI.TextEditor.EVENT_SPACE); }); this.editor.on(BI.Editor.EVENT_BACKSPACE, function (v) { self.fireEvent(BI.TextEditor.EVENT_BACKSPACE); }); this.editor.on(BI.Editor.EVENT_VALID, function () { self.fireEvent(BI.TextEditor.EVENT_VALID); }); this.editor.on(BI.Editor.EVENT_CONFIRM, function () { self.fireEvent(BI.TextEditor.EVENT_CONFIRM); }); this.editor.on(BI.Editor.EVENT_REMOVE, function (v) { self.fireEvent(BI.TextEditor.EVENT_REMOVE); }); this.editor.on(BI.Editor.EVENT_START, function () { self.fireEvent(BI.TextEditor.EVENT_START); }); this.editor.on(BI.Editor.EVENT_PAUSE, function () { self.fireEvent(BI.TextEditor.EVENT_PAUSE); }); this.editor.on(BI.Editor.EVENT_STOP, function () { self.fireEvent(BI.TextEditor.EVENT_STOP); }); this.editor.on(BI.Editor.EVENT_ERROR, function () { self.fireEvent(BI.TextEditor.EVENT_ERROR, arguments); }); this.editor.on(BI.Editor.EVENT_ENTER, function () { self.fireEvent(BI.TextEditor.EVENT_ENTER); }); this.editor.on(BI.Editor.EVENT_RESTRICT, function () { self.fireEvent(BI.TextEditor.EVENT_RESTRICT); }); this.editor.on(BI.Editor.EVENT_EMPTY, function () { self.fireEvent(BI.TextEditor.EVENT_EMPTY); }); BI.createWidget({ type: "bi.vertical", scrolly: false, element: this, items: [this.editor] }); }, focus: function () { this.editor.focus(); }, blur: function () { this.editor.blur(); }, setErrorText: function (text) { this.editor.setErrorText(text); }, getErrorText: function () { return this.editor.getErrorText(); }, isValid: function () { return this.editor.isValid(); }, setValue: function (v) { this.editor.setValue(v); }, getValue: function () { return this.editor.getValue(); } }); BI.TextEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.TextEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.TextEditor.EVENT_BLUR = "EVENT_BLUR"; BI.TextEditor.EVENT_CLICK = "EVENT_CLICK"; BI.TextEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.TextEditor.EVENT_SPACE = "EVENT_SPACE"; BI.TextEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE"; BI.TextEditor.EVENT_START = "EVENT_START"; BI.TextEditor.EVENT_PAUSE = "EVENT_PAUSE"; BI.TextEditor.EVENT_STOP = "EVENT_STOP"; BI.TextEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.TextEditor.EVENT_VALID = "EVENT_VALID"; BI.TextEditor.EVENT_ERROR = "EVENT_ERROR"; BI.TextEditor.EVENT_ENTER = "EVENT_ENTER"; BI.TextEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.TextEditor.EVENT_REMOVE = "EVENT_REMOVE"; BI.TextEditor.EVENT_EMPTY = "EVENT_EMPTY"; BI.shortcut("bi.text_editor", BI.TextEditor);/** * 小号搜索框 * Created by GUY on 2015/9/29. * @class BI.SmallTextEditor * @extends BI.SearchEditor */ BI.SmallTextEditor = BI.inherit(BI.TextEditor, { _defaultConfig: function () { var conf = BI.SmallTextEditor.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-small-text-editor", height: 25 }); }, _init: function () { BI.SmallTextEditor.superclass._init.apply(this, arguments); } }); BI.shortcut("bi.small_text_editor", BI.SmallTextEditor);/** * 有确定取消按钮的弹出层 * @class BI.BarFloatSection * @extends BI.FloatSection * @abstract */ BI.BarFloatSection = BI.inherit(BI.FloatSection, { _defaultConfig: function () { return BI.extend(BI.BarFloatSection.superclass._defaultConfig.apply(this, arguments), { btns: [BI.i18nText(BI.i18nText("BI-Basic_Sure")), BI.i18nText("BI-Basic_Cancel")] }) }, _init: function () { BI.BarFloatSection.superclass._init.apply(this, arguments); var self = this; var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"]; flatten = BI.makeObject(flatten, true); BI.each(this.constructor.caller.caller.caller.caller.prototype, function (key) { if (flatten[key]) { return; } var f = self[key]; if (BI.isFunction(f)) { self[key] = BI.bind(function () { if (this.model._start === true) { this._F.push({f: f, arg: arguments}); return; } return f.apply(this, arguments); }, self); } }) }, rebuildSouth: function (south) { var self = this, o = this.options; this.sure = BI.createWidget({ type: 'bi.button', text: this.options.btns[0], height: 30, value: 0, handler: function (v) { self.end(); self.close(v); } }); this.cancel = BI.createWidget({ type: 'bi.button', text: this.options.btns[1], height: 30, value: 1, level: 'ignore', handler: function (v) { self.close(v); } }); BI.createWidget({ type: 'bi.right_vertical_adapt', element: south, hgap: 5, items: [this.cancel, this.sure] }); } }); /** * 有确定取消按钮的弹出层 * @class BI.BarPopoverSection * @extends BI.PopoverSection * @abstract */ BI.BarPopoverSection = BI.inherit(BI.PopoverSection, { _defaultConfig: function () { return BI.extend(BI.BarPopoverSection.superclass._defaultConfig.apply(this, arguments), { btns: [BI.i18nText(BI.i18nText("BI-Basic_Sure")), BI.i18nText(BI.i18nText("BI-Basic_Cancel"))] }) }, _init: function () { BI.BarPopoverSection.superclass._init.apply(this, arguments); }, rebuildSouth: function (south) { var self = this, o = this.options; this.sure = BI.createWidget({ type: 'bi.button', text: this.options.btns[0], warningTitle: o.warningTitle, height: 30, value: 0, handler: function (v) { self.end(); self.close(v); } }); this.cancel = BI.createWidget({ type: 'bi.button', text: this.options.btns[1], height: 30, value: 1, level: 'ignore', handler: function (v) { self.close(v); } }); BI.createWidget({ type: 'bi.right_vertical_adapt', element: south, hgap: 5, items: [this.cancel, this.sure] }); }, setConfirmButtonEnable: function(v){ this.sure.setEnable(!!v); } });/** * 下拉框弹出层的多选版本,toolbar带有若干按钮, zIndex在1000w * @class BI.MultiPopupView * @extends BI.Widget */ BI.MultiPopupView = BI.inherit(BI.PopupView, { _defaultConfig: function () { var conf = BI.MultiPopupView.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-multi-list-view", buttons: [BI.i18nText("BI-Basic_Sure")] }) }, _init: function () { BI.MultiPopupView.superclass._init.apply(this, arguments); }, _createToolBar: function () { var o = this.options, self = this; if (o.buttons.length === 0) { return; } var text = []; //构造[{text:content},……] BI.each(o.buttons, function (idx, item) { text.push({ text: item, value: idx }) }); this.buttongroup = BI.createWidget({ type: "bi.button_group", cls: "list-view-toolbar bi-high-light bi-border-top", height: 30, items: BI.createItems(text, { type: "bi.text_button", once: false, shadow: true, isShadowShowingOnSelected: true }), layouts: [{ type: "bi.center", hgap: 0, vgap: 0 }] }); this.buttongroup.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) { self.fireEvent(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, value, obj); }); return this.buttongroup; } }); BI.MultiPopupView.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON"; BI.shortcut("bi.multi_popup_view", BI.MultiPopupView);/** * 可以理解为MultiPopupView和Panel两个面板的结合体 * @class BI.PopupPanel * @extends BI.MultiPopupView */ BI.PopupPanel = BI.inherit(BI.MultiPopupView, { _defaultConfig: function () { var conf = BI.PopupPanel.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-popup-panel", title: "" }) }, _init: function () { BI.PopupPanel.superclass._init.apply(this, arguments); }, _createTool: function () { var self = this, o = this.options; var close = BI.createWidget({ type: "bi.icon_button", cls: "close-h-font", width: 25, height: 25 }); close.on(BI.IconButton.EVENT_CHANGE, function () { self.setVisible(false); self.fireEvent(BI.PopupPanel.EVENT_CLOSE); }); return BI.createWidget({ type: "bi.htape", cls: "popup-panel-title bi-background bi-border", height: 25, items: [{ el: { type: "bi.label", textAlign: "left", text: o.title, height: 25, lgap: 10 } }, { el: close, width: 25 }] }); } }); BI.PopupPanel.EVENT_CHANGE = "EVENT_CHANGE"; BI.PopupPanel.EVENT_CLOSE = "EVENT_CLOSE"; BI.PopupPanel.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON"; BI.shortcut("bi.popup_panel", BI.PopupPanel);/** * list面板 * * Created by GUY on 2015/10/30. * @class BI.ListPane * @extends BI.Pane */ BI.ListPane = BI.inherit(BI.Pane, { _defaultConfig: function () { var conf = BI.ListPane.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-list-pane", logic: { dynamic: true }, lgap: 0, rgap: 0, tgap: 0, bgap: 0, vgap: 0, hgap: 0, items: [], itemsCreator: BI.emptyFn, hasNext: BI.emptyFn, onLoaded: BI.emptyFn, el: { type: "bi.button_group" } }) }, _init: function () { BI.ListPane.superclass._init.apply(this, arguments); var self = this, o = this.options; this.button_group = BI.createWidget(o.el, { type: "bi.button_group", chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, behaviors: {}, items: o.items, itemsCreator: function (op, calback) { if (op.times === 1) { self.empty(); BI.nextTick(function () { self.loading() }); } o.itemsCreator(op, function () { calback.apply(self, arguments); op.times === 1 && BI.nextTick(function () { self.loaded(); }); }); }, hasNext: o.hasNext, layouts: [{ type: "bi.vertical" }] }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.ListPane.EVENT_CHANGE, value, obj); } }); this.check(); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Top), BI.extend({ scrolly: true, lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, vgap: o.vgap, hgap: o.hgap }, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Top, this.button_group) })))); }, hasPrev: function () { return this.button_group.hasPrev && this.button_group.hasPrev(); }, hasNext: function () { return this.button_group.hasNext && this.button_group.hasNext(); }, prependItems: function (items) { this.options.items = items.concat(this.options.items); this.button_group.prependItems.apply(this.button_group, arguments); this.check(); }, addItems: function (items) { this.options.items = this.options.items.concat(items); this.button_group.addItems.apply(this.button_group, arguments); this.check(); }, removeItemAt: function (indexes) { indexes = indexes || []; BI.removeAt(this.options.items, indexes); this.button_group.removeItemAt.apply(this.button_group, arguments); this.check(); }, populate: function (items) { var self = this, o = this.options; if (arguments.length === 0 && (BI.isFunction(this.button_group.attr("itemsCreator")))) {//接管loader的populate方法 this.button_group.attr("itemsCreator").apply(this, [{times: 1}, function () { if (arguments.length === 0) { throw new Error("参数不能为空"); } self.populate.apply(self, arguments); }]); return; } BI.ListPane.superclass.populate.apply(this, arguments); this.button_group.populate.apply(this.button_group, arguments); }, empty: function () { this.button_group.empty(); }, setNotSelectedValue: function () { this.button_group.setNotSelectedValue.apply(this.button_group, arguments); }, getNotSelectedValue: function () { return this.button_group.getNotSelectedValue(); }, setValue: function () { this.button_group.setValue.apply(this.button_group, arguments); }, getValue: function () { return this.button_group.getValue.apply(this.button_group, arguments); }, getAllButtons: function () { return this.button_group.getAllButtons(); }, getAllLeaves: function () { return this.button_group.getAllLeaves(); }, getSelectedButtons: function () { return this.button_group.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.button_group.getNotSelectedButtons(); }, getIndexByValue: function (value) { return this.button_group.getIndexByValue(value); }, getNodeById: function (id) { return this.button_group.getNodeById(id); }, getNodeByValue: function (value) { return this.button_group.getNodeByValue(value); } }); BI.ListPane.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.list_pane", BI.ListPane);/** * 带有标题栏的pane * @class BI.Panel * @extends BI.Widget */ BI.Panel = BI.inherit(BI.Widget,{ _defaultConfig : function(){ return BI.extend(BI.Panel.superclass._defaultConfig.apply(this,arguments),{ baseCls: "bi-panel bi-border", title:"", titleButtons:[], el:{}, logic:{ dynamic: false } }); }, _init:function(){ BI.Panel.superclass._init.apply(this,arguments); var o = this.options; BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("vertical", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("top", this._createTitle() ,this.options.el) })))); }, _createTitle:function(){ var self = this, o = this.options; this.text = BI.createWidget({ type: "bi.label", cls: "panel-title-text", text: o.title, height: 30 }); this.button_group = BI.createWidget({ type:"bi.button_group", items: o.titleButtons, layouts: [{ type: "bi.center_adapt", lgap:10 }] }); this.button_group.on(BI.Controller.EVENT_CHANGE, function(){ self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function(value, obj){ self.fireEvent(BI.Panel.EVENT_CHANGE, value, obj); }); return { el: { type: "bi.left_right_vertical_adapt", cls: "panel-title bi-tips bi-border-bottom bi-background", height: 30, items: { left: [this.text], right: [this.button_group] }, lhgap: 10, rhgap: 10 }, height: 30 }; }, setTitle: function(title){ this.text.setValue(title); } }); BI.Panel.EVENT_CHANGE = "Panel.EVENT_CHANGE"; BI.shortcut("bi.panel",BI.Panel);/** * 选择列表 * * Created by GUY on 2015/11/1. * @class BI.SelectList * @extends BI.Widget */ BI.SelectList = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SelectList.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-select-list", direction: BI.Direction.Top,//toolbar的位置 logic: { dynamic: true }, items: [], itemsCreator: BI.emptyFn, hasNext: BI.emptyFn, onLoaded: BI.emptyFn, toolbar: { type: "bi.multi_select_bar" }, el: { type: "bi.list_pane" } }) }, _init: function () { BI.SelectList.superclass._init.apply(this, arguments); var self = this, o = this.options; //全选 this.toolbar = BI.createWidget(o.toolbar); this.toolbar.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { var isAllSelected = this.isSelected(); if (type === BI.Events.CLICK) { self.setAllSelected(isAllSelected); self.fireEvent(BI.SelectList.EVENT_CHANGE, value, obj); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.list = BI.createWidget(o.el, { type: "bi.list_pane", items: o.items, itemsCreator: function (op, callback) { op.times === 1 && self.toolbar.setVisible(false); o.itemsCreator(op, function (items) { callback.apply(self, arguments); if (op.times === 1) { self.toolbar.setVisible(items && items.length > 0); self.toolbar.setEnable(items && items.length > 0); } self._checkAllSelected(); }); }, onLoaded: o.onLoaded, hasNext: o.hasNext }); this.list.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (type === BI.Events.CLICK) { self._checkAllSelected(); self.fireEvent(BI.SelectList.EVENT_CHANGE, value, obj); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({ scrolly: true }, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.toolbar, this.list) })))); if (o.items.length <= 0) { this.toolbar.setVisible(false); this.toolbar.setEnable(false); } }, _checkAllSelected: function () { var selectLength = this.list.getValue().length; var notSelectLength = this.getAllLeaves().length - selectLength; var hasNext = this.list.hasNext(); var isAlreadyAllSelected = this.toolbar.isSelected(); var isHalf = selectLength > 0 && (notSelectLength > 0 || (!isAlreadyAllSelected && hasNext)); isHalf = isHalf || (notSelectLength > 0 && hasNext && isAlreadyAllSelected); this.toolbar.setHalfSelected(isHalf); !isHalf && this.toolbar.setSelected(selectLength > 0 && notSelectLength <= 0 && (!hasNext || isAlreadyAllSelected)); }, setAllSelected: function (v) { BI.each(this.getAllButtons(), function (i, btn) { (btn.setSelected || btn.setAllSelected).apply(btn, [v]); }); this.toolbar.setSelected(v); this.toolbar.setHalfSelected(false); }, setToolBarVisible: function (b) { this.toolbar.setVisible(b); }, isAllSelected: function () { return this.toolbar.isSelected(); }, hasPrev: function () { return this.list.hasPrev(); }, hasNext: function () { return this.list.hasNext(); }, prependItems: function (items) { this.list.prependItems.apply(this.list, arguments); }, addItems: function (items) { this.list.addItems.apply(this.list, arguments); }, setValue: function (data) { var selectAll = data.type === BI.ButtonGroup.CHOOSE_TYPE_ALL; this.setAllSelected(selectAll); this.list[selectAll ? "setNotSelectedValue" : "setValue"](data.value); this._checkAllSelected(); }, getValue: function () { if (this.isAllSelected() === false) { return { type: BI.ButtonGroup.CHOOSE_TYPE_MULTI, value: this.list.getValue(), assist: this.list.getNotSelectedValue() }; } else { return { type: BI.ButtonGroup.CHOOSE_TYPE_ALL, value: this.list.getNotSelectedValue(), assist: this.list.getValue() }; } }, empty: function () { this.list.empty(); }, populate: function (items) { this.toolbar.setVisible(!BI.isEmptyArray(items)); this.toolbar.setEnable(!BI.isEmptyArray(items)); this.list.populate.apply(this.list, arguments); this._checkAllSelected(); }, _setEnable: function (enable) { BI.SelectList.superclass._setEnable.apply(this, arguments); this.toolbar.setEnable(enable); }, resetHeight: function (h) { var toolHeight = ( this.toolbar.element.outerHeight() || 25) * ( this.toolbar.isVisible() ? 1 : 0); this.list.resetHeight ? this.list.resetHeight(h - toolHeight) : this.list.element.css({"max-height": h - toolHeight + "px"}) }, setNotSelectedValue: function () { this.list.setNotSelectedValue.apply(this.list, arguments); this._checkAllSelected(); }, getNotSelectedValue: function () { return this.list.getNotSelectedValue(); }, getAllButtons: function () { return this.list.getAllButtons(); }, getAllLeaves: function () { return this.list.getAllLeaves(); }, getSelectedButtons: function () { return this.list.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.list.getNotSelectedButtons(); }, getIndexByValue: function (value) { return this.list.getIndexByValue(value); }, getNodeById: function (id) { return this.list.getNodeById(id); }, getNodeByValue: function (value) { return this.list.getNodeByValue(value); } }); BI.SelectList.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.select_list", BI.SelectList);/** * Created by roy on 15/11/6. */ BI.LazyLoader = BI.inherit(BI.Widget, { _const: { PAGE: 100 }, _defaultConfig: function () { return BI.extend(BI.LazyLoader.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-lazy-loader", el: {} }) }, _init: function () { var self = this, o = this.options; BI.LazyLoader.superclass._init.apply(this, arguments); var all = o.items.length; this.loader = BI.createWidget({ type: "bi.loader", element: this, //下面是button_group的属性 el: o.el, itemsCreator: function (options, populate) { populate(self._getNextItems(options)); }, hasNext: function (option) { return option.count < all; } }); this.loader.on(BI.Loader.EVENT_CHANGE, function (obj) { self.fireEvent(BI.LazyLoader.EVENT_CHANGE, obj) }) }, _getNextItems: function (options) { var self = this, o = this.options; var lastNum = o.items.length - this._const.PAGE * (options.times - 1); var lastItems = BI.last(o.items, lastNum); var nextItems = BI.first(lastItems, this._const.PAGE); return nextItems; }, populate: function (items) { this.loader.populate(items); }, addItems: function (items) { this.loader.addItems(items); }, empty: function () { this.loader.empty(); }, setNotSelectedValue: function () { this.loader.setNotSelectedValue.apply(this.loader, arguments); }, getNotSelectedValue: function () { return this.loader.getNotSelectedValue(); }, setValue: function () { this.loader.setValue.apply(this.loader, arguments); }, getValue: function () { return this.loader.getValue.apply(this.loader, arguments); }, getAllButtons: function () { return this.loader.getAllButtons(); }, getAllLeaves: function () { return this.loader.getAllLeaves(); }, getSelectedButtons: function () { return this.loader.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.loader.getNotSelectedButtons(); }, getIndexByValue: function (value) { return this.loader.getIndexByValue(value); }, getNodeById: function (id) { return this.loader.getNodeById(id); }, getNodeByValue: function (value) { return this.loader.getNodeByValue(value); } }); BI.LazyLoader.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.lazy_loader", BI.LazyLoader);/** * 恶心的加载控件, 为解决排序问题引入的控件 * * Created by GUY on 2015/11/12. * @class BI.ListLoader * @extends BI.Widget */ BI.ListLoader = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ListLoader.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-list-loader", isDefaultInit: true,//是否默认初始化数据 //下面是button_group的属性 el: { type: "bi.button_group" }, items: [], itemsCreator: BI.emptyFn, onLoaded: BI.emptyFn, //下面是分页信息 count: false, next: {}, hasNext: BI.emptyFn }) }, _nextLoad: function () { var self = this, o = this.options; this.next.setLoading(); o.itemsCreator.apply(this, [{times: ++this.times}, function () { self.next.setLoaded(); self.addItems.apply(self, arguments); }]); }, _init: function () { BI.ListLoader.superclass._init.apply(this, arguments); var self = this, o = this.options; if (o.itemsCreator === false) { o.next = false; } this.button_group = BI.createWidget(o.el, { type: "bi.button_group", element: this, chooseType: 0, items: o.items, behaviors: {}, layouts: [{ type: "bi.vertical" }] }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.ListLoader.EVENT_CHANGE, obj); } }); if (o.next !== false) { this.next = BI.createWidget(BI.extend({ type: "bi.loading_bar" }, o.next)); this.next.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self._nextLoad(); } }) } BI.createWidget({ type: "bi.vertical", element: this, items: [this.next] }); o.isDefaultInit && BI.isEmpty(o.items) && BI.nextTick(BI.bind(function () { this.populate(); }, this)); if (BI.isNotEmptyArray(o.items)) { this.populate(o.items); } }, hasNext: function () { var o = this.options; if (BI.isNumber(o.count)) { return this.count < o.count; } return !!o.hasNext.apply(this, [{ times: this.times, count: this.count }]) }, addItems: function (items) { this.count += items.length; if (BI.isObject(this.next)) { if (this.hasNext()) { this.options.items = this.options.items.concat(items); this.next.setLoaded(); } else { this.next.setEnd(); } } this.button_group.addItems.apply(this.button_group, arguments); this.next.element.appendTo(this.element); }, populate: function (items) { var self = this, o = this.options; if (arguments.length === 0 && (BI.isFunction(o.itemsCreator))) { o.itemsCreator.apply(this, [{times: 1}, function () { if (arguments.length === 0) { throw new Error("参数不能为空"); } self.populate.apply(self, arguments); o.onLoaded(); }]); return; } this.options.items = items; this.times = 1; this.count = 0; this.count += items.length; if (BI.isObject(this.next)) { if (this.hasNext()) { this.next.setLoaded(); } else { this.next.invisible(); } } BI.DOM.hang([this.next]); this.button_group.populate.apply(this.button_group, arguments); this.next.element.appendTo(this.element); }, empty: function () { BI.DOM.hang([this.next]); this.button_group.empty(); this.next.element.appendTo(this.element); BI.each([this.next], function (i, ob) { ob && ob.setVisible(false); }); }, setNotSelectedValue: function () { this.button_group.setNotSelectedValue.apply(this.button_group, arguments); }, getNotSelectedValue: function () { return this.button_group.getNotSelectedValue(); }, setValue: function () { this.button_group.setValue.apply(this.button_group, arguments); }, getValue: function () { return this.button_group.getValue.apply(this.button_group, arguments); }, getAllButtons: function () { return this.button_group.getAllButtons(); }, getAllLeaves: function () { return this.button_group.getAllLeaves(); }, getSelectedButtons: function () { return this.button_group.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.button_group.getNotSelectedButtons(); }, getIndexByValue: function (value) { return this.button_group.getIndexByValue(value); }, getNodeById: function (id) { return this.button_group.getNodeById(id); }, getNodeByValue: function (value) { return this.button_group.getNodeByValue(value); } }); BI.ListLoader.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.list_loader", BI.ListLoader);/** * Created by GUY on 2016/4/29. * * @class BI.SortList * @extends BI.Widget */ BI.SortList = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SortList.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-sort-list", isDefaultInit: true,//是否默认初始化数据 //下面是button_group的属性 el: { type: "bi.button_group" }, items: [], itemsCreator: BI.emptyFn, onLoaded: BI.emptyFn, //下面是分页信息 count: false, next: {}, hasNext: BI.emptyFn //containment: this.element, //connectWith: ".bi-sort-list", }) }, _init: function () { BI.SortList.superclass._init.apply(this, arguments); var self = this, o = this.options; this.loader = BI.createWidget({ type: "bi.list_loader", element: this, isDefaultInit: o.isDefaultInit, el: o.el, items: this._formatItems(o.items), itemsCreator: function (op, callback) { o.itemsCreator(op, function (items) { callback(self._formatItems(items)); }); }, onLoaded: o.onLoaded, count: o.count, next: o.next, hasNext: o.hasNext }); this.loader.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.SortList.EVENT_CHANGE, value, obj); } }); this.loader.element.sortable({ containment: o.containment || this.element, connectWith: o.connectWith || ".bi-sort-list", items: ".sort-item", cursor: o.cursor || "drag", tolerance: o.tolerance || "intersect", placeholder: { element: function ($currentItem) { var holder = BI.createWidget({ type: "bi.layout", cls: "bi-sortable-holder", height: $currentItem.outerHeight() }); holder.element.css({ "margin-left": $currentItem.css("margin-left"), "margin-right": $currentItem.css("margin-right"), "margin-top": $currentItem.css("margin-top"), "margin-bottom": $currentItem.css("margin-bottom"), "margin": $currentItem.css("margin") }); return holder.element; }, update: function () { } }, start: function (event, ui) { }, stop: function (event, ui) { self.fireEvent(BI.SortList.EVENT_CHANGE); }, over: function (event, ui) { } }); }, _formatItems: function (items) { BI.each(items, function (i, item) { item = BI.stripEL(item); item.cls = item.cls ? item.cls + " sort-item" : "sort-item"; item.attributes = { sorted: item.value }; }); return items; }, hasNext: function () { return this.loader.hasNext(); }, addItems: function (items) { this.loader.addItems(items); }, populate: function (items) { if (items) { arguments[0] = this._formatItems(items); } this.loader.populate.apply(this.loader, arguments); }, empty: function () { this.loader.empty(); }, setNotSelectedValue: function () { this.loader.setNotSelectedValue.apply(this.loader, arguments); }, getNotSelectedValue: function () { return this.loader.getNotSelectedValue(); }, setValue: function () { this.loader.setValue.apply(this.loader, arguments); }, getValue: function () { return this.loader.getValue(); }, getAllButtons: function () { return this.loader.getAllButtons(); }, getAllLeaves: function () { return this.loader.getAllLeaves(); }, getSelectedButtons: function () { return this.loader.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.loader.getNotSelectedButtons(); }, getIndexByValue: function (value) { return this.loader.getIndexByValue(value); }, getNodeById: function (id) { return this.loader.getNodeById(id); }, getNodeByValue: function (value) { return this.loader.getNodeByValue(value); }, getSortedValues: function () { return this.loader.element.sortable("toArray", {attribute: "sorted"}); } }); BI.SortList.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.sort_list", BI.SortList);/** * 有总页数和总行数的分页控件 * Created by Young's on 2016/10/13. */ BI.AllCountPager = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.AllCountPager.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-all-count-pager", height: 30, pages: 1, //必选项 curr: 1, //初始化当前页, pages为数字时可用, count: 1 //总行数 }) }, _init: function () { BI.AllCountPager.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.small_text_editor", cls: "pager-editor", validationChecker: function (v) { return (self.rowCount.getValue() === 0 && v === "0") || BI.isPositiveInteger(v); }, hgap: 4, vgap: 0, value: o.curr, errorText: BI.i18nText("BI-Please_Input_Positive_Integer"), width: 35, height: 20 }); this.pager = BI.createWidget({ type: "bi.pager", width: 36, layouts: [{ type: "bi.horizontal", hgap: 1, vgap: 1 }], dynamicShow: false, pages: o.pages, curr: o.curr, groups: 0, first: false, last: false, prev: { type: "bi.icon_button", value: "prev", title: BI.i18nText("BI-Previous_Page"), warningTitle: BI.i18nText("BI-Current_Is_First_Page"), height: 20, cls: "all-pager-prev column-pre-page-h-font" }, next: { type: "bi.icon_button", value: "next", title: BI.i18nText("BI-Next_Page"), warningTitle: BI.i18nText("BI-Current_Is_Last_Page"), height: 20, cls: "all-pager-next column-next-page-h-font" }, hasPrev: o.hasPrev, hasNext: o.hasNext, firstPage: o.firstPage, lastPage: o.lastPage }); this.editor.on(BI.TextEditor.EVENT_CONFIRM, function () { self.pager.setValue(BI.parseInt(self.editor.getValue())); self.fireEvent(BI.AllCountPager.EVENT_CHANGE); }); this.pager.on(BI.Pager.EVENT_CHANGE, function () { self.fireEvent(BI.AllCountPager.EVENT_CHANGE); }); this.pager.on(BI.Pager.EVENT_AFTER_POPULATE, function () { self.editor.setValue(self.pager.getCurrentPage()); }); this.allPages = BI.createWidget({ type: "bi.label", width: 30, title: o.pages, text: "/" + o.pages }); this.rowCount = BI.createWidget({ type: "bi.label", height: o.height, hgap: 5, text: o.count, title: o.count }); var count = BI.createWidget({ type: "bi.left", height: o.height, scrollable: false, items: [{ type: "bi.label", height: o.height, text: BI.i18nText("BI-Basic_Total"), width: 15 }, this.rowCount, { type: "bi.label", height: o.height, text: BI.i18nText("BI-Tiao_Data"), width: 50, textAlign: "left" }] }); BI.createWidget({ type: "bi.center_adapt", element: this, columnSize: ["", 35, 40, 36], items: [count, this.editor, this.allPages, this.pager] }) }, alwaysShowPager: true, setAllPages: function (v) { this.allPages.setText("/" + v); this.allPages.setTitle(v); this.pager.setAllPages(v); this.editor.setEnable(v >= 1); }, setValue: function (v) { this.pager.setValue(v); }, setVPage: function (v) { this.pager.setValue(v); }, setCount: function (count) { this.rowCount.setText(count); this.rowCount.setTitle(count); }, getCurrentPage: function () { return this.pager.getCurrentPage(); }, hasPrev: function () { return this.pager.hasPrev(); }, hasNext: function () { return this.pager.hasNext(); }, setPagerVisible: function (b) { this.editor.setVisible(b); this.allPages.setVisible(b); this.pager.setVisible(b); }, populate: function () { this.pager.populate(); } }); BI.AllCountPager.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.all_count_pager", BI.AllCountPager);/** * 显示页码的分页控件 * * Created by GUY on 2016/6/30. * @class BI.DirectionPager * @extends BI.Widget */ BI.DirectionPager = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DirectionPager.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-direction-pager", height: 30, horizontal: { pages: false, //总页数 curr: 1, //初始化当前页, pages为数字时可用 hasPrev: BI.emptyFn, hasNext: BI.emptyFn, firstPage: 1, lastPage: BI.emptyFn }, vertical: { pages: false, //总页数 curr: 1, //初始化当前页, pages为数字时可用 hasPrev: BI.emptyFn, hasNext: BI.emptyFn, firstPage: 1, lastPage: BI.emptyFn } }) }, _init: function () { BI.DirectionPager.superclass._init.apply(this, arguments); var self = this, o = this.options; var v = o.vertical, h = o.horizontal; this._createVPager(); this._createHPager(); this.layout = BI.createWidget({ type: "bi.absolute", scrollable: false, element: this, items: [{ el: this.vpager, top: 5, right: 74 }, { el: this.vlabel, top: 5, right: 111 }, { el: this.hpager, top: 5, right: -9 }, { el: this.hlabel, top: 5, right: 28 }] }); }, _createVPager: function () { var self = this, o = this.options; var v = o.vertical; this.vlabel = BI.createWidget({ type: "bi.label", width: 24, height: 20, value: v.curr, title: v.curr }); this.vpager = BI.createWidget({ type: "bi.pager", width: 76, layouts: [{ type: "bi.horizontal", scrollx: false, rgap: 24, vgap: 1 }], dynamicShow: false, pages: v.pages, curr: v.curr, groups: 0, first: false, last: false, prev: { type: "bi.icon_button", value: "prev", title: BI.i18nText("BI-Up_Page"), warningTitle: BI.i18nText("BI-Current_Is_First_Page"), height: 20, iconWidth: 16, iconHeight: 16, cls: "direction-pager-prev column-pre-page-h-font" }, next: { type: "bi.icon_button", value: "next", title: BI.i18nText("BI-Down_Page"), warningTitle: BI.i18nText("BI-Current_Is_Last_Page"), height: 20, iconWidth: 16, iconHeight: 16, cls: "direction-pager-next column-next-page-h-font" }, hasPrev: v.hasPrev, hasNext: v.hasNext, firstPage: v.firstPage, lastPage: v.lastPage }); this.vpager.on(BI.Pager.EVENT_CHANGE, function () { self.fireEvent(BI.DirectionPager.EVENT_CHANGE); }); this.vpager.on(BI.Pager.EVENT_AFTER_POPULATE, function () { self.vlabel.setValue(this.getCurrentPage()); self.vlabel.setTitle(this.getCurrentPage()); }); }, _createHPager: function () { var self = this, o = this.options; var h = o.horizontal; this.hlabel = BI.createWidget({ type: "bi.label", width: 24, height: 20, value: h.curr, title: h.curr }); this.hpager = BI.createWidget({ type: "bi.pager", width: 76, layouts: [{ type: "bi.horizontal", scrollx: false, rgap: 24, vgap: 1 }], dynamicShow: false, pages: h.pages, curr: h.curr, groups: 0, first: false, last: false, prev: { type: "bi.icon_button", value: "prev", title: BI.i18nText("BI-Left_Page"), warningTitle: BI.i18nText("BI-Current_Is_First_Page"), height: 20, iconWidth: 16, iconHeight: 16, cls: "direction-pager-prev row-pre-page-h-font" }, next: { type: "bi.icon_button", value: "next", title: BI.i18nText("BI-Right_Page"), warningTitle: BI.i18nText("BI-Current_Is_Last_Page"), height: 20, iconWidth: 16, iconHeight: 16, cls: "direction-pager-next row-next-page-h-font" }, hasPrev: h.hasPrev, hasNext: h.hasNext, firstPage: h.firstPage, lastPage: h.lastPage }); this.hpager.on(BI.Pager.EVENT_CHANGE, function () { self.fireEvent(BI.DirectionPager.EVENT_CHANGE); }); this.hpager.on(BI.Pager.EVENT_AFTER_POPULATE, function () { self.hlabel.setValue(this.getCurrentPage()); self.hlabel.setTitle(this.getCurrentPage()); }); }, getVPage: function () { return this.vpager.getCurrentPage(); }, getHPage: function () { return this.hpager.getCurrentPage(); }, setVPage: function (v) { this.vpager.setValue(v); this.vlabel.setValue(v); this.vlabel.setTitle(v); }, setHPage: function (v) { this.hpager.setValue(v); this.hlabel.setValue(v); this.hlabel.setTitle(v); }, hasVNext: function () { return this.vpager.hasNext(); }, hasHNext: function () { return this.hpager.hasNext(); }, hasVPrev: function () { return this.vpager.hasPrev(); }, hasHPrev: function () { return this.hpager.hasPrev(); }, setHPagerVisible: function (b) { this.hpager.setVisible(b); this.hlabel.setVisible(b); }, setVPagerVisible: function (b) { this.vpager.setVisible(b); this.vlabel.setVisible(b); }, populate: function () { this.vpager.populate(); this.hpager.populate(); var vShow = false, hShow = false; if (!this.hasHNext() && !this.hasHPrev()) { this.setHPagerVisible(false); } else { this.setHPagerVisible(true); hShow = true; } if (!this.hasVNext() && !this.hasVPrev()) { this.setVPagerVisible(false); } else { this.setVPagerVisible(true); vShow = true; } this.setVisible(hShow || vShow); var num = [74, 111, -9, 28]; var items = this.layout.attr("items"); if (vShow === true && hShow === true) { items[0].right = num[0]; items[1].right = num[1]; items[2].right = num[2]; items[3].right = num[3]; } else if (vShow === true) { items[0].right = num[2]; items[1].right = num[3]; } else if (hShow === true) { items[2].right = num[2]; items[3].right = num[3]; } this.layout.attr("items", items); this.layout.resize(); }, clear: function () { this.vpager.attr("curr", 1); this.hpager.attr("curr", 1); } }); BI.DirectionPager.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.direction_pager", BI.DirectionPager);/** * 分页控件 * * Created by GUY on 2015/8/31. * @class BI.DetailPager * @extends BI.Widget */ BI.DetailPager = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DetailPager.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-detail-pager", behaviors: {}, layouts: [{ type: "bi.horizontal", hgap: 10, vgap: 0 }], dynamicShow: true, //是否动态显示上一页、下一页、首页、尾页, 若为false,则指对其设置使能状态 //dynamicShow为false时以下两个有用 dynamicShowFirstLast: false,//是否动态显示首页、尾页 dynamicShowPrevNext: false,//是否动态显示上一页、下一页 pages: false, //总页数 curr: function () { return 1; }, //初始化当前页 groups: 0, //连续显示分页数 jump: BI.emptyFn, //分页的回调函数 first: false, //是否显示首页 last: false, //是否显示尾页 prev: "上一页", next: "下一页", firstPage: 1, lastPage: function () { //在万不得已时才会调用这个函数获取最后一页的页码, 主要作用于setValue方法 return 1; }, hasPrev: BI.emptyFn, //pages不可用时有效 hasNext: BI.emptyFn //pages不可用时有效 }) }, _init: function () { BI.DetailPager.superclass._init.apply(this, arguments); var self = this; this.currPage = BI.result(this.options, "curr"); //翻页太灵敏 this._lock = false; this._debouce = BI.debounce(function () { self._lock = false; }, 300); this._populate(); }, _populate: function () { var self = this, o = this.options, view = [], dict = {}; this.empty(); var pages = BI.result(o, "pages"); var curr = BI.result(this, "currPage"); var groups = BI.result(o, "groups"); var first = BI.result(o, "first"); var last = BI.result(o, "last"); var prev = BI.result(o, "prev"); var next = BI.result(o, "next"); if (pages === false) { groups = 0; first = false; last = false; } else { groups > pages && (groups = pages); } //计算当前组 dict.index = Math.ceil((curr + ((groups > 1 && groups !== pages) ? 1 : 0)) / (groups === 0 ? 1 : groups)); //当前页非首页,则输出上一页 if (((!o.dynamicShow && !o.dynamicShowPrevNext) || curr > 1) && prev !== false) { if (BI.isKey(prev)) { view.push({ text: prev, value: "prev", disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false) }) } else { view.push(BI.extend({ disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false) }, prev)); } } //当前组非首组,则输出首页 if (((!o.dynamicShow && !o.dynamicShowFirstLast) || (dict.index > 1 && groups !== 0)) && first) { view.push({ text: first, value: "first", disabled: !(dict.index > 1 && groups !== 0) }); if (dict.index > 1 && groups !== 0) { view.push({ type: "bi.label", cls: "page-ellipsis", text: "\u2026" }); } } //输出当前页组 dict.poor = Math.floor((groups - 1) / 2); dict.start = dict.index > 1 ? curr - dict.poor : 1; dict.end = dict.index > 1 ? (function () { var max = curr + (groups - dict.poor - 1); return max > pages ? pages : max; }()) : groups; if (dict.end - dict.start < groups - 1) { //最后一组状态 dict.start = dict.end - groups + 1; } var s = dict.start, e = dict.end; if (first && last && (dict.index > 1 && groups !== 0) && (pages > groups && dict.end < pages && groups !== 0)) { s++; e--; } for (; s <= e; s++) { if (s === curr) { view.push({ text: s, value: s, selected: true }) } else { view.push({ text: s, value: s }) } } //总页数大于连续分页数,且当前组最大页小于总页,输出尾页 if (((!o.dynamicShow && !o.dynamicShowFirstLast) || (pages > groups && dict.end < pages && groups !== 0)) && last) { if (pages > groups && dict.end < pages && groups !== 0) { view.push({ type: "bi.label", cls: "page-ellipsis", text: "\u2026" }); } view.push({ text: last, value: "last", disabled: !(pages > groups && dict.end < pages && groups !== 0) }) } //当前页不为尾页时,输出下一页 dict.flow = !prev && groups === 0; if (((!o.dynamicShow && !o.dynamicShowPrevNext) && next) || (curr !== pages && next || dict.flow)) { view.push((function () { if (BI.isKey(next)) { if (pages === false) { return {text: next, value: "next", disabled: o.hasNext(curr) === false} } return (dict.flow && curr === pages) ? {text: next, value: "next", disabled: true} : {text: next, value: "next", disabled: !(curr !== pages && next || dict.flow)}; } else { return BI.extend({ disabled: pages === false ? o.hasNext(curr) === false : !(curr !== pages && next || dict.flow) }, next); } }())); } this.button_group = BI.createWidget({ type: "bi.button_group", element: this, items: BI.createItems(view, { cls: "page-item bi-border bi-list-item-active", height: 23, hgap: 10 }), behaviors: o.behaviors, layouts: o.layouts }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (self._lock === true) { return; } self._lock = true; self._debouce(); if (type === BI.Events.CLICK) { var v = self.button_group.getValue()[0]; switch (v) { case "first": self.currPage = 1; break; case "last": self.currPage = pages; break; case "prev": self.currPage--; break; case "next": self.currPage++; break; default: self.currPage = v; break; } o.jump.apply(self, [{ pages: pages, curr: self.currPage }]); self._populate(); self.fireEvent(BI.DetailPager.EVENT_CHANGE, obj); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.fireEvent(BI.DetailPager.EVENT_AFTER_POPULATE); }, getCurrentPage: function () { return this.currPage; }, setAllPages: function (pages) { this.options.pages = pages; }, hasPrev: function (v) { v || (v = 1); var o = this.options; var pages = this.options.pages; return pages === false ? o.hasPrev(v) : v > 1; }, hasNext: function (v) { v || (v = 1); var o = this.options; var pages = this.options.pages; return pages === false ? o.hasNext(v) : v < pages; }, setValue: function (v) { var o = this.options; v = v | 0; v = v < 1 ? 1 : v; if (o.pages === false) { var lastPage = BI.result(o, "lastPage"), firstPage = 1; this.currPage = v > lastPage ? lastPage : ((firstPage = BI.result(o, "firstPage")), (v < firstPage ? firstPage : v)); } else { v = v > o.pages ? o.pages : v; this.currPage = v; } this._populate(); }, getValue: function () { var val = this.button_group.getValue()[0]; switch (val) { case "prev": return -1; case "next": return 1; case "first": return BI.MIN; case "last": return BI.MAX; default : return val; } }, attr: function (key, value) { BI.DetailPager.superclass.attr.apply(this, arguments); if (key === "curr") { this.currPage = BI.result(this.options, "curr"); } }, populate: function () { this._populate(); } }); BI.DetailPager.EVENT_CHANGE = "EVENT_CHANGE"; BI.DetailPager.EVENT_AFTER_POPULATE = "EVENT_AFTER_POPULATE"; BI.shortcut("bi.detail_pager", BI.DetailPager);/** * 分段控件使用的button * * Created by GUY on 2015/9/7. * @class BI.SegmentButton * @extends BI.BasicButton */ BI.SegmentButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.SegmentButton.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + ' bi-segment-button bi-list-item-active', shadow: true, readonly: true, hgap: 5 }) }, _init: function () { BI.SegmentButton.superclass._init.apply(this, arguments); var opts = this.options, self = this; //if (BI.isNumber(opts.height) && BI.isNull(opts.lineHeight)) { // this.element.css({lineHeight : (opts.height - 2) + 'px'}); //} this.text = BI.createWidget({ type: "bi.label", element: this, height: opts.height - 2, whiteSpace: opts.whiteSpace, text: opts.text, value: opts.value, hgap: opts.hgap }) }, setSelected: function () { BI.SegmentButton.superclass.setSelected.apply(this, arguments); }, setText: function (text) { BI.SegmentButton.superclass.setText.apply(this, arguments); this.text.setText(text); }, destroy: function () { BI.SegmentButton.superclass.destroy.apply(this, arguments); } }); BI.shortcut('bi.segment_button', BI.SegmentButton);/** * 单选按钮组 * * Created by GUY on 2015/9/7. * @class BI.Segment * @extends BI.Widget */ BI.Segment = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Segment.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-segment", items: [], height: 30 }); }, _init: function () { BI.Segment.superclass._init.apply(this, arguments); var self = this, o = this.options; this.buttonGroup = BI.createWidget({ element: this, type: "bi.button_group", items: BI.createItems(o.items, { type: "bi.segment_button", height: o.height - 2, whiteSpace: o.whiteSpace }), layout: [ { type: "bi.center" } ] }) this.buttonGroup.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments) }); this.buttonGroup.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) { self.fireEvent(BI.Segment.EVENT_CHANGE, value, obj) }) }, setValue: function (v) { this.buttonGroup.setValue(v); }, setEnabledValue: function (v) { this.buttonGroup.setEnabledValue(v); }, getValue: function () { return this.buttonGroup.getValue(); } }); BI.Segment.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.segment', BI.Segment);/** * 自适应宽度的表格 * * Created by GUY on 2016/2/3. * @class BI.AdaptiveTable * @extends BI.Widget */ BI.AdaptiveTable = BI.inherit(BI.Widget, { _const: { perColumnSize: 100 }, _defaultConfig: function () { return BI.extend(BI.AdaptiveTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-adaptive-table", el: { type: "bi.resizable_table" }, isNeedResize: true, isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效 isNeedMerge: false,//是否需要合并单元格 mergeCols: [], //合并的单元格列号 mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, rowSize: 25, regionColumnSize: [], header: [], items: [], //二维数组 //交叉表头 crossHeader: [], crossItems: [] }); }, _init: function () { BI.AdaptiveTable.superclass._init.apply(this, arguments); var self = this, o = this.options; var data = this._digest(); this.table = BI.createWidget(o.el, { type: "bi.resizable_table", element: this, width: o.width, height: o.height, isNeedResize: o.isNeedResize, isResizeAdapt: false, isNeedFreeze: o.isNeedFreeze, freezeCols: data.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: o.mergeRule, columnSize: data.columnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: data.regionColumnSize, header: o.header, items: o.items, //交叉表头 crossHeader: o.crossHeader, crossItems: o.crossItems }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); self._populate(); self.table.populate(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { o.columnSize = this.getColumnSize(); self._populate(); self.table.populate(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); }, _getFreezeColLength: function () { return this.options.isNeedFreeze === true ? this.options.freezeCols.length : 0; }, _digest: function () { var o = this.options; var columnSize = o.columnSize.slice(); var regionColumnSize = o.regionColumnSize.slice(); var freezeCols = o.freezeCols.slice(); var regionSize = o.regionColumnSize[0]; var freezeColLength = this._getFreezeColLength(); if (!regionSize || regionSize > o.width - 10 || regionSize < 10) { regionSize = (freezeColLength > o.columnSize.length / 2 ? 2 / 3 : 1 / 3) * o.width; } if (freezeColLength === 0) { regionSize = 0; } if (freezeCols.length >= columnSize.length) { freezeCols = []; } if (!BI.isNumber(columnSize[0])) { columnSize = o.minColumnSize.slice(); } var summaryFreezeColumnSize = 0, summaryColumnSize = 0; BI.each(columnSize, function (i, size) { if (i < freezeColLength) { summaryFreezeColumnSize += size; } summaryColumnSize += size; }); if (freezeColLength > 0) { columnSize[freezeColLength - 1] = BI.clamp(regionSize - (summaryFreezeColumnSize - columnSize[freezeColLength - 1]), o.minColumnSize[freezeColLength - 1] || 10, o.maxColumnSize[freezeColLength - 1] || Number.MAX_VALUE); } if (columnSize.length > 0) { columnSize[columnSize.length - 1] = BI.clamp(o.width - BI.GridTableScrollbar.SIZE - regionSize - (summaryColumnSize - summaryFreezeColumnSize - columnSize[columnSize.length - 1]), o.minColumnSize[columnSize.length - 1] || 10, o.maxColumnSize[columnSize.length - 1] || Number.MAX_VALUE); } regionColumnSize[0] = regionSize; return { freezeCols: freezeCols, columnSize: columnSize, regionColumnSize: regionColumnSize } }, _populate: function () { var o = this.options; var data = this._digest(); o.regionColumnSize = data.regionColumnSize; o.columnSize = data.columnSize; this.table.setColumnSize(data.columnSize); this.table.setRegionColumnSize(data.regionColumnSize); this.table.attr("freezeCols", data.freezeCols); }, setWidth: function (width) { BI.AdaptiveTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(width); }, setHeight: function (height) { BI.AdaptiveTable.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; }, getColumnSize: function () { return this.table.getColumnSize(); }, setRegionColumnSize: function (regionColumnSize) { this.options.regionColumnSize = regionColumnSize; }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, attr: function (key, value) { var v = BI.AdaptiveTable.superclass.attr.apply(this, arguments); if (key === "freezeCols") { return v; } return this.table.attr.apply(this.table, arguments); }, restore: function () { this.table.restore(); }, populate: function (items) { var self = this, o = this.options; this._populate(); this.table.populate.apply(this.table, arguments); }, destroy: function () { this.table.destroy(); BI.AdaptiveTable.superclass.destroy.apply(this, arguments); } }); BI.shortcut('bi.adaptive_table', BI.AdaptiveTable);/** * * 层级树状结构的表格 * * Created by GUY on 2016/8/12. * @class BI.DynamicSummaryLayerTreeTable * @extends BI.Widget */ BI.DynamicSummaryLayerTreeTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DynamicSummaryLayerTreeTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-dynamic-summary-layer-tree-table", el: { type: "bi.resizable_table" }, isNeedResize: true,//是否需要调整列宽 isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化 isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效 isNeedMerge: true,//是否需要合并单元格 mergeCols: [], mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, footerRowSize: 25, rowSize: 25, regionColumnSize: [], //行表头 rowHeaderCreator: null, headerCellStyleGetter: BI.emptyFn, summaryCellStyleGetter: BI.emptyFn, sequenceCellStyleGetter: BI.emptyFn, header: [], footer: false, items: [], //交叉表头 crossHeader: [], crossItems: [] }) }, _getVDeep: function () { return this.options.crossHeader.length;//纵向深度 }, _getHDeep: function () { var o = this.options; return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1); }, _createHeader: function (vDeep) { var self = this, o = this.options; var header = o.header || [], crossHeader = o.crossHeader || []; var items = BI.TableTree.formatCrossItems(o.crossItems, vDeep, o.headerCellStyleGetter); var result = []; BI.each(items, function (row, node) { var c = [crossHeader[row]]; result.push(c.concat(node || [])); }); if (header && header.length > 0) { var newHeader = this._formatColumns(header); var deep = this._getHDeep(); if (deep <= 0) { newHeader.unshift(o.rowHeaderCreator || { type: "bi.table_style_cell", text: BI.i18nText("BI-Row_Header"), styleGetter: o.headerCellStyleGetter }); } else { newHeader[0] = o.rowHeaderCreator || { type: "bi.table_style_cell", text: BI.i18nText("BI-Row_Header"), styleGetter: o.headerCellStyleGetter }; } result.push(newHeader); } return result; }, _formatItems: function (nodes, header, deep) { var self = this, o = this.options; var result = []; function track(node, layer) { node.type || (node.type = "bi.layer_tree_table_cell"); node.layer = layer; var next = [node]; next = next.concat(node.values || []); if (next.length > 0) { result.push(next); } if (BI.isNotEmptyArray(node.children)) { BI.each(node.children, function (index, child) { track(child, layer + 1); }); } } BI.each(nodes, function (i, node) { BI.each(node.children, function (j, c) { track(c, 0); }); if (BI.isArray(node.values)) { var next = [{ type: "bi.table_style_cell", text: BI.i18nText("BI-Summary_Values"), styleGetter: function () { return o.summaryCellStyleGetter(true); } }].concat(node.values); result.push(next) } }); return BI.DynamicSummaryTreeTable.formatSummaryItems(result, header, o.crossItems, 1); }, _formatColumns: function (columns, deep) { if (BI.isNotEmptyArray(columns)) { deep = deep || this._getHDeep(); return columns.slice(Math.max(0, deep - 1)); } return columns; }, _formatFreezeCols: function () { if (this.options.freezeCols.length > 0) { return [0]; } return []; }, _formatColumnSize: function (columnSize, deep) { if (columnSize.length <= 0) { return []; } var result = [0]; deep = deep || this._getHDeep(); BI.each(columnSize, function (i, size) { if (i < deep) { result[0] += size; return; } result.push(size); }); return result; }, _recomputeColumnSize: function () { var o = this.options; o.regionColumnSize = this.table.getRegionColumnSize(); var columnSize = this.table.getColumnSize().slice(); if (o.freezeCols.length > 1) { for (var i = 0; i < o.freezeCols.length - 1; i++) { columnSize.splice(1, 0, 0); } } o.columnSize = columnSize; }, _digest: function () { var o = this.options; var deep = this._getHDeep(); var vDeep = this._getVDeep(); var header = this._createHeader(vDeep); var data = this._formatItems(o.items, header, deep); var columnSize = o.columnSize.slice(); var minColumnSize = o.minColumnSize.slice(); var maxColumnSize = o.maxColumnSize.slice(); BI.removeAt(columnSize, data.deletedCols); BI.removeAt(minColumnSize, data.deletedCols); BI.removeAt(maxColumnSize, data.deletedCols); return { header: data.header, items: data.items, columnSize: this._formatColumnSize(columnSize, deep), minColumnSize: this._formatColumns(minColumnSize, deep), maxColumnSize: this._formatColumns(maxColumnSize, deep), freezeCols: this._formatFreezeCols() } }, _init: function () { BI.DynamicSummaryLayerTreeTable.superclass._init.apply(this, arguments); var self = this, o = this.options; var data = this._digest(); this.table = BI.createWidget(o.el, { type: "bi.resizable_table", element: this, width: o.width, height: o.height, isNeedResize: o.isNeedResize, isResizeAdapt: o.isResizeAdapt, isNeedFreeze: o.isNeedFreeze, freezeCols: data.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: [], mergeRule: o.mergeRule, columnSize: data.columnSize, minColumnSize: data.minColumnSize, maxColumnSize: data.maxColumnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, header: data.header, items: data.items }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { self._recomputeColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { self._recomputeColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); }, setWidth: function (width) { BI.DynamicSummaryLayerTreeTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(width); }, setHeight: function (height) { BI.DynamicSummaryLayerTreeTable.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; }, getColumnSize: function () { return this.options.columnSize; }, setRegionColumnSize: function (columnSize) { this.options.regionColumnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, attr: function (key, value) { var self = this; if (BI.isObject(key)) { BI.each(key, function (k, v) { self.attr(k, v); }); return; } BI.DynamicSummaryLayerTreeTable.superclass.attr.apply(this, arguments); switch (key) { case "columnSize": case "minColumnSize": case "maxColumnSize": case "freezeCols": case "mergeCols": return; } this.table.attr.apply(this.table, [key, value]); }, restore: function () { this.table.restore(); }, populate: function (items, header, crossItems, crossHeader) { var o = this.options; if (items) { o.items = items; } if (header) { o.header = header; } if (crossItems) { o.crossItems = crossItems; } if (crossHeader) { o.crossHeader = crossHeader; } var data = this._digest(); this.table.setColumnSize(data.columnSize); this.table.attr("minColumnSize", data.minColumnSize); this.table.attr("maxColumnSize", data.maxColumnSize); this.table.attr("freezeCols", data.freezeCols); this.table.populate(data.items, data.header); }, destroy: function () { this.table.destroy(); BI.DynamicSummaryLayerTreeTable.superclass.destroy.apply(this, arguments); } }); BI.shortcut("bi.dynamic_summary_layer_tree_table", BI.DynamicSummaryLayerTreeTable);/** * * 树状结构的表格 * * Created by GUY on 2015/8/12. * @class BI.DynamicSummaryTreeTable * @extends BI.Widget */ BI.DynamicSummaryTreeTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DynamicSummaryTreeTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-dynamic-summary-tree-table", el: { type: "bi.resizable_table" }, isNeedResize: true,//是否需要调整列宽 isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化 isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效 isNeedMerge: true,//是否需要合并单元格 mergeCols: [], mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, footerRowSize: 25, rowSize: 25, regionColumnSize: [], headerCellStyleGetter: BI.emptyFn, summaryCellStyleGetter: BI.emptyFn, sequenceCellStyleGetter: BI.emptyFn, header: [], footer: false, items: [], //交叉表头 crossHeader: [], crossItems: [] }) }, _getVDeep: function () { return this.options.crossHeader.length;//纵向深度 }, _getHDeep: function () { var o = this.options; return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1); }, _init: function () { BI.DynamicSummaryTreeTable.superclass._init.apply(this, arguments); var self = this, o = this.options; var data = this._digest(); this.table = BI.createWidget(o.el, { type: "bi.resizable_table", element: this, width: o.width, height: o.height, isNeedResize: o.isNeedResize, isResizeAdapt: o.isResizeAdapt, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: o.mergeRule, columnSize: o.columnSize, minColumnSize: o.minColumnSize, maxColumnSize: o.maxColumnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, header: data.header, items: data.items }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); var columnSize = this.getColumnSize(); var length = o.columnSize.length - columnSize.length; o.columnSize = columnSize.slice(); o.columnSize = o.columnSize.concat(BI.makeArray(length, 0)); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); var columnSize = this.getColumnSize(); var length = o.columnSize.length - columnSize.length; o.columnSize = columnSize.slice(); o.columnSize = o.columnSize.concat(BI.makeArray(length, 0)); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); }, _digest: function () { var o = this.options; var deep = this._getHDeep(); var vDeep = this._getVDeep(); var header = BI.TableTree.formatHeader(o.header, o.crossHeader, o.crossItems, deep, vDeep, o.headerCellStyleGetter); var items = BI.DynamicSummaryTreeTable.formatHorizontalItems(o.items, deep, false, o.summaryCellStyleGetter); var data = BI.DynamicSummaryTreeTable.formatSummaryItems(items, header, o.crossItems, deep); var columnSize = o.columnSize.slice(); var minColumnSize = o.minColumnSize.slice(); var maxColumnSize = o.maxColumnSize.slice(); BI.removeAt(columnSize, data.deletedCols); BI.removeAt(minColumnSize, data.deletedCols); BI.removeAt(maxColumnSize, data.deletedCols); return { header: data.header, items: data.items, columnSize: columnSize, minColumnSize: minColumnSize, maxColumnSize: maxColumnSize }; }, setWidth: function (width) { BI.DynamicSummaryTreeTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(width); }, setHeight: function (height) { BI.DynamicSummaryTreeTable.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; }, getColumnSize: function () { return this.options.columnSize; }, setRegionColumnSize: function (columnSize) { this.options.regionColumnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, attr: function (key) { BI.DynamicSummaryTreeTable.superclass.attr.apply(this, arguments); switch (key) { case "minColumnSize": case "maxColumnSize": return; } this.table.attr.apply(this.table, arguments); }, restore: function () { this.table.restore(); }, populate: function (items, header, crossItems, crossHeader) { var o = this.options; if (items) { o.items = items; } if (header) { o.header = header; } if (crossItems) { o.crossItems = crossItems; } if (crossHeader) { o.crossHeader = crossHeader; } var data = this._digest(); this.table.setColumnSize(data.columnSize); this.table.attr("minColumnSize", data.minColumnSize); this.table.attr("maxColumnSize", data.maxColumnSize); this.table.populate(data.items, data.header); }, destroy: function () { this.table.destroy(); BI.DynamicSummaryTreeTable.superclass.destroy.apply(this, arguments); } }); BI.extend(BI.DynamicSummaryTreeTable, { formatHorizontalItems: function (nodes, deep, isCross, styleGetter) { var result = []; function track(store, node) { var next; if (BI.isArray(node.children)) { BI.each(node.children, function (index, child) { var next; if (store != -1) { next = store.slice(); next.push(node); } else { next = []; } track(next, child); }); if (store != -1) { next = store.slice(); next.push(node); } else { next = []; } if ((store == -1 || node.children.length > 1) && BI.isNotEmptyArray(node.values)) { var summary = { text: BI.i18nText("BI-Summary_Values"), type: "bi.table_style_cell", styleGetter: function () { return styleGetter(store === -1) } }; for (var i = next.length; i < deep; i++) { next.push(summary); } if (!isCross) { next = next.concat(node.values); } if (next.length > 0) { if (!isCross) { result.push(next); } else { for (var k = 0, l = node.values.length; k < l; k++) { result.push(next); } } } } return; } if (store != -1) { next = store.slice(); for (var i = next.length; i < deep; i++) { next.push(node); } } else { next = []; } if (!isCross && BI.isArray(node.values)) { next = next.concat(node.values); } if (isCross && BI.isArray(node.values)) { for (var i = 0, len = node.values.length; i < len - 1; i++) { if (next.length > 0) { result.push(next); } } } if (next.length > 0) { result.push(next); } } BI.each(nodes, function (i, node) { track(-1, node); }); //填充空位 BI.each(result, function (i, line) { var last = BI.last(line); for (var j = line.length; j < deep; j++) { line.push(last); } }); return result; }, formatSummaryItems: function (items, header, crossItems, deep) { //求纵向需要去除的列 var cols = []; var leaf = 0; function track(node) { if (BI.isArray(node.children)) { BI.each(node.children, function (index, child) { track(child); }); if (BI.isNotEmptyArray(node.values)) { if (node.children.length === 1) { for (var i = 0; i < node.values.length; i++) { cols.push(leaf + i + deep); } } leaf += node.values.length; } return; } if (node.values && node.values.length > 1) { leaf += node.values.length; } else { leaf++; } } BI.each(crossItems, function (i, node) { track(node); }); if (cols.length > 0) { var nHeader = [], nItems = []; BI.each(header, function (i, node) { var nNode = node.slice(); BI.removeAt(nNode, cols); nHeader.push(nNode); }); BI.each(items, function (i, node) { var nNode = node.slice(); BI.removeAt(nNode, cols); nItems.push(nNode);; }); header = nHeader; items = nItems; } return {items: items, header: header, deletedCols: cols}; } }); BI.shortcut("bi.dynamic_summary_tree_table", BI.DynamicSummaryTreeTable);/** * * 层级树状结构的表格 * * Created by GUY on 2016/5/7. * @class BI.LayerTreeTable * @extends BI.Widget */ BI.LayerTreeTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.LayerTreeTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-layer-tree-table", el: { type: "bi.resizable_table" }, isNeedResize: false,//是否需要调整列宽 isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化 isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效 isNeedMerge: true,//是否需要合并单元格 mergeCols: [], mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, rowSize: 25, regionColumnSize: [], rowHeaderCreator: null, headerCellStyleGetter: BI.emptyFn, summaryCellStyleGetter: BI.emptyFn, sequenceCellStyleGetter: BI.emptyFn, header: [], items: [], //交叉表头 crossHeader: [], crossItems: [] }) }, _getVDeep: function () { return this.options.crossHeader.length;//纵向深度 }, _getHDeep: function () { var o = this.options; return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1); }, _createHeader: function (vDeep) { var self = this, o = this.options; var header = o.header || [], crossHeader = o.crossHeader || []; var items = BI.TableTree.formatCrossItems(o.crossItems, vDeep, o.headerCellStyleGetter); var result = []; BI.each(items, function (row, node) { var c = [crossHeader[row]]; result.push(c.concat(node || [])); }); if (header && header.length > 0) { var newHeader = this._formatColumns(header); var deep = this._getHDeep(); if (deep <= 0) { newHeader.unshift(o.rowHeaderCreator || { type: "bi.table_style_cell", text: BI.i18nText("BI-Row_Header"), styleGetter: o.headerCellStyleGetter }); } else { newHeader[0] = o.rowHeaderCreator || { type: "bi.table_style_cell", text: BI.i18nText("BI-Row_Header"), styleGetter: o.headerCellStyleGetter }; } result.push(newHeader); } return result; }, _formatItems: function (nodes) { var self = this, o = this.options; var result = []; function track(node, layer) { node.type || (node.type = "bi.layer_tree_table_cell"); node.layer = layer; var next = [node]; next = next.concat(node.values || []); if (next.length > 0) { result.push(next); } if (BI.isNotEmptyArray(node.children)) { BI.each(node.children, function (index, child) { track(child, layer + 1); }); } } BI.each(nodes, function (i, node) { BI.each(node.children, function (j, c) { track(c, 0); }); if (BI.isArray(node.values)) { var next = [{ type: "bi.table_style_cell", text: BI.i18nText("BI-Summary_Values"), styleGetter: function () { return o.summaryCellStyleGetter(true); } }].concat(node.values); result.push(next) } }); return result; }, _formatColumns: function (columns, deep) { if (BI.isNotEmptyArray(columns)) { deep = deep || this._getHDeep(); return columns.slice(Math.max(0, deep - 1)); } return columns; }, _formatFreezeCols: function () { if (this.options.freezeCols.length > 0) { return [0]; } return []; }, _formatColumnSize: function (columnSize, deep) { if (columnSize.length <= 0) { return []; } var result = [0]; deep = deep || this._getHDeep(); BI.each(columnSize, function (i, size) { if (i < deep) { result[0] += size; return; } result.push(size); }); return result; }, _digest: function () { var o = this.options; var deep = this._getHDeep(); var vDeep = this._getVDeep(); return { header: this._createHeader(vDeep), items: this._formatItems(o.items), columnSize: this._formatColumnSize(o.columnSize, deep), minColumnSize: this._formatColumns(o.minColumnSize, deep), maxColumnSize: this._formatColumns(o.maxColumnSize, deep), freezeCols: this._formatFreezeCols() } }, _init: function () { BI.LayerTreeTable.superclass._init.apply(this, arguments); var self = this, o = this.options; var data = this._digest(); this.table = BI.createWidget(o.el, { type: "bi.resizable_table", element: this, width: o.width, height: o.height, isNeedResize: o.isNeedResize, isResizeAdapt: o.isResizeAdapt, isNeedFreeze: o.isNeedFreeze, freezeCols: data.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: [], mergeRule: o.mergeRule, columnSize: data.columnSize, minColumnSize: data.minColumnSize, maxColumnSize: data.maxColumnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, header: data.header, items: data.items }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); }, setWidth: function (width) { BI.LayerTreeTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(width); }, setHeight: function (height) { BI.LayerTreeTable.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; }, getColumnSize: function () { var columnSize = this.table.getColumnSize(); var deep = this._getHDeep(); var pre = []; if (deep > 0) { pre = BI.makeArray(deep, columnSize[0] / deep); } return pre.concat(columnSize.slice(1)); }, setRegionColumnSize: function (columnSize) { this.options.regionColumnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, attr: function (key, value) { var self = this; if (BI.isObject(key)) { BI.each(key, function (k, v) { self.attr(k, v); }); return; } BI.LayerTreeTable.superclass.attr.apply(this, arguments); switch (key) { case "columnSize": case "minColumnSize": case "maxColumnSize": case "freezeCols": case "mergeCols": return; } this.table.attr.apply(this.table, [key, value]); }, restore: function () { this.table.restore(); }, populate: function (items, header, crossItems, crossHeader) { var o = this.options; o.items = items || []; if (header) { o.header = header; } if (crossItems) { o.crossItems = crossItems; } if (crossHeader) { o.crossHeader = crossHeader; } var data = this._digest(); this.table.setColumnSize(data.columnSize); this.table.attr("freezeCols", data.freezeCols); this.table.attr("minColumnSize", data.minColumnSize); this.table.attr("maxColumnSize", data.maxColumnSize); this.table.populate(data.items, data.header); }, destroy: function () { this.table.destroy(); BI.LayerTreeTable.superclass.destroy.apply(this, arguments); } }); BI.shortcut("bi.layer_tree_table", BI.LayerTreeTable);/** * * Created by GUY on 2016/5/26. * @class BI.TableStyleCell * @extends BI.Single */ BI.TableStyleCell = BI.inherit(BI.Single, { _defaultConfig: function () { return BI.extend(BI.TableStyleCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-table-style-cell", styleGetter: BI.emptyFn }); }, _init: function () { BI.TableStyleCell.superclass._init.apply(this, arguments); var o = this.options; this.text = BI.createWidget({ type: "bi.label", element: this, textAlign: "left", forceCenter: true, hgap: 5, text: o.text }); this._digestStyle(); }, _digestStyle: function () { var o = this.options; var style = o.styleGetter(); if (style) { this.text.element.css(style); } }, setText: function (text) { this.text.setText(text); }, populate: function () { this._digestStyle(); } }); BI.shortcut('bi.table_style_cell', BI.TableStyleCell);/** * * 树状结构的表格 * * Created by GUY on 2015/9/22. * @class BI.TableTree * @extends BI.Widget */ BI.TableTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.TableTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-table-tree", el: { type: "bi.resizable_table" }, isNeedResize: true,//是否需要调整列宽 isResizeAdapt: true,//是否需要在调整列宽或区域宽度的时候它们自适应变化 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为tree时生效 isNeedMerge: true,//是否需要合并单元格 mergeCols: [], mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, rowSize: 25, regionColumnSize: [], headerCellStyleGetter: BI.emptyFn, summaryCellStyleGetter: BI.emptyFn, sequenceCellStyleGetter: BI.emptyFn, header: [], items: [], //交叉表头 crossHeader: [], crossItems: [] }) }, _getVDeep: function () { return this.options.crossHeader.length;//纵向深度 }, _getHDeep: function () { var o = this.options; return Math.max(o.mergeCols.length, o.freezeCols.length, BI.TableTree.maxDeep(o.items) - 1); }, _init: function () { BI.TableTree.superclass._init.apply(this, arguments); var self = this, o = this.options; var data = this._digest(); this.table = BI.createWidget(o.el, { type: "bi.resizable_table", element: this, width: o.width, height: o.height, isNeedResize: o.isNeedResize, isResizeAdapt: o.isResizeAdapt, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: o.mergeRule, columnSize: o.columnSize, minColumnSize: o.minColumnSize, maxColumnSize: o.maxColumnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, header: data.header, items: data.items }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); }, _digest: function () { var self = this, o = this.options; var deep = this._getHDeep(); var vDeep = this._getVDeep(); var header = BI.TableTree.formatHeader(o.header, o.crossHeader, o.crossItems, deep, vDeep, o.headerCellStyleGetter); var items = BI.TableTree.formatItems(o.items, deep, false, o.summaryCellStyleGetter); return { header: header, items: items } }, setWidth: function (width) { BI.TableTree.superclass.setWidth.apply(this, arguments); this.table.setWidth(width); }, setHeight: function (height) { BI.TableTree.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; this.table.setColumnSize(columnSize); }, getColumnSize: function () { return this.table.getColumnSize(); }, setRegionColumnSize: function (columnSize) { this.options.regionColumnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, attr: function () { BI.TableTree.superclass.attr.apply(this, arguments); this.table.attr.apply(this.table, arguments); }, restore: function () { this.table.restore(); }, populate: function (items, header, crossItems, crossHeader) { var o = this.options; if (items) { o.items = items || []; } if (header) { o.header = header; } if (crossItems) { o.crossItems = crossItems; } if (crossHeader) { o.crossHeader = crossHeader; } var data = this._digest(); this.table.populate(data.items, data.header); }, destroy: function () { this.table.destroy(); BI.TableTree.superclass.destroy.apply(this, arguments); } }); BI.extend(BI.TableTree, { formatHeader: function (header, crossHeader, crossItems, hDeep, vDeep, styleGetter) { var items = BI.TableTree.formatCrossItems(crossItems, vDeep, styleGetter); var result = []; for (var i = 0; i < vDeep; i++) { var c = []; for (var j = 0; j < hDeep; j++) { c.push(crossHeader[i]); } result.push(c.concat(items[i] || [])); } if (header && header.length > 0) { result.push(header); } return result; }, formatItems: function (nodes, deep, isCross, styleGetter) { var self = this; var result = []; function track(store, node) { var next; if (BI.isArray(node.children)) { BI.each(node.children, function (index, child) { var next; if (store != -1) { next = store.slice(); next.push(node); } else { next = []; } track(next, child); }); if (store != -1) { next = store.slice(); next.push(node); } else { next = []; } if (/**(store == -1 || node.children.length > 1) &&**/ BI.isNotEmptyArray(node.values)) { var summary = { text: BI.i18nText("BI-Summary_Values"), type: "bi.table_style_cell", styleGetter: function () { return styleGetter(store === -1) } }; for (var i = next.length; i < deep; i++) { next.push(summary); } if (!isCross) { next = next.concat(node.values); } if (next.length > 0) { if (!isCross) { result.push(next); } else { for (var k = 0, l = node.values.length; k < l; k++) { result.push(next); } } } } return; } if (store != -1) { next = store.slice(); for (var i = next.length; i < deep; i++) { next.push(node); } } else { next = []; } if (!isCross && BI.isArray(node.values)) { next = next.concat(node.values); } if (isCross && BI.isArray(node.values)) { for (var i = 0, len = node.values.length; i < len - 1; i++) { if (next.length > 0) { result.push(next); } } } if (next.length > 0) { result.push(next); } } BI.each(nodes, function (i, node) { track(-1, node); }); //填充空位 BI.each(result, function (i, line) { var last = BI.last(line); for (var j = line.length; j < deep; j++) { line.push(last); } }); return result; }, formatCrossItems: function (nodes, deep, styleGetter) { var items = BI.TableTree.formatItems(nodes, deep, true, styleGetter); return BI.unzip(items); }, maxDeep: function (nodes) { function track(deep, node) { var d = deep; if (BI.isNotEmptyArray(node.children)) { BI.each(node.children, function (index, child) { d = Math.max(d, track(deep + 1, child)); }); } return d; } var deep = 1; if (BI.isObject(nodes)) { BI.each(nodes, function (i, node) { deep = Math.max(deep, track(1, node)); }); } return deep; } }); BI.shortcut("bi.tree_table", BI.TableTree);/** * guy * 复选导航条 * Created by GUY on 2015/8/25. * @class BI.MultiSelectBar * @extends BI.BasicButton */ BI.MultiSelectBar = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MultiSelectBar.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-multi-select-bar", height: 25, text: BI.i18nText('BI-Select_All'), isAllCheckedBySelectedValue: BI.emptyFn, //手动控制选中 disableSelected: true, isHalfCheckedBySelectedValue: function (selectedValues) { return selectedValues.length > 0; } }) }, _init: function () { BI.MultiSelectBar.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.checkbox", stopPropagation: true, handler: function () { self.setSelected(self.isSelected()); } }); this.half = BI.createWidget({ type: "bi.half_icon_button", stopPropagation: true, handler: function () { self.setSelected(true); } }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, self.isSelected(), self); }); this.half.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CLICK, self.isSelected(), self); }); this.half.on(BI.HalfIconButton.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectBar.EVENT_CHANGE, self.isSelected(), self); }); this.checkbox.on(BI.Checkbox.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectBar.EVENT_CHANGE, self.isSelected(), self); }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, keyword: o.keyword, value: o.value, py: o.py }); BI.createWidget({ type: "bi.htape", element: this, items: [{ width: 36, el: { type: "bi.center_adapt", items: [this.checkbox, this.half] } }, { el: this.text }] }); this.half.invisible(); }, //自己手动控制选中 beforeClick: function () { var isHalf = this.isHalfSelected(), isSelected = this.isSelected(); if (isHalf === true) { this.setSelected(true); } else { this.setSelected(!isSelected); } }, setSelected: function (v) { this.checkbox.setSelected(v); this.setHalfSelected(false); }, setHalfSelected: function (b) { this._half = !!b; if (b === true) { this.half.visible(); this.checkbox.invisible(); } else { this.half.invisible(); this.checkbox.visible(); } }, isHalfSelected: function () { return !!this._half; }, isSelected: function () { return this.checkbox.isSelected(); }, setValue: function (selectedValues) { BI.MultiSelectBar.superclass.setValue.apply(this, arguments); var isAllChecked = this.options.isAllCheckedBySelectedValue.apply(this, arguments); this.setSelected(isAllChecked); !isAllChecked && this.setHalfSelected(this.options.isHalfCheckedBySelectedValue.apply(this, arguments)); } }); BI.MultiSelectBar.EVENT_CHANGE = "MultiSelectBar.EVENT_CHANGE"; BI.shortcut("bi.multi_select_bar", BI.MultiSelectBar);/** * 倒立的Branch * @class BI.HandStandBranchExpander * @extend BI.Widget * create by young */ BI.HandStandBranchExpander = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.HandStandBranchExpander.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-handstand-branch-expander", direction: BI.Direction.Top, logic: { dynamic: true }, el: {type: "bi.label"}, popup: {} }) }, _init: function () { BI.HandStandBranchExpander.superclass._init.apply(this, arguments); var o = this.options; this._initExpander(); this._initBranchView(); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, { type: "bi.center_adapt", items: [this.expander] }, this.branchView) })))); }, _initExpander: function () { var self = this, o = this.options; this.expander = BI.createWidget(o.el); this.expander.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, _initBranchView: function () { var self = this, o = this.options; this.branchView = BI.createWidget(o.popup, {}); this.branchView.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, populate: function (items) { this.branchView.populate.apply(this.branchView, arguments); }, getValue: function () { return this.branchView.getValue(); } }); BI.HandStandBranchExpander.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.handstand_branch_expander", BI.HandStandBranchExpander);/** * @class BI.BranchExpander * @extend BI.Widget * create by young */ BI.BranchExpander = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.BranchExpander.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-branch-expander", direction: BI.Direction.Left, logic: { dynamic: true }, el: {}, popup: {} }) }, _init: function () { BI.BranchExpander.superclass._init.apply(this, arguments); var o = this.options; this._initExpander(); this._initBranchView(); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.expander, this.branchView) })))); }, _initExpander: function () { var self = this, o = this.options; this.expander = BI.createWidget(o.el, { type: "bi.label", width: 30, height: "100%" }); this.expander.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, _initBranchView: function () { var self = this, o = this.options; this.branchView = BI.createWidget(o.popup, {}); this.branchView.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, populate: function (items) { this.branchView.populate.apply(this.branchView, arguments); }, getValue: function () { return this.branchView.getValue(); } }); BI.BranchExpander.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.branch_expander", BI.BranchExpander);/** * @class BI.HandStandBranchTree * @extends BI.Widget * create by young * 横向分支的树 */ BI.HandStandBranchTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.HandStandBranchTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-handstand-branch-tree", expander: {}, el: {}, items: [] }) }, _init: function () { BI.HandStandBranchTree.superclass._init.apply(this, arguments); var self = this, o = this.options; this.branchTree = BI.createWidget({ type: "bi.custom_tree", element: this, expander: BI.extend({ type: "bi.handstand_branch_expander", el: {}, popup: { type: "bi.custom_tree" } }, o.expander), el: BI.extend({ type: "bi.button_tree", chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI, layouts: [{ type: "bi.horizontal_adapt" }] }, o.el), items: this.options.items }); this.branchTree.on(BI.CustomTree.EVENT_CHANGE, function(){ self.fireEvent(BI.HandStandBranchTree.EVENT_CHANGE, arguments); }); this.branchTree.on(BI.Controller.EVENT_CHANGE, function(){ self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, populate: function () { this.branchTree.populate.apply(this.branchTree, arguments); }, getValue: function () { return this.branchTree.getValue(); } }); BI.HandStandBranchTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.handstand_branch_tree", BI.HandStandBranchTree);/** * @class BI.BranchTree * @extends BI.Widget * create by young * 横向分支的树 */ BI.BranchTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.BranchTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-branch-tree", expander: {}, el: {}, items: [] }) }, _init: function () { BI.BranchTree.superclass._init.apply(this, arguments); var self = this, o = this.options; this.branchTree = BI.createWidget({ type: "bi.custom_tree", element: this, expander: BI.extend({ type: "bi.branch_expander", el: {}, popup: { type: "bi.custom_tree" } }, o.expander), el: BI.extend({ type: "bi.button_tree", chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI, layouts: [{ type: "bi.vertical" }] }, o.el), items: this.options.items }); this.branchTree.on(BI.CustomTree.EVENT_CHANGE, function(){ self.fireEvent(BI.BranchTree.EVENT_CHANGE, arguments); }); this.branchTree.on(BI.Controller.EVENT_CHANGE, function(){ self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, populate: function () { this.branchTree.populate.apply(this.branchTree, arguments); }, getValue: function () { return this.branchTree.getValue(); } }); BI.BranchTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.branch_tree", BI.BranchTree);/** * guy * 异步树 * @class BI.DisplayTree * @extends BI.TreeView */ BI.DisplayTree = BI.inherit(BI.TreeView, { _defaultConfig: function () { return BI.extend(BI.DisplayTree.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-display-tree" }) }, _init: function () { BI.DisplayTree.superclass._init.apply(this, arguments); }, //配置属性 _configSetting: function () { var setting = { view: { selectedMulti: false, dblClickExpand: false, showIcon: false, showTitle: false }, data: { key: { title: "title", name: "text" }, simpleData: { enable: true } }, callback: { beforeCollapse: beforeCollapse } }; function beforeCollapse(treeId, treeNode) { return false; } return setting; }, _dealWidthNodes: function (nodes) { nodes = BI.DisplayTree.superclass._dealWidthNodes.apply(this, arguments); var self = this, o = this.options; BI.each(nodes, function (i, node) { if (node.count > 0) { node.text = node.value + "(" + BI.i18nText("BI-Basic_Altogether") + node.count + BI.i18nText("BI-Basic_Count") + ")"; } else { node.text = node.value; } }); return nodes; }, initTree: function (nodes, setting) { var setting = setting || this._configSetting(); this.nodes = $.fn.zTree.init(this.tree.element, setting, nodes); }, destroy: function () { BI.DisplayTree.superclass.destroy.apply(this, arguments); } }); BI.DisplayTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.display_tree", BI.DisplayTree);/** * guy * 二级树 * @class BI.LevelTree * @extends BI.Single */ BI.LevelTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.LevelTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-level-tree", el: { chooseType: 0 }, expander: {}, items: [] }) }, _init: function () { BI.LevelTree.superclass._init.apply(this, arguments); this.initTree(this.options.items); }, _formatItems: function (nodes, layer) { var self = this; BI.each(nodes, function (i, node) { var extend = {layer: layer}; if (!BI.isKey(node.id)) { node.id = BI.UUID(); } if (node.isParent === true || BI.isNotEmptyArray(node.children)) { switch (i) { case 0 : extend.type = "bi.first_plus_group_node"; break; case nodes.length - 1 : extend.type = "bi.last_plus_group_node"; break; default : extend.type = "bi.mid_plus_group_node"; break; } BI.defaults(node, extend); self._formatItems(node.children, layer + 1); } else { switch (i) { case nodes.length - 1: extend.type = "bi.last_tree_leaf_item"; break; default : extend.type = "bi.mid_tree_leaf_item"; } BI.defaults(node, extend); } }); return nodes; }, _assertId: function (sNodes) { BI.each(sNodes, function (i, node) { if (!BI.isKey(node.id)) { node.id = BI.UUID(); } }); }, //构造树结构, initTree: function (nodes) { var self = this, o = this.options; this.empty(); this._assertId(nodes); this.tree = BI.createWidget({ type: "bi.custom_tree", element: this, expander: BI.extend({ el: {}, popup: { type: "bi.custom_tree" } }, o.expander), items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0), el: BI.extend({ type: "bi.button_tree", chooseType: 0, layouts: [{ type: "bi.vertical" }] }, o.el) }); this.tree.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.LevelTree.EVENT_CHANGE, arguments); } }) }, //生成树方法 stroke: function (nodes) { this.tree.stroke.apply(this.tree, arguments); }, populate: function (items) { items = this._formatItems(BI.Tree.transformToTreeFormat(items), 0); this.tree.populate(items); }, setValue: function (v) { this.tree.setValue(v); }, getValue: function () { return this.tree.getValue(); }, getAllLeaves: function () { return this.tree.getAllLeaves(); }, getNodeById: function (id) { return this.tree.getNodeById(id); }, getNodeByValue: function (id) { return this.tree.getNodeByValue(id); } }); BI.LevelTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.level_tree", BI.LevelTree);/** * 简单的多选树 * * Created by GUY on 2016/2/16. * @class BI.SimpleTreeView * @extends BI.Widget */ BI.SimpleTreeView = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SimpleTreeView.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-simple-tree", itemsCreator: BI.emptyFn, items: null }) }, _init: function () { BI.SimpleTreeView.superclass._init.apply(this, arguments); var self = this, o = this.options; this.structure = new BI.Tree(); this.tree = BI.createWidget({ type: "bi.tree_view", element: this, itemsCreator: function (op, callback) { var fn = function (items) { callback({ items: items }); self.structure.initTree(BI.Tree.transformToTreeFormat(items)); }; if (BI.isNotNull(o.items)) { fn(o.items); } else { o.itemsCreator(op, fn); } } }); this.tree.on(BI.TreeView.EVENT_CHANGE, function () { self.fireEvent(BI.SimpleTreeView.EVENT_CHANGE, arguments); }); if (BI.isNotEmptyArray(o.items)) { this.populate(); } }, populate: function (items, keyword) { if (items) { this.options.items = items; } this.tree.stroke({ keyword: keyword }); }, setValue: function (v) { v || (v = []); var self = this, map = {}; var selected = []; BI.each(v, function (i, val) { var node = self.structure.search(val, "value"); if (node) { var p = node; p = p.getParent(); if (p) { if (!map[p.value]) { map[p.value] = 0; } map[p.value]++; } while (p && p.getChildrenLength() <= map[p.value]) { selected.push(p.value); p = p.getParent(); if (p) { if (!map[p.value]) { map[p.value] = 0; } map[p.value]++; } } } }); this.tree.setValue(BI.makeObject(v.concat(selected))); }, _getValue: function () { var self = this, result = [], val = this.tree.getValue(); var track = function (nodes) { BI.each(nodes, function (key, node) { if (BI.isEmpty(node)) { result.push(key); } else { track(node); } }) }; track(val); return result; }, empty: function () { this.tree.empty(); }, getValue: function () { var self = this, result = [], val = this._getValue(); BI.each(val, function (i, key) { var target = self.structure.search(key, "value"); if (target) { self.structure._traverse(target, function (node) { if (node.isLeaf()) { result.push(node.value); } }) } }); return result; } }); BI.SimpleTreeView.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.simple_tree", BI.SimpleTreeView); /** * 文本输入框trigger * * Created by GUY on 2015/9/15. * @class BI.EditorTrigger * @extends BI.Trigger */ BI.EditorTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4 }, _defaultConfig: function () { var conf = BI.EditorTrigger.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-editor-trigger bi-border", height: 30, validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, allowBlank: false, watermark: "", errorText: "", triggerWidth: 30 }); }, _init: function () { this.options.height -= 2; BI.EditorTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.editor = BI.createWidget({ type: "bi.sign_editor", height: o.height, value: o.value, validationChecker: o.validationChecker, quitChecker: o.quitChecker, mouseOut: false, allowBlank: o.allowBlank, watermark: o.watermark, errorText: o.errorText }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.SignEditor.EVENT_CHANGE, function () { self.fireEvent(BI.EditorTrigger.EVENT_CHANGE, arguments); }); BI.createWidget({ element: this, type: 'bi.htape', items: [ { el: this.editor }, { el: { type: "bi.trigger_icon_button", cls: "bi-border-left", width: o.triggerWidth }, width: o.triggerWidth } ] }); }, getValue: function () { return this.editor.getValue(); }, setValue: function (value) { this.editor.setValue(value); }, setText: function (text) { this.editor.setState(text); } }); BI.EditorTrigger.EVENT_CHANGE = "BI.EditorTrigger.EVENT_CHANGE"; BI.shortcut("bi.editor_trigger", BI.EditorTrigger);/** * 图标按钮trigger * * Created by GUY on 2015/10/8. * @class BI.IconTrigger * @extends BI.Trigger */ BI.IconTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { return BI.extend(BI.IconTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-icon-trigger", el: {}, height: 30 }); }, _init: function () { var o = this.options; BI.IconTrigger.superclass._init.apply(this, arguments); this.iconButton = BI.createWidget(o.el, { type: "bi.trigger_icon_button", element: this, width: o.width, height: o.height }); } }); BI.shortcut('bi.icon_trigger', BI.IconTrigger);/** * 文字trigger * * Created by GUY on 2015/9/15. * @class BI.TextTrigger * @extends BI.Trigger */ BI.TextTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, triggerWidth: 30 }, _defaultConfig: function () { var conf = BI.TextTrigger.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-trigger", height: 30 }); }, _init: function () { BI.TextTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", height: o.height, text: o.text, hgap: c.hgap }); this.trigerButton = BI.createWidget({ type: "bi.trigger_icon_button", cls: "bi-border-left", width: c.triggerWidth }); BI.createWidget({ element: this, type: 'bi.htape', items: [ { el: this.text }, { el: this.trigerButton, width: c.triggerWidth } ] }); }, setValue: function (value) { this.text.setValue(value); this.text.setTitle(value); }, setText: function (text) { this.text.setText(text); this.text.setTitle(text); } }); BI.shortcut("bi.text_trigger", BI.TextTrigger);/** * 选择字段trigger * * Created by GUY on 2015/9/15. * @class BI.SelectTextTrigger * @extends BI.Trigger */ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { return BI.extend(BI.SelectTextTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-select-text-trigger bi-border", height: 24 }); }, _init: function () { this.options.height -= 2; BI.SelectTextTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.text_trigger", element: this, height: o.height }); if (BI.isKey(o.text)) { this.setValue(o.text); } }, setValue: function (vals) { var o = this.options; vals = BI.isArray(vals) ? vals : [vals]; var result = []; var items = BI.Tree.transformToArrayFormat(this.options.items); BI.each(items, function (i, item) { if (BI.deepContains(vals, item.value) && !result.contains(item.text || item.value)) { result.push(item.text || item.value); } }); if (result.length > 0) { this.trigger.setText(result.join(",")); } else { this.trigger.setText(o.text); } }, populate: function (items) { this.options.items = items; } }); BI.shortcut("bi.select_text_trigger", BI.SelectTextTrigger);/** * 选择字段trigger小一号的 * * @class BI.SmallSelectTextTrigger * @extends BI.Trigger */ BI.SmallSelectTextTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { return BI.extend(BI.SmallSelectTextTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-small-select-text-trigger bi-border", height: 20 }); }, _init: function () { this.options.height -= 2; BI.SmallSelectTextTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.small_text_trigger", element: this, height: o.height - 2 }); if (BI.isKey(o.text)) { this.setValue(o.text); } }, setValue: function (vals) { var o = this.options; vals = BI.isArray(vals) ? vals : [vals]; var result = []; var items = BI.Tree.transformToArrayFormat(this.options.items); BI.each(items, function (i, item) { if (BI.deepContains(vals, item.value) && !result.contains(item.text || item.value)) { result.push(item.text || item.value); } }); if (result.length > 0) { this.trigger.element.removeClass("bi-water-mark"); this.trigger.setText(result.join(",")); } else { this.trigger.element.addClass("bi-water-mark"); this.trigger.setText(o.text); } }, populate: function (items) { this.options.items = items; } }); BI.shortcut("bi.small_select_text_trigger", BI.SmallSelectTextTrigger);/** * 文字trigger(右边小三角小一号的) == * * @class BI.SmallTextTrigger * @extends BI.Trigger */ BI.SmallTextTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, triggerWidth: 20 }, _defaultConfig: function () { var conf = BI.SmallTextTrigger.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-trigger", height: 20 }); }, _init: function () { BI.SmallTextTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", height: o.height, text: o.text, hgap: c.hgap }); this.trigerButton = BI.createWidget({ type: "bi.trigger_icon_button", width: c.triggerWidth }); BI.createWidget({ element: this, type: 'bi.htape', items: [ { el: this.text }, { el: this.trigerButton, width: c.triggerWidth } ] }); }, setValue: function (value) { this.text.setValue(value); }, setText: function (text) { this.text.setText(text); } }); BI.shortcut("bi.small_text_trigger", BI.SmallTextTrigger);/** * * Created by GUY on 2016/5/26. * @class BI.SequenceTableTreeNumber * @extends BI.Widget */ BI.SequenceTableTreeNumber = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SequenceTableTreeNumber.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-sequence-table-tree-number", isNeedFreeze: false, startSequence: 1,//开始的序号 scrollTop: 0, headerRowSize: 25, rowSize: 25, sequenceHeaderCreator: null, header: [], items: [], //二维数组 //交叉表头 crossHeader: [], crossItems: [] }); }, _init: function () { BI.SequenceTableTreeNumber.superclass._init.apply(this, arguments); var self = this, o = this.options; this.vCurr = 1; this.hCurr = 1; this.tasks = []; this.renderedCells = []; this.renderedKeys = []; this.container = BI.createWidget({ type: "bi.absolute", width: 60, scrollable: false }); this.scrollContainer = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.container] }); this.headerContainer = BI.createWidget({ type: "bi.absolute", cls: "bi-border", width: 58, scrollable: false }); this.layout = BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: this.headerContainer, height: this._getHeaderHeight() - 2 }, {el: {type: "bi.layout"}, height: 2}, { el: this.scrollContainer }] }); //缓存第一行对应的序号 this.start = this.options.startSequence; this.cache = {}; this._nextState(); this._populate(); }, _getNextSequence: function (nodes) { var self = this; var start = this.start; var cnt = this.start; function track(node) { //如果已经有缓存了就不改计数了,复杂表会出现这种情况 self.cache[node.text || node.value] || (self.cache[node.text || node.value] = cnt); cnt++; } BI.each(nodes, function (i, node) { if (BI.isNotEmptyArray(node.children)) { BI.each(node.children, function (index, child) { if (index === 0) { if (self.cache[child.text || child.value]) { start = cnt = self.cache[child.text || child.value]; } } track(child) }); } }); this.start = cnt; return start; }, _getStart: function (nodes) { var self = this; var start = this.start; BI.some(nodes, function (i, node) { if (BI.isNotEmptyArray(node.children)) { return BI.some(node.children, function (index, child) { if (index === 0) { if (self.cache[child.text || child.value]) { start = self.cache[child.text || child.value]; return true; } } }); } }); return start; }, _formatNumber: function (nodes) { var self = this, o = this.options; var result = []; var count = this._getStart(nodes); function getLeafCount(node) { var cnt = 0; if (BI.isNotEmptyArray(node.children)) { BI.each(node.children, function (index, child) { cnt += getLeafCount(child); }); if (/**node.children.length > 1 && **/BI.isNotEmptyArray(node.values)) { cnt++; } } else { cnt++; } return cnt; } var start = 0, top = 0; BI.each(nodes, function (i, node) { if (BI.isArray(node.children)) { BI.each(node.children, function (index, child) { var cnt = getLeafCount(child); result.push({ text: count++, start: start, top: top, cnt: cnt, index: index, height: cnt * o.rowSize }); start += cnt; top += cnt * o.rowSize; }); if (BI.isNotEmptyArray(node.values)) { result.push({ text: BI.i18nText("BI-Summary_Values"), start: start++, top: top, cnt: 1, isSummary: true, height: o.rowSize }); top += o.rowSize; } } }); return result; }, _layout: function () { var self = this, o = this.options; var headerHeight = this._getHeaderHeight() - 2; var items = this.layout.attr("items"); if (o.isNeedFreeze === false) { items[0].height = 0; items[1].height = 0; } else if (o.isNeedFreeze === true) { items[0].height = headerHeight; items[1].height = 2; } this.layout.attr("items", items); this.layout.resize(); try { this.scrollContainer.element.scrollTop(o.scrollTop); } catch (e) { } }, _getHeaderHeight: function () { var o = this.options; return o.headerRowSize * (o.crossHeader.length + (o.header.length > 0 ? 1 : 0)); }, _nextState: function () { var o = this.options; this._getNextSequence(o.items); }, _prevState: function () { var self = this, o = this.options; var firstChild; BI.some(o.items, function (i, node) { if (BI.isNotEmptyArray(node.children)) { return BI.some(node.children, function (j, child) { firstChild = child; return true; }); } }); if (firstChild && BI.isNotEmptyObject(this.cache)) { this.start = this.cache[firstChild.text || firstChild.value]; } else { this.start = 1; } this._nextState(); }, _getMaxScrollTop: function (numbers) { var cnt = 0; BI.each(numbers, function (i, number) { cnt += number.cnt; }); return Math.max(0, cnt * this.options.rowSize - (this.options.height - this._getHeaderHeight()) + BI.DOM.getScrollWidth()); }, _createHeader: function () { var o = this.options; BI.createWidget({ type: "bi.absolute", element: this.headerContainer, items: [{ el: o.sequenceHeaderCreator || { type: "bi.table_style_cell", cls: "sequence-table-title-cell", styleGetter: o.headerCellStyleGetter, text: BI.i18nText("BI-Number_Index") }, left: 0, top: 0, right: 0, bottom: 0 }] }); }, _calculateChildrenToRender: function () { var self = this, o = this.options; var renderedCells = [], renderedKeys = []; var numbers = this._formatNumber(o.items); var intervalTree = BI.PrefixIntervalTree.uniform(numbers.length, 0); BI.each(numbers, function (i, number) { intervalTree.set(i, number.height); }); var scrollTop = BI.clamp(o.scrollTop, 0, this._getMaxScrollTop(numbers)); var index = intervalTree.greatestLowerBound(scrollTop); var offsetTop = -(scrollTop - (index > 0 ? intervalTree.sumTo(index - 1) : 0)); var height = offsetTop; var bodyHeight = o.height - this._getHeaderHeight(); while (height < bodyHeight && index < numbers.length) { renderedKeys.push(index); offsetTop += numbers[index].height; height += numbers[index].height; index++; } BI.each(renderedKeys, function (i, key) { var index = BI.deepIndexOf(self.renderedKeys, key); if (index > -1) { if (numbers[key].height !== self.renderedCells[index]._height) { self.renderedCells[index]._height = numbers[key].height; self.renderedCells[index].el.setHeight(numbers[key].height); } if (numbers[key].top !== self.renderedCells[index].top) { self.renderedCells[index].top = numbers[key].top; self.renderedCells[index].el.element.css("top", numbers[key].top + "px"); } renderedCells.push(self.renderedCells[index]); } else { var child = BI.createWidget(BI.extend({ type: "bi.table_style_cell", cls: "sequence-table-number-cell bi-border-left bi-border-right bi-border-bottom", width: 60, styleGetter: numbers[key].isSummary === true ? function () { return o.summaryCellStyleGetter(true); } : function (key) { return function () { return o.sequenceCellStyleGetter(key); } }(numbers[key].index) }, numbers[key])); renderedCells.push({ el: child, left: 0, top: numbers[key].top, _height: numbers[key].height }); } }); //已存在的, 需要添加的和需要删除的 var existSet = {}, addSet = {}, deleteArray = []; BI.each(renderedKeys, function (i, key) { if (BI.deepContains(self.renderedKeys, key)) { existSet[i] = key; } else { addSet[i] = key; } }); BI.each(this.renderedKeys, function (i, key) { if (BI.deepContains(existSet, key)) { return; } if (BI.deepContains(addSet, key)) { return; } deleteArray.push(i); }); BI.each(deleteArray, function (i, index) { self.renderedCells[index].el.destroy(); }); var addedItems = []; BI.each(addSet, function (index) { addedItems.push(renderedCells[index]) }); BI.createWidget({ type: "bi.absolute", element: this.container, items: addedItems }); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; this.container.setHeight(intervalTree.sumUntil(numbers.length)); }, _restore: function () { BI.each(this.renderedCells, function (i, cell) { cell.el.destroy(); }); this.renderedCells = []; this.renderedKeys = []; }, _populate: function () { var self = this; BI.each(this.tasks, function (i, task) { task.apply(self); }); this.tasks = []; this.headerContainer.empty(); this._createHeader(); this._layout(); this._calculateChildrenToRender(); }, setVerticalScroll: function (scrollTop) { if (this.options.scrollTop !== scrollTop) { this.options.scrollTop = scrollTop; try { this.scrollContainer.element.scrollTop(scrollTop); } catch (e) { } } }, getVerticalScroll: function () { return this.options.scrollTop; }, setVPage: function (v) { if (v <= 1) { this.cache = {}; this.start = this.options.startSequence; this._restore(); this.tasks.push(this._nextState); } else if (v === this.vCurr + 1) { this.tasks.push(this._nextState); } else if (v === this.vCurr - 1) { this.tasks.push(this._prevState); } this.vCurr = v; }, setHPage: function (v) { if (v !== this.hCurr) { this.tasks.push(this._prevState); } this.hCurr = v; }, restore: function () { this._restore(); }, populate: function (items, header, crossItems, crossHeader) { var o = this.options; if (items && items !== this.options.items) { o.items = items; this._restore(); this.tasks.push(this._prevState); } if (header && header !== this.options.header) { o.header = header; } if (crossItems && crossItems !== this.options.crossItems) { o.crossItems = crossItems; } if (crossHeader && crossHeader !== this.options.crossHeader) { o.crossHeader = crossHeader; } this._populate(); } }); BI.shortcut('bi.sequence_table_tree_number', BI.SequenceTableTreeNumber);/** * 自适应布局 * * 1、resize * 2、吸附 * 3、当前组件在最上方 * 4、可以撤销 * 5、上下之间插入组件 * * Created by GUY on 2016/2/23. * @class BI.AdaptiveArrangement * @extends BI.Widget */ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.AdaptiveArrangement.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-adaptive-arrangement", resizable: true, layoutType: BI.Arrangement.LAYOUT_TYPE.FREE, items: [] }); }, _init: function () { BI.AdaptiveArrangement.superclass._init.apply(this, arguments); var self = this, o = this.options; this.arrangement = BI.createWidget({ type: "bi.arrangement", element: this, layoutType: o.layoutType, items: o.items }); this.arrangement.on(BI.Arrangement.EVENT_SCROLL, function () { self.fireEvent(BI.AdaptiveArrangement.EVENT_SCROLL, arguments); }); this.zIndex = 0; BI.each(o.items, function (i, item) { self._initResizable(item.el); }); $(document).mousedown(function (e) { BI.each(self.getAllRegions(), function (i, region) { if (region.el.element.find(e.target).length === 0) { region.el.element.removeClass("selected"); } }); }); BI.ResizeDetector.addResizeListener(this, function () { self.arrangement.resize(); self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE); }); }, _isEqual: function () { return this.arrangement._isEqual.apply(this.arrangement, arguments); }, _setSelect: function (item) { if (!item.element.hasClass("selected")) { item.element.css("zIndex", ++this.zIndex); BI.each(this.getAllRegions(), function (i, region) { region.el.element.removeClass("selected"); }); item.element.addClass("selected"); } }, _initResizable: function (item) { var self = this, o = this.options; item.element.css("zIndex", ++this.zIndex); item.element.mousedown(function () { self._setSelect(item) }); // o.resizable && item.element.resizable({ // handles: "e, s, se", // minWidth: 20, // minHeight: 20, // autoHide: true, // helper: "bi-resizer", // start: function () { // item.element.css("zIndex", ++self.zIndex); // self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE); // }, // resize: function (e, ui) { // // self._resize(item.attr("id"), ui.size); // self._resize(item.attr("id"), e, ui.size, ui.position); // }, // stop: function (e, ui) { // self._stopResize(item.attr("id"), ui.size); // self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE, item.attr("id"), ui.size); // self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE); // } // }); }, // _resize: function (name, e, size, position) { // var self = this; // this.scrollInterval(e, false, true, function (changedSize) { // size.width += changedSize.offsetX; // size.height += changedSize.offsetY; // var containerWidth = self.arrangement.container.element.width(); // var containerHeight = self.arrangement.container.element.height(); // self.arrangement.container.element.width(containerWidth + changedSize.offsetX); // self.arrangement.container.element.height(containerHeight + changedSize.offsetY); // switch (self.getLayoutType()) { // case BI.Arrangement.LAYOUT_TYPE.FREE: // break; // case BI.Arrangement.LAYOUT_TYPE.GRID: // self.setRegionSize(name, size); // break; // } // self.fireEvent(BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE, name, size); // }); // }, // // _stopResize: function (name, size) { // var self = this; // this.scrollEnd(); // switch (this.getLayoutType()) { // case BI.Arrangement.LAYOUT_TYPE.FREE: // this.setRegionSize(name, size); // break; // case BI.Arrangement.LAYOUT_TYPE.GRID: // this.setRegionSize(name, size); // break; // } // }, _getScrollOffset: function () { return this.arrangement._getScrollOffset(); }, getClientWidth: function () { return this.arrangement.getClientWidth(); }, getClientHeight: function () { return this.arrangement.getClientHeight(); }, addRegion: function (region, position) { this._initResizable(region.el); this._setSelect(region.el); var self = this, flag; var old = this.arrangement.getAllRegions(); if (flag = this.arrangement.addRegion(region, position)) { this._old = old; } return flag; }, deleteRegion: function (name) { var flag; var old = this.getAllRegions(); if (flag = this.arrangement.deleteRegion(name)) { this._old = old; } else { this._old = this.getAllRegions(); this.relayout(); } return flag; }, setRegionSize: function (name, size) { var flag; var old = this.getAllRegions(); if (flag = this.arrangement.setRegionSize(name, size)) { this._old = old; } return flag; }, setPosition: function (position, size) { var self = this; return this.arrangement.setPosition(position, size); }, setRegionPosition: function (name, position) { var region = this.getRegionByName(name); return this.arrangement.setRegionPosition(name, position); }, setDropPosition: function (position, size) { return this.arrangement.setDropPosition(position, size); }, scrollInterval: function (e, isBorderScroll, isOverflowScroll, cb) { var self = this; var map = { top: [-1, 0], bottom: [1, 0], left: [0, -1], right: [0, 1] }; var clientSize = this.element.bounds(); function scrollTo(direction, callback) { if (direction === "") { self.lastActiveRegion = ""; if (self._scrollInterval) { clearInterval(self._scrollInterval); self._scrollInterval = null; } return; } if (self.lastActiveRegion !== direction) { self.lastActiveRegion = direction; if (self._scrollInterval) { clearInterval(self._scrollInterval); self._scrollInterval = null; } var count = 0; self._scrollInterval = setInterval(function () { count++; if (count <= 3) { return; } var offset = self._getScrollOffset(); var t = offset.top + map[direction][0] * 40; var l = offset.left + map[direction][1] * 40; if (t < 0 || l < 0) { return; } callback({ offsetX: map[direction][1] * 40, offsetY: map[direction][0] * 40 }); self.scrollTo({ top: t, left: l }); }, 300); } } cb({ offsetX: 0, offsetY: 0 }); var offset = this.element.offset(); var p = { left: e.pageX - offset.left, top: e.pageY - offset.top }; //向上滚 if (isBorderScroll && p.top >= 0 && p.top <= 30) { scrollTo("top", cb) } //向下滚 else if (isBorderScroll && p.top >= clientSize.height - 30 && p.top <= clientSize.height) { scrollTo("bottom", cb) } //向左滚 else if (isBorderScroll && p.left >= 0 && p.left <= 30) { scrollTo("left", cb) } //向右滚 else if (isBorderScroll && p.left >= clientSize.width - 30 && p.left <= clientSize.width) { scrollTo("right", cb) } else { if (isOverflowScroll === true) { if (p.top < 0) { scrollTo("top", cb); } else if (p.top > clientSize.height) { scrollTo("bottom", cb); } else if (p.left < 0) { scrollTo("left", cb); } else if (p.left > clientSize.width) { scrollTo("right", cb); } else { scrollTo("", cb); } } else { scrollTo("", cb); } } }, scrollEnd: function () { this.lastActiveRegion = ""; if (this._scrollInterval) { clearInterval(this._scrollInterval); this._scrollInterval = null; } }, scrollTo: function (scroll) { this.arrangement.scrollTo(scroll); }, zoom: function (ratio) { this.arrangement.zoom(ratio); }, resize: function () { this.arrangement.resize(); }, relayout: function () { return this.arrangement.relayout(); }, setLayoutType: function (type) { var self = this; this.arrangement.setLayoutType(type); }, getLayoutType: function () { return this.arrangement.getLayoutType(); }, getLayoutRatio: function () { return this.arrangement.getLayoutRatio(); }, getHelper: function () { return this.arrangement.getHelper(); }, getRegionByName: function (name) { return this.arrangement.getRegionByName(name); }, getAllRegions: function () { return this.arrangement.getAllRegions(); }, revoke: function () { if (this._old) { this.populate(BI.toArray(this._old)); } }, populate: function (items) { var self = this; BI.each(items, function (i, item) { self._initResizable(item.el); }); this.arrangement.populate(items); } }); BI.AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_START_RESIZE"; BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_RESIZE"; BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE = "AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE"; BI.AdaptiveArrangement.EVENT_RESIZE = "AdaptiveArrangement.EVENT_RESIZE"; BI.AdaptiveArrangement.EVENT_SCROLL = "AdaptiveArrangement.EVENT_SCROLL"; BI.shortcut('bi.adaptive_arrangement', BI.AdaptiveArrangement);/** * Arrangement的block面板 * * Created by GUY on 2016/3/1. * @class BI.ArrangementBlock * @extends BI.Widget */ BI.ArrangementBlock = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ArrangementBlock.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-arrangement-block bi-mask" }); } }); BI.shortcut('bi.arrangement_block', BI.ArrangementBlock);/** * Arrangement的drop面板 * * Created by GUY on 2016/3/1. * @class BI.ArrangementDroppable * @extends BI.Widget */ BI.ArrangementDroppable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ArrangementDroppable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-arrangement-droppable bi-resizer" }); } }); BI.shortcut('bi.arrangement_droppable', BI.ArrangementDroppable);/** * 布局 * * Created by GUY on 2016/2/23. * @class BI.Arrangement * @extends BI.Widget */ BI.Arrangement = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.Arrangement.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-arrangement", layoutType: BI.Arrangement.LAYOUT_TYPE.GRID, items: [] }); }, _init: function () { BI.Arrangement.superclass._init.apply(this, arguments); var self = this, o = this.options; this.arrangement = BI.createWidget({ type: "bi.arrangement_droppable", cls: "arrangement-block", invisible: true }); this.block = BI.createWidget({ type: "bi.arrangement_block", invisible: true }); this.container = BI.createWidget({ type: "bi.absolute", items: o.items.concat([this.block, this.arrangement]) }); this.scrollContainer = BI.createWidget({ type: "bi.adaptive", width: "100%", height: "100%", scrollable: true, items: [this.container] }); this.scrollContainer.element.scroll(function () { self.fireEvent(BI.Arrangement.EVENT_SCROLL, { scrollLeft: self.scrollContainer.element.scrollLeft(), scrollTop: self.scrollContainer.element.scrollTop(), clientWidth: self.scrollContainer.element[0].clientWidth, clientHeight: self.scrollContainer.element[0].clientHeight }); }); BI.createWidget({ type: "bi.adaptive", element: this, items: [this.scrollContainer] }); this.regions = {}; if (o.items.length > 0) { BI.nextTick(function () { self.populate(o.items); }); } }, ////初始化操作//// _calculateRegions: function (items) { var self = this, o = this.options; this.regions = {}; BI.each(items, function (i, item) { var region = self._createOneRegion(item); self.regions[region.id] = region; }); }, _isEqual: function (num1, num2) { return Math.abs(num1 - num2) < 2; }, _isLessThan: function (num1, num2) { return num1 < num2 && !this._isEqual(num1, num2); }, _isMoreThan: function (num1, num2) { return num1 > num2 && !this._isEqual(num1, num2); }, _isLessThanEqual: function (num1, num2) { return num1 <= num2 || this._isEqual(num1, num2); }, _isMoreThanEqual: function (num1, num2) { return num1 >= num2 || this._isEqual(num1, num2); }, //获取占有的最大Region _getRegionOccupied: function (regions) { var self = this, o = this.options; if (BI.size(regions || this.regions) <= 0) { return { left: 0, top: 0, width: 0, height: 0 } } var minLeft = BI.MAX, maxLeft = BI.MIN, minTop = BI.MAX, maxTop = BI.MIN; BI.each(regions || this.regions, function (id, region) { minLeft = Math.min(minLeft, region.left); maxLeft = Math.max(maxLeft, region.left + region.width); minTop = Math.min(minTop, region.top); maxTop = Math.max(maxTop, region.top + region.height); }); return { left: minLeft, top: minTop, width: maxLeft - minLeft, height: maxTop - minTop } }, //两个区域的交叉面积 _getCrossArea: function (region1, region2) { if (region1.left <= region2.left) { if (region1.top <= region2.top) { if (region1.top + region1.height > region2.top && region1.left + region1.width > region2.left) { if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region1.left + region1.width, region2.left)) { return 0; } return (region1.top + region1.height - region2.top) * (region1.left + region1.width - region2.left); } } else { if (region2.top + region2.height > region1.top && region1.left + region1.width > region2.left) { if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region1.left + region1.width, region2.left)) { return 0; } return (region2.top + region2.height - region1.top) * (region1.left + region1.width - region2.left); } } } else { if (region1.top <= region2.top) { if (region1.top + region1.height > region2.top && region2.left + region2.width > region1.left) { if (this._isEqual(region1.top + region1.height, region2.top) || this._isEqual(region2.left + region2.width, region1.left)) { return 0; } return (region1.top + region1.height - region2.top) * (region2.left + region2.width - region1.left); } } else { if (region2.top + region2.height > region1.top && region2.left + region2.width > region1.left) { if (this._isEqual(region2.top + region2.height, region1.top) || this._isEqual(region2.left + region2.width, region1.left)) { return 0; } return (region2.top + region2.height - region1.top) * (region2.left + region2.width - region1.left); } } } return 0; }, //是否有覆盖的组件 _isRegionOverlay: function (regions) { var reg = []; BI.each(regions || this.regions, function (id, region) { reg.push(new BI.Region(region.left, region.top, region.width, region.height)); }); for (var i = 0, len = reg.length; i < len; i++) { for (var j = i + 1; j < len; j++) { var area1 = { left: reg[i].x, top: reg[i].y, width: reg[i].w, height: reg[i].h }; var area2 = { left: reg[j].x, top: reg[j].y, width: reg[j].w, height: reg[j].h }; if (reg[i].isIntersects(reg[j]) && this._getCrossArea(area1, area2) > 1) { return true; } } } return false; }, //布局是否是优良的 _isArrangeFine: function (regions) { switch (this.options.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: return true; case BI.Arrangement.LAYOUT_TYPE.GRID: // if (this._isRegionOverlay()) { // return false; // } } return true; }, _getRegionNames: function (regions) { var names = []; BI.each(regions || this.regions, function (i, region) { names.push(region.id || region.attr("id")); }); return names; }, _getRegionsByNames: function (names, regions) { names = BI.isArray(names) ? names : [names]; regions = regions || this.regions; if (BI.isArray(regions)) { var result = []; BI.each(regions, function (i, region) { if (names.contains(region.id || region.attr("id"))) { result.push(region); } }); } else { var result = {}; BI.each(names, function (i, name) { result[name] = regions[name]; }); } return result; }, _cloneRegion: function (regions) { var clone = {}; BI.each(regions || this.regions, function (id, region) { clone[id] = {}; clone[id].el = region.el; clone[id].id = region.id; clone[id].left = region.left; clone[id].top = region.top; clone[id].width = region.width; clone[id].height = region.height; }); return clone; }, //测试合法性 _test: function (regions) { var self = this; return !BI.any(regions || this.regions, function (i, region) { if (BI.isNaN(region.width) || BI.isNaN(region.height) || region.width <= 21 || region.height <= 21) { return true; } }) }, _getScrollOffset: function () { return { left: this.scrollContainer.element[0].scrollLeft, top: this.scrollContainer.element[0].scrollTop } }, ////操作//// _createOneRegion: function (item) { var el = BI.createWidget(item.el); el.setVisible(true); return { id: el.attr("id"), left: item.left, top: item.top, width: item.width, height: item.height, el: el } }, _applyRegion: function (regions) { var self = this, o = this.options; BI.each(regions || this.regions, function (i, region) { region.el.element.css({ left: region.left, top: region.top, width: region.width, height: region.height }); }); this._applyContainer(); this.ratio = this.getLayoutRatio(); }, _renderRegion: function () { var self = this; BI.createWidget({ type: "bi.absolute", element: this.container, items: BI.toArray(this.regions) }); }, getClientWidth: function () { return this.scrollContainer.element[0].clientWidth; }, getClientHeight: function () { return this.scrollContainer.element[0].clientHeight; }, _applyContainer: function () { //先掩藏后显示能够明确滚动条是否出现 this.scrollContainer.element.css("overflow", "hidden"); var occupied = this._getRegionOccupied(); this.container.element.width(occupied.left + occupied.width).height(occupied.top + occupied.height); this.scrollContainer.element.css("overflow", "auto"); return occupied; }, _modifyRegion: function (regions) { BI.each(this.regions, function (id, region) { if (regions[id]) { region.left = regions[id].left; region.top = regions[id].top; region.width = regions[id].width; region.height = regions[id].height; } }); }, _addRegion: function (item) { var region = this._createOneRegion(item); this.regions[region.id] = region; BI.createWidget({ type: "bi.absolute", element: this.container, items: [region] }); }, _deleteRegionByName: function (name) { this.regions[name].el.setVisible(false); delete this.regions[name]; }, _setArrangeSize: function (size) { this.arrangement.element.css({ left: size.left, top: size.top, width: size.width, height: size.height }) }, //Grid _getOneWidthPortion: function () { return this.getClientWidth() / BI.Arrangement.PORTION; }, _getOneHeightPortion: function () { return this.getClientHeight() / BI.Arrangement.H_PORTION; }, _getGridPositionAndSize: function (position) { var perWidth = this._getOneWidthPortion(); var perHeight = this._getOneHeightPortion(); var widthPortion = Math.round(position.width / perWidth); var leftPortion = Math.round(position.left / perWidth); var topPortion = Math.round(position.top / perHeight); var heightPortion = Math.round(position.height / perHeight); // if (leftPortion > BI.Arrangement.PORTION) { // leftPortion = BI.Arrangement.PORTION; // } // if (widthPortion > BI.Arrangement.PORTION) { // widthPortion = BI.Arrangement.PORTION; // } // if (leftPortion + widthPortion > BI.Arrangement.PORTION) { // leftPortion = BI.Arrangement.PORTION - widthPortion; // } if (widthPortion === 0) { widthPortion = 1; } if (heightPortion === 0) { heightPortion = 1; } return { x: leftPortion, y: topPortion, w: widthPortion, h: heightPortion } }, _getBlockPositionAndSize: function (position) { var perWidth = this._getOneWidthPortion(); var perHeight = this._getOneHeightPortion(); return { left: position.x * perWidth, top: position.y * perHeight, width: position.w * perWidth, height: position.h * perHeight }; }, _getLayoutsByRegions: function (regions) { var self = this; var result = []; BI.each(regions || this.regions, function (id, region) { result.push(BI.extend(self._getGridPositionAndSize(region), { i: region.id })) }); return result; }, _getLayoutIndexByName: function (layout, name) { return BI.findIndex(layout, function (i, l) { return l.i === name; }); }, _setBlockPositionAndSize: function (size) { this.block.element.css({ left: size.left, top: size.top, width: size.width, height: size.height }); }, _getRegionsByLayout: function (layout) { var self = this; var regions = {}; BI.each(layout, function (i, ly) { regions[ly.i] = BI.extend(self._getBlockPositionAndSize(ly), { id: ly.i }); }); return regions; }, _setRegionsByLayout: function (regions, layout) { var self = this; regions || (regions = this.regions); BI.each(layout, function (i, ly) { if (regions[ly.i]) { BI.extend(regions[ly.i], self._getBlockPositionAndSize(ly)); } }); return regions; }, _moveElement: function (layout, l, x, y, isUserAction) { var self = this; if (l._static) { return layout; } if (l.y === y && l.x === x) { return layout; } var movingUp = y && l.y > y; if (typeof x === 'number') { l.x = x; } if (typeof y === 'number') { l.y = y; } l.moved = true; var sorted = this._sortLayoutItemsByRowCol(layout); if (movingUp) { sorted = sorted.reverse(); } var collisions = getAllCollisions(sorted, l); for (var i = 0, len = collisions.length; i < len; i++) { var collision = collisions[i]; if (collision.moved) { continue; } if (l.y > collision.y && l.y - collision.y > collision.h / 4) { continue; } if (collision._static) { layout = this._moveElementAwayFromCollision(layout, collision, l, isUserAction); } else { layout = this._moveElementAwayFromCollision(layout, l, collision, isUserAction); } } return layout; function getAllCollisions(layout, layoutItem) { return BI.filter(layout, function (i, l) { return self._collides(l, layoutItem); }); } }, _sortLayoutItemsByRowCol: function (layout) { return [].concat(layout).sort(function (a, b) { if (a.y > b.y || (a.y === b.y && a.x > b.x)) { return 1; } return -1; }); }, _collides: function (l1, l2) { if (l1 === l2) { return false; } // same element if (l1.x + l1.w <= l2.x) { return false; } // l1 is left of l2 if (l1.x >= l2.x + l2.w) { return false; } // l1 is right of l2 if (l1.y + l1.h <= l2.y) { return false; } // l1 is above l2 if (l1.y >= l2.y + l2.h) { return false; } // l1 is below l2 return true; // boxes overlap }, _getFirstCollision: function (layout, layoutItem) { for (var i = 0, len = layout.length; i < len; i++) { if (this._collides(layout[i], layoutItem)) { return layout[i]; } } }, _moveElementAwayFromCollision: function (layout, collidesWith, itemToMove, isUserAction) { if (isUserAction) { var fakeItem = { x: itemToMove.x, y: itemToMove.y, w: itemToMove.w, h: itemToMove.h, i: '-1' }; fakeItem.y = Math.max(collidesWith.y - itemToMove.h, 0); if (!this._getFirstCollision(layout, fakeItem)) { return this._moveElement(layout, itemToMove, undefined, fakeItem.y); } } return this._moveElement(layout, itemToMove, undefined, itemToMove.y + 1); }, _compactItem: function (compareWith, l, verticalCompact) { if (verticalCompact) { while (l.y > 0 && !this._getFirstCollision(compareWith, l)) { l.y--; } } var collides; while ((collides = this._getFirstCollision(compareWith, l))) { l.y = collides.y + collides.h; } return l; }, compact: function (layout, verticalCompact) { var compareWith = getStatics(layout); var sorted = this._sortLayoutItemsByRowCol(layout); var out = []; for (var i = 0, len = sorted.length; i < len; i++) { var l = sorted[i]; if (!l._static) { l = this._compactItem(compareWith, l, verticalCompact); compareWith.push(l); } out[layout.indexOf(l)] = l; l.moved = false; } return out; function getStatics(layout) { return BI.filter(layout, function (i, l) { return l._static; }); } }, ////公有方法//// getRegionByName: function (name) { var obj = {}; obj[name] = this.regions[name]; return this._cloneRegion(obj)[name]; }, getAllRegions: function () { return BI.toArray(this._cloneRegion()); }, getHelper: function () { var helper = BI.createWidget({ type: "bi.layout", width: 18, height: 18, cls: "arrangement-helper bi-border" }); BI.createWidget({ type: "bi.absolute", element: this, items: [helper] }); return helper; }, _start: function () { if (this.options.layoutType === BI.Arrangement.LAYOUT_TYPE.GRID) { this.block.setVisible(true); } else { this.arrangement.setVisible(true); } }, _stop: function () { this.arrangement.setVisible(false); this.block.setVisible(false); }, ////公有操作//// setLayoutType: function (type) { var self = this, o = this.options; if (type !== o.layoutType) { o.layoutType = type; switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: break; case BI.Arrangement.LAYOUT_TYPE.GRID: this.relayout(); break; } } }, getLayoutType: function () { return this.options.layoutType; }, getLayoutRatio: function () { var occupied = this._getRegionOccupied(); var width = this.getClientWidth(), height = this.getClientHeight(); return { x: BI.parseFloat(BI.contentFormat((occupied.left + occupied.width) / width, "#.##;-#.##")), y: BI.parseFloat(BI.contentFormat((occupied.top + occupied.height) / height, "#.##;-#.##")) } }, addRegion: function (region, position) { if (position) { this.setPosition(position, region); } var self = this, o = this.options; if (!this.position) { return false; } var test = this._cloneRegion(); BI.each(this.position.regions, function (i, region) { test[region.id].left = region.left; test[region.id].top = region.top; test[region.id].width = region.width; test[region.id].height = region.height; }); var item = BI.extend({}, region, { left: this.position.insert.left, top: this.position.insert.top, width: this.position.insert.width, height: this.position.insert.height }); var added = this._createOneRegion(item); test[added.id] = added; if (this._test(test)) { delete test[added.id]; this._modifyRegion(test); this._addRegion(item); this._populate(this.getAllRegions()); return true; } return false; }, deleteRegion: function (name) { if (!this.regions[name]) { return false; } var self = this, o = this.options; switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: this._deleteRegionByName(name); this._populate(this.getAllRegions()); return true; case BI.Arrangement.LAYOUT_TYPE.GRID: this._deleteRegionByName(name); this._populate(this.getAllRegions()); this.resize(); return true; } return false; }, setRegionSize: function (name, size) { var self = this, o = this.options; var flag = false; switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: var clone = this._cloneRegion(); BI.extend(clone[name], { width: size.width, height: size.height }); if (this._test(clone)) { this._modifyRegion(clone); flag = true; } break; case BI.Arrangement.LAYOUT_TYPE.GRID: var clone = this._cloneRegion(); BI.extend(clone[name], { width: size.width, height: size.height }); if (this._test(clone)) { var layout = this._getLayoutsByRegions(clone); layout = this.compact(layout, true); var regions = this._getRegionsByLayout(layout); this._modifyRegion(regions); flag = true; } break; } this._applyRegion(); return flag; }, setPosition: function (position, size) { var self = this, o = this.options; var insert, regions = [], cur; if (position.left < 0 || position.top < 0) { switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: break; case BI.Arrangement.LAYOUT_TYPE.GRID: this.resize(); break; } this._stop(); this.position = null; return null; } var offset = this._getScrollOffset(); position = { left: position.left + offset.left, top: position.top + offset.top }; switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: var insert = { top: position.top < 0 ? 0 : position.top, left: position.left < 0 ? 0 : position.left, width: size.width, height: size.height }; this.position = { insert: insert }; this._setArrangeSize(insert); this._start(); break; case BI.Arrangement.LAYOUT_TYPE.GRID: var p = { top: position.top < 0 ? 0 : position.top, left: position.left < 0 ? 0 : position.left, width: size.width, height: size.height }; this._setArrangeSize(p); var cur = this._getGridPositionAndSize(p); var layout = [{ x: 0, y: BI.MAX, w: cur.w, h: cur.h, i: cur.i }].concat(this._getLayoutsByRegions()); layout = this._moveElement(layout, layout[0], cur.x, cur.y, true); layout = this.compact(layout, true); var regions = this._setRegionsByLayout(this._cloneRegion(), layout); var insert = this._getBlockPositionAndSize(layout[0]); this.position = { insert: insert, regions: regions }; this._applyRegion(regions); this._setBlockPositionAndSize(insert); this._start(); break; } return this.position; }, setRegionPosition: function (name, position) { var self = this, o = this.options; var offset = this._getScrollOffset(); position = BI.extend(position, { left: position.left + offset.left, top: position.top + offset.top }); switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: BI.extend(this.regions[name], { left: position.left < 0 ? 0 : position.left, top: position.top < 0 ? 0 : position.top }); this._applyRegion(); break; case BI.Arrangement.LAYOUT_TYPE.GRID: if (!position.stop) { BI.extend(this.regions[name], { left: position.left < 0 ? 0 : position.left, top: position.top < 0 ? 0 : position.top }); var cloned = this._cloneRegion(); var cur = this._getGridPositionAndSize(BI.extend(cloned[name], { left: position.left < 0 ? 0 : position.left, top: position.top < 0 ? 0 : position.top })); var x = cur.x, y = cur.y; cur = BI.extend(cur, { x: 0, y: BI.MAX, i: -1 }); delete cloned[name]; var layout = this._getLayoutsByRegions(cloned); layout = this._moveElement([cur].concat(layout), cur, x, y, true); layout = this.compact(layout, true); var regions = this._getRegionsByLayout(layout); this._modifyRegion(regions); this._applyRegion(); this._setBlockPositionAndSize(this._getBlockPositionAndSize(cur)); this.block.setVisible(true); } else { BI.extend(this.regions[name], { left: position.left < 0 ? 0 : position.left, top: position.top < 0 ? 0 : position.top }); var cloned = this._cloneRegion(); var layout = this._getLayoutsByRegions(cloned); layout = this.compact(layout, true); var regions = this._getRegionsByLayout(layout); this._modifyRegion(regions); this._applyRegion(); this.block.setVisible(false); } break; } }, setDropPosition: function (position, size) { var self = this; this.arrangement.setVisible(true); var offset = this._getScrollOffset(); this._setArrangeSize(BI.extend({}, size, { left: position.left + offset.left, top: position.top + offset.top })); return function () { self.arrangement.setVisible(false); } }, scrollTo: function (scroll) { this.scrollContainer.element.scrollTop(scroll.top); this.scrollContainer.element.scrollLeft(scroll.left); }, zoom: function (ratio) { var self = this, o = this.options; if (!ratio) { return; } var occupied = this._applyContainer(); switch (this.getLayoutType()) { case BI.Arrangement.LAYOUT_TYPE.FREE: if (this._isArrangeFine()) { var width = this.getClientWidth(); var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width); //var yRatio = ratio.y * height / (occupied.top + occupied.height); var regions = this._cloneRegion(); BI.each(regions, function (i, region) { region.left = region.left * xRatio; //region.top = region.top * yRatio; region.width = region.width * xRatio; //region.height = region.height * yRatio; }); if (this._test(regions)) { this._modifyRegion(regions); this._applyRegion(); } this.resize(); // } else { this.relayout(); } break; case BI.Arrangement.LAYOUT_TYPE.GRID: if (this._isArrangeFine()) { var width = this.getClientWidth(), height = this.getClientHeight(); var xRatio = (ratio.x || 1) * width / (occupied.left + occupied.width); var yRatio = (ratio.y || 1) * height / (occupied.top + occupied.height); var regions = this._cloneRegion(); BI.each(regions, function (i, region) { region.left = region.left * xRatio; region.width = region.width * xRatio; region.top = region.top * yRatio; region.height = region.height * yRatio; //做一下自适应布局到网格布局的兼容 var perWidth = self._getOneWidthPortion(); var widthPortion = Math.round(region.width / perWidth); var leftPortion = Math.round(region.left / perWidth); var comparePortion = Math.round((region.width + region.left) / perWidth); if (leftPortion + widthPortion !== comparePortion) { region.left = leftPortion * perWidth; region.width = comparePortion * perWidth - region.left; } }); if (this._test(regions)) { var layout = this._getLayoutsByRegions(regions); layout = this.compact(layout, true); regions = this._getRegionsByLayout(layout); this._modifyRegion(regions); this._applyRegion(); } } else { this.relayout(); } break; } }, resize: function () { var self = this, o = this.options; switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: break; case BI.Arrangement.LAYOUT_TYPE.GRID: this.zoom(this.ratio); var regions = this._cloneRegion(); var layout = this._getLayoutsByRegions(regions); layout = this.compact(layout, true); regions = this._getRegionsByLayout(layout); this._modifyRegion(regions); this._applyRegion(); break; } }, relayout: function () { var self = this, o = this.options; switch (o.layoutType) { case BI.Arrangement.LAYOUT_TYPE.FREE: break; case BI.Arrangement.LAYOUT_TYPE.GRID: if (!this._isArrangeFine()) { var perHeight = this._getOneHeightPortion(); var width = this.getClientWidth(), height = this.getClientHeight(); var regions = this._cloneRegion(); var clone = BI.toArray(regions); clone.sort(function (r1, r2) { if (self._isEqual(r1.top, r2.top)) { return r1.left - r2.left; } return r1.top - r2.top; }); var count = clone.length; var cols = 4, rows = Math.floor((count - 1) / 4 + 1); var w = width / cols, h = height / rows; var store = {}; BI.each(clone, function (i, region) { var row = Math.floor(i / 4), col = i % 4; BI.extend(region, { top: row * perHeight * 6, left: col * w, width: w, height: perHeight * 6 }); if (!store[row]) { store[row] = {}; } store[row][col] = region; }); //非4的倍数 // if (count % 4 !== 0) { // var lasts = store[rows - 1]; // var perWidth = width / (count % 4); // BI.each(lasts, function (i, region) { // BI.extend(region, { // left: BI.parseInt(i) * perWidth, // width: perWidth // }); // }); // } if (this._test(clone)) { var layout = this._getLayoutsByRegions(regions); layout = this.compact(layout, true); regions = this._getRegionsByLayout(layout); this._modifyRegion(regions); this._populate(clone); } } else { this.resize(); } break; } }, _populate: function (items) { this._stop(); this._calculateRegions(items); this._applyRegion(); }, populate: function (items) { var self = this; BI.each(this.regions, function (name, region) { self.regions[name].el.setVisible(false); delete self.regions[name]; }); this._populate(items); this._renderRegion(); } }); BI.Arrangement.EVENT_SCROLL = "EVENT_SCROLL"; BI.extend(BI.Arrangement, { PORTION: 36, H_PORTION: 18, LAYOUT_TYPE: { GRID: 0, FREE: 1 } }); BI.shortcut('bi.arrangement', BI.Arrangement);/** * 表关联树 * * Created by GUY on 2015/12/15. * @class BI.BranchRelation * @extends BI.Widget */ BI.BranchRelation = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.BranchRelation.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-branch-relation-tree", items: [], centerOffset: 0,//重心偏移量 direction: BI.Direction.Bottom, align: BI.VerticalAlign.Top }) }, _init: function () { BI.BranchRelation.superclass._init.apply(this, arguments); this.populate(this.options.items); }, //树分层 _stratification: function () { var levels = []; this.tree.recursion(function (node, route) { //node.isRoot = route.length <= 1; node.leaf = node.isLeaf(); if (!levels[route.length - 1]) { levels[route.length - 1] = []; } levels[route.length - 1].push(node); }); return levels; }, //计算所有节点的叶子结点个数 _calculateLeaves: function () { var count = 0; function track(node) { var c = 0; if (node.isLeaf()) { return 1; } BI.each(node.getChildren(), function (i, child) { c += track(child); }); node.set("leaves", c); return c; } count = track(this.tree.getRoot()); return count; }, //树平移 _translate: function (levels) { var adjust = []; var maxLevel = levels.length; BI.each(levels, function (i, nodes) { if (!adjust[i]) { adjust[i] = []; } BI.each(nodes, function (j, node) { if (node.isLeaf() && i < maxLevel - 1) { var newNode = new BI.Node(BI.UUID()); //newNode.isEmptyRoot = node.isRoot || node.isEmptyRoot; newNode.isNew = true; //把node向下一层移 var tar = 0; if (j > 0) { var c = nodes[j - 1].getLastChild(); tar = levels[i + 1].indexOf(c) + 1; } levels[i + 1].splice(tar, 0, node); //新增一个临时树节点 var index = node.parent.getChildIndex(node.id); node.parent.removeChildByIndex(index); node.parent.addChild(newNode, index); newNode.addChild(node); adjust[i].push(newNode); nodes[j] = newNode; } else { adjust[i].push(node); } }) }); return adjust; }, //树补白 _fill: function (levels) { var adjust = []; var maxLevel = levels.length; BI.each(levels, function (i, nodes) { if (!adjust[i]) { adjust[i] = []; } BI.each(nodes, function (j, node) { if (node.isLeaf() && i < maxLevel - 1) { var newNode = new BI.Node(BI.UUID()); newNode.leaf = true; newNode.width = node.width; newNode.height = node.height; newNode.isNew = true; //把node向下一层移 var tar = 0; if (j > 0) { var c = nodes[j - 1].getLastChild(); tar = levels[i + 1].indexOf(c) + 1; } levels[i + 1].splice(tar, 0, newNode); //新增一个临时树节点 node.addChild(newNode); } adjust[i].push(node); }) }); return adjust; }, //树调整 _adjust: function (adjust) { while (true) { var isAllNeedAjust = false; BI.backEach(adjust, function (i, nodes) { BI.each(nodes, function (j, node) { if (!node.isNew) { var needAdjust = true; BI.any(node.getChildren(), function (k, n) { if (!n.isNew) { needAdjust = false; return true; } }); if (!node.isLeaf() && needAdjust === true) { var allChilds = []; BI.each(node.getChildren(), function (k, n) { allChilds = allChilds.concat(n.getChildren()); }); node.removeAllChilds(); BI.each(allChilds, function (k, c) { node.addChild(c); }); var newNode = new BI.Node(BI.UUID()); //newNode.isEmptyRoot = node.isRoot || node.isEmptyRoot; newNode.isNew = true; var index = node.parent.getChildIndex(node.id); node.parent.removeChildByIndex(index); node.parent.addChild(newNode, index); newNode.addChild(node); isAllNeedAjust = true; } } }) }); if (isAllNeedAjust === false) { break; } else {//树重构 adjust = this._stratification(); } } return adjust; }, _calculateWidth: function () { var o = this.options; var width = 0; function track1(node) { var w = 0; if (node.isLeaf()) { return node.width; } BI.each(node.getChildren(), function (i, child) { w += track1(child); }); return w; } function track2(node) { var w = 0; if (node.isLeaf()) { return node.height; } BI.each(node.getChildren(), function (i, child) { w += track2(child); }); return w; } if (this._isVertical()) { width = track1(this.tree.getRoot()); } else { width = track2(this.tree.getRoot()); } return width; }, _isVertical: function () { var o = this.options; return o.direction === BI.Direction.Top || o.direction === BI.Direction.Bottom; }, _calculateHeight: function () { var o = this.options; var height = 0; function track1(node) { var h = 0; BI.each(node.getChildren(), function (i, child) { h = Math.max(h, track1(child)); }); return h + (node.height || 0); } function track2(node) { var h = 0; BI.each(node.getChildren(), function (i, child) { h = Math.max(h, track2(child)); }); return h + (node.width || 0); } if (this._isVertical()) { height = track1(this.tree.getRoot()); } else { height = track2(this.tree.getRoot()); } return height; }, _calculateXY: function (levels) { var o = this.options; var width = this._calculateWidth(); var height = this._calculateHeight(); var levelCount = levels.length; var allLeavesCount = this._calculateLeaves(); //计算坐标 var xy = {}; var levelHeight = height / levelCount; BI.each(levels, function (i, nodes) { //计算权重 var weights = []; BI.each(nodes, function (j, node) { weights[j] = (node.get("leaves") || 1) / allLeavesCount; }); BI.each(nodes, function (j, node) { //求前j个元素的权重 var weight = BI.sum(weights.slice(0, j)); //求坐标 var x = weight * width + weights[j] * width / 2; var y = i * levelHeight + levelHeight / 2; xy[node.id] = {x: x, y: y}; }) }); return xy; }, _stroke: function (levels, xy) { var height = this._calculateHeight(); var levelCount = levels.length; var levelHeight = height / levelCount; var self = this, o = this.options; switch (o.direction) { case BI.Direction.Top: BI.each(levels, function (i, nodes) { BI.each(nodes, function (j, node) { if (node.getChildrenLength() > 0 && !node.leaf) { var path = ""; var start = xy[node.id]; var split = start.y + levelHeight / 2; path += "M" + start.x + "," + (start.y + o.centerOffset) + "L" + start.x + "," + split; var end = []; BI.each(node.getChildren(), function (t, c) { var e = end[t] = xy[c.id]; path += "M" + e.x + "," + (e.y + o.centerOffset) + "L" + e.x + "," + split; }); if (end.length > 0) { path += "M" + BI.first(end).x + "," + split + "L" + BI.last(end).x + "," + split; } self.svg.path(path).attr("stroke", "#d4dadd"); } }) }); break; case BI.Direction.Bottom: BI.each(levels, function (i, nodes) { BI.each(nodes, function (j, node) { if (node.getChildrenLength() > 0 && !node.leaf) { var path = ""; var start = xy[node.id]; var split = start.y - levelHeight / 2; path += "M" + start.x + "," + (start.y - o.centerOffset) + "L" + start.x + "," + split; var end = []; BI.each(node.getChildren(), function (t, c) { var e = end[t] = xy[c.id]; path += "M" + e.x + "," + (e.y - o.centerOffset) + "L" + e.x + "," + split; }); if (end.length > 0) { path += "M" + BI.first(end).x + "," + split + "L" + BI.last(end).x + "," + split; } self.svg.path(path).attr("stroke", "#d4dadd"); } }) }); break; case BI.Direction.Left: BI.each(levels, function (i, nodes) { BI.each(nodes, function (j, node) { if (node.getChildrenLength() > 0 && !node.leaf) { var path = ""; var start = xy[node.id]; var split = start.y + levelHeight / 2; path += "M" + (start.y + o.centerOffset) + "," + start.x + "L" + split + "," + start.x; var end = []; BI.each(node.getChildren(), function (t, c) { var e = end[t] = xy[c.id]; path += "M" + (e.y + o.centerOffset) + "," + e.x + "L" + split + "," + e.x; }); if (end.length > 0) { path += "M" + split + "," + BI.first(end).x + "L" + split + "," + BI.last(end).x; } self.svg.path(path).attr("stroke", "#d4dadd"); } }) }); break; case BI.Direction.Right: BI.each(levels, function (i, nodes) { BI.each(nodes, function (j, node) { if (node.getChildrenLength() > 0 && !node.leaf) { var path = ""; var start = xy[node.id]; var split = start.y - levelHeight / 2; path += "M" + (start.y - o.centerOffset) + "," + start.x + "L" + split + "," + start.x; var end = []; BI.each(node.getChildren(), function (t, c) { var e = end[t] = xy[c.id]; path += "M" + (e.y - o.centerOffset) + "," + e.x + "L" + split + "," + e.x; }); if (end.length > 0) { path += "M" + split + "," + BI.first(end).x + "L" + split + "," + BI.last(end).x; } self.svg.path(path).attr("stroke", "#d4dadd"); } }) }); break; } }, _createBranches: function (levels) { var self = this, o = this.options; if (o.direction === BI.Direction.Bottom || o.direction === BI.Direction.Right) { levels = levels.reverse(); } var xy = this._calculateXY(levels); //画图 this._stroke(levels, xy); }, _isNeedAdjust: function () { var o = this.options; return o.direction === BI.Direction.Top && o.align === BI.VerticalAlign.Bottom || o.direction === BI.Direction.Bottom && o.align === BI.VerticalAlign.Top || o.direction === BI.Direction.Left && o.align === BI.HorizontalAlign.Right || o.direction === BI.Direction.Right && o.align === BI.HorizontalAlign.Left }, setValue: function (value) { }, getValue: function () { }, _transformToTreeFormat: function (sNodes) { var i, l; if (!sNodes) { return []; } if (BI.isArray(sNodes)) { var r = []; var tmpMap = []; for (i = 0, l = sNodes.length; i < l; i++) { tmpMap[sNodes[i].id] = sNodes[i]; } for (i = 0, l = sNodes.length; i < l; i++) { if (tmpMap[sNodes[i].pId] && sNodes[i].id != sNodes[i].pId) { if (!tmpMap[sNodes[i].pId].children) { tmpMap[sNodes[i].pId].children = []; } tmpMap[sNodes[i].pId].children.push(sNodes[i]); } else { r.push(sNodes[i]); } } return r; } else { return [sNodes]; } }, populate: function (items) { var self = this, o = this.options; o.items = items || []; this.empty(); items = this._transformToTreeFormat(o.items); this.tree = new BI.Tree(); this.tree.initTree(items); this.svg = BI.createWidget({ type: "bi.svg" }); //树分层 var levels = this._stratification(); if (this._isNeedAdjust()) { //树平移 var adjust = this._translate(levels); //树调整 adjust = this._adjust(adjust); this._createBranches(adjust); } else { var adjust = this._fill(levels); this._createBranches(adjust); } var container = BI.createWidget({ type: "bi.layout", width: this._isVertical() ? this._calculateWidth() : this._calculateHeight(), height: this._isVertical() ? this._calculateHeight() : this._calculateWidth() }); BI.createWidget({ type: "bi.absolute", element: container, items: [{ el: this.svg, top: 0, left: 0, right: 0, bottom: 0 }] }); if (this._isVertical()) { items = [{ type: "bi.handstand_branch_tree", expander: { direction: o.direction }, el: { layouts: [{ type: "bi.horizontal_adapt", verticalAlign: o.align }] }, items: items }] } else { items = [{ type: "bi.branch_tree", expander: { direction: o.direction }, el: { layouts: [{ type: "bi.vertical" }, { type: o.align === BI.HorizontalAlign.Left ? "bi.left" : "bi.right" }] }, items: items }] } BI.createWidget({ type: "bi.adaptive", element: container, items: items }); BI.createWidget({ type: "bi.center_adapt", scrollable: true, element: this, items: [container] }); } }); BI.BranchRelation.EVENT_CHANGE = "BranchRelation.EVENT_CHANGE"; BI.shortcut("bi.branch_relation", BI.BranchRelation);/** * 日期控件中的月份下拉框 * * Created by GUY on 2015/9/7. * @class BI.MonthDateCombo * @extends BI.Trigger */ BI.MonthDateCombo = BI.inherit(BI.Trigger, { _defaultConfig: function() { return BI.extend( BI.MonthDateCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-month-combo", height: 25 }); }, _init: function() { BI.MonthDateCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.date_triangle_trigger" }); this.popup = BI.createWidget({ type: "bi.month_popup" }); this.popup.on(BI.YearPopup.EVENT_CHANGE, function(){ self.setValue(self.popup.getValue()); }) this.combo = BI.createWidget({ type: "bi.combo", offsetStyle: "center", element: this, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, popup: { minWidth: 85, stopPropagation: false, el: this.popup } }) this.combo.on(BI.Combo.EVENT_CHANGE, function(){ self.combo.hideView(); self.fireEvent(BI.MonthDateCombo.EVENT_CHANGE); }); }, setValue: function(v){ this.trigger.setValue(v + 1); this.popup.setValue(v); }, getValue: function(){ return this.popup.getValue(); } }); BI.MonthDateCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.month_date_combo', BI.MonthDateCombo);/** * 年份下拉框 * * Created by GUY on 2015/9/7. * @class BI.YearDateCombo * @extends BI.Trigger */ BI.YearDateCombo = BI.inherit(BI.Trigger, { _defaultConfig: function() { return BI.extend( BI.YearDateCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-year-combo", min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 height: 25 }); }, _init: function() { BI.YearDateCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.date_triangle_trigger" }); this.popup = BI.createWidget({ type: "bi.year_popup", min: o.min, max: o.max }); this.popup.on(BI.YearPopup.EVENT_CHANGE, function(){ self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.YearDateCombo.EVENT_CHANGE); }) this.combo = BI.createWidget({ type: "bi.combo", offsetStyle: "center", element: this, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, popup: { minWidth: 85, stopPropagation: false, el: this.popup } }) this.combo.on(BI.Combo.EVENT_CHANGE, function(){ self.fireEvent(BI.YearDateCombo.EVENT_CHANGE); }) }, setValue: function(v){ this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function(){ return this.popup.getValue(); } }); BI.YearDateCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.year_date_combo', BI.YearDateCombo);/** * Created by GUY on 2015/9/7. * @class BI.DatePicker * @extends BI.Widget */ BI.DatePicker = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.DatePicker.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-date-picker bi-background", height: 25, min: '1900-01-01', //最小日期 max: '2099-12-31' //最大日期 }) }, _init: function () { BI.DatePicker.superclass._init.apply(this, arguments); var self = this, o = this.options; this._year = new Date().getFullYear(); this._month = new Date().getMonth(); this.left = BI.createWidget({ type: "bi.icon_button", cls: "pre-page-h-font", width: 25, height: 25 }); this.left.on(BI.IconButton.EVENT_CHANGE, function () { if (self._month === 0) { self.setValue({ year: self.year.getValue() - 1, month: 11 }) } else { self.setValue({ year: self.year.getValue(), month: self.month.getValue() - 1 }) } self.fireEvent(BI.DatePicker.EVENT_CHANGE); }); this.right = BI.createWidget({ type: "bi.icon_button", cls: "next-page-h-font", width: 25, height: 25 }); this.right.on(BI.IconButton.EVENT_CHANGE, function () { if (self._month === 11) { self.setValue({ year: self.year.getValue() + 1, month: 0 }) } else { self.setValue({ year: self.year.getValue(), month: self.month.getValue() + 1 }) } self.fireEvent(BI.DatePicker.EVENT_CHANGE); }); this.year = BI.createWidget({ type: "bi.year_date_combo", min: o.min, max: o.max }); this.year.on(BI.YearDateCombo.EVENT_CHANGE, function () { self.setValue({ year: self.year.getValue(), month: self.month.getValue() }); self.fireEvent(BI.DatePicker.EVENT_CHANGE); }) this.month = BI.createWidget({ type: "bi.month_date_combo" }); this.month.on(BI.MonthDateCombo.EVENT_CHANGE, function () { self.setValue({ year: self.year.getValue(), month: self.month.getValue() }); self.fireEvent(BI.DatePicker.EVENT_CHANGE); }); BI.createWidget({ type: "bi.htape", element: this, items: [{ el: this.left, width: 25 }, { type: "bi.center_adapt", items: [{ type: "bi.horizontal", width: 100, items: [this.year, this.month] }] }, { el: this.right, width: 25 }] }) this.setValue({ year: this._year, month: this._month }) }, setValue: function (ob) { this._year = ob.year; this._month = ob.month; this.year.setValue(ob.year); this.month.setValue(ob.month); }, getValue: function () { return { year: this.year.getValue(), month: this.month.getValue() } } }); BI.DatePicker.EVENT_CHANGE = "EVENT_CHANGE" BI.shortcut("bi.date_picker", BI.DatePicker);/** * Created by GUY on 2015/9/7. * @class BI.DateCalendarPopup * @extends BI.Widget */ BI.DateCalendarPopup = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.DateCalendarPopup.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-date-calendar-popup", min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 selectedTime: null }) }, _createNav: function (v) { var date = BI.Calendar.getDateJSONByPage(v); var calendar = BI.createWidget({ type: "bi.calendar", logic: { dynamic: true }, min: this.options.min, max: this.options.max, year: date.year, month: date.month, day: this.selectedTime.day }); return calendar }, _init: function () { BI.DateCalendarPopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.today = new Date(); this._year = this.today.getFullYear(); this._month = this.today.getMonth(); this._day = this.today.getDate(); this.selectedTime = o.selectedTime || { year: this._year, month: this._month, day: this._day }; this.datePicker = BI.createWidget({ type: "bi.date_picker", min: o.min, max: o.max }); this.calendar = BI.createWidget({ direction: "top", element: this, logic: { dynamic: true }, type: "bi.navigation", tab: this.datePicker, cardCreator: BI.bind(this._createNav, this), afterCardCreated: function () { }, afterCardShow: function () { this.setValue(self.selectedTime); } }); this.datePicker.on(BI.DatePicker.EVENT_CHANGE, function () { self.selectedTime = self.datePicker.getValue(); self.selectedTime.day = 1; self.calendar.setSelect(BI.Calendar.getPageByDateJSON(self.selectedTime)); }); this.calendar.on(BI.Navigation.EVENT_CHANGE, function () { self.selectedTime = self.calendar.getValue(); self.setValue(self.selectedTime); self.fireEvent(BI.DateCalendarPopup.EVENT_CHANGE); }); }, setValue: function (timeOb) { this.datePicker.setValue(timeOb); this.calendar.setSelect(BI.Calendar.getPageByDateJSON(timeOb)); this.calendar.setValue(timeOb); this.selectedTime = timeOb; }, getValue: function () { return this.selectedTime; } }); BI.DateCalendarPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.date_calendar_popup", BI.DateCalendarPopup);/** * 日期控件中的年份或月份trigger * * Created by GUY on 2015/9/7. * @class BI.DateTriangleTrigger * @extends BI.Trigger */ BI.DateTriangleTrigger = BI.inherit(BI.Trigger, { _const: { height: 25, iconWidth: 16, iconHeight: 13 }, _defaultConfig: function() { return BI.extend( BI.DateTriangleTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-date-triangle-trigger pull-down-ha-font cursor-pointer", height: 25 }); }, _init: function() { BI.DateTriangleTrigger.superclass._init.apply(this, arguments); var o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", cls: "list-item-text", textAlign: "right", text: o.text, value: o.value, height: c.height }) this.icon = BI.createWidget({ type: "bi.icon", width: c.iconWidth, height: c.iconHeight }); BI.createWidget({ type: "bi.center_adapt", element: this, items: [{ type: "bi.center_adapt", width: 50, height: c.height, items: [this.text, this.icon] }] }) }, setValue: function(v){ this.text.setValue(v); }, getValue: function(){ return this.text.getValue(); }, setText: function(v){ this.text.setText(v); }, getText: function(){ return this.item.getText(); }, getKey: function(){ } }); BI.shortcut('bi.date_triangle_trigger', BI.DateTriangleTrigger);/** * 日期下拉框 * * Created by GUY on 2015/9/7. * @class BI.DateCombo * @extends BI.Widget */ BI.DateCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DateCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-date-combo bi-border", height: 30 }); }, _init: function () { BI.DateCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.date_trigger" }); this.trigger.on(BI.DateTrigger.EVENT_TRIGGER_CLICK, function () { self.combo.toggle(); }); this.popup = BI.createWidget({ type: "bi.date_calendar_popup" }); this.popup.on(BI.DateCalendarPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); }); this.combo = BI.createWidget({ type: "bi.combo", toggle: false, element: this, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, popup: { width: 270, el: this.popup, stopPropagation: false } }) }, setValue: function (v) { this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue(); } }); BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, vgap: 2, triggerWidth: 30, yearLength: 4, yearMonthLength: 7 }, _defaultConfig: function () { return BI.extend(BI.DateTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-date-trigger", min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 height: 25 }); }, _init: function () { BI.DateTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.editor = BI.createWidget({ type: "bi.sign_editor", height: o.height, validationChecker: function (v) { var date = v.match(/\d+/g); self._autoAppend(v, date); return self._dateCheck(v) && Date.checkLegal(v) && self._checkVoid({ year: date[0], month: date[1], day: date[2] }); }, quitChecker: function () { return false; }, hgap: c.hgap, vgap: c.vgap, allowBlank: true, watermark: BI.i18nText("BI-Basic_Unrestricted"), errorText: function () { if (self.editor.isEditing()) { return BI.i18nText("BI-Date_Trigger_Error_Text"); } return BI.i18nText("BI-Year_Trigger_Invalid_Text"); } }); this.editor.on(BI.SignEditor.EVENT_KEY_DOWN, function () { self.fireEvent(BI.DateTrigger.EVENT_KEY_DOWN) }); this.editor.on(BI.SignEditor.EVENT_FOCUS, function () { self.fireEvent(BI.DateTrigger.EVENT_FOCUS); }); this.editor.on(BI.SignEditor.EVENT_STOP, function () { self.fireEvent(BI.DateTrigger.EVENT_STOP); }); this.editor.on(BI.SignEditor.EVENT_VALID, function () { self.fireEvent(BI.DateTrigger.EVENT_VALID); }); this.editor.on(BI.SignEditor.EVENT_ERROR, function () { self.fireEvent(BI.DateTrigger.EVENT_ERROR); }); this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () { var value = self.editor.getValue(); if (BI.isNotNull(value)) { self.editor.setState(value); } if (BI.isNotEmptyString(value)) { var date = value.split("-"); self.store_value = { type: BI.DateTrigger.MULTI_DATE_CALENDAR, value:{ year: date[0] | 0, month: date[1] - 1, day: date[2] | 0 } }; } self.fireEvent(BI.DateTrigger.EVENT_CONFIRM); }); this.editor.on(BI.SignEditor.EVENT_SPACE, function () { if (self.editor.isValid()) { self.editor.blur(); } }); this.editor.on(BI.SignEditor.EVENT_START, function () { self.fireEvent(BI.DateTrigger.EVENT_START); }); this.editor.on(BI.SignEditor.EVENT_CHANGE, function () { self.fireEvent(BI.DateTrigger.EVENT_CHANGE); }); BI.createWidget({ type: "bi.htape", element: this, items: [{ el: BI.createWidget(), width: 30 }, { el: this.editor }] }) }, _dateCheck: function (date) { return Date.parseDateTime(date, "%Y-%x-%d").print("%Y-%x-%d") == date || Date.parseDateTime(date, "%Y-%X-%d").print("%Y-%X-%d") == date || Date.parseDateTime(date, "%Y-%x-%e").print("%Y-%x-%e") == date || Date.parseDateTime(date, "%Y-%X-%e").print("%Y-%X-%e") == date; }, _checkVoid: function (obj) { return !Date.checkVoid(obj.year, obj.month, obj.day, this.options.min, this.options.max)[0]; }, _autoAppend: function (v, dateObj) { var self = this; var date = Date.parseDateTime(v, "%Y-%X-%d").print("%Y-%X-%d"); var yearCheck = function (v) { return Date.parseDateTime(v, "%Y").print("%Y") == v && date >= self.options.min && date <= self.options.max; }; var monthCheck = function (v) { return Date.parseDateTime(v, "%Y-%X").print("%Y-%X") == v && date >= self.options.min && date <= self.options.max; }; if (BI.isNotNull(dateObj) && Date.checkLegal(v)) { switch (v.length) { case this._const.yearLength: if (yearCheck(v)) { this.editor.setValue(v + "-"); } break; case this._const.yearMonthLength: if (monthCheck(v)) { this.editor.setValue(v + "-"); } break; } } }, setValue: function (v) { var type, value, self = this; var date = new Date(); this.store_value = v; if (BI.isNotNull(v)) { type = v.type || BI.DateTrigger.MULTI_DATE_CALENDAR; value = v.value; if(BI.isNull(value)){ value = v; } } var _setInnerValue = function (date, text) { var dateStr = date.print("%Y-%x-%e"); self.editor.setState(dateStr); self.editor.setValue(dateStr); self.setTitle(text + ":" + dateStr); }; switch (type) { case BI.DateTrigger.MULTI_DATE_YEAR_PREV: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_PREV]; date = new Date((date.getFullYear() - 1 * value), date.getMonth(), date.getDate()); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_YEAR_AFTER: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_AFTER]; date = new Date((date.getFullYear() + 1 * value), date.getMonth(), date.getDate()); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_YEAR_BEGIN: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_BEGIN]; date = new Date(date.getFullYear(), 0, 1); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_YEAR_END: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_END]; date = new Date(date.getFullYear(), 11, 31); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_QUARTER_PREV: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_PREV]; date = new Date().getBeforeMulQuarter(value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_QUARTER_AFTER: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_AFTER]; date = new Date().getAfterMulQuarter(value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_QUARTER_BEGIN: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_BEGIN]; date = new Date().getQuarterStartDate(); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_QUARTER_END: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_END]; date = new Date().getQuarterEndDate(); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_MONTH_PREV: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_PREV]; date = new Date().getBeforeMultiMonth(value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_MONTH_AFTER: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_AFTER]; date = new Date().getAfterMultiMonth(value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_MONTH_BEGIN: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_BEGIN]; date = new Date(date.getFullYear(), date.getMonth(), 1); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_MONTH_END: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_END]; date = new Date(date.getFullYear(), date.getMonth(), (date.getLastDateOfMonth()).getDate()); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_WEEK_PREV: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_WEEK_PREV]; date = date.getOffsetDate(-7 * value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_WEEK_AFTER: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_WEEK_AFTER]; date = date.getOffsetDate(7 * value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_DAY_PREV: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_DAY_PREV]; date = date.getOffsetDate(-1 * value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_DAY_AFTER: var text = value + BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_DAY_AFTER]; date = date.getOffsetDate(1 * value); _setInnerValue(date, text); break; case BI.DateTrigger.MULTI_DATE_DAY_TODAY: var text = BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_DAY_TODAY]; date = new Date(); _setInnerValue(date, text); break; default: if (BI.isNull(value) || BI.isNull(value.day)) { this.editor.setState(""); this.editor.setValue(""); this.setTitle(""); } else { var dateStr = value.year + "-" + (value.month + 1) + "-" + value.day; this.editor.setState(dateStr); this.editor.setValue(dateStr); this.setTitle(dateStr); } break; } }, getKey: function () { return this.editor.getValue(); }, getValue: function () { return this.store_value; } }); BI.DateTrigger.MULTI_DATE_YEAR_PREV = 1; BI.DateTrigger.MULTI_DATE_YEAR_AFTER = 2; BI.DateTrigger.MULTI_DATE_YEAR_BEGIN = 3; BI.DateTrigger.MULTI_DATE_YEAR_END = 4; BI.DateTrigger.MULTI_DATE_MONTH_PREV = 5; BI.DateTrigger.MULTI_DATE_MONTH_AFTER = 6; BI.DateTrigger.MULTI_DATE_MONTH_BEGIN = 7; BI.DateTrigger.MULTI_DATE_MONTH_END = 8; BI.DateTrigger.MULTI_DATE_QUARTER_PREV = 9; BI.DateTrigger.MULTI_DATE_QUARTER_AFTER = 10; BI.DateTrigger.MULTI_DATE_QUARTER_BEGIN = 11; BI.DateTrigger.MULTI_DATE_QUARTER_END = 12; BI.DateTrigger.MULTI_DATE_WEEK_PREV = 13; BI.DateTrigger.MULTI_DATE_WEEK_AFTER = 14; BI.DateTrigger.MULTI_DATE_DAY_PREV = 15; BI.DateTrigger.MULTI_DATE_DAY_AFTER = 16; BI.DateTrigger.MULTI_DATE_DAY_TODAY = 17; BI.DateTrigger.MULTI_DATE_PARAM = 18; BI.DateTrigger.MULTI_DATE_CALENDAR = 19; BI.DateTrigger.MULTI_DATE_SEGMENT_NUM = {}; BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_PREV] = BI.i18nText("BI-Multi_Date_Year_Prev"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_AFTER] = BI.i18nText("BI-Multi_Date_Year_Next"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_BEGIN] = BI.i18nText("BI-Multi_Date_Year_Begin"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_YEAR_END] = BI.i18nText("BI-Multi_Date_Year_End"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_PREV] = BI.i18nText("BI-Multi_Date_Quarter_Prev"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_AFTER] = BI.i18nText("BI-Multi_Date_Quarter_Next"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_BEGIN] = BI.i18nText("BI-Multi_Date_Quarter_Begin"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_QUARTER_END] = BI.i18nText("BI-Multi_Date_Quarter_End"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_PREV] = BI.i18nText("BI-Multi_Date_Month_Prev"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_AFTER] = BI.i18nText("BI-Multi_Date_Month_Next"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_BEGIN] = BI.i18nText("BI-Multi_Date_Month_Begin"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_MONTH_END] = BI.i18nText("BI-Multi_Date_Month_End"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_WEEK_PREV] = BI.i18nText("BI-Multi_Date_Week_Prev"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_WEEK_AFTER] = BI.i18nText("BI-Multi_Date_Week_Next"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_DAY_PREV] = BI.i18nText("BI-Multi_Date_Day_Prev"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_DAY_AFTER] = BI.i18nText("BI-Multi_Date_Day_Next"); BI.DateTrigger.MULTI_DATE_SEGMENT_NUM[BI.DateTrigger.MULTI_DATE_DAY_TODAY] = BI.i18nText("BI-Multi_Date_Today"); BI.DateTrigger.EVENT_FOCUS = "EVENT_FOCUS"; BI.DateTrigger.EVENT_START = "EVENT_START"; BI.DateTrigger.EVENT_STOP = "EVENT_STOP"; BI.DateTrigger.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.DateTrigger.EVENT_CHANGE = "EVENT_CHANGE"; BI.DateTrigger.EVENT_VALID = "EVENT_VALID"; BI.DateTrigger.EVENT_ERROR = "EVENT_ERROR"; BI.DateTrigger.EVENT_TRIGGER_CLICK = "EVENT_TRIGGER_CLICK"; BI.DateTrigger.EVENT_KEY_DOWN = "EVENT_KEY_DOWN"; BI.shortcut("bi.date_trigger", BI.DateTrigger);/** * Created by zcf on 2017/2/20. */ BI.DatePaneWidget = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.DatePaneWidget.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-date-pane-widget", min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 selectedTime: null }) }, _init: function () { BI.DatePaneWidget.superclass._init.apply(this, arguments); var self = this, o = this.options; this.today = new Date(); this._year = this.today.getFullYear(); this._month = this.today.getMonth(); this.selectedTime = o.selectedTime || { year: this._year, month: this._month }; this.datePicker = BI.createWidget({ type: "bi.date_picker", min: o.min, max: o.max }); this.datePicker.on(BI.DatePicker.EVENT_CHANGE, function () { self.selectedTime = self.datePicker.getValue(); // self.selectedTime.day = 1; self.calendar.setSelect(BI.Calendar.getPageByDateJSON(self.selectedTime)); }); this.calendar = BI.createWidget({ direction: "top", element: this, logic: { dynamic: false }, type: "bi.navigation", tab: this.datePicker, cardCreator: BI.bind(this._createNav, this) // afterCardCreated: function () { // // }, // // afterCardShow: function () { // // this.setValue(self.selectedTime); // } }); this.calendar.on(BI.Navigation.EVENT_CHANGE, function () { self.selectedTime = self.calendar.getValue(); self.calendar.empty(); self.setValue(self.selectedTime); self.fireEvent(BI.DateCalendarPopup.EVENT_CHANGE); }); }, _createNav: function (v) { var date = BI.Calendar.getDateJSONByPage(v); var calendar = BI.createWidget({ type: "bi.calendar", logic: { dynamic: false }, min: this.options.min, max: this.options.max, year: date.year, month: date.month, day: this.selectedTime.day }); return calendar; }, _getNewCurrentDate: function () { var today = new Date(); return { year: today.getFullYear(), month: today.getMonth() } }, _setCalenderValue: function (date) { this.calendar.setSelect(BI.Calendar.getPageByDateJSON(date)); this.calendar.setValue(date); this.selectedTime = date; }, _setDatePicker: function (timeOb) { if (BI.isNull(timeOb) || BI.isNull(timeOb.year) || BI.isNull(timeOb.month)) { this.datePicker.setValue(this._getNewCurrentDate()); } else { this.datePicker.setValue(timeOb); } }, _setCalendar: function (timeOb) { if (BI.isNull(timeOb) || BI.isNull(timeOb.day)) { this.calendar.empty(); this._setCalenderValue(this._getNewCurrentDate()); } else { this._setCalenderValue(timeOb) } }, setValue: function (timeOb) { this._setDatePicker(timeOb); this._setCalendar(timeOb); }, getValue: function () { return this.selectedTime; } }); BI.shortcut("bi.date_pane_widget", BI.DatePaneWidget);/** * Created by Urthur on 2017/7/14. */ BI.DateTimeCombo = BI.inherit(BI.Single, { constants: { popupHeight: 290, popupWidth: 270, comboAdjustHeight: 1, border: 1, DATE_MIN_VALUE: "1900-01-01", DATE_MAX_VALUE: "2099-12-31" }, _defaultConfig: function () { return BI.extend(BI.DateTimeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-date-time-combo bi-border', height: 24 }); }, _init: function () { BI.DateTimeCombo.superclass._init.apply(this, arguments); var self = this, opts = this.options; var date = new Date(); this.storeValue = { year: date.getFullYear(), month: date.getMonth(), day: date.getDate(), hour: date.getHours(), minute: date.getMinutes(), second: date.getSeconds() }; this.trigger = BI.createWidget({ type: 'bi.date_time_trigger', min: this.constants.DATE_MIN_VALUE, max: this.constants.DATE_MAX_VALUE }); this.popup = BI.createWidget({ type: "bi.date_time_popup", min: this.constants.DATE_MIN_VALUE, max: this.constants.DATE_MAX_VALUE }); self.setValue(this.storeValue); this.popup.on(BI.DateTimePopup.BUTTON_CANCEL_EVENT_CHANGE, function () { self.setValue(self.storeValue); self.hidePopupView(); self.fireEvent(BI.DateTimeCombo.EVENT_CANCEL); }); this.popup.on(BI.DateTimePopup.BUTTON_OK_EVENT_CHANGE, function () { self.storeValue = self.popup.getValue(); self.setValue(self.storeValue); self.hidePopupView(); self.fireEvent(BI.DateTimeCombo.EVENT_CONFIRM); }); this.popup.on(BI.DateTimePopup.CALENDAR_EVENT_CHANGE, function () { self.trigger.setValue(self.popup.getValue()); self.fireEvent(BI.DateTimeCombo.EVENT_CHANGE); }); this.combo = BI.createWidget({ type: 'bi.combo', toggle: false, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, adjustLength: this.constants.comboAdjustHeight, popup: { el: this.popup, maxHeight: this.constants.popupHeight, width: this.constants.popupWidth, stopPropagation: false } }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.popup.setValue(self.storeValue); self.fireEvent(BI.DateTimeCombo.EVENT_BEFORE_POPUPVIEW); }); var triggerBtn = BI.createWidget({ type: "bi.trigger_icon_button", cls: "bi-trigger-date-button chart-date-normal-font bi-border-right", width: 30, height: 24 }); triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { if (self.combo.isViewVisible()) { self.combo.hideView(); } else { self.combo.showView(); } }); BI.createWidget({ type: "bi.htape", element: this, items: [{ type: "bi.absolute", items: [{ el: this.combo, top: 0, left: 0, right: 0, bottom: 0 }, { el: triggerBtn, top: 0, left: 0 }] }] }) }, setValue: function (v) { this.storeValue = v; this.popup.setValue(v); this.trigger.setValue(v); }, getValue: function () { return this.storeValue; }, hidePopupView: function () { this.combo.hideView(); } }); BI.DateTimeCombo.EVENT_CANCEL = "EVENT_CANCEL"; BI.DateTimeCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.DateTimeCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.DateTimeCombo.EVENT_BEFORE_POPUPVIEW = "BI.DateTimeCombo.EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.date_time_combo', BI.DateTimeCombo); /** * Created by Urthur on 2017/7/14. */ BI.CustomDateTimeCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.CustomDateTimeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-custom-date-time-combo" }) }, _init: function () { BI.CustomDateTimeCombo.superclass._init.apply(this, arguments); var self = this; this.DateTime = BI.createWidget({ type: "bi.date_time_combo", element: this }); this.DateTime.on(BI.DateTimeCombo.EVENT_CANCEL, function () { self.fireEvent(BI.CustomDateTimeCombo.EVENT_CHANGE); self.fireEvent(BI.CustomDateTimeCombo.EVENT_CANCEL); }); this.DateTime.on(BI.DateTimeCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.CustomDateTimeCombo.EVENT_CHANGE); self.fireEvent(BI.CustomDateTimeCombo.EVENT_CONFIRM); }); this.DateTime.on(BI.DateTimeCombo.EVENT_CHANGE, function () { self.fireEvent(BI.CustomDateTimeCombo.EVENT_CHANGE); }); }, getValue: function () { return this.DateTime.getValue(); }, setValue: function (v) { this.DateTime.setValue(v); } }); BI.CustomDateTimeCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.CustomDateTimeCombo.EVENT_CANCEL = "EVENT_CANCEL"; BI.CustomDateTimeCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.shortcut("bi.custom_date_time_combo", BI.CustomDateTimeCombo); /** * Created by Urthur on 2017/7/14. */ BI.DateTimePopup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DateTimePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-date-time-popup', width: 268, height: 290 }); }, _init: function () { BI.DateTimePopup.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.cancelButton = BI.createWidget({ type: 'bi.text_button', forceCenter: true, cls: 'bi-multidate-popup-button bi-border-top bi-border-right', shadow: true, text: BI.i18nText("BI-Basic_Cancel") }); this.cancelButton.on(BI.TextButton.EVENT_CHANGE, function () { self.fireEvent(BI.DateTimePopup.BUTTON_CANCEL_EVENT_CHANGE); }); this.okButton = BI.createWidget({ type: "bi.text_button", forceCenter: true, cls: 'bi-multidate-popup-button bi-border-top', shadow: true, text: BI.i18nText("BI-Basic_OK") }); this.okButton.on(BI.TextButton.EVENT_CHANGE, function () { self.fireEvent(BI.DateTimePopup.BUTTON_OK_EVENT_CHANGE); }); this.dateCombo = BI.createWidget({ type: "bi.date_calendar_popup", min: self.options.min, max: self.options.max }); self.dateCombo.on(BI.DateCalendarPopup.EVENT_CHANGE, function () { self.fireEvent(BI.DateTimePopup.CALENDAR_EVENT_CHANGE); }); this.dateSelect = BI.createWidget({ type: "bi.horizontal", cls: "bi-border-top", items: [{ type: "bi.label", text: BI.i18nText("BI-Basic_Time"), width: 45 },{ type: "bi.date_time_select", max: 23, min: 0, width: 60, height: 30, ref: function (_ref) { self.hour = _ref; self.hour.on(BI.DateTimeSelect.EVENT_CONFIRM, function () { self.fireEvent(BI.DateTimePopup.CALENDAR_EVENT_CHANGE); }); } },{ type: "bi.label", text: ":", width: 15 },{ type: "bi.date_time_select", max: 59, min: 0, width: 60, height: 30, ref: function (_ref) { self.minute = _ref; self.minute.on(BI.DateTimeSelect.EVENT_CONFIRM, function () { self.fireEvent(BI.DateTimePopup.CALENDAR_EVENT_CHANGE); }); } },{ type: "bi.label", text: ":", width: 15 },{ type: "bi.date_time_select", max: 59, min: 0, width: 60, height: 30, ref: function (_ref) { self.second = _ref; self.second.on(BI.DateTimeSelect.EVENT_CONFIRM, function () { self.fireEvent(BI.DateTimePopup.CALENDAR_EVENT_CHANGE); }); } }] }); var date = new Date(); this.dateCombo.setValue({ year: date.getFullYear(), month: date.getMonth(), day: date.getDate() }); this.hour.setValue(date.getHours()); this.minute.setValue(date.getMinutes()); this.second.setValue(date.getSeconds()); this.dateButton = BI.createWidget({ type: "bi.grid", items: [[this.cancelButton, this.okButton]] }); BI.createWidget({ element: this, type: "bi.vtape", items: [{ el: this.dateCombo }, { el: this.dateSelect, height: 50 },{ el: this.dateButton, height: 30 }] }); }, setValue: function (v) { var value = v, date; if (BI.isNull(value)) { date = new Date(); this.dateCombo.setValue({ year: date.getFullYear(), month: date.getMonth(), day: date.getDate() }); this.hour.setValue(date.getHours()); this.minute.setValue(date.getMinutes()); this.second.setValue(date.getSeconds()); } else { this.dateCombo.setValue({ year: value.year, month: value.month, day: value.day }); this.hour.setValue(value.hour); this.minute.setValue(value.minute); this.second.setValue(value.second); } }, getValue: function () { return { year: this.dateCombo.getValue().year, month: this.dateCombo.getValue().month, day: this.dateCombo.getValue().day, hour: this.hour.getValue(), minute: this.minute.getValue(), second: this.second.getValue() } } }); BI.DateTimePopup.BUTTON_OK_EVENT_CHANGE = "BUTTON_OK_EVENT_CHANGE"; BI.DateTimePopup.BUTTON_CANCEL_EVENT_CHANGE = "BUTTON_CANCEL_EVENT_CHANGE"; BI.DateTimePopup.CALENDAR_EVENT_CHANGE = "CALENDAR_EVENT_CHANGE"; BI.shortcut('bi.date_time_popup', BI.DateTimePopup); /** * Created by Urthur on 2017/7/14. */ BI.DateTimeSelect = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DateTimeSelect.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-date-time-select bi-border", max: 23, min: 0 }) }, _init: function () { BI.DateTimeSelect.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.sign_editor", value: this._alertInEditorValue(o.min), errorText: BI.i18nText("BI-Please_Input_Natural_Number"), validationChecker: function(v){ return BI.isNaturalNumber(v); } }); this.editor.on(BI.TextEditor.EVENT_CONFIRM, function(){ self._finetuning(0); self.fireEvent(BI.DateTimeSelect.EVENT_CONFIRM); }); this.topBtn = BI.createWidget({ type: "bi.icon_button", cls: "column-pre-page-h-font top-button bi-border-left bi-border-bottom" }); this.topBtn.on(BI.IconButton.EVENT_CHANGE, function(){ self._finetuning(1); self.fireEvent(BI.DateTimeSelect.EVENT_CONFIRM); }); this.bottomBtn = BI.createWidget({ type: "bi.icon_button", cls: "column-next-page-h-font bottom-button bi-border-left" }); this.bottomBtn.on(BI.IconButton.EVENT_CHANGE, function(){ self._finetuning(-1); self.fireEvent(BI.DateTimeSelect.EVENT_CONFIRM); }); this._finetuning(0); BI.createWidget({ type: "bi.htape", element: this, items: [this.editor, { el: { type: "bi.grid", columns: 1, rows: 2, items: [{ column: 0, row: 0, el: this.topBtn }, { column: 0, row: 1, el: this.bottomBtn }] }, width: 30 }] }); }, _alertOutEditorValue: function(v){ if (v > this.options.max){ v = this.options.min; } if (v < this.options.min){ v = this.options.max } return BI.parseInt(v); }, _alertInEditorValue: function(v){ if (v > this.options.max){ v = this.options.min; } if (v < this.options.min){ v = this.options.max; } v = v < 10 ? "0" + v : v; return v; }, _finetuning: function(add){ var v = BI.parseInt(this._alertOutEditorValue(this.editor.getValue())); this.editor.setValue(this._alertInEditorValue(v + add)); }, getValue: function () { var v = this.editor.getValue(); return this._alertOutEditorValue(v); }, setValue: function (v) { this.editor.setValue(this._alertInEditorValue(v)); this._finetuning(0); } }); BI.DateTimeSelect.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.shortcut("bi.date_time_select", BI.DateTimeSelect);/** * Created by Urthur on 2017/7/14. */ BI.DateTimeTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, triggerWidth: 30 }, _defaultConfig: function () { return BI.extend(BI.DateTimeTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-date-time-trigger", min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 height: 24, width: 200 }); }, _init: function () { BI.DateTimeTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.text = BI.createWidget({ type: "bi.label", textAlign: "left", height: o.height, width: o.width, hgap: c.hgap }); BI.createWidget({ type: "bi.htape", element: this, items: [{ el: BI.createWidget(), width: c.triggerWidth }, { el: this.text }] }) }, _printTime: function (v) { return v < 10 ? "0" + v : v; }, setValue: function (v) { var self = this; var value = v, dateStr; if(BI.isNull(value)){ value = new Date(); dateStr = value.print("%Y-%X-%d %H:%M:%S"); } else { var date = new Date(value.year,value.month,value.day,value.hour,value.minute,value.second); dateStr = date.print("%Y-%X-%d %H:%M:%S"); } this.text.setText(dateStr); this.text.setTitle(dateStr); } }); BI.shortcut("bi.date_time_trigger", BI.DateTimeTrigger);/** * 带有方向的pathchooser * * Created by GUY on 2016/4/21. * @class BI.DirectionPathChooser * @extends BI.Widget */ BI.DirectionPathChooser = BI.inherit(BI.Widget, { _const: { lineColor: "#808080", selectLineColor: "#009de3" }, _defaultConfig: function () { return BI.extend(BI.DirectionPathChooser.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-excel-table", items: [] }); }, _init: function () { BI.DirectionPathChooser.superclass._init.apply(this, arguments); var self = this, o = this.options; this.pathChooser = BI.createWidget({ type: "bi.path_chooser", element: this, items: o.items }); this.pathChooser.on(BI.PathChooser.EVENT_CHANGE, function (start, index) { //self._unselectAllArrows(); self._setValue(start, index); self.fireEvent(BI.DirectionPathChooser.EVENT_CHANGE); }); this._drawArrows(); }, _unselectAllArrows: function () { var self = this, lineColor = this._const.lineColor; BI.each(this.arrows, function (region, rs) { BI.each(rs, function (idx, arrows) { BI.each(arrows, function (i, arrow) { arrow.attr({fill: lineColor, stroke: lineColor}); }); }); }); }, _drawOneArrow: function (dot, direction) { //0,1,2,3 上右下左 var lineColor = this._const.lineColor; var selectLineColor = this._const.selectLineColor; var svg = this.pathChooser.svg; var path = ""; switch (direction) { case 0: path = "M" + dot.x + "," + dot.y + "L" + (dot.x - 3) + "," + (dot.y + 5) + "L" + (dot.x + 3) + "," + (dot.y + 5) + "L" + dot.x + "," + dot.y; break; case 1: path = "M" + dot.x + "," + dot.y + "L" + (dot.x - 5) + "," + (dot.y - 3) + "L" + (dot.x - 5) + "," + (dot.y + 3) + "L" + dot.x + "," + dot.y; break; case 2: path = "M" + dot.x + "," + dot.y + "L" + (dot.x - 3) + "," + (dot.y - 5) + "L" + (dot.x + 3) + "," + (dot.y - 5) + "L" + dot.x + "," + dot.y; break; case 3: path = "M" + dot.x + "," + dot.y + "L" + (dot.x + 5) + "," + (dot.y - 3) + "L" + (dot.x + 5) + "," + (dot.y + 3) + "L" + dot.x + "," + dot.y; break; } return svg.path(path).attr({fill: lineColor, stroke: lineColor}); }, _drawArrows: function () { var self = this, o = this.options; var routes = this.pathChooser.routes; var pathes = this.pathChooser.pathes; var store = this.pathChooser.store; this.arrows = {}; BI.each(routes, function (region, ps) { self.arrows[region] = []; BI.each(ps, function (idx, path) { self.arrows[region][idx] = []; var dots = pathes[region][idx]; BI.each(dots, function (i, dot) { if (i > 0 && i < dots.length - 1) { var arrow; if (dot.y === dots[i - 1].y) { if (dots[i + 1].y != dot.y) { if (store[path[path.length - 2]].direction === -1) { if (i - 1 > 0) { arrow = self._drawOneArrow(dots[i - 1], 3); } } else { arrow = self._drawOneArrow(dots[i], 1); } } } else if (dot.x === dots[i - 1].x) { if (dot.y > dots[i - 1].y) { if (store[BI.first(path)].direction === -1) { arrow = self._drawOneArrow(dots[i - 1], 0); } else { arrow = self._drawOneArrow(dot, 2); } } else { if (store[path[path.length - 2]].direction === -1) { arrow = self._drawOneArrow(dots[i - 1], 2); } else { arrow = self._drawOneArrow(dot, 0); } } } if (arrow) { self.arrows[region][idx].push(arrow); } } }); BI.each(path, function (i, node) { if (i !== 0) { var arrow; var from = path[i - 1]; if (store[from].direction === -1) { var regionIndex = self.pathChooser.getRegionIndexById(from); var x = getXoffsetByRegionIndex(regionIndex, -1); var y = getYByXoffset(dots, x); arrow = self._drawOneArrow({x: x, y: y}, 3); } else { var regionIndex = self.pathChooser.getRegionIndexById(node); var x = getXoffsetByRegionIndex(regionIndex); var y = getYByXoffset(dots, x); arrow = self._drawOneArrow({x: x, y: y}, 1); } if (arrow) { self.arrows[region][idx].push(arrow); } } }); }) }); function getXoffsetByRegionIndex(regionIndex, diregion) { if (diregion === -1) { return 100 * (regionIndex + 1) - 20; } return 100 * regionIndex + 20; } function getYByXoffset(dots, xoffset) { var finded = BI.find(dots, function (i, dot) { if (i > 0) { if (dots[i - 1].x < xoffset && dots[i].x > xoffset) { return true; } } }); return finded.y; } }, _setValue: function (start, index) { var self = this; var lineColor = this._const.lineColor; var selectLineColor = this._const.selectLineColor; var routes = this.pathChooser.routes; var starts = this.pathChooser.start; var each = [start]; if (starts.contains(start)) { each = starts; } BI.each(each, function (i, s) { BI.each(self.arrows[s], function (j, arrows) { BI.each(arrows, function (k, arrow) { arrow.attr({fill: lineColor, stroke: lineColor}).toFront(); }); }); }); BI.each(this.arrows[start][index], function (i, arrow) { arrow.attr({fill: selectLineColor, stroke: selectLineColor}).toFront(); }); var current = BI.last(routes[start][index]); while (current && routes[current] && routes[current].length === 1) { BI.each(self.arrows[current][0], function (i, arrow) { arrow.attr({fill: selectLineColor, stroke: selectLineColor}).toFront(); }); current = BI.last(routes[current][0]); } }, setValue: function (v) { this.pathChooser.setValue(v); this._unselectAllArrows(); var routes = this.pathChooser.routes; var nodes = BI.keys(routes), self = this; var result = [], array = []; BI.each(v, function (i, val) { if (BI.contains(nodes, val)) { if (array.length > 0) { array.push(val); result.push(array); array = []; } } array.push(val); }); if (array.length > 0) { result.push(array); } //画这n条路径 BI.each(result, function (idx, path) { var start = path[0]; var index = BI.findIndex(routes[start], function (idx, p) { if (BI.isEqual(path, p)) { return true; } }); if (index >= 0) { self._setValue(start, index); } }); }, getValue: function () { return this.pathChooser.getValue(); }, populate: function (items) { this.pathChooser.populate(items); this._drawArrows(); } }); BI.DirectionPathChooser.EVENT_CHANGE = "DirectionPathChooser.EVENT_CHANGE"; BI.shortcut('bi.direction_path_chooser', BI.DirectionPathChooser);/** * Created by roy on 15/8/14. */ BI.DownListCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.DownListCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-down-list-combo", invalid: false, height: 25, items: [], adjustLength: 0, direction: "bottom", trigger: "click", el: {} }) }, _init: function () { BI.DownListCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.popupview = BI.createWidget({ type: "bi.down_list_popup", items: o.items, chooseType: o.chooseType }); this.popupview.on(BI.DownListPopup.EVENT_CHANGE, function (value) { self.fireEvent(BI.DownListCombo.EVENT_CHANGE, value); self.downlistcombo.hideView(); }); this.popupview.on(BI.DownListPopup.EVENT_SON_VALUE_CHANGE, function (value, fatherValue) { self.fireEvent(BI.DownListCombo.EVENT_SON_VALUE_CHANGE, value, fatherValue); self.downlistcombo.hideView(); }); this.downlistcombo = BI.createWidget({ element: this, type: 'bi.combo', trigger: o.trigger, isNeedAdjustWidth: false, adjustLength: o.adjustLength, direction: o.direction, el: BI.createWidget(o.el, { type: "bi.icon_trigger", extraCls: o.iconCls ? o.iconCls : "pull-down-font", width: o.width, height: o.height }), popup: { el: this.popupview, stopPropagation: true, maxHeight: 1000 } }); this.downlistcombo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.DownListCombo.EVENT_BEFORE_POPUPVIEW); }); }, hideView: function () { this.downlistcombo.hideView(); }, showView: function () { this.downlistcombo.showView(); }, populate: function (items) { this.popupview.populate(items); }, setValue: function (v) { this.popupview.setValue(v); }, getValue: function () { return this.popupview.getValue() } }); BI.DownListCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.DownListCombo.EVENT_SON_VALUE_CHANGE = "EVENT_SON_VALUE_CHANGE"; BI.DownListCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut("bi.down_list_combo", BI.DownListCombo);/** * Created by roy on 15/9/6. */ BI.DownListGroup = BI.inherit(BI.Widget, { constants: { iconCls: "check-mark-ha-font" }, _defaultConfig: function () { return BI.extend(BI.DownListGroup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-down-list-group", items: [ { el: {} } ] }) }, _init: function () { BI.DownListGroup.superclass._init.apply(this, arguments); var o = this.options, self = this; this.downlistgroup = BI.createWidget({ element: this, type: "bi.button_tree", items: o.items, chooseType: 0,//0单选,1多选 layouts: [{ type: "bi.vertical", hgap: 0, vgap: 0 }] }); this.downlistgroup.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if(type === BI.Events.CLICK) { self.fireEvent(BI.DownListGroup.EVENT_CHANGE, arguments); } }) }, getValue:function(){ return this.downlistgroup.getValue(); }, setValue:function(v){ this.downlistgroup.setValue(v); } }) BI.DownListGroup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.down_list_group", BI.DownListGroup);BI.DownListItem = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.DownListItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-down-list-item bi-list-item-active", cls: "", height: 25, logic: { dynamic: true }, selected: false, iconHeight: null, iconWidth: null, textHgap: 0, textVgap: 0, textLgap: 0, textRgap: 0 }) }, _init: function () { BI.DownListItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.text = BI.createWidget({ type: "bi.icon_text_item", element: this, height: o.height, text: o.text, value: o.value, logic: o.logic, selected: o.selected, disabled: o.disabled, iconHeight: o.iconHeight, iconWidth: o.iconWidth, textHgap: o.textHgap, textVgap: o.textVgap, textLgap: o.textLgap, textRgap: o.textRgap, father: o.father }); this.text.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.text.on(BI.IconTextItem.EVENT_CHANGE, function () { self.fireEvent(BI.DownListItem.EVENT_CHANGE); }); // this.setSelected(o.selected); }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, isSelected: function () { return this.text.isSelected(); }, setSelected: function (b) { this.text.setSelected(b); // if (b === true) { // this.element.addClass("dot-e-font"); // } else { // this.element.removeClass("dot-e-font"); // } }, setValue: function (v) { this.text.setValue(v); }, getValue: function () { return this.text.getValue(); } }); BI.DownListItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.down_list_item", BI.DownListItem);BI.DownListGroupItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.DownListGroupItem.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-down-list-group-item", logic: { dynamic: false }, // invalid: true, iconCls1: "dot-e-font", iconCls2: "pull-right-e-font" }) }, _init: function () { BI.DownListGroupItem.superclass._init.apply(this, arguments); var o = this.options; var self = this; this.text = BI.createWidget({ type: "bi.label", cls: "list-group-item-text", textAlign: "left", text: o.text, value: o.value, height: o.height }); this.icon1 = BI.createWidget({ type: "bi.icon_button", cls: o.iconCls1, width: 25, forceNotSelected: true }); this.icon2 = BI.createWidget({ type: "bi.icon_button", cls: o.iconCls2, width: 25, forceNotSelected: true }); var blank = BI.createWidget({ type: "bi.layout", width: 25 }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.icon2, top: 0, bottom: 0, right: 0 }] }); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic("horizontal", BI.extend(o.logic, { items: BI.LogicFactory.createLogicItemsByDirection("left", this.icon1, this.text, blank) })))); this.element.hover(function () { if (self.isEnabled()) { self.hover(); } }, function () { if (self.isEnabled()) { self.dishover() } }); }, hover: function () { BI.DownListGroupItem.superclass.hover.apply(this, arguments); this.icon1.element.addClass("hover"); this.icon2.element.addClass("hover"); }, dishover: function () { BI.DownListGroupItem.superclass.dishover.apply(this, arguments); this.icon1.element.removeClass("hover"); this.icon2.element.removeClass("hover"); }, doClick: function () { BI.DownListGroupItem.superclass.doClick.apply(this, arguments); if (this.isValid()) { this.fireEvent(BI.DownListGroupItem.EVENT_CHANGE, this.getValue()); } }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, setValue: function (v) { var self = this, o = this.options; v = BI.isArray(v) ? v : [v]; BI.find(v, function (idx, value) { if (BI.contains(o.childValues, value)) { self.icon1.setSelected(true); return true; } else { self.icon1.setSelected(false); } }) } }); BI.DownListGroupItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.down_list_group_item", BI.DownListGroupItem);/** * Created by roy on 15/9/8. * 处理popup中的item分组样式 * 一个item分组中的成员大于一时,该分组设置为单选,并且默认状态第一个成员设置为已选择项 */ BI.DownListPopup = BI.inherit(BI.Pane, { constants: { nextIcon: "pull-right-e-font", height: 25, iconHeight: 12, iconWidth: 12, hgap: 0, vgap: 0, border: 1 }, _defaultConfig: function () { var conf = BI.DownListPopup.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: "bi-down-list-popup", items: [], chooseType: BI.Selection.Multi }) }, _init: function () { BI.DownListPopup.superclass._init.apply(this, arguments); this.singleValues = []; this.childValueMap = {}; this.fatherValueMap = {}; var self = this, o = this.options, children = this._createChildren(o.items); this.popup = BI.createWidget({ type: "bi.button_tree", items: BI.createItems(children, {}, { adjustLength: -2 } ), layouts: [{ type: "bi.vertical", hgap: this.constants.hgap, vgap: this.constants.vgap }], chooseType: o.chooseType }); this.popup.on(BI.ButtonTree.EVENT_CHANGE, function (value, object) { var changedValue = value; if (BI.isNotNull(self.childValueMap[value])) { changedValue = self.childValueMap[value]; self.fireEvent(BI.DownListPopup.EVENT_SON_VALUE_CHANGE, changedValue, self.fatherValueMap[value]) } else { self.fireEvent(BI.DownListPopup.EVENT_CHANGE, changedValue, object); } if (!self.singleValues.contains(changedValue)) { var item = self.getValue(); var result = []; BI.each(item, function (i, valueObject) { if (valueObject.value != changedValue) { result.push(valueObject); } }); self.setValue(result); } }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.popup] }); }, _createChildren: function (items) { var self = this, result = []; BI.each(items, function (i, it) { var item_done = { type: "bi.down_list_group", items: [] }; BI.each(it, function (i, item) { if (BI.isNotEmptyArray(item.children) && !BI.isEmpty(item.el)) { item.type = "bi.combo_group"; item.cls = "down-list-group"; item.trigger = "hover"; item.isNeedAdjustWidth = false; item.el.title = item.el.title || item.el.text; item.el.type = "bi.down_list_group_item"; item.el.logic = { dynamic: true }; item.el.height = self.constants.height; item.el.iconCls2 = self.constants.nextIcon; item.popup = { lgap: 4, el: { type: "bi.button_tree", chooseType: 0, layouts: [{ type: "bi.vertical" }] } }; item.el.childValues = []; BI.each(item.children, function (i, child) { var fatherValue = BI.deepClone(item.el.value); var childValue = BI.deepClone(child.value); self.singleValues.push(child.value); child.type = "bi.down_list_item"; child.extraCls = " child-down-list-item"; child.title = child.title || child.text; child.textRgap = 10; child.isNeedAdjustWidth = false; child.logic = { dynamic: true }; child.father = fatherValue; self.fatherValueMap[self._createChildValue(fatherValue, childValue)] = fatherValue; self.childValueMap[self._createChildValue(fatherValue, childValue)] = childValue; child.value = self._createChildValue(fatherValue, childValue); item.el.childValues.push(child.value); }) } else { item.type = "bi.down_list_item"; item.title = item.title || item.text; item.textRgap = 10; item.isNeedAdjustWidth = false; item.logic = { dynamic: true } } var el_done = {}; el_done.el = item; item_done.items.push(el_done); }); if (self._isGroup(item_done.items)) { BI.each(item_done.items, function (i, item) { self.singleValues.push(item.el.value); }) } result.push(item_done); if (self._needSpliter(i, items.length)) { var spliter_container = BI.createWidget({ type: "bi.vertical", items: [{ el: { type: "bi.layout", cls: "bi-down-list-spliter bi-border-top cursor-pointer", height: 0 } }], cls: "bi-down-list-spliter-container cursor-pointer", lgap: 10, rgap: 10 }); result.push(spliter_container); } }); return result; }, _isGroup: function (i) { return i.length > 1; }, _needSpliter: function (i, itemLength) { return i < itemLength - 1; }, _createChildValue: function (fatherValue, childValue) { return fatherValue + "_" + childValue }, populate: function (items) { BI.DownListPopup.superclass.populate.apply(this, arguments); var self = this; self.childValueMap = {}; self.fatherValueMap = {}; self.singleValues = []; var children = self._createChildren(items); var popupItem = BI.createItems(children, {}, { adjustLength: -2 } ); self.popup.populate(popupItem); }, setValue: function (valueItem) { var self = this; var valueArray = []; BI.each(valueItem, function (i, item) { var value; if (BI.isNotNull(item.childValue)) { value = self._createChildValue(item.value, item.childValue); } else { value = item.value; } valueArray.push(value); } ); this.popup.setValue(valueArray); }, getValue: function () { var self = this, result = []; var values = this.popup.getValue(); BI.each(values, function (i, value) { var valueItem = {}; if (BI.isNotNull(self.childValueMap[value])) { var fartherValue = self.fatherValueMap[value]; valueItem.childValue = self.childValueMap[value]; valueItem.value = fartherValue; } else { valueItem.value = value; } result.push(valueItem); }); return result; } }); BI.DownListPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.DownListPopup.EVENT_SON_VALUE_CHANGE = "EVENT_SON_VALUE_CHANGE"; BI.shortcut("bi.down_list_popup", BI.DownListPopup);/** * * Created by GUY on 2016/3/28. * @class BI.ExcelTableCell * @extends BI.Widget */ BI.ExcelTableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ExcelTableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-excel-table-cell", text: "" }); }, _init: function () { BI.ExcelTableCell.superclass._init.apply(this, arguments); var self = this, o = this.options; BI.createWidget({ type: "bi.label", element: this, textAlign: "left", whiteSpace: "normal", height: this.options.height, text: this.options.text, value: this.options.value }) } }); BI.shortcut('bi.excel_table_cell', BI.ExcelTableCell);/** * * Created by GUY on 2016/3/28. * @class BI.ExcelTableHeaderCell * @extends BI.Widget */ BI.ExcelTableHeaderCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ExcelTableHeaderCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-excel-table-header-cell bi-background", text: "" }); }, _init: function () { BI.ExcelTableHeaderCell.superclass._init.apply(this, arguments); var self = this, o = this.options; BI.createWidget({ type: "bi.label", element: this, textAlign: BI.HorizontalAlign.Center, whiteSpace: "normal", height: this.options.height, text: this.options.text, value: this.options.value }) } }); BI.shortcut('bi.excel_table_header_cell', BI.ExcelTableHeaderCell);/** * Excel表格 * * Created by GUY on 2016/3/28. * @class BI.ExcelTable * @extends BI.Widget */ BI.ExcelTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.ExcelTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-excel-table", el: { type: "bi.responsive_table" }, isNeedResize: false, isResizeAdapt: true, isNeedMerge: false,//是否需要合并单元格 mergeCols: [], //合并的单元格列号 mergeRule: function (row1, row2) { //合并规则, 默认相等时合并 return BI.isEqual(row1, row2); }, columnSize: [], headerRowSize: 37, footerRowSize: 37, rowSize: 37, regionColumnSize: false, items: [] //二维数组 }); }, _init: function () { BI.ExcelTable.superclass._init.apply(this, arguments); var self = this, o = this.options; var mergeCols = []; BI.each(o.mergeCols, function (i, col) { mergeCols.push(col + 1); }); this.table = BI.createWidget(o.el, { type: "bi.table_view", element: this, isNeedFreeze: false, isNeedMerge: o.isNeedMerge, mergeCols: mergeCols, mergeRule: o.mergeRule, columnSize: [""].concat(o.columnSize), headerRowSize: 18, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize || [82, ""] }); if (BI.isNotEmptyArray(o.items)) { this.populate(o.items); } BI.nextTick(function () { self.setRegionColumnSize(o.regionColumnSize || [82, ""]); }); }, resize: function () { this.table.resize(); }, setColumnSize: function (columnSize) { this.table.setColumnSize(columnSize); }, getColumnSize: function () { return this.table.getColumnSize(); }, getCalculateColumnSize: function () { return this.table.getCalculateColumnSize(); }, setHeaderColumnSize: function (columnSize) { this.table.setHeaderColumnSize(columnSize); }, setRegionColumnSize: function (columnSize) { this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, getCalculateRegionColumnSize: function () { return this.table.getCalculateRegionColumnSize(); }, getCalculateRegionRowSize: function () { return this.table.getCalculateRegionRowSize(); }, getClientRegionColumnSize: function () { return this.table.getClientRegionColumnSize(); }, getScrollRegionColumnSize: function () { return this.table.getScrollRegionColumnSize(); }, getScrollRegionRowSize: function () { return this.table.getScrollRegionRowSize(); }, hasVerticalScroll: function () { return this.table.hasVerticalScroll(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, getColumns: function () { return this.table.getColumns(); }, resizeHeader: function () { this.table.resize(); this.table._resizeHeader && this.table._resizeHeader(); }, attr: function (key,value) { var self = this; if (BI.isObject(key)) { BI.each(key, function (k, v) { self.attr(k, v); }); return; } BI.ExcelTable.superclass.attr.apply(this, arguments); switch (key){ case "mergeCols": var mCols = []; BI.each(value, function (i, col) { mCols.push(col + 1); }); value=mCols; break; } this.table.attr.apply(this.table, arguments); }, populate: function (rows) { var self = this; var columnSize = this.getColumnSize(); var items = []; var header = [{ type: "bi.excel_table_header_cell" }]; if (BI.isNotNull(rows)) { BI.each(columnSize, function (i, size) { header.push({ type: "bi.excel_table_header_cell", text: BI.int2Abc(i + 1) }); }); BI.each(rows, function (i, row) { items.push([{ type: "bi.excel_table_header_cell", text: (i + 1) }].concat(row)); }); } this.table.populate(items, [header]); }, destroy: function () { this.table.destroy(); BI.ExcelTable.superclass.destroy.apply(this, arguments); } }); BI.shortcut('bi.excel_table', BI.ExcelTable);/** * 文件管理控件组 * * Created by GUY on 2015/12/11. * @class BI.FileManagerButtonGroup * @extends BI.Widget */ BI.FileManagerButtonGroup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FileManagerButtonGroup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager-button_group", items: [] }) }, _init: function () { BI.FileManagerButtonGroup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.button_group = BI.createWidget({ type: "bi.button_tree", element: this, chooseType: BI.Selection.Multi, items: this._formatItems(o.items), layouts: [{ type: "bi.vertical" }] }); this.button_group.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, _formatItems: function (items) { var self = this, o = this.options; BI.each(items, function (i, item) { if (item.children && item.children.length > 0) { item.type = "bi.file_manager_folder_item"; } else { item.type = "bi.file_manager_file_item"; } }); return items; }, setValue: function (v) { this.button_group.setValue(v); }, getValue: function () { return this.button_group.getValue(); }, getNotSelectedValue: function () { return this.button_group.getNotSelectedValue(); }, getAllLeaves: function () { return this.button_group.getAllLeaves(); }, getAllButtons: function () { return this.button_group.getAllButtons(); }, getSelectedButtons: function () { return this.button_group.getSelectedButtons(); }, getNotSelectedButtons: function () { return this.button_group.getNotSelectedButtons(); }, populate: function (items) { this.button_group.populate(this._formatItems(items)); } }); BI.FileManagerButtonGroup.EVENT_CHANGE = "FileManagerButtonGroup.EVENT_CHANGE"; BI.shortcut("bi.file_manager_button_group", BI.FileManagerButtonGroup);/** * 文件管理控件 * * Created by GUY on 2015/12/11. * @class BI.FileManager * @extends BI.Widget */ BI.FileManager = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FileManager.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager", el: {}, items: [] }) }, _init: function () { BI.FileManager.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tree = new BI.Tree(); var items = BI.Tree.transformToTreeFormat(o.items); this.tree.initTree(items); this.selectedValues = []; this.nav = BI.createWidget({ type: "bi.file_manager_nav", items: BI.deepClone(items) }); this.nav.on(BI.FileManagerNav.EVENT_CHANGE, function (value, obj) { if (value == "-1") {//根节点 self.populate({children: self.tree.toJSON()}); } else { var node = self.tree.search(obj.attr("id")); self.populate(BI.extend({id: node.id}, node.get("data"), {children: self.tree.toJSON(node)})); } self.setValue(self.selectedValues); }); this.list = BI.createWidget(o.el, { type: "bi.file_manager_list", items: items }); this.list.on(BI.Controller.EVENT_CHANGE, function (type, selected, obj) { if (type === BI.Events.CHANGE) { var node = self.tree.search(obj.attr("id")); self.populate(BI.extend({id: node.id}, node.get("data"), {children: self.tree.toJSON(node)})); } else if (type === BI.Events.CLICK) { var values = []; if (obj instanceof BI.MultiSelectBar) { var t = self.list.getValue(); selected = t.type === BI.Selection.All; values = BI.concat(t.assist, t.value); } else { values = obj.getAllLeaves(); } BI.each(values, function (i, v) { if (selected === true) { self.selectedValues.pushDistinct(v); } else { self.selectedValues.remove(v); } }); } self.setValue(self.selectedValues); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.list, left: 0, right: 0, top: 0, bottom: 10 }, { el: this.nav, left: 40, right: 100, top: 0 }] }); }, setValue: function (value) { this.selectedValues = value || []; this.list.setValue(this.selectedValues); }, getValue: function () { var obj = this.list.getValue(); var res = obj.type === BI.Selection.All ? obj.assist : obj.value; res.pushDistinctArray(this.selectedValues); return res; }, _populate: function (items) { this.list.populate(items); }, getSelectedValue: function () { return this.nav.getValue()[0]; }, getSelectedId: function () { return this.nav.getId()[0]; }, populate: function (node) { var clone = BI.deepClone(node); this._populate(node.children); this.nav.populate(clone); } }); BI.FileManager.EVENT_CHANGE = "FileManager.EVENT_CHANGE"; BI.shortcut("bi.file_manager", BI.FileManager);/** * 文件管理控件 * * Created by GUY on 2015/12/11. * @class BI.FileManagerFileItem * @extends BI.Single */ BI.FileManagerFileItem = BI.inherit(BI.Single, { _defaultConfig: function () { return BI.extend(BI.FileManagerFileItem.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager-file-item bi-list-item bi-border-bottom", height: 30 }) }, _init: function () { BI.FileManagerFileItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checked = BI.createWidget({ type: "bi.multi_select_bar", text: "", width: 36, height: o.height }); this.checked.on(BI.Controller.EVENT_CHANGE, function () { arguments[2] = self; self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); BI.createWidget({ type: "bi.htape", element: this, items: [{ el: this.checked, width: 36 }, { el: { type: "bi.icon_button", cls: "create-by-me-file-font" }, width: 20 }, { el: { type: "bi.label", textAlign: "left", height: o.height, text: o.text, value: o.value } }] }) }, getAllLeaves: function(){ return [this.options.value]; }, isSelected: function () { return this.checked.isSelected(); }, setSelected: function (v) { this.checked.setSelected(v); } }); BI.FileManagerFileItem.EVENT_CHANGE = "FileManagerFileItem.EVENT_CHANGE"; BI.shortcut("bi.file_manager_file_item", BI.FileManagerFileItem);/** * 文件管理控件 * * Created by GUY on 2015/12/11. * @class BI.FileManagerFolderItem * @extends BI.Single */ BI.FileManagerFolderItem = BI.inherit(BI.Single, { _defaultConfig: function () { return BI.extend(BI.FileManagerFolderItem.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager-folder-item bi-list-item bi-border-bottom", height: 30 }) }, _init: function () { BI.FileManagerFolderItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checked = BI.createWidget({ type: "bi.multi_select_bar", text: "", width: 36, height: o.height }); this.checked.on(BI.Controller.EVENT_CHANGE, function () { arguments[2] = self; self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.button = BI.createWidget({ type: "bi.text_button", textAlign: "left", height: o.height, text: o.text, value: o.value }); this.button.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.CHANGE, o.value, self); }); this.tree = new BI.Tree(); this.tree.initTree([{ id: o.id, children: o.children }]); this.selectValue = []; BI.createWidget({ type: "bi.htape", element: this, items: [{ el: this.checked, width: 36 }, { el: { type: "bi.icon_button", cls: "create-by-me-folder-font" }, width: 20 }, { el: this.button }] }) }, setAllSelected: function (v) { this.checked.setSelected(v); this.selectValue = []; }, setHalfSelected: function (v) { this.checked.setHalfSelected(v); if(!v){ this.selectValue = []; } }, setValue: function (v) { var self = this, o = this.options; var isHalf = false; var selectValue = []; this.tree.traverse(function (node) { if (node.isLeaf()) { if (BI.contains(v, node.get("data").value)) { selectValue.push(node.get("data").value); } else { isHalf = true; } } }); this.setAllSelected(selectValue.length > 0 && !isHalf); this.setHalfSelected(selectValue.length > 0 && isHalf); if (this.checked.isHalfSelected()) { this.selectValue = selectValue; } }, getAllButtons: function () { return [this]; }, getAllLeaves: function () { var o = this.options; var res = []; this.tree.traverse(function (node) { if (node.isLeaf()) { res.push(node.get("data").value) } }); return res; }, getNotSelectedValue: function () { var self = this, o = this.options; var res = []; var isAllSelected = this.checked.isSelected(); if (isAllSelected === true) { return res; } var isHalfSelected = this.checked.isHalfSelected(); this.tree.traverse(function (node) { if (node.isLeaf()) { var v = node.get("data").value; if (isHalfSelected === true) { if (!BI.contains(self.selectValue, node.get("data").value)) { res.push(v); } } else { res.push(v); } } }); return res; }, getValue: function () { var res = []; if (this.checked.isSelected()) { this.tree.traverse(function (node) { if (node.isLeaf()) { res.push(node.get("data").value); } }); return res; } if (this.checked.isHalfSelected()) { return this.selectValue; } return []; } }); BI.FileManagerFolderItem.EVENT_CHANGE = "FileManagerFolderItem.EVENT_CHANGE"; BI.shortcut("bi.file_manager_folder_item", BI.FileManagerFolderItem);/** * 文件管理控件列表 * * Created by GUY on 2015/12/11. * @class BI.FileManagerList * @extends BI.Widget */ BI.FileManagerList = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FileManagerList.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager-list", el: {}, items: [] }) }, _init: function () { BI.FileManagerList.superclass._init.apply(this, arguments); var self = this, o = this.options; this.list = BI.createWidget({ type: "bi.select_list", element: this, items: o.items, toolbar: { type: "bi.multi_select_bar", height: 40, text: "" }, el: { type: "bi.list_pane", el: BI.isWidget(o.el) ? o.el : BI.extend({ type: "bi.file_manager_button_group" }, o.el) } }); this.list.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, setValue: function (v) { this.list.setValue({ value: v }); }, getValue: function () { return this.list.getValue(); }, populate: function (items) { this.list.populate(items); this.list.setToolBarVisible(true); } }); BI.FileManagerList.EVENT_CHANGE = "FileManagerList.EVENT_CHANGE"; BI.shortcut("bi.file_manager_list", BI.FileManagerList);/** * 文件管理导航按钮 * * Created by GUY on 2015/12/11. * @class BI.FileManagerNavButton * @extends BI.Widget */ BI.FileManagerNavButton = BI.inherit(BI.Widget, { _const: { normal_color: "#ffffff", select_color: "#eff1f4" }, _defaultConfig: function () { return BI.extend(BI.FileManagerNavButton.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager-nav-button", selected: false, height: 40 }) }, _init: function () { BI.FileManagerNavButton.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.button = BI.createWidget({ type: "bi.text_button", cls: "file-manager-nav-button-text bi-card", once: true, selected: o.selected, text: o.text, title: o.text, value: o.value, height: o.height, lgap: 20, rgap: 10 }); this.button.on(BI.Controller.EVENT_CHANGE, function () { arguments[2] = self; self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var svg = BI.createWidget({ type: "bi.svg", cls: "file-manager-nav-button-triangle", width: 15, height: o.height }); var path = svg.path("M0,0L15,20L0,40").attr({ "stroke": c.select_color, "fill": o.selected ? c.select_color : c.normal_color }); this.button.on(BI.TextButton.EVENT_CHANGE, function () { if (this.isSelected()) { path.attr("fill", c.select_color); } else { path.attr("fill", c.normal_color); } }); BI.createWidget({ type: "bi.default", element: this, items: [this.button] }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: svg, right: -15, top: 0, bottom: 0 }] }) }, isSelected: function () { return this.button.isSelected(); }, setValue: function (v) { this.button.setValue(v); }, getValue: function () { return this.button.getValue(); }, populate: function (items) { } }); BI.FileManagerNavButton.EVENT_CHANGE = "FileManagerNavButton.EVENT_CHANGE"; BI.shortcut("bi.file_manager_nav_button", BI.FileManagerNavButton);/** * 文件管理导航 * * Created by GUY on 2015/12/11. * @class BI.FileManagerNav * @extends BI.Widget */ BI.FileManagerNav = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FileManagerNav.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-file-manager-nav bi-border-left", height: 40, items: [] }) }, _init: function () { BI.FileManagerNav.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tree = new BI.Tree(); this.refreshTreeData(o.items); this.tree.getRoot().set("data", { text: BI.i18nText("BI-Created_By_Me"), value: BI.FileManagerNav.ROOT_CREATE_BY_ME, id: BI.FileManagerNav.ROOT_CREATE_BY_ME }); this.button_group = BI.createWidget({ type: "bi.button_group", element: this, items: [{ type: "bi.file_manager_nav_button", text: BI.i18nText("BI-Created_By_Me"), selected: true, id: BI.FileManagerNav.ROOT_CREATE_BY_ME, value: BI.FileManagerNav.ROOT_CREATE_BY_ME }], layouts: [{ type: "bi.horizontal" }] }); this.button_group.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.button_group.on(BI.ButtonGroup.EVENT_CHANGE, function (value, obj) { self.fireEvent(BI.FileManagerNav.EVENT_CHANGE, arguments); }); }, _getAllParents: function (id) { var node, res = []; if (!id) { node = this.tree.getRoot(); } else { node = this.tree.search(id); } while (node.parent) { res.push(node); node = node.parent; } res.push(node); return res.reverse(); }, _formatNodes: function (nodes) { var res = []; BI.each(nodes, function (i, node) { res.push(BI.extend({ type: "bi.file_manager_nav_button", id: node.id }, node.get("data"))); }); BI.last(res).selected = true; return res; }, getValue: function () { return this.button_group.getValue(); }, getId: function () { var ids = []; BI.each(this.button_group.getSelectedButtons(), function (i, btn) { ids.push(btn.attr("id")); }); return ids; }, refreshTreeData: function(items){ this.tree.initTree(BI.Tree.transformToTreeFormat(items)); this.tree.getRoot().set("data", { text: BI.i18nText("BI-Created_By_Me"), value: BI.FileManagerNav.ROOT_CREATE_BY_ME, id: BI.FileManagerNav.ROOT_CREATE_BY_ME }); }, populate: function (node) { var parents = BI.isNull(node) ? [this.tree.getRoot()] : this._getAllParents(node.id); this.button_group.populate(this._formatNodes(parents)); } }); BI.extend(BI.FileManagerNav, { ROOT_CREATE_BY_ME: "-1" }); BI.FileManagerNav.EVENT_CHANGE = "FileManagerNav.EVENT_CHANGE"; BI.shortcut("bi.file_manager_nav", BI.FileManagerNav);/** * Created by windy on 2017/3/13. * 数值微调器 */ BI.FineTuningNumberEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.FineTuningNumberEditor.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-fine-tuning-number-editor bi-border", value: -1 }) }, _init: function () { BI.FineTuningNumberEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: "bi.sign_editor", height: o.height, value: this._alertInEditorValue(o.value), errorText: BI.i18nText("BI-Please_Input_Natural_Number"), validationChecker: function(v){ return BI.isNaturalNumber(v) || self._alertOutEditorValue(v) === -1; } }); this.editor.on(BI.TextEditor.EVENT_CONFIRM, function(){ self._finetuning(0); self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM); }); this.topBtn = BI.createWidget({ type: "bi.icon_button", trigger: "lclick,", cls: "column-pre-page-h-font top-button bi-border-left bi-border-bottom" }); this.topBtn.on(BI.IconButton.EVENT_CHANGE, function(){ self._finetuning(1); self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM); }); this.bottomBtn = BI.createWidget({ type: "bi.icon_button", trigger: "lclick,", cls: "column-next-page-h-font bottom-button bi-border-left bi-border-top" }); this.bottomBtn.on(BI.IconButton.EVENT_CHANGE, function(){ self._finetuning(-1); self.fireEvent(BI.FineTuningNumberEditor.EVENT_CONFIRM); }); this._finetuning(0); BI.createWidget({ type: "bi.htape", element: this, items: [this.editor, { el: { type: "bi.grid", columns: 1, rows: 2, items: [{ column: 0, row: 0, el: this.topBtn }, { column: 0, row: 1, el: this.bottomBtn }] }, width: 23 }] }); }, _alertOutEditorValue: function(v){ return v === BI.i18nText("BI-Basic_Auto") ? -1 : v; }, _alertInEditorValue: function(v){ return BI.parseInt(v) === -1 ? BI.i18nText("BI-Basic_Auto") : v; }, //微调 _finetuning: function(add){ var v = BI.parseInt(this._alertOutEditorValue(this.editor.getValue())); this.editor.setValue(this._alertInEditorValue(v + add)); this.bottomBtn.setEnable((v + add) > -1); }, getValue: function () { var v = this.editor.getValue(); return this._alertOutEditorValue(v); }, setValue: function (v) { this.editor.setValue(this._alertInEditorValue(v)); this._finetuning(0); } }); BI.FineTuningNumberEditor.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.shortcut("bi.fine_tuning_number_editor", BI.FineTuningNumberEditor);/** * 交互行为布局 * * * Created by GUY on 2016/7/23. * @class BI.InteractiveArrangement * @extends BI.Widget */ BI.InteractiveArrangement = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.InteractiveArrangement.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-interactive-arrangement", resizable: true, layoutType: BI.Arrangement.LAYOUT_TYPE.GRID, items: [] }); }, _init: function () { BI.InteractiveArrangement.superclass._init.apply(this, arguments); var self = this, o = this.options; this.arrangement = BI.createWidget({ type: "bi.adaptive_arrangement", element: this, resizable: o.resizable, layoutType: o.layoutType, items: o.items }); this.arrangement.on(BI.AdaptiveArrangement.EVENT_SCROLL, function () { self.fireEvent(BI.InteractiveArrangement.EVENT_SCROLL, arguments); }); this.arrangement.on(BI.AdaptiveArrangement.EVENT_RESIZE, function () { self.fireEvent(BI.InteractiveArrangement.EVENT_RESIZE, arguments); }); this.arrangement.on(BI.AdaptiveArrangement.EVENT_ELEMENT_RESIZE, function (id, size) { var p = self._getRegionClientPosition(id); self.draw({ left: p.left, top: p.top }, size, id); }); this.arrangement.on(BI.AdaptiveArrangement.EVENT_ELEMENT_STOP_RESIZE, function (id, size) { self.stopDraw(); self.setRegionSize(id, size); }); this.tags = []; }, _isEqual: function (num1, num2) { return this.arrangement._isEqual(num1, num2); }, _getScrollOffset: function () { return this.arrangement._getScrollOffset(); }, _positionAt: function (position, regions) { var self = this; regions = regions || this.getAllRegions(); var left = [], center = [], right = [], top = [], middle = [], bottom = []; BI.each(regions, function (i, region) { var client = self._getRegionClientPosition(region.id); if (Math.abs(client.left - position.left) <= 3) { left.push(region); } if (Math.abs(client.left + client.width / 2 - position.left) <= 3) { center.push(region); } if (Math.abs(client.left + client.width - position.left) <= 3) { right.push(region); } if (Math.abs(client.top - position.top) <= 3) { top.push(region); } if (Math.abs(client.top + client.height / 2 - position.top) <= 3) { middle.push(region); } if (Math.abs(client.top + client.height - position.top) <= 3) { bottom.push(region); } }); return { left: left, center: center, right: right, top: top, middle: middle, bottom: bottom } }, _getRegionClientPosition: function (name) { var region = this.getRegionByName(name); var offset = this.arrangement._getScrollOffset(); return { top: region.top - offset.top, left: region.left - offset.left, width: region.width, height: region.height, id: region.id } }, _vAlign: function (position, regions) { var self = this; var vs = this._positionAt(position, regions); var positions = []; var l; if (vs.left.length > 0) { l = this._getRegionClientPosition(vs.left[0].id).left; } else if (vs.right.length > 0) { var temp = this._getRegionClientPosition(vs.right[0].id); l = temp.left + temp.width; } var rs = vs.left.concat(vs.right); BI.each(rs, function (i, region) { var p = self._getRegionClientPosition(region.id); if (self._isEqual(p.left, l) || self._isEqual(p.left + p.width, l)) { var topPoint = { top: p.top + p.height / 2, left: l }; positions.push({ id: region.id, start: topPoint, end: { left: l, top: position.top } }); } }); return positions; }, _leftAlign: function (position, size, regions) { var self = this; return this._vAlign({ left: position.left, top: position.top + size.height / 2 }, regions); }, _rightAlign: function (position, size, regions) { var self = this; return this._vAlign({ left: position.left + size.width, top: position.top + size.height / 2 }, regions); }, _hAlign: function (position, regions) { var self = this; var hs = this._positionAt(position, regions); var positions = []; var t; if (hs.top.length > 0) { var temp = this._getRegionClientPosition(hs.top[0].id); t = temp.top; } else if (hs.bottom.length > 0) { var temp = this._getRegionClientPosition(hs.bottom[0].id); t = temp.top + temp.height; } var rs = hs.top.concat(hs.bottom); BI.each(rs, function (i, region) { var p = self._getRegionClientPosition(region.id); if (self._isEqual(p.top, t) || self._isEqual(p.top + p.height, t)) { var leftPoint = { top: t, left: p.left + p.width / 2 }; positions.push({ id: p.id, start: leftPoint, end: { left: position.left, top: t } }); } }); return positions; }, _topAlign: function (position, size, regions) { var self = this; return this._hAlign({ left: position.left + size.width / 2, top: position.top }, regions); }, _bottomAlign: function (position, size, regions) { var self = this; return this._hAlign({ left: position.left + size.width / 2, top: position.top + size.height }, regions); }, _centerAlign: function (position, size, regions) { var self = this; var cs = this._positionAt({ left: position.left + size.width / 2, top: position.top + size.height / 2 }, regions); var positions = []; var l; if (cs.center.length > 0) { var temp = this._getRegionClientPosition(cs.center[0].id); l = temp.left + temp.width / 2; } BI.each(cs.center, function (i, region) { var p = self._getRegionClientPosition(region.id); if (self._isEqual(p.left + p.width / 2, l)) { var topPoint = { top: p.top + p.height / 2, left: p.left + p.width / 2 }; positions.push({ id: p.id, start: topPoint, end: { left: l, top: position.top + size.height / 2 } }); } }); return positions; }, _middleAlign: function (position, size, regions) { var self = this; var cs = this._positionAt({ left: position.left + size.width / 2, top: position.top + size.height / 2 }, regions); var positions = []; var t; if (cs.middle.length > 0) { var temp = this._getRegionClientPosition(cs.middle[0].id); t = temp.top + temp.height / 2; } BI.each(cs.middle, function (i, region) { var p = self._getRegionClientPosition(region.id); if (self._isEqual(p.top + p.height / 2, t)) { var topPoint = { top: p.top + p.height / 2, left: p.left + p.width / 2 }; positions.push({ id: p.id, start: topPoint, end: { left: position.left + size.width / 2, top: t } }); } }); return positions; }, _drawOneTag: function (start, end) { var s = BI.createWidget({ type: "bi.icon_button", //invisible: true, width: 13, height: 13, cls: "drag-tag-font interactive-arrangement-dragtag-icon" }); var e = BI.createWidget({ type: "bi.icon_button", //invisible: true, width: 13, height: 13, cls: "drag-tag-font interactive-arrangement-dragtag-icon" }); if (this._isEqual(start.left, end.left)) { var line = BI.createWidget({ type: "bi.layout", //invisible: true, cls: "interactive-arrangement-dragtag-line", width: 1, height: Math.abs(start.top - end.top) }); } else { var line = BI.createWidget({ type: "bi.layout", //invisible: true, cls: "interactive-arrangement-dragtag-line", height: 1, width: Math.abs(start.left - end.left) }); } BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: s, left: start.left - 6, top: start.top - 7 }, { el: e, left: end.left - 6, top: end.top - 7 }, { el: line, left: Math.min(start.left, end.left), top: Math.min(start.top, end.top) }] }); this.tags.push(s); this.tags.push(e); this.tags.push(line); }, stopDraw: function () { BI.each(this.tags, function (i, w) { w.destroy(); }); this.tags = []; }, _getRegionExcept: function (name, regions) { var other = []; BI.each(regions || this.getAllRegions(), function (i, region) { if (!(name && region.id === name)) { other.push(region); } }); return other; }, getClientWidth: function () { return this.arrangement.getClientWidth(); }, getClientHeight: function () { return this.arrangement.getClientHeight(); }, getPosition: function (name, position, size) { var regions = this.getAllRegions(); var me; if (name) { me = this._getRegionClientPosition(name); } var other = this._getRegionExcept(name, regions); position = position || { left: me.left, top: me.top }; size = size || { width: me.width, height: me.height }; var left = this._leftAlign(position, size, other); var right = this._rightAlign(position, size, other); var top = this._topAlign(position, size, other, other); var bottom = this._bottomAlign(position, size, other); var center = this._centerAlign(position, size, other); var middle = this._middleAlign(position, size, other); BI.each(center, function (i, pos) { position.left = pos.end.left - size.width / 2; }); BI.each(right, function (i, pos) { position.left = pos.end.left - size.width; }); BI.each(left, function (i, pos) { position.left = pos.end.left; }); BI.each(middle, function (i, pos) { position.top = pos.end.top - size.height / 2; }); BI.each(bottom, function (i, pos) { position.top = pos.end.top - size.height; }); BI.each(top, function (i, pos) { position.top = pos.end.top; }); return position; }, //position不动 变size getSize: function (name, position, size) { var regions = this.getAllRegions(); var me; if (name) { me = this._getRegionClientPosition(name); } var other = this._getRegionExcept(name, regions); position = position || { left: me.left, top: me.top }; size = size || { width: me.width, height: me.height }; var left = this._leftAlign(position, size, other); var right = this._rightAlign(position, size, other); var top = this._topAlign(position, size, other, other); var bottom = this._bottomAlign(position, size, other); var center = this._centerAlign(position, size, other); var middle = this._middleAlign(position, size, other); BI.each(center, function (i, pos) { size.width = (pos.end.left - position.left) * 2; }); BI.each(right, function (i, pos) { size.width = pos.end.left - position.left; }); BI.each(left, function (i, pos) { }); BI.each(middle, function (i, pos) { size.height = (pos.end.top - position.top) * 2; }); BI.each(bottom, function (i, pos) { size.height = pos.end.top - position.top; }); BI.each(top, function (i, pos) { }); return size; }, draw: function (position, size, name) { var self = this; this.stopDraw(); switch (this.getLayoutType()) { case BI.Arrangement.LAYOUT_TYPE.FREE: var other = this._getRegionExcept(name); var left = this._leftAlign(position, size, other); var right = this._rightAlign(position, size, other); var top = this._topAlign(position, size, other); var bottom = this._bottomAlign(position, size, other); var center = this._centerAlign(position, size, other); var middle = this._middleAlign(position, size, other); BI.each(center, function (i, pos) { self._drawOneTag(pos.start, pos.end); }); BI.each(right, function (i, pos) { self._drawOneTag(pos.start, pos.end); }); BI.each(left, function (i, pos) { self._drawOneTag(pos.start, pos.end); }); BI.each(middle, function (i, pos) { self._drawOneTag(pos.start, pos.end); }); BI.each(bottom, function (i, pos) { self._drawOneTag(pos.start, pos.end); }); BI.each(top, function (i, pos) { self._drawOneTag(pos.start, pos.end); }); break; case BI.Arrangement.LAYOUT_TYPE.GRID: break; } }, addRegion: function (region, position) { this.stopDraw(); return this.arrangement.addRegion(region, position); }, deleteRegion: function (name) { return this.arrangement.deleteRegion(name); }, setRegionSize: function (name, size) { size = this.getSize(name, null, size); return this.arrangement.setRegionSize(name, size); }, setPosition: function (position, size) { var self = this; this.stopDraw(); if (position.left > 0 && position.top > 0) { switch (this.getLayoutType()) { case BI.Arrangement.LAYOUT_TYPE.FREE: position = this.getPosition(null, position, size); this.draw(position, size); break; case BI.Arrangement.LAYOUT_TYPE.GRID: break; } } var at = this.arrangement.setPosition(position, size); return at; }, setRegionPosition: function (name, position) { if (position.left > 0 && position.top > 0) { switch (this.getLayoutType()) { case BI.Arrangement.LAYOUT_TYPE.FREE: position = this.getPosition(name, position); break; case BI.Arrangement.LAYOUT_TYPE.GRID: break; } } return this.arrangement.setRegionPosition(name, position); }, setDropPosition: function (position, size) { var self = this; this.stopDraw(); if (position.left > 0 && position.top > 0) { switch (this.getLayoutType()) { case BI.Arrangement.LAYOUT_TYPE.FREE: position = this.getPosition(null, position, size); this.draw(position, size); break; case BI.Arrangement.LAYOUT_TYPE.GRID: break; } } var callback = self.arrangement.setDropPosition(position, size); return function () { callback(); self.stopDraw(); } }, scrollInterval: function () { this.arrangement.scrollInterval.apply(this.arrangement, arguments); }, scrollEnd: function () { this.arrangement.scrollEnd.apply(this.arrangement, arguments); }, scrollTo: function (scroll) { this.arrangement.scrollTo(scroll); }, zoom: function (ratio) { this.arrangement.zoom(ratio); }, resize: function () { return this.arrangement.resize(); }, relayout: function () { return this.arrangement.relayout(); }, setLayoutType: function (type) { this.arrangement.setLayoutType(type); }, getLayoutType: function () { return this.arrangement.getLayoutType(); }, getLayoutRatio: function () { return this.arrangement.getLayoutRatio(); }, getHelper: function () { return this.arrangement.getHelper(); }, getRegionByName: function (name) { return this.arrangement.getRegionByName(name); }, getAllRegions: function () { return this.arrangement.getAllRegions(); }, revoke: function () { return this.arrangement.revoke(); }, populate: function (items) { var self = this; this.arrangement.populate(items); } }); BI.InteractiveArrangement.EVENT_RESIZE = "InteractiveArrangement.EVENT_RESIZE"; BI.InteractiveArrangement.EVENT_SCROLL = "InteractiveArrangement.EVENT_SCROLL"; BI.shortcut('bi.interactive_arrangement', BI.InteractiveArrangement);/** * 月份下拉框 * * Created by GUY on 2015/8/28. * @class BI.MonthCombo * @extends BI.Trigger */ BI.MonthCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MonthCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-month-combo", behaviors: {}, height: 25 }); }, _init: function () { BI.MonthCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.month_trigger" }); this.trigger.on(BI.MonthTrigger.EVENT_CONFIRM, function (v) { if (this.getKey() && this.getKey() !== self.storeValue) { self.setValue(this.getValue()); } else if (!this.getKey()) { self.setValue(); } self.fireEvent(BI.MonthCombo.EVENT_CONFIRM); }); this.trigger.on(BI.MonthTrigger.EVENT_FOCUS, function () { self.storeValue = this.getKey(); }); this.trigger.on(BI.MonthTrigger.EVENT_START, function () { self.combo.hideView(); }); this.trigger.on(BI.MonthTrigger.EVENT_STOP, function () { if (!self.combo.isViewVisible()) { self.combo.showView(); } }); this.trigger.on(BI.MonthTrigger.EVENT_CHANGE, function () { self.combo.isViewVisible() && self.combo.hideView(); }); this.popup = BI.createWidget({ type: "bi.month_popup", behaviors: o.behaviors }); this.popup.on(BI.MonthPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.MonthCombo.EVENT_CONFIRM); }); this.combo = BI.createWidget({ type: "bi.combo", element: this, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, popup: { minWidth: 85, el: this.popup } }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.MonthCombo.EVENT_BEFORE_POPUPVIEW); }); }, setValue: function (v) { this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue(); } }); BI.MonthCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.MonthCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.month_combo', BI.MonthCombo);/** * 月份展示面板 * * Created by GUY on 2015/9/2. * @class BI.MonthPopup * @extends BI.Trigger */ BI.MonthPopup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MonthPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-month-popup", behaviors: {} }); }, _init: function () { BI.MonthPopup.superclass._init.apply(this, arguments); var self = this, o = this.options; //纵向排列月 var month = [0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11]; var items = []; items.push(month.slice(0, 2)); items.push(month.slice(2, 4)); items.push(month.slice(4, 6)); items.push(month.slice(6, 8)); items.push(month.slice(8, 10)); items.push(month.slice(10, 12)); items = BI.map(items, function (i, item) { return BI.map(item, function (j, td) { return { type: "bi.text_item", cls: "bi-list-item-active", textAlign: "center", whiteSpace: "nowrap", once: false, forceSelected: true, height: 23, width: 38, value: td, text: td + 1 }; }); }); this.month = BI.createWidget({ type: "bi.button_group", element: this, behaviors: o.behaviors, items: BI.createItems(items, {}), layouts: [BI.LogicFactory.createLogic("table", BI.extend({ dynamic: true }, { columns: 2, rows: 6, columnSize: [1 / 2, 1 / 2], rowSize: 25 })), { type: "bi.center_adapt", vgap: 1, hgap: 2 }] }); this.month.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.MonthPopup.EVENT_CHANGE); } }) }, getValue: function () { return this.month.getValue()[0]; }, setValue: function (v) { this.month.setValue([v]); } }); BI.MonthPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.month_popup", BI.MonthPopup);/** * 月份trigger * * Created by GUY on 2015/8/21. * @class BI.MonthTrigger * @extends BI.Trigger */ BI.MonthTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, vgap: 2, triggerWidth: 25, errorText: BI.i18nText("BI-Month_Trigger_Error_Text") }, _defaultConfig: function () { return BI.extend(BI.MonthTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-month-trigger bi-border", height: 25 }); }, _init: function () { BI.MonthTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.editor = BI.createWidget({ type: "bi.sign_editor", height: o.height, validationChecker: function (v) { return v === "" || (BI.isPositiveInteger(v) && v >= 1 && v <= 12); }, quitChecker: function (v) { return false; }, hgap: c.hgap, vgap: c.vgap, allowBlank: true, errorText: c.errorText }); this.editor.on(BI.SignEditor.EVENT_FOCUS, function () { self.fireEvent(BI.MonthTrigger.EVENT_FOCUS); }); this.editor.on(BI.SignEditor.EVENT_CHANGE, function () { self.fireEvent(BI.MonthTrigger.EVENT_CHANGE); }); this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () { var value = self.editor.getValue(); if (BI.isNotNull(value)) { self.editor.setValue(value); self.editor.setTitle(value); } self.fireEvent(BI.MonthTrigger.EVENT_CONFIRM); }); this.editor.on(BI.SignEditor.EVENT_SPACE, function () { if (self.editor.isValid()) { self.editor.blur(); } }); this.editor.on(BI.SignEditor.EVENT_START, function () { self.fireEvent(BI.MonthTrigger.EVENT_START); }); this.editor.on(BI.SignEditor.EVENT_STOP, function () { self.fireEvent(BI.MonthTrigger.EVENT_STOP); }); BI.createWidget({ element: this, type: 'bi.htape', items: [ { el: this.editor }, { el: { type: "bi.text_button", text: BI.i18nText("BI-Multi_Date_Month"), baseCls: "bi-trigger-month-text", width: c.triggerWidth }, width: c.triggerWidth }, { el: { type: "bi.trigger_icon_button", width: c.triggerWidth }, width: c.triggerWidth } ] }); }, setValue: function (v) { if(BI.isNotNull(v)){ this.editor.setState(v + 1); this.editor.setValue(v + 1); this.editor.setTitle(v + 1); return; } this.editor.setState(); this.editor.setValue(); this.editor.setTitle(); }, getKey: function () { return this.editor.getValue() | 0; }, getValue: function () { return this.editor.getValue() - 1; } }); BI.MonthTrigger.EVENT_FOCUS = "EVENT_FOCUS"; BI.MonthTrigger.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.MonthTrigger.EVENT_START = "EVENT_START"; BI.MonthTrigger.EVENT_STOP = "EVENT_STOP"; BI.MonthTrigger.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.month_trigger", BI.MonthTrigger);/** * @class BI.MultiLayerSelectTreeCombo * @extends BI.Widget */ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSelectTreeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multilayer_select_tree-combo", isDefaultInit: false, height: 30, text: "", items: [] }); }, _init: function () { BI.MultiLayerSelectTreeCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.single_tree_trigger", text: o.text, height: o.height, items: o.items }); this.popup = BI.createWidget({ type: "bi.multilayer_select_tree_popup", isDefaultInit: o.isDefaultInit, items: o.items }); this.combo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup } }); this.combo.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.popup.on(BI.MultiLayerSelectTreePopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.MultiLayerSelectTreeCombo.EVENT_CHANGE); }); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue(); }, populate: function (items) { this.combo.populate(items); } }); BI.MultiLayerSelectTreeCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multilayer_select_tree_combo", BI.MultiLayerSelectTreeCombo);/** * guy * 二级树 * @class BI.MultiLayerSelectLevelTree * @extends BI.Select */ BI.MultiLayerSelectLevelTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSelectLevelTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multilayer-select-level-tree", isDefaultInit: false, items: [], itemsCreator: BI.emptyFn }) }, _init: function () { BI.MultiLayerSelectLevelTree.superclass._init.apply(this, arguments); this.initTree(this.options.items); }, _formatItems: function (nodes, layer) { var self = this; BI.each(nodes, function (i, node) { var extend = {}; node.layer = layer; if (!BI.isKey(node.id)) { node.id = BI.UUID(); } if (node.isParent === true || BI.isNotEmptyArray(node.children)) { switch (i) { case 0 : extend.type = "bi.multilayer_select_tree_first_plus_group_node"; break; case nodes.length - 1 : extend.type = "bi.multilayer_select_tree_last_plus_group_node"; break; default : extend.type = "bi.multilayer_select_tree_mid_plus_group_node"; break; } BI.defaults(node, extend); self._formatItems(node.children, layer + 1); } else { switch (i) { case nodes.length - 1: extend.type = "bi.multilayer_single_tree_last_tree_leaf_item"; break; default : extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item"; } BI.defaults(node, extend); } }); return nodes; }, _assertId: function (sNodes) { BI.each(sNodes, function (i, node) { node.id = node.id || BI.UUID(); }); }, //构造树结构, initTree: function (nodes) { var self = this, o = this.options; this.empty(); this._assertId(nodes); this.tree = BI.createWidget({ type: "bi.custom_tree", element: this, expander: { type: "bi.select_tree_expander", isDefaultInit: o.isDefaultInit, el: {}, popup: { type: "bi.custom_tree" } }, items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0), itemsCreator: o.itemsCreator, el: { type: "bi.button_tree", chooseType: BI.Selection.Single, layouts: [{ type: "bi.vertical" }] } }); this.tree.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.MultiLayerSelectLevelTree.EVENT_CHANGE, arguments); } }) }, populate: function (nodes) { this.tree.populate(this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0)); }, setValue: function (v) { this.tree.setValue(v); }, getValue: function () { return this.tree.getValue(); }, getAllLeaves: function () { return this.tree.getAllLeaves(); }, getNodeById: function (id) { return this.tree.getNodeById(id); }, getNodeByValue: function (id) { return this.tree.getNodeByValue(id); } }); BI.MultiLayerSelectLevelTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multilayer_select_level_tree", BI.MultiLayerSelectLevelTree);/** * Created by GUY on 2016/1/26. * * @class BI.MultiLayerSelectTreePopup * @extends BI.Pane */ BI.MultiLayerSelectTreePopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSelectTreePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multilayer-select-tree-popup", tipText: BI.i18nText("BI-No_Selected_Item"), isDefaultInit: false, itemsCreator: BI.emptyFn, items: [] }); }, _init: function () { BI.MultiLayerSelectTreePopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tree = BI.createWidget({ type: 'bi.multilayer_select_level_tree', isDefaultInit: o.isDefaultInit, items: o.items, itemsCreator: o.itemsCreator }); BI.createWidget({ type: "bi.vertical", scrolly: false, scrollable: true, element: this, items: [this.tree] }); this.tree.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.tree.on(BI.MultiLayerSelectLevelTree.EVENT_CHANGE, function () { self.fireEvent(BI.MultiLayerSelectTreePopup.EVENT_CHANGE); }); this.check(); }, getValue: function () { return this.tree.getValue(); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.tree.setValue(v); }, populate: function (items) { BI.MultiLayerSelectTreePopup.superclass.populate.apply(this, arguments); this.tree.populate(items); } }); BI.MultiLayerSelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multilayer_select_tree_popup", BI.MultiLayerSelectTreePopup);/** * 加号表示的组节点 * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSelectTreeFirstPlusGroupNode * @extends BI.NodeButton */ BI.MultiLayerSelectTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-select-tree-first-plus-group-node bi-list-item-active", layer: 0,//第几层级 id: "", pId: "", readonly: true, open: false, height: 25 }) }, _init: function () { BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.select_tree_first_plus_group_node", cls: "bi-list-item-none", stopPropagation: true, logic: { dynamic: true }, id: o.id, pId: o.pId, open: o.open, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { self.setSelected(self.isSelected()); self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, isOnce: function () { return true; }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, isSelected: function () { return this.node.isSelected(); }, setSelected: function (b) { BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass.setSelected.apply(this, arguments); this.node.setSelected(b); }, doClick: function () { BI.NodeButton.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerSelectTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments); this.node.setOpened(v); } }); BI.shortcut("bi.multilayer_select_tree_first_plus_group_node", BI.MultiLayerSelectTreeFirstPlusGroupNode);/** * 加号表示的组节点 * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSelectTreeLastPlusGroupNode * @extends BI.NodeButton */ BI.MultiLayerSelectTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerSelectTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-select-tree-last-plus-group-node bi-list-item-active", layer: 0,//第几层级 id: "", pId: "", readonly: true, open: false, height: 25 }) }, _init: function () { BI.MultiLayerSelectTreeLastPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.select_tree_last_plus_group_node", cls: "bi-list-item-none", stopPropagation: true, logic: { dynamic: true }, id: o.id, pId: o.pId, open: o.open, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { self.setSelected(self.isSelected()); self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, isSelected: function () { return this.node.isSelected(); }, setSelected: function (b) { BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.setSelected.apply(this, arguments); this.node.setSelected(b); }, doClick: function () { BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerSelectTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments); this.node.setOpened(v); } }); BI.shortcut("bi.multilayer_select_tree_last_plus_group_node", BI.MultiLayerSelectTreeLastPlusGroupNode);/** * 加号表示的组节点 * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSelectTreeMidPlusGroupNode * @extends BI.NodeButton */ BI.MultiLayerSelectTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerSelectTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-select-tree-mid-plus-group-node bi-list-item-active", layer: 0,//第几层级 id: "", pId: "", readonly: true, open: false, height: 25 }) }, _init: function () { BI.MultiLayerSelectTreeMidPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.select_tree_mid_plus_group_node", cls: "bi-list-item-none", stopPropagation: true, logic: { dynamic: true }, id: o.id, pId: o.pId, open: o.open, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { self.setSelected(self.isSelected()); self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, isSelected: function () { return this.node.isSelected(); }, setSelected: function (b) { BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.setSelected.apply(this, arguments); this.node.setSelected(b); }, doClick: function () { BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerSelectTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments); this.node.setOpened(v); } }); BI.shortcut("bi.multilayer_select_tree_mid_plus_group_node", BI.MultiLayerSelectTreeMidPlusGroupNode);/** * 多层级下拉单选树 * Created by GUY on 2016/1/26. * * @class BI.MultiLayerSingleTreeCombo * @extends BI.Widget */ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSingleTreeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multilayer-singletree-combo", isDefaultInit: false, height: 30, text: "", itemsCreator: BI.emptyFn, items: [] }); }, _init: function () { BI.MultiLayerSingleTreeCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.single_tree_trigger", text: o.text, height: o.height, items: o.items }); this.popup = BI.createWidget({ type: "bi.multilayer_single_tree_popup", isDefaultInit: o.isDefaultInit, items: o.items }); this.combo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup } }); this.combo.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.popup.on(BI.MultiLayerSingleTreePopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.MultiLayerSingleTreeCombo.EVENT_CHANGE); }); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue(); }, populate: function (items) { this.combo.populate(items); } }); BI.MultiLayerSingleTreeCombo.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multilayer_single_tree_combo", BI.MultiLayerSingleTreeCombo);/** * guy * 二级树 * @class BI.MultiLayerSingleLevelTree * @extends BI.Single */ BI.MultiLayerSingleLevelTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSingleLevelTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multilayer-single-level-tree", isDefaultInit: false, items: [], itemsCreator: BI.emptyFn }) }, _init: function () { BI.MultiLayerSingleLevelTree.superclass._init.apply(this, arguments); this.initTree(this.options.items); }, _formatItems: function (nodes, layer) { var self = this; BI.each(nodes, function (i, node) { var extend = {}; node.layer = layer; if (!BI.isKey(node.id)) { node.id = BI.UUID(); } if (node.isParent === true || BI.isNotEmptyArray(node.children)) { switch (i) { case 0 : extend.type = "bi.multilayer_single_tree_first_plus_group_node"; break; case nodes.length - 1 : extend.type = "bi.multilayer_single_tree_last_plus_group_node"; break; default : extend.type = "bi.multilayer_single_tree_mid_plus_group_node"; break; } BI.defaults(node, extend); self._formatItems(node.children, layer + 1); } else { switch (i) { case nodes.length - 1: extend.type = "bi.multilayer_single_tree_last_tree_leaf_item"; break; default : extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item"; } BI.defaults(node, extend); } }); return nodes; }, _assertId: function (sNodes) { BI.each(sNodes, function (i, node) { node.id = node.id || BI.UUID(); }); }, //构造树结构, initTree: function (nodes) { var self = this, o = this.options; this.empty(); this._assertId(nodes); this.tree = BI.createWidget({ type: "bi.custom_tree", element: this, expander: { isDefaultInit: o.isDefaultInit, el: {}, popup: { type: "bi.custom_tree" } }, items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0), itemsCreator: function (op, callback) { o.itemsCreator(op, function (items) { callback(BI.Tree.transformToTreeFormat(items), 0) }) }, el: { type: "bi.button_tree", chooseType: BI.Selection.Single, layouts: [{ type: "bi.vertical" }] } }); this.tree.on(BI.Controller.EVENT_CHANGE, function (type, v) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.MultiLayerSingleLevelTree.EVENT_CHANGE, v); } }) }, populate: function (nodes) { this.tree.populate(this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0)); }, setValue: function (v) { this.tree.setValue(v); }, getValue: function () { return this.tree.getValue(); }, getAllLeaves: function () { return this.tree.getAllLeaves(); }, getNodeById: function (id) { return this.tree.getNodeById(id); }, getNodeByValue: function (id) { return this.tree.getNodeByValue(id); } }); BI.MultiLayerSingleLevelTree.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multilayer_single_level_tree", BI.MultiLayerSingleLevelTree); /** * Created by GUY on 2016/1/26. * * @class BI.MultiLayerSingleTreePopup * @extends BI.Pane */ BI.MultiLayerSingleTreePopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSingleTreePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multilayer-singletree-popup", tipText: BI.i18nText("BI-No_Selected_Item"), isDefaultInit: false, itemsCreator: BI.emptyFn, items: [] }); }, _init: function () { BI.MultiLayerSingleTreePopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tree = BI.createWidget({ type: 'bi.multilayer_single_level_tree', isDefaultInit: o.isDefaultInit, items: o.items, itemsCreator: o.itemsCreator }); BI.createWidget({ type: "bi.vertical", scrolly: false, scrollable: true, element: this, items: [this.tree] }); this.tree.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.tree.on(BI.MultiLayerSingleLevelTree.EVENT_CHANGE, function () { self.fireEvent(BI.MultiLayerSingleTreePopup.EVENT_CHANGE); }); this.check(); }, getValue: function () { return this.tree.getValue(); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.tree.setValue(v); }, populate: function (items) { BI.MultiLayerSingleTreePopup.superclass.populate.apply(this, arguments); this.tree.populate(items); } }); BI.MultiLayerSingleTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multilayer_single_tree_popup", BI.MultiLayerSingleTreePopup);/** * 加号表示的组节点 * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSingleTreeFirstPlusGroupNode * @extends BI.NodeButton */ BI.MultiLayerSingleTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-single-tree-first-plus-group-node bi-list-item", layer: 0,//第几层级 id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.first_plus_group_node", cls: "bi-list-item-none", logic: { dynamic: true }, id: o.id, pId: o.pId, open: o.open, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, doClick: function () { BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerSingleTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.node)) { this.node.setOpened(v); } } }); BI.shortcut("bi.multilayer_single_tree_first_plus_group_node", BI.MultiLayerSingleTreeFirstPlusGroupNode);/** * 加号表示的组节点 * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSingleTreeLastPlusGroupNode * @extends BI.NodeButton */ BI.MultiLayerSingleTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerSingleTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-single-tree-last-plus-group-node bi-list-item", layer: 0,//第几层级 id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.MultiLayerSingleTreeLastPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.last_plus_group_node", cls: "bi-list-item-none", logic: { dynamic: true }, id: o.id, pId: o.pId, open: o.open, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, doClick: function () { BI.MultiLayerSingleTreeLastPlusGroupNode.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerSingleTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.node)) { this.node.setOpened(v); } } }); BI.shortcut("bi.multilayer_single_tree_last_plus_group_node", BI.MultiLayerSingleTreeLastPlusGroupNode);/** * 加号表示的组节点 * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSingleTreeMidPlusGroupNode * @extends BI.NodeButton */ BI.MultiLayerSingleTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.MultiLayerSingleTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { extraCls: "bi-multilayer-single-tree-mid-plus-group-node bi-list-item", layer: 0,//第几层级 id: "", pId: "", open: false, height: 25 }) }, _init: function () { BI.MultiLayerSingleTreeMidPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.node = BI.createWidget({ type: "bi.mid_plus_group_node", cls: "bi-list-item-none", logic: { dynamic: true }, id: o.id, pId: o.pId, open: o.open, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.node.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.node); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.node.doRedMark.apply(this.node, arguments); }, unRedMark: function () { this.node.unRedMark.apply(this.node, arguments); }, doClick: function () { BI.MultiLayerSingleTreeMidPlusGroupNode.superclass.doClick.apply(this, arguments); this.node.setSelected(this.isSelected()); }, setOpened: function (v) { BI.MultiLayerSingleTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.node)) { this.node.setOpened(v); } } }); BI.shortcut("bi.multilayer_single_tree_mid_plus_group_node", BI.MultiLayerSingleTreeMidPlusGroupNode);/** * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSingleTreeFirstTreeLeafItem * @extends BI.BasicButton */ BI.MultiLayerSingleTreeFirstTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-multilayer-single-tree-first-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, layer: 0, id: "", pId: "", height: 25 }) }, _init: function () { BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.item = BI.createWidget({ type: "bi.first_tree_leaf_item", cls: "bi-list-item-none", logic: { dynamic: true }, id: o.id, pId: o.pId, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.item.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.item); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.item.doRedMark.apply(this.item, arguments); }, unRedMark: function () { this.item.unRedMark.apply(this.item, arguments); }, doHighLight: function () { this.item.doHighLight.apply(this.item, arguments); }, unHighLight: function () { this.item.unHighLight.apply(this.item, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass.doClick.apply(this, arguments); this.item.setSelected(this.isSelected()); }, setSelected: function (v) { BI.MultiLayerSingleTreeFirstTreeLeafItem.superclass.setSelected.apply(this, arguments); this.item.setSelected(v); } }); BI.shortcut("bi.multilayer_single_tree_first_tree_leaf_item", BI.MultiLayerSingleTreeFirstTreeLeafItem);/** * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSingleTreeLastTreeLeafItem * @extends BI.BasicButton */ BI.MultiLayerSingleTreeLastTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSingleTreeLastTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-multilayer-single-tree-last-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, layer: 0, id: "", pId: "", height: 25 }) }, _init: function () { BI.MultiLayerSingleTreeLastTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.item = BI.createWidget({ type: "bi.last_tree_leaf_item", cls: "bi-list-item-none", logic: { dynamic: true }, id: o.id, pId: o.pId, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.item.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.item); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.item.doRedMark.apply(this.item, arguments); }, unRedMark: function () { this.item.unRedMark.apply(this.item, arguments); }, doHighLight: function () { this.item.doHighLight.apply(this.item, arguments); }, unHighLight: function () { this.item.unHighLight.apply(this.item, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.MultiLayerSingleTreeLastTreeLeafItem.superclass.doClick.apply(this, arguments); this.item.setSelected(this.isSelected()); }, setSelected: function (v) { BI.MultiLayerSingleTreeLastTreeLeafItem.superclass.setSelected.apply(this, arguments); this.item.setSelected(v); } }); BI.shortcut("bi.multilayer_single_tree_last_tree_leaf_item", BI.MultiLayerSingleTreeLastTreeLeafItem);/** * * Created by GUY on 2016/1/27. * @class BI.MultiLayerSingleTreeMidTreeLeafItem * @extends BI.BasicButton */ BI.MultiLayerSingleTreeMidTreeLeafItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.MultiLayerSingleTreeMidTreeLeafItem.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-multilayer-single-tree-mid-tree-leaf-item bi-list-item-active", logic: { dynamic: false }, layer: 0, id: "", pId: "", height: 25 }) }, _init: function () { BI.MultiLayerSingleTreeMidTreeLeafItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.item = BI.createWidget({ type: "bi.mid_tree_leaf_item", cls: "bi-list-item-none", logic: { dynamic: true }, id: o.id, pId: o.pId, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.item.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) {//本身实现click功能 return; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); var items = []; BI.count(0, o.layer, function () { items.push({ type: "bi.layout", cls: "base-line-conn-background", width: 13, height: o.height }) }); items.push(this.item); BI.createWidget({ type: "bi.td", element: this, columnSize: BI.makeArray(o.layer, 13), items: [items] }) }, doRedMark: function () { this.item.doRedMark.apply(this.item, arguments); }, unRedMark: function () { this.item.unRedMark.apply(this.item, arguments); }, doHighLight: function () { this.item.doHighLight.apply(this.item, arguments); }, unHighLight: function () { this.item.unHighLight.apply(this.item, arguments); }, getId: function () { return this.options.id; }, getPId: function () { return this.options.pId; }, doClick: function () { BI.MultiLayerSingleTreeMidTreeLeafItem.superclass.doClick.apply(this, arguments); this.item.setSelected(this.isSelected()); }, setSelected: function (v) { BI.MultiLayerSingleTreeMidTreeLeafItem.superclass.setSelected.apply(this, arguments); this.item.setSelected(v); } }); BI.shortcut("bi.multilayer_single_tree_mid_tree_leaf_item", BI.MultiLayerSingleTreeMidTreeLeafItem);/** * * @class BI.MultiSelectCheckPane * @extends BI.Widget */ BI.MultiSelectCheckPane = BI.inherit(BI.Widget, { constants: { height: 25, lgap: 10, tgap: 5 }, _defaultConfig: function () { return BI.extend(BI.MultiSelectCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-select-check-pane bi-background", items: [], itemsCreator: BI.emptyFn, valueFormatter: BI.emptyFn, onClickContinueSelect: BI.emptyFn }); }, _init: function () { BI.MultiSelectCheckPane.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.storeValue = {}; this.display = BI.createWidget({ type: 'bi.display_selected_list', items: opts.items, itemsCreator: function (op, callback) { op = BI.extend(op || {}, { selectedValues: self.storeValue.value }); if (self.storeValue.type === BI.Selection.Multi) { callback({ items: BI.map(self.storeValue.value, function (i, v) { var txt = opts.valueFormatter(v) || v; return { text: txt, value: v, title: txt } }) }); return; } opts.itemsCreator(op, callback); } }); this.continueSelect = BI.createWidget({ type: 'bi.text_button', text: BI.i18nText('BI-Continue_Select'), cls: 'multi-select-check-selected bi-high-light' }); this.continueSelect.on(BI.TextButton.EVENT_CHANGE, function () { opts.onClickContinueSelect(); }); BI.createWidget({ type: 'bi.vtape', element: this, items: [{ height: this.constants.height, el: { type: 'bi.left', cls: 'multi-select-continue-select', items: [ { el: { type: "bi.label", text: BI.i18nText('BI-Selected_Data') }, lgap: this.constants.lgap, tgap: this.constants.tgap }, { el: this.continueSelect, lgap: this.constants.lgap, tgap: this.constants.tgap }] } }, { height: 'fill', el: this.display }] }); }, setValue: function (v) { this.storeValue = v || {}; }, empty: function () { this.display.empty(); }, populate: function () { this.display.populate.apply(this.display, arguments); } }); BI.shortcut("bi.multi_select_check_pane", BI.MultiSelectCheckPane);/** * * * 查看已选弹出层的展示面板 * @class BI.DisplaySelectedList * @extends BI.Widget */ BI.DisplaySelectedList = BI.inherit(BI.Pane, { constants: { height: 25, lgap: 10 }, _defaultConfig: function () { return BI.extend(BI.DisplaySelectedList.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-display-list", itemsCreator: BI.emptyFn, items: [] }); }, _init: function () { BI.DisplaySelectedList.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.hasNext = false; this.button_group = BI.createWidget({ type: "bi.list_pane", element: this, el: { type: "bi.loader", isDefaultInit: false, logic: { dynamic: true, scrolly: true }, items: this._createItems(opts.items), chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI, layouts: [{ type: "bi.vertical", lgap: 10 }] }, itemsCreator: function (options, callback) { opts.itemsCreator(options, function (ob) { self.hasNext = !!ob.hasNext; callback(self._createItems(ob.items)); }) }, hasNext: function () { return self.hasNext; } }); }, _createItems: function (items) { return BI.createItems(items, { type: 'bi.icon_text_item', cls: 'cursor-default check-font display-list-item bi-tips', once: true, invalid: true, selected: true, height: this.constants.height, logic: { dynamic: true } }); }, empty: function () { this.button_group.empty(); }, populate: function (items) { if (arguments.length === 0) { this.button_group.populate(); } else { this.button_group.populate(this._createItems(items)); } } }); BI.shortcut('bi.display_selected_list', BI.DisplaySelectedList);/** * * @class BI.MultiSelectCombo * @extends BI.Single */ BI.MultiSelectCombo = BI.inherit(BI.Single, { _defaultConfig: function () { return BI.extend(BI.MultiSelectCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-combo', itemsCreator: BI.emptyFn, valueFormatter: BI.emptyFn, height: 28 }); }, _init: function () { BI.MultiSelectCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; var assertShowValue = function () { BI.isKey(self._startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](self._startValue); self.trigger.getSearcher().setState(self.storeValue); self.trigger.getCounter().setButtonChecked(self.storeValue); }; this.storeValue = {}; //标记正在请求数据 this.requesting = false; this.trigger = BI.createWidget({ type: "bi.multi_select_trigger", height: o.height, // adapter: this.popup, masker: { offset: { left: 1, top: 1, right: 2, bottom: 33 } }, valueFormatter: o.valueFormatter, itemsCreator: function (op, callback) { o.itemsCreator(op, function (res) { if (op.times === 1 && BI.isNotNull(op.keywords)) { //预防trigger内部把当前的storeValue改掉 self.trigger.setValue(BI.deepClone(self.getValue())); } callback.apply(self, arguments); }); } }); this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { self._setStartValue(""); this.getSearcher().setValue(self.storeValue); }); this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { self._setStartValue(""); }); this.trigger.on(BI.MultiSelectTrigger.EVENT_PAUSE, function () { if (this.getSearcher().hasMatched()) { var keyword = this.getSearcher().getKeyword(); self._join({ type: BI.Selection.Multi, value: [keyword] }, function () { self.combo.setValue(self.storeValue); self._setStartValue(keyword); assertShowValue(); self.populate(); self._setStartValue(""); }) } }); this.trigger.on(BI.MultiSelectTrigger.EVENT_SEARCHING, function (keywords) { var last = BI.last(keywords); keywords = BI.initial(keywords || []); if (keywords.length > 0) { self._joinKeywords(keywords, function () { if (BI.isEndWithBlank(last)) { self.combo.setValue(self.storeValue); assertShowValue(); self.combo.populate(); self._setStartValue(""); } else { self.combo.setValue(self.storeValue); assertShowValue(); } }); } }); this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function (value, obj) { if (obj instanceof BI.MultiSelectBar) { self._joinAll(this.getValue(), function () { assertShowValue(); }); } else { self._join(this.getValue(), function () { assertShowValue(); }); } }); this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { this.getCounter().setValue(self.storeValue); }); this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { if (!self.combo.isViewVisible()) { self.combo.showView(); } }); this.combo = BI.createWidget({ type: "bi.combo", toggle: false, el: this.trigger, adjustLength: 1, popup: { type: 'bi.multi_select_popup_view', ref: function () { self.popup = this; self.trigger.setAdapter(this); }, listeners: [{ eventName: BI.MultiSelectPopupView.EVENT_CHANGE, action: function () { self.storeValue = this.getValue(); self._adjust(function () { assertShowValue(); }); } }, { eventName: BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM, action: function () { self._defaultState(); } }, { eventName: BI.MultiSelectPopupView.EVENT_CLICK_CLEAR, action: function () { self.setValue(); self._defaultState(); } }], itemsCreator: o.itemsCreator, valueFormatter: o.valueFormatter, onLoaded: function () { BI.nextTick(function () { self.combo.adjustWidth(); self.combo.adjustHeight(); self.trigger.getCounter().adjustView(); self.trigger.getSearcher().adjustView(); }); } }, hideChecker: function (e) { return triggerBtn.element.find(e.target).length === 0; } }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { this.setValue(self.storeValue); BI.nextTick(function () { self.populate(); }); }); //当退出的时候如果还在处理请求,则等请求结束后再对外发确定事件 this.wants2Quit = false; this.combo.on(BI.Combo.EVENT_AFTER_HIDEVIEW, function () { //important:关闭弹出时又可能没有退出编辑状态 self.trigger.stopEditing(); if (self.requesting === true) { self.wants2Quit = true; } else { self.fireEvent(BI.MultiSelectCombo.EVENT_CONFIRM); } }); var triggerBtn = BI.createWidget({ type: "bi.trigger_icon_button", width: o.height, height: o.height, cls: "multi-select-trigger-icon-button bi-border-left" }); triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { self.trigger.getCounter().hideView(); if (self.combo.isViewVisible()) { self.combo.hideView(); } else { self.combo.showView(); } }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.combo, left: 0, right: 0, top: 0, bottom: 0 }, { el: triggerBtn, right: 0, top: 0, bottom: 0 }] }) }, _defaultState: function () { this.trigger.stopEditing(); this.combo.hideView(); }, _assertValue: function (val) { val || (val = {}); val.type || (val.type = BI.Selection.Multi); val.value || (val.value = []); }, _makeMap: function (values) { return BI.makeObject(values || []); }, _joinKeywords: function (keywords, callback) { var self = this, o = this.options; this._assertValue(this.storeValue); this.requesting = true; o.itemsCreator({ type: BI.MultiSelectCombo.REQ_GET_ALL_DATA, keywords: keywords }, function (ob) { var values = BI.pluck(ob.items, "value"); digest(values); }); function digest(items) { var selectedMap = self._makeMap(items); BI.each(keywords, function (i, val) { if (BI.isNotNull(selectedMap[val])) { self.storeValue.value[self.storeValue.type === BI.Selection.Multi ? "pushDistinct" : "remove"](val); } }); self._adjust(callback); } }, _joinAll: function (res, callback) { var self = this, o = this.options; this._assertValue(res); this.requesting = true; o.itemsCreator({ type: BI.MultiSelectCombo.REQ_GET_ALL_DATA, keywords: [this.trigger.getKey()] }, function (ob) { var items = BI.pluck(ob.items, "value"); if (self.storeValue.type === res.type) { var change = false; var map = self._makeMap(self.storeValue.value); BI.each(items, function (i, v) { if (BI.isNotNull(map[v])) { change = true; delete map[v]; } }); change && (self.storeValue.value = BI.values(map)); self._adjust(callback); return; } var selectedMap = self._makeMap(self.storeValue.value); var notSelectedMap = self._makeMap(res.value); var newItems = []; BI.each(items, function (i, item) { if (BI.isNotNull(selectedMap[items[i]])) { delete selectedMap[items[i]]; } if (BI.isNull(notSelectedMap[items[i]])) { newItems.push(item); } }); self.storeValue.value = newItems.concat(BI.values(selectedMap)); self._adjust(callback); }) }, _adjust: function (callback) { var self = this, o = this.options; if (!this._count) { o.itemsCreator({ type: BI.MultiSelectCombo.REQ_GET_DATA_LENGTH }, function (res) { self._count = res.count; adjust(); callback(); }); } else { adjust(); callback(); } function adjust() { if (self.storeValue.type === BI.Selection.All && self.storeValue.value.length >= self._count) { self.storeValue = { type: BI.Selection.Multi, value: [] } } else if (self.storeValue.type === BI.Selection.Multi && self.storeValue.value.length >= self._count) { self.storeValue = { type: BI.Selection.All, value: [] } } if (self.wants2Quit === true) { self.fireEvent(BI.MultiSelectCombo.EVENT_CONFIRM); self.wants2Quit = false; } self.requesting = false; } }, _join: function (res, callback) { var self = this, o = this.options; this._assertValue(res); this._assertValue(this.storeValue); if (this.storeValue.type === res.type) { var map = this._makeMap(this.storeValue.value); BI.each(res.value, function (i, v) { if (!map[v]) { self.storeValue.value.push(v); map[v] = v; } }); var change = false; BI.each(res.assist, function (i, v) { if (BI.isNotNull(map[v])) { change = true; delete map[v]; } }); change && (this.storeValue.value = BI.values(map)); self._adjust(callback); return; } this._joinAll(res, callback); }, _setStartValue: function (value) { this._startValue = value; this.popup.setStartValue(value); }, setValue: function (v) { this.storeValue = v || {}; this._assertValue(this.storeValue); this.combo.setValue(this.storeValue); }, getValue: function () { return this.storeValue; }, populate: function () { this._count = null; this.combo.populate.apply(this.combo, arguments); } }); BI.extend(BI.MultiSelectCombo, { REQ_GET_DATA_LENGTH: 0, REQ_GET_ALL_DATA: -1 }); BI.MultiSelectCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.shortcut('bi.multi_select_combo', BI.MultiSelectCombo);/** * 多选加载数据面板 * Created by guy on 15/11/2. * @class BI.MultiSelectLoader * @extends Widget */ BI.MultiSelectLoader = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectLoader.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-loader', logic: { dynamic: true }, el: { height: 400 }, valueFormatter: BI.emptyFn, itemsCreator: BI.emptyFn, onLoaded: BI.emptyFn }); }, _init: function () { BI.MultiSelectLoader.superclass._init.apply(this, arguments); var self = this, opts = this.options; var hasNext = false; this.button_group = BI.createWidget({ type: "bi.select_list", element: this, logic: opts.logic, el: BI.extend({ onLoaded: opts.onLoaded, el: { type: "bi.loader", isDefaultInit: false, logic: { dynamic: true, scrolly: true }, el: { chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI, behaviors: { redmark: function () { return true; } }, layouts: [{ type: "bi.vertical" }] } } }, opts.el), itemsCreator: function (op, callback) { var startValue = self._startValue; self.storeValue && (op = BI.extend(op || {}, { selectedValues: BI.isKey(startValue) && self.storeValue.type === BI.Selection.Multi ? self.storeValue.value.concat(startValue) : self.storeValue.value })); opts.itemsCreator(op, function (ob) { hasNext = ob.hasNext; var firstItems = []; if (op.times === 1 && self.storeValue) { var json = BI.map(self.storeValue.value, function (i, v) { var txt = opts.valueFormatter(v) || v; return { text: txt, value: v, title: txt, selected: self.storeValue.type === BI.Selection.Multi } }); if (BI.isKey(self._startValue) && !self.storeValue.value.contains(self._startValue)) { var txt = opts.valueFormatter(startValue) || startValue; json.unshift({ text: txt, value: startValue, title: txt, selected: true }) } firstItems = self._createItems(json); } callback(firstItems.concat(self._createItems(ob.items)), ob.keyword || ""); if (op.times === 1 && self.storeValue) { BI.isKey(startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](startValue); self.setValue(self.storeValue); } (op.times === 1) && self._scrollToTop(); }); }, hasNext: function () { return hasNext; } }); this.button_group.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.button_group.on(BI.SelectList.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectLoader.EVENT_CHANGE, arguments); }); }, _createItems: function (items) { return BI.createItems(items, { type: "bi.multi_select_item", logic: this.options.logic, height: 25, selected: this.isAllSelected() }) }, _scrollToTop: function () { var self = this; BI.delay(function () { self.button_group.element.scrollTop(0); }, 30); }, isAllSelected: function () { return this.button_group.isAllSelected(); }, _assertValue: function (val) { val || (val = {}); val.type || (val.type = BI.Selection.Multi); val.value || (val.value = []); }, setStartValue: function (v) { this._startValue = v; }, setValue: function (v) { this.storeValue = v || {}; this._assertValue(this.storeValue); this.button_group.setValue(this.storeValue); }, getValue: function () { return this.button_group.getValue(); }, getAllButtons: function () { return this.button_group.getAllButtons(); }, empty: function () { this.button_group.empty(); }, populate: function (items) { this.button_group.populate.apply(this.button_group, arguments); }, resetHeight: function (h) { this.button_group.resetHeight(h); }, resetWidth: function (w) { this.button_group.resetWidth(w); } }); BI.MultiSelectLoader.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.multi_select_loader', BI.MultiSelectLoader);/** * 带加载的多选下拉面板 * @class BI.MultiSelectPopupView * @extends Widget */ BI.MultiSelectPopupView = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectPopupView.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-popup-view', maxWidth: 'auto', minWidth: 135, maxHeight: 400, valueFormatter: BI.emptyFn, itemsCreator: BI.emptyFn, onLoaded: BI.emptyFn }); }, _init: function () { BI.MultiSelectPopupView.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.loader = BI.createWidget({ type: "bi.multi_select_loader", itemsCreator: opts.itemsCreator, valueFormatter: opts.valueFormatter, onLoaded: opts.onLoaded }); this.popupView = BI.createWidget({ type: "bi.multi_popup_view", stopPropagation: false, maxWidth: opts.maxWidth, minWidth: opts.minWidth, maxHeight: opts.maxHeight, element: this, buttons: [BI.i18nText('BI-Basic_Clears'), BI.i18nText('BI-Basic_Sure')], el: this.loader }); this.popupView.on(BI.MultiPopupView.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectPopupView.EVENT_CHANGE); }); this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { switch (index) { case 0: self.fireEvent(BI.MultiSelectPopupView.EVENT_CLICK_CLEAR); break; case 1: self.fireEvent(BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM); break; } }); }, isAllSelected: function () { return this.loader.isAllSelected(); }, setStartValue: function (v) { this.loader.setStartValue(v); }, setValue: function (v) { this.popupView.setValue(v); }, getValue: function () { return this.popupView.getValue(); }, populate: function (items) { this.popupView.populate.apply(this.popupView, arguments); }, resetHeight: function (h) { this.popupView.resetHeight(h); }, resetWidth: function (w) { this.popupView.resetWidth(w); } }); BI.MultiSelectPopupView.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiSelectPopupView.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiSelectPopupView.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut('bi.multi_select_popup_view', BI.MultiSelectPopupView);/** * * 复选下拉框 * @class BI.MultiSelectTrigger * @extends BI.Trigger */ BI.MultiSelectTrigger = BI.inherit(BI.Trigger, { constants: { height: 14, rgap: 4, lgap: 4 }, _defaultConfig: function () { return BI.extend(BI.MultiSelectTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-select-trigger bi-border", itemsCreator: BI.emptyFn, valueFormatter: BI.emptyFn, searcher: {}, switcher: {}, adapter: null, masker: {} }); }, _init: function () { BI.MultiSelectTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options; if (o.height) { this.setHeight(o.height - 2); } this.searcher = BI.createWidget(o.searcher, { type: "bi.multi_select_searcher", height: o.height, itemsCreator: o.itemsCreator, valueFormatter: o.valueFormatter, popup: {}, adapter: o.adapter, masker: o.masker }); this.searcher.on(BI.MultiSelectSearcher.EVENT_START, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_START); }); this.searcher.on(BI.MultiSelectSearcher.EVENT_PAUSE, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_PAUSE); }); this.searcher.on(BI.MultiSelectSearcher.EVENT_SEARCHING, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_SEARCHING, arguments); }); this.searcher.on(BI.MultiSelectSearcher.EVENT_STOP, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_STOP); }); this.searcher.on(BI.MultiSelectSearcher.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_CHANGE, arguments); }); this.numberCounter = BI.createWidget(o.switcher, { type: 'bi.multi_select_check_selected_switcher', valueFormatter: o.valueFormatter, itemsCreator: o.itemsCreator, adapter: o.adapter, masker: o.masker }); this.numberCounter.on(BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK); }); this.numberCounter.on(BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW); }); var wrapNumberCounter = BI.createWidget({ type: 'bi.right_vertical_adapt', hgap: 4, items: [{ el: this.numberCounter }] }); var wrapper = BI.createWidget({ type: 'bi.htape', element: this, items: [ { el: this.searcher, width: 'fill' }, { el: wrapNumberCounter, width: 0 }, { el: BI.createWidget(), width: 30 }] }); this.numberCounter.on(BI.Events.VIEW, function (b) { BI.nextTick(function () {//自动调整宽度 wrapper.attr("items")[1].width = (b === true ? self.numberCounter.element.outerWidth() + 8 : 0); wrapper.resize(); }); }); this.element.click(function (e) { if (self.element.__isMouseInBounds__(e) && !self.numberCounter.element.__isMouseInBounds__(e)) { self.numberCounter.hideView(); } }); }, getCounter: function () { return this.numberCounter; }, getSearcher: function () { return this.searcher; }, stopEditing: function () { this.searcher.stopSearch(); this.numberCounter.hideView(); }, setAdapter: function (adapter) { this.searcher.setAdapter(adapter); this.numberCounter.setAdapter(adapter); }, setValue: function (ob) { this.searcher.setValue(ob); this.numberCounter.setValue(ob); }, getKey: function () { return this.searcher.getKey(); }, getValue: function () { return this.searcher.getValue(); } }); BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK = "EVENT_TRIGGER_CLICK"; BI.MultiSelectTrigger.EVENT_COUNTER_CLICK = "EVENT_COUNTER_CLICK"; BI.MultiSelectTrigger.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiSelectTrigger.EVENT_START = "EVENT_START"; BI.MultiSelectTrigger.EVENT_STOP = "EVENT_STOP"; BI.MultiSelectTrigger.EVENT_PAUSE = "EVENT_PAUSE"; BI.MultiSelectTrigger.EVENT_SEARCHING = "EVENT_SEARCHING"; BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW = "EVENT_BEFORE_COUNTER_POPUPVIEW"; BI.shortcut('bi.multi_select_trigger', BI.MultiSelectTrigger);/** * 多选加载数据搜索loader面板 * Created by guy on 15/11/4. * @class BI.MultiSelectSearchLoader * @extends Widget */ BI.MultiSelectSearchLoader = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectSearchLoader.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-search-loader', itemsCreator: BI.emptyFn, keywordGetter: BI.emptyFn, valueFormatter: BI.emptyFn, }); }, _init: function () { BI.MultiSelectSearchLoader.superclass._init.apply(this, arguments); var self = this, opts = this.options; var hasNext = false; this.button_group = BI.createWidget({ type: "bi.select_list", element: this, logic: { dynamic: false }, el: { tipText: BI.i18nText("BI-No_Select"), el: { type: "bi.loader", isDefaultInit: false, logic: { dynamic: true, scrolly: true }, el: { chooseType: BI.ButtonGroup.CHOOSE_TYPE_MULTI, behaviors: { redmark: function () { return true; } }, layouts: [{ type: "bi.vertical" }] } } }, itemsCreator: function (op, callback) { self.storeValue && (op = BI.extend(op || {}, { selectedValues: self.storeValue.value })); opts.itemsCreator(op, function (ob) { var keyword = ob.keyword = opts.keywordGetter(); hasNext = ob.hasNext; var firstItems = []; if (op.times === 1 && self.storeValue) { var json = self._filterValues(self.storeValue); firstItems = self._createItems(json); } callback(firstItems.concat(self._createItems(ob.items)), keyword); if (op.times === 1 && self.storeValue) { self.setValue(self.storeValue); } }); }, hasNext: function () { return hasNext; } }); this.button_group.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.button_group.on(BI.SelectList.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectSearchLoader.EVENT_CHANGE, arguments); }); }, _createItems: function (items) { return BI.createItems(items, { type: "bi.multi_select_item", logic: { dynamic: false }, height: 25, selected: this.isAllSelected() }) }, isAllSelected: function () { return this.button_group.isAllSelected(); }, _filterValues: function (src) { var o = this.options; var keyword = o.keywordGetter(); var values = BI.deepClone(src.value) || []; var newValues = BI.map(values, function (i, v) { return { text: o.valueFormatter(v) || v, value: v }; }); if (BI.isKey(keyword)) { var search = BI.Func.getSearchResult(newValues, keyword); values = search.matched.concat(search.finded); } return BI.map(values, function (i, v) { return { text: v.text, title: v.text, value: v.value, selected: src.type === BI.Selection.All } }) }, setValue: function (v) { //暂存的值一定是新的值,不然v改掉后,storeValue也跟着改了 this.storeValue = BI.deepClone(v); this.button_group.setValue(v); }, getValue: function () { return this.button_group.getValue(); }, getAllButtons: function () { return this.button_group.getAllButtons(); }, empty: function () { this.button_group.empty(); }, populate: function (items) { this.button_group.populate.apply(this.button_group, arguments); }, resetHeight: function (h) { this.button_group.resetHeight(h); }, resetWidth: function (w) { this.button_group.resetWidth(w); } }); BI.MultiSelectSearchLoader.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.multi_select_search_loader', BI.MultiSelectSearchLoader);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiSelectSearchPane * @extends Widget */ BI.MultiSelectSearchPane = BI.inherit(BI.Widget, { constants: { height: 25, lgap: 10, tgap: 5 }, _defaultConfig: function () { return BI.extend(BI.MultiSelectSearchPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-select-search-pane bi-card", itemsCreator: BI.emptyFn, valueFormatter: BI.emptyFn, keywordGetter: BI.emptyFn }); }, _init: function () { BI.MultiSelectSearchPane.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tooltipClick = BI.createWidget({ type: "bi.label", invisible: true, text: BI.i18nText('BI-Click_Blank_To_Select'), cls: 'multi-select-toolbar', height: this.constants.height }); this.loader = BI.createWidget({ type: "bi.multi_select_search_loader", keywordGetter: o.keywordGetter, valueFormatter: o.valueFormatter, itemsCreator: function (op, callback) { o.itemsCreator.apply(self, [op, function (res) { callback(res); self.setKeyword(o.keywordGetter()); }]); } }); this.loader.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.resizer = BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: this.tooltipClick, height: 0 }, { el: this.loader }] }); this.tooltipClick.setVisible(false); }, setKeyword: function (keyword) { var btn; var isVisible = this.loader.getAllButtons().length > 0 && (btn = this.loader.getAllButtons()[0]) && (keyword === btn.getValue()); if (isVisible !== this.tooltipClick.isVisible()) { this.tooltipClick.setVisible(isVisible); this.resizer.attr("items")[0].height = (isVisible ? this.constants.height : 0); this.resizer.resize(); } }, isAllSelected: function () { return this.loader.isAllSelected(); }, hasMatched: function () { return this.tooltipClick.isVisible(); }, setValue: function (v) { this.loader.setValue(v); }, getValue: function () { return this.loader.getValue(); }, empty: function () { this.loader.empty(); }, populate: function (items) { this.loader.populate.apply(this.loader, arguments); } }); BI.MultiSelectSearchPane.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.multi_select_search_pane", BI.MultiSelectSearchPane);/** * 查看已选按钮 * Created by guy on 15/11/3. * @class BI.MultiSelectCheckSelectedButton * @extends BI.Single */ BI.MultiSelectCheckSelectedButton = BI.inherit(BI.Single, { _const: { checkSelected: BI.i18nText('BI-Check_Selected') }, _defaultConfig: function () { return BI.extend(BI.MultiSelectCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-check-selected-button bi-high-light', itemsCreator: BI.emptyFn }); }, _init: function () { BI.MultiSelectCheckSelectedButton.superclass._init.apply(this, arguments); var self = this; this.numberCounter = BI.createWidget({ type: 'bi.text_button', element: this, hgap: 4, text: "0", textAlign: 'center', textHeight: 15 }); this.numberCounter.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.numberCounter.on(BI.TextButton.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); }); this.numberCounter.element.hover(function () { self.numberCounter.setTag(self.numberCounter.getText()); self.numberCounter.setText(self._const.checkSelected); }, function () { self.numberCounter.setText(self.numberCounter.getTag()); }); this.setVisible(false); }, setValue: function (ob) { var self = this, o = this.options; ob || (ob = {}); ob.type || (ob.type = BI.Selection.Multi); ob.value || (ob.value = []); if (ob.type === BI.Selection.All) { o.itemsCreator({ type: BI.MultiSelectCombo.REQ_GET_DATA_LENGTH }, function (res) { var length = res.count - ob.value.length; BI.nextTick(function(){ self.numberCounter.setText(length); self.setVisible(length > 0); }); }); return; } BI.nextTick(function(){ self.numberCounter.setText(ob.value.length); self.setVisible(ob.value.length > 0); }) }, getValue: function () { } }); BI.MultiSelectCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.multi_select_check_selected_button', BI.MultiSelectCheckSelectedButton);/** * 多选输入框 * Created by guy on 15/11/3. * @class BI.MultiSelectEditor * @extends Widget */ BI.MultiSelectEditor = BI.inherit(BI.Widget, { _const: { checkSelected: BI.i18nText('BI-Check_Selected') }, _defaultConfig: function () { return BI.extend(BI.MultiSelectEditor.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-editor', el: {} }); }, _init: function () { BI.MultiSelectEditor.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget(o.el, { type: 'bi.state_editor', element: this, height: o.height, watermark: BI.i18nText('BI-Basic_Search'), allowBlank: true }); this.editor.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.editor.on(BI.StateEditor.EVENT_PAUSE, function () { self.fireEvent(BI.MultiSelectEditor.EVENT_PAUSE); }); this.editor.on(BI.StateEditor.EVENT_CLICK_LABEL, function () { }); }, focus: function () { this.editor.focus(); }, blur: function () { this.editor.blur(); }, setState: function (state) { this.editor.setState(state); }, setValue: function (v) { this.editor.setValue(v); }, getValue: function () { var v = this.editor.getState(); if (BI.isArray(v) && v.length > 0) { return v[v.length - 1]; } else { return ""; } }, getKeywords: function () { var val = this.editor.getLastValidValue(); var keywords = val.match(/[\S]+/g); if (BI.isEndWithBlank(val)) { return keywords.concat([' ']); } return keywords; }, populate: function (items) { } }); BI.MultiSelectEditor.EVENT_PAUSE = "MultiSelectEditor.EVENT_PAUSE"; BI.shortcut('bi.multi_select_editor', BI.MultiSelectEditor);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiSelectSearcher * @extends Widget */ BI.MultiSelectSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectSearcher.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-searcher', itemsCreator: BI.emptyFn, el: {}, popup: {}, valueFormatter: BI.emptyFn, adapter: null, masker: {} }); }, _init: function () { BI.MultiSelectSearcher.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget(o.el, { type: 'bi.multi_select_editor', height: o.height }); this.searcher = BI.createWidget({ type: "bi.searcher", element: this, height: o.height, isAutoSearch: false, isAutoSync: false, onSearch: function (op, callback) { callback(); }, el: this.editor, popup: BI.extend({ type: "bi.multi_select_search_pane", valueFormatter: o.valueFormatter, keywordGetter: function () { return self.editor.getValue(); }, itemsCreator: function (op, callback) { op.keyword = self.editor.getValue(); this.setKeyword(op.keyword); o.itemsCreator(op, callback); } }, o.popup), adapter: o.adapter, masker: o.masker }); this.searcher.on(BI.Searcher.EVENT_START, function () { self.fireEvent(BI.MultiSelectSearcher.EVENT_START); }); this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { if (this.hasMatched()) { } self.fireEvent(BI.MultiSelectSearcher.EVENT_PAUSE); }); this.searcher.on(BI.Searcher.EVENT_STOP, function () { self.fireEvent(BI.MultiSelectSearcher.EVENT_STOP); }); this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectSearcher.EVENT_CHANGE, arguments); }); this.searcher.on(BI.Searcher.EVENT_SEARCHING, function () { var keywords = this.getKeywords(); self.fireEvent(BI.MultiSelectSearcher.EVENT_SEARCHING, keywords); }); }, adjustView: function () { this.searcher.adjustView(); }, isSearching: function () { return this.searcher.isSearching(); }, stopSearch: function () { this.searcher.stopSearch(); }, getKeyword: function () { return this.editor.getValue(); }, hasMatched: function () { return this.searcher.hasMatched(); }, hasChecked: function () { return this.searcher.getView() && this.searcher.getView().hasChecked(); }, setAdapter: function (adapter) { this.searcher.setAdapter(adapter); }, setState: function (ob) { var o = this.options; ob || (ob = {}); ob.value || (ob.value = []); if (ob.type === BI.Selection.All) { if (BI.size(ob.assist) === 1) { this.editor.setState(o.valueFormatter(ob.assist[0] + "") || (ob.assist[0] + "")); } else { this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.All); } } else { if (BI.size(ob.value) === 1) { this.editor.setState(o.valueFormatter(ob.value[0] + "") || (ob.value[0] + "")); } else { this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.None); } } }, setValue: function (ob) { this.setState(ob); this.searcher.setValue(ob); }, getKey: function () { return this.editor.getValue(); }, getValue: function () { return this.searcher.getValue(); }, populate: function (items) { this.searcher.populate.apply(this.searcher, arguments); } }); BI.MultiSelectSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.MultiSelectSearcher.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiSelectSearcher.EVENT_START = "EVENT_START"; BI.MultiSelectSearcher.EVENT_STOP = "EVENT_STOP"; BI.MultiSelectSearcher.EVENT_PAUSE = "EVENT_PAUSE"; BI.MultiSelectSearcher.EVENT_SEARCHING = "EVENT_SEARCHING"; BI.shortcut('bi.multi_select_searcher', BI.MultiSelectSearcher);/** * 查看已选switcher * Created by guy on 15/11/3. * @class BI.MultiSelectCheckSelectedSwitcher * @extends Widget */ BI.MultiSelectCheckSelectedSwitcher = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectCheckSelectedSwitcher.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-check-selected-switcher', itemsCreator: BI.emptyFn, valueFormatter: BI.emptyFn, el: {}, popup: {}, adapter: null, masker: {} }); }, _init: function () { BI.MultiSelectCheckSelectedSwitcher.superclass._init.apply(this, arguments); var self = this, o = this.options; this.button = BI.createWidget(o.el, { type: "bi.multi_select_check_selected_button", itemsCreator: o.itemsCreator }); this.button.on(BI.Events.VIEW, function () { self.fireEvent(BI.Events.VIEW, arguments); }); this.switcher = BI.createWidget({ type: "bi.switcher", toggle: false, element: this, el: this.button, popup: BI.extend({ type: "bi.multi_select_check_pane", valueFormatter: o.valueFormatter, itemsCreator: o.itemsCreator, onClickContinueSelect: function () { self.switcher.hideView(); } }, o.popup), adapter: o.adapter, masker: o.masker }); this.switcher.on(BI.Switcher.EVENT_TRIGGER_CHANGE, function () { self.fireEvent(BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE); }); this.switcher.on(BI.Switcher.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW); }); this.switcher.on(BI.Switcher.EVENT_AFTER_POPUPVIEW, function () { var me = this; BI.nextTick(function () { me.populate(); }); }); this.switcher.element.click(function (e) { e.stopPropagation(); }); }, adjustView: function () { this.switcher.adjustView(); }, hideView: function () { this.switcher.empty(); this.switcher.hideView(); }, setAdapter: function (adapter) { this.switcher.setAdapter(adapter); }, setValue: function (v) { this.switcher.setValue(v); }, setButtonChecked: function (v) { this.button.setValue(v) }, getValue: function () { }, populate: function (items) { this.switcher.populate.apply(this.switcher, arguments); } }); BI.MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE = "MultiSelectCheckSelectedSwitcher.EVENT_TRIGGER_CHANGE"; BI.MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW = "MultiSelectCheckSelectedSwitcher.EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.multi_select_check_selected_switcher', BI.MultiSelectCheckSelectedSwitcher);/** * Created by zcf_1 on 2017/5/2. */ BI.MultiSelectList = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectList.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-list', itemsCreator: BI.emptyFn, valueFormatter: BI.emptyFn }) }, _init: function () { BI.MultiSelectList.superclass._init.apply(this, arguments); var self = this, o = this.options; this.storeValue = {}; var assertShowValue = function () { BI.isKey(self._startValue) && self.storeValue.value[self.storeValue.type === BI.Selection.All ? "remove" : "pushDistinct"](self._startValue); // self.trigger.setValue(self.storeValue); }; this.adapter = BI.createWidget({ type: "bi.multi_select_loader", cls: "popup-multi-select-list bi-border-left bi-border-right bi-border-bottom", itemsCreator: o.itemsCreator, valueFormatter: o.valueFormatter, // onLoaded: o.onLoaded, el: { height: "" } }); this.adapter.on(BI.MultiSelectLoader.EVENT_CHANGE, function () { self.storeValue = this.getValue(); self._adjust(function () { assertShowValue(); self.fireEvent(BI.MultiSelectList.EVENT_CHANGE); }); }); this.searcherPane = BI.createWidget({ type: "bi.multi_select_search_pane", cls: "bi-border-left bi-border-right bi-border-bottom", valueFormatter: o.valueFormatter, keywordGetter: function () { return self.trigger.getKeyword(); }, itemsCreator: function (op, callback) { op.keyword = self.trigger.getKeyword(); this.setKeyword(op.keyword); o.itemsCreator(op, callback); } }); this.searcherPane.setVisible(false); this.trigger = BI.createWidget({ type: "bi.searcher", isAutoSearch: false, isAutoSync: false, onSearch: function (op, callback) { callback(); }, adapter: this.adapter, popup: this.searcherPane, height: 200, masker: false, listeners: [{ eventName: BI.Searcher.EVENT_START, action: function () { self._showSearcherPane(); self._setStartValue(""); this.setValue(BI.deepClone(self.storeValue)); } }, { eventName: BI.Searcher.EVENT_STOP, action: function () { self._showAdapter(); self._setStartValue(""); self.adapter.setValue(self.storeValue); //需要刷新回到初始界面,否则搜索的结果不能放在最前面 self.adapter.populate(); } }, { eventName: BI.Searcher.EVENT_PAUSE, action: function () { if (this.hasMatched()) { var keyword = this.getKeyword(); self._join({ type: BI.Selection.Multi, value: [keyword] }, function () { self._showAdapter(); self.adapter.setValue(self.storeValue); self._setStartValue(keyword); assertShowValue(); self._setStartValue(""); self.fireEvent(BI.MultiSelectList.EVENT_CHANGE); }) } else { self._showAdapter(); } } }, { eventName: BI.Searcher.EVENT_SEARCHING, action: function () { var keywords = this.getKeyword(); var last = BI.last(keywords); keywords = BI.initial(keywords || []); if (keywords.length > 0) { self._joinKeywords(keywords, function () { if (BI.isEndWithBlank(last)) { self.adapter.setValue(self.storeValue); assertShowValue(); self.adapter.populate(); self._setStartValue(""); } else { self.adapter.setValue(self.storeValue); assertShowValue(); } }); } } }, { eventName: BI.Searcher.EVENT_CHANGE, action: function (value, obj) { if (obj instanceof BI.MultiSelectBar) { self._joinAll(this.getValue(), function () { assertShowValue(); }); } else { self._join(this.getValue(), function () {//安徽省 北京 assertShowValue(); }); } } }] }); BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: this.trigger, height: 30 }, { el: this.adapter, height: "fill" }] }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.searcherPane, top: 30, bottom: 0, left: 0, right: 0 }] }) }, _showAdapter: function () { this.adapter.setVisible(true); this.searcherPane.setVisible(false); }, _showSearcherPane: function () { this.searcherPane.setVisible(true); this.adapter.setVisible(false); }, _defaultState: function () { this.trigger.stopEditing(); }, _assertValue: function (val) { val || (val = {}); val.type || (val.type = BI.Selection.Multi); val.value || (val.value = []); }, _makeMap: function (values) { return BI.makeObject(values || []); }, _joinKeywords: function (keywords, callback) { var self = this, o = this.options; this._assertValue(this.storeValue); if (!this._allData) { o.itemsCreator({ type: BI.MultiSelectList.REQ_GET_ALL_DATA }, function (ob) { self._allData = BI.pluck(ob.items, "value"); digest(self._allData); }) } else { digest(this._allData) } function digest(items) { var selectedMap = self._makeMap(items); BI.each(keywords, function (i, val) { if (BI.isNotNull(selectedMap[val])) { self.storeValue.value[self.storeValue.type === BI.Selection.Multi ? "pushDistinct" : "remove"](val); } }); self._adjust(callback); } }, _joinAll: function (res, callback) { var self = this, o = this.options; this._assertValue(res); o.itemsCreator({ type: BI.MultiSelectList.REQ_GET_ALL_DATA, keyword: self.trigger.getKeyword() }, function (ob) { var items = BI.pluck(ob.items, "value"); if (self.storeValue.type === res.type) { var change = false; var map = self._makeMap(self.storeValue.value); BI.each(items, function (i, v) { if (BI.isNotNull(map[v])) { change = true; delete map[v]; } }); change && (self.storeValue.value = BI.values(map)); self._adjust(callback); return; } var selectedMap = self._makeMap(self.storeValue.value); var notSelectedMap = self._makeMap(res.value); var newItems = []; BI.each(items, function (i, item) { if (BI.isNotNull(selectedMap[items[i]])) { delete selectedMap[items[i]]; } if (BI.isNull(notSelectedMap[items[i]])) { newItems.push(item); } }); self.storeValue.value = newItems.concat(BI.values(selectedMap)); self._adjust(callback); }) }, _adjust: function (callback) { var self = this, o = this.options; if (!this._count) { o.itemsCreator({ type: BI.MultiSelectList.REQ_GET_DATA_LENGTH }, function (res) { self._count = res.count; adjust(); callback(); }); } else { adjust(); callback(); } function adjust() { if (self.storeValue.type === BI.Selection.All && self.storeValue.value.length >= self._count) { self.storeValue = { type: BI.Selection.Multi, value: [] } } else if (self.storeValue.type === BI.Selection.Multi && self.storeValue.value.length >= self._count) { self.storeValue = { type: BI.Selection.All, value: [] } } } }, _join: function (res, callback) { var self = this, o = this.options; this._assertValue(res); this._assertValue(this.storeValue); if (this.storeValue.type === res.type) { var map = this._makeMap(this.storeValue.value); BI.each(res.value, function (i, v) { if (!map[v]) { self.storeValue.value.push(v); map[v] = v; } }); var change = false; BI.each(res.assist, function (i, v) { if (BI.isNotNull(map[v])) { change = true; delete map[v]; } }); change && (this.storeValue.value = BI.values(map)); self._adjust(callback); return; } this._joinAll(res, callback); }, _setStartValue: function (value) { this._startValue = value; this.adapter.setStartValue(value); }, isAllSelected: function () { return this.adapter.isAllSelected(); }, resize: function () { // this.trigger.getCounter().adjustView(); // this.trigger.adjustView(); }, setValue: function (v) { this.storeValue = v || {}; this._assertValue(this.storeValue); this.adapter.setValue(this.storeValue); this.trigger.setValue(this.storeValue); }, getValue: function () { return this.storeValue; }, populate: function () { this._count = null; this._allData = null; this.adapter.populate.apply(this.adapter, arguments); this.trigger.populate.apply(this.trigger, arguments); } }); BI.extend(BI.MultiSelectList, { REQ_GET_DATA_LENGTH: 0, REQ_GET_ALL_DATA: -1 }); BI.MultiSelectList.EVENT_CHANGE = "BI.MultiSelectList.EVENT_CHANGE"; BI.shortcut("bi.multi_select_list", BI.MultiSelectList);/** * Created by zcf_1 on 2017/5/11. */ BI.MultiSelectTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectTree.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-select-tree', itemsCreator: BI.emptyFn }) }, _init: function () { BI.MultiSelectTree.superclass._init.apply(this, arguments); var self = this, o = this.options; this.storeValue = {value: {}}; this.adapter = BI.createWidget({ type: "bi.multi_select_tree_popup", itemsCreator: o.itemsCreator }); this.adapter.on(BI.MultiSelectTreePopup.EVENT_CHANGE, function () { if (self.searcher.isSearching()) { self.storeValue = {value: self.searcherPane.getValue()}; } else { self.storeValue = {value: self.adapter.getValue()}; } self.setSelectedValue(self.storeValue.value); self.fireEvent(BI.MultiSelectTree.EVENT_CHANGE); }); //搜索中的时候用的是parttree,同adapter中的synctree不一样 this.searcherPane = BI.createWidget({ type: "bi.multi_tree_search_pane", cls: "bi-border-left bi-border-right bi-border-bottom", keywordGetter: function () { return self.searcher.getKeyword(); }, itemsCreator: function (op, callback) { op.keyword = self.searcher.getKeyword(); o.itemsCreator(op, callback); } }); this.searcherPane.setVisible(false); this.searcher = BI.createWidget({ type: "bi.searcher", isAutoSearch: false, isAutoSync: false, onSearch: function (op, callback) { callback({ keyword: self.searcher.getKeyword() }); }, adapter: this.adapter, popup: this.searcherPane, masker: false, listeners: [{ eventName: BI.Searcher.EVENT_START, action: function () { self._showSearcherPane(); // self.storeValue = {value: self.adapter.getValue()}; // self.searcherPane.setSelectedValue(self.storeValue.value); } }, { eventName: BI.Searcher.EVENT_STOP, action: function () { self._showAdapter(); // self.storeValue = {value: self.searcherPane.getValue()}; // self.adapter.setSelectedValue(self.storeValue.value); BI.nextTick(function () { self.adapter.populate(); }); } }, { eventName: BI.Searcher.EVENT_CHANGE, action: function () { if (self.searcher.isSearching()) { self.storeValue = {value: self.searcherPane.getValue()}; } else { self.storeValue = {value: self.adapter.getValue()}; } self.setSelectedValue(self.storeValue.value); self.fireEvent(BI.MultiSelectTree.EVENT_CHANGE); } }, { eventName: BI.Searcher.EVENT_PAUSE, action: function () { self._showAdapter(); } }] }); BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: this.searcher, height: 30 }, { el: this.adapter, height: "fill" }] }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.searcherPane, top: 30, bottom: 0, left: 0, right: 0 }] }) }, _showAdapter: function () { this.adapter.setVisible(true); this.searcherPane.setVisible(false); }, _showSearcherPane: function () { this.searcherPane.setVisible(true); this.adapter.setVisible(false); }, resize: function () { }, setSelectedValue: function (v) { this.storeValue.value = v || {}; this.adapter.setSelectedValue(v); this.searcherPane.setSelectedValue(v); this.searcher.setValue({ value: v || {} }); }, setValue: function (v) { this.adapter.setValue(v); }, stopSearch: function () { this.searcher.stopSearch(); }, updateValue: function (v) { this.adapter.updateValue(v); }, getValue: function () { return this.storeValue.value; }, populate: function () { this.searcher.populate.apply(this.searcher, arguments); this.adapter.populate.apply(this.adapter, arguments); } }); BI.MultiSelectTree.EVENT_CHANGE = "BI.MultiSelectTree.EVENT_CHANGE"; BI.shortcut("bi.multi_select_tree", BI.MultiSelectTree);/** * Created by zcf on 2016/12/21. */ BI.MultiSelectTreePopup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiSelectTreePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-select-tree-popup bi-border-left bi-border-right bi-border-bottom", itemsCreator: BI.emptyFn }); }, _init: function () { BI.MultiSelectTreePopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.popup = BI.createWidget({ type: "bi.async_tree", element: this, itemsCreator: o.itemsCreator }); this.popup.on(BI.TreeView.EVENT_AFTERINIT, function () { self.fireEvent(BI.MultiSelectTreePopup.EVENT_AFTER_INIT) }); this.popup.on(BI.TreeView.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectTreePopup.EVENT_CHANGE) }); }, hasChecked: function () { return this.popup.hasChecked(); }, getValue: function () { return this.popup.getValue(); }, setValue: function (v) { v || (v = {}); this.popup.setValue(v); }, setSelectedValue: function (v) { v || (v = {}); this.popup.setSelectedValue(v); }, updateValue: function (v) { this.popup.updateValue(v); this.popup.refresh(); }, populate: function (config) { this.popup.stroke(config); } }); BI.MultiSelectTreePopup.EVENT_AFTER_INIT = "BI.MultiSelectTreePopup.EVENT_AFTER_INIT"; BI.MultiSelectTreePopup.EVENT_CHANGE = "BI.MultiSelectTreePopup.EVENT_CHANGE"; BI.shortcut("bi.multi_select_tree_popup", BI.MultiSelectTreePopup);/** * * @class BI.MultiTreeCheckPane * @extends BI.Pane */ BI.MultiTreeCheckPane = BI.inherit(BI.Pane, { constants: { height: 25, lgap: 10, tgap: 5 }, _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-check-pane bi-background", onClickContinueSelect: BI.emptyFn }); }, _init: function () { BI.MultiTreeCheckPane.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.selectedValues = {}; var continueSelect = BI.createWidget({ type: 'bi.text_button', text: BI.i18nText('BI-Continue_Select'), cls: 'multi-tree-check-selected' }); continueSelect.on(BI.TextButton.EVENT_CHANGE, function () { opts.onClickContinueSelect(); BI.nextTick(function () { self.empty(); }); }); var backToPopup = BI.createWidget({ type: 'bi.left', cls: 'multi-tree-continue-select', items: [ { el: { type: "bi.label", text: BI.i18nText('BI-Selected_Data') }, lgap: this.constants.lgap, tgap: this.constants.tgap }, { el: continueSelect, lgap: this.constants.lgap, tgap: this.constants.tgap }] }); this.display = BI.createWidget({ type: "bi.display_tree", cls: "bi-multi-tree-display", itemsCreator: function (op, callback) { op.type = BI.TreeView.REQ_TYPE_GET_SELECTED_DATA; opts.itemsCreator(op, callback); } }); this.display.on(BI.Events.AFTERINIT, function () { self.fireEvent(BI.Events.AFTERINIT); }); this.display.on(BI.TreeView.EVENT_INIT, function () { backToPopup.setVisible(false); }); this.display.on(BI.TreeView.EVENT_AFTERINIT, function () { backToPopup.setVisible(true); }); BI.createWidget({ type: 'bi.vtape', element: this, items: [{ height: this.constants.height, el: backToPopup }, { height: 'fill', el: this.display }] }); }, empty: function () { this.display.empty(); }, populate: function (configs) { this.display.stroke(configs); }, setValue: function (v) { v || (v = {}); this.display.setSelectedValue(v.value); }, getValue: function () { } }); BI.MultiTreeCheckPane.EVENT_CONTINUE_CLICK = "EVENT_CONTINUE_CLICK"; BI.shortcut("bi.multi_tree_check_pane", BI.MultiTreeCheckPane);/** * * @class BI.MultiTreeCombo * @extends BI.Single */ BI.MultiTreeCombo = BI.inherit(BI.Single, { constants: { offset: { top: 1, left: 1, right: 2, bottom: 33 } }, _defaultConfig: function () { return BI.extend(BI.MultiTreeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-tree-combo', itemsCreator: BI.emptyFn, height: 25 }); }, _init: function () { BI.MultiTreeCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; var isInit = false; var want2showCounter = false; this.trigger = BI.createWidget({ type: "bi.multi_select_trigger", height: o.height, // adapter: this.popup, masker: { offset: this.constants.offset }, searcher: { type: "bi.multi_tree_searcher", itemsCreator: o.itemsCreator }, switcher: { el: { type: "bi.multi_tree_check_selected_button" }, popup: { type: "bi.multi_tree_check_pane", itemsCreator: o.itemsCreator } } }); this.combo = BI.createWidget({ type: "bi.combo", toggle: false, el: this.trigger, adjustLength: 1, popup: { type: 'bi.multi_tree_popup_view', ref: function () { self.popup = this; self.trigger.setAdapter(this); }, listeners: [{ eventName: BI.MultiTreePopup.EVENT_AFTERINIT, action: function () { self.trigger.getCounter().adjustView(); isInit = true; if (want2showCounter === true) { showCounter(); } } }, { eventName: BI.MultiTreePopup.EVENT_CHANGE, action: function () { change = true; var val = { type: BI.Selection.Multi, value: this.hasChecked() ? {1: 1} : {} }; self.trigger.getSearcher().setState(val); self.trigger.getCounter().setButtonChecked(val); } }, { eventName: BI.MultiTreePopup.EVENT_CLICK_CONFIRM, action: function () { self.combo.hideView(); } }, { eventName: BI.MultiTreePopup.EVENT_CLICK_CLEAR, action: function () { clear = true; self.setValue(); self._defaultState(); } }], itemsCreator: o.itemsCreator, onLoaded: function () { BI.nextTick(function () { self.trigger.getCounter().adjustView(); self.trigger.getSearcher().adjustView(); }); } }, hideChecker: function (e) { return triggerBtn.element.find(e.target).length === 0; } }); this.storeValue = {value: {}}; var change = false; var clear = false; //标识当前是否点击了清空 var isSearching = function () { return self.trigger.getSearcher().isSearching(); }; var isPopupView = function () { return self.combo.isViewVisible(); }; this.trigger.on(BI.MultiSelectTrigger.EVENT_START, function () { self.storeValue = {value: self.combo.getValue()}; this.setValue(self.storeValue); }); this.trigger.on(BI.MultiSelectTrigger.EVENT_STOP, function () { self.storeValue = {value: this.getValue()}; self.combo.setValue(self.storeValue); BI.nextTick(function () { if (isPopupView()) { self.combo.populate(); } }); }); function showCounter() { if (isSearching()) { self.storeValue = {value: self.trigger.getValue()}; } else if (isPopupView()) { self.storeValue = {value: self.combo.getValue()}; } self.trigger.setValue(self.storeValue); } this.trigger.on(BI.MultiSelectTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW, function () { if (want2showCounter === false) { want2showCounter = true; } if (isInit === true) { want2showCounter = null; showCounter(); } }); this.trigger.on(BI.MultiSelectTrigger.EVENT_TRIGGER_CLICK, function () { self.combo.toggle(); }); this.trigger.on(BI.MultiSelectTrigger.EVENT_COUNTER_CLICK, function () { if (!self.combo.isViewVisible()) { self.combo.showView(); } }); this.trigger.on(BI.MultiSelectTrigger.EVENT_CHANGE, function () { var val = { type: BI.Selection.Multi, value: this.getSearcher().hasChecked() ? {1: 1} : {} }; this.getSearcher().setState(val); this.getCounter().setButtonChecked(val); }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { if (isSearching()) { return; } if (change === true) { self.storeValue = {value: self.combo.getValue()}; change = false; } self.combo.setValue(self.storeValue); self.populate(); }); this.combo.on(BI.Combo.EVENT_BEFORE_HIDEVIEW, function () { if (isSearching()) { self.trigger.stopEditing(); self.fireEvent(BI.MultiTreeCombo.EVENT_CONFIRM); }else{ if (isPopupView()) { self.trigger.stopEditing(); self.storeValue = {value: self.combo.getValue()}; if (clear === true) { self.storeValue = {value: {}}; } self.fireEvent(BI.MultiTreeCombo.EVENT_CONFIRM); } } clear = false; change = false; }); var triggerBtn = BI.createWidget({ type: "bi.trigger_icon_button", width: o.height, height: o.height, cls: "multi-select-trigger-icon-button bi-border-left" }); triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { self.trigger.getCounter().hideView(); if (self.combo.isViewVisible()) { self.combo.hideView(); } else { self.combo.showView(); } }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.combo, left: 0, right: 0, top: 0, bottom: 0 }, { el: triggerBtn, right: 0, top: 0, bottom: 0 }] }) }, _defaultState: function () { this.trigger.stopEditing(); this.combo.hideView(); }, setValue: function (v) { this.storeValue.value = v || {}; this.combo.setValue({ value: v || {} }); }, getValue: function () { return this.storeValue.value; }, populate: function () { this.combo.populate.apply(this.combo, arguments); } }); BI.MultiTreeCombo.EVENT_CONFIRM = "MultiTreeCombo.EVENT_CONFIRM"; BI.shortcut('bi.multi_tree_combo', BI.MultiTreeCombo);/** * 带加载的多选下拉面板 * @class BI.MultiTreePopup * @extends BI.Pane */ BI.MultiTreePopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-tree-popup', maxWidth: 'auto', minWidth: 100, maxHeight: 400, onLoaded: BI.emptyFn }); }, _init: function () { BI.MultiTreePopup.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.selectedValues = {}; this.tree = BI.createWidget({ type: "bi.async_tree", height: 400, cls:"popup-view-tree", itemsCreator: opts.itemsCreator, onLoaded: opts.onLoaded }); this.popupView = BI.createWidget({ type: "bi.multi_popup_view", element: this, stopPropagation: false, maxWidth: opts.maxWidth, minWidth: opts.minWidth, maxHeight: opts.maxHeight, buttons: [BI.i18nText('BI-Basic_Clears'), BI.i18nText('BI-Basic_Sure')], el: this.tree }); this.popupView.on(BI.MultiPopupView.EVENT_CLICK_TOOLBAR_BUTTON, function (index) { switch (index) { case 0: self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CLEAR); break; case 1: self.fireEvent(BI.MultiTreePopup.EVENT_CLICK_CONFIRM); break; } }); this.tree.on(BI.TreeView.EVENT_CHANGE, function () { self.fireEvent(BI.MultiTreePopup.EVENT_CHANGE); }); this.tree.on(BI.TreeView.EVENT_AFTERINIT, function () { self.fireEvent(BI.MultiTreePopup.EVENT_AFTERINIT); }); }, getValue: function () { return this.tree.getValue(); }, setValue: function (v) { v || (v = {}); this.tree.setSelectedValue(v.value); }, populate: function (config) { this.tree.stroke(config); }, hasChecked: function () { return this.tree.hasChecked(); }, resetHeight: function (h) { this.popupView.resetHeight(h); }, resetWidth: function (w) { this.popupView.resetWidth(w); } }); BI.MultiTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiTreePopup.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreePopup.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.MultiTreePopup.EVENT_AFTERINIT = "EVENT_AFTERINIT"; BI.shortcut('bi.multi_tree_popup_view', BI.MultiTreePopup);/** * * 在搜索框中输入文本弹出的面板 * @class BI.MultiTreeSearchPane * @extends BI.Pane */ BI.MultiTreeSearchPane = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.MultiTreeSearchPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-multi-tree-search-pane bi-card", itemsCreator: BI.emptyFn, keywordGetter: BI.emptyFn }); }, _init: function () { BI.MultiTreeSearchPane.superclass._init.apply(this, arguments); var self = this, opts = this.options; this.partTree = BI.createWidget({ type: "bi.part_tree", element: this, tipText: BI.i18nText("BI-No_Select"), itemsCreator: function (op, callback) { op.keyword = opts.keywordGetter(); opts.itemsCreator(op, callback); } }); this.partTree.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.partTree.on(BI.TreeView.EVENT_CHANGE, function () { self.fireEvent(BI.MultiTreeSearchPane.EVENT_CHANGE); }); }, hasChecked: function () { return this.partTree.hasChecked(); }, setValue: function (v) { this.setSelectedValue(v.value); }, setSelectedValue: function (v) { v || (v = {}); this.partTree.setSelectedValue(v); }, getValue: function () { return this.partTree.getValue(); }, empty: function () { this.partTree.empty(); }, populate: function (op) { this.partTree.stroke.apply(this.partTree, arguments); } }); BI.MultiTreeSearchPane.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiTreeSearchPane.EVENT_CLICK_CONFIRM = "EVENT_CLICK_CONFIRM"; BI.MultiTreeSearchPane.EVENT_CLICK_CLEAR = "EVENT_CLICK_CLEAR"; BI.shortcut("bi.multi_tree_search_pane", BI.MultiTreeSearchPane);/** * 查看已选按钮 * Created by guy on 15/11/3. * @class BI.MultiTreeCheckSelectedButton * @extends BI.Single */ BI.MultiTreeCheckSelectedButton = BI.inherit(BI.Single, { _const: { checkSelected: BI.i18nText('BI-Check_Selected') }, _defaultConfig: function () { return BI.extend(BI.MultiTreeCheckSelectedButton.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-tree-check-selected-button', itemsCreator: BI.emptyFn }); }, _init: function () { BI.MultiTreeCheckSelectedButton.superclass._init.apply(this, arguments); var self = this; this.indicator = BI.createWidget({ type: 'bi.icon_button', cls: 'check-font trigger-check-selected', width: 15, height: 15, stopPropagation: true }); this.checkSelected = BI.createWidget({ type: 'bi.text_button', cls: "trigger-check-selected", invisible: true, hgap: 4, text: this._const.checkSelected, textAlign: 'center', textHeight: 15 }); this.checkSelected.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.checkSelected.on(BI.TextButton.EVENT_CHANGE, function () { self.fireEvent(BI.MultiSelectCheckSelectedButton.EVENT_CHANGE, arguments); }); BI.createWidget({ type: "bi.horizontal", element: this, items: [this.indicator, this.checkSelected] }) this.element.hover(function () { self.indicator.setVisible(false); self.checkSelected.setVisible(true); }, function () { self.indicator.setVisible(true); self.checkSelected.setVisible(false); }); this.setVisible(false); }, setValue: function (v) { v || (v = {}); this.setVisible(BI.size(v.value) > 0); } }); BI.MultiTreeCheckSelectedButton.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut('bi.multi_tree_check_selected_button', BI.MultiTreeCheckSelectedButton);/** * searcher * Created by guy on 15/11/3. * @class BI.MultiTreeSearcher * @extends Widget */ BI.MultiTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiTreeSearcher.superclass._defaultConfig.apply(this, arguments), { baseCls: 'bi-multi-tree-searcher', itemsCreator: BI.emptyFn, popup: {}, adapter: null, masker: {} }); }, _init: function () { BI.MultiTreeSearcher.superclass._init.apply(this, arguments); var self = this, o = this.options; this.editor = BI.createWidget({ type: 'bi.multi_select_editor', height: o.height, el: { type: "bi.simple_state_editor", height: o.height } }); this.searcher = BI.createWidget({ type: "bi.searcher", element: this, isAutoSearch: false, isAutoSync: false, onSearch: function (op, callback) { callback({ keyword: self.editor.getValue() }); }, el: this.editor, popup: BI.extend({ type: "bi.multi_tree_search_pane", keywordGetter: function () { return self.editor.getValue(); }, itemsCreator: function (op, callback) { op.keyword = self.editor.getValue(); o.itemsCreator(op, callback); } }, o.popup), adapter: o.adapter, masker: o.masker }); this.searcher.on(BI.Searcher.EVENT_START, function () { self.fireEvent(BI.MultiTreeSearcher.EVENT_START); }); this.searcher.on(BI.Searcher.EVENT_PAUSE, function () { if (this.hasMatched()) { } self.fireEvent(BI.MultiTreeSearcher.EVENT_PAUSE); }); this.searcher.on(BI.Searcher.EVENT_STOP, function () { self.fireEvent(BI.MultiTreeSearcher.EVENT_STOP); }); this.searcher.on(BI.Searcher.EVENT_CHANGE, function () { self.fireEvent(BI.MultiTreeSearcher.EVENT_CHANGE, arguments); }); }, adjustView: function () { this.searcher.adjustView(); }, setAdapter: function (adapter) { this.searcher.setAdapter(adapter); }, isSearching: function () { return this.searcher.isSearching(); }, stopSearch: function () { this.searcher.stopSearch(); }, getKeyword: function () { return this.editor.getValue(); }, hasMatched: function () { return this.searcher.hasMatched(); }, hasChecked: function () { return this.searcher.getView() && this.searcher.getView().hasChecked(); }, setState: function (ob) { ob || (ob = {}); ob.value || (ob.value = []); if (ob.type === BI.Selection.All) { this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.All); } else { this.editor.setState(BI.size(ob.value) > 0 ? BI.Selection.Multi : BI.Selection.None); } }, setValue: function (ob) { this.setState(ob); this.searcher.setValue(ob); }, getKey: function () { return this.editor.getValue(); }, getValue: function () { return this.searcher.getValue(); }, populate: function (items) { this.searcher.populate.apply(this.searcher, arguments); } }); BI.MultiTreeSearcher.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.MultiTreeSearcher.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultiTreeSearcher.EVENT_START = "EVENT_START"; BI.MultiTreeSearcher.EVENT_STOP = "EVENT_STOP"; BI.MultiTreeSearcher.EVENT_PAUSE = "EVENT_PAUSE"; BI.shortcut('bi.multi_tree_searcher', BI.MultiTreeSearcher);//小于号的值为:0,小于等于号的值为:1 //closeMIn:最小值的符号,closeMax:最大值的符号 /** * Created by roy on 15/9/17. * */ BI.NumericalInterval = BI.inherit(BI.Single, { constants: { typeError: "typeBubble", numberError: "numberBubble", signalError: "signalBubble", editorWidth: 114, columns: 5, width: 30, rows: 1, numberErrorCls: "number-error", border: 1, less: 0, less_equal: 1, numTip: "" }, _defaultConfig: function () { var conf = BI.NumericalInterval.superclass._defaultConfig.apply(this, arguments) return BI.extend(conf, { extraCls: "bi-numerical-interval", height: 25, validation: "valid" }) }, _init: function () { var self = this, c = this.constants, o = this.options; BI.NumericalInterval.superclass._init.apply(this, arguments) this.smallEditor = BI.createWidget({ type: "bi.editor", height: o.height - 2, watermark: BI.i18nText("BI-Basic_Unrestricted"), allowBlank: true, value: o.min, level: "warning", tipType: "warning", quitChecker: function () { return false; }, validationChecker: function (v) { if (!BI.isNumeric(v)) { self.smallEditorBubbleType = c.typeError; return false; } return true; }, cls: "numerical-interval-small-editor bi-border-top bi-border-bottom bi-border-left" }); this.smallTip = BI.createWidget({ type: "bi.label", text: o.numTip, height: o.height - 2, invisible: true }); BI.createWidget({ type: "bi.absolute", element: this.smallEditor.element, items: [{ el: this.smallTip, top: 0, right: 5 }] }); this.bigEditor = BI.createWidget({ type: "bi.editor", height: o.height - 2, watermark: BI.i18nText("BI-Basic_Unrestricted"), allowBlank: true, value: o.max, level: "warning", tipType: "warning", quitChecker: function () { return false; }, validationChecker: function (v) { if (!BI.isNumeric(v)) { self.bigEditorBubbleType = c.typeError; return false; } return true; }, cls: "numerical-interval-big-editor bi-border-top bi-border-bottom bi-border-right" }); this.bigTip = BI.createWidget({ type: "bi.label", text: o.numTip, height: o.height - 2, invisible: true }); BI.createWidget({ type: "bi.absolute", element: this.bigEditor.element, items: [{ el: this.bigTip, top: 0, right: 5 }] }); //this.smallCombo = BI.createWidget({ // type: "bi.numerical_interval_combo", // cls: "numerical-interval-small-combo", // height: o.height, // value: o.closemin ? 1 : 0, // offsetStyle: "left" //}); // //this.bigCombo = BI.createWidget({ // type: "bi.numerical_interval_combo", // cls: "numerical-interval-big-combo", // height: o.height, // value: o.closemax ? 1 : 0, // offsetStyle: "left" //}); this.smallCombo = BI.createWidget({ type: "bi.icon_combo", cls: "numerical-interval-small-combo bi-border", height: o.height - 2, items: [{ text: "(" + BI.i18nText("BI-Less_Than") + ")", iconClass: "less-font", value: 0 }, { text: "(" + BI.i18nText("BI-Less_And_Equal") + ")", value: 1, iconClass: "less-equal-font" }] }); if (o.closemin === true) { this.smallCombo.setValue(1); } else { this.smallCombo.setValue(0); } this.bigCombo = BI.createWidget({ type: "bi.icon_combo", cls: "numerical-interval-big-combo bi-border", height: o.height - 2, items: [{ text: "(" + BI.i18nText("BI-Less_Than") + ")", iconClass: "less-font", value: 0 }, { text: "(" + BI.i18nText("BI-Less_And_Equal") + ")", value: 1, iconClass: "less-equal-font" }] }); if (o.closemax === true) { this.bigCombo.setValue(1); } else { this.bigCombo.setValue(0); } this.label = BI.createWidget({ type: "bi.label", text: BI.i18nText("BI-Basic_Value"), textHeight: o.height - c.border * 2, width: c.width - c.border * 2, height: o.height - c.border * 2, level: "warning", tipType: "warning" }); this.left = BI.createWidget({ type: "bi.htape", items: [{ el: self.smallEditor }, { el: self.smallCombo, width: c.width - c.border * 2 }] }); this.right = BI.createWidget({ type: "bi.htape", items: [{ el: self.bigCombo, width: c.width - c.border * 2 }, { el: self.bigEditor }] }); BI.createWidget({ element: self, type: "bi.center", hgap: 15, height: o.height, items: [ { type: "bi.absolute", items: [{ el: self.left, left: -15, right: 0, top: 0, bottom: 0 }] }, { type: "bi.absolute", items: [{ el: self.right, left: 0, right: -15, top: 0, bottom: 0 }] } ] }); BI.createWidget({ element: self, type: "bi.horizontal_auto", items: [ self.label ] }); self._setValidEvent(self.bigEditor, c.bigEditor); self._setValidEvent(self.smallEditor, c.smallEditor); self._setErrorEvent(self.bigEditor, c.bigEditor); self._setErrorEvent(self.smallEditor, c.smallEditor); self._setBlurEvent(self.bigEditor); self._setBlurEvent(self.smallEditor); self._setFocusEvent(self.bigEditor); self._setFocusEvent(self.smallEditor); self._setComboValueChangedEvent(self.bigCombo); self._setComboValueChangedEvent(self.smallCombo); self._setEditorValueChangedEvent(self.bigEditor); self._setEditorValueChangedEvent(self.smallEditor); }, _checkValidation: function () { var self = this, c = this.constants, o = this.options; self._setTitle(""); BI.Bubbles.hide(c.typeError); BI.Bubbles.hide(c.numberError); BI.Bubbles.hide(c.signalError); if (!self.smallEditor.isValid() || !self.bigEditor.isValid()) { self.element.removeClass("number-error"); o.validation = "invalid"; return c.typeError; } else { if (BI.isEmptyString(self.smallEditor.getValue()) || BI.isEmptyString(self.bigEditor.getValue())) { self.element.removeClass("number-error"); o.validation = "valid"; return ""; } else { var smallValue = parseFloat(self.smallEditor.getValue()), bigValue = parseFloat(self.bigEditor.getValue()), bigComboValue = self.bigCombo.getValue(), smallComboValue = self.smallCombo.getValue(); if (bigComboValue[0] === c.less_equal && smallComboValue[0] === c.less_equal) { if (smallValue > bigValue) { self.element.addClass("number-error"); o.validation = "invalid"; return c.numberError; } else { self.element.removeClass("number-error"); o.validation = "valid"; return ""; } } else { if (smallValue > bigValue) { self.element.addClass("number-error"); o.validation = "invalid"; return c.numberError; } else if (smallValue === bigValue) { self.element.addClass("number-error"); o.validation = "invalid"; return c.signalError; } else { self.element.removeClass("number-error"); o.validation = "valid"; return ""; } } } } }, _setTitle: function (v) { var self = this; self.bigEditor.setTitle(v); self.smallEditor.setTitle(v); self.label.setTitle(v); }, _setFocusEvent: function (w) { var self = this, c = this.constants; w.on(BI.Editor.EVENT_FOCUS, function () { self._setTitle(""); switch (self._checkValidation()) { case c.typeError: BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, { offsetStyle: "center" }); break; case c.numberError: BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, { offsetStyle: "center" }); break; case c.signalError: BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, { offsetStyle: "center" }); break; default : return } }) }, _setBlurEvent: function (w) { var c = this.constants, self = this; w.on(BI.Editor.EVENT_BLUR, function () { BI.Bubbles.hide(c.typeError); BI.Bubbles.hide(c.numberError); BI.Bubbles.hide(c.signalError); switch (self._checkValidation()) { case c.typeError: self._setTitle(BI.i18nText("BI-Numerical_Interval_Input_Data")); break; case c.numberError: self._setTitle(BI.i18nText("BI-Numerical_Interval_Number_Value")); break; case c.signalError: self._setTitle(BI.i18nText("BI-Numerical_Interval_Signal_Value")); break; default: self._setTitle(""); } }) }, _setErrorEvent: function (w) { var c = this.constants, self = this w.on(BI.Editor.EVENT_ERROR, function () { self._checkValidation(); BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, { offsetStyle: "center" }); self.fireEvent(BI.NumericalInterval.EVENT_ERROR); }) }, _setValidEvent: function (w) { var self = this, c = this.constants; w.on(BI.Editor.EVENT_VALID, function () { switch (self._checkValidation()) { case c.numberError: BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, { offsetStyle: "center" }); self.fireEvent(BI.NumericalInterval.EVENT_ERROR); break; case c.signalError: BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, { offsetStyle: "center" }); self.fireEvent(BI.NumericalInterval.EVENT_ERROR); break; default: self.fireEvent(BI.NumericalInterval.EVENT_VALID); } }) }, _setEditorValueChangedEvent: function (w) { var self = this, c = this.constants; w.on(BI.Editor.EVENT_CHANGE, function () { switch (self._checkValidation()) { case c.typeError: BI.Bubbles.show(c.typeError, BI.i18nText("BI-Numerical_Interval_Input_Data"), self, { offsetStyle: "center" }); break; case c.numberError: BI.Bubbles.show(c.numberError, BI.i18nText("BI-Numerical_Interval_Number_Value"), self, { offsetStyle: "center" }); break; case c.signalError: BI.Bubbles.show(c.signalError, BI.i18nText("BI-Numerical_Interval_Signal_Value"), self, { offsetStyle: "center" }); break; default : break; } self.fireEvent(BI.NumericalInterval.EVENT_CHANGE); }); }, _setComboValueChangedEvent: function (w) { var self = this, c = this.constants; w.on(BI.IconCombo.EVENT_CHANGE, function () { switch (self._checkValidation()) { case c.typeError: self._setTitle(BI.i18nText("BI-Numerical_Interval_Input_Data")); self.fireEvent(BI.NumericalInterval.EVENT_ERROR); break; case c.numberError: self._setTitle(BI.i18nText("BI-Numerical_Interval_Number_Value")); self.fireEvent(BI.NumericalInterval.EVENT_ERROR); break; case c.signalError: self._setTitle(BI.i18nText("BI-Numerical_Interval_Signal_Value")); self.fireEvent(BI.NumericalInterval.EVENT_ERROR); break; default : self.fireEvent(BI.NumericalInterval.EVENT_CHANGE); self.fireEvent(BI.NumericalInterval.EVENT_VALID); } }) }, isStateValid: function () { return this.options.validation === "valid"; }, setMinEnable: function (b) { this.smallEditor.setEnable(b); }, setCloseMinEnable: function (b) { this.smallCombo.setEnable(b); }, setMaxEnable: function (b) { this.bigEditor.setEnable(b); }, setCloseMaxEnable: function (b) { this.bigCombo.setEnable(b); }, showNumTip: function () { this.smallTip.setVisible(true); this.bigTip.setVisible(true); }, hideNumTip: function () { this.smallTip.setVisible(false); this.bigTip.setVisible(false); }, setNumTip: function(numTip) { this.smallTip.setText(numTip); this.bigTip.setText(numTip); }, getNumTip: function() { return this.smallTip.getText(); }, setValue: function (data) { data = data || {}; var self = this, combo_value; if (BI.isNumeric(data.min) || BI.isEmptyString(data.min)) { self.smallEditor.setValue(data.min); } if (!BI.isNotNull(data.min)) { self.smallEditor.setValue(""); } if (BI.isNumeric(data.max) || BI.isEmptyString(data.max)) { self.bigEditor.setValue(data.max); } if (!BI.isNotNull(data.max)) { self.bigEditor.setValue(""); } if (!BI.isNull(data.closemin)) { if (data.closemin === true) { combo_value = 1 } else { combo_value = 0 } self.smallCombo.setValue(combo_value); } if (!BI.isNull(data.closemax)) { if (data.closemax === true) { combo_value = 1 } else { combo_value = 0 } self.bigCombo.setValue(combo_value); } }, getValue: function () { var self = this, value = {}, minComboValue = self.smallCombo.getValue(), maxComboValue = self.bigCombo.getValue(); value.min = self.smallEditor.getValue(); value.max = self.bigEditor.getValue(); if (minComboValue[0] === 0) { value.closemin = false } else { value.closemin = true } if (maxComboValue[0] === 0) { value.closemax = false } else { value.closemax = true } return value; } }); BI.NumericalInterval.EVENT_CHANGE = "EVENT_CHANGE"; BI.NumericalInterval.EVENT_VALID = "EVENT_VALID"; BI.NumericalInterval.EVENT_ERROR = "EVENT_ERROR"; BI.shortcut("bi.numerical_interval", BI.NumericalInterval);/** * * 表格 * * Created by GUY on 2015/9/22. * @class BI.PageTableCell * @extends BI.Single */ BI.PageTableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.PageTableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-page-table-cell", text: "", title: "" }) }, _init: function () { BI.PageTableCell.superclass._init.apply(this, arguments); var label = BI.createWidget({ type: "bi.label", element: this, textAlign: "left", whiteSpace: "nowrap", height: this.options.height, text: this.options.text, title: this.options.title, value: this.options.value, lgap: 5, rgap: 5 }); if (BI.isNotNull(this.options.styles) && BI.isObject(this.options.styles)) { this.element.css(this.options.styles); } } }); BI.shortcut("bi.page_table_cell", BI.PageTableCell);/** * 分页表格 * * Created by GUY on 2016/2/15. * @class BI.PageTable * @extends BI.Widget */ BI.PageTable = BI.inherit(BI.Widget, { _const: { scrollWidth: 18, minScrollWidth: 100 }, _defaultConfig: function () { return BI.extend(BI.PageTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-page-table", el: { type: "bi.sequence_table" }, pager: { horizontal: { pages: false, //总页数 curr: 1, //初始化当前页, pages为数字时可用 hasPrev: BI.emptyFn, hasNext: BI.emptyFn, firstPage: 1, lastPage: BI.emptyFn }, vertical: { pages: false, //总页数 curr: 1, //初始化当前页, pages为数字时可用 hasPrev: BI.emptyFn, hasNext: BI.emptyFn, firstPage: 1, lastPage: BI.emptyFn } }, itemsCreator: BI.emptyFn, isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效 isNeedMerge: false,//是否需要合并单元格 mergeCols: [], //合并的单元格列号 mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, rowSize: 25, regionColumnSize: [], headerCellStyleGetter: BI.emptyFn, summaryCellStyleGetter: BI.emptyFn, sequenceCellStyleGetter: BI.emptyFn, header: [], items: [], //二维数组 //交叉表头 crossHeader: [], crossItems: [] }); }, _init: function () { BI.PageTable.superclass._init.apply(this, arguments); var self = this, o = this.options; this.hCurr = 1; this.vCurr = 1; this.table = BI.createWidget(o.el, { type: "bi.sequence_table", width: o.width, height: o.height && o.height - 30, isNeedResize: true, isResizeAdapt: false, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: o.mergeRule, columnSize: o.columnSize, minColumnSize: o.minColumnSize, maxColumnSize: o.maxColumnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, headerCellStyleGetter: o.headerCellStyleGetter, summaryCellStyleGetter: o.summaryCellStyleGetter, sequenceCellStyleGetter: o.sequenceCellStyleGetter, header: o.header, items: o.items, //交叉表头 crossHeader: o.crossHeader, crossItems: o.crossItems }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); this.pager = BI.createWidget(o.pager, { type: "bi.direction_pager", height: 30 }); this.pager.on(BI.Pager.EVENT_CHANGE, function () { var vpage = this.getVPage && this.getVPage(); if (BI.isNull(vpage)) { vpage = this.getCurrentPage(); } var hpage = this.getHPage && this.getHPage(); o.itemsCreator({ vpage: vpage, hpage: hpage }, function (items, header, crossItems, crossHeader) { self.table.setVPage ? self.table.setVPage(vpage) : self.table.setValue(vpage); self.table.setHPage && self.table.setHPage(hpage); self.populate.apply(self, arguments); }); }); BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.table, left: 0, top: 0 }, { el: this.pager, left: 0, right: 0, bottom: 0 }] }) }, setHPage: function (v) { this.hCurr = v; this.pager.setHPage && this.pager.setHPage(v); this.table.setHPage && this.table.setHPage(v); }, setVPage: function (v) { this.vCurr = v; this.pager.setVPage && this.pager.setVPage(v); this.table.setVPage && this.table.setVPage(v); }, getHPage: function () { var hpage = this.pager.getHPage && this.pager.getHPage(); if (BI.isNotNull(hpage)) { return hpage; } hpage = this.pager.getCurrentPage && this.pager.getCurrentPage(); if (BI.isNotNull(hpage)) { return hpage; } return this.hpage; }, getVPage: function () { var vpage = this.pager.getVPage && this.pager.getVPage(); if (BI.isNotNull(vpage)) { return vpage; } vpage = this.pager.getCurrentPage && this.pager.getCurrentPage(); if (BI.isNotNull(vpage)) { return vpage; } return this.vpage; }, setWidth: function (width) { BI.PageTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(width); }, setHeight: function (height) { BI.PageTable.superclass.setHeight.apply(this, arguments); var showPager = false; if (this.pager.alwaysShowPager) { showPager = true; } else if (this.pager.hasHNext && this.pager.hasHNext()) { showPager = true; } else if (this.pager.hasHPrev && this.pager.hasHPrev()) { showPager = true; } else if (this.pager.hasVNext && this.pager.hasVNext()) { showPager = true; } else if (this.pager.hasVPrev && this.pager.hasVPrev()) { showPager = true; } else if (this.pager.hasNext && this.pager.hasNext()) { showPager = true; } else if (this.pager.hasPrev && this.pager.hasPrev()) { showPager = true; } this.table.setHeight(height - (showPager ? 30 : 0)); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; this.table.setColumnSize(columnSize); }, getColumnSize: function () { return this.table.getColumnSize(); }, setRegionColumnSize: function (columnSize) { this.options.columnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, restore: function () { this.table.restore(); }, attr: function () { BI.PageTable.superclass.attr.apply(this, arguments); this.table.attr.apply(this.table, arguments); }, populate: function () { this.pager.populate(); this.table.populate.apply(this.table, arguments); }, destroy: function () { this.table.destroy(); this.pager && this.pager.destroy(); BI.PageTable.superclass.destroy.apply(this, arguments); } }); BI.shortcut('bi.page_table', BI.PageTable);/** * 路径选择 * * Created by GUY on 2015/12/4. * @class BI.PathChooser * @extends BI.Widget */ BI.PathChooser = BI.inherit(BI.Widget, { _const: { lineColor: "#d4dadd", selectLineColor: "#3f8ce8" }, _defaultConfig: function () { return BI.extend(BI.PathChooser.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-path-chooser", items: [] }) }, _init: function () { BI.PathChooser.superclass._init.apply(this, arguments); this.populate(this.options.items); }, _createRegions: function (regions) { var self = this; this.regions = BI.createWidgets(BI.map(regions, function (i, region) { return { type: "bi.path_region", title: self.texts[region] || region } })); this.regionMap = {}; BI.each(regions, function (i, region) { self.regionMap[region] = i; }); this.container = BI.createWidget({ type: "bi.horizontal", verticalAlign: "top", scrollx: false, scrolly: false, hgap: 10, items: this.regions }); BI.createWidget({ type: "bi.vertical_adapt", element: this, scrollable: true, hgap: 10, items: [this.container] }); }, getRegionIndexById: function (id) { var node = this.store[id]; var regionType = node.get("region"); return this.regionMap[regionType]; }, _drawPath: function (start, offset, index) { var self = this; var starts = []; if (BI.contains(this.start, start)) { starts = this.start; } else { starts = [start]; } BI.each(starts, function (i, s) { BI.each(self.radios[s], function (i, rad) { rad.setSelected(false); }); BI.each(self.lines[s], function (i, line) { line.attr("stroke", self._const.lineColor); }); BI.each(self.regionIndexes[s], function (i, idx) { self.regions[idx].reset(); }); }); BI.each(this.routes[start][index], function (i, id) { var regionIndex = self.getRegionIndexById(id); self.regions[regionIndex].setSelect(offset + index, id); }); var current = BI.last(this.routes[start][index]); while (current && this.routes[current] && this.routes[current].length === 1) { BI.each(this.routes[current][0], function (i, id) { var regionIndex = self.getRegionIndexById(id); self.regions[regionIndex].setSelect(0, id); }); this.lines[current][0].attr("stroke", self._const.selectLineColor).toFront(); current = BI.last(this.routes[current][0]); } this.lines[start][index].attr("stroke", self._const.selectLineColor).toFront(); this.radios[start] && this.radios[start][index] && this.radios[start][index].setSelected(true); }, _drawRadio: function (start, offset, index, x, y) { var self = this; var radio = BI.createWidget({ type: "bi.radio", cls: "path-chooser-radio", selected: offset + index === 0, start: start, index: index }); radio.on(BI.Radio.EVENT_CHANGE, function () { self._drawPath(start, offset, index); self.fireEvent(BI.PathChooser.EVENT_CHANGE, start, index); }); if (!this.radios[start]) { this.radios[start] = []; } this.radios[start].push(radio); BI.createWidget({ type: "bi.absolute", element: this.container, items: [{ el: radio, left: x - 6.5, top: y - 6.5 }] }) }, _drawLine: function (start, lines) { var self = this; if (!this.lines[start]) { this.lines[start] = []; } if (!this.pathes[start]) { this.pathes[start] = []; } var startRegionIndex = this.getRegionIndexById(start); //start所在的位置,然后接着往下画其他的路径 var offset = this.regions[startRegionIndex].getIndexByValue(start); BI.each(lines, function (i, line) { self.pathes[start][i] = []; var idx = i + offset; var path = ""; var stop = 47.5 + 29 * idx; var sleft = 50 + 100 * startRegionIndex; var radioStartX = sleft, radioStartY = stop; var etop = stop; var endRegionIndex = self.getRegionIndexById(BI.last(line)); var endOffset = self.regions[endRegionIndex].getIndexByValue(BI.last(line)); var eleft = 50 + 100 * endRegionIndex; if (BI.contains(self.start, start)) { radioStartX = sleft - 50; path += "M" + (sleft - 50) + "," + stop; self.pathes[start][i].push({ x: sleft - 50, y: stop }) } else if (idx === 0) { radioStartX = sleft + 50; path += "M" + sleft + "," + stop; self.pathes[start][i].push({ x: sleft, y: stop }) } else { radioStartX = sleft + 50; path += "M" + sleft + "," + 47.5 + "L" + (sleft + 50) + "," + 47.5 + "L" + (sleft + 50) + "," + stop; self.pathes[start][i].push({ x: sleft, y: 47.5 }); self.pathes[start][i].push({ x: sleft + 50, y: 47.5 }); self.pathes[start][i].push({ x: sleft + 50, y: stop }); } if (idx > 0) { var endY = endOffset * 29 + 47.5; path += "L" + (eleft - 50) + "," + etop + "L" + (eleft - 50) + "," + endY + "L" + eleft + "," + endY; self.pathes[start][i].push({ x: eleft - 50, y: etop }); self.pathes[start][i].push({ x: eleft - 50, y: endY }); self.pathes[start][i].push({ x: eleft, y: endY }); } else { path += "L" + eleft + "," + etop; self.pathes[start][i].push({ x: eleft, y: etop }); } var graph = self.svg.path(path) .attr({ stroke: idx === 0 ? self._const.selectLineColor : self._const.lineColor, 'stroke-dasharray': '-' }); self.lines[start].push(graph); if (lines.length > 1) { self.lines[start][0].toFront(); } //第一个元素无论有多少个都要显示radio if (BI.contains(self.start, start)) { self.lines[self.regions[0].getValueByIndex(0)][0].toFront(); } if (lines.length > 1 || BI.contains(self.start, start)) { self._drawRadio(start, offset, i, radioStartX, radioStartY); } }); }, _drawLines: function (routes) { var self = this; this.lines = {}; this.pathes = {}; this.radios = {}; this.regionIndexes = {}; BI.each(routes, function (k, route) { if (!self.regionIndexes[k]) { self.regionIndexes[k] = []; } BI.each(route, function (i, rs) { BI.each(rs, function (j, id) { var regionIndex = self.getRegionIndexById(id); if (!BI.contains(self.regionIndexes[k], regionIndex)) { self.regionIndexes[k].push(regionIndex); } }); }) }); BI.each(routes, function (k, route) { self._drawLine(k, route); }); }, _pushNodes: function (nodes) { var self = this; var indexes = []; for (var i = 0; i < nodes.length; i++) { var id = nodes[i]; var index = self.getRegionIndexById(id); indexes.push(index); var region = self.regions[index]; if (i === nodes.length - 1) { if (!region.hasItem(id)) { region.addItem(id, self.texts[id]); } break; } if (i > 0 || BI.contains(self.start, id)) { region.addItem(id, self.texts[id]); } } for (var i = BI.first(indexes); i < BI.last(indexes); i++) { if (!BI.contains(indexes, i)) { self.regions[i].addItem(""); } } }, _createNodes: function () { var self = this, o = this.options; this.store = {}; this.texts = {}; this.start = []; this.end = []; BI.each(o.items, function (i, item) { self.start.push(BI.first(item).value); self.end.push(BI.last(item).value); }); this.start = BI.uniq(this.start); this.end = BI.uniq(this.end); var regions = []; var tree = new BI.Tree(); var branches = {}, max = 0; BI.each(o.items, function (i, items) { BI.each(items, function (j, item) { if (!BI.has(branches, item.value)) { branches[item.value] = 0; } branches[item.value]++; max = Math.max(max, branches[item.value]); var prev = {}; if (j > 0) { prev = items[j - 1]; } var parent = self.store[prev.value || ""]; var node = self.store[item.value] || new BI.Node(item.value); node.set(item); self.store[item.value] = node; self.texts[item.value] = item.text; self.texts[item.region] = item.regionText; parent = BI.isNull(parent) ? tree.getRoot() : parent; if (parent.getChildIndex(item.value) === -1) { tree.addNode(parent, node); } }) }); //算出区域列表 tree.traverse(function (node) { BI.each(node.getChildren(), function (i, child) { if (BI.contains(regions, child.get("region"))) { var index1 = BI.indexOf(regions, node.get("region")); var index2 = BI.indexOf(regions, child.get("region")); //交换区域 if (index1 > index2) { var t = regions[index2]; for (var j = index2; j < index1; j++) { regions[j] = regions[j + 1]; } regions[index1] = t; } } else { regions.push(child.get("region")); } }); }); this._createRegions(regions); //算出节点 BI.each(branches, function (k, branch) { if (branch < max) { delete branches[k]; } }); //过滤节点 var nodes = []; var n = tree.getRoot(); while (n && n.getChildrenLength() === 1) { if (BI.has(branches, n.getChildren()[0].id)) { delete branches[n.getChildren()[0].id]; n = n.getChildren()[0]; } else { n = null; } } tree.traverse(function (node) { if (BI.has(branches, node.id)) { nodes.push(node.id); delete branches[node.id]; } }); //填充节点 var routes = {}; var s, e; for (var i = 0, len = nodes.length; i < len + 1; i++) { if (len === 0) { s = []; BI.each(this.start, function (i, id) { s.push(tree.search(id)); }); e = []; BI.each(this.end, function (i, id) { e.push(tree.search(id)); }); } else if (i === len) { s = e; e = []; BI.each(this.end, function (i, id) { e.push(tree.search(id)); }); } else if (i === 0) { s = []; BI.each(this.start, function (i, id) { s.push(tree.search(id)); }); e = [tree.search(nodes[i])]; } else { s = [tree.search(e[0] || tree.getRoot(), nodes[i - 1])]; e = [tree.search(s[0], nodes[i])]; } BI.each(s, function (i, n) { tree._recursion(n, [n.id], function (node, route) { if (BI.contains(e, node)) { if (!routes[n.id]) { routes[n.id] = []; } routes[n.id].push(route); self._pushNodes(route); if (e.length <= 1) { return true; } } }) }); } this.routes = routes; this._drawLines(routes); }, _unselectAllPath: function () { var self = this; BI.each(this.radios, function (idx, rad) { BI.each(rad, function (i, r) { r.setSelected(false); }); }); BI.each(this.lines, function (idx, line) { BI.each(line, function (i, li) { li.attr("stroke", self._const.lineColor); }); }); BI.each(this.regions, function (idx, region) { region.reset(); }); }, populate: function (items) { this.options.items = items || []; var self = this; this.empty(); if (this.options.items.length <= 0) { return; } this.svg = BI.createWidget({ type: "bi.svg" }); this._createNodes(); BI.createWidget({ type: "bi.absolute", element: this.container, items: [{ el: this.svg, top: 0, left: 0, right: 0, bottom: 0 }] }); }, setValue: function (v) { this._unselectAllPath(); var nodes = BI.keys(this.routes), self = this; var result = [], array = []; BI.each(v, function (i, val) { if (BI.contains(nodes, val)) { if (array.length > 0) { array.push(val); result.push(array); array = []; } } array.push(val); }); if (array.length > 0) { result.push(array); } //画这n条路径 BI.each(result, function (idx, path) { var start = path[0]; var index = BI.findIndex(self.routes[start], function (idx, p) { if (BI.isEqual(path, p)) { return true; } }); if (index >= 0) { var startRegionIndex = self.getRegionIndexById(start); var offset = self.regions[startRegionIndex].getIndexByValue(start); self._drawPath(start, offset, index); } }); }, getValue: function () { var path = []; BI.each(this.regions, function (i, region) { var val = region.getValue(); if (BI.isKey(val)) { path.push(val); } }); return path; } }); BI.PathChooser.EVENT_CHANGE = "PathChooser.EVENT_CHANGE"; BI.shortcut("bi.path_chooser", BI.PathChooser);/** * 路径选择区域 * * Created by GUY on 2015/12/4. * @class BI.PathRegion * @extends BI.Widget */ BI.PathRegion = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.PathRegion.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-path-region bi-background", width: 80, title: "" }) }, _init: function () { BI.PathRegion.superclass._init.apply(this, arguments); var self = this, o = this.options; this.zIndex = 100; var title = BI.createWidget({ type: "bi.label", text: o.title, title: o.title, height: 30 }); title.element.css("zIndex", this.zIndex--); this.items = []; this.vertical = BI.createWidget({ type: "bi.vertical", element: this, bgap: 5, hgap: 10, items: [title] }) }, hasItem: function (val) { return BI.any(this.items, function (i, item) { return val === item.getValue(); }); }, addItem: function (value, text) { if (BI.isKey(value)) { var label = BI.createWidget({ type: "bi.label", cls: "path-region-label bi-card bi-border bi-list-item-select", text: text, value: value, title: text || value, height: 22 }); } else { var label = BI.createWidget({ type: "bi.layout", height: 24 }); } label.element.css("zIndex", this.zIndex--); this.items.push(label); this.vertical.addItem(label); if (this.items.length === 1) { this.setSelect(0, value); } }, reset: function () { BI.each(this.items, function (i, item) { item.element.removeClass("active"); }); }, setSelect: function (index, value) { this.reset(); if (this.items.length <= 0) { return; } if (this.items.length === 1) { this.items[0].element.addClass("active"); return; } if (this.items[index].attr("value") === value) { this.items[index].element.addClass("active"); } }, setValue: function (value) { this.setSelect(this.getIndexByValue(value), value); }, getValueByIndex: function (idx) { return this.items[idx].attr("value"); }, getIndexByValue: function (value) { return BI.findIndex(this.items, function (i, item) { return item.attr("value") === value; }); }, getValue: function () { var res; BI.any(this.items, function (i, item) { if (item.element.hasClass("active")) { res = item.getValue(); return true; } }); return res; } }); BI.PathRegion.EVENT_CHANGE = "PathRegion.EVENT_CHANGE"; BI.shortcut("bi.path_region", BI.PathRegion);/** * 预览表列 * * Created by GUY on 2015/12/25. * @class BI.PreviewTableCell * @extends BI.Widget */ BI.PreviewTableCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.PreviewTableCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-preview-table-cell", text: "" }); }, _init: function () { BI.PreviewTableCell.superclass._init.apply(this, arguments); var self = this, o = this.options; BI.createWidget({ type: "bi.label", element: this, textAlign: "left", whiteSpace: "normal", height: this.options.height, text: this.options.text, value: this.options.value }) } }); BI.shortcut('bi.preview_table_cell', BI.PreviewTableCell);/** * 预览表 * * Created by GUY on 2015/12/25. * @class BI.PreviewTableHeaderCell * @extends BI.Widget */ BI.PreviewTableHeaderCell = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.PreviewTableHeaderCell.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-preview-table-header-cell", text: "" }); }, _init: function () { BI.PreviewTableHeaderCell.superclass._init.apply(this, arguments); var self = this, o = this.options; BI.createWidget({ type: "bi.label", element: this, textAlign: "left", whiteSpace: "normal", height: this.options.height, text: this.options.text, value: this.options.value }) } }); BI.shortcut('bi.preview_table_header_cell', BI.PreviewTableHeaderCell);/** * 预览表 * * Created by GUY on 2015/12/25. * @class BI.PreviewTable * @extends BI.Widget */ BI.PreviewTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.PreviewTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-preview-table", isNeedFreeze: false, freezeCols: [], rowSize: null, columnSize: [], headerRowSize: 30, header: [], items: [] }); }, _init: function () { BI.PreviewTable.superclass._init.apply(this, arguments); var self = this, o = this.options; this.table = BI.createWidget({ type: "bi.table_view", element: this, isNeedResize: false, isResizeAdapt: false, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, rowSize: o.rowSize, columnSize: o.columnSize, headerRowSize: o.headerRowSize, header: BI.map(o.header, function (i, items) { return BI.map(items, function (j, item) { return BI.extend({ type: "bi.preview_table_header_cell" }, item); }); }), items: BI.map(o.items, function (i, items) { return BI.map(items, function (j, item) { return BI.extend({ type: "bi.preview_table_cell" }, item); }); }) }); this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () { self._adjustColumns(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments); }); this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () { self._adjustColumns(); }); }, //是否有自适应调节的列,即列宽为"" _hasAdaptCol: function (columnSize) { return BI.any(columnSize, function (i, size) { return size === ""; }) }, _isPercentage: function (columnSize) { return columnSize[0] <= 1; }, _adjustColumns: function () { var self = this, o = this.options; if (o.isNeedFreeze === true) { //如果存在百分比的情况 if (this._isPercentage(o.columnSize)) { if (this._hasAdaptCol(o.columnSize)) { var findCols = [], remain = 0; BI.each(o.columnSize, function (i, size) { if (size === "") { findCols.push(i); } else { remain += size; } }); remain = 1 - remain; var average = remain / findCols.length; BI.each(findCols, function (i, col) { o.columnSize[col] = average; }); } var isRight = BI.first(o.freezeCols) !== 0; var freezeSize = [], notFreezeSize = []; BI.each(o.columnSize, function (i, size) { if (o.freezeCols.contains(i)) { freezeSize.push(size); } else { notFreezeSize.push(size); } }); var sumFreezeSize = BI.sum(freezeSize), sumNotFreezeSize = BI.sum(notFreezeSize); BI.each(freezeSize, function (i, size) { freezeSize[i] = size / sumFreezeSize; }); BI.each(notFreezeSize, function (i, size) { notFreezeSize[i] = size / sumNotFreezeSize; }); this.table.setRegionColumnSize(isRight ? ["fill", sumFreezeSize] : [sumFreezeSize, "fill"]); this.table.setColumnSize(isRight ? (notFreezeSize.concat(freezeSize)) : (freezeSize.concat(notFreezeSize))); } } else { //如果存在自适应宽度的列或者是百分比计算的列,需要将整个表宽设为100% if (this._hasAdaptCol(o.columnSize) || this._isPercentage(o.columnSize)) { this.table.setRegionColumnSize(["100%"]); } } }, setColumnSize: function (columnSize) { return this.table.setColumnSize(columnSize); }, getColumnSize: function () { return this.table.getColumnSize(); }, getCalculateColumnSize: function () { return this.table.getCalculateColumnSize(); }, setHeaderColumnSize: function (columnSize) { return this.table.setHeaderColumnSize(columnSize); }, setRegionColumnSize: function (columnSize) { return this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, getCalculateRegionColumnSize: function () { return this.table.getCalculateRegionColumnSize(); }, getCalculateRegionRowSize: function () { return this.table.getCalculateRegionRowSize(); }, getClientRegionColumnSize: function () { return this.table.getClientRegionColumnSize(); }, getScrollRegionColumnSize: function () { return this.table.getScrollRegionColumnSize() }, getScrollRegionRowSize: function () { return this.table.getScrollRegionRowSize() }, hasVerticalScroll: function () { return this.table.hasVerticalScroll(); }, setVerticalScroll: function (scrollTop) { return this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { return this.table.setLeftHorizontalScroll(scrollLeft) }, setRightHorizontalScroll: function (scrollLeft) { return this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, getColumns: function () { return this.table.getColumns(); }, populate: function (items, header) { this.table.populate(items, header); } }); BI.PreviewTable.EVENT_CHANGE = "PreviewTable.EVENT_CHANGE"; BI.shortcut('bi.preview_table', BI.PreviewTable);/** * 季度下拉框 * * Created by GUY on 2015/8/28. * @class BI.QuarterCombo * @extends BI.Widget */ BI.QuarterCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.QuarterCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-quarter-combo", behaviors: {}, height: 25 }); }, _init: function () { BI.QuarterCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.storeValue = ""; this.trigger = BI.createWidget({ type: "bi.quarter_trigger" }); this.trigger.on(BI.QuarterTrigger.EVENT_FOCUS, function () { self.storeValue = this.getKey(); }); this.trigger.on(BI.QuarterTrigger.EVENT_CHANGE, function () { self.combo.isViewVisible() && self.combo.hideView(); }); this.trigger.on(BI.QuarterTrigger.EVENT_START, function () { self.combo.isViewVisible() && self.combo.hideView(); }); this.trigger.on(BI.QuarterTrigger.EVENT_STOP, function () { if (!self.combo.isViewVisible()) { self.combo.showView(); } }); this.trigger.on(BI.QuarterTrigger.EVENT_CONFIRM, function () { if (self.combo.isViewVisible()) { return; } if (this.getKey() && this.getKey() !== self.storeValue) { self.setValue(this.getKey()); } else if (!this.getKey()) { self.setValue(); } self.fireEvent(BI.QuarterCombo.EVENT_CONFIRM); }); this.popup = BI.createWidget({ type: "bi.quarter_popup", behaviors: o.behaviors }); this.popup.on(BI.QuarterPopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.QuarterCombo.EVENT_CONFIRM); }); this.combo = BI.createWidget({ type: "bi.combo", element: this, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, popup: { minWidth: 85, el: this.popup } }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.QuarterCombo.EVENT_BEFORE_POPUPVIEW); }); }, setValue: function (v) { this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue() || ""; } }); BI.QuarterCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.QuarterCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.quarter_combo', BI.QuarterCombo);/** * 季度展示面板 * * Created by GUY on 2015/9/2. * @class BI.QuarterPopup * @extends BI.Trigger */ BI.QuarterPopup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.QuarterPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-quarter-popup", behaviors: {} }); }, _init: function () { BI.QuarterPopup.superclass._init.apply(this, arguments); var self = this, o = this.options; var items = [{ text: Date._QN[01], value: 1 }, { text: Date._QN[2], value: 2 }, { text: Date._QN[3], value: 3 }, { text: Date._QN[4], value: 4 }]; items = BI.map(items, function (j, item) { return BI.extend(item, { type: "bi.text_item", cls: "bi-list-item-active", textAlign: "left", whiteSpace: "nowrap", once: false, forceSelected: true, height: 25 }); }); this.quarter = BI.createWidget({ type: "bi.button_group", element: this, behaviors: o.behaviors, items: BI.createItems(items, {}), layouts: [{ type: "bi.vertical" }] }); this.quarter.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.MonthPopup.EVENT_CHANGE); } }) }, getValue: function () { return this.quarter.getValue()[0]; }, setValue: function (v) { this.quarter.setValue([v]); } }); BI.QuarterPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.quarter_popup", BI.QuarterPopup);/** * 季度trigger * * Created by GUY on 2015/8/21. * @class BI.QuarterTrigger * @extends BI.Trigger */ BI.QuarterTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, vgap: 2, triggerWidth: 30, textWidth: 40, errorText: BI.i18nText("BI-Quarter_Trigger_Error_Text") }, _defaultConfig: function () { return BI.extend(BI.QuarterTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-quarter-trigger bi-border", height: 25 }); }, _init: function () { BI.QuarterTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.editor = BI.createWidget({ type: "bi.sign_editor", height: o.height, validationChecker: function (v) { return v === "" || (BI.isPositiveInteger(v) && v >= 1 && v <= 4); }, quitChecker: function (v) { return false; }, hgap: c.hgap, vgap: c.vgap, allowBlank: true, errorText: c.errorText }); this.editor.on(BI.SignEditor.EVENT_FOCUS, function () { self.fireEvent(BI.QuarterTrigger.EVENT_FOCUS); }); this.editor.on(BI.SignEditor.EVENT_CHANGE, function () { self.fireEvent(BI.QuarterTrigger.EVENT_CHANGE); }); this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () { var value = self.editor.getValue(); if (BI.isNotNull(value)) { self.editor.setValue(value); self.editor.setTitle(value); } self.fireEvent(BI.QuarterTrigger.EVENT_CONFIRM); }); this.editor.on(BI.SignEditor.EVENT_SPACE, function () { if (self.editor.isValid()) { self.editor.blur(); } }); this.editor.on(BI.SignEditor.EVENT_START, function () { self.fireEvent(BI.QuarterTrigger.EVENT_START); }); this.editor.on(BI.SignEditor.EVENT_STOP, function () { self.fireEvent(BI.QuarterTrigger.EVENT_STOP); }); BI.createWidget({ element: this, type: 'bi.htape', items: [ { el: this.editor }, { el: { type: "bi.text_button", baseCls: "bi-trigger-quarter-text", text: BI.i18nText("BI-Multi_Date_Quarter"), width: c.textWidth }, width: c.textWidth }, { el: { type: "bi.trigger_icon_button", width: c.triggerWidth }, width: c.triggerWidth } ] }); }, setValue: function (v) { this.editor.setState(v); this.editor.setValue(v); this.editor.setTitle(v); }, getKey: function () { return this.editor.getValue(); } }); BI.QuarterTrigger.EVENT_FOCUS = "EVENT_FOCUS"; BI.QuarterTrigger.EVENT_CHANGE = "EVENT_CHANGE"; BI.QuarterTrigger.EVENT_START = "EVENT_START"; BI.QuarterTrigger.EVENT_STOP = "EVENT_STOP"; BI.QuarterTrigger.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.shortcut("bi.quarter_trigger", BI.QuarterTrigger);/** * 关联视图字段Item * * Created by GUY on 2015/12/23. * @class BI.RelationViewItem * @extends BI.Widget */ BI.RelationViewItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.RelationViewItem.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-relation-view-item bi-list-item-active", height: 25, hoverIn: BI.emptyFn, hoverOut: BI.emptyFn }); }, _init: function () { BI.RelationViewItem.superclass._init.apply(this, arguments); var self = this, o = this.options; this.element.hover(o.hoverIn, o.hoverOut); var items = []; if (o.isPrimary) { items.push({ type: "bi.icon", width: 16, height: 16, title: BI.i18nText("BI-Primary_Key") }); } items.push({ type: "bi.label", text: o.text, value: o.value, height: o.height, textAlign: "left", width: o.isPrimary ? 70 : 90 }); BI.createWidget({ type: "bi.vertical_adapt", element: this, items: items, cls: "primary-key-font", lgap: 5 }); }, enableHover: function (opt) { BI.RelationViewRegion.superclass.enableHover.apply(this, [{ container: "body" }]); }, setSelected: function (b) { this.element[b ? "addClass" : "removeClass"]("active"); } }); BI.shortcut('bi.relation_view_item', BI.RelationViewItem);/** * 关联视图 * * Created by GUY on 2015/12/22. * @class BI.RelationView * @extends BI.Widget */ BI.RelationView = BI.inherit(BI.Widget, { _const: { lineColor: "#c4c6c6", selectLineColor: "#009de3" }, _defaultConfig: function () { return BI.extend(BI.RelationView.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-relation-view", items: [] }); }, _init: function () { BI.RelationView.superclass._init.apply(this, arguments); this.populate(this.options.items); }, _calculateWidths: function () { var widths = []; BI.each(this.views, function (i, items) { BI.each(items, function (j, obj) { if (!widths[j]) { widths[j] = BI.MIN; } widths[j] = Math.max(widths[j], obj.getWidth()); }) }); return widths; }, _calculateHeights: function () { var heights = BI.makeArray(BI.size(this.views), BI.MIN); BI.each(this.views, function (i, items) { BI.each(items, function (j, obj) { heights[i] = Math.max(heights[i], obj.getHeight()); }) }); return heights; }, _hoverIn: function (target) { var self = this, c = this._const; BI.each(this.relations, function (start, rs) { BI.each(rs, function (end, relation) { if (relation[0].primary.value === target || relation[0].foreign.value === target) { self.lines[start][end].attr("stroke", c.selectLineColor).toFront(); self.storeViews[start].setValue(relation[0].primary.value); self.storeViews[end].setValue(relation[0].foreign.value); } }); }); }, _hoverOut: function (target) { var self = this, c = this._const; BI.each(this.relations, function (start, rs) { BI.each(rs, function (end, relation) { if (relation[0].primary.value === target || relation[0].foreign.value === target) { self.lines[start][end].attr("stroke", c.lineColor); self.storeViews[start].setValue([]); self.storeViews[end].setValue([]); } }); }); }, previewRelationTables: function(relationTables, show) { if (!show) { BI.each(this.storeViews, function (i, view) { view.toggleRegion(true); view.setPreviewSelected(false); }); BI.each(this.lines, function (i, lines) { BI.each(lines, function (j, line) { line.show(); }); }); return; } BI.each(this.storeViews, function (id, view) { if (!relationTables.contains(id)) { view.toggleRegion(false); } else { view.setPreviewSelected(true); } }); BI.each(this.lines, function (id, lines) { BI.each(lines, function (cId, line) { if (!relationTables.contains(id) || !relationTables.contains(cId)) { line.hide(); } }); }); }, populate: function (items) { var self = this, o = this.options, c = this._const; o.items = items || []; this.empty(); this.svg = BI.createWidget({ type: "bi.svg" }); //算出所有的区域和关联 var regions = this.regions = {}, relations = this.relations = {}; BI.each(items, function (i, item) { var pr = item.primary.region, fr = item.foreign && item.foreign.region; if (pr && !relations[pr]) { relations[pr] = {}; } if (pr && fr && !relations[pr][fr]) { relations[pr][fr] = []; } if (pr && !regions[pr]) { regions[pr] = []; } if (fr && !regions[fr]) { regions[fr] = []; } if (pr && !BI.deepContains(regions[pr], item.primary)) { regions[pr].push(item.primary); } if (fr && !BI.deepContains(regions[fr], item.foreign)) { regions[fr].push(item.foreign); } pr && fr && relations[pr][fr].push(item); }); //求拓扑 var topology = []; var rs = BI.clone(regions), store = {}; while (!BI.isEmpty(rs)) { var clone = BI.clone(rs); BI.each(o.items, function (i, item) { if (!store[item.primary.region]) { delete clone[item.foreign && item.foreign.region]; } }); topology.push(BI.keys(clone)); BI.extend(store, clone); BI.each(clone, function (k, v) { delete rs[k]; }); } //构建视图 var views = this.views = {}, storeViews = this.storeViews = {}, indexes = this.indexes = {}; var verticals = []; BI.each(topology, function (i, items) { if (!views[i]) { views[i] = {}; } var horizontal = []; BI.each(items, function (j, region) { var items = regions[region]; views[i][j] = storeViews[region] = BI.createWidget({ type: "bi.relation_view_region_container", value: region, header: items[0].regionTitle, text: items.length > 0 ? items[0].regionText : "", handler: items.length > 0 ? items[0].regionHandler : BI.emptyFn, items: items, belongPackage: items.length > 0 ? items[0].belongPackage : true }); if (BI.isNotNull(items[0]) && BI.isNotNull(items[0].keyword)) { views[i][j].doRedMark(items[0].keyword); } views[i][j].on(BI.RelationViewRegionContainer.EVENT_HOVER_IN, function (v) { self._hoverIn(v); }); views[i][j].on(BI.RelationViewRegionContainer.EVENT_HOVER_OUT, function (v) { self._hoverOut(v); }); views[i][j].on(BI.RelationViewRegionContainer.EVENT_PREVIEW, function (v) { self.fireEvent(BI.RelationView.EVENT_PREVIEW, region, v); }); indexes[region] = {i: i, j: j}; horizontal.push(views[i][j]); }); verticals.push({ type: "bi.horizontal", items: horizontal }) }); //求每一行的高度 var heights = this._calculateHeights(); //求每一列的宽度 var widths = this._calculateWidths(); //求相对宽度和高度 var offsetWidths = [0], offsetHeights = [0]; BI.each(heights, function (i, h) { if (i === 0) { return; } offsetHeights[i] = offsetHeights[i - 1] + heights[i - 1]; }); BI.each(widths, function (i, w) { if (i === 0) { return; } offsetWidths[i] = offsetWidths[i - 1] + widths[i - 1]; }); //画线 var lines = this.lines = {};//缓存所有的线 BI.each(relations, function (start, rs) { BI.each(rs, function (end, relation) { var startIndex = indexes[start], endIndex = indexes[end]; var top = 0, right = 1, bottom = 2, left = 3; var startDirection = bottom, endDirection = top; // if (startIndex.j > endIndex.j) { // startDirection = left; // endDirection = right; // } else if (startIndex.j < endIndex.j) { // startDirection = right; // endDirection = left; // } else if (startIndex.i < endIndex.i) { // startDirection = bottom; // endDirection = top; // } else if (startIndex.i > endIndex.i) { // startDirection = top; // endDirection = bottom; // } var draw = function (i, j, direction, isForeign) { var x = offsetWidths[j] + (widths[j] - views[i][j].getWidth()) / 2; var y = offsetHeights[i] + (heights[i] - views[i][j].getHeight()) / 2; var path = "", position; switch (direction) { case top: position = isForeign ? views[i][j].getTopRightPosition() : views[i][j].getTopLeftPosition(); x += position.x; y += position.y; path = "M" + x + "," + y + "L" + x + "," + (y - 10); y -= 10; break; case right: position = views[i][j].getRightPosition(); x += position.x; y += position.y; path = "M" + x + "," + y + "L" + (x + 10) + "," + y; x += 10; break; case bottom: position = views[i][j].getBottomPosition(); x += position.x; y += position.y; path = "M" + x + "," + y + "L" + x + "," + (y + 10); y += 10; break; case left: position = views[i][j].getLeftPosition(); x += position.x; y += position.y; path = "M" + x + "," + y + "L" + (x - 10) + "," + y; x -= 10; break; } return {x: x, y: y, path: path}; }; var path = ""; var si = draw(startIndex.i, startIndex.j, startDirection); var ei = draw(endIndex.i, endIndex.j, endDirection, true); path += si.path + ei.path; if (!lines[start]) { lines[start] = {}; } path += "M" + si.x + "," + si.y + "L" + ei.x + "," + ei.y; var line = lines[start][end] = self.svg.path(path) .attr({"stroke": c.lineColor, "stroke-width": "2"}) .hover(function () { line.attr("stroke", c.selectLineColor).toFront(); storeViews[start].setValue(relation[0].primary.value); storeViews[end].setValue(relation[0].foreign.value); }, function () { line.attr("stroke", c.lineColor); storeViews[start].setValue([]); storeViews[end].setValue([]); }); }); }); var container = BI.createWidget(); BI.createWidget({ type: "bi.vertical", element: container, items: verticals }); BI.createWidget({ type: "bi.absolute", element: container, items: [{ el: this.svg, left: 0, right: 0, top: 0, bottom: 0 }] }); BI.createWidget({ type: "bi.center_adapt", scrollable: true, element: this, items: [container] }); } }); BI.RelationView.EVENT_CHANGE = "RelationView.EVENT_CHANGE"; BI.RelationView.EVENT_PREVIEW = "EVENT_PREVIEW"; BI.shortcut('bi.relation_view', BI.RelationView);/** * Created by Young's on 2017/3/10. */ BI.RelationViewRegionContainer = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.RelationViewRegionContainer.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-relation-view-region-container", width: 150 }); }, _init: function () { BI.RelationViewRegionContainer.superclass._init.apply(this, arguments); var self = this, o = this.options; this.region = BI.createWidget({ type: "bi.relation_view_region", value: o.value, header: o.header, text: o.text, handler: o.handler, items: o.items, belongPackage: o.belongPackage }); this.region.on(BI.RelationViewRegion.EVENT_PREVIEW, function (v) { self.fireEvent(BI.RelationViewRegionContainer.EVENT_PREVIEW, v); }); this.region.on(BI.RelationViewRegion.EVENT_HOVER_IN, function (v) { self.fireEvent(BI.RelationViewRegionContainer.EVENT_HOVER_IN, v); }); this.region.on(BI.RelationViewRegion.EVENT_HOVER_OUT, function (v) { self.fireEvent(BI.RelationViewRegionContainer.EVENT_HOVER_OUT, v); }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.region], width: this.region.getWidth(), height: this.region.getHeight() }); }, doRedMark: function () { this.region.doRedMark.apply(this.region, arguments); }, unRedMark: function () { this.region.unRedMark.apply(this.region, arguments); }, getWidth: function () { return this.region.getWidth(); }, getHeight: function () { return this.region.getHeight(); }, //获取上方开始划线的位置 getTopLeftPosition: function () { return this.region.getTopLeftPosition(); }, getTopRightPosition: function () { return this.region.getTopRightPosition(); }, getBottomPosition: function () { return this.region.getBottomPosition(); }, getLeftPosition: function () { return this.region.getLeftPosition(); }, getRightPosition: function () { return this.region.getRightPosition(); }, setValue: function (v) { this.region.setValue(v); }, toggleRegion: function (v) { v === true ? this.region.element.fadeIn() : this.region.element.fadeOut(); }, setPreviewSelected: function(v) { this.region.setPreviewSelected(v); } }); BI.RelationViewRegionContainer.EVENT_HOVER_IN = "RelationViewRegion.EVENT_HOVER_IN"; BI.RelationViewRegionContainer.EVENT_HOVER_OUT = "RelationViewRegion.EVENT_HOVER_OUT"; BI.RelationViewRegionContainer.EVENT_PREVIEW = "RelationViewRegion.EVENT_PREVIEW"; BI.shortcut("bi.relation_view_region_container", BI.RelationViewRegionContainer);/** * 关联视图 * * Created by GUY on 2015/12/23. * @class BI.RelationViewRegion * @extends BI.BasicButton */ BI.RelationViewRegion = BI.inherit(BI.BasicButton, { _defaultConfig: function () { return BI.extend(BI.RelationViewRegion.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-relation-view-region cursor-pointer", width: 150, text: "", value: "", header: "", items: [], belongPackage: true }); }, _init: function () { BI.RelationViewRegion.superclass._init.apply(this, arguments); var self = this, o = this.options; this.preview = BI.createWidget({ type: "bi.icon_button", cls: "relation-table-preview-font", width: 25, height: 25, stopPropagation: true }); this.preview.on(BI.IconButton.EVENT_CHANGE, function () { self.fireEvent(BI.RelationViewRegion.EVENT_PREVIEW, this.isSelected()); }); this.title = BI.createWidget({ type: "bi.label", height: 25, width: 70, text: o.text, value: o.value, textAlign: "left" }); //title放body上 if (BI.isKey(o.header)) { this.title.setTitle(o.header, { container: "body" }) } this.button_group = BI.createWidget({ type: "bi.button_group", items: this._createItems(o.items), layouts: [{ type: "bi.vertical" }] }); BI.createWidget({ type: "bi.vertical", element: this, items: [{ type: "bi.vertical", cls: "relation-view-region-container bi-card bi-border " + (o.belongPackage ? "" : "other-package"), items: [{ type: "bi.vertical_adapt", cls: "relation-view-region-title bi-border-bottom", items: [this.preview, this.title] }, this.button_group] }], hgap: 25, vgap: 20 }) }, _createItems: function (items) { var self = this; return BI.map(items, function (i, item) { return BI.extend(item, { type: "bi.relation_view_item", hoverIn: function () { self.setValue(item.value); self.fireEvent(BI.RelationViewRegion.EVENT_HOVER_IN, item.value); }, hoverOut: function () { self.setValue([]); self.fireEvent(BI.RelationViewRegion.EVENT_HOVER_OUT, item.value); } }) }); }, doRedMark: function () { this.title.doRedMark.apply(this.title, arguments); }, unRedMark: function () { this.title.unRedMark.apply(this.title, arguments); }, getWidth: function () { return this.options.width; }, getHeight: function () { return this.button_group.getAllButtons().length * 25 + 25 + 2 * 20 + 3; }, //获取上方开始划线的位置 getTopLeftPosition: function () { return { x: 25 + 10, y: 20 } }, getTopRightPosition: function () { return { x: this.getWidth() - 25 - 10, y: 20 } }, getBottomPosition: function () { return { x: 25 + 10, y: this.getHeight() - 20 } }, getLeftPosition: function () { return { x: 25, y: 20 + 10 } }, getRightPosition: function () { return { x: this.getWidth() - 25, y: 20 + 10 } }, setValue: function (v) { this.button_group.setValue(v); }, setPreviewSelected: function(v) { this.preview.setSelected(v); } }); BI.RelationViewRegion.EVENT_HOVER_IN = "RelationViewRegion.EVENT_HOVER_IN"; BI.RelationViewRegion.EVENT_HOVER_OUT = "RelationViewRegion.EVENT_HOVER_OUT"; BI.RelationViewRegion.EVENT_PREVIEW = "RelationViewRegion.EVENT_PREVIEW"; BI.shortcut('bi.relation_view_region', BI.RelationViewRegion);/** * 自适应宽度的表格 * * Created by GUY on 2016/2/3. * @class BI.ResponisveTable * @extends BI.Widget */ BI.ResponisveTable = BI.inherit(BI.Widget, { _const: { perColumnSize: 100 }, _defaultConfig: function () { return BI.extend(BI.ResponisveTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-responsive-table", isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效 isNeedMerge: false,//是否需要合并单元格 mergeCols: [], //合并的单元格列号 mergeRule: function (row1, row2) { //合并规则, 默认相等时合并 return BI.isEqual(row1, row2); }, columnSize: [], headerRowSize: 25, footerRowSize: 25, rowSize: 25, regionColumnSize: false, header: [], footer: false, items: [], //二维数组 //交叉表头 crossHeader: [], crossItems: [] }); }, _init: function () { BI.ResponisveTable.superclass._init.apply(this, arguments); var self = this, o = this.options; this.table = BI.createWidget({ type: "bi.table_view", element: this, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: o.mergeRule, columnSize: o.columnSize, headerRowSize: o.headerRowSize, footerRowSize: o.footerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, header: o.header, footer: o.footer, items: o.items, //交叉表头 crossHeader: o.crossHeader, crossItems: o.crossItems }); this.table.on(BI.Table.EVENT_TABLE_AFTER_INIT, function () { self._initRegionSize(); self.table.resize(); self._resizeHeader(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT, arguments); }); this.table.on(BI.Table.EVENT_TABLE_RESIZE, function () { self._resizeRegion(); self._resizeHeader(); self.fireEvent(BI.Table.EVENT_TABLE_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function () { self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, function () { self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_REGION_RESIZE, function () { //important:在冻结并自适应列宽的情况下要随时变更表头宽度 if (o.isNeedResize === true && self._isAdaptiveColumn()) { self._resizeHeader(); } self.fireEvent(BI.Table.EVENT_TABLE_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { self._resizeHeader(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, function () { self._resizeBody(); self.fireEvent(BI.Table.EVENT_TABLE_BEFORE_COLUMN_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_COLUMN_RESIZE, function () { self.fireEvent(BI.Table.EVENT_TABLE_COLUMN_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { self._resizeRegion(); self._resizeHeader(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); }, _initRegionSize: function () { var o = this.options; if (o.isNeedFreeze === true) { var regionColumnSize = this.table.getRegionColumnSize(); var maxWidth = this.table.element.width(); if (!regionColumnSize[0] || (regionColumnSize[0] === 'fill') || regionColumnSize[0] > maxWidth || regionColumnSize[1] > maxWidth) { var freezeCols = o.freezeCols; if (freezeCols.length === 0) { this.table.setRegionColumnSize([0, "fill"]); } else if (freezeCols.length > 0 && freezeCols.length < o.columnSize.length) { var size = maxWidth / 3; if (freezeCols.length > o.columnSize.length / 2) { size = maxWidth * 2 / 3; } this.table.setRegionColumnSize([size, "fill"]); } else { this.table.setRegionColumnSize(["fill", 0]); } } } }, _getBlockSize: function () { var o = this.options; var columnSize = this.table.getCalculateColumnSize(); if (o.isNeedFreeze === true) { var columnSizeLeft = [], columnSizeRight = []; BI.each(columnSize, function (i, size) { if (o.freezeCols.contains(i)) { columnSizeLeft.push(size); } else { columnSizeRight.push(size); } }); //因为有边框,所以加上数组长度的参数调整 var sumLeft = BI.sum(columnSizeLeft) + columnSizeLeft.length, sumRight = BI.sum(columnSizeRight) + columnSizeRight.length; return { sumLeft: sumLeft, sumRight: sumRight, left: columnSizeLeft, right: columnSizeRight } } return { size: columnSize, sum: BI.sum(columnSize) + columnSize.length }; }, _isAdaptiveColumn: function (columnSize) { return !(BI.last(columnSize || this.table.getColumnSize()) > 1.05); }, _resizeHeader: function () { var self = this, o = this.options; if (o.isNeedFreeze === true) { //若是当前处于自适应调节阶段 if (this._isAdaptiveColumn()) { var columnSize = this.table.getCalculateColumnSize(); this.table.setHeaderColumnSize(columnSize); } else { var regionColumnSize = this.table.getClientRegionColumnSize(); var block = this._getBlockSize(); var sumLeft = block.sumLeft, sumRight = block.sumRight; var columnSizeLeft = block.left, columnSizeRight = block.right; columnSizeLeft[columnSizeLeft.length - 1] += regionColumnSize[0] - sumLeft; columnSizeRight[columnSizeRight.length - 1] += regionColumnSize[1] - sumRight; var newLeft = BI.clone(columnSizeLeft), newRight = BI.clone(columnSizeRight); newLeft[newLeft.length - 1] = ""; newRight[newRight.length - 1] = ""; this.table.setColumnSize(newLeft.concat(newRight)); block = self._getBlockSize(); if (columnSizeLeft[columnSizeLeft.length - 1] < block.left[block.left.length - 1]) { columnSizeLeft[columnSizeLeft.length - 1] = block.left[block.left.length - 1] } if (columnSizeRight[columnSizeRight.length - 1] < block.right[block.right.length - 1]) { columnSizeRight[columnSizeRight.length - 1] = block.right[block.right.length - 1] } self.table.setColumnSize(columnSizeLeft.concat(columnSizeRight)); } } else { if (!this._isAdaptiveColumn()) { var regionColumnSize = this.table.getClientRegionColumnSize(); var block = this._getBlockSize(); var sum = block.sum; var size = block.size; size[size.length - 1] += regionColumnSize[0] - sum; var newSize = BI.clone(size); newSize[newSize.length - 1] = ""; this.table.setColumnSize(newSize); block = this._getBlockSize(); if (size[size.length - 1] < block.size[block.size.length - 1]) { size[size.length - 1] = block.size[block.size.length - 1] } this.table.setColumnSize(size); } } }, _resizeBody: function () { if (this._isAdaptiveColumn()) { var columnSize = this.table.getCalculateColumnSize(); this.setColumnSize(columnSize); } }, _adjustRegion: function () { var o = this.options; var regionColumnSize = this.table.getCalculateRegionColumnSize(); if (o.isNeedFreeze === true && o.freezeCols.length > 0 && o.freezeCols.length < o.columnSize.length) { var block = this._getBlockSize(); var sumLeft = block.sumLeft, sumRight = block.sumRight; if (sumLeft < regionColumnSize[0] || regionColumnSize[0] >= (sumLeft + sumRight)) { this.table.setRegionColumnSize([sumLeft, "fill"]); } this._resizeRegion(); } }, _resizeRegion: function () { var o = this.options; var regionColumnSize = this.table.getCalculateRegionColumnSize(); if (o.isNeedFreeze === true && o.freezeCols.length > 0 && o.freezeCols.length < o.columnSize.length) { var maxWidth = this.table.element.width(); if (regionColumnSize[0] < 15 || regionColumnSize[1] < 15) { var freezeCols = o.freezeCols; var size = maxWidth / 3; if (freezeCols.length > o.columnSize.length / 2) { size = maxWidth * 2 / 3; } this.table.setRegionColumnSize([size, "fill"]); } } }, resize: function () { this.table.resize(); this._resizeRegion(); this._resizeHeader(); }, setColumnSize: function (columnSize) { this.table.setColumnSize(columnSize); this._adjustRegion(); this._resizeHeader(); }, getColumnSize: function () { return this.table.getColumnSize(); }, getCalculateColumnSize: function () { return this.table.getCalculateColumnSize(); }, setHeaderColumnSize: function (columnSize) { this.table.setHeaderColumnSize(columnSize); this._adjustRegion(); this._resizeHeader(); }, setRegionColumnSize: function (columnSize) { this.table.setRegionColumnSize(columnSize); this._resizeHeader(); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, getCalculateRegionColumnSize: function () { return this.table.getCalculateRegionColumnSize(); }, getCalculateRegionRowSize: function () { return this.table.getCalculateRegionRowSize(); }, getClientRegionColumnSize: function () { return this.table.getClientRegionColumnSize(); }, getScrollRegionColumnSize: function () { return this.table.getScrollRegionColumnSize(); }, getScrollRegionRowSize: function () { return this.table.getScrollRegionRowSize(); }, hasVerticalScroll: function () { return this.table.hasVerticalScroll(); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, getLeftHorizontalScroll: function () { return this.table.getLeftHorizontalScroll(); }, getRightHorizontalScroll: function () { return this.table.getRightHorizontalScroll(); }, getColumns: function () { return this.table.getColumns(); }, attr: function () { BI.ResponisveTable.superclass.attr.apply(this, arguments); this.table.attr.apply(this.table, arguments); }, populate: function (items) { var self = this, o = this.options; this.table.populate.apply(this.table, arguments); if (o.isNeedFreeze === true) { BI.nextTick(function () { self._initRegionSize(); self.table.resize(); self._resizeHeader(); }); } } }); BI.shortcut('bi.responsive_table', BI.ResponisveTable);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.SelectTreeFirstPlusGroupNode * @extends BI.NodeButton */ BI.SelectTreeFirstPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.SelectTreeFirstPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-select-tree-first-plus-group-node bi-list-item-active", logic: { dynamic: false }, id: "", pId: "", readonly: true, open: false, height: 25 }) }, _init: function () { BI.SelectTreeFirstPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.first_tree_node_checkbox", stopPropagation: true }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, isOnce: function () { return true; }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.NodeButton.superclass.doClick.apply(this, arguments); }, setOpened: function (v) { BI.SelectTreeFirstPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.select_tree_first_plus_group_node", BI.SelectTreeFirstPlusGroupNode);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.SelectTreeLastPlusGroupNode * @extends BI.NodeButton */ BI.SelectTreeLastPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.SelectTreeLastPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-select-tree-last-plus-group-node bi-list-item-active", logic: { dynamic: false }, id: "", pId: "", readonly: true, open: false, height: 25 }) }, _init: function () { BI.SelectTreeLastPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.last_tree_node_checkbox", stopPropagation: true }) this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, isOnce: function () { return true; }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.NodeButton.superclass.doClick.apply(this, arguments); }, setOpened: function (v) { BI.SelectTreeLastPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.select_tree_last_plus_group_node", BI.SelectTreeLastPlusGroupNode);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.SelectTreeMidPlusGroupNode * @extends BI.NodeButton */ BI.SelectTreeMidPlusGroupNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.SelectTreeMidPlusGroupNode.superclass._defaultConfig.apply(this, arguments); return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-select-tree-mid-plus-group-node bi-list-item-active", logic: { dynamic: false }, id: "", pId: "", readonly: true, open: false, height: 25 }) }, _init: function () { BI.SelectTreeMidPlusGroupNode.superclass._init.apply(this, arguments); var self = this, o = this.options; this.checkbox = BI.createWidget({ type: "bi.mid_tree_node_checkbox", stopPropagation: true }); this.text = BI.createWidget({ type: "bi.label", textAlign: "left", whiteSpace: "nowrap", textHeight: o.height, height: o.height, hgap: o.hgap, text: o.text, value: o.value, py: o.py }); this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.triggerExpand(); } else { self.triggerCollapse(); } } }); var type = BI.LogicFactory.createLogicTypeByDirection(BI.Direction.Left); var items = BI.LogicFactory.createLogicItemsByDirection(BI.Direction.Left, { width: 25, el: this.checkbox }, this.text); BI.createWidget(BI.extend({ element: this }, BI.LogicFactory.createLogic(type, BI.extend(o.logic, { items: items })))); }, isOnce: function () { return true; }, doRedMark: function () { this.text.doRedMark.apply(this.text, arguments); }, unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); }, doClick: function () { BI.NodeButton.superclass.doClick.apply(this, arguments); }, setOpened: function (v) { BI.SelectTreeMidPlusGroupNode.superclass.setOpened.apply(this, arguments); if (BI.isNotNull(this.checkbox)) { this.checkbox.setSelected(v); } } }); BI.shortcut("bi.select_tree_mid_plus_group_node", BI.SelectTreeMidPlusGroupNode);/** * @class BI.SelectTreeCombo * @extends BI.Widget */ BI.SelectTreeCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SelectTreeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-select-tree-combo", height: 30, text: "", items: [] }); }, _init: function () { BI.SelectTreeCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.single_tree_trigger", text: o.text, height: o.height, items: o.items }); this.popup = BI.createWidget({ type: "bi.select_tree_popup", items: o.items }); this.combo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup } }); this.combo.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.popup.on(BI.SingleTreePopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.combo.hideView(); }); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue(); }, populate: function (items) { this.combo.populate(items); } }); BI.shortcut("bi.select_tree_combo", BI.SelectTreeCombo);/** * @class BI.SelectTreeExpander * @extends BI.Widget */ BI.SelectTreeExpander = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SelectTreeExpander.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-select-tree-expander", trigger: "click", toggle: true, direction: "bottom", isDefaultInit: true, el: {}, popup: {} }); }, _init: function () { BI.SelectTreeExpander.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(BI.extend({stopPropagation: true}, o.el)); this.trigger.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { if (this.isSelected()) { self.expander.setValue([]); } } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.expander = BI.createWidget({ type: "bi.expander", element: this, trigger: o.trigger, toggle: o.toggle, direction: o.direction, isDefaultInit: o.isDefaultInit, el: this.trigger, popup: o.popup }); this.expander.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { self.trigger.setSelected(false); } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); }, setValue: function (v) { if (BI.contains(v, this.trigger.getValue())) { this.trigger.setSelected(true); this.expander.setValue([]); } else { this.trigger.setSelected(false); this.expander.setValue(v); } }, getValue: function () { if (this.trigger.isSelected()) { return [this.trigger.getValue()]; } return this.expander.getValue(); }, populate: function (items) { this.expander.populate(items); } }); BI.shortcut("bi.select_tree_expander", BI.SelectTreeExpander);/** * @class BI.SelectTreePopup * @extends BI.Pane */ BI.SelectTreePopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.SelectTreePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-select-tree-popup", tipText: BI.i18nText("BI-No_Selected_Item"), items: [] }); }, _formatItems: function (nodes, layer) { var self = this; BI.each(nodes, function (i, node) { var extend = {layer: layer}; node.id = node.id || BI.UUID(); if (node.isParent === true || BI.isNotEmptyArray(node.children)) { switch (i) { case 0 : extend.type = "bi.select_tree_first_plus_group_node"; break; case nodes.length - 1 : extend.type = "bi.select_tree_last_plus_group_node"; break; default : extend.type = "bi.select_tree_mid_plus_group_node"; break; } BI.defaults(node, extend); self._formatItems(node.children); } else { switch (i) { case nodes.length - 1: extend.type = "bi.last_tree_leaf_item"; break; default : extend.type = "bi.mid_tree_leaf_item"; } BI.defaults(node, extend); } }); return nodes; }, _init: function () { BI.SelectTreePopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tree = BI.createWidget({ type: 'bi.level_tree', expander: { type: "bi.select_tree_expander", isDefaultInit: true }, items: this._formatItems(BI.Tree.transformToTreeFormat(o.items)), chooseType: BI.Selection.Single }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.tree] }); this.tree.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.tree.on(BI.LevelTree.EVENT_CHANGE, function () { self.fireEvent(BI.SelectTreePopup.EVENT_CHANGE); }); this.check(); }, getValue: function () { return this.tree.getValue(); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.tree.setValue(v); }, populate: function (items) { BI.SelectTreePopup.superclass.populate.apply(this, arguments); this.tree.populate(items); } }); BI.SelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.select_tree_popup", BI.SelectTreePopup);/** * * Created by GUY on 2016/8/10. * @class BI.SequenceTableDynamicNumber * @extends BI.SequenceTableTreeNumber */ BI.SequenceTableDynamicNumber = BI.inherit(BI.SequenceTableTreeNumber, { _defaultConfig: function () { return BI.extend(BI.SequenceTableDynamicNumber.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-sequence-table-dynamic-number" }); }, _init: function () { BI.SequenceTableDynamicNumber.superclass._init.apply(this, arguments); }, _formatNumber: function (nodes) { var self = this, o = this.options; var result = []; var count = this._getStart(nodes); function getLeafCount(node) { var cnt = 0; if (BI.isNotEmptyArray(node.children)) { BI.each(node.children, function (index, child) { cnt += getLeafCount(child); }); if (node.children.length > 1 && BI.isNotEmptyArray(node.values)) { cnt++; } } else { cnt++; } return cnt; } var start = 0, top = 0; BI.each(nodes, function (i, node) { if (BI.isArray(node.children)) { BI.each(node.children, function (index, child) { var cnt = getLeafCount(child); result.push({ text: count++, start: start, top: top, cnt: cnt, index: index, height: cnt * o.rowSize }); start += cnt; top += cnt * o.rowSize; }); if (BI.isNotEmptyArray(node.values)) { result.push({ text: BI.i18nText("BI-Summary_Values"), start: start++, top: top, cnt: 1, isSummary: true, height: o.rowSize }); top += o.rowSize; } } }); return result; } }); BI.shortcut('bi.sequence_table_dynamic_number', BI.SequenceTableDynamicNumber);/** * * Created by GUY on 2016/5/26. * @class BI.SequenceTableListNumber * @extends BI.Widget */ BI.SequenceTableListNumber = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SequenceTableListNumber.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-sequence-table-list-number", isNeedFreeze: false, scrollTop: 0, startSequence: 1,//开始的序号 headerRowSize: 25, rowSize: 25, sequenceHeaderCreator: null, header: [], items: [], //二维数组 //交叉表头 crossHeader: [], crossItems: [], pageSize: 20 }); }, _init: function () { BI.SequenceTableListNumber.superclass._init.apply(this, arguments); var self = this, o = this.options; this.start = o.startSequence; this.renderedCells = []; this.renderedKeys = []; this.container = BI.createWidget({ type: "bi.absolute", width: 60, scrollable: false }); this.scrollContainer = BI.createWidget({ type: "bi.vertical", scrollable: false, scrolly: false, items: [this.container] }); this.headerContainer = BI.createWidget({ type: "bi.absolute", cls: "bi-border", width: 58, scrollable: false }); this.layout = BI.createWidget({ type: "bi.vtape", element: this, items: [{ el: this.headerContainer, height: o.headerRowSize * o.header.length - 2 }, { el: {type: "bi.layout"}, height: 2 }, { el: this.scrollContainer }] }); this._populate(); }, _layout: function () { var self = this, o = this.options; var headerHeight = o.headerRowSize * o.header.length - 2; var items = this.layout.attr("items"); if (o.isNeedFreeze === false) { items[0].height = 0; items[1].height = 0; } else if (o.isNeedFreeze === true) { items[0].height = headerHeight; items[1].height = 2; } this.layout.attr("items", items); this.layout.resize(); this.container.setHeight(o.items.length * o.rowSize); try { this.scrollContainer.element.scrollTop(o.scrollTop); } catch (e) { } }, _createHeader: function () { var o = this.options; BI.createWidget({ type: "bi.absolute", element: this.headerContainer, items: [{ el: o.sequenceHeaderCreator || { type: "bi.table_style_cell", cls: "sequence-table-title-cell", styleGetter: o.headerCellStyleGetter, text: BI.i18nText("BI-Number_Index") }, left: 0, top: 0, right: 0, bottom: 0 }] }); }, _calculateChildrenToRender: function () { var self = this, o = this.options; var scrollTop = BI.clamp(o.scrollTop, 0, o.rowSize * o.items.length - (o.height - o.header.length * o.headerRowSize) + BI.DOM.getScrollWidth()); var start = Math.floor(scrollTop / o.rowSize); var end = start + Math.floor((o.height - o.header.length * o.headerRowSize) / o.rowSize); var renderedCells = [], renderedKeys = []; for (var i = start, cnt = 0; i <= end && i < o.items.length; i++, cnt++) { var index = BI.deepIndexOf(this.renderedKeys, this.start + i); var top = i * o.rowSize; if (index > -1) { if (o.rowSize !== this.renderedCells[index]._height) { this.renderedCells[index]._height = o.rowSize; this.renderedCells[index].el.setHeight(o.rowSize); } if (this.renderedCells[index].top !== top) { this.renderedCells[index].top = top; this.renderedCells[index].el.element.css("top", top + "px"); } renderedCells.push(this.renderedCells[index]); } else { var child = BI.createWidget(BI.extend({ type: "bi.table_style_cell", cls: "sequence-table-number-cell bi-border-left bi-border-right bi-border-bottom", width: 60, height: o.rowSize, text: this.start + i, styleGetter: function (index) { return function () { return o.sequenceCellStyleGetter(self.start + i - 1); } }(cnt) })); renderedCells.push({ el: child, left: 0, top: top, _height: o.rowSize }); } renderedKeys.push(this.start + i); } //已存在的, 需要添加的和需要删除的 var existSet = {}, addSet = {}, deleteArray = []; BI.each(renderedKeys, function (i, key) { if (BI.deepContains(self.renderedKeys, key)) { existSet[i] = key; } else { addSet[i] = key; } }); BI.each(this.renderedKeys, function (i, key) { if (BI.deepContains(existSet, key)) { return; } if (BI.deepContains(addSet, key)) { return; } deleteArray.push(i); }); BI.each(deleteArray, function (i, index) { self.renderedCells[index].el.destroy(); }); var addedItems = []; BI.each(addSet, function (index) { addedItems.push(renderedCells[index]) }); BI.createWidget({ type: "bi.absolute", element: this.container, items: addedItems }); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; }, _populate: function () { this.headerContainer.empty(); this._createHeader(); this._layout(); this._calculateChildrenToRender(); }, setVerticalScroll: function (scrollTop) { if (this.options.scrollTop !== scrollTop) { this.options.scrollTop = scrollTop; try { this.scrollContainer.element.scrollTop(scrollTop); } catch (e) { } } }, getVerticalScroll: function () { return this.options.scrollTop; }, setVPage: function (v) { v = v < 1 ? 1 : v; var o = this.options; this.start = (v - 1) * o.pageSize + 1; }, _restore: function () { var o = this.options; BI.each(this.renderedCells, function (i, cell) { cell.el.destroy(); }); this.renderedCells = []; this.renderedKeys = []; }, restore: function () { this._restore(); }, populate: function (items, header) { var o = this.options; if (items && items !== this.options.items) { o.items = items; this._restore(); } if (header && header !== this.options.header) { o.header = header; } this._populate(); } }); BI.shortcut('bi.sequence_table_list_number', BI.SequenceTableListNumber);/** * 带有序号的表格 * * Created by GUY on 2016/5/26. * @class BI.SequenceTable * @extends BI.Widget */ BI.SequenceTable = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SequenceTable.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-sequence-table", el: { type: "bi.adaptive_table" }, sequence: {}, isNeedResize: true, isResizeAdapt: false, isNeedFreeze: false,//是否需要冻结单元格 freezeCols: [], //冻结的列号,从0开始,isNeedFreeze为true时生效 isNeedMerge: false,//是否需要合并单元格 mergeCols: [], //合并的单元格列号 mergeRule: BI.emptyFn, columnSize: [], minColumnSize: [], maxColumnSize: [], headerRowSize: 25, rowSize: 25, regionColumnSize: [], headerCellStyleGetter: BI.emptyFn, summaryCellStyleGetter: BI.emptyFn, sequenceCellStyleGetter: BI.emptyFn, header: [], items: [], //二维数组 //交叉表头 crossHeader: [], crossItems: [], showSequence: false, startSequence: 1//开始的序号 }); }, _init: function () { BI.SequenceTable.superclass._init.apply(this, arguments); var self = this, o = this.options; this.sequence = BI.createWidget(o.sequence, { type: "bi.sequence_table_list_number", invisible: o.showSequence === false, startSequence: o.startSequence, isNeedFreeze: o.isNeedFreeze, header: o.header, items: o.items, crossHeader: o.crossHeader, crossItems: o.crossItems, headerRowSize: o.headerRowSize, rowSize: o.rowSize, width: 60, height: o.height && o.height - BI.GridTableScrollbar.SIZE, headerCellStyleGetter: o.headerCellStyleGetter, summaryCellStyleGetter: o.summaryCellStyleGetter, sequenceCellStyleGetter: o.sequenceCellStyleGetter }); this.table = BI.createWidget(o.el, { type: "bi.adaptive_table", width: o.showSequence === true ? o.width - 60 : o.width, height: o.height, isNeedResize: o.isNeedResize, isResizeAdapt: o.isResizeAdapt, isNeedFreeze: o.isNeedFreeze, freezeCols: o.freezeCols, isNeedMerge: o.isNeedMerge, mergeCols: o.mergeCols, mergeRule: o.mergeRule, columnSize: o.columnSize, minColumnSize: o.minColumnSize, maxColumnSize: o.maxColumnSize, headerRowSize: o.headerRowSize, rowSize: o.rowSize, regionColumnSize: o.regionColumnSize, headerCellStyleGetter: o.headerCellStyleGetter, summaryCellStyleGetter: o.summaryCellStyleGetter, sequenceCellStyleGetter: o.sequenceCellStyleGetter, header: o.header, items: o.items, //交叉表头 crossHeader: o.crossHeader, crossItems: o.crossItems }); this.table.on(BI.Table.EVENT_TABLE_SCROLL, function (scroll) { if (self.sequence.getVerticalScroll() !== this.getVerticalScroll()) { self.sequence.setVerticalScroll(this.getVerticalScroll()); self.sequence.populate(); } self.fireEvent(BI.Table.EVENT_TABLE_SCROLL, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_REGION_RESIZE, arguments); }); this.table.on(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, function () { o.regionColumnSize = this.getRegionColumnSize(); o.columnSize = this.getColumnSize(); self.fireEvent(BI.Table.EVENT_TABLE_AFTER_COLUMN_RESIZE, arguments); }); this.htape = BI.createWidget({ type: "bi.absolute", element: this, items: [{ el: this.sequence, left: 0, top: 0 }, { el: this.table, top: 0, left: o.showSequence === true ? 60 : 0 }] }); this._populate(); }, _populate: function () { var o = this.options; if (o.showSequence === true) { this.sequence.setVisible(true); this.table.element.css("left", "60px"); this.table.setWidth(o.width - 60); } else { this.sequence.setVisible(false); this.table.element.css("left", "0px"); this.table.setWidth(o.width); } }, setWidth: function (width) { BI.PageTable.superclass.setWidth.apply(this, arguments); this.table.setWidth(this.options.showSequence ? width - 60 : width); }, setHeight: function (height) { BI.PageTable.superclass.setHeight.apply(this, arguments); this.table.setHeight(height); this.sequence.setHeight(height - BI.GridTableScrollbar.SIZE); }, setColumnSize: function (columnSize) { this.options.columnSize = columnSize; this.table.setColumnSize(columnSize); }, getColumnSize: function () { return this.table.getColumnSize(); }, setRegionColumnSize: function (columnSize) { this.options.columnSize = columnSize; this.table.setRegionColumnSize(columnSize); }, getRegionColumnSize: function () { return this.table.getRegionColumnSize(); }, hasLeftHorizontalScroll: function () { return this.table.hasLeftHorizontalScroll(); }, hasRightHorizontalScroll: function () { return this.table.hasRightHorizontalScroll(); }, setLeftHorizontalScroll: function (scrollLeft) { this.table.setLeftHorizontalScroll(scrollLeft); }, setRightHorizontalScroll: function (scrollLeft) { this.table.setRightHorizontalScroll(scrollLeft); }, setVerticalScroll: function (scrollTop) { this.table.setVerticalScroll(scrollTop); this.sequence.setVerticalScroll(scrollTop); }, getVerticalScroll: function () { return this.table.getVerticalScroll(); }, setVPage: function (page) { this.sequence.setVPage && this.sequence.setVPage(page); }, setHPage: function (page) { this.sequence.setHPage && this.sequence.setHPage(page); }, attr: function () { BI.SequenceTable.superclass.attr.apply(this, arguments); this.table.attr.apply(this.table, arguments); this.sequence.attr.apply(this.sequence, arguments); }, restore: function () { this.table.restore(); this.sequence.restore(); }, populate: function (items, header, crossItems, crossHeader) { var o = this.options; if (items) { o.items = items; } if (header) { o.header = header; } if (crossItems) { o.crossItems = crossItems; } if (crossHeader) { o.crossHeader = crossHeader; } this._populate(); this.table.populate.apply(this.table, arguments); this.sequence.populate.apply(this.sequence, arguments); this.sequence.setVerticalScroll(this.table.getVerticalScroll()); }, destroy: function () { this.table.destroy(); BI.SequenceTable.superclass.destroy.apply(this, arguments); } }); BI.shortcut('bi.sequence_table', BI.SequenceTable);/** * @class BI.SingleTreeCombo * @extends BI.Widget */ BI.SingleTreeCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SingleTreeCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-single-tree-combo", trigger: {}, height: 30, text: "", items: [] }); }, _init: function () { BI.SingleTreeCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget(BI.extend({ type: "bi.single_tree_trigger", text: o.text, height: o.height, items: o.items }, o.trigger)); this.popup = BI.createWidget({ type: "bi.single_tree_popup", items: o.items }); this.combo = BI.createWidget({ type: "bi.combo", element: this, adjustLength: 2, el: this.trigger, popup: { el: this.popup } }); this.combo.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.SingleTreeCombo.EVENT_BEFORE_POPUPVIEW, arguments); }); this.popup.on(BI.SingleTreePopup.EVENT_CHANGE, function () { self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.SingleTreeCombo.EVENT_CHANGE); }); }, populate: function (items) { this.combo.populate(items); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.trigger.setValue(v); this.popup.setValue(v); }, getValue: function () { return this.popup.getValue(); } }); BI.SingleTreeCombo.EVENT_CHANGE = "SingleTreeCombo.EVENT_CHANGE"; BI.SingleTreeCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut("bi.single_tree_combo", BI.SingleTreeCombo);/** * @class BI.SingleTreePopup * @extends BI.Pane */ BI.SingleTreePopup = BI.inherit(BI.Pane, { _defaultConfig: function () { return BI.extend(BI.SingleTreePopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-single-tree-popup", tipText: BI.i18nText("BI-No_Selected_Item"), items: [] }); }, _init: function () { BI.SingleTreePopup.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tree = BI.createWidget({ type: 'bi.level_tree', expander: { isDefaultInit: true }, items: o.items, chooseType: BI.Selection.Single }); BI.createWidget({ type: "bi.vertical", element: this, items: [this.tree] }); this.tree.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); this.tree.on(BI.LevelTree.EVENT_CHANGE, function () { self.fireEvent(BI.SingleTreePopup.EVENT_CHANGE); }); this.check(); }, getValue: function () { return this.tree.getValue(); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.tree.setValue(v); }, populate: function (items) { BI.SingleTreePopup.superclass.populate.apply(this, arguments); this.tree.populate(items); } }); BI.SingleTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.single_tree_popup", BI.SingleTreePopup);/** * @class BI.SingleTreeTrigger * @extends BI.Trigger */ BI.SingleTreeTrigger = BI.inherit(BI.Trigger, { _defaultConfig: function () { return BI.extend(BI.SingleTreeTrigger.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-single-tree-trigger", height: 30, text: "", items: [] }); }, _init: function () { BI.SingleTreeTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options; this.trigger = BI.createWidget({ type: "bi.select_text_trigger", element: this, text: o.text, items: o.items, height: o.height }); }, _checkTitle: function () { var self = this, val = this.getValue(); BI.any(this.options.items, function (i, item) { if (val.contains(item.value)) { self.trigger.setTitle(item.text || item.value); return true; } }); }, setValue: function (v) { v = BI.isArray(v) ? v : [v]; this.options.value = v; this.trigger.setValue(v); this._checkTitle(); }, getValue: function () { return this.options.value || []; }, populate: function (items) { BI.SingleTreeTrigger.superclass.populate.apply(this, arguments); this.trigger.populate(items); } }); BI.shortcut("bi.single_tree_trigger", BI.SingleTreeTrigger);/** * 可以单选多选切换的树 * * Created by GUY on 2015/12/21. * @class BI.SwitchTree * @extends BI.Widget */ BI.SwitchTree = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.SwitchTree.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-switch-tree", items: [] }); }, _init: function () { BI.SwitchTree.superclass._init.apply(this, arguments); var self = this, o = this.options; this.tab = BI.createWidget({ type: "bi.tab", element: this, tab: null, defaultShowIndex: BI.SwitchTree.SelectType.SingleSelect, cardCreator: BI.bind(this._createTree, this) }); }, _createTree: function (type) { var self = this, o = this.options; switch (type) { case BI.SwitchTree.SelectType.SingleSelect: this.levelTree = BI.createWidget({ type: "bi.multilayer_single_level_tree", isDefaultInit: true, items: BI.deepClone(o.items) }); this.levelTree.on(BI.LevelTree.EVENT_CHANGE, function () { self.fireEvent(BI.SwitchTree.EVENT_CHANGE, arguments); }); return this.levelTree; case BI.SwitchTree.SelectType.MultiSelect: this.tree = BI.createWidget({ type: "bi.simple_tree", items: this._removeIsParent(BI.deepClone(o.items)) }); this.tree.on(BI.SimpleTreeView.EVENT_CHANGE, function () { self.fireEvent(BI.SwitchTree.EVENT_CHANGE, arguments); }); return this.tree; } }, _removeIsParent: function(items) { BI.each(items, function(i, item) { BI.isNotNull(item.isParent) && delete item.isParent; }); return items; }, switchSelect: function () { switch (this.getSelect()) { case BI.SwitchTree.SelectType.SingleSelect: this.setSelect(BI.SwitchTree.SelectType.MultiSelect); break; case BI.SwitchTree.SelectType.MultiSelect: this.setSelect(BI.SwitchTree.SelectType.SingleSelect); break; } }, setSelect: function (v) { this.tab.setSelect(v); }, getSelect: function () { return this.tab.getSelect(); }, setValue: function (v) { this.storeValue = v; switch (this.getSelect()) { case BI.SwitchTree.SelectType.SingleSelect: this.levelTree.setValue(v); break; case BI.SwitchTree.SelectType.MultiSelect: this.tree.setValue(v); break; } }, getValue: function () { return this.tab.getValue(); }, populate: function (items) { this.options.items = items; if (BI.isNotNull(this.levelTree)) { this.levelTree.populate(BI.deepClone(items)); } if (BI.isNotNull(this.tree)) { this.tree.populate(this._removeIsParent(BI.deepClone(items))); } } }); BI.SwitchTree.EVENT_CHANGE = "SwitchTree.EVENT_CHANGE"; BI.SwitchTree.SelectType = { SingleSelect: BI.Selection.Single, MultiSelect: BI.Selection.Multi }; BI.shortcut('bi.switch_tree', BI.SwitchTree); /** * 年份下拉框 * * Created by GUY on 2015/8/28. * @class BI.YearCombo * @extends BI.Widget */ BI.YearCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.YearCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-year-combo", behaviors: {}, min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 height: 25 }); }, _init: function () { BI.YearCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.storeValue = ""; this.trigger = BI.createWidget({ type: "bi.year_trigger", min: o.min, max: o.max }); this.trigger.on(BI.YearTrigger.EVENT_FOCUS, function () { self.storeValue = this.getKey(); }); this.trigger.on(BI.YearTrigger.EVENT_START, function () { self.combo.isViewVisible() && self.combo.hideView(); }); this.trigger.on(BI.YearTrigger.EVENT_STOP, function () { self.combo.showView(); }); this.trigger.on(BI.YearTrigger.EVENT_ERROR, function () { self.combo.isViewVisible() && self.combo.hideView(); }); this.trigger.on(BI.YearTrigger.EVENT_CONFIRM, function () { if (self.combo.isViewVisible()) { return; } if (this.getKey() && this.getKey() !== self.storeValue) { self.setValue(this.getKey()); } else if (!this.getKey()) { self.setValue(); } self.fireEvent(BI.YearCombo.EVENT_CONFIRM); }); this.combo = BI.createWidget({ type: "bi.combo", element: this, destroyWhenHide: true, isNeedAdjustHeight: false, isNeedAdjustWidth: false, el: this.trigger, popup: { minWidth: 85, stopPropagation: false, el: { type: "bi.year_popup", ref: function () { self.popup = this; }, listeners: [{ eventName: BI.YearPopup.EVENT_CHANGE, action: function () { self.setValue(self.popup.getValue()); self.combo.hideView(); self.fireEvent(BI.YearCombo.EVENT_CONFIRM); } }], behaviors: o.behaviors, min: o.min, max: o.max } } }); this.combo.on(BI.Combo.EVENT_BEFORE_POPUPVIEW, function () { var value = self.trigger.getKey(); if (BI.isNotNull(value)) { self.popup.setValue(value); } else if (!value && value !== self.storeValue) { self.popup.setValue(self.storeValue); } else { self.setValue(); } self.fireEvent(BI.YearCombo.EVENT_BEFORE_POPUPVIEW); }); }, setValue: function (v) { this.combo.setValue(v); }, getValue: function () { return this.popup.getValue(); } }); BI.YearCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.YearCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.year_combo', BI.YearCombo);/** * 年份展示面板 * * Created by GUY on 2015/9/2. * @class BI.YearPopup * @extends BI.Trigger */ BI.YearPopup = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.YearPopup.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-year-popup", behaviors: {}, min: '1900-01-01', //最小日期 max: '2099-12-31' //最大日期 }); }, _createYearCalendar: function (v) { var o = this.options, y = this._year; var calendar = BI.createWidget({ type: "bi.year_calendar", behaviors: o.behaviors, min: o.min, max: o.max, logic: { dynamic: true }, year: y + v * 12 }); calendar.setValue(this._year); return calendar; }, _init: function () { BI.YearPopup.superclass._init.apply(this, arguments); var self = this; this.selectedYear = this._year = new Date().getFullYear(); var backBtn = BI.createWidget({ type: "bi.icon_button", cls: "pre-page-h-font", width: 25, height: 25, value: -1 }); var preBtn = BI.createWidget({ type: "bi.icon_button", cls: "next-page-h-font", width: 25, height: 25, value: 1 }); this.navigation = BI.createWidget({ type: "bi.navigation", element: this, single: true, logic: { dynamic: true }, tab: { cls: "year-popup-navigation bi-high-light bi-border-top", height: 25, items: [backBtn, preBtn] }, cardCreator: BI.bind(this._createYearCalendar, this), afterCardShow: function () { this.setValue(self.selectedYear); var calendar = this.getSelectedCard(); backBtn.setEnable(!calendar.isFrontYear()); preBtn.setEnable(!calendar.isFinalYear()); } }); this.navigation.on(BI.Navigation.EVENT_CHANGE, function () { self.selectedYear = this.getValue(); self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.fireEvent(BI.YearPopup.EVENT_CHANGE, self.selectedYear); }); }, getValue: function () { return this.selectedYear; }, setValue: function (v) { var o = this.options; if (Date.checkVoid(v, 1, 1, o.min, o.max)[0]) { v = new Date().getFullYear(); this.selectedYear = ""; this.navigation.setSelect(BI.YearCalendar.getPageByYear(v)); this.navigation.setValue(""); } else { this.selectedYear = v; this.navigation.setSelect(BI.YearCalendar.getPageByYear(v)); this.navigation.setValue(v); } } }); BI.YearPopup.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.year_popup", BI.YearPopup);/** * 年份trigger * * Created by GUY on 2015/8/21. * @class BI.YearTrigger * @extends BI.Trigger */ BI.YearTrigger = BI.inherit(BI.Trigger, { _const: { hgap: 4, vgap: 2, triggerWidth: 25, errorText: BI.i18nText("BI-Please_Input_Positive_Integer"), errorTextInvalid: BI.i18nText("BI-Year_Trigger_Invalid_Text") }, _defaultConfig: function () { return BI.extend(BI.YearTrigger.superclass._defaultConfig.apply(this, arguments), { extraCls: "bi-year-trigger bi-border", min: '1900-01-01', //最小日期 max: '2099-12-31', //最大日期 height: 25 }); }, _init: function () { BI.YearTrigger.superclass._init.apply(this, arguments); var self = this, o = this.options, c = this._const; this.editor = BI.createWidget({ type: "bi.sign_editor", height: o.height, validationChecker: function (v) { self.editor.setErrorText(!BI.isPositiveInteger(v) ? c.errorText : c.errorTextInvalid); return v === "" || (BI.isPositiveInteger(v) && !Date.checkVoid(v, 1, 1, o.min, o.max)[0]); }, quitChecker: function (v) { return false; }, hgap: c.hgap, vgap: c.vgap, allowBlank: true, errorText: c.errorText }) this.editor.on(BI.SignEditor.EVENT_FOCUS, function () { self.fireEvent(BI.YearTrigger.EVENT_FOCUS); }); this.editor.on(BI.SignEditor.EVENT_STOP, function () { self.fireEvent(BI.YearTrigger.EVENT_STOP); }); this.editor.on(BI.SignEditor.EVENT_CONFIRM, function () { var value = self.editor.getValue(); if (BI.isNotNull(value)) { self.editor.setValue(value); self.editor.setTitle(value); } self.fireEvent(BI.YearTrigger.EVENT_CONFIRM); }); this.editor.on(BI.SignEditor.EVENT_SPACE, function () { if (self.editor.isValid()) { self.editor.blur(); } }); this.editor.on(BI.SignEditor.EVENT_START, function () { self.fireEvent(BI.YearTrigger.EVENT_START); }); this.editor.on(BI.SignEditor.EVENT_ERROR, function () { self.fireEvent(BI.YearTrigger.EVENT_ERROR); }); BI.createWidget({ element: this, type: 'bi.htape', items: [ { el: this.editor }, { el: { type: "bi.text_button", baseCls: "bi-trigger-year-text", text: BI.i18nText("BI-Multi_Date_Year"), width: c.triggerWidth }, width: c.triggerWidth }, { el: { type: "bi.trigger_icon_button", width: c.triggerWidth }, width: c.triggerWidth } ] }); }, setValue: function (v) { this.editor.setState(v); this.editor.setValue(v); this.editor.setTitle(v); }, getKey: function () { return this.editor.getValue() | 0; } }); BI.YearTrigger.EVENT_FOCUS = "EVENT_FOCUS"; BI.YearTrigger.EVENT_ERROR = "EVENT_ERROR"; BI.YearTrigger.EVENT_START = "EVENT_START"; BI.YearTrigger.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.YearTrigger.EVENT_STOP = "EVENT_STOP"; BI.shortcut("bi.year_trigger", BI.YearTrigger);/** * 年份 + 月份下拉框 * * @class BI.YearMonthCombo * @extends BI.Widget */ BI.YearMonthCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.YearMonthCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-year-month-combo", yearBehaviors: {}, monthBehaviors: {}, height: 25 }); }, _init: function () { BI.YearMonthCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.year = BI.createWidget({ type: "bi.year_combo", behaviors: o.yearBehaviors }); this.month = BI.createWidget({ type: "bi.month_combo", behaviors: o.monthBehaviors }); this.year.on(BI.YearCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.YearMonthCombo.EVENT_CONFIRM); }); this.year.on(BI.YearCombo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.YearMonthCombo.EVENT_BEFORE_POPUPVIEW); }); this.month.on(BI.MonthCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.YearMonthCombo.EVENT_CONFIRM); }); this.month.on(BI.MonthCombo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.YearMonthCombo.EVENT_BEFORE_POPUPVIEW); }); BI.createWidget({ type: "bi.center", element: this, hgap: 5, items: [this.year, this.month] }); }, setValue: function (v) { v = v || {}; this.month.setValue(v.month); this.year.setValue(v.year); }, getValue: function () { return { year: this.year.getValue(), month: this.month.getValue() }; } }); BI.YearMonthCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.YearMonthCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.year_month_combo', BI.YearMonthCombo);/** * 年份 + 月份下拉框 * * @class BI.YearQuarterCombo * @extends BI.Widget */ BI.YearQuarterCombo = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.YearQuarterCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-year-quarter-combo", yearBehaviors: {}, quarterBehaviors: {}, height: 25 }); }, _init: function () { BI.YearQuarterCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; this.year = BI.createWidget({ type: "bi.year_combo", behaviors: o.yearBehaviors }); this.quarter = BI.createWidget({ type: "bi.quarter_combo", behaviors: o.quarterBehaviors }); this.year.on(BI.YearCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.YearQuarterCombo.EVENT_CONFIRM); }); this.year.on(BI.YearCombo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.YearQuarterCombo.EVENT_BEFORE_POPUPVIEW); }); this.quarter.on(BI.QuarterCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.YearQuarterCombo.EVENT_CONFIRM); }); this.quarter.on(BI.QuarterCombo.EVENT_BEFORE_POPUPVIEW, function () { self.fireEvent(BI.YearQuarterCombo.EVENT_BEFORE_POPUPVIEW); }); BI.createWidget({ type: "bi.center", element: this, hgap: 5, items: [this.year, this.quarter] }); }, setValue: function (v) { v = v || {}; this.quarter.setValue(v.quarter); this.year.setValue(v.year); }, getValue: function () { return { year: this.year.getValue(), quarter: this.quarter.getValue() }; } }); BI.YearQuarterCombo.EVENT_CONFIRM = "EVENT_CONFIRM"; BI.YearQuarterCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut('bi.year_quarter_combo', BI.YearQuarterCombo);/** * 简单的复选下拉框控件, 适用于数据量少的情况, 与valuechooser的区别是allvaluechooser setValue和getValue返回的是所有值 * 封装了字段处理逻辑 * * Created by GUY on 2015/10/29. * @class BI.AbstractAllValueChooser * @extends BI.Widget */ BI.AbstractAllValueChooser = BI.inherit(BI.Widget, { _const: { perPage: 100 }, _defaultConfig: function () { return BI.extend(BI.AbstractAllValueChooser.superclass._defaultConfig.apply(this, arguments), { width: 200, height: 30, items: null, itemsCreator: BI.emptyFn, cache: true }); }, _valueFormatter: function (v) { var text = v; if (BI.isNotNull(this.items)) { BI.some(this.items, function (i, item) { if (item.value === v) { text = item.text; return true; } }); } return text; }, _itemsCreator: function (options, callback) { var self = this, o = this.options; if (!o.cache || !this.items) { o.itemsCreator({}, function (items) { self.items = items; call(items); }); } else { call(this.items); } function call(items) { var keywords = (options.keywords || []).slice(); if (options.keyword) { keywords.push(options.keyword); } BI.each(keywords, function (i, kw) { var search = BI.Func.getSearchResult(items, kw); items = search.matched.concat(search.finded); }); if (options.selectedValues) {//过滤 var filter = BI.makeObject(options.selectedValues, true); items = BI.filter(items, function (i, ob) { return !filter[ob.value]; }); } if (options.type === BI.MultiSelectCombo.REQ_GET_ALL_DATA) { callback({ items: items }); return; } if (options.type === BI.MultiSelectCombo.REQ_GET_DATA_LENGTH) { callback({count: items.length}); return; } callback({ items: items, hasNext: false }); } } });/** * 简单的复选下拉框控件, 适用于数据量少的情况, 与valuechooser的区别是allvaluechooser setValue和getValue返回的是所有值 * 封装了字段处理逻辑 * * Created by GUY on 2015/10/29. * @class BI.AllValueChooserCombo * @extends BI.AbstractAllValueChooser */ BI.AllValueChooserCombo = BI.inherit(BI.AbstractAllValueChooser, { _defaultConfig: function () { return BI.extend(BI.AllValueChooserCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-all-value-chooser-combo", width: 200, height: 30, items: null, itemsCreator: BI.emptyFn, cache: true }); }, _init: function () { BI.AllValueChooserCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; if (BI.isNotNull(o.items)) { this.items = o.items; } this.combo = BI.createWidget({ type: 'bi.multi_select_combo', element: this, itemsCreator: BI.bind(this._itemsCreator, this), valueFormatter: BI.bind(this._valueFormatter, this), width: o.width, height: o.height }); this.combo.on(BI.MultiSelectCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.AllValueChooserCombo.EVENT_CONFIRM); }); }, setValue: function (v) { this.combo.setValue({ type: BI.Selection.Multi, value: v || [] }); }, getValue: function () { var val = this.combo.getValue() || {}; if (val.type === BI.Selection.All) { return val.assist; } return val.value || []; }, populate: function () { this.combo.populate.apply(this, arguments); } }); BI.AllValueChooserCombo.EVENT_CONFIRM = "AllValueChooserCombo.EVENT_CONFIRM"; BI.shortcut('bi.all_value_chooser_combo', BI.AllValueChooserCombo);/** * 简单的复选下拉框控件, 适用于数据量少的情况, 与valuechooser的区别是allvaluechooser setValue和getValue返回的是所有值 * 封装了字段处理逻辑 * * Created by GUY on 2015/10/29. * @class BI.AllValueChooserPane * @extends BI.AbstractAllValueChooser */ BI.AllValueChooserPane = BI.inherit(BI.AbstractAllValueChooser, { _defaultConfig: function () { return BI.extend(BI.AllValueChooserPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-all-value-chooser-pane", width: 200, height: 30, items: null, itemsCreator: BI.emptyFn, cache: true }); }, _init: function () { BI.AllValueChooserPane.superclass._init.apply(this, arguments); var self = this, o = this.options; if (BI.isNotNull(o.items)) { this.items = o.items; } this.list = BI.createWidget({ type: 'bi.multi_select_list', element: this, itemsCreator: BI.bind(this._itemsCreator, this), valueFormatter: BI.bind(this._valueFormatter, this), width: o.width, height: o.height }); this.list.on(BI.MultiSelectList.EVENT_CHANGE, function () { self.fireEvent(BI.AllValueChooserPane.EVENT_CHANGE); }); }, setValue: function (v) { this.list.setValue({ type: BI.Selection.Multi, value: v || [] }); }, getValue: function () { var val = this.list.getValue() || {}; if (val.type === BI.Selection.All) { return val.assist; } return val.value || []; }, populate: function () { this.list.populate.apply(this.list, arguments); } }); BI.AllValueChooserPane.EVENT_CHANGE = "AllValueChooserPane.EVENT_CHANGE"; BI.shortcut('bi.all_value_chooser_pane', BI.AllValueChooserPane);BI.AbstractTreeValueChooser = BI.inherit(BI.Widget, { _const: { perPage: 100 }, _defaultConfig: function () { return BI.extend(BI.AbstractTreeValueChooser.superclass._defaultConfig.apply(this, arguments), { items: null, itemsCreator: BI.emptyFn }); }, _initData: function (items) { this.items = items; var nodes = BI.Tree.treeFormat(items); this.tree = new BI.Tree(); this.tree.initTree(nodes); }, _itemsCreator: function (options, callback) { var self = this, o = this.options; if (!this.items) { o.itemsCreator({}, function (items) { self._initData(items); call(); }); } else { call(); } function call() { switch (options.type) { case BI.TreeView.REQ_TYPE_INIT_DATA: self._reqInitTreeNode(options, callback); break; case BI.TreeView.REQ_TYPE_ADJUST_DATA: self._reqAdjustTreeNode(options, callback); break; case BI.TreeView.REQ_TYPE_SELECT_DATA: self._reqSelectedTreeNode(options, callback); break; case BI.TreeView.REQ_TYPE_GET_SELECTED_DATA: self._reqDisplayTreeNode(options, callback); break; default : self._reqTreeNode(options, callback); break; } } }, _reqDisplayTreeNode: function (op, callback) { var self = this; var result = []; var selectedValues = op.selectedValues; if (selectedValues == null || BI.isEmpty(selectedValues)) { callback({}); return; } doCheck([], this.tree.getRoot(), selectedValues); callback({ items: result }); function doCheck(parentValues, node, selected) { if (selected == null || BI.isEmpty(selected)) { BI.each(node.getChildren(), function (i, child) { var newParents = BI.clone(parentValues); newParents.push(child.value); var llen = self._getChildCount(newParents); createOneJson(child, node.id, llen); doCheck(newParents, child, {}); }); return; } BI.each(selected, function (k) { var node = self._getTreeNode(parentValues, k); var newParents = BI.clone(parentValues); newParents.push(node.value); createOneJson(node, node.parent && node.parent.id, getCount(selected[k], newParents)); doCheck(newParents, node, selected[k]); }) } function getCount(jo, parentValues) { if (jo == null) { return 0; } if (BI.isEmpty(jo)) { return self._getChildCount(parentValues); } return BI.size(jo); } function createOneJson(node, pId, llen) { result.push({ id: node.id, pId: pId, text: node.text + (llen > 0 ? ("(" + BI.i18nText("BI-Basic_Altogether") + llen + BI.i18nText("BI-Basic_Count") + ")") : ""), value: node.value, open: true }); } }, _reqSelectedTreeNode: function (op, callback) { var self = this; var selectedValues = BI.deepClone(op.selectedValues); var notSelectedValue = op.notSelectedValue || {}; var keyword = op.keyword || ""; var parentValues = op.parentValues || []; if (selectedValues == null || BI.isEmpty(selectedValues)) { callback({}); return; } dealWithSelectedValues(selectedValues); callback(selectedValues); function dealWithSelectedValues(selectedValues) { var p = parentValues.concat(notSelectedValue); //存储的值中存在这个值就把它删掉 //例如选中了中国-江苏-南京, 取消中国或江苏或南京 if (canFindKey(selectedValues, p)) { //如果搜索的值在父亲链中 if (isSearchValueInParent(p)) { //例如选中了 中国-江苏, 搜索江苏, 取消江苏 //例如选中了 中国-江苏, 搜索江苏, 取消中国 self._deleteNode(selectedValues, p); } else { var searched = []; var finded = search(parentValues, notSelectedValue, [], searched); if (finded && BI.isNotEmptyArray(searched)) { BI.each(searched, function (i, arr) { var node = self._getNode(selectedValues, arr); if (node) { //例如选中了 中国-江苏-南京,搜索南京,取消中国 self._deleteNode(selectedValues, arr); } else { //例如选中了 中国-江苏,搜索南京,取消中国 expandSelectedValue(selectedValues, arr, BI.last(arr)); } }) } } } //存储的值中不存在这个值,但父亲节点是全选的情况 //例如选中了中国-江苏,取消南京 //important 选中了中国-江苏,取消了江苏,但是搜索的是南京 if (isChild(selectedValues, p)) { var result = [], finded = false; //如果parentValues中有匹配的值,说明搜索结果不在当前值下 if (isSearchValueInParent(p)) { finded = true; } else { //从当前值开始搜 finded = search(parentValues, notSelectedValue, result); p = parentValues; } if (finded === true) { //去掉点击的节点之后的结果集 expandSelectedValue(selectedValues, p, notSelectedValue); //添加去掉搜索的结果集 if (result.length > 0) { BI.each(result, function (i, strs) { self._buildTree(selectedValues, strs); }) } } } } function expandSelectedValue(selectedValues, parents, notSelectedValue) { var next = selectedValues; var childrenCount = []; var path = []; //去掉点击的节点之后的结果集 BI.some(parents, function (i, v) { var t = next[v]; if (t == null) { if (i === 0) { return true; } if (BI.isEmpty(next)) { var split = parents.slice(0, i); var expanded = self._getChildren(split); path.push(split); childrenCount.push(expanded.length); //如果只有一个值且取消的就是这个值 if (i === parents.length - 1 && expanded.length === 1 && expanded[0] === notSelectedValue) { for (var j = childrenCount.length - 1; j >= 0; j--) { if (childrenCount[j] === 1) { self._deleteNode(selectedValues, path[j]); } else { break; } } } else { BI.each(expanded, function (m, child) { if (i === parents.length - 1 && child.value === notSelectedValue) { return true; } next[child.value] = {}; }); } next = next[v]; } else { return true; // next = {}; // next[v] = {}; } } else { next = t; } }); } function search(parents, current, result, searched) { var newParents = BI.clone(parents); newParents.push(current); if (self._isMatch(parents, current, keyword)) { searched && searched.push(newParents); return true; } var children = self._getChildren(newParents); var notSearch = []; var can = false; BI.each(children, function (i, child) { if (search(newParents, child.value, result, searched)) { can = true; } else { notSearch.push(child.value); } }); if (can === true) { BI.each(notSearch, function (i, v) { var next = BI.clone(newParents); next.push(v); result.push(next); }); } return can; } function isSearchValueInParent(parentValues) { for (var i = 0, len = parentValues.length; i < len; i++) { if (self._isMatch(parentValues.slice(0, parentValues.length - 1), parentValues[i], keyword)) { return true; } } return false; } function canFindKey(selectedValues, parents) { var t = selectedValues; for (var i = 0; i < parents.length; i++) { var v = parents[i]; t = t[v]; if (t == null) { return false; } } return true; } function isChild(selectedValues, parents) { var t = selectedValues; for (var i = 0; i < parents.length; i++) { var v = parents[i]; if (!BI.has(t, v)) { return false; } t = t[v]; if (BI.isEmpty(t)) { return true; } } return false; } }, _reqAdjustTreeNode: function (op, callback) { var self = this; var result = []; var selectedValues = op.selectedValues; if (selectedValues == null || BI.isEmpty(selectedValues)) { callback({}); return; } BI.each(selectedValues, function (k, v) { result.push([k]); }); dealWithSelectedValues(selectedValues, []); var jo = {}; BI.each(result, function (i, strs) { self._buildTree(jo, strs); }); callback(jo); function dealWithSelectedValues(selected, parents) { if (selected == null || BI.isEmpty(selected)) { return true; } var can = true; BI.each(selected, function (k, v) { var p = BI.clone(parents); p.push(k); if (!dealWithSelectedValues(selected[k], p)) { BI.each(selected[k], function (nk, nv) { var t = BI.clone(p); t.push(nk); result.push(t); }); can = false; } }); return can && isAllSelected(selected, parents); } function isAllSelected(selected, parents) { return BI.isEmpty(selected) || self._getChildCount(parents) === BI.size(selected); } }, _reqInitTreeNode: function (op, callback) { var self = this; var result = []; var keyword = op.keyword || ""; var selectedValues = op.selectedValues; var lastSearchValue = op.lastSearchValue || ""; var output = search(); BI.nextTick(function () { callback({ hasNext: output.length > self._const.perPage, items: result, lastSearchValue: BI.last(output) }) }); function search() { var children = self._getChildren([]); var start = children.length; if (lastSearchValue !== "") { for (var j = 0, len = start; j < len; j++) { if (children[j].value === lastSearchValue) { start = j + 1; break; } } } else { start = 0; } var output = []; for (var i = start, len = children.length; i < len; i++) { if (output.length < self._const.perPage) { var find = nodeSearch(1, [], children[i].value, false, result); } else if (output.length === self._const.perPage) { var find = nodeSearch(1, [], children[i].value, false, []); } if (find[0] === true) { output.push(children[i].value); } if (output.length > self._const.perPage) { break; } } return output; } function nodeSearch(deep, parentValues, current, isAllSelect, result) { if (self._isMatch(parentValues, current, keyword)) { var checked = isAllSelect || isSelected(parentValues, current); createOneJson(parentValues, current, false, checked, !isAllSelect && isHalf(parentValues, current), true, result); return [true, checked]; } var newParents = BI.clone(parentValues); newParents.push(current); var children = self._getChildren(newParents); var can = false, checked = false; var isCurAllSelected = isAllSelect || isAllSelected(parentValues, current); BI.each(children, function (i, child) { var state = nodeSearch(deep + 1, newParents, child.value, isCurAllSelected, result); if (state[1] === true) { checked = true; } if (state[0] === true) { can = true; } }); if (can === true) { checked = isCurAllSelected || (isSelected(parentValues, current) && checked); createOneJson(parentValues, current, true, checked, false, false, result); } return [can, checked]; } function createOneJson(parentValues, value, isOpen, checked, half, flag, result) { var node = self._getTreeNode(parentValues, value) result.push({ id: node.id, pId: node.pId, text: node.text, value: node.value, title: node.title, isParent: node.getChildrenLength() > 0, open: isOpen, checked: checked, halfCheck: half, flag: flag }); } function isHalf(parentValues, value) { var find = findSelectedObj(parentValues); if (find == null) { return null; } return BI.any(find, function (v, ob) { if (v === value) { if (ob != null && !BI.isEmpty(ob)) { return true; } } }); } function isAllSelected(parentValues, value) { var find = findSelectedObj(parentValues); if (find == null) { return null; } return BI.any(find, function (v, ob) { if (v === value) { if (ob != null && BI.isEmpty(ob)) { return true; } } }); } function isSelected(parentValues, value) { var find = findSelectedObj(parentValues); if (find == null) { return false; } return BI.any(find, function (v) { if (v === value) { return true; } }); } function findSelectedObj(parentValues) { var find = selectedValues; if (find == null) { return null; } BI.every(parentValues, function (i, v) { find = find[v]; if (find == null) { return false; } return true; }); return find; } }, _reqTreeNode: function (op, callback) { var self = this; var result = []; var times = op.times; var checkState = op.checkState || {}; var parentValues = op.parentValues || []; var selectedValues = op.selectedValues || {}; var valueMap = {}; // if (judgeState(parentValues, selectedValues, checkState)) { valueMap = dealWidthSelectedValue(parentValues, selectedValues); // } var nodes = this._getChildren(parentValues); for (var i = (times - 1) * this._const.perPage; nodes[i] && i < times * this._const.perPage; i++) { var state = getCheckState(nodes[i].value, parentValues, valueMap, checkState); result.push({ id: nodes[i].id, pId: nodes[i].pId, value: nodes[i].value, text: nodes[i].text, times: 1, isParent: nodes[i].getChildrenLength() > 0, checked: state[0], halfCheck: state[1] }) } BI.nextTick(function () { callback({ items: result, hasNext: nodes.length > times * self._const.perPage }); }); function judgeState(parentValues, selected_value, checkState) { var checked = checkState.checked, half = checkState.half; if (parentValues.length > 0 && !checked) { return false; } return (parentValues.length === 0 || (checked && half) && !BI.isEmpty(selected_value)); } function dealWidthSelectedValue(parentValues, selectedValues) { var valueMap = {}; BI.each(parentValues, function (i, v) { selectedValues = selectedValues[v] || {}; }); BI.each(selectedValues, function (value, obj) { if (BI.isNull(obj)) { valueMap[value] = [0, 0]; return; } if (BI.isEmpty(obj)) { valueMap[value] = [2, 0]; return; } var nextNames = {}; BI.each(obj, function (t, o) { if (BI.isNull(o) || BI.isEmpty(o)) { nextNames[t] = true; } }); valueMap[value] = [1, BI.size(nextNames)]; }); return valueMap; } function getCheckState(current, parentValues, valueMap, checkState) { var checked = checkState.checked, half = checkState.half; var tempCheck = false, halfCheck = false; if (BI.has(valueMap, current)) { //可能是半选 if (valueMap[current][0] === 1) { var values = BI.clone(parentValues); values.push(current); var childCount = self._getChildCount(values); if (childCount > 0 && childCount !== valueMap[current][1]) { halfCheck = true; } } else if (valueMap[current][0] === 2) { tempCheck = true; } } var check; if (!checked && !halfCheck && !tempCheck) { check = BI.has(valueMap, current); } else { check = ((tempCheck || checked) && !half) || BI.has(valueMap, current); } return [check, halfCheck]; } }, _getNode: function (selectedValues, parentValues) { var pNode = selectedValues; for (var i = 0, len = parentValues.length; i < len; i++) { if (pNode == null) { return null; } pNode = pNode[parentValues[i]]; } return pNode; }, _deleteNode: function (selectedValues, values) { var name = values[values.length - 1]; var p = values.slice(0, values.length - 1); var pNode = this._getNode(selectedValues, p); if (pNode != null && pNode[name]) { delete pNode[name]; //递归删掉空父节点 while (p.length > 0 && BI.isEmpty(pNode)) { name = p[p.length - 1]; p = p.slice(0, p.length - 1); pNode = this._getNode(selectedValues, p); if (pNode != null) { delete pNode[name]; } } } }, _buildTree: function (jo, values) { var t = jo; BI.each(values, function (i, v) { if (!BI.has(t, v)) { t[v] = {}; } t = t[v]; }); }, _isMatch: function (parentValues, value, keyword) { var node = this._getTreeNode(parentValues, value); var finded = BI.Func.getSearchResult([node.text || node.value], keyword); return finded.finded.length > 0 || finded.matched.length > 0; }, _getTreeNode: function (parentValues, v) { var self = this; var findedParentNode; var index = 0; this.tree.traverse(function (node) { if (self.tree.isRoot(node)) { return; } if (index > parentValues.length) { return false; } if (index === parentValues.length && node.value === v) { findedParentNode = node; return false; } if (node.value === parentValues[index]) { index++; return; } return true; }); return findedParentNode; }, _getChildren: function (parentValues) { if (parentValues.length > 0) { var value = BI.last(parentValues); var parent = this._getTreeNode(parentValues.slice(0, parentValues.length - 1), value); } else { var parent = this.tree.getRoot(); } return parent.getChildren(); }, _getChildCount: function (parentValues) { return this._getChildren(parentValues).length; } });/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. * @class BI.TreeValueChooserCombo * @extends BI.Widget */ BI.TreeValueChooserCombo = BI.inherit(BI.AbstractTreeValueChooser, { _defaultConfig: function () { return BI.extend(BI.TreeValueChooserCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-tree-value-chooser-combo", width: 200, height: 30, items: null, itemsCreator: BI.emptyFn }); }, _init: function () { BI.TreeValueChooserCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; if (BI.isNotNull(o.items)) { this._initData(o.items); } this.combo = BI.createWidget({ type: 'bi.multi_tree_combo', element: this, itemsCreator: BI.bind(this._itemsCreator, this), width: o.width, height: o.height }); this.combo.on(BI.MultiTreeCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.TreeValueChooserCombo.EVENT_CONFIRM); }); }, setValue: function (v) { this.combo.setValue(v); }, getValue: function () { return this.combo.getValue(); }, populate: function () { this.combo.populate.apply(this.combo, arguments); } }); BI.TreeValueChooserCombo.EVENT_CONFIRM = "TreeValueChooserCombo.EVENT_CONFIRM"; BI.shortcut('bi.tree_value_chooser_combo', BI.TreeValueChooserCombo);/** * 简单的复选下拉树控件, 适用于数据量少的情况 * * Created by GUY on 2015/10/29. * @class BI.TreeValueChooserPane * @extends BI.AbstractTreeValueChooser */ BI.TreeValueChooserPane = BI.inherit(BI.AbstractTreeValueChooser, { _defaultConfig: function () { return BI.extend(BI.TreeValueChooserPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-tree-value-chooser-pane", items: null, itemsCreator: BI.emptyFn }); }, _init: function () { BI.TreeValueChooserPane.superclass._init.apply(this, arguments); var self = this, o = this.options; this.pane = BI.createWidget({ type: 'bi.multi_select_tree', element: this, itemsCreator: BI.bind(this._itemsCreator, this) }); this.pane.on(BI.MultiSelectTree.EVENT_CHANGE, function () { self.fireEvent(BI.TreeValueChooserPane.EVENT_CHANGE); }); if (BI.isNotNull(o.items)) { this._initData(o.items); this.populate(); } }, setSelectedValue: function (v) { this.pane.setSelectedValue(v); }, setValue: function (v) { this.pane.setValue(v); }, getValue: function () { return this.pane.getValue(); }, populate: function () { this.pane.populate.apply(this.pane, arguments); } }); BI.TreeValueChooserPane.EVENT_CHANGE = "TreeValueChooserPane.EVENT_CHANGE"; BI.shortcut('bi.tree_value_chooser_pane', BI.TreeValueChooserPane);/** * 简单的复选下拉框控件, 适用于数据量少的情况 * 封装了字段处理逻辑 * * Created by GUY on 2015/10/29. * @class BI.AbstractValueChooser * @extends BI.Widget */ BI.AbstractValueChooser = BI.inherit(BI.Widget, { _const: { perPage: 100 }, _defaultConfig: function () { return BI.extend(BI.AbstractValueChooser.superclass._defaultConfig.apply(this, arguments), { items: null, itemsCreator: BI.emptyFn, cache: true }); }, _valueFormatter: function (v) { var text = v; if (BI.isNotNull(this.items)) { BI.some(this.items, function (i, item) { if (item.value === v) { text = item.text; return true; } }); } return text; }, _getItemsByTimes: function (items, times) { var res = []; for (var i = (times - 1) * this._const.perPage; items[i] && i < times * this._const.perPage; i++) { res.push(items[i]); } return res; }, _hasNextByTimes: function (items, times) { return times * this._const.perPage < items.length; }, _itemsCreator: function (options, callback) { var self = this, o = this.options; if (!o.cache || !this.items) { o.itemsCreator({}, function (items) { self.items = items; call(items); }); } else { call(this.items); } function call(items) { var keywords = (options.keywords || []).slice(); if (options.keyword) { keywords.push(options.keyword); } BI.each(keywords, function (i, kw) { var search = BI.Func.getSearchResult(items, kw); items = search.matched.concat(search.finded); }); if (options.selectedValues) {//过滤 var filter = BI.makeObject(options.selectedValues, true); items = BI.filter(items, function (i, ob) { return !filter[ob.value]; }); } if (options.type === BI.MultiSelectCombo.REQ_GET_ALL_DATA) { callback({ items: items }); return; } if (options.type === BI.MultiSelectCombo.REQ_GET_DATA_LENGTH) { callback({count: items.length}); return; } callback({ items: self._getItemsByTimes(items, options.times), hasNext: self._hasNextByTimes(items, options.times) }); } } });/** * 简单的复选下拉框控件, 适用于数据量少的情况 * 封装了字段处理逻辑 * * Created by GUY on 2015/10/29. * @class BI.ValueChooserCombo * @extends BI.Widget */ BI.ValueChooserCombo = BI.inherit(BI.AbstractValueChooser, { _defaultConfig: function () { return BI.extend(BI.ValueChooserCombo.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-value-chooser-combo", width: 200, height: 30, items: null, itemsCreator: BI.emptyFn, cache: true }); }, _init: function () { BI.ValueChooserCombo.superclass._init.apply(this, arguments); var self = this, o = this.options; if (BI.isNotNull(o.items)) { this.items = o.items; } this.combo = BI.createWidget({ type: 'bi.multi_select_combo', element: this, itemsCreator: BI.bind(this._itemsCreator, this), valueFormatter: BI.bind(this._valueFormatter, this), width: o.width, height: o.height }); this.combo.on(BI.MultiSelectCombo.EVENT_CONFIRM, function () { self.fireEvent(BI.ValueChooserCombo.EVENT_CONFIRM); }); }, setValue: function (v) { this.combo.setValue(v); }, getValue: function () { var val = this.combo.getValue() || {}; return { type: val.type, value: val.value } }, populate: function () { this.combo.populate.apply(this, arguments); } }); BI.ValueChooserCombo.EVENT_CONFIRM = "ValueChooserCombo.EVENT_CONFIRM"; BI.shortcut('bi.value_chooser_combo', BI.ValueChooserCombo);/** * 简单的复选下拉框控件, 适用于数据量少的情况 * 封装了字段处理逻辑 * * Created by GUY on 2015/10/29. * @class BI.ValueChooserPane * @extends BI.Widget */ BI.ValueChooserPane = BI.inherit(BI.AbstractValueChooser, { _defaultConfig: function () { return BI.extend(BI.ValueChooserPane.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-value-chooser-pane", items: null, itemsCreator: BI.emptyFn, cache: true }); }, _init: function () { BI.ValueChooserPane.superclass._init.apply(this, arguments); var self = this, o = this.options; this.list = BI.createWidget({ type: 'bi.multi_select_list', element: this, itemsCreator: BI.bind(this._itemsCreator, this), valueFormatter: BI.bind(this._valueFormatter, this) }); this.list.on(BI.MultiSelectList.EVENT_CHANGE, function () { self.fireEvent(BI.ValueChooserPane.EVENT_CHANGE); }); if (BI.isNotNull(o.items)) { this.items = o.items; this.populate(); } }, setValue: function (v) { this.list.setValue(v); }, getValue: function () { var val = this.list.getValue() || {}; return { type: val.type, value: val.value } }, populate: function () { this.list.populate.apply(this.list, arguments); } }); BI.ValueChooserPane.EVENT_CHANGE = "ValueChooserPane.EVENT_CHANGE"; BI.shortcut('bi.value_chooser_pane', BI.ValueChooserPane);