2005-04-16 12:30:48 +00:00
// Miscellaneous core Javascript functions for Moodle
2010-01-21 20:55:58 +00:00
// Global M object is initilised in inline javascript
2010-01-20 20:42:23 +00:00
2010-01-21 20:55:58 +00:00
/ * *
2012-08-06 10:21:37 +02:00
* Add module to list of available modules that can be loaded from YUI .
2010-01-29 08:30:13 +00:00
* @ param { Array } modules
2010-01-21 20:55:58 +00:00
* /
M . yui . add _module = function ( modules ) {
2010-01-29 08:30:13 +00:00
for ( var modname in modules ) {
2012-08-06 10:21:37 +02:00
YUI _config . modules [ modname ] = modules [ modname ] ;
2010-01-24 00:05:37 +00:00
}
2010-01-21 20:55:58 +00:00
} ;
2010-06-04 01:49:53 +00:00
/ * *
* The gallery version to use when loading YUI modules from the gallery .
* Will be changed every time when using local galleries .
* /
M . yui . galleryversion = '2010.04.21-21-51' ;
2010-01-24 10:34:02 +00:00
2010-01-22 10:34:09 +00:00
/ * *
* Various utility functions
* /
2010-05-10 09:38:04 +00:00
M . util = M . util || { } ;
2010-01-24 10:34:02 +00:00
2010-02-07 09:43:07 +00:00
/ * *
* Language strings - initialised from page footer .
* /
2010-05-10 09:38:04 +00:00
M . str = M . str || { } ;
2010-02-07 09:43:07 +00:00
2010-01-24 10:34:02 +00:00
/ * *
* Returns url for images .
2010-01-29 08:30:13 +00:00
* @ param { String } imagename
* @ param { String } component
* @ return { String }
2010-01-24 10:34:02 +00:00
* /
M . util . image _url = function ( imagename , component ) {
2012-05-08 10:25:58 +01:00
if ( ! component || component == '' || component == 'moodle' || component == 'core' ) {
2012-05-05 14:45:26 +02:00
component = 'core' ;
2010-01-24 10:34:02 +00:00
}
2012-09-27 10:58:42 +12:00
var url = M . cfg . wwwroot + '/theme/image.php' ;
2012-05-05 14:45:26 +02:00
if ( M . cfg . themerev > 0 && M . cfg . slasharguments == 1 ) {
2012-09-27 10:58:42 +12:00
if ( ! M . cfg . svgicons ) {
url += '/_s' ;
}
url += '/' + M . cfg . theme + '/' + component + '/' + M . cfg . themerev + '/' + imagename ;
2012-05-05 14:45:26 +02:00
} else {
2012-09-27 10:58:42 +12:00
url += '?theme=' + M . cfg . theme + '&component=' + component + '&rev=' + M . cfg . themerev + '&image=' + imagename ;
if ( ! M . cfg . svgicons ) {
url += '&svg=0' ;
}
2010-01-24 10:34:02 +00:00
}
return url ;
} ;
2010-02-15 16:26:26 +00:00
M . util . in _array = function ( item , array ) {
for ( var i = 0 ; i < array . length ; i ++ ) {
if ( item == array [ i ] ) {
return true ;
}
}
return false ;
2010-09-18 11:04:02 +00:00
} ;
2010-02-15 16:26:26 +00:00
2010-01-24 10:34:02 +00:00
/ * *
* Init a collapsible region , see print _collapsible _region in weblib . php
2010-01-29 08:30:13 +00:00
* @ param { YUI } Y YUI3 instance with all libraries loaded
* @ param { String } id the HTML id for the div .
* @ param { String } userpref the user preference that records the state of this box . false if none .
* @ param { String } strtooltip
2010-01-24 10:34:02 +00:00
* /
M . util . init _collapsible _region = function ( Y , id , userpref , strtooltip ) {
Y . use ( 'anim' , function ( Y ) {
2010-02-06 15:08:12 +00:00
new M . util . CollapsibleRegion ( Y , id , userpref , strtooltip ) ;
2010-01-24 10:34:02 +00:00
} ) ;
} ;
/ * *
2010-01-29 08:30:13 +00:00
* Object to handle a collapsible region : instantiate and forget styled object
2010-02-06 15:08:12 +00:00
*
2010-01-29 08:30:13 +00:00
* @ class
2010-01-24 10:34:02 +00:00
* @ constructor
2010-01-29 08:30:13 +00:00
* @ param { YUI } Y YUI3 instance with all libraries loaded
* @ param { String } id The HTML id for the div .
* @ param { String } userpref The user preference that records the state of this box . false if none .
* @ param { String } strtooltip
2010-01-24 10:34:02 +00:00
* /
M . util . CollapsibleRegion = function ( Y , id , userpref , strtooltip ) {
// Record the pref name
this . userpref = userpref ;
// Find the divs in the document.
2010-01-29 08:30:13 +00:00
this . div = Y . one ( '#' + id ) ;
// Get the caption for the collapsible region
var caption = this . div . one ( '#' + id + '_caption' ) ;
// Create a link
var a = Y . Node . create ( '<a href="#"></a>' ) ;
2012-09-04 16:02:54 +08:00
a . setAttribute ( 'title' , strtooltip ) ;
// Get all the nodes from caption, remove them and append them to <a>
while ( caption . hasChildNodes ( ) ) {
child = caption . get ( 'firstChild' ) ;
child . remove ( ) ;
a . append ( child ) ;
}
2010-01-29 08:30:13 +00:00
caption . append ( a ) ;
// Get the height of the div at this point before we shrink it if required
var height = this . div . get ( 'offsetHeight' ) ;
2012-09-22 21:05:14 +03:00
var collapsedimage = 't/collapsed' ; // ltr mode
2012-11-19 18:32:37 +08:00
if ( right _to _left ( ) ) {
2012-09-22 21:05:14 +03:00
collapsedimage = 't/collapsed_rtl' ;
} else {
collapsedimage = 't/collapsed' ;
}
2010-01-29 08:30:13 +00:00
if ( this . div . hasClass ( 'collapsed' ) ) {
// Add the correct image and record the YUI node created in the process
2012-09-22 21:05:14 +03:00
this . icon = Y . Node . create ( '<img src="' + M . util . image _url ( collapsedimage , 'moodle' ) + '" alt="" />' ) ;
2010-01-29 08:30:13 +00:00
// Shrink the div as it is collapsed by default
this . div . setStyle ( 'height' , caption . get ( 'offsetHeight' ) + 'px' ) ;
} else {
// Add the correct image and record the YUI node created in the process
this . icon = Y . Node . create ( '<img src="' + M . util . image _url ( 't/expanded' , 'moodle' ) + '" alt="" />' ) ;
2010-01-24 10:34:02 +00:00
}
2010-01-29 08:30:13 +00:00
a . append ( this . icon ) ;
2010-01-24 10:34:02 +00:00
// Create the animation.
2010-01-29 08:30:13 +00:00
var animation = new Y . Anim ( {
2010-01-24 10:34:02 +00:00
node : this . div ,
duration : 0.3 ,
2010-01-29 08:30:13 +00:00
easing : Y . Easing . easeBoth ,
to : { height : caption . get ( 'offsetHeight' ) } ,
from : { height : height }
2010-01-24 10:34:02 +00:00
} ) ;
2010-02-06 15:08:12 +00:00
2010-01-24 10:34:02 +00:00
// Handler for the animation finishing.
2010-01-29 08:30:13 +00:00
animation . on ( 'end' , function ( ) {
this . div . toggleClass ( 'collapsed' ) ;
2012-09-22 21:05:14 +03:00
var collapsedimage = 't/collapsed' ; // ltr mode
2012-11-19 18:32:37 +08:00
if ( right _to _left ( ) ) {
2012-09-22 21:05:14 +03:00
collapsedimage = 't/collapsed_rtl' ;
} else {
collapsedimage = 't/collapsed' ;
}
2010-01-29 08:30:13 +00:00
if ( this . div . hasClass ( 'collapsed' ) ) {
2012-09-22 21:05:14 +03:00
this . icon . set ( 'src' , M . util . image _url ( collapsedimage , 'moodle' ) ) ;
2010-01-29 08:30:13 +00:00
} else {
this . icon . set ( 'src' , M . util . image _url ( 't/expanded' , 'moodle' ) ) ;
2010-01-24 00:05:37 +00:00
}
2010-01-24 10:34:02 +00:00
} , this ) ;
2010-01-29 08:30:13 +00:00
// Hook up the event handler.
a . on ( 'click' , function ( e , animation ) {
e . preventDefault ( ) ;
// Animate to the appropriate size.
if ( animation . get ( 'running' ) ) {
animation . stop ( ) ;
}
animation . set ( 'reverse' , this . div . hasClass ( 'collapsed' ) ) ;
// Update the user preference.
if ( this . userpref ) {
2010-02-06 15:20:24 +00:00
M . util . set _user _preference ( this . userpref , ! this . div . hasClass ( 'collapsed' ) ) ;
2010-01-29 08:30:13 +00:00
}
animation . run ( ) ;
} , this , animation ) ;
2010-01-24 10:34:02 +00:00
} ;
/ * *
* The user preference that stores the state of this box .
* @ property userpref
* @ type String
* /
M . util . CollapsibleRegion . prototype . userpref = null ;
/ * *
* The key divs that make up this
2010-01-29 08:30:13 +00:00
* @ property div
* @ type Y . Node
2010-01-24 10:34:02 +00:00
* /
M . util . CollapsibleRegion . prototype . div = null ;
/ * *
* The key divs that make up this
* @ property icon
2010-01-29 08:30:13 +00:00
* @ type Y . Node
2010-01-24 10:34:02 +00:00
* /
M . util . CollapsibleRegion . prototype . icon = null ;
2010-02-06 15:20:24 +00:00
/ * *
* Makes a best effort to connect back to Moodle to update a user preference ,
* however , there is no mechanism for finding out if the update succeeded .
*
* Before you can use this function in your JavsScript , you must have called
* user _preference _allow _ajax _update from moodlelib . php to tell Moodle that
* the udpate is allowed , and how to safely clean and submitted values .
*
* @ param String name the name of the setting to udpate .
* @ param String the value to set it to .
* /
M . util . set _user _preference = function ( name , value ) {
2012-08-06 10:21:37 +02:00
YUI ( ) . use ( 'io' , function ( Y ) {
2010-02-06 15:20:24 +00:00
var url = M . cfg . wwwroot + '/lib/ajax/setuserpref.php?sesskey=' +
M . cfg . sesskey + '&pref=' + encodeURI ( name ) + '&value=' + encodeURI ( value ) ;
// If we are a developer, ensure that failures are reported.
var cfg = {
2010-02-06 17:35:11 +00:00
method : 'get' ,
2010-02-09 14:48:29 +00:00
on : { }
2010-02-06 15:20:24 +00:00
} ;
if ( M . cfg . developerdebug ) {
cfg . on . failure = function ( id , o , args ) {
2010-02-06 17:35:11 +00:00
alert ( "Error updating user preference '" + name + "' using ajax. Clicking this link will repeat the Ajax call that failed so you can see the error: " ) ;
2010-02-06 15:20:24 +00:00
}
}
// Make the request.
Y . io ( url , cfg ) ;
} ) ;
} ;
2010-02-06 17:35:11 +00:00
/ * *
* Prints a confirmation dialog in the style of DOM . confirm ( ) .
* @ param object event A YUI DOM event or null if launched manually
* @ param string message The message to show in the dialog
* @ param string url The URL to forward to if YES is clicked . Disabled if fn is given
* @ param function fn A JS function to run if YES is clicked .
* /
M . util . show _confirm _dialog = function ( e , args ) {
var target = e . target ;
if ( e . preventDefault ) {
e . preventDefault ( ) ;
}
2012-08-06 10:21:37 +02:00
YUI ( ) . use ( 'yui2-container' , 'yui2-event' , function ( Y ) {
2012-08-06 22:48:32 +02:00
var simpledialog = new Y . YUI2 . widget . SimpleDialog ( 'confirmdialog' ,
2010-05-04 09:43:29 +00:00
{ width : '300px' ,
2010-02-06 17:35:11 +00:00
fixedcenter : true ,
modal : true ,
visible : false ,
draggable : false
}
) ;
2010-02-07 09:43:07 +00:00
simpledialog . setHeader ( M . str . admin . confirmation ) ;
2010-02-06 17:35:11 +00:00
simpledialog . setBody ( args . message ) ;
2012-08-06 22:48:32 +02:00
simpledialog . cfg . setProperty ( 'icon' , Y . YUI2 . widget . SimpleDialog . ICON _WARN ) ;
2010-02-06 17:35:11 +00:00
var handle _cancel = function ( ) {
simpledialog . hide ( ) ;
} ;
var handle _yes = function ( ) {
simpledialog . hide ( ) ;
if ( args . callback ) {
// args comes from PHP, so callback will be a string, needs to be evaluated by JS
var callback = null ;
if ( Y . Lang . isFunction ( args . callback ) ) {
callback = args . callback ;
} else {
callback = eval ( '(' + args . callback + ')' ) ;
}
if ( Y . Lang . isObject ( args . scope ) ) {
var sc = args . scope ;
} else {
var sc = e . target ;
}
if ( args . callbackargs ) {
callback . apply ( sc , args . callbackargs ) ;
} else {
callback . apply ( sc ) ;
}
return ;
}
2011-01-05 14:02:42 +08:00
var targetancestor = null ,
targetform = null ;
if ( target . test ( 'a' ) ) {
2010-02-06 17:35:11 +00:00
window . location = target . get ( 'href' ) ;
2011-12-08 17:50:11 +00:00
2011-01-05 14:02:42 +08:00
} else if ( ( targetancestor = target . ancestor ( 'a' ) ) !== null ) {
window . location = targetancestor . get ( 'href' ) ;
2011-12-08 17:50:11 +00:00
2011-01-05 14:02:42 +08:00
} else if ( target . test ( 'input' ) ) {
2011-12-09 11:31:47 +00:00
targetform = target . ancestor ( function ( node ) { return node . get ( 'tagName' ) . toLowerCase ( ) == 'form' ; } ) ;
// We cannot use target.ancestor('form') on the previous line
// because of http://yuilibrary.com/projects/yui3/ticket/2531561
2011-12-08 17:50:11 +00:00
if ( ! targetform ) {
return ;
}
if ( target . get ( 'name' ) && target . get ( 'value' ) ) {
targetform . append ( '<input type="hidden" name="' + target . get ( 'name' ) +
'" value="' + target . get ( 'value' ) + '">' ) ;
2010-02-06 17:35:11 +00:00
}
2011-12-08 17:50:11 +00:00
targetform . submit ( ) ;
} else if ( target . get ( 'tagName' ) . toLowerCase ( ) == 'form' ) {
// We cannot use target.test('form') on the previous line because of
// http://yuilibrary.com/projects/yui3/ticket/2531561
target . submit ( ) ;
2010-02-06 17:35:11 +00:00
} else if ( M . cfg . developerdebug ) {
2011-12-09 11:43:41 +13:00
alert ( "Element of type " + target . get ( 'tagName' ) + " is not supported by the M.util.show_confirm_dialog function. Use A, INPUT, or FORM" ) ;
2010-02-06 17:35:11 +00:00
}
} ;
2011-07-05 13:50:59 +01:00
if ( ! args . cancellabel ) {
args . cancellabel = M . str . moodle . cancel ;
}
if ( ! args . continuelabel ) {
args . continuelabel = M . str . moodle . yes ;
}
var buttons = [
{ text : args . cancellabel , handler : handle _cancel , isDefault : true } ,
{ text : args . continuelabel , handler : handle _yes }
] ;
2010-02-06 17:35:11 +00:00
simpledialog . cfg . queueProperty ( 'buttons' , buttons ) ;
simpledialog . render ( document . body ) ;
simpledialog . show ( ) ;
} ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-02-06 17:35:11 +00:00
2010-02-06 18:47:44 +00:00
/** Useful for full embedding of various stuff */
M . util . init _maximised _embed = function ( Y , id ) {
var obj = Y . one ( '#' + id ) ;
if ( ! obj ) {
return ;
}
var get _htmlelement _size = function ( el , prop ) {
if ( Y . Lang . isString ( el ) ) {
el = Y . one ( '#' + el ) ;
}
2012-11-19 15:43:46 +08:00
// Ensure element exists.
if ( el ) {
var val = el . getStyle ( prop ) ;
if ( val == 'auto' ) {
val = el . getComputedStyle ( prop ) ;
}
return parseInt ( val ) ;
} else {
return 0 ;
2010-02-06 18:47:44 +00:00
}
} ;
var resize _object = function ( ) {
obj . setStyle ( 'width' , '0px' ) ;
obj . setStyle ( 'height' , '0px' ) ;
2011-03-12 17:42:52 +01:00
var newwidth = get _htmlelement _size ( 'maincontent' , 'width' ) - 35 ;
2010-02-06 18:47:44 +00:00
2011-03-12 17:42:52 +01:00
if ( newwidth > 500 ) {
2010-02-06 18:47:44 +00:00
obj . setStyle ( 'width' , newwidth + 'px' ) ;
} else {
2011-03-12 17:42:52 +01:00
obj . setStyle ( 'width' , '500px' ) ;
2010-02-06 18:47:44 +00:00
}
2010-10-15 08:55:24 +00:00
var headerheight = get _htmlelement _size ( 'page-header' , 'height' ) ;
var footerheight = get _htmlelement _size ( 'page-footer' , 'height' ) ;
2012-09-15 12:50:33 +02:00
var newheight = parseInt ( Y . one ( 'body' ) . get ( 'winHeight' ) ) - footerheight - headerheight - 100 ;
2010-10-15 08:55:24 +00:00
if ( newheight < 400 ) {
newheight = 400 ;
2010-02-06 18:47:44 +00:00
}
2010-10-15 08:55:24 +00:00
obj . setStyle ( 'height' , newheight + 'px' ) ;
2010-02-06 18:47:44 +00:00
} ;
resize _object ( ) ;
// fix layout if window resized too
window . onresize = function ( ) {
resize _object ( ) ;
} ;
} ;
2010-02-09 17:39:13 +00:00
/ * *
* Attach handler to single _select
2012-09-21 15:17:22 +01:00
*
* This code was deprecated in Moodle 2.4 and will be removed in Moodle 2.6
*
* Please see lib / yui / formautosubmit / formautosubmit . js for its replacement
2010-02-09 17:39:13 +00:00
* /
2010-02-10 16:20:28 +00:00
M . util . init _select _autosubmit = function ( Y , formid , selectid , nothing ) {
2012-09-21 15:17:22 +01:00
if ( M . cfg . developerdebug ) {
Y . log ( "You are using a deprecated function call (M.util.init_select_autosubmit). Please look at rewriting your call to use moodle-core-formautosubmit" ) ;
}
2010-05-20 05:22:33 +00:00
Y . use ( 'event-key' , function ( ) {
var select = Y . one ( '#' + selectid ) ;
if ( select ) {
// Try to get the form by id
var form = Y . one ( '#' + formid ) || ( function ( ) {
// Hmmm the form's id may have been overriden by an internal input
// with the name id which will KILL IE.
// We need to manually iterate at this point because if the case
// above is true YUI's ancestor method will also kill IE!
var form = select ;
while ( form && form . get ( 'nodeName' ) . toUpperCase ( ) !== 'FORM' ) {
form = form . ancestor ( ) ;
}
return form ;
} ) ( ) ;
// Make sure we have the form
if ( form ) {
2012-09-03 16:54:18 +08:00
var buttonflag = 0 ;
2010-05-20 05:22:33 +00:00
// Create a function to handle our change event
2011-08-04 12:01:52 +08:00
var processchange = function ( e , paramobject ) {
if ( ( nothing === false || select . get ( 'value' ) != nothing ) && paramobject . lastindex != select . get ( 'selectedIndex' ) ) {
2012-09-03 16:54:18 +08:00
// chrome doesn't pick up on a click when selecting an element in a select menu, so we use
// the on change event to fire this function. This just checks to see if a button was
// first pressed before redirecting to the appropriate page.
if ( Y . UA . os == 'windows' && Y . UA . chrome ) {
if ( buttonflag == 1 ) {
buttonflag = 0 ;
this . submit ( ) ;
}
} else {
this . submit ( ) ;
}
}
if ( e . button == 1 ) {
buttonflag = 1 ;
2010-05-20 05:22:33 +00:00
}
2012-11-21 16:54:58 +08:00
paramobject . lastindex = select . get ( 'selectedIndex' ) ;
2010-09-18 11:04:02 +00:00
} ;
2012-09-03 16:54:18 +08:00
var changedown = function ( e , paramobject ) {
if ( ( nothing === false || select . get ( 'value' ) != nothing ) && paramobject . lastindex != select . get ( 'selectedIndex' ) ) {
if ( e . keyCode == 13 ) {
form . submit ( ) ;
}
2012-11-21 16:54:58 +08:00
paramobject . lastindex = select . get ( 'selectedIndex' ) ;
2012-09-03 16:54:18 +08:00
}
}
2011-08-04 12:01:52 +08:00
var paramobject = new Object ( ) ;
paramobject . lastindex = select . get ( 'selectedIndex' ) ;
2012-09-03 16:54:18 +08:00
paramobject . eventchangeorblur = select . on ( 'click' , processchange , form , paramobject ) ;
// Bad hack to circumvent problems with different browsers on different systems.
if ( Y . UA . os == 'macintosh' ) {
if ( Y . UA . webkit ) {
paramobject . eventchangeorblur = select . on ( 'change' , processchange , form , paramobject ) ;
}
paramobject . eventkeypress = Y . on ( 'key' , processchange , select , 'press:13' , form , paramobject ) ;
2012-07-05 16:09:43 +02:00
} else {
2012-09-03 16:54:18 +08:00
if ( Y . UA . os == 'windows' && Y . UA . chrome ) {
paramobject . eventchangeorblur = select . on ( 'change' , processchange , form , paramobject ) ;
}
paramobject . eventkeypress = Y . on ( 'keydown' , changedown , select , '' , form , paramobject ) ;
2012-07-05 16:09:43 +02:00
}
2010-05-20 05:22:33 +00:00
}
2010-02-11 13:27:02 +00:00
}
} ) ;
2010-02-09 17:39:13 +00:00
} ;
2010-02-06 18:47:44 +00:00
2010-02-10 10:22:25 +00:00
/ * *
* Attach handler to url _select
2012-09-03 16:54:18 +08:00
* Deprecated from 2.4 onwards .
* Please use @ see init _select _autosubmit ( ) for redirecting to a url ( above ) .
* This function has accessability issues and also does not use the formid passed through as a parameter .
2010-02-10 10:22:25 +00:00
* /
M . util . init _url _select = function ( Y , formid , selectid , nothing ) {
2012-09-21 15:17:22 +01:00
if ( M . cfg . developerdebug ) {
Y . log ( "You are using a deprecated function call (M.util.init_url_select). Please look at rewriting your call to use moodle-core-formautosubmit" ) ;
}
2012-08-06 10:21:37 +02:00
YUI ( ) . use ( 'node' , function ( Y ) {
2010-02-11 13:27:02 +00:00
Y . on ( 'change' , function ( ) {
2010-05-20 05:22:33 +00:00
if ( ( nothing == false && Y . Lang . isBoolean ( nothing ) ) || Y . one ( '#' + selectid ) . get ( 'value' ) != nothing ) {
window . location = M . cfg . wwwroot + Y . one ( '#' + selectid ) . get ( 'value' ) ;
}
2010-02-11 13:27:02 +00:00
} ,
'#' + selectid ) ;
} ) ;
} ;
/ * *
* Breaks out all links to the top frame - used in frametop page layout .
* /
M . util . init _frametop = function ( Y ) {
Y . all ( 'a' ) . each ( function ( node ) {
node . set ( 'target' , '_top' ) ;
} ) ;
Y . all ( 'form' ) . each ( function ( node ) {
node . set ( 'target' , '_top' ) ;
} ) ;
2010-02-10 10:22:25 +00:00
} ;
2010-05-27 01:40:11 +00:00
/ * *
* Finds all nodes that match the given CSS selector and attaches events to them
* so that they toggle a given classname when clicked .
*
* @ param { YUI } Y
* @ param { string } id An id containing elements to target
* @ param { string } cssselector A selector to use to find targets
* @ param { string } toggleclassname A classname to toggle
* /
2010-11-22 05:35:39 +00:00
M . util . init _toggle _class _on _click = function ( Y , id , cssselector , toggleclassname , togglecssselector ) {
if ( togglecssselector == '' ) {
togglecssselector = cssselector ;
}
2010-05-27 01:40:11 +00:00
var node = Y . one ( '#' + id ) ;
2010-11-22 05:35:39 +00:00
node . all ( cssselector ) . each ( function ( n ) {
n . on ( 'click' , function ( e ) {
2010-05-27 01:40:11 +00:00
e . stopPropagation ( ) ;
2010-11-22 05:35:39 +00:00
if ( e . target . test ( cssselector ) && ! e . target . test ( 'a' ) && ! e . target . test ( 'img' ) ) {
if ( this . test ( togglecssselector ) ) {
this . toggleClass ( toggleclassname ) ;
} else {
this . ancestor ( togglecssselector ) . toggleClass ( toggleclassname ) ;
}
2010-05-27 01:40:11 +00:00
}
2010-11-22 05:35:39 +00:00
} , n ) ;
2010-05-27 01:40:11 +00:00
} ) ;
// Attach this click event to the node rather than all selectors... will be much better
// for performance
node . on ( 'click' , function ( e ) {
if ( e . target . hasClass ( 'addtoall' ) ) {
2010-11-22 05:35:39 +00:00
this . all ( togglecssselector ) . addClass ( toggleclassname ) ;
2010-05-27 01:40:11 +00:00
} else if ( e . target . hasClass ( 'removefromall' ) ) {
2010-11-22 05:35:39 +00:00
this . all ( togglecssselector + '.' + toggleclassname ) . removeClass ( toggleclassname ) ;
2010-05-27 01:40:11 +00:00
}
} , node ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-05-27 01:40:11 +00:00
2010-06-16 08:36:06 +00:00
/ * *
* Initialises a colour picker
*
* Designed to be used with admin _setting _configcolourpicker although could be used
* anywhere , just give a text input an id and insert a div with the class admin _colourpicker
* above or below the input ( must have the same parent ) and then call this with the
* id .
*
* This code was mostly taken from my [ Sam Hemelryk ] css theme tool available in
* contrib / blocks . For better docs refer to that .
*
* @ param { YUI } Y
* @ param { int } id
* @ param { object } previewconf
* /
M . util . init _colour _picker = function ( Y , id , previewconf ) {
/ * *
* We need node and event - mouseenter
* /
Y . use ( 'node' , 'event-mouseenter' , function ( ) {
/ * *
* The colour picker object
* /
var colourpicker = {
box : null ,
input : null ,
image : null ,
preview : null ,
current : null ,
eventClick : null ,
eventMouseEnter : null ,
eventMouseLeave : null ,
eventMouseMove : null ,
width : 300 ,
height : 100 ,
factor : 5 ,
/ * *
* Initalises the colour picker by putting everything together and wiring the events
* /
init : function ( ) {
this . input = Y . one ( '#' + id ) ;
this . box = this . input . ancestor ( ) . one ( '.admin_colourpicker' ) ;
this . image = Y . Node . create ( '<img alt="" class="colourdialogue" />' ) ;
this . image . setAttribute ( 'src' , M . util . image _url ( 'i/colourpicker' , 'moodle' ) ) ;
this . preview = Y . Node . create ( '<div class="previewcolour"></div>' ) ;
this . preview . setStyle ( 'width' , this . height / 2 ) . setStyle ( 'height' , this . height / 2 ) . setStyle ( 'backgroundColor' , this . input . get ( 'value' ) ) ;
this . current = Y . Node . create ( '<div class="currentcolour"></div>' ) ;
this . current . setStyle ( 'width' , this . height / 2 ) . setStyle ( 'height' , this . height / 2 - 1 ) . setStyle ( 'backgroundColor' , this . input . get ( 'value' ) ) ;
this . box . setContent ( '' ) . append ( this . image ) . append ( this . preview ) . append ( this . current ) ;
if ( typeof ( previewconf ) === 'object' && previewconf !== null ) {
Y . one ( '#' + id + '_preview' ) . on ( 'click' , function ( e ) {
2010-07-02 07:19:35 +00:00
if ( Y . Lang . isString ( previewconf . selector ) ) {
2010-07-02 07:12:12 +00:00
Y . all ( previewconf . selector ) . setStyle ( previewconf . style , this . input . get ( 'value' ) ) ;
} else {
for ( var i in previewconf . selector ) {
Y . all ( previewconf . selector [ i ] ) . setStyle ( previewconf . style , this . input . get ( 'value' ) ) ;
}
}
2010-06-16 08:36:06 +00:00
} , this ) ;
}
this . eventClick = this . image . on ( 'click' , this . pickColour , this ) ;
this . eventMouseEnter = Y . on ( 'mouseenter' , this . startFollow , this . image , this ) ;
} ,
/ * *
* Starts to follow the mouse once it enter the image
* /
startFollow : function ( e ) {
this . eventMouseEnter . detach ( ) ;
this . eventMouseLeave = Y . on ( 'mouseleave' , this . endFollow , this . image , this ) ;
this . eventMouseMove = this . image . on ( 'mousemove' , function ( e ) {
this . preview . setStyle ( 'backgroundColor' , this . determineColour ( e ) ) ;
} , this ) ;
} ,
/ * *
* Stops following the mouse
* /
endFollow : function ( e ) {
this . eventMouseMove . detach ( ) ;
this . eventMouseLeave . detach ( ) ;
this . eventMouseEnter = Y . on ( 'mouseenter' , this . startFollow , this . image , this ) ;
} ,
/ * *
* Picks the colour the was clicked on
* /
pickColour : function ( e ) {
var colour = this . determineColour ( e ) ;
this . input . set ( 'value' , colour ) ;
this . current . setStyle ( 'backgroundColor' , colour ) ;
} ,
/ * *
* Calculates the colour fromthe given co - ordinates
* /
determineColour : function ( e ) {
var eventx = Math . floor ( e . pageX - e . target . getX ( ) ) ;
var eventy = Math . floor ( e . pageY - e . target . getY ( ) ) ;
var imagewidth = this . width ;
var imageheight = this . height ;
var factor = this . factor ;
var colour = [ 255 , 0 , 0 ] ;
var matrices = [
[ 0 , 1 , 0 ] ,
[ - 1 , 0 , 0 ] ,
[ 0 , 0 , 1 ] ,
[ 0 , - 1 , 0 ] ,
[ 1 , 0 , 0 ] ,
[ 0 , 0 , - 1 ]
] ;
var matrixcount = matrices . length ;
var limit = Math . round ( imagewidth / matrixcount ) ;
var heightbreak = Math . round ( imageheight / 2 ) ;
for ( var x = 0 ; x < imagewidth ; x ++ ) {
var divisor = Math . floor ( x / limit ) ;
var matrix = matrices [ divisor ] ;
colour [ 0 ] += matrix [ 0 ] * factor ;
colour [ 1 ] += matrix [ 1 ] * factor ;
colour [ 2 ] += matrix [ 2 ] * factor ;
if ( eventx == x ) {
break ;
}
}
var pixel = [ colour [ 0 ] , colour [ 1 ] , colour [ 2 ] ] ;
if ( eventy < heightbreak ) {
pixel [ 0 ] += Math . floor ( ( ( 255 - pixel [ 0 ] ) / heightbreak ) * ( heightbreak - eventy ) ) ;
pixel [ 1 ] += Math . floor ( ( ( 255 - pixel [ 1 ] ) / heightbreak ) * ( heightbreak - eventy ) ) ;
pixel [ 2 ] += Math . floor ( ( ( 255 - pixel [ 2 ] ) / heightbreak ) * ( heightbreak - eventy ) ) ;
} else if ( eventy > heightbreak ) {
pixel [ 0 ] = Math . floor ( ( imageheight - eventy ) * ( pixel [ 0 ] / heightbreak ) ) ;
pixel [ 1 ] = Math . floor ( ( imageheight - eventy ) * ( pixel [ 1 ] / heightbreak ) ) ;
pixel [ 2 ] = Math . floor ( ( imageheight - eventy ) * ( pixel [ 2 ] / heightbreak ) ) ;
}
return this . convert _rgb _to _hex ( pixel ) ;
} ,
/ * *
* Converts an RGB value to Hex
* /
convert _rgb _to _hex : function ( rgb ) {
var hex = '#' ;
var hexchars = "0123456789ABCDEF" ;
for ( var i = 0 ; i < 3 ; i ++ ) {
var number = Math . abs ( rgb [ i ] ) ;
if ( number == 0 || isNaN ( number ) ) {
hex += '00' ;
} else {
hex += hexchars . charAt ( ( number - number % 16 ) / 16 ) + hexchars . charAt ( number % 16 ) ;
}
}
return hex ;
}
2010-09-18 11:04:02 +00:00
} ;
2010-06-16 08:36:06 +00:00
/ * *
* Initialise the colour picker : ) Hoorah
* /
colourpicker . init ( ) ;
} ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-06-16 08:36:06 +00:00
2010-08-17 08:31:20 +00:00
M . util . init _block _hider = function ( Y , config ) {
Y . use ( 'base' , 'node' , function ( Y ) {
M . util . block _hider = M . util . block _hider || ( function ( ) {
var blockhider = function ( ) {
blockhider . superclass . constructor . apply ( this , arguments ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-08-17 08:31:20 +00:00
blockhider . prototype = {
initializer : function ( config ) {
2010-09-18 11:04:02 +00:00
this . set ( 'block' , '#' + this . get ( 'id' ) ) ;
2010-08-17 08:31:20 +00:00
var b = this . get ( 'block' ) ,
t = b . one ( '.title' ) ,
a = null ;
if ( t && ( a = t . one ( '.block_action' ) ) ) {
2011-06-27 16:19:47 +01:00
var hide = Y . Node . create ( '<img class="block-hider-hide" tabindex="0" alt="' + config . tooltipVisible + '" title="' + config . tooltipVisible + '" />' ) ;
2010-08-17 08:31:20 +00:00
hide . setAttribute ( 'src' , this . get ( 'iconVisible' ) ) . on ( 'click' , this . updateState , this , true ) ;
2011-06-27 16:19:47 +01:00
hide . on ( 'keypress' , this . updateStateKey , this , true ) ;
var show = Y . Node . create ( '<img class="block-hider-show" tabindex="0" alt="' + config . tooltipHidden + '" title="' + config . tooltipHidden + '" />' ) ;
2010-08-17 08:31:20 +00:00
show . setAttribute ( 'src' , this . get ( 'iconHidden' ) ) . on ( 'click' , this . updateState , this , false ) ;
2011-06-27 16:19:47 +01:00
show . on ( 'keypress' , this . updateStateKey , this , false ) ;
2010-08-17 08:31:20 +00:00
a . insert ( show , 0 ) . insert ( hide , 0 ) ;
}
} ,
updateState : function ( e , hide ) {
M . util . set _user _preference ( this . get ( 'preference' ) , hide ) ;
if ( hide ) {
this . get ( 'block' ) . addClass ( 'hidden' ) ;
} else {
this . get ( 'block' ) . removeClass ( 'hidden' ) ;
}
2011-06-27 16:19:47 +01:00
} ,
updateStateKey : function ( e , hide ) {
if ( e . keyCode == 13 ) { //allow hide/show via enter key
this . updateState ( this , hide ) ;
}
2010-08-17 08:31:20 +00:00
}
2010-09-18 11:04:02 +00:00
} ;
2010-08-17 08:31:20 +00:00
Y . extend ( blockhider , Y . Base , blockhider . prototype , {
NAME : 'blockhider' ,
ATTRS : {
id : { } ,
preference : { } ,
iconVisible : {
value : M . util . image _url ( 't/switch_minus' , 'moodle' )
} ,
iconHidden : {
value : M . util . image _url ( 't/switch_plus' , 'moodle' )
} ,
block : {
setter : function ( node ) {
return Y . one ( node ) ;
}
}
}
} ) ;
return blockhider ;
} ) ( ) ;
new M . util . block _hider ( config ) ;
} ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-08-17 08:31:20 +00:00
2010-11-02 14:24:19 +00:00
/ * *
* Returns a string registered in advance for usage in JavaScript
*
* If you do not pass the third parameter , the function will just return
* the corresponding value from the M . str object . If the third parameter is
* provided , the function performs { $a } placeholder substitution in the
* same way as PHP get _string ( ) in Moodle does .
*
* @ param { String } identifier string identifier
* @ param { String } component the component providing the string
* @ param { Object | String } a optional variable to populate placeholder with
* /
M . util . get _string = function ( identifier , component , a ) {
var stringvalue ;
if ( M . cfg . developerdebug ) {
// creating new instance if YUI is not optimal but it seems to be better way then
// require the instance via the function API - note that it is used in rare cases
// for debugging only anyway
2012-07-12 11:27:46 +12:00
// To ensure we don't kill browser performance if hundreds of get_string requests
// are made we cache the instance we generate within the M.util namespace.
// We don't publicly define the variable so that it doesn't get abused.
if ( typeof M . util . get _string _yui _instance === 'undefined' ) {
M . util . get _string _yui _instance = new YUI ( { debug : true } ) ;
}
var Y = M . util . get _string _yui _instance ;
2010-11-02 14:24:19 +00:00
}
if ( ! M . str . hasOwnProperty ( component ) || ! M . str [ component ] . hasOwnProperty ( identifier ) ) {
stringvalue = '[[' + identifier + ',' + component + ']]' ;
if ( M . cfg . developerdebug ) {
Y . log ( 'undefined string ' + stringvalue , 'warn' , 'M.util.get_string' ) ;
}
return stringvalue ;
}
stringvalue = M . str [ component ] [ identifier ] ;
if ( typeof a == 'undefined' ) {
// no placeholder substitution requested
return stringvalue ;
}
if ( typeof a == 'number' || typeof a == 'string' ) {
// replace all occurrences of {$a} with the placeholder value
stringvalue = stringvalue . replace ( /\{\$a\}/g , a ) ;
return stringvalue ;
}
if ( typeof a == 'object' ) {
// replace {$a->key} placeholders
for ( var key in a ) {
if ( typeof a [ key ] != 'number' && typeof a [ key ] != 'string' ) {
if ( M . cfg . developerdebug ) {
Y . log ( 'invalid value type for $a->' + key , 'warn' , 'M.util.get_string' ) ;
}
continue ;
}
var search = '{$a->' + key + '}' ;
search = search . replace ( /[-[\]{}()*+?.,\\^$|#\s]/g , '\\$&' ) ;
search = new RegExp ( search , 'g' ) ;
stringvalue = stringvalue . replace ( search , a [ key ] ) ;
}
return stringvalue ;
}
if ( M . cfg . developerdebug ) {
Y . log ( 'incorrect placeholder type' , 'warn' , 'M.util.get_string' ) ;
}
return stringvalue ;
} ;
2011-07-14 15:58:01 +02:00
/ * *
* Set focus on username or password field of the login form
* /
M . util . focus _login _form = function ( Y ) {
var username = Y . one ( '#username' ) ;
var password = Y . one ( '#password' ) ;
if ( username == null || password == null ) {
// something is wrong here
return ;
}
var curElement = document . activeElement
if ( curElement == 'undefined' ) {
// legacy browser - skip refocus protection
} else if ( curElement . tagName == 'INPUT' ) {
// user was probably faster to focus something, do not mess with focus
return ;
}
if ( username . get ( 'value' ) == '' ) {
username . focus ( ) ;
} else {
password . focus ( ) ;
}
}
2013-01-15 15:45:15 +08:00
/ * *
* Set focus on login error message
* /
M . util . focus _login _error = function ( Y ) {
2013-01-17 13:01:27 +08:00
var errorlog = Y . one ( '#loginerrormessage' ) ;
2013-01-15 15:45:15 +08:00
if ( errorlog ) {
errorlog . focus ( ) ;
}
}
2012-04-23 14:45:44 +01:00
/ * *
* Adds lightbox hidden element that covers the whole node .
*
* @ param { YUI } Y
* @ param { Node } the node lightbox should be added to
* @ retun { Node } created lightbox node
* /
M . util . add _lightbox = function ( Y , node ) {
var WAITICON = { 'pix' : "i/loading_small" , 'component' : 'moodle' } ;
// Check if lightbox is already there
if ( node . one ( '.lightbox' ) ) {
return node . one ( '.lightbox' ) ;
}
node . setStyle ( 'position' , 'relative' ) ;
var waiticon = Y . Node . create ( '<img />' )
. setAttrs ( {
'src' : M . util . image _url ( WAITICON . pix , WAITICON . component )
} )
. setStyles ( {
'position' : 'relative' ,
2012-11-14 14:24:51 +08:00
'top' : '50%'
2012-04-23 14:45:44 +01:00
} ) ;
var lightbox = Y . Node . create ( '<div></div>' )
. setStyles ( {
'opacity' : '.75' ,
'position' : 'absolute' ,
'width' : '100%' ,
'height' : '100%' ,
'top' : 0 ,
'left' : 0 ,
'backgroundColor' : 'white' ,
2012-11-14 14:24:51 +08:00
'textAlign' : 'center'
2012-04-23 14:45:44 +01:00
} )
. setAttribute ( 'class' , 'lightbox' )
. hide ( ) ;
lightbox . appendChild ( waiticon ) ;
node . append ( lightbox ) ;
return lightbox ;
}
2011-07-14 15:58:01 +02:00
2012-04-26 10:43:25 +01:00
/ * *
* Appends a hidden spinner element to the specified node .
*
* @ param { YUI } Y
* @ param { Node } the node the spinner should be added to
* @ return { Node } created spinner node
* /
M . util . add _spinner = function ( Y , node ) {
var WAITICON = { 'pix' : "i/loading_small" , 'component' : 'moodle' } ;
// Check if spinner is already there
if ( node . one ( '.spinner' ) ) {
return node . one ( '.spinner' ) ;
}
var spinner = Y . Node . create ( '<img />' )
. setAttribute ( 'src' , M . util . image _url ( WAITICON . pix , WAITICON . component ) )
. addClass ( 'spinner' )
. addClass ( 'iconsmall' )
. hide ( ) ;
node . append ( spinner ) ;
return spinner ;
}
2010-01-24 10:34:02 +00:00
//=== old legacy JS code, hopefully to be replaced soon by M.xx.yy and YUI3 code ===
2005-01-09 15:10:12 +00:00
function checkall ( ) {
2009-03-31 03:24:21 +00:00
var inputs = document . getElementsByTagName ( 'input' ) ;
for ( var i = 0 ; i < inputs . length ; i ++ ) {
if ( inputs [ i ] . type == 'checkbox' ) {
2012-03-22 10:09:39 +08:00
if ( inputs [ i ] . disabled || inputs [ i ] . readOnly ) {
continue ;
}
2009-03-31 03:24:21 +00:00
inputs [ i ] . checked = true ;
}
2007-01-06 19:22:58 +00:00
}
2005-01-09 15:10:12 +00:00
}
2005-03-06 12:00:46 +00:00
function checknone ( ) {
2009-03-31 03:24:21 +00:00
var inputs = document . getElementsByTagName ( 'input' ) ;
for ( var i = 0 ; i < inputs . length ; i ++ ) {
if ( inputs [ i ] . type == 'checkbox' ) {
2012-03-22 10:09:39 +08:00
if ( inputs [ i ] . disabled || inputs [ i ] . readOnly ) {
continue ;
}
2009-03-31 03:24:21 +00:00
inputs [ i ] . checked = false ;
}
2007-01-06 19:22:58 +00:00
}
2005-03-06 12:00:46 +00:00
}
2009-06-12 12:01:16 +00:00
/ * *
* Either check , or uncheck , all checkboxes inside the element with id is
* @ param id the id of the container
* @ param checked the new state , either '' or 'checked' .
* /
function select _all _in _element _with _id ( id , checked ) {
var container = document . getElementById ( id ) ;
if ( ! container ) {
return ;
}
var inputs = container . getElementsByTagName ( 'input' ) ;
for ( var i = 0 ; i < inputs . length ; ++ i ) {
if ( inputs [ i ] . type == 'checkbox' || inputs [ i ] . type == 'radio' ) {
inputs [ i ] . checked = checked ;
}
}
}
2005-08-24 23:08:54 +00:00
function select _all _in ( elTagName , elClass , elId ) {
2007-01-06 19:22:58 +00:00
var inputs = document . getElementsByTagName ( 'input' ) ;
2005-08-24 23:08:54 +00:00
inputs = filterByParent ( inputs , function ( el ) { return findParentNode ( el , elTagName , elClass , elId ) ; } ) ;
2005-03-18 14:36:10 +00:00
for ( var i = 0 ; i < inputs . length ; ++ i ) {
2006-04-21 05:17:08 +00:00
if ( inputs [ i ] . type == 'checkbox' || inputs [ i ] . type == 'radio' ) {
2005-03-18 14:36:10 +00:00
inputs [ i ] . checked = 'checked' ;
}
}
}
2005-08-24 23:08:54 +00:00
function deselect _all _in ( elTagName , elClass , elId ) {
2005-03-18 14:36:10 +00:00
var inputs = document . getElementsByTagName ( 'INPUT' ) ;
2005-08-24 23:08:54 +00:00
inputs = filterByParent ( inputs , function ( el ) { return findParentNode ( el , elTagName , elClass , elId ) ; } ) ;
2005-03-18 14:36:10 +00:00
for ( var i = 0 ; i < inputs . length ; ++ i ) {
2006-04-21 05:17:08 +00:00
if ( inputs [ i ] . type == 'checkbox' || inputs [ i ] . type == 'radio' ) {
2005-03-18 14:36:10 +00:00
inputs [ i ] . checked = '' ;
}
}
}
function confirm _if ( expr , message ) {
if ( ! expr ) {
return true ;
}
return confirm ( message ) ;
}
2005-04-16 12:30:48 +00:00
/ *
findParentNode ( start , elementName , elementClass , elementID )
2006-11-21 09:17:46 +00:00
2005-04-16 12:30:48 +00:00
Travels up the DOM hierarchy to find a parent element with the
specified tag name , class , and id . All conditions must be met ,
but any can be ommitted . Returns the BODY element if no match
found .
* /
function findParentNode ( el , elName , elClass , elId ) {
2009-06-12 12:01:16 +00:00
while ( el . nodeName . toUpperCase ( ) != 'BODY' ) {
if ( ( ! elName || el . nodeName . toUpperCase ( ) == elName ) &&
2005-04-16 12:30:48 +00:00
( ! elClass || el . className . indexOf ( elClass ) != - 1 ) &&
2009-06-12 12:01:16 +00:00
( ! elId || el . id == elId ) ) {
2005-04-16 12:30:48 +00:00
break ;
}
el = el . parentNode ;
}
return el ;
}
2006-12-14 12:44:10 +00:00
/ *
findChildNode ( start , elementName , elementClass , elementID )
Travels down the DOM hierarchy to find all child elements with the
specified tag name , class , and id . All conditions must be met ,
but any can be ommitted .
2006-12-19 07:03:08 +00:00
Doesn ' t examine children of matches .
2006-12-14 12:44:10 +00:00
* /
function findChildNodes ( start , tagName , elementClass , elementID , elementName ) {
var children = new Array ( ) ;
2007-01-24 19:39:59 +00:00
for ( var i = 0 ; i < start . childNodes . length ; i ++ ) {
2006-12-19 07:03:08 +00:00
var classfound = false ;
2007-01-24 19:39:59 +00:00
var child = start . childNodes [ i ] ;
2006-12-19 07:03:08 +00:00
if ( ( child . nodeType == 1 ) && //element node type
2009-03-16 06:09:05 +00:00
( elementClass && ( typeof ( child . className ) == 'string' ) ) ) {
2006-12-19 07:03:08 +00:00
var childClasses = child . className . split ( /\s+/ ) ;
2009-03-16 06:09:05 +00:00
for ( var childClassIndex in childClasses ) {
if ( childClasses [ childClassIndex ] == elementClass ) {
2006-12-19 07:03:08 +00:00
classfound = true ;
break ;
}
}
}
2006-12-28 09:32:45 +00:00
if ( child . nodeType == 1 ) { //element node type
if ( ( ! tagName || child . nodeName == tagName ) &&
( ! elementClass || classfound ) &&
( ! elementID || child . id == elementID ) &&
( ! elementName || child . name == elementName ) )
{
children = children . concat ( child ) ;
} else {
children = children . concat ( findChildNodes ( child , tagName , elementClass , elementID , elementName ) ) ;
}
2006-12-14 12:44:10 +00:00
}
}
return children ;
}
2005-04-16 12:30:48 +00:00
2007-04-30 18:03:19 +00:00
function unmaskPassword ( id ) {
2013-03-25 11:47:05 +08:00
var pw = document . getElementById ( id ) ;
var chb = document . getElementById ( id + 'unmask' ) ;
// MDL-30438 - The capability to changing the value of input type is not supported by IE8 or lower.
// Replacing existing child with a new one, removed all yui properties for the node. Therefore, this
// functionality won't work in IE8 or lower.
// This is a temporary fixed to allow other browsers to function properly.
if ( Y . UA . ie == 0 || Y . UA . ie >= 9 ) {
if ( chb . checked ) {
pw . type = "text" ;
} else {
pw . type = "password" ;
}
} else { //IE Browser version 8 or lower
try {
// first try IE way - it can not set name attribute later
if ( chb . checked ) {
var newpw = document . createElement ( '<input type="text" autocomplete="off" name="' + pw . name + '">' ) ;
} else {
var newpw = document . createElement ( '<input type="password" autocomplete="off" name="' + pw . name + '">' ) ;
}
newpw . attributes [ 'class' ] . nodeValue = pw . attributes [ 'class' ] . nodeValue ;
} catch ( e ) {
var newpw = document . createElement ( 'input' ) ;
newpw . setAttribute ( 'autocomplete' , 'off' ) ;
newpw . setAttribute ( 'name' , pw . name ) ;
if ( chb . checked ) {
newpw . setAttribute ( 'type' , 'text' ) ;
} else {
newpw . setAttribute ( 'type' , 'password' ) ;
}
newpw . setAttribute ( 'class' , pw . getAttribute ( 'class' ) ) ;
}
newpw . id = pw . id ;
newpw . size = pw . size ;
newpw . onblur = pw . onblur ;
newpw . onchange = pw . onchange ;
newpw . value = pw . value ;
pw . parentNode . replaceChild ( newpw , pw ) ;
2007-04-06 14:18:02 +00:00
}
}
2005-04-16 12:30:48 +00:00
function filterByParent ( elCollection , parentFinder ) {
var filteredCollection = [ ] ;
2009-06-12 12:01:16 +00:00
for ( var i = 0 ; i < elCollection . length ; ++ i ) {
2005-04-16 12:30:48 +00:00
var findParent = parentFinder ( elCollection [ i ] ) ;
2011-08-01 12:50:11 +08:00
if ( findParent . nodeName . toUpperCase ( ) != 'BODY' ) {
2005-04-16 12:30:48 +00:00
filteredCollection . push ( elCollection [ i ] ) ;
}
}
return filteredCollection ;
}
2005-05-12 14:45:16 +00:00
/ *
All this is here just so that IE gets to handle oversized blocks
in a visually pleasing manner . It does a browser detect . So sue me .
* /
function fix _column _widths ( ) {
var agt = navigator . userAgent . toLowerCase ( ) ;
if ( ( agt . indexOf ( "msie" ) != - 1 ) && ( agt . indexOf ( "opera" ) == - 1 ) ) {
fix _column _width ( 'left-column' ) ;
fix _column _width ( 'right-column' ) ;
}
}
function fix _column _width ( colName ) {
if ( column = document . getElementById ( colName ) ) {
if ( ! column . offsetWidth ) {
setTimeout ( "fix_column_width('" + colName + "')" , 20 ) ;
return ;
}
var width = 0 ;
var nodes = column . childNodes ;
for ( i = 0 ; i < nodes . length ; ++ i ) {
2010-05-06 06:16:07 +00:00
if ( nodes [ i ] . className . indexOf ( "block" ) != - 1 ) {
2005-05-12 14:45:16 +00:00
if ( width < nodes [ i ] . offsetWidth ) {
width = nodes [ i ] . offsetWidth ;
}
}
}
for ( i = 0 ; i < nodes . length ; ++ i ) {
2010-05-06 06:16:07 +00:00
if ( nodes [ i ] . className . indexOf ( "block" ) != - 1 ) {
2005-05-12 14:45:16 +00:00
nodes [ i ] . style . width = width + 'px' ;
}
}
}
}
2006-03-14 05:26:40 +00:00
/ *
2007-05-08 16:25:18 +00:00
Insert myValue at current cursor position
* /
2006-03-14 05:26:40 +00:00
function insertAtCursor ( myField , myValue ) {
2007-05-08 16:25:18 +00:00
// IE support
if ( document . selection ) {
myField . focus ( ) ;
sel = document . selection . createRange ( ) ;
sel . text = myValue ;
}
// Mozilla/Netscape support
else if ( myField . selectionStart || myField . selectionStart == '0' ) {
var startPos = myField . selectionStart ;
var endPos = myField . selectionEnd ;
myField . value = myField . value . substring ( 0 , startPos )
+ myValue + myField . value . substring ( endPos , myField . value . length ) ;
} else {
myField . value += myValue ;
}
2006-03-14 05:26:40 +00:00
}
2007-06-25 14:38:02 +00:00
/ *
2007-07-13 08:14:37 +00:00
Call instead of setting window . onload directly or setting body onload = .
Adds your function to a chain of functions rather than overwriting anything
that exists .
* /
2007-06-25 14:38:02 +00:00
function addonload ( fn ) {
var oldhandler = window . onload ;
window . onload = function ( ) {
if ( oldhandler ) oldhandler ( ) ;
2007-07-13 08:14:37 +00:00
fn ( ) ;
2007-06-25 14:38:02 +00:00
}
}
2009-08-28 08:47:31 +00:00
/ * *
* Replacement for getElementsByClassName in browsers that aren ' t cool enough
2009-11-01 16:48:45 +00:00
*
2009-08-28 08:47:31 +00:00
* Relying on the built - in getElementsByClassName is far , far faster than
* using YUI .
2009-11-01 16:48:45 +00:00
*
2009-08-28 08:47:31 +00:00
* Note : the third argument used to be an object with odd behaviour . It now
* acts like the 'name' in the HTML5 spec , though the old behaviour is still
* mimicked if you pass an object .
*
* @ param { Node } oElm The top - level node for searching . To search a whole
* document , use ` document ` .
* @ param { String } strTagName filter by tag names
* @ param { String } name same as HTML5 spec
* /
function getElementsByClassName ( oElm , strTagName , name ) {
// for backwards compatibility
if ( typeof name == "object" ) {
var names = new Array ( ) ;
for ( var i = 0 ; i < name . length ; i ++ ) names . push ( names [ i ] ) ;
name = names . join ( '' ) ;
}
// use native implementation if possible
if ( oElm . getElementsByClassName && Array . filter ) {
if ( strTagName == '*' ) {
return oElm . getElementsByClassName ( name ) ;
} else {
return Array . filter ( oElm . getElementsByClassName ( name ) , function ( el ) {
return el . nodeName . toLowerCase ( ) == strTagName . toLowerCase ( ) ;
} ) ;
}
}
// native implementation unavailable, fall back to slow method
2008-09-24 09:32:46 +00:00
var arrElements = ( strTagName == "*" && oElm . all ) ? oElm . all : oElm . getElementsByTagName ( strTagName ) ;
var arrReturnElements = new Array ( ) ;
var arrRegExpClassNames = new Array ( ) ;
2009-08-28 08:47:31 +00:00
var names = name . split ( ' ' ) ;
for ( var i = 0 ; i < names . length ; i ++ ) {
arrRegExpClassNames . push ( new RegExp ( "(^|\\s)" + names [ i ] . replace ( /\-/g , "\\-" ) + "(\\s|$)" ) ) ;
2008-09-24 09:32:46 +00:00
}
var oElement ;
var bMatchesAll ;
2009-03-16 06:09:05 +00:00
for ( var j = 0 ; j < arrElements . length ; j ++ ) {
2008-09-24 09:32:46 +00:00
oElement = arrElements [ j ] ;
bMatchesAll = true ;
2009-03-16 06:09:05 +00:00
for ( var k = 0 ; k < arrRegExpClassNames . length ; k ++ ) {
if ( ! arrRegExpClassNames [ k ] . test ( oElement . className ) ) {
2008-09-24 09:32:46 +00:00
bMatchesAll = false ;
break ;
}
}
2009-03-16 06:09:05 +00:00
if ( bMatchesAll ) {
2008-09-24 09:32:46 +00:00
arrReturnElements . push ( oElement ) ;
}
}
return ( arrReturnElements )
}
2008-09-25 03:14:24 +00:00
2013-02-25 16:45:33 +08:00
/ * *
* Increment a file name .
*
* @ param string file name .
* @ param boolean ignoreextension do not extract the extension prior to appending the
* suffix . Useful when incrementing folder names .
* @ return string the incremented file name .
* /
function increment _filename ( filename , ignoreextension ) {
var extension = '' ;
var basename = filename ;
// Split the file name into the basename + extension.
if ( ! ignoreextension ) {
var dotpos = filename . lastIndexOf ( '.' ) ;
if ( dotpos !== - 1 ) {
basename = filename . substr ( 0 , dotpos ) ;
extension = filename . substr ( dotpos , filename . length ) ;
}
}
// Look to see if the name already has (NN) at the end of it.
var number = 0 ;
var hasnumber = basename . match ( /^(.*) \((\d+)\)$/ ) ;
if ( hasnumber !== null ) {
// Note the current number & remove it from the basename.
number = parseInt ( hasnumber [ 2 ] , 10 ) ;
basename = hasnumber [ 1 ] ;
}
number ++ ;
var newname = basename + ' (' + number + ')' + extension ;
return newname ;
}
2012-11-19 18:32:37 +08:00
/ * *
* Return whether we are in right to left mode or not .
*
* @ return boolean
* /
function right _to _left ( ) {
var body = Y . one ( 'body' ) ;
var rtl = false ;
if ( body && body . hasClass ( 'dir-rtl' ) ) {
rtl = true ;
}
return rtl ;
}
2009-07-27 10:33:00 +00:00
function openpopup ( event , args ) {
2010-05-04 08:29:05 +00:00
if ( event ) {
2010-08-19 05:43:06 +00:00
if ( event . preventDefault ) {
event . preventDefault ( ) ;
} else {
event . returnValue = false ;
}
2010-05-04 08:29:05 +00:00
}
2010-09-09 11:30:06 +00:00
2012-10-03 09:49:01 +08:00
// Make sure the name argument is set and valid.
2012-09-13 16:51:45 +08:00
var nameregex = /[^a-z0-9_]/i ;
2012-10-03 09:49:01 +08:00
if ( typeof args . name !== 'string' ) {
args . name = '_blank' ;
} else if ( args . name . match ( nameregex ) ) {
// Cleans window name because IE does not support funky ones.
2012-09-13 16:51:45 +08:00
args . name = args . name . replace ( nameregex , '_' ) ;
if ( M . cfg . developerdebug ) {
alert ( 'DEVELOPER NOTICE: Invalid \'name\' passed to openpopup()' ) ;
}
}
2010-05-04 08:29:05 +00:00
var fullurl = args . url ;
if ( ! args . url . match ( /https?:\/\// ) ) {
fullurl = M . cfg . wwwroot + args . url ;
2008-09-25 03:14:24 +00:00
}
2012-07-27 13:19:17 +01:00
if ( args . fullscreen ) {
args . options = args . options .
replace ( /top=\d+/ , 'top=0' ) .
replace ( /left=\d+/ , 'left=0' ) .
replace ( /width=\d+/ , 'width=' + screen . availWidth ) .
replace ( /height=\d+/ , 'height=' + screen . availHeight ) ;
}
2010-05-04 08:29:05 +00:00
var windowobj = window . open ( fullurl , args . name , args . options ) ;
if ( ! windowobj ) {
return true ;
}
2012-07-27 13:19:17 +01:00
2010-05-04 08:29:05 +00:00
if ( args . fullscreen ) {
2012-08-09 12:52:11 +01:00
// In some browser / OS combinations (E.g. Chrome on Windows), the
// window initially opens slighly too big. The width and heigh options
// seem to control the area inside the browser window, so what with
// scroll-bars, etc. the actual window is bigger than the screen.
// Therefore, we need to fix things up after the window is open.
var hackcount = 100 ;
var get _size _exactly _right = function ( ) {
2012-07-27 13:19:17 +01:00
windowobj . moveTo ( 0 , 0 ) ;
2012-08-09 12:52:11 +01:00
windowobj . resizeTo ( screen . availWidth , screen . availHeight ) ;
// Unfortunately, it seems that in Chrome on Ubuntu, if you call
// something like windowobj.resizeTo(1280, 1024) too soon (up to
// about 50ms) after the window is open, then it actually behaves
// as if you called windowobj.resizeTo(0, 0). Therefore, we need to
// check that the resize actually worked, and if not, repeatedly try
// again after a short delay until it works (but with a limit of
// hackcount repeats.
if ( hackcount > 0 && ( windowobj . innerHeight < 10 || windowobj . innerWidth < 10 ) ) {
hackcount -= 1 ;
setTimeout ( get _size _exactly _right , 10 ) ;
}
}
setTimeout ( get _size _exactly _right , 0 ) ;
2010-05-04 08:29:05 +00:00
}
windowobj . focus ( ) ;
2010-09-09 11:30:06 +00:00
2010-05-04 08:29:05 +00:00
return false ;
2008-09-25 03:14:24 +00:00
}
2008-09-25 10:07:11 +00:00
2008-12-10 08:57:50 +00:00
/** Close the current browser window. */
2009-08-13 01:15:58 +00:00
function close _window ( e ) {
2010-08-19 05:43:06 +00:00
if ( e . preventDefault ) {
e . preventDefault ( ) ;
} else {
e . returnValue = false ;
}
2011-01-29 13:55:47 +00:00
window . close ( ) ;
2008-12-10 08:57:50 +00:00
}
2009-06-23 01:18:22 +00:00
/ * *
* Used in a couple of modules to hide navigation areas when using AJAX
* /
2009-06-26 09:06:16 +00:00
2009-09-11 02:17:54 +00:00
function show _item ( itemid ) {
var item = document . getElementById ( itemid ) ;
if ( item ) {
item . style . display = "" ;
}
}
function destroy _item ( itemid ) {
var item = document . getElementById ( itemid ) ;
if ( item ) {
item . parentNode . removeChild ( item ) ;
}
}
2009-06-26 09:06:16 +00:00
/ * *
* Tranfer keyboard focus to the HTML element with the given id , if it exists .
* @ param controlid the control id .
* /
function focuscontrol ( controlid ) {
var control = document . getElementById ( controlid ) ;
if ( control ) {
control . focus ( ) ;
}
2009-06-26 09:38:14 +00:00
}
2009-07-07 09:09:16 +00:00
/ * *
* Transfers keyboard focus to an HTML element based on the old style style of focus
* This function should be removed as soon as it is no longer used
* /
2009-07-08 09:01:20 +00:00
function old _onload _focus ( formid , controlname ) {
2009-10-29 07:48:55 +00:00
if ( document . forms [ formid ] && document . forms [ formid ] . elements && document . forms [ formid ] . elements [ controlname ] ) {
2009-07-08 09:01:20 +00:00
document . forms [ formid ] . elements [ controlname ] . focus ( ) ;
2009-07-07 09:09:16 +00:00
}
}
2009-07-24 02:44:44 +00:00
function build _querystring ( obj ) {
2010-07-22 05:51:40 +00:00
return convert _object _to _string ( obj , '&' ) ;
}
function build _windowoptionsstring ( obj ) {
return convert _object _to _string ( obj , ',' ) ;
}
function convert _object _to _string ( obj , separator ) {
2009-07-24 02:44:44 +00:00
if ( typeof obj !== 'object' ) {
return null ;
}
var list = [ ] ;
for ( var k in obj ) {
k = encodeURIComponent ( k ) ;
var value = obj [ k ] ;
if ( obj [ k ] instanceof Array ) {
for ( var i in value ) {
list . push ( k + '[]=' + encodeURIComponent ( value [ i ] ) ) ;
}
} else {
list . push ( k + '=' + encodeURIComponent ( value ) ) ;
}
}
2010-07-22 05:51:40 +00:00
return list . join ( separator ) ;
2009-07-24 02:44:44 +00:00
}
2009-08-16 04:14:46 +00:00
function stripHTML ( str ) {
var re = /<\S[^><]*>/g ;
var ret = str . replace ( re , "" ) ;
return ret ;
}
2009-09-18 03:50:46 +00:00
Number . prototype . fixed = function ( n ) {
with ( Math )
return round ( Number ( this ) * pow ( 10 , n ) ) / pow ( 10 , n ) ;
2010-09-18 11:04:02 +00:00
} ;
2009-09-18 03:50:46 +00:00
function update _progress _bar ( id , width , pt , msg , es ) {
2010-11-11 07:56:49 +00:00
var percent = pt ;
2009-09-18 03:50:46 +00:00
var status = document . getElementById ( "status_" + id ) ;
var percent _indicator = document . getElementById ( "pt_" + id ) ;
var progress _bar = document . getElementById ( "progress_" + id ) ;
var time _es = document . getElementById ( "time_" + id ) ;
status . innerHTML = msg ;
percent _indicator . innerHTML = percent . fixed ( 2 ) + '%' ;
if ( percent == 100 ) {
progress _bar . style . background = "green" ;
time _es . style . display = "none" ;
} else {
progress _bar . style . background = "#FFCC66" ;
2010-11-11 07:56:49 +00:00
if ( es == '?' ) {
time _es . innerHTML = "" ;
2009-09-18 03:50:46 +00:00
} else {
time _es . innerHTML = es . fixed ( 2 ) + " sec" ;
time _es . style . display
= "block" ;
}
}
progress _bar . style . width = width + "px" ;
}
2009-09-23 06:05:36 +00:00
2010-01-05 00:43:09 +00:00
// ===== Deprecated core Javascript functions for Moodle ====
// DO NOT USE!!!!!!!
2010-01-21 20:55:58 +00:00
// Do not put this stuff in separate file because it only adds extra load on servers!
2010-01-05 00:43:09 +00:00
2010-01-26 09:32:21 +00:00
/ * *
* Used in a couple of modules to hide navigation areas when using AJAX
* /
function hide _item ( itemid ) {
2010-02-06 15:08:12 +00:00
// use class='hiddenifjs' instead
2010-01-26 09:32:21 +00:00
var item = document . getElementById ( itemid ) ;
if ( item ) {
item . style . display = "none" ;
}
}
2010-05-03 08:44:34 +00:00
2012-10-07 09:55:08 +01:00
M . util . help _popups = {
setup : function ( Y ) {
Y . one ( 'body' ) . delegate ( 'click' , this . open _popup , 'a.helplinkpopup' , this ) ;
} ,
open _popup : function ( e ) {
// Prevent the default page action
e . preventDefault ( ) ;
// Grab the anchor that was clicked
var anchor = e . target . ancestor ( 'a' , true ) ;
var args = {
'name' : 'popup' ,
'url' : anchor . getAttribute ( 'href' ) ,
'options' : ''
} ;
var options = [
'height=600' ,
'width=800' ,
'top=0' ,
'left=0' ,
'menubar=0' ,
'location=0' ,
'scrollbars' ,
'resizable' ,
'toolbar' ,
'status' ,
'directories=0' ,
'fullscreen=0' ,
'dependent'
]
args . options = options . join ( ',' ) ;
openpopup ( e , args ) ;
}
}
2012-10-10 11:03:00 +01:00
/ * *
* This code bas been deprecated and will be removed from Moodle 2.7
*
* Please see lib / yui / popuphelp / popuphelp . js for its replacement
* /
2010-05-04 08:29:05 +00:00
M . util . help _icon = {
2012-11-21 09:31:41 +00:00
initialised : false ,
2012-10-10 11:03:00 +01:00
setup : function ( Y , properties ) {
this . add ( Y , properties ) ;
2012-11-21 09:31:41 +00:00
} ,
2012-10-10 11:03:00 +01:00
add : function ( Y ) {
if ( M . cfg . developerdebug ) {
Y . log ( "You are using a deprecated function call (M.util.help_icon.add). " +
"Please look at rewriting your call to support lib/yui/popuphelp/popuphelp.js" ) ;
}
if ( ! this . initialised ) {
YUI ( ) . use ( 'moodle-core-popuphelp' , function ( ) {
M . core . init _popuphelp ( [ ] ) ;
2010-05-04 08:29:05 +00:00
} ) ;
}
2012-10-10 11:03:00 +01:00
this . initialised = true ;
2010-05-03 08:44:34 +00:00
}
2010-09-18 11:04:02 +00:00
} ;
2010-05-10 05:24:00 +00:00
/ * *
* Custom menu namespace
* /
M . core _custom _menu = {
/ * *
* This method is used to initialise a custom menu given the id that belongs
* to the custom menu ' s root node .
2010-09-09 11:30:06 +00:00
*
2010-05-10 05:24:00 +00:00
* @ param { YUI } Y
* @ param { string } nodeid
* /
init : function ( Y , nodeid ) {
2010-05-11 07:16:23 +00:00
var node = Y . one ( '#' + nodeid ) ;
if ( node ) {
Y . use ( 'node-menunav' , function ( Y ) {
// Get the node
// Remove the javascript-disabled class.... obviously javascript is enabled.
node . removeClass ( 'javascript-disabled' ) ;
// Initialise the menunav plugin
node . plug ( Y . Plugin . NodeMenuNav ) ;
} ) ;
}
2010-05-10 05:24:00 +00:00
}
2010-09-18 11:04:02 +00:00
} ;
2010-05-18 07:58:45 +00:00
/ * *
* Used to store form manipulation methods and enhancments
* /
M . form = M . form || { } ;
/ * *
* Converts a nbsp indented select box into a multi drop down custom control much
* like the custom menu . It also selectable categories on or off .
*
* $form - > init _javascript _enhancement ( 'elementname' , 'smartselect' , array ( 'selectablecategories' => true | false , 'mode' => 'compact' | 'spanning' ) ) ;
*
* @ param { YUI } Y
* @ param { string } id
* @ param { Array } options
* /
M . form . init _smartselect = function ( Y , id , options ) {
2010-05-19 05:56:13 +00:00
if ( ! id . match ( /^id_/ ) ) {
id = 'id_' + id ;
}
var select = Y . one ( 'select#' + id ) ;
2010-05-18 07:58:45 +00:00
if ( ! select ) {
return false ;
}
Y . use ( 'event-delegate' , function ( ) {
var smartselect = {
id : id ,
structure : [ ] ,
options : [ ] ,
submenucount : 0 ,
currentvalue : null ,
currenttext : null ,
shownevent : null ,
cfg : {
selectablecategories : true ,
mode : null
} ,
nodes : {
select : null ,
loading : null ,
menu : null
} ,
init : function ( Y , id , args , nodes ) {
if ( typeof ( args ) == 'object' ) {
for ( var i in this . cfg ) {
if ( args [ i ] || args [ i ] === false ) {
this . cfg [ i ] = args [ i ] ;
}
}
}
2010-09-09 11:30:06 +00:00
2010-05-18 07:58:45 +00:00
// Display a loading message first up
this . nodes . select = nodes . select ;
this . currentvalue = this . nodes . select . get ( 'selectedIndex' ) ;
this . currenttext = this . nodes . select . all ( 'option' ) . item ( this . currentvalue ) . get ( 'innerHTML' ) ;
var options = Array ( ) ;
2010-09-18 11:04:02 +00:00
options [ '' ] = { text : this . currenttext , value : '' , depth : 0 , children : [ ] } ;
2010-05-18 07:58:45 +00:00
this . nodes . select . all ( 'option' ) . each ( function ( option , index ) {
var rawtext = option . get ( 'innerHTML' ) ;
var text = rawtext . replace ( /^( )*/ , '' ) ;
if ( rawtext === text ) {
text = rawtext . replace ( /^(\s)*/ , '' ) ;
var depth = ( rawtext . length - text . length ) + 1 ;
} else {
var depth = ( ( rawtext . length - text . length ) / 12 ) + 1 ;
}
option . set ( 'innerHTML' , text ) ;
options [ 'i' + index ] = { text : text , depth : depth , index : index , children : [ ] } ;
} , this ) ;
this . structure = [ ] ;
var structcount = 0 ;
for ( var i in options ) {
var o = options [ i ] ;
if ( o . depth == 0 ) {
this . structure . push ( o ) ;
structcount ++ ;
} else {
var d = o . depth ;
var current = this . structure [ structcount - 1 ] ;
for ( var j = 0 ; j < o . depth - 1 ; j ++ ) {
if ( current && current . children ) {
current = current . children [ current . children . length - 1 ] ;
}
}
if ( current && current . children ) {
current . children . push ( o ) ;
}
}
}
this . nodes . menu = Y . Node . create ( this . generate _menu _content ( ) ) ;
this . nodes . menu . one ( '.smartselect_mask' ) . setStyle ( 'opacity' , 0.01 ) ;
this . nodes . menu . one ( '.smartselect_mask' ) . setStyle ( 'width' , ( this . nodes . select . get ( 'offsetWidth' ) + 5 ) + 'px' ) ;
this . nodes . menu . one ( '.smartselect_mask' ) . setStyle ( 'height' , ( this . nodes . select . get ( 'offsetHeight' ) ) + 'px' ) ;
if ( this . cfg . mode == null ) {
var formwidth = this . nodes . select . ancestor ( 'form' ) . get ( 'offsetWidth' ) ;
if ( formwidth < 400 || this . nodes . menu . get ( 'offsetWidth' ) < formwidth * 2 ) {
this . cfg . mode = 'compact' ;
} else {
this . cfg . mode = 'spanning' ;
}
}
if ( this . cfg . mode == 'compact' ) {
this . nodes . menu . addClass ( 'compactmenu' ) ;
} else {
this . nodes . menu . addClass ( 'spanningmenu' ) ;
this . nodes . menu . delegate ( 'mouseover' , this . show _sub _menu , '.smartselect_submenuitem' , this ) ;
}
Y . one ( document . body ) . append ( this . nodes . menu ) ;
var pos = this . nodes . select . getXY ( ) ;
pos [ 0 ] += 1 ;
this . nodes . menu . setXY ( pos ) ;
this . nodes . menu . on ( 'click' , this . handle _click , this ) ;
2010-05-18 08:11:12 +00:00
Y . one ( window ) . on ( 'resize' , function ( ) {
var pos = this . nodes . select . getXY ( ) ;
pos [ 0 ] += 1 ;
this . nodes . menu . setXY ( pos ) ;
} , this ) ;
2010-05-18 07:58:45 +00:00
} ,
generate _menu _content : function ( ) {
var content = '<div id="' + this . id + '_smart_select" class="smartselect">' ;
content += this . generate _submenu _content ( this . structure [ 0 ] , true ) ;
content += '</ul></div>' ;
return content ;
} ,
generate _submenu _content : function ( item , rootelement ) {
this . submenucount ++ ;
var content = '' ;
if ( item . children . length > 0 ) {
if ( rootelement ) {
content += '<div class="smartselect_mask" href="#ss_submenu' + this . submenucount + '"> </div>' ;
content += '<div id="ss_submenu' + this . submenucount + '" class="smartselect_menu">' ;
content += '<div class="smartselect_menu_content">' ;
} else {
content += '<li class="smartselect_submenuitem">' ;
var categoryclass = ( this . cfg . selectablecategories ) ? 'selectable' : 'notselectable' ;
content += '<a class="smartselect_menuitem_label ' + categoryclass + '" href="#ss_submenu' + this . submenucount + '" value="' + item . index + '">' + item . text + '</a>' ;
content += '<div id="ss_submenu' + this . submenucount + '" class="smartselect_submenu">' ;
content += '<div class="smartselect_submenu_content">' ;
}
content += '<ul>' ;
for ( var i in item . children ) {
content += this . generate _submenu _content ( item . children [ i ] , false ) ;
}
content += '</ul>' ;
content += '</div>' ;
content += '</div>' ;
if ( rootelement ) {
} else {
content += '</li>' ;
}
} else {
content += '<li class="smartselect_menuitem">' ;
content += '<a class="smartselect_menuitem_content selectable" href="#" value="' + item . index + '">' + item . text + '</a>' ;
content += '</li>' ;
}
return content ;
} ,
select : function ( e ) {
var t = e . target ;
e . halt ( ) ;
this . currenttext = t . get ( 'innerHTML' ) ;
this . currentvalue = t . getAttribute ( 'value' ) ;
this . nodes . select . set ( 'selectedIndex' , this . currentvalue ) ;
this . hide _menu ( ) ;
} ,
handle _click : function ( e ) {
var target = e . target ;
if ( target . hasClass ( 'smartselect_mask' ) ) {
this . show _menu ( e ) ;
} else if ( target . hasClass ( 'selectable' ) || target . hasClass ( 'smartselect_menuitem' ) ) {
this . select ( e ) ;
} else if ( target . hasClass ( 'smartselect_menuitem_label' ) || target . hasClass ( 'smartselect_submenuitem' ) ) {
this . show _sub _menu ( e ) ;
}
} ,
show _menu : function ( e ) {
e . halt ( ) ;
var menu = e . target . ancestor ( ) . one ( '.smartselect_menu' ) ;
menu . addClass ( 'visible' ) ;
this . shownevent = Y . one ( document . body ) . on ( 'click' , this . hide _menu , this ) ;
} ,
show _sub _menu : function ( e ) {
e . halt ( ) ;
var target = e . target ;
if ( ! target . hasClass ( 'smartselect_submenuitem' ) ) {
target = target . ancestor ( '.smartselect_submenuitem' ) ;
}
if ( this . cfg . mode == 'compact' && target . one ( '.smartselect_submenu' ) . hasClass ( 'visible' ) ) {
target . ancestor ( 'ul' ) . all ( '.smartselect_submenu.visible' ) . removeClass ( 'visible' ) ;
return ;
}
target . ancestor ( 'ul' ) . all ( '.smartselect_submenu.visible' ) . removeClass ( 'visible' ) ;
target . one ( '.smartselect_submenu' ) . addClass ( 'visible' ) ;
} ,
hide _menu : function ( ) {
this . nodes . menu . all ( '.visible' ) . removeClass ( 'visible' ) ;
if ( this . shownevent ) {
this . shownevent . detach ( ) ;
}
}
2010-09-18 11:04:02 +00:00
} ;
2010-05-18 07:58:45 +00:00
smartselect . init ( Y , id , options , { select : select } ) ;
} ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-09-09 11:30:06 +00:00
2011-03-12 17:42:52 +01:00
/** List of flv players to be loaded */
M . util . video _players = [ ] ;
/** List of mp3 players to be loaded */
M . util . audio _players = [ ] ;
/ * *
* Add video player
* @ param id element id
* @ param fileurl media url
* @ param width
* @ param height
* @ param autosize true means detect size from media
* /
M . util . add _video _player = function ( id , fileurl , width , height , autosize ) {
M . util . video _players . push ( { id : id , fileurl : fileurl , width : width , height : height , autosize : autosize , resized : false } ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-09-09 11:30:06 +00:00
2011-03-12 17:42:52 +01:00
/ * *
* Add audio player .
* @ param id
* @ param fileurl
* @ param small
* /
M . util . add _audio _player = function ( id , fileurl , small ) {
M . util . audio _players . push ( { id : id , fileurl : fileurl , small : small } ) ;
2010-09-18 11:04:02 +00:00
} ;
2010-09-09 11:30:06 +00:00
2011-03-12 17:42:52 +01:00
/ * *
* Initialise all audio and video player , must be called from page footer .
* /
M . util . load _flowplayer = function ( ) {
if ( M . util . video _players . length == 0 && M . util . audio _players . length == 0 ) {
return ;
}
if ( typeof ( flowplayer ) == 'undefined' ) {
var loaded = false ;
var embed _function = function ( ) {
if ( loaded || typeof ( flowplayer ) == 'undefined' ) {
return ;
2010-09-09 11:30:06 +00:00
}
2011-03-12 17:42:52 +01:00
loaded = true ;
var controls = {
autoHide : true
}
/* TODO: add CSS color overrides for the flv flow player */
for ( var i = 0 ; i < M . util . video _players . length ; i ++ ) {
var video = M . util . video _players [ i ] ;
if ( video . width > 0 && video . height > 0 ) {
2013-03-24 18:35:09 +01:00
var src = { src : M . cfg . wwwroot + '/lib/flowplayer/flowplayer-3.2.16.swf' , width : video . width , height : video . height } ;
2011-03-12 17:42:52 +01:00
} else {
2013-03-24 18:35:09 +01:00
var src = M . cfg . wwwroot + '/lib/flowplayer/flowplayer-3.2.16.swf' ;
2011-03-12 17:42:52 +01:00
}
flowplayer ( video . id , src , {
plugins : { controls : controls } ,
clip : {
url : video . fileurl , autoPlay : false , autoBuffering : true , scaling : 'fit' , mvideo : video ,
onMetaData : function ( clip ) {
if ( clip . mvideo . autosize && ! clip . mvideo . resized ) {
clip . mvideo . resized = true ;
//alert("metadata!!! "+clip.width+' '+clip.height+' '+JSON.stringify(clip.metaData));
if ( typeof ( clip . metaData . width ) == 'undefined' || typeof ( clip . metaData . height ) == 'undefined' ) {
// bad luck, we have to guess - we may not get metadata at all
var width = clip . width ;
var height = clip . height ;
} else {
var width = clip . metaData . width ;
var height = clip . metaData . height ;
}
var minwidth = 300 ; // controls are messed up in smaller objects
if ( width < minwidth ) {
height = ( height * minwidth ) / width ;
width = minwidth ;
}
var object = this . _api ( ) ;
object . width = width ;
object . height = height ;
}
2012-11-26 15:01:31 +08:00
}
2011-03-12 17:42:52 +01:00
}
} ) ;
}
if ( M . util . audio _players . length == 0 ) {
return ;
}
var controls = {
autoHide : false ,
fullscreen : false ,
next : false ,
previous : false ,
scrubber : true ,
play : true ,
pause : true ,
volume : true ,
mute : false ,
backgroundGradient : [ 0.5 , 0 , 0.3 ]
} ;
var rule ;
for ( var j = 0 ; j < document . styleSheets . length ; j ++ ) {
2011-12-22 16:34:32 +01:00
// To avoid javascript security violation accessing cross domain stylesheets
var allrules = false ;
try {
if ( typeof ( document . styleSheets [ j ] . rules ) != 'undefined' ) {
allrules = document . styleSheets [ j ] . rules ;
} else if ( typeof ( document . styleSheets [ j ] . cssRules ) != 'undefined' ) {
allrules = document . styleSheets [ j ] . cssRules ;
} else {
// why??
continue ;
}
} catch ( e ) {
2011-03-12 17:42:52 +01:00
continue ;
}
2011-12-22 16:34:32 +01:00
// On cross domain style sheets Chrome V8 allows access to rules but returns null
if ( ! allrules ) {
continue ;
}
2011-03-12 17:42:52 +01:00
for ( var i = 0 ; i < allrules . length ; i ++ ) {
rule = '' ;
if ( /^\.mp3flowplayer_.*Color$/ . test ( allrules [ i ] . selectorText ) ) {
if ( typeof ( allrules [ i ] . cssText ) != 'undefined' ) {
2011-10-28 15:21:02 +02:00
rule = allrules [ i ] . cssText ;
2011-03-12 17:42:52 +01:00
} else if ( typeof ( allrules [ i ] . style . cssText ) != 'undefined' ) {
rule = allrules [ i ] . style . cssText ;
}
if ( rule != '' && /.*color\s*:\s*([^;]+).*/gi . test ( rule ) ) {
rule = rule . replace ( /.*color\s*:\s*([^;]+).*/gi , '$1' ) ;
var colprop = allrules [ i ] . selectorText . replace ( /^\.mp3flowplayer_/ , '' ) ;
controls [ colprop ] = rule ;
}
}
}
allrules = false ;
}
for ( i = 0 ; i < M . util . audio _players . length ; i ++ ) {
var audio = M . util . audio _players [ i ] ;
if ( audio . small ) {
controls . controlall = false ;
controls . height = 15 ;
controls . time = false ;
} else {
controls . controlall = true ;
controls . height = 25 ;
controls . time = true ;
}
2013-03-24 18:35:09 +01:00
flowplayer ( audio . id , M . cfg . wwwroot + '/lib/flowplayer/flowplayer-3.2.16.swf' , {
2012-09-02 15:11:57 +02:00
plugins : { controls : controls , audio : { url : M . cfg . wwwroot + '/lib/flowplayer/flowplayer.audio-3.2.10.swf' } } ,
2011-03-12 17:42:52 +01:00
clip : { url : audio . fileurl , provider : "audio" , autoPlay : false }
} ) ;
}
}
2012-09-02 15:11:57 +02:00
if ( M . cfg . jsrev == - 1 ) {
2013-03-24 18:35:09 +01:00
var jsurl = M . cfg . wwwroot + '/lib/flowplayer/flowplayer-3.2.12.js' ;
2011-03-12 17:42:52 +01:00
} else {
2013-03-24 18:35:09 +01:00
var jsurl = M . cfg . wwwroot + '/lib/javascript.php?jsfile=/lib/flowplayer/flowplayer-3.2.12.min.js&rev=' + M . cfg . jsrev ;
2011-03-12 17:42:52 +01:00
}
var fileref = document . createElement ( 'script' ) ;
fileref . setAttribute ( 'type' , 'text/javascript' ) ;
fileref . setAttribute ( 'src' , jsurl ) ;
fileref . onload = embed _function ;
fileref . onreadystatechange = embed _function ;
document . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( fileref ) ;
}
2012-01-23 11:36:53 +00:00
} ;