UNPKG

lettuce

Version:

Lettuce JS, Mini Mobile Framework for Romantic with DSL.

549 lines (536 loc) 13.9 kB
/** * @author:leo * @email:cwq0312@163.com * @version:1.2.33 */ (function() { var win = this, doc = win.document || {}, nav = win.navigator || {}, // UA = nav.appVersion || nav.userAgent, loc = win.location; var encode = encodeURIComponent, decode = decodeURIComponent, slice = [].slice, // baseURL = loc.protocol + "//" + loc.hostname + (loc.port ? ":" + loc.port : ""), // config = { context: "/" //工程上下文目录 }; //var readyRE = /complete|loaded|interactive/i; // define qmik object function Q(selector, context) { return Q.init(selector, context) } Q.extend = function() { var args = arguments, ret = args[0] || {}, i = 1; switch (args.length) { case 0: return; case 1: ret = this; i = 0; break } each(slice.call(args, i), function(j, v) { v && each(v, function(key, val) { isNull(val) || (ret[key] = val) }) }); return ret } var strtype = String.prototype; Q.extend(strtype, { trim: function() { return this.replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, "") }, toLower: strtype.toLowerCase, toUpper: strtype.toUpperCase }); function grep(array, callback) { var ret = []; each(array, function(i, v) { (callback ? callback(i, v) : !isNull(v)) && ret.push(v) }); return ret } // public function // /////////////////////////////////////////////////////////////////// // isNull function isNull(v) { return v === undefined || v === null } function likeNull(v) { return isNull(v) || (isString(v) && (v == "undefined" || v == "null" || v.trim() == "")) } // isString function isString(v) { return typeof v == 'string' } // isDom function isDom(v) { return v && v.nodeType == 1 } // isArray function isArray(v) { return v instanceof Array } function likeArray(v) { // like Array return !isString(v) && (isArray(v) || (Q.isQmik && Q.isQmik(v)) || (function() { v += ""; return v == "[object Arguments]" || v == "[object NodeList]" || v == "[object HTMLCollection]" || v == "[object StaticNodeList]" })()) } // isFunction function isFun(v) { return v instanceof Function } function isError(v) { return v instanceof Error } function isObject(v) { return v instanceof Object } function each(obj, callback) { // each fun(k,v) var i; if (likeArray(obj)) { for (i = 0; i < obj.length; i++) { callback.call(obj[i], i, obj[i]) } } else if (isObject(obj)) { for (i in obj) { callback.call(obj[i], i, obj[i]) } } return obj; } // isNumber function isNum(v) { return typeof v == 'number' } function isBool(v) { return typeof v == 'boolean' } /* function isBaseType(v) { return isBool(v) || isString(v) || isNum(v) }*/ function toString(v) { return (isBool(v) || isString(v) || isNum(v)) ? v + "" : isFun(v) ? v.toString() : JSON.stringify(v) } // to json function toJSON(v) { return likeNull(v) ? "" : JSON.parse(v) } function isEvent(e) { return win.Event && e instanceof win.Event || e == win.event } function execObject(v) { return isFun(v) ? v() : v } function merge() { // merge array or object var args = arguments, array = args[0], isA = isArray(array); for(var i=1;i<args.length;i++){ each(args[i], function(k, v){ isA ? array.push(v) : array[k] = v }) } return array } /* function isGrandfather(grandfather, child) { return isDom(child) && (grandfather === child.parentNode ? !0 : isGrandfather(grandfather, child.parentNode)) }*/ // 合并url,参数个数不限 function concactUrl() { return Q.map(arguments, function(i, url) { return isArray(url) ? url.join("") : url }).join("/").replace(/(^\w+:\/\/)|([\/]{2,})/g, function(v) { return !/^\w+:\/\//.test(v) ? "/" : v }) } function loadResource(type, url, success, error) { url = Q.url(url); var isCss = type == "css", isScript = type == "js", // tagName = isCss ? "link" : isScript ? "script" : "iframe", node = doc.createElement(tagName), qnode = Q(node).attr({ _src: url, async: "async" }); isCss ? qnode.attr("rel", "stylesheet") : isScript && qnode.attr("type", "text/javascript"); /*node.ready(function(e) { success && success(node) }).on("error", function(e) { node.remove(); error && error(node) });*/ qnode.on({ load: function() { success && success(node) }, error: function() { qnode.remove(); error && error(node) } }); if (isCss) node.href = url; else node.src = url; Q("head").append(node); return node } /** 字符串变量${name}替换 */ function replaceVar(str, data){ data = data || {}; return isNull(str) ? null : (str+"").replace(/(\$[!]?\{[\.\w_ -]*\})|(\{\{[\.\w_ -]*\}\})/g, function(name) { var keys = name.replace(/(^\$?[!]?\{\{?)|(\}\}?$)/g, "").trim(); keys = keys.split("."); var val = data[keys[0]]; for (var i = 1; i < keys.length; i++) { try { val = val[keys[i]] } catch (e) { Q.log(e, str); return "" } } return val || ""; }) } /* 为每个渲染模块注入此方法 */ function addRenderChild(struct, item){ this.child = this.child || []; this.child.push({ text:Q.render(struct, item) }); } //////////Delay class, function 实现setTimeout的功能 function Delay(fun, time, params) { var me = this; me.pid = setTimeout(function() { fun.apply(fun, params) }, time) } Q.extend(Delay.prototype, { stop: function() { clearTimeout(this.pid) } }); /////////////// ///////////////////Cycle class function Cycle(fun, cycleTime, ttl, params) { var me = this, chisu = 1; function _exec() { if ((isNull(ttl) || (chisu * cycleTime) < ttl)) { fun.apply(fun, params); me._p = new Delay(_exec, cycleTime, params); } chisu++; } me._p = new Delay(_exec, cycleTime, params); } Q.extend(Cycle.prototype, { stop: function() { this._p && this._p.stop() } }); ////////////////////// Q .extend({ encode: encode, decode: decode, isDom: isDom, isBool: isBool, isString: isString, isFun: isFun, isFunction: isFun, isNum: isNum, isNumber: isNum, isArray: isArray, isNull: isNull, isError: isError, each: each, stringify: toString, parseJSON: toJSON, isEvent: isEvent, likeArray: likeArray, isDate: function(v) { return v instanceof Date }, isObject: isObject, isPlainObject: function(v) { // isPlainObject if (isNull(v) || v + '' != '[object Object]' || v.nodeType || v == win) return !1; var k; for (k in v) {} return isNull(k) || Object.prototype.hasOwnProperty.call(v, k) }, likeNull: likeNull, /** * 继承类 子类subClass继承父类superClass的属性方法, 注:子类有父类的属性及方法时,不会被父类替换 */ inherit: function(subClass, superClass) { function F() {} var subPrototype = subClass.prototype; F.prototype = superClass.prototype; subClass.prototype = new F(); subClass.prototype.constructor = subClass; if (superClass.prototype.constructor == Object.prototype.constructor) { superClass.prototype.constructor = superClass; } for (var name in subPrototype) { subClass.prototype[name] = subPrototype[name]; } for (var name in superClass) { subClass[name] = superClass[name]; } }, trim: function(v) { return isNull(v) ? "" : isString(v) ? v.trim() : v.toString().trim() }, toLower: function(v) { return v ? v.toLower() : v }, toUpper: function(v) { return v ? v.toUpper() : v }, // 合并数组或对象 merge: merge, inArray: function(value, array) { if (Q.likeArray(array)) for (var i = 0; i < array.length; i++) if (array[i] === value) return i; return -1 }, unique: function(array) { var ret = []; each(array, function(i, value) { Q.inArray(value, ret) < 0 && ret.push(value) }); return ret }, //contains : isGrandfather, /** * 对数组里的内容,做部做一次数据映射转换, * 例: * var array=[1,2,3]; * array = Qmik.map(array,function(index,val){ * return index*val * }); * console.log(array);//>>0,2,6 */ map: function(array, callback) { var r = [], i = 0; for (; array && i < array.length; i++) isNull(array[i]) || r.push(callback(i, array[i])); /*each(array, function(i, val) { isNull(val) || r.push(callback(i, val)); })*/ return r }, /** * 取得脚本 */ getScript: function(url, success, error) { return loadResource("js", url, success, error) }, /** * 取得css */ getCss: function(url, success, error) { return loadResource("css", url, success, error) }, grep: grep, /** * 抽取数组里面每个元素的name和value属性,转换成一个url形式(a=b&name=g)的字符串 */ param: function(array) { var h = []; each(array, function(i, v) { isString(i) ? h.push(encode(i) + '=' + encode(execObject(v))) : v.name && h.push(encode(v.name) + '=' + encode(execObject(v.value))) }); return h.join('&') }, /** * 当前时间 */ now: function(d) { return (d || 0) + new Date().getTime() }, // 延迟执行,==setTimeout /** * target:apply,call的指向对象 */ delay: function(fun, time) { //var params = slice.call(arguments, 2); return new Delay(fun, time, slice.call(arguments, 2)) }, // 周期执行 /** * fun:执行的方法 * cycleTime:执行的周期时间 * ttl:过期时间,执行时间>ttl时,停止执行,单位 ms(毫秒) * target:apply,call的指向对象 */ cycle: function(fun, cycleTime, ttl) { //var params = slice.call(arguments, 3); return new Cycle(fun, cycleTime, ttl, slice.call(arguments, 3)); }, log: function() { var args = arguments; if (config.debug || isError(args[0])) { try{console.log.apply(Q, args)}catch(e){Q.each(args,function(i,v){console.log(v)})}; } }, isIphone: function() { return /iPhone OS/.test(UA) }, isAndroid: function() { return /Android/.test(UA) }, isWP: function() { return /Windows Phone/.test(UA) }, isIE: function() { return /MSIE/.test(UA) }, /** * is Firefox */ isFF: function() { return /Firefox/.test(UA) }, /** * is Webkit */ isWK: function() { return /WebKit/.test(UA) }, isOpera: function() { return /Opera/.test(UA) }, isRetinal: function() { //判断是否是视网膜高清屏,默认是高清屏 return (win.devicePixelRatio || 2) >= 1.5; }, config: function(opts, _config) { _config = arguments.length <= 1 ? config : (_config || {}); var ret = _config; if (arguments.length < 1 || isNull(opts)) {} else if (!isObject(opts)) { ret = _config[opts] } else { each(opts, function(key, val) { isObject(val) && _config[key] ? Q.extend(_config[key], val) : (_config[key] = val) }) } return ret //return (arguments.length < 1 || isNull(opts)) ? _config : isObject(opts) ? Q.extend(_config, opts) : _config[opts] }, /** * 合并url,if 参数 _url为空,则 */ url: function(_url) { return arguments.length < 1 ? baseURL : !/^[a-zA-Z0-9]+:\/\//.test(_url) ? concactUrl(baseURL, (/^\//.test(_url) ? "" : config.context || "/") + "/" + _url) : _url }, cssPrefix: function(style) { var ret = {}; if (isString(style)) { ret = (Q.isWK() ? "-webkit-" : Q.isIE() ? "-ms-" : Q.isFF() ? "-moz-" : Q.isOpera() ? "-o-" : "") + style; } else { each(Q.extend({}, style), function(key, val) { ret[Q.cssPrefix(key)] = val }) } return ret }, /** 局部页面渲染引擎 struct:数据结构:{ tag:'div[id="${id}" name="${name}" itemid="${itemid}"]', text:'显示文本', child:[//子节点 { tag:'p[class="title"]', text:'显示内容' }, { tag:'p[class="remark"]', text:'显示内容' } ] }, item://数据 { id:"", name:"", itemid:"" } */ render: function(struct, data) { var h = [], tag = (struct.tag || "").trim(), text = struct.text; data = struct.data || data; text = replaceVar(text, data); struct.add = addRenderChild; if ( tag=="" && !isNull(text)) { return text } if(!/^\s*\w+\s*(\[.*\])?\s*$/.test(tag)){ console.log("tag is lllegal:",tag); return "" } var tagName = (tag.match(/^[^\[]+/)||[""])[0]; var attr = (tag.match(/\[.*$/) || [""])[0].replace(/(^\s*\[)|(\s*\]\s*$)/g, ""); h.push('<' + tagName + " "); attr = replaceVar(attr, data); h.push(attr); h.push('>'); isNull(text) || h.push(text); struct.exec && Q.execCatch(function(){ struct.exec() }); isArray(struct.child) && each(struct.child, function(i, ch) { ch && h.push(Q.render(ch, data)); }); h.push('</' + tagName + '>'); return h.join(""); }, /** 执行方法并捕获异常,不向外抛出异常,try{}catch(e){} 影响方法的美观性 fun:执行方法 args:数组,参数[] error:抛出异常回调,无异常不回调 */ execCatch: function (fun, args, error) { try { fun.apply(fun, args||[]); } catch (e) { Q.log(e, e.stack); error && error(e); } } }); each([ Q.url, Q.now ], function(i, val) { val.toString = val }); //不对外部开放,不保持此对象api不变动, Q._in = { createEvent: function(type) { return doc.createEvent ? doc.createEvent(type) : doc.createEventObject(type) }, isSE: function() { return !isNull(doc.addEventListener) } }; /////////////////////////////////////////////////////// Q.version = "1.3.80"; Q.global = win; win.Qmik = Q; win.$ = win.$ || Q; })();