From cfa948f6b0462e09f44c3e73412f56294233adad Mon Sep 17 00:00:00 2001 From: Borys Levytskyi Date: Thu, 2 Apr 2015 21:56:59 +0300 Subject: [PATCH] databinding and commands --- .idea/workspace.xml | 262 ++++++++++++++++++++++++------------ index.html | 42 ++++-- js/app.js | 57 ++++++-- js/components/bindr.js | 86 ++++++++++++ js/components/expression.js | 5 + js/expressionInputCtrl.js | 22 +++ 6 files changed, 367 insertions(+), 107 deletions(-) create mode 100644 js/components/bindr.js create mode 100644 js/expressionInputCtrl.js diff --git a/.idea/workspace.xml b/.idea/workspace.xml index b188363..0e9af16 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -23,41 +23,41 @@ + + + + + + + + + + + + + + + + + + + + - + - + - - - - - - - - - - - - - - - - - - - - - - + + @@ -66,8 +66,18 @@ - - + + + + + + + + + + + + @@ -76,23 +86,13 @@ - + - - - - - - - - - - @@ -103,11 +103,21 @@ + + + + + + + + + + - - + + @@ -138,18 +148,24 @@ @@ -252,7 +268,11 @@ + + + + @@ -315,15 +335,14 @@ - - + + - - + @@ -331,6 +350,7 @@ + @@ -354,9 +374,59 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -629,42 +699,10 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -679,24 +717,72 @@ - - + + + + + + + + + + + + + + + + + + - + - + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/index.html b/index.html index cecbc4f..11b5887 100644 --- a/index.html +++ b/index.html @@ -5,19 +5,22 @@ + - + + +
@@ -25,17 +28,38 @@ diff --git a/js/app.js b/js/app.js index 4b308cb..2ab6797 100644 --- a/js/app.js +++ b/js/app.js @@ -1,25 +1,62 @@ -(function (should) { +(function (should, bindr) { var app = {}; app.views = {}; - var services = {}; + var servicesContainer = {}; + var controllersContainer = {}; + var events = {}; - app.service = function(name, impl) { + function resolveOrInject(name, inst, container, entityName) { + var resolved; should.beString(name); - if(impl != null) { - services[name] = impl; - console.log(name + " service registered"); - return impl; + if (inst != null) { + container[name] = inst; + console.log(name + " " + entityName + " registered"); + resolved = inst; + } + else { + resolved = container[name]; + should.check(resolved != null, name + " " + entityName + " wasn't found"); } - var svc = services[name]; - should.check(svc != null, name + " service wasn't found"); - return svc; + return resolved; + } + + app.service = function(name, inst) { + return resolveOrInject(name, inst, servicesContainer, "service"); + }; + + app.controller = function(name, inst) { + return resolveOrInject(name, inst, controllersContainer, "controller"); + }; + + app.command = function(name) { + var evt = events[name]; + if(evt == null) { + evt = events[name] = new Command(name); + } + return evt; }; window.app = app; + function Command(name) { + this.name = name; + this.handlers = []; + } + + Command.prototype.fire = function (arg) { + for(var i=0; i<1; i++) { + this.handlers[i](arg); + } + }; + + Command.prototype.subscribe = function (handler) { + this.handlers.push(handler); + // TODO: unsubcribe + } + })(window.should); \ No newline at end of file diff --git a/js/components/bindr.js b/js/components/bindr.js new file mode 100644 index 0000000..610c607 --- /dev/null +++ b/js/components/bindr.js @@ -0,0 +1,86 @@ +(function(){ + var bindr = {}; + + bindr.model = function(definition){ + var model = new bindr.Model(); + for(var property in definition){ + if(!definition.hasOwnProperty(property)){ + continue; + } + + Object.defineProperty(model, property, { + get:bindr.Model.createGetter(property), + set:bindr.Model.createSetter(property) + }); + + model[property] = definition[property]; + } + return model; + }; + + bindr.Model = function() { + this.handlers = []; + }; + + bindr.Model.createGetter = function (propertyName){ + return function(){ + return this["_" + propertyName]; + } + }; + + bindr.Model.createSetter = function(propertyName){ + return function(value){ + this["_" + propertyName] = value; + this.notifyPropertyChanged(propertyName, value); + } + }; + + bindr.Model.prototype.observe = function (handler){ + this.handlers.push(handler); + }; + + bindr.Model.prototype.notifyPropertyChanged = function(propertyName, value){ + this.handlers.forEach(function(h){ + h(propertyName, value); + }); + }; + + bindr.bindElement = function(model, element, propertyName) { + if(element.bindr != null) { + return; + } + + if(element.tagName == "INPUT") { + bindInput(model, element, propertyName); + } + else { + bindHtmlElement(model, element, propertyName); + } + + element.bindr = {}; // will be used later + }; + + function bindInput(model, intput, propertyName) { + intput.addEventListener('keyup', function(e){ + model[propertyName] = e.srcElement.value; + }); + + model.observe(function(property, value){ + if(window.event && window.event.srcElement == intput) { + return; + } + + intput.value = value; + }); + } + + function bindHtmlElement(model, el, propertyName) { + model.observe(function(propery, value){ + if(propery == propertyName) { + el.innerHTML = value; + } + }); + } + + window.bindr = bindr; +})(); \ No newline at end of file diff --git a/js/components/expression.js b/js/components/expression.js index ff7cfda..553a7aa 100644 --- a/js/components/expression.js +++ b/js/components/expression.js @@ -4,7 +4,12 @@ app.service('expression', { parse: function(string) { var matches = twoOperandsRegex.exec(string); + if(matches == null) { + return null; + } + console.log(matches); + return { string:matches[0], operand1: parseInt(matches[1], 10), diff --git a/js/expressionInputCtrl.js b/js/expressionInputCtrl.js new file mode 100644 index 0000000..6030cd9 --- /dev/null +++ b/js/expressionInputCtrl.js @@ -0,0 +1,22 @@ +(function(){ + function subscribeEvents(element) { + element.addEventListener('keyup', function(args) { + + if(args.keyCode == 13) { + // Enter + app.command('calculateExpression').fire(); + } + + console.log(args) + }); + } + + app.controller('expressionInputCtrl', { + bind: function (element) { + subscribeEvents(element); + } + }); + + + +})(window.app);