I'm not referring to the clothes you wear, rather the conventions you use in your coding. In fact it's less about style and more following a set of style rules - so closer to being fashionable. There are some examples of style guides out there and they range from the conservative like Google's style guide to the more extreme such as NPM's
I'm not going to tell you what style out there is best, instead I'm only going to tell you that when you're working on previous code or another project you should follow their guidelines. It's definitely easier on the eyes when jumping between files and the code looks the same. In fact go have a look at the JQuery source or any other large open source project with a lot of contributors and see if you can spot which parts are written by different people.
If you're writing for yourself or starting off with a new team have a look at different styles and see which is easiest to understand, even try writing a bit in each and see which flows more naturally for you. It's quite objective which style can be best and a good programmer should be able to adjust between the formats relatively easy.
Monday, April 30, 2012
Wednesday, April 25, 2012
optimizes often used templates
In the todomvc posts I've been doing the todo creates it's dom from a string:
But we can do one better. The htmlToDocumentFragment works by setting the string as the innerHTML of a div then grabbing the dom underneath it. A better option would be to set the DOM structure once and then use a deep clone to get the structure for other todos. So how should it look?
What we do is the first time the file is opened we set a class variable on mvc.todocontrol and then we can just do a deep clone of that making things faster which could be very useful if we start to have thousands of todo items on the page.
todomvc.todocontrol.prototype.createDom = function() {
this.el = goog.dom.htmlToDocumentFragment('<li>' +
'<div class="view">' +
'<input class="toggle" type="checkbox">' +
'<label>' + this.getModel().get('text') + '</label>' +
'<a class="destroy"></a>' +
'</div>' +
'<input class="edit" type="text" value="Create a TodoMVC template">' +
'</li>');
this.setElementInternal(this.el);
};
But we can do one better. The htmlToDocumentFragment works by setting the string as the innerHTML of a div then grabbing the dom underneath it. A better option would be to set the DOM structure once and then use a deep clone to get the structure for other todos. So how should it look?
todomvc.todocontrol.dom = goog.dom.htmlToDocumentFragment('<li>' +
'<div class="view">' +
'<input class="toggle" type="checkbox">' +
'<label>' + this.getModel().get('text') + '</label>' +
'<a class="destroy"></a>' +
'</div>' +
'<input class="edit" type="text" value="Create a TodoMVC template">' +
'</li>');
todomvc.todocontrol.prototype.createDom = function() {
this.el = todomvc.todocontrol.dom.cloneNode(true);
this.setElementInternal(this.el);
};
What we do is the first time the file is opened we set a class variable on mvc.todocontrol and then we can just do a deep clone of that making things faster which could be very useful if we start to have thousands of todo items on the page.
PlastronJS by example pt6
this post we're going to move code in to the todomvc template.
First download the todomvc template from https://github.com/addyosmani/todomvc (it should be in a folder called template) and copy everything across to the folder. Next we'll move the contents of /lib to /js/libs.
now some editing. I edited the index.html file to add a class name the same as id to "toggle-all" as I want to use the mvc.Control to handle those events and at the moment it only takes a classname to clarify the element, and one to the main input as "todo-entry" for the same reason.
Next we edit the part at the bottom where it asks for our scripts so we have this:
<script src="js/libs/closure-library/closure/goog/base.js"></script>
<script src="deps.js"></script>
<script src="js/app.js"></script>
<script>
todomvc.main();
</script>
I then copy and pasted our main.js in to app.'s and because it's in a closer I gave the window a reference to todomvc:
you might also notice that above I changed the todolistcontrol to decorate rather than render. You do this when there is already a DOM structure that the control should use. And here is the list control:
What I've done is add a schema to the list. The schema lists a new attribute on the list called completed. It has a get which tells me what I want back and model: true which tells the schema that the get uses the list of models and so changes should fire when the models change. I can then get a list of completed models any time by using .get('completed') but more importantly I can listen for changes on 'completed'.
We no longer need the createDom as it's already there for us so we move on to enterDocument.
The keyup event doesn't change except to tell the new models where they should render.
The next two clicks are for the check all and clear completed. They both run through the models in the list and one will set their complete value the other will tell the model to dispose itself.
The next is on a model change and will hide the footer and list if need be, I have similar lines of code to make it run the first time (in case in the future I want to already have notes displayed).
The last one binds to the 'completed' key I set in the schema and will update the items left when the completed number changes.
Now on to the todo:
here I change the createDom to use the HTML in the index.html (and I remove it from the index.html). I have four listeners setup, two are listening on the view and two on the model. So I listen on the view for the check box or the dispose button and I set the complete attribute or dispose of the model. I also listen to the complete attribute and set the views class and toggle check and lastly I listen for dispose on the model and dispose of my control.
Last thing to do is run the depswriter with the new file and directories:
js/libs/closure-library/closure/bin/calcdeps.py --dep js/libs/closure-library --input js/app.js --path js/libs/plastronjs --path js/libs/plastronjs/sync --path js/ --output_mode deps > deps.js
and that's it!
I have removed the functionality to edit a note but that shouldn't be too tricky. Next thing we need to do is put in comments for the functions and see how it all compiles.
N.B: download latest PlastronJS - there are a few fixes
First download the todomvc template from https://github.com/addyosmani/todomvc (it should be in a folder called template) and copy everything across to the folder. Next we'll move the contents of /lib to /js/libs.
now some editing. I edited the index.html file to add a class name the same as id to "toggle-all" as I want to use the mvc.Control to handle those events and at the moment it only takes a classname to clarify the element, and one to the main input as "todo-entry" for the same reason.
Next we edit the part at the bottom where it asks for our scripts so we have this:
<script src="js/libs/closure-library/closure/goog/base.js"></script>
<script src="deps.js"></script>
<script src="js/app.js"></script>
<script>
todomvc.main();
</script>
I then copy and pasted our main.js in to app.'s and because it's in a closer I gave the window a reference to todomvc:
/*
[MIT licensed](http://en.wikipedia.org/wiki/MIT_License)
(c) [You](http://addyosmani.github.com/todomvc/)
*/
goog.provide('todomvc.main');
goog.require('mvc.Collection');
goog.require('todomvc.listcontrol');
goog.require('goog.dom');
(function() {
// Your starting point. Enjoy the ride!
todomvc.main = function() {
var todolist = new mvc.Collection();
var todolistControl = new todomvc.listcontrol(todolist);
todolistControl.decorate(goog.dom.getElement('todoapp'));
window['a'] = todolist;
window['b'] = todolistControl;
};
window.todomvc = todomvc;
})();
you might also notice that above I changed the todolistcontrol to decorate rather than render. You do this when there is already a DOM structure that the control should use. And here is the list control:
goog.provide('todomvc.listcontrol');
goog.require('mvc.Control');
goog.require('todomvc.todocontrol');
goog.require('goog.dom');
todomvc.listcontrol = function(model) {
goog.base(this, model);
this.getModel().setSchema({
'completed': {
get: function() {
return this.getModels(function(mod) {
return mod.get('complete');
});
},
models: true
}
});
};
goog.inherits(todomvc.listcontrol, mvc.Control);
todomvc.listcontrol.prototype.enterDocument = function() {
goog.base(this, 'enterDocument');
this.on('keyup', function(e) {
// on return
if (e.keyCode != 13) return;
// create new model
var text = (this.getEls('input')[0]).value;
var newModel = this.getModel().newModel({'text': text});
//create new model control
var newModelControl = new todomvc.todocontrol(newModel);
newModelControl.render(goog.dom.getElement('todo-list'));
}, 'todo-entry');
this.click(function(e) {
goog.array.forEach(this.getModel().get('completed'), function(model) {
model.dispose();
});
}, 'clear-completed');
this.click(function(e) {
goog.array.forEach(this.getModel().getModels(), function(mod) {
mod.set('complete', e.target.checked);
});
}, 'toggle-all');
this.getModel().modelChange(function() {
goog.dom.getElement('main').style.display = this.getModels().length ?
'block' : 'none';
goog.dom.getElementsByTagNameAndClass('footer')[0].style.display =
this.getModels().length ? 'block' : 'none';
});
goog.dom.getElement('main').style.display =
this.getModel().getModels().length ? 'block' : 'none';
goog.dom.getElementsByTagNameAndClass('footer')[0].style.display =
this.getModel().getModels().length ? 'block' : 'none';
this.getModel().bind('completed', function(mods) {
goog.dom.setTextContent(goog.dom.getElement('todo-count'),
(this.getModel().getModels().length - mods.length) + ' items left');
}, this);
};
What I've done is add a schema to the list. The schema lists a new attribute on the list called completed. It has a get which tells me what I want back and model: true which tells the schema that the get uses the list of models and so changes should fire when the models change. I can then get a list of completed models any time by using .get('completed') but more importantly I can listen for changes on 'completed'.
We no longer need the createDom as it's already there for us so we move on to enterDocument.
The keyup event doesn't change except to tell the new models where they should render.
The next two clicks are for the check all and clear completed. They both run through the models in the list and one will set their complete value the other will tell the model to dispose itself.
The next is on a model change and will hide the footer and list if need be, I have similar lines of code to make it run the first time (in case in the future I want to already have notes displayed).
The last one binds to the 'completed' key I set in the schema and will update the items left when the completed number changes.
Now on to the todo:
goog.provide('todomvc.todocontrol');
goog.require('mvc.Control');
todomvc.todocontrol = function(model) {
goog.base(this, model);
this.editable = false;
};
goog.inherits(todomvc.todocontrol, mvc.Control);
todomvc.todocontrol.prototype.createDom = function() {
this.el = goog.dom.htmlToDocumentFragment('<li>' +
'<div class="view">' +
'<input class="toggle" type="checkbox">' +
'<label>' + this.getModel().get('text') + '</label>' +
'<a class="destroy"></a>' +
'</div>' +
'<input class="edit" type="text" value="Create a TodoMVC template">' +
'</li>');
this.setElementInternal(this.el);
};
todomvc.todocontrol.prototype.enterDocument = function() {
this.click(function(e) {
if (e.target.checked) {
this.getModel().set('complete', true);
} else {
this.getModel().set('complete', false);
}
}, 'toggle');
this.getModel().bind('complete', function(complete) {
if (complete) {
goog.dom.classes.add(this.getElement(), 'done');
} else {
goog.dom.classes.remove(this.getElement(), 'done');
}
this.getEls('.toggle')[0].checked = complete;
}, this);
this.getModel().bindUnload(function() {
this.dispose();
}, this);
this.click(function(e) {
e.preventDefault();
this.getModel().dispose();
return false;
}, "destroy")
};
here I change the createDom to use the HTML in the index.html (and I remove it from the index.html). I have four listeners setup, two are listening on the view and two on the model. So I listen on the view for the check box or the dispose button and I set the complete attribute or dispose of the model. I also listen to the complete attribute and set the views class and toggle check and lastly I listen for dispose on the model and dispose of my control.
Last thing to do is run the depswriter with the new file and directories:
js/libs/closure-library/closure/bin/calcdeps.py --dep js/libs/closure-library --input js/app.js --path js/libs/plastronjs --path js/libs/plastronjs/sync --path js/ --output_mode deps > deps.js
and that's it!
I have removed the functionality to edit a note but that shouldn't be too tricky. Next thing we need to do is put in comments for the functions and see how it all compiles.
N.B: download latest PlastronJS - there are a few fixes
Subscribe to:
Posts (Atom)