/** * @file * Attaches behaviors for the Tour module's toolbar tab. */ (function ($, Backbone, Drupal, document) { "use strict"; var queryString = decodeURI(window.location.search); /** * Attaches the tour's toolbar tab behavior. * * It uses the query string for: * - tour: When ?tour=1 is present, the tour will start automatically * after the page has loaded. * - tips: Pass ?tips=class in the url to filter the available tips to * the subset which match the given class. * * Example: * http://example.com/foo?tour=1&tips=bar */ Drupal.behaviors.tour = { attach: function (context) { $('body').once('tour', function (index, element) { var model = new Drupal.tour.models.StateModel(); new Drupal.tour.views.ToggleTourView({ el: $(context).find('#toolbar-tab-tour'), model: model }); model // Allow other scripts to respond to tour events. .on('change:isActive', function (model, isActive) { $(document).trigger((isActive) ? 'drupalTourStarted' : 'drupalTourStopped'); }) // Initialization: check whether a tour is available on the current page. .set('tour', $(context).find('ol#tour')); // Start the tour immediately if toggled via query string. if (/tour=?/i.test(queryString)) { model.set('isActive', true); } }); } }; Drupal.tour = Drupal.tour || {models: {}, views: {}}; /** * Backbone Model for tours. */ Drupal.tour.models.StateModel = Backbone.Model.extend({ defaults: { // Indicates whether the Drupal root window has a tour. tour: [], // Indicates whether the tour is currently running. isActive: false, // Indicates which tour is the active one (necessary to cleanly stop). activeTour: [] } }); /** * Handles edit mode toggle interactions. */ Drupal.tour.views.ToggleTourView = Backbone.View.extend({ events: {'click': 'onClick'}, /** * Implements Backbone Views' initialize(). */ initialize: function () { this.listenTo(this.model, 'change:tour change:isActive', this.render); this.listenTo(this.model, 'change:isActive', this.toggleTour); }, /** * Implements Backbone Views' render(). */ render: function () { // Render the visibility. this.$el.toggleClass('hidden', this._getTour().length === 0); // Render the state. var isActive = this.model.get('isActive'); this.$el.find('button') .toggleClass('active', isActive) .prop('aria-pressed', isActive); return this; }, /** * Model change handler; starts or stops the tour. */ toggleTour: function () { if (this.model.get('isActive')) { var $tour = this._getTour(); this._removeIrrelevantTourItems($tour, this._getDocument()); var that = this; if ($tour.find('li').length) { $tour.joyride({ autoStart: true, postRideCallback: function () { that.model.set('isActive', false); }, template: { // HTML segments for tip layout link: '×', button: '' } }); this.model.set({isActive: true, activeTour: $tour}); } } else { this.model.get('activeTour').joyride('destroy'); this.model.set({isActive: false, activeTour: []}); } }, /** * Toolbar tab click event handler; toggles isActive. */ onClick: function (event) { this.model.set('isActive', !this.model.get('isActive')); event.preventDefault(); event.stopPropagation(); }, /** * Gets the tour. * * @return jQuery * A jQuery element pointing to a