diff --git a/CHANGELOG.md b/CHANGELOG.md index f0ba5a3c..80b0efe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ ## Change Log +### v0.2.3 (2014/12/10) + + * [#139](https://github.com/linkedin/hopscotch/pull/139) RefreshBubblePosition updates all known callouts + * [#136](https://github.com/linkedin/hopscotch/pull/136) Ignore skipped steps in numbering + * [#137](https://github.com/linkedin/hopscotch/pull/137) NextOnTarget Click event not always removed + * [#133](https://github.com/linkedin/hopscotch/pull/133) Add right-to-left support to hopscotch + * [#128](https://github.com/linkedin/hopscotch/pull/128) Trailing comma in opts.i18n object + * [#126](https://github.com/linkedin/hopscotch/pull/126) Revert defuault z-index to empty vs auto + * [#102](https://github.com/linkedin/hopscotch/pull/102) Callbacks on callouts do not work + + ### v0.2.2 (2014/06/26) * [#91](https://github.com/linkedin/hopscotch/pull/91) Don't cache step targets - support for single page apps diff --git a/archives/hopscotch-0.2.3.tar.gz b/archives/hopscotch-0.2.3.tar.gz new file mode 100644 index 00000000..93c2afe7 Binary files /dev/null and b/archives/hopscotch-0.2.3.tar.gz differ diff --git a/archives/hopscotch-0.2.3.zip b/archives/hopscotch-0.2.3.zip new file mode 100644 index 00000000..d70a27cb Binary files /dev/null and b/archives/hopscotch-0.2.3.zip differ diff --git a/dist/css/hopscotch.css b/dist/css/hopscotch.css index 2e2095d9..f84ba7ff 100644 --- a/dist/css/hopscotch.css +++ b/dist/css/hopscotch.css @@ -1,4 +1,4 @@ -/**! hopscotch - v0.2.2 +/**! hopscotch - v0.2.3 * * Copyright 2014 LinkedIn Corp. All rights reserved. * diff --git a/dist/css/hopscotch.min.css b/dist/css/hopscotch.min.css index 58282889..44594ecb 100644 --- a/dist/css/hopscotch.min.css +++ b/dist/css/hopscotch.min.css @@ -1,4 +1,4 @@ -/**! hopscotch - v0.2.2 +/**! hopscotch - v0.2.3 * * Copyright 2014 LinkedIn Corp. All rights reserved. * diff --git a/dist/js/hopscotch.js b/dist/js/hopscotch.js index d7ccce2c..8dbe8d96 100644 --- a/dist/js/hopscotch.js +++ b/dist/js/hopscotch.js @@ -1,4 +1,4 @@ -/**! hopscotch - v0.2.2 +/**! hopscotch - v0.2.3 * * Copyright 2014 LinkedIn Corp. All rights reserved. * @@ -36,7 +36,11 @@ hasJquery = (typeof window.jQuery !== undefinedStr), hasSessionStorage = false, isStorageWritable = false, - document = window.document; + document = window.document, + rtlMatches = { + left: 'right', + right: 'left' + }; // If cookies are disabled, accessing sessionStorage can throw an error. // sessionStorage could also throw an error in Safari on write (even though it exists). @@ -61,6 +65,7 @@ bubblePadding: 15, arrowWidth: 20, skipIfNoElement: true, + isRtl: false, cookieName: 'hopscotch.tour.state' }; @@ -519,6 +524,37 @@ else { this.setState(name,'',-1); } + }, + + /** + * Originally called it orientation, but placement is more intuitive. + * Allowing both for now for backwards compatibility. + * @private + */ + normalizePlacement: function(step) { + if (!step.placement && step.orientation) { + step.placement = step.orientation; + } + }, + + /** + * If step is right-to-left enabled, flip the placement and xOffset, but only once. + * @private + */ + flipPlacement: function(step){ + if(step.isRtl && !step._isFlipped){ + var props = ['orientation', 'placement'], prop, i; + if(step.xOffset){ + step.xOffset = -1 * this.getPixelValue(step.xOffset); + } + for(i in props){ + prop = props[i]; + if(step.hasOwnProperty(prop) && rtlMatches.hasOwnProperty(step[prop])) { + step[prop] = rtlMatches[step[prop]]; + } + } + step._isFlipped = true; + } } }; @@ -582,29 +618,31 @@ top, left, arrowOffset, + verticalLeftPosition, targetEl = utils.getStepTarget(step), el = this.element, - arrowEl = this.arrowEl; + arrowEl = this.arrowEl, + arrowPos = step.isRtl ? 'right' : 'left'; + + utils.flipPlacement(step); + utils.normalizePlacement(step); bubbleBoundingWidth = el.offsetWidth; bubbleBoundingHeight = el.offsetHeight; utils.removeClass(el, 'fade-in-down fade-in-up fade-in-left fade-in-right'); - // Originally called it orientation, but placement is more intuitive. - // Allowing both for now for backwards compatibility. - if (!step.placement && step.orientation) { - step.placement = step.orientation; - } - // SET POSITION boundingRect = targetEl.getBoundingClientRect(); + + verticalLeftPosition = step.isRtl ? boundingRect.right - bubbleBoundingWidth : boundingRect.left; + if (step.placement === 'top') { top = (boundingRect.top - bubbleBoundingHeight) - this.opt.arrowWidth; - left = boundingRect.left; + left = verticalLeftPosition; } else if (step.placement === 'bottom') { top = boundingRect.bottom + this.opt.arrowWidth; - left = boundingRect.left; + left = verticalLeftPosition; } else if (step.placement === 'left') { top = boundingRect.top; @@ -627,20 +665,20 @@ } if (!arrowOffset) { arrowEl.style.top = ''; - arrowEl.style.left = ''; + arrowEl.style[arrowPos] = ''; } else if (step.placement === 'top' || step.placement === 'bottom') { arrowEl.style.top = ''; if (arrowOffset === 'center') { - arrowEl.style.left = Math.floor((bubbleBoundingWidth / 2) - arrowEl.offsetWidth/2) + 'px'; + arrowEl.style[arrowPos] = Math.floor((bubbleBoundingWidth / 2) - arrowEl.offsetWidth/2) + 'px'; } else { // Numeric pixel value - arrowEl.style.left = arrowOffset + 'px'; + arrowEl.style[arrowPos] = arrowOffset + 'px'; } } else if (step.placement === 'left' || step.placement === 'right') { - arrowEl.style.left = ''; + arrowEl.style[arrowPos] = ''; if (arrowOffset === 'center') { arrowEl.style.top = Math.floor((bubbleBoundingHeight / 2) - arrowEl.offsetHeight/2) + 'px'; } @@ -710,6 +748,8 @@ if(currTour){ customTourData = currTour.customData; tourSpecificRenderer = currTour.customRenderer; + step.isRtl = step.hasOwnProperty('isRtl') ? step.isRtl : + (currTour.hasOwnProperty('isRtl') ? currTour.isRtl : this.opt.isRtl); unsafe = currTour.unsafe; if(Array.isArray(currTour.steps)){ totalSteps = currTour.steps.length; @@ -720,6 +760,7 @@ customTourData = step.customData; tourSpecificRenderer = step.customRenderer; unsafe = step.unsafe; + step.isRtl = step.hasOwnProperty('isRtl') ? step.isRtl : this.opt.isRtl; } // Determine label for next button @@ -731,11 +772,9 @@ nextBtnText = utils.getI18NString('nextBtn'); } - // Originally called it orientation, but placement is more intuitive. - // Allowing both for now for backwards compatibility. - if (!step.placement && step.orientation) { - step.placement = step.orientation; - } + utils.flipPlacement(step); + utils.normalizePlacement(step); + this.placement = step.placement; // Setup the configuration options we want to pass along to the template @@ -744,7 +783,7 @@ prevBtn: utils.getI18NString('prevBtn'), nextBtn: nextBtnText, closeTooltip: utils.getI18NString('closeTooltip'), - stepNum: this._getStepI18nNum(idx), + stepNum: this._getStepI18nNum(this._getStepNum(idx)) }, buttons:{ showPrev: (utils.valOrDefault(step.showPrevButton, this.opt.showPrevButton) && (idx > 0)), @@ -758,6 +797,7 @@ isLast: utils.valOrDefault(isLast, false), title: (step.title || ''), content: (step.content || ''), + isRtl: step.isRtl, placement: step.placement, padding: utils.valOrDefault(step.padding, this.opt.bubblePadding), width: utils.getPixelValue(step.width) || this.opt.bubbleWidth, @@ -804,7 +844,7 @@ } // Set z-index and arrow placement - el.style.zIndex = (typeof step.zindex === 'number') ? step.zindex : 'auto'; + el.style.zIndex = (typeof step.zindex === 'number') ? step.zindex : ''; this._setArrow(step.placement); // Set bubble positioning @@ -819,7 +859,26 @@ return this; }, - + /** + * Get step number considering steps that were skipped because their target wasn't found + * + * @private + */ + _getStepNum: function(idx) { + var skippedStepsCount = 0, + stepIdx, + skippedSteps = winHopscotch.getSkippedStepsIndexes(), + i, + len = skippedSteps.length; + //count number of steps skipped before current step + for(i = 0; i < len; i++) { + stepIdx = skippedSteps[i]; + if(stepIdx= currTour.steps.length) { + if (!currTour || currStepNum < 0 || currStepNum >= currTour.steps.length) { step = null; } else { @@ -1422,10 +1514,17 @@ target = utils.getStepTarget(step); if (target) { + //this step was previously skipped, but now its target exists, + //remove this step from skipped steps set + if(skippedSteps[currStepNum]) { + delete skippedSteps[currStepNum]; + } // We're done! Return the step number via the callback. cb(currStepNum); } else { + //mark this step as skipped, since its target wasn't found + skippedSteps[currStepNum] = true; // Haven't found a valid target yet. Recursively call // goToStepWithTarget. utils.invokeEventCallbacks('error'); @@ -1466,7 +1565,14 @@ bubble.hide(); doCallbacks = utils.valOrDefault(doCallbacks, true); + step = getCurrStep(); + + if (step.nextOnTargetClick) { + // Detach the listener when tour is moving to a different step + utils.removeEvtListener(utils.getStepTarget(step), 'click', targetClickNextFn); + } + origStep = step; if (direction > 0) { wasMultiPage = origStep.multipage; @@ -1505,7 +1611,7 @@ if (wasMultiPage) { // Update state for the next page - utils.setState(getOption('cookieName'), currTour.id + ':' + currStepNum, 1); + setStateHelper(); // Next step is on a different page, so no need to attempt to render it. return; @@ -1555,7 +1661,7 @@ var tmpOpt = {}, prop, tourState, - tourPair; + tourStateValues; // Set tour-specific configurations for (prop in tour) { @@ -1573,9 +1679,13 @@ // Get existing tour state, if it exists. tourState = utils.getState(getOption('cookieName')); if (tourState) { - tourPair = tourState.split(':'); - cookieTourId = tourPair[0]; // selecting tour is not supported by this framework. - cookieTourStep = tourPair[1]; + tourStateValues = tourState.split(':'); + cookieTourId = tourStateValues[0]; // selecting tour is not supported by this framework. + cookieTourStep = tourStateValues[1]; + + if(tourStateValues.length > 2) { + cookieSkippedSteps = tourStateValues[2].split(','); + } cookieTourStep = parseInt(cookieTourStep, 10); } @@ -1587,12 +1697,12 @@ * Find the first step to show for a tour. (What is the first step with a * target on the page?) */ - findStartingStep = function(startStepNum, cb) { + findStartingStep = function(startStepNum, savedSkippedSteps, cb) { var step, - target, - stepNum; + target; currStepNum = startStepNum || 0; + skippedSteps = savedSkippedSteps || {}; step = getCurrStep(); target = utils.getStepTarget(step); @@ -1610,6 +1720,9 @@ // that has a target on the page or end the tour if we can't find such a step. utils.invokeEventCallbacks('error'); + //this step was skipped, since its target does not exist + skippedSteps[currStepNum] = true; + if (getOption('skipIfNoElement')) { goToStepWithTarget(1, cb); return; @@ -1623,25 +1736,24 @@ showStepHelper = function(stepNum) { var step = currTour.steps[stepNum], - tourSteps = currTour.steps, - numTourSteps = tourSteps.length, - cookieVal = currTour.id + ':' + stepNum, bubble = getBubble(), - targetEl = utils.getStepTarget(step), - isLast, - showBubble; + targetEl = utils.getStepTarget(step); - showBubble = function() { + function showBubble() { bubble.show(); utils.invokeEventCallbacks('show', step.onShow); - }; + } + + if (currStepNum !== stepNum && getCurrStep().nextOnTargetClick) { + // Detach the listener when tour is moving to a different step + utils.removeEvtListener(utils.getStepTarget(getCurrStep()), 'click', targetClickNextFn); + } // Update bubble for current step - currStepNum = stepNum; + currStepNum = stepNum; bubble.hide(false); - isLast = (stepNum === numTourSteps - 1); bubble.render(step, stepNum, function(adjustScroll) { // when done adjusting window scroll, call showBubble helper fn if (adjustScroll) { @@ -1657,6 +1769,17 @@ } }); + setStateHelper(); + }, + + setStateHelper = function() { + var cookieVal = currTour.id + ':' + currStepNum, + skipedStepIndexes = winHopscotch.getSkippedStepsIndexes(); + + if(skipedStepIndexes && skipedStepIndexes.length > 0) { + cookieVal += ':' + skipedStepIndexes.join(','); + } + utils.setState(getOption('cookieName'), cookieVal, 1); }, @@ -1703,6 +1826,7 @@ this.startTour = function(tour, stepNum) { var bubble, currStepNum, + skippedSteps = {}, self = this; // loadTour if we are calling startTour directly. (When we call startTour @@ -1728,13 +1852,18 @@ if (typeof currStepNum === "undefined" && currTour.id === cookieTourId && typeof cookieTourStep !== undefinedStr) { currStepNum = cookieTourStep; + if(cookieSkippedSteps.length > 0){ + for(var i = 0, len = cookieSkippedSteps.length; i < len; i++) { + skippedSteps[cookieSkippedSteps[i]] = true; + } + } } else if (!currStepNum) { currStepNum = 0; } // Find the current step we should begin the tour on, and then actually start the tour. - findStartingStep(currStepNum, function(stepNum) { + findStartingStep(currStepNum, skippedSteps, function(stepNum) { var target = (stepNum !== -1) && utils.getStepTarget(currTour.steps[stepNum]); if (!target) { @@ -1812,13 +1941,6 @@ * @returns {Object} Hopscotch */ this.nextStep = function(doCallbacks) { - var step = getCurrStep(), - targetEl = utils.getStepTarget(step); - - if (step.nextOnTargetClick) { - // Detach the listener after we've clicked on the target OR the next button. - utils.removeEvtListener(targetEl, 'click', targetClickNextFn); - } changeStep.call(this, doCallbacks, 1); return this; }; @@ -1833,9 +1955,20 @@ * @returns {Object} Hopscotch */ this.endTour = function(clearState, doCallbacks) { - var bubble = getBubble(); + var bubble = getBubble(), + currentStep; + clearState = utils.valOrDefault(clearState, true); doCallbacks = utils.valOrDefault(doCallbacks, true); + + //remove event listener if current step had it added + if(currTour) { + currentStep = getCurrStep(); + if(currentStep && currentStep.nextOnTargetClick) { + utils.removeEvtListener(utils.getStepTarget(currentStep), 'click', targetClickNextFn); + } + } + currStepNum = 0; cookieTourStep = undefined; @@ -1886,16 +2019,37 @@ return currStepNum; }; + /** + * getSkippedStepsIndexes + * + * @return {Array} Array of skipped step indexes + */ + this.getSkippedStepsIndexes = function() { + var skippedStepsIdxArray = [], + stepIds; + + for(stepIds in skippedSteps){ + skippedStepsIdxArray.push(stepIds); + } + + return skippedStepsIdxArray; + }; + /** * refreshBubblePosition * * Tell hopscotch that the position of the current tour element changed - * and the bubble therefore needs to be redrawn + * and the bubble therefore needs to be redrawn. Also refreshes position + * of all Hopscotch Callouts on the page. * * @returns {Object} Hopscotch */ this.refreshBubblePosition = function() { - bubble.setPosition(getCurrStep()); + var currStep = getCurrStep(); + if(currStep){ + getBubble().setPosition(currStep); + } + this.getCalloutManager().refreshCalloutPositions(); return this; }; @@ -2131,6 +2285,10 @@ * TRUE. * - onNext: Function - A callback to be invoked after every click on * a "Next" button. + * - isRtl: Boolean - Set to true when instantiating in a right-to-left + * language environment, or if mirrored positioning is + * needed. + * Defaults to FALSE. * * - i18n: Object - For i18n purposes. Allows you to change the * text of button labels and step numbers. diff --git a/dist/js/hopscotch.min.js b/dist/js/hopscotch.min.js index 401a4af3..3ba661e4 100644 --- a/dist/js/hopscotch.min.js +++ b/dist/js/hopscotch.min.js @@ -1,4 +1,4 @@ -/**! hopscotch - v0.2.2 +/**! hopscotch - v0.2.3 * * Copyright 2014 LinkedIn Corp. All rights reserved. * @@ -14,4 +14,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -!function(context,namespace){var Hopscotch,HopscotchBubble,HopscotchCalloutManager,HopscotchI18N,customI18N,customRenderer,customEscape,utils,callbacks,helpers,winLoadHandler,defaultOpts,templateToUse="bubble_default",Sizzle=window.Sizzle||null,winHopscotch=context[namespace],undefinedStr="undefined",waitingToStart=!1,hasJquery=typeof window.jQuery!==undefinedStr,hasSessionStorage=!1,isStorageWritable=!1,document=window.document;try{typeof window.sessionStorage!==undefinedStr&&(hasSessionStorage=!0,sessionStorage.setItem("hopscotch.test.storage","ok"),sessionStorage.removeItem("hopscotch.test.storage"),isStorageWritable=!0)}catch(err){}defaultOpts={smoothScroll:!0,scrollDuration:1e3,scrollTopMargin:200,showCloseButton:!0,showPrevButton:!1,showNextButton:!0,bubbleWidth:280,bubblePadding:15,arrowWidth:20,skipIfNoElement:!0,cookieName:"hopscotch.tour.state"},winHopscotch||(Array.isArray||(Array.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)}),winLoadHandler=function(){waitingToStart&&winHopscotch.startTour()},utils={addClass:function(a,b){var c,d,e,f;if(a.className){for(d=b.split(/\s+/),c=" "+a.className+" ",e=0,f=d.length;f>e;++e)c.indexOf(" "+d[e]+" ")<0&&(c+=d[e]+" ");a.className=c.replace(/^\s+|\s+$/g,"")}else a.className=b},removeClass:function(a,b){var c,d,e,f;for(d=b.split(/\s+/),c=" "+a.className+" ",e=0,f=d.length;f>e;++e)c=c.replace(" "+d[e]+" "," ");a.className=c.replace(/^\s+|\s+$/g,"")},hasClass:function(a,b){var c;return a.className?(c=" "+a.className+" ",-1!==c.indexOf(" "+b+" ")):!1},getPixelValue:function(a){var b=typeof a;return"number"===b?a:"string"===b?parseInt(a,10):0},valOrDefault:function(a,b){return typeof a!==undefinedStr?a:b},invokeCallbackArrayHelper:function(a){var b;return Array.isArray(a)&&(b=helpers[a[0]],"function"==typeof b)?b.apply(this,a.slice(1)):void 0},invokeCallbackArray:function(a){var b,c;if(Array.isArray(a)){if("string"==typeof a[0])return utils.invokeCallbackArrayHelper(a);for(b=0,c=a.length;c>b;++b)utils.invokeCallback(a[b])}},invokeCallback:function(a){return"function"==typeof a?a():"string"==typeof a&&helpers[a]?helpers[a]():utils.invokeCallbackArray(a)},invokeEventCallbacks:function(a,b){var c,d,e=callbacks[a];if(b)return this.invokeCallback(b);for(c=0,d=e.length;d>c;++c)this.invokeCallback(e[c].cb)},getScrollTop:function(){var a;return a=typeof window.pageYOffset!==undefinedStr?window.pageYOffset:document.documentElement.scrollTop},getScrollLeft:function(){var a;return a=typeof window.pageXOffset!==undefinedStr?window.pageXOffset:document.documentElement.scrollLeft},getWindowHeight:function(){return window.innerHeight||document.documentElement.clientHeight},getWindowWidth:function(){return window.innerWidth||document.documentElement.clientWidth},addEvtListener:function(a,b,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},removeEvtListener:function(a,b,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)},documentIsReady:function(){return"complete"===document.readyState||"interactive"===document.readyState},evtPreventDefault:function(a){a.preventDefault?a.preventDefault():event&&(event.returnValue=!1)},extend:function(a,b){var c;for(c in b)b.hasOwnProperty(c)&&(a[c]=b[c])},getStepTargetHelper:function(a){var b=document.getElementById(a);if(b)return b;if(hasJquery)return b=jQuery(a),b.length?b[0]:null;if(Sizzle)return b=new Sizzle(a),b.length?b[0]:null;if(document.querySelector)try{return document.querySelector(a)}catch(c){}return/^#[a-zA-Z][\w-_:.]*$/.test(a)?document.getElementById(a.substring(1)):null},getStepTarget:function(a){var b;if(!a||!a.target)return null;if("string"==typeof a.target)return utils.getStepTargetHelper(a.target);if(Array.isArray(a.target)){var c,d;for(c=0,d=a.target.length;d>c;c++)if("string"==typeof a.target[c]&&(b=utils.getStepTargetHelper(a.target[c])))return b;return null}return a.target},getI18NString:function(a){return customI18N[a]||HopscotchI18N[a]},setState:function(a,b,c){var d,e="";if(hasSessionStorage&&isStorageWritable)try{sessionStorage.setItem(a,b)}catch(f){isStorageWritable=!1,this.setState(a,b,c)}else hasSessionStorage&&sessionStorage.removeItem(a),c&&(d=new Date,d.setTime(d.getTime()+24*c*60*60*1e3),e="; expires="+d.toGMTString()),document.cookie=a+"="+b+e+"; path=/"},getState:function(a){var b,c,d,e=a+"=",f=document.cookie.split(";");if(hasSessionStorage&&(d=sessionStorage.getItem(a)))return d;for(b=0;b0,showNext:utils.valOrDefault(a.showNextButton,this.opt.showNextButton),showCTA:utils.valOrDefault(a.showCTAButton&&a.ctaLabel,!1),ctaLabel:a.ctaLabel,showClose:utils.valOrDefault(this.opt.showCloseButton,!0)},step:{num:b,isLast:utils.valOrDefault(k,!1),title:a.title||"",content:a.content||"",placement:a.placement,padding:utils.valOrDefault(a.padding,this.opt.bubblePadding),width:utils.getPixelValue(a.width)||this.opt.bubbleWidth,customData:a.customData||{}},tour:{isTour:this.opt.isTourBubble,numSteps:h,unsafe:utils.valOrDefault(f,!1),customData:e||{}}},"function"==typeof d)m.innerHTML=d(l);else if("string"==typeof d){if(!hopscotch.templates||"function"!=typeof hopscotch.templates[d])throw'Bubble rendering failed - template "'+d+'" is not a function.';m.innerHTML=hopscotch.templates[d](l)}else if(customRenderer)m.innerHTML=customRenderer(l);else{if(!hopscotch.templates||"function"!=typeof hopscotch.templates[templateToUse])throw'Bubble rendering failed - template "'+templateToUse+'" is not a function.';m.innerHTML=hopscotch.templates[templateToUse](l)}for(children=m.children,numChildren=children.length,i=0;numChildren>i;i++)node=children[i],utils.hasClass(node,"hopscotch-arrow")&&(this.arrowEl=node);return m.style.zIndex="number"==typeof a.zindex?a.zindex:"auto",this._setArrow(a.placement),this.hide(!1),this.setPosition(a),c&&c(!a.fixedElement),this},_getStepI18nNum:function(a){var b=utils.getI18NString("stepNums");return b&&af||f>=e.steps.length?null:e.steps[f]},n=function(){j.nextStep()},o=function(a){var b,c,d,e,f,g,h=k(),i=h.element,j=utils.getPixelValue(i.style.top),n=j+utils.getPixelValue(i.offsetHeight),o=utils.getStepTarget(m()),p=o.getBoundingClientRect(),q=p.top+utils.getScrollTop(),r=p.bottom+utils.getScrollTop(),s=q>j?j:q,t=n>r?n:r,u=utils.getScrollTop(),v=u+utils.getWindowHeight(),w=s-l("scrollTopMargin");s>=u&&(s<=u+l("scrollTopMargin")||v>=t)?a&&a():l("smoothScroll")?typeof YAHOO!==undefinedStr&&typeof YAHOO.env!==undefinedStr&&typeof YAHOO.env.ua!==undefinedStr&&typeof YAHOO.util!==undefinedStr&&typeof YAHOO.util.Scroll!==undefinedStr?(b=YAHOO.env.ua.webkit?document.body:document.documentElement,d=YAHOO.util.Easing?YAHOO.util.Easing.easeOut:void 0,c=new YAHOO.util.Scroll(b,{scroll:{to:[0,w]}},l("scrollDuration")/1e3,d),c.onComplete.subscribe(a),c.animate()):hasJquery?jQuery("body, html").animate({scrollTop:w},l("scrollDuration"),a):(0>w&&(w=0),e=u>s?-1:1,f=Math.abs(u-w)/(l("scrollDuration")/10),(g=function(){var b=utils.getScrollTop(),c=b+e*f;return e>0&&c>=w||0>e&&w>=c?(c=w,a&&a(),void window.scrollTo(0,c)):(window.scrollTo(0,c),utils.getScrollTop()===b?void(a&&a()):void setTimeout(g,10))})()):(window.scrollTo(0,w),a&&a())},p=function(a,b){var c,d,g;f+a>=0&&f+a0?d.multipage:f>0&&e.steps[f-1].multipage,h=function(c){var h;if(-1===c)return this.endTour(!0);if(a&&(h=b>0?utils.invokeEventCallbacks("next",d.onNext):utils.invokeEventCallbacks("prev",d.onPrev)),c===f){if(g)return void utils.setState(l("cookieName"),e.id+":"+f,1);h=utils.valOrDefault(h,!0),h?this.showStep(c):this.endTour(!1)}},!g&&l("skipIfNoElement"))p(b,function(a){h.call(j,a)});else if(f+b>=0&&f+b=e.steps.length)throw"Specified step number out of bounds.";d=b}return utils.documentIsReady()?("undefined"==typeof d&&e.id===g&&typeof h!==undefinedStr?d=h:d||(d=0),s(d,function(a){var b=-1!==a&&utils.getStepTarget(e.steps[a]);return b?(utils.invokeEventCallbacks("start"),c=k(),c.hide(!1),f.isActive=!0,void(utils.getStepTarget(m())?f.showStep(a):(utils.invokeEventCallbacks("error"),l("skipIfNoElement")&&f.nextStep(!1)))):void f.endTour(!1,!1)}),this):(waitingToStart=!0,this)},this.showStep=function(a){var b=e.steps[a];return b.delay?setTimeout(function(){t(a)},b.delay):t(a),this},this.prevStep=function(a){return q.call(this,a,-1),this},this.nextStep=function(a){var b=m(),c=utils.getStepTarget(b);return b.nextOnTargetClick&&utils.removeEvtListener(c,"click",n),q.call(this,a,1),this},this.endTour=function(a,b){var c=k();return a=utils.valOrDefault(a,!0),b=utils.valOrDefault(b,!0),f=0,h=void 0,c.hide(),a&&utils.clearState(l("cookieName")),this.isActive&&(this.isActive=!1,e&&b&&utils.invokeEventCallbacks("end")),this.removeCallbacks(null,!0),this.resetDefaultOptions(),e=null,this},this.getCurrTour=function(){return e},this.getCurrTarget=function(){return utils.getStepTarget(m())},this.getCurrStepNum=function(){return f},this.refreshBubblePosition=function(){return b.setPosition(m()),this},this.listen=function(a,b,c){return a&&callbacks[a].push({cb:b,fromTour:c}),this},this.unlisten=function(a,b){var c,d,e=callbacks[a];for(c=0,d=e.length;d>c;++c)e[c]===b&&e.splice(c,1);return this},this.removeCallbacks=function(a,b){var c,d,e,f;for(f in callbacks)if(!a||a===f)if(b)for(c=callbacks[f],d=0,e=c.length;e>d;++d)c[d].fromTour&&(c.splice(d--,1),--e);else callbacks[f]=[];return this},this.registerHelper=function(a,b){"string"==typeof a&&"function"==typeof b&&(helpers[a]=b)},this.unregisterHelper=function(a){helpers[a]=null},this.invokeHelper=function(a){var b,c,d=[];for(b=1,c=arguments.length;c>b;++b)d.push(arguments[b]);helpers[a]&&helpers[a].call(null,d)},this.setCookieName=function(a){return d.cookieName=a,this},this.resetDefaultOptions=function(){return d={},this},this.resetDefaultI18N=function(){return customI18N={},this},this.getState=function(){return utils.getState(l("cookieName"))},i=function(a,b){var c,e,f,g,h=["next","prev","start","end","show","error","close"];for(d||this.resetDefaultOptions(),utils.extend(d,a),a&&utils.extend(customI18N,a.i18n),f=0,g=h.length;g>f;++f)e="on"+h[f].charAt(0).toUpperCase()+h[f].substring(1),a[e]&&this.listen(h[f],a[e],b);return c=k(!0),this},this.configure=function(a){return i.call(this,a,!1)},this.setRenderer=function(a){var b=typeof a;return"string"===b?(templateToUse=a,customRenderer=void 0):"function"===b&&(customRenderer=a),this},this.setEscaper=function(a){return"function"==typeof a&&(customEscape=a),this},u.call(this,a)},winHopscotch=new Hopscotch,context[namespace]=winHopscotch,function(){var _={};_.escape=function(a){return customEscape?customEscape(a):null==a?"":(""+a).replace(new RegExp("[&<>\"']","g"),function(a){return"&"==a?"&":"<"==a?"<":">"==a?">":'"'==a?""":"'"==a?"'":void 0})},this.hopscotch=this.hopscotch||{},this.hopscotch.templates=this.hopscotch.templates||{},this.hopscotch.templates.bubble_default=function(obj){function optEscape(a,b){return b?_.escape(a):a}obj||(obj={});{var __t,__p="";_.escape,Array.prototype.join}with(obj)__p+='\n
\n ',tour.isTour&&(__p+=''+(null==(__t=i18n.stepNum)?"":__t)+""),__p+='\n
\n ',""!==step.title&&(__p+='

'+(null==(__t=optEscape(step.title,tour.unsafe))?"":__t)+"

"),__p+="\n ",""!==step.content&&(__p+='
'+(null==(__t=optEscape(step.content,tour.unsafe))?"":__t)+"
"),__p+='\n
\n
\n ',buttons.showPrev&&(__p+='"),__p+="\n ",buttons.showCTA&&(__p+='"),__p+="\n ",buttons.showNext&&(__p+='"),__p+="\n
\n ",buttons.showClose&&(__p+=''+(null==(__t=i18n.closeTooltip)?"":__t)+""),__p+='\n
\n
\n
\n
\n
';return __p}}())}(window,"hopscotch"); \ No newline at end of file +!function(context,namespace){var Hopscotch,HopscotchBubble,HopscotchCalloutManager,HopscotchI18N,customI18N,customRenderer,customEscape,utils,callbacks,helpers,winLoadHandler,defaultOpts,templateToUse="bubble_default",Sizzle=window.Sizzle||null,winHopscotch=context[namespace],undefinedStr="undefined",waitingToStart=!1,hasJquery=typeof window.jQuery!==undefinedStr,hasSessionStorage=!1,isStorageWritable=!1,document=window.document,rtlMatches={left:"right",right:"left"};try{typeof window.sessionStorage!==undefinedStr&&(hasSessionStorage=!0,sessionStorage.setItem("hopscotch.test.storage","ok"),sessionStorage.removeItem("hopscotch.test.storage"),isStorageWritable=!0)}catch(err){}defaultOpts={smoothScroll:!0,scrollDuration:1e3,scrollTopMargin:200,showCloseButton:!0,showPrevButton:!1,showNextButton:!0,bubbleWidth:280,bubblePadding:15,arrowWidth:20,skipIfNoElement:!0,isRtl:!1,cookieName:"hopscotch.tour.state"},winHopscotch||(Array.isArray||(Array.isArray=function(a){return"[object Array]"===Object.prototype.toString.call(a)}),winLoadHandler=function(){waitingToStart&&winHopscotch.startTour()},utils={addClass:function(a,b){var c,d,e,f;if(a.className){for(d=b.split(/\s+/),c=" "+a.className+" ",e=0,f=d.length;f>e;++e)c.indexOf(" "+d[e]+" ")<0&&(c+=d[e]+" ");a.className=c.replace(/^\s+|\s+$/g,"")}else a.className=b},removeClass:function(a,b){var c,d,e,f;for(d=b.split(/\s+/),c=" "+a.className+" ",e=0,f=d.length;f>e;++e)c=c.replace(" "+d[e]+" "," ");a.className=c.replace(/^\s+|\s+$/g,"")},hasClass:function(a,b){var c;return a.className?(c=" "+a.className+" ",-1!==c.indexOf(" "+b+" ")):!1},getPixelValue:function(a){var b=typeof a;return"number"===b?a:"string"===b?parseInt(a,10):0},valOrDefault:function(a,b){return typeof a!==undefinedStr?a:b},invokeCallbackArrayHelper:function(a){var b;return Array.isArray(a)&&(b=helpers[a[0]],"function"==typeof b)?b.apply(this,a.slice(1)):void 0},invokeCallbackArray:function(a){var b,c;if(Array.isArray(a)){if("string"==typeof a[0])return utils.invokeCallbackArrayHelper(a);for(b=0,c=a.length;c>b;++b)utils.invokeCallback(a[b])}},invokeCallback:function(a){return"function"==typeof a?a():"string"==typeof a&&helpers[a]?helpers[a]():utils.invokeCallbackArray(a)},invokeEventCallbacks:function(a,b){var c,d,e=callbacks[a];if(b)return this.invokeCallback(b);for(c=0,d=e.length;d>c;++c)this.invokeCallback(e[c].cb)},getScrollTop:function(){var a;return a=typeof window.pageYOffset!==undefinedStr?window.pageYOffset:document.documentElement.scrollTop},getScrollLeft:function(){var a;return a=typeof window.pageXOffset!==undefinedStr?window.pageXOffset:document.documentElement.scrollLeft},getWindowHeight:function(){return window.innerHeight||document.documentElement.clientHeight},getWindowWidth:function(){return window.innerWidth||document.documentElement.clientWidth},addEvtListener:function(a,b,c){return a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},removeEvtListener:function(a,b,c){return a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent("on"+b,c)},documentIsReady:function(){return"complete"===document.readyState||"interactive"===document.readyState},evtPreventDefault:function(a){a.preventDefault?a.preventDefault():event&&(event.returnValue=!1)},extend:function(a,b){var c;for(c in b)b.hasOwnProperty(c)&&(a[c]=b[c])},getStepTargetHelper:function(a){var b=document.getElementById(a);if(b)return b;if(hasJquery)return b=jQuery(a),b.length?b[0]:null;if(Sizzle)return b=new Sizzle(a),b.length?b[0]:null;if(document.querySelector)try{return document.querySelector(a)}catch(c){}return/^#[a-zA-Z][\w-_:.]*$/.test(a)?document.getElementById(a.substring(1)):null},getStepTarget:function(a){var b;if(!a||!a.target)return null;if("string"==typeof a.target)return utils.getStepTargetHelper(a.target);if(Array.isArray(a.target)){var c,d;for(c=0,d=a.target.length;d>c;c++)if("string"==typeof a.target[c]&&(b=utils.getStepTargetHelper(a.target[c])))return b;return null}return a.target},getI18NString:function(a){return customI18N[a]||HopscotchI18N[a]},setState:function(a,b,c){var d,e="";if(hasSessionStorage&&isStorageWritable)try{sessionStorage.setItem(a,b)}catch(f){isStorageWritable=!1,this.setState(a,b,c)}else hasSessionStorage&&sessionStorage.removeItem(a),c&&(d=new Date,d.setTime(d.getTime()+24*c*60*60*1e3),e="; expires="+d.toGMTString()),document.cookie=a+"="+b+e+"; path=/"},getState:function(a){var b,c,d,e=a+"=",f=document.cookie.split(";");if(hasSessionStorage&&(d=sessionStorage.getItem(a)))return d;for(b=0;b0,showNext:utils.valOrDefault(a.showNextButton,this.opt.showNextButton),showCTA:utils.valOrDefault(a.showCTAButton&&a.ctaLabel,!1),ctaLabel:a.ctaLabel,showClose:utils.valOrDefault(this.opt.showCloseButton,!0)},step:{num:b,isLast:utils.valOrDefault(k,!1),title:a.title||"",content:a.content||"",isRtl:a.isRtl,placement:a.placement,padding:utils.valOrDefault(a.padding,this.opt.bubblePadding),width:utils.getPixelValue(a.width)||this.opt.bubbleWidth,customData:a.customData||{}},tour:{isTour:this.opt.isTourBubble,numSteps:h,unsafe:utils.valOrDefault(f,!1),customData:e||{}}},"function"==typeof d)m.innerHTML=d(l);else if("string"==typeof d){if(!hopscotch.templates||"function"!=typeof hopscotch.templates[d])throw'Bubble rendering failed - template "'+d+'" is not a function.';m.innerHTML=hopscotch.templates[d](l)}else if(customRenderer)m.innerHTML=customRenderer(l);else{if(!hopscotch.templates||"function"!=typeof hopscotch.templates[templateToUse])throw'Bubble rendering failed - template "'+templateToUse+'" is not a function.';m.innerHTML=hopscotch.templates[templateToUse](l)}for(children=m.children,numChildren=children.length,i=0;ic;c++)b=e[c],a>b&&d++;return a-d},_getStepI18nNum:function(a){var b=utils.getI18NString("stepNums");return b&&af||f>=e.steps.length?null:e.steps[f]},p=function(){j.nextStep()},q=function(a){var b,c,d,e,f,g,h=m(),i=h.element,j=utils.getPixelValue(i.style.top),k=j+utils.getPixelValue(i.offsetHeight),l=utils.getStepTarget(o()),p=l.getBoundingClientRect(),q=p.top+utils.getScrollTop(),r=p.bottom+utils.getScrollTop(),s=q>j?j:q,t=k>r?k:r,u=utils.getScrollTop(),v=u+utils.getWindowHeight(),w=s-n("scrollTopMargin");s>=u&&(s<=u+n("scrollTopMargin")||v>=t)?a&&a():n("smoothScroll")?typeof YAHOO!==undefinedStr&&typeof YAHOO.env!==undefinedStr&&typeof YAHOO.env.ua!==undefinedStr&&typeof YAHOO.util!==undefinedStr&&typeof YAHOO.util.Scroll!==undefinedStr?(b=YAHOO.env.ua.webkit?document.body:document.documentElement,d=YAHOO.util.Easing?YAHOO.util.Easing.easeOut:void 0,c=new YAHOO.util.Scroll(b,{scroll:{to:[0,w]}},n("scrollDuration")/1e3,d),c.onComplete.subscribe(a),c.animate()):hasJquery?jQuery("body, html").animate({scrollTop:w},n("scrollDuration"),a):(0>w&&(w=0),e=u>s?-1:1,f=Math.abs(u-w)/(n("scrollDuration")/10),(g=function(){var b=utils.getScrollTop(),c=b+e*f;return e>0&&c>=w||0>e&&w>=c?(c=w,a&&a(),void window.scrollTo(0,c)):(window.scrollTo(0,c),utils.getScrollTop()===b?void(a&&a()):void setTimeout(g,10))})()):(window.scrollTo(0,w),a&&a())},r=function(a,b){var c,d,g;f+a>=0&&f+a0?d.multipage:f>0&&e.steps[f-1].multipage,h=function(c){var e;if(-1===c)return this.endTour(!0);if(a&&(e=b>0?utils.invokeEventCallbacks("next",d.onNext):utils.invokeEventCallbacks("prev",d.onPrev)),c===f){if(g)return void w();e=utils.valOrDefault(e,!0),e?this.showStep(c):this.endTour(!1)}},!g&&n("skipIfNoElement"))r(b,function(a){h.call(j,a)});else if(f+b>=0&&f+b2&&(l=d[2].split(",")),h=parseInt(h,10)),this},u=function(a,b,c){var d,e;if(f=a||0,k=b||{},d=o(),e=utils.getStepTarget(d))return void c(f);if(!e){if(utils.invokeEventCallbacks("error"),k[f]=!0,n("skipIfNoElement"))return void r(1,c);f=-1,c(f)}},v=function(a){function b(){d.show(),utils.invokeEventCallbacks("show",c.onShow)}var c=e.steps[a],d=m(),g=utils.getStepTarget(c);f!==a&&o().nextOnTargetClick&&utils.removeEvtListener(utils.getStepTarget(o()),"click",p),f=a,d.hide(!1),d.render(c,a,function(a){a?q(b):b(),c.nextOnTargetClick&&utils.addEvtListener(g,"click",p)}),w()},w=function(){var a=e.id+":"+f,b=winHopscotch.getSkippedStepsIndexes();b&&b.length>0&&(a+=":"+b.join(",")),utils.setState(n("cookieName"),a,1)},x=function(a){a&&this.configure(a)};this.getCalloutManager=function(){return typeof c===undefinedStr&&(c=new HopscotchCalloutManager),c},this.startTour=function(a,b){var c,d,f={},i=this;if(e||(e=a,t.call(this,a)),typeof b!==undefinedStr){if(b>=e.steps.length)throw"Specified step number out of bounds.";d=b}if(!utils.documentIsReady())return waitingToStart=!0,this;if("undefined"==typeof d&&e.id===g&&typeof h!==undefinedStr){if(d=h,l.length>0)for(var j=0,k=l.length;k>j;j++)f[l[j]]=!0}else d||(d=0);return u(d,f,function(a){var b=-1!==a&&utils.getStepTarget(e.steps[a]);return b?(utils.invokeEventCallbacks("start"),c=m(),c.hide(!1),i.isActive=!0,void(utils.getStepTarget(o())?i.showStep(a):(utils.invokeEventCallbacks("error"),n("skipIfNoElement")&&i.nextStep(!1)))):void i.endTour(!1,!1)}),this},this.showStep=function(a){var b=e.steps[a];return b.delay?setTimeout(function(){v(a)},b.delay):v(a),this},this.prevStep=function(a){return s.call(this,a,-1),this},this.nextStep=function(a){return s.call(this,a,1),this},this.endTour=function(a,b){var c,d=m();return a=utils.valOrDefault(a,!0),b=utils.valOrDefault(b,!0),e&&(c=o(),c&&c.nextOnTargetClick&&utils.removeEvtListener(utils.getStepTarget(c),"click",p)),f=0,h=void 0,d.hide(),a&&utils.clearState(n("cookieName")),this.isActive&&(this.isActive=!1,e&&b&&utils.invokeEventCallbacks("end")),this.removeCallbacks(null,!0),this.resetDefaultOptions(),e=null,this},this.getCurrTour=function(){return e},this.getCurrTarget=function(){return utils.getStepTarget(o())},this.getCurrStepNum=function(){return f},this.getSkippedStepsIndexes=function(){var a,b=[];for(a in k)b.push(a);return b},this.refreshBubblePosition=function(){var a=o();return a&&m().setPosition(a),this.getCalloutManager().refreshCalloutPositions(),this},this.listen=function(a,b,c){return a&&callbacks[a].push({cb:b,fromTour:c}),this},this.unlisten=function(a,b){var c,d,e=callbacks[a];for(c=0,d=e.length;d>c;++c)e[c]===b&&e.splice(c,1);return this},this.removeCallbacks=function(a,b){var c,d,e,f;for(f in callbacks)if(!a||a===f)if(b)for(c=callbacks[f],d=0,e=c.length;e>d;++d)c[d].fromTour&&(c.splice(d--,1),--e);else callbacks[f]=[];return this},this.registerHelper=function(a,b){"string"==typeof a&&"function"==typeof b&&(helpers[a]=b)},this.unregisterHelper=function(a){helpers[a]=null},this.invokeHelper=function(a){var b,c,d=[];for(b=1,c=arguments.length;c>b;++b)d.push(arguments[b]);helpers[a]&&helpers[a].call(null,d)},this.setCookieName=function(a){return d.cookieName=a,this},this.resetDefaultOptions=function(){return d={},this},this.resetDefaultI18N=function(){return customI18N={},this},this.getState=function(){return utils.getState(n("cookieName"))},i=function(a,b){var c,e,f,g,h=["next","prev","start","end","show","error","close"];for(d||this.resetDefaultOptions(),utils.extend(d,a),a&&utils.extend(customI18N,a.i18n),f=0,g=h.length;g>f;++f)e="on"+h[f].charAt(0).toUpperCase()+h[f].substring(1),a[e]&&this.listen(h[f],a[e],b);return c=m(!0),this},this.configure=function(a){return i.call(this,a,!1)},this.setRenderer=function(a){var b=typeof a;return"string"===b?(templateToUse=a,customRenderer=void 0):"function"===b&&(customRenderer=a),this},this.setEscaper=function(a){return"function"==typeof a&&(customEscape=a),this},x.call(this,a)},winHopscotch=new Hopscotch,context[namespace]=winHopscotch,function(){var _={};_.escape=function(a){return customEscape?customEscape(a):null==a?"":(""+a).replace(new RegExp("[&<>\"']","g"),function(a){return"&"==a?"&":"<"==a?"<":">"==a?">":'"'==a?""":"'"==a?"'":void 0})},this.hopscotch=this.hopscotch||{},this.hopscotch.templates=this.hopscotch.templates||{},this.hopscotch.templates.bubble_default=function(obj){function optEscape(a,b){return b?_.escape(a):a}obj||(obj={});{var __t,__p="";_.escape,Array.prototype.join}with(obj)__p+='\n
\n ',tour.isTour&&(__p+=''+(null==(__t=i18n.stepNum)?"":__t)+""),__p+='\n
\n ',""!==step.title&&(__p+='

'+(null==(__t=optEscape(step.title,tour.unsafe))?"":__t)+"

"),__p+="\n ",""!==step.content&&(__p+='
'+(null==(__t=optEscape(step.content,tour.unsafe))?"":__t)+"
"),__p+='\n
\n
\n ',buttons.showPrev&&(__p+='"),__p+="\n ",buttons.showCTA&&(__p+='"),__p+="\n ",buttons.showNext&&(__p+='"),__p+="\n
\n ",buttons.showClose&&(__p+=''+(null==(__t=i18n.closeTooltip)?"":__t)+""),__p+='\n
\n
\n
\n
\n
';return __p}}())}(window,"hopscotch"); \ No newline at end of file diff --git a/package.json b/package.json index cebefa05..8076498b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hopscotch", - "version": "0.2.2", + "version": "0.2.3", "description": "A framework to make it easy for developers to add product tours to their pages.", "main": "Gruntfile.js", "directories": {