angular.js/src/Angular.js

369 lines
9.7 KiB
JavaScript
Raw Normal View History

2010-01-06 00:36:58 +00:00
if (typeof document.getAttribute == 'undefined')
2010-01-12 00:15:12 +00:00
document.getAttribute = function() {};
2010-01-06 00:36:58 +00:00
if (typeof Node == 'undefined') {
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
};
}
2010-01-12 00:15:12 +00:00
function noop() {}
if (!window['console']) window['console']={'log':noop, 'error':noop};
2010-01-26 07:49:52 +00:00
var consoleNode, msie,
jQuery = window['jQuery'] || window['$'], // weirdness to make IE happy
2010-01-12 00:15:12 +00:00
foreach = _.each,
extend = _.extend,
2010-01-29 06:10:49 +00:00
identity = _.identity,
2010-01-12 00:15:12 +00:00
angular = window['angular'] || (window['angular'] = {}),
angularValidator = angular['validator'] || (angular['validator'] = {}),
angularFilter = angular['filter'] || (angular['filter'] = {}),
2010-01-29 06:10:49 +00:00
angularFormatter = angular['formatter'] || (angular['formatter'] = {}),
2010-01-12 00:15:12 +00:00
angularCallbacks = angular['callbacks'] || (angular['callbacks'] = {}),
angularAlert = angular['alert'] || (angular['alert'] = function(){
log(arguments); window.alert.apply(window, arguments);
});
var isVisible = isVisible || function (element) {
return jQuery(element).is(":visible");
}
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;
}
}
2010-01-12 00:15:12 +00:00
function consoleLog(level, objs) {
2010-01-06 00:36:58 +00:00
var log = document.createElement("div");
log.className = level;
var msg = "";
var sep = "";
for ( var i = 0; i < objs.length; i++) {
var obj = objs[i];
2010-01-09 23:02:43 +00:00
msg += sep + (typeof obj == 'string' ? obj : toJson(obj));
2010-01-06 00:36:58 +00:00
sep = " ";
}
log.appendChild(document.createTextNode(msg));
2010-01-09 23:02:43 +00:00
consoleNode.appendChild(log);
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function isNode(inp) {
2010-01-06 00:36:58 +00:00
return inp &&
inp.tagName &&
inp.nodeName &&
inp.ownerDocument &&
inp.removeAttribute;
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function isLeafNode (node) {
2010-01-06 00:36:58 +00:00
switch (node.nodeName) {
case "OPTION":
case "PRE":
case "TITLE":
return true;
default:
return false;
}
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function setHtml(node, html) {
2010-01-09 23:02:43 +00:00
if (isLeafNode(node)) {
if (msie) {
2010-01-06 00:36:58 +00:00
node.innerText = html;
} else {
node.textContent = html;
}
} else {
node.innerHTML = html;
}
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function escapeHtml(html) {
2010-01-06 00:36:58 +00:00
if (!html || !html.replace)
return html;
return html.
replace(/&/g, '&amp;').
replace(/</g, '&lt;').
replace(/>/g, '&gt;');
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function escapeAttr(html) {
2010-01-06 00:36:58 +00:00
if (!html || !html.replace)
return html;
return html.replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g,
'&quot;');
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function bind(_this, _function) {
2010-01-06 00:36:58 +00:00
if (!_this)
throw "Missing this";
if (!_.isFunction(_function))
throw "Missing function";
return function() {
return _function.apply(_this, arguments);
};
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function outerHTML(node) {
2010-01-06 00:36:58 +00:00
var temp = document.createElement('div');
temp.appendChild(node);
var outerHTML = temp.innerHTML;
temp.removeChild(node);
return outerHTML;
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function trim(str) {
2010-01-06 00:36:58 +00:00
return str.replace(/^ */, '').replace(/ *$/, '');
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function toBoolean(value) {
2010-01-06 00:36:58 +00:00
var v = ("" + value).toLowerCase();
if (v == 'f' || v == '0' || v == 'false' || v == 'no')
value = false;
return !!value;
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
function merge(src, dst) {
2010-01-06 00:36:58 +00:00
for ( var key in src) {
var value = dst[key];
var type = typeof value;
if (type == 'undefined') {
2010-01-09 23:02:43 +00:00
dst[key] = fromJson(toJson(src[key]));
} else if (type == 'object' && value.constructor != array &&
2010-01-06 00:36:58 +00:00
key.substring(0, 1) != "$") {
2010-01-09 23:02:43 +00:00
merge(src[key], value);
2010-01-06 00:36:58 +00:00
}
}
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
// ////////////////////////////
2010-01-23 23:54:58 +00:00
// UrlWatcher
2010-01-06 00:36:58 +00:00
// ////////////////////////////
2010-01-12 00:15:12 +00:00
function UrlWatcher(location) {
2010-01-06 00:36:58 +00:00
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;
2010-01-12 00:15:12 +00:00
}
2010-01-06 00:36:58 +00:00
2010-01-12 00:15:12 +00:00
UrlWatcher.prototype = {
2010-01-23 23:54:58 +00:00
listen: function(fn){
this.listener = fn;
},
2010-01-12 00:15:12 +00:00
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;
2010-01-06 00:36:58 +00:00
}
}
2010-01-12 00:15:12 +00:00
self.setTimeout(pull, self.delay);
};
pull();
},
2010-01-23 23:54:58 +00:00
set: function(url) {
var existingURL = this.location.href;
2010-01-19 01:56:08 +00:00
if (!existingURL.match(/#/))
existingURL += '#';
if (existingURL != url)
2010-01-23 23:54:58 +00:00
this.location.href = url;
2010-01-19 01:56:08 +00:00
this.existingURL = url;
2010-01-12 00:15:12 +00:00
},
2010-01-23 23:54:58 +00:00
get: function() {
2010-01-12 00:15:12 +00:00
return window.location.href;
}
2010-01-06 00:36:58 +00:00
};
2010-01-23 23:54:58 +00:00
/////////////////////////////////////////////////
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();
2010-01-19 01:56:08 +00:00
}
2010-01-23 23:54:58 +00:00
return null;
};
fn['controller'] = function() {
return this.data('controller') || NullController.instance;
};
2010-01-23 23:54:58 +00:00
}
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);
var controlBar = new ControlBar(element.find('body'), config['server'], config['database']);
2010-01-23 23:54:58 +00:00
var onUpdate = function(){binder.updateView();};
var server = config['database'] =="$MEMORY" ?
2010-01-25 03:12:01 +00:00
new FrameServer(window) :
new Server(config['server'], jQuery['getScript']);
server = new VisualServer(server, new Status(element.find('body')), onUpdate);
2010-01-23 23:54:58 +00:00
var users = new Users(server, controlBar);
var databasePath = '/data/' + config['database'];
2010-01-23 23:54:58 +00:00
var post = function(request, callback){
server.request("POST", databasePath, request, callback);
};
var datastore = new DataStore(post, users, binder.anchor);
binder.datastore = datastore;
2010-01-23 23:54:58 +00:00
binder.updateListeners.push(function(){datastore.flush();});
var scope = new Scope({
'$anchor' : binder.anchor,
'$updateView': _(binder.updateView).bind(binder),
'$config' : config,
2010-02-04 22:02:20 +00:00
'$invalidWidgets': [],
2010-01-23 23:54:58 +00:00
'$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();
2010-01-24 20:10:26 +00:00
binder.updateView();
2010-01-23 23:54:58 +00:00
return self;
},
'element':element[0],
'updateView': _(binder.updateView).bind(binder),
2010-01-23 23:54:58 +00:00
'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});
2010-01-23 23:54:58 +00:00
};
angular['compile'] = function(element, config) {
jQuery = window['jQuery'];
msie = jQuery['browser']['msie'];
2010-01-23 23:54:58 +00:00
config = _({
'server': "",
'location': {'get':noop, 'set':noop, 'listen':noop}
}).extend(config||{});
configureLogging(config);
configureJQueryPlugins();
return wireAngular(jQuery(element), config);
2010-01-12 00:15:12 +00:00
};