UNPKG

instructorjs

Version:

On-screen tutorials for web pages and web applications

354 lines (237 loc) 12.4 kB
# InstructorJS On-screen tutorials for web pages and web applications ## Overview <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). ## Dependencies InstructorJS depends on **JQuery** version 2.2.4, **JQuery ScrollTo** version 2.1.2, and **Konva** version 4.1.2. ## Install 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"; } ``` ## Usage 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**](#multi-page-tutorials) See below for information on step configuration: ## Instructor Configurations `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; } }); ``` #### These configurations can exist on the main config object or on the final step config `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. ## Step Configurations `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()); } ``` ## Build #### Install build dependencies: ```bash $ yarn install ``` or ```bash $ npm install ``` #### Create the minified JS/CSS: ```bash $ yarn build ``` or ```bash $ npm run build ``` or ```bash $ gulp ``` #### Run the demo locally: ```bash $ node server.js ``` Then, navigate to <http://localhost:8080/demo/website/index.html> ## CREDITS Draws initial inspiration and code from [EnjoyHint](https://github.com/xbsoftware/enjoyhint) ## LICENSE MIT