diff --git a/bi/base.js b/bi/base.js index b85a2d5a99..2d39187d1d 100644 --- a/bi/base.js +++ b/bi/base.js @@ -1078,10 +1078,9 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { //如果是一个简单的layout _isSimpleLayout: function () { var o = this.options; - return o.layouts.length === 1 + return o.layouts.length === 1 && !BI.isArray(o.items[0]) }, - doBehavior: function () { var args = Array.prototype.slice.call(arguments); args.unshift(this.buttons); @@ -30424,11 +30423,9 @@ BI.Table = BI.inherit(BI.Widget, { self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT); } }); - BI.Resizers.add(this.getName(), function (e) { - if (BI.isWindow(e.target) && self.element.is(":visible")) { - self._resize(); - self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); - } + BI.ResizeDetector.addResizeListener(this, function () { + self._resize(); + self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); }); }, @@ -30810,6 +30807,7 @@ BI.Table = BI.inherit(BI.Widget, { .addClass(c === rows.length - 1 ? "last-col" : ""); var w = BI.createWidget(map[r][c], { type: "bi.table_cell", + root: true, textAlign: "left", width: BI.isNumeric(width) ? width : "", height: BI.isNumeric(height) ? height : "", @@ -30889,6 +30887,7 @@ BI.Table = BI.inherit(BI.Widget, { return this.footer; }, + _createBody: function () { var self = this, o = this.options; this.body = this._body(); diff --git a/bi/core.css b/bi/core.css index bf8c698a1f..c94ea5fe62 100644 --- a/bi/core.css +++ b/bi/core.css @@ -1,131 +1,3 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ -html, -body, -div, -span, -applet, -object, -iframe, -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote, -pre, -a, -abbr, -acronym, -address, -big, -cite, -code, -del, -dfn, -em, -img, -ins, -kbd, -q, -s, -samp, -small, -strike, -strong, -sub, -sup, -tt, -var, -b, -u, -i, -center, -dl, -dt, -dd, -ol, -ul, -li, -fieldset, -form, -label, -legend, -table, -caption, -tbody, -tfoot, -thead, -tr, -th, -td, -article, -aside, -canvas, -details, -embed, -figure, -figcaption, -footer, -header, -hgroup, -menu, -nav, -output, -ruby, -section, -summary, -time, -mark, -audio, -video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -menu, -nav, -section { - display: block; -} -body { - line-height: 1; -} -ol, -ul { - list-style: none; -} -blockquote, -q { - quotes: none; -} -blockquote:before, -blockquote:after, -q:before, -q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} @charset "UTF-8"; /*! * animate.css -http://daneden.me/animate diff --git a/bi/core.js b/bi/core.js index ae283440f6..bc36f84a65 100644 --- a/bi/core.js +++ b/bi/core.js @@ -49,9 +49,9 @@ BI.Factory = { // } return view; } -};(function(root, factory) { - root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); -}(this, function(root, BI, _, $) { +};(function (root, factory) { + root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); +}(this, function (root, BI, _, $) { var previousBI = root.BI; @@ -68,7 +68,7 @@ BI.Factory = { // Runs BI.js in *noConflict* mode, returning the `BI` variable // to its previous owner. Returns a reference to this BI object. - BI.noConflict = function() { + BI.noConflict = function () { root.BI = previousBI; return this; }; @@ -101,7 +101,7 @@ BI.Factory = { // Bind an event to a `callback` function. Passing `"all"` will bind // the callback to all events fired. - on: function(name, callback, context) { + 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] = []); @@ -111,10 +111,10 @@ BI.Factory = { // 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) { + once: function (name, callback, context) { if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; - var once = _.once(function() { + var once = _.once(function () { self.off(name, once); callback.apply(this, arguments); }); @@ -126,7 +126,7 @@ BI.Factory = { // 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) { + off: function (name, callback, context) { if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; // Remove all callbacks for all events. @@ -157,7 +157,7 @@ BI.Factory = { callback && callback !== event.callback && callback !== event.callback._callback || context && context !== event.context - ) { + ) { remaining.push(event); } } @@ -173,11 +173,15 @@ BI.Factory = { 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) { + trigger: function (name) { if (!this._events) return this; var args = slice.call(arguments, 1); if (!eventsApi(this, 'trigger', name, args)) return this; @@ -188,10 +192,14 @@ BI.Factory = { 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) { + listenTo: function (obj, name, callback) { var listeningTo = this._listeningTo || (this._listeningTo = {}); var id = obj._listenId || (obj._listenId = _.uniqueId('l')); listeningTo[id] = obj; @@ -200,7 +208,7 @@ BI.Factory = { return this; }, - listenToOnce: function(obj, name, callback) { + listenToOnce: function (obj, name, callback) { if (typeof name === 'object') { for (var event in name) this.listenToOnce(obj, event, name[event]); return this; @@ -213,7 +221,7 @@ BI.Factory = { return this; } if (!callback) return this; - var once = _.once(function() { + var once = _.once(function () { this.stopListening(obj, name, once); callback.apply(this, arguments); }); @@ -223,7 +231,7 @@ BI.Factory = { // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. - stopListening: function(obj, name, callback) { + stopListening: function (obj, name, callback) { var listeningTo = this._listeningTo; if (!listeningTo) return this; var remove = !name && !callback; @@ -245,7 +253,7 @@ BI.Factory = { // 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) { + var eventsApi = function (obj, action, name, rest) { if (!name) return true; // Handle event maps. @@ -271,19 +279,29 @@ BI.Factory = { // 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 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; + 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.bind = Events.on; Events.unbind = Events.off; // Allow the `BI` object to serve as a global event bus, for folks who @@ -300,7 +318,7 @@ BI.Factory = { // 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 M = BI.M = function (attributes, options) { var attrs = attributes || {}; options = options || {}; this.cid = _.uniqueId('c'); @@ -329,40 +347,47 @@ BI.Factory = { // CouchDB users may want to set this to `"_id"`. idAttribute: 'ID', - _defaultConfig: function(){return {}}, + _defaultConfig: function () { + return {} + }, + + init: function () { + }, // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _init: function () { + this.init(); + }, // Return a copy of the model's `attributes` object. - toJSON: function(options) { + 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() { + sync: function () { return BI.sync.apply(this, arguments); }, // Get the value of an attribute. - get: function(attr) { + get: function (attr) { return this.attributes[attr]; }, // Get the HTML-escaped value of an attribute. - escape: function(attr) { + 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) { + has: function (attr) { return _.has(this.attributes, attr); }, // Special-cased proxy to underscore's `_.matches` method. - matches: function(attrs) { + matches: function (attrs) { var keys = _.keys(attrs), length = keys.length; var obj = Object(this.attributes); for (var i = 0; i < length; i++) { @@ -375,7 +400,7 @@ BI.Factory = { // 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) { + set: function (key, val, options) { var attr, attrs, unset, changes, silent, changing, changed, prev, current; if (key == null) return this; @@ -393,11 +418,11 @@ BI.Factory = { if (!this._validate(attrs, options)) return false; // Extract attributes and options. - unset = options.unset; - silent = options.silent; - changes = []; - changing = this._changing; - this._changing = true; + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; if (!changing) { this._previousAttributes = _.clone(this.attributes); @@ -447,12 +472,12 @@ BI.Factory = { // Remove an attribute from the model, firing `"change"`. `unset` is a noop // if the attribute doesn't exist. - unset: function(attr, options) { + 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) { + clear: function (options) { var attrs = {}; for (var key in this.attributes) attrs[key] = void 0; return this.set(attrs, _.extend({}, options, {unset: true})); @@ -460,7 +485,7 @@ BI.Factory = { // 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) { + hasChanged: function (attr) { if (attr == null) return !_.isEmpty(this.changed); return _.has(this.changed, attr); }, @@ -471,7 +496,7 @@ BI.Factory = { // 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) { + changedAttributes: function (diff) { if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; var val, changed = false; var old = this._changing ? this._previousAttributes : this.attributes; @@ -484,27 +509,27 @@ BI.Factory = { // Get the previous value of an attribute, recorded at the time the last // `"change"` event was fired. - previous: function(attr) { + 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() { + 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) { + 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) { + options.success = function (resp) { + if (!options.noset) { if (!model.set(model.parse(resp, options), options)) return false; } if (success) success(resp, model, options); @@ -517,7 +542,7 @@ BI.Factory = { // 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) { + save: function (key, val, options) { var attrs, method, xhr, attributes = this.attributes; // Handle both `"key", value` and `{key: value}` -style arguments. @@ -549,7 +574,7 @@ BI.Factory = { if (options.parse === void 0) options.parse = true; var model = this; var success = options.success; - options.success = function(resp) { + options.success = function (resp) { // Ensure attributes are restored during synchronous saves. model.attributes = attributes; var serverAttrs = model.parse(resp, options); @@ -576,17 +601,17 @@ BI.Factory = { // 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) { + destroy: function (options) { options = options ? _.clone(options) : {}; var model = this; var success = options.success; - var destroy = function() { + var destroy = function () { model.stopListening(); model.trigger('destroy', model.collection, model, options); }; - options.success = function(resp) { + 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); @@ -606,7 +631,7 @@ BI.Factory = { // 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() { + url: function () { var base = _.result(this.collection, 'url'); if (this.isNew()) return base; @@ -615,28 +640,28 @@ BI.Factory = { // **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) { + parse: function (resp, options) { return resp; }, // Create a new model with identical attributes to this one. - clone: function() { + 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() { + 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 })); + 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) { + _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; @@ -651,9 +676,9 @@ BI.Factory = { 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) { + _.each(modelMethods, function (method) { if (!_[method]) return; - M.prototype[method] = function() { + M.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.attributes); return _[method].apply(_, args); @@ -673,7 +698,7 @@ BI.Factory = { // 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) { + 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; @@ -695,26 +720,29 @@ BI.Factory = { // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _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); }); + toJSON: function (options) { + return this.map(function (model) { + return model.toJSON(options); + }); }, // Proxy `BI.sync` by default. - sync: function() { + sync: function () { return BI.sync.apply(this, arguments); }, // Add a model, or list of models to the set. - add: function(models, options) { + 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) { + remove: function (models, options) { var singular = !_.isArray(models); models = singular ? [models] : _.clone(models); options || (options = {}); @@ -740,7 +768,7 @@ BI.Factory = { // 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) { + set: function (models, options) { options = _.defaults({}, options, setOptions); if (options.parse) models = this.parse(models, options); var singular = !_.isArray(models); @@ -841,7 +869,7 @@ BI.Factory = { // 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) { + 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); @@ -854,66 +882,66 @@ BI.Factory = { }, // Add a model to the end of the collection. - push: function(model, options) { + 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) { + 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) { + unshift: function (model, options) { return this.add(model, _.extend({at: 0}, options)); }, // Remove a model from the beginning of the collection. - shift: function(options) { + 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() { + slice: function () { return slice.apply(this.models, arguments); }, // Get a model from the set by id. - get: function(obj) { + 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) { + 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) { + where: function (attrs, first) { var matches = _.matches(attrs); - return this[first ? 'find' : 'filter'](function(model) { + 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) { + 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) { + sort: function (options) { if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); options || (options = {}); @@ -929,19 +957,19 @@ BI.Factory = { }, // Pluck an attribute from each model in the collection. - pluck: function(attr) { + 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) { + 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) { + options.success = function (resp) { var method = options.reset ? 'reset' : 'set'; collection[method](resp, options); if (success) success(collection, resp, options); @@ -954,13 +982,13 @@ BI.Factory = { // 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) { + 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) { + options.success = function (model, resp) { if (options.wait) collection.add(model, options); if (success) success(model, resp, options); }; @@ -970,12 +998,12 @@ BI.Factory = { // **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) { + parse: function (resp, options) { return resp; }, // Create a new collection with an identical list of models as this one. - clone: function() { + clone: function () { return new this.constructor(this.models, { model: this.model, comparator: this.comparator @@ -989,15 +1017,15 @@ BI.Factory = { // Private method to reset all internal state. Called when the collection // is first _initd or reset. - _reset: function() { + _reset: function () { this.length = 0; this.models = []; - this._byId = {}; + this._byId = {}; }, // Prepare a hash of attributes (or other model) to be added to this // collection. - _prepareModel: function(attrs, options) { + _prepareModel: function (attrs, options) { if (this._isModel(attrs)) { if (!attrs.collection) attrs.collection = this; return attrs; @@ -1017,7 +1045,7 @@ BI.Factory = { }, // Internal method to create a model's ties to a collection. - _addReference: function(model, options) { + _addReference: function (model, options) { this._byId[model.cid] = model; var id = this.modelId(model.attributes); if (id != null) this._byId[id] = model; @@ -1025,7 +1053,7 @@ BI.Factory = { }, // Internal method to sever a model's ties to a collection. - _removeReference: function(model, options) { + _removeReference: function (model, options) { if (this === model.collection) delete model.collection; model.off('all', this._onModelEvent, this); }, @@ -1034,7 +1062,7 @@ BI.Factory = { // 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) { + _onModelEvent: function (event, model, collection, options) { if ((event === 'add' || event === 'remove') && collection !== this) return; if (event === 'destroy') this.remove(model, options); if (event === 'change') { @@ -1061,9 +1089,9 @@ BI.Factory = { 'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition']; // Mix in each Underscore method as a proxy to `Collection#models`. - _.each(methods, function(method) { + _.each(methods, function (method) { if (!_[method]) return; - Collection.prototype[method] = function() { + Collection.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.models); return _[method].apply(_, args); @@ -1074,10 +1102,10 @@ BI.Factory = { var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; // Use attributes instead of properties. - _.each(attributeMethods, function(method) { + _.each(attributeMethods, function (method) { if (!_[method]) return; - Collection.prototype[method] = function(value, context) { - var iterator = _.isFunction(value) ? value : function(model) { + Collection.prototype[method] = function (value, context) { + var iterator = _.isFunction(value) ? value : function (model) { return model.get(value); }; return _[method](this.models, iterator, context); @@ -1097,7 +1125,7 @@ BI.Factory = { // 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) { + var V = BI.V = function (options) { this.cid = _.uniqueId('view'); options = options || {}; this.options = _.defaults(options, _.result(this, '_defaultConfig')); @@ -1120,28 +1148,33 @@ BI.Factory = { // jQuery delegate for element lookup, scoped to DOM elements within the // current view. This should be preferred to global lookups where possible. - $: function(selector) { + $: function (selector) { return this.$el.find(selector); }, - _defaultConfig: function(){return {}}, + _defaultConfig: function () { + return {} + }, // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _init: function () { + }, //容器,默认放在this.element上 - _vessel: function(){return 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) { + 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() { + remove: function () { this._removeElement(); this.stopListening(); return this; @@ -1150,7 +1183,7 @@ BI.Factory = { // 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() { + _removeElement: function () { this.$el.remove(); if ($.browser.msie === true) { this.el.outerHTML = ''; @@ -1159,33 +1192,33 @@ BI.Factory = { // Change the view's element (`this.el` property) and re-delegate the // view's events on the new element. - setElement: function(element) { + setElement: function (element) { this.undelegateEvents(); this._setElement(element); - this.$vessel = this._vessel(); - this._render(this.$vessel); + this.vessel = this._vessel(); + this.render(this.vessel); this.delegateEvents(); return this; }, - setVisible: function(visible){ + setVisible: function (visible) { this.options.invisible = !visible; - if (visible){ + if (visible) { this.element.show(); } else { this.element.hide(); } }, - isVisible: function(){ + isVisible: function () { return !this.options.invisible; }, - visible: function(){ + visible: function () { this.setVisible(true); }, - invisible: function(){ + invisible: function () { this.setVisible(false); }, @@ -1194,7 +1227,7 @@ BI.Factory = { // 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) { + _setElement: function (el) { this.$el = el instanceof BI.$ ? el : BI.$(el); this.element = this.$el; this.el = this.$el[0]; @@ -1213,7 +1246,7 @@ BI.Factory = { // 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) { + delegateEvents: function (events) { if (!(events || (events = _.result(this, 'events')))) return this; this.undelegateEvents(); for (var key in events) { @@ -1229,27 +1262,27 @@ BI.Factory = { // 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.on(eventName + '.delegateEvents' + this.cid, selector, listener); + 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.off('.delegateEvents' + this.cid); + 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.off(eventName + '.delegateEvents' + this.cid, selector, listener); + 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) { + _createElement: function (tagName) { return document.createElement(tagName); }, @@ -1257,7 +1290,7 @@ BI.Factory = { // 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() { + _ensureElement: function () { var attrs = _.extend({}, _.result(this, 'attributes')); if (this.baseCls) attrs['class'] = _.result(this, 'baseCls'); if (!this.element) { @@ -1270,7 +1303,7 @@ BI.Factory = { // Set attributes from a hash on this view's element. Exposed for // subclasses using an alternative DOM manipulation API. - _setAttributes: function(attributes) { + _setAttributes: function (attributes) { this.$el.attr(attributes); } @@ -1294,7 +1327,7 @@ BI.Factory = { // 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) { + BI.sync = function (method, model, options) { var type = methodMap[method]; // Default options, unless specified. @@ -1308,8 +1341,8 @@ BI.Factory = { // Ensure that we have a URL. if (!options.url) { - params.url = _.result(model, method+"URL") || _.result(model, 'url'); - if(!params.url){ + params.url = _.result(model, method + "URL") || _.result(model, 'url'); + if (!params.url) { return; } } @@ -1332,7 +1365,7 @@ BI.Factory = { params.type = 'POST'; if (options.emulateJSON) params.data._method = type; var beforeSend = options.beforeSend; - options.beforeSend = function(xhr) { + options.beforeSend = function (xhr) { xhr.setRequestHeader('X-HTTP-Method-Override', type); if (beforeSend) return beforeSend.apply(this, arguments); }; @@ -1345,7 +1378,7 @@ BI.Factory = { // Pass along `textStatus` and `errorThrown` from jQuery. var error = options.error; - options.error = function(xhr, textStatus, errorThrown) { + options.error = function (xhr, textStatus, errorThrown) { options.textStatus = textStatus; options.errorThrown = errorThrown; if (error) error.apply(this, arguments); @@ -1361,9 +1394,9 @@ BI.Factory = { var methodMap = { 'create': 'POST', 'update': 'PUT', - 'patch': 'PATCH', + 'patch': 'PATCH', 'delete': 'DELETE', - 'read': 'GET' + 'read': 'GET' }; // Set the default implementation of `BI.ajax` to proxy through to `$`. @@ -1375,7 +1408,7 @@ BI.Factory = { // 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) { + var Router = BI.Router = function (options) { options || (options = {}); if (options.routes) this.routes = options.routes; this._bindRoutes(); @@ -1385,16 +1418,17 @@ BI.Factory = { // 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; + 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(){}, + _init: function () { + }, // Manually bind a single named route to a callback. For example: // @@ -1402,7 +1436,7 @@ BI.Factory = { // ... // }); // - route: function(route, name, callback) { + route: function (route, name, callback) { if (!_.isRegExp(route)) route = this._routeToRegExp(route); if (_.isFunction(name)) { callback = name; @@ -1410,7 +1444,7 @@ BI.Factory = { } if (!callback) callback = this[name]; var router = this; - BI.history.route(route, function(fragment) { + 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)); @@ -1423,12 +1457,12 @@ BI.Factory = { // 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) { + 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) { + navigate: function (fragment, options) { BI.history.navigate(fragment, options); return this; }, @@ -1436,7 +1470,7 @@ BI.Factory = { // 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() { + _bindRoutes: function () { if (!this.routes) return; this.routes = _.result(this, 'routes'); var route, routes = _.keys(this.routes); @@ -1447,10 +1481,10 @@ BI.Factory = { // Convert a route string into a regular expression, suitable for matching // against the current location hash. - _routeToRegExp: function(route) { + _routeToRegExp: function (route) { route = route.replace(escapeRegExp, '\\$&') .replace(optionalParam, '(?:$1)?') - .replace(namedParam, function(match, optional) { + .replace(namedParam, function (match, optional) { return optional ? match : '([^/?]+)'; }) .replace(splatParam, '([^?]*?)'); @@ -1460,9 +1494,9 @@ BI.Factory = { // 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) { + _extractParameters: function (route, fragment) { var params = route.exec(fragment).slice(1); - return _.map(params, function(param, i) { + 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; @@ -1479,7 +1513,7 @@ BI.Factory = { // [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() { + var History = BI.History = function () { this.handlers = []; _.bindAll(this, 'checkUrl'); @@ -1510,27 +1544,27 @@ BI.Factory = { interval: 50, // Are we at the app root? - atRoot: function() { + 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() { + 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) { + 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() { + 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); @@ -1538,7 +1572,7 @@ BI.Factory = { }, // Get the cross-browser normalized URL fragment from the path or hash. - getFragment: function(fragment) { + getFragment: function (fragment) { if (fragment == null) { if (this._hasPushState || !this._wantsHashChange) { fragment = this.getPath(); @@ -1551,19 +1585,19 @@ BI.Factory = { // Start the hash change handling, returning `true` if the current URL matches // an existing route, and `false` otherwise. - start: function(options) { + 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.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(); + 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, '/'); @@ -1605,8 +1639,8 @@ BI.Factory = { // Add a cross-platform `addEventListener` shim for older browsers. var addEventListener = window.addEventListener || function (eventName, listener) { - return attachEvent('on' + 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. @@ -1623,11 +1657,11 @@ BI.Factory = { // Disable BI.history, perhaps temporarily. Not useful in a real app, // but possibly useful for unit testing Routers. - stop: function() { + stop: function () { // Add a cross-platform `removeEventListener` shim for older browsers. var removeEventListener = window.removeEventListener || function (eventName, listener) { - return detachEvent('on' + eventName, listener); - }; + return detachEvent('on' + eventName, listener); + }; // Remove window listeners. if (this._hasPushState) { @@ -1649,13 +1683,13 @@ BI.Factory = { // Add a route to be tested when the fragment changes. Routes added later // may override previous routes. - route: function(route, callback) { + 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) { + checkUrl: function (e) { var current = this.getFragment(); // If the user pressed the back button, the iframe's hash will have @@ -1672,9 +1706,9 @@ BI.Factory = { // 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) { + loadUrl: function (fragment) { fragment = this.fragment = this.getFragment(fragment); - return _.any(this.handlers, function(handler) { + return _.any(this.handlers, function (handler) { if (handler.route.test(fragment)) { handler.callback(fragment); return true; @@ -1689,7 +1723,7 @@ BI.Factory = { // 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) { + navigate: function (fragment, options) { if (!History.started) return false; if (!options || options === true) options = {trigger: !!options}; @@ -1735,7 +1769,7 @@ BI.Factory = { // Update the hash location, either replacing the current entry, or adding // a new one to the browser history. - _updateHash: function(location, fragment, replace) { + _updateHash: function (location, fragment, replace) { if (replace) { var href = location.href.replace(/(javascript:|#).*$/, ''); location.replace(href + '#' + fragment); @@ -1756,7 +1790,7 @@ BI.Factory = { // 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 extend = function (protoProps, staticProps) { var parent = this; var child; @@ -1766,7 +1800,9 @@ BI.Factory = { if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { - child = function(){ return parent.apply(this, arguments); }; + child = function () { + return parent.apply(this, arguments); + }; } // Add static properties to the constructor function, if supplied. @@ -1774,7 +1810,9 @@ BI.Factory = { // Set the prototype chain to inherit from `parent`, without calling // `parent`'s constructor function. - var Surrogate = function(){ this.constructor = child; }; + var Surrogate = function () { + this.constructor = child; + }; Surrogate.prototype = parent.prototype; child.prototype = new Surrogate; @@ -1793,14 +1831,14 @@ BI.Factory = { 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() { + 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 wrapError = function (model, options) { var error = options.error; - options.error = function(resp) { + options.error = function (resp) { if (error) error(model, resp, options); model.trigger('error', model, resp, options); }; @@ -3143,597 +3181,606 @@ if (!window.BI) { } } }); -})(jQuery);BI.cjkEncode = function (text) { - // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) - if (typeof text !== 'string') { - return text; +})(jQuery);;(function () { + function isEmpty(value) { + // 判断是否为空值 + var result = value === "" || value === null || value === undefined; + return result; } - 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); + BI.cjkEncode = function (text) { + // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) + if (typeof text !== 'string') { + return text; } - } - 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); + 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); } - //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', - '"': '\\"', - "\\": '\\\\' + return newText }; - 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); - }) + '"'; + 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 '"' + s + '"'; + return o; }; - 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; + 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); + }) + '"'; } - } - a.push("]"); - return a.join(""); - }; + return '"' + s + '"'; + }; - 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)) { + 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(BI.jsonEncode(i), ":", - v === null ? "null" : BI.jsonEncode(v)); + a.push(v === null ? "null" : BI.jsonEncode(v)); b = true; } } - } - a.push("}"); - return a.join(""); - } -}; + a.push("]"); + return a.join(""); + }; -BI.contentFormat = function (cv, fmt) { - if (BI.isEmpty(cv)) { - //原值为空,返回空字符 - return ''; - } - var text = cv.toString(); - if (BI.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 (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(""); } - if (!BI.isNull(cv)) { - var needTrim = fmt.match(/^DT/); - text = BI.date2Str(cv, fmt.substring(needTrim ? 2 : 1)); - } - } else if (fmt.match(/E/)) { - //科学计数格式 - text = BI._eFormat(text, fmt); - } else { - //数字格式 - text = BI._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} - */ -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; + 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 = BI._eFormat(text, fmt); + } else { + //数字格式 + text = BI._numberFormat(text, fmt); } - result += compileJFmt({ - 'char': flagch, - 'str': str, - 'len': len - start - }, date); - } - return result; + //¤ - 货币格式 + text = text.replace(/¤/g, '¥'); + return text; + }; - 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'); + /** + * 把日期对象按照指定格式转化成字符串 + * + * @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} + */ + 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 = date.getSeconds(); + str += ch; } - break; - case 'a': - str = date.getHours() < 12 ? 'am' : 'pm'; - break; - case 'z': - str = date.getTimezone(); - break; - default: - str = jfmt.str; - break; + } + result += compileJFmt({ + 'char': flagch, + 'str': str, + 'len': len - start + }, date); } - return str; - } -}; + return result; -/** - * 数字格式 - */ -BI._numberFormat = function (text, format) { - var text = text + ''; - //数字格式,区分正负数 - var numMod = format.indexOf(';'); - if (numMod > -1) { - if (text >= 0) { - return BI._numberFormat(text + "", format.substring(0, numMod)); - } else { - return BI._numberFormat((-text) + "", format.substr(numMod + 1)); + 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; } - } - 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 = BI._dealWithRight(tright, fright); - if (right.leftPlus) { - //小数点后有进位 - tleft = parseInt(tleft) + 1 + ''; + }; - tleft = isNaN(tleft) ? '1' : tleft; - } - right = right.num; - var left = BI._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 - */ -BI._dealWithRight = function (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 (BI.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 (!BI.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 = BI.parseINT(num) + 1 + ''; - //进位到整数部分 - if (newnum.length > orilen) { - newnum = newnum.substr(1); + /** + * 数字格式 + */ + BI._numberFormat = function (text, format) { + var text = text + ''; + //数字格式,区分正负数 + var numMod = format.indexOf(';'); + if (numMod > -1) { + if (text >= 0) { + return BI._numberFormat(text + "", format.substring(0, numMod)); } else { - newnum = BI.leftPad(newnum, orilen, '0'); - result.leftPlus = false; + return BI._numberFormat((-text) + "", format.substr(numMod + 1)); + } + } + 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 = BI._dealWithRight(tright, fright); + if (right.leftPlus) { + //小数点后有进位 + tleft = parseInt(tleft) + 1 + ''; + + tleft = isNaN(tleft) ? '1' : tleft; + } + right = right.num; + var left = BI._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 + */ + BI._dealWithRight = function (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; } - right = right.replace(/^[0-9]+/, newnum); } - } - result.num = right; - return result; -}; + 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 = BI.parseINT(num) + 1 + ''; + //进位到整数部分 + if (newnum.length > orilen) { + newnum = newnum.substr(1); + } else { + newnum = BI.leftPad(newnum, orilen, '0'); + result.leftPlus = false; + } + right = right.replace(/^[0-9]+/, newnum); + } + } + result.num = right; + return result; + }; -BI.parseINT = function (str) { - return parseInt(str, 10); -}; + BI.parseINT = function (str) { + return parseInt(str, 10); + }; -BI.leftPad = function (val, size, ch) { - var result = String(val); - if (!ch) { - ch = " "; - } - while (result.length < size) { - result = ch + result; - } - return result.toString(); -}; + BI.leftPad = function (val, size, ch) { + var result = String(val); + if (!ch) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result.toString(); + }; -/** - * 处理小数点左边整数部分 - * @param tleft 左边内容 - * @param fleft 左边格式 - * @returns {string} 返回处理结果 - * @private - */ -BI._dealWithLeft = function (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 (BI.isEmpty(c)) { - c = '0'; - } - last = -1; - left = c + left; - j--; - break; - case '#': - last = i; - left = c + left; - j--; - break; - case ',': - if (!BI.isEmpty(c)) { - //计算一个,分隔区间的长度 - var com = fleft.match(/,[#0]+/); - if (com) { - combo = com[0].length - 1; + /** + * 处理小数点左边整数部分 + * @param tleft 左边内容 + * @param fleft 左边格式 + * @returns {string} 返回处理结果 + * @private + */ + BI._dealWithLeft = function (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'; } - 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; + 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; } - var lres = res.substr(0, n + combo); - if (!BI.isEmpty(lres)) { - newstr = lres + ',' + newstr; + } + 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); } - left = left.replace(/[0-9]+,/, newstr); - } - return left; -}; + return left; + }; -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); + BI.object2Number = function (value) { + if (value == null) { + return 0; + } + if (typeof value == 'number') { + return value; } else { - return parseFloat(str); + 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 (!BI.isInvalidDate(dt)) { - return dt; + 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 (!BI.isInvalidDate(dt)) { + return dt; + } - return new Date(); - } -}; + return new Date(); + } + }; -BI.isArray = function (a) { - return Object.prototype.toString.call(a) == '[object Array]'; -}; + BI.isArray = function (a) { + return Object.prototype.toString.call(a) == '[object Array]'; + }; -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 (!BI.isInvalidDate(dt)) { - return dt; - } - if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { - dt = new Date("1970/01/01 " + str); + 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 (!BI.isInvalidDate(dt)) { return dt; } + if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { + dt = new Date("1970/01/01 " + str); + if (!BI.isInvalidDate(dt)) { + return dt; + } + } + dt = BI.str2Date(str, "HH:mm:ss"); + if (!BI.isInvalidDate(dt)) { + return dt; + } + return new Date(); } - dt = BI.str2Date(str, "HH:mm:ss"); - if (!BI.isInvalidDate(dt)) { - return dt; - } - return new Date(); - } -}; + }; // 判断是否是无效的日期 -BI.isInvalidDate = function (date) { - return date == "Invalid Date" || date == "NaN"; -}; + BI.isInvalidDate = function (date) { + return date == "Invalid Date" || date == "NaN"; + }; -/** - * 科学计数格式 - */ -BI._eFormat = function (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; + /** + * 科学计数格式 + */ + BI._eFormat = function (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'; + 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; } - } 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; -};/** + return text; + }; +})(); +/** * 事件集合 * @class BI.Events */ @@ -4254,8 +4301,7 @@ BI.OB = function (config) { }; $.extend(BI.OB.prototype, { props: {}, - init: function () { - }, + init: null, _defaultConfig: function (config) { return {}; @@ -4263,7 +4309,7 @@ $.extend(BI.OB.prototype, { _init: function () { this._initListeners(); - this.init(); + this.init && this.init(); }, _initListeners: function () { @@ -4386,6 +4432,7 @@ $.extend(BI.OB.prototype, { 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, @@ -4401,41 +4448,30 @@ BI.Widget = BI.inherit(BI.OB, { }, //生命周期函数 - beforeCreate: function () { - - }, - - created: function () { + beforeCreate: null, - }, + created: null, - render: function () { + render: null, - }, + beforeMounted: null, - beforeMounted: function () { - - }, - - mounted: function () { - - }, + mounted: null, update: null, - destroyed: function () { - }, + destroyed: null, _init: function () { BI.Widget.superclass._init.apply(this, arguments); - this.beforeCreate(); + this.beforeCreate && this.beforeCreate(); this._initRoot(); this._initElementWidth(); this._initElementHeight(); this._initVisualEffects(); this._initState(); this._initElement(); - this.created(); + this.created && this.created(); }, /** @@ -4445,6 +4481,7 @@ BI.Widget = BI.inherit(BI.OB, { _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; @@ -4508,7 +4545,7 @@ BI.Widget = BI.inherit(BI.OB, { _initElement: function () { var self = this; - var els = this.render(); + var els = this.render && this.render(); if (BI.isPlainObject(els)) { els = [els]; } @@ -4542,13 +4579,13 @@ BI.Widget = BI.inherit(BI.OB, { if (!isMounted) { return; } - this.beforeMounted(); + this.beforeMounted && this.beforeMounted(); this._isMounted = true; this._mountChildren(); BI.each(this._children, function (i, widget) { widget._mount && widget._mount(); }); - this.mounted(); + this.mounted && this.mounted(); }, _mountChildren: function () { @@ -4574,7 +4611,7 @@ BI.Widget = BI.inherit(BI.OB, { this._parent = null; this._isMounted = false; this.purgeListeners(); - this.destroyed(); + this.destroyed && this.destroyed(); }, setWidth: function (w) { @@ -4636,6 +4673,9 @@ BI.Widget = BI.inherit(BI.OB, { 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"); @@ -4761,7 +4801,7 @@ BI.Widget = BI.inherit(BI.OB, { empty: function () { BI.each(this._children, function (i, widget) { - widget._unMount(); + widget._unMount && widget._unMount(); }); this._children = {}; this.element.empty(); @@ -4774,7 +4814,7 @@ BI.Widget = BI.inherit(BI.OB, { this._children = {}; this._parent = null; this._isMounted = false; - this.destroyed(); + this.destroyed && this.destroyed(); this.element.destroy(); this.fireEvent(BI.Events.DESTROY); this.purgeListeners(); @@ -5370,10 +5410,10 @@ BI.View = BI.inherit(BI.V, { }); var vessel = BI.createWidget(); this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel); - return vessel.element; + return vessel; }, - _render: function (vessel) { + render: function (vessel) { return this; }, @@ -5741,15 +5781,26 @@ BI.View = BI.inherit(BI.V, { }, + _unMount: function () { + BI.each(this._cardLayouts, function (name, card) { + card && card._unMount(); + }); + delete this._cardLayouts; + delete this._cards; + this.off(); + this.destroyed(); + }, + destroy: function () { BI.each(this._cardLayouts, function (name, card) { - card && card.destroy(); + card && card._unMount(); }); delete this._cardLayouts; delete this._cards; + this.destroyed(); this.remove(); this.trigger(BI.Events.DESTROY); - this.destroyed(); + this.off(); }, destroyed: function () { @@ -11509,9 +11560,8 @@ BI.Layout = BI.inherit(BI.Widget, { removeIndex = nameOrWidget; } if (removeIndex) { - this.options.items.splice(removeIndex, 1); + this._removeItemAt(removeIndex | 0); } - BI.Layout.superclass.removeWidget.apply(this, arguments); }, empty: function () { @@ -12305,7 +12355,7 @@ BI.FloatCenterAdaptLayout = BI.inherit(BI.Layout, { element: this, items: [this.left] }); - this.removeWidget(this.container.getName()); + this.removeWidget(this.container); }, stroke: function (items) { @@ -12368,7 +12418,7 @@ BI.FloatHorizontalLayout = BI.inherit(BI.Layout, { element: this, items: [this.left] }); - this.removeWidget(this.container.getName()); + this.removeWidget(this.container); }, _addElement: function (i, item) { diff --git a/bi/widget.css b/bi/widget.css index 300750cb60..51d0750008 100644 --- a/bi/widget.css +++ b/bi/widget.css @@ -632,6 +632,14 @@ /****添加计算宽度的--运算符直接需要space****/ /****** common color(常用颜色,可用于普遍场景) *****/ /**** custom color(自定义颜色,用于特定场景) ****/ +.bi-responsive-table > div.bottom-left > div > div > table > * > * > td.last-col, +.bi-responsive-table > div.bottom-right > div > div > table > * > * > td.last-col, +.bi-responsive-table > div > div > table > * > * > td.last-col { + min-width: 80px; +} +/****添加计算宽度的--运算符直接需要space****/ +/****** common color(常用颜色,可用于普遍场景) *****/ +/**** custom color(自定义颜色,用于特定场景) ****/ .bi-sequence-table-dynamic-number .sequence-table-title-cell { overflow: hidden; overflow-x: hidden; diff --git a/bi/widget.js b/bi/widget.js index 42a46c18d7..fec31d1b5f 100644 --- a/bi/widget.js +++ b/bi/widget.js @@ -419,8 +419,10 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { if (o.isNeedResizeContainer) { var isResizing = false; + var needEnd = false; var height; var interval; + var startSize; var resize = function (e, ui) { if (isResizing) { return; @@ -442,20 +444,26 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { minHeight: 20, helper: "bi-resizer", autoHide: true, + start: function (e, ui) { + startSize = BI.clone(ui.size); + }, resize: function (e, ui) { - if (ui.size.height >= self.arrangement.container.element.height()) { + if (ui.size.height >= startSize.height - 10) { resize(e, ui); } else { interval && clearInterval(interval); + needEnd = true; } }, stop: function (e, ui) { var size = ui.size; - if (isResizing) { + if (isResizing && !needEnd) { size.height = height; } self.arrangement.setContainerSize(ui.size); + needEnd = false; isResizing = false; + startSize = null; interval && clearInterval(interval); self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE); } @@ -484,17 +492,21 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { 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 () { - if (!item.element.hasClass("selected")) { - item.element.css("zIndex", ++self.zIndex); - BI.each(self.getAllRegions(), function (i, region) { - region.el.element.removeClass("selected"); - }); - item.element.addClass("selected"); - } + self._setSelect(item) }); o.resizable && item.element.resizable({ handles: "e, s, se", @@ -663,6 +675,7 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { addRegion: function (region, position) { this._initResizable(region.el); + this._setSelect(region.el); var self = this, flag; var old = this.arrangement.getAllRegions(); if (BI.isNotNull(this.position)) { @@ -4892,6 +4905,9 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge 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); }); @@ -4907,7 +4923,7 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge if (BI.isNotEmptyString(value)) { var date = value.split("-"); self.store_value = { - type: BICst.MULTI_DATE_CALENDAR, + type: BI.DateTrigger.MULTI_DATE_CALENDAR, value:{ year: date[0] | 0, month: date[1] - 1, @@ -4975,7 +4991,7 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge var date = new Date(); this.store_value = v; if (BI.isNotNull(v)) { - type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value; + type = v.type || BI.DateTrigger.MULTI_DATE_CALENDAR; value = v.value; if(BI.isNull(value)){ value = v; } @@ -4987,88 +5003,88 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge self.setTitle(text + ":" + dateStr); }; switch (type) { - case BICst.MULTI_DATE_YEAR_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV]; + 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 BICst.MULTI_DATE_YEAR_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER]; + 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 BICst.MULTI_DATE_YEAR_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN]; + 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 BICst.MULTI_DATE_YEAR_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END]; + 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 BICst.MULTI_DATE_QUARTER_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV]; + 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 BICst.MULTI_DATE_QUARTER_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER]; + 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 BICst.MULTI_DATE_QUARTER_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN]; + 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 BICst.MULTI_DATE_QUARTER_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END]; + 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 BICst.MULTI_DATE_MONTH_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV]; + 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 BICst.MULTI_DATE_MONTH_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER]; + 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 BICst.MULTI_DATE_MONTH_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN]; + 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 BICst.MULTI_DATE_MONTH_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END]; + 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 BICst.MULTI_DATE_WEEK_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV]; + 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 BICst.MULTI_DATE_WEEK_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER]; + 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 BICst.MULTI_DATE_DAY_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV]; + 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 BICst.MULTI_DATE_DAY_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER]; + 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 BICst.MULTI_DATE_DAY_TODAY: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY]; + 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; @@ -5095,8 +5111,58 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge } }); + +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"; @@ -13801,11 +13867,6 @@ BI.PreviewTable = BI.inherit(BI.Widget, { populate: function (items, header) { this.table.populate(items, header); - }, - - destroy: function () { - this.table.destroy(); - BI.PreviewTable.superclass.destroy.apply(this, arguments); } }); BI.PreviewTable.EVENT_CHANGE = "PreviewTable.EVENT_CHANGE"; @@ -14691,6 +14752,368 @@ 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 () { + if (self.element.is(":visible")) { + self._initRegionSize(); + self.table.resize(); + self._resizeHeader(); + } + }); + } + } +}); +BI.shortcut('bi.responsive_table', BI.ResponisveTable);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.SelectTreeFirstPlusGroupNode diff --git a/demo/js/config/widget.js b/demo/js/config/widget.js index b8051a4813..bb559fde40 100644 --- a/demo/js/config/widget.js +++ b/demo/js/config/widget.js @@ -1,6 +1,18 @@ Demo.WIDGET_CONFIG = [{ id: 4, text: "详细控件" +}, { + id: 401, + pId: 4, + text: "table" +}, { + pId: 401, + text: "bi.preview_table", + value: "demo.preview_table" +}, { + pId: 401, + text: "bi.responsive_table", + value: "demo.responsive_table" }, { pId: 4, text: "bi.multi_select_combo", diff --git a/demo/js/widget/table/demo.preview_table.js b/demo/js/widget/table/demo.preview_table.js new file mode 100644 index 0000000000..17113ff3c9 --- /dev/null +++ b/demo/js/widget/table/demo.preview_table.js @@ -0,0 +1,233 @@ +Demo.Func = BI.inherit(BI.Widget, { + props: { + baseCls: "demo-func" + }, + + render: function () { + var items = [[{ + text: "第一行第一列" + }, { + text: "第一行第二列" + }, { + text: "第一行第三列" + }], [{ + text: "第二行第一列" + }, { + text: "第二行第二列" + }, { + text: "第二行第三列" + }], [{ + text: "第二行第一列" + }, { + text: "第三行第二列" + }, { + text: "第三行第三列" + }], [{ + text: "第二行第一列" + }, { + text: "第四行第二列" + }, { + text: "第四行第三列" + }], [{ + text: "第五行第一列" + }, { + text: "第五行第二列" + }, { + text: "第五行第三列" + }], [{ + text: "第六行第一列" + }, { + text: "第六行第二列" + }, { + text: "第六行第三列" + }], [{ + text: "第七行第一列" + }, { + text: "第七行第二列" + }, { + text: "第七行第三列" + }], [{ + text: "第八行第一列" + }, { + text: "第八行第二列" + }, { + text: "第八行第三列" + }], [{ + text: "第九行第一列" + }, { + text: "第九行第二列" + }, { + text: "第九行第三列" + }], [{ + text: "第十行第一列" + }, { + text: "第十行第二列" + }, { + text: "第十行第三列" + }], [{ + text: "第十一行第一列" + }, { + text: "第十一行第二列" + }, { + text: "第十一行第三列" + }], [{ + text: "第十二行第一列" + }, { + text: "第十二行第二列" + }, { + text: "第十二行第三列" + }], [{ + text: "第十三行第一列" + }, { + text: "第十三行第二列" + }, { + text: "第十三行第三列" + }], [{ + text: "第十四行第一列" + }, { + text: "第十四行第二列" + }, { + text: "第十四行第三列" + }], [{ + text: "第十五行第一列" + }, { + text: "第十五行第二列" + }, { + text: "第十五行第三列" + }], [{ + text: "第十六行第一列" + }, { + text: "第十六行第二列" + }, { + text: "第十六行第三列" + }], [{ + text: "第十七行第一列" + }, { + text: "第十七行第二列" + }, { + text: "第十七行第三列" + }], [{ + text: "第十八行第一列" + }, { + text: "第十八行第二列" + }, { + text: "第十八行第三列" + }]]; + + var header = [[{ + text: "表头1" + }, { + text: "表头2" + }, { + text: "表头3" + }]]; + + var table1 = BI.createWidget({ + type: "bi.preview_table", + columnSize: ["", "", ""], + header: header, + items: items + }); + var table2 = BI.createWidget({ + type: "bi.preview_table", + header: header, + columnSize: [100, "", 50], + items: items + }); + var table3 = BI.createWidget({ + type: "bi.preview_table", + header: header, + columnSize: [0.2, 0.4, 0.4], + headerRowSize: 30, + items: items + }); + var table4 = BI.createWidget({ + type: "bi.preview_table", + header: header, + isNeedFreeze: true, + freezeCols: [0, 1], + columnSize: [0.2, "", 0.4], + items: items + }); + var table5 = BI.createWidget({ + type: "bi.preview_table", + header: header, + isNeedFreeze: true, + freezeCols: [0, 1], + columnSize: [200, 100, ""], + items: items + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: { + type: "bi.grid", + columns: 3, + rows: 2, + items: [[{ + el: { + type: "bi.absolute", + items: [{ + el: table1, + left: 5, + right: 5, + top: 5, + bottom: 5 + }] + } + }, { + el: { + type: "bi.absolute", + items: [{ + el: table2, + left: 5, + right: 5, + top: 5, + bottom: 5 + }] + } + }, { + el: { + type: "bi.absolute", + items: [{ + el: table3, + left: 5, + right: 5, + top: 5, + bottom: 5 + }] + } + }], [{ + el: { + type: "bi.absolute", + items: [{ + el: table4, + left: 5, + right: 5, + top: 5, + bottom: 5 + }] + } + }, { + el: { + type: "bi.absolute", + items: [{ + el: table5, + left: 5, + right: 5, + top: 5, + bottom: 5 + }] + } + }]] + }, + left: 10, + right: 10, + top: 10, + bottom: 10 + }] + }) + } +}); +BI.shortcut("demo.preview_table", Demo.Func); \ No newline at end of file diff --git a/demo/js/widget/table/demo.responsive_table.js b/demo/js/widget/table/demo.responsive_table.js new file mode 100644 index 0000000000..018a3092e9 --- /dev/null +++ b/demo/js/widget/table/demo.responsive_table.js @@ -0,0 +1,158 @@ +Demo.Func = BI.inherit(BI.Widget, { + props: { + baseCls: "demo-func" + }, + + render: function () { + var items = [[{ + text: "第一行第一列" + }, { + text: "第一行第一列" + }, { + text: "第一行第一列" + }], [{ + text: "第一行第一列" + }, { + text: "第一行第一列" + }, { + text: "第一行第一列" + }], [{ + text: "第三行第一列" + }, { + text: "第三行第二列" + }, { + text: "第三行第三列" + }], [{ + text: "第四行第一列" + }, { + text: "第四行第二列" + }, { + text: "第四行第三列" + }], [{ + text: "第五行第一列" + }, { + text: "第五行第二列" + }, { + text: "第五行第三列" + }], [{ + text: "第六行第一列" + }, { + text: "第六行第二列" + }, { + text: "第六行第三列" + }], [{ + text: "第七行第一列" + }, { + text: "第七行第二列" + }, { + text: "第七行第三列" + }], [{ + text: "第八行第一列" + }, { + text: "第八行第二列" + }, { + text: "第八行第三列" + }], [{ + text: "第九行第一列" + }, { + text: "第九行第二列" + }, { + text: "第九行第三列" + }], [{ + text: "第十行第一列" + }, { + text: "第十行第二列" + }, { + text: "第十行第三列" + }], [{ + text: "第十一行第一列" + }, { + text: "第十一行第二列" + }, { + text: "第十一行第三列" + }], [{ + text: "第十二行第一列" + }, { + text: "第十二行第二列" + }, { + text: "第十二行第三列" + }], [{ + text: "第十三行第一列" + }, { + text: "第十三行第二列" + }, { + text: "第十三行第三列" + }], [{ + text: "第十四行第一列" + }, { + text: "第十四行第二列" + }, { + text: "第十四行第三列" + }], [{ + text: "第十五行第一列" + }, { + text: "第十五行第二列" + }, { + text: "第十五行第三列" + }], [{ + text: "第十六行第一列" + }, { + text: "第十六行第二列" + }, { + text: "第十六行第三列" + }], [{ + text: "第十七行第一列" + }, { + text: "第十七行第二列" + }, { + text: "第十七行第三列" + }], [{ + text: "第十八行第一列" + }, { + text: "第十八行第二列" + }, { + text: "第十八行第三列" + }]]; + + + var header = [[{ + text: "表头1" + }, { + text: "表头2" + }, { + text: "表头3" + }]]; + + + var table1 = BI.createWidget({ + type: "bi.responsive_table", + isNeedMerge: true, + isNeedFreeze: true, + mergeCols: [0, 1], + columnSize: ["", "", ""], + items: items, + header: header + }); + BI.createWidget({ + type: "bi.absolute", + element: this, + items: [{ + el: { + type: "bi.grid", + columns: 2, + rows: 2, + items: [{ + column: 0, + row: 0, + el: table1 + }] + }, + left: 10, + right: 10, + top: 10, + bottom: 10 + }] + }) + } +}); +BI.shortcut("demo.responsive_table", Demo.Func); \ No newline at end of file diff --git a/dist/base.js b/dist/base.js index b85a2d5a99..2d39187d1d 100644 --- a/dist/base.js +++ b/dist/base.js @@ -1078,10 +1078,9 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { //如果是一个简单的layout _isSimpleLayout: function () { var o = this.options; - return o.layouts.length === 1 + return o.layouts.length === 1 && !BI.isArray(o.items[0]) }, - doBehavior: function () { var args = Array.prototype.slice.call(arguments); args.unshift(this.buttons); @@ -30424,11 +30423,9 @@ BI.Table = BI.inherit(BI.Widget, { self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT); } }); - BI.Resizers.add(this.getName(), function (e) { - if (BI.isWindow(e.target) && self.element.is(":visible")) { - self._resize(); - self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); - } + BI.ResizeDetector.addResizeListener(this, function () { + self._resize(); + self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); }); }, @@ -30810,6 +30807,7 @@ BI.Table = BI.inherit(BI.Widget, { .addClass(c === rows.length - 1 ? "last-col" : ""); var w = BI.createWidget(map[r][c], { type: "bi.table_cell", + root: true, textAlign: "left", width: BI.isNumeric(width) ? width : "", height: BI.isNumeric(height) ? height : "", @@ -30889,6 +30887,7 @@ BI.Table = BI.inherit(BI.Widget, { return this.footer; }, + _createBody: function () { var self = this, o = this.options; this.body = this._body(); diff --git a/dist/core.css b/dist/core.css index bf8c698a1f..c94ea5fe62 100644 --- a/dist/core.css +++ b/dist/core.css @@ -1,131 +1,3 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ -html, -body, -div, -span, -applet, -object, -iframe, -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote, -pre, -a, -abbr, -acronym, -address, -big, -cite, -code, -del, -dfn, -em, -img, -ins, -kbd, -q, -s, -samp, -small, -strike, -strong, -sub, -sup, -tt, -var, -b, -u, -i, -center, -dl, -dt, -dd, -ol, -ul, -li, -fieldset, -form, -label, -legend, -table, -caption, -tbody, -tfoot, -thead, -tr, -th, -td, -article, -aside, -canvas, -details, -embed, -figure, -figcaption, -footer, -header, -hgroup, -menu, -nav, -output, -ruby, -section, -summary, -time, -mark, -audio, -video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -menu, -nav, -section { - display: block; -} -body { - line-height: 1; -} -ol, -ul { - list-style: none; -} -blockquote, -q { - quotes: none; -} -blockquote:before, -blockquote:after, -q:before, -q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} @charset "UTF-8"; /*! * animate.css -http://daneden.me/animate diff --git a/dist/core.js b/dist/core.js index ceb4a35c63..18bd9eefae 100644 --- a/dist/core.js +++ b/dist/core.js @@ -11065,9 +11065,9 @@ BI.Factory = { // } return view; } -};(function(root, factory) { - root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); -}(this, function(root, BI, _, $) { +};(function (root, factory) { + root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); +}(this, function (root, BI, _, $) { var previousBI = root.BI; @@ -11084,7 +11084,7 @@ BI.Factory = { // Runs BI.js in *noConflict* mode, returning the `BI` variable // to its previous owner. Returns a reference to this BI object. - BI.noConflict = function() { + BI.noConflict = function () { root.BI = previousBI; return this; }; @@ -11117,7 +11117,7 @@ BI.Factory = { // Bind an event to a `callback` function. Passing `"all"` will bind // the callback to all events fired. - on: function(name, callback, context) { + 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] = []); @@ -11127,10 +11127,10 @@ BI.Factory = { // 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) { + once: function (name, callback, context) { if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; - var once = _.once(function() { + var once = _.once(function () { self.off(name, once); callback.apply(this, arguments); }); @@ -11142,7 +11142,7 @@ BI.Factory = { // 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) { + off: function (name, callback, context) { if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; // Remove all callbacks for all events. @@ -11173,7 +11173,7 @@ BI.Factory = { callback && callback !== event.callback && callback !== event.callback._callback || context && context !== event.context - ) { + ) { remaining.push(event); } } @@ -11189,11 +11189,15 @@ BI.Factory = { 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) { + trigger: function (name) { if (!this._events) return this; var args = slice.call(arguments, 1); if (!eventsApi(this, 'trigger', name, args)) return this; @@ -11204,10 +11208,14 @@ BI.Factory = { 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) { + listenTo: function (obj, name, callback) { var listeningTo = this._listeningTo || (this._listeningTo = {}); var id = obj._listenId || (obj._listenId = _.uniqueId('l')); listeningTo[id] = obj; @@ -11216,7 +11224,7 @@ BI.Factory = { return this; }, - listenToOnce: function(obj, name, callback) { + listenToOnce: function (obj, name, callback) { if (typeof name === 'object') { for (var event in name) this.listenToOnce(obj, event, name[event]); return this; @@ -11229,7 +11237,7 @@ BI.Factory = { return this; } if (!callback) return this; - var once = _.once(function() { + var once = _.once(function () { this.stopListening(obj, name, once); callback.apply(this, arguments); }); @@ -11239,7 +11247,7 @@ BI.Factory = { // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. - stopListening: function(obj, name, callback) { + stopListening: function (obj, name, callback) { var listeningTo = this._listeningTo; if (!listeningTo) return this; var remove = !name && !callback; @@ -11261,7 +11269,7 @@ BI.Factory = { // 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) { + var eventsApi = function (obj, action, name, rest) { if (!name) return true; // Handle event maps. @@ -11287,19 +11295,29 @@ BI.Factory = { // 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 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; + 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.bind = Events.on; Events.unbind = Events.off; // Allow the `BI` object to serve as a global event bus, for folks who @@ -11316,7 +11334,7 @@ BI.Factory = { // 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 M = BI.M = function (attributes, options) { var attrs = attributes || {}; options = options || {}; this.cid = _.uniqueId('c'); @@ -11345,40 +11363,47 @@ BI.Factory = { // CouchDB users may want to set this to `"_id"`. idAttribute: 'ID', - _defaultConfig: function(){return {}}, + _defaultConfig: function () { + return {} + }, + + init: function () { + }, // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _init: function () { + this.init(); + }, // Return a copy of the model's `attributes` object. - toJSON: function(options) { + 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() { + sync: function () { return BI.sync.apply(this, arguments); }, // Get the value of an attribute. - get: function(attr) { + get: function (attr) { return this.attributes[attr]; }, // Get the HTML-escaped value of an attribute. - escape: function(attr) { + 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) { + has: function (attr) { return _.has(this.attributes, attr); }, // Special-cased proxy to underscore's `_.matches` method. - matches: function(attrs) { + matches: function (attrs) { var keys = _.keys(attrs), length = keys.length; var obj = Object(this.attributes); for (var i = 0; i < length; i++) { @@ -11391,7 +11416,7 @@ BI.Factory = { // 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) { + set: function (key, val, options) { var attr, attrs, unset, changes, silent, changing, changed, prev, current; if (key == null) return this; @@ -11409,11 +11434,11 @@ BI.Factory = { if (!this._validate(attrs, options)) return false; // Extract attributes and options. - unset = options.unset; - silent = options.silent; - changes = []; - changing = this._changing; - this._changing = true; + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; if (!changing) { this._previousAttributes = _.clone(this.attributes); @@ -11463,12 +11488,12 @@ BI.Factory = { // Remove an attribute from the model, firing `"change"`. `unset` is a noop // if the attribute doesn't exist. - unset: function(attr, options) { + 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) { + clear: function (options) { var attrs = {}; for (var key in this.attributes) attrs[key] = void 0; return this.set(attrs, _.extend({}, options, {unset: true})); @@ -11476,7 +11501,7 @@ BI.Factory = { // 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) { + hasChanged: function (attr) { if (attr == null) return !_.isEmpty(this.changed); return _.has(this.changed, attr); }, @@ -11487,7 +11512,7 @@ BI.Factory = { // 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) { + changedAttributes: function (diff) { if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; var val, changed = false; var old = this._changing ? this._previousAttributes : this.attributes; @@ -11500,27 +11525,27 @@ BI.Factory = { // Get the previous value of an attribute, recorded at the time the last // `"change"` event was fired. - previous: function(attr) { + 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() { + 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) { + 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) { + options.success = function (resp) { + if (!options.noset) { if (!model.set(model.parse(resp, options), options)) return false; } if (success) success(resp, model, options); @@ -11533,7 +11558,7 @@ BI.Factory = { // 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) { + save: function (key, val, options) { var attrs, method, xhr, attributes = this.attributes; // Handle both `"key", value` and `{key: value}` -style arguments. @@ -11565,7 +11590,7 @@ BI.Factory = { if (options.parse === void 0) options.parse = true; var model = this; var success = options.success; - options.success = function(resp) { + options.success = function (resp) { // Ensure attributes are restored during synchronous saves. model.attributes = attributes; var serverAttrs = model.parse(resp, options); @@ -11592,17 +11617,17 @@ BI.Factory = { // 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) { + destroy: function (options) { options = options ? _.clone(options) : {}; var model = this; var success = options.success; - var destroy = function() { + var destroy = function () { model.stopListening(); model.trigger('destroy', model.collection, model, options); }; - options.success = function(resp) { + 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); @@ -11622,7 +11647,7 @@ BI.Factory = { // 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() { + url: function () { var base = _.result(this.collection, 'url'); if (this.isNew()) return base; @@ -11631,28 +11656,28 @@ BI.Factory = { // **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) { + parse: function (resp, options) { return resp; }, // Create a new model with identical attributes to this one. - clone: function() { + 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() { + 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 })); + 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) { + _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; @@ -11667,9 +11692,9 @@ BI.Factory = { 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) { + _.each(modelMethods, function (method) { if (!_[method]) return; - M.prototype[method] = function() { + M.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.attributes); return _[method].apply(_, args); @@ -11689,7 +11714,7 @@ BI.Factory = { // 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) { + 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; @@ -11711,26 +11736,29 @@ BI.Factory = { // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _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); }); + toJSON: function (options) { + return this.map(function (model) { + return model.toJSON(options); + }); }, // Proxy `BI.sync` by default. - sync: function() { + sync: function () { return BI.sync.apply(this, arguments); }, // Add a model, or list of models to the set. - add: function(models, options) { + 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) { + remove: function (models, options) { var singular = !_.isArray(models); models = singular ? [models] : _.clone(models); options || (options = {}); @@ -11756,7 +11784,7 @@ BI.Factory = { // 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) { + set: function (models, options) { options = _.defaults({}, options, setOptions); if (options.parse) models = this.parse(models, options); var singular = !_.isArray(models); @@ -11857,7 +11885,7 @@ BI.Factory = { // 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) { + 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); @@ -11870,66 +11898,66 @@ BI.Factory = { }, // Add a model to the end of the collection. - push: function(model, options) { + 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) { + 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) { + unshift: function (model, options) { return this.add(model, _.extend({at: 0}, options)); }, // Remove a model from the beginning of the collection. - shift: function(options) { + 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() { + slice: function () { return slice.apply(this.models, arguments); }, // Get a model from the set by id. - get: function(obj) { + 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) { + 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) { + where: function (attrs, first) { var matches = _.matches(attrs); - return this[first ? 'find' : 'filter'](function(model) { + 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) { + 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) { + sort: function (options) { if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); options || (options = {}); @@ -11945,19 +11973,19 @@ BI.Factory = { }, // Pluck an attribute from each model in the collection. - pluck: function(attr) { + 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) { + 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) { + options.success = function (resp) { var method = options.reset ? 'reset' : 'set'; collection[method](resp, options); if (success) success(collection, resp, options); @@ -11970,13 +11998,13 @@ BI.Factory = { // 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) { + 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) { + options.success = function (model, resp) { if (options.wait) collection.add(model, options); if (success) success(model, resp, options); }; @@ -11986,12 +12014,12 @@ BI.Factory = { // **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) { + parse: function (resp, options) { return resp; }, // Create a new collection with an identical list of models as this one. - clone: function() { + clone: function () { return new this.constructor(this.models, { model: this.model, comparator: this.comparator @@ -12005,15 +12033,15 @@ BI.Factory = { // Private method to reset all internal state. Called when the collection // is first _initd or reset. - _reset: function() { + _reset: function () { this.length = 0; this.models = []; - this._byId = {}; + this._byId = {}; }, // Prepare a hash of attributes (or other model) to be added to this // collection. - _prepareModel: function(attrs, options) { + _prepareModel: function (attrs, options) { if (this._isModel(attrs)) { if (!attrs.collection) attrs.collection = this; return attrs; @@ -12033,7 +12061,7 @@ BI.Factory = { }, // Internal method to create a model's ties to a collection. - _addReference: function(model, options) { + _addReference: function (model, options) { this._byId[model.cid] = model; var id = this.modelId(model.attributes); if (id != null) this._byId[id] = model; @@ -12041,7 +12069,7 @@ BI.Factory = { }, // Internal method to sever a model's ties to a collection. - _removeReference: function(model, options) { + _removeReference: function (model, options) { if (this === model.collection) delete model.collection; model.off('all', this._onModelEvent, this); }, @@ -12050,7 +12078,7 @@ BI.Factory = { // 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) { + _onModelEvent: function (event, model, collection, options) { if ((event === 'add' || event === 'remove') && collection !== this) return; if (event === 'destroy') this.remove(model, options); if (event === 'change') { @@ -12077,9 +12105,9 @@ BI.Factory = { 'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition']; // Mix in each Underscore method as a proxy to `Collection#models`. - _.each(methods, function(method) { + _.each(methods, function (method) { if (!_[method]) return; - Collection.prototype[method] = function() { + Collection.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.models); return _[method].apply(_, args); @@ -12090,10 +12118,10 @@ BI.Factory = { var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; // Use attributes instead of properties. - _.each(attributeMethods, function(method) { + _.each(attributeMethods, function (method) { if (!_[method]) return; - Collection.prototype[method] = function(value, context) { - var iterator = _.isFunction(value) ? value : function(model) { + Collection.prototype[method] = function (value, context) { + var iterator = _.isFunction(value) ? value : function (model) { return model.get(value); }; return _[method](this.models, iterator, context); @@ -12113,7 +12141,7 @@ BI.Factory = { // 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) { + var V = BI.V = function (options) { this.cid = _.uniqueId('view'); options = options || {}; this.options = _.defaults(options, _.result(this, '_defaultConfig')); @@ -12136,28 +12164,33 @@ BI.Factory = { // jQuery delegate for element lookup, scoped to DOM elements within the // current view. This should be preferred to global lookups where possible. - $: function(selector) { + $: function (selector) { return this.$el.find(selector); }, - _defaultConfig: function(){return {}}, + _defaultConfig: function () { + return {} + }, // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _init: function () { + }, //容器,默认放在this.element上 - _vessel: function(){return 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) { + 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() { + remove: function () { this._removeElement(); this.stopListening(); return this; @@ -12166,7 +12199,7 @@ BI.Factory = { // 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() { + _removeElement: function () { this.$el.remove(); if ($.browser.msie === true) { this.el.outerHTML = ''; @@ -12175,33 +12208,33 @@ BI.Factory = { // Change the view's element (`this.el` property) and re-delegate the // view's events on the new element. - setElement: function(element) { + setElement: function (element) { this.undelegateEvents(); this._setElement(element); - this.$vessel = this._vessel(); - this._render(this.$vessel); + this.vessel = this._vessel(); + this.render(this.vessel); this.delegateEvents(); return this; }, - setVisible: function(visible){ + setVisible: function (visible) { this.options.invisible = !visible; - if (visible){ + if (visible) { this.element.show(); } else { this.element.hide(); } }, - isVisible: function(){ + isVisible: function () { return !this.options.invisible; }, - visible: function(){ + visible: function () { this.setVisible(true); }, - invisible: function(){ + invisible: function () { this.setVisible(false); }, @@ -12210,7 +12243,7 @@ BI.Factory = { // 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) { + _setElement: function (el) { this.$el = el instanceof BI.$ ? el : BI.$(el); this.element = this.$el; this.el = this.$el[0]; @@ -12229,7 +12262,7 @@ BI.Factory = { // 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) { + delegateEvents: function (events) { if (!(events || (events = _.result(this, 'events')))) return this; this.undelegateEvents(); for (var key in events) { @@ -12245,27 +12278,27 @@ BI.Factory = { // 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.on(eventName + '.delegateEvents' + this.cid, selector, listener); + 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.off('.delegateEvents' + this.cid); + 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.off(eventName + '.delegateEvents' + this.cid, selector, listener); + 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) { + _createElement: function (tagName) { return document.createElement(tagName); }, @@ -12273,7 +12306,7 @@ BI.Factory = { // 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() { + _ensureElement: function () { var attrs = _.extend({}, _.result(this, 'attributes')); if (this.baseCls) attrs['class'] = _.result(this, 'baseCls'); if (!this.element) { @@ -12286,7 +12319,7 @@ BI.Factory = { // Set attributes from a hash on this view's element. Exposed for // subclasses using an alternative DOM manipulation API. - _setAttributes: function(attributes) { + _setAttributes: function (attributes) { this.$el.attr(attributes); } @@ -12310,7 +12343,7 @@ BI.Factory = { // 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) { + BI.sync = function (method, model, options) { var type = methodMap[method]; // Default options, unless specified. @@ -12324,8 +12357,8 @@ BI.Factory = { // Ensure that we have a URL. if (!options.url) { - params.url = _.result(model, method+"URL") || _.result(model, 'url'); - if(!params.url){ + params.url = _.result(model, method + "URL") || _.result(model, 'url'); + if (!params.url) { return; } } @@ -12348,7 +12381,7 @@ BI.Factory = { params.type = 'POST'; if (options.emulateJSON) params.data._method = type; var beforeSend = options.beforeSend; - options.beforeSend = function(xhr) { + options.beforeSend = function (xhr) { xhr.setRequestHeader('X-HTTP-Method-Override', type); if (beforeSend) return beforeSend.apply(this, arguments); }; @@ -12361,7 +12394,7 @@ BI.Factory = { // Pass along `textStatus` and `errorThrown` from jQuery. var error = options.error; - options.error = function(xhr, textStatus, errorThrown) { + options.error = function (xhr, textStatus, errorThrown) { options.textStatus = textStatus; options.errorThrown = errorThrown; if (error) error.apply(this, arguments); @@ -12377,9 +12410,9 @@ BI.Factory = { var methodMap = { 'create': 'POST', 'update': 'PUT', - 'patch': 'PATCH', + 'patch': 'PATCH', 'delete': 'DELETE', - 'read': 'GET' + 'read': 'GET' }; // Set the default implementation of `BI.ajax` to proxy through to `$`. @@ -12391,7 +12424,7 @@ BI.Factory = { // 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) { + var Router = BI.Router = function (options) { options || (options = {}); if (options.routes) this.routes = options.routes; this._bindRoutes(); @@ -12401,16 +12434,17 @@ BI.Factory = { // 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; + 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(){}, + _init: function () { + }, // Manually bind a single named route to a callback. For example: // @@ -12418,7 +12452,7 @@ BI.Factory = { // ... // }); // - route: function(route, name, callback) { + route: function (route, name, callback) { if (!_.isRegExp(route)) route = this._routeToRegExp(route); if (_.isFunction(name)) { callback = name; @@ -12426,7 +12460,7 @@ BI.Factory = { } if (!callback) callback = this[name]; var router = this; - BI.history.route(route, function(fragment) { + 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)); @@ -12439,12 +12473,12 @@ BI.Factory = { // 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) { + 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) { + navigate: function (fragment, options) { BI.history.navigate(fragment, options); return this; }, @@ -12452,7 +12486,7 @@ BI.Factory = { // 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() { + _bindRoutes: function () { if (!this.routes) return; this.routes = _.result(this, 'routes'); var route, routes = _.keys(this.routes); @@ -12463,10 +12497,10 @@ BI.Factory = { // Convert a route string into a regular expression, suitable for matching // against the current location hash. - _routeToRegExp: function(route) { + _routeToRegExp: function (route) { route = route.replace(escapeRegExp, '\\$&') .replace(optionalParam, '(?:$1)?') - .replace(namedParam, function(match, optional) { + .replace(namedParam, function (match, optional) { return optional ? match : '([^/?]+)'; }) .replace(splatParam, '([^?]*?)'); @@ -12476,9 +12510,9 @@ BI.Factory = { // 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) { + _extractParameters: function (route, fragment) { var params = route.exec(fragment).slice(1); - return _.map(params, function(param, i) { + 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; @@ -12495,7 +12529,7 @@ BI.Factory = { // [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() { + var History = BI.History = function () { this.handlers = []; _.bindAll(this, 'checkUrl'); @@ -12526,27 +12560,27 @@ BI.Factory = { interval: 50, // Are we at the app root? - atRoot: function() { + 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() { + 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) { + 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() { + 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); @@ -12554,7 +12588,7 @@ BI.Factory = { }, // Get the cross-browser normalized URL fragment from the path or hash. - getFragment: function(fragment) { + getFragment: function (fragment) { if (fragment == null) { if (this._hasPushState || !this._wantsHashChange) { fragment = this.getPath(); @@ -12567,19 +12601,19 @@ BI.Factory = { // Start the hash change handling, returning `true` if the current URL matches // an existing route, and `false` otherwise. - start: function(options) { + 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.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(); + 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, '/'); @@ -12621,8 +12655,8 @@ BI.Factory = { // Add a cross-platform `addEventListener` shim for older browsers. var addEventListener = window.addEventListener || function (eventName, listener) { - return attachEvent('on' + 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. @@ -12639,11 +12673,11 @@ BI.Factory = { // Disable BI.history, perhaps temporarily. Not useful in a real app, // but possibly useful for unit testing Routers. - stop: function() { + stop: function () { // Add a cross-platform `removeEventListener` shim for older browsers. var removeEventListener = window.removeEventListener || function (eventName, listener) { - return detachEvent('on' + eventName, listener); - }; + return detachEvent('on' + eventName, listener); + }; // Remove window listeners. if (this._hasPushState) { @@ -12665,13 +12699,13 @@ BI.Factory = { // Add a route to be tested when the fragment changes. Routes added later // may override previous routes. - route: function(route, callback) { + 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) { + checkUrl: function (e) { var current = this.getFragment(); // If the user pressed the back button, the iframe's hash will have @@ -12688,9 +12722,9 @@ BI.Factory = { // 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) { + loadUrl: function (fragment) { fragment = this.fragment = this.getFragment(fragment); - return _.any(this.handlers, function(handler) { + return _.any(this.handlers, function (handler) { if (handler.route.test(fragment)) { handler.callback(fragment); return true; @@ -12705,7 +12739,7 @@ BI.Factory = { // 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) { + navigate: function (fragment, options) { if (!History.started) return false; if (!options || options === true) options = {trigger: !!options}; @@ -12751,7 +12785,7 @@ BI.Factory = { // Update the hash location, either replacing the current entry, or adding // a new one to the browser history. - _updateHash: function(location, fragment, replace) { + _updateHash: function (location, fragment, replace) { if (replace) { var href = location.href.replace(/(javascript:|#).*$/, ''); location.replace(href + '#' + fragment); @@ -12772,7 +12806,7 @@ BI.Factory = { // 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 extend = function (protoProps, staticProps) { var parent = this; var child; @@ -12782,7 +12816,9 @@ BI.Factory = { if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { - child = function(){ return parent.apply(this, arguments); }; + child = function () { + return parent.apply(this, arguments); + }; } // Add static properties to the constructor function, if supplied. @@ -12790,7 +12826,9 @@ BI.Factory = { // Set the prototype chain to inherit from `parent`, without calling // `parent`'s constructor function. - var Surrogate = function(){ this.constructor = child; }; + var Surrogate = function () { + this.constructor = child; + }; Surrogate.prototype = parent.prototype; child.prototype = new Surrogate; @@ -12809,14 +12847,14 @@ BI.Factory = { 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() { + 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 wrapError = function (model, options) { var error = options.error; - options.error = function(resp) { + options.error = function (resp) { if (error) error(model, resp, options); model.trigger('error', model, resp, options); }; @@ -14175,8 +14213,7 @@ BI.OB = function (config) { }; $.extend(BI.OB.prototype, { props: {}, - init: function () { - }, + init: null, _defaultConfig: function (config) { return {}; @@ -14184,7 +14221,7 @@ $.extend(BI.OB.prototype, { _init: function () { this._initListeners(); - this.init(); + this.init && this.init(); }, _initListeners: function () { @@ -14307,6 +14344,7 @@ $.extend(BI.OB.prototype, { 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, @@ -14322,41 +14360,30 @@ BI.Widget = BI.inherit(BI.OB, { }, //生命周期函数 - beforeCreate: function () { + beforeCreate: null, - }, + created: null, - created: function () { + render: null, - }, - - render: function () { - - }, - - beforeMounted: function () { - - }, - - mounted: function () { + beforeMounted: null, - }, + mounted: null, update: null, - destroyed: function () { - }, + destroyed: null, _init: function () { BI.Widget.superclass._init.apply(this, arguments); - this.beforeCreate(); + this.beforeCreate && this.beforeCreate(); this._initRoot(); this._initElementWidth(); this._initElementHeight(); this._initVisualEffects(); this._initState(); this._initElement(); - this.created(); + this.created && this.created(); }, /** @@ -14366,6 +14393,7 @@ BI.Widget = BI.inherit(BI.OB, { _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; @@ -14429,7 +14457,7 @@ BI.Widget = BI.inherit(BI.OB, { _initElement: function () { var self = this; - var els = this.render(); + var els = this.render && this.render(); if (BI.isPlainObject(els)) { els = [els]; } @@ -14463,13 +14491,13 @@ BI.Widget = BI.inherit(BI.OB, { if (!isMounted) { return; } - this.beforeMounted(); + this.beforeMounted && this.beforeMounted(); this._isMounted = true; this._mountChildren(); BI.each(this._children, function (i, widget) { widget._mount && widget._mount(); }); - this.mounted(); + this.mounted && this.mounted(); }, _mountChildren: function () { @@ -14495,7 +14523,7 @@ BI.Widget = BI.inherit(BI.OB, { this._parent = null; this._isMounted = false; this.purgeListeners(); - this.destroyed(); + this.destroyed && this.destroyed(); }, setWidth: function (w) { @@ -14557,6 +14585,9 @@ BI.Widget = BI.inherit(BI.OB, { 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"); @@ -14682,7 +14713,7 @@ BI.Widget = BI.inherit(BI.OB, { empty: function () { BI.each(this._children, function (i, widget) { - widget._unMount(); + widget._unMount && widget._unMount(); }); this._children = {}; this.element.empty(); @@ -14695,7 +14726,7 @@ BI.Widget = BI.inherit(BI.OB, { this._children = {}; this._parent = null; this._isMounted = false; - this.destroyed(); + this.destroyed && this.destroyed(); this.element.destroy(); this.fireEvent(BI.Events.DESTROY); this.purgeListeners(); @@ -15291,10 +15322,10 @@ BI.View = BI.inherit(BI.V, { }); var vessel = BI.createWidget(); this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel); - return vessel.element; + return vessel; }, - _render: function (vessel) { + render: function (vessel) { return this; }, @@ -15662,15 +15693,26 @@ BI.View = BI.inherit(BI.V, { }, + _unMount: function () { + BI.each(this._cardLayouts, function (name, card) { + card && card._unMount(); + }); + delete this._cardLayouts; + delete this._cards; + this.off(); + this.destroyed(); + }, + destroy: function () { BI.each(this._cardLayouts, function (name, card) { - card && card.destroy(); + card && card._unMount(); }); delete this._cardLayouts; delete this._cards; + this.destroyed(); this.remove(); this.trigger(BI.Events.DESTROY); - this.destroyed(); + this.off(); }, destroyed: function () { @@ -19651,9 +19693,8 @@ BI.Layout = BI.inherit(BI.Widget, { removeIndex = nameOrWidget; } if (removeIndex) { - this.options.items.splice(removeIndex, 1); + this._removeItemAt(removeIndex | 0); } - BI.Layout.superclass.removeWidget.apply(this, arguments); }, empty: function () { @@ -19809,597 +19850,606 @@ BI.PopoverSection = BI.inherit(BI.Widget, { } }); -BI.PopoverSection.EVENT_CLOSE = "EVENT_CLOSE";BI.cjkEncode = function (text) { - // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) - if (typeof text !== 'string') { - return text; +BI.PopoverSection.EVENT_CLOSE = "EVENT_CLOSE";;(function () { + function isEmpty(value) { + // 判断是否为空值 + var result = value === "" || value === null || value === undefined; + return result; } - 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); + BI.cjkEncode = function (text) { + // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) + if (typeof text !== 'string') { + return text; } - } - 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); + 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); } - //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', - '"': '\\"', - "\\": '\\\\' + return newText }; - 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); - }) + '"'; + 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 '"' + s + '"'; + return o; }; - 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; + 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); + }) + '"'; } - } - a.push("]"); - return a.join(""); - }; + return '"' + s + '"'; + }; - 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)) { + 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(BI.jsonEncode(i), ":", - v === null ? "null" : BI.jsonEncode(v)); + a.push(v === null ? "null" : BI.jsonEncode(v)); b = true; } } - } - a.push("}"); - return a.join(""); - } -}; + a.push("]"); + return a.join(""); + }; -BI.contentFormat = function (cv, fmt) { - if (BI.isEmpty(cv)) { - //原值为空,返回空字符 - return ''; - } - var text = cv.toString(); - if (BI.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 (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(""); } - if (!BI.isNull(cv)) { - var needTrim = fmt.match(/^DT/); - text = BI.date2Str(cv, fmt.substring(needTrim ? 2 : 1)); - } - } else if (fmt.match(/E/)) { - //科学计数格式 - text = BI._eFormat(text, fmt); - } else { - //数字格式 - text = BI._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} - */ -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; + 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 = BI._eFormat(text, fmt); + } else { + //数字格式 + text = BI._numberFormat(text, fmt); } - result += compileJFmt({ - 'char': flagch, - 'str': str, - 'len': len - start - }, date); - } - return result; + //¤ - 货币格式 + text = text.replace(/¤/g, '¥'); + return text; + }; - 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'); + /** + * 把日期对象按照指定格式转化成字符串 + * + * @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} + */ + 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 = date.getSeconds(); + str += ch; } - break; - case 'a': - str = date.getHours() < 12 ? 'am' : 'pm'; - break; - case 'z': - str = date.getTimezone(); - break; - default: - str = jfmt.str; - break; + } + result += compileJFmt({ + 'char': flagch, + 'str': str, + 'len': len - start + }, date); } - return str; - } -}; + return result; -/** - * 数字格式 - */ -BI._numberFormat = function (text, format) { - var text = text + ''; - //数字格式,区分正负数 - var numMod = format.indexOf(';'); - if (numMod > -1) { - if (text >= 0) { - return BI._numberFormat(text + "", format.substring(0, numMod)); - } else { - return BI._numberFormat((-text) + "", format.substr(numMod + 1)); + 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; } - } - 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 = BI._dealWithRight(tright, fright); - if (right.leftPlus) { - //小数点后有进位 - tleft = parseInt(tleft) + 1 + ''; + }; - tleft = isNaN(tleft) ? '1' : tleft; - } - right = right.num; - var left = BI._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 - */ -BI._dealWithRight = function (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 (BI.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 (!BI.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 = BI.parseINT(num) + 1 + ''; - //进位到整数部分 - if (newnum.length > orilen) { - newnum = newnum.substr(1); + /** + * 数字格式 + */ + BI._numberFormat = function (text, format) { + var text = text + ''; + //数字格式,区分正负数 + var numMod = format.indexOf(';'); + if (numMod > -1) { + if (text >= 0) { + return BI._numberFormat(text + "", format.substring(0, numMod)); } else { - newnum = BI.leftPad(newnum, orilen, '0'); - result.leftPlus = false; + return BI._numberFormat((-text) + "", format.substr(numMod + 1)); + } + } + 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 = BI._dealWithRight(tright, fright); + if (right.leftPlus) { + //小数点后有进位 + tleft = parseInt(tleft) + 1 + ''; + + tleft = isNaN(tleft) ? '1' : tleft; + } + right = right.num; + var left = BI._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 + */ + BI._dealWithRight = function (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; } - right = right.replace(/^[0-9]+/, newnum); } - } - result.num = right; - return result; -}; + 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 = BI.parseINT(num) + 1 + ''; + //进位到整数部分 + if (newnum.length > orilen) { + newnum = newnum.substr(1); + } else { + newnum = BI.leftPad(newnum, orilen, '0'); + result.leftPlus = false; + } + right = right.replace(/^[0-9]+/, newnum); + } + } + result.num = right; + return result; + }; -BI.parseINT = function (str) { - return parseInt(str, 10); -}; + BI.parseINT = function (str) { + return parseInt(str, 10); + }; -BI.leftPad = function (val, size, ch) { - var result = String(val); - if (!ch) { - ch = " "; - } - while (result.length < size) { - result = ch + result; - } - return result.toString(); -}; + BI.leftPad = function (val, size, ch) { + var result = String(val); + if (!ch) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result.toString(); + }; -/** - * 处理小数点左边整数部分 - * @param tleft 左边内容 - * @param fleft 左边格式 - * @returns {string} 返回处理结果 - * @private - */ -BI._dealWithLeft = function (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 (BI.isEmpty(c)) { - c = '0'; - } - last = -1; - left = c + left; - j--; - break; - case '#': - last = i; - left = c + left; - j--; - break; - case ',': - if (!BI.isEmpty(c)) { - //计算一个,分隔区间的长度 - var com = fleft.match(/,[#0]+/); - if (com) { - combo = com[0].length - 1; + /** + * 处理小数点左边整数部分 + * @param tleft 左边内容 + * @param fleft 左边格式 + * @returns {string} 返回处理结果 + * @private + */ + BI._dealWithLeft = function (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'; } - 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; + 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; } - var lres = res.substr(0, n + combo); - if (!BI.isEmpty(lres)) { - newstr = lres + ',' + newstr; + } + 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); } - left = left.replace(/[0-9]+,/, newstr); - } - return left; -}; + return left; + }; -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); + BI.object2Number = function (value) { + if (value == null) { + return 0; + } + if (typeof value == 'number') { + return value; } else { - return parseFloat(str); + 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 (!BI.isInvalidDate(dt)) { - return dt; + 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 (!BI.isInvalidDate(dt)) { + return dt; + } - return new Date(); - } -}; + return new Date(); + } + }; -BI.isArray = function (a) { - return Object.prototype.toString.call(a) == '[object Array]'; -}; + BI.isArray = function (a) { + return Object.prototype.toString.call(a) == '[object Array]'; + }; -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 (!BI.isInvalidDate(dt)) { - return dt; - } - if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { - dt = new Date("1970/01/01 " + str); + 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 (!BI.isInvalidDate(dt)) { return dt; } + if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { + dt = new Date("1970/01/01 " + str); + if (!BI.isInvalidDate(dt)) { + return dt; + } + } + dt = BI.str2Date(str, "HH:mm:ss"); + if (!BI.isInvalidDate(dt)) { + return dt; + } + return new Date(); } - dt = BI.str2Date(str, "HH:mm:ss"); - if (!BI.isInvalidDate(dt)) { - return dt; - } - return new Date(); - } -}; + }; // 判断是否是无效的日期 -BI.isInvalidDate = function (date) { - return date == "Invalid Date" || date == "NaN"; -}; + BI.isInvalidDate = function (date) { + return date == "Invalid Date" || date == "NaN"; + }; -/** - * 科学计数格式 - */ -BI._eFormat = function (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; + /** + * 科学计数格式 + */ + BI._eFormat = function (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'; + 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; } - } 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; -};/** + return text; + }; +})(); +/** * guy * * @class BI.HighlightBehavior @@ -25719,7 +25769,7 @@ BI.FloatCenterAdaptLayout = BI.inherit(BI.Layout, { element: this, items: [this.left] }); - this.removeWidget(this.container.getName()); + this.removeWidget(this.container); }, stroke: function (items) { @@ -25782,7 +25832,7 @@ BI.FloatHorizontalLayout = BI.inherit(BI.Layout, { element: this, items: [this.left] }); - this.removeWidget(this.container.getName()); + this.removeWidget(this.container); }, _addElement: function (i, item) { diff --git a/dist/widget.css b/dist/widget.css index 300750cb60..51d0750008 100644 --- a/dist/widget.css +++ b/dist/widget.css @@ -632,6 +632,14 @@ /****添加计算宽度的--运算符直接需要space****/ /****** common color(常用颜色,可用于普遍场景) *****/ /**** custom color(自定义颜色,用于特定场景) ****/ +.bi-responsive-table > div.bottom-left > div > div > table > * > * > td.last-col, +.bi-responsive-table > div.bottom-right > div > div > table > * > * > td.last-col, +.bi-responsive-table > div > div > table > * > * > td.last-col { + min-width: 80px; +} +/****添加计算宽度的--运算符直接需要space****/ +/****** common color(常用颜色,可用于普遍场景) *****/ +/**** custom color(自定义颜色,用于特定场景) ****/ .bi-sequence-table-dynamic-number .sequence-table-title-cell { overflow: hidden; overflow-x: hidden; diff --git a/dist/widget.js b/dist/widget.js index 42a46c18d7..fec31d1b5f 100644 --- a/dist/widget.js +++ b/dist/widget.js @@ -419,8 +419,10 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { if (o.isNeedResizeContainer) { var isResizing = false; + var needEnd = false; var height; var interval; + var startSize; var resize = function (e, ui) { if (isResizing) { return; @@ -442,20 +444,26 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { minHeight: 20, helper: "bi-resizer", autoHide: true, + start: function (e, ui) { + startSize = BI.clone(ui.size); + }, resize: function (e, ui) { - if (ui.size.height >= self.arrangement.container.element.height()) { + if (ui.size.height >= startSize.height - 10) { resize(e, ui); } else { interval && clearInterval(interval); + needEnd = true; } }, stop: function (e, ui) { var size = ui.size; - if (isResizing) { + if (isResizing && !needEnd) { size.height = height; } self.arrangement.setContainerSize(ui.size); + needEnd = false; isResizing = false; + startSize = null; interval && clearInterval(interval); self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE); } @@ -484,17 +492,21 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { 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 () { - if (!item.element.hasClass("selected")) { - item.element.css("zIndex", ++self.zIndex); - BI.each(self.getAllRegions(), function (i, region) { - region.el.element.removeClass("selected"); - }); - item.element.addClass("selected"); - } + self._setSelect(item) }); o.resizable && item.element.resizable({ handles: "e, s, se", @@ -663,6 +675,7 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { addRegion: function (region, position) { this._initResizable(region.el); + this._setSelect(region.el); var self = this, flag; var old = this.arrangement.getAllRegions(); if (BI.isNotNull(this.position)) { @@ -4892,6 +4905,9 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge 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); }); @@ -4907,7 +4923,7 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge if (BI.isNotEmptyString(value)) { var date = value.split("-"); self.store_value = { - type: BICst.MULTI_DATE_CALENDAR, + type: BI.DateTrigger.MULTI_DATE_CALENDAR, value:{ year: date[0] | 0, month: date[1] - 1, @@ -4975,7 +4991,7 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge var date = new Date(); this.store_value = v; if (BI.isNotNull(v)) { - type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value; + type = v.type || BI.DateTrigger.MULTI_DATE_CALENDAR; value = v.value; if(BI.isNull(value)){ value = v; } @@ -4987,88 +5003,88 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge self.setTitle(text + ":" + dateStr); }; switch (type) { - case BICst.MULTI_DATE_YEAR_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV]; + 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 BICst.MULTI_DATE_YEAR_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER]; + 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 BICst.MULTI_DATE_YEAR_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN]; + 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 BICst.MULTI_DATE_YEAR_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END]; + 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 BICst.MULTI_DATE_QUARTER_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV]; + 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 BICst.MULTI_DATE_QUARTER_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER]; + 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 BICst.MULTI_DATE_QUARTER_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN]; + 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 BICst.MULTI_DATE_QUARTER_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END]; + 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 BICst.MULTI_DATE_MONTH_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV]; + 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 BICst.MULTI_DATE_MONTH_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER]; + 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 BICst.MULTI_DATE_MONTH_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN]; + 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 BICst.MULTI_DATE_MONTH_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END]; + 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 BICst.MULTI_DATE_WEEK_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV]; + 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 BICst.MULTI_DATE_WEEK_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER]; + 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 BICst.MULTI_DATE_DAY_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV]; + 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 BICst.MULTI_DATE_DAY_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER]; + 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 BICst.MULTI_DATE_DAY_TODAY: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY]; + 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; @@ -5095,8 +5111,58 @@ BI.shortcut('bi.date_combo', BI.DateCombo);BI.DateTrigger = BI.inherit(BI.Trigge } }); + +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"; @@ -13801,11 +13867,6 @@ BI.PreviewTable = BI.inherit(BI.Widget, { populate: function (items, header) { this.table.populate(items, header); - }, - - destroy: function () { - this.table.destroy(); - BI.PreviewTable.superclass.destroy.apply(this, arguments); } }); BI.PreviewTable.EVENT_CHANGE = "PreviewTable.EVENT_CHANGE"; @@ -14691,6 +14752,368 @@ 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 () { + if (self.element.is(":visible")) { + self._initRegionSize(); + self.table.resize(); + self._resizeHeader(); + } + }); + } + } +}); +BI.shortcut('bi.responsive_table', BI.ResponisveTable);/** * 加号表示的组节点 * Created by GUY on 2015/9/6. * @class BI.SelectTreeFirstPlusGroupNode diff --git a/src/base/combination/group.button.js b/src/base/combination/group.button.js index 655960ab40..f680af2cc7 100644 --- a/src/base/combination/group.button.js +++ b/src/base/combination/group.button.js @@ -115,10 +115,9 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { //如果是一个简单的layout _isSimpleLayout: function () { var o = this.options; - return o.layouts.length === 1 + return o.layouts.length === 1 && !BI.isArray(o.items[0]) }, - doBehavior: function () { var args = Array.prototype.slice.call(arguments); args.unshift(this.buttons); diff --git a/src/base/table/table.js b/src/base/table/table.js index 1b95ff6de9..d37e894e63 100644 --- a/src/base/table/table.js +++ b/src/base/table/table.js @@ -359,11 +359,9 @@ BI.Table = BI.inherit(BI.Widget, { self.fireEvent(BI.Table.EVENT_TABLE_AFTER_INIT); } }); - BI.Resizers.add(this.getName(), function (e) { - if (BI.isWindow(e.target) && self.element.is(":visible")) { - self._resize(); - self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); - } + BI.ResizeDetector.addResizeListener(this, function () { + self._resize(); + self.fireEvent(BI.Table.EVENT_TABLE_RESIZE); }); }, @@ -745,6 +743,7 @@ BI.Table = BI.inherit(BI.Widget, { .addClass(c === rows.length - 1 ? "last-col" : ""); var w = BI.createWidget(map[r][c], { type: "bi.table_cell", + root: true, textAlign: "left", width: BI.isNumeric(width) ? width : "", height: BI.isNumeric(height) ? height : "", @@ -824,6 +823,7 @@ BI.Table = BI.inherit(BI.Widget, { return this.footer; }, + _createBody: function () { var self = this, o = this.options; this.body = this._body(); diff --git a/src/core/alias.js b/src/core/alias.js index 5ec5cd1c6f..b507b66f1f 100644 --- a/src/core/alias.js +++ b/src/core/alias.js @@ -1,591 +1,599 @@ -BI.cjkEncode = function (text) { - // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) - if (typeof text !== 'string') { - return text; +;(function () { + function isEmpty(value) { + // 判断是否为空值 + var result = value === "" || value === null || value === undefined; + return result; } - 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); + BI.cjkEncode = function (text) { + // alex:如果非字符串,返回其本身(cjkEncode(234) 返回 ""是不对的) + if (typeof text !== 'string') { + return text; } - } - - 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); + 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); } - //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', - '"': '\\"', - "\\": '\\\\' + return newText }; - 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); - }) + '"'; + 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 '"' + s + '"'; + return o; }; - 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; + 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); + }) + '"'; } - } - a.push("]"); - return a.join(""); - }; + return '"' + s + '"'; + }; - 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)) { + 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(BI.jsonEncode(i), ":", - v === null ? "null" : BI.jsonEncode(v)); + 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(""); } - a.push("}"); - return a.join(""); - } -}; + }; -BI.contentFormat = function (cv, fmt) { - if (BI.isEmpty(cv)) { - //原值为空,返回空字符 - return ''; - } - var text = cv.toString(); - if (BI.isEmpty(fmt)) { - //格式为空,返回原字符 - return text; - } - if (fmt.match(/^T/)) { - //T - 文本格式 + 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 = BI._eFormat(text, fmt); + } else { + //数字格式 + text = BI._numberFormat(text, fmt); + } + //¤ - 货币格式 + text = text.replace(/¤/g, '¥'); 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); + }; + + /** + * 把日期对象按照指定格式转化成字符串 + * + * @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} + */ + 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); } - if (!BI.isNull(cv)) { - var needTrim = fmt.match(/^DT/); - text = BI.date2Str(cv, fmt.substring(needTrim ? 2 : 1)); + 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; } - } else if (fmt.match(/E/)) { - //科学计数格式 - text = BI._eFormat(text, fmt); - } else { - //数字格式 - text = BI._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} - */ -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; + /** + * 数字格式 + */ + BI._numberFormat = function (text, format) { + var text = text + ''; + //数字格式,区分正负数 + var numMod = format.indexOf(';'); + if (numMod > -1) { + if (text >= 0) { + return BI._numberFormat(text + "", format.substring(0, numMod)); } else { - str += ch; + return BI._numberFormat((-text) + "", format.substr(numMod + 1)); } } - 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; + 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, ''); } - return str; - } -}; + var right = BI._dealWithRight(tright, fright); + if (right.leftPlus) { + //小数点后有进位 + tleft = parseInt(tleft) + 1 + ''; -/** - * 数字格式 - */ -BI._numberFormat = function (text, format) { - var text = text + ''; - //数字格式,区分正负数 - var numMod = format.indexOf(';'); - if (numMod > -1) { - if (text >= 0) { - return BI._numberFormat(text + "", format.substring(0, numMod)); + tleft = isNaN(tleft) ? '1' : tleft; + } + right = right.num; + var left = BI._dealWithLeft(tleft, fleft); + if (!(/[0-9]/.test(left))) { + left = left + '0'; + } + if (!(/[0-9]/.test(right))) { + return left + right; } else { - return BI._numberFormat((-text) + "", format.substr(numMod + 1)); + return left + '.' + right; } - } - 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 = BI._dealWithRight(tright, fright); - if (right.leftPlus) { - //小数点后有进位 - tleft = parseInt(tleft) + 1 + ''; - - tleft = isNaN(tleft) ? '1' : tleft; - } - right = right.num; - var left = BI._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 - */ -BI._dealWithRight = function (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 (BI.isEmpty(c)) { - c = '0'; - } - right += c; - j++; - break; - case '#': - right += c; - j++; - break; - default : - right += ch; - break; + }; + /** + * 处理小数点右边小数部分 + * @param tright 右边内容 + * @param fright 右边格式 + * @returns {JSON} 返回处理结果和整数部分是否需要进位 + * @private + */ + BI._dealWithRight = function (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 (!BI.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 = BI.parseINT(num) + 1 + ''; - //进位到整数部分 - if (newnum.length > orilen) { - newnum = newnum.substr(1); - } else { - newnum = BI.leftPad(newnum, orilen, '0'); - result.leftPlus = false; + 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 = BI.parseINT(num) + 1 + ''; + //进位到整数部分 + if (newnum.length > orilen) { + newnum = newnum.substr(1); + } else { + newnum = BI.leftPad(newnum, orilen, '0'); + result.leftPlus = false; + } + right = right.replace(/^[0-9]+/, newnum); } - right = right.replace(/^[0-9]+/, newnum); } - } - result.num = right; - return result; -}; + result.num = right; + return result; + }; -BI.parseINT = function (str) { - return parseInt(str, 10); -}; + BI.parseINT = function (str) { + return parseInt(str, 10); + }; -BI.leftPad = function (val, size, ch) { - var result = String(val); - if (!ch) { - ch = " "; - } - while (result.length < size) { - result = ch + result; - } - return result.toString(); -}; + BI.leftPad = function (val, size, ch) { + var result = String(val); + if (!ch) { + ch = " "; + } + while (result.length < size) { + result = ch + result; + } + return result.toString(); + }; -/** - * 处理小数点左边整数部分 - * @param tleft 左边内容 - * @param fleft 左边格式 - * @returns {string} 返回处理结果 - * @private - */ -BI._dealWithLeft = function (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 (BI.isEmpty(c)) { - c = '0'; - } - last = -1; - left = c + left; - j--; - break; - case '#': - last = i; - left = c + left; - j--; - break; - case ',': - if (!BI.isEmpty(c)) { - //计算一个,分隔区间的长度 - var com = fleft.match(/,[#0]+/); - if (com) { - combo = com[0].length - 1; + /** + * 处理小数点左边整数部分 + * @param tleft 左边内容 + * @param fleft 左边格式 + * @returns {string} 返回处理结果 + * @private + */ + BI._dealWithLeft = function (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'; } - 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; + 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; } - var lres = res.substr(0, n + combo); - if (!BI.isEmpty(lres)) { - newstr = lres + ',' + newstr; + } + 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); } - left = left.replace(/[0-9]+,/, newstr); - } - return left; -}; + return left; + }; -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); + BI.object2Number = function (value) { + if (value == null) { + return 0; + } + if (typeof value == 'number') { + return value; } else { - return parseFloat(str); + 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 (!BI.isInvalidDate(dt)) { - return dt; + 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 (!BI.isInvalidDate(dt)) { + return dt; + } - return new Date(); - } -}; + return new Date(); + } + }; -BI.isArray = function (a) { - return Object.prototype.toString.call(a) == '[object Array]'; -}; + BI.isArray = function (a) { + return Object.prototype.toString.call(a) == '[object Array]'; + }; -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 (!BI.isInvalidDate(dt)) { - return dt; + BI.object2Time = function (obj) { + if (obj == null) { + return new Date(); } - if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { - dt = new Date("1970/01/01 " + str); + if (obj instanceof Date) { + return obj; + } else { + var str = obj + ""; + str = str.replace(/-/g, '/'); + var dt = new Date(str); if (!BI.isInvalidDate(dt)) { return dt; } + if (str.indexOf('/') === -1 && str.indexOf(':') !== -1) { + dt = new Date("1970/01/01 " + str); + if (!BI.isInvalidDate(dt)) { + return dt; + } + } + dt = BI.str2Date(str, "HH:mm:ss"); + if (!BI.isInvalidDate(dt)) { + return dt; + } + return new Date(); } - dt = BI.str2Date(str, "HH:mm:ss"); - if (!BI.isInvalidDate(dt)) { - return dt; - } - return new Date(); - } -}; + }; // 判断是否是无效的日期 -BI.isInvalidDate = function (date) { - return date == "Invalid Date" || date == "NaN"; -}; + BI.isInvalidDate = function (date) { + return date == "Invalid Date" || date == "NaN"; + }; -/** - * 科学计数格式 - */ -BI._eFormat = function (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; + /** + * 科学计数格式 + */ + BI._eFormat = function (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 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'; + 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; } - } 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; -}; \ No newline at end of file + return text; + }; +})(); diff --git a/src/core/mvc/fbi.js b/src/core/mvc/fbi.js index 9a70f5c493..a00ec13c79 100644 --- a/src/core/mvc/fbi.js +++ b/src/core/mvc/fbi.js @@ -1,6 +1,6 @@ -(function(root, factory) { - root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); -}(this, function(root, BI, _, $) { +(function (root, factory) { + root.BI = factory(root, root.BI || {}, root._, (root.jQuery || root.$)); +}(this, function (root, BI, _, $) { var previousBI = root.BI; @@ -17,7 +17,7 @@ // Runs BI.js in *noConflict* mode, returning the `BI` variable // to its previous owner. Returns a reference to this BI object. - BI.noConflict = function() { + BI.noConflict = function () { root.BI = previousBI; return this; }; @@ -50,7 +50,7 @@ // Bind an event to a `callback` function. Passing `"all"` will bind // the callback to all events fired. - on: function(name, callback, context) { + 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] = []); @@ -60,10 +60,10 @@ // 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) { + once: function (name, callback, context) { if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; var self = this; - var once = _.once(function() { + var once = _.once(function () { self.off(name, once); callback.apply(this, arguments); }); @@ -75,7 +75,7 @@ // 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) { + off: function (name, callback, context) { if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; // Remove all callbacks for all events. @@ -106,7 +106,7 @@ callback && callback !== event.callback && callback !== event.callback._callback || context && context !== event.context - ) { + ) { remaining.push(event); } } @@ -122,11 +122,15 @@ 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) { + trigger: function (name) { if (!this._events) return this; var args = slice.call(arguments, 1); if (!eventsApi(this, 'trigger', name, args)) return this; @@ -137,10 +141,14 @@ 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) { + listenTo: function (obj, name, callback) { var listeningTo = this._listeningTo || (this._listeningTo = {}); var id = obj._listenId || (obj._listenId = _.uniqueId('l')); listeningTo[id] = obj; @@ -149,7 +157,7 @@ return this; }, - listenToOnce: function(obj, name, callback) { + listenToOnce: function (obj, name, callback) { if (typeof name === 'object') { for (var event in name) this.listenToOnce(obj, event, name[event]); return this; @@ -162,7 +170,7 @@ return this; } if (!callback) return this; - var once = _.once(function() { + var once = _.once(function () { this.stopListening(obj, name, once); callback.apply(this, arguments); }); @@ -172,7 +180,7 @@ // Tell this object to stop listening to either specific events ... or // to every object it's currently listening to. - stopListening: function(obj, name, callback) { + stopListening: function (obj, name, callback) { var listeningTo = this._listeningTo; if (!listeningTo) return this; var remove = !name && !callback; @@ -194,7 +202,7 @@ // 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) { + var eventsApi = function (obj, action, name, rest) { if (!name) return true; // Handle event maps. @@ -220,19 +228,29 @@ // 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 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; + 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.bind = Events.on; Events.unbind = Events.off; // Allow the `BI` object to serve as a global event bus, for folks who @@ -249,7 +267,7 @@ // 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 M = BI.M = function (attributes, options) { var attrs = attributes || {}; options = options || {}; this.cid = _.uniqueId('c'); @@ -278,40 +296,47 @@ // CouchDB users may want to set this to `"_id"`. idAttribute: 'ID', - _defaultConfig: function(){return {}}, + _defaultConfig: function () { + return {} + }, + + init: function () { + }, // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _init: function () { + this.init(); + }, // Return a copy of the model's `attributes` object. - toJSON: function(options) { + 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() { + sync: function () { return BI.sync.apply(this, arguments); }, // Get the value of an attribute. - get: function(attr) { + get: function (attr) { return this.attributes[attr]; }, // Get the HTML-escaped value of an attribute. - escape: function(attr) { + 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) { + has: function (attr) { return _.has(this.attributes, attr); }, // Special-cased proxy to underscore's `_.matches` method. - matches: function(attrs) { + matches: function (attrs) { var keys = _.keys(attrs), length = keys.length; var obj = Object(this.attributes); for (var i = 0; i < length; i++) { @@ -324,7 +349,7 @@ // 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) { + set: function (key, val, options) { var attr, attrs, unset, changes, silent, changing, changed, prev, current; if (key == null) return this; @@ -342,11 +367,11 @@ if (!this._validate(attrs, options)) return false; // Extract attributes and options. - unset = options.unset; - silent = options.silent; - changes = []; - changing = this._changing; - this._changing = true; + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; if (!changing) { this._previousAttributes = _.clone(this.attributes); @@ -396,12 +421,12 @@ // Remove an attribute from the model, firing `"change"`. `unset` is a noop // if the attribute doesn't exist. - unset: function(attr, options) { + 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) { + clear: function (options) { var attrs = {}; for (var key in this.attributes) attrs[key] = void 0; return this.set(attrs, _.extend({}, options, {unset: true})); @@ -409,7 +434,7 @@ // 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) { + hasChanged: function (attr) { if (attr == null) return !_.isEmpty(this.changed); return _.has(this.changed, attr); }, @@ -420,7 +445,7 @@ // 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) { + changedAttributes: function (diff) { if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; var val, changed = false; var old = this._changing ? this._previousAttributes : this.attributes; @@ -433,27 +458,27 @@ // Get the previous value of an attribute, recorded at the time the last // `"change"` event was fired. - previous: function(attr) { + 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() { + 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) { + 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) { + options.success = function (resp) { + if (!options.noset) { if (!model.set(model.parse(resp, options), options)) return false; } if (success) success(resp, model, options); @@ -466,7 +491,7 @@ // 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) { + save: function (key, val, options) { var attrs, method, xhr, attributes = this.attributes; // Handle both `"key", value` and `{key: value}` -style arguments. @@ -498,7 +523,7 @@ if (options.parse === void 0) options.parse = true; var model = this; var success = options.success; - options.success = function(resp) { + options.success = function (resp) { // Ensure attributes are restored during synchronous saves. model.attributes = attributes; var serverAttrs = model.parse(resp, options); @@ -525,17 +550,17 @@ // 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) { + destroy: function (options) { options = options ? _.clone(options) : {}; var model = this; var success = options.success; - var destroy = function() { + var destroy = function () { model.stopListening(); model.trigger('destroy', model.collection, model, options); }; - options.success = function(resp) { + 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); @@ -555,7 +580,7 @@ // 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() { + url: function () { var base = _.result(this.collection, 'url'); if (this.isNew()) return base; @@ -564,28 +589,28 @@ // **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) { + parse: function (resp, options) { return resp; }, // Create a new model with identical attributes to this one. - clone: function() { + 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() { + 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 })); + 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) { + _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; @@ -600,9 +625,9 @@ 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) { + _.each(modelMethods, function (method) { if (!_[method]) return; - M.prototype[method] = function() { + M.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.attributes); return _[method].apply(_, args); @@ -622,7 +647,7 @@ // 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) { + 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; @@ -644,26 +669,29 @@ // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _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); }); + toJSON: function (options) { + return this.map(function (model) { + return model.toJSON(options); + }); }, // Proxy `BI.sync` by default. - sync: function() { + sync: function () { return BI.sync.apply(this, arguments); }, // Add a model, or list of models to the set. - add: function(models, options) { + 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) { + remove: function (models, options) { var singular = !_.isArray(models); models = singular ? [models] : _.clone(models); options || (options = {}); @@ -689,7 +717,7 @@ // 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) { + set: function (models, options) { options = _.defaults({}, options, setOptions); if (options.parse) models = this.parse(models, options); var singular = !_.isArray(models); @@ -790,7 +818,7 @@ // 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) { + 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); @@ -803,66 +831,66 @@ }, // Add a model to the end of the collection. - push: function(model, options) { + 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) { + 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) { + unshift: function (model, options) { return this.add(model, _.extend({at: 0}, options)); }, // Remove a model from the beginning of the collection. - shift: function(options) { + 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() { + slice: function () { return slice.apply(this.models, arguments); }, // Get a model from the set by id. - get: function(obj) { + 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) { + 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) { + where: function (attrs, first) { var matches = _.matches(attrs); - return this[first ? 'find' : 'filter'](function(model) { + 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) { + 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) { + sort: function (options) { if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); options || (options = {}); @@ -878,19 +906,19 @@ }, // Pluck an attribute from each model in the collection. - pluck: function(attr) { + 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) { + 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) { + options.success = function (resp) { var method = options.reset ? 'reset' : 'set'; collection[method](resp, options); if (success) success(collection, resp, options); @@ -903,13 +931,13 @@ // 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) { + 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) { + options.success = function (model, resp) { if (options.wait) collection.add(model, options); if (success) success(model, resp, options); }; @@ -919,12 +947,12 @@ // **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) { + parse: function (resp, options) { return resp; }, // Create a new collection with an identical list of models as this one. - clone: function() { + clone: function () { return new this.constructor(this.models, { model: this.model, comparator: this.comparator @@ -938,15 +966,15 @@ // Private method to reset all internal state. Called when the collection // is first _initd or reset. - _reset: function() { + _reset: function () { this.length = 0; this.models = []; - this._byId = {}; + this._byId = {}; }, // Prepare a hash of attributes (or other model) to be added to this // collection. - _prepareModel: function(attrs, options) { + _prepareModel: function (attrs, options) { if (this._isModel(attrs)) { if (!attrs.collection) attrs.collection = this; return attrs; @@ -966,7 +994,7 @@ }, // Internal method to create a model's ties to a collection. - _addReference: function(model, options) { + _addReference: function (model, options) { this._byId[model.cid] = model; var id = this.modelId(model.attributes); if (id != null) this._byId[id] = model; @@ -974,7 +1002,7 @@ }, // Internal method to sever a model's ties to a collection. - _removeReference: function(model, options) { + _removeReference: function (model, options) { if (this === model.collection) delete model.collection; model.off('all', this._onModelEvent, this); }, @@ -983,7 +1011,7 @@ // 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) { + _onModelEvent: function (event, model, collection, options) { if ((event === 'add' || event === 'remove') && collection !== this) return; if (event === 'destroy') this.remove(model, options); if (event === 'change') { @@ -1010,9 +1038,9 @@ 'lastIndexOf', 'isEmpty', 'chain', 'sample', 'partition']; // Mix in each Underscore method as a proxy to `Collection#models`. - _.each(methods, function(method) { + _.each(methods, function (method) { if (!_[method]) return; - Collection.prototype[method] = function() { + Collection.prototype[method] = function () { var args = slice.call(arguments); args.unshift(this.models); return _[method].apply(_, args); @@ -1023,10 +1051,10 @@ var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy']; // Use attributes instead of properties. - _.each(attributeMethods, function(method) { + _.each(attributeMethods, function (method) { if (!_[method]) return; - Collection.prototype[method] = function(value, context) { - var iterator = _.isFunction(value) ? value : function(model) { + Collection.prototype[method] = function (value, context) { + var iterator = _.isFunction(value) ? value : function (model) { return model.get(value); }; return _[method](this.models, iterator, context); @@ -1046,7 +1074,7 @@ // 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) { + var V = BI.V = function (options) { this.cid = _.uniqueId('view'); options = options || {}; this.options = _.defaults(options, _.result(this, '_defaultConfig')); @@ -1069,28 +1097,33 @@ // jQuery delegate for element lookup, scoped to DOM elements within the // current view. This should be preferred to global lookups where possible. - $: function(selector) { + $: function (selector) { return this.$el.find(selector); }, - _defaultConfig: function(){return {}}, + _defaultConfig: function () { + return {} + }, // _init is an empty function by default. Override it with your own // initialization logic. - _init: function(){}, + _init: function () { + }, //容器,默认放在this.element上 - _vessel: function(){return 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) { + 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() { + remove: function () { this._removeElement(); this.stopListening(); return this; @@ -1099,7 +1132,7 @@ // 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() { + _removeElement: function () { this.$el.remove(); if ($.browser.msie === true) { this.el.outerHTML = ''; @@ -1108,33 +1141,33 @@ // Change the view's element (`this.el` property) and re-delegate the // view's events on the new element. - setElement: function(element) { + setElement: function (element) { this.undelegateEvents(); this._setElement(element); - this.$vessel = this._vessel(); - this._render(this.$vessel); + this.vessel = this._vessel(); + this.render(this.vessel); this.delegateEvents(); return this; }, - setVisible: function(visible){ + setVisible: function (visible) { this.options.invisible = !visible; - if (visible){ + if (visible) { this.element.show(); } else { this.element.hide(); } }, - isVisible: function(){ + isVisible: function () { return !this.options.invisible; }, - visible: function(){ + visible: function () { this.setVisible(true); }, - invisible: function(){ + invisible: function () { this.setVisible(false); }, @@ -1143,7 +1176,7 @@ // 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) { + _setElement: function (el) { this.$el = el instanceof BI.$ ? el : BI.$(el); this.element = this.$el; this.el = this.$el[0]; @@ -1162,7 +1195,7 @@ // 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) { + delegateEvents: function (events) { if (!(events || (events = _.result(this, 'events')))) return this; this.undelegateEvents(); for (var key in events) { @@ -1178,27 +1211,27 @@ // 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.on(eventName + '.delegateEvents' + this.cid, selector, listener); + 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.off('.delegateEvents' + this.cid); + 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.off(eventName + '.delegateEvents' + this.cid, selector, listener); + 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) { + _createElement: function (tagName) { return document.createElement(tagName); }, @@ -1206,7 +1239,7 @@ // 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() { + _ensureElement: function () { var attrs = _.extend({}, _.result(this, 'attributes')); if (this.baseCls) attrs['class'] = _.result(this, 'baseCls'); if (!this.element) { @@ -1219,7 +1252,7 @@ // Set attributes from a hash on this view's element. Exposed for // subclasses using an alternative DOM manipulation API. - _setAttributes: function(attributes) { + _setAttributes: function (attributes) { this.$el.attr(attributes); } @@ -1243,7 +1276,7 @@ // 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) { + BI.sync = function (method, model, options) { var type = methodMap[method]; // Default options, unless specified. @@ -1257,8 +1290,8 @@ // Ensure that we have a URL. if (!options.url) { - params.url = _.result(model, method+"URL") || _.result(model, 'url'); - if(!params.url){ + params.url = _.result(model, method + "URL") || _.result(model, 'url'); + if (!params.url) { return; } } @@ -1281,7 +1314,7 @@ params.type = 'POST'; if (options.emulateJSON) params.data._method = type; var beforeSend = options.beforeSend; - options.beforeSend = function(xhr) { + options.beforeSend = function (xhr) { xhr.setRequestHeader('X-HTTP-Method-Override', type); if (beforeSend) return beforeSend.apply(this, arguments); }; @@ -1294,7 +1327,7 @@ // Pass along `textStatus` and `errorThrown` from jQuery. var error = options.error; - options.error = function(xhr, textStatus, errorThrown) { + options.error = function (xhr, textStatus, errorThrown) { options.textStatus = textStatus; options.errorThrown = errorThrown; if (error) error.apply(this, arguments); @@ -1310,9 +1343,9 @@ var methodMap = { 'create': 'POST', 'update': 'PUT', - 'patch': 'PATCH', + 'patch': 'PATCH', 'delete': 'DELETE', - 'read': 'GET' + 'read': 'GET' }; // Set the default implementation of `BI.ajax` to proxy through to `$`. @@ -1324,7 +1357,7 @@ // 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) { + var Router = BI.Router = function (options) { options || (options = {}); if (options.routes) this.routes = options.routes; this._bindRoutes(); @@ -1334,16 +1367,17 @@ // 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; + 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(){}, + _init: function () { + }, // Manually bind a single named route to a callback. For example: // @@ -1351,7 +1385,7 @@ // ... // }); // - route: function(route, name, callback) { + route: function (route, name, callback) { if (!_.isRegExp(route)) route = this._routeToRegExp(route); if (_.isFunction(name)) { callback = name; @@ -1359,7 +1393,7 @@ } if (!callback) callback = this[name]; var router = this; - BI.history.route(route, function(fragment) { + 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)); @@ -1372,12 +1406,12 @@ // 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) { + 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) { + navigate: function (fragment, options) { BI.history.navigate(fragment, options); return this; }, @@ -1385,7 +1419,7 @@ // 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() { + _bindRoutes: function () { if (!this.routes) return; this.routes = _.result(this, 'routes'); var route, routes = _.keys(this.routes); @@ -1396,10 +1430,10 @@ // Convert a route string into a regular expression, suitable for matching // against the current location hash. - _routeToRegExp: function(route) { + _routeToRegExp: function (route) { route = route.replace(escapeRegExp, '\\$&') .replace(optionalParam, '(?:$1)?') - .replace(namedParam, function(match, optional) { + .replace(namedParam, function (match, optional) { return optional ? match : '([^/?]+)'; }) .replace(splatParam, '([^?]*?)'); @@ -1409,9 +1443,9 @@ // 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) { + _extractParameters: function (route, fragment) { var params = route.exec(fragment).slice(1); - return _.map(params, function(param, i) { + 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; @@ -1428,7 +1462,7 @@ // [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() { + var History = BI.History = function () { this.handlers = []; _.bindAll(this, 'checkUrl'); @@ -1459,27 +1493,27 @@ interval: 50, // Are we at the app root? - atRoot: function() { + 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() { + 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) { + 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() { + 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); @@ -1487,7 +1521,7 @@ }, // Get the cross-browser normalized URL fragment from the path or hash. - getFragment: function(fragment) { + getFragment: function (fragment) { if (fragment == null) { if (this._hasPushState || !this._wantsHashChange) { fragment = this.getPath(); @@ -1500,19 +1534,19 @@ // Start the hash change handling, returning `true` if the current URL matches // an existing route, and `false` otherwise. - start: function(options) { + 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.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(); + 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, '/'); @@ -1554,8 +1588,8 @@ // Add a cross-platform `addEventListener` shim for older browsers. var addEventListener = window.addEventListener || function (eventName, listener) { - return attachEvent('on' + 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. @@ -1572,11 +1606,11 @@ // Disable BI.history, perhaps temporarily. Not useful in a real app, // but possibly useful for unit testing Routers. - stop: function() { + stop: function () { // Add a cross-platform `removeEventListener` shim for older browsers. var removeEventListener = window.removeEventListener || function (eventName, listener) { - return detachEvent('on' + eventName, listener); - }; + return detachEvent('on' + eventName, listener); + }; // Remove window listeners. if (this._hasPushState) { @@ -1598,13 +1632,13 @@ // Add a route to be tested when the fragment changes. Routes added later // may override previous routes. - route: function(route, callback) { + 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) { + checkUrl: function (e) { var current = this.getFragment(); // If the user pressed the back button, the iframe's hash will have @@ -1621,9 +1655,9 @@ // 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) { + loadUrl: function (fragment) { fragment = this.fragment = this.getFragment(fragment); - return _.any(this.handlers, function(handler) { + return _.any(this.handlers, function (handler) { if (handler.route.test(fragment)) { handler.callback(fragment); return true; @@ -1638,7 +1672,7 @@ // 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) { + navigate: function (fragment, options) { if (!History.started) return false; if (!options || options === true) options = {trigger: !!options}; @@ -1684,7 +1718,7 @@ // Update the hash location, either replacing the current entry, or adding // a new one to the browser history. - _updateHash: function(location, fragment, replace) { + _updateHash: function (location, fragment, replace) { if (replace) { var href = location.href.replace(/(javascript:|#).*$/, ''); location.replace(href + '#' + fragment); @@ -1705,7 +1739,7 @@ // 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 extend = function (protoProps, staticProps) { var parent = this; var child; @@ -1715,7 +1749,9 @@ if (protoProps && _.has(protoProps, 'constructor')) { child = protoProps.constructor; } else { - child = function(){ return parent.apply(this, arguments); }; + child = function () { + return parent.apply(this, arguments); + }; } // Add static properties to the constructor function, if supplied. @@ -1723,7 +1759,9 @@ // Set the prototype chain to inherit from `parent`, without calling // `parent`'s constructor function. - var Surrogate = function(){ this.constructor = child; }; + var Surrogate = function () { + this.constructor = child; + }; Surrogate.prototype = parent.prototype; child.prototype = new Surrogate; @@ -1742,14 +1780,14 @@ 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() { + 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 wrapError = function (model, options) { var error = options.error; - options.error = function(resp) { + options.error = function (resp) { if (error) error(model, resp, options); model.trigger('error', model, resp, options); }; diff --git a/src/core/ob.js b/src/core/ob.js index 182c68f071..bb71c38743 100644 --- a/src/core/ob.js +++ b/src/core/ob.js @@ -14,8 +14,7 @@ BI.OB = function (config) { }; $.extend(BI.OB.prototype, { props: {}, - init: function () { - }, + init: null, _defaultConfig: function (config) { return {}; @@ -23,7 +22,7 @@ $.extend(BI.OB.prototype, { _init: function () { this._initListeners(); - this.init(); + this.init && this.init(); }, _initListeners: function () { diff --git a/src/core/view.js b/src/core/view.js index b5e19022d0..5dcab2c4ff 100644 --- a/src/core/view.js +++ b/src/core/view.js @@ -130,10 +130,10 @@ BI.View = BI.inherit(BI.V, { }); var vessel = BI.createWidget(); this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel); - return vessel.element; + return vessel; }, - _render: function (vessel) { + render: function (vessel) { return this; }, @@ -501,15 +501,26 @@ BI.View = BI.inherit(BI.V, { }, + _unMount: function () { + BI.each(this._cardLayouts, function (name, card) { + card && card._unMount(); + }); + delete this._cardLayouts; + delete this._cards; + this.off(); + this.destroyed(); + }, + destroy: function () { BI.each(this._cardLayouts, function (name, card) { - card && card.destroy(); + card && card._unMount(); }); delete this._cardLayouts; delete this._cards; + this.destroyed(); this.remove(); this.trigger(BI.Events.DESTROY); - this.destroyed(); + this.off(); }, destroyed: function () { diff --git a/src/core/widget.js b/src/core/widget.js index 90c1e8eb19..2f4f3d3902 100644 --- a/src/core/widget.js +++ b/src/core/widget.js @@ -8,6 +8,7 @@ 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, @@ -23,41 +24,30 @@ BI.Widget = BI.inherit(BI.OB, { }, //生命周期函数 - beforeCreate: function () { + beforeCreate: null, - }, - - created: function () { + created: null, - }, + render: null, - render: function () { + beforeMounted: null, - }, - - beforeMounted: function () { - - }, - - mounted: function () { - - }, + mounted: null, update: null, - destroyed: function () { - }, + destroyed: null, _init: function () { BI.Widget.superclass._init.apply(this, arguments); - this.beforeCreate(); + this.beforeCreate && this.beforeCreate(); this._initRoot(); this._initElementWidth(); this._initElementHeight(); this._initVisualEffects(); this._initState(); this._initElement(); - this.created(); + this.created && this.created(); }, /** @@ -67,6 +57,7 @@ BI.Widget = BI.inherit(BI.OB, { _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; @@ -130,7 +121,7 @@ BI.Widget = BI.inherit(BI.OB, { _initElement: function () { var self = this; - var els = this.render(); + var els = this.render && this.render(); if (BI.isPlainObject(els)) { els = [els]; } @@ -164,13 +155,13 @@ BI.Widget = BI.inherit(BI.OB, { if (!isMounted) { return; } - this.beforeMounted(); + this.beforeMounted && this.beforeMounted(); this._isMounted = true; this._mountChildren(); BI.each(this._children, function (i, widget) { widget._mount && widget._mount(); }); - this.mounted(); + this.mounted && this.mounted(); }, _mountChildren: function () { @@ -196,7 +187,7 @@ BI.Widget = BI.inherit(BI.OB, { this._parent = null; this._isMounted = false; this.purgeListeners(); - this.destroyed(); + this.destroyed && this.destroyed(); }, setWidth: function (w) { @@ -258,6 +249,9 @@ BI.Widget = BI.inherit(BI.OB, { 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"); @@ -383,7 +377,7 @@ BI.Widget = BI.inherit(BI.OB, { empty: function () { BI.each(this._children, function (i, widget) { - widget._unMount(); + widget._unMount && widget._unMount(); }); this._children = {}; this.element.empty(); @@ -396,7 +390,7 @@ BI.Widget = BI.inherit(BI.OB, { this._children = {}; this._parent = null; this._isMounted = false; - this.destroyed(); + this.destroyed && this.destroyed(); this.element.destroy(); this.fireEvent(BI.Events.DESTROY); this.purgeListeners(); diff --git a/src/core/wrapper/layout.js b/src/core/wrapper/layout.js index 477c5d7ce7..4074b3fd74 100644 --- a/src/core/wrapper/layout.js +++ b/src/core/wrapper/layout.js @@ -361,9 +361,8 @@ BI.Layout = BI.inherit(BI.Widget, { removeIndex = nameOrWidget; } if (removeIndex) { - this.options.items.splice(removeIndex, 1); + this._removeItemAt(removeIndex | 0); } - BI.Layout.superclass.removeWidget.apply(this, arguments); }, empty: function () { diff --git a/src/core/wrapper/layout/adapt/float.center.js b/src/core/wrapper/layout/adapt/float.center.js index 29d7367a82..78f9630945 100644 --- a/src/core/wrapper/layout/adapt/float.center.js +++ b/src/core/wrapper/layout/adapt/float.center.js @@ -37,7 +37,7 @@ BI.FloatCenterAdaptLayout = BI.inherit(BI.Layout, { element: this, items: [this.left] }); - this.removeWidget(this.container.getName()); + this.removeWidget(this.container); }, stroke: function (items) { diff --git a/src/core/wrapper/layout/adapt/float.horizontal.js b/src/core/wrapper/layout/adapt/float.horizontal.js index 11f905bb47..8fd043e21a 100644 --- a/src/core/wrapper/layout/adapt/float.horizontal.js +++ b/src/core/wrapper/layout/adapt/float.horizontal.js @@ -32,7 +32,7 @@ BI.FloatHorizontalLayout = BI.inherit(BI.Layout, { element: this, items: [this.left] }); - this.removeWidget(this.container.getName()); + this.removeWidget(this.container); }, _addElement: function (i, item) { diff --git a/src/css/core/reset.css b/src/css/core/reset.css deleted file mode 100644 index 0007ead9b5..0000000000 --- a/src/css/core/reset.css +++ /dev/null @@ -1,128 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ -html, -body, -div, -span, -applet, -object, -iframe, -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote, -pre, -a, -abbr, -acronym, -address, -big, -cite, -code, -del, -dfn, -em, -img, -ins, -kbd, -q, -s, -samp, -small, -strike, -strong, -sub, -sup, -tt, -var, -b, -u, -i, -center, -dl, -dt, -dd, -ol, -ul, -li, -fieldset, -form, -label, -legend, -table, -caption, -tbody, -tfoot, -thead, -tr, -th, -td, -article, -aside, -canvas, -details, -embed, -figure, -figcaption, -footer, -header, -hgroup, -menu, -nav, -output, -ruby, -section, -summary, -time, -mark, -audio, -video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -menu, -nav, -section { - display: block; -} -body { - line-height: 1; -} -ol, -ul { - list-style: none; -} -blockquote, -q { - quotes: none; -} -blockquote:before, -blockquote:after, -q:before, -q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} diff --git a/src/css/widget/responsivetable/responsivetable.css b/src/css/widget/responsivetable/responsivetable.css new file mode 100644 index 0000000000..e19ce6816c --- /dev/null +++ b/src/css/widget/responsivetable/responsivetable.css @@ -0,0 +1,8 @@ +/****添加计算宽度的--运算符直接需要space****/ +/****** common color(常用颜色,可用于普遍场景) *****/ +/**** custom color(自定义颜色,用于特定场景) ****/ +.bi-responsive-table > div.bottom-left > div > div > table > * > * > td.last-col, +.bi-responsive-table > div.bottom-right > div > div > table > * > * > td.last-col, +.bi-responsive-table > div > div > table > * > * > td.last-col { + min-width: 80px; +} diff --git a/src/less/core/reset.less b/src/less/core/reset.less deleted file mode 100644 index 3df61e8d94..0000000000 --- a/src/less/core/reset.less +++ /dev/null @@ -1,48 +0,0 @@ -/* http://meyerweb.com/eric/tools/css/reset/ - v2.0 | 20110126 - License: none (public domain) -*/ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; -} -/* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; -} -body { - line-height: 1; -} -ol, ul { - list-style: none; -} -blockquote, q { - quotes: none; -} -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; -} -table { - border-collapse: collapse; - border-spacing: 0; -} \ No newline at end of file diff --git a/src/less/widget/responsivetable/responsivetable.less b/src/less/widget/responsivetable/responsivetable.less new file mode 100644 index 0000000000..87cbfb2890 --- /dev/null +++ b/src/less/widget/responsivetable/responsivetable.less @@ -0,0 +1,11 @@ +@import "../../bibase"; + +.bi-responsive-table { + & > div.bottom-left > div > div > table, & > div.bottom-right > div > div > table, > div > div > table { + & > * > * > td { + &.last-col { + min-width: 80px; + } + } + } +} \ No newline at end of file diff --git a/src/widget/adaptivearrangement/adaptivearrangement.js b/src/widget/adaptivearrangement/adaptivearrangement.js index 7dfb8f5be3..63f8ff2efd 100644 --- a/src/widget/adaptivearrangement/adaptivearrangement.js +++ b/src/widget/adaptivearrangement/adaptivearrangement.js @@ -37,8 +37,10 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { if (o.isNeedResizeContainer) { var isResizing = false; + var needEnd = false; var height; var interval; + var startSize; var resize = function (e, ui) { if (isResizing) { return; @@ -60,20 +62,26 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { minHeight: 20, helper: "bi-resizer", autoHide: true, + start: function (e, ui) { + startSize = BI.clone(ui.size); + }, resize: function (e, ui) { - if (ui.size.height >= self.arrangement.container.element.height()) { + if (ui.size.height >= startSize.height - 10) { resize(e, ui); } else { interval && clearInterval(interval); + needEnd = true; } }, stop: function (e, ui) { var size = ui.size; - if (isResizing) { + if (isResizing && !needEnd) { size.height = height; } self.arrangement.setContainerSize(ui.size); + needEnd = false; isResizing = false; + startSize = null; interval && clearInterval(interval); self.fireEvent(BI.AdaptiveArrangement.EVENT_RESIZE); } @@ -102,17 +110,21 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { 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 () { - if (!item.element.hasClass("selected")) { - item.element.css("zIndex", ++self.zIndex); - BI.each(self.getAllRegions(), function (i, region) { - region.el.element.removeClass("selected"); - }); - item.element.addClass("selected"); - } + self._setSelect(item) }); o.resizable && item.element.resizable({ handles: "e, s, se", @@ -281,6 +293,7 @@ BI.AdaptiveArrangement = BI.inherit(BI.Widget, { addRegion: function (region, position) { this._initResizable(region.el); + this._setSelect(region.el); var self = this, flag; var old = this.arrangement.getAllRegions(); if (BI.isNotNull(this.position)) { diff --git a/src/widget/date/trigger.date.js b/src/widget/date/trigger.date.js index 77674d91db..a425ce6f8a 100644 --- a/src/widget/date/trigger.date.js +++ b/src/widget/date/trigger.date.js @@ -51,6 +51,9 @@ BI.DateTrigger = BI.inherit(BI.Trigger, { 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); }); @@ -66,7 +69,7 @@ BI.DateTrigger = BI.inherit(BI.Trigger, { if (BI.isNotEmptyString(value)) { var date = value.split("-"); self.store_value = { - type: BICst.MULTI_DATE_CALENDAR, + type: BI.DateTrigger.MULTI_DATE_CALENDAR, value:{ year: date[0] | 0, month: date[1] - 1, @@ -134,7 +137,7 @@ BI.DateTrigger = BI.inherit(BI.Trigger, { var date = new Date(); this.store_value = v; if (BI.isNotNull(v)) { - type = v.type || BICst.MULTI_DATE_CALENDAR; value = v.value; + type = v.type || BI.DateTrigger.MULTI_DATE_CALENDAR; value = v.value; if(BI.isNull(value)){ value = v; } @@ -146,88 +149,88 @@ BI.DateTrigger = BI.inherit(BI.Trigger, { self.setTitle(text + ":" + dateStr); }; switch (type) { - case BICst.MULTI_DATE_YEAR_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_PREV]; + 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 BICst.MULTI_DATE_YEAR_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_AFTER]; + 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 BICst.MULTI_DATE_YEAR_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_BEGIN]; + 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 BICst.MULTI_DATE_YEAR_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_YEAR_END]; + 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 BICst.MULTI_DATE_QUARTER_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_PREV]; + 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 BICst.MULTI_DATE_QUARTER_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_AFTER]; + 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 BICst.MULTI_DATE_QUARTER_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_BEGIN]; + 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 BICst.MULTI_DATE_QUARTER_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_QUARTER_END]; + 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 BICst.MULTI_DATE_MONTH_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_PREV]; + 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 BICst.MULTI_DATE_MONTH_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_AFTER]; + 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 BICst.MULTI_DATE_MONTH_BEGIN: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_BEGIN]; + 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 BICst.MULTI_DATE_MONTH_END: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_MONTH_END]; + 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 BICst.MULTI_DATE_WEEK_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_PREV]; + 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 BICst.MULTI_DATE_WEEK_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_WEEK_AFTER]; + 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 BICst.MULTI_DATE_DAY_PREV: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_PREV]; + 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 BICst.MULTI_DATE_DAY_AFTER: - var text = value + BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_AFTER]; + 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 BICst.MULTI_DATE_DAY_TODAY: - var text = BICst.MULTI_DATE_SEGMENT_NUM[BICst.MULTI_DATE_DAY_TODAY]; + 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; @@ -254,8 +257,58 @@ BI.DateTrigger = BI.inherit(BI.Trigger, { } }); + +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"; diff --git a/src/widget/previewtable/previewtable.js b/src/widget/previewtable/previewtable.js index 51cad7aaf6..8e8bf5ba0d 100644 --- a/src/widget/previewtable/previewtable.js +++ b/src/widget/previewtable/previewtable.js @@ -198,11 +198,6 @@ BI.PreviewTable = BI.inherit(BI.Widget, { populate: function (items, header) { this.table.populate(items, header); - }, - - destroy: function () { - this.table.destroy(); - BI.PreviewTable.superclass.destroy.apply(this, arguments); } }); BI.PreviewTable.EVENT_CHANGE = "PreviewTable.EVENT_CHANGE"; diff --git a/src/widget/responsivetable/responsivetable.js b/src/widget/responsivetable/responsivetable.js new file mode 100644 index 0000000000..17b9f1616c --- /dev/null +++ b/src/widget/responsivetable/responsivetable.js @@ -0,0 +1,363 @@ +/** + * 自适应宽度的表格 + * + * 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 () { + if (self.element.is(":visible")) { + self._initRegionSize(); + self.table.resize(); + self._resizeHeader(); + } + }); + } + } +}); +BI.shortcut('bi.responsive_table', BI.ResponisveTable); \ No newline at end of file