mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
469 lines
12 KiB
JavaScript
469 lines
12 KiB
JavaScript
if (typeof document.getAttribute == 'undefined')
|
|
document.getAttribute = function() {};
|
|
if (typeof Node == 'undefined') {
|
|
//TODO: can we get rid of this?
|
|
Node = {
|
|
ELEMENT_NODE : 1,
|
|
ATTRIBUTE_NODE : 2,
|
|
TEXT_NODE : 3,
|
|
CDATA_SECTION_NODE : 4,
|
|
ENTITY_REFERENCE_NODE : 5,
|
|
ENTITY_NODE : 6,
|
|
PROCESSING_INSTRUCTION_NODE : 7,
|
|
COMMENT_NODE : 8,
|
|
DOCUMENT_NODE : 9,
|
|
DOCUMENT_TYPE_NODE : 10,
|
|
DOCUMENT_FRAGMENT_NODE : 11,
|
|
NOTATION_NODE : 12
|
|
};
|
|
}
|
|
|
|
function noop() {}
|
|
function identity($) {return $;}
|
|
if (!window['console']) window['console']={'log':noop, 'error':noop};
|
|
|
|
function extensionMap(angular, name) {
|
|
var extPoint;
|
|
return angular[name] || (extPoint = angular[name] = function (name, fn, prop){
|
|
if (isDefined(fn)) {
|
|
extPoint[name] = extend(fn, prop || {});
|
|
}
|
|
return extPoint[name];
|
|
});
|
|
}
|
|
|
|
function extensionList(angular, name) {
|
|
var extPoint, length = 0;
|
|
return angular[name] || (extPoint = angular[name] = function (fn, prop){
|
|
if (isDefined(fn)) {
|
|
extPoint[length] = extend(fn, prop || {});
|
|
length++;
|
|
}
|
|
return extPoint;
|
|
});
|
|
}
|
|
|
|
var consoleNode, msie,
|
|
VALUE = 'value',
|
|
NOOP = 'noop',
|
|
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
|
|
slice = Array.prototype.slice,
|
|
angular = window['angular'] || (window['angular'] = {}),
|
|
angularTextMarkup = extensionList(angular, 'textMarkup'),
|
|
angularAttrMarkup = extensionList(angular, 'attrMarkup'),
|
|
angularDirective = extensionMap(angular, 'directive'),
|
|
angularWidget = extensionMap(angular, 'widget'),
|
|
angularValidator = extensionMap(angular, 'validator'),
|
|
angularFilter = extensionMap(angular, 'filter'),
|
|
angularFormatter = extensionMap(angular, 'formatter'),
|
|
angularCallbacks = extensionMap(angular, 'callbacks'),
|
|
angularAlert = angular['alert'] || (angular['alert'] = function(){
|
|
log(arguments); window.alert.apply(window, arguments);
|
|
});
|
|
angular['copy'] = copy;
|
|
|
|
var isVisible = isVisible || function (element) {
|
|
return jQuery(element).is(":visible");
|
|
};
|
|
|
|
function foreach(obj, iterator, context) {
|
|
var key;
|
|
if (obj) {
|
|
if (obj.forEach) {
|
|
obj.forEach(iterator, context);
|
|
} else if (obj instanceof Array) {
|
|
for (key = 0; key < obj.length; key++)
|
|
iterator.call(context, obj[key], key);
|
|
} else {
|
|
for (key in obj)
|
|
iterator.call(context, obj[key], key);
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function extend(dst, obj) {
|
|
foreach(obj, function(value, key){
|
|
dst[key] = value;
|
|
});
|
|
return dst;
|
|
}
|
|
|
|
function isDefined(value){ return typeof value != 'undefined'; }
|
|
function isObject(value){ return typeof value == 'object';}
|
|
function isString(value){ return typeof value == 'string';}
|
|
function isArray(value) { return value instanceof Array; }
|
|
function isFunction(value){ return typeof value == 'function';}
|
|
function lowercase(value){ return isString(value) ? value.toLowerCase() : value; }
|
|
function uppercase(value){ return isString(value) ? value.toUpperCase() : value; }
|
|
function trim(value) { return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value; };
|
|
|
|
function log(a, b, c){
|
|
var console = window['console'];
|
|
switch(arguments.length) {
|
|
case 1:
|
|
console['log'](a);
|
|
break;
|
|
case 2:
|
|
console['log'](a, b);
|
|
break;
|
|
default:
|
|
console['log'](a, b, c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function error(a, b, c){
|
|
var console = window['console'];
|
|
switch(arguments.length) {
|
|
case 1:
|
|
console['error'](a);
|
|
break;
|
|
case 2:
|
|
console['error'](a, b);
|
|
break;
|
|
default:
|
|
console['error'](a, b, c);
|
|
break;
|
|
}
|
|
}
|
|
|
|
function consoleLog(level, objs) {
|
|
var log = document.createElement("div");
|
|
log.className = level;
|
|
var msg = "";
|
|
var sep = "";
|
|
for ( var i = 0; i < objs.length; i++) {
|
|
var obj = objs[i];
|
|
msg += sep + (typeof obj == 'string' ? obj : toJson(obj));
|
|
sep = " ";
|
|
}
|
|
log.appendChild(document.createTextNode(msg));
|
|
consoleNode.appendChild(log);
|
|
}
|
|
|
|
function isNode(inp) {
|
|
return inp &&
|
|
inp.tagName &&
|
|
inp.nodeName &&
|
|
inp.ownerDocument &&
|
|
inp.removeAttribute;
|
|
}
|
|
|
|
function isLeafNode (node) {
|
|
if (node) {
|
|
switch (node.nodeName) {
|
|
case "OPTION":
|
|
case "PRE":
|
|
case "TITLE":
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function copy(source, destination){
|
|
if (!destination) {
|
|
if (!source) {
|
|
return source;
|
|
} else if (_.isArray(source)) {
|
|
return copy(source, []);
|
|
} else {
|
|
return copy(source, {});
|
|
}
|
|
} else {
|
|
if (_.isArray(source)) {
|
|
while(destination.length) {
|
|
destination.pop();
|
|
}
|
|
} else {
|
|
_(destination).each(function(value, key){
|
|
delete destination[key];
|
|
});
|
|
}
|
|
return $.extend(true, destination, source);
|
|
}
|
|
};
|
|
|
|
function setHtml(node, html) {
|
|
if (isLeafNode(node)) {
|
|
if (msie) {
|
|
node.innerText = html;
|
|
} else {
|
|
node.textContent = html;
|
|
}
|
|
} else {
|
|
node.innerHTML = html;
|
|
}
|
|
}
|
|
|
|
function escapeHtml(html) {
|
|
if (!html || !html.replace)
|
|
return html;
|
|
return html.
|
|
replace(/&/g, '&').
|
|
replace(/</g, '<').
|
|
replace(/>/g, '>');
|
|
}
|
|
|
|
function escapeAttr(html) {
|
|
if (!html || !html.replace)
|
|
return html;
|
|
return html.replace(/</g, '<').replace(/>/g, '>').replace(/\"/g,
|
|
'"');
|
|
}
|
|
|
|
function bind(_this, _function) {
|
|
var curryArgs = slice.call(arguments, 2, arguments.length);
|
|
return function() {
|
|
return _function.apply(_this, curryArgs.concat(slice.call(arguments, 0, arguments.length)));
|
|
};
|
|
}
|
|
|
|
function bindTry(_this, _function) {
|
|
var args = arguments,
|
|
last = args.length - 1,
|
|
curryArgs = slice.call(args, 2, last),
|
|
exceptionHandler = args[last];
|
|
return function() {
|
|
try {
|
|
return _function.apply(_this, curryArgs.concat(slice.call(arguments, 0, arguments.length)));
|
|
} catch (e) {
|
|
if (e = exceptionHandler(e)) throw e;
|
|
}
|
|
};
|
|
}
|
|
|
|
function errorHandlerFor(element) {
|
|
return function(error){
|
|
element.attr('ng-error', angular.toJson(error));
|
|
element.addClass('ng-exception');
|
|
};
|
|
}
|
|
|
|
function outerHTML(node) {
|
|
var temp = document.createElement('div');
|
|
temp.appendChild(node);
|
|
var outerHTML = temp.innerHTML;
|
|
temp.removeChild(node);
|
|
return outerHTML;
|
|
}
|
|
|
|
function toBoolean(value) {
|
|
var v = ("" + value).toLowerCase();
|
|
if (v == 'f' || v == '0' || v == 'false' || v == 'no')
|
|
value = false;
|
|
return !!value;
|
|
}
|
|
|
|
function merge(src, dst) {
|
|
for ( var key in src) {
|
|
var value = dst[key];
|
|
var type = typeof value;
|
|
if (type == 'undefined') {
|
|
dst[key] = fromJson(toJson(src[key]));
|
|
} else if (type == 'object' && value.constructor != array &&
|
|
key.substring(0, 1) != "$") {
|
|
merge(src[key], value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ////////////////////////////
|
|
// UrlWatcher
|
|
// ////////////////////////////
|
|
|
|
function UrlWatcher(location) {
|
|
this.location = location;
|
|
this.delay = 25;
|
|
this.setTimeout = function(fn, delay) {
|
|
window.setTimeout(fn, delay);
|
|
};
|
|
this.listener = function(url) {
|
|
return url;
|
|
};
|
|
this.expectedUrl = location.href;
|
|
}
|
|
|
|
UrlWatcher.prototype = {
|
|
listen: function(fn){
|
|
this.listener = fn;
|
|
},
|
|
watch: function() {
|
|
var self = this;
|
|
var pull = function() {
|
|
if (self.expectedUrl !== self.location.href) {
|
|
var notify = self.location.hash.match(/^#\$iframe_notify=(.*)$/);
|
|
if (notify) {
|
|
if (!self.expectedUrl.match(/#/)) {
|
|
self.expectedUrl += "#";
|
|
}
|
|
self.location.href = self.expectedUrl;
|
|
var id = '_iframe_notify_' + notify[1];
|
|
var notifyFn = angularCallbacks[id];
|
|
delete angularCallbacks[id];
|
|
try {
|
|
(notifyFn||noop)();
|
|
} catch (e) {
|
|
alert(e);
|
|
}
|
|
} else {
|
|
self.listener(self.location.href);
|
|
self.expectedUrl = self.location.href;
|
|
}
|
|
}
|
|
self.setTimeout(pull, self.delay);
|
|
};
|
|
pull();
|
|
},
|
|
|
|
set: function(url) {
|
|
var existingURL = this.location.href;
|
|
if (!existingURL.match(/#/))
|
|
existingURL += '#';
|
|
if (existingURL != url)
|
|
this.location.href = url;
|
|
this.existingURL = url;
|
|
},
|
|
|
|
get: function() {
|
|
return window.location.href;
|
|
}
|
|
};
|
|
|
|
/////////////////////////////////////////////////
|
|
function configureJQueryPlugins() {
|
|
var fn = jQuery['fn'];
|
|
fn['scope'] = function() {
|
|
var element = this;
|
|
while (element && element.get(0)) {
|
|
var scope = element.data("scope");
|
|
if (scope)
|
|
return scope;
|
|
element = element.parent();
|
|
}
|
|
return null;
|
|
};
|
|
fn['controller'] = function() {
|
|
return this.data('controller') || NullController.instance;
|
|
};
|
|
}
|
|
|
|
function configureLogging(config) {
|
|
if (config.debug == 'console' && !consoleNode) {
|
|
consoleNode = document.createElement("div");
|
|
consoleNode.id = 'ng-console';
|
|
document.getElementsByTagName('body')[0].appendChild(consoleNode);
|
|
log = function() {
|
|
consoleLog('ng-console-info', arguments);
|
|
};
|
|
console.error = function() {
|
|
consoleLog('ng-console-error', arguments);
|
|
};
|
|
}
|
|
}
|
|
|
|
function exposeMethods(obj, methods){
|
|
var bound = {};
|
|
foreach(methods, function(fn, name){
|
|
bound[name] = _(fn).bind(obj);
|
|
});
|
|
return bound;
|
|
}
|
|
|
|
function wireAngular(element, config) {
|
|
var widgetFactory = new WidgetFactory(config['server'], config['database']);
|
|
var binder = new Binder(element[0], widgetFactory, datastore, config['location'], config);
|
|
binder.updateListeners.push(config.onUpdateView);
|
|
var controlBar = new ControlBar(element.find('body'), config['server'], config['database']);
|
|
var onUpdate = function(){binder.updateView();};
|
|
var server = config['database'] =="$MEMORY" ?
|
|
new FrameServer(window) :
|
|
new Server(config['server'], jQuery['getScript']);
|
|
server = new VisualServer(server, new NullStatus(element.find('body')), onUpdate);
|
|
var users = new Users(server, controlBar);
|
|
var databasePath = '/data/' + config['database'];
|
|
var post = function(request, callback){
|
|
server.request("POST", databasePath, request, callback);
|
|
};
|
|
var datastore = new DataStore(post, users, binder.anchor);
|
|
binder.datastore = datastore;
|
|
binder.updateListeners.push(function(){datastore.flush();});
|
|
var scope = new Scope({
|
|
'$anchor' : binder.anchor,
|
|
'$updateView': _(binder.updateView).bind(binder),
|
|
'$config' : config,
|
|
'$invalidWidgets': [],
|
|
'$console' : window.console,
|
|
'$datastore' : exposeMethods(datastore, {
|
|
'load': datastore.load,
|
|
'loadMany': datastore.loadMany,
|
|
'loadOrCreate': datastore.loadOrCreate,
|
|
'loadAll': datastore.loadAll,
|
|
'save': datastore.save,
|
|
'remove': datastore.remove,
|
|
'flush': datastore.flush,
|
|
'query': datastore.query,
|
|
'entity': datastore.entity,
|
|
'entities': datastore.entities,
|
|
'documentCountsByUser': datastore.documentCountsByUser,
|
|
'userDocumentIdsByEntity': datastore.userDocumentIdsByEntity,
|
|
'join': datastore.join
|
|
}),
|
|
'$save' : function(callback) {
|
|
datastore.saveScope(scope.state, callback, binder.anchor);
|
|
},
|
|
'$window' : window,
|
|
'$uid' : function() {
|
|
return "" + new Date().getTime();
|
|
},
|
|
'$users' : users
|
|
}, "ROOT");
|
|
|
|
element.data('scope', scope);
|
|
binder.entity(scope);
|
|
binder.compile();
|
|
controlBar.bind();
|
|
|
|
//TODO: remove this code
|
|
new PopUp(element).bind();
|
|
|
|
var self = _(exposeMethods(scope, {
|
|
'set': scope.set,
|
|
'get': scope.get,
|
|
'eval': scope.eval
|
|
})).extend({
|
|
'init':function(){
|
|
config['location']['listen'](_(binder.onUrlChange).bind(binder));
|
|
binder.parseAnchor();
|
|
binder.executeInit();
|
|
binder.updateView();
|
|
return self;
|
|
},
|
|
'element':element[0],
|
|
'updateView': _(binder.updateView).bind(binder),
|
|
'config':config
|
|
});
|
|
return self;
|
|
}
|
|
|
|
angular['startUrlWatcher'] = function(){
|
|
var watcher = new UrlWatcher(window['location']);
|
|
watcher.watch();
|
|
return exposeMethods(watcher, {'listen':watcher.listen, 'set':watcher.set, 'get':watcher.get});
|
|
};
|
|
|
|
angular['compile'] = function(element, config) {
|
|
jQuery = window['jQuery'];
|
|
msie = jQuery['browser']['msie'];
|
|
config = _({
|
|
'onUpdateView': noop,
|
|
'server': "",
|
|
'location': {'get':noop, 'set':noop, 'listen':noop}
|
|
}).extend(config||{});
|
|
|
|
configureLogging(config);
|
|
configureJQueryPlugins();
|
|
|
|
return wireAngular(jQuery(element), config);
|
|
};
|