diff --git a/protected/humhub/docs/CHANGELOG.md b/protected/humhub/docs/CHANGELOG.md
index 4104c9c4fa..b28b0cbafd 100644
--- a/protected/humhub/docs/CHANGELOG.md
+++ b/protected/humhub/docs/CHANGELOG.md
@@ -11,7 +11,8 @@ HumHub Change Log
- Fix: #3552 `humhub\modules\user\authclient\AuthAction:auth()` not compatible with `yii\authclient\AuthAction:auth()`
- Fix: #3545 OEmbed fetch limit ignored
- Enh: Added `humhub\libs\RestrictedCallException`
-
+- Chng: Switched from [bootstrap-tour](https://github.com/sorich87/bootstrap-tour) to [bootstrap-tourist](https://github.com/IGreatlyDislikeJavascript/bootstrap-tourist) due to incompatibility to bootstrap v3.4.1
+- Enh: Added `humhub.modules.tour` module for handling tour logic
1.3.12 (March 26, 2019)
---------------------------
diff --git a/protected/humhub/models/UrlOembed.php b/protected/humhub/models/UrlOembed.php
index 99da29da41..c20f2db1db 100644
--- a/protected/humhub/models/UrlOembed.php
+++ b/protected/humhub/models/UrlOembed.php
@@ -176,7 +176,7 @@ class UrlOembed extends ActiveRecord
}
try {
- if (!static::findExistingOembed($url)) {
+ if (!self::findExistingOembed($url)) {
static::loadUrl($url);
}
} catch(RestrictedCallException $re) {
diff --git a/protected/humhub/modules/stream/tests/codeception/acceptance.suite.yml b/protected/humhub/modules/stream/tests/codeception/acceptance.suite.yml
index 9fdd29247e..ac654c6b92 100644
--- a/protected/humhub/modules/stream/tests/codeception/acceptance.suite.yml
+++ b/protected/humhub/modules/stream/tests/codeception/acceptance.suite.yml
@@ -18,4 +18,5 @@ modules:
WebDriver:
url: 'http://localhost:8080/'
browser: chrome
+ window_size: maximize
port: 4444
\ No newline at end of file
diff --git a/protected/humhub/modules/tour/assets/TourAsset.php b/protected/humhub/modules/tour/assets/TourAsset.php
new file mode 100644
index 0000000000..15944d045f
--- /dev/null
+++ b/protected/humhub/modules/tour/assets/TourAsset.php
@@ -0,0 +1,58 @@
+ true];
+
+ /**
+ * @inheritdoc
+ */
+ public $js = [
+ 'js/bootstrap-tourist.min.js',
+ 'js/humhub.tour.js'
+ ];
+
+ public $css = [
+ 'css/bootstrap-tourist.min.css'
+ ];
+
+ /**
+ * @param View $view
+ * @return AssetBundle
+ */
+ public static function register($view)
+ {
+ $view->registerJsConfig('tour', [
+ 'dashboardUrl' => Url::to(['/dashboard/dashboard']),
+ 'completedUrl' => Url::to(['/tour/tour/tour-completed']),
+ 'template' => '
'
+ ]);
+ return parent::register($view);
+ }
+}
+
diff --git a/protected/humhub/modules/tour/controllers/TourController.php b/protected/humhub/modules/tour/controllers/TourController.php
index eb9403c26a..f53f71df82 100644
--- a/protected/humhub/modules/tour/controllers/TourController.php
+++ b/protected/humhub/modules/tour/controllers/TourController.php
@@ -8,6 +8,7 @@
namespace humhub\modules\tour\controllers;
+use humhub\modules\space\models\Membership;
use Yii;
use yii\web\HttpException;
use humhub\modules\space\models\Space;
@@ -22,16 +23,10 @@ use humhub\modules\space\models\Space;
*/
class TourController extends \humhub\components\Controller
{
-
- /**
- * @inheritdoc
- */
- public function behaviors()
+ public function getAccessRules()
{
return [
- 'acl' => [
- 'class' => \humhub\components\behaviors\AccessControl::class,
- ]
+ ['login']
];
}
@@ -42,19 +37,16 @@ class TourController extends \humhub\components\Controller
{
// get section parameter from completed tour
- $section = Yii::$app->request->get('section');
+ $section = Yii::$app->request->post('section');
- if (!in_array($section, Yii::$app->params['tour']['acceptableNames']))
+ if (!in_array($section, Yii::$app->params['tour']['acceptableNames'])) {
return;
+ }
// set tour status to seen for current user
Yii::$app->getModule('tour')->settings->user()->set($section, 1);
}
- /*
- * Update user settings for hiding tour panel on dashboard
- */
-
public function actionHidePanel()
{
// set tour status to seen for current user
@@ -62,7 +54,10 @@ class TourController extends \humhub\components\Controller
}
/**
- * This is a special case, because we need to find a space to start the tour
+ * This is a special case, because we need to find a space to start the tour
+ *
+ * @return \yii\web\Response
+ * @throws HttpException
*/
public function actionStartSpaceTour()
{
@@ -70,7 +65,7 @@ class TourController extends \humhub\components\Controller
$space = null;
// Loop over all spaces where the user is member
- foreach (\humhub\modules\space\models\Membership::getUserSpaces() as $space) {
+ foreach (Membership::getUserSpaces() as $space) {
if ($space->isAdmin() && !$space->isArchived()) {
// If user is admin on this space, it´s the perfect match
break;
diff --git a/protected/humhub/modules/tour/resources/css/bootstrap-tourist.css b/protected/humhub/modules/tour/resources/css/bootstrap-tourist.css
new file mode 100644
index 0000000000..27658b5a31
--- /dev/null
+++ b/protected/humhub/modules/tour/resources/css/bootstrap-tourist.css
@@ -0,0 +1,66 @@
+/* ========================================================================
+ * Bootstrap Tourist v0.7
+ * Copyright FFS 2019
+ * @ IGreatlyDislikeJavascript on Github
+ *
+ * bootstrap-tour - v0.11.0
+ * http://bootstraptour.com
+ * ========================================================================
+ * Copyright 2012-2015 Ulrich Sossou
+ *
+ * ========================================================================
+ * Licensed under the MIT License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/MIT
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================================
+ */
+
+.tour-backdrop {
+ position: absolute;
+ z-index: 1100;
+ background-color: #000;
+ opacity: 0.8;
+ filter: alpha(opacity=80);
+}
+.tour-prevent {
+ position: absolute;
+ z-index: 1102;
+ background-color: #ccc;
+ opacity: 0.20;
+ filter: alpha(opacity=20);
+}
+.popover[class*="tour-"] {
+ z-index: 1110;
+}
+.popover[class*="tour-"] .popover-navigation {
+ padding: 9px 14px;
+ overflow: hidden;
+}
+.popover[class*="tour-"] .popover-navigation *[data-role="end"] {
+ float: right;
+}
+.popover[class*="tour-"] .popover-navigation *[data-role="prev"],
+.popover[class*="tour-"] .popover-navigation *[data-role="next"],
+.popover[class*="tour-"] .popover-navigation *[data-role="end"] {
+ cursor: pointer;
+}
+.popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,
+.popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,
+.popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled {
+ cursor: default;
+}
+.popover[class*="tour-"].orphan {
+ position: fixed;
+ margin-top: 0;
+}
+.popover[class*="tour-"].orphan .arrow {
+ display: none;
+}
\ No newline at end of file
diff --git a/protected/humhub/modules/tour/resources/css/bootstrap-tourist.min.css b/protected/humhub/modules/tour/resources/css/bootstrap-tourist.min.css
new file mode 100644
index 0000000000..932d283cf1
--- /dev/null
+++ b/protected/humhub/modules/tour/resources/css/bootstrap-tourist.min.css
@@ -0,0 +1 @@
+.tour-backdrop{position:absolute;z-index:1100;background-color:#000;opacity:.8;filter:alpha(opacity=80)}.tour-prevent{position:absolute;z-index:1102;background-color:#ccc;opacity:.20;filter:alpha(opacity=20)}.popover[class*="tour-"]{z-index:1110}.popover[class*="tour-"] .popover-navigation{padding:9px 14px;overflow:hidden}.popover[class*="tour-"] .popover-navigation *[data-role="end"]{float:right}.popover[class*="tour-"] .popover-navigation *[data-role="prev"],.popover[class*="tour-"] .popover-navigation *[data-role="next"],.popover[class*="tour-"] .popover-navigation *[data-role="end"]{cursor:pointer}.popover[class*="tour-"] .popover-navigation *[data-role="prev"].disabled,.popover[class*="tour-"] .popover-navigation *[data-role="next"].disabled,.popover[class*="tour-"] .popover-navigation *[data-role="end"].disabled{cursor:default}.popover[class*="tour-"].orphan{position:fixed;margin-top:0}.popover[class*="tour-"].orphan .arrow{display:none}
\ No newline at end of file
diff --git a/protected/humhub/modules/tour/resources/js/bootstrap-tourist.js b/protected/humhub/modules/tour/resources/js/bootstrap-tourist.js
new file mode 100644
index 0000000000..67f4f40165
--- /dev/null
+++ b/protected/humhub/modules/tour/resources/js/bootstrap-tourist.js
@@ -0,0 +1,2293 @@
+/* ========================================================================
+ *
+ * Bootstrap Tourist v0.10
+ * Copyright FFS 2019
+ * @ IGreatlyDislikeJavascript on Github
+ *
+ * This code is a fork of bootstrap-tour, with a lot of extra features
+ * and fixes. You can read about why this fork exists here:
+ *
+ * https://github.com/sorich87/bootstrap-tour/issues/713
+ *
+ * The entire purpose of this fork is to start rewriting bootstrap-tour
+ * into native ES6 instead of the original coffeescript, and to implement
+ * the features and fixes requested in the github repo. Ideally this fork
+ * will then be taken back into the main repo and become part of
+ * bootstrap-tour again - this is not a fork to create a new plugin!
+ *
+ * I'm not a JS coder, so suggest you test very carefully and read the
+ * docs (comments) below before using.
+ *
+ * ========================================================================
+ * ENTIRELY BASED UPON:
+ *
+ * bootstrap-tour - v0.11.0
+ * http://bootstraptour.com
+ * ========================================================================
+ * Copyright 2012-2015 Ulrich Sossou
+ *
+ * ========================================================================
+ * Licensed under the MIT License (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/MIT
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================================================================
+ *
+ * Updated for CS by FFS 2018 - v0.10
+ *
+ * Changes from 0.9:
+ * - smartPlacement option removed, deprecated
+ * - default params compatibility for IE
+ * - auto progress bar was killed in changes 0.7 -> 0.8 due to Bootstrap sanitizer, this is readded
+ * - major change to manipulation of BS4 popper.js for orphan steps
+ * - change to implementation of backdrop
+ *
+ * Changes from 0.8:
+ * - The fast fix in v0.7 didn't work for Bootstrap 4. This release is to ensure fully working popovers in BS4. Issue is that the Bootstrap CDN
+ * doesn't actually have the whitelist property, so developing against it is basically useless :(
+ * - Improved BS4 support and template switching. Changed options for framework vs template.
+ *
+ * Changes from 0.7:
+ * - Fast release to fix breaking change in Bootstrap 3.4.1, fixes this issue: https://github.com/sorich87/bootstrap-tour/issues/723#issuecomment-471107788
+ * Issue is caused by the BS sanitizer, to avoid this reoccurring the "sanitizeWhitelist:" and "sanitizeFunction:" global options added
+ *
+ * Changes from 0.6:
+ * - Fixed invalid call to debug in _showNextStep()
+ * - Added onPreviouslyEnded() callback: https://github.com/sorich87/bootstrap-tour/issues/720
+ * - Added selector to switch between bootstrap3 and bootstrap4 or custom template, thanks to: https://github.com/sorich87/bootstrap-tour/pull/643
+ *
+ * Changes from 0.5:
+ * - Added "unfix" for bootstrap selectpicker to revert zindex after step that includes this plugin
+ * - Fixed issue with Bootstrap dialogs. Handling of dialogs is now robust
+ * - Fixed issue with BootstrapDialog plugin: https://nakupanda.github.io/bootstrap3-dialog/ . See notes below for help.
+ * - Improved the background overlay and scroll handling, unnecessary work removed
+
+
+ ---------
+
+
+ This fork and code adds following features to Bootstrap Tour
+
+ 1. onNext/onPrevious - prevent auto-move to next step, allow .goTo
+ 2. *** Do not call Tour.init *** - fixed tours with hidden elements on page reload
+ 3. Dynamically determine step element by function
+ 4. Only continue tour when reflex element is clicked using reflexOnly
+ 5. Call onElementUnavailable if step element is missing
+ 6. Scroll flicker/continual step reload fixed
+ 7. Magic progress bar and progress text, plus options to customize per step
+ 8. Prevent user interaction with element using preventInteraction
+ 9. Wait for arbitrary DOM element to be visible before showing tour step/crapping out due to missing element, using delayOnElement
+ 10. Handle bootstrap modal dialogs better - autodetect modals or children of modals, and call onModalHidden to handle when user dismisses modal without following tour steps
+ 11. Automagically fixes drawing issues with Bootstrap Selectpicker (https://github.com/snapappointments/bootstrap-select/)
+ 12. Call onPreviouslyEnded if tour.start() is called for a tour that has previously ended (see docs)
+ 13. Switch between Bootstrap 3 or 4 (popover methods and template) automatically using tour options
+ 14. Added sanitizeWhitelist and sanitizeFunction global options
+
+ --------------
+ 1. Control flow from onNext() / onPrevious() options:
+ Returning false from onNext/onPrevious handler will prevent Tour from automatically moving to the next/previous step.
+ Tour flow methods (Tour.goTo etc) now also work correctly in onNext/onPrevious.
+ Option is available per step or globally:
+
+ var tourSteps = [
+ {
+ element: "#inputBanana",
+ title: "Bananas!",
+ content: "Bananas are yellow, except when they're not",
+ onNext: function(tour){
+ if($('#inputBanana').val() !== "banana")
+ {
+ // no banana? highlight the banana field
+ $('#inputBanana').css("background-color", "red");
+ // do not jump to the next tour step!
+ return false;
+ }
+ }
+ }
+ ];
+
+ var Tour=new Tour({
+ steps: tourSteps,
+ framework: "bootstrap3", // or "bootstrap4" depending on your version of bootstrap
+ onNext: function(tour)
+ {
+ if(someVar = true)
+ {
+ // force the tour to jump to slide 3
+ tour.goTo(3);
+ // Prevent default move to next step - important!
+ return false;
+ }
+ }
+ });
+
+ --------------
+ 2. Do not call Tour.init
+ When setting up Tour, do not call Tour.init().
+ Call Tour.start() to start/resume the Tour from previous step
+ Call Tour.restart() to always start Tour from first step
+
+ Tour.init() was a redundant method that caused conflict with hidden Tour elements.
+
+---------------
+ 3. Dynamically determine element by function
+ Step "element:" option allows element to be determined programmatically. Return a jquery object.
+ The following is possible:
+
+ var tourSteps = [
+ {
+ element: function() { return $(document).find("...something..."); },
+ title: "Dynamic",
+ content: "Element found by function"
+ },
+ {
+ element: "#static",
+ title: "Static",
+ content: "Element found by static ID"
+ }
+ ];
+
+---------------
+ 4. Only continue tour when reflex element is clicked
+ Use step option reflexOnly in conjunction with step option reflex to automagically hide the "next" button in the tour, and only continue when the user clicks the element:
+ var tourSteps = [
+ {
+ element: "#myButton",
+ reflex: true,
+ reflexOnly: true,
+ title: "Click it",
+ content: "Click to continue, or you're stuck"
+ }
+ ];
+
+----------------
+ 5. Call function when element is missing
+ If the element specified in the step (static or dynamically determined as per feature #3), onElementUnavailable is called.
+ Function signature: function(tour, stepNumber) {}
+ Option is available at global and per step levels.
+
+ function tourBroken(tour, stepNumber)
+ {
+ alert("Uhoh, tour element is done broke on step number " + stepNumber);
+ }
+
+ var tourSteps = [
+ {
+ element: "#btnMagic",
+ onElementUnavailable: tourBroken,
+ title: "Hold my beer",
+ content: "now watch this"
+ }
+ ];
+
+---------------
+ 6. Scroll flicker / continue reload fixed
+ Original Tour constantly reloaded the current tour step on scroll & similar events. This produced flickering, constant reloads and therefore constant calls to all the step function calls.
+ This is now fixed. Scrolling the browser window does not cause the tour step to reload.
+
+ IMPORTANT: orphan steps are stuck to the center of the screen. However steps linked to elements ALWAYS stay stuck to their element, even if user scrolls the element & tour popover
+ off the screen. This is my personal preference, as original functionality of tour step moving with the scroll even when the element was off the viewport seemed strange.
+
+---------------
+ 7. Progress bar & progress text:
+ Use the following options globally or per step to show tour progress:
+ showProgressBar - shows a bootstrap progress bar for tour progress at the top of the tour content
+ showProgressText - shows a textual progress (N/X, i.e.: 1/24 for slide 1 of 24) in the tour title
+
+ var tourSteps = [
+ {
+ element: "#inputBanana",
+ title: "Bananas!",
+ content: "Bananas are yellow, except when they're not",
+ },
+ {
+ element: "#inputOranges",
+ title: "Oranges!",
+ content: "Oranges are not bananas",
+ showProgressBar: false, // don't show the progress bar on this step only
+ showProgressText: false, // don't show the progress text on this step only
+ }
+ ];
+ var Tour=new Tour({
+ framework: "bootstrap3", // or "bootstrap4" depending on your version of bootstrap
+ steps: tourSteps,
+ showProgressBar: true, // default show progress bar
+ showProgressText: true, // default show progress text
+ });
+
+ 7b. Customize the progressbar/progress text:
+ In conjunction with 7a, provide the following functions globally or per step to draw your own progressbar/progress text:
+
+ getProgressBarHTML(percent)
+ getProgressTextHTML(stepNumber, percent, stepCount)
+
+ These will be called when each step is shown, with the appropriate percentage/step number etc passed to your function. Return an HTML string of a "drawn" progress bar/progress text
+ which will be directly inserted into the tour step.
+
+ Example:
+ var tourSteps = [
+ {
+ element: "#inputBanana",
+ title: "Bananas!",
+ content: "Bananas are yellow, except when they're not",
+ },
+ {
+ element: "#inputOranges",
+ title: "Oranges!",
+ content: "Oranges are not bananas",
+ getProgressBarHTML: function(percent)
+ {
+ // override the global progress bar function for this step
+ return '
You're ' + percent + ' of the way through!
';
+ }
+ }
+ ];
+ var Tour=new Tour({
+ steps: tourSteps,
+ showProgressBar: true, // default show progress bar
+ showProgressText: true, // default show progress text
+ getProgressBarHTML: function(percent)
+ {
+ // default progress bar for all steps. Return valid HTML to draw the progress bar you want
+ return '
';
+ },
+ getProgressTextHTML: function(stepNumber, percent, stepCount)
+ {
+ // default progress text for all steps
+ return 'Slide ' + stepNumber + "/" + stepCount;
+ },
+
+ });
+
+----------------
+ 8. Prevent interaction with element
+ Sometimes you want to highlight a DOM element (button, input field) for a tour step, but don't want the user to be able to interact with it.
+ Use preventInteraction to stop the user touching the element:
+
+ var tourSteps = [
+ {
+ element: "#btnMCHammer",
+ preventInteraction: true,
+ title: "Hammer Time",
+ content: "You can't touch this"
+ }
+ ];
+
+----------------
+ 9. Wait for an element to appear before continuing tour
+ Sometimes a tour step element might not be immediately ready because of transition effects etc. This is a specific issue with bootstrap select, which is relatively slow to show the selectpicker
+ dropdown after clicking.
+ Use delayOnElement to instruct Tour to wait for **ANY** element to appear before showing the step (or crapping out due to missing element). Yes this means the tour step element can be one DOM
+ element, but the delay will wait for a completely separate DOM element to appear. This is really useful for hidden divs etc.
+ Use in conjunction with onElementUnavailable for robust tour step handling.
+
+ delayOnElement is an object with the following:
+ delayOnElement: {
+ delayElement: "#waitForMe", // the element to wait to become visible, or the string literal "element" to use the step element
+ maxDelay: 2000, // optional milliseconds to wait/timeout for the element, before crapping out. If maxDelay is not specified, this is 2000ms by default
+ }
+
+ var tourSteps = [
+ {
+ element: "#btnPrettyTransition",
+ delayOnElement: {
+ delayElement: "element" // use string literal "element" to wait for this step's element, i.e.: #btnPrettyTransition
+ },
+ title: "Ages",
+ content: "This button takes ages to appear"
+ },
+ {
+ element: "#inputUnrelated",
+ delayOnElement: {
+ delayElement: "#divStuff" // wait until DOM element "divStuff" is visible before showing this tour step against DOM element "inputUnrelated"
+ },
+ title: "Waiting",
+ content: "This input is nice, but you only see this step when the other div appears"
+ },
+ {
+ element: "#btnDontForgetThis",
+ delayOnElement: {
+ delayElement: "element", // use string literal "element" to wait for this step's element, i.e.: #btnDontForgetThis
+ maxDelay: 5000 // wait 5 seconds for it to appear before timing out
+ },
+ title: "Cool",
+ content: "Remember the onElementUnavailable option!",
+ onElementUnavailable: function(tour, stepNumber)
+ {
+ // This will be called if btnDontForgetThis is not visible after 5 seconds
+ console.log("Well that went badly wrong");
+ }
+ },
+ ];
+
+----------------
+ 10. Trigger when modal closes
+ If tour element is a modal, or is a DOM element inside a modal, the element can disappear "at random" if the user dismisses the dialog.
+ In this case, onModalHidden global and per step function is called. Only functional when step is not an orphan.
+ This is useful if a tour includes a step that launches a modal, and the tour requires the user to take some actions inside the modal before OK'ing it and moving to the next
+ tour step.
+
+ Return (int) step number to immediately move to that step
+ Return exactly false to not change tour state in any way - this is useful if you need to reshow the modal because some validation failed
+ Return anything else to move to the next step
+
+ element === Bootstrap modal, or element parent === bootstrap modal is automatically detected.
+
+ var Tour=new Tour({
+ steps: tourSteps,
+ framework: "bootstrap3", // or "bootstrap4" depending on your version of bootstrap
+ onModalHidden: function(tour, stepNumber)
+ {
+ console.log("Well damn, this step's element was a modal, or inside a modal, and the modal just done got dismissed y'all. Moving to step 3.");
+
+ // move to step number 3
+ return 3;
+ },
+ });
+
+
+ var Tour=new Tour({
+ steps: tourSteps,
+ onModalHidden: function(tour, stepNumber)
+ {
+ if(validateSomeModalContent() == false)
+ {
+ // The validation failed, user dismissed modal without properly taking actions.
+ // Show the modal again
+ showModalAgain();
+
+ // Instruct tour to stay on same step
+ return false;
+ }
+ else
+ {
+ // Content was valid. Return null or do nothing to instruct tour to continue to next step
+ }
+ },
+ });
+
+
+
+ 10b. Handle Dialogs and BootstrapDialog plugin better https://nakupanda.github.io/bootstrap3-dialog/
+ Plugin makes creating dialogs very easy, but it does some extra stuff to the dialogs and dynamically creates/destroys them. This
+ causes issues with plugins that want to include a modal dialog in the steps using this plugin.
+
+ To use Tour to highlight an element in a dialog, just use the element ID as you would for any normal step. The dialog will be automatically
+ detected and handled.
+
+ To use Tour to highlight an entire dialog, set the step element to the dialog div. Tour will automatically realize this is a dialog, and
+ shift the element to use the modal-content div inside the dialog. This makes life friendly, because you can do this:
+
+
+
+
+ ...blah...
+
+
+
+
+ Then use element: myModal in the Tour.
+
+
+ FOR BOOTSTRAPDIALOG PLUGIN: this plugin creates random UUIDs for the dialog DOM ID. You need to fix the ID to something you know. Do this:
+
+ dlg = new BootstrapDialog.confirm({
+ ....all the options...
+ });
+
+ // BootstrapDialog gives a random GUID ID for dialog. Give it a proper one
+ $objModal = dlg.getModal();
+ $objModal.attr("id", "myModal");
+ dlg.setId("myModal");
+
+
+ Now you can use element: myModal in the tour, even when the dialog is created by BootstrapDialog plugin.
+
+
+----------------
+ 11. Fix conflict with Bootstrap Selectpicker: https://github.com/snapappointments/bootstrap-select/
+ Selectpicker draws a custom select. Tour now automagically finds and adjusts the selectpicker dropdown so that it appears correctly within the tour
+
+
+----------------
+ 12. Call onPreviouslyEnded if tour.start() is called for a tour that has previously ended
+ See the following github issue: https://github.com/sorich87/bootstrap-tour/issues/720
+ Original behavior for a tour that had previously ended was to call onStart() callback, and then abort without calling onEnd(). This has been altered so
+ that calling start() on a tour that has previously ended (cookie step set to end etc) will now ONLY call onPreviouslyEnded().
+
+ This restores the functionality that allows app JS to simply call tour.start() on page load, and the Tour will now only call onStart() / onEnd() when
+ the tour really is started or ended.
+
+ var Tour=new Tour({
+ steps: [ ..... ],
+ framework: "bootstrap3", // or "bootstrap4" depending on your version of bootstrap
+ onPreviouslyEnded: function(tour)
+ {
+ console.log("Looks like this tour has already ended");
+ },
+ });
+
+ tour.start();
+
+----------------
+ 13. Switch between Bootstrap 3 or 4 (popover methods, template) automatically using tour options, or use a custom template
+ With thanks to this thread: https://github.com/sorich87/bootstrap-tour/pull/643
+
+ Tour is compatible with bootstrap 3 and 4 if the right template and framework is used for the popover. Bootstrap3 framework compatibility is used by default.
+
+ To select the correct template and framework, use the "framework" global option. Note this option does more than just select a template, it also changes which
+ methods are used to manage the Tour popovers to be BS3 or BS4 compatible.
+
+ var Tour=new Tour({
+ steps: tourSteps,
+ template: null, // template option is null by default. Tourist will use the appropriate template
+ // for the framework version, in this case BS3 as per next option
+ framework: "bootstrap3", // can be string literal "bootstrap3" or "bootstrap4"
+ });
+
+
+ To use a custom template, use the "template" global option:
+
+ var Tour=new Tour({
+ steps: tourSteps,
+ framework: "bootstrap4", // can be string literal "bootstrap3" or "bootstrap4"
+ template: '
....blah....
'
+ });
+
+ Review the following logic:
+ - If template == null, default framework template is used based on whether framework is set to "bootstrap3" or "bootstrap4"
+ - If template != null, the specified template is always used
+ - If framework option is not literal "bootstrap3" or "bootstrap4", error will occur
+
+
+ To add additional templates, search the code for "PLACEHOLDER: TEMPLATES LOCATION". This will take you to an array that contains the templates, simply edit
+ or add as required.
+
+
+----------------
+ 14. Options to manipulate the Bootstrap sanitizer, and fix the sanitizer related breaking change in BS 3.4.x
+ BS 3.4.1 added a sanitizer to popover and tooltips - this breaking change strips non-whitelisted DOM elements from popover content, title etc.
+ See: https://getbootstrap.com/docs/3.4/javascript/#js-sanitizer and https://blog.getbootstrap.com/2019/02/13/bootstrap-4-3-1-and-3-4-1/
+
+ This Bootstrap change resulted in Tour navigation buttons being killed from the DOM: https://github.com/sorich87/bootstrap-tour/issues/723#issuecomment-471107788
+
+ This has been fixed in code, Tour navigation buttons now appear and work by default.
+
+ To prevent future similar reoccurrences, and also allow the manipulation of the sanitizer "allowed list" for Tours that want to add extra content into
+ tour steps, two features added to global options. To understand the purpose and operation of these features, review the following information on the Bootstrap
+ sanitizer: https://getbootstrap.com/docs/3.4/javascript/#js-sanitizer
+
+ --IMPORTANT NOTE-- SECURITY RISK: if you do not understand the purpose of the sanitizer, why it exists in bootstrap or how it relates to Tour, do not use these options.
+
+ Global options:
+
+ sanitizeWhitelist: specify an object that will be merged with the Bootstrap Popover default whitelist. Use the same structure as the default Bootstrap
+ whitelist.
+
+ sanitizeFunction: specify a function that will be used to sanitize Tour content, with the following signature: string function(content).
+ Specifying a function for this option will cause sanitizeWhitelist to be ignored.
+ Specifying anything other than a function for this option will be ignored, and sanitizeWhitelist will be used
+
+ Examples:
+
+ Allow tour step content to include a button with attributes data-someplugin1="..." and data-somethingelse="...". Allow content to include a selectpicker.
+ var Tour=new Tour({
+ steps: tourSteps,
+ sanitizeWhitelist: {
+ "button" : ["data-someplugin1", "data-somethingelse"], // allows