From 97eed3fa1e3905ba74bf6a842dc7e523ad645213 Mon Sep 17 00:00:00 2001 From: Borys Levytskyi Date: Fri, 3 Apr 2015 17:15:51 +0300 Subject: [PATCH] Extracted mode views and controllers into separate features. --- app/app.js | 31 ++---------- app/bitwise/expression.js | 22 ++++---- app/controllers.js | 6 ++- app/models.js | 27 ++++++++++ app/services.js | 38 ++++++++++++++ app/views.js | 70 +++++++++++--------------- components/bindr.js | 34 ------------- components/controllersFeature.js | 67 ++++++++++++++++++++++++ components/{html.js => htmlBuilder.js} | 6 ++- components/modelViewsFeature.js | 21 ++++++++ index.html | 16 +++--- 11 files changed, 215 insertions(+), 123 deletions(-) create mode 100644 app/models.js create mode 100644 components/controllersFeature.js rename components/{html.js => htmlBuilder.js} (90%) create mode 100644 components/modelViewsFeature.js diff --git a/app/app.js b/app/app.js index ffb979e..7f4a328 100644 --- a/app/app.js +++ b/app/app.js @@ -1,7 +1,8 @@ (function (should, commandr, bindr, Container) { var app = { - views: {} + views: {}, + models: {} }; var commandHandlers = {}; @@ -23,11 +24,8 @@ app.service = app.component; - app.controller = function(name, inst) { - this.addControllerMixin(inst); - this.di.register(name, inst); - }; + // TODO: introduce command feature app.command = function(name, handler) { var cmd = commandHandlers[name]; @@ -58,34 +56,15 @@ }; app.bootstrap = function(rootViewElement) { + this.rootViewElement = rootViewElement; invokeRunObservers(); - bindr.bindControllers(rootViewElement, app.di); }; function invokeRunObservers() { runObservers.forEach(function(o){ o(); }); } - app.addControllerMixin = function (component) { - component.attachView = function(viewElement) { - - this.viewElement = viewElement; - - if(typeof component.onViewAttached == 'function') { - component.onViewAttached(viewElement); - } - }; - - component.detachView = function() { - - this.viewElement = null; - - if(typeof component.onViewDetached == 'function') { - component.onViewDetached(viewElement); - } - }; - } - window.app = app; + })(window.should, window.commandr, window.bindr, window.Container); \ No newline at end of file diff --git a/app/bitwise/expression.js b/app/bitwise/expression.js index b9738cc..523e160 100644 --- a/app/bitwise/expression.js +++ b/app/bitwise/expression.js @@ -24,15 +24,14 @@ var o1 = parseInt(matches[1], 10); var o2 = parseInt(matches[3], 10); - return { - string: matches.input, - operand1: o1, - sign: matches[2], - operand2: o2, - calculate: function() { - return eval(this.string); - } - } + var m = new app.models.BitwiseOperation(); + m.operand1 = o1; + m.operand2 = o2; + m.sing = matches[2]; + m.string = matches.input; + m.result = eval(matches.input); + + return m; } function createListOfNumbersExpression(matches) { @@ -42,10 +41,7 @@ numbers.push(parseInt(matches[i], 10)); } - return { - string:matches.input, - operands: numbers - } + return app.models.BitwiseNumbers(numbers); } })(window.app); \ No newline at end of file diff --git a/app/controllers.js b/app/controllers.js index bf40f9b..fe18b98 100644 --- a/app/controllers.js +++ b/app/controllers.js @@ -20,7 +20,11 @@ clear: function (){ this.viewElement.innerHTML = ''; }, - insert: function (htmlElement) { + display: function (htmlElement) { + if(typeof htmlElement.tagName == "undefined") { + htmlElement = app.buildViewFor(htmlElement); + } + var vw = this.viewElement; if(vw.childNodes.length == 0) { vw.appendChild(htmlElement); diff --git a/app/models.js b/app/models.js new file mode 100644 index 0000000..3dbef77 --- /dev/null +++ b/app/models.js @@ -0,0 +1,27 @@ +(function(app) { + + function BitwiseOperation () { + } + + BitwiseOperation.prototype.calculate = function () { + return eval(this.string); + }; + + function BitwiseNumbers(numbers) { + this.numbers = numbers; + } + + function ErrorResult(message) { + this.message = message; + } + + function HelpResult (commands) { + this.commands = commands; + } + + app.models.BitwiseOperation = BitwiseOperation; + app.models.BitwiseNumbers = BitwiseNumbers; + app.models.ErrorResult = ErrorResult; + app.models.HelpResult = HelpResult; + +})(window.app); diff --git a/app/services.js b/app/services.js index bbcd401..7a2e885 100644 --- a/app/services.js +++ b/app/services.js @@ -3,7 +3,45 @@ app.service('html', { builder: function () { return new HtmlBuilder(); + }, + view: function (tml, model) { + var func = template.compile(tml); + return HtmlBuilder.createElement(func(model)); } }); + var template = { + compile: function (template) { + var regex = /(?:{([^}]+)})/g; + + var sb = []; + + sb.push('(function() {') + sb.push('return function (model) { ') + sb.push('\tvar html = [];') + sb.push('\twith (model) { ') + var m, index = 0; + while ((m = regex.exec(template)) !== null) { + if(m.index > index) { + sb.push("\t\thtml.push('" + normalize(template.substr(index, m.index - index)) + "');"); + } + sb.push('\t\thtml.push(' + m[1] + ');'); + index = m.index + m[0].length; + } + + if(index < template.length - 1) { + sb.push("\t\thtml.push('" + normalize(template.substr(index, template.length - index)) + "');"); + } + sb.push('\t}'); + sb.push("\treturn html.join('');"); + sb.push('}'); + sb.push('})()') + console.log(sb.join('\r\n')); + return eval(sb.join('\r\n')); + } + }; + + function normalize(str) { + return str.replace(/(\r|\n)+/g, '').replace("'", "\\\'"); + } })(window.app, window.HtmlBuilder); \ No newline at end of file diff --git a/app/views.js b/app/views.js index d2fa23e..cef6490 100644 --- a/app/views.js +++ b/app/views.js @@ -4,42 +4,37 @@ var formatter = app.service('formatter'); var calc = app.service('calc'); - function ExpressionView(expression) { - this.expression = expression; - } - - ExpressionView.prototype.render = function () { - var expr = this.expression, - hb = app.service('html').builder(); - - console.log('Rendering expression: ', expr) - - if(typeof expr.calculate == "function") { - return renderCalculableExpression(expr, hb); - } else { - return renderListOfNumbers(expr, hb); + app.modelView(app.models.BitwiseOperation, { + $html:null, + renderView: function(model) { + return renderCalculableExpression(model, this.$html.builder()); } + }); - }; + app.modelView(app.models.BitwiseNumbers, { + $html:null, + renderView: function(model) { + return renderListOfNumbers(model.numbers, this.$html.builder()); + } + }); function renderCalculableExpression(expr, hb) { - var result = expr.calculate(), - maxLen = calc.maxNumberOfBits([expr.operand1, expr.operand2, result]); + var maxLen = calc.maxNumberOfBits([expr.operand1, expr.operand2, expr.result]); hb.element('table', { class: "expression", cellspacing: "0"}, function () { buildRow(hb, expr.operand1, formatter.toBinaryString(expr.operand1, maxLen)); buildRow(hb, expr.operand2, formatter.toBinaryString(expr.operand2, maxLen)); - buildRow(hb, expr.string, formatter.toBinaryString(result, maxLen), { class: 'result'}); + buildRow(hb, expr.result, formatter.toBinaryString(expr.result, maxLen), { class: 'result'}); }); return hb.toHtmlElement(); } - function renderListOfNumbers(expr, hb) { - var maxLen = calc.maxNumberOfBits(expr.operands); + function renderListOfNumbers(numbers, hb) { + var maxLen = calc.maxNumberOfBits(numbers); hb.element('table', { class: "expression", cellspacing: "0"}, function () { - expr.operands.forEach(function(o){ + numbers.forEach(function(o){ buildRow(hb, o, formatter.toBinaryString(o, maxLen)); }); }); @@ -62,27 +57,18 @@ } } - app.views.ExpressionView = ExpressionView; - -})(window.app); - -// Help View -(function(app){ - function HelpView(commands) { - this.commands = commands; - } - - HelpView.prototype.render = function() { - var hb = app.service('html').builder(); - var commands = this.commands; - hb.element('ul', { class: 'result' }, function() { - commands.forEach(function(c) { - hb.element('li', c.name + " — " + c.description); - });}); - return hb.toHtmlElement(); - }; - - app.views.HelpView = HelpView; + app.modelView(app.models.HelpResult, { + $html: null, + renderView: function(model) { + var hb = this.$html.builder(); + var commands = model.commands; + hb.element('ul', { class: 'result' }, function() { + commands.forEach(function(c) { + hb.element('li', c.name + " — " + c.description); + });}); + return hb.toHtmlElement(); + } + }); })(window.app); diff --git a/components/bindr.js b/components/bindr.js index 9a59fa5..2ca8e8f 100644 --- a/components/bindr.js +++ b/components/bindr.js @@ -72,40 +72,6 @@ }; - bindr.bindControllers = function (rootViewElement, container) { - var elements = rootViewElement.querySelectorAll('[data-controller]'), - i = 0, l = elements.length, ctrlName, ctrl, attached; - - for(;i - + + + + + @@ -50,8 +54,7 @@ return; } - var expressionView = new window.app.views.ExpressionView(expr); - this.$resultView.insert(expressionView.render()); + this.$resultView.display(expr); cmdArgs.commandHandled = true; } @@ -68,9 +71,9 @@ { name: 'clear', description: 'Clears console'} ]; - var helpView = new app.views.HelpView(commands); + var model = new app.models.HelpResult(commands); - resultView.insert(helpView.render()); + resultView.display(model); cmdArgs.commandHandled = true; }); @@ -90,12 +93,13 @@ var hb = html.builder(); hb.element('div', { class: "result error", html: "Unknown expression: " + cmdArgs.input }); - resultView.insert(hb.toHtmlElement()); + resultView.display(hb.toHtmlElement()); cmdArgs.commandHandled = true; }); app.bootstrap(document.getElementById('rootView')); + })();