forked from fanruan/fineui
Browse Source
* commit 'd265384f4c2d0cc21177179f0593f75fd1bd6367': update update update 将fix提出来 ie中input自带叉号没去掉 update update update update downlistcombo container 去第三方jsmaster
guy
7 years ago
53 changed files with 15122 additions and 24947 deletions
@ -1,136 +0,0 @@
|
||||
Demo.CanvasTable = BI.inherit(BI.Widget, { |
||||
props: { |
||||
baseCls: "demo-face" |
||||
}, |
||||
|
||||
render: function () { |
||||
var self = this; |
||||
return { |
||||
type: "bi.absolute", |
||||
items: [{ |
||||
el: { |
||||
type: "bi.sequence_table", |
||||
ref: function () { |
||||
self.table = this; |
||||
}, |
||||
isNeedFreeze: null, |
||||
isNeedMerge: false, |
||||
summaryCellStyleGetter: function (isLast) { |
||||
return { |
||||
background: "rgb(4, 177, 194)", |
||||
color: "#ffffff", |
||||
fontWeight: "bold" |
||||
}; |
||||
}, |
||||
sequenceCellStyleGetter: function (index) { |
||||
return { |
||||
background: "rgb(4, 177, 194)", |
||||
color: "#ffffff", |
||||
fontWeight: "bold" |
||||
}; |
||||
}, |
||||
headerCellStyleGetter: function () { |
||||
return { |
||||
background: "rgb(4, 177, 194)", |
||||
color: "#ffffff", |
||||
fontWeight: "bold" |
||||
}; |
||||
}, |
||||
el: { |
||||
type: "bi.adaptive_table", |
||||
el: { |
||||
type: "bi.resizable_table", |
||||
el: { |
||||
type: "bi.canvas_table" |
||||
} |
||||
} |
||||
}, |
||||
sequence: { |
||||
type: "bi.sequence_table_list_number", |
||||
pageSize: 100, |
||||
sequenceHeaderCreator: { |
||||
type: "bi.normal_sequence_header_cell", |
||||
styleGetter: function () { |
||||
return { |
||||
background: "rgb(4, 177, 194)", |
||||
color: "#ffffff", |
||||
fontWeight: "bold" |
||||
}; |
||||
} |
||||
} |
||||
}, |
||||
itemsCreator: function (op, populate) { |
||||
} |
||||
}, |
||||
left: 0, |
||||
right: 0, |
||||
top: 0, |
||||
bottom: 0 |
||||
}] |
||||
}; |
||||
}, |
||||
|
||||
mounted: function () { |
||||
var self = this; |
||||
if (BI.isNull(BI.isExpanded)) { |
||||
BI.isExpanded = false; |
||||
} else if (!BI.isExpanded) { |
||||
TABLE_ITEMS = this._expandData(TABLE_ITEMS, 3); |
||||
TABLE_HEADER = this._expandHeadData(TABLE_HEADER, 3); |
||||
BI.isExpanded = true; |
||||
} |
||||
this._resizeHandler = BI.debounce(function () { |
||||
var width = self.element.width(), height = self.element.height(); |
||||
if (self.table.getWidth() !== width || self.table.getHeight() !== height) { |
||||
self.table.setWidth(width); |
||||
self.table.setHeight(height); |
||||
self.table.populate(); |
||||
} |
||||
}, 0); |
||||
BI.ResizeDetector.addResizeListener(this, function () { |
||||
self._resizeHandler(); |
||||
}); |
||||
this.table.setWidth(this.element.width()); |
||||
this.table.setHeight(this.element.height()); |
||||
this.table.attr("columnSize", BI.makeArray(TABLE_HEADER[0].length, "")); |
||||
this.table.attr("minColumnSize", BI.makeArray(TABLE_HEADER[0].length, 60)); |
||||
this.table.attr("isNeedFreeze", true); |
||||
this.table.attr("freezeCols", []); |
||||
this.table.attr("showSequence", true); |
||||
this.table.attr("headerRowSize", 15); |
||||
this.table.attr("rowSize", 15); |
||||
this.table.populate(TABLE_ITEMS, TABLE_HEADER); |
||||
}, |
||||
|
||||
_expandData: function (items, times) { |
||||
var copy = BI.deepClone(items); |
||||
for (var m = 0; m < times - 1; m++) { |
||||
BI.each(items, function (i, row) { |
||||
copy.push(row); |
||||
}); |
||||
} |
||||
|
||||
for (var n = 0; n < copy.length; n++) { |
||||
for (var m = 0; m < times - 1; m++) { |
||||
BI.each(items[n % 100], function (j, item) { |
||||
copy[n].push(item); |
||||
}) |
||||
} |
||||
} |
||||
return copy; |
||||
}, |
||||
|
||||
_expandHeadData: function (items, times) { |
||||
var copy = BI.deepClone(items); |
||||
for (var n = 0; n < copy.length; n++) { |
||||
for (var m = 0; m < times - 1; m++) { |
||||
BI.each(items[n], function (j, item) { |
||||
copy[n].push(item); |
||||
}) |
||||
} |
||||
} |
||||
return copy; |
||||
} |
||||
}); |
||||
|
||||
BI.shortcut("demo.canvas_table", Demo.CanvasTable); |
@ -1,228 +0,0 @@
|
||||
/** |
||||
* canvas绘图 |
||||
* |
||||
* Created by Shichao on 2017/09/29. |
||||
* @class BI.CanvasNew |
||||
* @extends BI.Widget |
||||
*/ |
||||
BI.CanvasNew = BI.inherit(BI.Widget, { |
||||
|
||||
_defaultConfig: function () { |
||||
return BI.extend(BI.CanvasNew.superclass._defaultConfig.apply(this, arguments), { |
||||
baseCls: "bi-canvas-new" |
||||
}) |
||||
}, |
||||
|
||||
_init: function () { |
||||
BI.CanvasNew.superclass._init.apply(this, arguments); |
||||
var self = this, o = this.options; |
||||
var canvas = this._createHiDPICanvas(o.width, o.height); |
||||
this.element.append(canvas); |
||||
this.canvas = canvas; |
||||
this._queue = []; |
||||
}, |
||||
|
||||
_getContext: function () { |
||||
if (!this.ctx) { |
||||
this.ctx = this.canvas.getContext('2d'); |
||||
} |
||||
return this.ctx; |
||||
}, |
||||
|
||||
getContext: function () { |
||||
return this._getContext(); |
||||
}, |
||||
|
||||
_getPixelRatio: function () { |
||||
var ctx = document.createElement("canvas").getContext("2d"), |
||||
dpr = window.devicePixelRatio || 1, |
||||
bsr = ctx.webkitBackingStorePixelRatio || |
||||
ctx.mozBackingStorePixelRatio || |
||||
ctx.msBackingStorePixelRatio || |
||||
ctx.oBackingStorePixelRatio || |
||||
ctx.backingStorePixelRatio || 1; |
||||
return dpr / bsr; |
||||
}, |
||||
|
||||
getPixelRatio: function () { |
||||
return this._getPixelRatio(); |
||||
}, |
||||
|
||||
_createHiDPICanvas: function (w, h, ratio) { |
||||
if (!ratio) { |
||||
ratio = this._getPixelRatio(); |
||||
} |
||||
this.ratio = ratio; |
||||
var canvas = document.createElement("canvas"); |
||||
if (!document.createElement('canvas').getContext) { |
||||
canvas = window.G_vmlCanvasManager.initElement(canvas); |
||||
} |
||||
canvas.width = w * ratio; |
||||
canvas.height = h * ratio; |
||||
canvas.style.width = w + "px"; |
||||
canvas.style.height = h + "px"; |
||||
canvas.getContext("2d").setTransform(ratio, 0, 0, ratio, 0, 0); |
||||
return canvas; |
||||
}, |
||||
|
||||
_attr: function (key, value) { |
||||
var self = this; |
||||
if (BI.isNull(key)) { |
||||
return; |
||||
} |
||||
if (BI.isObject(key)) { |
||||
BI.each(key, function (k, v) { |
||||
self._queue.push({ k: k, v: v }); |
||||
}); |
||||
return; |
||||
} |
||||
this._queue.push({ k: key, v: value }); |
||||
}, |
||||
|
||||
_line: function (x0, y0) { |
||||
var self = this; |
||||
var args = [].slice.call(arguments, 2); |
||||
if (BI.isOdd(args.length)) { |
||||
this._attr(BI.last(args)); |
||||
args = BI.initial(args); |
||||
} |
||||
this._attr("moveTo", [x0, y0]); |
||||
var odd = BI.filter(args, function (i) { |
||||
return i % 2 === 0; |
||||
}); |
||||
var even = BI.filter(args, function (i) { |
||||
return i % 2 !== 0; |
||||
}); |
||||
args = BI.zip(odd, even); |
||||
BI.each(args, function (i, point) { |
||||
self._attr("lineTo", point); |
||||
}); |
||||
}, |
||||
|
||||
line: function (x0, y0, x1, y1) { |
||||
this._line.apply(this, arguments); |
||||
this._attr("stroke", []); |
||||
}, |
||||
|
||||
rect: function (x, y, w, h, color) { |
||||
this._attr("fillStyle", color); |
||||
this._attr("fillRect", [x, y, w, h]); |
||||
}, |
||||
|
||||
circle: function (x, y, radius, color) { |
||||
this._attr({ |
||||
fillStyle: color, |
||||
beginPath: [], |
||||
arc: [x, y, radius, 0, Math.PI * 2, true], |
||||
closePath: [], |
||||
fill: [] |
||||
}); |
||||
}, |
||||
|
||||
hollow: function () { |
||||
this._attr("beginPath", []); |
||||
this._line.apply(this, arguments); |
||||
this._attr("closePath", []); |
||||
this._attr("stroke", []); |
||||
}, |
||||
|
||||
solid: function () { |
||||
this.hollow.apply(this, arguments); |
||||
this._attr("fill", []); |
||||
}, |
||||
|
||||
text: function (x, y, text, fillStyle) { |
||||
this._attr("fillStyle", BI.isNull(fillStyle) ? "rgb(102, 102, 102)" : fillStyle); |
||||
this._attr("fillText", [text, x, y]); |
||||
}, |
||||
|
||||
setFontStyle: function (fontStyle) { |
||||
this.fontStyle = fontStyle; |
||||
}, |
||||
|
||||
setFontVariant: function (fontVariant) { |
||||
this.fontVariant = fontVariant; |
||||
}, |
||||
|
||||
setFontWeight: function (fontWeight) { |
||||
this.fontWeight = fontWeight; |
||||
}, |
||||
|
||||
setFontSize: function (fontSize) { |
||||
this.fontSize = fontSize; |
||||
}, |
||||
|
||||
setFontFamily: function (fontFamily) { |
||||
this.fontFamily = fontFamily; |
||||
}, |
||||
|
||||
setFont: function () { |
||||
var fontStyle = this.fontStyle || "", |
||||
fontVariant = this.fontVariant || "", |
||||
fontWeight = this.fontWeight || "", |
||||
fontSize = this.fontSize || "12px", |
||||
fontFamily = this.fontFamily || "sans-serif", |
||||
font = fontStyle + " " + fontVariant + " " + fontWeight + " " + fontSize + " " + fontFamily; |
||||
this._getContext().font = font; |
||||
}, |
||||
|
||||
gradient: function (x0, y0, x1, y1, start, end) { |
||||
var grd = this._getContext().createLinearGradient(x0, y0, x1, y1); |
||||
grd.addColorStop(0, start); |
||||
grd.addColorStop(1, end); |
||||
return grd; |
||||
}, |
||||
|
||||
reset: function (x, y) { |
||||
this._getContext().clearRect(x, y, this.canvas.width, this.canvas.height); |
||||
}, |
||||
|
||||
remove: function (x, y, width, height) { |
||||
this._getContext().clearRect(x, y, width, height); |
||||
}, |
||||
|
||||
stroke: function (callback) { |
||||
var self = this; |
||||
BI.nextTick(function () { |
||||
var ctx = self._getContext(); |
||||
BI.each(self._queue, function (i, q) { |
||||
if (BI.isFunction(ctx[q.k])) { |
||||
ctx[q.k].apply(ctx, q.v); |
||||
} else { |
||||
ctx[q.k] = q.v; |
||||
} |
||||
}); |
||||
self._queue = []; |
||||
callback && callback(); |
||||
}); |
||||
}, |
||||
|
||||
setWidth: function (width) { |
||||
BI.CanvasNew.superclass.setWidth.apply(this, arguments); |
||||
this.ratio = this._getPixelRatio(); |
||||
this.canvas.width = width * this.ratio; |
||||
this.canvas.style.width = width + "px"; |
||||
this.canvas.getContext("2d").setTransform(this.ratio, 0, 0, this.ratio, 0, 0); |
||||
}, |
||||
|
||||
setHeight: function (height) { |
||||
BI.CanvasNew.superclass.setHeight.apply(this, arguments); |
||||
this.ratio = this._getPixelRatio(); |
||||
this.canvas.height = height * this.ratio; |
||||
this.canvas.style.height = height + "px"; |
||||
this.canvas.getContext("2d").setTransform(this.ratio, 0, 0, this.ratio, 0, 0); |
||||
}, |
||||
|
||||
setBlock: function () { |
||||
this.canvas.style.display = "block"; |
||||
}, |
||||
|
||||
transform: function (a, b, c, d, e, f) { |
||||
this._attr("transform", [a, b, c, d, e, f]); |
||||
}, |
||||
|
||||
translate: function (x, y) { |
||||
this._attr("translate", [x, y]); |
||||
} |
||||
}); |
||||
BI.shortcut("bi.canvas_new", BI.CanvasNew); |
@ -1,17 +1,17 @@
|
||||
Demo.ADDONS_CONFIG = [{ |
||||
id: 7, |
||||
id: 1000, |
||||
text: "addons" |
||||
}, { |
||||
pId: 7, |
||||
id: 701, |
||||
pId: 1000, |
||||
id: 1001, |
||||
text: "拓展图表控件" |
||||
}, { |
||||
pId: 701, |
||||
pId: 1001, |
||||
text: "柱状图", |
||||
value: "demo.axis_chart" |
||||
}, { |
||||
pId: 7, |
||||
id: 702, |
||||
pId: 1000, |
||||
id: 1002, |
||||
text: "滚动sliders", |
||||
value: "demo.slider" |
||||
}]; |
@ -0,0 +1,52 @@
|
||||
var model = new Fix.Observer({ |
||||
name: 1, |
||||
arr: [{ |
||||
n: 'a' |
||||
}, { |
||||
n: 'b' |
||||
}] |
||||
}).model; |
||||
Demo.Computed = BI.inherit(Fix.VM, { |
||||
computed: { |
||||
b: function () { |
||||
return this.model.name + 1 |
||||
}, |
||||
c: function () { |
||||
return this.model.name + this.model.b |
||||
} |
||||
}, |
||||
}) |
||||
|
||||
Demo.Store = BI.inherit(Fix.VM, { |
||||
_init: function () { |
||||
this.computed = new Demo.Computed(model).model; |
||||
}, |
||||
computed: { |
||||
b: function () { |
||||
return this.computed.c + 1 |
||||
}, |
||||
}, |
||||
methods: { |
||||
run: function () { |
||||
var t = this.model.b; |
||||
this.computed.name = 2; |
||||
} |
||||
} |
||||
}); |
||||
|
||||
Demo.Fix = BI.inherit(BI.Widget, { |
||||
_store: function () { |
||||
return new Demo.Store(); |
||||
}, |
||||
watch: { |
||||
b: function () { |
||||
debugger; |
||||
} |
||||
}, |
||||
mounted: function () { |
||||
|
||||
this.store.run() |
||||
} |
||||
}); |
||||
|
||||
BI.shortcut("demo.fix", Demo.Fix); |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,51 @@
|
||||
;(function () { |
||||
function initWatch(vm, watch) { |
||||
vm._watchers || (vm._watchers = []); |
||||
for (var key in watch) { |
||||
var handler = watch[key] |
||||
if (BI.isArray(handler)) { |
||||
for (var i = 0; i < handler.length; i++) { |
||||
vm._watchers.push(createWatcher(vm, key, handler[i])) |
||||
} |
||||
} else { |
||||
vm._watchers.push(createWatcher(vm, key, handler)) |
||||
} |
||||
} |
||||
} |
||||
|
||||
function createWatcher(vm, keyOrFn, handler, options) { |
||||
if (BI.isPlainObject(handler)) { |
||||
options = handler |
||||
handler = handler.handler |
||||
} |
||||
if (typeof handler === 'string') { |
||||
handler = vm[handler] |
||||
} |
||||
return Fix.VM.prototype.$watch.call(vm, keyOrFn, handler, options) |
||||
} |
||||
|
||||
var _init = BI.Widget.prototype._init; |
||||
BI.Widget.prototype._init = function () { |
||||
if (window.Fix && this._store) { |
||||
this.store = this._store(); |
||||
if (this.store instanceof Fix.VM) { |
||||
this.model = this.store.model; |
||||
} else { |
||||
this.model = this.store; |
||||
} |
||||
initWatch(this, this.watch); |
||||
} |
||||
_init.apply(this, arguments); |
||||
}; |
||||
|
||||
var destroy = BI.Widget.prototype.destroy; |
||||
BI.Widget.prototype.destroy = function () { |
||||
destroy.apply(this, arguments); |
||||
this.store && this.store.destroy(); |
||||
BI.each(this._watchers, function (i, unwatch) { |
||||
unwatch(); |
||||
}); |
||||
this._watchers && (this._watchers = []); |
||||
this.store && (this.store = null); |
||||
} |
||||
}()); |
@ -0,0 +1,958 @@
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } |
||||
|
||||
(function (global, factory) { |
||||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : factory(global.Fix = global.Fix || {}); |
||||
})(this, function (exports) { |
||||
'use strict'; |
||||
|
||||
function noop(a, b, c) {} |
||||
|
||||
function isNative(Ctor) { |
||||
return typeof Ctor === 'function' && /native code/.test(Ctor.toString()); |
||||
} |
||||
|
||||
var rhashcode = /\d\.\d{4}/; |
||||
|
||||
//生成UUID http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
||||
function makeHashCode(prefix) { |
||||
/* istanbul ignore next*/ |
||||
prefix = prefix || 'bi'; |
||||
/* istanbul ignore next*/ |
||||
return String(Math.random() + Math.random()).replace(rhashcode, prefix); |
||||
} |
||||
|
||||
var hasProto = '__proto__' in {}; |
||||
|
||||
var getIEVersion = function getIEVersion() { |
||||
var version = 0; |
||||
var agent = navigator.userAgent.toLowerCase(); |
||||
var v1 = agent.match(/(?:msie\s([\w.]+))/); |
||||
var v2 = agent.match(/(?:trident.*rv:([\w.]+))/); |
||||
if (v1 && v2 && v1[1] && v2[1]) { |
||||
version = Math.max(v1[1] * 1, v2[1] * 1); |
||||
} else if (v1 && v1[1]) { |
||||
version = v1[1] * 1; |
||||
} else if (v2 && v2[1]) { |
||||
version = v2[1] * 1; |
||||
} else { |
||||
version = 0; |
||||
} |
||||
return version; |
||||
}; |
||||
var isIE9Below = getIEVersion() < 9; |
||||
|
||||
var _toString = Object.prototype.toString; |
||||
|
||||
function isPlainObject(obj) { |
||||
return _toString.call(obj) === '[object Object]'; |
||||
} |
||||
|
||||
function remove(arr, item) { |
||||
if (arr.length) { |
||||
var _index = arr.indexOf(item); |
||||
if (_index > -1) { |
||||
return arr.splice(_index, 1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
var bailRE = /[^\w.$]/; |
||||
|
||||
function parsePath(path) { |
||||
if (bailRE.test(path)) { |
||||
return; |
||||
} |
||||
var segments = path.split('.'); |
||||
return function (obj) { |
||||
for (var i = 0; i < segments.length; i++) { |
||||
if (!obj) return; |
||||
obj = obj[segments[i]]; |
||||
} |
||||
return obj; |
||||
}; |
||||
} |
||||
|
||||
var nextTick = function () { |
||||
var callbacks = []; |
||||
var pending = false; |
||||
var timerFunc = void 0; |
||||
|
||||
function nextTickHandler() { |
||||
pending = false; |
||||
var copies = callbacks.slice(0); |
||||
callbacks.length = 0; |
||||
for (var i = 0; i < copies.length; i++) { |
||||
copies[i](); |
||||
} |
||||
} |
||||
|
||||
// An asynchronous deferring mechanism.
|
||||
// In pre 2.4, we used to use microtasks (Promise/MutationObserver)
|
||||
// but microtasks actually has too high a priority and fires in between
|
||||
// supposedly sequential events (e.g. #4521, #6690) or even between
|
||||
// bubbling of the same event (#6566). Technically setImmediate should be
|
||||
// the ideal choice, but it's not available everywhere; and the only polyfill
|
||||
// that consistently queues the callback after all DOM events triggered in the
|
||||
// same loop is by using MessageChannel.
|
||||
/* istanbul ignore if */ |
||||
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { |
||||
timerFunc = function timerFunc() { |
||||
setImmediate(nextTickHandler); |
||||
}; |
||||
} else if (typeof MessageChannel !== 'undefined' && (isNative(MessageChannel) || |
||||
// PhantomJS
|
||||
MessageChannel.toString() === '[object MessageChannelConstructor]')) { |
||||
var channel = new MessageChannel(); |
||||
var port = channel.port2; |
||||
channel.port1.onmessage = nextTickHandler; |
||||
timerFunc = function timerFunc() { |
||||
port.postMessage(1); |
||||
}; |
||||
} else |
||||
/* istanbul ignore next */ |
||||
if (typeof Promise !== 'undefined' && isNative(Promise)) { |
||||
// use microtask in non-DOM environments, e.g. Weex
|
||||
var p = Promise.resolve(); |
||||
timerFunc = function timerFunc() { |
||||
p.then(nextTickHandler); |
||||
}; |
||||
} else { |
||||
// fallback to setTimeout
|
||||
timerFunc = function timerFunc() { |
||||
setTimeout(nextTickHandler, 0); |
||||
}; |
||||
} |
||||
|
||||
return function queueNextTick(cb, ctx) { |
||||
var _resolve = void 0; |
||||
callbacks.push(function () { |
||||
if (cb) { |
||||
try { |
||||
cb.call(ctx); |
||||
} catch (e) {} |
||||
} else if (_resolve) { |
||||
_resolve(ctx); |
||||
} |
||||
}); |
||||
if (!pending) { |
||||
pending = true; |
||||
timerFunc(); |
||||
} |
||||
// $flow-disable-line
|
||||
if (!cb && typeof Promise !== 'undefined') { |
||||
return new Promise(function (resolve, reject) { |
||||
_resolve = resolve; |
||||
}); |
||||
} |
||||
}; |
||||
}(); |
||||
|
||||
var falsy; |
||||
var $$skipArray = { |
||||
__ob__: falsy, |
||||
$accessors: falsy, |
||||
$vbthis: falsy, |
||||
$vbsetter: falsy |
||||
}; |
||||
|
||||
var uid = 0; |
||||
|
||||
/** |
||||
* A dep is an observable that can have multiple |
||||
* directives subscribing to it. |
||||
*/ |
||||
|
||||
var Dep = function () { |
||||
function Dep() { |
||||
_classCallCheck(this, Dep); |
||||
|
||||
this.id = uid++; |
||||
this.subs = []; |
||||
} |
||||
|
||||
Dep.prototype.addSub = function addSub(sub) { |
||||
this.subs.push(sub); |
||||
}; |
||||
|
||||
Dep.prototype.removeSub = function removeSub(sub) { |
||||
remove(this.subs, sub); |
||||
}; |
||||
|
||||
Dep.prototype.depend = function depend() { |
||||
if (Dep.target) { |
||||
Dep.target.addDep(this); |
||||
} |
||||
}; |
||||
|
||||
Dep.prototype.notify = function notify() { |
||||
// stabilize the subscriber list first
|
||||
var subs = this.subs.slice(); |
||||
for (var i = 0, l = subs.length; i < l; i++) { |
||||
subs[i].update(); |
||||
} |
||||
}; |
||||
|
||||
return Dep; |
||||
}(); |
||||
|
||||
// the current target watcher being evaluated.
|
||||
// this is globally unique because there could be only one
|
||||
// watcher being evaluated at any time.
|
||||
|
||||
|
||||
Dep.target = null; |
||||
var targetStack = []; |
||||
|
||||
function pushTarget(_target) { |
||||
if (Dep.target) targetStack.push(Dep.target); |
||||
Dep.target = _target; |
||||
} |
||||
|
||||
function popTarget() { |
||||
Dep.target = targetStack.pop(); |
||||
} |
||||
|
||||
//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8
|
||||
//标准浏览器使用__defineGetter__, __defineSetter__实现
|
||||
var canHideProperty = true; |
||||
try { |
||||
Object.defineProperty({}, '_', { |
||||
value: 'x' |
||||
}); |
||||
delete $$skipArray.$vbsetter; |
||||
delete $$skipArray.$vbthis; |
||||
} catch (e) { |
||||
/* istanbul ignore next*/ |
||||
canHideProperty = false; |
||||
} |
||||
|
||||
var createViewModel = Object.defineProperties; |
||||
var defineProperty = void 0; |
||||
|
||||
var timeBucket = new Date() - 0; |
||||
/* istanbul ignore if*/ |
||||
if (!canHideProperty) { |
||||
if ('__defineGetter__' in {}) { |
||||
defineProperty = function defineProperty(obj, prop, desc) { |
||||
if ('value' in desc) { |
||||
obj[prop] = desc.value; |
||||
} |
||||
if ('get' in desc) { |
||||
obj.__defineGetter__(prop, desc.get); |
||||
} |
||||
if ('set' in desc) { |
||||
obj.__defineSetter__(prop, desc.set); |
||||
} |
||||
return obj; |
||||
}; |
||||
createViewModel = function createViewModel(obj, descs) { |
||||
for (var prop in descs) { |
||||
if (descs.hasOwnProperty(prop)) { |
||||
defineProperty(obj, prop, descs[prop]); |
||||
} |
||||
} |
||||
return obj; |
||||
}; |
||||
} |
||||
/* istanbul ignore if*/ |
||||
if (isIE9Below) { |
||||
var VBClassPool = {}; |
||||
window.execScript([// jshint ignore:line
|
||||
'Function parseVB(code)', '\tExecuteGlobal(code)', 'End Function' //转换一段文本为VB代码
|
||||
].join('\n'), 'VBScript'); |
||||
|
||||
var VBMediator = function VBMediator(instance, accessors, name, value) { |
||||
// jshint ignore:line
|
||||
var accessor = accessors[name]; |
||||
if (arguments.length === 4) { |
||||
accessor.set.call(instance, value); |
||||
} else { |
||||
return accessor.get.call(instance); |
||||
} |
||||
}; |
||||
createViewModel = function createViewModel(name, accessors, properties) { |
||||
// jshint ignore:line
|
||||
var buffer = []; |
||||
buffer.push('\tPrivate [$vbsetter]', '\tPublic [$accessors]', '\tPublic Default Function [$vbthis](ac' + timeBucket + ', s' + timeBucket + ')', '\t\tSet [$accessors] = ac' + timeBucket + ': set [$vbsetter] = s' + timeBucket, '\t\tSet [$vbthis] = Me', //链式调用
|
||||
'\tEnd Function'); |
||||
//添加普通属性,因为VBScript对象不能像JS那样随意增删属性,必须在这里预先定义好
|
||||
var uniq = { |
||||
$vbthis: true, |
||||
$vbsetter: true, |
||||
$accessors: true |
||||
}; |
||||
for (name in $$skipArray) { |
||||
if (!uniq[name]) { |
||||
buffer.push('\tPublic [' + name + ']'); |
||||
uniq[name] = true; |
||||
} |
||||
} |
||||
//添加访问器属性
|
||||
for (name in accessors) { |
||||
if (uniq[name]) { |
||||
continue; |
||||
} |
||||
uniq[name] = true; |
||||
buffer.push( |
||||
//由于不知对方会传入什么,因此set, let都用上
|
||||
'\tPublic Property Let [' + name + '](val' + timeBucket + ')', //setter
|
||||
'\t\tCall [$vbsetter](Me, [$accessors], "' + name + '", val' + timeBucket + ')', '\tEnd Property', '\tPublic Property Set [' + name + '](val' + timeBucket + ')', //setter
|
||||
'\t\tCall [$vbsetter](Me, [$accessors], "' + name + '", val' + timeBucket + ')', '\tEnd Property', '\tPublic Property Get [' + name + ']', //getter
|
||||
'\tOn Error Resume Next', //必须优先使用set语句,否则它会误将数组当字符串返回
|
||||
'\t\tSet[' + name + '] = [$vbsetter](Me, [$accessors],"' + name + '")', '\tIf Err.Number <> 0 Then', '\t\t[' + name + '] = [$vbsetter](Me, [$accessors],"' + name + '")', '\tEnd If', '\tOn Error Goto 0', '\tEnd Property'); |
||||
} |
||||
|
||||
for (name in properties) { |
||||
if (!uniq[name]) { |
||||
uniq[name] = true; |
||||
buffer.push('\tPublic [' + name + ']'); |
||||
} |
||||
} |
||||
|
||||
buffer.push('\tPublic [hasOwnProperty]'); |
||||
buffer.push('End Class'); |
||||
var body = buffer.join('\r\n'); |
||||
var className = VBClassPool[body]; |
||||
if (!className) { |
||||
className = makeHashCode('VBClass'); |
||||
window.parseVB('Class ' + className + body); |
||||
window.parseVB(['Function ' + className + 'Factory(acc, vbm)', //创建实例并传入两个关键的参数
|
||||
'\tDim o', '\tSet o = (New ' + className + ')(acc, vbm)', '\tSet ' + className + 'Factory = o', 'End Function'].join('\r\n')); |
||||
VBClassPool[body] = className; |
||||
} |
||||
var ret = window[className + 'Factory'](accessors, VBMediator); //得到其产品
|
||||
return ret; //得到其产品
|
||||
}; |
||||
} |
||||
} |
||||
|
||||
var createViewModel$1 = createViewModel; |
||||
|
||||
var queue = []; |
||||
var activatedChildren = []; |
||||
var has = {}; |
||||
var waiting = false; |
||||
var flushing = false; |
||||
var index = 0; |
||||
|
||||
function resetSchedulerState() { |
||||
index = queue.length = activatedChildren.length = 0; |
||||
has = {}; |
||||
waiting = flushing = false; |
||||
} |
||||
|
||||
function flushSchedulerQueue() { |
||||
flushing = true; |
||||
var watcher = void 0, |
||||
id = void 0; |
||||
|
||||
// Sort queue before flush.
|
||||
// This ensures that:
|
||||
// 1. Components are updated from parent to child. (because parent is always
|
||||
// created before the child)
|
||||
// 2. A component's user watchers are run before its render watcher (because
|
||||
// user watchers are created before the render watcher)
|
||||
// 3. If a component is destroyed during a parent component's watcher run,
|
||||
// its watchers can be skipped.
|
||||
queue.sort(function (a, b) { |
||||
return a.id - b.id; |
||||
}); |
||||
|
||||
// do not cache length because more watchers might be pushed
|
||||
// as we run existing watchers
|
||||
for (index = 0; index < queue.length; index++) { |
||||
watcher = queue[index]; |
||||
id = watcher.id; |
||||
has[id] = null; |
||||
watcher.run(); |
||||
} |
||||
|
||||
resetSchedulerState(); |
||||
} |
||||
|
||||
function queueWatcher(watcher) { |
||||
var id = watcher.id; |
||||
if (has[id] == null) { |
||||
has[id] = true; |
||||
if (!flushing) { |
||||
queue.push(watcher); |
||||
} else { |
||||
// if already flushing, splice the watcher based on its id
|
||||
// if already past its id, it will be run next immediately.
|
||||
var i = queue.length - 1; |
||||
while (i > index && queue[i].id > watcher.id) { |
||||
i--; |
||||
} |
||||
queue.splice(i + 1, 0, watcher); |
||||
} |
||||
// queue the flush
|
||||
if (!waiting) { |
||||
waiting = true; |
||||
nextTick(flushSchedulerQueue); |
||||
} |
||||
} |
||||
} |
||||
|
||||
var uid$1 = 0; |
||||
|
||||
var Watcher = function () { |
||||
function Watcher(vm, expOrFn, cb, options) { |
||||
_classCallCheck(this, Watcher); |
||||
|
||||
this.vm = vm; |
||||
// vm._watchers || (vm._watchers = [])
|
||||
// vm._watchers.push(this)
|
||||
// options
|
||||
if (options) { |
||||
this.deep = !!options.deep; |
||||
this.user = !!options.user; |
||||
this.lazy = !!options.lazy; |
||||
this.sync = !!options.sync; |
||||
} else { |
||||
this.deep = this.user = this.lazy = this.sync = false; |
||||
} |
||||
this.cb = cb; |
||||
this.id = ++uid$1; // uid for batching
|
||||
this.active = true; |
||||
this.dirty = this.lazy; // for lazy watchers
|
||||
this.deps = []; |
||||
this.newDeps = []; |
||||
this.depIds = new Set(); |
||||
this.newDepIds = new Set(); |
||||
this.expression = ''; |
||||
// parse expression for getter
|
||||
if (typeof expOrFn === 'function') { |
||||
this.getter = expOrFn; |
||||
} else { |
||||
this.getter = parsePath(expOrFn); |
||||
if (!this.getter) { |
||||
this.getter = function () {}; |
||||
} |
||||
} |
||||
this.value = this.lazy ? undefined : this.get(); |
||||
} |
||||
|
||||
Watcher.prototype.get = function get() { |
||||
pushTarget(this); |
||||
var value = void 0; |
||||
var vm = this.vm; |
||||
try { |
||||
value = this.getter.call(vm, vm); |
||||
} catch (e) { |
||||
if (this.user) {} else { |
||||
throw e; |
||||
} |
||||
} finally { |
||||
// "touch" every property so they are all tracked as
|
||||
// dependencies for deep watching
|
||||
if (this.deep) { |
||||
traverse(value); |
||||
} |
||||
popTarget(); |
||||
this.cleanupDeps(); |
||||
} |
||||
return value; |
||||
}; |
||||
|
||||
Watcher.prototype.addDep = function addDep(dep) { |
||||
var id = dep.id; |
||||
if (!this.newDepIds.has(id)) { |
||||
this.newDepIds.add(id); |
||||
this.newDeps.push(dep); |
||||
if (!this.depIds.has(id)) { |
||||
dep.addSub(this); |
||||
} |
||||
} |
||||
}; |
||||
|
||||
Watcher.prototype.cleanupDeps = function cleanupDeps() { |
||||
var i = this.deps.length; |
||||
while (i--) { |
||||
var dep = this.deps[i]; |
||||
if (!this.newDepIds.has(dep.id)) { |
||||
dep.removeSub(this); |
||||
} |
||||
} |
||||
var tmp = this.depIds; |
||||
this.depIds = this.newDepIds; |
||||
this.newDepIds = tmp; |
||||
this.newDepIds.clear(); |
||||
tmp = this.deps; |
||||
this.deps = this.newDeps; |
||||
this.newDeps = tmp; |
||||
this.newDeps.length = 0; |
||||
}; |
||||
|
||||
Watcher.prototype.update = function update() { |
||||
/* istanbul ignore else */ |
||||
if (this.lazy) { |
||||
this.dirty = true; |
||||
} else if (this.sync) { |
||||
this.run(); |
||||
} else { |
||||
queueWatcher(this); |
||||
} |
||||
}; |
||||
|
||||
Watcher.prototype.run = function run() { |
||||
if (this.active) { |
||||
var value = this.get(); |
||||
if (value !== this.value || |
||||
// Deep watchers and watchers on Object/Arrays should fire even
|
||||
// when the value is the same, because the value may
|
||||
// have mutated.
|
||||
_.isObject(value) || this.deep) { |
||||
// set new value
|
||||
var oldValue = this.value; |
||||
this.value = value; |
||||
if (this.user) { |
||||
try { |
||||
this.cb.call(this.vm, value, oldValue); |
||||
} catch (e) {} |
||||
} else { |
||||
this.cb.call(this.vm, value, oldValue); |
||||
} |
||||
} |
||||
} |
||||
}; |
||||
|
||||
Watcher.prototype.evaluate = function evaluate() { |
||||
this.value = this.get(); |
||||
this.dirty = false; |
||||
}; |
||||
|
||||
Watcher.prototype.depend = function depend() { |
||||
var i = this.deps.length; |
||||
while (i--) { |
||||
this.deps[i].depend(); |
||||
} |
||||
}; |
||||
|
||||
Watcher.prototype.teardown = function teardown() { |
||||
if (this.active) { |
||||
// remove self from vm's watcher list
|
||||
// this is a somewhat expensive operation so we skip it
|
||||
// if the vm is being destroyed.
|
||||
if (!this.vm._isBeingDestroyed) { |
||||
remove(this.vm._watchers, this); |
||||
} |
||||
var i = this.deps.length; |
||||
while (i--) { |
||||
this.deps[i].removeSub(this); |
||||
} |
||||
this.active = false; |
||||
} |
||||
}; |
||||
|
||||
return Watcher; |
||||
}(); |
||||
|
||||
var seenObjects = new Set(); |
||||
|
||||
function traverse(val) { |
||||
seenObjects.clear(); |
||||
_traverse(val, seenObjects); |
||||
} |
||||
|
||||
function _traverse(val, seen) { |
||||
var i = void 0, |
||||
keys = void 0; |
||||
var isA = _.isArray(val); |
||||
if (!isA && !_.isObject(val)) { |
||||
return; |
||||
} |
||||
if (val.__ob__) { |
||||
var depId = val.__ob__.dep.id; |
||||
if (seen.has(depId)) { |
||||
return; |
||||
} |
||||
seen.add(depId); |
||||
} |
||||
if (isA) { |
||||
i = val.length; |
||||
while (i--) { |
||||
_traverse(val[i], seen); |
||||
} |
||||
} else { |
||||
keys = _.keys(val); |
||||
i = keys.length; |
||||
while (i--) { |
||||
_traverse(val[keys[i]], seen); |
||||
} |
||||
} |
||||
} |
||||
|
||||
var arrayProto = Array.prototype; |
||||
var arrayMethods = []; |
||||
_.each(['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'], function (method) { |
||||
var original = arrayProto[method]; |
||||
arrayMethods[method] = function mutator() { |
||||
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { |
||||
args[_key] = arguments[_key]; |
||||
} |
||||
|
||||
var ob = this.__ob__; |
||||
var inserted = void 0; |
||||
switch (method) { |
||||
case 'push': |
||||
case 'unshift': |
||||
inserted = args; |
||||
break; |
||||
case 'splice': |
||||
inserted = args.slice(2); |
||||
break; |
||||
} |
||||
if (inserted) inserted = ob.observeArray(inserted); |
||||
switch (method) { |
||||
case 'push': |
||||
case 'unshift': |
||||
args = inserted; |
||||
break; |
||||
case 'splice': |
||||
args = [args[0], args[1]].concat(inserted ? inserted : []); |
||||
break; |
||||
} |
||||
var result = original.apply(this, args); |
||||
ob.dep.notify(); |
||||
return result; |
||||
}; |
||||
}); |
||||
|
||||
var arrayKeys = _.keys(arrayMethods); |
||||
|
||||
var observerState = { |
||||
shouldConvert: true |
||||
}; |
||||
|
||||
/** |
||||
* Observer class that are attached to each observed |
||||
* object. Once attached, the observer converts target |
||||
* object's property keys into getter/setters that |
||||
* collect dependencies and dispatches updates. |
||||
*/ |
||||
|
||||
var Observer = function () { |
||||
function Observer(value) { |
||||
_classCallCheck(this, Observer); |
||||
|
||||
this.value = value; |
||||
this.dep = new Dep(); |
||||
this.vmCount = 0; |
||||
if (_.isArray(value)) { |
||||
var augment = hasProto ? protoAugment : copyAugment; |
||||
augment(value, arrayMethods, arrayKeys); |
||||
this.model = this.observeArray(value); |
||||
} else { |
||||
this.model = this.walk(value); |
||||
} |
||||
this.model['__ob__'] = this; |
||||
} |
||||
|
||||
Observer.prototype.walk = function walk(obj) { |
||||
return defineReactive(obj); |
||||
}; |
||||
|
||||
Observer.prototype.observeArray = function observeArray(items) { |
||||
for (var i = 0, l = items.length; i < l; i++) { |
||||
items[i] = observe(items[i]).model; |
||||
} |
||||
return items; |
||||
}; |
||||
|
||||
return Observer; |
||||
}(); |
||||
|
||||
function protoAugment(target, src, keys) { |
||||
/* eslint-disable no-proto */ |
||||
target.__proto__ = src; |
||||
/* eslint-enable no-proto */ |
||||
} |
||||
|
||||
/* istanbul ignore next */ |
||||
function copyAugment(target, src, keys) { |
||||
for (var i = 0, l = keys.length; i < l; i++) { |
||||
var key = keys[i]; |
||||
target[key] = src[key]; |
||||
} |
||||
} |
||||
|
||||
function observe(value, asRootData) { |
||||
if (!_.isObject(value)) { |
||||
return; |
||||
} |
||||
var ob = void 0; |
||||
if (_.has(value, '__ob__') && value.__ob__ instanceof Observer) { |
||||
ob = value.__ob__; |
||||
} else if (observerState.shouldConvert && (_.isArray(value) || isPlainObject(value)) && !value._isVue) { |
||||
ob = new Observer(value); |
||||
} |
||||
if (asRootData && ob) { |
||||
ob.vmCount++; |
||||
} |
||||
return ob; |
||||
} |
||||
|
||||
function defineReactive(obj, shallow) { |
||||
|
||||
var props = {}; |
||||
_.each(obj, function (val, key) { |
||||
if (key in $$skipArray) { |
||||
return; |
||||
} |
||||
var dep = new Dep(); |
||||
var childOb = !shallow && observe(val); |
||||
props[key] = { |
||||
enumerable: true, |
||||
configurable: true, |
||||
get: function reactiveGetter() { |
||||
var value = val; |
||||
if (Dep.target) { |
||||
dep.depend(); |
||||
if (childOb) { |
||||
childOb.dep.depend(); |
||||
if (_.isArray(value)) { |
||||
dependArray(value); |
||||
} |
||||
} |
||||
} |
||||
return value; |
||||
}, |
||||
set: function reactiveSetter(newVal) { |
||||
var value = val; |
||||
if (newVal === value || newVal !== newVal && value !== value) { |
||||
return; |
||||
} |
||||
val = newVal; |
||||
childOb = !shallow && observe(newVal); |
||||
obj[key] = childOb ? childOb.model : newVal; |
||||
dep.notify(); |
||||
} |
||||
}; |
||||
}); |
||||
return createViewModel$1(obj, props); |
||||
} |
||||
|
||||
/** |
||||
* Set a property on an object. Adds the new property and |
||||
* triggers change notification if the property doesn't |
||||
* already exist. |
||||
*/ |
||||
function set(target, key, val) { |
||||
if (_.isArray(target)) { |
||||
target.length = Math.max(target.length, key); |
||||
target.splice(key, 1, val); |
||||
return val; |
||||
} |
||||
if (_.has(target, key)) { |
||||
target[key] = val; |
||||
return val; |
||||
} |
||||
var ob = target.__ob__; |
||||
if (target._isVue || ob && ob.vmCount) { |
||||
return val; |
||||
} |
||||
if (!ob) { |
||||
target[key] = val; |
||||
return val; |
||||
} |
||||
defineReactive(ob.value, key, val); |
||||
ob.dep.notify(); |
||||
return val; |
||||
} |
||||
|
||||
/** |
||||
* Delete a property and trigger change if necessary. |
||||
*/ |
||||
function del(target, key) { |
||||
if (_.isArray(target)) { |
||||
target.splice(key, 1); |
||||
return; |
||||
} |
||||
var ob = target.__ob__; |
||||
if (target._isVue || ob && ob.vmCount) { |
||||
return; |
||||
} |
||||
if (!_.has(target, key)) { |
||||
return; |
||||
} |
||||
delete target[key]; |
||||
if (!ob) { |
||||
return; |
||||
} |
||||
ob.dep.notify(); |
||||
} |
||||
|
||||
/** |
||||
* Collect dependencies on array elements when the array is touched, since |
||||
* we cannot intercept array element access like property getters. |
||||
*/ |
||||
function dependArray(value) { |
||||
for (var e, i = 0, l = value.length; i < l; i++) { |
||||
e = value[i]; |
||||
e && e.__ob__ && e.__ob__.dep.depend(); |
||||
if (_.isArray(e)) { |
||||
dependArray(e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
var computedWatcherOptions = { lazy: true }; |
||||
|
||||
function initComputed(vm, computed) { |
||||
var watchers = vm._computedWatchers = {}; |
||||
|
||||
defineComputed(vm, computed); |
||||
|
||||
for (var key in computed) { |
||||
var userDef = computed[key]; |
||||
var getter = typeof userDef === 'function' ? _.bind(userDef, vm) : _.bind(userDef.get, vm); |
||||
|
||||
watchers[key] = new Watcher(vm.$$computed, getter || noop, noop, computedWatcherOptions); |
||||
} |
||||
} |
||||
|
||||
function defineComputed(target, computed) { |
||||
var props = {}; |
||||
var shouldCache = true; |
||||
for (var key in computed) { |
||||
if (!(key in target)) { |
||||
var sharedPropertyDefinition = { |
||||
enumerable: true, |
||||
configurable: true, |
||||
get: noop, |
||||
set: noop |
||||
}; |
||||
var userDef = computed[key]; |
||||
if (typeof userDef === 'function') { |
||||
sharedPropertyDefinition.get = createComputedGetter(target, key); |
||||
sharedPropertyDefinition.set = noop; |
||||
} else { |
||||
sharedPropertyDefinition.get = userDef.get ? shouldCache && userDef.cache !== false ? createComputedGetter(key) : userDef.get : noop; |
||||
sharedPropertyDefinition.set = userDef.set ? userDef.set : noop; |
||||
} |
||||
|
||||
props[key] = sharedPropertyDefinition; |
||||
} |
||||
} |
||||
target.$$computed = createViewModel$1({}, props); |
||||
} |
||||
|
||||
function createComputedGetter(vm, key) { |
||||
return function computedGetter() { |
||||
var watcher = vm._computedWatchers && vm._computedWatchers[key]; |
||||
if (watcher) { |
||||
if (watcher.dirty) { |
||||
watcher.evaluate(); |
||||
} |
||||
if (Dep.target) { |
||||
watcher.depend(); |
||||
} |
||||
return watcher.value; |
||||
} |
||||
}; |
||||
} |
||||
|
||||
function initMethods(vm, methods) { |
||||
for (var key in methods) { |
||||
vm[key] = methods[key] == null ? noop : _.bind(methods[key], vm); |
||||
} |
||||
} |
||||
|
||||
function createWatcher(vm, keyOrFn, handler, options) { |
||||
if (isPlainObject(handler)) { |
||||
options = handler; |
||||
handler = handler.handler; |
||||
} |
||||
if (typeof handler === 'string') { |
||||
handler = vm[handler]; |
||||
} |
||||
return vm.$watch(keyOrFn, handler, options); |
||||
} |
||||
|
||||
var VM = function () { |
||||
function VM(model) { |
||||
_classCallCheck(this, VM); |
||||
|
||||
var vm = this; |
||||
if (model instanceof Observer || model instanceof VM) { |
||||
model = model.model; |
||||
} |
||||
if (_.has(model, '__ob__')) { |
||||
this.$$model = model; |
||||
} else { |
||||
this.options = model || {}; |
||||
} |
||||
initComputed(this, this.computed); |
||||
initMethods(this, this.methods); |
||||
var keys = _.keys(this.$$model).concat(_.keys(this.computed)); |
||||
var props = {}; |
||||
|
||||
var _loop = function _loop(i, len) { |
||||
var key = keys[i]; |
||||
if (!(key in $$skipArray)) { |
||||
props[key] = { |
||||
enumerable: true, |
||||
configurable: true, |
||||
get: function get() { |
||||
return key in vm.$$computed ? vm.$$computed[key] : vm.$$model[key]; |
||||
}, |
||||
set: function set(val) { |
||||
if (!vm.$$model || !(key in vm.$$model)) { |
||||
return; |
||||
} |
||||
return vm.$$model[key] = val; |
||||
} |
||||
}; |
||||
} |
||||
}; |
||||
|
||||
for (var i = 0, len = keys.length; i < len; i++) { |
||||
_loop(i, len); |
||||
} |
||||
this.model = createViewModel$1({}, props); |
||||
this.$$model && (this.model.__ob__ = this.$$model.__ob__); |
||||
this._init(); |
||||
} |
||||
|
||||
VM.prototype.$watch = function $watch(expOrFn, cb, options) { |
||||
var vm = this; |
||||
if (isPlainObject(cb)) { |
||||
return createWatcher(vm, expOrFn, cb, options); |
||||
} |
||||
options = options || {}; |
||||
options.user = true; |
||||
var watcher = new Watcher(vm.model, expOrFn, _.bind(cb, vm), options); |
||||
if (options.immediate) { |
||||
cb.call(vm, watcher.value); |
||||
} |
||||
return function unwatchFn() { |
||||
watcher.teardown(); |
||||
}; |
||||
}; |
||||
|
||||
VM.prototype._init = function _init() {}; |
||||
|
||||
VM.prototype.destroy = function destroy() { |
||||
for (var _key2 in this._computedWatchers) { |
||||
this._computedWatchers[_key2].teardown(); |
||||
} |
||||
}; |
||||
|
||||
return VM; |
||||
}(); |
||||
|
||||
var version = '2.0'; |
||||
|
||||
exports.version = version; |
||||
exports.$$skipArray = $$skipArray; |
||||
exports.VM = VM; |
||||
exports.observerState = observerState; |
||||
exports.Observer = Observer; |
||||
exports.observe = observe; |
||||
exports.defineReactive = defineReactive; |
||||
exports.set = set; |
||||
exports.del = del; |
||||
exports.Watcher = Watcher; |
||||
|
||||
exports.__esModule = true; |
||||
}); |
@ -1,86 +0,0 @@
|
||||
/** |
||||
* |
||||
* @class BI.FloatBoxRouter |
||||
* @extends BI.WRouter |
||||
*/ |
||||
BI.FloatBoxRouter = BI.inherit(BI.WRouter, { |
||||
routes: {}, |
||||
|
||||
_init: function () { |
||||
this.store = {}; |
||||
this.views = {}; |
||||
}, |
||||
|
||||
createView: function (url, modelData, viewData, context) { |
||||
return BI.Factory.createView(url, this.get(url), modelData || {}, viewData || {}, context) |
||||
}, |
||||
|
||||
open: function (url, modelData, viewData, context, options) { |
||||
var self = this, isValid = BI.isKey(modelData); |
||||
options || (options = {}); |
||||
url = context.rootURL + "/" + url; |
||||
var data = void 0; |
||||
if (isValid) { |
||||
modelData = modelData + "";//避免modelData是数字
|
||||
var keys = modelData.split('.'); |
||||
BI.each(keys, function (i, k) { |
||||
if (i === 0) { |
||||
data = context.model.get(k) || {}; |
||||
} else { |
||||
data = data[k] || {}; |
||||
} |
||||
}); |
||||
data.id = options.id || keys[keys.length - 1]; |
||||
} else { |
||||
data = modelData; |
||||
} |
||||
BI.extend(data, options.data); |
||||
if (!this.controller) { |
||||
this.controller = new BI.FloatBoxController(); |
||||
} |
||||
if (!this.store[url]) { |
||||
this.store[url] = BI.createWidget({ |
||||
type: "bi.float_box" |
||||
}, options); |
||||
var view = this.createView(url, data, viewData, context); |
||||
isValid && context.model.addChild(modelData, view.model); |
||||
view.listenTo(view.model, "destroy", function () { |
||||
self.remove(url, context); |
||||
}); |
||||
context.on(BI.Events.UNMOUNT, function () { |
||||
self.remove(url, context); |
||||
}); |
||||
this.store[url].populate(view); |
||||
this.views[url] = view; |
||||
this.controller.add(url, this.store[url]); |
||||
context && context.on("end:" + view.cid, function () { |
||||
BI.nextTick(function () { |
||||
self.close(url); |
||||
// view.end();
|
||||
(context.listenEnd.apply(context, isValid ? modelData.split('.') : [modelData]) !== false) && context.populate(); |
||||
}, 30) |
||||
}).on("change:" + view.cid, _.bind(context.notifyParent, context)) |
||||
} |
||||
this.controller.open(url); |
||||
this.views[url].populate(data, options.force || true); |
||||
return this; |
||||
}, |
||||
|
||||
close: function (url) { |
||||
if (this.controller) { |
||||
this.controller.close(url); |
||||
} |
||||
return this; |
||||
}, |
||||
|
||||
remove: function (url, context) { |
||||
url = context.rootURL + "/" + url; |
||||
if (this.controller) { |
||||
this.controller.remove(url); |
||||
delete this.store[url]; |
||||
this.views[url] && this.views[url].model.destroy(); |
||||
delete this.views[url]; |
||||
} |
||||
return this; |
||||
} |
||||
}); |
@ -1,38 +0,0 @@
|
||||
/** |
||||
* 统一绑定事件 |
||||
* @type {*|void|Object} |
||||
*/ |
||||
BI.EventList = BI.inherit(BI.OB, { |
||||
_defaultConfig: function() { |
||||
return BI.extend(BI.EventList.superclass._defaultConfig.apply(this, arguments), { |
||||
event: "click", |
||||
callback: BI.emptyFn, |
||||
handle: "", |
||||
items:[] |
||||
}); |
||||
}, |
||||
|
||||
_init : function() { |
||||
BI.EventList.superclass._init.apply(this, arguments); |
||||
this.populate(this.options.items); |
||||
}, |
||||
|
||||
_getHandle: function(item){ |
||||
var handle = this.options.handle ? _.result(item, this.options.handle) : item; |
||||
return handle.element || handle; |
||||
}, |
||||
|
||||
populate: function(items){ |
||||
var self = this, |
||||
event = this.options.event, |
||||
callback = this.options.callback; |
||||
BI.nextTick(function(){ |
||||
BI.each(items, function(i, item){ |
||||
var fn = callback(item); |
||||
BI.isFunction(fn) && (fn = BI.debounce(fn, BI.EVENT_RESPONSE_TIME, true)); |
||||
self._getHandle(item)[event](fn); |
||||
}) |
||||
}) |
||||
|
||||
} |
||||
}); |
@ -1,36 +0,0 @@
|
||||
/** |
||||
* 统一监听jquery事件 |
||||
* @type {*|void|Object} |
||||
*/ |
||||
BI.ListenerList = BI.inherit(BI.OB, { |
||||
_defaultConfig: function() { |
||||
return BI.extend(BI.ListenerList.superclass._defaultConfig.apply(this, arguments), { |
||||
event: "click", |
||||
callback: BI.emptyFn, |
||||
items:[] |
||||
}); |
||||
}, |
||||
|
||||
_init : function() { |
||||
BI.ListenerList.superclass._init.apply(this, arguments); |
||||
this.populate(this.options.items); |
||||
}, |
||||
|
||||
_getHandle: function(item){ |
||||
var handle = this.options.handle ? _.result(item, this.options.handle) : item; |
||||
return handle.element || handle; |
||||
}, |
||||
|
||||
populate: function(items){ |
||||
var self = this, |
||||
event = this.options.event, |
||||
callback = this.options.callback; |
||||
BI.nextTick(function(){ |
||||
BI.each(items, function(i, item){ |
||||
var fn = callback(item); |
||||
BI.isFunction(fn) && (fn = BI.debounce(fn, BI.EVENT_RESPONSE_TIME, true)); |
||||
self._getHandle(item).on(event, fn); |
||||
}) |
||||
}) |
||||
} |
||||
}); |
@ -1,33 +0,0 @@
|
||||
/** |
||||
* Created by GUY on 2015/6/25. |
||||
*/ |
||||
/** |
||||
* 统一监听jquery事件 |
||||
* @type {*|void|Object} |
||||
*/ |
||||
BI.OffList = BI.inherit(BI.OB, { |
||||
_defaultConfig: function() { |
||||
return BI.extend(BI.OffList.superclass._defaultConfig.apply(this, arguments), { |
||||
event: "click", |
||||
items:[] |
||||
}); |
||||
}, |
||||
|
||||
_init : function() { |
||||
BI.OffList.superclass._init.apply(this, arguments); |
||||
this.populate(this.options.items); |
||||
}, |
||||
|
||||
_getHandle: function(item){ |
||||
var handle = this.options.handle ? _.result(item, this.options.handle) : item; |
||||
return handle.element || handle; |
||||
}, |
||||
|
||||
populate: function(items){ |
||||
var self = this, |
||||
event = this.options.event; |
||||
BI.each(items, function(i, item){ |
||||
self._getHandle(item).off(event); |
||||
}) |
||||
} |
||||
}); |
@ -1,518 +0,0 @@
|
||||
BI.Model = BI.inherit(BI.M, { |
||||
props: {}, |
||||
init: null, |
||||
destroyed: null, |
||||
|
||||
_defaultConfig: function () { |
||||
return BI.extend({ |
||||
"default": "just a default", |
||||
"current": void 0 |
||||
}, this.props) |
||||
}, |
||||
|
||||
_static: function () { |
||||
return {}; |
||||
}, |
||||
|
||||
_init: function () { |
||||
BI.Model.superclass._init.apply(this, arguments); |
||||
this.on("change:current", function (obj, val) { |
||||
BI.isNotNull(val) && this.refresh(val); |
||||
}).on("change", function (changed, prev, context, options) { |
||||
if (this._start === true || BI.has(changed, "current")) { |
||||
return; |
||||
} |
||||
this.actionStart(); |
||||
if (!this.local()) { |
||||
!BI.has(this._tmp, BI.keys(changed)) && this.parent && this.parent._change(this); |
||||
this._changing_ = true; |
||||
this.change(changed, prev, context, options); |
||||
this._changing_ = false; |
||||
} |
||||
}); |
||||
|
||||
this._tmp = {};//过渡属性
|
||||
|
||||
this._hass = {}; |
||||
this._gets = [];//记录交互行为
|
||||
this._start = false; |
||||
this._changing_ = false; |
||||
|
||||
this._read = BI.debounce(BI.bind(this.fetch, this), 30); |
||||
this._save = BI.debounce(BI.bind(this.save, this), 30); |
||||
this._F = []; |
||||
this.init && this.init(); |
||||
}, |
||||
|
||||
toJSON: function () { |
||||
var json = BI.Model.superclass.toJSON.apply(this, arguments); |
||||
delete json["baseCls"]; |
||||
delete json["current"]; |
||||
delete json["default"]; |
||||
delete json["parent"]; |
||||
delete json["rootURL"]; |
||||
delete json["id"]; |
||||
delete json["tag"]; |
||||
BI.each(this._gets, function (i, action) { |
||||
delete json[action]; |
||||
}); |
||||
return json; |
||||
}, |
||||
|
||||
copy: function () { |
||||
if (this._start === true || this._changing_ === true) { |
||||
this._F.push({f: this.copy, arg: arguments}); |
||||
return; |
||||
} |
||||
this.trigger("copy"); |
||||
}, |
||||
//子节点的一个类似副本
|
||||
similar: function (value, key1, key2, key3) { |
||||
return value; |
||||
}, |
||||
|
||||
_map: function (child) { |
||||
var self = this; |
||||
var map = {}, current = {}; |
||||
var mapping = function (key, ch) { |
||||
key = key + ""; |
||||
if (key === "") { |
||||
return; |
||||
} |
||||
var keys = key.split('.'); |
||||
if (!map[keys[0]]) { |
||||
map[keys[0]] = self.get(keys[0]); |
||||
} |
||||
var parent = map, last = void 0; |
||||
BI.each(keys, function (i, k) { |
||||
last && (parent = parent[last] || (parent[last] = {})); |
||||
last = k; |
||||
}); |
||||
parent[last] = ch.toJSON(); |
||||
}; |
||||
BI.each(this._childs, function (key, chs) { |
||||
if (!BI.isArray(chs)) { |
||||
chs = [chs]; |
||||
} |
||||
BI.each(chs, function (i, ch) { |
||||
if (ch === child) { |
||||
current[key] = child; |
||||
return; |
||||
} |
||||
//mapping(key, ch);
|
||||
}) |
||||
}); |
||||
BI.each(current, function (key, ch) { |
||||
mapping(key, ch); |
||||
}); |
||||
var tmp = {}; |
||||
BI.each(this._tmp, function (k) { |
||||
if (map[k]) { |
||||
tmp[k] = map[k]; |
||||
delete map[k]; |
||||
} |
||||
}); |
||||
this.tmp(tmp); |
||||
return map; |
||||
}, |
||||
|
||||
_change: function (child) { |
||||
var self = this; |
||||
var childMap = this._map(child); |
||||
//this.set(childMap);
|
||||
var changes = []; |
||||
var changing = this._changing; |
||||
var changed; |
||||
var options = {}; |
||||
this._changing = true; |
||||
if (!changing) { |
||||
this._previousAttributes = _.clone(this.attributes); |
||||
this.changed = {}; |
||||
} |
||||
var current = this.attributes, prev = this._previousAttributes, val; |
||||
for (var attr in childMap) { |
||||
val = childMap[attr]; |
||||
changes.push(attr); |
||||
this.changed[attr] = val; |
||||
current[attr] = val; |
||||
} |
||||
if (changes.length) this._pending = options; |
||||
for (var i = 0, length = changes.length; i < length; i++) { |
||||
this.trigger('change:' + changes[i], this, current[changes[i]], options); |
||||
} |
||||
if (changing) return this; |
||||
changed = BI.clone(this.changed); |
||||
while (this._pending) { |
||||
options = this._pending; |
||||
this._pending = false; |
||||
this.trigger('change', changed, prev, this, options); |
||||
} |
||||
this._pending = false; |
||||
this._changing = false; |
||||
if (changes.length) { |
||||
this.trigger("changed", changed, prev, this, options); |
||||
} |
||||
return this; |
||||
}, |
||||
|
||||
splice: function (old, key1, key2, key3) { |
||||
|
||||
}, |
||||
|
||||
duplicate: function (copy, key1, key2, key3) { |
||||
|
||||
}, |
||||
|
||||
change: function (changed, prev) { |
||||
|
||||
}, |
||||
|
||||
actionStart: function () { |
||||
this._start = true; |
||||
return this; |
||||
}, |
||||
|
||||
actionEnd: function () { |
||||
var self = this; |
||||
this._start = false; |
||||
var _gets = this._gets.slice(0), _F = this._F.slice(0); |
||||
this._gets = []; |
||||
this._hass = {}; |
||||
this._F = []; |
||||
BI.each(_gets, function (i, action) { |
||||
self.unset(action, {silent: true}); |
||||
}); |
||||
BI.each(_F, function (i, fn) { |
||||
fn.f.apply(self, fn.arg); |
||||
}); |
||||
return this; |
||||
}, |
||||
|
||||
addChild: function (name, child) { |
||||
name = name + ""; |
||||
var self = this; |
||||
this._childs || (this._childs = {}); |
||||
if (this._childs[name]) { |
||||
if (BI.isArray(this._childs[name])) { |
||||
this._childs[name].push(child); |
||||
} else { |
||||
this._childs[name] = [this._childs[name]].concat(child) |
||||
} |
||||
} else { |
||||
this._childs[name] = child; |
||||
} |
||||
child && child.on("destroy", function () { |
||||
var keys = name.split('.'); |
||||
var g = self.get(keys[0]), p, c; |
||||
var sset = !!self._tmp[keys[0]] ? "tmp" : "set", unset = "un" + sset; |
||||
|
||||
BI.each(keys, function (i, k) { |
||||
if (i === 0) { |
||||
c = g; |
||||
return; |
||||
} |
||||
p = c; |
||||
c = c[k]; |
||||
}); |
||||
self.removeChild(name, child); |
||||
var newKeys = BI.clone(keys); |
||||
keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g)); |
||||
keys.length > 1 ? (delete p[keys[keys.length - 1]], self[sset](keys[0], g, {silent: true})) : self[unset](name, {silent: true}); |
||||
!BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self); |
||||
self.splice.apply(self, newKeys); |
||||
self.trigger("splice", newKeys); |
||||
BI.remove(self._childs, child); |
||||
}).on("copy", function () { |
||||
var keys = name.split('.'); |
||||
var g = self.get(keys[0]), p, c; |
||||
var sset = !!self._tmp[keys[0]] ? "tmp" : "set"; |
||||
BI.each(keys, function (i, k) { |
||||
if (i === 0) { |
||||
c = g; |
||||
return; |
||||
} |
||||
p = c; |
||||
c = c[k]; |
||||
}); |
||||
var copy = BI.UUID(), newKeys = BI.clone(keys); |
||||
keys.length > 1 ? newKeys.unshift(BI.deepClone(p[keys[keys.length - 1]])) : newKeys.unshift(BI.deepClone(g)); |
||||
var backup = self.similar.apply(self, newKeys); |
||||
if (BI.isKey(backup.id)) { |
||||
copy = backup.id; |
||||
delete backup.id; |
||||
} |
||||
keys.length > 1 ? (p[copy] = backup, self[sset](keys[0], g, {silent: true})) : self[sset](copy, backup, {silent: true}); |
||||
keys.unshift(copy); |
||||
!BI.has(self._tmp, keys[0]) && self.parent && self.parent._change(self); |
||||
self.duplicate.apply(self, keys); |
||||
self.trigger("duplicate", keys); |
||||
}); |
||||
}, |
||||
|
||||
removeChild: function (name, child) { |
||||
if (BI.isArray(this._childs[name])) { |
||||
BI.remove(this._childs[name], child); |
||||
if (BI.isEmpty(this._childs[name])) { |
||||
delete this._childs[name]; |
||||
} |
||||
return; |
||||
} |
||||
delete this._childs[name]; |
||||
}, |
||||
|
||||
has: function (attr, istemp) { |
||||
if (istemp === true) { |
||||
return _.has(this.tmp, attr); |
||||
} |
||||
if (this._start === true && this._changing_ === false) { |
||||
this._hass[attr] = true; |
||||
} |
||||
return BI.Model.superclass.has.apply(this, arguments); |
||||
}, |
||||
|
||||
cat: function (attr) { |
||||
if (_.has(this._tmp, attr)) { |
||||
return this._tmp[attr]; |
||||
} |
||||
if (this._start === true && this._hass[attr]) { |
||||
delete this._hass[attr]; |
||||
switch (attr) { |
||||
case "default": |
||||
break; |
||||
case "current": |
||||
break; |
||||
default : |
||||
this._gets.push(attr); |
||||
break; |
||||
} |
||||
} |
||||
if (_.has(this.attributes, attr)) { |
||||
return this.attributes[attr]; |
||||
} |
||||
var sta = _.result(this, "_static"); |
||||
return BI.isFunction(sta[attr]) ? sta[attr].apply(this, Array.prototype.slice.apply(arguments, [1])) : sta[attr]; |
||||
}, |
||||
|
||||
get: function () { |
||||
return BI.deepClone(this.cat.apply(this, arguments)); |
||||
}, |
||||
|
||||
set: function (key, val, options) { |
||||
if (this._start === true || this._changing_ === true) { |
||||
this._F.push({f: this.set, arg: arguments}); |
||||
return this; |
||||
} |
||||
return BI.Model.superclass.set.apply(this, arguments); |
||||
}, |
||||
|
||||
unset: function (attr, options) { |
||||
var self = this; |
||||
BI.each(this._childs, function (key, model) { |
||||
key = key + ""; |
||||
var keys = key.split('.'); |
||||
if (_.isEqual(attr, keys[0])) { |
||||
delete self._childs[attr]; |
||||
if (!BI.isArray(model)) { |
||||
model = [model]; |
||||
} |
||||
BI.each(model, function (i, m) { |
||||
m.trigger("unset"); |
||||
}); |
||||
} |
||||
}); |
||||
return BI.Model.superclass.unset.apply(this, arguments); |
||||
}, |
||||
|
||||
tmp: function (key, val, options) { |
||||
if (this._start === true || this._changing_ === true) { |
||||
this._F.push({f: this.tmp, arg: arguments}); |
||||
return this; |
||||
} |
||||
var attr, attrs, unset, changes, silent, changing, changed, prev, current; |
||||
if (key == null) return this; |
||||
if (typeof key === 'object') { |
||||
attrs = key; |
||||
options = val; |
||||
} else { |
||||
(attrs = {})[key] = val; |
||||
} |
||||
options || (options = {}); |
||||
|
||||
unset = options.unset; |
||||
silent = options.silent; |
||||
changes = []; |
||||
changing = this._changingTmp; |
||||
this._changingTmp = true; |
||||
|
||||
if (!changing) { |
||||
this._previousTmp = _.clone(this._tmp); |
||||
this.changedTmp = {}; |
||||
} |
||||
if (!this._previousTmp) { |
||||
this._previousTmp = _.clone(this._tmp); |
||||
} |
||||
current = this._tmp, prev = this._previousTmp; |
||||
|
||||
for (attr in attrs) { |
||||
val = attrs[attr]; |
||||
if (!_.isEqual(current[attr], val)) changes.push(attr); |
||||
if (!_.isEqual(prev[attr], val)) { |
||||
this.changedTmp[attr] = val; |
||||
} else { |
||||
delete this.changedTmp[attr]; |
||||
} |
||||
unset ? delete current[attr] : current[attr] = val; |
||||
} |
||||
|
||||
if (!silent) { |
||||
if (changes.length) this._pendingTmp = options; |
||||
for (var i = 0, length = changes.length; i < length; i++) { |
||||
this.trigger('change:' + changes[i], this, current[changes[i]], options); |
||||
} |
||||
} |
||||
|
||||
if (changing) return this; |
||||
changed = BI.clone(this.changedTmp); |
||||
if (!silent) { |
||||
while (this._pendingTmp) { |
||||
options = this._pendingTmp; |
||||
this._pendingTmp = false; |
||||
this.trigger('change', changed, prev, this, options); |
||||
} |
||||
} |
||||
this._pendingTmp = false; |
||||
this._changingTmp = false; |
||||
if (!silent && changes.length) this.trigger("changed", changed, prev, this, options); |
||||
return this; |
||||
}, |
||||
|
||||
untmp: function (attr, options) { |
||||
var self = this; |
||||
BI.each(this._childs, function (key, model) { |
||||
key = key + ""; |
||||
var keys = key.split('.'); |
||||
if (_.isEqual(attr, keys[0])) { |
||||
delete self._childs[attr]; |
||||
if (!BI.isArray(model)) { |
||||
model = [model]; |
||||
} |
||||
BI.each(model, function (i, m) { |
||||
m.trigger("unset"); |
||||
}); |
||||
} |
||||
}); |
||||
return this.tmp(attr, void 0, _.extend({}, options, {unset: true})); |
||||
}, |
||||
|
||||
cancel: function (options) { |
||||
var self = this; |
||||
var tmp = BI.clone(this._tmp); |
||||
this._tmp = {}; |
||||
BI.each(tmp, function (k) { |
||||
self.untmp(k, options); |
||||
}); |
||||
}, |
||||
|
||||
submit: function () { |
||||
var tmp = BI.clone(this._tmp); |
||||
this._tmp = {}; |
||||
this.set(tmp); |
||||
return this; |
||||
}, |
||||
|
||||
urlRoot: function () { |
||||
return BI.servletURL; |
||||
}, |
||||
|
||||
parse: function (data) { |
||||
return data; |
||||
}, |
||||
|
||||
setEditing: function (edit) { |
||||
this._editing = edit; |
||||
}, |
||||
|
||||
getEditing: function () { |
||||
if (this._start !== true) { |
||||
throw new Error("getEditing函数只允许在local中调用"); |
||||
} |
||||
return this._editing; |
||||
}, |
||||
|
||||
local: function () { |
||||
|
||||
}, |
||||
|
||||
load: function (data) { |
||||
|
||||
}, |
||||
|
||||
refresh: function () { |
||||
|
||||
}, |
||||
|
||||
/** |
||||
* 更新整个model |
||||
*/ |
||||
updateURL: function () { |
||||
|
||||
}, |
||||
/** |
||||
* 添加一个元素或删除一个元素或修改一个元素 |
||||
*/ |
||||
patchURL: function () { |
||||
|
||||
}, |
||||
/** |
||||
* 删除整个model, destroy方法调用 |
||||
*/ |
||||
deleteURL: function () { |
||||
|
||||
}, |
||||
/** |
||||
* 读取model |
||||
*/ |
||||
readURL: function () { |
||||
|
||||
}, |
||||
|
||||
read: function (options) { |
||||
if (this._start == true || this._changing_ === true) { |
||||
this._F.push({f: this.read, arg: arguments}); |
||||
return; |
||||
} |
||||
this._read(options); |
||||
}, |
||||
|
||||
update: function (options) { |
||||
if (this._start == true || this._changing_ === true) { |
||||
this._F.push({f: this.update, arg: arguments}); |
||||
return; |
||||
} |
||||
this._save(null, options); |
||||
}, |
||||
|
||||
patch: function (options) { |
||||
if (this._start == true || this._changing_ === true) { |
||||
this._F.push({f: this.patch, arg: arguments}); |
||||
return; |
||||
} |
||||
this._save(null, BI.extend({}, options, { |
||||
patch: true |
||||
})); |
||||
}, |
||||
|
||||
_destroy: function () { |
||||
var children = BI.extend({}, this._childs); |
||||
this._childs = {}; |
||||
BI.each(children, function (i, child) { |
||||
child._destroy(); |
||||
}); |
||||
this.destroyed && this.destroyed(); |
||||
}, |
||||
|
||||
destroy: function () { |
||||
this._destroy(); |
||||
BI.Model.superclass.destroy.apply(this, arguments); |
||||
} |
||||
}); |
@ -1,44 +0,0 @@
|
||||
/** |
||||
* MVC工厂 |
||||
* guy |
||||
* @class BI.Factory |
||||
*/ |
||||
BI.Factory = { |
||||
parsePath: function parsePath (path) { |
||||
var segments = path.split('.'); |
||||
return function (obj) { |
||||
for (var i = 0; i < segments.length; i++) { |
||||
if (!obj) { |
||||
return; |
||||
} |
||||
obj = obj[segments[i]]; |
||||
} |
||||
return obj; |
||||
} |
||||
}, |
||||
createView : function(url, viewFunc, mData, vData, context){ |
||||
var modelFunc = viewFunc.replace(/View/, "Model"); |
||||
modelFunc = this.parsePath(modelFunc)(window); |
||||
if(!_.isFunction(modelFunc)){ |
||||
modelFunc = BI.Model; |
||||
} |
||||
// try {
|
||||
var model = new (modelFunc)(_.extend({}, mData, { |
||||
parent: context && context.model, |
||||
rootURL: url |
||||
}), {silent: true}); |
||||
// } catch (e) {
|
||||
//
|
||||
// }
|
||||
// try {
|
||||
var view = new (this.parsePath(viewFunc)(window))(_.extend({}, vData, { |
||||
model: model, |
||||
parent: context, |
||||
rootURL: url |
||||
})); |
||||
// } catch (e) {
|
||||
//
|
||||
// }
|
||||
return view; |
||||
} |
||||
}; |
@ -1,48 +0,0 @@
|
||||
/** |
||||
* MVC路由 |
||||
* @class BI.WRouter |
||||
* @extends BI.Router |
||||
* @type {*|void|Object} |
||||
*/ |
||||
BI.WRouter = BI.Router.extend({ |
||||
add: function(route, callback){ |
||||
this.handlers || (this.handlers=[]); |
||||
this.handlers.unshift({route: route, callback: callback}) |
||||
}, |
||||
|
||||
route: function(route, name, callback) { |
||||
if (!_.isRegExp(route)) route = this._routeToRegExp(route); |
||||
if (_.isFunction(name)) { |
||||
callback = name; |
||||
name = ''; |
||||
} |
||||
if (!callback) callback = this[name]; |
||||
var self = this; |
||||
this.add(route, function(fragment) { |
||||
var args = self._extractParameters(route, fragment); |
||||
var result = self.execute(callback, args, name) |
||||
if (result !== false) { |
||||
self.trigger.apply(self, ['route:' + name].concat(args)); |
||||
self.trigger('route', name, args); |
||||
} |
||||
return result; |
||||
}); |
||||
return this; |
||||
}, |
||||
|
||||
execute: function(callback, args, name) { |
||||
if (callback) return callback.apply(this, args); |
||||
return name; |
||||
}, |
||||
|
||||
get: function(fragment){ |
||||
var result = null; |
||||
_.any(this.handlers, function(handler) { |
||||
if (handler.route.test(fragment)) { |
||||
result = handler.callback(fragment); |
||||
return true; |
||||
} |
||||
}); |
||||
return result; |
||||
} |
||||
}); |
@ -0,0 +1,45 @@
|
||||
//缓存this.element的操作数据
|
||||
if (jQuery) { |
||||
function wrap(prefix, name) { |
||||
return "_bi-widget" + prefix + name; |
||||
} |
||||
|
||||
(function ($) { |
||||
var css = $.fn.css; |
||||
$.fn.css = function (name, value) { |
||||
if (this._isWidget === true) { |
||||
var key; |
||||
//this.element不允许get样式
|
||||
if (BI.isPlainObject(name)) { |
||||
for (key in name) { |
||||
this.css(key, name[key]); |
||||
} |
||||
return this; |
||||
} |
||||
key = wrap("css", name); |
||||
if (this[key] !== value) { |
||||
css.apply(this, arguments); |
||||
this[key] = value; |
||||
return this; |
||||
} |
||||
return this; |
||||
} |
||||
return css.apply(this, arguments); |
||||
}; |
||||
$.each(["width", "height", "innerWidth", "innerHeight", "outerWidth", "outerHeight"], function (index, name) { |
||||
var fn = $.fn[name]; |
||||
$.fn[name] = function (value) { |
||||
if (this._isWidget === true && arguments.length === 1) { |
||||
var key = wrap("", name); |
||||
if (this[key] !== value) { |
||||
fn.apply(this, arguments); |
||||
this[key] = value; |
||||
return this; |
||||
} |
||||
return this; |
||||
} |
||||
return fn.apply(this, arguments); |
||||
} |
||||
}) |
||||
})(jQuery); |
||||
} |
@ -1,536 +0,0 @@
|
||||
/** |
||||
* @class BI.View |
||||
* @extends BI.V |
||||
* @type {*|void|Object} |
||||
*/ |
||||
BI.View = BI.inherit(BI.V, { |
||||
|
||||
//生命周期函数
|
||||
beforeCreate: null, |
||||
|
||||
created: null, |
||||
|
||||
beforeDestroy: null, |
||||
|
||||
destroyed: null, |
||||
|
||||
_init: function () { |
||||
BI.View.superclass._init.apply(this, arguments); |
||||
this.beforeCreate && this.beforeCreate(); |
||||
var self = this; |
||||
this.listenTo(this.model, "change:current", function (obj, val) { |
||||
if (BI.isNotNull(val) && val.length > 0) { |
||||
this.refresh(val); |
||||
} |
||||
}).listenTo(this.model, "change", function (changed) { |
||||
this.delegateEvents(); |
||||
}).listenTo(this.model, "changed", function (changed, prev, context, options) { |
||||
if (BI.has(changed, "current") && BI.size(changed) > 1) { |
||||
throw new Error("refresh操作不能调用set操作"); |
||||
} |
||||
var notLocal = !BI.has(changed, "current") && !this.local() && this.notifyParent().notify(); |
||||
this.model.actionEnd() && this.actionEnd(); |
||||
this.model._changing_ = true; |
||||
notLocal && !BI.isEmpty(changed) && this.change(changed, prev, context, options); |
||||
this.model._changing_ = false; |
||||
this.model.actionEnd() && this.actionEnd(); |
||||
}).listenTo(this.model, "destroy", function () { |
||||
this._destroy(); |
||||
}).listenTo(this.model, "unset", function () { |
||||
this._destroy(); |
||||
}).listenTo(this.model, "splice", function (arg) { |
||||
this.splice.apply(this, arg); |
||||
}).listenTo(this.model, "duplicate", function (arg) { |
||||
this.duplicate.apply(this, arg); |
||||
}); |
||||
this._F = []; |
||||
var flatten = ["_init", "_defaultConfig", "_vessel", "_render", "getName", "listenEnd", "local", "refresh", "load", "change"]; |
||||
flatten = BI.makeObject(flatten, true); |
||||
BI.each(this.constructor.caller.caller.prototype, function (key) { |
||||
if (flatten[key]) { |
||||
return; |
||||
} |
||||
var f = self[key]; |
||||
if (BI.isFunction(f)) { |
||||
self[key] = BI.bind(function () { |
||||
if (this.model._start === true) { |
||||
this._F.push({f: f, arg: arguments}); |
||||
return; |
||||
} |
||||
return f.apply(this, arguments); |
||||
}, self); |
||||
} |
||||
}); |
||||
this.created && this.created(); |
||||
}, |
||||
|
||||
change: function (changed, prev) { |
||||
|
||||
}, |
||||
|
||||
actionEnd: function () { |
||||
var self = this; |
||||
var _F = this._F.slice(0); |
||||
this._F = []; |
||||
BI.each(_F, function (i, f) { |
||||
f.f.apply(self, f.arg); |
||||
}); |
||||
return this; |
||||
}, |
||||
|
||||
delegateEvents: function (events) { |
||||
if (!(events || (events = BI.deepClone(_.result(this, 'events'))))) return this; |
||||
var delegateEventSplitter = /^(\S+)\s*(.*)$/; |
||||
for (var key in events) { |
||||
var method = events[key]; |
||||
if (!_.isFunction(method)) method = this[events[key]]; |
||||
if (!method) continue; |
||||
var match = key.match(delegateEventSplitter); |
||||
var ev = true; |
||||
switch (match[1]) { |
||||
case "draggable": |
||||
break; |
||||
case "droppable": |
||||
break; |
||||
case "sortable": |
||||
break; |
||||
case "resizable": |
||||
break; |
||||
case "hover": |
||||
break; |
||||
default : |
||||
ev = false; |
||||
break; |
||||
} |
||||
|
||||
var off = new BI.OffList({ |
||||
event: match[1] + '.delegateEvents' + this.cid |
||||
}); |
||||
|
||||
var keys = match[2].split('.'); |
||||
var handle = keys[1]; |
||||
var bind = ev ? new BI.EventList({ |
||||
event: match[1], |
||||
handle: handle, |
||||
callback: BI.bind(method, this) |
||||
}) : new BI.ListenerList({ |
||||
event: match[1] + '.delegateEvents' + this.cid, |
||||
handle: handle, |
||||
callback: BI.bind(method, this), |
||||
context: this |
||||
}); |
||||
|
||||
var list = []; |
||||
if (this[keys[0]] && (this[keys[0]] instanceof $ || this[keys[0]].element instanceof $)) { |
||||
list = [this[keys[0]]] |
||||
delete events[key]; |
||||
} else if (BI.isArray(this[keys[0]]) || BI.isPlainObject(this[keys[0]])) { |
||||
list = this[keys[0]] |
||||
delete events[key]; |
||||
} |
||||
off.populate(list); |
||||
bind.populate(list); |
||||
} |
||||
return BI.View.superclass.delegateEvents.apply(this, [events]); |
||||
}, |
||||
|
||||
_vessel: function () { |
||||
this._cardLayouts = {}; |
||||
this._cardLayouts[this.getName()] = new BI.CardLayout({ |
||||
element: this |
||||
}); |
||||
var vessel = BI.createWidget(); |
||||
this._cardLayouts[this.getName()].addCardByName(this.getName(), vessel); |
||||
return vessel; |
||||
}, |
||||
|
||||
render: function (vessel) { |
||||
return this; |
||||
}, |
||||
|
||||
/** |
||||
* 创建儿子所在容器 |
||||
* @param key |
||||
* @param vessel |
||||
* @param options isLayer:是否是弹出层, defaultShowName:默认显示项 |
||||
* @returns {BI.View} |
||||
*/ |
||||
addSubVessel: function (key, vessel, options) { |
||||
options || (options = {}); |
||||
this._cardLayouts || (this._cardLayouts = {}); |
||||
var id = key + this.cid; |
||||
options.isLayer && (vessel = BI.Layers.has(id) ? BI.Layers.get(id) : BI.Layers.create(id, vessel)); |
||||
if (this._cardLayouts[key]) { |
||||
options.defaultShowName && this._cardLayouts[key].setDefaultShowName(options.defaultShowName); |
||||
return this; |
||||
} |
||||
this._cardLayouts[key] = BI.createWidget({ |
||||
type: "bi.card", |
||||
element: vessel, |
||||
defaultShowName: options.defaultShowName |
||||
}); |
||||
return this; |
||||
}, |
||||
|
||||
removeSubVessel: function (key) { |
||||
var self = this, id = key + this.cid; |
||||
BI.Layers.remove(id); |
||||
var cardNames = this._cardLayouts[key] && this._cardLayouts[key].getAllCardNames(); |
||||
BI.each(cardNames, function (i, name) { |
||||
delete self._cards[name]; |
||||
}); |
||||
this._cardLayouts[key] && this._cardLayouts[key]._destroy(); |
||||
return this; |
||||
}, |
||||
|
||||
createView: function (url, modelData, viewData, context) { |
||||
return BI.Factory.createView(url, this.get(url), modelData, viewData, context); |
||||
}, |
||||
|
||||
/** |
||||
* 跳转到指定的card |
||||
* @param cardName |
||||
*/ |
||||
skipTo: function (cardName, layout, modelData, viewData, options) { |
||||
if (this.model._start === true || this._changing_ === true) { |
||||
this._F.push({f: this.skipTo, arg: arguments}); |
||||
return this; |
||||
} |
||||
var self = this, isValid = BI.isKey(modelData), data = void 0; |
||||
BI.isKey(layout) && (layout = layout + ""); |
||||
layout = layout || this.getName(); |
||||
options || (options = {}); |
||||
if (isValid) { |
||||
modelData = modelData + "";//避免modelData是数字
|
||||
var keys = modelData.split('.'); |
||||
BI.each(keys, function (i, k) { |
||||
if (i === 0) { |
||||
data = self.model.get(k) || {}; |
||||
} else { |
||||
data = data[k] || {}; |
||||
} |
||||
}); |
||||
data.id = options.id || keys[keys.length - 1]; |
||||
} else { |
||||
data = modelData; |
||||
} |
||||
BI.extend(data, options.data); |
||||
var action = options.action || new BI.ShowAction(); |
||||
var cardLayout = this._cardLayouts[layout]; |
||||
if (!cardLayout) { |
||||
return this; |
||||
} |
||||
cardLayout.setVisible(true); |
||||
if (BI.isKey(cardName) && !cardLayout.isCardExisted(cardName)) { |
||||
var view = this.createView(this.rootURL + "/" + cardName, data, viewData, this); |
||||
isValid && this.model.addChild(modelData, view.model); |
||||
view.listenTo(view.model, "destroy", function () { |
||||
delete self._cards[cardName]; |
||||
cardLayout.deleteCardByName(cardName); |
||||
if (cardLayout.isAllCardHide()) { |
||||
cardLayout.setVisible(false); |
||||
BI.Layers.hide(layout + self.cid); |
||||
} |
||||
}).listenTo(view.model, "unset", function () { |
||||
delete self._cards[cardName]; |
||||
cardLayout.deleteCardByName(cardName); |
||||
}); |
||||
cardLayout.addCardByName(cardName, view); |
||||
this._cards || (this._cards = {}); |
||||
this._cards[cardName] = view; |
||||
data = {}; |
||||
this.on("end:" + view.cid, function () { |
||||
var isNew = false, t, keys; |
||||
if (isValid) { |
||||
keys = modelData.split('.'); |
||||
BI.each(keys, function (i, k) { |
||||
if (i === 0) { |
||||
t = self.model.get(k) || (isNew = true); |
||||
} else { |
||||
t = t[k] || (isNew = true); |
||||
} |
||||
}); |
||||
} |
||||
if (isNew) { |
||||
delete self._cards[cardName]; |
||||
self.model.removeChild(modelData, view.model); |
||||
cardLayout.deleteCardByName(cardName); |
||||
view._destroy(); |
||||
cardLayout.setVisible(false); |
||||
} |
||||
action.actionBack(view, null, function () { |
||||
if (cardLayout.isAllCardHide()) { |
||||
cardLayout.setVisible(false); |
||||
BI.Layers.hide(layout + self.cid); |
||||
} |
||||
!isNew && (self.listenEnd.apply(self, isValid ? keys : [modelData]) !== false) && self.populate(); |
||||
}) |
||||
}).on("change:" + view.cid, _.bind(this.notifyParent, this)); |
||||
} |
||||
BI.isKey(cardName) && BI.Layers.show(layout + this.cid); |
||||
cardLayout.showCardByName(cardName, action, function () { |
||||
BI.isKey(cardName) && self._cards[cardName].populate(data, options); |
||||
}); |
||||
!BI.isKey(cardName) && BI.Layers.hide(layout + this.cid); |
||||
return this._cards[cardName]; |
||||
}, |
||||
|
||||
listenEnd: function (key1, key2, key3) { |
||||
return this; |
||||
}, |
||||
|
||||
/** |
||||
* 告诉父亲我的操作结束了,后面的事情任由父亲处置 |
||||
* @param force 强制下次再次进入该节点时不进行刷新操作, 默认执行刷新 |
||||
* @returns {BI.View} |
||||
*/ |
||||
notifyParentEnd: function (force) { |
||||
this.parent && this.parent.trigger("end:" + this.cid); |
||||
this.trigger("end"); |
||||
!force && this.notify(); |
||||
return this; |
||||
}, |
||||
|
||||
/** |
||||
* 通知父亲我的数据发生了变化 |
||||
*/ |
||||
notifyParent: function () { |
||||
this.parent && this.parent.notify().trigger("change:" + this.cid); |
||||
return this; |
||||
}, |
||||
|
||||
/** |
||||
* 告诉Model数据改变了 |
||||
*/ |
||||
notify: function () { |
||||
this.model.unset("current", {silent: true}); |
||||
return this; |
||||
}, |
||||
|
||||
getName: function () { |
||||
return "VIEW" |
||||
}, |
||||
|
||||
/** |
||||
* 全局刷新 |
||||
* @param current |
||||
*/ |
||||
refresh: function (current) { |
||||
}, |
||||
/** |
||||
* 局部刷新 |
||||
*/ |
||||
local: function () { |
||||
return false; |
||||
}, |
||||
|
||||
load: function (data) { |
||||
|
||||
}, |
||||
|
||||
readData: function (force, options) { |
||||
options || (options = {}); |
||||
var self = this; |
||||
var args = [].slice.call(arguments, 2); |
||||
if (!force && this._readed === true) {//只从后台获取一次数据
|
||||
callback(this.model.toJSON()); |
||||
return; |
||||
} |
||||
//采用静默方式读数据,该数据变化不引起data的change事件触发
|
||||
var success = options.success; |
||||
this.model.read(BI.extend({ |
||||
silent: true |
||||
}, options, { |
||||
success: function (data, model) { |
||||
callback(data); |
||||
!force && (self._readed = true); |
||||
self.delegateEvents(); |
||||
success && success(data, model); |
||||
} |
||||
})); |
||||
|
||||
function callback(data) { |
||||
self.model.load(data); |
||||
self.load(data); |
||||
BI.each(args, function (i, arg) { |
||||
if (BI.isFunction(arg)) { |
||||
arg.apply(self, [data]); |
||||
} |
||||
}) |
||||
} |
||||
}, |
||||
|
||||
//处理model的通用方法
|
||||
cat: function () { |
||||
return this.model.cat.apply(this.model, arguments); |
||||
}, |
||||
|
||||
get: function () { |
||||
return this.model.get.apply(this.model, arguments); |
||||
}, |
||||
|
||||
set: function () { |
||||
return this.model.set.apply(this.model, arguments); |
||||
}, |
||||
|
||||
has: function () { |
||||
return this.model.has.apply(this.model, arguments); |
||||
}, |
||||
|
||||
getEditing: function () { |
||||
return this.model.getEditing(); |
||||
}, |
||||
|
||||
reading: function (options) { |
||||
var self = this; |
||||
var name = BI.UUID(); |
||||
this.model.read(BI.extend({}, options, { |
||||
beforeSend: function () { |
||||
var loading = BI.createWidget({ |
||||
type: 'bi.vertical', |
||||
items: [{ |
||||
type: "bi.layout", |
||||
height: 30, |
||||
cls: "loading-background" |
||||
}], |
||||
element: BI.Maskers.make(name, self) |
||||
}); |
||||
loading.setVisible(true); |
||||
}, |
||||
complete: function (data) { |
||||
options.complete && options.complete(data); |
||||
BI.Maskers.remove(name); |
||||
} |
||||
})); |
||||
}, |
||||
|
||||
updating: function (options) { |
||||
var self = this; |
||||
var name = BI.UUID(); |
||||
this.model.update(BI.extend({}, options, { |
||||
noset: true, |
||||
beforeSend: function () { |
||||
var loading = BI.createWidget({ |
||||
type: 'bi.vertical', |
||||
items: [{ |
||||
type: "bi.layout", |
||||
height: 30, |
||||
cls: "loading-background" |
||||
}], |
||||
element: BI.Maskers.make(name, self) |
||||
}); |
||||
loading.setVisible(true); |
||||
}, |
||||
complete: function (data) { |
||||
options.complete && options.complete(data); |
||||
BI.Maskers.remove(name); |
||||
} |
||||
})); |
||||
}, |
||||
|
||||
patching: function (options) { |
||||
var self = this; |
||||
var name = BI.UUID(); |
||||
this.model.patch(BI.extend({}, options, { |
||||
noset: true, |
||||
beforeSend: function () { |
||||
var loading = BI.createWidget({ |
||||
type: 'bi.vertical', |
||||
items: [{ |
||||
type: "bi.layout", |
||||
height: 30, |
||||
cls: "loading-background" |
||||
}], |
||||
element: BI.Maskers.make(name, self) |
||||
}); |
||||
loading.setVisible(true); |
||||
}, |
||||
complete: function (data) { |
||||
options.complete && options.complete(data); |
||||
BI.Maskers.remove(name); |
||||
} |
||||
})); |
||||
}, |
||||
|
||||
populate: function (modelData, options) { |
||||
var self = this; |
||||
options || (options = {}); |
||||
if (options.force === true) { |
||||
this.notify(); |
||||
} |
||||
if (this._cardLayouts && this._cardLayouts[this.getName()]) { |
||||
this._cardLayouts[this.getName()].showCardByName(this.getName()); |
||||
} |
||||
//BI.each(this._cardLayouts, function (key, layout) {
|
||||
// layout.showCardByName(layout.getDefaultShowName() || self.getName());
|
||||
//});
|
||||
//BI.each(this._cards, function (i, card) {
|
||||
// card.notify && card.notify();
|
||||
//});
|
||||
if (this._F.length > 0) { |
||||
throw new Error("流程错误"); |
||||
} |
||||
if (options.force === true) { |
||||
this.model.set(modelData, options).set({current: this.model.get("default")}); |
||||
return; |
||||
} |
||||
if (options.force === false) { |
||||
this.model.set(modelData); |
||||
return; |
||||
} |
||||
var filter = BI.clone(modelData || {}); |
||||
delete filter.id; |
||||
var contains = BI.has(this.model.toJSON(), _.keys(filter)); |
||||
var match = BI.isEmpty(filter) || (contains && this.model.matches(modelData)); |
||||
if (match === true) { |
||||
this.model.set({current: this.model.get("default")}); |
||||
} else if (contains === false) { |
||||
this.model.set(modelData); |
||||
} else { |
||||
this.model.set(modelData, options).set({current: this.model.get("default")}); |
||||
} |
||||
}, |
||||
|
||||
//删除子节点触发
|
||||
splice: function (old, key1, key2, key3) { |
||||
|
||||
}, |
||||
|
||||
//复制子节点触发
|
||||
duplicate: function (copy, key1, key2, key3) { |
||||
|
||||
}, |
||||
|
||||
_unMount: function () { |
||||
this.beforeDestroy && this.beforeDestroy(); |
||||
BI.each(this._cardLayouts, function (name, card) { |
||||
card && card._unMount(); |
||||
}); |
||||
delete this._cardLayouts; |
||||
delete this._cards; |
||||
this.destroyed && this.destroyed(); |
||||
this.trigger(BI.Events.UNMOUNT); |
||||
this.off(); |
||||
}, |
||||
|
||||
_destroy: function () { |
||||
var self = this; |
||||
BI.each(this._cardLayouts, function (name, card) { |
||||
card && card._unMount(); |
||||
BI.Layers.remove(name + self.cid); |
||||
}); |
||||
delete this._cardLayouts; |
||||
delete this._cards; |
||||
this.destroyed && this.destroyed(); |
||||
this.remove(); |
||||
this.trigger(BI.Events.DESTROY); |
||||
this.off(); |
||||
} |
||||
}); |
||||
|
||||
BI.View.registerVMRouter = function (viewRouter, modelRouter) { |
||||
//配置View
|
||||
BI.View.createView = BI.View.prototype.createView = function (url, modelData, viewData, context) { |
||||
return BI.Factory.createView(url, viewRouter.get(url), _.extend({}, modelRouter.get(url), modelData), viewData || {}, context); |
||||
}; |
||||
}; |
@ -1,145 +0,0 @@
|
||||
/** |
||||
* jQuery "splendid textchange" plugin |
||||
* http://benalpert.com/2013/06/18/a-near-perfect-oninput-shim-for-ie-8-and-9.html
|
||||
* |
||||
* (c) 2013 Ben Alpert, released under the MIT license |
||||
*/ |
||||
|
||||
(function($) { |
||||
|
||||
var testNode = document.createElement("input"); |
||||
var isInputSupported = "oninput" in testNode && |
||||
(!("documentMode" in document) || document.documentMode > 9); |
||||
|
||||
var hasInputCapabilities = function(elem) { |
||||
// The HTML5 spec lists many more types than `text` and `password` on
|
||||
// which the input event is triggered but none of them exist in IE 8 or
|
||||
// 9, so we don't check them here.
|
||||
// TODO: <textarea> should be supported too but IE seems to reset the
|
||||
// selection when changing textarea contents during a selectionchange
|
||||
// event so it's not listed here for now.
|
||||
return elem.nodeName === "INPUT" && |
||||
(elem.type === "text" || elem.type === "password"); |
||||
}; |
||||
|
||||
var activeElement = null; |
||||
var activeElementValue = null; |
||||
var activeElementValueProp = null; |
||||
|
||||
/** |
||||
* (For old IE.) Replacement getter/setter for the `value` property that |
||||
* gets set on the active element. |
||||
*/ |
||||
var newValueProp = { |
||||
get: function() { |
||||
return activeElementValueProp.get.call(this); |
||||
}, |
||||
set: function(val) { |
||||
activeElementValue = val; |
||||
activeElementValueProp.set.call(this, val); |
||||
} |
||||
}; |
||||
|
||||
/** |
||||
* (For old IE.) Starts tracking propertychange events on the passed-in element |
||||
* and override the value property so that we can distinguish user events from |
||||
* value changes in JS. |
||||
*/ |
||||
var startWatching = function(target) { |
||||
activeElement = target; |
||||
activeElementValue = target.value; |
||||
activeElementValueProp = Object.getOwnPropertyDescriptor( |
||||
target.constructor.prototype, "value"); |
||||
|
||||
Object.defineProperty(activeElement, "value", newValueProp); |
||||
activeElement.attachEvent("onpropertychange", handlePropertyChange); |
||||
}; |
||||
|
||||
/** |
||||
* (For old IE.) Removes the event listeners from the currently-tracked |
||||
* element, if any exists. |
||||
*/ |
||||
var stopWatching = function() { |
||||
if (!activeElement) return; |
||||
|
||||
// delete restores the original property definition
|
||||
delete activeElement.value; |
||||
activeElement.detachEvent("onpropertychange", handlePropertyChange); |
||||
|
||||
activeElement = null; |
||||
activeElementValue = null; |
||||
activeElementValueProp = null; |
||||
}; |
||||
|
||||
/** |
||||
* (For old IE.) Handles a propertychange event, sending a textChange event if |
||||
* the value of the active element has changed. |
||||
*/ |
||||
var handlePropertyChange = function(nativeEvent) { |
||||
if (nativeEvent.propertyName !== "value") return; |
||||
|
||||
var value = nativeEvent.srcElement.value; |
||||
if (value === activeElementValue) return; |
||||
activeElementValue = value; |
||||
|
||||
$(activeElement).trigger("textchange"); |
||||
}; |
||||
|
||||
if (isInputSupported) { |
||||
$(document) |
||||
.on("input", function(e) { |
||||
// In modern browsers (i.e., not IE 8 or 9), the input event is
|
||||
// exactly what we want so fall through here and trigger the
|
||||
// event...
|
||||
if (e.target.nodeName !== "TEXTAREA") { |
||||
// ...unless it's a textarea, in which case we don't fire an
|
||||
// event (so that we have consistency with our old-IE shim).
|
||||
$(e.target).trigger("textchange"); |
||||
} |
||||
}); |
||||
} else { |
||||
$(document) |
||||
.on("focusin", function(e) { |
||||
// In IE 8, we can capture almost all .value changes by adding a
|
||||
// propertychange handler and looking for events with propertyName
|
||||
// equal to 'value'.
|
||||
// In IE 9, propertychange fires for most input events but is buggy
|
||||
// and doesn't fire when text is deleted, but conveniently,
|
||||
// selectionchange appears to fire in all of the remaining cases so
|
||||
// we catch those and forward the event if the value has changed.
|
||||
// In either case, we don't want to call the event handler if the
|
||||
// value is changed from JS so we redefine a setter for `.value`
|
||||
// that updates our activeElementValue variable, allowing us to
|
||||
// ignore those changes.
|
||||
if (hasInputCapabilities(e.target)) { |
||||
// stopWatching() should be a noop here but we call it just in
|
||||
// case we missed a blur event somehow.
|
||||
stopWatching(); |
||||
startWatching(e.target); |
||||
} |
||||
}) |
||||
|
||||
.on("focusout", function() { |
||||
stopWatching(); |
||||
}) |
||||
|
||||
.on("selectionchange keyup keydown", function() { |
||||
// On the selectionchange event, e.target is just document which
|
||||
// isn't helpful for us so just check activeElement instead.
|
||||
//
|
||||
// 90% of the time, keydown and keyup aren't necessary. IE 8 fails
|
||||
// to fire propertychange on the first input event after setting
|
||||
// `value` from a script and fires only keydown, keypress, keyup.
|
||||
// Catching keyup usually gets it and catching keydown lets us fire
|
||||
// an event for the first keystroke if user does a key repeat
|
||||
// (it'll be a little delayed: right before the second keystroke).
|
||||
// Other input methods (e.g., paste) seem to fire selectionchange
|
||||
// normally.
|
||||
if (activeElement && activeElement.value !== activeElementValue) { |
||||
activeElementValue = activeElement.value; |
||||
$(activeElement).trigger("textchange"); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
})(jQuery); |
Loading…
Reference in new issue