added hooks and dependencies for tutorial flow

This commit is contained in:
Kev Zettler 2011-07-06 22:35:15 -07:00
parent e78726caa4
commit a342f7e6b1
5 changed files with 486 additions and 1 deletions

View File

@ -11,7 +11,7 @@
- if can? :create, Page
- content_for :buttons do
= admin_button_tag :new, new_admin_page_url, :class => 'new'
= admin_button_tag :new, new_admin_page_url, :class => 'new', :id => "newpage"
%p!= t('.help')

View File

@ -9,6 +9,8 @@
%span= '|'
= link_to t('.switch'), '#', :id => 'sites-picker-link'
%span= '|'
= link_to 'Help', '#guider=help', :id => "tutorial"
%span= '|'
= link_to t('.logout'), destroy_admin_session_url, :confirm => t('admin.messages.confirm')

View File

@ -0,0 +1,322 @@
/**
* guiders.js
*
* version 1.1.0
*
* Developed at Optimizely. (www.optimizely.com)
* We make A/B testing you'll actually use.
*
* Released under the Apache License 2.0.
* www.apache.org/licenses/LICENSE-2.0.html
*
* Questions about Guiders or Optimizely?
* Email us at jeff+pickhardt@optimizely.com or hello@optimizely.com.
*
* Enjoy!
*/
var guiders = (function($){
var guiders = {
version: "1.1.0",
_defaultSettings: {
attachTo: null,
buttons: [{name: "Close"}],
buttonCustomHTML: "",
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.",
isHashable: true,
onShow: null,
overlay: false,
position: 0, // 1-12 follows an analog clock, 0 means centered
title: "Sample title goes here",
width: 400
},
_htmlSkeleton: [
"<div class='guider'>",
" <div class='guider_content'>",
" <h1 class='guider_title'></h1>",
" <p class='guider_description'></p>",
" <div class='guider_buttons'>",
" </div>",
" </div>",
" <div class='guider_arrow'>",
" </div>",
"</div>"
].join(""),
_arrowSize: 42, // = arrow's width and height
_guiders: {},
_currentGuiderID: null,
_lastCreatedGuiderID: null,
_addButtons: function(myGuider) {
// Add buttons
var guiderButtonsContainer = myGuider.elem.find(".guider_buttons");
for (var i = myGuider.buttons.length-1; i >= 0; i--) {
var thisButton = myGuider.buttons[i];
var thisButtonElem = $("<a></a>", {
"class" : "guider_button",
"text" : thisButton.name });
if (typeof thisButton.classString !== "undefined" && thisButton.classString !== null) {
thisButtonElem.addClass(thisButton.classString);
}
guiderButtonsContainer.append(thisButtonElem);
if (thisButton.onclick) {
thisButtonElem.bind("click", thisButton.onclick);
} else if (!thisButton.onclick && thisButton.name.toLowerCase() === "close") {
thisButtonElem.bind("click", function() { guiders.hideAll(); });
} else if (!thisButton.onclick && thisButton.name.toLowerCase() === "next") {
thisButtonElem.bind("click", function() { guiders.next(); });
}
}
if (myGuider.buttonCustomHTML !== "") {
var myCustomHTML = $(myGuider.buttonCustomHTML);
myGuider.elem.find(".guider_buttons").append(myCustomHTML);
}
},
_attach: function(myGuider) {
if (typeof myGuider.attachTo === "undefined" || myGuider === null) {
return;
}
var myHeight = myGuider.elem.innerHeight();
var myWidth = myGuider.elem.innerWidth();
if (myGuider.position === 0) {
myGuider.elem.css("position", "absolute");
myGuider.elem.css("top", ($(window).height() - myHeight) / 3 + $(window).scrollTop() + "px");
myGuider.elem.css("left", ($(window).width() - myWidth) / 2 + $(window).scrollLeft() + "px");
return;
}
myGuider.attachTo = $(myGuider.attachTo);
var base = myGuider.attachTo.offset();
var attachToHeight = myGuider.attachTo.innerHeight();
var attachToWidth = myGuider.attachTo.innerWidth();
var top = base.top;
var left = base.left;
var bufferOffset = 0.9 * guiders._arrowSize;
var offsetMap = { // Follows the form: [height, width]
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[myGuider.position];
top += offset[0];
left += offset[1];
myGuider.elem.css({
"position":"absolute",
"top": top,
"left": left
});
},
_guiderById: function(id) {
if (typeof guiders._guiders[id] === "undefined") {
throw "Cannot find guider with id " + id;
}
return guiders._guiders[id];
},
_showOverlay: function() {
$("#guider_overlay").fadeIn("fast");
},
_hideOverlay: function() {
$("#guider_overlay").fadeOut("fast");
},
_initializeOverlay: function() {
if ($("#guider_overlay").length === 0) {
$("<div id=\"guider_overlay\"></div>").hide().appendTo("body");
}
},
_styleArrow: function(myGuider) {
var position = myGuider.position || 0;
if (!position) {
return;
}
var myGuiderArrow = $(myGuider.elem.find(".guider_arrow"));
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"
};
myGuiderArrow.addClass(newClass[position]);
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]
};
var position = positionMap[myGuider.position];
myGuiderArrow.css(position[0], position[1] + "px");
},
/**
* 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');"
*/
_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);
}
}
},
next: function() {
var currentGuider = guiders._guiders[guiders._currentGuiderID];
if (typeof currentGuider === "undefined") {
return;
}
var nextGuiderId = currentGuider.next || null;
if (nextGuiderId !== null && nextGuiderId !== "") {
var myGuider = guiders._guiderById(nextGuiderId);
var omitHidingOverlay = myGuider.overlay ? true : false;
guiders.hideAll(omitHidingOverlay);
guiders.show(nextGuiderId);
}
},
createGuider: function(passedSettings) {
if (passedSettings === null || passedSettings === undefined) {
passedSettings = {};
}
// Extend those settings with passedSettings
myGuider = $.extend({}, guiders._defaultSettings, passedSettings);
myGuider.id = myGuider.id || String(Math.floor(Math.random() * 1000));
var guiderElement = $(guiders._htmlSkeleton);
myGuider.elem = guiderElement;
myGuider.elem.css("width", myGuider.width + "px");
guiderElement.find("h1.guider_title").html(myGuider.title);
guiderElement.find("p.guider_description").html(myGuider.description);
guiders._addButtons(myGuider);
guiderElement.hide();
guiderElement.appendTo("body");
guiderElement.attr("id", myGuider.id);
// Ensure myGuider.attachTo is a jQuery element.
if (typeof myGuider.attachTo !== "undefined" && myGuider !== null) {
guiders._attach(myGuider);
guiders._styleArrow(myGuider);
}
guiders._initializeOverlay();
guiders._guiders[myGuider.id] = myGuider;
guiders._lastCreatedGuiderID = myGuider.id;
/**
* 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);
}
return guiders;
},
hideAll: function(omitHidingOverlay) {
$(".guider").fadeOut("fast");
if (typeof omitHidingOverlay !== "undefined" && omitHidingOverlay === true) {
// do nothing for now
} else {
guiders._hideOverlay();
}
return guiders;
},
show: function(id) {
if (!id && guiders._lastCreatedGuiderID) {
id = guiders._lastCreatedGuiderID;
}
var myGuider = guiders._guiderById(id);
if (myGuider.overlay) {
guiders._showOverlay();
}
guiders._attach(myGuider);
// You can use an onShow function to take some action before the guider is shown.
if (myGuider.onShow) {
myGuider.onShow(myGuider);
}
myGuider.elem.fadeIn("fast");
var windowHeight = $(window).height();
var scrollHeight = $(window).scrollTop();
var guiderOffset = myGuider.elem.offset();
var guiderElemHeight = myGuider.elem.height();
if (guiderOffset.top - scrollHeight < 0 ||
guiderOffset.top + guiderElemHeight + 40 > scrollHeight + windowHeight) {
window.scrollTo(0, Math.max(guiderOffset.top + (guiderElemHeight / 2) - (windowHeight / 2), 0));
}
guiders._currentGuiderID = id;
return guiders;
}
};
return guiders;
}).call(this, jQuery);

View File

@ -0,0 +1,43 @@
$(document).ready(function(){
guiders.createGuider({
description: "Welcome to LocomotiveCMS, <br /><br /> This guide will help you get up and running with locomotive",
buttons: [{name: "Quit Guide", onclick: guiders.hideAll},
{name: "Continue", onclick: guiders.next}],
id: "welcome",
next: "help",
overlay: true,
title: "Welcome to Locomotive CMS"
});
guiders.createGuider({
attachTo: "#tutorial",
buttons: [{name: "Close", onclick: guiders.hideAll}],
description: "How To:<ul>\
<li><a id='new_page_tutorial' href=\"/admin/pages#guider=newpage\">Make a new Page</a></li>\
<li><a href=\"\">Edit a Page</a></li></ul>",
id: "help",
position: 6,
width: 200,
title: "Locomotive Tutorials",
});
$('#new_page_tutorial').click(function(){
guiders.hideAll();
guiders.show('newpage');
return false;
});
guiders.createGuider({
attachTo: "#newpage",
buttons: [{name: "Close", onclick: guiders.hideAll}],
description: "Click above to make a new page",
id: "newpage",
position: 6,
width: 200,
title: "Make a new page",
});
});

View File

@ -0,0 +1,118 @@
.guider {
background: #FFF;
border: 1px solid #666;
font-family: arial;
position: absolute;
outline: none;
z-index: 100000005 !important;
padding: 4px 12px;
width: 500px;
z-index: 100;
/* Shadow */
-moz-box-shadow: 0 0px 8px #111;
-webkit-box-shadow: 0 0px 8px #111;
box-shadow: 0 0px 8px #111;
/* End shadow */
/* Rounded corners */
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
border-radius: 4px;
/* End rounded corners */
}
.guider_buttons {
height: 36px;
position: relative;
width: 100%;
}
.guider_content {
position: relative;
}
.guider_content h1 {
color: #1054AA;
font-size: 21px;
}
.guider_content p {
color: #333;
font-size: 13px;
}
.guider_button {
background: -moz-linear-gradient(top, #5CA9FF 0%, #3D79C3 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #5CA9FF), color-stop(100%, #3D79C3));
background-color: #4A95E0; /* overruled by background gradient, in browsers where they exist */
border: solid 1px #4B5D7E;
color: #FFF;
cursor: pointer;
display: inline-block;
float: right;
font-size: 75%;
font-weight: bold;
margin-left: 6px;
min-width: 40px;
padding: 3px 5px;
text-align: center;
text-decoration: none;
/* Rounded corners */
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
border-radius: 2px;
/* End rounded corners */
}
#guider_overlay {
background-color: #000;
width: 100%;
height: 100%;
position: fixed;
top: 0px;
left: 0px;
opacity: 0.5;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
filter: alpha(opacity=50);
z-index: 10;
}
.guider_arrow {
width: 42px;
height: 42px;
position: absolute;
display: none;
background-repeat: no-repeat;
z-index: 100000006 !important;
/**
* For optimization, the arrows image is inlined in the css below.
*
* To use your own arrows image, replace this background-image with your own arrows.
* It should have four arrows, top, right, left, and down.
*/
background-image: url(data:image/png;base64,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);
*background-image: url('guider_arrows.png');
}
.guider_arrow_right {
display: block;
background-position: 0px 0px;
right: -42px;
}
.guider_arrow_down {
display: block;
background-position: 0px -42px;
bottom: -42px;
}
.guider_arrow_up {
display: block;
background-position: 0px -126px;
top: -42px;
}
.guider_arrow_left {
display: block;
background-position: 0px -84px;
left: -42px;
}