https://docs.moodle.org/dev/api.php?action=feedcontributions&user=Danowar&feedformat=atomMoodleDocs - User contributions [en]2024-03-29T08:37:18ZUser contributionsMediaWiki 1.39.6https://docs.moodle.org/dev/index.php?title=Talk:Main_Page&diff=61337Talk:Main Page2021-09-16T11:59:49Z<p>Danowar: </p>
<hr />
<div>'''Note: This is not the place to ask questions. If you have a development related question, ask it in the [https://moodle.org/mod/forum/view.php?id=55 General Developer forum].'''<br />
<br />
== Broken link in accessibility section ==<br />
<br />
Please note that on the following page: https://docs.moodle.org/dev/Accessibility the link to the British standard is broken: http://www.southampton.ac.uk/web4all/standards/BS_16steps/<br />
<br />
===Previously broken link in accessibility section fixed===<br />
Please note that the page at https://docs.moodle.org/dev/Accessibility now correctly links to https://www.access8878.co.uk/getting-started-with-bs-8878/16-steps.aspx [[User:German Valero|German Valero]] ([[User talk:German Valero|talk]])<br />
<br />
== Missing (?) link to PHPStorm in "Developer Tools" category ==<br />
I don't know what's the condition to appear on the main dev page, but as I'm using IntelliJ/PHPStorm I noticed it's article was missing there [[Setting_up_PhpStorm]]<br />
<br />
And more importantly the link to VSCode is missing https://docs.moodle.org/dev/Setting_up_VSCode</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Making_changes_show_up_during_development&diff=61336Making changes show up during development2021-09-16T11:25:05Z<p>Danowar: Added an overview table, talked about opcache, added something about ES modules, threw CSS + SCSS + LESS together, categorized possible actions in "GUI", "developer way" or "file system", added Events section (no caching detected)</p>
<hr />
<div>Sometime, when you are trying to do Moodle development, you edit the code, and nothing seems to change as a result. This is because, to improve performance, Moodle now has all sorts of caching built in. When this is happening, this page will try to give you the quickest way to make your changes show up in all situation.<br />
== General advice ==<br />
# In your development site, change most of the admin settings like 'Cache language strings', 'Cache JavaScript' to be suitable for development. Note that doing this will slow down your development site a bit.<br />
# If in doubt, visit <nowiki>http://your.domain/moodle</nowiki>'''/admin''' to check that the Moodle install is up-to-date.<br />
# And then <nowiki>http://your.domain/moodle</nowiki>'''/admin/purgecaches.php''' and click the 'Purge all caches' button. This will slow things down for the next few requests, until the caches have re-populated. Note there is also a CLI tool to purge caches.<br />
# Depending on what you changed in your plugin, then in addition to the above, you may need to remember to increase the version number in the plugin's version.php, or the changes will not show up.<br />
# You may have forgotten to run grunt.<br />
# If you have just added a new Behat or PHPunit test, you may need to re-run admin/tool/.../cli/init.php<br />
The above steps are a brute force approach. They will probably work, but are probably not the fastest way. <br />
<br />
Here's a quick overview about what changes need which actions to be followed with. Below, we list for all the various type of change you can make, the most efficient way to make the change show up.<br />
<br />
Keep in mind that once you're done developing your plugin, you should '''always''' bump the version number.<br />
{| class="wikitable"<br />
|+<br />
!Changed<br />
!Delete specific cache<br />
!Purge all caches<br />
!Bump plugin version<br />
!Other<br />
|-<br />
|PHP<br />
|opcache, if enabled<br />
| -<br />
| -<br />
|<br />
|-<br />
|Autoloaded classes<br />
|x<br />
| -<br />
| -<br />
|<br />
|-<br />
|JavaScript<br />
|x<br />
| -<br />
| -<br />
|<br />
|-<br />
|CSS, SCSS, LESS<br />
|x<br />
| -<br />
| -<br />
|<br />
|-<br />
|Language strings<br />
|x<br />
| -<br />
| -<br />
|<br />
|-<br />
|Capabilities<br />
| -<br />
| -<br />
|x<br />
|<br />
|-<br />
|Events<br />
|?<br />
|?<br />
|?<br />
|<br />
|-<br />
|Scheduled tasks<br />
| -<br />
| -<br />
|x<br />
|<br />
|-<br />
|Web services<br />
|?<br />
|?<br />
|?<br />
|<br />
|-<br />
|Database structure<br />
| -<br />
| -<br />
|x<br />
|<br />
|-<br />
|Behat<br />
| -<br />
| -<br />
| -<br />
|see below<br />
|}<br />
<br />
== PHP ==<br />
After changing the PHP files (*.php), you should just need to press reload (F5) in your browser.<br />
<br />
If you somehow have opcache enabled on your server, you may have to delete it depending on your settings.<br />
=== Adding or removing an autoloaded class ===<br />
If you get class-not-found errors, you need to either do any of these:<br />
<br />
* GUI: visit <nowiki>http://your.domain/moodle</nowiki>'''/admin'''<br />
* File system: Delete the file '''core_component.php''' in the moodledata cache directory.<br />
<br />
== JavaScript ==<br />
<br />
=== AMD Modules ===<br />
While changing older [[Javascript Modules|AMD Javascript Module]] source files (amd/src/*.js), if you have Administration -> Appearance -> AJAX and Javascript -> Cache Javascript turned off, then you should just need to reload (F5) in your browser. If JS caching is on, you need to re-run grunt, because Moodle will always prefer to load the minified modules then.<br />
<br />
=== ES Modules ===<br />
If you're using the newer ES module syntax, you always have to re-run grunt or have it running in watch mode, as the normal js files need to be transpiled by grunt (using babel) to be usable.<br />
<br />
== CSS, SCSS, LESS ==<br />
After changing the CSS styles (*.css, *.scss, *.less) you may either:<br />
<br />
* GUI: Purge all caches via '''/admin/purgecaches.php'''<br />
* "developer way": Write a mini script that calls '''theme_reset_all_caches()'''<br />
<br />
== Language strings ==<br />
After changing language pack strings (lang/en/type_plugin.php), you may either:<br />
* Prevention: The best option is to turn off Admin -> Language -> Language settings -> Cache all language strings when doing development. Then you only need to press F5 to refresh to see your changes.<br />
* GUI: Otherwise you need to Purge all caches (or just the Language strings cache) before reloading.<br />
* "developer_way": Write a mini script that calls '''get_string_manager()->reset_caches()'''<br />
== Capabilities ==<br />
After changing capabilities (db/access.php) you need to<br />
# Bump the plugin version number.<br />
# Go to admin -> Notifications.<br />
Then check that the capabilities show up on Site administration > Users > Permissions > Define roles for any role.<br />
<br />
== Events ==<br />
After changing event listeners (db/events.php) you don't seem to need to do anything. Event listeners don't seem to be cached in any way.<br />
<br />
== Scheduled tasks ==<br />
After changing scheduled tasks (db/tasks.php) you need to<br />
# Bump the plugin version number.<br />
# Go to admin -> Notifications.<br />
Then check that the task shows up on Admin -> Server -> Scheduled tasks.<br />
== Web services ==<br />
After changing web services (db/services.php) ...<br />
== Database structure ==<br />
After changing the database scheme (db/install.xml, db/upgrade.php) ...<br />
== PHPunit ==<br />
== Behat ==<br />
After you add a new *.feature file, you need to re-run<br />
$ php admin/tool/behat/cli/init.php<br />
== Mobile support for plugins ==<br />
If you are doing the kind of development described in [[Mobile support for plugins]], using a pre-built version of the app like https://mobileapp.moodledemo.net/.<br />
<br />
Note, these steps were originally written by people mostly on question type plugins. Hopefully they are generally applicable, but if they don't make sense in your case, that might be why. Please edit to improve them.<br />
=== General note ===<br />
If there are lots of red error messages appearing in the JavaScript console (but not the very common error 'ERROR Error: Uncaught (in promise): null...' that repeats every minute and fills the console logs!) it is often necessary to clear site data and restart.<br />
# In browser developer tools, go to Application -> Clear storage.<br />
# Close the browser, and re-launch.<br />
===Adding mobile support to a plugin for the first time===<br />
# Bump the plugin version number.<br />
# Go to admin -> Notifications.<br />
# F5 in the app to restart.<br />
=== HTML template ===<br />
After changing an existing template (mobile/*.html), just pull down in the app to refresh.<br />
=== Client-side JavaScript ===<br />
After changing an existing client-side JavaScript (mobile/*.js), press F5 in the browser developer tools to restart the app.<br />
=== Server-side classes/output/mobile.php ===<br />
???<br />
=== Mobile CSS ===<br />
# Bump version number in db/mobile.php<br />
# Purge caches (specifically the tool_mobile/plugininfo MUC cache)<br />
# Press F5 to restart the app.</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Talk:Main_Page&diff=61334Talk:Main Page2021-09-16T10:30:38Z<p>Danowar: </p>
<hr />
<div>'''Note: This is not the place to ask questions. If you have a development related question, ask it in the [https://moodle.org/mod/forum/view.php?id=55 General Developer forum].'''<br />
<br />
== Broken link in accessibility section ==<br />
<br />
Please note that on the following page: https://docs.moodle.org/dev/Accessibility the link to the British standard is broken: http://www.southampton.ac.uk/web4all/standards/BS_16steps/<br />
<br />
===Previously broken link in accessibility section fixed===<br />
Please note that the page at https://docs.moodle.org/dev/Accessibility now correctly links to https://www.access8878.co.uk/getting-started-with-bs-8878/16-steps.aspx [[User:German Valero|German Valero]] ([[User talk:German Valero|talk]])<br />
<br />
===Missing (?) link to PHPStorm in "Developer Tools" category ===<br />
I don't know what's the condition to appear on the main dev page, but as I'm using IntelliJ/PHPStorm I noticed it's article was missing there [[Setting_up_PhpStorm]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Plugin_contribution&diff=58948Plugin contribution2021-06-07T14:40:54Z<p>Danowar: Small typo</p>
<hr />
<div>{{Plugins development}}<br />
<br />
This page describes how to contribute your code into the [[Plugins directory]] to share it with the Moodle community.<br />
<br />
== Why ==<br />
<br />
You are encouraged to share your plugin with the community. But firstly, to be clear and honest, you do not necessarily need to submit your plugin into the Plugins directory. Maybe it is a custom plugin that solves one particular site's needs and you do not really want to share it with others. Remember you can always simply host your plugin on your own site and let users download it manually from there.<br />
<br />
Having your plugin registered with the Plugins directory has several benefits.<br />
<br />
* Your plugin is easier to install. Plugins directory integrates with Moodle. Administrators can simply install your plugin from the plugins directory via the web interface.<br />
* Your plugin is easier to update. Whenever you release a new version of your plugin, all administrators having it installed are notified about the available update. They can easily upgrade to the new version from within the Moodle administration UI.<br />
* You reserve the component name ([[Frankenstyle|frankenstyle]]) of your plugin. Plugins directory is the official register of Moodle plugins. As with the internet domain names, there can't be two plugins having the same component name.<br />
* The plugin can be localised. Plugins in the Plugins directory are implicitly registered with [[AMOS]] and can be localised using the same tools that are used for localising the standard Moodle UI.<br />
* The plugin must be approved. Many institutions respect the approval review procedure and do not allow to install a plugin on their servers unless it has been approved in the plugins directory.<br />
<br />
== Before you start ==<br />
<br />
Before submitting your work to the Plugins directory, you should make sure you have all required and recommended resources available.<br />
<br />
* '''Plugin type''' - Different [[Plugin types|plugin types]] are best suited for certain types of functionality. It is important to choose the appropriate plugin type to implement the desired features.<br />
* '''Plugin name''' - See the [[Frankenstyle]] page for details.<br />
* '''Repository''' - You are expected to have the plugin code published and shared in a way that facilitates collaboration on further development. Ideally, you have the code available in a public Git repository. Most developers found [https://github.com Github] a good place to host their code on. The [[#Repository]] section below provides more details.<br />
* '''Tracker''' - You are expected to have a system where users can report issues, bugs and feature requests for the plugin. Again, many developers use [https://guides.github.com/features/issues/ Github issues] happily these days. You can also use the Moodle tracker if you prefer. See [[#Tracker]] section for more details.<br />
* '''Documentation''' - The plugin should have a good documentation available. See [[Plugin documentation]] for options.<br />
* '''Screenshots''' - Prepare good screenshots that illustrate your plugin's essential features.<br />
<br />
== Sharing code in the Plugins directory ==<br />
<br />
So you have written a new plugin and want to share it now in the [[Plugins directory]]? Great! Shortly, the workflow of publishing and maintaining your plugin in the Plugins directory looks like this:<br />
<br />
<div class="container"><br />
[[Image:plugin-contribution-workflow.png|640px]]<br />
<br />
''Workflow of contributing a plugin into the Moodle plugins directory ([[Media:plugin-contribution-workflow.svg|SVG version]])''<br />
</div><br />
<br />
# You upload the initial plugin version for approval. To help the approval review go smoothly, please feel encouraged to review the [[Plugin contribution checklist]] and follow all the guidelines there.<br />
# After you submit the plugin for approval, please brace yourself with patience. You will likely wait some weeks before you get initial review results. We generally try and provide the feedback sooner, but it is not always possible. The actual approval queue stats [https://moodle.org/plugins/queue.php are available].<br />
# The plugin goes through the validation and approval process.<br />
# Almost all plugins are sent back as "needing more work" as a result of the initial review, and there is no reason to feel bad about that. It is natural part of the workflow. You may find particular issues reported so you have an opportunity to demonstrate your ability to co-operate with the reporter to resolve them.<br />
# Once the plugin is approved, its strings are registered with [[AMOS]] and can be translated. The plugin itself should ship with English strings only. The page [[Translating plugins]] has more details.<br />
# We do not automatically pull from Github. You have to explicitly release new version via the Plugins directory. Still you are encouraged to use Git tags - releasing new version is easier then.<br />
<br />
=== Repository ===<br />
<br />
* Git is de-facto standard source code management system for Moodle plugins.<br />
* You are supposed to publish and share your plugin code so that others can clone it easily and eventually contribute patches for it easily.<br />
* [https://github.com/ Github] is a popular choice of many Moodle developers these days.<br />
* The layout should be that the root of the repository is the root of the plugin folder. In other words, in the root of your repository there should be files like version.php and folders like lang or classes. That way, your plugin can be directly cloned (checked out) into existing Moodle installation without conflicting with other contributed plugins of the same type, also obtained via Git.<br />
* It is suggested to follow the common naming convention of Moodle related repositories: moodle-{plugintype}_{pluginname}. For example, the birthday block has a repository name of moodle-block_birthday and is located at https://github.com/arborrow/moodle-block_birthday. Other developers can fork the code and work from their repositories.<br />
<br />
=== Tracker ===<br />
<br />
You are expected to have a system where users can report feature requests, bugs, and other code issues. Following the open source best practise, these reports should be open and public and the associated procedures should be as transparent as possible.<br />
<br />
There are multiple options on where to host the issues tracker. Most plugin developers today prefer to have the issue tracker close to their source code management system - so they use the native issue tracker built into Github, BitBucket or some similar system. It is suggested to use a system that your users are likely to be familiar with.<br />
<br />
==Tutorial==<br />
There is a [[Tutorial]] to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way. <br />
<br />
==See also==<br />
<br />
* [[Moodle icons]]<br />
* [[Overview]] of Moodle development<br />
* Using Moodle [http://moodle.org/mod/forum/discuss.php?d=99037 Best practices for code modification?] forum discussion<br />
* [http://aosabook.org/en/moodle.html Moodle] in The Architecture of Open Source Applications, by Tim Hunt - an overview of all aspects of how Moodle works, it focuses on those areas where Moodle's design is particularly interesting.<br />
* [http://www.examulator.com/er/ The Moodle 3.0 database schema] reverse engineered and [[Database schema introduction]].<br />
* [https://moodle.org/mod/forum/discuss.php?d=322196 Preparing plugins for Moodle 3.0] excellent summary in this forum thread. Also applies for Moodle 3.1 and newer.<br />
<br />
[[Category:Guidelines for contributors]]<br />
[[Category:Plugins]]<br />
[[Category:Plugin documentation]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Environment_checking&diff=52732Environment checking2017-07-18T13:53:29Z<p>Danowar: /* Feedback messages */</p>
<hr />
<div>When you install or upgrade Moodle, before the install actually changes anything, it takes you to the /admin/environment.php page, to check that various aspects of your server meets the minimum requirement. For example, it checks PHP version, database version, various PHP extensions, and so on.<br />
<br />
The code to actually do the checking is in lib/environmentlib.php. The main entry point is the check_moodle_environment function, which runs the appropriate check using environment_check, then displays the results using print_moodle_environment.<br />
<br />
==Configuration file overview==<br />
<br />
The process is controlled by the the /admin/environment.xml file, which looks roughly like this:<br />
<br />
<code xml><br />
<?xml version="1.0" encoding="UTF-8" ?><br />
<COMPATIBILITY_MATRIX><br />
<MOODLE version="3.0"><br />
<!-- Various conditions --><br />
</MOODLE><br />
<MOODLE version="3.1"><br />
<!-- Various conditions --><br />
</MOODLE><br />
<!-- etc. --><br />
</COMPATIBILITY_MATRIX><br />
</code><br />
<br />
The 'Various conditions' that can be tested are described below.<br />
<br />
{{Moodle 2.8}}<br />
Note that, since Moodle 2.6.5, 2.7.2 and 2.8 it's possible, for additional plugins, never for core, to have their '''own environment.xml files''' (under own root directory) where any other environment check can be added, following the same rules than the main /admin/environment.xml one (see MDL-39840 for more details).<br />
<br />
{{Moodle 2.9}}<br />
Also, since Moodle 2.9, within additional plugins environment.xml files, it's possible to replace the <MOODLE version="x.y"> element by a simpler <PLUGIN name="frankenstyle_name"> that will be applied '''for all the versions''' of the plugin. The use of this new tag gets precedence over any <MOODLE> tag so usually you must decide between the '''versioned or un-versioned''' alternatives (see MDL-48177 for more details).<br />
<br />
==Things that apply to all tests==<br />
<br />
===Required or optional===<br />
<br />
The element in the XML file that define the conditions each need to have a '''level="..."''' attribute, with value '''required''' or '''optional'''. This is read by the get_level function in lib/environmentlib.php.<br />
<br />
===Feedback messages===<br />
<br />
Inside any of the conditions elements, you can specify a feedback string<br />
<br />
<pre><br />
<FEEDBACK><br />
<ON_ERROR message="failmessage" /><br />
<ON_OK message="passmessage" /><br />
</FEEDBACK><br />
</pre><br />
<br />
If level="required" it must be <ON_ERROR>, but if level="optional", you have to use <ON_CHECK>. I don't know why. The whole <FEEDBACK> element is optional, as are any or all of the <ON_ERROR>, <ON_CHECK> or <ON_OK> elements. Any messages you provide will be displayed, if appropriate, otherwise not.<br />
<br />
In plugins, the message can be taken from lang/admin.php or from the plugin itself.<br />
Example:<br />
<pre><br />
<FEEDBACK><br />
<ON_ERROR message="failmessage" plugin="plugintype_plugin_name_where_string_is_defined"/><br />
</FEEDBACK><br />
</pre><br />
<br />
The message is looked up using get_string($stringtouse, 'admin', $rec), where $rec holds a bunch of information. This is done in the print_moodle_environment function in lib/environmentlib.php.<br />
<br />
===Bypassing and restricting===<br />
<br />
Both bypassing and restricting are two methods to '''change''' the result of one test. They are used to introduce some exception mechanism to some simple '''version checking''' tests like the '''DATABASE''' or '''PHP''' explained below.<br />
<br />
For example, for Moodle 1.8, min required PHP version is 4.3.0, so any 5.x version should be enough. But we have found that PHP versions 5.0.x have some unsolved problems preventing Moodle to run properly. So one mechanism to '''RESTRICT''' the official (relaxed) 4.3.0 requirement is needed. (you can read more about this at [http://tracker.moodle.org/browse/MDL-5653 MDL-5653]).<br />
<br />
Exactly the opposite happens with the '''BYPASS''' mechanism, that can be used to relax some stronger requirement.<br />
<br />
Note that both these features '''should be used in core-core exclusively''' and only to introduce exceptions to '''version checking''' tests whenever we found some important problem with any '''DATABASE''' or '''PHP''' version as explained above.<br />
<br />
So, any non-core-core plugin shouldn't use this at all. Use the new '''Custom checks''' explained below instead.<br />
<br />
==Types of test==<br />
<br />
===Database type and version===<br />
<br />
For example<br />
<br />
<pre><br />
<DATABASE level="required"><br />
<VENDOR name="mysql" version="3.23" /><br />
<VENDOR name="postgres" version="7.4" /><br />
</DATABASE><br />
</pre><br />
<br />
===PHP version===<br />
<br />
For example<br />
<br />
<pre><br />
<PHP version="4.3.0" level="required" /><br />
</pre><br />
<br />
===PHP extensions===<br />
<br />
For example<br />
<br />
<pre><br />
<PHP_EXTENSIONS><br />
<PHP_EXTENSION name="iconv" level="optional"><br />
<FEEDBACK><br />
<ON_CHECK message="iconvrecommended" /><br />
</FEEDBACK><br />
</PHP_EXTENSION><br />
<!-- etc. --><br />
</PHP_EXTENSIONS><br />
</pre><br />
<br />
===Unicode===<br />
<br />
This checks that the database is set to use the Unicode character encoding.<br />
<br />
<pre><br />
<UNICODE level="optional"><br />
<FEEDBACK><br />
<ON_CHECK message="unicoderecommended" /><br />
</FEEDBACK><br />
</UNICODE><br />
</pre><br />
<br />
=== Custom checks === <br />
{{Moodle 1.9}}<br />
<br />
This runs a custom PHP function that returns true or false.<br />
<br />
<pre><br />
<CUSTOM_CHECKS><br />
<CUSTOM_CHECK file="question/environmentchecks.php" function="question_check_norqpquestions" level="optional"><br />
<FEEDBACK><br />
<ON_CHECK message="rqpdeprecatedmessage" /><br />
</FEEDBACK><br />
</CUSTOM_CHECK><br />
<!-- etc. --><br />
</CUSTOM_CHECKS><br />
</pre><br />
<br />
This will cause the "$CFG->dirroot/question/environmentchecks.php" to be included, and question_check_something($result) to be called. This should update the $result object (probably by calling $result->setStatus([true/false])) are return it. Alternatively, it may return NULL if the check is not relevant on this server. For example if it is only relevant if some plugin is installed.<br />
<br />
I propose these naming conventions:<br />
* If you need environment checks, <br />
** <strike>if your code has a db/upgrade.php file, you should put your check function in there.</strike><br />
** <strike>otherwise create an environmentchecks.php to hold any checks.</strike><br />
** ''proposed alternative:'' create an environmentchecks.php to hold any checks for your plugin ([[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 13:16, 27 April 2007 (CDT)This is proposed in order to avoid get confused with the xxx/db/upgrade.php file that is present inside each plugin).<br />
* Functions in that file are given names like mymodule_check_something, where the something explains briefly what is being checked. ([[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] 13:16, 27 April 2007 (CDT)I would propose to test that function name contains "_check_" in order to avoid arbitrary code execution with a hacked xml file).<br />
<br />
<br />
'''Note''': please do not abuse custom checks when you are doing something that should actually be implemented as a new type of check in environment lib. It's highly recommended to comment about your new custom check at [http://moodle.org/mod/forum/view.php?id=55 General Developer Forum] '''before''' implementing it.</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Process&diff=52559Process2017-06-08T11:50:27Z<p>Danowar: Minor fixes to list</p>
<hr />
<div>This document summarises the various development processes used in developing Moodle. There are four main processes that overlap.<br />
<br />
==Integration workflow in the tracker==<br />
<br />
The Moodle tracker keeps track of the status of all bug fixes and new features. <br />
<br />
We use a workflow that ensures that new code receives multiple reviews by different people before it is included into the core Moodle code.<br />
<br />
[[Image:Workflow.jpg]]<br />
<br />
A number of roles make this work:<br />
<br />
===Users===<br />
<br />
Users report bugs and make feature requests directly in the tracker, by creating new issues with a summary and a description.<br />
<br />
===Developers===<br />
<br />
Developers work on the issues in the tracker to specify solutions and write code that implements these solutions. They will often ask other developers to "peer review" their code in the early stages to avoid problems later on.<br />
<br />
While many of the developers work for Moodle.com, a large number are part of the global development community around Moodle. If you're interested in becoming a recognised developer, see [[Tracker_guide#Tracker_groups_and_permissions|Tracker groups and permissions]].<br />
<br />
===CiBoT===<br />
<br />
CiBoT is not a person but a bot who monitors the tracker and performs the [[Automated code review]] when issue is submitted for Peer review or when developer added ''cime'' label.<br />
<br />
===Component leads===<br />
<br />
[http://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Acomponents-panel Component leads] are developers with some responsibility for particular components (plugins or modules) in Moodle. They have authority to decide that a particular fix is suitable and complete enough to be considered for integration in Moodle core and should be called upon to complete peer reviews for code in their components.<br />
<br />
===Integrators===<br />
<br />
On Monday and Tuesday of each week, the integration team (a small team of senior developers employed by Moodle HQ) conducts a code-level review of all issues in the integration queue. This is often called the "pull" process. If the fix is judged appropriate they will integrate the code into our git integration repository for further testing and it gets added to the testing queue.<br />
<br />
If they find problems they reject the issue and send it back to the developer for further work.<br />
<br />
===Testers===<br />
<br />
On Wednesday each week, testers look at all the issues in the testing queue, trying each fix and feature to make sure that it does actually fix the problem it was supposed to, and that there are no regressions.<br />
<br />
If they find problems they reject the issue and integrators may remove it from the integration repository and push it back to the developer for further work.<br />
<br />
See [[Testing of integrated issues]] for more details.<br />
<br />
===Production maintainers===<br />
<br />
On Thursday each week, production maintainers merge all the issues that passed testing into the git production repository, and it becomes available for use on production systems via git and download packages.<br />
<br />
==Stable maintenance cycles==<br />
<br />
Moodle releases regular updates of the stable version of the software to fix bugs and other issues. Releases like 2.2.1, 2.2.2, 2.2.3 etc only include fixes based on the latest major release (2.2) and never any significant new features or database changes.<br />
<br />
At Moodle HQ there are teams of developers using the [http://www.scrum.org/ Scrum framework] to work on these issues (as well as new features for [[#Major_release_cycles|major releases]]). <br />
<br />
===Minor release (point release) timing===<br />
<br />
After [[#Major_release_cycles|major releases]] there will be minor releases.<br />
* x.x.1 will occur approximately two months after each major release (eg. 2.x).<br />
* There will then be another point release every two months after that.<br />
<br />
See the [[Releases#General_release_calendar|General release calendar]] for details.<br />
<br />
===Issue triage===<br />
<br />
[[Bug_triage|Issue triage]] involves evaluating new issues, making sure that they are recorded correctly. One of the most important jobs triagers do is to identify issues that should be fixed in the stable branch. These are set with a priority ranging from "Trivial" up to "Blocker" and other features are checked.<br />
<br />
At Moodle HQ there are currently teams working on stable issues (mostly bugs reported by users) and improvements and new features (Partners, Moodle Association, user suggestions and Martin Dougiamas).<br />
<br />
===Scrum===<br />
<br />
At Moodle HQ, every three weeks, the stable team takes a number of the most urgent issues from the backlog to work on during a period known as a ''sprint''.<br />
<br />
At the start of a sprint there is a period of planning and estimation. All issues on the backlog are given a relative rank that is based on issue features including priority, security, Partner interest, patches and votes. Issues are given a relative size in Story Points and these points are summed to allow the teams to determine how many issues they can work on in the sprint.<br />
<br />
During the sprint, the team meets daily to discuss solutions and progress, as well as to organise testing and peer reviews of code. The team has a ''Scrum master'' to help everyone stay organised, to "unblock" any barriers to progress and to protect the team from distracting influences (mostly people attempting to add to the developers' workloads) during the sprint. The teams' work is documented publicly in the tracker.<br />
<br />
Whenever a solution for an issue is finished, it is submitted into to the standard integration workflow process described above.<br />
<br />
==Major release cycles==<br />
<br />
Since Moodle 2.0, we have a policy of release major versions (eg 2.1, 2.2) every six months in May and November. See the [[Releases#General_release_calendar|General release calendar]] for more details.<br />
<br />
Each release can be different, but generally the cycles work as follows.<br />
<br />
===Define roadmap===<br />
<br />
The product owner (Martin Dougiamas) defines the likely roadmap based on community wishes, third-party developments and important issues within the existing code. <br />
<br />
Sometimes new features might be based on earlier features, sometimes they may be something developed by a third party that needs to be evaluated and sometimes it might be something completely new.<br />
<br />
===Planning and development===<br />
<br />
The UX team, employed at Moodle HQ, work on specifications of major new features throughout the cycle, specifying project ahead of development time.<br />
<br />
New features are worked on by the "Dev" team. The process of [[#New_feature_development|new feature development]] is described below. When specifications are in place, new code is developed during sprints and goes through the standard weekly integration workflow described above.<br />
<br />
===Testing===<br />
<br />
During development, as new code is integrated, automated testing conducted at the [[PHPUnit|code]] and [[Acceptance_testing|interface]] levels, to make sure there are no regressions caused by new features.<br />
<br />
In the last month before the release, a feature freeze is called (no new features can be added) and our QA team performs manual functional testing of Moodle features. The current list of functional tests is listed in the tracker in the [http://tracker.moodle.org/browse/MDLQA-1 MDLQA project]. This list of tests is extended as new features are added, but it is also being reduced as more automated [[Acceptance_testing|acceptance tests]] are developed.<br />
<br />
For more details, see [[Testing]].<br />
<br />
===Sprints===<br />
<br />
At Moodle HQ, development takes place in sprints. The sprints are three-week periods during which developers to focus on a fixed list of issues. Sprints are arranged within each release cycle as shown in the diagram below.<br />
<br />
===Events during cycle===<br />
<br />
During each cycle there are a periods and events that occur between and around sprints.<br />
<br />
[[Image:Dev sprint calendar.png|800px]]<br />
<br />
; '''Planning and bug fixing'''<br />
: A period during which the Roadmap is explored, specs are written and prototypes are created. Regressions in the recent release are fixed as they arise.<br />
; '''End sync period'''<br />
: During the [[Integration Review#On-sync period|on-sync period]], the recent release and master versions are kept synchronised. No new code is added during this period, which ensures regressions are fixed rapidly. This also allows for planning and provides relief for developers after a release.<br />
; '''Personal projects'''<br />
: Affecting full-time HQ developers only, this period allows for individual creations to be explored and provides a break from sprints.<br />
; '''Code freeze'''<br />
: A point after which no new code (only fixes to existing code) is accepted until beyond the release. This stabilisation allows for QA testing.<br />
; '''QA, bug fixing, continuous integration'''<br />
: A period after the code freeze where quality assurance testing takes place. No new code is added, which means developers are able to respond rapidly to bugs found. Integration becomes [[Integration Review#During continuous integration/Freeze/QA period|continuous]], meaning that failed QA tests can be re-run within days rather than having to wait for the weekly release.<br />
; '''Release candidate'''<br />
: A point prior to the full release where a candidate is made public for wider testing.<br />
<br />
==New feature development==<br />
<br />
Major new features in Moodle usually should go through the following process.<br />
<br />
===Specification===<br />
<br />
The User Experience (UX) team should create detailed wireframes and features and goals for the new feature. It should be agreed upon and as final as possible before development starts.<br />
<br />
Developers should create a detailed spec (here in the developer docs) outlining their goals for the development and their design for meeting those goals. The more detail the better.<br />
<br />
Developers should also create an issue in the tracker (linking to your docs) to keep track of the project status.<br />
<br />
===Community consultation===<br />
<br />
Get the community involved in looking at the spec to see if it meets their needs and to get further feedback. Please post in the [http://moodle.org/mod/forum/view.php?id=8052 Future major features forum] on moodle.org. You could also blog/tweet about it etc.<br />
<br />
Community developers proposing a new feature will want to talk with HQ core developers to make sure the ideas make sense, and possibly get some review on database design, architecture and so on.<br />
<br />
===Develop the code using Git===<br />
<br />
Develop your code on an open Git repository, like github.com. That enables people to see your code and to help you as it develops. Testers and early adopters also have the opportunity to try it early in the process and give you more valuable feedback.<br />
<br />
It is essential that your code follows the [[Coding|Moodle Coding Guide]].<br />
<br />
===Submit your code for peer review===<br />
<br />
Click on "Request peer review" button in the tracker.<br />
<br />
You need to fill in the information about your public git repository and which branches the fixes are on. Make sure you are listed as Assignee.<br />
<br />
This would be a good time to fill in the testing instructions for how to verify your fix is correct. You may also wish to add a comment in the bug.<br />
<br />
Component leads should put issues, which affect code in their components, up for peer review to allow interested parties to provide feedback. However, if it is not reviewed in a week, a component lead may send the issue to integration. If integrators consider that the issue has not been given proper chance for peer review (e.g. is extremely large or complex...) it can be decided to move the issue back in the process.<br />
<br />
All other developers, including people who are component leads but working outside their component, should have their issues peer reviewed before they are sent to integration.<br />
<br />
===Peer review===<br />
<br />
The [http://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Acomponents-panel component lead] should peer-review the change. If there is no component lead for an affected component, any other recognised developer may complete the peer review. The peer reviewer will either give you comments on the code and if it needs more work.<br />
<br />
Process and the list of things to check are described in [[Peer reviewing]].<br />
<br />
===Submit the code for integration===<br />
<br />
The developer is responsible for acting on the feedback from the peer reviewer. If changes have been made and the developer is satisfied that this has accommodated the feedback from the peer reviewer, then the developer can submit the issue for integration. If there have been significant changes after the peer review, or if the peer reviewer has raised concerns about the approach taken, then the developer should offer the issue up for peer review again, most often to the same peer reviewer, but not necessarily.<br />
<br />
Submitting an issue to integration is much the same as for any Moodle code. See the information about the integration workflow above.<br />
<br />
==Fixing a bug==<br />
<br />
Bug fixes, and minor features or enhancements should go through the following process. (The only exception is English language string typo fixes or suggested improvements, which may be contributed to the en_fix language pack on the [http://lang.moodle.org/ Moodle translation site].)<br />
<br />
===Make sure there is a tracker issue===<br />
<br />
Every change must have an issue in the tracker. If you are fixing a bug, there is probably one there already, but if not, create one. [[Tracker tips|Tips for searching tracker]].<br />
<br />
===Decide which branches the fix is required on===<br />
<br />
Bugs should normally be fixed on all the supported stable branches that are affected. New features should just go into master, but sometimes minor enhancements are made on the most recent stable branch.<br />
<br />
===Develop your change using git===<br />
<br />
Develop your fix and push the change to an open git repository, for example on github.com. See also [[Git for developers]]<br />
<br />
It is essential that your code follows the [[Coding|Moodle Coding Guide]].<br />
<br />
You will need to push one commit for each branch the fix needs to be applied to. Often people use branch names like wip_MDL-12345_31_brief_name so it is clear what each branch is. [http://kernel.org/pub/software/scm/git/docs/git-cherry-pick.html git cherry-pick] can help with replicating the fix onto different branches.<br />
<br />
===Submit your code for peer review===<br />
<br />
Once your fix is done, it should be submitted for a peer review.<br />
<br />
The following information is necessary for this:<br />
* Information about your public git repository<br />
** repository URL<br />
** branch name(s)<br />
** diff URL<br />
* testing instructions for how to verify your fix is correct<br />
* alternatively: Add the relevant information to the commit comments<br />
<br />
Start the peer review process in the Moodle tracker:<br />
* First time<br />
** just comment on the issue with the above information<br />
**After your first fix is integrated you will be added to developers group and will be able to send issues for peer review<br />
* Subsequent times (or rather after you are in the developer group)<br />
** Click on "Request peer review" button in the tracker<br />
* Always<br />
** Make sure you are listed as Assignee<br />
<br />
The component lead or another user with sufficient privileges will then send the issue up for peer for you<br />
<br />
===Peer review===<br />
<br />
The [https://tracker.moodle.org/projects/MDL?selectedItem=com.atlassian.jira.jira-projects-plugin:components-page component lead] should peer-review the change. If there is no component lead for an affected component, any other recognised developer may complete the peer review. The peer reviewer will either give you comments on the code and if it needs more work.<br />
<br />
Process and the list of things to check are described in [[Peer reviewing]].<br />
<br />
===Submit your code for integration===<br />
<br />
It will then be reviewed the following week by one of the integration team and either integrated or rejected. Once integrated, the fix will be tested, and then included in the next weekly release.<br />
<br />
==Security issues==<br />
<br />
Issues identified as [[Security|security issues]] are resolved in a slightly different way, in order to achieve responsible disclosure as described in [[Moodle security procedures]].<br />
<br />
* Security issues should be labelled as "Minor" or "Serious" in order control visibility of the issue.<br />
** An issue reported with a security level of "Could be a security issue" should be evaluated as soon as possible and either set as "Minor" or "Serious" or the security level should be set to "None".<br />
* Solutions to security issues should not:<br />
** be made available in public repositories.<br />
*** If a developer has shared a solution as Git branches via Github, they should be asked to provide the solutions as [[How_to_create_a_patch|stand-alone patches]] attached to the issue and to [[#How to remove a branch from Github|remove the solution from Github]].<br />
** contain details about the security problem in the commit message.<br />
*** Instead use generic terms like, "improve", "better handling of" ..<br />
* The solution will not be integrated until the week before a [[Process#Stable_maintenance_cycles|minor release]] following the normal [[Release process|Release process]]. In short, the issue will be incorporated into the integration version, rebased, tested and made ready for release as a normal issue would, but not until as late as possible.<br />
* Details of security issues will be shared with registered admins with the minor release.<br />
* Details of security issues will not be publicly announced until one week after a minor release to allow admins to update.<br />
<br />
Note that not all the labelled (minor) security issues are always handled following the procedure above. It's possible that, after discussion, it's decided a given issue is not a real Moodle security problem (say external disclosures/potential attacks using Moodle as vector, not as target, discussions revealing some private details...). Those issues will be processed as normal issues, generating the needed user documentation if necessary and will be part of the habitual weekly releases.<br />
<br />
====How to remove a branch from Github====<br />
<br />
To remove a branch from Github, you can use the following command.<br />
<br />
git push github :remote_branch<br />
<br />
Where ''remote_branch'' is the name of your remote branch, for example 'wip-mdl-1234'. This effectively replaces the remote branch with nothing, removing the remote branch, but leaving the branch intact in your local Git repository. Please note that its likely that your commit will still exist on github due to the nature of git, so its best to avoid doing this in the first place.<br />
<br />
==Policy issues==<br />
<br />
Occasionally within Moodle we run into policy issues where a high-level decision needs to be made about how things are to be done.<br />
<br />
In these cases the process is as follows:<br />
* Create an issue in the tracker with a [https://tracker.moodle.org/browse/MDL/component/12733 Policy component] and put "POLICY:" as a prefix on the summary.<br />
* In the description describe the problem clearly as well as all the options. If it's long then make a page here in Moodle Dev Docs and link to it.<br />
* Do not use this issue for code. If there are issues that depend on this policy decision, then add tracker links to them as dependencies.<br />
* Feel free to encourage people to come and talk about the policy to support various points of view. The more evidence we have (from everyone in the community) the better.<br />
<br />
Some time has been scheduled in the weekly Moodle HQ meeting to look at Policy issues and try to make decisions on them. We discuss all the evidence and try to achieve a high amount of consensus. Deadlocked issues can be resolved by a decision from Martin Dougiamas (this is rarely needed).<br />
<br />
Decisions will be posted on the issue and that issue will be closed, allowing any dependent issues to continue to integration (or not). Decisions are final and bribes hardly ever work.<br />
<br />
==See also==<br />
<br />
* [[Release process]]<br />
* [[Deprecation]]<br />
* [http://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11350 Integration dashboard]<br />
<br />
Walks-though of the process for contributors:<br />
* By Dan Poltawski, Integrator: http://www.slideshare.net/poltawski/how-to-guarantee-your-change-is-integrated-to-moodle-core, https://www.youtube.com/watch?v=836WtnM2YpM<br />
* By Tim Hunt, contributor: http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html and https://www.youtube.com/watch?v=gPPA3h7OGQU<br />
<br />
[[Category:Processes]]<br />
[[Category:Quality Assurance]]<br />
[[Category:Git]]<br />
[[Category:Core development]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Process&diff=52558Process2017-06-08T11:48:49Z<p>Danowar: /* Submit your code for peer review */ Clearer process (?)</p>
<hr />
<div>This document summarises the various development processes used in developing Moodle. There are four main processes that overlap.<br />
<br />
==Integration workflow in the tracker==<br />
<br />
The Moodle tracker keeps track of the status of all bug fixes and new features. <br />
<br />
We use a workflow that ensures that new code receives multiple reviews by different people before it is included into the core Moodle code.<br />
<br />
[[Image:Workflow.jpg]]<br />
<br />
A number of roles make this work:<br />
<br />
===Users===<br />
<br />
Users report bugs and make feature requests directly in the tracker, by creating new issues with a summary and a description.<br />
<br />
===Developers===<br />
<br />
Developers work on the issues in the tracker to specify solutions and write code that implements these solutions. They will often ask other developers to "peer review" their code in the early stages to avoid problems later on.<br />
<br />
While many of the developers work for Moodle.com, a large number are part of the global development community around Moodle. If you're interested in becoming a recognised developer, see [[Tracker_guide#Tracker_groups_and_permissions|Tracker groups and permissions]].<br />
<br />
===CiBoT===<br />
<br />
CiBoT is not a person but a bot who monitors the tracker and performs the [[Automated code review]] when issue is submitted for Peer review or when developer added ''cime'' label.<br />
<br />
===Component leads===<br />
<br />
[http://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Acomponents-panel Component leads] are developers with some responsibility for particular components (plugins or modules) in Moodle. They have authority to decide that a particular fix is suitable and complete enough to be considered for integration in Moodle core and should be called upon to complete peer reviews for code in their components.<br />
<br />
===Integrators===<br />
<br />
On Monday and Tuesday of each week, the integration team (a small team of senior developers employed by Moodle HQ) conducts a code-level review of all issues in the integration queue. This is often called the "pull" process. If the fix is judged appropriate they will integrate the code into our git integration repository for further testing and it gets added to the testing queue.<br />
<br />
If they find problems they reject the issue and send it back to the developer for further work.<br />
<br />
===Testers===<br />
<br />
On Wednesday each week, testers look at all the issues in the testing queue, trying each fix and feature to make sure that it does actually fix the problem it was supposed to, and that there are no regressions.<br />
<br />
If they find problems they reject the issue and integrators may remove it from the integration repository and push it back to the developer for further work.<br />
<br />
See [[Testing of integrated issues]] for more details.<br />
<br />
===Production maintainers===<br />
<br />
On Thursday each week, production maintainers merge all the issues that passed testing into the git production repository, and it becomes available for use on production systems via git and download packages.<br />
<br />
==Stable maintenance cycles==<br />
<br />
Moodle releases regular updates of the stable version of the software to fix bugs and other issues. Releases like 2.2.1, 2.2.2, 2.2.3 etc only include fixes based on the latest major release (2.2) and never any significant new features or database changes.<br />
<br />
At Moodle HQ there are teams of developers using the [http://www.scrum.org/ Scrum framework] to work on these issues (as well as new features for [[#Major_release_cycles|major releases]]). <br />
<br />
===Minor release (point release) timing===<br />
<br />
After [[#Major_release_cycles|major releases]] there will be minor releases.<br />
* x.x.1 will occur approximately two months after each major release (eg. 2.x).<br />
* There will then be another point release every two months after that.<br />
<br />
See the [[Releases#General_release_calendar|General release calendar]] for details.<br />
<br />
===Issue triage===<br />
<br />
[[Bug_triage|Issue triage]] involves evaluating new issues, making sure that they are recorded correctly. One of the most important jobs triagers do is to identify issues that should be fixed in the stable branch. These are set with a priority ranging from "Trivial" up to "Blocker" and other features are checked.<br />
<br />
At Moodle HQ there are currently teams working on stable issues (mostly bugs reported by users) and improvements and new features (Partners, Moodle Association, user suggestions and Martin Dougiamas).<br />
<br />
===Scrum===<br />
<br />
At Moodle HQ, every three weeks, the stable team takes a number of the most urgent issues from the backlog to work on during a period known as a ''sprint''.<br />
<br />
At the start of a sprint there is a period of planning and estimation. All issues on the backlog are given a relative rank that is based on issue features including priority, security, Partner interest, patches and votes. Issues are given a relative size in Story Points and these points are summed to allow the teams to determine how many issues they can work on in the sprint.<br />
<br />
During the sprint, the team meets daily to discuss solutions and progress, as well as to organise testing and peer reviews of code. The team has a ''Scrum master'' to help everyone stay organised, to "unblock" any barriers to progress and to protect the team from distracting influences (mostly people attempting to add to the developers' workloads) during the sprint. The teams' work is documented publicly in the tracker.<br />
<br />
Whenever a solution for an issue is finished, it is submitted into to the standard integration workflow process described above.<br />
<br />
==Major release cycles==<br />
<br />
Since Moodle 2.0, we have a policy of release major versions (eg 2.1, 2.2) every six months in May and November. See the [[Releases#General_release_calendar|General release calendar]] for more details.<br />
<br />
Each release can be different, but generally the cycles work as follows.<br />
<br />
===Define roadmap===<br />
<br />
The product owner (Martin Dougiamas) defines the likely roadmap based on community wishes, third-party developments and important issues within the existing code. <br />
<br />
Sometimes new features might be based on earlier features, sometimes they may be something developed by a third party that needs to be evaluated and sometimes it might be something completely new.<br />
<br />
===Planning and development===<br />
<br />
The UX team, employed at Moodle HQ, work on specifications of major new features throughout the cycle, specifying project ahead of development time.<br />
<br />
New features are worked on by the "Dev" team. The process of [[#New_feature_development|new feature development]] is described below. When specifications are in place, new code is developed during sprints and goes through the standard weekly integration workflow described above.<br />
<br />
===Testing===<br />
<br />
During development, as new code is integrated, automated testing conducted at the [[PHPUnit|code]] and [[Acceptance_testing|interface]] levels, to make sure there are no regressions caused by new features.<br />
<br />
In the last month before the release, a feature freeze is called (no new features can be added) and our QA team performs manual functional testing of Moodle features. The current list of functional tests is listed in the tracker in the [http://tracker.moodle.org/browse/MDLQA-1 MDLQA project]. This list of tests is extended as new features are added, but it is also being reduced as more automated [[Acceptance_testing|acceptance tests]] are developed.<br />
<br />
For more details, see [[Testing]].<br />
<br />
===Sprints===<br />
<br />
At Moodle HQ, development takes place in sprints. The sprints are three-week periods during which developers to focus on a fixed list of issues. Sprints are arranged within each release cycle as shown in the diagram below.<br />
<br />
===Events during cycle===<br />
<br />
During each cycle there are a periods and events that occur between and around sprints.<br />
<br />
[[Image:Dev sprint calendar.png|800px]]<br />
<br />
; '''Planning and bug fixing'''<br />
: A period during which the Roadmap is explored, specs are written and prototypes are created. Regressions in the recent release are fixed as they arise.<br />
; '''End sync period'''<br />
: During the [[Integration Review#On-sync period|on-sync period]], the recent release and master versions are kept synchronised. No new code is added during this period, which ensures regressions are fixed rapidly. This also allows for planning and provides relief for developers after a release.<br />
; '''Personal projects'''<br />
: Affecting full-time HQ developers only, this period allows for individual creations to be explored and provides a break from sprints.<br />
; '''Code freeze'''<br />
: A point after which no new code (only fixes to existing code) is accepted until beyond the release. This stabilisation allows for QA testing.<br />
; '''QA, bug fixing, continuous integration'''<br />
: A period after the code freeze where quality assurance testing takes place. No new code is added, which means developers are able to respond rapidly to bugs found. Integration becomes [[Integration Review#During continuous integration/Freeze/QA period|continuous]], meaning that failed QA tests can be re-run within days rather than having to wait for the weekly release.<br />
; '''Release candidate'''<br />
: A point prior to the full release where a candidate is made public for wider testing.<br />
<br />
==New feature development==<br />
<br />
Major new features in Moodle usually should go through the following process.<br />
<br />
===Specification===<br />
<br />
The User Experience (UX) team should create detailed wireframes and features and goals for the new feature. It should be agreed upon and as final as possible before development starts.<br />
<br />
Developers should create a detailed spec (here in the developer docs) outlining their goals for the development and their design for meeting those goals. The more detail the better.<br />
<br />
Developers should also create an issue in the tracker (linking to your docs) to keep track of the project status.<br />
<br />
===Community consultation===<br />
<br />
Get the community involved in looking at the spec to see if it meets their needs and to get further feedback. Please post in the [http://moodle.org/mod/forum/view.php?id=8052 Future major features forum] on moodle.org. You could also blog/tweet about it etc.<br />
<br />
Community developers proposing a new feature will want to talk with HQ core developers to make sure the ideas make sense, and possibly get some review on database design, architecture and so on.<br />
<br />
===Develop the code using Git===<br />
<br />
Develop your code on an open Git repository, like github.com. That enables people to see your code and to help you as it develops. Testers and early adopters also have the opportunity to try it early in the process and give you more valuable feedback.<br />
<br />
It is essential that your code follows the [[Coding|Moodle Coding Guide]].<br />
<br />
===Submit your code for peer review===<br />
<br />
Click on "Request peer review" button in the tracker.<br />
<br />
You need to fill in the information about your public git repository and which branches the fixes are on. Make sure you are listed as Assignee.<br />
<br />
This would be a good time to fill in the testing instructions for how to verify your fix is correct. You may also wish to add a comment in the bug.<br />
<br />
Component leads should put issues, which affect code in their components, up for peer review to allow interested parties to provide feedback. However, if it is not reviewed in a week, a component lead may send the issue to integration. If integrators consider that the issue has not been given proper chance for peer review (e.g. is extremely large or complex...) it can be decided to move the issue back in the process.<br />
<br />
All other developers, including people who are component leads but working outside their component, should have their issues peer reviewed before they are sent to integration.<br />
<br />
===Peer review===<br />
<br />
The [http://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Acomponents-panel component lead] should peer-review the change. If there is no component lead for an affected component, any other recognised developer may complete the peer review. The peer reviewer will either give you comments on the code and if it needs more work.<br />
<br />
Process and the list of things to check are described in [[Peer reviewing]].<br />
<br />
===Submit the code for integration===<br />
<br />
The developer is responsible for acting on the feedback from the peer reviewer. If changes have been made and the developer is satisfied that this has accommodated the feedback from the peer reviewer, then the developer can submit the issue for integration. If there have been significant changes after the peer review, or if the peer reviewer has raised concerns about the approach taken, then the developer should offer the issue up for peer review again, most often to the same peer reviewer, but not necessarily.<br />
<br />
Submitting an issue to integration is much the same as for any Moodle code. See the information about the integration workflow above.<br />
<br />
==Fixing a bug==<br />
<br />
Bug fixes, and minor features or enhancements should go through the following process. (The only exception is English language string typo fixes or suggested improvements, which may be contributed to the en_fix language pack on the [http://lang.moodle.org/ Moodle translation site].)<br />
<br />
===Make sure there is a tracker issue===<br />
<br />
Every change must have an issue in the tracker. If you are fixing a bug, there is probably one there already, but if not, create one. [[Tracker tips|Tips for searching tracker]].<br />
<br />
===Decide which branches the fix is required on===<br />
<br />
Bugs should normally be fixed on all the supported stable branches that are affected. New features should just go into master, but sometimes minor enhancements are made on the most recent stable branch.<br />
<br />
===Develop your change using git===<br />
<br />
Develop your fix and push the change to an open git repository, for example on github.com. See also [[Git for developers]]<br />
<br />
It is essential that your code follows the [[Coding|Moodle Coding Guide]].<br />
<br />
You will need to push one commit for each branch the fix needs to be applied to. Often people use branch names like wip_MDL-12345_31_brief_name so it is clear what each branch is. [http://kernel.org/pub/software/scm/git/docs/git-cherry-pick.html git cherry-pick] can help with replicating the fix onto different branches.<br />
<br />
===Submit your code for peer review===<br />
<br />
Once your fix is done, it should be submitted for a peer review.<br />
<br />
The following information is necessary for this:<br />
* Information about your public git repository<br />
** repository URL<br />
** branch name(s)<br />
** diff URL<br />
** testing instructions for how to verify your fix is correct<br />
** alternatively: Put relevant informations in the commit comments<br />
<br />
Start the peer review process in the Moodle tracker:<br />
* First time<br />
** just comment on the issue with the above information<br />
**After your first fix is integrated you will be added to developers group and will be able to send issues for peer review<br />
* Subsequent times (or rather after you are in the developer group)<br />
** Click on "Request peer review" button in the tracker<br />
* Always<br />
** Make sure you are listed as Assignee<br />
<br />
The component lead or another user with sufficient privileges will then send the issue up for peer for you<br />
<br />
===Peer review===<br />
<br />
The [https://tracker.moodle.org/projects/MDL?selectedItem=com.atlassian.jira.jira-projects-plugin:components-page component lead] should peer-review the change. If there is no component lead for an affected component, any other recognised developer may complete the peer review. The peer reviewer will either give you comments on the code and if it needs more work.<br />
<br />
Process and the list of things to check are described in [[Peer reviewing]].<br />
<br />
===Submit your code for integration===<br />
<br />
It will then be reviewed the following week by one of the integration team and either integrated or rejected. Once integrated, the fix will be tested, and then included in the next weekly release.<br />
<br />
==Security issues==<br />
<br />
Issues identified as [[Security|security issues]] are resolved in a slightly different way, in order to achieve responsible disclosure as described in [[Moodle security procedures]].<br />
<br />
* Security issues should be labelled as "Minor" or "Serious" in order control visibility of the issue.<br />
** An issue reported with a security level of "Could be a security issue" should be evaluated as soon as possible and either set as "Minor" or "Serious" or the security level should be set to "None".<br />
* Solutions to security issues should not:<br />
** be made available in public repositories.<br />
*** If a developer has shared a solution as Git branches via Github, they should be asked to provide the solutions as [[How_to_create_a_patch|stand-alone patches]] attached to the issue and to [[#How to remove a branch from Github|remove the solution from Github]].<br />
** contain details about the security problem in the commit message.<br />
*** Instead use generic terms like, "improve", "better handling of" ..<br />
* The solution will not be integrated until the week before a [[Process#Stable_maintenance_cycles|minor release]] following the normal [[Release process|Release process]]. In short, the issue will be incorporated into the integration version, rebased, tested and made ready for release as a normal issue would, but not until as late as possible.<br />
* Details of security issues will be shared with registered admins with the minor release.<br />
* Details of security issues will not be publicly announced until one week after a minor release to allow admins to update.<br />
<br />
Note that not all the labelled (minor) security issues are always handled following the procedure above. It's possible that, after discussion, it's decided a given issue is not a real Moodle security problem (say external disclosures/potential attacks using Moodle as vector, not as target, discussions revealing some private details...). Those issues will be processed as normal issues, generating the needed user documentation if necessary and will be part of the habitual weekly releases.<br />
<br />
====How to remove a branch from Github====<br />
<br />
To remove a branch from Github, you can use the following command.<br />
<br />
git push github :remote_branch<br />
<br />
Where ''remote_branch'' is the name of your remote branch, for example 'wip-mdl-1234'. This effectively replaces the remote branch with nothing, removing the remote branch, but leaving the branch intact in your local Git repository. Please note that its likely that your commit will still exist on github due to the nature of git, so its best to avoid doing this in the first place.<br />
<br />
==Policy issues==<br />
<br />
Occasionally within Moodle we run into policy issues where a high-level decision needs to be made about how things are to be done.<br />
<br />
In these cases the process is as follows:<br />
* Create an issue in the tracker with a [https://tracker.moodle.org/browse/MDL/component/12733 Policy component] and put "POLICY:" as a prefix on the summary.<br />
* In the description describe the problem clearly as well as all the options. If it's long then make a page here in Moodle Dev Docs and link to it.<br />
* Do not use this issue for code. If there are issues that depend on this policy decision, then add tracker links to them as dependencies.<br />
* Feel free to encourage people to come and talk about the policy to support various points of view. The more evidence we have (from everyone in the community) the better.<br />
<br />
Some time has been scheduled in the weekly Moodle HQ meeting to look at Policy issues and try to make decisions on them. We discuss all the evidence and try to achieve a high amount of consensus. Deadlocked issues can be resolved by a decision from Martin Dougiamas (this is rarely needed).<br />
<br />
Decisions will be posted on the issue and that issue will be closed, allowing any dependent issues to continue to integration (or not). Decisions are final and bribes hardly ever work.<br />
<br />
==See also==<br />
<br />
* [[Release process]]<br />
* [[Deprecation]]<br />
* [http://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11350 Integration dashboard]<br />
<br />
Walks-though of the process for contributors:<br />
* By Dan Poltawski, Integrator: http://www.slideshare.net/poltawski/how-to-guarantee-your-change-is-integrated-to-moodle-core, https://www.youtube.com/watch?v=836WtnM2YpM<br />
* By Tim Hunt, contributor: http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html and https://www.youtube.com/watch?v=gPPA3h7OGQU<br />
<br />
[[Category:Processes]]<br />
[[Category:Quality Assurance]]<br />
[[Category:Git]]<br />
[[Category:Core development]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&diff=52346Useful core Javascript modules2017-05-10T13:34:40Z<p>Danowar: /* Language strings (core/str) */</p>
<hr />
<div>{{Moodle 2.9}}<br />
<br />
== Configuration settings (core/config) ==<br />
<br />
Example of using config module:<br />
<code javascript><br />
require(['core/config’], function(mdlcfg) {<br />
console.log(mdlcfg.wwwroot); // outputs the wwwroot of moodle to console<br />
});<br />
</code><br />
<br />
== Language strings (core/str) ==<br />
<br />
Example of using language strings module (retrieved via ajax, if the string is not yet loaded)<br />
<code javascript><br />
require([‘core/str’], function(str) {<br />
// start retrieving the localized string; store the promise that some time in the future the string will be there.<br />
var editaPresent = str.get_string('edita', 'core', stringargument);<br />
// as soon as the string is retrieved, i.e. the promise has been fulfilled,<br />
// edit the text of a UI element so that it then is the localized string<br />
// Note: $.when can be used with an arbitrary number of promised things<br />
$.when(editaPresent).done(function(localizedEditString) {<br />
$("someUIElementSelector").text = localizedEditString;<br />
});<br />
});<br />
</code><br />
<br />
The string will be retrieved via AJAX request on the first use and cached in browser local storage until purge caches or site upgrade<br />
<br />
IT IS NOT RECOMMENDED to call:<br />
<code php><br />
$PAGE->requires->string_for_js('edita', 'core'); // You do not need this!<br />
</code><br />
<br />
Because:<br />
* The list of strings used now needs to be maintained in 2 places<br />
* The strings are always sent, and bloat the page size even if they are not used<br />
* All strings fetched via the AJAX method above are cached in browser local storage anyway, so these strings will never be used 99% of the time<br />
<br />
==Notifications (core/notification)==<br />
<br />
Examples:<br />
<code javascript><br />
require(['core/notification’], function(notification) {<br />
notification.alert('Hello', 'Welcome to my site!', 'Continue');<br />
});<br />
</code><br />
<br />
Strings and notifications:<br />
<code javascript><br />
require(['core/str', 'core/notification’], function(str, notification) {<br />
str.get_strings([<br />
{'key' : 'delete'},<br />
{'key' : 'confirmdeletetag', component : 'tag'},<br />
{'key' : 'yes'},<br />
{'key' : 'no'},<br />
]).done(function(s) {<br />
notification.confirm(s[0], s[1], s[2], s[3], function() {<br />
window.location.href = href;<br />
});<br />
}<br />
).fail(notification.exception);<br />
});<br />
</code><br />
<br />
== URL module (core/url) ==<br />
<br />
Useful Functions:<br />
<code javascript><br />
// Generate an absolute URL by using the relative path to a file and optionally slash arguments<br />
url.fileUrl(relativeScript, slashArgs)<br />
// Generate an absolute URL from the given relative path, include the URL parameters and possibly the current session key<br />
url.relativeUrl(relativePath, params, includeSessionKey)<br />
// Generates an image url using the filename of the image and the Moodle component (core, plugin, etc.) where it can be found<br />
url.imageUrl(imagename, component)<br />
</code><br />
<br />
Example:<br />
<br />
<code javascript><br />
// Prerequisites:<br />
// - A Javascript file is present under $CFG->wwwroot."/path/to/file.js"<br />
require(['core/url'], function(url) {<br />
url.fileUrl("/path/to/file.js", "");<br />
console.log("Generated URL: " + url);<br />
});<br />
</code><br />
<br />
== Tree (core/tree) ==<br />
{{Moodle 3.1}}<br />
If you want to add a hierarchical interface, you should use the tree module. It will handle user interaction and accessibility for you.<br />
<br />
<code javascript><br />
define(['jquery', 'core/tree'], function($, Tree) {<br />
return {<br />
init: function() {<br />
new Tree("css/jquery selector of the tree container");<br />
}<br />
};<br />
});<br />
</code><br />
<br />
Read more about the [[Tree]] module<br />
<br />
== Modal (core/modal) ==<br />
If you'd like to add a modal to your page the modal modules will handle all of the magic for you, all you need to bring is your content!<br />
<code javascript><br />
require(['jquery', 'core/modal_factory'], function($, ModalFactory) {<br />
var trigger = $('#create-modal');<br />
ModalFactory.create({<br />
title: 'test title',<br />
body: '<p>test body content</p>',<br />
footer: 'test footer content',<br />
}, trigger)<br />
.done(function(modal) {<br />
// Do what you want with your new modal.<br />
});<br />
});<br />
</code><br />
<br />
Read more about the [[AMD_Modal]] module<br />
<br />
==See also==<br />
* [[Javascript Modules]]<br />
* [[Fragment]]<br />
<br />
<br />
[[Category:AJAX]]<br />
[[Category:Javascript]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Useful_core_Javascript_modules&diff=52344Useful core Javascript modules2017-05-10T13:23:59Z<p>Danowar: /* URL module (core/url) */</p>
<hr />
<div>{{Moodle 2.9}}<br />
<br />
== Configuration settings (core/config) ==<br />
<br />
Example of using config module:<br />
<code javascript><br />
require(['core/config’], function(mdlcfg) {<br />
console.log(mdlcfg.wwwroot); // outputs the wwwroot of moodle to console<br />
});<br />
</code><br />
<br />
== Language strings (core/str) ==<br />
<br />
Example of using language strings module (retrieved via ajax, if the string is not yet loaded)<br />
<code javascript><br />
require([‘core/str’], function(str) {<br />
str.get_string('edita', 'core', stringargument).done(function(s) {<br />
console.log(s);<br />
}).fail(console.log(e));<br />
});<br />
</code><br />
<br />
The string will be retrieved via AJAX request on the first use and cached in browser local storage until purge caches or site upgrade<br />
<br />
IT IS NOT RECOMMENDED to call:<br />
<code php><br />
$PAGE->requires->string_for_js('edita', 'core'); // You do not need this!<br />
</code><br />
<br />
Because:<br />
* The list of strings used now needs to be maintained in 2 places<br />
* The strings are always sent, and bloat the page size even if they are not used<br />
* All strings fetched via the AJAX method above are cached in browser local storage anyway, so these strings will never be used 99% of the time<br />
<br />
==Notifications (core/notification)==<br />
<br />
Examples:<br />
<code javascript><br />
require(['core/notification’], function(notification) {<br />
notification.alert('Hello', 'Welcome to my site!', 'Continue');<br />
});<br />
</code><br />
<br />
Strings and notifications:<br />
<code javascript><br />
require(['core/str', 'core/notification’], function(str, notification) {<br />
str.get_strings([<br />
{'key' : 'delete'},<br />
{'key' : 'confirmdeletetag', component : 'tag'},<br />
{'key' : 'yes'},<br />
{'key' : 'no'},<br />
]).done(function(s) {<br />
notification.confirm(s[0], s[1], s[2], s[3], function() {<br />
window.location.href = href;<br />
});<br />
}<br />
).fail(notification.exception);<br />
});<br />
</code><br />
<br />
== URL module (core/url) ==<br />
<br />
Useful Functions:<br />
<code javascript><br />
// Generate an absolute URL by using the relative path to a file and optionally slash arguments<br />
url.fileUrl(relativeScript, slashArgs)<br />
// Generate an absolute URL from the given relative path, include the URL parameters and possibly the current session key<br />
url.relativeUrl(relativePath, params, includeSessionKey)<br />
// Generates an image url using the filename of the image and the Moodle component (core, plugin, etc.) where it can be found<br />
url.imageUrl(imagename, component)<br />
</code><br />
<br />
Example:<br />
<br />
<code javascript><br />
// Prerequisites:<br />
// - A Javascript file is present under $CFG->wwwroot."/path/to/file.js"<br />
require(['core/url'], function(url) {<br />
url.fileUrl("/path/to/file.js", "");<br />
console.log("Generated URL: " + url);<br />
});<br />
</code><br />
<br />
== Tree (core/tree) ==<br />
{{Moodle 3.1}}<br />
If you want to add a hierarchical interface, you should use the tree module. It will handle user interaction and accessibility for you.<br />
<br />
<code javascript><br />
define(['jquery', 'core/tree'], function($, Tree) {<br />
return {<br />
init: function() {<br />
new Tree("css/jquery selector of the tree container");<br />
}<br />
};<br />
});<br />
</code><br />
<br />
Read more about the [[Tree]] module<br />
<br />
== Modal (core/modal) ==<br />
If you'd like to add a modal to your page the modal modules will handle all of the magic for you, all you need to bring is your content!<br />
<code javascript><br />
require(['jquery', 'core/modal_factory'], function($, ModalFactory) {<br />
var trigger = $('#create-modal');<br />
ModalFactory.create({<br />
title: 'test title',<br />
body: '<p>test body content</p>',<br />
footer: 'test footer content',<br />
}, trigger)<br />
.done(function(modal) {<br />
// Do what you want with your new modal.<br />
});<br />
});<br />
</code><br />
<br />
Read more about the [[AMD_Modal]] module<br />
<br />
==See also==<br />
* [[Javascript Modules]]<br />
* [[Fragment]]<br />
<br />
<br />
[[Category:AJAX]]<br />
[[Category:Javascript]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Talk:Javascript_Modules&diff=52343Talk:Javascript Modules2017-05-10T12:31:43Z<p>Danowar: </p>
<hr />
<div>1. I have a third party javascript module which doesn't use an external framework (e.g. jQuery) and isn't an AMD module. I may only have the minified version of the module. I want to include it in my Moodle page. How do I do that?<br />
<br />
2. Same question as above but the module is a jQuery non-AMD module. How do I include it?<br />
<br />
The page reads to me like there should be a way to do that... it mentions that there is a way, but only describes what to do if the JavaScript file is an AMD module.</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Talk:Javascript_Modules&diff=52342Talk:Javascript Modules2017-05-10T12:31:04Z<p>Danowar: Created page with "1. I have a javascript module which doesn't use an external framework (e.g. jQuery) and isn't an AMD module. I may only have the minified version of the module. I want to incl..."</p>
<hr />
<div>1. I have a javascript module which doesn't use an external framework (e.g. jQuery) and isn't an AMD module. I may only have the minified version of the module. I want to include it in my Moodle page. How do I do that?<br />
<br />
2. Same question as above but the module is a jQuery non-AMD module. How do I include it?<br />
<br />
The page reads to me like there should be a way to do that... it mentions that there is a way, but only describes what to do if the JavaScript file is an AMD module.</div>Danowarhttps://docs.moodle.org/dev/index.php?title=YUI/Shifter&diff=50688YUI/Shifter2016-07-28T13:22:27Z<p>Danowar: Helpful natural language? (and tables for cleaner reading)</p>
<hr />
<div>{{Moodle 2.5}}<br />
{{Moodle 2.6}}<br />
{{Moodle 2.7}}<br />
<br />
== What is Shifter and what does it do? ==<br />
<br />
[http://yui.github.com/shifter Shifter] is a tool written by the YUI team to help ''build'' YUI modules.<br />
It has been supported since Moodle 2.5.<br />
<br />
It is written in JavaScript itself, and written as a [http://nodejs.org Node.JS] module which can be installed from [https://npmjs.org/package/shifter NPM].<br />
<br />
Shifter takes your source JavaScript file(s), along with some meta-data, and wraps it all together into a built file. This file is known in YUI parlance as a '''module'''.<br />
After building this file, Shifter then produces three versions:<br />
* the file in its original form (DEBUG - '-debug' filename postfix);<br />
* the DEBUG file with all debugging calls to Y.Log removed (RAW - no filename postfix); and<br />
* the RAW file minified using [https://github.com/mishoo/UglifyJS UglifyJS] ('-min' filename postfix).<br />
<br />
The meta-data file includes information on the module name, and its dependencies on other modules.<br />
<br />
By separating out the actual JS code from its dependencies, we are able to take those dependencies and use them elsewhere in Moodle.<br />
As an example, this dependency data can be used to inform the Loading system to reduce the number of HTTP requests with Combo Loading. This has a benefical effect upon performance.<br />
<br />
Another feature of Shifter is its ability to handle ''rollups''. Rollups describe the inclusion of multiple YUI classes in the same module. This means that you can have different but related components all in the same module, but without having a single large and less-managable source file.<br />
<br />
=== Why do I need build my modules? ===<br />
<br />
Technically you don't, and you can continue to use the old data structure, but by doing so you can benefit from:<br />
* reduced data sent over the wire due to minification - great for slower connections and mobile devices;<br />
* reduced number of http queries - the separation of module meta-data means that it can be consumed and fed into the Loader allowing your module to use combo-loading;<br />
* a slightly simplified JS syntax for your source files.<br />
<br />
== Installing Shifter ==<br />
<br />
As of Moodle 2.9, the shifter process is managed by the "Grunt" task runner. See [[ Grunt ]] for more information.<br />
<br />
Shifter is written in JavaScript and the [http://nodejs.org Node.JS] environment. You will need to install Node.JS first. This is usually fairly easy as there are pre-built binary packages for '''Windows and Mac OS'''.<br />
<br />
After installing Node.JS you then use the Node NPM tool to install Shifter:<br />
npm install shifter@0.4.6 -g<br />
<br />
Note: At present, the supported version of Shifter for use in Moodle is version ''0.4.6''. You are not ''required'' to run a specific version of Shifter, but this is the version that Moodle YUI modules will be built with and you may find it beneficial to do so too.<br />
<br />
For '''Ubuntu''' run:<br />
<br />
sudo apt-get install npm<br />
sudo apt-get install python-software-properties python g++ make<br />
sudo apt-get update<br />
sudo apt-get install nodejs<br />
sudo ln -s /usr/bin/nodejs /usr/local/bin/node<br />
sudo npm install shifter@0.4.6 -g<br />
<br />
For '''CentOS''' run the following as root:<br />
yum install nodejs npm<br />
npm install shifter@0.4.6 -g<br />
<br />
If you are behind a proxy, you will need to read http://jjasonclark.com/how-to-setup-node-behind-web-proxy.<br />
<br />
== How do I write a YUI module which uses Shifter? ==<br />
<br />
Easy - it's mostly just a case of building the right directory structure.<br />
<br />
Assuming that you are creating a new YUI module in your block named fruit, and that your new YUI module will be called fruitbowl, we know the following:<br />
{| class="wikitable"<br />
|'''Plugin type'''<br />
|block<br />
|-<br />
|'''Plugin name'''<br />
|fruit<br />
|-<br />
|'''Plugin frankenstyle name'''<br />
|block_fruit<br />
|-<br />
|'''YUI Module name'''<br />
|moodle-block_fruit-fruitbowl<br />
|-<br />
|}<br />
<br />
This means that your Moodle plugin directory is:<br />
/blocks/fruit<br />
<br />
And your ''fruitbowl'' YUI module source will therefore be in:<br />
/blocks/fruit/yui/src/fruitbowl<br />
<br />
The overall module directory structure looks like this:<br />
<code bash><br />
yui/<br />
|-- src<br />
|-- fruitbowl<br />
|-- build.json<br />
|-- js<br />
| |-- fruitbowl.js<br />
|-- meta<br />
|-- fruitbowl.json<br />
</code><br />
<br />
=== build.json ===<br />
<br />
The ''build.json'' file defines the eventual modules which will be built, and the source files that you've written:<br />
<br />
<code javascript><br />
{<br />
"name": "moodle-block_fruit-fruitbowl",<br />
"builds": {<br />
"moodle-block_fruit-fruitbowl": {<br />
"jsfiles": [<br />
"fruitbowl.js"<br />
]<br />
}<br />
}<br />
}<br />
</code><br />
The above example can be read as "My module has the name 'moodle-block_fruit-fruitbowl'. When building, shifter builds one submodule (?) named 'moodle-block_fruit-fruitbowl' using the Javascript file 'fruitbowl.js'.<br />
<br />
=== meta/MODNAME.json ===<br />
<br />
The ''meta/MODNAME.json'' file describes the list of dependencies for each module:<br />
<br />
<code javascript><br />
{<br />
"moodle-block_fruit-fruitbowl": {<br />
"requires": [<br />
"base",<br />
"node"<br />
]<br />
}<br />
}<br />
</code><br />
To build the submodule 'moodle-block_fruit-fruitbowl', it is required to include both the 'base' and 'node' modules.<br />
<br />
=== js/MODNAME.js ===<br />
<br />
The files in the js directory are the contents of your YUI module. This should include setting it up in the '''''M''''' namespace. As an example of a very basic structure:<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
M.block_fruit.fruitbowl = {<br />
init: function() {<br />
Y.one('#example').set('innerHTML', 'Example content');<br />
}<br />
};<br />
</code><br />
<br />
=== Can I put two modules in one directory tree? ===<br />
<br />
If you are still using Moodle 2.5, this does not work due to bug MDL-40478 (the non-default files cannot be loaded).<br />
<br />
If you are using Moodle 2.6+ this is possible. It may sometimes be sensible if the modules are not independent, e.g. if one module will only ever be used by the other one rather than directly called from PHP, or another module.<br />
<br />
If the modules are independent or might well be used separately from each other, then it is probably best to use a separate directory tree for each.<br />
<br />
See examples in mod/scorm/yui/src and lib/yui/src/notification.<br />
<br />
=== How do I load one of these modules from PHP code? ===<br />
<br />
You need to run Shifter so that it generates the compiled code. See below.<br />
<br />
Once you've done that, you can use PHP code like the following:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl', 'M.block_fruit.fruitbowl.init', array());<br />
</code><br />
<br />
(The last empty array contains parameters for the init function, if required.)<br />
<br />
== How do I use shifter? ==<br />
<br />
So after writing out your structure, you now need to build it into a module. After installing Shifter, you have several options.<br />
<br />
=== During development ===<br />
<br />
A really nice way of running shifter during development is to have it detect changes to your files as you save them:<br />
<br />
cd ~/git/moodle/blocks/fruit/yui/src<br />
shifter --watch<br />
<br />
The '''--watch''' option will watch for any changes to JS, JSON, CSS, or images within any module in the current directory and build that module when it detects changes.<br />
''Note: There can be a short delay of a few seconds while the changes are discovered and the file is built''<br />
<br />
This is great for development because you don't have to continously run shifter manually.<br />
<br />
=== All YUI modules for the Moodle plugin you're currently working on ===<br />
<br />
If you are working on several YUI modules at once, then you can have shifter build all of them at the same time:<br />
<br />
cd ~/git/moodle/blocks/fruit/yui/src<br />
shifter --walk<br />
<br />
=== Just the module you're working on now ===<br />
If you want to build just the module you're working on at the moment:<br />
<br />
cd ~/git/moodle/blocks/fruit/yui/src<br />
shifter --walk fruitbowl<br />
<br />
Or:<br />
<br />
cd ~/git/moodle/blocks/fruit/yui/src/fruitbowl<br />
shifter<br />
<br />
=== Across the whole of Moodle ===<br />
If you want to build every YUI module in Moodle at once:<br />
<br />
cd ~/git/moodle<br />
shifter --walk --recursive<br />
<br />
== Submitting my JavaScript back to Moodle core ==<br />
<br />
If you're working on some JavaScript for Moodle core, either in the form of a bug fix or a new feature, then you probably want to know what to do with your built module.<br />
<br />
'''We ask that you build your module and submit both the changes to tbe built module and the source directory.'''<br />
<br />
In addition, the Continuous Integration server (Jenkins) will run ''shifter --walk --recursive'' on every run to ensure that all built files are up-to-date and correct.<br />
<br />
If there are several commits to the same YUI module within a single period of Moodle integration, then the built files will conflict. In this case the integration team will manually build the module and resolve the conflict. If you are aware that there may be multiple changes to the same file, please indicate this when submitting your change for Integration Review. If you are familiar with the changes, you may wish to consider building the issues upon one another too.<br />
<br />
== How do I convert my existing module? ==<br />
<br />
If you already have an existing moodle YUI module and want to convert it to the new Shifter format, then it's pretty easy on the whole:<br />
<br />
# create a new src/MODNAME directory;<br />
# create js and meta directories within this;<br />
# copy over your existing js file into the js directory;<br />
# extract the meta-data;<br />
# write your build.json;<br />
# remove the YUI.add() wrapper from the top and bottom of your js file; and<br />
# remove the old file.<br />
<br />
To create the complete directory structure and copy your existing code into the right directory (steps 1 - 3):<br />
<br />
mkdir -p src/MODNAME/{js,meta}<br />
cp MODNAME/MODNAME.js src/MODNAME/js/<br />
<br />
Refer to the section above on the correct contents of the build.json and meta/MODNAME.json files.<br />
<br />
== Can I run my shifted module in older versions of Moodle 2 (before 2.5)? ==<br />
<br />
We are aware that many developers wish to reduce the overhead of maintaining a plugin for multiple versions of Moodle and that using Shifter will make this much harder. Unfortunately you can't use the shifted version of your module directly, but you can run them in parallel by copying the built file into the old directory structure.<br />
<br />
Moodle will always ''prefer'' the built shifted module over the older style module if both are present.<br />
<br />
If doing this, we would recommend copying over the minified version of your file so that older versions of moodle benefit from your user of shifted code.<br />
<br />
On a Linux-like operating system, you can use the following (again with our fruit example):<br />
cp yui/build/moodle-mod_fruit-fruitbowl/moodle-mod_fruit-fruitbowl-min.js yui/fruitbowl/fruitbowl.js<br />
<br />
Whilst developing, you may want to use a symlink so that you don't have to keep copying your changes after building them:<br />
ln -s yui/build/moodle-mod_fruit-fruitbowl/moodle-mod_fruit-fruitbowl.js yui/fruitbowl/fruitbowl.js<br />
<br />
==See also==<br />
* [[ Grunt ]]<br />
* [[ Javascript Modules ]]<br />
* [[ JavaScript guidelines ]]<br />
<br />
[[ Category:Javascript ]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=YUI/Modules&diff=50683YUI/Modules2016-07-27T11:18:55Z<p>Danowar: </p>
<hr />
<div>{{Moodle 2.5}}<br />
{{Moodle 2.6}}<br />
{{Moodle 2.7}}<br />
<br />
== YUI modules ==<br />
<br />
You may want to [[#Additional_functions_instead_of_anonymous_functions|Jump straight to the complete example]].<br />
<br />
=== What is a module and why would I want to use one? ===<br />
<br />
Many people are used to writing their JavaScript code either inline, or in a<br />
separate file included using <script> tags in their HTML. Although both of<br />
these are supported within Moodle, we highly recommend investing a little<br />
time in looking into the [[YUI]] module system as it offers some really great<br />
features which will benefit you in the long run.<br />
<br />
These features and benefits include:<br />
* a host of existing modules that you can hook into and use; which offer<br />
* code sandboxing to ensure that you always have a good/clean copy of the code; with<br />
* powerful dependency management; which can utilise<br />
* asynchronous loading to load dependencies in parallel; and<br />
* loading of dependencies in any order (you don't have to include script tags in a set order); and<br />
* separation of loading from execution; and<br />
* combo loading to reduce the number of individual HTTP transactions.<br />
<br />
By using existing modules in your code, you can benefit in other ways too, such as:<br />
* a consistent look and feel across Moodle; and<br />
* most of the edge cases already catered for.<br />
<br />
The Moodle community is in the process of improving much of its JavaScript<br />
in areas such as code, documentation, and processes. This includes updating<br />
older code, adding documentation, seeding dependency information for<br />
modules to improve load efficiency for browsers, and much more.<br />
<br />
You may find the following resources particularly helpful:<br />
* [[YUI]]; and<br />
* [[YUI/Shifter]].<br />
<br />
=== Structure and naming ===<br />
<br />
A YUI module is structured in a particular way, both on file, and in the<br />
file itself. Before you start writing your module, you need to know a few<br />
bits of information:<br />
* what is the [[Frankenstyle]] name of your Moodle plugin;<br />
* what does your YUI module do in a single word.<br />
<br />
You can use these pieces of information to work out the namespace for your<br />
plugin. This namespace fits into the template:<br />
<br />
moodle-FRANKENSTYLE-MODULENAME<br />
<br />
As an example, writing a plugin for the fictional ''''fruit'''' '''block''' which<br />
offers fruit to users:<br />
* you may decide to call this module the ''''fruitbowl'''' as the module offers fruit to users, and presents it in an appealing way so that they can see it.<br />
* The block is fruit, therefore the frankenstyle name is block_fruit.<br />
<br />
Therefor the name for this module will be:<br />
<br />
moodle-block_fruit-fruitbowl<br />
<br />
<br />
The other thing that you need to know in order to create your first module<br />
is where in your plugin the code needs to be.<br />
<br />
As described in the [[Javascript/Shifter#How_do_I_write_a_YUI_module_which_uses_Shifter.3F]] documentation, the code will need to go in your plugin directory inside a yui directory.<br />
<br />
Since Moodle 2.5, the structure for this directory is:<br />
<code bash><br />
yui/<br />
|-- src<br />
|-- fruitbowl<br />
|-- build.json<br />
|-- js<br />
| |-- fruitbowl.js<br />
|-- meta<br />
|-- fruitbowl.json<br />
</code><br />
''Note: Moodle 2.5 onwards is backwards compatibly with the previous structure.''<br />
<br />
So in the case of moodle-block_fruit-fruitbowl, the JavaScript code will need to go into:<br />
/block/fruit/yui/src/fruitbowl/js/fruitbowl.js<br />
<br />
(Sorry, it does look a little more complicated than it really is)<br />
<br />
See the notes in the [[Javascript/Shifter#How_do_I_write_a_YUI_module_which_uses_Shifter.3F|Shifter]] documentation for details on the build.json and meta/MODULENAME.json file contents.<br />
<br />
Now that you know where your code needs to be on disk, you can actually include and write it.<br />
<br />
=== Including your module from your PHP code ===<br />
<br />
Rather than using <script> tags to include JavaScript code, Moodle makes<br />
use of the YUI loader and a single inline script tag in the page footer.<br />
<br />
Moving JavaScript to a page footer is important to the perceived performance of a page, and the YUI loader helps further.<br />
<br />
The YUI loader also intelligiently loads page dependencies, in as few<br />
requests as possible by making use of a combo-loader system.<br />
It will also attempt to use the appropriate version of your JavaScript<br />
depending on your $CFG->jsrev settings. In normal operation, a minified<br />
version of your code is used; and with $CFG->cachejs false, then a debugging version is used.<br />
<br />
To ensure that your module is loaded, there is a '''yui_module()'''<br />
function on the page requirements class. This can be accessed using:<br />
<br />
<code php><br />
$PAGE->requires->yui_module();<br />
// or:<br />
$this->page->requires->yui_module();<br />
</code><br />
<br />
The yui_module function takes the module name, and the init function to<br />
call as it's first two arguments, and an optional list of arguments as a<br />
third argument:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init');<br />
</code><br />
<br />
==== Passing arguments from your PHP to your module ====<br />
<br />
You may want to pass a set of arguments to your JavaScript. You can do so<br />
using the optional third argument to yui_module which accepts an array of<br />
arguments.<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init',<br />
array(<br />
'value1',<br />
'value2',<br />
));<br />
</code><br />
<br />
These will be presented to the JavaScript function you name:<br />
<br />
<code javascript><br />
init = function(argument1, argument2) {<br />
// Use the arguments here.<br />
};<br />
</code><br />
<br />
Often it makes more sense to pass a single argument with an associative array:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init',<br />
array(array(<br />
'key1' => 'value1',<br />
'key2' => 'value2',<br />
)));<br />
</code><br />
<br />
These will be presented to the JavaScript function you name:<br />
<br />
<code javascript><br />
init = function(params) {<br />
// Use the arguments through params.key1 and params.key2.<br />
};<br />
</code><br />
<br />
=== A basic module ===<br />
<br />
The most common use-case for JavaScript in Moodle is to utilise existing<br />
modules to do something. Your module isn't intended to be reused, or<br />
extended by some other piece of code. In these cases, you want to keep<br />
things simple.<br />
<br />
This section will build up the YUI module gradually, but you can cheat and skip to the [[#Additional_functions_instead_of_anonymous_functions|completed example]].<br />
<br />
==== Namespacing ====<br />
<br />
One of the great benefits of using YUI is the ability to sandbox code in<br />
such a way that you can be sure that it won't interfere with other JS code<br />
in Moodle, this is done by placing your object in a JavaScript object.<br />
Using our fictitious example, this namespace is very similar to the module<br />
name namespace:<br />
<br />
M.FRANKENSTYLE.MODNAME<br />
<br />
As a JavaScript object this would look like:<br />
<br />
<code bash><br />
M: {<br />
FRANKENSTYLE: {<br />
MODNAME: {<br />
// Your code and functions go here.<br />
}<br />
}<br />
}<br />
</code><br />
<br />
The easiest way of creating this structure is by using the logical OR operator.<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
M.block_fruit.fruitbowl = {};<br />
var NS = M.block_fruit.fruitbowl;<br />
</code><br />
<br />
This ensures that any existing code on the M.block_fruit object is not<br />
inadvertently overwritten, but also ensures that the definition for the<br />
fruitbowl code is clean.<br />
<br />
That's to say that, if you have already used your fruitbowl code once on<br />
the page, and have modified it in some way (for example to override a<br />
function), then the next time it is used, it will be in it's original state<br />
with the original function.<br />
<br />
==== Initialisation ====<br />
<br />
Once you have your namespace, you'll want to create one or more functions on this namespace in which to put your code. Typically, we use an 'init' function to perform the initial setup.<br />
The amount that this code does should be kept to a minimum because every<br />
piece of JavaScript which has to be executed at page load is a piece of<br />
code slowing the page down. As a best practice:<br />
* don't modify the DOM unless you need to do so;<br />
* don't create anything you aren't using immediately (for example a JS dialogue hidden until first used); and<br />
* use event delegation where possible.<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
var NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', function(e) {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Add a border to the fruit so we can see that it was selected.<br />
e.setStyle('border', '1px solid black');<br />
}, Y.config.doc, '.fruit');<br />
};<br />
</code><br />
<br />
==== Separation of code from configuration and style (loose coupling) ====<br />
<br />
As another best practice, we encourage you to separate out the code from<br />
configuration, and not to apply any CSS styles directly. Instead, use<br />
techniques to move the configuration out of the code itself and into<br />
variables or attributes, and use CSS classes which the theme can modify.<br />
<br />
Typically to make it easier to read your code, and to modify it later, we<br />
recommend creating two static objects at the top of your code: one for CSS<br />
selectors, and one for CSS class names.<br />
<code javascript><br />
var CSS = {<br />
FRUIT: 'fruit',<br />
SELECTED: 'selected'<br />
},<br />
SELECTORS = {<br />
FRUIT: '.' + CSS.FRUIT<br />
},<br />
NS;<br />
<br />
M.block_fruit = M.block_fruit || {};<br />
NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', function() {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Apply the relevant class which contains indications that this fruit was selected.<br />
e.target.addClass(CSS.SELECTED);<br />
}, Y.config.doc, SELECTORS.FRUIT, this);<br />
};<br />
</code><br />
<br />
With this change, if at a later date you need to change the styling on a<br />
selected fruit, this can be done in the theme. An alternative theme can<br />
also choose to theme the same item in a completely different way.<br />
<br />
It also means that if you need to change the class names, you can do so<br />
once in the JavaScript without making it difficult to work out the purpose<br />
of a particular line of code from git.<br />
<br />
<br />
==== Additional functions instead of anonymous functions ====<br />
<br />
Although it's often quicker to write an inline anonymous function when<br />
you write your event handlers, loops, and at other times, it's often much<br />
easier to read the code if you move it to a function on your namespace and<br />
call it accordingly.<br />
<br />
<code javascript><br />
var CSS = {<br />
FRUIT: 'fruit',<br />
SELECTED: 'selected'<br />
},<br />
SELECTORS = {<br />
FRUIT: '.' + CSS.FRUIT<br />
},<br />
NS;<br />
<br />
M.block_fruit = M.block_fruit || {};<br />
NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', this.handle_selection, Y.config.doc, SELECTORS.FRUIT, this);<br />
};<br />
<br />
NS.handle_selection = function(e) {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Apply the relevant class which contains indications that this fruit was selected.<br />
e.target.addClass(CSS.SELECTED);<br />
};<br />
</code><br />
<br />
Now you can clearly see your what your initialiser does, and you can call handle_selection for other events too without duplicating code.<br />
<br />
=== A re-usable module ===<br />
<br />
{{Work in progress}} This section of documentation has yet to be written.<br />
<br />
=== Notes ===<br />
<br />
There is a proposal to [[YUI/Namespacing|alter the namespace]] for YUI modules. This is likely to be implemented from Moodle 2.7 onwards.<br />
<br />
[[Category:Javascript]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=YUI/Modules&diff=50682YUI/Modules2016-07-27T11:17:38Z<p>Danowar: Oops</p>
<hr />
<div>{{Moodle 2.5}}<br />
{{Moodle 2.6}}<br />
{{Moodle 2.7}}<br />
<br />
== YUI modules ==<br />
<br />
You may want to [[#Additional_functions_instead_of_anonymous_functions|Jump straight to the complete example]].<br />
<br />
=== What is a module and why would I want to use one? ===<br />
<br />
Many people are used to writing their JavaScript code either inline, or in a<br />
separate file included using <script> tags in their HTML. Although both of<br />
these are supported within Moodle, we highly recommend investing a little<br />
time in looking into the [[YUI]] module system as it offers some really great<br />
features which will benefit you in the long run.<br />
<br />
These features and benefits include:<br />
* a host of existing modules that you can hook into and use; which offer<br />
* code sandboxing to ensure that you always have a good/clean copy of the code; with<br />
* powerful dependency management; which can utilise<br />
* asynchronous loading to load dependencies in parallel; and<br />
* loading of dependencies in any order (you don't have to include script tags in a set order); and<br />
* separation of loading from execution; and<br />
* combo loading to reduce the number of individual HTTP transactions.<br />
<br />
By using existing modules in your code, you can benefit in other ways too, such as:<br />
* a consistent look and feel across Moodle; and<br />
* most of the edge cases already catered for.<br />
<br />
The Moodle community is in the process of improving much of its JavaScript<br />
in areas such as code, documentation, and processes. This includes updating<br />
older code, adding documentation, seeding dependency information for<br />
modules to improve load efficiency for browsers, and much more.<br />
<br />
You may find the following resources particularly helpful:<br />
* [[YUI]]; and<br />
* [[YUI/Shifter]].<br />
<br />
=== Structure and naming ===<br />
<br />
A YUI module is structured in a particular way, both on file, and in the<br />
file itself. Before you start writing your module, you need to know a few<br />
bits of information:<br />
* what is the [[Frankenstyle]] name of your Moodle plugin;<br />
* what does your YUI module do in a single word.<br />
<br />
You can use these pieces of information to work out the namespace for your<br />
plugin. This namespace fits into the template:<br />
<br />
moodle-FRANKENSTYLE-MODULENAME<br />
<br />
As an example, writing a plugin for the fictional ''''fruit'''' '''block''' which<br />
offers fruit to users:<br />
* you may decide to call this module the ''''fruitbowl'''' as the module offers fruit to users, and presents it in an appealing way so that they can see it.<br />
* The block is fruit, therefore the frankenstyle name is block_fruit.<br />
<br />
Therefor the name for this module will be:<br />
<br />
moodle-block_fruit-fruitbowl<br />
<br />
<br />
The other thing that you need to know in order to create your first module<br />
is where in your plugin the code needs to be.<br />
<br />
As described in the [[Javascript/Shifter#How_do_I_write_a_YUI_module_which_uses_Shifter.3F]] documentation, the code will need to go in your plugin directory inside a yui directory.<br />
<br />
Since Moodle 2.5, the structure for this directory is:<br />
<code bash><br />
yui/<br />
|-- src<br />
|-- fruitbowl<br />
|-- build.json<br />
|-- js<br />
| |-- fruitbowl.js<br />
|-- meta<br />
|-- fruitbowl.json<br />
</code><br />
''Note: Moodle 2.5 onwards is backwards compatibly with the previous structure.''<br />
<br />
So in the case of moodle-block_fruit-fruitbowl, the JavaScript code will need to go into:<br />
/block/fruit/yui/src/fruitbowl/js/fruitbowl.js<br />
<br />
(Sorry, it does look a little more complicated than it really is)<br />
<br />
See the notes in the [[Javascript/Shifter#How_do_I_write_a_YUI_module_which_uses_Shifter.3F|Shifter]] documentation for details on the build.json and meta/MODULENAME.json file contents.<br />
<br />
Now that you know where your code needs to be on disk, you can actually include and write it.<br />
<br />
=== Including your module from your PHP code ===<br />
<br />
Rather than using <script> tags to include JavaScript code, Moodle makes<br />
use of the YUI loader and a single inline script tag in the page footer.<br />
<br />
Moving JavaScript to a page footer is important to the perceived performance of a page, and the YUI loader helps further.<br />
<br />
The YUI loader also intelligiently loads page dependencies, in as few<br />
requests as possible by making use of a combo-loader system.<br />
It will also attempt to use the appropriate version of your JavaScript<br />
depending on your $CFG->jsrev settings. In normal operation, a minified<br />
version of your code is used; and with $CFG->cachejs false, then a debugging version is used.<br />
<br />
To ensure that your module is loaded, there is a '''yui_module()'''<br />
function on the page requirements class. This can be accessed using:<br />
<br />
<code php><br />
$PAGE->requires->yui_module();<br />
// or:<br />
$this->page->requires->yui_module();<br />
</code><br />
<br />
The yui_module function takes the module name, and the init function to<br />
call as it's first two arguments, and an optional list of arguments as a<br />
third argument:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init');<br />
</code><br />
<br />
==== Passing arguments from your PHP to your module ====<br />
<br />
You may want to pass a set of arguments to your JavaScript. You can do so<br />
using the optional third argument to yui_module which accepts an array of<br />
arguments.<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init',<br />
array(<br />
'value1',<br />
'value2',<br />
));<br />
</code><br />
<br />
These will be presented to the JavaScript function you name:<br />
<br />
<code javascript><br />
init = function(argument1, argument2) {<br />
// Use the arguments here.<br />
};<br />
</code><br />
<br />
Often it makes more sense to pass a single argument with an associative array:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init',<br />
array(array(<br />
'key1' => 'value1',<br />
'key2' => 'value2',<br />
)));<br />
</code><br />
<br />
These will be presented to the JavaScript function you name:<br />
<br />
<code javascript><br />
init = function(params) {<br />
// Use the arguments through params.key1 and params.key2.<br />
};<br />
</code><br />
<br />
=== A basic module ===<br />
<br />
The most common use-case for JavaScript in Moodle is to utilise existing<br />
modules to do something. Your module isn't intended to be reused, or<br />
extended by some other piece of code. In these cases, you want to keep<br />
things simple.<br />
<br />
This section will build up the YUI module gradually, but you can cheat and skip to the [[#Additional_functions_instead_of_anonymous_functions|completed example]].<br />
<br />
==== Namespacing ====<br />
<br />
One of the great benefits of using YUI is the ability to sandbox code in<br />
such a way that you can be sure that it won't interfere with other JS code<br />
in Moodle, this is done by placing your object in a JavaScript object.<br />
Using our fictitious example, this namespace is very similar to the module<br />
name namespace:<br />
<br />
M.FRANKENSTYLE.MODNAME<br />
<br />
As a JavaScript object this would look like:<br />
<br />
<code bash><br />
M: {<br />
FRANKENSTYLE: {<br />
MODNAME: {<br />
// Your code and functions go here.<br />
}<br />
}<br />
}<br />
</code><br />
<br />
The easiest way of creating this structure is by using the logical OR operator.<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
M.block_fruit.fruitbowl = {};<br />
var NS = M.block_fruit.fruitbowl;<br />
</code><br />
<br />
This ensures that any existing code on the M.block_fruit object is not<br />
inadvertently overwritten, but also ensures that the definition for the<br />
fruitbowl code is clean.<br />
<br />
That's to say that, if you have already used your fruitbowl code once on<br />
the page, and have modified it in some way (for example to override a<br />
function), then the next time it is used, it will be in it's original state<br />
with the original function.<br />
<br />
==== Initialisation ====<br />
<br />
Once you have your namespace, you'll want to create one or more functions on this namespace in which to put your code. Typically, we use an 'init' function to perform the initial setup.<br />
The amount that this code does should be kept to a minimum because every<br />
piece of JavaScript which has to be executed at page load is a piece of<br />
code slowing the page down. As a best practice:<br />
* don't modify the DOM unless you need to do so;<br />
* don't create anything you aren't using immediately (for example a JS dialogue hidden until first used); and<br />
* use event delegation where possible.<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
var NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', function(e) {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Add a border to the fruit so we can see that it was selected.<br />
e.setStyle('border', '1px solid black');<br />
}, Y.config.doc, '.fruit');<br />
};<br />
</code><br />
<br />
==== Separation of code from configuration and style (loose coupling) ====<br />
<br />
As another best practice, we encourage you to separate out the code from<br />
configuration, and not to apply any CSS styles directly. Instead, use<br />
techniques to move the configuration out of the code itself and into<br />
variables or attributes, and use CSS classes which the theme can modify.<br />
<br />
Typically to make it easier to read your code, and to modify it later, we<br />
recommend creating two static objects at the top of your code: one for CSS<br />
selectors, and one for CSS class names.<br />
<code javascript><br />
var CSS = {<br />
FRUIT: 'fruit',<br />
SELECTED: 'selected'<br />
},<br />
SELECTORS = {<br />
FRUIT: '.' + CSS.FRUIT<br />
},<br />
NS;<br />
<br />
M.block_fruit = M.block_fruit || {};<br />
NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', function() {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Apply the relevant class which contains indications that this fruit was selected.<br />
e.target.addClass(CSS.SELECTED);<br />
}, Y.config.doc, SELECTORS.FRUIT, this);<br />
};<br />
</code><br />
<br />
With this change, if at a later date you need to change the styling on a<br />
selected fruit, this can be done in the theme. An alternative theme can<br />
also choose to theme the same item in a completely different way.<br />
<br />
It also means that if you need to change the class names, you can do so<br />
once in the JavaScript without making it difficult to work out the purpose<br />
of a particular line of code from git.<br />
<br />
<br />
==== Additional functions instead of anonymous functions ====<br />
<br />
Although it's often quicker to write an inline anonymous function when<br />
you write your event handlers, loops, and at other times, it's often much<br />
easier to read the code if you move it to a function on your namespace and<br />
call it accordingly.<br />
<br />
<code javascript><br />
var CSS = {<br />
FRUIT: 'fruit',<br />
SELECTED: 'selected'<br />
},<br />
SELECTORS = {<br />
FRUIT: '.' + CSS.FRUIT<br />
},<br />
NS;<br />
<br />
M.block_fruit = M.block_fruit || {};<br />
NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', this.handle_selection, Y.config.doc, SELECTORS.FRUIT, this);<br />
};<br />
<br />
NS.handle_selection = function(e) {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Apply the relevant class which contains indications that this fruit was selected.<br />
e.target.addClass(CSS.SELECTED);<br />
};<br />
</code><br />
<br />
Now you can clearly see your what your initialiser does, and you can call handle_selection for other events too without duplicating code.<br />
<br />
=== A re-usable module ===<br />
<br />
{{Work in progress}} This section of documentation has yet to be written.<br />
<br />
=== Notes ===<br />
<br />
There is a proposal to [[YUI/Namespacing|alter the namespace]] for YUI modules. This is likely to be implemented from Moodle 2.7 onwards.</div>Danowarhttps://docs.moodle.org/dev/index.php?title=YUI/Modules&diff=50681YUI/Modules2016-07-27T11:17:13Z<p>Danowar: </p>
<hr />
<div>{{Moodle 2.5}}<br />
{{Moodle 2.6}}<br />
{{Moodle 2.7}}<br />
{{Javascript}}<br />
<br />
== YUI modules ==<br />
<br />
You may want to [[#Additional_functions_instead_of_anonymous_functions|Jump straight to the complete example]].<br />
<br />
=== What is a module and why would I want to use one? ===<br />
<br />
Many people are used to writing their JavaScript code either inline, or in a<br />
separate file included using <script> tags in their HTML. Although both of<br />
these are supported within Moodle, we highly recommend investing a little<br />
time in looking into the [[YUI]] module system as it offers some really great<br />
features which will benefit you in the long run.<br />
<br />
These features and benefits include:<br />
* a host of existing modules that you can hook into and use; which offer<br />
* code sandboxing to ensure that you always have a good/clean copy of the code; with<br />
* powerful dependency management; which can utilise<br />
* asynchronous loading to load dependencies in parallel; and<br />
* loading of dependencies in any order (you don't have to include script tags in a set order); and<br />
* separation of loading from execution; and<br />
* combo loading to reduce the number of individual HTTP transactions.<br />
<br />
By using existing modules in your code, you can benefit in other ways too, such as:<br />
* a consistent look and feel across Moodle; and<br />
* most of the edge cases already catered for.<br />
<br />
The Moodle community is in the process of improving much of its JavaScript<br />
in areas such as code, documentation, and processes. This includes updating<br />
older code, adding documentation, seeding dependency information for<br />
modules to improve load efficiency for browsers, and much more.<br />
<br />
You may find the following resources particularly helpful:<br />
* [[YUI]]; and<br />
* [[YUI/Shifter]].<br />
<br />
=== Structure and naming ===<br />
<br />
A YUI module is structured in a particular way, both on file, and in the<br />
file itself. Before you start writing your module, you need to know a few<br />
bits of information:<br />
* what is the [[Frankenstyle]] name of your Moodle plugin;<br />
* what does your YUI module do in a single word.<br />
<br />
You can use these pieces of information to work out the namespace for your<br />
plugin. This namespace fits into the template:<br />
<br />
moodle-FRANKENSTYLE-MODULENAME<br />
<br />
As an example, writing a plugin for the fictional ''''fruit'''' '''block''' which<br />
offers fruit to users:<br />
* you may decide to call this module the ''''fruitbowl'''' as the module offers fruit to users, and presents it in an appealing way so that they can see it.<br />
* The block is fruit, therefore the frankenstyle name is block_fruit.<br />
<br />
Therefor the name for this module will be:<br />
<br />
moodle-block_fruit-fruitbowl<br />
<br />
<br />
The other thing that you need to know in order to create your first module<br />
is where in your plugin the code needs to be.<br />
<br />
As described in the [[Javascript/Shifter#How_do_I_write_a_YUI_module_which_uses_Shifter.3F]] documentation, the code will need to go in your plugin directory inside a yui directory.<br />
<br />
Since Moodle 2.5, the structure for this directory is:<br />
<code bash><br />
yui/<br />
|-- src<br />
|-- fruitbowl<br />
|-- build.json<br />
|-- js<br />
| |-- fruitbowl.js<br />
|-- meta<br />
|-- fruitbowl.json<br />
</code><br />
''Note: Moodle 2.5 onwards is backwards compatibly with the previous structure.''<br />
<br />
So in the case of moodle-block_fruit-fruitbowl, the JavaScript code will need to go into:<br />
/block/fruit/yui/src/fruitbowl/js/fruitbowl.js<br />
<br />
(Sorry, it does look a little more complicated than it really is)<br />
<br />
See the notes in the [[Javascript/Shifter#How_do_I_write_a_YUI_module_which_uses_Shifter.3F|Shifter]] documentation for details on the build.json and meta/MODULENAME.json file contents.<br />
<br />
Now that you know where your code needs to be on disk, you can actually include and write it.<br />
<br />
=== Including your module from your PHP code ===<br />
<br />
Rather than using <script> tags to include JavaScript code, Moodle makes<br />
use of the YUI loader and a single inline script tag in the page footer.<br />
<br />
Moving JavaScript to a page footer is important to the perceived performance of a page, and the YUI loader helps further.<br />
<br />
The YUI loader also intelligiently loads page dependencies, in as few<br />
requests as possible by making use of a combo-loader system.<br />
It will also attempt to use the appropriate version of your JavaScript<br />
depending on your $CFG->jsrev settings. In normal operation, a minified<br />
version of your code is used; and with $CFG->cachejs false, then a debugging version is used.<br />
<br />
To ensure that your module is loaded, there is a '''yui_module()'''<br />
function on the page requirements class. This can be accessed using:<br />
<br />
<code php><br />
$PAGE->requires->yui_module();<br />
// or:<br />
$this->page->requires->yui_module();<br />
</code><br />
<br />
The yui_module function takes the module name, and the init function to<br />
call as it's first two arguments, and an optional list of arguments as a<br />
third argument:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init');<br />
</code><br />
<br />
==== Passing arguments from your PHP to your module ====<br />
<br />
You may want to pass a set of arguments to your JavaScript. You can do so<br />
using the optional third argument to yui_module which accepts an array of<br />
arguments.<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init',<br />
array(<br />
'value1',<br />
'value2',<br />
));<br />
</code><br />
<br />
These will be presented to the JavaScript function you name:<br />
<br />
<code javascript><br />
init = function(argument1, argument2) {<br />
// Use the arguments here.<br />
};<br />
</code><br />
<br />
Often it makes more sense to pass a single argument with an associative array:<br />
<br />
<code php><br />
$PAGE->requires->yui_module('moodle-block_fruit-fruitbowl',<br />
'M.block_fruit.fruitbowl.init',<br />
array(array(<br />
'key1' => 'value1',<br />
'key2' => 'value2',<br />
)));<br />
</code><br />
<br />
These will be presented to the JavaScript function you name:<br />
<br />
<code javascript><br />
init = function(params) {<br />
// Use the arguments through params.key1 and params.key2.<br />
};<br />
</code><br />
<br />
=== A basic module ===<br />
<br />
The most common use-case for JavaScript in Moodle is to utilise existing<br />
modules to do something. Your module isn't intended to be reused, or<br />
extended by some other piece of code. In these cases, you want to keep<br />
things simple.<br />
<br />
This section will build up the YUI module gradually, but you can cheat and skip to the [[#Additional_functions_instead_of_anonymous_functions|completed example]].<br />
<br />
==== Namespacing ====<br />
<br />
One of the great benefits of using YUI is the ability to sandbox code in<br />
such a way that you can be sure that it won't interfere with other JS code<br />
in Moodle, this is done by placing your object in a JavaScript object.<br />
Using our fictitious example, this namespace is very similar to the module<br />
name namespace:<br />
<br />
M.FRANKENSTYLE.MODNAME<br />
<br />
As a JavaScript object this would look like:<br />
<br />
<code bash><br />
M: {<br />
FRANKENSTYLE: {<br />
MODNAME: {<br />
// Your code and functions go here.<br />
}<br />
}<br />
}<br />
</code><br />
<br />
The easiest way of creating this structure is by using the logical OR operator.<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
M.block_fruit.fruitbowl = {};<br />
var NS = M.block_fruit.fruitbowl;<br />
</code><br />
<br />
This ensures that any existing code on the M.block_fruit object is not<br />
inadvertently overwritten, but also ensures that the definition for the<br />
fruitbowl code is clean.<br />
<br />
That's to say that, if you have already used your fruitbowl code once on<br />
the page, and have modified it in some way (for example to override a<br />
function), then the next time it is used, it will be in it's original state<br />
with the original function.<br />
<br />
==== Initialisation ====<br />
<br />
Once you have your namespace, you'll want to create one or more functions on this namespace in which to put your code. Typically, we use an 'init' function to perform the initial setup.<br />
The amount that this code does should be kept to a minimum because every<br />
piece of JavaScript which has to be executed at page load is a piece of<br />
code slowing the page down. As a best practice:<br />
* don't modify the DOM unless you need to do so;<br />
* don't create anything you aren't using immediately (for example a JS dialogue hidden until first used); and<br />
* use event delegation where possible.<br />
<br />
<code javascript><br />
M.block_fruit = M.block_fruit || {};<br />
var NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', function(e) {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Add a border to the fruit so we can see that it was selected.<br />
e.setStyle('border', '1px solid black');<br />
}, Y.config.doc, '.fruit');<br />
};<br />
</code><br />
<br />
==== Separation of code from configuration and style (loose coupling) ====<br />
<br />
As another best practice, we encourage you to separate out the code from<br />
configuration, and not to apply any CSS styles directly. Instead, use<br />
techniques to move the configuration out of the code itself and into<br />
variables or attributes, and use CSS classes which the theme can modify.<br />
<br />
Typically to make it easier to read your code, and to modify it later, we<br />
recommend creating two static objects at the top of your code: one for CSS<br />
selectors, and one for CSS class names.<br />
<code javascript><br />
var CSS = {<br />
FRUIT: 'fruit',<br />
SELECTED: 'selected'<br />
},<br />
SELECTORS = {<br />
FRUIT: '.' + CSS.FRUIT<br />
},<br />
NS;<br />
<br />
M.block_fruit = M.block_fruit || {};<br />
NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', function() {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Apply the relevant class which contains indications that this fruit was selected.<br />
e.target.addClass(CSS.SELECTED);<br />
}, Y.config.doc, SELECTORS.FRUIT, this);<br />
};<br />
</code><br />
<br />
With this change, if at a later date you need to change the styling on a<br />
selected fruit, this can be done in the theme. An alternative theme can<br />
also choose to theme the same item in a completely different way.<br />
<br />
It also means that if you need to change the class names, you can do so<br />
once in the JavaScript without making it difficult to work out the purpose<br />
of a particular line of code from git.<br />
<br />
<br />
==== Additional functions instead of anonymous functions ====<br />
<br />
Although it's often quicker to write an inline anonymous function when<br />
you write your event handlers, loops, and at other times, it's often much<br />
easier to read the code if you move it to a function on your namespace and<br />
call it accordingly.<br />
<br />
<code javascript><br />
var CSS = {<br />
FRUIT: 'fruit',<br />
SELECTED: 'selected'<br />
},<br />
SELECTORS = {<br />
FRUIT: '.' + CSS.FRUIT<br />
},<br />
NS;<br />
<br />
M.block_fruit = M.block_fruit || {};<br />
NS = M.block_fruit.fruitbowl = {};<br />
<br />
NS.init = function() {<br />
Y.delegate('click', this.handle_selection, Y.config.doc, SELECTORS.FRUIT, this);<br />
};<br />
<br />
NS.handle_selection = function(e) {<br />
// Alert users when they've clicked on some fruit to tell them the obvious.<br />
alert("You clicked on some fruit");<br />
<br />
// Apply the relevant class which contains indications that this fruit was selected.<br />
e.target.addClass(CSS.SELECTED);<br />
};<br />
</code><br />
<br />
Now you can clearly see your what your initialiser does, and you can call handle_selection for other events too without duplicating code.<br />
<br />
=== A re-usable module ===<br />
<br />
{{Work in progress}} This section of documentation has yet to be written.<br />
<br />
=== Notes ===<br />
<br />
There is a proposal to [[YUI/Namespacing|alter the namespace]] for YUI modules. This is likely to be implemented from Moodle 2.7 onwards.</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Progressive_enhancement&diff=50680Progressive enhancement2016-07-27T08:34:52Z<p>Danowar: Broken link fixed</p>
<hr />
<div>'''Progressive enhancement''' is a new spin on the popular web design concept of ''graceful degredation''. While the latter focuses on the visual presentation of a web page for the mainstream audience, progressive enhancement prioritises delivering the content and functionality to everyone. By ensuring that it works for every user regardless of technology platform and then adding any non-essential functionality that requires certain capabilities in the browser (or its user) onto that baseline it ensures [[Usability|usability]] and [[accessibility]].<br />
<br />
<br />
== Progressive enhancement and Moodle ==<br />
<br />
=== YUI ===<br />
Moodle has adopted the [[YUI | Yahoo! user interface library]] as a platform to build [[AJAX]] and DHTML enhancements with. Yahoo! have adopted progressive enhancement as one of their key design goals for the library.<br />
<br />
=== Hijax ===<br />
<br />
Many of most popular AJAX applications were written from scratch with that goal in mind. While that may have saved them time and effort, it also makes it very easy to not support progressive enhancement. Coding for the mainstream audience first may make it very difficult to add support for everyone later. Moodle on the other hand was designed and built in a pre-AJAX age and so already has that infrastructure. [[Hijax]] is the name given to the technique of adding AJAX without removing or replacing the fall-back for less capable browsers. <br />
<br />
<br />
== See also ==<br />
<br />
* [[Javascript]]<br />
* [[AJAX]]<br />
* [[Hijax]]<br />
* [[Javascript FAQ]]<br />
<br />
* [http://hesketh.com/publications/inclusive_web_design_for_the_future/ ''Inclusive Web Design For the Future with Progressive Enhancement'' presentation]<br />
* [http://adactio.com/journal/959 ''Progressive enhancement with Ajax'' blog post]<br />
* [http://hesketh.com/publications/progressive_enhancement_paving_way_for_future.html ''Progressive Enhancement: Paving the Way for Future Web Design'' article]<br />
<br />
[[Category:Javascript]]<br />
[[Category:AJAX]]<br />
[[Category:Accessibility|Progressive enhancement]]</div>Danowarhttps://docs.moodle.org/dev/index.php?title=Automatic_class_loading&diff=50428Automatic class loading2016-06-16T12:14:27Z<p>Danowar: </p>
<hr />
<div>{{Moodle 2.6}}<br />
<br />
This document describes how to use the functionality of the automatic classloader provided by Moodle.<br />
<br />
==Class naming==<br />
<br />
To be discoverable by the Moodle automatic classloader, classes must adhere to the following class naming rules:<br />
* [[Frankenstyle]] Prefixes<br />
** Core classes must start with the prefix ''core_''.<br />
** Plugin class names must start with names such as ''mod_forum_'' (in the example of /mod/forum)<br />
* One class file for each class<br />
* Class file names must be class name without Frankenstyle prefix<br />
** e.g. Class '''mod_forum_some_class''' is stored in file '''mod/forum/classes/some_class.php'''<br />
** e.g. Class '''core_frankenstyle''' class is stored in '''lib/classes/frankenstyle.php'''<br />
<br />
==Class files and locations==<br />
<br />
The Moodle automatic classloader looks for classes only in specific locations (all caps represents a symbolic name, replace it with a real location)<br />
* Core classes<br />
** '''/lib/classes/''' and its subdirectories<br />
** '''SUBSYSTEMDIR/classes/''' and its subdirectories<br />
*** The list of subsystems and their respective directories can be found in code (/lib/classes/component.php, function fetch_subsystems)<br />
* Plugin classes<br />
** /PLUGIN/DIR/classes and its subdirectories<br />
<br />
==Code Examples==<br />
<br />
Example of autoloaded class in forum module:<br />
<br />
<code php><br />
<?php<br />
// file mod/forum/classes/some_class.php<br />
<br />
class mod_forum_some_class {<br />
<br />
}<br />
</code><br />
<br />
<code php><br />
<?php<br />
// file mod/forum/lib.php<br />
<br />
// no require_once() necessary here<br />
<br />
$instance = new mod_forum_some_class();<br />
<br />
</code><br />
<br />
<code php><br />
<br />
<?php<br />
<br />
// in any file<br />
<br />
if (class_exists('mod_forum_some_class')) {<br />
// do something<br />
}<br />
</code><br />
<br />
==Namespaces==<br />
<br />
PHP namespaces are designed to improve code organisation in your projects. Directory structure in classes/ is matching the namespace structure.<br />
<br />
<br />
Example:<br />
<br />
<code php><br />
<?php<br />
<br />
namespace core\event;<br />
<br />
// file lib/classes/event/base.php<br />
<br />
class base {<br />
}<br />
</code><br />
<br />
<code php><br />
<?php<br />
<br />
namespace mod_forum\event;<br />
<br />
// file mod/forums/classes/event/post_read.php<br />
<br />
class post_read extends \core\event\base {<br />
<br />
}<br />
</code><br />
<br />
<code php><br />
<?php<br />
<br />
// in any file<br />
<br />
\mod_forum\event\post_read::create($post->id, ...)->trigger();<br />
<br />
</code><br />
<br />
==Backwards compatibility==<br />
There are no know issues that could cause backwards incompatibility, however it is strongly recommended to use the classes subdirectory only for classes that are included automatically.<br />
<br />
==Performance and developer mode==<br />
<br />
Class autoloading improves performance and reduces memory footprint. Location of all classes is automatically stored in class map cache, the cache is updated automatically before upgrade or installation, during cache reset and in developer mode.<br />
<br />
There is only one inconvenience - if you add new class or remove it you need to do one of the following:<br />
* visit yourserver/admin/index.php<br />
* purge caches<br />
* or add '''$CFG->debug = (E_ALL | E_STRICT);''' to your config.php<br />
<br />
Otherwise the new class would not be found.<br />
<br />
==See also==<br />
<br />
* [[Frankenstyle]]<br />
* [[Automatic Class Loading Proposal]]<br />
<br />
[[Category:Plugins]]</div>Danowar