Skip to content

Instantly share code, notes, and snippets.

@cj
Created October 26, 2012 05:03
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cj/3956902 to your computer and use it in GitHub Desktop.
Save cj/3956902 to your computer and use it in GitHub Desktop.
/*
AngularUI for AngularJS
v0.1.0
@link http://angular-ui.github.com/
*/
angular.module("ui.config", []).value("ui.config", {});
angular.module("ui.filters", ["ui.config"]);
angular.module("ui.directives", ["ui.config"]);
angular.module("ui", ["ui.filters", "ui.directives", "ui.config"]);
angular.module("ui.directives", ["ui.config"]).factory("InputHelper", [
"$compile", "$http", "$templateCache", "ui.config", function($compile, $http, $templateCache, uiConfig) {
var compile, idUid, internalAttrs, nameUid, nextUid, snake_case;
nextUid = function(uid) {
var digit, index;
index = uid.length;
digit = void 0;
while (index) {
index--;
digit = uid[index].charCodeAt(0);
if (digit === 57) {
uid[index] = "A";
return uid.join("");
}
if (digit === 90) {
uid[index] = "0";
} else {
uid[index] = String.fromCharCode(digit + 1);
return uid.join("");
}
}
uid.unshift("0");
return uid.join("");
};
snake_case = function(name, separator) {
return name.replace(/[A-Z]/g, function(letter, pos) {
return (pos ? separator : "") + letter.toLowerCase();
});
};
uiConfig.uiinput = uiConfig.uiinput || {};
idUid = ["0", "0", "0"];
nameUid = ["0", "0", "0"];
internalAttrs = ["family", "kind", "validation"];
return {
restrict: "E",
priority: 10000,
terminal: true,
compile: compile = function(tElement, tAttrs, transclude) {
var control;
control = {
id: tAttrs.id || "id" + nextUid(idUid)
};
return function(scope, element, attrs) {
var childScope, targetTagName, tplFamily, tplKind;
childScope = scope.$new();
tplFamily = tAttrs.family || uiConfig.uiinput.family;
tplKind = tAttrs.kind || uiConfig.uiinput.kind;
targetTagName = tElement[0].tagName.substring(3).toLowerCase();
return $http.get(targetTagName + "." + tplFamily + "." + tplKind + ".html", {
cache: $templateCache
}).success(function(response) {
var inputEl;
element.html(response);
inputEl = angular.element(element.find(targetTagName)[0]);
angular.forEach(tAttrs, function(value, key) {
if (key.charAt(0) !== "$") {
if (key.indexOf("input") === 0) {
return control[key.charAt(5).toLowerCase() + key.substr(6)] = value;
} else {
return inputEl.attr(snake_case(key, "-"), value);
}
}
});
control.validation = angular.extend({}, uiConfig.uiinput.validation, scope.$eval(tAttrs.validation));
childScope.$control = control;
$compile(element.contents())(childScope);
return childScope.$field = inputEl.controller("ngModel");
});
};
}
};
}
]).directive("uiInput", [
"InputHelper", function(InputHelper) {
return InputHelper;
}
]).directive("uiTextarea", [
"InputHelper", function(InputHelper) {
return InputHelper;
}
]).directive("uiSelect", [
"InputHelper", function(InputHelper) {
return InputHelper;
}
]);
/*
General-purpose Event binding. Bind any event not natively supported by Angular
Pass an object with keynames for events to ui-event
Allows $event object and $params object to be passed
@example <input ui-event="{ focus : 'counter++', blur : 'someCallback()' }">
@example <input ui-event="{ myCustomEvent : 'myEventHandler($event, $params)'}">
@param ui-event {string|object literal} The event to bind to as a string or a hash of events with their callbacks
*/
angular.module("ui.directives").directive("uiEvent", [
"$parse", function($parse) {
return function(scope, elm, attrs) {
var events;
events = scope.$eval(attrs.uiEvent);
return angular.forEach(events, function(uiEvent, eventName) {
var fn;
fn = $parse(uiEvent);
return elm.bind(eventName, function(evt) {
var params;
params = Array.prototype.slice.call(arguments_);
params = params.splice(1);
return scope.$apply(function() {
return fn(scope, {
$event: evt,
$params: params
});
});
});
});
};
}
]);
/*
Bind one or more handlers to particular keys or their combination
@param hash {mixed} keyBindings Can be an object or string where keybinding expression of keys or keys combinations and AngularJS Exspressions are set. Object syntax: "{ keys1: expression1 [, keys2: expression2 [ , ... ]]}". String syntax: ""expression1 on keys1 [ and expression2 on keys2 [ and ... ]]"". Expression is an AngularJS Expression, and key(s) are dash-separated combinations of keys and modifiers (one or many, if any. Order does not matter). Supported modifiers are 'ctrl', 'shift', 'alt' and key can be used either via its keyCode (13 for Return) or name. Named keys are 'backspace', 'tab', 'enter', 'esc', 'space', 'pageup', 'pagedown', 'end', 'home', 'left', 'up', 'right', 'down', 'insert', 'delete'.
@example <input ui-keypress="{enter:'x = 1', 'ctrl-shift-space':'foo()', 'shift-13':'bar()'}" /> <input ui-keypress="foo = 2 on ctrl-13 and bar('hello') on shift-esc" />
*/
angular.module("ui.directives").directive("uiKeypress", [
"$parse", function($parse) {
return {
link: function(scope, elm, attrs) {
var combinations, expression, keys, keysByCode, params, paramsParsed;
keysByCode = {
8: "backspace",
9: "tab",
13: "enter",
27: "esc",
32: "space",
33: "pageup",
34: "pagedown",
35: "end",
36: "home",
37: "left",
38: "up",
39: "right",
40: "down",
45: "insert",
46: "delete"
};
params = void 0;
paramsParsed = void 0;
expression = void 0;
keys = void 0;
combinations = [];
try {
params = scope.$eval(attrs.uiKeypress);
paramsParsed = true;
} catch (error) {
params = attrs.uiKeypress.split(/\s+and\s+/i);
paramsParsed = false;
}
angular.forEach(params, function(v, k) {
var combination;
combination = {};
if (paramsParsed) {
combination.expression = $parse(v);
combination.keys = k;
} else {
v = v.split(/\s+on\s+/i);
combination.expression = $parse(v[0]);
combination.keys = v[1];
}
keys = {};
angular.forEach(combination.keys.split("-"), function(value) {
return keys[value] = true;
});
combination.keys = keys;
return combinations.push(combination);
});
return elm.bind("keydown", function(event) {
var altPressed, ctrlPressed, shiftPressed;
altPressed = event.metaKey || event.altKey;
ctrlPressed = event.ctrlKey;
shiftPressed = event.shiftKey;
return angular.forEach(combinations, function(combination) {
var altRequired, ctrlRequired, mainKeyPressed, shiftRequired;
mainKeyPressed = (combination.keys[keysByCode[event.keyCode]] || combination.keys[event.keyCode.toString()]) || false;
altRequired = combination.keys.alt || false;
ctrlRequired = combination.keys.ctrl || false;
shiftRequired = combination.keys.shift || false;
if (mainKeyPressed && (altRequired === altPressed) && (ctrlRequired === ctrlPressed) && (shiftRequired === shiftPressed)) {
return scope.$apply(function() {
return combination.expression(scope, {
$event: event
});
});
}
});
});
}
};
}
]);
/*
General-purpose jQuery wrapper. Simply pass the plugin name as the expression.
It is possible to specify a default set of parameters for each jQuery plugin.
Under the jq key, namespace each plugin by that which will be passed to ui-jq.
Unfortunately, at this time you can only pre-define the first parameter.
@example { jq : { datepicker : { showOn:'click' } } }
@param ui-jq {string} The $elm.[pluginName]() to call.
@param [ui-options] {mixed} Expression to be evaluated and passed as options to the function
Multiple parameters can be separated by commas
Set {ngChange:false} to disable passthrough support for change events ( since angular watches 'input' events, not 'change' events )
@example <input ui-jq="datepicker" ui-options="{showOn:'click'},secondParameter,thirdParameter">
*/
angular.module("ui.directives").directive("uiJq", [
"ui.config", function(uiConfig) {
return {
restrict: "A",
compile: function(tElm, tAttrs) {
var options;
if (!angular.isFunction(tElm[tAttrs.uiJq])) {
throw new Error("ui-jq: The \"" + tAttrs.uiJq + "\" function does not exist");
}
options = uiConfig.jq && uiConfig.jq[tAttrs.uiJq];
return function(scope, elm, attrs) {
var linkOptions, ngChange;
linkOptions = [];
ngChange = "change";
if (attrs.uiOptions) {
linkOptions = scope.$eval("[" + attrs.uiOptions + "]");
if (angular.isObject(options) && angular.isObject(linkOptions[0])) {
linkOptions[0] = angular.extend(options, linkOptions[0]);
}
} else {
if (options) {
linkOptions = [options];
}
}
if (attrs.ngModel && elm.is("select,input,textarea")) {
if (linkOptions && angular.isObject(linkOptions[0]) && linkOptions[0].ngChange !== undefined) {
ngChange = linkOptions[0].ngChange;
}
if (ngChange) {
elm.on(ngChange, function() {
return elm.trigger("input");
});
}
}
return elm[attrs.uiJq].apply(elm, linkOptions);
};
}
};
}
]);
angular.module("ui.directives").directive("uiWhenScrolled", function() {
return function(scope, elm, attr) {
var raw;
raw = elm[0];
return elm.bind("scroll", function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight - 40) {
return scope.$apply(attr.uiWhenScrolled);
}
});
};
});
angular.module("ui.directives").directive("uiPopover", [
"$compile", "$http", "$timeout", "$templateCache", function($compile, $http, $timeout, $templateCache) {
var postLink;
return {
restrict: "A",
link: postLink = function(scope, element, attr, ctrl) {
return element.popover({
content: function() {
$timeout((function() {
$compile(element.data("popover").tip())(scope);
scope.$digest();
return $("body > .popover").addClass(element.data("class") || "");
}), 0, false);
return $("#" + attr.uiPopover + "-tmpl").html();
},
trigger: element.data("trigger") || "hover",
html: true
});
},
controller: [
"$scope", "$element", function($scope, $element) {
return $scope.dismiss = function($scope) {
return $element.popover("hide");
};
}
]
};
}
]);
angular.module("ui.directives").directive("uiModal", [
"$compile", "$http", "$timeout", "$templateCache", function($compile, $http, $timeout, $templateCache) {
return {
restrict: "A",
link: function(scope, element, attr, ctrl) {
return element.on('click', function() {
var $modalButtons, $tmpl, button, buttons, modal, modalButtons, title, _fn, _i, _len;
$tmpl = angular.element('<div class="row-fluid">').append(angular.element("#" + attr.uiModal + "-tmpl").html());
$modalButtons = $tmpl.find('.modal-buttons');
title = $modalButtons.data('title');
buttons = $modalButtons.find('button');
modalButtons = [];
_fn = function() {
var $button, callback;
$button = $(button);
callback = scope.$parent[$button.data('callback')];
return modalButtons.push({
label: $button.text(),
"class": $button.prop('class') || 'btn',
callback: function() {
if (callback) {
return callback.call(scope);
}
}
});
};
for (_i = 0, _len = buttons.length; _i < _len; _i++) {
button = buttons[_i];
_fn();
}
$tmpl = $tmpl.find('.modal-buttons').html('').end();
modal = bootbox.dialog($tmpl, modalButtons, {
header: title
});
modal.prop({
id: attr.uiModal + "-modal"
});
return scope.$apply(function() {
return $compile(modal)(scope);
});
});
}
};
}
]);
/*
<div ng-controller="MyCtrl">
<span>Type numbers here -></span>
<input type="text" ui-mask="{{myMask}}" ng-model="number" />
<button ng-click="setField()">Press here to set the field from the model</button>
<pre>{{number}}</pre>
<button ng-click="myMask = '(9).99-99'">Press here to change mask</button>
</div>
function MyCtrl($scope) {
$scope.myMask = "(999).999-99";
$scope.setField = function() {
console.log("setting field");
$scope.number = 12345678;
};
}
*/
/*
Attaches jquery-ui input mask onto input element
*/
angular.module("ui.directives").directive("uiMask", [
function() {
return {
require: "ngModel",
link: function($scope, element, attrs, controller) {
controller.$render = function() {
var value;
value = controller.$viewValue || "";
element.val(value);
return element.mask($scope.$eval(attrs.uiMask));
};
controller.$parsers.push(function(value) {
var isValid;
isValid = element.isMaskValid() || angular.isUndefined(element.isMaskValid()) && element.val().length > 0;
controller.$setValidity("mask", isValid);
if (isValid) {
return value;
} else {
return undefined;
}
});
return element.bind("keyup", function() {
return $scope.$apply(function() {
return controller.$setViewValue(element.mask());
});
});
}
};
}
]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment