instructorjs
Version:
On-screen tutorials for web pages and web applications
354 lines (237 loc) • 12.4 kB
Markdown
On-screen tutorials for web pages and web applications
<img width="587" height="418" src="docs/images/instructor.gif">
InstructorJS provides a simple way to add tutorials to your website or web application.
Check out the demo [here](https://jasongardnerlv.github.io/instructor/website/index.html), and the demo source [here](https://github.com/jasongardnerlv/instructor/tree/master/demo).
InstructorJS depends on **JQuery** version 2.2.4, **JQuery ScrollTo** version 2.1.2, and **Konva** version 4.1.2.
Pull it via **Yarn**/**NPM**, or grab the minified versions from this repository.
```bash
$ yarn add instructorjs
```
or
```bash
$ npm i instructorjs
```
Once installed, you'll import the javascript and css files into your page:
```html
<html>
<head>
<!-- import the InstructorJS styles -->
<link
rel="stylesheet"
href="/node_modules/instructorjs/instructor.min.css"
/>
<!-- import the InstructorJS dependencies -->
<script src="/node_modules/jquery/jquery.min.js"></script>
<script src="/node_modules/konva/konva.min.js"></script>
<!-- import the InstructorJS library -->
<script type="module" src="/node_modules/instructorjs/instructor.min.js">
import {jqueryScrollTo} from 'jqueryScrollTo/jquery-scrollto.min.js';
import {InstructorFactory} from 'instructor/instructor.min.js'
jqueryScrollTo(window.$);
</script>
</head>
...
</html>
```
### Fonts
The default font for Instructor is _Gemelli_ and should be placed at **/fonts/gemelli.ttf**.
You can override this in your sites CSS, to import from a different location or import another font altogether:
```css
@font-face {
font-family: "Pacifico";
src: url("/path/to/fonts/Pacifico-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
.instructor .instructor_label {
font-family: "Pacifico", "Arial";
}
```
Create an **Instructor** instance and pass a configuration object.:
```javascript
const instructorFactory = InstructorFactory();
var instructor = new instructorFactory({
onEnd: function(startNextTutorial, cb) {
console.log("Tutorial Done!");
}
});
```
Then, you call the _run()_ method, passing the array of tutorial **Steps**:
```javascript
instructor.run([
{
event: "next",
description: "Hi, Welcome to the tutorial. Click <em>Next</em> to begin!"
},
{
event: "click",
selector: "#btnSave",
description: "Click the <strong>Save</strong> button to continue."
},
{
event: "finish",
description: "This completes the tutorial!"
}
]);
```
For information on tutorials that span multiple pages of a website, see [**Multi-Page Tutorials**](
See below for information on step configuration:
`customValidators`: (object) Collection of validation functions to use within steps. E.g. an email validator:
```javascript
var instructor = new Instructor({
customValidators: {
emailValidator: function(value) {
var emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return emailRegex.test(String(value).toLowerCase());
}
}
});
```
`onEnd`: (function) Called when the tutorials are complete. Provides 2 arguments:
- `triggerNextTutorial`: Passes the triggerNextTutorial from the main configs or final step config.
- `callback`: If provided, should be executed after your onEnd logic is processed, to facilitate final cleanup.
`onNext`: (function) Invoked on each step of the tutorial.
`onSkip`: (function) Invoked when the user clicks the 'X' to skip the tutorial.
`onStart`: (function) Invoked when the tutorial begins.
`nextLabel`: (string) The label to show on the next button, default is **Next**
`finishLabel`: (string) The label to show on the finish button, default is **Finish**
`sanitizer`: (function) A function that takes string and returns the _sanitized_ version of the string, used to do replacements within the step description text. Can be useful when needing to substitute values in the description, such as the host of a URL. For example:
```javascript
var instructor = new Instructor({
sanitizer: function(str) {
str = str.replace(
/\*\|current_url\|\*/g,
window.location.origin + window.location.pathname
);
return str;
}
});
```
`navigateOnFinish`: (string) An optional URL to navigate the browser to, upon completion of the tutorial.
`navigateOnFinishTarget`: (string) The window target, i.e. **\_blank**, **\_self**, etc
`reloadOnFinish`: (boolean) Reload the browser, upon completion of the tutorial.
`triggerNextTutorial`: (boolean) Passed to the _onEnd()_ function, to indicate the next tutorial should be started.
`event`: (string) The type of event that triggers advancement from this step. Types are:
- `next`: Provides a _next_ button and advances on button click.
- `trigger`: Advances on a DOM event. See `triggerEvent` below.
- `auto`: Immediately advances (no user interaction required).
- `finish`: Provides a _finish_ button and completes the tutorial upon click.
- `select`: Advances on selection of an HTML select control.
- `submit`: Advances on HTML form submission.
- `key`: Advances on keystroke. See `keyCode` below.
`description`: (string) The text to display for this step. Can include HTML. See [**Description Styling**](#description-styling) below.
`selector`: (string) The CSS selector or element reference that corresponds to the area that will be highlighted (cutout and arrow).
`preventInteraction`: (boolean) Whether or not the user should be able to interact with the highlighted area | default: false
`defaultValue`: (string) The initial value to set on the input control (or any element supporting _.val()_).
`eventSelector`: (string) Use this to specify an alternate selector or element reference, when the element that you want to highlight differs from the one that will produce the event.
`triggerEvent`: (string) When using the `trigger` event type, this used to specify the event that will cause the trigger, such as _click_.
`validation`: (object) Validates a input control before allowing advancement. Properties include:
- `selector`: (string) The CSS selector or element reference of the element that is going to be validated.
- `customValidator`: (string) Optionally, the name of validator from the `customValidators` top-level configurations.
- `valueFunction`: (string) The JQuery function to call on the element to get the value for comparison, e.g. "val","html","text",etc.
- `value`: (string) The value to compare to the result of the `valueFunction` to test validity.
- `invert`: (boolean) Whether the inverse of the value test is valid. Useful for testing for _not empty_ when `value` is set to ""
`exists`: (boolean) Only runs the step if the selector is actually present on the page.
`marginX`/`marginY`: (number) Extra margin within the highlight area, making the cutout larger
`bottom`/`left`/`right`/`top`: (number) Reduces the size of the highlight area, making the cutout smaller (negative numbers have the opposite effect)
`timeout`: (number) Time, in millis, to delay before the step displays (such as waiting for a page animation to complete). | default: 100
`noScroll`: (boolean) When highlighting an element, do not try to automatically scroll the element into view. | default: false
`preventAutoFocus`: (boolean) When highlighting an element, do not apply focus automatically to the element. | default: false
`scroller`: (string|element) CSS selector or element reference that will be used to scroll the highlighted element into focus. | default: document.body
`repositionEvent`: (object) Used to reposition the text/highlight/arrow on a page event (things on the page moved around while the step was shown). Properties include:
- `selector`: (string|element) CSS selector or element reference to listen for the event on.
- `event`: (string) The name of the event to listen for.
`shape`: (string) The shape of the highlight cutout. Options are "rect" and "circle". | default: rect
`radius`: (number) If using a "circle" `shape`, this controls the radius of the highlight cutout. | default: computed off the max dimension of the element
`onBeforeStart`: (function) Invoked before the step is run.
`onAfterEnd`: (function) Invoked after the step is run.
`isBootstrapEvent` (boolean) If using Bootstrap, this can be used to handle Bootstrap events, such as setting the `event` property to _show.bs.modal_, in order to advance the step when the Bootstrap modal is shown.
`isTinyMce`: (boolean) If using TinyMCE, set this to true, in order to set the `defaultValue` of the text editor. | default: false
`scrollAnimationSpeed`: (number) Controls the speed of the animation of the step content and scrolling (in millis). | default: 250
## Description Styling
Within the step description HTML string, there are a few HTML tags that have been repurposed as short-hand for certain style characteristics. Classes are available, as an alternative.
They include:
`<strong/>`: Blue font color, generally used to draw attention to a specific word or phrase. | CSS class _instructor_primary_
`<em/>`: Green font color, generally used to indicate an action with positive outcome. | CSS class _instructor_success_
`<del/>`: Red font color, generally used to indicate an action with negative outcome. | CSS class _instructor_danger_
`<ins/>`: Yellow font color, generally used to indicate example text. | CSS class _instructor_example_
## Multi-Page Tutorials
Often, you'll have tutorials that span multiple pages of a website, or need to continue after a browser refresh. InstructorJS does not maintain state, but does
provide a few hooks that let you easily manage progress of a tutorial, so that you can resume a tutorial across navigation/reload. The **Demo** provided with
InstructorJS illustrates this simply using _LocalStorage_, but you could store progress in whatever manner makes sense for your application.
The relevant parts of the demo explained:
```javascript
//find the current tutorial Id stored in LocalStorage
var cachedTut = localStorage.getItem("instructor-tut");
//if it doesn't exist, then we're at zero (the beginning)
var finishedTut = cachedTut ? Number(cachedTut) : 0;
//Start InstructorJS
runTutorial();
function runTutorial() {
//Create an InstructorJS instance
var instructor = new Instructor({
onSkip: function() {
//if we click the "X" button to skip the tutorial, let's remove any progress so far
localStorage.removeItem("instructor-tut");
},
onEnd: function(startNextTutorial, cb) {
//done with the tutorial, increment the counter and update LocalStorage
++finishedTut;
localStorage.setItem("instructor-tut", finishedTut);
//call the callback, mainly necessary for "submit" event types
if (cb) cb();
//if the tutorial is configured to kick the next tutorial on completion, start it
//otherwise, clear out LocalStorage, so the demo can be restarted on next visit
if (startNextTutorial) runTutorial();
else localStorage.removeItem("instructor-tut");
}
});
getTutorial(finishedTut + 1).then(data => {
//checking a "route" arg, to make sure the tutorial should be run for the current page/route
if (location.pathname.endsWith(data.route)) instructor.run(data.steps);
});
}
function getTutorial(tutId) {
//grabs the tutorial data for the desired tutorial, which is stored in a
//separate JSON file in the demo
return fetch(`../tutorials/tutorial-${tutId}.json`).then(res => res.json());
}
```
```bash
$ yarn install
```
or
```bash
$ npm install
```
```bash
$ yarn build
```
or
```bash
$ npm run build
```
or
```bash
$ gulp
```
```bash
$ node server.js
```
Then, navigate to <http://localhost:8080/demo/website/index.html>
Draws initial inspiration and code from [EnjoyHint](https://github.com/xbsoftware/enjoyhint)
MIT