
gerrit at wikimedia
Aug 11, 2013, 6:52 PM
Post #2 of 2
(4 views)
Permalink
|
|
[MediaWiki-commits] [Gerrit] Get jshint passing on migrated Guiders code, other style fixes - change (mediawiki...GuidedTour)
[In reply to]
|
|
jenkins-bot has submitted this change and it was merged. Change subject: Get jshint passing on migrated Guiders code, other style fixes ...................................................................... Get jshint passing on migrated Guiders code, other style fixes Mark some methods deprecated. Change-Id: I092891ac9d34dab846dfb6f3e427d5f172aef419 --- M .jshintignore M GuidedTour.php M modules/ext.guidedTour.css D modules/mediawiki.libs.guiders/mediawiki.libs.guiders.exposeGuiders.js M modules/mediawiki.libs.guiders/mediawiki.libs.guiders.js 5 files changed, 895 insertions(+), 860 deletions(-) Approvals: Ori.livneh: Looks good to me, approved jenkins-bot: Verified diff --git a/.jshintignore b/.jshintignore index d6b2112..77f12ae 100644 --- a/.jshintignore +++ b/.jshintignore @@ -1,2 +1 @@ docs/ -modules/mediawiki.libs.guiders/mediawiki.libs.guiders.js diff --git a/GuidedTour.php b/GuidedTour.php index 6d2bac5..a877adf 100644 --- a/GuidedTour.php +++ b/GuidedTour.php @@ -62,7 +62,6 @@ 'styles' => 'mediawiki.libs.guiders.css', 'scripts' => array( 'mediawiki.libs.guiders.js', - 'mediawiki.libs.guiders.exposeGuiders.js', ), 'localBasePath' => $dir . $guidersPath, 'remoteExtPath' => "GuidedTour/$guidersPath", diff --git a/modules/ext.guidedTour.css b/modules/ext.guidedTour.css index 69252e6..aba214a 100644 --- a/modules/ext.guidedTour.css +++ b/modules/ext.guidedTour.css @@ -55,7 +55,7 @@ } /** - Since Guiders uses dynamic absolute positioning, the elements below need to be flipped at a higher level. + Since Guiders uses dynamic absolute positioning, the elements below need to be flipped at a higher level. */ /* @noflip */ diff --git a/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.exposeGuiders.js b/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.exposeGuiders.js deleted file mode 100644 index 1ba0d94..0000000 --- a/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.exposeGuiders.js +++ /dev/null @@ -1,13 +0,0 @@ -/*global guiders: false */ -( function ( mw ) { - - /* This is in the same module as the Guiders code. Capture it - * in mw.libs - * (per https://www.mediawiki.org/wiki/Manual:Coding_conventions/JavaScript#Globals) - * before we leave the module/anonymous function. - * - * It is not actually global in production mode; that just suppresses an - * inapplicable jshint warning on this file. - */ - mw.libs.guiders = guiders; -}( mediaWiki ) ); diff --git a/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.js b/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.js index 9da4f8a..369f1b2 100644 --- a/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.js +++ b/modules/mediawiki.libs.guiders/mediawiki.libs.guiders.js @@ -1,3 +1,8 @@ +/*jshint camelcase: false, scripturl: true*/ +// TODO (mattflaschen, 2013-07-30): Remove these after the following are resolved: +// * Camel case - Remove the deprecated public camel case identifiers. +// * Script URL, we need to determine the replacement, either a wrapper of the onclick that +// calls preventDefault, or another element with no default. /** * guiders.js * @@ -39,961 +44,1006 @@ // Previously, there was a MediaWiki-specific repository for // Guiders (based on the upstream one). For earlier version control history, see // https://git.wikimedia.org/log/mediawiki%2Fextensions%2FGuidedTour%2Fguiders.git -var guiders = (function($) { - var guiders = {}; - guiders.version = "1.2.8"; +// TODO (mattflaschen, 2013-07-30): +mediaWiki.libs.guiders = (function($) { + var guiders, _resizing; - guiders._defaultSettings = { - attachTo: null, // Selector of the element to attach to. - autoAdvance: null, //replace with array of selector, event to bind to cause auto-advance - autoFocus: false, // Determines whether or not the browser scrolls to the element." - bindAdvanceHandler: function(this_obj) { //see guiders.handlers below for other common options - if (!this_obj.autoAdvance) { return; } - this_obj._advanceHandler = function() { - $(this_obj.autoAdvance[0]).unbind(this_obj.autoAdvance[1], this_obj._advanceHandler); //unbind event before next - switch (this_obj.autoAdvance[1]) { - case 'hover': //delay hover so the guider has time to get into position (in the case of flyout menus, etc) - guiders.hideAll(); //hide immediately - setTimeout(function() { guiders.next(); }, 1000); //1 second delay - break; - case 'blur': - // fall through... - default: - guiders.next(); - } - }; - }, - buttons: [{name: "Close"}], - buttonCustomHTML: "", - classString: null, - closeOnEscape: false, - closeOnClickOutside: false, - description: "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", - highlight: null, - // If guider would go off screen to the left or right, flip horizontally. - // If guider would go off the top of the screen, flip vertically. If it would go off the bottom of the screen do nothing, since most pages scroll in the vertical direction. - // It will be flipped both ways if it would be off-screen on two sides. - flipToKeepOnScreen: false, - isHashable: true, - offset: { - top: null, - left: null - }, - onClose: null, // Function taking two arguments, the guider and a boolean for close type (false for text close button, true for everything else). Returns true to end tour, false or undefined to dismiss current step. If there is no function, dismiss-only is default. - onHide: null, - onShow: null, - overlay: false, + guiders = {}; - // 1-12 follows an analog clock, 0 means centered. You can also use the string positions - // listed below at guiders._offsetNameMapping, such as "topRight". - position: 0, - // Function handler that allows you to skip this guider if the function returns true. - shouldSkip: function () { - return false; - }, - title: "Sample title goes here", - width: 400, - xButton: false, // this places a closer "x" button in the top right of the guider - _advanceHandler: null //action to do on advance. Set by bindAdvanceHandler closure done on show() - }; + guiders.version = '1.2.8'; - // Begin additional functionality - guiders.failStep = ""; - /** - * Various common utility handlers you can bind as advance handlers to your - * guider configurations - */ - guiders.handlers = { - /** - * Auto-advance if the element is missing - */ - advance_if_not_exists: function() { - return guiders._defaultSettings._bindAdvanceHandler; - }, - /** - * Advance if test_function() returns true - */ - advance_if_test: function(test_function) { - return function(this_obj) { - var bind_obj = $(this_obj.autoAdvance[0]); - this_obj._advanceHandler = function() { - if (!test_function()) { return; } //don't advance if test_function is false - bind_obj.unbind(this_obj.autoAdvance[1], this_obj._advanceHandler); //unbind event before next - guiders.next(); - }; - } - }, - /** - * Advance if the form element has content - */ - advance_if_form_content: function(this_obj) { - var bind_obj = $(this_obj.autoAdvance[0]); - this_obj._advanceHandler = function() { - if ($(this_obj.autoAdvance[0]).val() == '') { return; } //don't advance if you haven't added content - bind_obj.unbind(this_obj.autoAdvance[1], this_obj._advanceHandler); //unbind event before next - guiders.next(); - }; - }, - /** - * Skip if form element has content - * - * this context will be inside the actual guider step, not here - */ - skip_if_form_content: function() { //skip if form element has content - return ($(this.autoAdvance[0]).val() !== '') - } - }; - // end additional functionality + guiders._defaultSettings = { + attachTo: null, // Selector of the element to attach to. + autoAdvance: null, //replace with array of selector, event to bind to cause auto-advance + autoFocus: false, // Determines whether or not the browser scrolls to the element. + bindAdvanceHandler: function(thisObj) { //see guiders.handlers below for other common options + if (!thisObj.autoAdvance) { return; } + thisObj._advanceHandler = function() { + $(thisObj.autoAdvance[0]).unbind(thisObj.autoAdvance[1], thisObj._advanceHandler); //unbind event before next + switch (thisObj.autoAdvance[1]) { + case 'hover': //delay hover so the guider has time to get into position (in the case of flyout menus, etc) + guiders.hideAll(); //hide immediately + setTimeout(function() { guiders.next(); }, 1000); //1 second delay + break; + case 'blur': + /* falls through */ + default: + guiders.next(); + } + }; + }, + buttons: [{name: 'Close'}], + buttonCustomHTML: '', + classString: null, + closeOnEscape: false, + closeOnClickOutside: false, + description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + highlight: null, + // If guider would go off screen to the left or right, flip horizontally. + // If guider would go off the top of the screen, flip vertically. If it would go off the bottom of the screen do nothing, since most pages scroll in the vertical direction. + // It will be flipped both ways if it would be off-screen on two sides. + flipToKeepOnScreen: false, + isHashable: true, + offset: { + top: null, + left: null + }, + onClose: null, // Function taking two arguments, the guider and a boolean for close type (false for text close button, true for everything else). Returns true to end tour, false or undefined to dismiss current step. If there is no function, dismiss-only is default. + onHide: null, + onShow: null, + overlay: false, - guiders._htmlSkeleton = [. - "<div class='guider'>", - " <div class='guider_content'>", - " <h1 class='guider_title'></h1>", - " <div class='guider_close'></div>", - " <p class='guider_description'></p>", - " <div class='guider_buttons'>", - " </div>", - " </div>", - " <div class='guider_arrow'>", - " </div>", - "</div>" - ].join(""); + // 1-12 follows an analog clock, 0 means centered. You can also use the string positions + // listed below at guiders._offsetNameMapping, such as "topRight". + position: 0, + // Function handler that allows you to skip this guider if the function returns true. + shouldSkip: function () { + return false; + }, + title: 'Sample title goes here', + width: 400, + xButton: false, // this places a closer "x" button in the top right of the guider + _advanceHandler: null //action to do on advance. Set by bindAdvanceHandler closure done on show() + }; - guiders._arrowSize = 42; // This is the arrow's width and height. - guiders._backButtonTitle = "Back"; - guiders._buttonElement = "<a></a>"; - guiders._buttonAttributes = {"href": "javascript:void(0);"}; - guiders._buttonClass = "guider_button"; - guiders._closeButtonTitle = "Close"; - guiders._currentGuiderID = null; - guiders._guiderInits = {}; //stores uncreated guiders indexed by id - guiders._guiders = {}; //stores created guiders indexed by id - guiders._lastCreatedGuiderID = null; - guiders._nextButtonTitle = "Next"; - guiders._scrollDuration = 750; // In milliseconds + // Begin additional functionality + guiders.failStep = ''; + /** + * Various common utility handlers you can bind as advance handlers to your + * guider configurations + */ + guiders.handlers = { + /** + * Auto-advance if the element is missing + * + * @deprecated Use shouldSkip + */ + advance_if_not_exists: function() { + return guiders._defaultSettings._bindAdvanceHandler; + }, + /** + * Advance if testFunction() returns true + * + * @deprecated Use shouldSkip + */ + advance_if_test: function(testFunction) { + return function(thisObj) { + var bindObj = $(thisObj.autoAdvance[0]); + thisObj._advanceHandler = function() { + if (!testFunction()) { return; } //don't advance if testFunction is false + bindObj.unbind(thisObj.autoAdvance[1], thisObj._advanceHandler); //unbind event before next + guiders.next(); + }; + }; + }, + /** + * Advance if the form element has content + * + * @deprecated Use shouldSkip + */ + advance_if_form_content: function(thisObj) { + var bindObj = $(thisObj.autoAdvance[0]); + thisObj._advanceHandler = function() { + if ($(thisObj.autoAdvance[0]).val() === '') { return; } //don't advance if you haven't added content + bindObj.unbind(thisObj.autoAdvance[1], thisObj._advanceHandler); //unbind event before next + guiders.next(); + }; + }, + /** + * Skip if form element has content + * + * this context will be inside the actual guider step, not here + * + * @deprecated Use shouldSkip + */ + skip_if_form_content: function() { //skip if form element has content + return ($(this.autoAdvance[0]).val() !== ''); + } + }; + // end additional functionality - // See position above in guiders._defaultSettings - guiders._offsetNameMapping = { - "topLeft": 11, - "top": 12, - "topRight": 1, - "rightTop": 2, - "right": 3, - "rightBottom": 4, - "bottomRight": 5, - "bottom": 6, - "bottomLeft": 7, - "leftBottom": 8, - "left": 9, - "leftTop": 10 - }; - guiders._windowHeight = 0; + guiders._htmlSkeleton = [. + '<div class="guider">', + ' <div class="guider_content">', + ' <h1 class="guider_title"></h1>', + ' <div class="guider_close"></div>', + ' <p class="guider_description"></p>', + ' <div class="guider_buttons">', + ' </div>', + ' </div>', + ' <div class="guider_arrow">', + ' </div>', + '</div>' + ].join(''); - // Handles a user-initiated close action (e.g. clicking close or hitting ESC) - // isAlternativeClose is false for the text Close button, and true for everything else. - guiders.handleOnClose = function(myGuider, isAlternativeClose, closeMethod) { - if (myGuider.onClose) { - myGuider.onClose(myGuider, isAlternativeClose, closeMethod); - } + guiders._arrowSize = 42; // This is the arrow's width and height. + guiders._backButtonTitle = 'Back'; + guiders._buttonElement = '<a></a>'; + guiders._buttonAttributes = {'href': 'javascript:void(0);'}; + guiders._buttonClass = 'guider_button'; + guiders._closeButtonTitle = 'Close'; + guiders._currentGuiderID = null; + guiders._guiderInits = {}; //stores uncreated guiders indexed by id + guiders._guiders = {}; //stores created guiders indexed by id + guiders._lastCreatedGuiderID = null; + guiders._nextButtonTitle = 'Next'; + guiders._scrollDuration = 750; // In milliseconds - guiders.hideAll(); - }; + // See position above in guiders._defaultSettings + guiders._offsetNameMapping = { + topLeft: 11, + top: 12, + topRight: 1, + rightTop: 2, + right: 3, + rightBottom: 4, + bottomRight: 5, + bottom: 6, + bottomLeft: 7, + leftBottom: 8, + left: 9, + leftTop: 10 + }; + guiders._windowHeight = 0; - guiders._addButtons = function(myGuider) { - // Add buttons - var guiderButtonsContainer = myGuider.elem.find(".guider_buttons"); + // Handles a user-initiated close action (e.g. clicking close or hitting ESC) + // isAlternativeClose is false for the text Close button, and true for everything else. + guiders.handleOnClose = function(myGuider, isAlternativeClose, closeMethod) { + if (myGuider.onClose) { + myGuider.onClose(myGuider, isAlternativeClose, closeMethod); + } - if (myGuider.buttons === null || myGuider.buttons.length === 0) { - guiderButtonsContainer.remove(); - return; - } + guiders.hideAll(); + }; - for (var i = myGuider.buttons.length - 1; i >= 0; i--) { - var thisButton = myGuider.buttons[i]; - var thisButtonElem = $(guiders._buttonElement, - $.extend({"class" : guiders._buttonClass, "html" : thisButton.name }, guiders._buttonAttributes, thisButton.html || {}) - ); + guiders._addButtons = function(myGuider) { + var guiderButtonsContainer, i, thisButton, thisButtonElem, thisButtonName, + myCustomHTML; - if (typeof thisButton.classString !== "undefined" && thisButton.classString !== null) { - thisButtonElem.addClass(thisButton.classString); - } + function handleTextButton() { + guiders.handleOnClose(myGuider, false, 'textButton' /* close by button */); + } - guiderButtonsContainer.append(thisButtonElem); + function handleNextButton() { + if ( !myGuider.elem.data('locked') ) { + guiders.next(); + } + } - var thisButtonName = thisButton.name.toLowerCase(); - if (thisButton.onclick) { - thisButtonElem.bind("click", thisButton.onclick); - } else { - switch (thisButtonName) { - case guiders._closeButtonTitle.toLowerCase(): - thisButtonElem.bind("click", function () { - guiders.handleOnClose(myGuider, false, 'textButton' /* close by button */); - }); - break; - case guiders._nextButtonTitle.toLowerCase(): - thisButtonElem.bind("click", function () { - !myGuider.elem.data('locked') && guiders.next(); - }); - break; - case guiders._backButtonTitle.toLowerCase(): - thisButtonElem.bind("click", function () { - !myGuider.elem.data('locked') && guiders.prev(); - }); - break; - } - } - } + function handlePrevButton() { + if ( !myGuider.elem.data('locked') ) { + guiders.prev(); + } + } - if (myGuider.buttonCustomHTML !== "") { - var myCustomHTML = $(myGuider.buttonCustomHTML); - myGuider.elem.find(".guider_buttons").append(myCustomHTML); - } + // Add buttons + guiderButtonsContainer = myGuider.elem.find('.guider_buttons'); - if (myGuider.buttons.length === 0) { - guiderButtonsContainer.remove(); - } - }; + if (myGuider.buttons === null || myGuider.buttons.length === 0) { + guiderButtonsContainer.remove(); + return; + } - guiders._addXButton = function(myGuider) { - var xButtonContainer = myGuider.elem.find(".guider_close"); - var xButton = $("<div></div>", { - "class" : "x_button", - "role" : "button" }); - xButtonContainer.append(xButton); - xButton.click(function() { - guiders.handleOnClose(myGuider, true, 'xButton'); - }); - }; + for (i = myGuider.buttons.length - 1; i >= 0; i--) { + thisButton = myGuider.buttons[i]; + thisButtonElem = $(guiders._buttonElement, + $.extend({'class': guiders._buttonClass, html: thisButton.name }, guiders._buttonAttributes, thisButton.html || {}) + ); - guiders._wireEscape = function (myGuider) { - $(document).keydown(function(event) { - if (event.keyCode == 27 || event.which == 27) { - guiders.handleOnClose(myGuider, true, 'escapeKey' /*close by escape key */); - return false; - } - }); - }; + if (typeof thisButton.classString !== 'undefined' && thisButton.classString !== null) { + thisButtonElem.addClass(thisButton.classString); + } - guiders._unWireEscape = function (myGuider) { - $(document).unbind("keydown"); - }; + guiderButtonsContainer.append(thisButtonElem); - guiders._wireClickOutside = function (myGuider) { - $(document).bind('click.guiders', function (event) { - if ($(event.target).closest(".guider").length === 0) { - guiders.handleOnClose(myGuider, true, 'clickOutside' /* close by clicking outside */); - if (event.target.id === 'guider_overlay') { - return false; - } - } - }); - }; + thisButtonName = thisButton.name.toLowerCase(); + if (thisButton.onclick) { + thisButtonElem.bind('click', thisButton.onclick); + } else { + switch (thisButtonName) { + case guiders._closeButtonTitle.toLowerCase(): + thisButtonElem.bind( 'click', handleTextButton ); + break; + case guiders._nextButtonTitle.toLowerCase(): + thisButtonElem.bind( 'click', handleNextButton ); + break; + case guiders._backButtonTitle.toLowerCase(): + thisButtonElem.bind( 'click', handlePrevButton ); + break; + } + } + } - guiders._unWireClickOutside = function () { - $(document).unbind('click.guiders'); - }; + if (myGuider.buttonCustomHTML !== '') { + myCustomHTML = $(myGuider.buttonCustomHTML); + myGuider.elem.find('.guider_buttons').append(myCustomHTML); + } + if (myGuider.buttons.length === 0) { + guiderButtonsContainer.remove(); + } + }; - /** - * Flips a position horizontally, vertically, both, or not all. This can be used - * for various scenarios, such as handling right-to-left languages and flipping a position - * if the original one would go off screen. - * - * It accepts both string (e.g. "top") and numeric (e.g. 12) positions. - * - * @param {string|number} position position as in guider settings object - * @param {Object} options how to flip - * @param {boolean} options.vertical true to flip vertical (optional, defaults false) - * @param {boolean} options.horizontal true to flip vertical (optional, defaults false) - * @return {number} position with requested flippings in numeric form - */ - guiders.getFlippedPosition = function (position, options) { - var TOP_CLOCK = 12, HALF_CLOCK = 6; + guiders._addXButton = function(myGuider) { + var xButtonContainer, xButton; - if (!options.horizontal && !options.vertical) { - return position; - } + xButtonContainer = myGuider.elem.find('.guider_close'); + xButton = $('<div></div>', { + 'class': 'x_button', + role: 'button' }); + xButtonContainer.append(xButton); + xButton.click(function() { + guiders.handleOnClose(myGuider, true, 'xButton'); + }); + }; - // Convert to numeric if needed - if ( guiders._offsetNameMapping[position] !== undefined ) { - position = guiders._offsetNameMapping[position]; - } + guiders._wireEscape = function (myGuider) { + $(document).keydown(function(event) { + if (event.keyCode === 27 || event.which === 27) { + guiders.handleOnClose(myGuider, true, 'escapeKey' /*close by escape key */); + return false; + } + }); + }; - position = Number( position ); + // myGuider is passed though it's not currently used. + guiders._unWireEscape = function (/* myGuider */) { + $(document).unbind('keydown'); + }; - if ( position === 0 ) { - // Don't change center position. - return position; - } + guiders._wireClickOutside = function (myGuider) { + $(document).bind('click.guiders', function (event) { + if ($(event.target).closest('.guider').length === 0) { + guiders.handleOnClose(myGuider, true, 'clickOutside' /* close by clicking outside */); + if (event.target.id === 'guider_overlay') { + return false; + } + } + }); + }; - // This math is all based on the analog clock model used for guiders positioning. - if (options.horizontal && !options.vertical) { - position = TOP_CLOCK - position; - } else if ( options.vertical && !options.horizontal ) { - position = HALF_CLOCK - position; - } else if ( options.vertical && options.horizontal ) { - position = position + HALF_CLOCK; - } + guiders._unWireClickOutside = function () { + $(document).unbind('click.guiders'); + }; - if ( position < 1 ) { - position += TOP_CLOCK; - } else if ( position > TOP_CLOCK ) { - position -= TOP_CLOCK; - } - return position; - }; + /** + * Flips a position horizontally, vertically, both, or not all. This can be used + * for various scenarios, such as handling right-to-left languages and flipping a position + * if the original one would go off screen. + * + * It accepts both string (e.g. "top") and numeric (e.g. 12) positions. + * + * @param {string|number} position position as in guider settings object + * @param {Object} options how to flip + * @param {boolean} options.vertical true to flip vertical (optional, defaults false) + * @param {boolean} options.horizontal true to flip vertical (optional, defaults false) + * @return {number} position with requested flippings in numeric form + */ + guiders.getFlippedPosition = function (position, options) { + var TOP_CLOCK = 12, HALF_CLOCK = 6; - /** - * Returns CSS for attaching a guider to its associated element - * - * @param {jQuery} attachTo element to attach to - * @param {Object} guider guider object - * @param {number} position position for guider, using clock - * model (0-12). - * @return {Object} CSS properties for the attachment - */ -guiders._getAttachCss = function(attachTo, guider, position) { - var myHeight = guider.elem.innerHeight(); - var myWidth = guider.elem.innerWidth(); + if (!options.horizontal && !options.vertical) { + return position; + } - if (position === 0) { - // The guider is positioned in the center of the screen. - return { - "position": "fixed", - "top": ($(window).height() - myHeight) / 3 + "px", - "left": ($(window).width() - myWidth) / 2 + "px" - }; - } + // Convert to numeric if needed + if ( guiders._offsetNameMapping[position] !== undefined ) { + position = guiders._offsetNameMapping[position]; + } - // Otherwise, the guider is positioned relative to the attachTo element. - var base = attachTo.offset(); - var top = base.top; - var left = base.left; + position = Number( position ); - // topMarginOfBody corrects positioning if body has a top margin set on it. - var topMarginOfBody = $("body").outerHeight(true) - $("body").outerHeight(false); - top -= topMarginOfBody; + if ( position === 0 ) { + // Don't change center position. + return position; + } - var attachToHeight = attachTo.innerHeight(); - var attachToWidth = attachTo.innerWidth(); - var bufferOffset = 0.9 * guiders._arrowSize; + // This math is all based on the analog clock model used for guiders positioning. + if (options.horizontal && !options.vertical) { + position = TOP_CLOCK - position; + } else if ( options.vertical && !options.horizontal ) { + position = HALF_CLOCK - position; + } else if ( options.vertical && options.horizontal ) { + position = position + HALF_CLOCK; + } - // offsetMap follows the form: [height, width] - var offsetMap = { - 1: [-bufferOffset - myHeight, attachToWidth - myWidth], - 2: [0, bufferOffset + attachToWidth], - 3: [attachToHeight/2 - myHeight/2, bufferOffset + attachToWidth], - 4: [attachToHeight - myHeight, bufferOffset + attachToWidth], - 5: [bufferOffset + attachToHeight, attachToWidth - myWidth], - 6: [bufferOffset + attachToHeight, attachToWidth/2 - myWidth/2], - 7: [bufferOffset + attachToHeight, 0], - 8: [attachToHeight - myHeight, -myWidth - bufferOffset], - 9: [attachToHeight/2 - myHeight/2, -myWidth - bufferOffset], - 10: [0, -myWidth - bufferOffset], - 11: [-bufferOffset - myHeight, 0], - 12: [-bufferOffset - myHeight, attachToWidth/2 - myWidth/2] - }; - var offset = offsetMap[position]; - top += offset[0]; - left += offset[1]; + if ( position < 1 ) { + position += TOP_CLOCK; + } else if ( position > TOP_CLOCK ) { + position -= TOP_CLOCK; + } - var positionType = "absolute"; - // If the element you are attaching to is position: fixed, then we will make the guider - // position: fixed as well. - if (attachTo.css("position") == "fixed") { - positionType = "fixed"; - top -= $(window).scrollTop(); - left -= $(window).scrollLeft(); - } + return position; + }; - // If you specify an additional offset parameter when you create the guider, it gets added here. - if (guider.offset.top !== null) { - top += guider.offset.top; - } - if (guider.offset.left !== null) { - left += guider.offset.left; - } + /** + * Returns CSS for attaching a guider to its associated element + * + * @param {jQuery} attachTo element to attach to + * @param {Object} guider guider object + * @param {number} position position for guider, using clock + * model (0-12). + * @return {Object} CSS properties for the attachment + */ + guiders._getAttachCss = function(attachTo, guider, position) { + var myHeight, myWidth, base, top, left, topMarginOfBody, attachToHeight, + attachToWidth, bufferOffset, offsetMap, offset, positionType; - return { - "position": positionType, - "top": top, - "left": left - }; - }; + myHeight = guider.elem.innerHeight(); + myWidth = guider.elem.innerWidth(); - /** - * Attaches a guider - * - * @param {Object} myGuider guider to attach - * @return {jQuery|undefined} jQuery node for guider's element if successful, - * or undefined for invalid input. - */ - guiders._attach = function(myGuider) { - var position; + if (position === 0) { + // The guider is positioned in the center of the screen. + return { + position: 'fixed', + top: ($(window).height() - myHeight) / 3 + 'px', + left: ($(window).width() - myWidth) / 2 + 'px' + }; + } - if (typeof myGuider !== 'object') { - return; - } + // Otherwise, the guider is positioned relative to the attachTo element. + base = attachTo.offset(); + top = base.top; + left = base.left; - // We keep a local position, separate from the originally requested one. - // We alter this locally for auto-flip and missing elements. - // - // However, the DOM or window size may change later, and on each attach we want to start - // with the originally requested position as the baseline. + // topMarginOfBody corrects positioning if body has a top margin set on it. + topMarginOfBody = $('body').outerHeight(true) - $('body').outerHeight(false); + top -= topMarginOfBody; - var attachTo = $(myGuider.attachTo); - position = attachTo.length > 0 ? myGuider.position : 0; + attachToHeight = attachTo.innerHeight(); + attachToWidth = attachTo.innerWidth(); + bufferOffset = 0.9 * guiders._arrowSize; - var css = guiders._getAttachCss(attachTo, myGuider, position); + // offsetMap follows the form: [height, width] + offsetMap = { + 1: [-bufferOffset - myHeight, attachToWidth - myWidth], + 2: [0, bufferOffset + attachToWidth], + 3: [attachToHeight/2 - myHeight/2, bufferOffset + attachToWidth], + 4: [attachToHeight - myHeight, bufferOffset + attachToWidth], + 5: [bufferOffset + attachToHeight, attachToWidth - myWidth], + 6: [bufferOffset + attachToHeight, attachToWidth/2 - myWidth/2], + 7: [bufferOffset + attachToHeight, 0], + 8: [attachToHeight - myHeight, -myWidth - bufferOffset], + 9: [attachToHeight/2 - myHeight/2, -myWidth - bufferOffset], + 10: [0, -myWidth - bufferOffset], + 11: [-bufferOffset - myHeight, 0], + 12: [-bufferOffset - myHeight, attachToWidth/2 - myWidth/2] + }; + offset = offsetMap[position]; + top += offset[0]; + left += offset[1]; - if (myGuider.flipToKeepOnScreen) { - var rightOfGuider = css.left + myGuider.width; - var flipVertically = css.top < 0; - var flipHorizontally = css.left < 0 || rightOfGuider > $('body').innerWidth(); - if (flipVertically || flipHorizontally) { - position = guiders.getFlippedPosition(position, { - "vertical": flipVertically, - "horizontal": flipHorizontally - }); - css = guiders._getAttachCss(attachTo, myGuider, position); - } - } + positionType = 'absolute'; + // If the element you are attaching to is position: fixed, then we will make the guider + // position: fixed as well. + if (attachTo.css('position') === 'fixed') { + positionType = 'fixed'; + top -= $(window).scrollTop(); + left -= $(window).scrollLeft(); + } - guiders._styleArrow(myGuider, position); - return myGuider.elem.css(css); - }; + // If you specify an additional offset parameter when you create the guider, it gets added here. + if (guider.offset.top !== null) { + top += guider.offset.top; + } + if (guider.offset.left !== null) { + left += guider.offset.left; + } - /** - * Returns the guider by ID. - * - * Add check to create and grab guider from inits if it exists there. - * - * @param {string} id id of guider - * @return {Object} guider object - */ - guiders._guiderById = function(id) { - if (typeof guiders._guiders[id] === "undefined") { - if (typeof guiders._guiderInits[id] == "undefined") { - throw "Cannot find guider with id " + id; - } - var myGuider = guiders._guiderInits[id]; - // this can happen when resume() hits a snag somewhere - if (myGuider.attachTo && guiders.failStep && ($(myGuider.attachTo).length == 0)) { - throw "Guider attachment not found with id " + myGuider.attachTo; - } - guiders.createGuider(myGuider); - delete guiders._guiderInits[id]; //prevents recursion - // fall through ... - } - return guiders._guiders[id]; - }; + return { + position: positionType, + top: top, + left: left + }; + }; + + /** + * Attaches a guider + * + * @param {Object} myGuider guider to attach + * @return {jQuery|undefined} jQuery node for guider's element if successful, + * or undefined for invalid input. + */ + guiders._attach = function(myGuider) { + var position, attachTo, css, rightOfGuider, flipVertically, + flipHorizontally; + + if (typeof myGuider !== 'object') { + return; + } + + // We keep a local position, separate from the originally requested one. + // We alter this locally for auto-flip and missing elements. + // + // However, the DOM or window size may change later, and on each attach we want to start + // with the originally requested position as the baseline. + + attachTo = $(myGuider.attachTo); + position = attachTo.length > 0 ? myGuider.position : 0; + + css = guiders._getAttachCss(attachTo, myGuider, position); + + if (myGuider.flipToKeepOnScreen) { + rightOfGuider = css.left + myGuider.width; + flipVertically = css.top < 0; + flipHorizontally = css.left < 0 || rightOfGuider > $('body').innerWidth(); + if (flipVertically || flipHorizontally) { + position = guiders.getFlippedPosition(position, { + vertical: flipVertically, + horizontal: flipHorizontally + }); + css = guiders._getAttachCss(attachTo, myGuider, position); + } + } + + guiders._styleArrow(myGuider, position); + return myGuider.elem.css(css); + }; + + /** + * Returns the guider by ID. + * + * Add check to create and grab guider from inits if it exists there. + * + * @param {string} id id of guider + * @return {Object} guider object + */ + guiders._guiderById = function(id) { + if (typeof guiders._guiders[id] === 'undefined') { + if (typeof guiders._guiderInits[id] === 'undefined') { + throw 'Cannot find guider with id ' + id; + } + var myGuider = guiders._guiderInits[id]; + // this can happen when resume() hits a snag somewhere + if (myGuider.attachTo && guiders.failStep && ($(myGuider.attachTo).length === 0)) { + throw 'Guider attachment not found with id ' + myGuider.attachTo; + } + guiders.createGuider(myGuider); + delete guiders._guiderInits[id]; //prevents recursion + // fall through ... + } + return guiders._guiders[id]; + }; + + guiders._showOverlay = function(overlayClass) { + $('#guider_overlay').fadeIn('fast', function(){ + if (this.style.removeAttribute) { + this.style.removeAttribute('filter'); + } + }).each( function() { + if (overlayClass) { + $(this).addClass(overlayClass); + } + }); + // This callback is needed to fix an IE opacity bug. + // See also: + // http://www.kevinleary.net/jquery-fadein-fadeout-problems-in-internet-explorer/ + }; + + guiders._highlightElement = function(selector) { + $(selector).addClass('guider_highlight'); + }; + + guiders._dehighlightElement = function(selector) { + $(selector).removeClass('guider_highlight'); + }; + + guiders._hideOverlay = function() { + $('#guider_overlay').fadeOut('fast').removeClass(); + }; + + guiders._initializeOverlay = function() { + if ($('#guider_overlay').length === 0) { + $('<div id="guider_overlay"></div>').hide().appendTo('body'); + } + }; + + guiders._styleArrow = function(myGuider, position) { + var myGuiderArrow, newClass, myHeight, myWidth, arrowOffset, positionMap, + arrowPosition; - guiders._showOverlay = function(overlayClass) { - $("#guider_overlay").fadeIn("fast", function(){ - if (this.style.removeAttribute) { - this.style.removeAttribute("filter"); - } - }).each( function() { - if (overlayClass) { - $(this).addClass(overlayClass); - } - }); - // This callback is needed to fix an IE opacity bug. - // See also: - // http://www.kevinleary.net/jquery-fadein-fadeout-problems-in-internet-explorer/ - }; + myGuiderArrow = $(myGuider.elem.find('.guider_arrow')); - guiders._highlightElement = function(selector) { - $(selector).addClass('guider_highlight'); - }; + position = position || 0; - guiders._dehighlightElement = function(selector) { - $(selector).removeClass('guider_highlight'); - }; + // Remove possible old direction. + // Position, and thus arrow, can change on resize due to flipToKeepOnScreen + // Also, if an element is added to or removed from the DOM, the arrow may need to change on reposition. + // + // If there should be an arrow, the new one will be added below. + myGuiderArrow.removeClass('guider_arrow_down guider_arrow_left guider_arrow_up guider_arrow_right'); - guiders._hideOverlay = function() { - $("#guider_overlay").fadeOut("fast").removeClass(); - }; + // No arrow for center position + if (position === 0) { + return; + } + newClass = { + 1: 'guider_arrow_down', + 2: 'guider_arrow_left', + 3: 'guider_arrow_left', + 4: 'guider_arrow_left', + 5: 'guider_arrow_up', + 6: 'guider_arrow_up', + 7: 'guider_arrow_up', + 8: 'guider_arrow_right', + 9: 'guider_arrow_right', + 10: 'guider_arrow_right', + 11: 'guider_arrow_down', + 12: 'guider_arrow_down' + }; - guiders._initializeOverlay = function() { - if ($("#guider_overlay").length === 0) { - $("<div id=\"guider_overlay\"></div>").hide().appendTo("body"); - } - }; + myGuiderArrow.addClass(newClass[position]); - guiders._styleArrow = function(myGuider, position) { - var arrowPosition, - myGuiderArrow = $(myGuider.elem.find(".guider_arrow")); + myHeight = myGuider.elem.innerHeight(); + myWidth = myGuider.elem.innerWidth(); + arrowOffset = guiders._arrowSize / 2; + positionMap = { + 1: ['right', arrowOffset], + 2: ['top', arrowOffset], + 3: ['top', myHeight/2 - arrowOffset], + 4: ['bottom', arrowOffset], + 5: ['right', arrowOffset], + 6: ['left', myWidth/2 - arrowOffset], + 7: ['left', arrowOffset], + 8: ['bottom', arrowOffset], + 9: ['top', myHeight/2 - arrowOffset], + 10: ['top', arrowOffset], + 11: ['left', arrowOffset], + 12: ['left', myWidth/2 - arrowOffset] + }; + arrowPosition = positionMap[position]; + myGuiderArrow.css(arrowPosition[0], arrowPosition[1] + 'px'); + // TODO: experiment with pulsing + //myGuiderArrow.css(position[0], position[1] + "px").stop().pulse({backgroundPosition:["7px 0","0 0"],right:["-35px","-42px"]}, {times: 10, duration: 'slow'}); + }; - position = position || 0; + /** + * One way to show a guider to new users is to direct new users to a URL such as + * http://www.mysite.com/myapp#guider=welcome + * + * This can also be used to run guiders on multiple pages, by redirecting from + * one page to another, with the guider id in the hash tag. + * + * Alternatively, if you use a session variable or flash messages after sign up, + * you can add selectively add JavaScript to the page: "guiders.show('first');" + * + * @deprecated Use the tour parameter (and optionally step as well), + * mw.guidedTour.setTourCookie, or another launching mechanism. + */ + guiders._showIfHashed = function(myGuider) { + var GUIDER_HASH_TAG, hashIndex, hashGuiderId; - // Remove possible old direction. - // Position, and thus arrow, can change on resize due to flipToKeepOnScreen - // Also, if an element is added to or removed from the DOM, the arrow may need to change on reposition. - // - // If there should be an arrow, the new one will be added below. - myGuiderArrow.removeClass("guider_arrow_down guider_arrow_left guider_arrow_up guider_arrow_right"); + GUIDER_HASH_TAG = 'guider='; + hashIndex = window.location.hash.indexOf(GUIDER_HASH_TAG); + if (hashIndex !== -1) { + hashGuiderId = window.location.hash.substr(hashIndex + GUIDER_HASH_TAG.length); + if (myGuider.id.toLowerCase() === hashGuiderId.toLowerCase()) { + // Success! + guiders.show(myGuider.id); + } + } + }; - // No arrow for center position - if (position === 0) { - return; - } - var newClass = { - 1: "guider_arrow_down", - 2: "guider_arrow_left", - 3: "guider_arrow_left", - 4: "guider_arrow_left", - 5: "guider_arrow_up", - 6: "guider_arrow_up", - 7: "guider_arrow_up", - 8: "guider_arrow_right", - 9: "guider_arrow_right", - 10: "guider_arrow_right", - 11: "guider_arrow_down", - 12: "guider_arrow_down" - }; + guiders.reposition = function() { + var currentGuider = guiders._guiders[guiders._currentGuiderID]; + guiders._attach(currentGuider); + }; - myGuiderArrow.addClass(newClass[position]); + /** + Follows the chain of shouldSkip and returns the resulting guider, or undefined + if the last shouldSkip returns true + */ + guiders._followShouldSkip = function(guider) { + var guiderId; - var myHeight = myGuider.elem.innerHeight(); - var myWidth = myGuider.elem.innerWidth(); - var arrowOffset = guiders._arrowSize / 2; - var positionMap = { - 1: ["right", arrowOffset], - 2: ["top", arrowOffset], - 3: ["top", myHeight/2 - arrowOffset], - 4: ["bottom", arrowOffset], - 5: ["right", arrowOffset], - 6: ["left", myWidth/2 - arrowOffset], - 7: ["left", arrowOffset], - 8: ["bottom", arrowOffset], - 9: ["top", myHeight/2 - arrowOffset], - 10: ["top", arrowOffset], - 11: ["left", arrowOffset], - 12: ["left", myWidth/2 - arrowOffset] - }; - arrowPosition = positionMap[position]; - myGuiderArrow.css(arrowPosition[0], arrowPosition[1] + "px"); - // TODO: experiment with pulsing - //myGuiderArrow.css(position[0], position[1] + "px").stop().pulse({backgroundPosition:["7px 0","0 0"],right:["-35px","-42px"]}, {times: 10, duration: 'slow'}); - }; + while (guider.shouldSkip()) { + guiderId = guider.next; + if (guiderId === undefined) { + return undefined; + } else { + guider = guiders._guiderById(guiderId); + } + } - /** - * One way to show a guider to new users is to direct new users to a URL such as - * http://www.mysite.com/myapp#guider=welcome - * - * This can also be used to run guiders on multiple pages, by redirecting from - * one page to another, with the guider id in the hash tag. - * - * Alternatively, if you use a session variable or flash messages after sign up, - * you can add selectively add JavaScript to the page: "guiders.show('first');" - */ - guiders._showIfHashed = function(myGuider) { - var GUIDER_HASH_TAG = "guider="; - var hashIndex = window.location.hash.indexOf(GUIDER_HASH_TAG); - if (hashIndex !== -1) { - var hashGuiderId = window.location.hash.substr(hashIndex + GUIDER_HASH_TAG.length); - if (myGuider.id.toLowerCase() === hashGuiderId.toLowerCase()) { - // Success! - guiders.show(myGuider.id); - } - } - }; + return guider; + }; - guiders.reposition = function() { - var currentGuider = guiders._guiders[guiders._currentGuiderID]; - guiders._attach(currentGuider); - }; + /** + Skips as needed then updates the displayed guider - /** - Follows the chain of shouldSkip and returns the resulting guider, or undefined - if the last shouldSkip returns true - */ - guiders._followShouldSkip = function(guider) { - var guiderId; + If it does skip: + * It hides all currently showing guiders. + * If it lands on a new guider, it shows that. - while (guider.shouldSkip()) { - guiderId = guider.next; - if (guiderId === undefined) { - return undefined; - } else { - guider = guiders._guiderById(guiderId); - } - } + The startGuider parameter is optional and defaults to the guider + corresponding to guiders._currentGuiderID - return guider; - }; + Returns true if it skipped, false otherwise + */ + guiders.skipThenUpdateDisplay = function(startGuider) { + var endGuider, skipped, omitHidingOverlay; - /** - Skips as needed then updates the displayed guider + if (startGuider === undefined) { + if (guiders._currentGuiderID === null ) { + return false; + } + startGuider = guiders._guiderById(guiders._currentGuiderID); + } - If it does skip: - * It hides all currently showing guiders. - * If it lands on a new guider, it shows that. + endGuider = guiders._followShouldSkip(startGuider); - The startGuider parameter is optional and defaults to the guider - corresponding to guiders._currentGuiderID + skipped = endGuider !== startGuider; + if (skipped) { + if (endGuider !== undefined) { + omitHidingOverlay = endGuider.overlay ? true : false; + guiders.hideAll(omitHidingOverlay, true); + guiders.show(endGuider.id); + } else { + guiders.hideAll(); + } + } - Returns true if it skipped, false otherwise - */ - guiders.skipThenUpdateDisplay = function(startGuider) { - var endGuider, skipped, omitHidingOverlay; + return skipped; + }; - if (startGuider === undefined) { - if (guiders._currentGuiderID === null ) { - return false; - } - startGuider = guiders._guiderById(guiders._currentGuiderID); - } + guiders.next = function() { + var currentGuider, nextGuiderId, myGuider, omitHidingOverlay; + try { + currentGuider = guiders._guiderById(guiders._currentGuiderID); //has check to make sure guider is initialized + } catch (err) { + return; + } + currentGuider.elem.data('locked', true); + //remove current auto-advance handler bound before advancing + if (currentGuider.autoAdvance) { + $(currentGuider.autoAdvance[0]).unbind(currentGuider.autoAdvance[1], currentGuider._advanceHandler); + } - endGuider = guiders._followShouldSkip(startGuider); + nextGuiderId = currentGuider.next || null; + if (nextGuiderId !== null && nextGuiderId !== '') { + myGuider = guiders._guiderById(nextGuiderId); + // If skip function is bound, check to see if we should advance the guider + if (guiders.skipThenUpdateDisplay(myGuider)) { + return; + } + omitHidingOverlay = myGuider.overlay ? true : false; + guiders.hideAll(omitHidingOverlay, true); + if (currentGuider && currentGuider.highlight) { + guiders._dehighlightElement(currentGuider.highlight); + } + guiders.show(nextGuiderId); + } + }; - skipped = endGuider !== startGuider; - if (skipped) { - if (endGuider !== undefined) { - omitHidingOverlay = endGuider.overlay ? true : false; - guiders.hideAll(omitHidingOverlay, true); - guiders.show(endGuider.id); - } else { - guiders.hideAll(); - } - } + guiders.prev = function () { + var currentGuider, prevGuider, prevGuiderId, myGuider, omitHidingOverlay; - return skipped; - }; + currentGuider = guiders._guiders[guiders._currentGuiderID]; + if (typeof currentGuider === 'undefined') { + // not what we think it is + return; + } + if (currentGuider.prev === null) { + // no previous to look at + return; + } - guiders.next = function() { - //var currentGuider = guiders._guiders[guiders._currentGuiderID]; - try { - var currentGuider = guiders._guiderById(guiders._currentGuiderID); //has check to make sure guider is initialized - } catch (err) { - //console.log(err); - return; - } - currentGuider.elem.data('locked', true); - //remove current auto-advance handler bound before advancing - if (currentGuider.autoAdvance) { - $(currentGuider.autoAdvance[0]).unbind(currentGuider.autoAdvance[1], currentGuider._advanceHandler); - } + prevGuider = guiders._guiders[currentGuider.prev]; + prevGuider.elem.data('locked', true); - var nextGuiderId = currentGuider.next || null; - if (nextGuiderId !== null && nextGuiderId !== "") { - var myGuider = guiders._guiderById(nextGuiderId); - // If skip function is bound, check to see if we should advance the guider - if (guiders.skipThenUpdateDisplay(myGuider)) { - return; - } - var omitHidingOverlay = myGuider.overlay ? true : false; - guiders.hideAll(omitHidingOverlay, true); - if (currentGuider && currentGuider.highlight) { - guiders._dehighlightElement(currentGuider.highlight); - } - guiders.show(nextGuiderId); - } - }; + // Note we use prevGuider.id as "prevGuider" is _already_ looking at the previous guider + prevGuiderId = prevGuider.id || null; + if (prevGuiderId !== null && prevGuiderId !== '') { + myGuider = guiders._guiderById(prevGuiderId); + omitHidingOverlay = myGuider.overlay ? true : false; + guiders.hideAll(omitHidingOverlay, true); + if (prevGuider && prevGuider.highlight) { + guiders._dehighlightElement(prevGuider.highlight); + } + guiders.show(prevGuiderId); + } + }; - guiders.prev = function () { - var currentGuider = guiders._guiders[guiders._currentGuiderID]; - if (typeof currentGuider === "undefined") { - // not what we think it is - return; - } - if (currentGuider.prev === null) { - // no previous to look at - return; - } + /** + * This stores the guider but does no work on it. + * It is an alternative to createGuider() that defers the actual setup work. + */ + guiders.initGuider = function(passedSettings) { + if (passedSettings === null || passedSettings === undefined) { + return; + } + if (!passedSettings.id) { + return; + } + this._guiderInits[passedSettings.id] = passedSettings; + }; - var prevGuider = guiders._guiders[currentGuider.prev]; - prevGuider.elem.data('locked', true); + /** + * Creates a guider + * + * @param {Object} passedSettings settings for the guider + * @return {Object} guiders singleton + */ + guiders.createGuider = function(passedSettings) { + var guiderElement, myGuider, guiderTitleContainer; - // Note we use prevGuider.id as "prevGuider" is _already_ looking at the previous guider - var prevGuiderId = prevGuider.id || null; - if (prevGuiderId !== null && prevGuiderId !== "") { - var myGuider = guiders._guiderById(prevGuiderId); - var omitHidingOverlay = myGuider.overlay ? true : false; - guiders.hideAll(omitHidingOverlay, true); - if (prevGuider && prevGuider.highlight) { - guiders._dehighlightElement(prevGuider.highlight); - } - guiders.show(prevGuiderId); - } - }; + if (passedSettings === null || passedSettings === undefined) { + passedSettings = {}; + } - /** - * This stores the guider but does no work on it. - * It is an alternative to createGuider() that defers the actual setup work. - */ - guiders.initGuider = function(passedSettings) { - if (passedSettings === null || passedSettings === undefined) { - return; - } - if (!passedSettings.id) { - return; - } - this._guiderInits[passedSettings.id] = passedSettings; - }; + // Extend those settings with passedSettings + myGuider = $.extend({}, guiders._defaultSettings, passedSettings); + myGuider.id = myGuider.id || String(Math.floor(Math.random() * 1000)); - /** - * Creates a guider - * - * @param {Object} passedSettings settings for the guider - * @return {Object} guiders singleton - */ - guiders.createGuider = function(passedSettings) { - if (passedSettings === null || passedSettings === undefined) { - passedSettings = {}; - } + guiderElement = $(guiders._htmlSkeleton); + myGuider.elem = guiderElement; + if (typeof myGuider.classString !== 'undefined' && myGuider.classString !== null) { + myGuider.elem.addClass(myGuider.classString); + } + myGuider.elem.css('width', myGuider.width + 'px'); - // Extend those settings with passedSettings - var myGuider = $.extend({}, guiders._defaultSettings, passedSettings); - myGuider.id = myGuider.id || String(Math.floor(Math.random() * 1000)); + guiderTitleContainer = guiderElement.find('.guider_title'); + guiderTitleContainer.html(myGuider.title); - var guiderElement = $(guiders._htmlSkeleton); - myGuider.elem = guiderElement; - if (typeof myGuider.classString !== "undefined" && myGuider.classString !== null) { - myGuider.elem.addClass(myGuider.classString); - } - myGuider.elem.css("width", myGuider.width + "px"); + guiderElement.find('.guider_description').html(myGuider.description); - var guiderTitleContainer = guiderElement.find(".guider_title"); - guiderTitleContainer.html(myGuider.title); + guiders._addButtons(myGuider); - guiderElement.find(".guider_description").html(myGuider.description); + if (myGuider.xButton) { + guiders._addXButton(myGuider); + } - guiders._addButtons(myGuider); + guiderElement.hide(); + guiderElement.appendTo('body'); + guiderElement.attr('id', myGuider.id); - if (myGuider.xButton) { - guiders._addXButton(myGuider); - } + // If a string form (e.g. 'top') was passed, convert it to numeric (e.g. 12) + // As an alternative to the clock model, you can also use keywords to position the myGuider. + if (guiders._offsetNameMapping[myGuider.position]) { + myGuider.position = guiders._offsetNameMapping[myGuider.position]; + } - guiderElement.hide(); - guiderElement.appendTo("body"); - guiderElement.attr("id", myGuider.id); + guiders._initializeOverlay(); - // If a string form (e.g. "top") was passed, convert it to numeric (e.g. 12) - // As an alternative to the clock model, you can also use keywords to position the myGuider. - if (guiders._offsetNameMapping[myGuider.position]) { - myGuider.position = guiders._offsetNameMapping[myGuider.position]; - } + guiders._guiders[myGuider.id] = myGuider; + if ( guiders._lastCreatedGuiderID !== null ) { + myGuider.prev = guiders._lastCreatedGuiderID; + } + guiders._lastCreatedGuiderID = myGuider.id; - guiders._initializeOverlay(); + /** + * If the URL of the current window is of the form + * http://www.myurl.com/mypage.html#guider=id + * then show this guider. + */ + if (myGuider.isHashable) { + guiders._showIfHashed(myGuider); + } - guiders._guiders[myGuider.id] = myGuider; - if (guiders._lastCreatedGuiderID != null) { - myGuider.prev = guiders._lastCreatedGuiderID; - } - guiders._lastCreatedGuiderID = myGuider.id; + return guiders; + }; - /** - * If the URL of the current window is of the form - * http://www.myurl.com/mypage.html#guider=id - * then show this guider. - */ - if (myGuider.isHashable) { - guiders._showIfHashed(myGuider); - } + /** + * Hides all guiders + * + * @param {boolean|undefined} omitHidingOverlay falsy to hide overlay, + * true not to change it + * @param {boolean} next true if caller will immediately show another guider + * in place of the one being hidden (optional, defaults false) + * @return {Object} guiders singleton + */ + guiders.hideAll = function(omitHidingOverlay, next) { + next = next || false; - return guiders; - }; + $('.guider:visible').each(function(index, elem){ + var myGuider = guiders._guiderById($(elem).attr('id')); + if (myGuider.onHide) { + myGuider.onHide(myGuider, next); + } + }); + guiders._unWireClickOutside(); + $('.guider').fadeOut('fast'); + var currentGuider = guiders._guiders[guiders._currentGuiderID]; + if (currentGuider && currentGuider.highlight) { + guiders._dehighlightElement(currentGuider.highlight); + } + if (omitHidingOverlay !== true) { + guiders._hideOverlay(); + } + return guiders; + }; - /** - * Hides all guiders - * - * @param {boolean|undefined} omitHidingOverlay falsy to hide overlay, - * true not to change it - * @param {boolean} next true if caller will immediately show another guider - * in place of the one being hidden (optional, defaults false) - * @return {Object} guiders singleton - */ - guiders.hideAll = function(omitHidingOverlay, next) { - next = next || false; + /** + * Like show() but skips steps if necessary, and you must specify an id. + * + * @param {string} id id of guider to resume from + * @return {boolean} true if the displayed guider was changed, + * false otherwise + */ + guiders.resume = function(id) { + var myGuider; - $(".guider:visible").each(function(index, elem){ - var myGuider = guiders._guiderById($(elem).attr('id')); - if (myGuider.onHide) { - myGuider.onHide(myGuider, next); - } - }); - guiders._unWireClickOutside(); - $(".guider").fadeOut("fast"); - var currentGuider = guiders._guiders[guiders._currentGuiderID]; - if (currentGuider && currentGuider.highlight) { - guiders._dehighlightElement(currentGuider.highlight); - } - if (typeof omitHidingOverlay !== "undefined" && omitHidingOverlay === true) { - // do nothing for now - } else { - guiders._hideOverlay(); - } - return guiders; - }; + //if no id, don't resume (user code can call show) + if ( !id ) { + return false; + } + try { + myGuider = guiders._guiderById(id); + } catch (err) { + if ( guiders.failStep ) { + guiders.show(guiders.failStep); + return true; + } else { + return false; + } + } - /** - * Like show() but skips steps if necessary, and you must specify an id. - * - * @param {string} id id of guider to resume from - * @return {boolean} true if the displayed guider was changed, - * false otherwise - */ - guiders.resume = function(id) { - var myGuider; + if (guiders.skipThenUpdateDisplay(myGuider)) { + return true; + } + guiders.show(id); + return true; + }; - //if no id, don't resume (user code can call show) - if ( !id ) { - return false; - } - try { - myGuider = guiders._guiderById(id); - } catch (err) { - if ( guiders.failStep ) { - guiders.show(guiders.failStep); - return true; - } else { - return false; - } - } + /** + * Show a guider, ignoring shouldSkip + * + * @param {string} id id of guider to show. The default is the last guider created. + * @return {undefined|boolean|Object} Undefined in case of error, return value + * from the guider's onShow, if that is truthy, otherwise the guiders + * singleton. + */ + guiders.show = function(id) { + var myGuider, showReturn, windowHeight, scrollHeight, guiderOffset, + guiderElemHeight, isGuiderBelow, isGuiderAbove, nextGuiderId, + nextGuiderData, testInDom; - if (guiders.skipThenUpdateDisplay(myGuider)) { - return true; - } - guiders.show(id); - return true; - }; + if (!id && guiders._lastCreatedGuiderID) { + id = guiders._lastCreatedGuiderID; + } - /** - * Show a guider, ignoring shouldSkip - * - * @param {string} id id of guider to show. The default is the last guider created. - * @return {undefined|boolean|Object} Undefined in case of error, return value - * from the guider's onShow, if that is truthy, otherwise the guiders - * singleton. - */ - guiders.show = function(id) { - var myGuider; - if (!id && guiders._lastCreatedGuiderID) { - id = guiders._lastCreatedGuiderID; - } + try { + myGuider = guiders._guiderById(id); + } catch (err) { + //console.log(err); + return; + } - try { - myGuider = guiders._guiderById(id); - } catch (err) { - //console.log(err); - return; - } + // You can use an onShow function to take some action before the guider is shown. + if (myGuider.onShow) { + // if onShow returns something, assume this means you want to bypass the + // rest of onShow. + showReturn = myGuider.onShow(myGuider); + if (showReturn) { + return showReturn; + } + } + // handle binding of auto-advance action + if (myGuider.autoAdvance) { + myGuider.bindAdvanceHandler(myGuider); + $(myGuider.autoAdvance[0]).bind(myGuider.autoAdvance[1], myGuider._advanceHandler); + } + // handle overlay and highlight + if (myGuider.overlay) { + guiders._showOverlay(myGuider.overlay); + // if guider is attached to an element, make sure it's visible + if (myGuider.highlight) { + guiders._highlightElement(myGuider.highlight); + } + } + // bind esc = close action + if (myGuider.closeOnEscape) { + guiders._wireEscape(myGuider); + } else { + guiders._unWireEscape(myGuider); + } - // You can use an onShow function to take some action before the guider is shown. - if (myGuider.onShow) { - // if onShow returns something, assume this means you want to bypass the - // rest of onShow. - var show_return = myGuider.onShow(myGuider); - if (show_return) { - return show_return; - } - } - // handle binding of auto-advance action - if (myGuider.autoAdvance) { - myGuider.bindAdvanceHandler(myGuider); - $(myGuider.autoAdvance[0]).bind(myGuider.autoAdvance[1], myGuider._advanceHandler); - } - // handle overlay and highlight - if (myGuider.overlay) { - guiders._showOverlay(myGuider.overlay); - // if guider is attached to an element, make sure it's visible - if (myGuider.highlight) { - guiders._highlightElement(myGuider.highlight); - } - } - // bind esc = close action - if (myGuider.closeOnEscape) { - guiders._wireEscape(myGuider); - } else { - guiders._unWireEscape(myGuider); - } + if (myGuider.closeOnClickOutside) { + guiders._wireClickOutside(myGuider); + } - if (myGuider.closeOnClickOutside) { - guiders._wireClickOutside(myGuider); - } + guiders._attach(myGuider); + myGuider.elem.fadeIn('fast').data('locked', false); + guiders._currentGuiderID = id; - guiders._attach(myGuider); - myGuider.elem.fadeIn("fast").data("locked", false); - guiders._currentGuiderID = id; + windowHeight = guiders._windowHeight = $(window).height(); + scrollHeight = $(window).scrollTop(); + guiderOffset = myGuider.elem.offset(); + guiderElemHeight = myGuider.elem.height(); - var windowHeight = guiders._windowHeight = $(window).height(); - var scrollHeight = $(window).scrollTop(); - var guiderOffset = myGuider.elem.offset(); - var guiderElemHeight = myGuider.elem.height(); + isGuiderBelow = (scrollHeight + windowHeight < guiderOffset.top + guiderElemHeight); /* we will need to scroll down */ + isGuiderAbove = (guiderOffset.top < scrollHeight); /* we will need to scroll up */ - var isGuiderBelow = (scrollHeight + windowHeight < guiderOffset.top + guiderElemHeight); /* we will need to scroll down */ - var isGuiderAbove = (guiderOffset.top < scrollHeight); /* we will need to scroll up */ + if (myGuider.autoFocus && (isGuiderBelow || isGuiderAbove)) { + // Sometimes the browser won't scroll if the person just clicked, + // so let's do this in a setTimeout. + setTimeout(guiders.scrollToCurrent, 10); + } - if (myGuider.autoFocus && (isGuiderBelow || isGuiderAbove)) { - // Sometimes the browser won't scroll if the person just clicked, - // so let's do this in a setTimeout. - setTimeout(guiders.scrollToCurrent, 10); - } + $(myGuider.elem).trigger('guiders.show'); - $(myGuider.elem).trigger("guiders.show"); + // Create (preload) next guider if it hasn't been created + nextGuiderId = myGuider.next || null; + if (nextGuiderId !== null && nextGuiderId !== '') { + if ( ( nextGuiderData = guiders._guiderInits[nextGuiderId] ) ) { + //don't attach if it doesn't exist in DOM + testInDom = $(nextGuiderData.attachTo); + if ( testInDom.length > 0 ) { + guiders.createGuider(nextGuiderData); + nextGuiderData = undefined; + } + } + } - // Create (preload) next guider if it hasn't been created - var nextGuiderId = myGuider.next || null; - var nextGuiderData; - if (nextGuiderId !== null && nextGuiderId !== "") { - if (nextGuiderData = guiders._guiderInits[nextGuiderId]) { - //don't attach if it doesn't exist in DOM - var testInDom = $(nextGuiderData.attachTo); - if ( testInDom.length > 0 ) { - guiders.createGuider(nextGuiderData); - delete nextGuiderData; - } - } - } + return guiders; + }; - return guiders; - }; + /** + * Scroll to the current guider + * + * @return {Object} guiders singleton + */ + guiders.scrollToCurrent = function() { + var currentGuider, windowHeight, scrollHeight, guiderOffset, + guiderElemHeight, scrollToHeight; - /** - * Scroll to the current guider - * - * @return {Object} guiders singleton - */ - guiders.scrollToCurrent = function() { - var currentGuider = guiders._guiders[guiders._currentGuiderID]; - if (typeof currentGuider === "undefined") { - return; - } + currentGuider = guiders._guiders[guiders._currentGuiderID]; + if (typeof currentGuider === 'undefined') { + return; + } - var windowHeight = guiders._windowHeight; - var scrollHeight = $(window).scrollTop(); - var guiderOffset = currentGuider.elem.offset(); - var guiderElemHeight = currentGuider.elem.height(); + windowHeight = guiders._windowHeight; + scrollHeight = $(window).scrollTop(); + guiderOffset = currentGuider.elem.offset(); + guiderElemHeight = currentGuider.elem.height(); - // Scroll to the guider's position. - var scrollToHeight = Math.round(Math.max(guiderOffset.top + (guiderElemHeight / 2) - (windowHeight / 2), 0)); - // Basic concept from https://github.com/yckart/jquery.scrollto.js/blob/master/jquery.scrollto.js - $('html, body').animate({ - scrollTop: scrollToHeight - }, guiders._scrollDuration); - }; + // Scroll to the guider's position. + scrollToHeight = Math.round(Math.max(guiderOffset.top + (guiderElemHeight / 2) - (windowHeight / 2), 0)); + // Basic concept from https://github.com/yckart/jquery.scrollto.js/blob/master/jquery.scrollto.js + $('html, body').animate({ + scrollTop: scrollToHeight + }, guiders._scrollDuration); + }; - // Change the bubble position after browser gets resized - var _resizing = undefined; - $(window).resize(function() { - if (typeof(_resizing) !== "undefined") { - clearTimeout(_resizing); // Prevents seizures - } - _resizing = setTimeout(function() { - _resizing = undefined; - if (typeof (guiders) !== "undefined") { - guiders.reposition(); - } - }, 20); - }); + // Change the bubble position after browser gets resized + _resizing = undefined; + $(window).resize(function() { + if (typeof(_resizing) !== 'undefined') { + clearTimeout(_resizing); // Prevents seizures + } + _resizing = setTimeout(function() { + _resizing = undefined; + if (typeof (guiders) !== 'undefined') { + guiders.reposition(); + } + }, 20); + }); - $(document).ready(function() { - guiders.reposition(); - }); + $(document).ready(function() { + guiders.reposition(); + }); - return guiders; + return guiders; }).call(this, jQuery); -- To view, visit https://gerrit.wikimedia.org/r/76699 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: I092891ac9d34dab846dfb6f3e427d5f172aef419 Gerrit-PatchSet: 4 Gerrit-Project: mediawiki/extensions/GuidedTour Gerrit-Branch: master Gerrit-Owner: Mattflaschen <mflaschen [at] wikimedia> Gerrit-Reviewer: Mattflaschen <mflaschen [at] wikimedia> Gerrit-Reviewer: Ori.livneh <ori [at] wikimedia> Gerrit-Reviewer: Spage <spage [at] wikimedia> Gerrit-Reviewer: Swalling <swalling [at] wikimedia> Gerrit-Reviewer: jenkins-bot _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits [at] lists https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits
|