[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 YUI.add('moodle-core-tooltip', function (Y, NAME) { 2 3 /** 4 * Provides the base tooltip class. 5 * 6 * @module moodle-core-tooltip 7 */ 8 9 /** 10 * A base class for a tooltip. 11 * 12 * @param {Object} config Object literal specifying tooltip configuration properties. 13 * @class M.core.tooltip 14 * @constructor 15 * @extends M.core.dialogue 16 */ 17 function TOOLTIP(config) { 18 if (!config) { 19 config = {}; 20 } 21 22 // Override the default options provided by the parent class. 23 if (typeof config.draggable === 'undefined') { 24 config.draggable = true; 25 } 26 27 if (typeof config.constrain === 'undefined') { 28 config.constrain = true; 29 } 30 31 TOOLTIP.superclass.constructor.apply(this, [config]); 32 } 33 34 var SELECTORS = { 35 CLOSEBUTTON: '.closebutton' 36 }, 37 38 CSS = { 39 PANELTEXT: 'tooltiptext' 40 }, 41 RESOURCES = { 42 WAITICON: { 43 pix: 'i/loading_small', 44 component: 'moodle' 45 } 46 }, 47 ATTRS = {}; 48 49 /** 50 * Static property provides a string to identify the JavaScript class. 51 * 52 * @property NAME 53 * @type String 54 * @static 55 */ 56 TOOLTIP.NAME = 'moodle-core-tooltip'; 57 58 /** 59 * Static property used to define the CSS prefix applied to tooltip dialogues. 60 * 61 * @property CSS_PREFIX 62 * @type String 63 * @static 64 */ 65 TOOLTIP.CSS_PREFIX = 'moodle-dialogue'; 66 67 /** 68 * Static property used to define the default attribute configuration for the Tooltip. 69 * 70 * @property ATTRS 71 * @type String 72 * @static 73 */ 74 TOOLTIP.ATTRS = ATTRS; 75 76 /** 77 * The initial value of the header region before the content finishes loading. 78 * 79 * @attribute initialheadertext 80 * @type String 81 * @default '' 82 * @writeOnce 83 */ 84 ATTRS.initialheadertext = { 85 value: '' 86 }; 87 88 /** 89 * The initial value of the body region before the content finishes loading. 90 * 91 * The supplid string will be wrapped in a div with the CSS.PANELTEXT class and a standard Moodle spinner 92 * appended. 93 * 94 * @attribute initialbodytext 95 * @type String 96 * @default '' 97 * @writeOnce 98 */ 99 ATTRS.initialbodytext = { 100 value: '', 101 setter: function(content) { 102 var parentnode, 103 spinner; 104 parentnode = Y.Node.create('<div />') 105 .addClass(CSS.PANELTEXT); 106 107 spinner = Y.Node.create('<img />') 108 .setAttribute('src', M.util.image_url(RESOURCES.WAITICON.pix, RESOURCES.WAITICON.component)) 109 .addClass('spinner'); 110 111 if (content) { 112 // If we have been provided with content, add it to the parent and make 113 // the spinner appear correctly inline 114 parentnode.set('text', content); 115 spinner.addClass('iconsmall'); 116 } else { 117 // If there is no loading message, just make the parent node a lightbox 118 parentnode.addClass('content-lightbox'); 119 } 120 121 parentnode.append(spinner); 122 return parentnode; 123 } 124 }; 125 126 /** 127 * The initial value of the footer region before the content finishes loading. 128 * 129 * If a value is supplied, it will be wrapped in a <div> first. 130 * 131 * @attribute initialfootertext 132 * @type String 133 * @default '' 134 * @writeOnce 135 */ 136 ATTRS.initialfootertext = { 137 value: null, 138 setter: function(content) { 139 if (content) { 140 return Y.Node.create('<div />') 141 .set('text', content); 142 } 143 } 144 }; 145 146 /** 147 * The function which handles setting the content of the title region. 148 * The specified function will be called with a context of the tooltip instance. 149 * 150 * The default function will simply set the value of the title to object.heading as returned by the AJAX call. 151 * 152 * @attribute headerhandler 153 * @type Function|String|null 154 * @default set_header_content 155 */ 156 ATTRS.headerhandler = { 157 value: 'set_header_content' 158 }; 159 160 /** 161 * The function which handles setting the content of the body region. 162 * The specified function will be called with a context of the tooltip instance. 163 * 164 * The default function will simply set the value of the body area to a div containing object.text as returned 165 * by the AJAX call. 166 * 167 * @attribute bodyhandler 168 * @type Function|String|null 169 * @default set_body_content 170 */ 171 ATTRS.bodyhandler = { 172 value: 'set_body_content' 173 }; 174 175 /** 176 * The function which handles setting the content of the footer region. 177 * The specified function will be called with a context of the tooltip instance. 178 * 179 * By default, the footer is not set. 180 * 181 * @attribute footerhandler 182 * @type Function|String|null 183 * @default null 184 */ 185 ATTRS.footerhandler = { 186 value: null 187 }; 188 189 /** 190 * The function which handles modifying the URL that was clicked on. 191 * 192 * The default function rewrites '.php' to '_ajax.php'. 193 * 194 * @attribute urlmodifier 195 * @type Function|String|null 196 * @default null 197 */ 198 ATTRS.urlmodifier = { 199 value: null 200 }; 201 202 /** 203 * Set the Y.Cache object to use. 204 * 205 * By default a new Y.Cache object will be created for each instance of the tooltip. 206 * 207 * In certain situations, where multiple tooltips may share the same cache, it may be preferable to 208 * seed this cache from the calling method. 209 * 210 * @attribute textcache 211 * @type Y.Cache|null 212 * @default null 213 */ 214 ATTRS.textcache = { 215 value: null 216 }; 217 218 /** 219 * Set the default size of the Y.Cache object. 220 * 221 * This is only used if no textcache is specified. 222 * 223 * @attribute textcachesize 224 * @type Number 225 * @default 10 226 */ 227 ATTRS.textcachesize = { 228 value: 10 229 }; 230 231 Y.extend(TOOLTIP, M.core.dialogue, { 232 // The bounding box. 233 bb: null, 234 235 // Any event listeners we may need to cancel later. 236 listenevents: [], 237 238 // Cache of objects we've already retrieved. 239 textcache: null, 240 241 // The align position. This differs for RTL languages so we calculate once and store. 242 alignpoints: [ 243 Y.WidgetPositionAlign.TL, 244 Y.WidgetPositionAlign.RC 245 ], 246 247 initializer: function() { 248 // Set the initial values for the handlers. 249 // These cannot be set in the attributes section as context isn't present at that time. 250 if (!this.get('headerhandler')) { 251 this.set('headerhandler', this.set_header_content); 252 } 253 if (!this.get('bodyhandler')) { 254 this.set('bodyhandler', this.set_body_content); 255 } 256 if (!this.get('footerhandler')) { 257 this.set('footerhandler', function() {}); 258 } 259 if (!this.get('urlmodifier')) { 260 this.set('urlmodifier', this.modify_url); 261 } 262 263 // Set up the dialogue with initial content. 264 this.setAttrs({ 265 headerContent: this.get('initialheadertext'), 266 bodyContent: this.get('initialbodytext'), 267 footerContent: this.get('initialfootertext') 268 }); 269 270 // Hide and then render the dialogue. 271 this.hide(); 272 this.render(); 273 274 // Hook into a few useful areas. 275 this.bb = this.get('boundingBox'); 276 277 // Add an additional class to the boundingbox to allow tooltip-specific style to be 278 // set. 279 this.bb.addClass('moodle-dialogue-tooltip'); 280 281 // Change the alignment if this is an RTL language. 282 if (window.right_to_left()) { 283 this.alignpoints = [ 284 Y.WidgetPositionAlign.TR, 285 Y.WidgetPositionAlign.LC 286 ]; 287 } 288 289 // Set up the text cache if it's not set up already. 290 if (!this.get('textcache')) { 291 this.set('textcache', new Y.Cache({ 292 // Set a reasonable maximum cache size to prevent memory growth. 293 max: this.get('textcachesize') 294 })); 295 } 296 297 // Disable the textcache when in developerdebug. 298 if (M.cfg.developerdebug) { 299 this.get('textcache').set('max', 0); 300 } 301 302 return this; 303 }, 304 305 /** 306 * Display the tooltip for the clicked link. 307 * 308 * The anchor for the clicked link is used. 309 * 310 * @method display_panel 311 * @param {EventFacade} e The event from the clicked link. This is used to determine the clicked URL. 312 */ 313 display_panel: function(e) { 314 var clickedlink, thisevent, ajaxurl, config, cacheentry; 315 316 // Prevent the default click action and prevent the event triggering anything else. 317 e.preventDefault(); 318 319 // Cancel any existing listeners and close the panel if it's already open. 320 this.cancel_events(); 321 322 // Grab the clickedlink - this contains the URL we fetch and we align the panel to it. 323 clickedlink = e.target.ancestor('a', true); 324 325 // Reset the initial text to a spinner while we retrieve the text. 326 this.setAttrs({ 327 headerContent: this.get('initialheadertext'), 328 bodyContent: this.get('initialbodytext'), 329 footerContent: this.get('initialfootertext') 330 }); 331 332 // Now that initial setup has begun, show the panel. 333 this.show(e); 334 335 // Align with the link that was clicked. 336 this.align(clickedlink, this.alignpoints); 337 338 // Add some listen events to close on. 339 thisevent = this.bb.delegate('click', this.close_panel, SELECTORS.CLOSEBUTTON, this); 340 this.listenevents.push(thisevent); 341 342 thisevent = Y.one('body').on('key', this.close_panel, 'esc', this); 343 this.listenevents.push(thisevent); 344 345 // Listen for mousedownoutside events - clickoutside is broken on IE. 346 thisevent = this.bb.on('mousedownoutside', this.close_panel, this); 347 this.listenevents.push(thisevent); 348 349 // Modify the URL as required. 350 ajaxurl = Y.bind(this.get('urlmodifier'), this, clickedlink.get('href'))(); 351 352 cacheentry = this.get('textcache').retrieve(ajaxurl); 353 if (cacheentry) { 354 // The data from this help call was already cached so use that and avoid an AJAX call. 355 this._set_panel_contents(cacheentry.response); 356 } else { 357 // Retrieve the actual help text we should use. 358 config = { 359 method: 'get', 360 context: this, 361 sync: false, 362 on: { 363 complete: function(tid, response) { 364 this._set_panel_contents(response.responseText, ajaxurl); 365 } 366 } 367 }; 368 369 Y.io(ajaxurl, config); 370 } 371 }, 372 373 _set_panel_contents: function(response, ajaxurl) { 374 var responseobject; 375 376 // Attempt to parse the response into an object. 377 try { 378 responseobject = Y.JSON.parse(response); 379 if (responseobject.error) { 380 this.close_panel(); 381 Y.use('moodle-core-notification-ajaxexception', function() { 382 return new M.core.ajaxException(responseobject).show(); 383 }); 384 return this; 385 } 386 } catch (error) { 387 this.close_panel(); 388 Y.use('moodle-core-notification-exception', function() { 389 return new M.core.exception(error).show(); 390 }); 391 return this; 392 } 393 394 // Set the contents using various handlers. 395 // We must use Y.bind to ensure that the correct context is used when the default handlers are overridden. 396 Y.bind(this.get('headerhandler'), this, responseobject)(); 397 Y.bind(this.get('bodyhandler'), this, responseobject)(); 398 Y.bind(this.get('footerhandler'), this, responseobject)(); 399 400 if (ajaxurl) { 401 // Ensure that this data is added to the cache. 402 this.get('textcache').add(ajaxurl, response); 403 } 404 405 this.get('buttons').header[0].focus(); 406 }, 407 408 set_header_content: function(responseobject) { 409 this.set('headerContent', responseobject.heading); 410 }, 411 412 set_body_content: function(responseobject) { 413 var bodycontent = Y.Node.create('<div />') 414 .set('innerHTML', responseobject.text) 415 .setAttribute('role', 'alert') 416 .addClass(CSS.PANELTEXT); 417 this.set('bodyContent', bodycontent); 418 }, 419 420 modify_url: function(url) { 421 return url.replace(/\.php\?/, '_ajax.php?'); 422 }, 423 424 close_panel: function(e) { 425 // Hide the panel first. 426 this.hide(e); 427 428 // Cancel the listeners that we added in display_panel. 429 this.cancel_events(); 430 431 // Prevent any default click that the close button may have. 432 if (e) { 433 e.preventDefault(); 434 } 435 }, 436 437 cancel_events: function() { 438 // Detach all listen events to prevent duplicate triggers. 439 var thisevent; 440 while (this.listenevents.length) { 441 thisevent = this.listenevents.shift(); 442 thisevent.detach(); 443 } 444 } 445 }); 446 447 Y.Base.modifyAttrs(TOOLTIP, { 448 /** 449 * Whether the widget should be modal or not. 450 * 451 * Moodle override: We override this for tooltip to default it to false. 452 * 453 * @attribute Modal 454 * @type Boolean 455 * @default false 456 */ 457 modal: { 458 value: false 459 }, 460 461 focusOnPreviousTargetAfterHide: { 462 value: true 463 } 464 }); 465 466 M.core = M.core || {}; 467 M.core.tooltip = M.core.tooltip = TOOLTIP; 468 469 470 }, '@VERSION@', { 471 "requires": [ 472 "base", 473 "node", 474 "io-base", 475 "moodle-core-notification-dialogue", 476 "json-parse", 477 "widget-position", 478 "widget-position-align", 479 "event-outside", 480 "cache-base" 481 ] 482 });
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |