UNPKG

mockjs

Version:

生成随机数据 & 拦截 Ajax 请求

1,580 lines (1,396 loc) 272 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["Mock"] = factory(); else root["Mock"] = factory(); })(this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { /* global require, module, window */ var Handler = __webpack_require__(1) var Util = __webpack_require__(3) var Random = __webpack_require__(5) var RE = __webpack_require__(20) var toJSONSchema = __webpack_require__(23) var valid = __webpack_require__(25) var XHR if (typeof window !== 'undefined') XHR = __webpack_require__(27) /*! Mock - 模拟请求 & 模拟数据 https://github.com/nuysoft/Mock 墨智 mozhi.gyy@taobao.com nuysoft@gmail.com */ var Mock = { Handler: Handler, Random: Random, Util: Util, XHR: XHR, RE: RE, toJSONSchema: toJSONSchema, valid: valid, heredoc: Util.heredoc, setup: function(settings) { return XHR.setup(settings) }, _mocked: {} } Mock.version = '1.0.1-beta3' // 避免循环依赖 if (XHR) XHR.Mock = Mock /* * Mock.mock( template ) * Mock.mock( function() ) * Mock.mock( rurl, template ) * Mock.mock( rurl, function(options) ) * Mock.mock( rurl, rtype, template ) * Mock.mock( rurl, rtype, function(options) ) 根据数据模板生成模拟数据。 */ Mock.mock = function(rurl, rtype, template) { // Mock.mock(template) if (arguments.length === 1) { return Handler.gen(rurl) } // Mock.mock(rurl, template) if (arguments.length === 2) { template = rtype rtype = undefined } // 拦截 XHR if (XHR) window.XMLHttpRequest = XHR Mock._mocked[rurl + (rtype || '')] = { rurl: rurl, rtype: rtype, template: template } return Mock } module.exports = Mock /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { /* ## Handler 处理数据模板。 * Handler.gen( template, name?, context? ) 入口方法。 * Data Template Definition, DTD 处理数据模板定义。 * Handler.array( options ) * Handler.object( options ) * Handler.number( options ) * Handler.boolean( options ) * Handler.string( options ) * Handler.function( options ) * Handler.regexp( options ) 处理路径(相对和绝对)。 * Handler.getValueByKeyPath( key, options ) * Data Placeholder Definition, DPD 处理数据占位符定义 * Handler.placeholder( placeholder, context, templateContext, options ) */ var Constant = __webpack_require__(2) var Util = __webpack_require__(3) var Parser = __webpack_require__(4) var Random = __webpack_require__(5) var RE = __webpack_require__(20) var Handler = { extend: Util.extend } /* template 属性值(即数据模板) name 属性名 context 数据上下文,生成后的数据 templateContext 模板上下文, Handle.gen(template, name, options) context currentContext, templateCurrentContext, path, templatePath root, templateRoot */ Handler.gen = function(template, name, context) { /* jshint -W041 */ name = name == undefined ? '' : (name + '') context = context || {} context = { // 当前访问路径,只有属性名,不包括生成规则 path: context.path || [Constant.GUID], templatePath: context.templatePath || [Constant.GUID++], // 最终属性值的上下文 currentContext: context.currentContext, // 属性值模板的上下文 templateCurrentContext: context.templateCurrentContext || template, // 最终值的根 root: context.root || context.currentContext, // 模板的根 templateRoot: context.templateRoot || context.templateCurrentContext || template } // console.log('path:', context.path.join('.'), template) var rule = Parser.parse(name) var type = Util.type(template) var data if (Handler[type]) { data = Handler[type]({ // 属性值类型 type: type, // 属性值模板 template: template, // 属性名 + 生成规则 name: name, // 属性名 parsedName: name ? name.replace(Constant.RE_KEY, '$1') : name, // 解析后的生成规则 rule: rule, // 相关上下文 context: context }) if (!context.root) context.root = data return data } return template } Handler.extend({ array: function(options) { var result = [], i, ii; // 'name|1': [] // 'name|count': [] // 'name|min-max': [] if (options.template.length === 0) return result // 'arr': [{ 'email': '@EMAIL' }, { 'email': '@EMAIL' }] if (!options.rule.parameters) { for (i = 0; i < options.template.length; i++) { options.context.path.push(i) options.context.templatePath.push(i) result.push( Handler.gen(options.template[i], i, { path: options.context.path, templatePath: options.context.templatePath, currentContext: result, templateCurrentContext: options.template, root: options.context.root || result, templateRoot: options.context.templateRoot || options.template }) ) options.context.path.pop() options.context.templatePath.pop() } } else { // 'method|1': ['GET', 'POST', 'HEAD', 'DELETE'] if (options.rule.min === 1 && options.rule.max === undefined) { // fix #17 options.context.path.push(options.name) options.context.templatePath.push(options.name) result = Random.pick( Handler.gen(options.template, undefined, { path: options.context.path, templatePath: options.context.templatePath, currentContext: result, templateCurrentContext: options.template, root: options.context.root || result, templateRoot: options.context.templateRoot || options.template }) ) options.context.path.pop() options.context.templatePath.pop() } else { // 'data|+1': [{}, {}] if (options.rule.parameters[2]) { options.template.__order_index = options.template.__order_index || 0 options.context.path.push(options.name) options.context.templatePath.push(options.name) result = Handler.gen(options.template, undefined, { path: options.context.path, templatePath: options.context.templatePath, currentContext: result, templateCurrentContext: options.template, root: options.context.root || result, templateRoot: options.context.templateRoot || options.template })[ options.template.__order_index % options.template.length ] options.template.__order_index += +options.rule.parameters[2] options.context.path.pop() options.context.templatePath.pop() } else { // 'data|1-10': [{}] for (i = 0; i < options.rule.count; i++) { // 'data|1-10': [{}, {}] for (ii = 0; ii < options.template.length; ii++) { options.context.path.push(result.length) options.context.templatePath.push(ii) result.push( Handler.gen(options.template[ii], result.length, { path: options.context.path, templatePath: options.context.templatePath, currentContext: result, templateCurrentContext: options.template, root: options.context.root || result, templateRoot: options.context.templateRoot || options.template }) ) options.context.path.pop() options.context.templatePath.pop() } } } } } return result }, object: function(options) { var result = {}, keys, fnKeys, key, parsedKey, inc, i; // 'obj|min-max': {} /* jshint -W041 */ if (options.rule.min != undefined) { keys = Util.keys(options.template) keys = Random.shuffle(keys) keys = keys.slice(0, options.rule.count) for (i = 0; i < keys.length; i++) { key = keys[i] parsedKey = key.replace(Constant.RE_KEY, '$1') options.context.path.push(parsedKey) options.context.templatePath.push(key) result[parsedKey] = Handler.gen(options.template[key], key, { path: options.context.path, templatePath: options.context.templatePath, currentContext: result, templateCurrentContext: options.template, root: options.context.root || result, templateRoot: options.context.templateRoot || options.template }) options.context.path.pop() options.context.templatePath.pop() } } else { // 'obj': {} keys = [] fnKeys = [] // #25 改变了非函数属性的顺序,查找起来不方便 for (key in options.template) { (typeof options.template[key] === 'function' ? fnKeys : keys).push(key) } keys = keys.concat(fnKeys) /* 会改变非函数属性的顺序 keys = Util.keys(options.template) keys.sort(function(a, b) { var afn = typeof options.template[a] === 'function' var bfn = typeof options.template[b] === 'function' if (afn === bfn) return 0 if (afn && !bfn) return 1 if (!afn && bfn) return -1 }) */ for (i = 0; i < keys.length; i++) { key = keys[i] parsedKey = key.replace(Constant.RE_KEY, '$1') options.context.path.push(parsedKey) options.context.templatePath.push(key) result[parsedKey] = Handler.gen(options.template[key], key, { path: options.context.path, templatePath: options.context.templatePath, currentContext: result, templateCurrentContext: options.template, root: options.context.root || result, templateRoot: options.context.templateRoot || options.template }) options.context.path.pop() options.context.templatePath.pop() // 'id|+1': 1 inc = key.match(Constant.RE_KEY) if (inc && inc[2] && Util.type(options.template[key]) === 'number') { options.template[key] += parseInt(inc[2], 10) } } } return result }, number: function(options) { var result, parts; if (options.rule.decimal) { // float options.template += '' parts = options.template.split('.') // 'float1|.1-10': 10, // 'float2|1-100.1-10': 1, // 'float3|999.1-10': 1, // 'float4|.3-10': 123.123, parts[0] = options.rule.range ? options.rule.count : parts[0] parts[1] = (parts[1] || '').slice(0, options.rule.dcount) while (parts[1].length < options.rule.dcount) { parts[1] += ( // 最后一位不能为 0:如果最后一位为 0,会被 JS 引擎忽略掉。 (parts[1].length < options.rule.dcount - 1) ? Random.character('number') : Random.character('123456789') ) } result = parseFloat(parts.join('.'), 10) } else { // integer // 'grade1|1-100': 1, result = options.rule.range && !options.rule.parameters[2] ? options.rule.count : options.template } return result }, boolean: function(options) { var result; // 'prop|multiple': false, 当前值是相反值的概率倍数 // 'prop|probability-probability': false, 当前值与相反值的概率 result = options.rule.parameters ? Random.bool(options.rule.min, options.rule.max, options.template) : options.template return result }, string: function(options) { var result = '', i, placeholders, ph, phed; if (options.template.length) { // 'foo': '★', /* jshint -W041 */ if (options.rule.count == undefined) { result += options.template } // 'star|1-5': '★', for (i = 0; i < options.rule.count; i++) { result += options.template } // 'email|1-10': '@EMAIL, ', placeholders = result.match(Constant.RE_PLACEHOLDER) || [] // A-Z_0-9 > \w_ for (i = 0; i < placeholders.length; i++) { ph = placeholders[i] // 遇到转义斜杠,不需要解析占位符 if (/^\\/.test(ph)) { placeholders.splice(i--, 1) continue } phed = Handler.placeholder(ph, options.context.currentContext, options.context.templateCurrentContext, options) // 只有一个占位符,并且没有其他字符 if (placeholders.length === 1 && ph === result && typeof phed !== typeof result) { // result = phed break if (Util.isNumeric(phed)) { result = parseFloat(phed, 10) break } if (/^(true|false)$/.test(phed)) { result = phed === 'true' ? true : phed === 'false' ? false : phed // 已经是布尔值 break } } result = result.replace(ph, phed) } } else { // 'ASCII|1-10': '', // 'ASCII': '', result = options.rule.range ? Random.string(options.rule.count) : options.template } return result }, 'function': function(options) { // ( context, options ) return options.template.call(options.context.currentContext, options) }, 'regexp': function(options) { var source = '' // 'name': /regexp/, /* jshint -W041 */ if (options.rule.count == undefined) { source += options.template.source // regexp.source } // 'name|1-5': /regexp/, for (var i = 0; i < options.rule.count; i++) { source += options.template.source } return RE.Handler.gen( RE.Parser.parse( source ) ) } }) Handler.extend({ _all: function() { var re = {}; for (var key in Random) re[key.toLowerCase()] = key return re }, // 处理占位符,转换为最终值 placeholder: function(placeholder, obj, templateContext, options) { // console.log(options.context.path) // 1 key, 2 params Constant.RE_PLACEHOLDER.exec('') var parts = Constant.RE_PLACEHOLDER.exec(placeholder), key = parts && parts[1], lkey = key && key.toLowerCase(), okey = this._all()[lkey], params = parts && parts[2] || '' var pathParts = this.splitPathToArray(key) // 解析占位符的参数 try { // 1. 尝试保持参数的类型 /* #24 [Window Firefox 30.0 引用 占位符 抛错](https://github.com/nuysoft/Mock/issues/24) [BX9056: 各浏览器下 window.eval 方法的执行上下文存在差异](http://www.w3help.org/zh-cn/causes/BX9056) 应该属于 Window Firefox 30.0 的 BUG */ /* jshint -W061 */ params = eval('(function(){ return [].splice.call(arguments, 0 ) })(' + params + ')') } catch (error) { // 2. 如果失败,只能解析为字符串 // console.error(error) // if (error instanceof ReferenceError) params = parts[2].split(/,\s*/); // else throw error params = parts[2].split(/,\s*/) } // 占位符优先引用数据模板中的属性 if (obj && (key in obj)) return obj[key] // @index @key // if (Constant.RE_INDEX.test(key)) return +options.name // if (Constant.RE_KEY.test(key)) return options.name // 绝对路径 or 相对路径 if ( key.charAt(0) === '/' || pathParts.length > 1 ) return this.getValueByKeyPath(key, options) // 递归引用数据模板中的属性 if (templateContext && (typeof templateContext === 'object') && (key in templateContext) && (placeholder !== templateContext[key]) // fix #15 避免自己依赖自己 ) { // 先计算被引用的属性值 templateContext[key] = Handler.gen(templateContext[key], key, { currentContext: obj, templateCurrentContext: templateContext }) return templateContext[key] } // 如果未找到,则原样返回 if (!(key in Random) && !(lkey in Random) && !(okey in Random)) return placeholder // 递归解析参数中的占位符 for (var i = 0; i < params.length; i++) { Constant.RE_PLACEHOLDER.exec('') if (Constant.RE_PLACEHOLDER.test(params[i])) { params[i] = Handler.placeholder(params[i], obj, templateContext, options) } } var handle = Random[key] || Random[lkey] || Random[okey] switch (Util.type(handle)) { case 'array': // 自动从数组中取一个,例如 @areas return Random.pick(handle) case 'function': // 执行占位符方法(大多数情况) handle.options = options var re = handle.apply(Random, params) if (re === undefined) re = '' // 因为是在字符串中,所以默认为空字符串。 delete handle.options return re } }, getValueByKeyPath: function(key, options) { var originalKey = key var keyPathParts = this.splitPathToArray(key) var absolutePathParts = [] // 绝对路径 if (key.charAt(0) === '/') { absolutePathParts = [options.context.path[0]].concat( this.normalizePath(keyPathParts) ) } else { // 相对路径 if (keyPathParts.length > 1) { absolutePathParts = options.context.path.slice(0) absolutePathParts.pop() absolutePathParts = this.normalizePath( absolutePathParts.concat(keyPathParts) ) } } try { key = keyPathParts[keyPathParts.length - 1] var currentContext = options.context.root var templateCurrentContext = options.context.templateRoot for (var i = 1; i < absolutePathParts.length - 1; i++) { currentContext = currentContext[absolutePathParts[i]] templateCurrentContext = templateCurrentContext[absolutePathParts[i]] } // 引用的值已经计算好 if (currentContext && (key in currentContext)) return currentContext[key] // 尚未计算,递归引用数据模板中的属性 if (templateCurrentContext && (typeof templateCurrentContext === 'object') && (key in templateCurrentContext) && (originalKey !== templateCurrentContext[key]) // fix #15 避免自己依赖自己 ) { // 先计算被引用的属性值 templateCurrentContext[key] = Handler.gen(templateCurrentContext[key], key, { currentContext: currentContext, templateCurrentContext: templateCurrentContext }) return templateCurrentContext[key] } } catch(err) { } return '@' + keyPathParts.join('/') }, // https://github.com/kissyteam/kissy/blob/master/src/path/src/path.js normalizePath: function(pathParts) { var newPathParts = [] for (var i = 0; i < pathParts.length; i++) { switch (pathParts[i]) { case '..': newPathParts.pop() break case '.': break default: newPathParts.push(pathParts[i]) } } return newPathParts }, splitPathToArray: function(path) { var parts = path.split(/\/+/); if (!parts[parts.length - 1]) parts = parts.slice(0, -1) if (!parts[0]) parts = parts.slice(1) return parts; } }) module.exports = Handler /***/ }), /* 2 */ /***/ (function(module, exports) { /* ## Constant 常量集合。 */ /* RE_KEY 'name|min-max': value 'name|count': value 'name|min-max.dmin-dmax': value 'name|min-max.dcount': value 'name|count.dmin-dmax': value 'name|count.dcount': value 'name|+step': value 1 name, 2 step, 3 range [ min, max ], 4 drange [ dmin, dmax ] RE_PLACEHOLDER placeholder(*) [正则查看工具](http://www.regexper.com/) #26 生成规则 支持 负数,例如 number|-100-100 */ module.exports = { GUID: 1, RE_KEY: /(.+)\|(?:\+(\d+)|([\+\-]?\d+-?[\+\-]?\d*)?(?:\.(\d+-?\d*))?)/, RE_RANGE: /([\+\-]?\d+)-?([\+\-]?\d+)?/, RE_PLACEHOLDER: /\\*@([^@#%&()\?\s]+)(?:\((.*?)\))?/g // /\\*@([^@#%&()\?\s\/\.]+)(?:\((.*?)\))?/g // RE_INDEX: /^index$/, // RE_KEY: /^key$/ } /***/ }), /* 3 */ /***/ (function(module, exports) { /* ## Utilities */ var Util = {} Util.extend = function extend() { var target = arguments[0] || {}, i = 1, length = arguments.length, options, name, src, copy, clone if (length === 1) { target = this i = 0 } for (; i < length; i++) { options = arguments[i] if (!options) continue for (name in options) { src = target[name] copy = options[name] if (target === copy) continue if (copy === undefined) continue if (Util.isArray(copy) || Util.isObject(copy)) { if (Util.isArray(copy)) clone = src && Util.isArray(src) ? src : [] if (Util.isObject(copy)) clone = src && Util.isObject(src) ? src : {} target[name] = Util.extend(clone, copy) } else { target[name] = copy } } } return target } Util.each = function each(obj, iterator, context) { var i, key if (this.type(obj) === 'number') { for (i = 0; i < obj; i++) { iterator(i, i) } } else if (obj.length === +obj.length) { for (i = 0; i < obj.length; i++) { if (iterator.call(context, obj[i], i, obj) === false) break } } else { for (key in obj) { if (iterator.call(context, obj[key], key, obj) === false) break } } } Util.type = function type(obj) { return (obj === null || obj === undefined) ? String(obj) : Object.prototype.toString.call(obj).match(/\[object (\w+)\]/)[1].toLowerCase() } Util.each('String Object Array RegExp Function'.split(' '), function(value) { Util['is' + value] = function(obj) { return Util.type(obj) === value.toLowerCase() } }) Util.isObjectOrArray = function(value) { return Util.isObject(value) || Util.isArray(value) } Util.isNumeric = function(value) { return !isNaN(parseFloat(value)) && isFinite(value) } Util.keys = function(obj) { var keys = []; for (var key in obj) { if (obj.hasOwnProperty(key)) keys.push(key) } return keys; } Util.values = function(obj) { var values = []; for (var key in obj) { if (obj.hasOwnProperty(key)) values.push(obj[key]) } return values; } /* ### Mock.heredoc(fn) * Mock.heredoc(fn) 以直观、安全的方式书写(多行)HTML 模板。 **使用示例**如下所示: var tpl = Mock.heredoc(function() { /*! {{email}}{{age}} <!-- Mock { email: '@EMAIL', age: '@INT(1,100)' } --> *\/ }) **相关阅读** * [Creating multiline strings in JavaScript](http://stackoverflow.com/questions/805107/creating-multiline-strings-in-javascript)、 */ Util.heredoc = function heredoc(fn) { // 1. 移除起始的 function(){ /*! // 2. 移除末尾的 */ } // 3. 移除起始和末尾的空格 return fn.toString() .replace(/^[^\/]+\/\*!?/, '') .replace(/\*\/[^\/]+$/, '') .replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, '') // .trim() } Util.noop = function() {} module.exports = Util /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { /* ## Parser 解析数据模板(属性名部分)。 * Parser.parse( name ) ```json { parameters: [ name, inc, range, decimal ], rnage: [ min , max ], min: min, max: max, count : count, decimal: decimal, dmin: dmin, dmax: dmax, dcount: dcount } ``` */ var Constant = __webpack_require__(2) var Random = __webpack_require__(5) /* jshint -W041 */ module.exports = { parse: function(name) { name = name == undefined ? '' : (name + '') var parameters = (name || '').match(Constant.RE_KEY) var range = parameters && parameters[3] && parameters[3].match(Constant.RE_RANGE) var min = range && range[1] && parseInt(range[1], 10) // || 1 var max = range && range[2] && parseInt(range[2], 10) // || 1 // repeat || min-max || 1 // var count = range ? !range[2] && parseInt(range[1], 10) || Random.integer(min, max) : 1 var count = range ? !range[2] ? parseInt(range[1], 10) : Random.integer(min, max) : undefined var decimal = parameters && parameters[4] && parameters[4].match(Constant.RE_RANGE) var dmin = decimal && decimal[1] && parseInt(decimal[1], 10) // || 0, var dmax = decimal && decimal[2] && parseInt(decimal[2], 10) // || 0, // int || dmin-dmax || 0 var dcount = decimal ? !decimal[2] && parseInt(decimal[1], 10) || Random.integer(dmin, dmax) : undefined var result = { // 1 name, 2 inc, 3 range, 4 decimal parameters: parameters, // 1 min, 2 max range: range, min: min, max: max, // min-max count: count, // 是否有 decimal decimal: decimal, dmin: dmin, dmax: dmax, // dmin-dimax dcount: dcount } for (var r in result) { if (result[r] != undefined) return result } return {} } } /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { /* ## Mock.Random 工具类,用于生成各种随机数据。 */ var Util = __webpack_require__(3) var Random = { extend: Util.extend } Random.extend(__webpack_require__(6)) Random.extend(__webpack_require__(7)) Random.extend(__webpack_require__(8)) Random.extend(__webpack_require__(10)) Random.extend(__webpack_require__(13)) Random.extend(__webpack_require__(15)) Random.extend(__webpack_require__(16)) Random.extend(__webpack_require__(17)) Random.extend(__webpack_require__(14)) Random.extend(__webpack_require__(19)) module.exports = Random /***/ }), /* 6 */ /***/ (function(module, exports) { /* ## Basics */ module.exports = { // 返回一个随机的布尔值。 boolean: function(min, max, cur) { if (cur !== undefined) { min = typeof min !== 'undefined' && !isNaN(min) ? parseInt(min, 10) : 1 max = typeof max !== 'undefined' && !isNaN(max) ? parseInt(max, 10) : 1 return Math.random() > 1.0 / (min + max) * min ? !cur : cur } return Math.random() >= 0.5 }, bool: function(min, max, cur) { return this.boolean(min, max, cur) }, // 返回一个随机的自然数(大于等于 0 的整数)。 natural: function(min, max) { min = typeof min !== 'undefined' ? parseInt(min, 10) : 0 max = typeof max !== 'undefined' ? parseInt(max, 10) : 9007199254740992 // 2^53 return Math.round(Math.random() * (max - min)) + min }, // 返回一个随机的整数。 integer: function(min, max) { min = typeof min !== 'undefined' ? parseInt(min, 10) : -9007199254740992 max = typeof max !== 'undefined' ? parseInt(max, 10) : 9007199254740992 // 2^53 return Math.round(Math.random() * (max - min)) + min }, int: function(min, max) { return this.integer(min, max) }, // 返回一个随机的浮点数。 float: function(min, max, dmin, dmax) { dmin = dmin === undefined ? 0 : dmin dmin = Math.max(Math.min(dmin, 17), 0) dmax = dmax === undefined ? 17 : dmax dmax = Math.max(Math.min(dmax, 17), 0) var ret = this.integer(min, max) + '.'; for (var i = 0, dcount = this.natural(dmin, dmax); i < dcount; i++) { ret += ( // 最后一位不能为 0:如果最后一位为 0,会被 JS 引擎忽略掉。 (i < dcount - 1) ? this.character('number') : this.character('123456789') ) } return parseFloat(ret, 10) }, // 返回一个随机字符。 character: function(pool) { var pools = { lower: 'abcdefghijklmnopqrstuvwxyz', upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', number: '0123456789', symbol: '!@#$%^&*()[]' } pools.alpha = pools.lower + pools.upper pools['undefined'] = pools.lower + pools.upper + pools.number + pools.symbol pool = pools[('' + pool).toLowerCase()] || pool return pool.charAt(this.natural(0, pool.length - 1)) }, char: function(pool) { return this.character(pool) }, // 返回一个随机字符串。 string: function(pool, min, max) { var len switch (arguments.length) { case 0: // () len = this.natural(3, 7) break case 1: // ( length ) len = pool pool = undefined break case 2: // ( pool, length ) if (typeof arguments[0] === 'string') { len = min } else { // ( min, max ) len = this.natural(pool, min) pool = undefined } break case 3: len = this.natural(min, max) break } var text = '' for (var i = 0; i < len; i++) { text += this.character(pool) } return text }, str: function( /*pool, min, max*/ ) { return this.string.apply(this, arguments) }, // 返回一个整型数组。 range: function(start, stop, step) { // range( stop ) if (arguments.length <= 1) { stop = start || 0; start = 0; } // range( start, stop ) step = arguments[2] || 1; start = +start stop = +stop step = +step var len = Math.max(Math.ceil((stop - start) / step), 0); var idx = 0; var range = new Array(len); while (idx < len) { range[idx++] = start; start += step; } return range; } } /***/ }), /* 7 */ /***/ (function(module, exports) { /* ## Date */ var patternLetters = { yyyy: 'getFullYear', yy: function(date) { return ('' + date.getFullYear()).slice(2) }, y: 'yy', MM: function(date) { var m = date.getMonth() + 1 return m < 10 ? '0' + m : m }, M: function(date) { return date.getMonth() + 1 }, dd: function(date) { var d = date.getDate() return d < 10 ? '0' + d : d }, d: 'getDate', HH: function(date) { var h = date.getHours() return h < 10 ? '0' + h : h }, H: 'getHours', hh: function(date) { var h = date.getHours() % 12 return h < 10 ? '0' + h : h }, h: function(date) { return date.getHours() % 12 }, mm: function(date) { var m = date.getMinutes() return m < 10 ? '0' + m : m }, m: 'getMinutes', ss: function(date) { var s = date.getSeconds() return s < 10 ? '0' + s : s }, s: 'getSeconds', SS: function(date) { var ms = date.getMilliseconds() return ms < 10 && '00' + ms || ms < 100 && '0' + ms || ms }, S: 'getMilliseconds', A: function(date) { return date.getHours() < 12 ? 'AM' : 'PM' }, a: function(date) { return date.getHours() < 12 ? 'am' : 'pm' }, T: 'getTime' } module.exports = { // 日期占位符集合。 _patternLetters: patternLetters, // 日期占位符正则。 _rformat: new RegExp((function() { var re = [] for (var i in patternLetters) re.push(i) return '(' + re.join('|') + ')' })(), 'g'), // 格式化日期。 _formatDate: function(date, format) { return format.replace(this._rformat, function creatNewSubString($0, flag) { return typeof patternLetters[flag] === 'function' ? patternLetters[flag](date) : patternLetters[flag] in patternLetters ? creatNewSubString($0, patternLetters[flag]) : date[patternLetters[flag]]() }) }, // 生成一个随机的 Date 对象。 _randomDate: function(min, max) { // min, max min = min === undefined ? new Date(0) : min max = max === undefined ? new Date() : max return new Date(Math.random() * (max.getTime() - min.getTime())) }, // 返回一个随机的日期字符串。 date: function(format) { format = format || 'yyyy-MM-dd' return this._formatDate(this._randomDate(), format) }, // 返回一个随机的时间字符串。 time: function(format) { format = format || 'HH:mm:ss' return this._formatDate(this._randomDate(), format) }, // 返回一个随机的日期和时间字符串。 datetime: function(format) { format = format || 'yyyy-MM-dd HH:mm:ss' return this._formatDate(this._randomDate(), format) }, // 返回当前的日期和时间字符串。 now: function(unit, format) { // now(unit) now(format) if (arguments.length === 1) { // now(format) if (!/year|month|day|hour|minute|second|week/.test(unit)) { format = unit unit = '' } } unit = (unit || '').toLowerCase() format = format || 'yyyy-MM-dd HH:mm:ss' var date = new Date() /* jshint -W086 */ // 参考自 http://momentjs.cn/docs/#/manipulating/start-of/ switch (unit) { case 'year': date.setMonth(0) case 'month': date.setDate(1) case 'week': case 'day': date.setHours(0) case 'hour': date.setMinutes(0) case 'minute': date.setSeconds(0) case 'second': date.setMilliseconds(0) } switch (unit) { case 'week': date.setDate(date.getDate() - date.getDay()) } return this._formatDate(date, format) } } /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(module) {/* global document */ /* ## Image */ module.exports = { // 常见的广告宽高 _adSize: [ '300x250', '250x250', '240x400', '336x280', '180x150', '720x300', '468x60', '234x60', '88x31', '120x90', '120x60', '120x240', '125x125', '728x90', '160x600', '120x600', '300x600' ], // 常见的屏幕宽高 _screenSize: [ '320x200', '320x240', '640x480', '800x480', '800x480', '1024x600', '1024x768', '1280x800', '1440x900', '1920x1200', '2560x1600' ], // 常见的视频宽高 _videoSize: ['720x480', '768x576', '1280x720', '1920x1080'], /* 生成一个随机的图片地址。 替代图片源 http://fpoimg.com/ 参考自 http://rensanning.iteye.com/blog/1933310 http://code.tutsplus.com/articles/the-top-8-placeholders-for-web-designers--net-19485 */ image: function(size, background, foreground, format, text) { // Random.image( size, background, foreground, text ) if (arguments.length === 4) { text = format format = undefined } // Random.image( size, background, text ) if (arguments.length === 3) { text = foreground foreground = undefined } // Random.image() if (!size) size = this.pick(this._adSize) if (background && ~background.indexOf('#')) background = background.slice(1) if (foreground && ~foreground.indexOf('#')) foreground = foreground.slice(1) // http://dummyimage.com/600x400/cc00cc/470047.png&text=hello return 'http://dummyimage.com/' + size + (background ? '/' + background : '') + (foreground ? '/' + foreground : '') + (format ? '.' + format : '') + (text ? '&text=' + text : '') }, img: function() { return this.image.apply(this, arguments) }, /* BrandColors http://brandcolors.net/ A collection of major brand color codes curated by Galen Gidman. 大牌公司的颜色集合 // 获取品牌和颜色 $('h2').each(function(index, item){ item = $(item) console.log('\'' + item.text() + '\'', ':', '\'' + item.next().text() + '\'', ',') }) */ _brandColors: { '4ormat': '#fb0a2a', '500px': '#02adea', 'About.me (blue)': '#00405d', 'About.me (yellow)': '#ffcc33', 'Addvocate': '#ff6138', 'Adobe': '#ff0000', 'Aim': '#fcd20b', 'Amazon': '#e47911', 'Android': '#a4c639', 'Angie\'s List': '#7fbb00', 'AOL': '#0060a3', 'Atlassian': '#003366', 'Behance': '#053eff', 'Big Cartel': '#97b538', 'bitly': '#ee6123', 'Blogger': '#fc4f08', 'Boeing': '#0039a6', 'Booking.com': '#003580', 'Carbonmade': '#613854', 'Cheddar': '#ff7243', 'Code School': '#3d4944', 'Delicious': '#205cc0', 'Dell': '#3287c1', 'Designmoo': '#e54a4f', 'Deviantart': '#4e6252', 'Designer News': '#2d72da', 'Devour': '#fd0001', 'DEWALT': '#febd17', 'Disqus (blue)': '#59a3fc', 'Disqus (orange)': '#db7132', 'Dribbble': '#ea4c89', 'Dropbox': '#3d9ae8', 'Drupal': '#0c76ab', 'Dunked': '#2a323a', 'eBay': '#89c507', 'Ember': '#f05e1b', 'Engadget': '#00bdf6', 'Envato': '#528036', 'Etsy': '#eb6d20', 'Evernote': '#5ba525', 'Fab.com': '#dd0017', 'Facebook': '#3b5998', 'Firefox': '#e66000', 'Flickr (blue)': '#0063dc', 'Flickr (pink)': '#ff0084', 'Forrst': '#5b9a68', 'Foursquare': '#25a0ca', 'Garmin': '#007cc3', 'GetGlue': '#2d75a2', 'Gimmebar': '#f70078', 'GitHub': '#171515', 'Google Blue': '#0140ca', 'Google Green': '#16a61e', 'Google Red': '#dd1812', 'Google Yellow': '#fcca03', 'Google+': '#dd4b39', 'Grooveshark': '#f77f00', 'Groupon': '#82b548', 'Hacker News': '#ff6600', 'HelloWallet': '#0085ca', 'Heroku (light)': '#c7c5e6', 'Heroku (dark)': '#6567a5', 'HootSuite': '#003366', 'Houzz': '#73ba37', 'HTML5': '#ec6231', 'IKEA': '#ffcc33', 'IMDb': '#f3ce13', 'Instagram': '#3f729b', 'Intel': '#0071c5', 'Intuit': '#365ebf', 'Kickstarter': '#76cc1e', 'kippt': '#e03500', 'Kodery': '#00af81', 'LastFM': '#c3000d', 'LinkedIn': '#0e76a8', 'Livestream': '#cf0005', 'Lumo': '#576396', 'Mixpanel': '#a086d3', 'Meetup': '#e51937', 'Nokia': '#183693', 'NVIDIA': '#76b900', 'Opera': '#cc0f16', 'Path': '#e41f11', 'PayPal (dark)': '#1e477a', 'PayPal (light)': '#3b7bbf', 'Pinboard': '#0000e6', 'Pinterest': '#c8232c', 'PlayStation': '#665cbe', 'Pocket': '#ee4056', 'Prezi': '#318bff', 'Pusha': '#0f71b4', 'Quora': '#a82400', 'QUOTE.fm': '#66ceff', 'Rdio': '#008fd5', 'Readability': '#9c0000', 'Red Hat': '#cc0000', 'Resource': '#7eb400', 'Rockpack': '#0ba6ab', 'Roon': '#62b0d9', 'RSS': '#ee802f', 'Salesforce': '#1798c1', 'Samsung': '#0c4da2', 'Shopify': '#96bf48', 'Skype': '#00aff0', 'Snagajob': '#f47a20', 'Softonic': '#008ace', 'SoundCloud': '#ff7700', 'Space Box': '#f86960', 'Spotify': '#81b71a', 'Sprint': '#fee100', 'Squarespace': '#121212', 'StackOverflow': '#ef8236', 'Staples': '#cc0000', 'Status Chart': '#d7584f', 'Stripe': '#008cdd', 'StudyBlue': '#00afe1', 'StumbleUpon': '#f74425', 'T-Mobile': '#ea0a8e', 'Technorati': '#40a800', 'The Next Web': '#ef4423', 'Treehouse': '#5cb868', 'Trulia': '#5eab1f', 'Tumblr': '#34526f', 'Twitch.tv': '#6441a5', 'Twitter': '#00acee', 'TYPO3': '#ff8700', 'Ubuntu': '#dd4814', 'Ustream': '#3388ff', 'Verizon': '#ef1d1d', 'Vimeo': '#86c9ef', 'Vine': '#00a478', 'Virb': '#06afd8', 'Virgin Media': '#cc0000', 'Wooga': '#5b009c', 'WordPress (blue)': '#21759b', 'WordPress (orange)': '#d54e21', 'WordPress (grey)': '#464646', 'Wunderlist': '#2b88d9', 'XBOX': '#9bc848', 'XING': '#126567', 'Yahoo!': '#720e9e', 'Yandex': '#ffcc00', 'Yelp': '#c41200', 'YouTube': '#c4302b', 'Zalongo': '#5498dc', 'Zendesk': '#78a300', 'Zerply': '#9dcc7a', 'Zootool': '#5e8b1d' }, _brandNames: function() { var brands = []; for (var b in this._brandColors) { brands.push(b) } return brands }, /* 生成一段随机的 Base64 图片编码。 https://github.com/imsky/holder Holder renders image placeholders entirely on the client side. dataImageHolder: function(size) { return 'holder.js/' + size }, */ dataImage: function(size, text) { var canvas if (typeof document !== 'undefined') { canvas = document.createElement('canvas') } else { /* https://github.com/Automattic/node-canvas npm install canvas --save 安装问题: * http://stackoverflow.com/questions/22953206/gulp-issues-with-cario-install-command-not-found-when-trying-to-installing-canva * https://github.com/Automattic/node-canvas/issues/415 * https://github.com/Automattic/node-canvas/wiki/_pages PS:node-canvas 的安装过程实在是太繁琐了,所以不放入 package.json 的 dependencies。 */ var Canvas = module.require('canvas') canvas = new Canvas() } var ctx = canvas && canvas.getContext && canvas.getContext("2d") if (!canvas || !ctx) return '' if (!size) size = this.pick(this._adSize) text = text !== undefined ? text : size size = size.split('x') var width = parseInt(size[0], 10), height = parseInt(size[1], 10), background = this._brandColors[this.pick(this._brandNames())], foreground = '#FFF', text_height = 14, font = 'sans-serif'; canvas.width = width canvas.height = height ctx.textAlign = 'center' ctx.textBaseline = 'middle' ctx.fillStyle = background ctx.fillRect(0, 0, width, height) ctx.fillStyle = foreground ctx.font = 'bold ' + text_height + 'px ' + font ctx.fillText(text, (width / 2), (height / 2), width) return canvas.toDataURL('image/png') } } /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9)(module))) /***/ }), /* 9 */ /***/ (function(module, exports) { module.exports = function(module) { if(!module.webpackPolyfill) { module.deprecate = function() {}; module.paths = []; // module.parent = undefined by default module.children = []; module.webpackPolyfill = 1; } return module; } /***/ }), /* 10 */ /***/ (function(module, exports, __webpack_require__) { /* ## Color http://llllll.li/randomColor/ A color generator for JavaScript. randomColor generates attractive colors by default. More specifically, randomColor produces bright colors with a reasonably high saturation. This makes randomColor particularly useful for data visualizations and generative art. http://randomcolour.com/ var bg_colour = Math.floor(Math.random() * 16777215).toString(16); bg_colour = "#" + ("000000" + bg_colour).slice(-6); document.bgColor = bg_colour; http://martin.ankerl.com/2009/12/09/how-to-create-random-colors-programmatically/ Creating random colors is actually more difficult than it seems. The randomness itself is easy, but aesthetically pleasing randomness is more difficult. https://github.com/devongovett/color-generator http://www.paulirish.com/2009/random-hex-color-code-snippets/ Random Hex Color Code Generator in JavaScript http://chancejs.com/#color chance.color() // => '#79c157' chance.color({format: 'hex'}) // => '#d67118' chance.color({format: 'shorthex'}) // => '#60f' chance.color({format: 'rgb'}) // => 'rgb(110,52,164)' http://tool.c7sky.com/webcolor 网页设计常用色彩搭配表 https://github.com/One-com/one-color An OO-based JavaScript color parser/computation toolkit with support for RGB, HSV, HSL, CMYK, and alpha channels. API 很赞 https://github.com/harthur/color JavaScript color conversion and manipulation library https://github.com/leaverou/css-colors Share & convert CSS colors http://leaverou.github.io/css-colors/#slategray Type a CSS color keyword, #hex, hsl(), rgba(), whatever: 色调 hue http://baike.baidu.com/view/23368.htm 色调指的是一幅画中画面色彩的总体倾向,是大的色彩效果。 饱和度