Changed the way how application is composed

This commit is contained in:
Borys Levytskyi
2015-04-04 15:25:51 +03:00
parent d6e6f39688
commit 00a441d631
9 changed files with 292 additions and 189 deletions

View File

@@ -6,7 +6,7 @@
debugMode: false
};
var commandHandlers = {};
var appModules = [];
var runObservers = [];
app.di = new Container();
@@ -23,15 +23,28 @@
return this.di.resolve(name);
};
app.compose = function (module) {
appModules.push(module);
};
app.run = function(observer) {
runObservers.push(observer);
};
app.bootstrap = function(rootViewElement) {
this.rootViewElement = rootViewElement;
initializeModules();
invokeRunObservers();
};
function initializeModules() {
appModules.forEach(function(m) {
if(is.aFunction(m)) {
m();
}
});
}
function invokeRunObservers() {
runObservers.forEach(function(o){ o(); });
}

View File

@@ -1,9 +1,11 @@
(function(app, is){
app.compose(function() {
app.controller('expressionInputCtrl', {
$dispatcher:null,
app.controller('expressionInputCtrl', function (){
var dispatcher = app.component('dispatcher');
return {
onViewAttached: function () {
var d = this.$dispatcher;
var d = dispatcher;
var self = this;
self.history =[];
@@ -48,8 +50,12 @@
}
})
}
}
});
app.controller('resultViewCtrl', function() {
var html = app.component('html');
var resultViewController = {
$html: null,
clear: function (){
@@ -71,8 +77,9 @@
}
};
app.component('resultView', resultViewController);
app.controller('resultViewCtrl', resultViewController);
return resultViewController;
});
app.controller('configPanelCtrl', {
onViewAttached: function (){
@@ -84,4 +91,6 @@
}
});
})(window.app, window.is);
});

View File

@@ -1,13 +1,15 @@
(function(app, is){
app.compose(function() {
app.component('dispatcher', function() {
var handlers = [];
var is = app.component('is');
var resultView = app.controller('resultViewCtrl');
var dispatcher = {
$resultView:null,
dispatch: function(rawInput) {
var input = rawInput.trim();
var handler = this.findHandler(input);
if(handler != null) {
if(app.debugMode) {
@@ -69,19 +71,19 @@
var cmdResult = handler.handle(input);
if(cmdResult != null) {
var r = new app.models.DisplayResult(input, cmdResult);
this.$resultView.display(r);
resultView.display(r);
}
},
displayCommandError: function (input, message) {
var error = new app.models.ErrorResult(message);
this.$resultView.display(new app.models.DisplayResult(input, error));
resultView.display(new app.models.DisplayResult(input, error));
}
};
dispatcher.command('clear', function() {
app.get('resultView').clear();
app.controller('resultViewCtrl').clear();
});
app.component('dispatcher', dispatcher);
})(window.app, window.is);
return dispatcher;
});
});

View File

@@ -1,6 +1,7 @@
(function(app, HtmlBuilder){
app.component('html', HtmlBuilder);
app.component('is', is);
/*
var template = {
compile: function (template) {
@@ -37,4 +38,4 @@
return str.replace(/(\r|\n)+/g, '').replace("'", "\\\'");
}
*/
})(window.app, window.HtmlBuilder);
})(window.app, window.HtmlBuilder, window.is);

View File

@@ -1,24 +1,21 @@
// Expression View
(function(app) {
app.compose(function () {
var formatter = app.component('formatter');
var calc = app.component('calc');
var html = app.component('html');
app.modelView(app.models.BitwiseOperation, {
$html:null,
$calc:null,
renderView: function(expr) {
var maxLen = getBinaryLength([expr.operand1, expr.operand2, expr.result]);
var $html = app.component('html');
expr.operand1Binary = formatter.toBinaryString(expr.operand1, maxLen);
expr.operand2Binary = formatter.toBinaryString(expr.operand2, maxLen);
expr.resultBinary = formatter.toBinaryString(expr.result, maxLen);
var templateId = /<<|>>/.test(expr.sign) ? 'shiftExpressionView' : 'binaryExpressionView';
var html = document.getElementById(templateId).innerHTML;
var el = $html.element(html, expr);
var htmlTpl = document.getElementById(templateId).innerHTML;
var el = html.element(htmlTpl, expr);
colorizeBits(el);
return el;
@@ -26,11 +23,9 @@
});
app.modelView(app.models.BitwiseNumbers, {
$html:null,
$calc:null,
renderView: function(model) {
var maxLen = getBinaryLength(model.numbers);
var table = this.$html.element('<table class="expression"></table>');
var table = html.element('<table class="expression"></table>');
if(app.emphasizeBytes) {
if(maxLen % 8 != 0) {
@@ -58,24 +53,21 @@
});
app.modelView(app.models.HelpResult, {
$html: null,
renderView: function(model) {
var template = document.getElementById('helpView').innerHTML;
return this.$html.element(template);
return html.element(template);
}
});
app.modelView(app.models.ErrorResult, {
$html: null,
renderView: function(model) {
return this.$html.element('<div class="error">{message}</div>', model);
return html.element('<div class="error">{message}</div>', model);
}
});
app.modelView(app.models.DisplayResult, {
$html: null,
renderView: function(model) {
var resultView = this.$html.element(document.getElementById('resultView').innerHTML, model);
var resultView = html.element(document.getElementById('resultView').innerHTML, model);
var contentView = app.buildViewFor(model.content);
resultView.querySelector('.content').appendChild(contentView);
@@ -107,6 +99,5 @@
.replace(/1/g, '<span class="one">1</span>');
});
}
})(window.app);
});

View File

@@ -1,26 +1,40 @@
(function(app) {
(function(app, should, Container) {
app.controller = function(name, inst) {
var controllerDi = app.di; // TODO: Compbine
app.controller = function(name, instOrFactory) {
should.beString(name, "name");
if(instOrFactory == null) {
return controllerDi.resolve(name);
}
var reg = new Container.Registration(instOrFactory);
reg.onFirstTimeResolve = function (inst) {
addControllerMixin(inst);
this.di.register(name, inst);
};
function addControllerMixin(component) {
component.attachView = function(viewElement) {
controllerDi.register(name, reg);
};
function addControllerMixin(ctrl) {
ctrl.attachView = function(viewElement) {
this.viewElement = viewElement;
if(typeof component.onViewAttached == 'function') {
component.onViewAttached(viewElement);
if(typeof ctrl.onViewAttached == 'function') {
ctrl.onViewAttached(viewElement);
}
};
component.detachView = function() {
ctrl.detachView = function() {
this.viewElement = null;
if(typeof component.onViewDetached == 'function') {
component.onViewDetached(viewElement);
if(typeof ctrl.onViewDetached == 'function') {
ctrl.onViewDetached(viewElement);
}
};
}
@@ -29,7 +43,7 @@
attachControllers(app.rootViewElement, app.di);
});
function attachControllers(rootViewElement, di) {
function attachControllers(rootViewElement) {
var elements = rootViewElement.querySelectorAll('[data-controller]'),
i = 0, l = elements.length,
ctrlName,
@@ -38,7 +52,7 @@
for(;i<l;i++){
element = elements[i];
ctrlName = element.getAttribute('data-controller');
ctrl = di.resolve(ctrlName);
ctrl = app.controller(ctrlName);
if(ctrl == null) {
console.warn(ctrlName + ' controller wasn\'t found');
@@ -64,4 +78,9 @@
}
}
})(window.app);
function isController(obj) {
return obj.componentType == 'controller';
}
})(window.app, window.should, window.Container);

View File

@@ -1,31 +1,50 @@
// Problems: no check for the circular references
(function(){
(function(is){
function Container(store) {
this.store = {};
this.resolutionPath = [];
}
Container.prototype.register = function(name, inst) {
Container.prototype.register = function(name, def) {
var reg = this.store[name];
if(reg == null) {
reg = this.store[name] = { instance: inst };
if(def instanceof Registration) {
reg = def;
}
else {
reg = new Registration(def);
}
reg.name = name;
this.store[name] = reg;
}
console.log(name + ' component registered');
return reg;
};
Container.prototype.resolve = function(name) {
if(contains(this.resolutionPath, name)) {
throw new Error("Failed to resolve service: " + name + ". Circular reference: " + this.resolutionPath.join(' < '));
}
this.resolutionPath.unshift(name);
console.log('resolution path:' + this.resolutionPath.join(' < '));
var reg = this.store[name];
if(reg == null) {
throw new Error(name + ' component is not registered');
}
if(reg.resolved == null) {
var inst = reg.instance;
this.resolveProperties(inst);
reg.resolved = inst;
reg.createInstance();
}
this.resolutionPath.shift(name);
return reg.resolved;
};
@@ -46,5 +65,52 @@
}
};
Container.prototype.resolveMany = function (arr) {
var resolved = [], i = 0;
for(;i<0;i++) {
resolved.push(this.resolve(arr[i]));
}
return resolved;
};
function Registration(definition) {
this.def = definition;
this.resolved = null;
}
Registration.prototype.createInstance = function() {
var def = this.def;
if(typeof def == "function") {
if(is.array(def.inject)) {
this.resolved = def.apply(window, this.resolveMany(def.inject))
}
else {
this.resolved = def();
}
}
else {
// this.resolveProperties(inst);
this.resolved = def;
}
if(is.aFunction(this.onFirstTimeResolve)){
this.onFirstTimeResolve(this.resolved);
}
};
Container.Registration = Registration;
function contains(arr, item) {
var i = arr.length;
while(i-- > 0) {
if(arr[i] === item) {
return true;
}
}
return false;
}
window.Container = Container;
})();
})(window.is);

View File

@@ -22,6 +22,10 @@
htmlElement: function(obj) {
return obj instanceof HtmlElement;
},
array: function(obj) {
return obj instanceof Array;
}
};
})();

View File

@@ -41,7 +41,7 @@
</label>
</div>
<div id="output" data-controller="resultView">
<div id="output" data-controller="resultViewCtrl">
</div>
<script id="helpView" type="text/template">
@@ -118,35 +118,33 @@
<script type="text/javascript">
(function(){
var app = window.app;
app.run(function(){
var dispatcher = app.get('dispatcher');
dispatcher.command('help', function() {
return new app.models.HelpResult();
});
// TODO: Make as function
dispatcher.command({
$expression:null,
canHandle: function(input) { return this.$expression.canParse(input); },
canHandle: function(input) { return app.get('expression').canParse(input); },
handle: function(input) {
return this.$expression.parse(input);
return app.get('expression').parse(input);
}
});
app.emphasizeBytes = true; // TODO: Make into model
app.bootstrap(document.getElementById('rootView'));
app.debugMode = true;
dispatcher.dispatch('help');
});
})();
app.bootstrap(document.getElementById('rootView'));
app.component('dispatcher').dispatch('help');
</script>
</body>
</html>