diff --git a/bootstro.js b/bootstro.js index b95ee02..94c42be 100644 --- a/bootstro.js +++ b/bootstro.js @@ -6,10 +6,9 @@ * Revealing Module Pattern from * http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/ * - * Bootstrap popover variable width workaround + * Bootstrap popover variable width * http://stackoverflow.com/questions/10028218/twitter-bootstrap-popovers-multiple-widths-and-other-css-properties - * - * Lisence : MIT . See accompanied LICENSE file. + * */ $(document).ready(function(){ @@ -19,38 +18,143 @@ $(document).ready(function(){ var count; var popovers = []; //contains array of the popovers data var activeIndex = null; //index of active item + var defaultOrder = true; + // if true the DOM order is followed. it is changed to false when step index is given for atleast one element. + // refer line #322 var defaults = { - nextButton : '', - prevButton : '', - finishButton : '', + nextButtonText : 'Next »', //will be wrapped with button as below + //nextButton : '', + prevButtonText : '« Prev', + //prevButton : '', + finishButtonText : ' Ok I got it, get back to the site', + //finishButton : '', stopOnBackdropClick : true, - stopOnEsc : true + stopOnEsc : true, + + //onComplete : function(params){} //params = {idx : activeIndex} + //onExit : function(params){} //params = {idx : activeIndex} + //onStep : function(params){} //params = {idx : activeIndex, direction : [next|prev]} + //url : String // ajaxed url to get show data from + + margin : 100, //if the currently shown element's margin is less than this value + // the element should be scrolled so that i can be viewed properly. This is useful + // for sites which have fixed top/bottom nav bar }; var settings; //===================PRIVATE METHODS====================== + //http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling + function is_entirely_visible($elem) + { + var docViewTop = $(window).scrollTop(); + var docViewBottom = docViewTop + $(window).height(); + + var elemTop = $elem.offset().top; + var elemBottom = elemTop + $elem.height(); + + return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom) + && (elemBottom <= docViewBottom) && (elemTop >= docViewTop) ); + } + //add the nav buttons to the popover content; function add_nav_btn(content, i) { - count = $elements.size(); + var $el = get_element(i); + var nextButton, prevButton, finishButton; + content = content + "
"; + if ($el.attr('data-bootstro-nextButton')) + { + nextButton = $el.attr('data-bootstro-nextButton'); + } + else if ( $el.attr('data-bootstro-nextButtonText') ) + { + nextButton = ''; + } + else + { + if (typeof settings.nextButton != 'undefined' /*&& settings.nextButton != ''*/) + nextButton = settings.nextButton; + else + nextButton = ''; + } + + if ($el.attr('data-bootstro-prevButton')) + { + prevButton = $el.attr('data-bootstro-prevButton'); + } + else if ( $el.attr('data-bootstro-prevButtonText') ) + { + prevButton = ''; + } + else + { + if (typeof settings.prevButton != 'undefined' /*&& settings.prevButton != ''*/) + prevButton = settings.prevButton; + else + prevButton = ''; + } + + if ($el.attr('data-bootstro-finishButton')) + { + finishButton = $el.attr('data-bootstro-finishButton'); + } + else if ( $el.attr('data-bootstro-finishButtonText') ) + { + finishButton = ''; + } + else + { + if (typeof settings.finishButton != 'undefined' /*&& settings.finishButton != ''*/) + finishButton = settings.finishButton; + else + finishButton = ''; + } + + if (count != 1) { if (i == 0) - content = content + settings.nextButton; + content = content + nextButton; else if (i == count -1 ) - content = content + settings.prevButton; + content = content + prevButton; else - content = content + settings.nextButton + settings.prevButton + content = content + nextButton + prevButton } content = content + '
'; - content = content +'
' + settings.finishButton + '
'; + content = content +'
' + finishButton + '
'; return content; } + + nextIndex = function(indexToTry){ + closestIndex = null + // loop and find the next available value less than or equal to the indexToTry + $.each(indexes, function(){ + if (parseInt(this) >= parseInt(indexToTry)) { + closestIndex = this; + return false; + } + }); + return closestIndex; + } + + prevIndex = function(indexToTry){ + closestIndex = null + reverseIndexes = $.makeArray(indexes).reverse() + // loop and find the previous available value less than or equal to the indexToTry + $.each(reverseIndexes, function(){ + if (parseInt(this) <= parseInt(indexToTry)) { + closestIndex = this; + return false; + } + }); + return closestIndex; + } + //get the element to intro at stack i get_element = function(i) @@ -72,16 +176,20 @@ $(document).ready(function(){ */ } } + + getStepCount = function(i){ + return defaultOrder ? i : $.inArray(parseInt(i), indexes) + } get_popup = function(i) { var p = {}; - $el = get_element(i); + var $el = get_element(i); //p.selector = selector; var t = ''; if (count > 1) { - t = "" + (i +1) + "/" + count + ""; + t = "" + (getStepCount(i)+1) + "/" + count + ""; } p.title = $el.attr('data-bootstro-title') || ''; if (p.title != '' && t != '') @@ -120,10 +228,10 @@ $(document).ready(function(){ //destroy popover at stack index i bootstro.destroy_popover = function(i) { - i = i || 0; + var i = i || 0; if (i != 'all') { - $el = get_element(i);//$elements.eq(i); + var $el = get_element(i);//$elements.eq(i); $el.popover('destroy').removeClass('bootstro-highlight'); } /* @@ -143,9 +251,10 @@ $(document).ready(function(){ bootstro.destroy_popover(activeIndex); bootstro.unbind(); $("div.bootstro-backdrop").remove(); + if (typeof settings.onExit == 'function') + settings.onExit.call(this,{idx : getStepCount(activeIndex)}); }; - //go to the popover number idx starting from 0 bootstro.go_to = function(idx) { @@ -153,55 +262,130 @@ $(document).ready(function(){ bootstro.destroy_popover(activeIndex); if (count != 0) { - p = get_popup(idx); - $el = get_element(idx); + var p = get_popup(idx); + var $el = get_element(idx); $el.popover(p).popover('show'); - min = Math.min($(".popover.in").offset().top, $el.offset().top); - $('html,body').animate({ - scrollTop: min - 20}, - 'slow'); + //scroll if neccessary + var docviewTop = $(window).scrollTop(); + var top = Math.min($(".popover.in").offset().top, $el.offset().top); + + //distance between docviewTop & min. + var topDistance = top - docviewTop; + + if (topDistance < settings.margin) //the element too up above + $('html,body').animate({ + scrollTop: top - settings.margin}, + 'slow'); + else if(!is_entirely_visible($(".popover.in")) || !is_entirely_visible($el)) + //the element is too down below + $('html,body').animate({ + scrollTop: top - settings.margin}, + 'slow'); // html $el.addClass('bootstro-highlight'); activeIndex = idx; } }; + bootstro.next = function() { - if (activeIndex + 1 == count) + indexToEnd = defaultOrder ? count-1 : indexes.get(-1) + if (activeIndex == indexToEnd) { - alert('End of introduction'); + if (typeof settings.onComplete == 'function') + settings.onComplete.call(this, {idx : getStepCount(activeIndex)});// } else - bootstro.go_to(activeIndex + 1); + { + // bootstro.go_to(activeIndex + 1); + defaultOrder ? bootstro.go_to(activeIndex + 1) : bootstro.go_to(nextIndex(activeIndex + 1)); + if (typeof settings.onStep == 'function') + settings.onStep.call(this, {idx : activeIndex, direction : 'next'});// + } }; bootstro.prev = function() { - if (activeIndex == 0) + indexToEnd = defaultOrder ? 0 : indexes.get(0) + if (activeIndex == indexToEnd) { - alert('At start of intros'); + /* + if (typeof settings.onRewind == 'function') + settings.onRewind.call(this, {idx : activeIndex, direction : 'prev'});// + */ + } + else + { + defaultOrder ? bootstro.go_to(activeIndex - 1) : bootstro.go_to(prevIndex(activeIndex - 1)); + if (typeof settings.onStep == 'function') + settings.onStep.call(this, {idx : activeIndex, direction : 'prev'});// + } + }; + + bootstro._start = function(selector) + { + selector = selector || '.bootstro'; + + $elements = $(selector); + count = $elements.size(); + if (count > 0 && $('div.bootstro-backdrop').length === 0) + { + // Prevents multiple copies + $('
').appendTo('body'); + bootstro.bind(); + + indexes = $elements.map(function(){ return parseInt($(this).attr('data-bootstro-step')) }) + defaultOrder = $.grep(indexes, function(x){ return !(isNaN(x)) }).length == 0 ? true : false + // set defaultOrder to true inorder to follow DOM order when all the elements are not provided with data-bootstro-step attr + + if (!defaultOrder) + indexes = indexes.sort(function(a, b){ return a - b }) + + defaultOrder ? bootstro.go_to(0) : bootstro.go_to(nextIndex(0)); + // bootstro.go_to(0); } - else - bootstro.go_to(activeIndex -1); }; bootstro.start = function(selector, options) { - settings = $.extend(true, {}, defaults); //deep copy - //TODO: if options specifies a URL, get the intro text array from URL $.extend(settings, options || {}); + //if options specifies a URL, get the intro configuration from URL via ajax + if (typeof settings.url != 'undefined') + { + //get config from ajax + $.ajax({ + url : settings.url, + success : function(data){ + if (data.success) + { + //result is an array of {selector:'','title':'','width', ...} + var popover = data.result; + //console.log(popover); + var selectorArr = []; + $.each(popover, function(t,e){ + //only deal with the visible element + //build the selector + $.each(e, function(j, attr){ + $(e.selector).attr('data-bootstro-' + j, attr); + }); + if ($(e.selector).is(":visible")) + selectorArr.push(e.selector); + }); + selector = selectorArr.join(","); + bootstro._start(selector); + } + } + }); + } + else + { + bootstro._start(selector); + } - selector = selector || '.bootstro'; - $elements = $(selector); - count = $elements.size(); - - $('
').appendTo('body'); - bootstro.bind(); - bootstro.go_to(0); }; //bind the nav buttons click event @@ -253,4 +437,4 @@ $(document).ready(function(){ } }( window.bootstro = window.bootstro || {}, jQuery )); -}); +}); \ No newline at end of file diff --git a/bootstro.json b/bootstro.json new file mode 100644 index 0000000..98cdd92 --- /dev/null +++ b/bootstro.json @@ -0,0 +1 @@ +{"success":true,"result":[{"selector":"#demo_stopOn","title":"Ajaxed title from server","content":"I was found because I have selector=#demo_stopOn","width":"400px","placement":"right"},{"selector":"#demo_ajax","title":"Ajaxed Title 2","content":"I was found because I have selector=#demo_ajax","width":"400px","placement":"right"}]} diff --git a/bootstro.min.js b/bootstro.min.js index e1c308c..c6861c0 100644 --- a/bootstro.min.js +++ b/bootstro.min.js @@ -1 +1 @@ -$(document).ready(function(){(function(e,t,n){function f(e,t){i=r.size();e=e+"
";if(i!=1){if(t==0)e=e+a.nextButton;else if(t==i-1)e=e+a.prevButton;else e=e+a.nextButton+a.prevButton}e=e+"
";e=e+'
'+a.finishButton+"
";return e}var r;var i;var s=[];var o=null;var u={nextButton:'',prevButton:'',finishButton:'',stopOnBackdropClick:true,stopOnEsc:true};var a;get_element=function(e){if(r.filter("[data-bootstro-step="+e+"]").size()>0)return r.filter("[data-bootstro-step="+e+"]");else{return r.eq(e)}};get_popup=function(e){var t={};$el=get_element(e);var n="";if(i>1){n=""+(e+1)+"/"+i+""}t.title=$el.attr("data-bootstro-title")||"";if(t.title!=""&&n!="")t.title=n+" - "+t.title;else if(t.title=="")t.title=n;t.content=$el.attr("data-bootstro-content")||"";t.content=f(t.content,e);t.placement=$el.attr("data-bootstro-placement")||"top";var r="";if($el.attr("data-bootstro-width")){t.width=$el.attr("data-bootstro-width");r=r+"width:"+$el.attr("data-bootstro-width")+";"}if($el.attr("data-bootstro-height")){t.height=$el.attr("data-bootstro-height");r=r+"height:"+$el.attr("data-bootstro-height")+";"}t.trigger="manual";t.html=$el.attr("data-bootstro-html")||"top";t.template='

'+"
";return t};e.destroy_popover=function(e){e=e||0;if(e!="all"){$el=get_element(e);$el.popover("destroy").removeClass("bootstro-highlight")}};e.stop=function(){e.destroy_popover(o);e.unbind();t("div.bootstro-backdrop").remove()};e.go_to=function(n){e.destroy_popover(o);if(i!=0){p=get_popup(n);$el=get_element(n);$el.popover(p).popover("show");min=Math.min(t(".popover.in").offset().top,$el.offset().top);t("html,body").animate({scrollTop:min-20},"slow");$el.addClass("bootstro-highlight");o=n}};e.next=function(){if(o+1==i){alert("End of introduction")}else e.go_to(o+1)};e.prev=function(){if(o==0){alert("At start of intros")}else e.go_to(o-1)};e.start=function(n,s){a=t.extend(true,{},u);t.extend(a,s||{});n=n||".bootstro";r=t(n);i=r.size();t('
').appendTo("body");e.bind();e.go_to(0)};e.bind=function(){e.unbind();t("html").on("click.bootstro",".bootstro-next-btn",function(t){e.next();t.preventDefault();return false});t("html").on("click.bootstro",".bootstro-prev-btn",function(t){e.prev();t.preventDefault();return false});t("html").on("click.bootstro",".bootstro-finish-btn",function(t){e.stop()});if(a.stopOnBackdropClick){t("html").on("click.bootstro","div.bootstro-backdrop",function(n){if(t(n.target).hasClass("bootstro-backdrop"))e.stop()})}t(document).on("keydown.bootstro",function(t){var n=t.keyCode?t.keyCode:t.which;if(n==39||n==40)e.next();else if(n==37||n==38)e.prev();else if(n==27&&a.stopOnEsc)e.stop()})};e.unbind=function(){t("html").unbind("click.bootstro");t(document).unbind("keydown.bootstro")}})(window.bootstro=window.bootstro||{},jQuery)}) +$(document).ready(function(){(function(e,t,n){function f(e){var n=t(window).scrollTop();var r=n+t(window).height();var i=e.offset().top;var s=i+e.height();return s>=n&&i<=r&&s<=r&&i>=n}function l(e,t){var n=get_element(t);var r,s,o;e=e+"
";if(n.attr("data-bootstro-nextButton")){r=n.attr("data-bootstro-nextButton")}else if(n.attr("data-bootstro-nextButtonText")){r='"}else{if(typeof a.nextButton!="undefined")r=a.nextButton;else r='"}if(n.attr("data-bootstro-prevButton")){s=n.attr("data-bootstro-prevButton")}else if(n.attr("data-bootstro-prevButtonText")){s='"}else{if(typeof a.prevButton!="undefined")s=a.prevButton;else s='"}if(n.attr("data-bootstro-finishButton")){o=n.attr("data-bootstro-finishButton")}else if(n.attr("data-bootstro-finishButtonText")){o='"}else{if(typeof a.finishButton!="undefined")o=a.finishButton;else o='"}if(i!=1){if(t==0)e=e+r;else if(t==i-1)e=e+s;else e=e+r+s}e=e+"
";e=e+'
'+o+"
";return e}var r;var i;var s=[];var o=null;var u={nextButtonText:"Next »",prevButtonText:"« Prev",finishButtonText:' Ok I got it, get back to the site',stopOnBackdropClick:true,stopOnEsc:true,margin:100};var a;get_element=function(e){if(r.filter("[data-bootstro-step="+e+"]").size()>0)return r.filter("[data-bootstro-step="+e+"]");else{return r.eq(e)}};get_popup=function(e){var t={};var n=get_element(e);var r="";if(i>1){r=""+(e+1)+"/"+i+""}t.title=n.attr("data-bootstro-title")||"";if(t.title!=""&&r!="")t.title=r+" - "+t.title;else if(t.title=="")t.title=r;t.content=n.attr("data-bootstro-content")||"";t.content=l(t.content,e);t.placement=n.attr("data-bootstro-placement")||"top";var s="";if(n.attr("data-bootstro-width")){t.width=n.attr("data-bootstro-width");s=s+"width:"+n.attr("data-bootstro-width")+";"}if(n.attr("data-bootstro-height")){t.height=n.attr("data-bootstro-height");s=s+"height:"+n.attr("data-bootstro-height")+";"}t.trigger="manual";t.html=n.attr("data-bootstro-html")||"top";t.template='

'+"
";return t};e.destroy_popover=function(e){var e=e||0;if(e!="all"){var t=get_element(e);t.popover("destroy").removeClass("bootstro-highlight")}};e.stop=function(){e.destroy_popover(o);e.unbind();t("div.bootstro-backdrop").remove();if(typeof a.onExit=="function")a.onExit.call(this,{idx:o})};e.go_to=function(n){e.destroy_popover(o);if(i!=0){var r=get_popup(n);var s=get_element(n);s.popover(r).popover("show");var u=t(window).scrollTop();var l=Math.min(t(".popover.in").offset().top,s.offset().top);var c=l-u;if(c0&&t("div.bootstro-backdrop").length===0){t('
').appendTo("body");e.bind();e.go_to(0)}};e.start=function(n,r){a=t.extend(true,{},u);t.extend(a,r||{});if(typeof a.url!="undefined"){t.ajax({url:a.url,success:function(r){if(r.success){var i=r.result;var s=[];t.each(i,function(e,n){t.each(n,function(e,r){t(n.selector).attr("data-bootstro-"+e,r)});if(t(n.selector).is(":visible"))s.push(n.selector)});n=s.join(",");e._start(n)}}})}else{e._start(n)}};e.bind=function(){e.unbind();t("html").on("click.bootstro",".bootstro-next-btn",function(t){e.next();t.preventDefault();return false});t("html").on("click.bootstro",".bootstro-prev-btn",function(t){e.prev();t.preventDefault();return false});t("html").on("click.bootstro",".bootstro-finish-btn",function(t){e.stop()});if(a.stopOnBackdropClick){t("html").on("click.bootstro","div.bootstro-backdrop",function(n){if(t(n.target).hasClass("bootstro-backdrop"))e.stop()})}t(document).on("keydown.bootstro",function(t){var n=t.keyCode?t.keyCode:t.which;if(n==39||n==40)e.next();else if(n==37||n==38)e.prev();else if(n==27&&a.stopOnEsc)e.stop()})};e.unbind=function(){t("html").unbind("click.bootstro");t(document).unbind("keydown.bootstro")}})(window.bootstro=window.bootstro||{},jQuery)})