bitcoin-atm
bitcoin atm for pyc inc.
git clone https://9o.is/git/bitcoin-atm.git
commit 3d45c9c069706a5dfee70f34cea3273cc517d898 parent a65f88b036b3293233ccc4f5f091f9c764ce9d9c Author: Jul <jul@9o.is> Date: Mon, 9 Jun 2014 21:38:32 -0400 modularized js code Diffstat:
| M | Gruntfile.js | | | 4 | +--- |
| A | src/main/webapp/app/ActorsBridge.js | | | 29 | +++++++++++++++++++++++++++++ |
| M | src/main/webapp/app/App.js | | | 51 | +-------------------------------------------------- |
| A | src/main/webapp/app/controllers/Forms.js | | | 147 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/main/webapp/app/directives/disabler.js | | | 29 | +++++++++++++++++++++++++++++ |
| R | src/main/webapp/app/App.spec.js -> src/main/webapp/app/test/App.spec.js | | | 0 |
6 files changed, 207 insertions(+), 53 deletions(-)
diff --git a/Gruntfile.js b/Gruntfile.js @@ -97,9 +97,7 @@ module.exports = function(grunt) { }, jasmine: { - src: [ - '<%= dirs.src %>/app/App.js' - ], + src: '<%= app_files.js %>', options: { vendor: [ 'http://maps.googleapis.com/maps/api/js?sensor=false&language=en', diff --git a/src/main/webapp/app/ActorsBridge.js b/src/main/webapp/app/ActorsBridge.js @@ -0,0 +1,28 @@ +/** + * Actors Bridge: comet updates are handled here. + */ +window.ActorsBridge = function(sendFunc) { + "use strict"; + + var self = this; + + self.send = sendFunc; + + /** + * Broadcasts message to angular app in html document. + */ + self.broadcast = function(event, message) { + var scope = angular.element('[ng-app]').scope(); + scope.$apply(function () { + scope.$broadcast(event, message); + }); + }; + + /** + * Updates the price for price ticker. + */ + self.newPrice = function(message) { + self.broadcast('new-price', message); + }; + +}; +\ No newline at end of file diff --git a/src/main/webapp/app/App.js b/src/main/webapp/app/App.js @@ -1,31 +1,7 @@ /** - * Actors Bridge: comet updates are handled here - */ -window.ActorsBridge = function(sendFunc) { - "use strict"; - - var self = this; - self.send = sendFunc; - - /* Broadcasts message to angular app in html document. */ - self.broadcast = function(event, message) { - var scope = angular.element('[ng-app]').scope(); - scope.$apply(function () { - scope.$broadcast(event, message); - }); - }; - - /* Updates the price for price ticker. */ - self.newPrice = function(message) { - self.broadcast('new-price', message); - }; - -}; - -/** * Main Angular Module */ -var app = angular.module("app", ['ui.bootstrap']); +var app = angular.module("app", ['ui.bootstrap', 'Forms', 'disabler']); /** * Button display 'loading' (with a spinner) during ajax. @@ -49,31 +25,6 @@ app.directive('disabler', ['$compile', function($compile) { }]); /** - * General abstract controller for other forms. - */ -app.controller('FormCtrl', ['$scope', function($scope) { - - /* Client-side data */ - $scope.model = {}; - - /* Success inputs for ng-class */ - $scope.stateSuccess = function(el) { - return "{'state-success':form."+el+".$valid && !form."+el+".$pristine}"; - }; - - /* Success and Failure inputs in ng-class */ - $scope.stateSuccessError = function(el) { - return "{'state-error':form."+el+".$invalid && !form."+el+".$pristine,'state-success':form."+el+".$valid && !form."+el+".$pristine}"; - }; - - /* Resets client-side data. */ - $scope.reset = function() { - $scope.model = {}; - $scope.form.$setPristine(); - }; -}]); - -/** * Price Ticker shows price per bitcoin. */ app.controller('PriceTickerCtrl', ['$scope', '$rootScope', function($scope, $rootScope) { diff --git a/src/main/webapp/app/controllers/Forms.js b/src/main/webapp/app/controllers/Forms.js @@ -0,0 +1,146 @@ +/** + * This modules simplifies the troubles of connecting with Liftweb 3.0's + * promises. + * + * Included ngAlert as dependency since Forms module checks the success + * of the message using ngAlert's message formatting. + */ +angular.module("Forms", ['ngAlert']) + + /** + * Simple form controller with helper functions like submit + * which handles the complexity of sending data and handling + * response from backend server. + */ + .controller('FormCtrl', ['$scope', function($scope) { + + /** + * Client-side data + */ + $scope.model = {}; + + /** + * Success inputs for ng-class + */ + $scope.stateSuccess = function(el) { + return "{'state-success':form."+el+".$valid && !form."+el+".$pristine}"; + }; + + /** + * Success and Failure inputs in ng-class + */ + $scope.stateSuccessError = function(el) { + return "{'state-error':form."+el+".$invalid && !form."+el+".$pristine,'state-success':form."+el+".$valid && !form."+el+".$pristine}"; + }; + + /** + * Sends data to server. (Useful for Liftweb's roundtrip with ngAlert at least) + */ + $scope.submit = function(className, funcName, successFunc, failureFunc) { + $scope.loading = true; + window[className][funcName]($scope.model).then(function(alert) { + $scope.$apply(function() { + $scope.loading = false; + if(alert.msg_type === "success") { + if(typeof(successFunc) === "function") { + successFunc(alert); + } + } else { + if(typeof(failureFunc) === "function") { + failureFunc(alert); + } + } + }); + }); + }; + + /** + * Resets client-side data and the entire form. + */ + $scope.reset = function() { + $scope.model = {}; + $scope.form.$setPristine(); + }; + }]) + + /** + * Form controller that is initialized with server-side data. + */ + .controller('LoadedFormCtrl', ['$scope', '$controller', function($scope, $controller) { + $controller('FormCtrl', {$scope: $scope}); + + /** + * Known server-side data + */ + $scope.master = {}; + + /** + * Checks whether the client-side data is different + * from known server-side data. + */ + $scope.diff = function(name) { + return $scope.master[name] !== $scope.model[name]; + }; + + /** + * Initiates the form with existing data from the server. + */ + $scope.init = function(className, funcName) { + window[className][funcName]().then(function(data) { + $scope.$apply(function() { + $scope.model = angular.copy(data); + $scope.master = angular.copy(data); + }); + }); + }; + }]) + + /** + * Form controller to easily update (server-side data) inputs immediately. + */ + .controller('AutoUpdateFormCtrl', ['$scope', '$controller', '$rootScope', function($scope, $controller, $rootScope) { + $controller('LoadedFormCtrl', {$scope: $scope, $controller: $controller}); + + /** + * Updates server-side data with client-side's data corresponding + * to a change of a data model 'name'. + * + * Sets funcName+"_loading" scoped variable to true (useful for Ajax animations) + */ + $scope.update = function(className, funcName, successFunc, failureFunc) { + // if values are different, update + if($scope.diff(funcName)) { + $scope[funcName+"_loading"] = true; + window[className][funcName]($scope.model[funcName]).then(function(alert) { + $scope.$apply(function() { + $scope[funcName+"_loading"] = false; + if(alert.msg_type === "success") { + $scope.master= angular.copy($scope.model); + $scope.reset(); + + if(typeof(successFunc) === "function") { + successFunc(); + } + } else { + $rootScope.$broadcast('alertDialog', alert); + + if(typeof(failureFunc) === "function") { + failureFunc(); + } + } + }); + }); + } else { + $scope.reset(); + } + }; + + /** + * Sets client-side data with server and resets entire form. + */ + $scope.reset = function() { + $scope.model = {}; + $scope.form.$setPristine(); + $scope.model= angular.copy($scope.master); + }; + }]); +\ No newline at end of file diff --git a/src/main/webapp/app/directives/disabler.js b/src/main/webapp/app/directives/disabler.js @@ -0,0 +1,28 @@ +/** + * Disables button and displays loading. (Useful for Ajax) + * Depends on FontAwesome's spinning icon. + * + * Usage: + * + * <button type="submit" disabler ng-model="loading">Submit</button> + * + * Set $scope.loading to true in javascript code to display + * the button as loading. + */ +angular.module("disabler", []) + .directive('disabler', ['$compile', function($compile) { + return { + link: function(scope, elm, attrs) { + var btnContents = $compile(elm.contents())(scope); + scope.$watch(attrs.ngModel, function(value) { + if (value) { + elm.html("<i class='fa fa-spinner fa-spin'></i> Loading"); + elm.attr('disabled',true); + } else { + elm.html('').append(btnContents); + elm.attr('disabled',false); + } + }); + } + }; + }]); +\ No newline at end of file diff --git a/src/main/webapp/app/App.spec.js b/src/main/webapp/app/test/App.spec.js