| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- var config = require('./config'),
- toString = ({}).toString,
- win = window,
- console = win.console,
- def = Object.defineProperty,
- OBJECT = 'object',
- THIS_RE = /[^\w]this[^\w]/,
- BRACKET_RE_S = /\['([^']+)'\]/g,
- BRACKET_RE_D = /\["([^"]+)"\]/g,
- ViewModel // late def
- var defer =
- win.requestAnimationFrame ||
- win.webkitRequestAnimationFrame ||
- win.setTimeout
- /**
- * Normalize keypath with possible brackets into dot notations
- */
- function normalizeKeypath (key) {
- return key.indexOf('[') < 0
- ? key
- : key.replace(BRACKET_RE_S, '.$1')
- .replace(BRACKET_RE_D, '.$1')
- }
- var utils = module.exports = {
- /**
- * Convert a string template to a dom fragment
- */
- toFragment: require('./fragment'),
- /**
- * Parse the various types of template options
- */
- parseTemplateOption: require('./template-parser.js'),
- /**
- * get a value from an object keypath
- */
- get: function (obj, key) {
- /* jshint eqeqeq: false */
- key = normalizeKeypath(key)
- if (key.indexOf('.') < 0) {
- return obj[key]
- }
- var path = key.split('.'),
- d = -1, l = path.length
- while (++d < l && obj != null) {
- obj = obj[path[d]]
- }
- return obj
- },
- /**
- * set a value to an object keypath
- */
- set: function (obj, key, val) {
- /* jshint eqeqeq: false */
- key = normalizeKeypath(key)
- if (key.indexOf('.') < 0) {
- obj[key] = val
- return
- }
- var path = key.split('.'),
- d = -1, l = path.length - 1
- while (++d < l) {
- if (obj[path[d]] == null) {
- obj[path[d]] = {}
- }
- obj = obj[path[d]]
- }
- obj[path[d]] = val
- },
- /**
- * return the base segment of a keypath
- */
- baseKey: function (key) {
- return key.indexOf('.') > 0
- ? key.split('.')[0]
- : key
- },
- /**
- * Create a prototype-less object
- * which is a better hash/map
- */
- hash: function () {
- return Object.create(null)
- },
- /**
- * get an attribute and remove it.
- */
- attr: function (el, type) {
- var attr = config.prefix + '-' + type,
- val = el.getAttribute(attr)
- if (val !== null) {
- el.removeAttribute(attr)
- }
- return val
- },
- /**
- * Define an ienumerable property
- * This avoids it being included in JSON.stringify
- * or for...in loops.
- */
- defProtected: function (obj, key, val, enumerable, writable) {
- def(obj, key, {
- value : val,
- enumerable : enumerable,
- writable : writable,
- configurable : true
- })
- },
- /**
- * A less bullet-proof but more efficient type check
- * than Object.prototype.toString
- */
- isObject: function (obj) {
- return typeof obj === OBJECT && obj && !Array.isArray(obj)
- },
- /**
- * A more accurate but less efficient type check
- */
- isTrueObject: function (obj) {
- return toString.call(obj) === '[object Object]'
- },
- /**
- * Most simple bind
- * enough for the usecase and fast than native bind()
- */
- bind: function (fn, ctx) {
- return function (arg) {
- return fn.call(ctx, arg)
- }
- },
- /**
- * Make sure null and undefined output empty string
- */
- guard: function (value) {
- /* jshint eqeqeq: false, eqnull: true */
- return value == null
- ? ''
- : (typeof value == 'object')
- ? JSON.stringify(value)
- : value
- },
- /**
- * When setting value on the VM, parse possible numbers
- */
- checkNumber: function (value) {
- return (isNaN(value) || value === null || typeof value === 'boolean')
- ? value
- : Number(value)
- },
- /**
- * simple extend
- */
- extend: function (obj, ext) {
- for (var key in ext) {
- if (obj[key] !== ext[key]) {
- obj[key] = ext[key]
- }
- }
- return obj
- },
- /**
- * filter an array with duplicates into uniques
- */
- unique: function (arr) {
- var hash = utils.hash(),
- i = arr.length,
- key, res = []
- while (i--) {
- key = arr[i]
- if (hash[key]) continue
- hash[key] = 1
- res.push(key)
- }
- return res
- },
- /**
- * Convert the object to a ViewModel constructor
- * if it is not already one
- */
- toConstructor: function (obj) {
- ViewModel = ViewModel || require('./viewmodel')
- return utils.isObject(obj)
- ? ViewModel.extend(obj)
- : typeof obj === 'function'
- ? obj
- : null
- },
- /**
- * Check if a filter function contains references to `this`
- * If yes, mark it as a computed filter.
- */
- checkFilter: function (filter) {
- if (THIS_RE.test(filter.toString())) {
- filter.computed = true
- }
- },
- /**
- * convert certain option values to the desired format.
- */
- processOptions: function (options) {
- var components = options.components,
- partials = options.partials,
- template = options.template,
- filters = options.filters,
- key
- if (components) {
- for (key in components) {
- components[key] = utils.toConstructor(components[key])
- }
- }
- if (partials) {
- for (key in partials) {
- partials[key] = utils.parseTemplateOption(partials[key])
- }
- }
- if (filters) {
- for (key in filters) {
- utils.checkFilter(filters[key])
- }
- }
- if (template) {
- options.template = utils.parseTemplateOption(template)
- }
- },
- /**
- * used to defer batch updates
- */
- nextTick: function (cb, context) {
- if (context) {
- defer(utils.bind(cb, context), 0)
- }
- else {
- defer(cb, 0)
- }
- },
- /**
- * add class for IE
- * uses classList if available
- */
- addClass: function (el, cls) {
- if (el.classList) {
- el.classList.add(cls)
- } else {
- var cur = ' ' + utils.getClassName(el) + ' '
- if (cur.indexOf(' ' + cls + ' ') < 0) {
- el.setAttribute('class', (cur + cls).trim())
- }
- }
- },
- /**
- * remove class for IE
- */
- removeClass: function (el, cls) {
- if (el.classList) {
- el.classList.remove(cls)
- } else {
- var cur = ' ' + utils.getClassName(el) + ' ',
- tar = ' ' + cls + ' '
- while (cur.indexOf(tar) >= 0) {
- cur = cur.replace(tar, ' ')
- }
- el.setAttribute('class', cur.trim())
- }
- },
- /**
- * get class name for IE
- */
- getClassName: function(el) {
- return (el.className instanceof SVGAnimatedString ? el.className.baseVal : el.className)
- },
- /**
- * Convert an object to Array
- * used in v-repeat and array filters
- */
- objectToArray: function (obj) {
- var res = [], val, data
- for (var key in obj) {
- val = obj[key]
- data = utils.isObject(val)
- ? val
- : { $value: val }
- data.$key = key
- res.push(data)
- }
- return res
- }
- }
- enableDebug()
- function enableDebug () {
- /**
- * log for debugging
- */
- utils.log = function (msg) {
- if (config.debug && console) {
- console.log(msg)
- }
- }
- /**
- * warnings, traces by default
- * can be suppressed by `silent` option.
- */
- utils.warn = function (msg) {
- if (!config.silent && console) {
- console.warn(msg)
- if (config.debug && console.trace) {
- console.trace()
- }
- }
- }
- }
|