Created
August 17, 2014 07:12
-
-
Save NeuronQ/94a1dcd2055b88b73949 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Parses an escaped url query string into key-value pairs. | |
* @returns {Object.<string,boolean|Array>} | |
*/ | |
function parseKeyValubue(/**string*/keyValue) { | |
var obj = {}, key_value, key; | |
forEach((keyValue || "").split('&'), function(keyValue) { | |
if ( keyValue ) { | |
key_value = keyValue.replace(/\+/g,'%20').split('='); | |
key = tryDecodeURIComponent(key_value[0]); | |
if ( isDefined(key) ) { | |
var val = isDefined(key_value[1]) ? tryDecodeURIComponent(key_value[1]) : true; | |
if (!hasOwnProperty.call(obj, key)) { | |
obj[key] = val; | |
} else if(isArray(obj[key])) { | |
obj[key].push(val); | |
} else { | |
obj[key] = [obj[key],val]; | |
} | |
} | |
} | |
}); | |
return obj; | |
} | |
function toKeyValue(obj) { | |
var parts = []; | |
forEach(obj, function(value, key) { | |
if (isArray(value)) { | |
forEach(value, function(arrayValue) { | |
parts.push(encodeUriQuery(key, true) + | |
(arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true))); | |
}); | |
} else { | |
parts.push(encodeUriQuery(key, true) + | |
(value === true ? '' : '=' + encodeUriQuery(value, true))); | |
} | |
}); | |
return parts.length ? parts.join('&') : ''; | |
} | |
/** | |
* We need our custom method because encodeURIComponent is too aggressive and doesn't follow | |
* http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path | |
* segments: | |
* segment = *pchar | |
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" | |
* pct-encoded = "%" HEXDIG HEXDIG | |
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" | |
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" | |
* / "*" / "+" / "," / ";" / "=" | |
*/ | |
function encodeUriSegment(val) { | |
return encodeUriQuery(val, true). | |
replace(/%26/gi, '&'). | |
replace(/%3D/gi, '='). | |
replace(/%2B/gi, '+'); | |
} | |
/** | |
* This method is intended for encoding *key* or *value* parts of query component. We need a custom | |
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be | |
* encoded per http://tools.ietf.org/html/rfc3986: | |
* query = *( pchar / "/" / "?" ) | |
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@" | |
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" | |
* pct-encoded = "%" HEXDIG HEXDIG | |
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" | |
* / "*" / "+" / "," / ";" / "=" | |
*/ | |
function encodeUriQuery(val, pctEncodeSpaces) { | |
return encodeURIComponent(val). | |
replace(/%40/gi, '@'). | |
replace(/%3A/gi, ':'). | |
replace(/%24/g, '$'). | |
replace(/%2C/gi, ','). | |
replace(/%3B/gi, ';'). | |
replace(/%20/g, (pctEncodeSpaces ? '%20' : '+')); | |
} | |
var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-']; | |
function getNgAttribute(element, ngAttr) { | |
var attr, i, ii = ngAttrPrefixes.length; | |
element = jqLite(element); | |
for (i=0; i<ii; ++i) { | |
attr = ngAttrPrefixes[i] + ngAttr; | |
if (isString(attr = element.attr(attr))) { | |
return attr; | |
} | |
} | |
return null; | |
} | |
/** | |
* @ngdoc directive | |
* @name ngApp | |
* @module ng | |
* | |
* ... | |
*/ | |
function angularInit(element, bootstrap) { | |
var appElement, | |
module, | |
config = {}; | |
// The element `element` has priority over any other element | |
forEach(ngAttrPrefixes, function(prefix) { | |
var name = prefix + 'app'; | |
if (!appElement && element.hasAttribute && element.hasAttribute(name)) { | |
appElement = element; | |
module = element.getAttribute(name); | |
} | |
}); | |
forEach(ngAttrPrefixes, function(prefix) { | |
var name = prefix + 'app'; | |
var candidate; | |
if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) { | |
appElement = candidate; | |
module = candidate.getAttribute(name); | |
} | |
}); | |
if (appElement) { | |
config.strictDi = getNgAttribute(appElement, "strict-di") !== null; | |
bootstrap(appElement, module ? [module] : [], config); | |
} | |
} | |
/** | |
* @ngdoc function | |
* @name angular.bootstrap | |
* @module ng | |
* @description | |
* Use this function to manually start up angular application. | |
* | |
* ... | |
*/ | |
function bootstrap(element, modules, config) { | |
if (!isObject(config)) config = {}; | |
var defaultConfig = { | |
strictDi: false | |
}; | |
config = extend(defaultConfig, config); | |
var doBootstrap = function() { | |
element = jqLite(element); | |
if (element.injector()) { | |
var tag = (element[0] === document) ? 'document' : startingTag(element); | |
throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag); | |
} | |
modules = modules || []; | |
modules.unshift(['$provide', function($provide) { | |
$provide.value('$rootElement', element); | |
}]); | |
modules.unshift('ng'); | |
var injector = createInjector(modules, config.strictDi); | |
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', | |
function(scope, element, compile, injector) { | |
scope.$apply(function() { | |
element.data('$injector', injector); | |
compile(element)(scope); | |
}); | |
}] | |
); | |
return injector; | |
}; | |
var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; | |
if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) return doBootstrap(); | |
window.name = window.name.replace(NG_DEFER_BOOTSTRAP, ''); | |
angular.resumeBootstrap = function(extraModules) { | |
forEach(extraModules, function(module) { | |
modules.push(module); | |
}); | |
doBootstrap(); | |
}; | |
} | |
var SNAKE_CASE_REGEXP = /[A-Z]/g; | |
function snake_case(name, separator) { | |
separator = separator || '_'; | |
return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) { | |
return (pos ? separator : '') + letter.toLowerCase(); | |
}); | |
} | |
function bindJQuery() { | |
var originalCleanData; | |
// bind to jQuery if present; | |
jQuery = window.jQuery; | |
// Use jQuery if it exists with proper functionality, otherwise default to us. | |
// Angular 1.2+ requires jQuery 1.7+ for on()/off() support. | |
// Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older | |
// versions. It will not work for sure with jQuery <1.7, though. | |
if (jQuery && jQuery.fn.on) { | |
jqLite = jQuery; | |
extend(jQuery.fn, { | |
scope: JQLitePrototype.scope, | |
isolateScope: JQLitePrototype.isolateScope, | |
controller: JQLitePrototype.controller, | |
injector: JQLitePrototype.injector, | |
inheritedData: JQLitePrototype.inheritedData | |
}); | |
originalCleanData = jQuery.cleanData; | |
// Prevent double-proxying. | |
originalCleanData = originalCleanData.$$original || originalCleanData; | |
// All nodes removed from the DOM via various jQuery APIs like .remove() | |
// are passed through jQuery.cleanData. Monkey-patch this method to fire | |
// the $destroy event on all removed nodes. | |
jQuery.cleanData = function(elems) { | |
for (var i = 0, elem; (elem = elems[i]) != null; i++) { | |
jQuery(elem).triggerHandler('$destroy'); | |
} | |
originalCleanData(elems); | |
}; | |
jQuery.cleanData.$$original = originalCleanData; | |
} else { | |
jqLite = JQLite; | |
} | |
angular.element = jqLite; | |
} | |
/** | |
* throw error if the argument is falsy. | |
*/ | |
function assertArg(arg, name, reason) { | |
if (!arg) { | |
throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required")); | |
} | |
return arg; | |
} | |
function assertArgFn(arg, name, acceptArrayAnnotation) { | |
if (acceptArrayAnnotation && isArray(arg)) { | |
arg = arg[arg.length - 1]; | |
} | |
assertArg(isFunction(arg), name, 'not a function, got ' + | |
(arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg)); | |
return arg; | |
} | |
/** | |
* throw error if the name given is hasOwnProperty | |
* @param {String} name the name to test | |
* @param {String} context the context in which the name is used, such as module or directive | |
*/ | |
function assertNotHasOwnProperty(name, context) { | |
if (name === 'hasOwnProperty') { | |
throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context); | |
} | |
} | |
/** | |
* Return the value accessible from the object by path. Any undefined traversals are ignored | |
* @param {Object} obj starting object | |
* @param {String} path path to traverse | |
* @param {boolean} [bindFnToScope=true] | |
* @returns {Object} value as accessible by path | |
*/ | |
//TODO(misko): this function needs to be removed | |
function getter(obj, path, bindFnToScope) { | |
if (!path) return obj; | |
var keys = path.split('.'); | |
var key; | |
var lastInstance = obj; | |
var len = keys.length; | |
for (var i = 0; i < len; i++) { | |
key = keys[i]; | |
if (obj) { | |
obj = (lastInstance = obj)[key]; | |
} | |
} | |
if (!bindFnToScope && isFunction(obj)) { | |
return bind(lastInstance, obj); | |
} | |
return obj; | |
} | |
/** | |
* Return the DOM siblings between the first and last node in the given array. | |
* @param {Array} array like object | |
* @returns {DOMElement} object containing the elements | |
*/ | |
function getBlockElements(nodes) { | |
var startNode = nodes[0], | |
endNode = nodes[nodes.length - 1]; | |
if (startNode === endNode) { | |
return jqLite(startNode); | |
} | |
var element = startNode; | |
var elements = [element]; | |
do { | |
element = element.nextSibling; | |
if (!element) break; | |
elements.push(element); | |
} while (element !== endNode); | |
return jqLite(elements); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment