angular.js/src/Loader.js

405 lines
10 KiB
JavaScript
Raw Normal View History

2010-01-06 00:36:58 +00:00
// Copyright (C) 2008,2009 BRAT Tech LLC
// IE compatibility
if (typeof document.getAttribute == 'undefined')
document.getAttribute = function() {
};
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-09 23:02:43 +00:00
var callbacks = {};
if (!window.angular){ angular = {}; window['angular'] = angular; }
if (!angular.validator) angular.validator = {};
if (!angular.filter) angular.filter = {};
if (!window.console)
2010-01-06 00:36:58 +00:00
window.console = {
log:function() {},
error:function() {}
};
2010-01-09 23:02:43 +00:00
if (_.isUndefined(alert)) {
alert = function(){console.log(arguments); window.alert.apply(window, arguments); };
2010-01-06 00:36:58 +00:00
}
2010-01-09 23:02:43 +00:00
var consoleNode;
consoleLog = function(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-06 00:36:58 +00:00
};
2010-01-09 23:02:43 +00:00
isNode = function(inp) {
2010-01-06 00:36:58 +00:00
return inp &&
inp.tagName &&
inp.nodeName &&
inp.ownerDocument &&
inp.removeAttribute;
};
2010-01-09 23:02:43 +00:00
isLeafNode = function(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-09 23:02:43 +00:00
noop = function() {
2010-01-06 00:36:58 +00:00
};
2010-01-09 23:02:43 +00:00
setHtml = function(node, html) {
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-09 23:02:43 +00:00
escapeHtml = function(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-09 23:02:43 +00:00
escapeAttr = function(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-09 23:02:43 +00:00
bind = function(_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-09 23:02:43 +00:00
shiftBind = function(_this, _function) {
2010-01-06 00:36:58 +00:00
return function() {
var args = [ this ];
for ( var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
return _function.apply(_this, args);
};
};
2010-01-09 23:02:43 +00:00
outerHTML = function(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-09 23:02:43 +00:00
trim = function(str) {
2010-01-06 00:36:58 +00:00
return str.replace(/^ */, '').replace(/ *$/, '');
};
2010-01-09 23:02:43 +00:00
toBoolean = function(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-09 23:02:43 +00:00
merge = function(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
}
}
};
// ////////////////////////////
// Loader
// ////////////////////////////
2010-01-09 23:02:43 +00:00
Loader = function(document, head, config) {
2010-01-06 00:36:58 +00:00
this.document = jQuery(document);
this.head = jQuery(head);
this.config = config;
this.location = window.location;
};
2010-01-09 23:02:43 +00:00
Loader.prototype.load = function() {
2010-01-06 00:36:58 +00:00
this.configureLogging();
this.loadCss('/stylesheets/jquery-ui/smoothness/jquery-ui-1.7.1.css');
2010-01-09 23:02:43 +00:00
this.loadCss('/stylesheets/css');
2010-01-06 00:36:58 +00:00
console.log("Server: " + this.config.server);
2010-01-09 23:02:43 +00:00
msie = jQuery.browser.msie;
2010-01-06 00:36:58 +00:00
this.configureJQueryPlugins();
this.computeConfiguration();
this.bindHtml();
};
2010-01-09 23:02:43 +00:00
Loader.prototype.configureJQueryPlugins = function() {
2010-01-06 00:36:58 +00:00
console.log('Loader.configureJQueryPlugins()');
jQuery.fn.removeNode = function() {
var node = this.get(0);
node.parentNode.removeChild(node);
};
jQuery.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;
};
jQuery.fn.controller = function() {
2010-01-09 23:02:43 +00:00
return this.data('controller') || NullController.instance;
2010-01-06 00:36:58 +00:00
};
};
2010-01-09 23:02:43 +00:00
Loader.prototype.uid = function() {
2010-01-06 00:36:58 +00:00
return "" + new Date().getTime();
};
2010-01-09 23:02:43 +00:00
Loader.prototype.computeConfiguration = function() {
2010-01-06 00:36:58 +00:00
var config = this.config;
if (!config.database) {
var match = config.server.match(/https?:\/\/([\w]*)/);
2010-01-06 00:36:58 +00:00
config.database = match ? match[1] : "$MEMORY";
}
};
2010-01-09 23:02:43 +00:00
Loader.prototype.bindHtml = function() {
2010-01-06 00:36:58 +00:00
console.log('Loader.bindHtml()');
2010-01-09 23:02:43 +00:00
var watcher = new UrlWatcher(this.location);
2010-01-06 00:36:58 +00:00
var document = this.document;
2010-01-09 23:02:43 +00:00
var widgetFactory = new WidgetFactory(this.config.server, this.config.database);
var binder = new Binder(document[0], widgetFactory, watcher, this.config);
widgetFactory.onChangeListener = shiftBind(binder, binder.updateModel);
var controlBar = new ControlBar(document.find('body'), this.config.server);
2010-01-06 00:36:58 +00:00
var onUpdate = function(){binder.updateView();};
var server = this.config.database=="$MEMORY" ?
2010-01-09 23:02:43 +00:00
new FrameServer(this.window) :
new Server(this.config.server, jQuery.getScript);
server = new VisualServer(server, new Status(jQuery(document.body)), onUpdate);
var users = new Users(server, controlBar);
2010-01-06 00:36:58 +00:00
var databasePath = '/data/' + this.config.database;
var post = function(request, callback){
server.request("POST", databasePath, request, callback);
};
2010-01-09 23:02:43 +00:00
var datastore = new DataStore(post, users, binder.anchor);
2010-01-06 00:36:58 +00:00
binder.updateListeners.push(function(){datastore.flush();});
2010-01-09 23:02:43 +00:00
var scope = new Scope( {
2010-01-06 00:36:58 +00:00
$anchor : binder.anchor,
$binder : binder,
$config : this.config,
$console : window.console,
$datastore : datastore,
$save : function(callback) {
datastore.saveScope(scope.state, callback, binder.anchor);
},
$window : window,
$uid : this.uid,
$users : users
}, "ROOT");
jQuery.each(["get", "set", "eval", "addWatchListener", "updateView"],
function(i, method){
2010-01-09 23:02:43 +00:00
angular[method] = bind(scope, scope[method]);
2010-01-06 00:36:58 +00:00
});
document.data('scope', scope);
console.log('$binder.entity()');
binder.entity(scope);
console.log('$binder.compile()');
binder.compile();
console.log('ControlBar.bind()');
controlBar.bind();
console.log('$users.fetchCurrentUser()');
function fetchCurrentUser() {
users.fetchCurrentUser(function(u) {
if (!u && document.find("[ng-auth=eager]").length) {
users.login();
}
});
}
fetchCurrentUser();
console.log('PopUp.bind()');
2010-01-09 23:02:43 +00:00
new PopUp(document).bind();
2010-01-06 00:36:58 +00:00
console.log('$binder.parseAnchor()');
binder.parseAnchor();
console.log('$binder.executeInit()');
binder.executeInit();
console.log('$binder.updateView()');
binder.updateView();
2010-01-09 23:02:43 +00:00
watcher.listener = bind(binder, binder.onUrlChange, watcher);
watcher.onUpdate = function(){alert("update");};
2010-01-06 00:36:58 +00:00
watcher.watch();
document.find("body").show();
console.log('ready()');
};
2010-01-09 23:02:43 +00:00
Loader.prototype.visualPost = function(delegate) {
var status = new Status(jQuery(document.body));
2010-01-06 00:36:58 +00:00
return function(request, delegateCallback) {
status.beginRequest(request);
var callback = function() {
status.endRequest();
try {
delegateCallback.apply(this, arguments);
} catch (e) {
2010-01-09 23:02:43 +00:00
alert(toJson(e));
2010-01-06 00:36:58 +00:00
}
};
delegate(request, callback);
};
};
2010-01-09 23:02:43 +00:00
Loader.prototype.configureLogging = function() {
2010-01-06 00:36:58 +00:00
var url = window.location.href + '#';
url = url.split('#')[1];
var config = {
debug : null
};
var configs = url.split('&');
for ( var i = 0; i < configs.length; i++) {
var part = (configs[i] + '=').split('=');
config[part[0]] = part[1];
}
if (config.debug == 'console') {
2010-01-09 23:02:43 +00:00
consoleNode = document.createElement("div");
consoleNode.id = 'ng-console';
document.getElementsByTagName('body')[0].appendChild(consoleNode);
2010-01-06 00:36:58 +00:00
console.log = function() {
2010-01-09 23:02:43 +00:00
consoleLog('ng-console-info', arguments);
2010-01-06 00:36:58 +00:00
};
console.error = function() {
2010-01-09 23:02:43 +00:00
consoleLog('ng-console-error', arguments);
2010-01-06 00:36:58 +00:00
};
}
};
2010-01-09 23:02:43 +00:00
Loader.prototype.loadCss = function(css) {
2010-01-06 00:36:58 +00:00
var cssTag = document.createElement('link');
cssTag.rel = "stylesheet";
cssTag.type = "text/css";
if (!css.match(/^http:/))
css = this.config.server + css;
cssTag.href = css;
this.head[0].appendChild(cssTag);
};
2010-01-09 23:02:43 +00:00
UrlWatcher = function(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-09 23:02:43 +00:00
UrlWatcher.prototype.watch = function() {
2010-01-06 00:36:58 +00:00
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];
2010-01-09 23:02:43 +00:00
var notifyFn = callbacks[id];
delete callbacks[id];
2010-01-06 00:36:58 +00:00
try {
2010-01-09 23:02:43 +00:00
(notifyFn||noop)();
2010-01-06 00:36:58 +00:00
} catch (e) {
2010-01-09 23:02:43 +00:00
alert(e);
2010-01-06 00:36:58 +00:00
}
} else {
self.listener(self.location.href);
self.expectedUrl = self.location.href;
}
}
self.setTimeout(pull, self.delay);
};
pull();
};
2010-01-09 23:02:43 +00:00
UrlWatcher.prototype.setUrl = function(url) {
2010-01-06 00:36:58 +00:00
var existingURL = window.location.href;
if (!existingURL.match(/#/))
existingURL += '#';
if (existingURL != url)
window.location.href = url;
2010-01-09 23:02:43 +00:00
this.existingURL = url;
2010-01-06 00:36:58 +00:00
};
2010-01-09 23:02:43 +00:00
UrlWatcher.prototype.getUrl = function() {
2010-01-06 00:36:58 +00:00
return window.location.href;
};
2010-01-09 21:43:16 +00:00
angular['compile'] = function(root, config) {
config = config || {};
var defaults = {
server: ""
};
//todo: don't load stylesheet by default
//todo: don't start watcher
2010-01-09 23:02:43 +00:00
var loader = new Loader(root, jQuery("head"), _(defaults).extend(config));
2010-01-09 21:43:16 +00:00
loader.load();
return jQuery(root).scope();
};
2010-01-09 21:21:24 +00:00