diff --git a/core/MAINTAINERS.txt b/core/MAINTAINERS.txt index c289eb5..16e9b28 100644 --- a/core/MAINTAINERS.txt +++ b/core/MAINTAINERS.txt @@ -307,6 +307,9 @@ Taxonomy module Toolbar module - ? +Tour module +- Nick Schuch 'nick_schuch' http://drupal.org/user/1412036 + Tracker module - David Strauss 'David Strauss' http://drupal.org/user/93254 diff --git a/core/modules/tour/js/tour.js b/core/modules/tour/js/tour.js index 975a258..d8885be 100644 --- a/core/modules/tour/js/tour.js +++ b/core/modules/tour/js/tour.js @@ -12,46 +12,48 @@ */ Drupal.behaviors.tour = { attach: function (context) { - var model = new Drupal.tour.models.StateModel(); - var view = new Drupal.tour.views.ToggleTourView({ - el: $(context).find('#toolbar-tab-tour'), - model: model - }); - - // Update the model based on Overlay events. - $(document) - // Overlay is opening: cancel tour if active and mark overlay as open. - .on('drupalOverlayOpen.tour', function () { - model.set({ isActive: false, overlayIsOpen: true }); - }) - // Overlay is loading a new URL: clear tour & cancel if active. - .on('drupalOverlayBeforeLoad.tour', function () { - model.set({ isActive: false, overlayTour: [] }); - }) - // Overlay is closing: clear tour & cancel if active, mark overlay closed. - .on('drupalOverlayClose.tour', function () { - model.set({ isActive: false, overlayIsOpen: false, overlayTour: [] }); - }) - // Overlay has loaded DOM: check whether a tour is available. - .on('drupalOverlayReady.tour', function () { - // We must select the tour in the Overlay's window using the Overlay's - // jQuery, because the joyride plugin only works for the window in which - // it was loaded. - // @todo Make upstream contribution so this can be simplified, which - // should also allow us to *not* load jquery.joyride.js in the Overlay, - // resulting in better front-end performance. - var overlay = Drupal.overlay.iframeWindow; - var $overlayContext = overlay.jQuery(overlay.document); - model.set('overlayTour', $overlayContext.find('#tour')); + $('body').once('tour', function (index, element) { + var model = new Drupal.tour.models.StateModel(); + var view = 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('#tour')); + // Update the model based on Overlay events. + $(document) + // Overlay is opening: cancel tour if active and mark overlay as open. + .on('drupalOverlayOpen.tour', function () { + model.set({ isActive: false, overlayIsOpen: true }); + }) + // Overlay is loading a new URL: clear tour & cancel if active. + .on('drupalOverlayBeforeLoad.tour', function () { + model.set({ isActive: false, overlayTour: [] }); + }) + // Overlay is closing: clear tour & cancel if active, mark overlay closed. + .on('drupalOverlayClose.tour', function () { + model.set({ isActive: false, overlayIsOpen: false, overlayTour: [] }); + }) + // Overlay has loaded DOM: check whether a tour is available. + .on('drupalOverlayReady.tour', function () { + // We must select the tour in the Overlay's window using the Overlay's + // jQuery, because the joyride plugin only works for the window in which + // it was loaded. + // @todo Make upstream contribution so this can be simplified, which + // should also allow us to *not* load jquery.joyride.js in the Overlay, + // resulting in better front-end performance. + var overlay = Drupal.overlay.iframeWindow; + var $overlayContext = overlay.jQuery(overlay.document); + model.set('overlayTour', $overlayContext.find('ol#tour')); + }); + + 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')); + }); } }; @@ -199,4 +201,4 @@ Drupal.tour.views.ToggleTourView = Backbone.View.extend({ }); -})(jQuery, Backbone, Drupal, document); +})(jQuery, Backbone, Drupal, document); \ No newline at end of file diff --git a/core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php b/core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php index 71ce552..89a7e76 100644 --- a/core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php +++ b/core/modules/tour/lib/Drupal/tour/Plugin/Core/Entity/Tour.php @@ -13,7 +13,7 @@ use Drupal\tour\TipsBag; /** - * Defines the configured text tour entity. + * Defines the configured tour entity. * * @Plugin( * id = "tour", diff --git a/core/modules/tour/lib/Drupal/tour/Plugin/tour/tip/TipPluginText.php b/core/modules/tour/lib/Drupal/tour/Plugin/tour/tip/TipPluginText.php index c492d8e..c189d23 100644 --- a/core/modules/tour/lib/Drupal/tour/Plugin/tour/tip/TipPluginText.php +++ b/core/modules/tour/lib/Drupal/tour/Plugin/tour/tip/TipPluginText.php @@ -87,9 +87,8 @@ public function getAttributes() { * Overrides \Drupal\tour\Plugin\tour\tour\TipPluginInterface::getOutput(); */ public function getOutput() { - return array( - '#markup' => '

' . check_plain($this->getLabel()) . '

-

' . filter_xss_admin($this->getBody()) . '

' - ); + $output = '

' . check_plain($this->getLabel()) . '

'; + $output .= '

' . filter_xss_admin($this->getBody()) . '

'; + return array('#markup' => $output); } } diff --git a/core/modules/tour/lib/Drupal/tour/Tests/TourPluginTest.php b/core/modules/tour/lib/Drupal/tour/Tests/TourPluginTest.php index 188e83c..8256eed 100644 --- a/core/modules/tour/lib/Drupal/tour/Tests/TourPluginTest.php +++ b/core/modules/tour/lib/Drupal/tour/Tests/TourPluginTest.php @@ -28,9 +28,6 @@ class TourPluginTest extends DrupalUnitTestBase { */ protected $pluginManager; - /** - * Defines test info. - */ public static function getInfo() { return array( 'name' => 'Tour plugin tests', @@ -39,9 +36,6 @@ public static function getInfo() { ); } - /** - * Sets up the test. - */ protected function setUp() { parent::setUp(); diff --git a/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php b/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php index e8b97f5..6e45d3f 100644 --- a/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php +++ b/core/modules/tour/lib/Drupal/tour/Tests/TourTest.php @@ -44,19 +44,19 @@ public function testTourFunctionality() { $this->drupalGet('tour-test-1'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-1', - ':text' => 'The first tip' + ':text' => 'The first tip', )); $this->assertEqual(count($elements), 1, 'Found English variant of tip 1.'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-2', - ':text' => 'The quick brown fox' + ':text' => 'The quick brown fox', )); $this->assertNotEqual(count($elements), 1, 'Did not find English variant of tip 2.'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-1', - ':text' => 'La pioggia cade in spagna' + ':text' => 'La pioggia cade in spagna', )); $this->assertNotEqual(count($elements), 1, 'Did not find Italian variant of tip 1.'); @@ -67,13 +67,13 @@ public function testTourFunctionality() { $this->drupalGet('tour-test-2/subpath'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-2', - ':text' => 'The quick brown fox' + ':text' => 'The quick brown fox', )); $this->assertEqual(count($elements), 1, 'Found English variant of tip 2.'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-1', - ':text' => 'The first tip' + ':text' => 'The first tip', )); $this->assertNotEqual(count($elements), 1, 'Did not find English variant of tip 1.'); @@ -84,13 +84,13 @@ public function testTourFunctionality() { $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-1', - ':text' => 'La pioggia cade in spagna' + ':text' => 'La pioggia cade in spagna', )); $this->assertEqual(count($elements), 1, 'Found Italian variant of tip 1.'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-test-1', - ':text' => 'The first tip' + ':text' => 'The first tip', )); $this->assertNotEqual(count($elements), 1, 'Did not find English variant of tip 1.'); @@ -131,17 +131,17 @@ public function testTourFunctionality() { $this->drupalGet('tour-test-1'); $elements = $this->xpath('//li[@data-id=:data_id and ./h2[contains(., :text)]]', array( ':data_id' => 'tour-code-test-1', - ':text' => 'The rain in spain' + ':text' => 'The rain in spain', )); $this->assertEqual(count($elements), 1, 'Found the required tip markup for tip 4'); // Verify that the weight sorting works by ensuring the lower weight item - // (tip 4) has the close button. - $elements = $this->xpath('//li[@data-id=:data_id and ./div[contains(., :text)]]', array( + // (tip 4) has the 'End tour' button. + $elements = $this->xpath('//li[@data-id=:data_id and @data-text=:text]', array( ':data_id' => 'tour-code-test-1', - ':text' => '3 of 3' + ':text' => 'End tour', )); - $this->assertEqual(count($elements), 1, 'Found code tip was weighted last and had "3 of 3".'); + $this->assertEqual(count($elements), 1, 'Found code tip was weighted last and had "End tour".'); // Test hook_tour_alter(). $this->assertText('Altered by hook_tour_tips_alter'); diff --git a/core/modules/tour/lib/Drupal/tour/TipPluginBase.php b/core/modules/tour/lib/Drupal/tour/TipPluginBase.php index 4779061..a9d42e0 100644 --- a/core/modules/tour/lib/Drupal/tour/TipPluginBase.php +++ b/core/modules/tour/lib/Drupal/tour/TipPluginBase.php @@ -45,6 +45,7 @@ */ public function __construct(array $configuration, $plugin_id, CacheDecorator $discovery) { parent::__construct($configuration, $plugin_id, $discovery); + $this->definition = $this->discovery->getDefinition($plugin_id); $this->module = $this->definition['module']; } diff --git a/core/modules/tour/lib/Drupal/tour/TourManager.php b/core/modules/tour/lib/Drupal/tour/TourManager.php index 633006d..ee44c9b 100644 --- a/core/modules/tour/lib/Drupal/tour/TourManager.php +++ b/core/modules/tour/lib/Drupal/tour/TourManager.php @@ -14,7 +14,7 @@ use Drupal\Component\Plugin\Discovery\ProcessDecorator; /** - * Configurable text tour manager. + * Configurable tour manager. */ class TourManager extends PluginManagerBase { @@ -30,6 +30,8 @@ public function __construct() { /** * Overrides \Drupal\Component\Plugin\PluginManagerBase::createInstance(). + * + * Pass the TipsBag to the plugin constructor. */ public function createInstance($plugin_id, array $configuration = array(), TipsBag $bag = NULL) { $plugin_class = DefaultFactory::getPluginClass($plugin_id, $this->discovery); diff --git a/core/modules/tour/tests/tour_test/lib/Drupal/tour_test/Plugin/tour/tip/TipPluginImage.php b/core/modules/tour/tests/tour_test/lib/Drupal/tour_test/Plugin/tour/tip/TipPluginImage.php index af280a3..bde0902 100644 --- a/core/modules/tour/tests/tour_test/lib/Drupal/tour_test/Plugin/tour/tip/TipPluginImage.php +++ b/core/modules/tour/tests/tour_test/lib/Drupal/tour_test/Plugin/tour/tip/TipPluginImage.php @@ -40,9 +40,9 @@ class TipPluginImage extends TipPluginBase { * Overrides \Drupal\tour\Plugin\tour\tour\TipPluginInterface::getOutput(). */ public function getOutput() { - return array( - '#markup' => '

' . check_plain($this->get('label')) . '

-

' . theme('image', array('uri' => $this->get('url'), 'alt' => $this->get('alt'))) . '

' - ); + $output = '

' . check_plain($this->get('label')) . '

'; + $output .= '

' . theme('image', array('uri' => $this->get('url'), 'alt' => $this->get('alt'))) . '

'; + return array('#markup' => $output); } + } diff --git a/core/modules/tour/tour.module b/core/modules/tour/tour.module index 391b9a6..7c1e1d6 100644 --- a/core/modules/tour/tour.module +++ b/core/modules/tour/tour.module @@ -106,6 +106,11 @@ function tour_toolbar() { * Implements hook_preprocess_HOOK() for page.tpl.php. */ function tour_preprocess_page(&$variables) { + if (!user_access('access tour')) { + return; + } + + // @todo replace this with http://drupal.org/node/1918768 once it is committed. $path = current_path(); $langcode = language(LANGUAGE_TYPE_CONTENT)->langcode; $tour_items = array(); @@ -161,6 +166,11 @@ function tour_preprocess_page(&$variables) { $index++; } + // Give the last tip the "End tour" button. + end($list_items); + $key = key($list_items); + $list_items[$key]['#wrapper_attributes']['data-text'] = t('End tour'); + $variables['page']['help']['tour'] = array( '#theme' => 'item_list', '#items' => $list_items, @@ -191,14 +201,14 @@ function tour_preprocess_page(&$variables) { } /** - * Implements hook_tour_tour_insert(). + * Implements hook_tour_insert(). */ function tour_tour_insert($entity) { drupal_container()->get('plugin.manager.tour')->clearCachedDefinitions(); } /** - * Implements hook_tour_tour_update(). + * Implements hook_tour_update(). */ function tour_tour_update($entity) { drupal_container()->get('plugin.manager.tour')->clearCachedDefinitions();