I've been learning Backbone.js which is MVC (or MV*) for client-side JavaScript.
In Backbone.js, you define a model (the "M") by doing this:
var Model1 = Backbone.Model.extend({
});
You create an instance of a model by doing this:
var model1 = new Model1();
To define a Backbone.js view (the "V"), you can do something like this:
var View1 = Backbone.View.extend({
events: {
click: function(e) {
alert('Clicked!');
}
}
});
To create an instance of the view, you can do this:
<a id="a1" href="#"><span>My Link</span></a>
...
var view1 = new View1({el: '#a1'});
Now, here comes Dumb Idiom #1. You can do this:
alert(view1.$el.css('display'));
Say what? What's view1.$el? It's a dumb shorthand that saves two characters. It means $(view1.el) in regular old jQuery but instead of typing those two parentheses, you can use a shortcut that only works in Backbone.js and easily throws everybody, including yourself, for a loop.
But, wait, there's more. Here comes Dumb Idiom #2. Instead of using jQuery find(), you can do this:
alert(view1.$('span').html());
What is this? In Backbone.js but not standard jQuery, you can use view1.$('span') as a shorthand for $(view1.el).find('span'). We save a few more characters here (i.e. nine) but pay for it with the need to memorize yet another idiom.
Backbone.js, stick to your knitting! You aren't jQuery and shouldn't be inventing unnecessary and non-standard idioms for jQuery.
Thursday, August 22, 2013
Wednesday, July 10, 2013
More Simple JavaScript Inheritance
I like John Resig's Simple JavaScript Inheritance ... except that I hate having to refactor my JavaScript code to use it.
As John suggests, suppose that I have some code:
function Person(isDancing){
this.dancing = isDancing;
}
Person.prototype.dance = function(){
return this.dancing;
};
function Ninja(){
this.dancing = false;
}
Ninja.prototype.dance = function(){
return this.dancing;
};
Ninja.prototype.swingSword = function(){
return true;
};
That's normal JavaScript object code. Now, I decide to use John Resig's "Simple JavaScript Inheritance". John Resig suggests that I rewrite my code like this:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
});
Instead of rewriting the code into a new code syntax, I only add an extend() call at the end of each new JavaScript class. Once I've done that, if I want, I can call this._super() where ever I need to.
As John suggests, suppose that I have some code:
function Person(isDancing){
this.dancing = isDancing;
}
Person.prototype.dance = function(){
return this.dancing;
};
function Ninja(){
this.dancing = false;
}
Ninja.prototype.dance = function(){
return this.dancing;
};
Ninja.prototype.swingSword = function(){
return true;
};
That's normal JavaScript object code. Now, I decide to use John Resig's "Simple JavaScript Inheritance". John Resig suggests that I rewrite my code like this:
var Person = Class.extend({
init: function(isDancing){
this.dancing = isDancing;
},
dance: function(){
return this.dancing;
}
});
var Ninja = Person.extend({
init: function(){
this._super( false );
},
dance: function(){
// Call the inherited version of dance()
return this._super();
},
swingSword: function(){
return true;
}
});
Changes are in red. The implementations stay the same but the code syntax is different. It's a bit of a hassle if you have little bit of code and, for a lot of code, it's even more of a hassle.
Why can't I reuse my code as-is with only a few modifications? Something like this:
function Person(isDancing){
function Person(isDancing){
this.dancing = isDancing;
}
Person.prototype.dance = function(){
return this.dancing;
};
Person = Class.extend(Person);
function Ninja(){
this._super( false );
}
Ninja.prototype.dance = function(){
// Call the inherited version of dance()
return this._super();
};
Ninja.prototype.swingSword = function(){
return true;
};
Ninja = Person.extend(Ninja);
Ninja = Person.extend(Ninja);
I make this possible using a slight modification to John Resig's script. By checking to see if the argument passed to extend() is a function, instead of an object, the script can handle both syntaxes: John Resig's original syntax and the traditional JavaScript object syntax.
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* Init-by-function modification
* By Daniel Howard http://www.svexpertise.com/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
if ( typeof prop == 'function' ) {
prop.prototype.init = prop;
for (var name in prop)
prop.prototype[name] = prop[name];
prop = prop.prototype;
}
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
When a function is detected, instead of an object, the function is first saved to the init property. Then, all enumerable function properties (which will behave pretty much like static variables in classical class-based systems) are saved to the function's prototype object. Finally, and here's the magic pixie dust, the function's prototype object is used as the argument which the rest of the code generates the JavaScript class from. John Resig's code behaves the same but the function's prototype object becomes "the class object" instead of being directly passed as the original argument.
Person = Class.extend(Person);
...
Ninja = Person.extend(Ninja);
The extend() calls above take the JavaScript constructor functions and return the new JavaScript class. By assigning the return value to the function (variable), the new JavaScript class replaces the traditional JavaScript object creation function.
With this modification and technique, you can write traditional JavaScript object code and, if you later want to use John Resig's "Simple JavaScript Inheritance", you can add it with ease.
Monday, June 3, 2013
Effective XML by Elliotte Rusty Harold (2004)
I finished reading Effective XML by Elliotte Rusty Harold over the weekend. It's an old book, almost 10 years old, published in 2004. Still, it is interesting and I wanted to summarize the book for myself and anybody else who is interested.
It is divided into 4 parts: Syntax, Structure, Semantics and Implementation. Total, there are 50 suggestions to improving your XML.
Syntax
#1: Include an XML declaration.
Like “<?xml version="1.0" encoding="utf-8" standalone="yes" ?>” for example.#2: Mark up with ASCII if possible.
Don’t use Chinese characters as tag names.#3: Stay with XML 1.0.
XML 1.1 makes several inadvisable things possible, like tag names in obscure, non-alphabetic languages.#4: Use standard entity references.
Prefer named references (e.g. Ě) to character references (e.g. ě). Don’t invent your own names if somebody else already has.#5: Comment DTDs liberally.
DTDs are hard to understand. Use lots of comments so they can be understood.#6: Name elements with camel case.
CamelCase instead of camel-case is easier to map to variables.#7: Parameterize DTDs.
You can build all kinds of flexibility into DTDs using parameters, including conditionals and changing namespaces.#8: Modularize DTDs.
You can split DTDs into multiple files for more flexibility.#9: Distinguish text from markup.
The title isn’t very good but what he’s saying is that, once you delimit XML tags and use them as text, they aren’t accessible to the parser. They are just text.#10: White space matters.
White space, such as newlines and indentation, will be included in a text node when it’s read in. In other cases, like DTDs, it is irrelevant.Structure
#11: Make structure explicit through markup.
Avoid mini-formats where the developer has to parse a text node or attribute value to separate it further. Use tags instead of embedding spaces or commas in text or values.#12: Store metadata in attributes.
The content/text should be the data itself; attributes should give metadata about the data. The content/text should contain what people normally want to see with attributes hiding away less important info.#13: Remember mixed content.
A single sentence isn’t necessarily a single text node. It might be multiple text nodes, separated by child tags enclosing certain fragments. Don’t assume that the XML is flat or expect a rigid schema.#14: Allow all XML syntax.
Don’t invent an XML format or XML parser that forbids XML processing directives, comments or other standard XML features.#15: Build on top of structures, not syntax.
Don’t try to differentiate between things that the XML parser says are the same. Don’t write applications that do something different if it is a named reference vs a character reference. Or do something different if it is an empty element versus an element with the empty string.#16: Prefer URLs to unparsed entities and notations.
DTDs can be used to define unparsed entities and notations but it’s better to avoid them and just stick the value right in the XML itself.#17: Use processing instructions for process-specific content.
XML processing instructions, like “<?xml-stylesheet ?>”, are not returned by parsers as easily but have their uses, especially for data that cuts across parent-child relationships. Use them where appropriate.#18: Include all information in the instance document.
Avoid using DTD and other XML features that modify the XML data from outside, such as default attributes. The XML should contain all the data, even if the parser doesn’t read the DTD or other linked documents.#19: Encode binary data using quoted printable and/or Base64.
Binary data can be encoded and inserted in XML. If you need it, do that.#20: Use namespaces for modularity and flexibility.
Namespaces look like URLs but they are just IDs. Choose and use a namespace for the data. Don’t avoid it just because you don’t understand it or don’t care.#21: Rely on namespace URIs, not prefixes.
Don’t use the “svg:” prefix without setting it to “http://www.w3.org/2000/svg”. Don’t use namespaces without defining the namespace URI.#22: Don’t use namespace prefixes in element content and attribute values.
It is very confusing when XML prefixes are used other places than as a tag name. Instead, require the full namespace URL to be used, maybe as an attribute that modifies the unprefixed tag name. For example, instead of <element xmlns:ex=”…” type=”ex:year”>, do <element type=”year” typens=”…”>.#23: Reuse XHTML for generic narrative content.
Use XHTML to content that is paragraphs of text instead of inventing your own schema or restricting the content to unformatted text.#24: Choose the right schema language for the job.
You have a choice between DTDs and XML Schema. There is also RELAX NG, Schematron or even using Java.#25: Pretend there’s no such thing as the PSVI.
PSVI is XML data annotated with its schema information produced by advanced XML parsers. Some libraries can read the PSVI and produces a memory objects automatically from XML data, like Hibernate does for SQL databases. PSVI is a nice theory but not practical.#26: Version documents, schemas and stylesheets.
Add version numbers to XML and its related documents because it will change over time. You can use dates or major/minor versions. Don’t assume that your data, schemas and stylesheets will never need revision.#27: Mark up according to meaning.
Put XML tags around things according to what they are, not just how they are formatted. For example, italics has several different uses so be more specific with the XML tag.Semantics
#28: Use only what you need.
XML has lots of parts: XML 1.0, well-formedness, DTDs, Namespaces, XPath, Schemas, XLinks (Simple and Extended), XPointers, XInclude, Infoset, PSVI, XML 1.1, Namespaces 1.1, SVG, MathML, RDF, OWL, CSS, XSLT, XSL-FO, XQuery and so on. Use what you need. Don’t feel that you have to understand and use it all.#29: Always user a parser.
Don’t try to write your own XML parser using regular expressions or something. Use an off-the-shelf XML parser.#30: Layer functionality.
Feel free to process XML is whatever order works best for you. Feel free to do validation before and/or after other processing. Creating a processing chain that gets you to your final result.#31: Program to standard APIs.
Write code so it is easy to swap in a new parser.#32: Choose SAX for computer efficiency.
SAX is an event-based, streaming parser. Efficiency isn’t usually needed so you normally don’t need SAX.#33: Choose DOM for standards support.
DOM is a solid standard with lots of implementations. Many developers understand it. It is weird in some places, though.#34: Read the complete DTD.
If standalone is set to “no” in the XML declaration, the DTD is required. Skipping a required DTD may result in parsing errors. Be flexible in accepting XML data by reading DTDs.#35: Navigate with XPath.
Doing “//name” with XPath is easier and less error prone than crawling the DOM tree using getChildNode(). It’s hard to write getChildNode() code that doesn’t rely on tag parent-child relationships, tag order, number of tags and other variations in XML data.#36: Serialize XML with XML.
Don’t convert XML into an opaque binary format for no reason. Leave XML as XML.#37: Validate inside your program with schemas.
Validate XML data using schemas rather than just breaking/crashing. The point of validation is to detect invalid data.Implementation
#38: Write in Unicode.
Use UTF-8. ASCII is a subset of UTF-8. If using Japanese, Chinese or similar languages, use UTF-16. Don’t use obsolete ASCII formats. Do Unicode correctly with normalization and sorting.#39: Parameterize XSLT stylesheets.
Use xsl:variable (like a constant) and xsl:param to make it easy to change fonts, sizes and other stuff in XSLT.#40: Avoid vendor lock-in.
Avoid tools that have binary XML formats, unclear tag names, proprietary XML parsers and proprietary APIs.#41: Hang on to your relational database.
XML does not replace SQL databases but you can use XML with them.#42: Document namespaces with RDDL.
Namespaces are just IDs but people still try to use them as URLs. RDDL is an XML schema for a web page that is posted at a namespace “URL” that can provide resources, natures and purposes (such as DTDs) that might be useful.#43: Preprocess XSLT on the server side.
For speed and consistency, preprocess and cache XSLT transformations on the server side using web server plugins.#44: Serve XML+CSS to the client.
Browser clients can style using XSLT. CSS can be applied conditionally, depending on the display type.#45: Pick the correct MIME media type.
Have your web server serve up application/xml instead of text/xml. Use more official, more accurate mime types, like application/xml+svg, if appropriate.#46: Tidy up your HTML.
Converting HTML to XHTML will uncover bugs which are worth fixing. Do validation and fix any bugs that are found. Really old browsers don’t support some XHTML constructs.#47: Catalog common resources.
XML Catalogs, used with parsers, allow you locally cache remote resources like DTDs and schemas. Instead of getting the file from a remote site, the request is redirected to the local machine.#48: Verify documents with XML digital signatures.
You probably don’t need it but there is a standard for doing digital signatures in XML.#49: Hide confidential data with XML encryption.
You probably don’t need it but there is a standard for doing encryption in XML.#50: Compress if space is a problem.
XML doesn’t waste that much space but, if needed, you can compress it.Tuesday, May 28, 2013
XXHTML
Do you know what XML is? An example of XML is:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<person>
<name type="common">Bob</name>
<name type="scientific">Homo Sapiens</name>
<intelligence>Average</intelligence>
</person>
XML is a standard data format. It looks like HTML but you can make up your own tags and attribute names.
If you put the XML above into a file named bob.xml and load it into a browser like Firefox, you get a nice view into the XML data, laid out in a tree. The browser shows this as a courtesy. It is only useful to the programmer as an informational tool; the tree display isn't used in programs, web sites or end users.
If you rename bob.xml to bob.html and load bob.html into a browser, it might be blank or it might be an unformatted jumble of text.
To display the XML in HTML, you can use XSL.
First, you need to add a reference to the XSL file from the XML file:
<?xml-stylesheet type="text/xsl" href="reader.xsl" ?>
Now, the XML file looks like this:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml-stylesheet type="text/xsl" href="reader.xsl" ?>
<person>
<name type="common">Bob</name>
<name type="scientific">Homo Sapiens</name>
<intelligence>Average</intelligence>
</person>
Next, you need to write a XSL stylesheet. A partial version of the reader.xsl file might look like:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nbsp " ">
]>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:str="http://example.com/namespace" exclude-result-prefixes="str">
<xsl:output method="html" encoding="iso-8859-1" doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"/>
<xsl:template match="/">
<html>
<head>
<title>People</title>
</head>
<body>
<xsl:for-each select="//person">
<span>
...
<xsl:value-of select="text()" />
...
<xsl:choose>
<xsl:when test="position() mod 2 = 1">
...
</span>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Ugh. All that trouble, just to get some simple HTML. Not to mention that ordinary HTML hackers aren't likely to understand your XML and they surely won't understand your XSL. Plus, when you select "View Source" from the menus in a browser, many browsers show only the original XML and don't show the XSL or the final HTML that is shown in a browser.
Why does it have to be so hard? Why can't renaming bob.xml to bob.html just work, at least in some simple way?
I propose a simple standard: XXHTML. This stands for "XML friendly XHTML".
Instead of using custom XML tags, XXHTML use XHTML like this:
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<?xml-stylesheet type="text/xsl" href="reader.xsl" ?>
<html>
<head>
<title>People</title>
<style>
span {
display: block;
}
</head>
<body>
<div class="person">
<span class="name" type="common">Bob</span>
<span class="name" type="scientific">Homo Sapiens</span>
<span class="intelligence">Average</span>
</div>
</body>
</html>
Rather than use custom tags, like person, let's use standard XHTML tags, like span, but encode them such that a standard XHTML property, like class, encapsulates custom XML tag name. We can do that in such a way that it is easy to pick out all the information using XML and XPath in XSL but still have it be normal looking HTML.
By doing this, renaming bob.xml to bob.html is actually useful and makes sense to HTML hackers. But it also provides all the same functionality in XML and XSL.
XXHTML is a win-win.
Subscribe to:
Posts (Atom)