/**
* Set a property on an object. Adds the new property and
* triggers change notification if the property doesn't
* already exist.
*
* @param {Object} obj
* @param {String} key
* @param {*} val
* @public
*/
export function set (obj, key, val) {
if (hasOwn(obj, key)) {
obj[key] = val
return
}
if (obj._isVue) {
set(obj._data, key, val)
return
}
var ob = obj.__ob__
if (!ob) {
obj[key] = val
return
}
ob.convert(key, val)
ob.dep.notify()
if (ob.vms) {
var i = ob.vms.length
while (i--) {
var vm = ob.vms[i]
vm._proxy(key)
vm._digest()
}
}
return val
}
/**
* Delete a property and trigger change if necessary.
*
* @param {Object} obj
* @param {String} key
*/
export function del (obj, key) {
if (!hasOwn(obj, key)) {
return
}
delete obj[key]
var ob = obj.__ob__
if (!ob) {
if (obj._isVue) {
delete obj._data[key]
obj._digest()
}
return
}
ob.dep.notify()
if (ob.vms) {
var i = ob.vms.length
while (i--) {
var vm = ob.vms[i]
vm._unproxy(key)
vm._digest()
}
}
}
var hasOwnProperty = Object.prototype.hasOwnProperty
/**
* Check whether the object has the property.
*
* @param {Object} obj
* @param {String} key
* @return {Boolean}
*/
export function hasOwn (obj, key) {
return hasOwnProperty.call(obj, key)
}
/**
* Check if an expression is a literal value.
*
* @param {String} exp
* @return {Boolean}
*/
var literalValueRE = /^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/
export function isLiteral (exp) {
return literalValueRE.test(exp)
}
/**
* Check if a string starts with $ or _
*
* @param {String} str
* @return {Boolean}
*/
export function isReserved (str) {
var c = (str + '').charCodeAt(0)
return c === 0x24 || c === 0x5F
}
/**
* Guard text output, make sure undefined outputs
* empty string
*
* @param {*} value
* @return {String}
*/
export function _toString (value) {
return value == null
? ''
: value.toString()
}
/**
* Check and convert possible numeric strings to numbers
* before setting back to data
*
* @param {*} value
* @return {*|Number}
*/
export function toNumber (value) {
if (typeof value !== 'string') {
return value
} else {
var parsed = Number(value)
return isNaN(parsed)
? value
: parsed
}
}
/**
* Convert string boolean literals into real booleans.
*
* @param {*} value
* @return {*|Boolean}
*/
export function toBoolean (value) {
return value === 'true'
? true
: value === 'false'
? false
: value
}
/**
* Strip quotes from a string
*
* @param {String} str
* @return {String | false}
*/
export function stripQuotes (str) {
var a = str.charCodeAt(0)
var b = str.charCodeAt(str.length - 1)
return a === b && (a === 0x22 || a === 0x27)
? str.slice(1, -1)
: str
}
/**
* Camelize a hyphen-delmited string.
*
* @param {String} str
* @return {String}
*/
var camelizeRE = /-(\w)/g
export function camelize (str) {
return str.replace(camelizeRE, toUpper)
}
function toUpper (_, c) {
return c ? c.toUpperCase() : ''
}
/**
* Hyphenate a camelCase string.
*
* @param {String} str
* @return {String}
*/
var hyphenateRE = /([a-z\d])([A-Z])/g
export function hyphenate (str) {
return str
.replace(hyphenateRE, '$1-$2')
.toLowerCase()
}
/**
* Converts hyphen/underscore/slash delimitered names into
* camelized classNames.
*
* e.g. my-component => MyComponent
* some_else => SomeElse
* some/comp => SomeComp
*
* @param {String} str
* @return {String}
*/
var classifyRE = /(?:^|[-_\/])(\w)/g
export function classify (str) {
return str.replace(classifyRE, toUpper)
}
/**
* Simple bind, faster than native
*
* @param {Function} fn
* @param {Object} ctx
* @return {Function}
*/
export function bind (fn, ctx) {
return function (a) {
var l = arguments.length
return l
? l > 1
? fn.apply(ctx, arguments)
: fn.call(ctx, a)
: fn.call(ctx)
}
}
/**
* Convert an Array-like object to a real Array.
*
* @param {Array-like} list
* @param {Number} [start] - start index
* @return {Array}
*/
export function toArray (list, start) {
start = start || 0
var i = list.length - start
var ret = new Array(i)
while (i--) {
ret[i] = list[i + start]
}
return ret
}
/**
* Mix properties into target object.
*
* @param {Object} to
* @param {Object} from
*/
export function extend (to, from) {
var keys = Object.keys(from)
var i = keys.length
while (i--) {
to[keys[i]] = from[keys[i]]
}
return to
}
/**
* Quick object check - this is primarily used to tell
* Objects from primitive values when we know the value
* is a JSON-compliant type.
*
* @param {*} obj
* @return {Boolean}
*/
export function isObject (obj) {
return obj !== null && typeof obj === 'object'
}
/**
* Strict object type check. Only returns true
* for plain JavaScript objects.
*
* @param {*} obj
* @return {Boolean}
*/
var toString = Object.prototype.toString
var OBJECT_STRING = '[object Object]'
export function isPlainObject (obj) {
return toString.call(obj) === OBJECT_STRING
}
/**
* Array type check.
*
* @param {*} obj
* @return {Boolean}
*/
export const isArray = Array.isArray
/**
* Define a property.
*
* @param {Object} obj
* @param {String} key
* @param {*} val
* @param {Boolean} [enumerable]
*/
export function def (obj, key, val, enumerable) {
Object.defineProperty(obj, key, {
value: val,
enumerable: !!enumerable,
writable: true,
configurable: true
})
}
/**
* Debounce a function so it only gets called after the
* input stops arriving after the given wait period.
*
* @param {Function} func
* @param {Number} wait
* @return {Function} - the debounced function
*/
export function debounce (func, wait) {
var timeout, args, context, timestamp, result
var later = function () {
var last = Date.now() - timestamp
if (last < wait && last >= 0) {
timeout = setTimeout(later, wait - last)
} else {
timeout = null
result = func.apply(context, args)
if (!timeout) context = args = null
}
}
return function () {
context = this
args = arguments
timestamp = Date.now()
if (!timeout) {
timeout = setTimeout(later, wait)
}
return result
}
}
/**
* Manual indexOf because it's slightly faster than
* native.
*
* @param {Array} arr
* @param {*} obj
*/
export function indexOf (arr, obj) {
var i = arr.length
while (i--) {
if (arr[i] === obj) return i
}
return -1
}
/**
* Make a cancellable version of an async callback.
*
* @param {Function} fn
* @return {Function}
*/
export function cancellable (fn) {
var cb = function () {
if (!cb.cancelled) {
return fn.apply(this, arguments)
}
}
cb.cancel = function () {
cb.cancelled = true
}
return cb
}
/**
* Check if two values are loosely equal - that is,
* if they are plain objects, do they have the same shape?
*
* @param {*} a
* @param {*} b
* @return {Boolean}
*/
export function looseEqual (a, b) {
/* eslint-disable eqeqeq */
return a == b || (
isObject(a) && isObject(b)
? JSON.stringify(a) === JSON.stringify(b)
: false
)
/* eslint-enable eqeqeq */
}
|