mirror of
https://github.com/BorysLevytskyi/BitwiseCmd.git
synced 2025-12-22 20:52:58 +01:00
Changed the way how application is composed
This commit is contained in:
15
app/app.js
15
app/app.js
@@ -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(); });
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
27
app/views.js
27
app/views.js
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
|
||||
htmlElement: function(obj) {
|
||||
return obj instanceof HtmlElement;
|
||||
},
|
||||
|
||||
array: function(obj) {
|
||||
return obj instanceof Array;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
22
index.html
22
index.html
@@ -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>
|
||||
Reference in New Issue
Block a user