開発:Javaスクリプトガイドライン

移動先: 案内, 検索

Moodle 2.0


作成中です - Mitsuhiro Yoshida 2010年2月2日 (火) 16:13 (UTC)

Javaスクリプトの使用に関して、私たちの新しいAPIに依存するため、このガイドラインは、Moodle 2.0以降のバージョンにのみ、完全に適用されます。

2.0以前のバージョンのMoodleにてJavaスクリプトを書く場合、心の中では、このガイドラインに従ってください。そして、$PAGE->requires->js/yui_lib の代わりに、require_js関数を使用してください。

一般原則

Moodleは、Javaスクリプト抜きで使用できるようにすべき

Moodle内のすべては、Javaスクリプトを無効にしても動作できるようにすべきです。これは、アクセシビリティにとって重要であり、unobtrusive JavaScriptおよびprogressive enhancementの原理に合致します。

埋め込みJavaスクリプトを最小限に抑える

ほとんどすべてのJavaスクリプトコードは、.jsファイルに分離されるべきです。また、HTMLコードページに埋め込むJavaスクリプトの量を可能な限り押さえるべきです。

HTML内の唯一の <script> タグでは、

  1. 必要な.jsファイルをインクルードするため、<script src=... タグを使用すべきです。
  2. インストールを始動するため、シンプルな関数をコールします。例えば: example <script type="text/javascript">initialise_my_widget('some', 'data', 123);</script>
  3. PHPからJavaスクリプトにデータを送信するには、変数を定義します。例えば次のようになります: <script type="text/javascript">var moodle_cfg = {"modpixpath":"http:\/\/tim.moodle.local\/moodle\/mod","sesskey":"ZVNQiq7pHu","developerdebug":true};</script>

あなたは、HTML内で古い形式の onXXX="event_handler" 属性を使用すべきではありません。最新のDOMイベントを使用してください。YUIイベントライブラリにより、DOMイベントの使用か容易になります。

Javaスクリプトライブラリ

  • Moodleの公式なJavaスクリプトライブラリは、YUIです。あなたの好きなライブラリではないかもしれませんが、慎重な調査の上、選択されたライブラリですので、このライブラリを使用してください。
  • Moodleには、独自のJavaスクリプトライブラリコードもあります。通常、lib/javascript-static.jsの中に入っています。
  • Moodleは、HTMLエディタとしてTinyMCEを使用します。

いつ、Javaスクリプトをインクルードするか

Yahoo's best practice guidelinesのように、Javaスクリプトのロードおよび実行は、可能な限り遅くした方が良いでしょう。理想的には、scriptタグは </body> クローズタグの直前に配置します (これは、MoodleのJavaスクリプト処理関数のデフォルトの挙動と同じです)。

Since everything should work without JavaScript, load and initialising your scripts only after everything else on the page has loaded should not be a problem and will increase the perceived page-load performance for users.

Minimise the number of .js files

Try not to use too many different .js files. Each separate file that the browser has to load incurs an overhead.

On the other hand, organise the JavaScript logically to ease maintenance, and don't include large amounts of irrelevant JavaScript code. Code that is loaded but never used is a waste of time.

So, if you are writing a new module that needs its own JavaScript, try starting with with a single file mod/mymod/mymod.js. If you find that you are writing a lot of JavaScript that is only needed when the teacher edits your module, but is not needed by students, then consider splitting that code into a separate file like mod/mymod/edit.js, and only including it where needed.

How to achive these general principles in Moodle

The rest of this page explains how you can achieve the above goals.

Getting Moodle to load your JavaScript files

Everything required by the current page is tracked by the $PAGE->requires object, which is an instance of the page_requirements_manager class. You use it like this:

$PAGE->requires->js('mod/mymod/scripts.js');

By default, this will put the <script> tag that loads the script at the end of the <body> tag, as recommended. If you really must load the script sooner, use one of the following

// Load the js file from head.
// (This will throw an exception if head has already been output.)
$PAGE->requires->js('mod/mymod/scripts.js')->in_head();
 
// Loads the js file as soon as possible (from head, if that has
// not been output yet, otherwise output the script tag right here.)
echo $PAGE->requires->js('mod/mymod/scripts.js')->asap();

$PAGE->requires keeps track of which files have been included, so even if two different pieces of code request the same library, it is only loaded once.

Getting Moodle to load YUI libraries

Because YUI is the official JavaScript library for Moodle, there is a short cut syntax for loading the YUI libraries.

$PAGE->requires->yui_lib('autocomplete');

This knows about the dependencies between the JavaScript libraries, so the above code will actually load the five libraries yahoo, dom, event, datasource and autocomplete. It will also load the required CSS file autocomplete/assets/skins/sam/autocomplete.css.

Because some YUI libraries rely on associated CSS, and because CSS can only be included in the <head> section of the HTML, you should try to call $PAGE->requires->yui_lib before <head> is output, if at all possible. If your code does try to require a YUI library after the header has been printed, and if that YUI library requires some CSS, and exception will be thrown explaining the problem, so you will know it happened.

JavaScript coding style

Moodle JavaScript code should should follow the same coding style as Moodle PHP code, allowing for the differences between PHP and JavaScript.

For example, all the rules on function_names, class_names and variablenames apply. You should document your code with JSDoc comments. Layout your JavaScript expressions and statements like the equivalent PHP ones.

Normally, your .js files should simply define things like functions, classes and variables. When the file is loaded, no JavaScript code should actually be executed that has any effect unless it is the sort of code that can safely be executed once per HTML page. This is so that it plays nicely with the require_once-like behaviour of $PAGE->requires->js.

Try to add as few things as possible to the global JavaScript name-space - use a few objects in the global name-space with properties and methods.

(An extreme example of this practice is the YUI libraries which only add a single YAHOO object to the global scope and put everything inside that. Moodle code does not need to go to that extreme - and do not add Moodle-specific code to the YAHOO namespace!)

Activating your JavaScript

Since your .js files should not actually do anything when they are loaded, you need some way to trigger them into action. Normally the best way to do this is to put a simple inline script in the HTML that just calls an initialisation function. Typically, you want the HTML page you generate to look like this:

<!-- HTML code that will work with JavaScript disabled,
     perhaps with an id="mything" attribute on the main HTML tag. -->
<script type="text/javascript">
    init_my_script('perhaps some data', 'for example', 'mything');
</script>

The best way to generate this initialisation script is to use another feature of $PAGE->requires:

$PAGE->requires->js_function_call('init_my_script',
        array('perhaps some data', 'for example', 'mything'));

Once again, by default the <script> tag will be generated at the end of the HTML, but you can change that with modifiers like ->asap() or ->on_dom_ready() (which uses the YUI onDomReady event). Note that the data passed from PHP to JavaScript is automatically escaped using json_encode, so you can pass arrays, objects, and strings containing special characters without worrying.

Getting more variables from PHP to JavaScript

The arguments you pass to the initialisation function are one way to get specific data from your PHP code to your JavaScript. However, when you need to initialise several things on the page and they all need the same data, there is a better way:

$data = array(
    'value1' => $value1,
    'value2' => $value2,
);
$PAGE->requires->data_for_js('mymod_config', $data);

If you do that, then in JavaScript, mymod_config.value1 will contain the value of the PHP variable $value1.

Getting language strings from PHP to JavaScript

One type of value you frequently need to get from PHP to JavaScript is the translation of some language strings into the current language. Because this is a common requirement, there is a special syntax for this:

$PAGE->requires->string_for_js('tooltip', 'mymod');

If you make this call, then the JavaScript variable mstr.mymod.tooltip will hold the value of get_string('tooltip', 'mymod').

Different in content when JavaScript is on or off

Remember the overriding principals that everything should work with JavaScript off, and we should adopt a Progressive enhancement approach. However, there are valid reasons why sometimes you need different content with JavaScript is on or off. We can break it down into three cases:

Content that should only be visible with JavaScript off

An example of this is the automatic search when you are looking for a user to assign a role to. With JavaScript on, the search automatically starts after a delay. With JavaScript off, we want an explicit Search button visible.

To handle this case, Moodle automatically add a class 'jsenabled' to the body tag using JavaScript. So you just need to add a rule like

body.jsenebled .mywidget .submitbutton {
    display: none;
}

to the stylesheet, and the button will be invisible if JavaScript is enabled.

An alternative strategy is to remove the particular bits of HTML from the page using DOM methods. However, if your JavaScript is only loaded at the end of the page, it may take some time for the extra content to disappear, which leads to a disconcerting flicker in the page.

Yet another approach is the old-fashioned <noscript> tag.

Content that needs to be visible right away when JavaScript is on

An example is the [+] or [-] icon that can be used to expand/collapse each block if JavaScript is on.

We can divide this into two subcases:

Content generated by PHP code

Where the HTML for the JavaScript only widget is generated by PHP, we can make it invisible when JavaScript is off using just CSS:

.mywidget {
    display: none;
}
body.jsenabled .mywidget {
    display: block;
}

However, it could be argued that this approach is not really progressive enhancement.

Content generated by JavaScript code

This is more in keeping with progressive enhancement, and this is the way that the expand/collapse block icon is handled.

We build the icon using DOM methods. The only problem is that as the JavaScript is loaded in the footer, there is a small delay before the icons appear. Since when the icons appear, they do not cause other content on the page to move around, that is OK. Also, this delayed appearance is becoming more common on the web. For example, on http://twitter.com/, some things only appear a moment after the main part of the page has finished loading.

However, it the delayed appearance is really a problem, then the only solution is to embed the JavaScript that generates the extra content in the middle of the HTML, using $PAGE->requires->js_function_call(...)->now();.

Content that only appears when the user does something, when JavaScript is on

An example of this is something like file picker dialog that appears when you add an image to some content in the HTML editor, or the one that pops up when you click 'Add new question' in the quiz editing interface.

We have the same two sub-cases:

Content generated by PHP code

In this case, you need to make sure the content is always covered by a display: none; rule in the CSS, but then when the user takes an action like clicking a button to reveal the extra content, you need to override that class name some how, perhaps my adding or removing a className using JavaScript.

Content generated by JavaScript code

In this case, there is no problem. When the use triggers the extra content to appear, it is constructed using DOM methods. There may be a tiny delay, but the chances are that it will hardly be noticeable to the human eye.

In the content generation may be slow (perhaps because it is waiting for an Ajax request) then you should display a progress icon. See, for example, the loading of the tooltip for help icons.

Don't break XHTML strict!

Remember that all Moodle output must be XHTML strict, and that means that the HTML output must be well-formed XML. Inline JavaScript is a great way to break that. (JavaScript uses the < and & symbols that must be escaped in XML.) Therefore any JavaScript inline in the HTML should be escaped in a CDATA section:

<script type="text/javascript">
//<![CDATA[
 
   // Your JavaScript code goes here.
 
//]]>
</script>

Of course, if you are following the above guidelines and putting most of your JavaScript in separate .js files, and using $PAGE->requiers->js_function_call/string_for_js/data_for_js for the rest, then you do not need to worry about this section.

Testing

JavaScript support varies a lot between browsers. JavaScript needs to be tested in IE, Firefox and Safari. Ideally, Moodle will support all the browsers that YUI does.

関連情報