H5P Guides

Coding guidelines

General

All code in a single library or code base should look like a single person wrote it. This means that contributors should adhere to the coding standard that exists within a library to keep the code consistent and avoid confusion.

  • Indentation should be 2 spaces, no tabs.
  • No trailing whitespace at the end of the line.
  • Source files should have Unix line endings(\n).
  • All binary and bit operators should be surrounded with whitespaces. Unary operators should not.

Control structures should be formatted like this:

if (foo && bar) {
  foobar();
}
else if (foo || bar) {
  foo(bar);
}
else {
  bar(foo);
}

switch (foo) {
  case 1:
    bar();
    break;

  default:
    foo();
}

Use camelCase. Classes / constructors start with a capital letter.
Use JSDoc style to document functions.

Remember to make it possible to localize all text strings in the GUI.

Filenames and URLs

An obvious filename is a great filename. If a user can look at the file and make an accurate guess about the contents of the file before ever opening it, you've done your job.

When creating filenames with multiple words in the format of a phrase, hyphens are best to separate the terms, e.g. drag-and-drop.js.

JavaScript

General

  • Always declare variables, avoid polluting the global namespace.
  • Var declarations should be at the beginning of their respective function scopes because declarations get hoisted to the top of their scope, but not their assignment.
  • Use the literal syntax for array and object creation. E.g. var item = {}; not var item = new Object();
  • Do not use reserved words as keys. A list of javascript reserved keywords can be found at MDN.
  • Strings should be surrounded by single quotes. Strings longer than 80 characters should be concatenated across multiple lines.
  • Use thoughtful naming and a readable structure.
  • camelCase in functions and variables.
  • PascalCase in constructor and library names.
  • UPPERCASE_NAME in symbolic constants.
  • Create an alias to this using self as an identifier inside scopes.
  • Typechecking should check both typeof and instanceof (typeOf message === "string" || message instanceOf String)
  • Use as few DOM insertions as possible, modifying detached nodes are significantly faster than when they are attached. 
  • Use dot notation when accessing objects.
  • Use /** .... */ for multiline comments, use // for single line comments.

Structure

It might be wise sticking with a well-known design pattern. E.g. Revealing Module Pattern

var MyNamespace = MyNamespace || {};

/**
 * MyNamespace Test Module.
 */
MyNamespace.Test = (function ($) {
  // Cached. Context is shared between instances.
  var totalDevices = 0;

  /**
   * Test Device Constructor
   *
   * @param {String} name
   */
  function TestDevice(name) {
    // Private
    var calls = 0;

    // Keep track of total number of devices on the page
    totalDevices++;

    /**
     * Private. Increase calls.
     */
    var call = function () {
      calls++;
    };

    /**
     * Public.
     *
     * @returns {String}
     */
    this.toString = function () {
      call();
      return 'My name is: ' + name;
    };
  };

  /**
   * Test Constructor
   *
   * @param {Object} parameters
   * @param {Number} id
   */
  function Test(parameters, id) {  // Pro Tip: Naming constructors makes it easier to debug!
    var testDevices = [];

    for (var i = 0; i < parameters.devices.length; i++) {
      testDevices.push(new TestDevice(parameters.devices]));
    }
    
    /**
     * Public. Attach html to the given container.
     *
     * @param {jQuery} $container
     */
    this.attach = function ($container) {
      var html = '';

      for (var i = 0; i < testDevices.length; i++) {
        html += testDevices[i];
      }

      $container.addClass('mynamespce-test').html(html);
    };
  };

  /**
   * Public static.
   */
  Test.getTotalDevices = function () {
    return totalDevices;
  };
  
  return Test;
})(H5P.jQuery);

To learn more about JavaScript Design Patterns check out this book.

Remember to use spacing when creating anonymous functions and put semi-colons after every expression!

Graphics

Try using graphics that scales well on different devices and browsers. Use fonts for icons and SVG for larger images.

Buttons

Try to stick with buttons for actions and anchor tags for links. Any tag can easily be transformed into a button:

<ul class="mynamespace-actions">
  <li role="button" tabindex="1">Copy</li>
  <li role="button" tabindex="1">Paste</li>
</ul> 

Animations

Favor CSS3 animations over using JavaScript.

Modern browsers can leverage the GPU to animate the following styles very well:

  • Position  -  transform: translateX(n) translateY(n) translateZ(n);
  • Scale  - transform: scale(n);
  • Rotation -  transform: rotate(ndeg);
  • Opacity  - opacity: n;

By favouring these solutions over e.g. "left: -1000px;", you will get much smoother animations.

You can read more details about these thechniques in this blog post.