.. _dev_closure: ========================================= Javascript Development with Closure Tools ========================================= This is an introductory guide to developing and building Javascript for MediaDrop. Beginning with v0.9, all new javascript development will be based on `Closure Tools` instead of the Mootools framework. Currently we're using two main components of Closure Tools: .. glossary:: Closure Library "The `Closure Library `_ is a broad, well-tested, modular, and cross-browser JavaScript library. You can pull just what you need from a large set of reusable UI widgets and controls, and from lower-level utilities for DOM manipulation, server communication, animation, data structures, unit testing, rich-text editing, and more." Closure Compiler "The `Closure Compiler `_ is a tool for making JavaScript download and run faster. It is a true compiler for JavaScript. Instead of compiling from a source language to machine code, it compiles from JavaScript to better JavaScript. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls." Getting Closure Tools --------------------- First off, you'll need to get Closure Library. Checkout the official SVN repository into your root MediaDrop directory: .. sourcecode:: bash $ cd MediaDrop $ svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library Next, you'll need to `download the latest version of Closure Compiler `_ and extract it into place: .. sourcecode:: bash cd batch-scripts/closure/compiler wget http://closure-compiler.googlecode.com/files/compiler-latest.tar.gz tar -xzvf compiler-latest.tar.gz .. note:: The shell scripts detailed below require the library and compiler to be accessible at these locations. If you'd like to store them elsewhere, you'll have to edit ``mediadrop/config/middleware.py`` and the shell scripts at ``batch-scripts/closure/``. Development Workflow -------------------- Ordinarily all MediaDrop javascript that is loaded is pre-compiled. This is ideal for file size and run-time performance on the client, but as a side effect, it obfuscates the code. This makes it extremely difficult to trace compiled code, so it's important for developers to be able to run the uncompiled source code when necessary. MediaDrop comes with a javascript debug mode built-in. When enabled, all javascript is loaded in its original source form. Simply append ``?debug=true`` to any URL to enable debug mode for that request. It's important to compile your code regularly throughout your development process. The compiler is capable of quickly finding many bugs in your code and it often provides more precise error messages than a browser might. Don't think of it as a white-space remover: it's a very useful tool and you should run it regularly. Compiling your code can sometimes introduce bugs that aren't present in uncompiled code. This is because the compiler imposes certain restrictions on your Javascript. You should familiarize yourself with `the optimizations the compiler makes `_ and their ramifications. Working in Debug Mode --------------------- MediaDrop contains a special debug mode which triggers uncompiled source files be loaded instead of a single pre-compiled and obfuscated file. Enable it by appending ``?debug=true`` to any MediaDrop URL. In debug mode, there are three files that are initially loaded. Any additional files that they depend on are loaded at run time, which we'll explain in more detail below. The initial files are: .. glossary:: ``goog/base.js`` This is the core of Closure Library. Among other things, it defines the dependency management functions ``goog.require()`` and ``goog.provide()``. ``mcore/deps.js`` This file is auto-generated and informs the dependency manager in what files dependencies can be found. This allows the correct script file to be loaded when one of your source files calls ``goog.require('mcore.players.Html5Player');`` (which happens to be mcore/players/html5.js in this example). ``mcore/base.js`` This file contains our actual application code. It exposes the API that you can call from within the page as needed. It can depend on other javascript files which will be loaded at run-time when in debug mode. Additional dependencies are loaded dynamically thanks to these two core functions: .. glossary:: ``goog.provide(string name)`` Indicate that the file which makes this call defines the given name. This does not actually do anything at run time, but is parsed by the build script that generates ``mcore/deps.js``. (It is also parsed by the compiler build script.) ``goog.require(string name)`` Load the file which has indicated it provides the given name. In debug mode this creates a new