Development:JavaScript namespacing proposal: Difference between revisions
Sam Hemelryk (talk | contribs) (New page: The idea of JavaScript namespacing was raised during the developers meeting that occured on Tuesday 29th September 2009 and I think its a fantastic idea, so I wrote this wee proposal and p...) |
Sam Hemelryk (talk | contribs) No edit summary |
||
Line 5: | Line 5: | ||
===Concept=== | ===Concept=== | ||
The concept is to apply a namespacing scheme to the JavaScript that is used by Moodle core code. By namespacing the JavaScript we can better define the structure of the JavaScript code as well as hopefully make it both more easily accessible and with any luck make it easier to develop JavaScript that is potentially reusable. | The concept is to apply a namespacing scheme to the JavaScript that is used by Moodle core code. By namespacing the JavaScript we can better define the structure of the JavaScript code as well as hopefully make it both more easily accessible and with any luck make it easier to develop JavaScript that is potentially reusable. | ||
===The root namespace=== | ===The root namespace=== | ||
After discussing this with the development team it was decided that the core namespace will be <strong>M</strong>. The original concept was to go with MOODLE however we decided that there was no need to go with the so many characters where one would do, and this fit in with the changes YUI was making in the release of version 3.0 changing their root namespace from <strong>YAHOO</strong> to | |||
<strong>Y</strong>. | |||
===Core namespaces=== | ===Core namespaces=== | ||
The following are namspaces that will be created in order to support the initial conversion to a namespaced JavaScript core. | The following are namspaces that will be created in order to support the initial conversion to a namespaced JavaScript core. | ||
; | ; control : JavaScript that creates controls, or structures used throughout Moodle. | ||
; dom : JavaScript for interacting with the DOM. | ; dom : JavaScript for interacting with the DOM. | ||
; form : JavaScript for interacting with forms. | ; form : JavaScript for interacting with forms. | ||
; util : Miscellaneous JavaScript functions. | |||
; util : | |||
; user : JavaScript that is utilised in direct respect to the user. | ; user : JavaScript that is utilised in direct respect to the user. | ||
===Creating new namespaces=== | |||
Ideally additional code (or as it is being converted) should be namespaced directly after M with a name fitting to the PHP code. For modules this would be the module name e.g. M.forum . | |||
===Time estimate=== | ===Time estimate=== | ||
Line 40: | Line 26: | ||
===Implementation=== | ===Implementation=== | ||
The implementation of the core namespace and supporting functions to further namespace is reasonably simple, however it would need to be the very first bit of Moodle | The implementation of the core namespace and supporting functions to further namespace is reasonably simple, however it would need to be the very first bit of Moodle JavaScript to be executed. This simply means it would be defined and set up within javascript-priority.js which is the first file to be included in the HTML head. | ||
===Conversion of JavaScript files=== | ===Conversion of JavaScript files=== | ||
Line 51: | Line 37: | ||
|- | |- | ||
| block_hider | | block_hider | ||
| | | M.util.block_hider | ||
| object | | object | ||
|- | |- | ||
| checkall | | checkall | ||
| | | M.form.check_all | ||
| function | | function | ||
|- | |- | ||
| checknone | | checknone | ||
| | | M.form.check_none | ||
| function | | function | ||
|- | |- | ||
| collapsible_region | | collapsible_region | ||
| | | M.dom.collapsible_region | ||
| object | | object | ||
|- | |- | ||
| deselect_all_in | | deselect_all_in | ||
| | | M.form.deselect_all_in | ||
| function | | function | ||
|- | |- | ||
| findParentNode | | findParentNode | ||
| | | M.dom.find_parent | ||
| function | | function | ||
|- | |- | ||
| fix_column_width | | fix_column_width | ||
| | | M.util.fix_column_width | ||
| function | | function | ||
|- | |- | ||
| fix_column_widths | | fix_column_widths | ||
| | | M.util.fix_column_widths | ||
| function | | function | ||
|- | |- | ||
| focuscontrol | | focuscontrol | ||
| | | M.form.set_focus | ||
| function | | function | ||
|- | |- | ||
| frame_breakout | | frame_breakout | ||
| | | M.frame.add_breakout_target | ||
| function | | function | ||
|- | |- | ||
| init_help_icons | | init_help_icons | ||
| | | M.util.init_help_icons | ||
| function | | function | ||
|- | |- | ||
| openpopup | | openpopup | ||
| | | M.util.window.popup | ||
| function | | function | ||
|- | |- | ||
| select_all_in | | select_all_in | ||
| | | M.form.select_all_in | ||
| function | | function | ||
|- | |- | ||
| submit_form_by_id | | submit_form_by_id | ||
| | | M.form.submit_form_by_id | ||
| function | | function | ||
|- | |- | ||
| emoticons_help | | emoticons_help | ||
| | | M.util.emoticons_help | ||
| object | | object | ||
|- | |- | ||
Line 123: | Line 109: | ||
|- | |- | ||
| build_querystring | | build_querystring | ||
| | | M.util.build_query_string | ||
| function | | function | ||
|- | |- | ||
| cancel_scroll_to_end | | cancel_scroll_to_end | ||
| | | M.util.scroll.cancel_autoscroll | ||
| function | | function | ||
|- | |- | ||
| close_window | | close_window | ||
| | | M.util.window.close | ||
| function | | function | ||
|- | |- | ||
| close_window_reload | | close_window_reload | ||
| | | M.util.window.reload_close | ||
| function | | function | ||
|- | |- | ||
| confirm_dialog | | confirm_dialog | ||
| | | M.control.confirmdialog | ||
| object | | object | ||
|- | |- | ||
| create_UFO_object | | create_UFO_object | ||
| | | M.control.ufo.create | ||
| function | | function | ||
|- | |- | ||
| destroy_item | | destroy_item | ||
| | | M.dom.element.remove | ||
| function | | function | ||
|- | |- | ||
Line 155: | Line 141: | ||
|- | |- | ||
| hide_item | | hide_item | ||
| | | M.dom.element.hide | ||
| function | | function | ||
|- | |- | ||
| json_decode | | json_decode | ||
| | | M.util.json.decode | ||
| function | | function | ||
|- | |- | ||
| json_encode | | json_encode | ||
| | | M.util.json.encode | ||
| function | | function | ||
|- | |- | ||
| repeatedly_scroll_t | | repeatedly_scroll_t | ||
| | | M.util.scroll.autoscroll | ||
| function | | function | ||
|- | |- | ||
| scroll_to_end | | scroll_to_end | ||
| | | M.util.scroll.bottom | ||
| function | | function | ||
|- | |- | ||
| | | | ||
| | | M.util.scroll.top | ||
| function | | function | ||
|- | |- | ||
| set_user_preference | | set_user_preference | ||
| | | M.user.set_preference | ||
| function | | function | ||
|- | |- | ||
| show_item | | show_item | ||
| | | M.dom.element.show | ||
| function | | function | ||
|- | |- | ||
| stripHTML | | stripHTML | ||
| | | M.util.strip_html | ||
| function | | function | ||
|- | |- | ||
| unmaskPassword | | unmaskPassword | ||
| | | M.form.unmask_password | ||
| function | | function | ||
|- | |- | ||
| update_progress_bar | | update_progress_bar | ||
| | | M.control.progressbar.update | ||
| function | | function | ||
|} | |} | ||
Line 207: | Line 193: | ||
|- | |- | ||
| create_shadow | | create_shadow | ||
| | | M.control.shadow.create | ||
| function | | function | ||
|- | |- | ||
| move_all_sidetabs_t... | | move_all_sidetabs_t... | ||
| | | M.control.dock.undock_all | ||
| function | | function | ||
|- | |- | ||
| navigation_tab_panel | | navigation_tab_panel | ||
| | | M.control.dock | ||
| object | | object | ||
|- | |- | ||
| navigation_tree | | navigation_tree | ||
| | | M.control.tree | ||
| object | | object | ||
|- | |- | ||
| navigation_tree_branch | | navigation_tree_branch | ||
| | | M.control.tree.branch | ||
| object | | object | ||
|- | |- | ||
| remove_shadow | | remove_shadow | ||
| | | M.control.shadow.remove | ||
| function | | function | ||
|- | |- | ||
| setup_new_navtree | | setup_new_navtree | ||
| | | M.control.tree.init | ||
| function | | function | ||
|} | |} | ||
Line 243: | Line 229: | ||
|- | |- | ||
| deprecate | | deprecate | ||
| | | M.util.deprecate | ||
| function | | function | ||
|- | |- | ||
| deprecated_addonload | | deprecated_addonload | ||
| | | M.util.deprecated.addonload | ||
| function | | function | ||
|- | |- | ||
| deprecated_confirm_if | | deprecated_confirm_if | ||
| | | M.util.deprecated.confirm_if | ||
| function | | function | ||
|- | |- | ||
| submitFormById | | submitFormById | ||
| | | M.util.deprecated.submitFormById | ||
| function | | function | ||
|} | |} | ||
Line 267: | Line 253: | ||
|- | |- | ||
| date_selector_calendar | | date_selector_calendar | ||
| | | M.form.mforms.date_selector.calendar | ||
| object | | object | ||
|- | |- | ||
| elementShowAdvanced | | elementShowAdvanced | ||
| | | M.form.mforms.show_advanced.show | ||
| function | | function | ||
|- | |- | ||
| get_form_element_value | | get_form_element_value | ||
| | | M.form.mforms.get_element_value | ||
| function | | function | ||
|- | |- | ||
| init_date_selectors | | init_date_selectors | ||
| | | M.form.mforms.date_selector.init | ||
| function | | function | ||
|- | |- | ||
| lockoptionsall | | lockoptionsall | ||
| | | M.form.mforms.lockoptionsall | ||
| function | | function | ||
|- | |- | ||
| lockoptionsallsetup | | lockoptionsallsetup | ||
| | | M.form.mforms.lockoptionsallsetup | ||
| function | | function | ||
|- | |- | ||
| set_form_element_disabled | | set_form_element_disabled | ||
| | | M.form.mforms.disable_element | ||
| funciton | | funciton | ||
|- | |- | ||
| showAdvancedInit | | showAdvancedInit | ||
| | | M.form.mforms.show_advanced.init | ||
| function | | function | ||
|- | |- | ||
| showAdvancedOnClick | | showAdvancedOnClick | ||
| | | M.form.mforms.show_advanced.handle_click | ||
| function | | function | ||
|} | |} | ||
===Resulting namespaced structure=== | ===Resulting namespaced structure=== | ||
*<strong> | *<strong>M</strong> | ||
**<strong> | **<strong>control</strong> | ||
***<em>confirmdialog</em> | ***<em>confirmdialog</em> | ||
***<em>dock</em> | ***<em>dock</em> | ||
Line 371: | Line 357: | ||
**<strong>user</strong> | **<strong>user</strong> | ||
***set_preference | ***set_preference | ||
===Why bother?=== | |||
Because .... | |||
# It greatly reduces the chances of developers accidentally creating clashing methods, or variables. Not just with core code but more importantly conflicts that may arise between 3rd party extensions. | |||
# Hopefully make the JavaScript code more usable and obvious by providing better organisation and structure. This will in turn hopefully reduce the number of identical functions that arise. | |||
# It's the sort of thing that can only be done when revision of code is necessary and there's no time like a major release for that. | |||
# It looks better, more organised. | |||
===Questions=== | |||
To answer a few quick questions about the process: | |||
; How long would it take to namespace the JavaScript : It wouldn't take very long at all to go through and apply a namespacing scheme to the JavaScript once the structure has been decided upon. Once the JavaScript has been namespaced it would be a simple case of iterating through the files that make up Moodle and converting references to the original JavaScript functions to their namespaced equivalents. | |||
; Does all JavaScript have to be namespaced : No not at all. Initially only the core JavaScript files would be converted. After this it would be up to developers to namespace their code should they choose to.... it would be the perfect opportunity to revise that legacy JavaScript ;) | |||
; What about code that uses the old function calls? : All of the core uses should be converted as part of the task of namespacing however we certainly need to support the old function calls. We will create mapping functions that simply take a call to a non-namespaced function and pass it to its namespaced equivalent. | |||
; Will any of the JavaScript change? : No. A couple of new internal functions will be introduced to support namespacing however the actual JavaScript functions being namespaced will not change. You will still be able to call them as you did before, you will just need to use the namespaced reference. |
Revision as of 08:26, 30 September 2009
The idea of JavaScript namespacing was raised during the developers meeting that occured on Tuesday 29th September 2009 and I think its a fantastic idea, so I wrote this wee proposal and plan to hopefully win people over and get this is in for Moodle 2.0.
Note: This proposal assumes that the patch proposed for MDL-16699 that splits javascript-static into two files and moves JavaScript that is only being used in a single place within Moodle to a file that can be included by the code that uses it.
Concept
The concept is to apply a namespacing scheme to the JavaScript that is used by Moodle core code. By namespacing the JavaScript we can better define the structure of the JavaScript code as well as hopefully make it both more easily accessible and with any luck make it easier to develop JavaScript that is potentially reusable.
The root namespace
After discussing this with the development team it was decided that the core namespace will be M. The original concept was to go with MOODLE however we decided that there was no need to go with the so many characters where one would do, and this fit in with the changes YUI was making in the release of version 3.0 changing their root namespace from YAHOO to
Y.
Core namespaces
The following are namspaces that will be created in order to support the initial conversion to a namespaced JavaScript core.
- control
- JavaScript that creates controls, or structures used throughout Moodle.
- dom
- JavaScript for interacting with the DOM.
- form
- JavaScript for interacting with forms.
- util
- Miscellaneous JavaScript functions.
- user
- JavaScript that is utilised in direct respect to the user.
Creating new namespaces
Ideally additional code (or as it is being converted) should be namespaced directly after M with a name fitting to the PHP code. For modules this would be the module name e.g. M.forum .
Time estimate
I think it would take a day to namespace the JavaScript files, and then a further day or two to convert the function calls and test. It is a reasonably simple procedure and with all of the JavaScript clean up that has gone into head already there should be realivily few edge cases left.
Implementation
The implementation of the core namespace and supporting functions to further namespace is reasonably simple, however it would need to be the very first bit of Moodle JavaScript to be executed. This simply means it would be defined and set up within javascript-priority.js which is the first file to be included in the HTML head.
Conversion of JavaScript files
lib/javascript-static.js
Declaration | Namespaced declaration | Declaration type |
---|---|---|
block_hider | M.util.block_hider | object |
checkall | M.form.check_all | function |
checknone | M.form.check_none | function |
collapsible_region | M.dom.collapsible_region | object |
deselect_all_in | M.form.deselect_all_in | function |
findParentNode | M.dom.find_parent | function |
fix_column_width | M.util.fix_column_width | function |
fix_column_widths | M.util.fix_column_widths | function |
focuscontrol | M.form.set_focus | function |
frame_breakout | M.frame.add_breakout_target | function |
init_help_icons | M.util.init_help_icons | function |
openpopup | M.util.window.popup | function |
select_all_in | M.form.select_all_in | function |
submit_form_by_id | M.form.submit_form_by_id | function |
emoticons_help | M.util.emoticons_help | object |
old_onload_focus | To be depreacted as part of MDL-19740 |
lib/javascript-priority.js
Declaration | Namespaced declaration | Declaration type |
---|---|---|
build_querystring | M.util.build_query_string | function |
cancel_scroll_to_end | M.util.scroll.cancel_autoscroll | function |
close_window | M.util.window.close | function |
close_window_reload | M.util.window.reload_close | function |
confirm_dialog | M.control.confirmdialog | object |
create_UFO_object | M.control.ufo.create | function |
destroy_item | M.dom.element.remove | function |
getElementsByClassName | Should really be deprecated in favour of YUI equivilant | |
hide_item | M.dom.element.hide | function |
json_decode | M.util.json.decode | function |
json_encode | M.util.json.encode | function |
repeatedly_scroll_t | M.util.scroll.autoscroll | function |
scroll_to_end | M.util.scroll.bottom | function |
M.util.scroll.top | function | |
set_user_preference | M.user.set_preference | function |
show_item | M.dom.element.show | function |
stripHTML | M.util.strip_html | function |
unmaskPassword | M.form.unmask_password | function |
update_progress_bar | M.control.progressbar.update | function |
Declaration | Namespaced declaration | Declaration type |
---|---|---|
create_shadow | M.control.shadow.create | function |
move_all_sidetabs_t... | M.control.dock.undock_all | function |
navigation_tab_panel | M.control.dock | object |
navigation_tree | M.control.tree | object |
navigation_tree_branch | M.control.tree.branch | object |
remove_shadow | M.control.shadow.remove | function |
setup_new_navtree | M.control.tree.init | function |
lib/javascript-deprecated.js
Declaration | Namespaced declaration | Declaration type |
---|---|---|
deprecate | M.util.deprecate | function |
deprecated_addonload | M.util.deprecated.addonload | function |
deprecated_confirm_if | M.util.deprecated.confirm_if | function |
submitFormById | M.util.deprecated.submitFormById | function |
lib/form/form.js
Declaration | Namespaced declaration | Declaration type |
---|---|---|
date_selector_calendar | M.form.mforms.date_selector.calendar | object |
elementShowAdvanced | M.form.mforms.show_advanced.show | function |
get_form_element_value | M.form.mforms.get_element_value | function |
init_date_selectors | M.form.mforms.date_selector.init | function |
lockoptionsall | M.form.mforms.lockoptionsall | function |
lockoptionsallsetup | M.form.mforms.lockoptionsallsetup | function |
set_form_element_disabled | M.form.mforms.disable_element | funciton |
showAdvancedInit | M.form.mforms.show_advanced.init | function |
showAdvancedOnClick | M.form.mforms.show_advanced.handle_click | function |
Resulting namespaced structure
- M
- control
- confirmdialog
- dock
- undock_all
- tree
- branch
- progressbar
- update
- shadow
- create
- remove
- ufo
- create
- dom
- element
- hide
- remove
- show
- collapsible_region
- find_parent
- element
- form
- mforms
- date_selector
- calendar
- init
- show_advanced
- init
- handle_click
- show
- get_element_value
- lockoptionsall
- lockoptionsallsetup
- disable_element
- date_selector
- check_all
- check_none
- deselect_all_in
- set_focus
- select_all_in
- submit_form_by_id
- unmask_password
- mforms
- util
- deprecated
- addonload
- confirm_if
- submitFormById
- json
- decode
- encode
- scroll
- autoscroll
- bottom
- top
- window
- close
- popup
- reload_close
- block_hider
- fix_column_width
- fix_column_widths
- init_help_icons
- emoticons_help
- build_query_string
- strip_html
- deprecate
- deprecated
- user
- set_preference
- control
Why bother?
Because ....
- It greatly reduces the chances of developers accidentally creating clashing methods, or variables. Not just with core code but more importantly conflicts that may arise between 3rd party extensions.
- Hopefully make the JavaScript code more usable and obvious by providing better organisation and structure. This will in turn hopefully reduce the number of identical functions that arise.
- It's the sort of thing that can only be done when revision of code is necessary and there's no time like a major release for that.
- It looks better, more organised.
Questions
To answer a few quick questions about the process:
- How long would it take to namespace the JavaScript
- It wouldn't take very long at all to go through and apply a namespacing scheme to the JavaScript once the structure has been decided upon. Once the JavaScript has been namespaced it would be a simple case of iterating through the files that make up Moodle and converting references to the original JavaScript functions to their namespaced equivalents.
- Does all JavaScript have to be namespaced
- No not at all. Initially only the core JavaScript files would be converted. After this it would be up to developers to namespace their code should they choose to.... it would be the perfect opportunity to revise that legacy JavaScript ;)
- What about code that uses the old function calls?
- All of the core uses should be converted as part of the task of namespacing however we certainly need to support the old function calls. We will create mapping functions that simply take a call to a non-namespaced function and pass it to its namespaced equivalent.
- Will any of the JavaScript change?
- No. A couple of new internal functions will be introduced to support namespacing however the actual JavaScript functions being namespaced will not change. You will still be able to call them as you did before, you will just need to use the namespaced reference.