// Copyright (C) 2009 BRAT Tech LLC
nglr.WidgetFactory = function(serverUrl) {
this.nextUploadId = 0;
this.serverUrl = serverUrl;
this.createSWF = swfobject.createSWF;
this.onChangeListener = function(){};
};
nglr.WidgetFactory.prototype.createController = function(input, scope) {
var controller;
var type = input.attr('type').toLowerCase();
var exp = input.attr('name');
if (exp) exp = exp.split(':').pop();
var event = "change";
var bubbleEvent = true;
if (type == 'button' || type == 'submit' || type == 'reset') {
controller = new nglr.ButtonController(input[0], exp);
event = "click";
bubbleEvent = false;
} else if (type == 'text' || type == 'textarea') {
controller = new nglr.TextController(input[0], exp);
event = "keyup change";
} else if (type == 'checkbox') {
controller = new nglr.CheckboxController(input[0], exp);
event = "click";
} else if (type == 'radio') {
controller = new nglr.RadioController(input[0], exp);
event="click";
} else if (type == 'select-one') {
controller = new nglr.SelectController(input[0], exp);
} else if (type == 'select-multiple') {
controller = new nglr.MultiSelectController(input[0], exp);
} else if (type == 'file') {
controller = this.createFileController(input, exp);
} else {
throw 'Unknown type: ' + type;
}
input.data('controller', controller);
var binder = scope.get('$binder');
var action = function() {
if (controller.updateModel(scope)) {
var action = jQuery(controller.view).attr('ng-action') || "";
if (scope.evalWidget(controller, action)) {
binder.updateView(scope);
}
}
return bubbleEvent;
};
jQuery(controller.view, ":input").
bind(event, action);
return controller;
};
nglr.WidgetFactory.prototype.createFileController = function(fileInput) {
var uploadId = '__uploadWidget_' + (this.nextUploadId++);
var view = nglr.FileController.template(uploadId);
fileInput.after(view);
var att = {
data:this.serverUrl + "/admin/ServerAPI.swf",
width:"95", height:"20", align:"top",
wmode:"transparent"};
var par = {
flashvars:"uploadWidgetId=" + uploadId,
allowScriptAccess:"always"};
var swfNode = this.createSWF(att, par, uploadId);
fileInput.remove();
var cntl = new nglr.FileController(view, fileInput[0].name, swfNode, this.serverUrl);
jQuery(swfNode).data('controller', cntl);
return cntl;
};
nglr.WidgetFactory.prototype.createTextWidget = function(textInput) {
var controller = new nglr.TextController(textInput);
controller.onChange(this.onChangeListener);
return controller;
};
/////////////////////
// FileController
///////////////////////
nglr.FileController = function(view, scopeName, uploader, serverUrl) {
this.view = view;
this.uploader = uploader;
this.scopeName = scopeName;
this.uploadUrl = serverUrl + '/upload';
this.attachmentBase = serverUrl + '/attachments';
this.value = null;
this.lastValue = undefined;
};
nglr.FileController.dispatchEvent = function(id, event, args) {
var object = document.getElementById(id);
var controller = jQuery(object).data("controller");
nglr.FileController.prototype['_on_' + event].apply(controller, args);
};
nglr.FileController.template = function(id) {
return jQuery('' +
'' +
'' +
'' +
'' +
'');
};
nglr.FileController.prototype._on_cancel = function() {
};
nglr.FileController.prototype._on_complete = function() {
};
nglr.FileController.prototype._on_httpStatus = function(status) {
nglr.alert("httpStatus:" + this.scopeName + " status:" + status);
};
nglr.FileController.prototype._on_ioError = function() {
nglr.alert("ioError:" + this.scopeName);
};
nglr.FileController.prototype._on_open = function() {
nglr.alert("open:" + this.scopeName);
};
nglr.FileController.prototype._on_progress = function(bytesLoaded, bytesTotal) {
};
nglr.FileController.prototype._on_securityError = function() {
nglr.alert("securityError:" + this.scopeName);
};
nglr.FileController.prototype._on_uploadCompleteData = function(data) {
this.value = nglr.fromJson(data);
this.value.url = this.attachmentBase + '/' + this.value.id + '/' + this.value.text;
this.view.find("input").attr('checked', true);
var scope = this.view.scope();
this.updateModel(scope);
scope.get('$binder').updateView();
};
nglr.FileController.prototype._on_select = function(name, size, type) {
this.name = name;
this.view.find("a").text(name).attr('href', name);
this.view.find("span").text(filters.bytes(size));
this.upload();
};
nglr.FileController.prototype.updateModel = function(scope) {
var isChecked = this.view.find("input").attr('checked');
var value = isChecked ? this.value : null;
if (this.lastValue === value) {
return false;
} else {
scope.set(this.scopeName, value);
return true;
}
};
nglr.FileController.prototype.updateView = function(scope) {
var modelValue = scope.get(this.scopeName);
if (modelValue && this.value !== modelValue) {
this.value = modelValue;
this.view.find("a").
attr("href", this.value.url).
text(this.value.name);
this.view.find("span").text(filters.bytes(this.value.size));
}
this.view.find("input").attr('checked', !!modelValue);
};
nglr.FileController.prototype.upload = function() {
if (this.name) {
this.uploader.uploadFile(this.uploadUrl);
}
};
///////////////////////
// NullController
///////////////////////
nglr.NullController = function(view) {this.view = view;};
nglr.NullController.prototype.updateModel = function() { return true; };
nglr.NullController.prototype.updateView = function() { };
nglr.NullController.instance = new nglr.NullController();
///////////////////////
// ButtonController
///////////////////////
nglr.ButtonController = function(view) {this.view = view;};
nglr.ButtonController.prototype.updateModel = function(scope) { return true; };
nglr.ButtonController.prototype.updateView = function(scope) {};
///////////////////////
// TextController
///////////////////////
nglr.TextController = function(view, exp) {
this.view = view;
this.exp = exp;
this.validator = view.getAttribute('ng-validate');
this.required = typeof view.attributes['ng-required'] != "undefined";
this.lastErrorText = null;
this.lastValue = undefined;
this.initialValue = view.value;
var widget = view.getAttribute('ng-widget');
if (widget === 'datepicker') {
jQuery(view).datepicker();
}
};
nglr.TextController.prototype.updateModel = function(scope) {
var value = this.view.value;
if (this.lastValue === value) {
return false;
} else {
scope.set(this.exp, value);
this.lastValue = value;
return true;
}
};
nglr.TextController.prototype.updateView = function(scope) {
var view = this.view;
var value = scope.get(this.exp);
if (typeof value === "undefined") {
value = this.initialValue;
scope.set(this.exp, value);
}
value = value ? value : '';
if (this.lastValue != value) {
view.value = value;
this.lastValue = value;
}
var isValidationError = false;
view.removeAttribute('ng-error');
if (this.required) {
isValidationError = !(value && value.length > 0);
}
var errorText = isValidationError ? "Required Value" : null;
if (!isValidationError && this.validator && value) {
errorText = scope.validate(this.validator, value);
isValidationError = !!errorText;
}
if (this.lastErrorText !== errorText) {
this.lastErrorText = isValidationError;
if (errorText !== null) {
view.setAttribute('ng-error', errorText);
scope.markInvalid(this);
}
jQuery(view).toggleClass('ng-validation-error', isValidationError);
}
};
///////////////////////
// CheckboxController
///////////////////////
nglr.CheckboxController = function(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.checked ? view.value : "";
};
nglr.CheckboxController.prototype.updateModel = function(scope) {
var input = this.view;
var value = input.checked ? input.value : '';
if (this.lastValue === value) {
return false;
} else {
scope.setEval(this.exp, value);
this.lastValue = value;
return true;
}
};
nglr.CheckboxController.prototype.updateView = function(scope) {
var input = this.view;
var value = scope.eval(this.exp);
if (typeof value === "undefined") {
value = this.initialValue;
scope.setEval(this.exp, value);
}
input.checked = input.value == (''+value);
};
///////////////////////
// SelectController
///////////////////////
nglr.SelectController = function(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = view.value;
};
nglr.SelectController.prototype.updateModel = function(scope) {
var input = this.view;
if (input.selectedIndex < 0) {
scope.set(this.exp, null);
} else {
var value = this.view.value;
if (this.lastValue === value) {
return false;
} else {
scope.set(this.exp, value);
this.lastValue = value;
return true;
}
}
};
nglr.SelectController.prototype.updateView = function(scope) {
var input = this.view;
var value = scope.get(this.exp);
if (typeof value === 'undefined') {
value = this.initialValue;
scope.set(this.exp, value);
}
if (value !== this.lastValue) {
input.value = value ? value : "";
this.lastValue = value;
}
};
///////////////////////
// MultiSelectController
///////////////////////
nglr.MultiSelectController = function(view, exp) {
this.view = view;
this.exp = exp;
this.lastValue = undefined;
this.initialValue = this.selected();
};
nglr.MultiSelectController.prototype.selected = function () {
var value = [];
var options = this.view.options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
if (option.selected) {
value.push(option.value);
}
}
return value;
};
nglr.MultiSelectController.prototype.updateModel = function(scope) {
var value = this.selected();
// TODO: This is wrong! no caching going on here as we are always comparing arrays
if (this.lastValue === value) {
return false;
} else {
scope.set(this.exp, value);
this.lastValue = value;
return true;
}
};
nglr.MultiSelectController.prototype.updateView = function(scope) {
var input = this.view;
var selected = scope.get(this.exp);
if (typeof selected === "undefined") {
selected = this.initialValue;
scope.set(this.exp, selected);
}
if (selected !== this.lastValue) {
var options = input.options;
for ( var i = 0; i < options.length; i++) {
var option = options[i];
option.selected = selected.contains(option.value);
}
this.lastValue = selected;
}
};
///////////////////////
// RadioController
///////////////////////
nglr.RadioController = function(view, exp) {
this.view = view;
this.exp = exp;
this.lastChecked = undefined;
this.lastValue = undefined;
this.inputValue = view.value;
this.initialValue = view.checked ? view.value : null;
};
nglr.RadioController.prototype.updateModel = function(scope) {
var input = this.view;
if (this.lastChecked) {
return false;
} else {
input.checked = true;
this.lastValue = scope.set(this.exp, this.inputValue);
this.lastChecked = true;
return true;
}
};
nglr.RadioController.prototype.updateView = function(scope) {
var input = this.view;
var value = scope.get(this.exp);
if (this.initialValue && typeof value === "undefined") {
value = this.initialValue;
scope.set(this.exp, value);
}
if (this.lastValue != value) {
this.lastChecked = input.checked = this.inputValue == (''+value);
this.lastValue = value;
}
};
///////////////////////
//ElementController
///////////////////////
nglr.BindUpdater = function(view, exp) {
this.view = view;
this.exp = exp.parseBindings();
this.hasError = false;
this.scopeSelf = {element:view};
};
nglr.BindUpdater.toText = function(obj) {
var e = nglr.escapeHtml;
switch(typeof obj) {
case "string":
case "boolean":
case "number":
return e(obj);
case "function":
return nglr.BindUpdater.toText(obj());
case "object":
if (nglr.isNode(obj)) {
return nglr.outerHTML(obj);
} else if (obj && obj.TAG === filters.Meta.TAG) {
switch(typeof obj.html) {
case "string":
case "number":
return obj.html;
case "function":
return obj.html();
default:
break;
}
switch(typeof obj.text) {
case "string":
case "number":
return e(obj.text);
case "function":
return e(obj.text());
default:
break;
}
}
if (obj === null)
return "";
return e(nglr.toJson(obj, true));
default:
return "";
}
};
nglr.BindUpdater.prototype.updateModel = function(scope) {};
nglr.BindUpdater.prototype.updateView = function(scope) {
var html = [];
var parts = this.exp;
var length = parts.length;
for(var i=0; i iteratorLength; --r) {
var unneeded = this.children.pop();
unneeded.element.removeNode();
}
// Special case for option in select
if (child && child.element[0].nodeName === "OPTION") {
var select = jQuery(child.element[0].parentNode);
var cntl = select.data('controller');
if (cntl) {
cntl.lastValue = undefined;
cntl.updateView(scope);
}
}
});
};
//////////////////////////////////
// PopUp
//////////////////////////////////
nglr.PopUp = function(doc) {
this.doc = doc;
};
nglr.PopUp.OUT_EVENT = "mouseleave mouseout click dblclick keypress keyup";
nglr.PopUp.prototype.bind = function () {
var self = this;
this.doc.find('.ng-validation-error,.ng-exception').
live("mouseover", nglr.PopUp.onOver);
};
nglr.PopUp.onOver = function(e) {
nglr.PopUp.onOut();
var jNode = jQuery(this);
jNode.bind(nglr.PopUp.OUT_EVENT, nglr.PopUp.onOut);
var position = jNode.position();
var de = document.documentElement;
var w = self.innerWidth || (de&&de.clientWidth) || document.body.clientWidth;
var hasArea = w - position.left;
var width = 300;
var title = jNode.hasClass("ng-exception") ? "EXCEPTION:" : "Validation error...";
var msg = jNode.attr("ng-error");
var x;
var arrowPos = hasArea>(width+75) ? "left" : "right";
var tip = jQuery(
"" +
"
" +
"
"+title+"
" +
"
"+msg+"
" +
"
");
jQuery("body").append(tip);
if(arrowPos === 'left'){
x = position.left + this.offsetWidth + 11;
}else{
x = position.left - (width + 15);
tip.find('.ng-arrow-right').css({left:width+1});
}
tip.css({left: x+"px", top: (position.top - 3)+"px"});
return true;
};
nglr.PopUp.onOut = function() {
jQuery('#ng-callout').
unbind(nglr.PopUp.OUT_EVENT, nglr.PopUp.onOut).
remove();
return true;
};
//////////////////////////////////
// Status
//////////////////////////////////
nglr.Status = function (body) {
this.body = body;
this.requestCount = 0;
};
nglr.Status.ANGULAR = "<a class='ng-angular-logo' href='http://www.getangular.com'><angular/></a>™";
nglr.Status.prototype.beginRequest = function () {
if (this.requestCount === 0) {
<<<<<<< HEAD:public/javascripts/nglr/Widgets.js
this.dialogView = jQuery('');
=======
this.dialogView = jQuery('');
this.progressWidget = this.dialogView.find("div");
this.progressWidget.progressbar({value:0});
>>>>>>> master:public/javascripts/nglr/Widgets.js
this.dialogView.dialog({bgiframe:true, minHeight:50, modal:true});
this.maxRequestCount = 0;
}
this.requestCount++;
this.maxRequestCount++;
};
nglr.Status.prototype.endRequest = function () {
this.requestCount--;
if (this.requestCount === 0) {
this.dialogView.dialog("destroy");
this.dialogView.remove();
this.dialogView = null;
}
};