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:
Ryan Shaw 2016-04-12 09:47:42 -06:00
parent 2876c583e3
commit 80a7fb0941
28 changed files with 1 additions and 1580 deletions

View File

@ -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"

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"; }

View File

@ -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";

View File

@ -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>
Its 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;
}

View File

@ -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 courses 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>

View File

@ -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 youve changed an answer youll 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>

View File

@ -1,2 +0,0 @@
require 'lib/tour'
require 'config/tours'

View File

@ -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

View File

@ -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

View File

@ -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',

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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;
});

View File

@ -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;
});

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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')

View File

@ -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 }