remove "Tour" functionality. nothing used it.
closes: CNVS-28669 refs: CNVS-28781 Back in 2013 we came up with an awesome idea to have these "Tours" to introduce new features and stuff. It was a great idea but we don't use it anymore. it has been commented out so it doesn't show up in the styleguide and all but one (see below) were commented out of config/tours.rb. so in the interest of not letting code hang around that we don't use, I'm removing it (unless anyone is opposed or has a good reason to leave it). If we want to do it in the future, we can just add it back, because yay Git! There was one place in quizzes that was still trying to use a tour. if you go to create a quiz and edit a question and then pick another option as the correct answer for a multiple choice question it would try to show a tour telling you that you could regrade all the existing submissions. but in reality it just threw a javascript error and the tour never popped up. So even though it was still in the code, it didn't work. Since no one noticed that it stopped working, I'm assuming we don't need it any more. Quizzes team and quizzes product/QA, will you confirm this is ok? test plan: * no tours should show up anywhere in canvas * read that paragraph above about the "regrade existing" thing in quizzes. * try that feature, it should work but no tour should show up and no error should occur in the console Change-Id: Ib2d6bbb80f93fd7ca0a33d20c1f57ee16e7027ea Reviewed-on: https://gerrit.instructure.com/76875 Tested-by: Jenkins Reviewed-by: Jennifer Stern <jstern@instructure.com> QA-Review: Michael Hargiss <mhargiss@instructure.com> Product-Review: Ryan Shaw <ryan@instructure.com>
This commit is contained in:
parent
2876c583e3
commit
80a7fb0941
|
@ -678,14 +678,6 @@
|
|||
"codepoint": 61853,
|
||||
"source": "public/fonts/icons/toggle-right.svg"
|
||||
},
|
||||
"tour-info": {
|
||||
"codepoint": 61854,
|
||||
"source": "public/fonts/icons/tour-info.svg"
|
||||
},
|
||||
"tour-step-counter": {
|
||||
"codepoint": 61855,
|
||||
"source": "public/fonts/icons/tour-step-counter.svg"
|
||||
},
|
||||
"trash": {
|
||||
"codepoint": 61856,
|
||||
"source": "public/fonts/icons/trash.svg"
|
||||
|
|
|
@ -5,7 +5,6 @@ require [
|
|||
# true modules that we manage in this file
|
||||
'Backbone'
|
||||
'compiled/helpDialog'
|
||||
'compiled/tours'
|
||||
|
||||
# modules that do their own thing on every page that simply need to
|
||||
# be required
|
||||
|
@ -47,9 +46,8 @@ require [
|
|||
'vendor/jquery.pageless'
|
||||
'vendor/jquery.scrollTo'
|
||||
'compiled/badge_counts'
|
||||
], ($, _, Backbone, helpDialog, tours) ->
|
||||
], ($, _, Backbone, helpDialog) ->
|
||||
helpDialog.initTriggers()
|
||||
tours.init()
|
||||
|
||||
$('#skip_navigation_link').on 'click', ->
|
||||
$($(this).attr('href')).attr('tabindex', -1).focus()
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
define ['require'], (require) ->
|
||||
|
||||
init: ->
|
||||
return unless ENV.TOURS
|
||||
for tourName in ENV.TOURS
|
||||
require ["compiled/views/tours/#{tourName}"], (tour) ->
|
||||
new tour name: tourName
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
define [
|
||||
'jquery'
|
||||
'vendor/usher/usher'
|
||||
'Backbone'
|
||||
'jquery.ajaxJSON'
|
||||
], ($, Usher, Backbone, template) ->
|
||||
|
||||
##
|
||||
# Base class for all tours. A tour with the ruby name
|
||||
# :first_time_login should be found at
|
||||
# views/tours/FirstTimeLogin.coffee to be automatically included.
|
||||
#
|
||||
# examples:
|
||||
#
|
||||
# class DiscussionTourView
|
||||
# template: template
|
||||
|
||||
class TourView extends Backbone.View
|
||||
|
||||
events:
|
||||
'click .usher-close': 'dismissSession'
|
||||
'click .dismiss-tour': 'dismissForever'
|
||||
|
||||
@optionProperty 'name'
|
||||
|
||||
initialize: ->
|
||||
super
|
||||
@render()
|
||||
@$el.appendTo $(document.body)
|
||||
@tour = new Usher @$el
|
||||
@attachTour()
|
||||
|
||||
start: =>
|
||||
@tour.start()
|
||||
|
||||
attachTour: ->
|
||||
setTimeout @start, 2000
|
||||
|
||||
dismissSession: ->
|
||||
$.ajaxJSON "/tours/dismiss/session/#{@name}", 'DELETE'
|
||||
|
||||
dismissForever: ->
|
||||
$.ajaxJSON "/tours/dismiss/#{@name}", 'DELETE'
|
||||
@tour.close()
|
||||
|
||||
##
|
||||
# Use this when you have no hook to something being rendered
|
||||
onElementRendered: (selector, cb, _attempts) ->
|
||||
el = $(selector)
|
||||
_attempts = ++_attempts or 1
|
||||
return cb(el) if el.length
|
||||
return if _attempts is 60
|
||||
setTimeout (=> @onElementRendered(selector, cb, _attempts)), 250
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
define [
|
||||
'jquery'
|
||||
'compiled/views/TourView'
|
||||
'jst/tours/AgendaTour'
|
||||
'vendor/usher/usher'
|
||||
], ($, TourView, template, Usher) ->
|
||||
|
||||
class AgendaTour extends TourView
|
||||
|
||||
template: template
|
||||
|
||||
calendarMenu: ->
|
||||
$("#calendar_menu_item")
|
||||
|
||||
calendarLink: ->
|
||||
@calendarMenu().find('a')
|
||||
|
||||
agendaStep2Button: ->
|
||||
@$el.find('.agenda-step-2-button')
|
||||
|
||||
agendaStep3Button: ->
|
||||
@$el.find('.agenda-step-3-on-agenda-already-button')
|
||||
|
||||
locationProvider: ->
|
||||
return @_locProvider if @_locProvider?
|
||||
return window.location
|
||||
|
||||
onCalendar: ->
|
||||
# TODO Ask if we are always going to have this url be /calendar2
|
||||
@locationProvider().pathname is '/calendar2'
|
||||
|
||||
agendaHasAssignments: =>
|
||||
$(".agenda-event").length > 0
|
||||
|
||||
attachTour: ->
|
||||
pageHasHeader = @calendarMenu().length > 0
|
||||
return false unless pageHasHeader
|
||||
if @onCalendar()
|
||||
@attachTourOnCalendarPage()
|
||||
else
|
||||
@attachTourForNonCalendarPage()
|
||||
|
||||
onItemGroupRender: (callback)=>
|
||||
@onElementRendered "div.item-group-container", =>
|
||||
callback.call()
|
||||
|
||||
setupStep4Path: ->
|
||||
targetStep = 'agenda-step-4-no-assignments'
|
||||
if @agendaHasAssignments()
|
||||
targetStep = 'agenda-step-4'
|
||||
@agendaStep3Button().attr('data-usher-show', targetStep)
|
||||
|
||||
agendaIsActive: ->
|
||||
agendaButton = $('#agenda')
|
||||
return agendaButton.hasClass 'active'
|
||||
|
||||
attachTourOnCalendarPage: ->
|
||||
continuingFromOtherPage = localStorage.AgendaTourContinue
|
||||
@onElementRendered '#agenda', =>
|
||||
if not continuingFromOtherPage
|
||||
@agendaStep2Button().attr('data-usher-show', 'agenda-step-2-on-calendar')
|
||||
if @agendaIsActive()
|
||||
@$el.find('.agenda-step-3.btn').attr('data-usher-show', 'agenda-step-3-on-agenda-already')
|
||||
@onItemGroupRender(=> @setupStep4Path())
|
||||
@start()
|
||||
else
|
||||
@attachAgendaButton()
|
||||
@start()
|
||||
else
|
||||
delete localStorage.AgendaTourContinue
|
||||
if @agendaIsActive()
|
||||
@onItemGroupRender =>
|
||||
@setupStep4Path()
|
||||
@tour.start('agenda-step-3-on-agenda-already')
|
||||
else
|
||||
@attachAgendaButton()
|
||||
@tour.start('agenda-step-3')
|
||||
|
||||
onAgendaButtonClick: =>
|
||||
if @agendaHasAssignments()
|
||||
@tour.show('agenda-step-4')
|
||||
else
|
||||
@tour.show('agenda-step-4-no-assignments')
|
||||
|
||||
attachAgendaButton: ->
|
||||
$('#agenda').on 'click', =>
|
||||
@onItemGroupRender =>
|
||||
@onAgendaButtonClick()
|
||||
|
||||
attachTourForNonCalendarPage: ->
|
||||
@tour.on 'agenda-step-2', =>
|
||||
@calendarLink().on 'click', ->
|
||||
localStorage.AgendaTourContinue = '1'
|
||||
@tour.start()
|
|
@ -1,16 +0,0 @@
|
|||
define [
|
||||
'jquery'
|
||||
'compiled/views/TourView'
|
||||
'jst/tours/QuizRegrade'
|
||||
'vendor/usher/usher'
|
||||
], ($, TourView, template, Usher) ->
|
||||
|
||||
class QuizRegrade extends TourView
|
||||
|
||||
template: template
|
||||
|
||||
attachTour: ->
|
||||
$(document).one 'click', '.select_answer_link', =>
|
||||
setTimeout =>
|
||||
@tour.start()
|
||||
, 500
|
|
@ -63,8 +63,6 @@ class ApplicationController < ActionController::Base
|
|||
before_filter :init_body_classes
|
||||
after_filter :set_response_headers
|
||||
after_filter :update_enrollment_last_activity_at
|
||||
after_filter :teardown_live_events_context
|
||||
include Tour
|
||||
|
||||
add_crumb(proc {
|
||||
title = I18n.t('links.dashboard', 'My Dashboard')
|
||||
|
@ -129,8 +127,6 @@ class ApplicationController < ActionController::Base
|
|||
@js_env[:TIMEZONE] = Time.zone.tzinfo.identifier if !@js_env[:TIMEZONE]
|
||||
@js_env[:CONTEXT_TIMEZONE] = @context.time_zone.tzinfo.identifier if !@js_env[:CONTEXT_TIMEZONE] && @context.respond_to?(:time_zone) && @context.time_zone.present?
|
||||
@js_env[:LOCALE] = I18n.qualified_locale if !@js_env[:LOCALE]
|
||||
@js_env[:TOURS] = tours_to_run
|
||||
|
||||
@js_env[:lolcalize] = true if ENV['LOLCALIZE']
|
||||
end
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
class ToursController < ApplicationController
|
||||
|
||||
##
|
||||
# Prevents the current version of the tour from displaying ever again to the
|
||||
# current user.
|
||||
|
||||
def dismiss
|
||||
tour = find_tour_from_params
|
||||
dismissed = @current_user.preferences[:dismissed_tours] ||= {}
|
||||
dismissed[tour[:name]] = tour[:version]
|
||||
@current_user.save!
|
||||
render :json => true
|
||||
end
|
||||
|
||||
##
|
||||
# Dismisses the tour for this session only.
|
||||
|
||||
def dismiss_session
|
||||
tour = find_tour_from_params
|
||||
(session[:dismissed_tours] ||= {})[tour[:name]] = tour[:version]
|
||||
render :json => true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_tour_from_params
|
||||
name = params[:name].underscore.to_sym
|
||||
tour = Tour.tours[name]
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -297,7 +297,6 @@ Either use `<a>` with icon desired icon class added or insert `<i>` inside `<but
|
|||
<span class="span3"><i class="icon-files-fair-use"></i> icon-files-fair-use</span>
|
||||
<span class="span3"><i class="icon-files-obtained-permission"></i>icon-files-obtained-permission</span>
|
||||
<span class="span3"><i class="icon-files-public-domain"></i> icon-files-public-domain</span>
|
||||
<span class="span3"><i class="icon-tour-info"></i> icon-tour-info</span>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<span class="span3"><i class="icon-import"></i> icon-import</span>
|
||||
|
@ -569,8 +568,6 @@ h1, h2, h3, h4, .h1, .h2, .h3, .h4, p {
|
|||
.icon-timer:before { content: "\f19b"; }
|
||||
.icon-toggle-left:before { content: "\f19c"; }
|
||||
.icon-toggle-right:before { content: "\f19d"; }
|
||||
.icon-tour-info:before { content: "\f19e"; }
|
||||
.icon-tour-step-counter:before { content: "\f19f"; }
|
||||
.icon-trash:before { content: "\f1a0"; }
|
||||
.icon-trouble:before { content: "\f1a1"; }
|
||||
.icon-twitter:before { content: "\f1a2"; }
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
@import "post-to-sis-state";
|
||||
@import "pill";
|
||||
@import "alerts";
|
||||
@import "tour-popovers";
|
||||
@import "element-toggler";
|
||||
@import "ic-super-toggle";
|
||||
@import "ic-image-text-combo";
|
||||
|
|
|
@ -1,173 +0,0 @@
|
|||
@import "base/environment";
|
||||
|
||||
/* Tour Popups
|
||||
- give a `<div>` classes of `tour` and `popover`.
|
||||
- use `controls` for buttons at the bottom of the popover
|
||||
- everything else is just html
|
||||
|
||||
(inline styles in this demo are not desired, obviously)
|
||||
|
||||
```html
|
||||
<div class="popover tour top" style="position:static; margin-top: 10px; display: block;">
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<h1 class="h4">Canvas just got better!</h1>
|
||||
<p>
|
||||
It’s now possible to set the read/unread status of your discussion posts manually.
|
||||
</p>
|
||||
|
||||
<div class="controls clearfix">
|
||||
<div class="pull-right">
|
||||
<a href="#" class="btn">No thanks</a>
|
||||
<a href="#" class="btn btn-primary">Show me how</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
*/
|
||||
.popover.tour {
|
||||
z-index: 1000; // yeah, one thousand
|
||||
width: 350px;
|
||||
padding: 20px;
|
||||
color: $gray;
|
||||
font-weight: 200;
|
||||
@include fontSize(15px);
|
||||
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
|
||||
// When a rule is used, it should have less margin in the popups
|
||||
hr {
|
||||
margin: 10px 0;
|
||||
}
|
||||
}
|
||||
.popover-content {
|
||||
padding: 0; // reset for our popovers
|
||||
}
|
||||
|
||||
.popover.tour .controls {
|
||||
margin: 10px 0 0 0;
|
||||
padding: 0 10px 0 0;
|
||||
}
|
||||
.controls--buttons-only {
|
||||
button {margin-right: 5px;}
|
||||
}
|
||||
.controls--items-align-right {
|
||||
// Container flex
|
||||
flex: 1;
|
||||
// Inner content to flex
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.popover-content p {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
i.usher-close {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
padding: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tour-icon {
|
||||
padding-left: 10px;
|
||||
// We're overwriting a bunch of stuff on the icon
|
||||
// todo: we should evenutally fix icons so we don't have to do this
|
||||
//
|
||||
i.icon-tour-info {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
&:before {
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
font-size: 20px !important;
|
||||
font-size: 1.3rem !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tour-content {
|
||||
padding-left: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
.tour-content .btn-link {
|
||||
padding: 0; // takes off button padding on btn-link styles to keep flush with side
|
||||
color: $ic-brand-primary;
|
||||
}
|
||||
// Tour Popup Style: Notification box
|
||||
// ===================================
|
||||
// This styles the tour box look more like a notification, used
|
||||
// when you want to soft trigger a tour
|
||||
|
||||
.popover.tour.tour--notification {
|
||||
width: 330px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 20px 20px 10px;
|
||||
|
||||
.popover-content {padding: 0;} // reset area padding
|
||||
|
||||
.tour-content {
|
||||
padding-left: 10px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
i.usher-close {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
@include fontSize($ic-font-size--small);
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.controls {
|
||||
margin: 10px 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.hide-tour-link {
|
||||
text-align: right;
|
||||
padding-right: 10px;
|
||||
button {
|
||||
@include fontSize($ic-font-size--xsmall);
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Tour Step Counter
|
||||
// ===================================
|
||||
// This styles the litle step dots
|
||||
//
|
||||
.step-counter.step-counter--align-left {
|
||||
margin-top: 0;
|
||||
}
|
||||
.step-counter_item {
|
||||
color: $ic-color-neutral;
|
||||
margin: 0 5px;
|
||||
font-size: 6px !important;
|
||||
}
|
||||
i.icon-tour-step-counter {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 6px !important;
|
||||
color: $grayLight;
|
||||
&:before {
|
||||
font-size: 6px !important;
|
||||
}
|
||||
&.step-counter_item--current {
|
||||
color: $ic-brand-primary;
|
||||
}
|
||||
}
|
||||
|
||||
// Tour Popup Style: Lists
|
||||
// ===================================
|
||||
// This styles the tour box content when it has lists
|
||||
.tour-content__list {
|
||||
margin: 0 15px 0 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.tour-content__list-item {
|
||||
padding: 5px 0;
|
||||
margin-left: 17px;
|
||||
}
|
|
@ -1,257 +0,0 @@
|
|||
{{!-- Shows on any page in Canvas when a new session is kicked off--}}
|
||||
<div
|
||||
id="agenda-step-1"
|
||||
class="popover tour tour--notification"
|
||||
data-points-to="#identity"
|
||||
data-position="bottom"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>{{#t}}Your <strong>Assignments</strong> list has improved!{{/t}}</p>
|
||||
<div class="controls">
|
||||
<button class="agenda-step-2-button btn btn-small btn-success" data-usher-show="agenda-step-2">{{#t}}Show me{{/t}}</button>
|
||||
<button class="btn btn-small usher-close">{{#t}}Not now{{/t}}</button>
|
||||
</div>
|
||||
<div class="hide-tour-link">
|
||||
<button class="btn btn-link dismiss-tour">{{#t}}don't show again{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- If are you are starting from an area that is not calendar... --}}
|
||||
<div
|
||||
id="agenda-step-2"
|
||||
data-points-to="#menu #calendar_menu_item"
|
||||
class="popover tour bottom"
|
||||
data-position="bottom"
|
||||
data-offset-x="-100"
|
||||
data-offset-y="10"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>
|
||||
{{#t}}Click here on the <strong>Calendar</strong> link{{/t}}
|
||||
</p>
|
||||
<div class="controls">
|
||||
<div class="step-counter" aria-hidden="true">
|
||||
<i class="icon-tour-step-counter step-counter_item step-counter_item--current"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- If you're on the calendar page when you start the tour --}}
|
||||
<div
|
||||
id="agenda-step-2-on-calendar"
|
||||
data-points-to="#menu #calendar_menu_item"
|
||||
class="popover tour bottom"
|
||||
data-position="bottom"
|
||||
data-offset-x="-100"
|
||||
data-offset-y="10"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>
|
||||
{{#t}}Your Assignment list can now be found on the <strong>Calendar</strong> page.{{/t}}
|
||||
</p>
|
||||
<div class="controls grid-row middle-xs">
|
||||
<div class="step-counter" aria-hidden="true">
|
||||
<i class="icon-tour-step-counter step-counter_item step-counter_item--current"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
</div>
|
||||
<div class="controls--items-align-right">
|
||||
<button class="agenda-step-3 btn btn-small" data-usher-show="agenda-step-3">{{#t}}Next{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- Click on the Agenda view --}}
|
||||
<div
|
||||
id="agenda-step-3"
|
||||
data-points-to=".calendar_view_buttons #agenda"
|
||||
class="popover tour bottom"
|
||||
data-position="bottom"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>
|
||||
{{#t}}Now click the <strong>Agenda</strong> button{{/t}}
|
||||
</p>
|
||||
<div class="controls">
|
||||
<div class="step-counter" aria-hidden="true">
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item step-counter_item--current"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- If the Agenda view is already active... --}}
|
||||
<div
|
||||
id="agenda-step-3-on-agenda-already"
|
||||
data-points-to=".calendar_view_buttons #agenda"
|
||||
class="popover tour bottom"
|
||||
data-position="bottom"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>
|
||||
{{#t}}To view assignments, make sure the <strong>Agenda</strong> view is active.{{/t}}
|
||||
</p>
|
||||
<div class="controls grid-row middle-xs">
|
||||
<div class="step-counter" aria-hidden="true">
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item step-counter_item--current"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
</div>
|
||||
<div class="controls--items-align-right">
|
||||
<button class="agenda-step-3-on-agenda-already-button btn btn-small" data-usher-show="agenda-step-4">{{#t}}Next{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{!-- If no assignments - Show a window describing the assignments list --}}
|
||||
<div
|
||||
id="agenda-step-4-no-assignments"
|
||||
data-points-to="span.agendaView--no-assignments"
|
||||
class="popover tour bottom"
|
||||
data-position="bottom"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>
|
||||
{{#t}}Your Assignments will show here listed by due date.{{/t}}
|
||||
</p>
|
||||
<div class="controls grid-row middle-xs">
|
||||
<div class="step-counter step-counter--align-left" aria-hidden="true">
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item step-counter_item--current"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
</div>
|
||||
<div class="controls--items-align-right">
|
||||
<button class="btn btn-small" data-usher-show="agenda-step-5">{{#t}}Next{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{{!-- If Assignments - Show a window describing the assignments list --}}
|
||||
<div
|
||||
id="agenda-step-4"
|
||||
data-points-to="li.agenda-event:first-child span.ig-title"
|
||||
class="popover tour bottom"
|
||||
data-position="bottom"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>
|
||||
{{#t}}Here are your Assignments, listed by due date.{{/t}}
|
||||
</p>
|
||||
<div class="controls grid-row middle-xs">
|
||||
<div class="step-counter step-counter--align-left" aria-hidden="true">
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item step-counter_item--current"></i>
|
||||
<i class="icon-tour-step-counter step-counter_item"></i>
|
||||
</div>
|
||||
<div class="controls--items-align-right">
|
||||
<button class="btn btn-small" data-usher-show="agenda-step-5">{{#t}}Next{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{!-- Last step - show you can turn calendars on and off --}}
|
||||
<div
|
||||
id="agenda-step-5"
|
||||
data-points-to="#context-list-holder"
|
||||
class="popover tour left"
|
||||
data-position="left"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>{{#t}}You can hide or show a course’s assignments by toggling them on or off.{{/t}}</p>
|
||||
<div class="controls grid-row middle-xs controls--buttons-only">
|
||||
<button class="btn usher-close">{{#t}}Remind me next time{{/t}}</button>
|
||||
<button class="btn dismiss-tour">{{#t}}Okay, got it{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
|
@ -1,41 +0,0 @@
|
|||
<div
|
||||
id="tour-quiz-regrade-step1"
|
||||
data-points-to=".regrade-options"
|
||||
class="popover tour top"
|
||||
data-position="top"
|
||||
data-offset-x="10"
|
||||
data-offset-y="10"
|
||||
>
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content">
|
||||
<div class="grid-row">
|
||||
<div class="tour-icon">
|
||||
<i class="icon-tour-info" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="tour-content">
|
||||
<p>{{#t}}You can now set regrade options for students who have already taken the quiz.{{/t}}</p>
|
||||
<ul class="tour-content__list">
|
||||
<li class="tour-content__list-item">
|
||||
{{#t}}
|
||||
Once you’ve changed an answer you’ll need to choose an option before updating the question.
|
||||
{{/t}}
|
||||
</li>
|
||||
<li class="tour-content__list-item">
|
||||
{{#t}}
|
||||
Make sure you choose the most appropiate option as students' scores MAY be affected.
|
||||
{{/t}}
|
||||
</li>
|
||||
<li class="tour-content__list-item">
|
||||
{{#t}}
|
||||
Canvas will regrade all your submissions after you save the quiz, this may take a few minutes.
|
||||
{{/t}}
|
||||
</li>
|
||||
</ul>
|
||||
<div class="controls">
|
||||
<button class="btn usher-close">{{#t "got_it"}}Ok, got it{{/t}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
require 'lib/tour'
|
||||
require 'config/tours'
|
|
@ -705,8 +705,6 @@ CanvasRails::Application.routes.draw do
|
|||
get 'search/bookmarks' => 'users#bookmark_search', as: :bookmark_search
|
||||
get 'search/rubrics' => 'search#rubrics'
|
||||
get 'search/all_courses' => 'search#all_courses'
|
||||
delete 'tours/dismiss/:name' => 'tours#dismiss', as: :dismiss_tour
|
||||
delete 'tours/dismiss/session/:name' => 'tours#dismiss_session', as: :dismiss_tour_session
|
||||
resources :users do
|
||||
match 'masquerade', via: [:get, :post]
|
||||
delete :delete
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
# Define all the feature tours in this file with the tour method.
|
||||
#
|
||||
# examples:
|
||||
#
|
||||
# tour(:first_time_login, 1, 'users#user_dashboard') {
|
||||
# # assuming we have this method, returning true will then initialize
|
||||
# # a tour found in coffeescripts/views/tours/FirstTimeLogin
|
||||
# user.has_never_logged_in?
|
||||
# }
|
||||
#
|
||||
# # Can call with a hash instead, and omit the block to always
|
||||
# # include the tour.
|
||||
# tour({
|
||||
# :name => :course_tour,
|
||||
# :version => 1,
|
||||
# :actions => [
|
||||
# 'courses#show',
|
||||
# 'assignments#show',
|
||||
# 'settings#show',
|
||||
# ]
|
||||
# })
|
||||
|
||||
Tour.config do
|
||||
|
||||
tour(:quiz_regrade, 1, ['quizzes#edit'])
|
||||
|
||||
# We are taking this out for now
|
||||
# tour(:agenda_tour, 1, '*')
|
||||
|
||||
|
||||
#tour(:discussion_topic_auto_unread, 1, ['discussion_topics#show', 'discussion_topics#index']) do
|
||||
#if params["action"] == "show"
|
||||
#DiscussionTopic.find(params["id"]).discussion_entries.length > 0
|
||||
#elsif params["tour-topic-id"]
|
||||
#true
|
||||
#end
|
||||
#end
|
||||
|
||||
end
|
||||
|
|
@ -73,7 +73,6 @@ entries['instructure-common'] = [
|
|||
'compiled/models/User',
|
||||
'compiled/PandaPub',
|
||||
'compiled/registration/incompleteRegistrationWarning',
|
||||
'compiled/tours',
|
||||
'compiled/util/brandableCss',
|
||||
'compiled/util/DateValidator',
|
||||
'compiled/util/PandaPubPoller',
|
||||
|
|
79
lib/tour.rb
79
lib/tour.rb
|
@ -1,79 +0,0 @@
|
|||
##
|
||||
# Controller module that determines which feature tours to show the user
|
||||
|
||||
module Tour
|
||||
|
||||
@@tours = {}
|
||||
|
||||
##
|
||||
# Adds an tour config, used in `config/tours.rb`
|
||||
#
|
||||
# ==== Parameters
|
||||
#
|
||||
# Accepts argument list or hash of parameter names.
|
||||
#
|
||||
# * +name+ - The name of the tour
|
||||
#
|
||||
# * +version+ - The version of the tour, increment this if you want users to
|
||||
# see the tour again even if they've dismissed it previously (i.e. the
|
||||
# dashboard changed and we make a new tour for it, replacing the old one)
|
||||
#
|
||||
# * +actions+ - A string or array of actions, in the format of
|
||||
# 'controller#action', to have the tour included on. If your tour spans
|
||||
# several pages, you'll want to include it on all of them.
|
||||
#
|
||||
# * +&block+ - Return true to include the tour when the page loads, false
|
||||
# otherwise. No block assumes true. The block is called with the current
|
||||
# controller as the context.
|
||||
|
||||
def self.tour(name, version=nil, actions=nil, &block)
|
||||
if name.is_a?(Hash)
|
||||
version = name[:version]
|
||||
actions = name[:actions]
|
||||
name = name[:name]
|
||||
end
|
||||
@@tours[name] = {
|
||||
:name => name,
|
||||
:js_name => name.to_s.classify,
|
||||
:actions => [actions].flatten,
|
||||
:block => block,
|
||||
:version => version
|
||||
}
|
||||
end
|
||||
|
||||
def self.where
|
||||
self.tours.values.select { |tour| yield(tour) }
|
||||
end
|
||||
|
||||
def self.config(&block)
|
||||
instance_eval(&block)
|
||||
end
|
||||
|
||||
def self.tours
|
||||
@@tours
|
||||
end
|
||||
|
||||
def tour_is_dismissed?(tour)
|
||||
dismissed = session[:dismissed_tours] || {}
|
||||
return true if dismissed[tour[:name]] == tour[:version]
|
||||
dismissed = @current_user.preferences[:dismissed_tours] || {}
|
||||
return true if dismissed[tour[:name]] == tour[:version]
|
||||
false
|
||||
end
|
||||
|
||||
def tours_to_run
|
||||
return if !@current_user || api_request?
|
||||
controller_action = "#{controller_name}##{action_name}"
|
||||
Tour.where { |tour|
|
||||
# An tour will be included on the page if the action matches
|
||||
next unless tour[:actions].include?(controller_action) || tour[:actions].include?('*')
|
||||
# its not dismissed
|
||||
next if tour_is_dismissed?(tour)
|
||||
# and the block returns true (or doesn't exist)
|
||||
next true if tour[:block].nil?
|
||||
instance_eval(&tour[:block])
|
||||
}.map {|e| e[:js_name]}
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -297,7 +297,6 @@ Either use `<a>` with icon desired icon class added or insert `<i>` inside `<but
|
|||
<span class="span3"><i class="icon-files-fair-use"></i> icon-files-fair-use</span>
|
||||
<span class="span3"><i class="icon-files-obtained-permission"></i>icon-files-obtained-permission</span>
|
||||
<span class="span3"><i class="icon-files-public-domain"></i> icon-files-public-domain</span>
|
||||
<span class="span3"><i class="icon-tour-info"></i> icon-tour-info</span>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<span class="span3"><i class="icon-import"></i> icon-import</span>
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<svg viewBox="0 0 499 499" xmlns="http://www.w3.org/2000/svg"><title>Tour-Info</title><path d="M249.5 0C111.713 0 0 111.713 0 249.5S111.713 499 249.5 499 499 387.287 499 249.5 387.287 0 249.5 0zm33.992 361.245c-10.43 4.162-18.79 7.307-25.032 9.5-6.242 2.175-13.48 3.255-21.713 3.255-12.69 0-22.55-3.097-29.566-9.308-7.032-6.226-10.54-14.104-10.54-23.666 0-3.717.27-7.513.79-11.39.522-3.89 1.375-8.26 2.545-13.15l13.068-46.524a206.322 206.322 0 0 0 2.956-12.66c.79-3.986 1.184-7.623 1.184-10.91 0-5.958-1.217-10.103-3.65-12.438-2.434-2.335-7.096-3.51-13.986-3.51-3.398 0-6.858.54-10.414 1.604s-6.606 2.08-9.134 3.018l3.477-14.327c8.58-3.527 16.782-6.514 24.604-9.007 7.84-2.51 15.235-3.733 22.22-3.733 12.595 0 22.298 3.034 29.124 9.15 6.827 6.098 10.24 14.04 10.24 23.824 0 2.018-.237 5.56-.726 10.658-.475 5.1-1.328 9.8-2.608 14.026l-13.037 46.364c-1.06 3.717-2.023 7.974-2.86 12.755-.854 4.78-1.265 8.386-1.265 10.832 0 6.162 1.375 10.34 4.11 12.595 2.75 2.208 7.49 3.336 14.253 3.336 3.162 0 6.75-.555 10.763-1.683 3.998-1.096 6.89-2.08 8.707-2.923l-3.508 14.31zm-2.55-188.693c-6.057 5.643-13.34 8.448-21.863 8.448-8.526 0-15.824-2.805-21.926-8.448-6.103-5.626-9.154-12.45-9.154-20.473 0-8.008 3.05-14.864 9.154-20.553 6.102-5.69 13.4-8.527 21.925-8.527 8.523 0 15.805 2.837 21.86 8.527 6.04 5.69 9.06 12.545 9.06 20.552 0 8.02-3.02 14.846-9.06 20.472z" fill="#4E4E4C" fill-rule="evenodd"/></svg>
|
Before Width: | Height: | Size: 1.4 KiB |
|
@ -1 +0,0 @@
|
|||
<svg width="6" height="6" viewBox="0 0 6 6" xmlns="http://www.w3.org/2000/svg"><title>Tour-Step-Counter</title><circle cx="23" cy="3" r="3" transform="translate(-20)" fill="#010101" fill-rule="evenodd"/></svg>
|
Before Width: | Height: | Size: 210 B |
|
@ -1,145 +0,0 @@
|
|||
define(['jquery'], function($) {
|
||||
|
||||
function ScrollIntoView(el, options) {
|
||||
this.callback = $.proxy(this, 'callback');
|
||||
this.$el = $(el);
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.findScrollParent();
|
||||
this.scroll();
|
||||
}
|
||||
|
||||
ScrollIntoView.prototype.defaults = {
|
||||
duration: 200,
|
||||
offset: {
|
||||
x: 20,
|
||||
y: 20
|
||||
}
|
||||
};
|
||||
|
||||
ScrollIntoView.window = $(window);
|
||||
|
||||
ScrollIntoView.SCROLLABLE_ROOT = document.body;
|
||||
|
||||
ScrollIntoView.prototype.scroll = function() {
|
||||
this.calculateDimensions();
|
||||
this.calculateScrollOptions();
|
||||
if ($.isEmptyObject(this.scrollOptions)) {
|
||||
this.callback();
|
||||
} else {
|
||||
this.scrollParent.animate(this.scrollOptions, this.callback);
|
||||
}
|
||||
};
|
||||
|
||||
ScrollIntoView.prototype.callback = function() {
|
||||
this.options.complete && this.options.complete.call(this.$el);
|
||||
};
|
||||
|
||||
ScrollIntoView.prototype.findScrollParent = function() {
|
||||
var parent = this.$el.scrollParent();
|
||||
if (parent[0] == document) {
|
||||
parent = $(this.constructor.SCROLLABLE_ROOT);
|
||||
}
|
||||
this.scrollParent = parent;
|
||||
};
|
||||
|
||||
ScrollIntoView.prototype.calculateDimensions = function() {
|
||||
var el = this.calculateElementDimensions(this.$el);
|
||||
var parent = this.calculateElementDimensions(this.scrollParent);
|
||||
this.dimensions = {
|
||||
relative: {
|
||||
top: el.box.top - (parent.box.top + parent.border.top),
|
||||
right: parent.box.right - parent.border.right -
|
||||
parent.scrollbar.right - el.box.right,
|
||||
bottom: parent.box.bottom - parent.border.bottom -
|
||||
parent.scrollbar.bottom - el.box.bottom,
|
||||
left: el.box.left - (parent.box.left + parent.border.left)
|
||||
},
|
||||
element: el,
|
||||
parent: parent
|
||||
};
|
||||
};
|
||||
|
||||
ScrollIntoView.prototype.calculateElementDimensions = function($el) {
|
||||
var win = this.constructor.window;
|
||||
var isRoot = $el[0] == this.constructor.SCROLLABLE_ROOT;
|
||||
if (isRoot) $el = $(document.documentElement);
|
||||
var rect = $el[0].getBoundingClientRect();
|
||||
return {
|
||||
border: this.calculateBorder($el[0]),
|
||||
scroll: {
|
||||
top: (isRoot ? win : $el).scrollTop(),
|
||||
left: (isRoot ? win : $el).scrollLeft()
|
||||
},
|
||||
scrollbar: {
|
||||
right: isRoot ? 0 : $el.innerWidth() - $el[0].clientWidth,
|
||||
bottom: isRoot ? 0 : $el.innerHeight() - $el[0].clientHeight
|
||||
},
|
||||
box: {
|
||||
top: isRoot ? 0 : rect.top,
|
||||
right: isRoot ? $el[0].clientWidth : rect.right,
|
||||
bottom: isRoot ? $el[0].clientHeight : rect.bottom,
|
||||
left: isRoot ? 0 : rect.left
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
ScrollIntoView.prototype.calculateBorder = function(el) {
|
||||
var hasComputedStyle = !!(document.defaultView &&
|
||||
document.defaultView.getComputedStyle);
|
||||
var styles = hasComputedStyle ?
|
||||
document.defaultView.getComputedStyle(el, null) :
|
||||
el.currentStyle;
|
||||
var b = {
|
||||
top: (parseFloat(hasComputedStyle ?
|
||||
styles.borderTopWidth :
|
||||
$.css(el, "borderTopWidth")) || 0),
|
||||
left: (parseFloat(hasComputedStyle ?
|
||||
styles.borderLeftWidth :
|
||||
$.css(el, "borderLeftWidth")) || 0),
|
||||
bottom: (parseFloat(hasComputedStyle ?
|
||||
styles.borderBottomWidth :
|
||||
$.css(el, "borderBottomWidth")) || 0),
|
||||
right: (parseFloat(hasComputedStyle ?
|
||||
styles.borderRightWidth :
|
||||
$.css(el, "borderRightWidth")) || 0)
|
||||
};
|
||||
return {
|
||||
top: b.top,
|
||||
left: b.left,
|
||||
bottom: b.bottom,
|
||||
right: b.right,
|
||||
vertical: b.top + b.bottom,
|
||||
horizontal: b.left + b.right
|
||||
};
|
||||
};
|
||||
|
||||
ScrollIntoView.prototype.calculateScrollOptions = function() {
|
||||
var options = {};
|
||||
var relative = this.dimensions.relative;
|
||||
var offset = this.options.offset;
|
||||
var e = this.dimensions.element;
|
||||
var p = this.dimensions.parent;
|
||||
if (relative.top < 0) { // above viewport
|
||||
options.scrollTop = p.scroll.top + relative.top - offset.y;
|
||||
} else if (relative.top > 0 && relative.bottom < 0) { // below viewport
|
||||
options.scrollTop = p.scroll.top + offset.y +
|
||||
Math.min(relative.top, -relative.bottom);
|
||||
}
|
||||
if (relative.left < 0) { // left of viewport
|
||||
options.scrollLeft = p.scroll.left + relative.left - offset.x;
|
||||
} else if (relative.left > 0 && relative.right < 0) { // right of viewport
|
||||
options.scrollLeft = p.scroll.left + offset.x +
|
||||
Math.min(relative.left, -relative.right);
|
||||
}
|
||||
this.scrollOptions = options;
|
||||
};
|
||||
|
||||
$.fn.scrollIntoView = function(options, duration) {
|
||||
if (duration && options) options.duration = duration;
|
||||
new ScrollIntoView(this, options);
|
||||
return this;
|
||||
};
|
||||
|
||||
return ScrollIntoView;
|
||||
|
||||
});
|
|
@ -1,321 +0,0 @@
|
|||
/**
|
||||
* Initialize a new Usher with an $Element or selector.
|
||||
*
|
||||
* @param {String|$Element} selector CSS selector string or jQuery element
|
||||
* @api public
|
||||
* @return {Usher}
|
||||
*/
|
||||
|
||||
define(['jquery', 'jqueryui/core', 'vendor/usher/scrollIntoView'], function($) {
|
||||
|
||||
function Usher(selector, options) {
|
||||
if (!(this instanceof Usher)) return new Usher(selector);
|
||||
this.options = $.extend({}, this.defaults, options);
|
||||
this.bindMethods();
|
||||
this.$el = jQuery(selector);
|
||||
this.eventProxy = $({});
|
||||
this.initPopups();
|
||||
this.attachEvents();
|
||||
this.$el.hide();
|
||||
return this;
|
||||
}
|
||||
|
||||
Usher.prototype.defaults = {
|
||||
position: true,
|
||||
resetStyles: { opacity: 0 },
|
||||
offset: {x: 20, y: 20},
|
||||
animations: {
|
||||
left: { left: '-=10px', opacity: 1 },
|
||||
right: { left: '+=10px', opacity: 1 },
|
||||
bottom: { top: '+=10px', opacity: 1 },
|
||||
top: { top: '-=10px', opacity: 1 }
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a tour.
|
||||
*
|
||||
* @return {Usher}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Usher.prototype.start = function(index) {
|
||||
index = index == null ? 0 : index;
|
||||
this.show(index);
|
||||
};
|
||||
|
||||
Usher.prototype.indexOfPopupId = function(id) {
|
||||
for (var i = 0; i < this.popups.length; i++) {
|
||||
if (this.popups[i].attr('id') == id) return i;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Show the popup at `index`.
|
||||
*
|
||||
* @param {Number} index
|
||||
* @return {Usher}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Usher.prototype.show = function(index) {
|
||||
if (typeof index === 'string') {
|
||||
index = this.indexOfPopupId(index);
|
||||
}
|
||||
this.$el.show();
|
||||
this.hideCurrent();
|
||||
this.$popup = this.popups[index];
|
||||
this.beforeShow();
|
||||
this.$popup.show();
|
||||
this.$popup.css(this.options.resetStyles);
|
||||
if (this.options.position) {
|
||||
this.position();
|
||||
}
|
||||
this.scroll(this.animate);
|
||||
this.trigger(this.$popup.attr('id'));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds event listener to the instance.
|
||||
*
|
||||
* Events:
|
||||
*
|
||||
* - when a popup is shown, triggers its id
|
||||
* - when a popup is hidden, triggers {id}:hide
|
||||
* - when the tour is closed
|
||||
*
|
||||
* @param {String} popupId
|
||||
* @param {Function} handler
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Usher.prototype.on = function(popupId, handler) {
|
||||
this.eventProxy.on(popupId, handler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes an event listener from the instance.
|
||||
*
|
||||
* @param {String} event
|
||||
* @param {Function} handler
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Usher.prototype.off = function(event, handler) {
|
||||
this.eventProxy.off(event, handler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Closes the tour.
|
||||
*
|
||||
* @returns {Usher}
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Usher.prototype.close = function(event) {
|
||||
this.$el.hide();
|
||||
if (event) event.preventDefault();
|
||||
this.trigger('hide');
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Called before a popup is shown.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.beforeShow = function() {
|
||||
this.trigger(this.$popup.attr('id') + ':before');
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Animates the popup.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.animate = function() {
|
||||
this.$popup.animate(this.getPopupAnimation(), 200);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets animation options for the popup animation.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.getPopupAnimation = function() {
|
||||
var direction = this.$popup.data('position') || 'bottom';
|
||||
return this.options.animations[direction];
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers event listeners on `name` for both the usher
|
||||
* instance and the $el.
|
||||
*
|
||||
* @param {String} name
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.trigger = function(event) {
|
||||
this.eventProxy.trigger.apply(this.eventProxy, arguments);
|
||||
this.$el.trigger.apply(this.$el, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds methods to the instance to be used functionally.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.bindMethods = function() {
|
||||
var methods = ['initPopups', 'close', 'animate', 'showFromDataAttribute'];
|
||||
for (var i = 0; i < methods.length; i += 1) {
|
||||
this[methods[i]] = $.proxy(this, methods[i]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Attaches events to `$el`.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.attachEvents = function() {
|
||||
this.$el.on('click.usher', '.usher-close', this.close);
|
||||
$('body').on('click.usher', '[data-usher-show]', this.showFromDataAttribute);
|
||||
};
|
||||
|
||||
Usher.prototype.showFromDataAttribute = function(event) {
|
||||
var id = $(event.target).data('usherShow');
|
||||
this.show(id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes events from `$el`.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.removeEvents = function() {
|
||||
this.$el.off('.usher');
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes popup elements.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.initPopups = function() {
|
||||
this.popups = this.$el.children().map(this.initPopup);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize single popup element.
|
||||
*
|
||||
* @return {$Element}
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.initPopup = function(index, el) {
|
||||
return $(el).hide().css('position', 'absolute');
|
||||
};
|
||||
|
||||
/**
|
||||
* Hides current popup.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.hideCurrent = function() {
|
||||
if (!this.$popup) return; // don't first time showing
|
||||
this.$popup.hide();
|
||||
this.trigger(this.$popup.attr('id') + ':hide');
|
||||
};
|
||||
|
||||
/**
|
||||
* Positions the current popup.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.position = function() {
|
||||
var pointsTo = this.$popup.data('points-to');
|
||||
if (pointsTo) {
|
||||
this.pointTo(pointsTo);
|
||||
} else {
|
||||
this.positionDefault();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Positions the current popup in the center of the viewport.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.positionDefault = function() {
|
||||
this.$popup.position(this.constructor.positions['default']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Positions the current popup relative to the element it points to.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.pointTo = function(pointTo) {
|
||||
var position = this.$popup.data('position') || 'bottom';
|
||||
var options = this.constructor.positions[position];
|
||||
options.of = $(pointTo);
|
||||
this.$popup.position(options);
|
||||
};
|
||||
|
||||
/**
|
||||
* Scrolls the current popup into view.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.scroll = function(callback) {
|
||||
this.$popup.scrollIntoView({
|
||||
offset: this.getScrollOffset(),
|
||||
complete: callback
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines the offset in `scroll`
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
Usher.prototype.getScrollOffset = function() {
|
||||
return {
|
||||
x: parseInt(this.$popup.data('offset-x') || this.options.offset.x, 10),
|
||||
y: parseInt(this.$popup.data('offset-y') || this.options.offset.y, 10)
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Map `points-to` values to `$.fn.position` options.
|
||||
*/
|
||||
|
||||
// collision: 'none' because $.fn.position mistakenly flips the element if
|
||||
// the `of` element has a negative scrollX :\
|
||||
Usher.positions = {
|
||||
left: { my: 'right', at: 'left', collision: 'none' },
|
||||
right: { my: 'left', at: 'right', collision: 'none' },
|
||||
top: { my: 'bottom', at: 'top', collision: 'none' },
|
||||
bottom: { my: 'top', at: 'bottom', collision: 'none' },
|
||||
'default': { my: 'center', at: 'center', of: window, collision: 'none' }
|
||||
};
|
||||
|
||||
return Usher;
|
||||
|
||||
});
|
|
@ -1,149 +0,0 @@
|
|||
define [
|
||||
'jquery'
|
||||
'Backbone'
|
||||
'compiled/views/tours/AgendaTour'
|
||||
'helpers/assertions'
|
||||
'helpers/util'
|
||||
'helpers/jquery.simulate'
|
||||
], ($, Backbone, AgendaTour, assert, util) ->
|
||||
|
||||
view = null
|
||||
$fixtures = null
|
||||
fakeUsher = null
|
||||
fakeLocation = {
|
||||
pathname: '/'
|
||||
}
|
||||
|
||||
class FakeUsher
|
||||
constructor: ->
|
||||
@_started = false
|
||||
@_showing = null
|
||||
@_stepbacks = {}
|
||||
|
||||
start: (target)->
|
||||
@_startTarget = target
|
||||
@_started = true
|
||||
|
||||
show: (target)->
|
||||
@_showing = target
|
||||
|
||||
on: (step, callback)->
|
||||
@_stepbacks[step] = callback
|
||||
|
||||
takeStep: (step)->
|
||||
@_stepbacks[step].call()
|
||||
|
||||
addActiveAgendaButton = ->
|
||||
agendaButton = $('<button id="agenda" class="active"></button>')
|
||||
agendaButton.appendTo $fixtures
|
||||
|
||||
addAgendaButton = ->
|
||||
agendaButton = $('<button id="agenda"></button>')
|
||||
agendaButton.appendTo $fixtures
|
||||
return agendaButton
|
||||
|
||||
addItemGroupContainer = ->
|
||||
itemGroupContainer = $('<div class="item-group-container"></div>')
|
||||
itemGroupContainer.appendTo $fixtures
|
||||
|
||||
addCalendarMenu = ->
|
||||
calendarMenu = $('<div id="calendar_menu_item"><a href="#">Calendar Link</a></div>')
|
||||
calendarMenu.appendTo $fixtures
|
||||
|
||||
addAgendaAssignment = ->
|
||||
assignment = $('<div class="agenda-event">')
|
||||
assignment.appendTo $fixtures
|
||||
|
||||
module 'AgendaTour',
|
||||
setup: ->
|
||||
view = new AgendaTour()
|
||||
$fixtures = $('#fixtures')
|
||||
view.render().$el.appendTo($fixtures)
|
||||
fakeUsher = new FakeUsher()
|
||||
view.tour = fakeUsher
|
||||
delete localStorage.AgendaTourContinue
|
||||
|
||||
teardown: ->
|
||||
view.remove()
|
||||
$fixtures.empty()
|
||||
|
||||
test 'location dependency injection', ->
|
||||
equal window.location, view.locationProvider()
|
||||
|
||||
test 'checking if onCalendar', ->
|
||||
equal false, view.onCalendar()
|
||||
view._locProvider = fakeLocation
|
||||
fakeLocation.pathname = '/calendar2'
|
||||
equal true, view.onCalendar()
|
||||
|
||||
test "agendaHasAssignments is false if none in the dom", ->
|
||||
equal false, view.agendaHasAssignments()
|
||||
|
||||
test "agendaHasAssignments is true if one in the dom", ->
|
||||
addAgendaAssignment()
|
||||
equal true, view.agendaHasAssignments()
|
||||
|
||||
test 'attachTour short circuits if theres no header', ->
|
||||
equal false, view.attachTour()
|
||||
|
||||
test 'attachTourForNonCalendarPage starts the tour', ->
|
||||
equal false, fakeUsher._started
|
||||
view.attachTourForNonCalendarPage()
|
||||
equal true, fakeUsher._started
|
||||
|
||||
test 'attachTourForNonCalendarPage tracks when weve been to the calendar', ->
|
||||
addCalendarMenu()
|
||||
equal localStorage.AgendaTourContinue, undefined
|
||||
view.attachTourForNonCalendarPage()
|
||||
fakeUsher.takeStep('agenda-step-2')
|
||||
calendarLink = $('#calendar_menu_item a')
|
||||
calendarLink.triggerHandler('click')
|
||||
equal localStorage.AgendaTourContinue, '1'
|
||||
|
||||
test "agendaButton goes to step 4 when there are assignments", ->
|
||||
agendaButton = addAgendaButton()
|
||||
addItemGroupContainer()
|
||||
view.attachAgendaButton()
|
||||
agendaButton.triggerHandler('click')
|
||||
equal fakeUsher._showing, 'agenda-step-4-no-assignments'
|
||||
|
||||
test "agendaButton goes to step 4-no-assignments when there are no assignments", ->
|
||||
addAgendaAssignment()
|
||||
agendaButton = addAgendaButton()
|
||||
addItemGroupContainer()
|
||||
view.attachAgendaButton()
|
||||
agendaButton.triggerHandler('click')
|
||||
equal fakeUsher._showing, 'agenda-step-4'
|
||||
|
||||
test 'attaching the tour on the calendar page with inactive agenda', ->
|
||||
addAgendaButton()
|
||||
addItemGroupContainer()
|
||||
view.attachTourOnCalendarPage()
|
||||
equal view.agendaStep2Button().attr('data-usher-show'), 'agenda-step-2-on-calendar'
|
||||
equal true, fakeUsher._started
|
||||
|
||||
test 'attaching tour on calendar with active agenda sets up step 4 path', ->
|
||||
addActiveAgendaButton()
|
||||
addItemGroupContainer()
|
||||
view.attachTourOnCalendarPage()
|
||||
equal view.agendaStep3Button().attr('data-usher-show'), 'agenda-step-4-no-assignments'
|
||||
equal true, fakeUsher._started
|
||||
|
||||
test 'attaching tour on calendar from another page with inactive agenda', ->
|
||||
localStorage.AgendaTourContinue = '1'
|
||||
addAgendaButton()
|
||||
addItemGroupContainer()
|
||||
view.attachTourOnCalendarPage()
|
||||
equal 'agenda-step-3', fakeUsher._startTarget
|
||||
equal true, fakeUsher._started
|
||||
|
||||
test 'attaching calendar tour with active agenda from other page and an assignment', ->
|
||||
localStorage.AgendaTourContinue = '1'
|
||||
addAgendaAssignment()
|
||||
addActiveAgendaButton()
|
||||
addItemGroupContainer()
|
||||
view.attachTourOnCalendarPage()
|
||||
equal view.agendaStep3Button().attr('data-usher-show'), 'agenda-step-4'
|
||||
equal 'agenda-step-3-on-agenda-already', fakeUsher._startTarget
|
||||
equal true, fakeUsher._started
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
||||
|
||||
describe ToursController do
|
||||
|
||||
before :each do
|
||||
Tour.tour(:fake_tour, 1, 'users#index')
|
||||
user(:active_all => true)
|
||||
user_session(@user)
|
||||
end
|
||||
|
||||
it "should add dismissed tours to user preferences" do
|
||||
expect(@user.preferences[:dismissed_tours]).to be_nil
|
||||
delete 'dismiss', :name => 'FakeTour'
|
||||
@user.reload
|
||||
expect(@user.preferences[:dismissed_tours]).to eq({:fake_tour => 1})
|
||||
end
|
||||
|
||||
it "should override old dismissed tours with new versions" do
|
||||
# set version one back as though the user dismissed v0 already
|
||||
@user.preferences[:dismissed_tours] = {:fake_tour => 0}
|
||||
expect(@user.preferences[:dismissed_tours]).to eq({:fake_tour => 0})
|
||||
delete 'dismiss', :name => 'FakeTour'
|
||||
@user.reload
|
||||
# :fake_tour should be the current version (1) not the old version (0)
|
||||
expect(@user.preferences[:dismissed_tours]).to eq({:fake_tour => 1})
|
||||
end
|
||||
|
||||
it "should add dismissed tours to user session" do
|
||||
delete 'dismiss_session', :name => 'FakeTour'
|
||||
expect(request.session[:dismissed_tours]).to eq({:fake_tour => 1})
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper.rb')
|
||||
|
||||
describe Tour do
|
||||
describe "tour" do
|
||||
let(:block) {
|
||||
Proc.new { true }
|
||||
}
|
||||
|
||||
def assert_tour
|
||||
tour = Tour.tours[:fake]
|
||||
expect(tour[:name]).to eq :fake
|
||||
expect(tour[:version]).to eq 1
|
||||
expect(tour[:actions]).to eq ['controller#action']
|
||||
expect(tour[:block]).to eq block
|
||||
end
|
||||
|
||||
it "should configure an tour" do
|
||||
Tour.tour :fake, 1, 'controller#action', &block
|
||||
assert_tour
|
||||
end
|
||||
|
||||
it "should configure an tour with a hash" do
|
||||
Tour.tour({
|
||||
:name => :fake,
|
||||
:version => 1,
|
||||
:actions => 'controller#action'
|
||||
}, &block)
|
||||
assert_tour
|
||||
end
|
||||
end
|
||||
|
||||
describe "tours_to_run" do
|
||||
|
||||
class FakeUser
|
||||
def preferences
|
||||
{:dismissed_tours => {:dismissed => 1}}
|
||||
end
|
||||
end
|
||||
|
||||
class FakeController
|
||||
def initialize
|
||||
@current_user = FakeUser.new
|
||||
end
|
||||
def self.before_filter(name); true; end
|
||||
def controller_name; 'controller'; end
|
||||
|
||||
def action_name; 'action'; end
|
||||
|
||||
def session
|
||||
{:dismissed_tours => {:dismissed => 1}}
|
||||
end
|
||||
|
||||
def api_request?; false; end
|
||||
include Tour
|
||||
end
|
||||
|
||||
before :each do
|
||||
@controller = FakeController.new
|
||||
end
|
||||
|
||||
def tour_included?(name)
|
||||
tours = @controller.tours_to_run
|
||||
tours && tours.include?(name.to_s.classify)
|
||||
end
|
||||
|
||||
it "should add tours to js_env" do
|
||||
Tour.tour(:fake, 1, 'controller#action') { true }
|
||||
expect(tour_included?(:fake)).to be_truthy
|
||||
end
|
||||
|
||||
it "should not include an tour if the block returns false" do
|
||||
Tour.tour(:fake, 1, 'controller#action') { false }
|
||||
expect(tour_included?(:fake)).to be_falsey
|
||||
end
|
||||
|
||||
it "should include an tour if no block is given" do
|
||||
Tour.tour :fake, 1, 'controller#action'
|
||||
expect(tour_included?(:fake)).to be_truthy
|
||||
end
|
||||
|
||||
it "should not include an tour if user has dismissed it" do
|
||||
Tour.tour :dismissed, 1, 'controller#action'
|
||||
expect(tour_included?(:dismissed)).to be_falsey
|
||||
end
|
||||
|
||||
it "should not exclude an tour if user has dismissed an old version of it" do
|
||||
Tour.tour :dismissed, 2, 'controller#action'
|
||||
expect(tour_included?(:dismissed)).to be_truthy
|
||||
end
|
||||
|
||||
it "should not include an tour if user has dismissed it this session" do
|
||||
Tour.tour :dismissed, 1, 'controller#action'
|
||||
expect(tour_included?(:dismissed)).to be_falsey
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -469,21 +469,12 @@ module QuizzesCommon
|
|||
visible_regrade_options[option_index].click
|
||||
fj('.ui-dialog:visible .btn-primary').click
|
||||
wait_for_ajaximations
|
||||
close_regrade_tooltip if driver.browser == :chrome
|
||||
end
|
||||
|
||||
def visible_regrade_options
|
||||
ffj('label.checkbox:visible', '.regrade_enabled')
|
||||
end
|
||||
|
||||
# clicks |Okay, got it|
|
||||
def close_regrade_tooltip
|
||||
move_to_click('.btn.usher-close') if driver.browser == :chrome
|
||||
f('.btn.usher-close').click if driver.browser != :chrome
|
||||
# may need additional case for IE
|
||||
wait_for_ajaximations
|
||||
end
|
||||
|
||||
# clicks |Okay, fine|
|
||||
def close_times_up_dialog
|
||||
times_up_dialog = fj('div#times_up_dialog:visible')
|
||||
|
|
|
@ -40,8 +40,6 @@ describe 'Viewing graded quizzes' do
|
|||
wait_for_ajaximations
|
||||
select_regrade_option(1)
|
||||
wait_for_ajaximations
|
||||
regrade_tour = f('#tour-quiz-regrade-step1')
|
||||
close_regrade_tooltip if driver.browser == :chrome && regrade_tour.displayed?
|
||||
save_question
|
||||
expect_new_page_load { click_save_settings_button }
|
||||
|
||||
|
|
Loading…
Reference in New Issue