UNPKG

vesh-vj

Version:

VESH's JavaScript Framework

1,101 lines (1,091 loc) 73.8 kB
(function(V, $) { V.viewmodel = { APP: 'VESH.viewmodel', NIAPP: 'Ni' }; var M = V.viewmodel; V.view = { APP: 'VESH.view' }; var W = V.view; V.hasRight = function(name, isAdmin) { if (V.getValue(isAdmin, false) && (typeof(User) == 'undefined' || !V.isValid(User))) { return false; } if (User) { //添加后门 if (!V.isValid(Pers)) { V.showException("permission.js不存在"); return false; } if (V.getValue(isAdmin, false) && Pers) return true; var id = V.getValue(Pers[name], '_'); return ((',' + V.getValue(User.PIDS, '') + ',').indexOf(',' + id + ',') >= 0); } return false; }; //定义业务逻辑层的两个基本对象页面与控件 //首先页面实例化M.Page 然后 页面绑定 W.Page 然后W.Page 调用Document.ready 将界面根据middler进行设置,并针对_对象进行初始化设置并进行binding binding完成后直接发布document.ready事件 //一般的viewmodel层通过type定义其Middler中的控件类型实现与前端的绑定 //一般的view层生成后通过bind命令绑定viewmodel,并提供fill命令更新viewmodel的相关字段,将自身的render命令注入viewmodel的update命令更新控件,viewmodel定义事件并由view调用,一般会在调用事件时自动调用自身的fill方法更新viewmodel,然后在属性调用时根据返回的参数更新自身。在viewmodel更新状态后,可调用update(更新{})方法完成数据在view层的填充,同时将属性更新viewmodel。 //分别定义view与viewmodel的Control 控件本身只支持先构建,构建与init合并,最后执行bind操作 M.Control = function() { //data属性的定义 on事件的处理 update方法的主动更新 var _ = this, __ = {}; { _.bind = function(view) { _.v = view; _.config = _.v.config; _.middler = _.v.middler; _.ni = _.v.ni; _.session = _.v.session; }; _.data = _.data || {}; } }; var WTemplates = {}; var FuncTmp = function() { var _ = this; _.__ = { funs: [], node: $('<div style="display:none;"></div>').appendTo(window.document.body) } }; V.merge(FuncTmp.prototype, { addCallback: function(fun) { var _ = this, __ = _.__; (__.template) ? fun($(__.template)): fun && (__.funs[__.funs.length] = fun); }, callback: function() { var __ = this.__; V.whileC(function() { return __.funs.shift() }, function(v) { v($(__.template)); }); }, init: function(path) { var _ = this, __ = this.__; if (path.indexOf('<') >= 0) { __.node.append(path); __.template = __.node[0].innerHTML; __.node.remove(); } else { if ((path || '').startWith('~') && V.getSettings("include")['last']) { var prefix = V.getSettings("include")['last'].split('/'); prefix.pop(); path = prefix.join('/') + path.replace(/~/, ''); } __.node.load(path, function() { __.template = __.node[0].innerHTML __.node.remove(); _.callback(); }); } } }, true); W.getTemplate = function(path, func) { if (!V.isValid(path) || V.getType(path) != 'string') { throw new Error('控件模板不能为空或者非字符串!'); } if (!WTemplates[path]) { WTemplates[path] = new FuncTmp(); WTemplates[path].init(path); } WTemplates[path].addCallback(func); }; //动画基类,用于提供默认的方法定义 供真实的动画进行处理 譬如抖动 移动 翻转 等等 W.Action = function() { this.go = function(node, func) { if (func) { func(); } }; }; //css专用的属性动画设置 默认可使用animate.min.css 进行动画设置 W.CssAction = function(css) { var __ = {}; V.inherit.apply(this, [W.Action, []]); __.go = this.go; __.css = V.getValue(css, ''); this.go = function(node, func) { if (V.isValid(__.css)) { node = $(node); var _f = func; var _c = function() { node.off('animationend').css('-webkit-animation', '').css('-moz-animation', '').css('-o-animation', ''); if (_f) { var _s = _f; _f = null; _s(); }; }; node.off('webkitAnimationEnd').on('webkitAnimationEnd', _c); node.off('mozAnimationEnd').on('mozAnimationEnd', _c); node.off('MSAnimationEnd').on('MSAnimationEnd', _c); node.off('oanimationend').on('oanimationend', _c); node.off('animationend').on('animationend', _c); node.css('animation', css).css('-webkit-animation', css).css('-webkit-animation-play-state', 'running').css('-moz-animation', css).css('-moz-animation-play-state', 'running').css('-o-animation', css).css('-o-animation-play-state', 'running'); } }; }; W.readyLoad = function(_) { //_.readyLoad.wait唯一判断是否出现子控件 当出现子控件时 需要子控件全部完成(有异步加载的需要判断 父控件的wait为false而且本级全部子控件的ready为真,无异步加载的需要父控件判断 本级全部子控件的ready为真)才能启动onload方法调用并确定父控件的ready为真 并开始启动上级判断。 应确保父控件的ready if (!_.readyLoad.ready && _.controls && _.controls.length) { //此为本级无异步加载的父控件判断 if (!_.controls.filter(function(v) { return !v.readyLoad.ready }).length) { //console.log('readyLoad', _, _.readyLoad.ready ? '' : '', _.readyLoad.wait ? '锁定' : '不锁'); // _.controls.map(function(v) { // console.log('readyLoad2', v, v.readyLoad.ready); // }); _.controls.map(function(v) { try { !v.readyLoad.hasLoad && v.readyLoad.onLoad(v.readyLoad.node); v.readyLoad.hasLoad = true; } catch (e) { console.log(v, e.stack); } }); _.readyLoad.ready = true; //console.log('非叶子控件 全部完成!', _, _.parent); (_.parent && _.parent.readyLoad && !_.parent.readyLoad.wait) && W.readyLoad(_.parent); } // else console.log('无异步但是有未完成', _.controls.filter(function(v) { // if (!v.readyLoad.ready) // console.log(v, v.readyLoad.ready); // return !v.readyLoad.ready; // }).length); } else { //console.log('叶子节点判断', _, !_.readyLoad.ready, _.controls, _.controls && _.controls.length); //有异步加载的需要判断 父控件的wait为false而且本级全部子控件的ready为真,无异步加载的需要父控件判断 本级全部子控件的ready为真 //叶子控件 _.readyLoad.ready = true; //(_.parent && _.parent.readyLoad && !_.parent.readyLoad.wait) && console.log('readyLoad parent', _.parent, _.parent ? '有父亲' : '无父亲', _.parent.readyLoad ? "父亲有readyLoad" : '', _.parent.readyLoad.wait ? "父亲被锁定" : ''); (_.parent && _.parent.readyLoad && !_.parent.readyLoad.wait) && W.readyLoad(_.parent); } }; //html与css的加载 其对应的节点的替换 事件的统一触发与处理 update事件的注入 控件均支持先创建 再init 然后bind绑定的过程 再调用onLoad和render事件 W.Control = function(path, params) { var _ = this, __ = { drag: {}, drop: {} }; { _.path = path; _.vm = null; _.events = {}; _.params = V.getValue(params, {}); __.desc = ""; _.addDesc = function(d) { __.desc += (d + "\r\n"); }; _.desc = function() { console.log(__.desc + 'VJ.view.Control\r\n数据定义:\r\npath:html模板定义\r\nvm:虚拟控件对象\r\nevents:事件对象\r\nparams:默认参数对象\r\n'); }; } //处理控件下载完成后的操作 _.onLoad = function(node) { _.render(V.merge({}, _.vm.data)); _.call('load'); }; //在更新_.vm.data _.fill = function() { return {}; }; //可以将数据更新到标签上 _.render = function(data) { V.forC(data, function(key, value) { switch (key.toLowerCase()) { case 'dispose': (value) && _.dispose(); break; case 'css': V.forC(value, function(k, v) { _.node.css(k, v); }); break; case 'attr': V.forC(value, function(k, v) { _.node.attr(k, v); }); break; case 'hasright': if (true === value || V.hasRight(value)) { if (__.ebbody) { _.node.show().append(__.ebbody.children()); __.ebbody.remove(); delete __.ebbody; } } else { __.ebbody = V.newEl('div').append(_.node.children()); _.node.hide().empty(); }; break; case 'enable': if (value) { _.node.removeAttr('disabled'); } else { _.node.attr('disabled', 'disabled'); } break; case 'invisible': if (value) { _.node.children().show(); } else { _.node.children().hide(); } break; case 'visible': if (value) { _.node.show(); } else { _.node.hide(); } break; case 'addclass': _.node.addClass(value); break; case 'removeclass': _.node.removeClass(value); break; case 'drag': //drag node说明可移动的对象,mode true,false是否许可继续进行 move,copy,none(默认),func可产生移动对象 value = value.node ? value : { mode: value }; !!value.mode ? _.drag(value.node || _.node, value.mode) : _.clearDrag(value.node || _.node); break; case 'drop': //drop node说明可移动的对象,mode true,false是否许可继续进行 move,copy,none(默认)可产生移动对象 value = value.node ? value : { mode: value }; !!value.mode ? _.drop(value.node || _.node, value.mode) : _.clearDrop(value.node || _.node); break; case 'animate': //仅处理简单类型的动画 譬如一次性调用的动画名或者一个动画名带一个回调函数,可支持多个 if (typeof(value) == 'string') { _.animate(value); } else { var ret = []; V.forC(value, function(k2, v2) { ret.push([k2, v2]); }, function() { var i = 0; //异步处理 var _f = function() { var v2 = ret[i]; i++; _.animate(v2[0], function() { if (typeof(v2[1]) == 'function') V.tryC(function() { v2[1](); }); if (i < ret.length) { _f(); } }); }; _f(); }); } break; case 'globalposition': value += ''; //此方法不支持重复设置 if (_.node.attr('position')) { V.showException('W.Control.data.globalposition 不允许重复设置!' + _.node.attr('position')); } else { _.node.attr('position', value.toLowerCase()); _.node.css('position', 'absolute'); var parent = $(window); switch (value.toLowerCase()) { case 'top': parent.scroll(function() { _.node.css('top', document.body.scrollTop + "px"); }); _.node.css('top', document.body.scrollTop + "px"); break; case 'bottom': parent.scroll(function() { _.node.css('top', (document.body.scrollTop + $(window).height() - _.node.height()) + "px"); }); _.node.css('top', (document.body.scrollTop + $(window).height() - _.node.height()) + "px"); break; } } break; case 'position': value += ''; //此方法不支持重复设置 if (_.node.attr('position')) { V.showException('W.Control.data.postion 不允许重复设置!' + _.node.attr('position')); } else { _.node.attr('position', value.toLowerCase()); _.node.css('position', 'absolute'); var parent = _.node.parent(); switch (value.toLowerCase()) { case 'top': parent.scroll(function() { _.node.css('top', parent[0].scrollTop + "px"); }); _.node.css('top', parent[0].scrollTop + "px"); break; case 'bottom': parent.scroll(function() { _.node.css('top', (parent[0].scrollTop + $(document).height() - _.node.height()) + "px"); }); _.node.css('top', (parent[0].scrollTop + $(document).height() - _.node.height()) + "px"); break; } } break; case 'valid': V.merge(_.get(), _.fill(), true); if (_.valid) { _.valid(data.value || _.get().value, value); } else if (value) value(); break; case 'validate': { var inputs = _.node.find('input'); _.validate(_, inputs.length ? inputs : _.node); } break; case 'show': _.vm.data.visible = true; _.animate(value, function() {}); V.once(function() { _.node.show(); }, 1); break; case 'hide': _.animate(value, function() { _.node.hide(); _.vm.data.visible = false; }); break; case 'desc': (value) && _.desc(); break; } }); return data; }; _.init = function(parent, node, params) { _.parent = parent; _.config = _.parent.config; _.middler = _.parent.middler; _.ni = _.parent.ni; _.session = _.parent.session; _.node = node; _.params = V.merge(_.params, { data: V.getValue(params, {}) }); }; //初始化viewmodel操作 _.bind = function(vm) { //完成配置合并 _.vm = V.merge(_.params, vm || { data: {} }); V.forC(_.vm, function(k, v) { vm[k] = v; (k.toLowerCase().indexOf('on') == 0) && ( _.events[k.toLowerCase().substring(2)] = v ) }, null, true); _.vm = vm; //用于获取绑定对象的数据 _.get = function() { return _.vm.data; } //完成类型名注入 _.vm.nodeName = _.nodeName; //完成方法注入 _.vm.update = function() { if (arguments.length == 0) { _.vm.data = V.merge(_.vm.data, _.fill()); } else { var as = Array.prototype.slice.call(arguments); //as = V.getValue(as, [null]); if (as[0]) V.merge(_.vm.data, as[0], true); as[0] = as[0] ? as[0] : V.merge({}, _.vm.data); _.render.apply(_, as); } return _.vm.data; }; _.vm.call = function() { return _.call.apply(_.parent.vms, arguments); }; _.vm.add = function() { _.addControl.apply(_, arguments); }; _.vm.remove = function() { _.removeControl.apply(_, arguments); }; _.vm.desc = function() { _.desc(); }; _.vm.get = function(key) { _.vm.data = V.merge(_.vm.data, _.fill()); return key ? _.vm.data[key] : _.vm.data; }; _.vm.bind(_); _.readyLoad = { ready: false, node: null, onLoad: _.onLoad, path: _.path, wait: false //等待递归调用readyLoad方法时等待父类的replaceNode执行完成 }; if (_.path) { W.getTemplate(_.path, function(node) { _.replaceNode(node); _.readyLoad.wait = false; _.readyLoad.node = node; _.preonload && _.preonload(node); W.readyLoad(_); //_.onLoad(node); }); } else { _.node.show(); _.readyLoad.wait = false; _.readyLoad.node = _.node; _.preonload && _.preonload(_.node); W.readyLoad(_); //_.onLoad(_.node); } }; //用于扩展给主要对象绑定事件使用 一般用于bind事件的默认值 _.bindEvent = function(node, k, v) { node = $(node); try { ($._data(node[0], "events")); } catch (e) { console.log('发现有极端情况会报nodeName错误!'); return; } if (typeof(node[k]) == 'function' && (!$._data(node[0], "events") || !$._data(node[0], "events")[k])) { switch (k.toLowerCase()) { case 'hover': if ((!$._data(node[0], "events") || (!$._data(node[0], "events")['mouseenter']) && !$._data(node[0], "events")['mouseleave'])) node[k](function(e) { if (node.attr('disabled') || node.parents("[disabled]").length > 0) return; _.call(k, { e: e, hover: true }); }, function(e) { if (node.attr('disabled') || node.parents("[disabled]").length > 0) return; _.call(k, { e: e, hover: false }); }); break; case 'resize': node[0].onresize = function(e) { if (node.attr('disabled') || node.parents('[disabled]').length > 0) return; _.call(k, { e: e, width: node.width(), height: node.height() }); } break; default: node[k](function(e) { if (node.attr('disabled') || node.parents('[disabled]').length > 0) return; _.call(k, { e: e }); }); } } }; _.initControls = function(vm, node) { //此处进行内部控件生成需要判定controls属性 (vm.controls || node.find('[_]').length > 0) && (function() { _.readyLoad.wait = true; var cons = vm.controls || {}; _.controls = []; _.vs = {}; _.vms = cons; _.models = _.vms; V.each(node.find('[_]').toArray(), function(v1) { var v = $(v1); var id = v.attr('id'); var json = eval("({" + v.attr('_') + "})"); var type = json.type ? json.type : (id && cons[id] && cons[id].type) ? cons[id].type : null; //对于容器类对象的处理方式 var nodeName = type ? type.toLowerCase() : v[0].nodeName.toLowerCase(); var obj = _.middler.getObjectByAppName(W.APP, nodeName); if (!obj) V.showException('配置文件中没有找到对象类型定义:' + nodeName); obj.init(_, v, V.isValid(v.attr('_')) ? json : null); obj.page = _.page; _.controls[_.controls.length] = (obj); if (!id) { id = nodeName + V.random(); } obj.nodeName = nodeName; if (!cons[id]) { cons[id] = { data: {} }; } _.vs[id] = obj; V.inherit.apply(cons[id], [M.Control, []]); obj.bind(cons[id]); }, function() { //实现通过type属性完成数据初始化的功能 V.forC(cons, function(key, v) { if (v.type && !v.v) { var obj = _.middler.getObjectByAppName(W.APP, v.type); if (!obj) throw new Error('配置文件中没有找到对象类型定义:' + v.type); var node2 = V.newEl('div'); node.append(node2); obj.init(_, node2, null); obj.page = _.page; _.controls[_.controls.length] = (obj); _.vs[key] = obj; V.inherit.apply(v, [M.Control, []]); obj.bind(v); } }, null, true) }, true); })(); }; _.replaceNode = function(node) { node = $(node); var attrs = _.node[0].attributes; if (attrs) { var i = attrs.length; V.whileC(function() { i--; return i >= 0 ? { key: attrs[i].name, val: attrs[i].value } : null }, function(v) { var n = v.key.toLowerCase() == 'id' ? $(node[0]) : node; if (n.length > 1) { for (var i = 0; i < n.length; i++) { var _n = $(n[i]); if (V.isValid(v.val) && v.val != 'false') { _n.attr(v.key, ((V.isValid(_n.attr(v.key)) && _n.attr(v.key) != v.val) ? _n.attr(v.key) + " " : "") + v.val); } } } else { if (V.isValid(v.val) && v.val != 'false') { n.attr(v.key, ((V.isValid(n.attr(v.key)) && n.attr(v.key) != v.val) ? n.attr(v.key) + " " : "") + v.val); } } }, null, true); } _.initControls(_.vm, node); node.append(_.node.children()); if (_.node[0].nodeName.toLowerCase() == 'body') { _.node.empty().append(node); } else { _.node.after(node).remove(); } _.node = node; }; _.call = function(name, param, tparam) { name = name.toLowerCase(); var val = null; //所有的事件调用全部采用异步调用方式 V.once V.merge(_.vm.data, _.fill(), param || {}, true); param = V.merge(_.vm.data, tparam || {}); (_.events[name]) && V.tryC(function() { val = _.events[name].apply(_.parent.vms, [param, _.vm]); if (val && V.toJsonString(val).length > 2) { V.merge(_.vm.data, val, true) _.render(val); } }); return val; }; _.dispose = function(e) { V.tryC(function() { _.call('dispose', { e: e }); _.clearControl(); }); _.node.remove(); }; //这里提供子类用于覆盖同名函数,修改动画对象。 _.animate = function(name, func) { _._animate(name, null, func); }; //动画方法 用于将middler获取到的动画对象进行动画设置并返回设置函数 而动画对象本身应该仅仅具有业务意义 譬如active hide append等等 _._animate = function(name, node, func) { name = name || ''; var action = _.middler.getObjectByAppName(W.APP, name); if (action) { action.go(node ? node : _.node, func || null); } }; //用于绑定验证控件 _.validate = function(input) { if (_.middler) { var obj = _.middler.getObjectByAppName(W.APP, 'ValidateManager'); if (obj) { obj.validate(_, input); } } }; //用于说明错误提示 _.onError = function(text) { _.get().isError = true; _.call('error', { error: text }); }; //用于清理错误提示 _.onClearError = function() { _.call('clearerror'); }; //用于说明正确信息 _.onSuccess = function() { delete _.get().isError; _.call('success') }; //控件处理 _.addControl = function(node, v) { if (!_.controls) { _.controls = []; _.vs = {}; _.vms = {}; _.models = _.vms; } var obj = _.middler.getObjectByAppName(W.APP, v.type); if (!obj) throw new Error('配置文件中没有找到对象类型定义:' + v.type); node = node ? node : V.newEl('div').appendTo(_.node); obj.init(_, node, v.data); obj.page = _.page; _.controls[_.controls.length] = (obj); var key = V.getValue(v.id, V.random()); if (_.vs[key]) { V.showException('控件id为' + key + '的子控件已经存在,请更换id名'); return; } node.attr('id', key); _.vs[key] = obj; V.inherit.apply(v, [M.Control, []]); _.vms[key] = v; _.readyLoad.ready = false; obj.bind(v); return v; }; _.removeControl = function(id) { delete _.vms[id]; if (_.vs[id]) { var val = _.vs[id]; delete _.vs[id]; _.controls = $.grep(_.controls, function(v, i) { return v != val; }); if (val) val.dispose(); V.tryC(function() { val.node.remove(); }); } }; _.clearControl = function() { if (_.controls) { var vs = _.vs; _.controls = []; _.vms = {}; _.models = _.vms; _.vs = {}; var div = $('<div style="display:none;"></div>').appendTo(window.document.body); _.node.children().appendTo(div); _.node.empty(); V.forC(vs, function(k, v) { v.dispose(); }, function() { div.remove(); }, true); } else { _.controls = []; _.vms = {}; _.models = _.vms; _.vs = {}; } }; V.applyCommandAndEvent(this); _.getPosition = function(node) { var docs = node; var pos = { x: docs.offsetLeft, y: docs.offsetTop }; docs = docs.offsetParent; while (docs) { var off = []; if (docs.style && docs.style.transform && docs.style.transform.indexOf('translate3d') >= 0) { docs.style.transform.replace(/[+-]\d+(px)/g, function(v) { //一般第一个是 x 第二个是y off[off.length] = parseInt(v); }); } pos.x += (off[0] ? off[0] : 0) + docs.offsetLeft; //不断叠加与祖先级的距离 pos.y += (off[1] ? off[1] : 0) + docs.offsetTop; docs = docs.offsetParent; } return pos; }; //实现自定义拖拽 _.clearDrag = function(node) { $(node).attr('_draggable', false).removeClass('g_drag'); }; _.clearDrop = function(node) { $(node).attr('_dropable', false).removeClass('g_drop'); }; //drag:true/move/copy/none/function(){} _.drag = function(node, mode, getData) { node = $(node); var id = node.attr('_dragid') || V.random(); if (!(mode === true && node.attr('_dragid'))) { mode = mode === true ? 'move' : mode; node.attr('_dragid') && delete __.drag[node.attr('_dragid')]; __.drag[id] = { mode: (mode + '').toLowerCase(), getData: getData || function(e) { return _.vm.data.dragData || _.vm.data.value || {}; }, func: typeof(mode) == 'function' ? mode : (function() { switch ((mode + '').toLowerCase()) { case 'move': return function(e) { var _n = $(e.target).clone(); $(e.target).hide(); return _n; }; case 'copy': return function(e) { return $(e.target).clone(); }; case 'none': default: return function(e) { return null; }; } })() }; } node.attr('_draggable') === undefined && node.on('mousedown', function(e) { if (node.attr('_draggable') != 'true') return; V.cancel(e), V.stopProp(e); var back = V.newEl('div').appendTo(document.body).css({ width: '100%', height: '100%', top: 0, left: 0, position: 'fixed', cursor: 'point' }); //防止同一对象多次设置drag状态或者对多个对象设置drag状态时无法生效 var id = node.attr('_dragid'); e.oriTarget = e.target; e.target = node; //开始启动拖拽 W.Control.drag = { enable: true, id: id, Data: __.drag[id].getData(e, _.vm), Point: { X: e.offsetX || e.pageX, Y: e.offsetY || e.pageY, left: e.offsetX || e.pageX, top: e.offsetY || e.pageY }, val: {}, mode: __.drag[id].mode, node: node, time: new Date().getTime(), dragNode: __.drag[id] && __.drag[id].func(e, _.vm) }; //dragstart可以修改left,top,dragData等拖拽参数 var val = _.call('dragstart', V.merge({ e: e, dragData: W.Control.drag.Data, dragNode: W.Control.drag.dragNode }, W.Control.drag.Point)) || W.Control.drag.Point; W.Control.drag.dragNode && W.Control.drag.dragNode.appendTo(back).css({ left: val.left, top: val.top, position: 'absolute' }); W.Control.drag.Data = V.toJsonString(val.Data || _.vm.data.dragData || W.Control.drag.Data); back.on('mousemove', function(e) { V.cancel(e), V.stopProp(e); if (!W.Control.drag) return; W.Control.drag.val = { left: e.pageX - W.Control.drag.Point.X, top: e.pageY - W.Control.drag.Point.Y, X: e.pageX, Y: e.pageY }; //drag事件可以修改left和top进行重新定位 var val = _.call('drag', V.merge({ e: e, dragNode: W.Control.drag.dragNode }, W.Control.drag.val)) || W.Control.drag.val; W.Control.drag.val = val; W.Control.drag.dragNode && W.Control.drag.dragNode.css({ left: val.left, top: val.top }); }); back.on('mouseup', function(e) { V.cancel(e), V.stopProp(e); W.Control.drag.val = { left: e.pageX - W.Control.drag.Point.X, top: e.pageY - W.Control.drag.Point.Y, X: e.pageX, Y: e.pageY }; //dragend可以修改拖拽后的drag数据 allowDrop 确认是否允许拖拽和释放. var val = _.call('dragend', V.merge({ e: e, dragData: V.json(W.Control.drag.Data) || {}, dragNode: W.Control.drag.mode == 'move' ? W.Control.drag.node : W.Control.drag.dragNode }, W.Control.drag.val)) || W.Control.drag.val; W.Control.drag.val = val; val.Data && (W.Control.drag.Data = V.toJsonString(V.merge(V.json(W.Control.drag.Data), val.Data))); delete val.Data; W.Control.drag.node && W.Control.drag.node.show(); back.remove(); back = null; var allowDrop = true; V.forC(val || {}, function(k, v) { if (k.toLowerCase() == 'allowdrop' && v === false) { allowDrop = false; } }, null, true); allowDrop && (W.Control.drop = W.Control.drag, V.once(function() { //限期响应 delete W.Control.drop; }, 500)); delete W.Control.drag; }); }); node.attr('_dragid', id).attr('_draggable', true).addClass('g_drag'); }; //drop:true/move/copy/none _.drop = function(node, mode) { node = $(node); var id = node.attr('_dropid') || V.random(); if (!(mode === true && node.attr('_dropid'))) { node.attr('_dropid') && delete __.drop[node.attr('_dropid')]; mode = mode === true ? 'move' : mode; __.drop[id] = { mode: (mode + '').toLowerCase(), candrop: true, func: typeof(mode) == 'function' ? mode : (function() { switch ((mode + '').toLowerCase()) { case 'move': return function(e) { _.node.append(W.Control.drop.node || $(e.target)); }; case 'copy': return function(e) { _.node.append(W.Control.drop.dragNode || $(e.target).clone()); }; case 'none': default: return function(e) {}; } })() }; } typeof(node.attr('_dropable')) === 'undefined' && (node.on('mouseover', function(e) { if (!W.Control.drop || node.attr('_dropable') != 'true') return; V.cancel(e), V.stopProp(e); var id = node.attr('_dropid'); var val = _.call('drop', V.merge({ e: e, dragData: V.json(W.Control.drop.Data), dragNode: __.drop[id].mode == 'copy' ? W.Control.drop.dragNode : W.Control.drop.node }, W.Control.drop.val)) || W.Control.drop.val; __.drop[id] && __.drop[id].func(e, _.vm); delete W.Control.drop; })); node.attr('_dropid', id).attr('_dropable', true).addClass('g_drop'); }; _.wheel = function(node, func) { var $node = $(node); //不兼容FF $node.on('mousewheel', function(e) { V.cancel(e); var data = Math.abs(e.originalEvent.deltaY); (Math.floor(data) == data) ? func({ name: 'wheel', e: e, deltaX: e.originalEvent.deltaX, deltaY: e.originalEvent.deltaY }): func({ name: 'scale', e: e, scale: e.originalEvent.wheelDelta > 0 ? 1 : -1 }); }); $node.on('mousemove', function(e) { $node.select(); }) } }; { //配置JSON数据格式定义的控件 /** * * VJ.registScript(path,function(){ var __ = {}; var _ = this; VJ.inherit.apply(_,[VJ.view.WControl, { template:'', vm:{ data:{}, controls:{} onLoad:function(D,I){} }, onLoad:{k:function(node){}}, // {} fill:function(){ return {} },// {} render:{k:function(v,data){}},//{} }]); }) * @param {*} json */ W.Control2 = function(json) { var __ = V.merge({ template: '', vm: {}, onLoad: {}, render: {} }, json); __.event = __.event || __.onLoad; var _ = this; { V.inherit.apply(this, [W.Control, [__.template, __.vm]]); __.prerender = _.render; //__.preonLoad = _.onLoad; _.fill = __.fill || _.fill; //todo 定义所有可监听的事件 默认这里未添加BindEvent的默认内容 _.Events = {}; //todo 定义所有属性 默认这里属性和方法必须决定是否同步或者异步执行 应该先取代再瘦身 //todo 父子类无法简单继承 要求 父类的json和子类的json不是覆盖关系 _.Propertis = {}; __.async = {}; __.sync = {}; __.finally = {}; __.merge = {}; V.forC(__.render || {}, function(k, v) { var k2 = k.toLowerCase(); v = typeof(v) === 'function' ? { Desc: '属性没有任何描述', sync: true, //默认为同步处理, finally: false, //finally一定是异步的 override: false, //是否覆盖父类方法 merge: false, //是否采用深度复制 Method: v } : V.merge({ Desc: '属性没有任何描述', sync: true, //默认为同步处理, finally: false, //finally一定是异步的 override: false, //是否覆盖父类方法 merge: false, //是否采用深度复制 }, v); //Method为false或者未定义则不可作为可用属性出现 v && (function() { v.Method = v.Method || function() {}; _.Propertis[k] = v.Desc; var poi = v.finally ? 'finally' : v.sync ? 'sync' : 'async'; __[poi][k2] = v; v.merge === true && (__.merge[k2] = true); v.as && (v.as = V.isArray(v.as) ? v.as : [v.as]) && v.as.forEach(function(v2) { __[poi][v2.toLowerCase()] = v; }); })(); }, null, true); } _.call = function(name, param, tparam) { name = name.toLowerCase(); var val = null; V.merge(_.vm.data, _.fill(), true); var mgData = {}; V.forC(param || {}, function(k, v) {!__.merge[k.toLowerCase()] ? (_.vm.data[k] = v) : (mgData[k] = v); }, function() { V.merge(_.vm.data, mgData, true); }, true); //所有的事件调用全部采用异步调用方式 V.once (_.events[name]) && V.tryC(function() { param = V.merge(_.vm.data, tparam || {}); val = _.events[name].apply(_.parent.vms, [param, _.vm]); if (val && V.toJsonString(val).length > 2) { V.merge(_.vm.data, val, true) _.render(val); } }); return val; }; _.preonload = function(node) { var em = V.merge({}, __.event); V.forC(em, function(k, v) { v = typeof(v) === 'function' ? { Desc: '没有任何描述', Method: v } : v; em[k.toLowerCase()] = v; _.Events[k] = v.Desc; }, function() { //提供load方法作为控件初始化使用 em['init'] && em['init'].Method.apply(_, [node]); V.forC(_.events, function(k, v) { k = k.toLowerCase(); ((em[k] && em[k].Method) ? em[k].Method : _.bindEvent).apply(_, [node, k, v]); }, function() { //__.preonLoad(node); 不再调用父类的onLoad方法由Control统一控制完成 em['finally'] && em['finally'].Method.apply(_, [node]); }, true); }, true); }; _.render = function(data) { //如何实现在这种情况下对父类方法的覆盖和复用? var ret = { async: [], sync: [], finally: [] }; var rdata = {}; V.forC(data, function(k, v) { var k2 = k.toLowerCase(); var name = !!__.sync[k2] ? 'sync' : (!!__.async[k2] ? 'async' : !!__.finally[k2] ? 'finally' : false); name ? ret[name][ret[name].length] = { func: __[name][k2].Method, data: v, name: k2 } : rdata[k2] = (v && v.Method) || v; //保证完整赋值 !__.merge[k2] && (_.vm.data[k] = v); }, function() { rdata = __.prerender(rdata); //保证同异步同时启动 一般会是同步先执行完 然后 执行异步 最后是finally方法 ret.sync.forEach(function(v) { v.func.apply(_, [v.data, data, v.name]); }); V.each(ret.async, function(v) { v.func.apply(_, [v.data, data, v.name]); }, function() { V.each(ret.finally, function(v) { v.func.apply(_, [v.data, data, v.name]); }) }); }, true); return rdata; }; }; //专门为Control2继承而使用 var _mergefunc = function(_, ret, json, json2, name) { ret[name] = !!json[name] && !!json2[name] ? (function() { var em = json[name]; var em2 = json2[name]; var data = {}; V.forC(em, function(k, v) { data[k] = !!em2[k] ? (function() { var v1 = typeof(v) == 'function' ? { Method: v, override: false } : v, v2 = typeof(em2[k]) == 'function' ? { Method: em2[k], override: false } : em2[k]; delete em2[k]; var data2 = V.merge(v1, v2); data2.Method = v2.override ? data2.Method : function() { return v1.Method.apply(this, arguments) & v2.Method.apply(this, arguments); }; return data2; })() : v; }, function() { data = V.merge(data, em2); }, true); return data; })() : (json[name] || ret[name]); } /** * 专门为Control2继承而使用 * @param {*} json * @param {*} json */ var _merge = function(json, json2) { var _ = this; var ret = V.merge(json, json2); ret.template = json2.template || json.template; _mergefunc(_, ret, json, json2, 'onLoad'); _mergefunc(_, ret, json, json2, 'fill'); _mergefunc(_, ret, json, json2, 'render'); ret.fill && (ret.fill = (ret.fill.Method || ret.fill)); return ret; }; W.Control2.merge = function() { var _ = this; var as = (arguments.length > 0 ? Array.prototype.slice.call(arguments) : [{}]) as.forEach(function(v, i) { i > 0 && (as[0] = _merge.apply(_, [as[0], v])); }); return as[0]; }; } //分别定义view与viewmodel的Page M.Page = function(cm, data) { var _ = this, __ = {}; _.vms = V.getValue(data, {}); _.models = _.vms; //默认使用配置作为事件定义 V.inherit.apply(_, [M.Control, []]); _.page = _.vms.page || {}; _.data = _.page.data || {}; if (cm) { switch (V.getType(cm)) { case 'object': case 'Object': if (cm.getConfigValue) { _.config = cm; } else { _.config = V.config.getApplicationConfigManagerFromObj(cm); } break; case 'string': cm = eval('(' + cm + ')'); _.config = V.config.getApplicationConfigManagerFromObj(cm); } } else { _.config = V.config.getApplicationConfigManagerFromObj(); } _.middler = new V.middler.Middler(_.config); _.ni = new V.ni.NiTemplateManager(_.config, M.NIAPP); _.session = _.middler.getObjectByAppName(M.APP, 'SessionDataManager'); _.getModels = function(id) { return id ? (_.vms[id] ? _.vms[id] : null) : _.vms; }; _.setModels = function(id, v) { _.vms[id] = v; }; __.bind = _.bind; _.bind = function(view) { __.bind(view); _.page.v = view; } //初始化操作 var _page = _.middler.getObjectByAppName(W.APP, 'page'); if (!_page) { throw new Error('没有找到page对应的页面view层对象'); } //所有页面的操作起点 _page.ready(function() { _page.init(_, $(document.body)); _page.bind(_); }); }; W.Page = function(path) { var _ = this, __ = {}; { V.inherit.apply(_, [W.Control, [path]]); _.vs = {}; _.controls = []; __.render = _.render; __.onLoad = _.onLoad; __.dispose = _.dispose; } //用于重载触发方式 ready{init,bind(replace,onload),bindControl{onReady}} _.ready = function(func) { $(function() { func(); _.bindControl(_.node); }); window.onbeforeunload = function(e) { _.events['close'] ? (e.returnValue = _.vm.get().close || '请稍等……', _.call('close', { e: e })) : _.dispose(); }; }; //一般调用M.Page对象都比较特殊 _.bind = function(page) { var vm = page.page; _.page = page; if (vm) { //仅针对page节点 _.vm = vm; //完成配置合并 _.vm.data = V.merge(_.params, V.getValue(_.vm.data, {})); //完成方法注入 _.vm.update = function() { if (arguments.length == 0) { _.vm.data = V.merge(_.vm.data, _.fill()); } else { var as = Array.prototype.slice.call(arguments); as[0] = (as.length > 0 && as[0]) ? (function() { V.merge(_.vm.data, as[0], true); return as[0]; })() : V.merge({}, _.vm.data); _.render.apply(_, as); } return _.vm.data; }; _.vm.call = function() { return _.call.apply(_.page.getModels(), arguments); }; _.vm.add = function() { _.addControl.apply(_, arguments); }; _.vm.remove = function() { _.removeControl.apply(_, arguments); }; _.vm.desc = function() { _.desc(); }; _.vm.get = function(key) { _.vm.data = V.merge(_.vm.data, _.fill()); return key ? _.vm.data[key] : _.vm.data; }; _.page.registEvent = _.registEvent; _.page.callEvent = _.callEvent; _.page.hasEvent = _.hasEvent; _.page.clearEvent = _.clearEvent; _.page.registCommand = _.registCommand; _.page.callCommand = _.callCommand; _.page.hasCommand = _.hasCommand; _.page.clearCommand = _.clearCommand; V.forC(vm, function(key, value) { key = key.toLowerCase(); if (key.indexOf('on') == 0) { //事件注册 _.events[key.substring(2)] = value; }