--- ../PATCHS/js-standards-current.txt 2013-03-28 12:28:48.697476272 +0100 +++ ../PATCHS/js-standards.txt 2013-03-28 12:24:42.129478625 +0100 @@ -1,5 +1,43 @@ -

Indenting

-Use an indent of 2 spaces, with no tabs. No trailing whitespace. + + + +

Strict mode

+All scripts should be using the strict mode by adding "use strict"; at the top of the closure. + + +(function ($, Drupal, _) { + + "use strict"; + + // Rest of the code. + +})(jQuery, Drupal, _); + + + +

Variable declaration

+It is not recommended not to mix assignment and no-assignment variables under a single var statement. Additionally, it is preferred to use multiple var statements in combination with new-lines to avoid having variables accidentally leak into the global scope. + + +// confusing +var foo = 'bar', x, y, meh = 'bla'; + +// error-prone +var foo = 'bar', + x, + y, + meh = 'bla'; + +// Recomended +var x, y; +var foo = 'bar'; +var meh = 'bla'; +

String Concatenation

@@ -21,10 +59,13 @@

CamelCasing

-Unlike the variables and functions defined in Drupal's PHP, multi-word variables and functions in JavaScript should be lowerCamelCased. The first letter of each variable or function should be lowercase, while the first letter of subsequent words should be capitalized. There should be no underscores between the words. +Multi-word variables and functions in JavaScript should be lowerCamelCased. The first letter of each variable or function should be lowercase, while the first letter of subsequent words should be capitalized. There should be no underscores between the words. + +Constructors should start with a capital letter. +

Semi-colons

-JavaScript allows any expression to be used as a statement and uses semi-colons to mark the end of a statement. However, it attempts to make this optional with "semi-colon insertion", which can mask some errors and will also cause JS aggregation to fail. All statements should be followed by ; except for the following: +JavaScript allows any expression to be used as a statement and uses semi-colons to mark the end of a statement. However, it attempts to make this optional with "semi-colon insertion", which can mask some errors and will also cause JS aggregation to fail. All statements should be followed by ; except for the following: for, function, if, switch, try, while @@ -46,7 +87,8 @@ In addition the return value expression must start on the same line as the return keyword in order to avoid semi-colon insertion. -If the "Optimize JavaScript files" performance option in Drupal 6 is enabled, and there are missing semi-colons, then the JS aggregation will fail. It is therefore very important that semi-colons are used. +If the "Optimize JavaScript files" performance option in Drupal 6 is enabled, and there are missing semi-colons, then the JS aggregation will fail. It is therefore very important that semi-colons are used. +

Control Structures

These include if, for, while, switch, etc. Here is an example if statement, since it is the most complicated of them: @@ -66,6 +108,7 @@ You are strongly encouraged to always use curly braces even in situations where they are technically optional. Having them increases readability and decreases the likelihood of logic errors being introduced when new lines are added. +

switch

For switch statements: @@ -100,15 +143,17 @@

for in

The for in statement allows for looping through the names of all of the properties of an object. Unfortunately, all of the members which were inherited through the prototype chain will also be included in the loop. This has the disadvantage of serving up method functions when the interest is in data members. To prevent this, the body of every for in statement should be wrapped in an if statement that does filtering. It can select for a particular type or range of values, or it can exclude functions, or it can exclude properties from the prototype. For example: -for (var variable in object) if (filter) { - // Statements... +for (var variable in object) { + if (filter) { + // Statements... + } } You can use the hasOwnProperty method to distinguish the true members of the object (but always put it inside the loop, not on the same line: -for (var variable in object) { - if (object.hasOwnProperty(variable)) +for (var index in object) { + if (object.hasOwnProperty(index)) { // Statements... } } @@ -123,7 +168,7 @@

Functions

-

Function and method names

+

Function and method names

Drupal.behaviors.tableDrag = function (context) { for (var base in Drupal.settings.tableDrag) { @@ -149,15 +194,14 @@ ... }; -function funStuff(field, settings) { +function funStuff (field, settings) { settings = settings || Drupal.settings; alert("This JS file does fun message popups."); return field; } @@ -169,16 +213,12 @@ foobar = foo(bar, baz, quux); -As displayed above, there should be one space on either side of an equals sign used to assign the return value of a function to a variable. In the case of a block of related assignments, more space may be inserted to promote readability: - -short = foo(bar); -longVariable = foo(baz); - +

Variables and Arrays

All variables should be declared with var before they are used and should only be declared once. Doing this makes the program easier to read and makes it easier to detect undeclared variables that may become implied globals. -Variables should not be defined in the global scope; try to define them in a local function scope at all costs. All variables should be declared at the beginning of a function. +Variables should never be defined in the global scope; try to define them in a local function scope at all costs. All variables should be declared at the beginning of a function.

Constants and Global Variables

@@ -193,7 +233,7 @@ This variable would then be referenced: -Drupal.settings.myModule.basePath; +drupalSettings.myModule.basePath; @@ -211,7 +251,7 @@

Comments

Inline documentation for source files should follow the Doxygen formatting conventions. -Non-documentation comments are strongly encouraged. A general rule of thumb is that if you look at a section of code and think "Wow, I don't want to try and describe that", you need to comment it before you forget how it works. Comments can be removed by JS compression utilities later, so they don't negatively impact on the file download size. +Non-documentation comments are strongly encouraged. A general rule of thumb is that if you look at a section of code and think "Wow, I don't want to try and describe that", you need to comment it before you forget how it works. Comments can be removed by JS compression utilities later, so they don't negatively impact on the file download size. Non-documentation comments should use capitalized sentences with punctuation. All caps are used in comments only when referencing constants, e.g., TRUE. Comments should be on a separate line immediately before the code line or block they reference. For example: @@ -226,23 +266,10 @@

"with" statement

-The with statement was intended to provide a shorthand for accessing members in deeply nested objects. For example, it is possible to use the following shorthand (but not recommended) to access foo.bar.foobar.abc, etc: - -with (foo.bar.foobar) { - var abc = true; - var xyz = true; -} - -However it's impossible to know by looking at the above code which abc and xyz will get modified. Does foo.bar.foobar get modified? Or is it the global variables abc and xyz? +Do not use the with statement. -Instead you should use the explicit longer version: - -foo.bar.foobar.abc = true; -foo.bar.foobar.xyz = true; - - -or if you really want to use a shorthand, use the following alternative method: +Instead you should use the explicit version: var o = foo.bar.foobar; o.abc = true; @@ -252,6 +279,8 @@

Operators

True or false comparisons

+Always use strict comparaison using === and !==. + The == and != operators do type coercion before comparing. This is bad because it causes: ' \t\r\n' == 0 to be true. This can mask type errors. When comparing to any of the following values, use the === or !== operators, which do not do type coercion: @@ -301,30 +330,60 @@

Typeof

When using a typeof check, don't use the parenthesis for the typeof. The following is the correct coding standard: -if (typeof myVariable == 'string') { +if (typeof myVariable === 'string') { // ... } -

Modifying the DOM

-When adding new HTML elements to the DOM, don't use document.createElement(). For cross-browser compatibility reasons and also in an effort to reduce file size, you should use the jQuery equivalent. - -Don't: - -this.popup = document.createElement('div'); -this.popup.id = 'autocomplete'; - -Do: - -this.popup = $('
')[0]; -

Drupal 6 (and later) Specific Stuff

Drupal 6 saw the introduction of JavaScript theming and translation of JavaScript files.

Theming

-There is a theming mechanism for JavaScript code. Any modules containing JavaScript which produces HTML content must now provide default theme functions in the Drupal.theme.prototype namespace. +There is a theming mechanism for JavaScript code. Any modules containing JavaScript which produces HTML content must now provide default theme functions in the Drupal.theme namespace.

String Translation

All strings in JavaScript files should be wrapped in Drupal.t() which is an equivalent of the well-known t() function. Likewise, there is also an equivalent to format_plural(), named Drupal.formatPlural(). The parameter order is exactly like their server-side counterparts. + + +

File closure

+All js files should have a closure to avoid adding variables to the global namespace. The parameter of the closure correspond to the dependencies needed for the script to work. If a script declare jQuery, Drupal, drupalSettings and underscore as dependencies in hook_library_info() as so: + + array( + 'myjsfile.js' => array(), + ), + 'dependencies' => array( + array('system', 'jquery'), + array('system', 'drupal'), + array('system', 'drupalSettings'), + array('system', 'underscore'), + // The following dependencies do not declare a global + // object but adds to the jQuery or Drupal object. + // They will not be present in the closure declaration. + array('system', 'jquery.once'), + array('system', 'drupal.ajax'), + ), + ); + + return $libraries; +} +?> + + +Then the js file should contain the following closure declaration: + + +(function ($, Drupal, drupalSettings, _) { + + "use strict"; + + +})(jQuery, Drupal, drupalSettings, _); + + +When this script will be minified it will help replace all the global variables by short names inside the closure. +